f.select.cc (fotoxx-23.0) | : | f.select.cc (fotoxx-23.1) | ||
---|---|---|---|---|
/******************************************************************************* * | /******************************************************************************* * | |||
Fotoxx edit photos and manage collections | Fotoxx - edit photos and manage collections | |||
Copyright 2007-2023 Michael Cornelison | Copyright 2007-2023 Michael Cornelison | |||
source code URL: https://kornelix.net | source code URL: https://kornelix.net | |||
contact: mkornelix@gmail.com | contact: mkornelix@gmail.com | |||
This program is free software: you can redistribute it and/or modify | This program is free software: you can redistribute it and/or modify | |||
it under the terms of the GNU General Public License as published by | it under the terms of the GNU General Public License as published by | |||
the Free Software Foundation, either version 3 of the License, or | the Free Software Foundation, either version 3 of the License, or | |||
(at your option) any later version. See https://www.gnu.org/licenses | (at your option) any later version. See https://www.gnu.org/licenses | |||
skipping to change at line 89 | skipping to change at line 89 | |||
******************************************************************************** */ | ******************************************************************************** */ | |||
#define EX extern // enable extern declarations | #define EX extern // enable extern declarations | |||
#include "fotoxx.h" // (variables in fotoxx.h are refs) | #include "fotoxx.h" // (variables in fotoxx.h are refs) | |||
/******************************************************************************* */ | /******************************************************************************* */ | |||
// user select area dialog | // user select area dialog | |||
// line drawing and selection by color range are combined | // line drawing and selection by color range are combined | |||
void m_select_area(GtkWidget *, cchar *menu) // menu function | void m_select_area(GtkWidget *, ch *menu) // menu function | |||
{ | { | |||
int select_dialog_event(zdialog *, cchar *event); // dialog event and completion funcs | int select_dialog_event(zdialog *, ch *event); // dialog event and completion funcs | |||
cchar *title = "Select Area for Edits"; | ch *title = "Select Area for Edits"; | |||
zdialog *zd; | zdialog *zd; | |||
if (menu) F1_help_topic = "select area"; | if (menu) F1_help_topic = "select area"; | |||
Plog(1,"m_select_area \n"); | Plog(1,"m_select_area \n"); | |||
if (FGWM != 'F') return; | if (FGWM != 'F') return; | |||
if (! curr_file) return; // no image | if (! curr_file) return; // no image | |||
if (zd_sela) return; // already active | if (zd_sela) return; // already active | |||
skipping to change at line 248 | skipping to change at line 248 | |||
zdialog_stuff(zd,"ckallcolors",0); | zdialog_stuff(zd,"ckallcolors",0); | |||
zdialog_run(zd,select_dialog_event,"save"); // run dialog - parallel | zdialog_run(zd,select_dialog_event,"save"); // run dialog - parallel | |||
if (sa_stat) sa_show(1,0); // show existing area | if (sa_stat) sa_show(1,0); // show existing area | |||
return; | return; | |||
} | } | |||
// dialog event and completion callback function | // dialog event and completion callback function | |||
int select_dialog_event(zdialog *zd, cchar *event) | int select_dialog_event(zdialog *zd, ch *event) | |||
{ | { | |||
int Nckevents = 8, ii, kk, cc; | int Nckevents = 8, ii, kk, cc; | |||
cchar *ckevents[8] = { "ckrect", "ckelips", "ckdraw", "ckfollow", "ckrepl" , | ch *ckevents[8] = { "ckrect", "ckelips", "ckdraw", "ckfollow", "ckrepl" , | |||
"ckmouse", "ckonecolor", "ckallcolors" }; | "ckmouse", "ckonecolor", "ckallcolors" }; | |||
if (strmatch(event,"escape")) { // escape key | if (strmatch(event,"escape")) { // escape key | |||
if (sa_edgecalc_busy) Fescape = 2; | if (sa_edgecalc_busy) Fescape = 1; | |||
// kill edge calc. if busy | // kill edge calc. if busy | |||
else zd->zstat = -2; | else zd->zstat = -2; | |||
// kill dialog | // else kill dialog | |||
} | } | |||
if (sa_edgecalc_busy) return 1; // block until done | if (sa_edgecalc_busy) return 1; // block until done | |||
if (! curr_file) event = "done"; // image went away | if (! curr_file) event = "done"; // image went away | |||
if (FGWM != 'F') event = "done"; | if (FGWM != 'F') event = "done"; | |||
if (strmatch(event,"done") || zd->zstat) // done or cancel | if (strmatch(event,"done") || zd->zstat) // done or cancel | |||
{ | { | |||
freeMouse(); // disconnect mouse function | freeMouse(); // disconnect mouse function | |||
skipping to change at line 339 | skipping to change at line 339 | |||
if (strmatch(event,"show")) sa_show(1,0); // show area | if (strmatch(event,"show")) sa_show(1,0); // show area | |||
if (strmatch(event,"hide")) sa_show(0,0); // hide area | if (strmatch(event,"hide")) sa_show(0,0); // hide area | |||
if (strmatch(event,"clear")) sa_clear(); // clear area | if (strmatch(event,"clear")) sa_clear(); // clear area | |||
if (strmatch(event,"blendwidth") && sa_stat == 3) { // blend width changed and area finished | if (strmatch(event,"blendwidth") && sa_stat == 3) { // blend width changed and area finished | |||
zdialog_fetch(zd,"blendwidth",sa_blendwidth); // update sa_blendwidth | zdialog_fetch(zd,"blendwidth",sa_blendwidth); // update sa_blendwidth | |||
if (sa_blendwidth > 0) sa_edgecalc(); // do edge calc. if not already | if (sa_blendwidth > 0) sa_edgecalc(); // do edge calc. if not already | |||
if (sa_edgecalc_done && CEF && CEF->zd) // if edit is active, | if (sa_edgecalc_done && CEF && CEF->zd) // if edit is active, | |||
zdialog_send_event(CEF->zd,event); // notify new blendwidth | zdialog_send_event(CEF->zd,event); // notify new blendwidth | |||
if (! zd_sela) return 1; // dialog canceled | if (! zd_sela) return 1; // dialog canceled | |||
if (zd->zstat) { | if (zd->zstat) return 1; | |||
// dialog completed | // dialog completed | |||
zdialog_send_event(zd,"zstat"); | ||||
return 1; | ||||
} | ||||
} | } | |||
if (strmatchN(event,"creep",5) && sa_stat == 3) { // edge creep changed and area finished | if (strmatchN(event,"creep",5) && sa_stat == 3) { // edge creep changed and area finished | |||
if (event[5] == '+') sa_edgecreep(+1); | if (event[5] == '+') sa_edgecreep(+1); | |||
else sa_edgecreep(-1); | else sa_edgecreep(-1); | |||
sa_blendwidth = 0; | sa_blendwidth = 0; | |||
zdialog_stuff(zd,"blendwidth",0); | zdialog_stuff(zd,"blendwidth",0); | |||
} | } | |||
if (strmatch(event,"red")) memcpy(LINE_COLOR,RED,3*sizeof(int)); | if (strmatch(event,"red")) memcpy(LINE_COLOR,RED,3*sizeof(int)); | |||
skipping to change at line 908 | skipping to change at line 905 | |||
int newdrag; | int newdrag; | |||
static int pxcc, mxdown, mydown, dragseq; | static int pxcc, mxdown, mydown, dragseq; | |||
int startx, starty, endx, endy; | int startx, starty, endx, endy; | |||
float slope; | float slope; | |||
if (sa_stat != 1) return; // area gone? | if (sa_stat != 1) return; // area gone? | |||
if (sa_mode == mode_allcolors && ! sa_pixselc) { // allocate memory for this mode | if (sa_mode == mode_allcolors && ! sa_pixselc) { // allocate memory for this mode | |||
pxcc = Fpxb->ww * Fpxb->hh; | pxcc = Fpxb->ww * Fpxb->hh; | |||
sa_stackdirec = (char *) zmalloc(pxcc,"select-area"); | sa_stackdirec = (ch *) zmalloc(pxcc,"select-area"); | |||
sa_stack = (int *) zmalloc(pxcc * sizeof(int),"select-area"); | sa_stack = (int *) zmalloc(pxcc * sizeof(int),"select-area"); | |||
sa_maxstack = pxcc; | sa_maxstack = pxcc; | |||
sa_Nstack = 0; | sa_Nstack = 0; | |||
sa_pixselc = (uint8 *) zmalloc(pxcc,"select-area"); | sa_pixselc = (uint8 *) zmalloc(pxcc,"select-area"); | |||
} | } | |||
if (sa_mode != mode_allcolors && sa_pixselc) { // free memory otherwise | if (sa_mode != mode_allcolors && sa_pixselc) { // free memory otherwise | |||
zfree(sa_stackdirec); | zfree(sa_stackdirec); | |||
zfree(sa_stack); | zfree(sa_stack); | |||
zfree(sa_pixselc); | zfree(sa_pixselc); | |||
skipping to change at line 1043 | skipping to change at line 1040 | |||
void sa_mouse_select1(int mode, int select) | void sa_mouse_select1(int mode, int select) | |||
{ | { | |||
int mrad, mrad2; | int mrad, mrad2; | |||
int rad2, ii, jj; | int rad2, ii, jj; | |||
int px, py, rx, ry; | int px, py, rx, ry; | |||
int xlo, xhi, ylo, yhi, newpix; | int xlo, xhi, ylo, yhi, newpix; | |||
uint8 *pix1; | uint8 *pix1; | |||
float match1, match2; | float match1, match2; | |||
static float red, green, blue; | static float red, green, blue; | |||
static char colorbutt[16]; | static ch colorbutt[16]; | |||
px = sa_mousex; | px = sa_mousex; | |||
py = sa_mousey; | py = sa_mousey; | |||
if (px < 0 || px > Fpxb->ww-2) return; // mouse outside image | if (px < 0 || px > Fpxb->ww-2) return; // mouse outside image | |||
if (py < 0 || py > Fpxb->hh-2) return; | if (py < 0 || py > Fpxb->hh-2) return; | |||
if (mode == 1) // left click | if (mode == 1) // left click | |||
{ | { | |||
red = green = blue = 0; | red = green = blue = 0; | |||
skipping to change at line 1155 | skipping to change at line 1152 | |||
{ | { | |||
int mrad, mrad2, srange2; | int mrad, mrad2, srange2; | |||
int rad1, rad2, ii; | int rad1, rad2, ii; | |||
int kk, px, py, rx, ry; | int kk, px, py, rx, ry; | |||
int ppx, ppy, npx, npy; | int ppx, ppy, npx, npy; | |||
int xlo, xhi, ylo, yhi, newpix; | int xlo, xhi, ylo, yhi, newpix; | |||
uint8 *pix1; | uint8 *pix1; | |||
float red, green, blue, ff1, ff2; | float red, green, blue, ff1, ff2; | |||
float match1, match2, match3; | float match1, match2, match3; | |||
int thresh, Npixels; | int thresh, Npixels; | |||
char direc; | ch direc; | |||
struct Ctab_t { // table of pixel colors in mouse circle | struct Ctab_t { // table of pixel colors in mouse circle | |||
int count; // count of pixels with this color | int count; // count of pixels with this color | |||
float rgb[3]; // RGB color | float rgb[3]; // RGB color | |||
}; | }; | |||
Ctab_t Ctab[1000]; // table | Ctab_t Ctab[1000]; // table | |||
int Ntab; // table count | int Ntab; // table count | |||
px = sa_mousex; | px = sa_mousex; | |||
py = sa_mousey; | py = sa_mousey; | |||
skipping to change at line 1257 | skipping to change at line 1254 | |||
Ctab[ii].rgb[0] = red; // add unmatched pixel color to table | Ctab[ii].rgb[0] = red; // add unmatched pixel color to table | |||
Ctab[ii].rgb[1] = green; | Ctab[ii].rgb[1] = green; | |||
Ctab[ii].rgb[2] = blue; | Ctab[ii].rgb[2] = blue; | |||
Ctab[ii].count = 1; | Ctab[ii].count = 1; | |||
Ntab++; | Ntab++; | |||
if (Ntab == 1000) goto endmatch; // exit two nested loops | if (Ntab == 1000) goto endmatch; // exit two nested loops | |||
} | } | |||
} endmatch: | } endmatch: | |||
int keys[1][3] = { { 0, sizeof(int), 4 } }; // sort position, length, descending | int keys[1][3] = { { 0, sizeof(int), 4 } }; // sort position, length, descending | |||
MemSort((char *) Ctab, sizeof(Ctab_t), Ntab, keys, 1); // sort descending count of matching pixels | MemSort((ch *) Ctab, sizeof(Ctab_t), Ntab, keys, 1); // sort descending count of matching pixels | |||
thresh = 0.03 * Ntab; // exclude minority pixels | thresh = 0.03 * Ntab; // exclude minority pixels | |||
if (Ntab < 100) thresh = 3; | if (Ntab < 100) thresh = 3; | |||
if (Ntab < 40) thresh = 2; | if (Ntab < 40) thresh = 2; | |||
for (ii = 0; ii < Ntab; ii++) | for (ii = 0; ii < Ntab; ii++) | |||
if (Ctab[ii].count < thresh) break; | if (Ctab[ii].count < thresh) break; | |||
Ntab = ii; | Ntab = ii; | |||
// search pixels outside mouse radius but within range for matching colors | // search pixels outside mouse radius but within range for matching colors | |||
skipping to change at line 1455 | skipping to change at line 1452 | |||
return; | return; | |||
} | } | |||
// Finish select area - map pixels enclosed by edge pixels | // Finish select area - map pixels enclosed by edge pixels | |||
// into sa_pixmap[ii]: 0/1/2 = outside/edge/inside (ii = py * Fww + px) | // into sa_pixmap[ii]: 0/1/2 = outside/edge/inside (ii = py * Fww + px) | |||
// total count = sa_Npixel | // total count = sa_Npixel | |||
zdialog *sa_finzd = 0; // finish area zdialog | zdialog *sa_finzd = 0; // finish area zdialog | |||
int sa_fincancel; // finish area - user cancel | int sa_fincancel; // finish area - user cancel | |||
int sa_finish_dialog_event(zdialog *zd, cchar *event); // private functions | int sa_finish_dialog_event(zdialog *zd, ch *event); // private functions | |||
void sa_finish_mousefunc(); | void sa_finish_mousefunc(); | |||
void sa_finish_mappix(); | void sa_finish_mappix(); | |||
void sa_finish_color(); | void sa_finish_color(); | |||
void sa_finish() | void sa_finish() | |||
{ | { | |||
cchar *fmess = | ch *fmess = | |||
"Fill selected areas with color for visual verification. \n" | "Fill selected areas with color for visual verification. \n" | |||
"Method 1: left-click in each selected area not already filled. \n" | "Method 1: left-click in each selected area not already filled. \n" | |||
"Method 2: right-click OUTSIDE all selected areas. \n" | "Method 2: right-click OUTSIDE all selected areas. \n" | |||
"Press [help] button for clarification"; | "Press [help] button for clarification"; | |||
int zstat, cc; | int zstat, cc; | |||
Plog(1,"sa_finish() \n"); | Plog(1,"sa_finish() \n"); | |||
if (! sa_stat) return; // no area? | if (! sa_stat) return; // no area? | |||
if (! sa_validate()) return; // invalid for current image | if (! sa_validate()) return; // invalid for current image | |||
sa_finish_auto(); // auto-finish mouse-selected areas 22.16 | sa_finish_auto(); // auto-finish mouse-selected areas 22.16 | |||
if (sa_stat != 3) return; | if (sa_stat != 3) return; | |||
// sa_show(1,0); // zdialog_run() will Fpaint() 22.31 | // sa_show(1,0); // zdialog_run() will Fpaint() 22.31 | |||
cc = Fpxb->ww * Fpxb->hh; | cc = Fpxb->ww * Fpxb->hh; | |||
if (sa_stackdirec) zfree(sa_stackdirec); | if (sa_stackdirec) zfree(sa_stackdirec); | |||
sa_stackdirec = (char *) zmalloc(cc,"select-area"); | sa_stackdirec = (ch *) zmalloc(cc,"select-area"); | |||
if (sa_stack) zfree(sa_stack); | if (sa_stack) zfree(sa_stack); | |||
sa_stack = (int *) zmalloc(cc * sizeof(int),"select-area"); | sa_stack = (int *) zmalloc(cc * sizeof(int),"select-area"); | |||
sa_maxstack = cc; | sa_maxstack = cc; | |||
sa_fincancel = 0; | sa_fincancel = 0; | |||
sa_Nstack = 0; | sa_Nstack = 0; | |||
/*** | /*** | |||
_________________________________________________________________ | _________________________________________________________________ | |||
| Finish Area | | | Finish Area | | |||
skipping to change at line 1547 | skipping to change at line 1544 | |||
sa_stat = 3; // area is finished | sa_stat = 3; // area is finished | |||
areanumber++; // next sequential number | areanumber++; // next sequential number | |||
sa_edgecalc_done = sa_blendwidth = 0; // edge calculation is missing | sa_edgecalc_done = sa_blendwidth = 0; // edge calculation is missing | |||
if (zd_sela) zdialog_stuff(zd_sela,"blendwidth",0); | if (zd_sela) zdialog_stuff(zd_sela,"blendwidth",0); | |||
Fpaintnow(); | Fpaintnow(); | |||
return; | return; | |||
} | } | |||
// dialog event and completion function | // dialog event and completion function | |||
int sa_finish_dialog_event(zdialog *zd, cchar *event) | int sa_finish_dialog_event(zdialog *zd, ch *event) | |||
{ | { | |||
cchar *fmess = | ch *fmess = | |||
"Method 1: \n" | "Method 1: \n" | |||
" Left-click inside an outlined area that is not already filled. \ n" | " Left-click inside an outlined area that is not already filled. \ n" | |||
" Area will be filled with color for visible verification. \n" | " Area will be filled with color for visible verification. \n" | |||
" Gaps in the outline will cause overflow outside the area. \n" | " Gaps in the outline will cause overflow outside the area. \n" | |||
" Repeat for each outlined area that is not already filled. \n" | " Repeat for each outlined area that is not already filled. \n" | |||
"Method 2: \n" | "Method 2: \n" | |||
" Right-click outside ALL outlined areas. \n" | " Right-click outside ALL outlined areas. \n" | |||
" All areas will be filled with color for visible verification. \n " | " All areas will be filled with color for visible verification. \n " | |||
" Gaps in an area outline will cause that area not to be filled. \ n" | " Gaps in an area outline will cause that area not to be filled. \ n" | |||
"Gaps in an area outline: \n" | "Gaps in an area outline: \n" | |||
skipping to change at line 1650 | skipping to change at line 1647 | |||
return; | return; | |||
} | } | |||
// function to map all pixels found within enclosure containing starting pixel | // function to map all pixels found within enclosure containing starting pixel | |||
void sa_finish_mappix() | void sa_finish_mappix() | |||
{ | { | |||
int px, py, ii, jj, kk; | int px, py, ii, jj, kk; | |||
int ppx, ppy, npx, npy; | int ppx, ppy, npx, npy; | |||
char direc; | ch direc; | |||
Plog(1,"sa_finish_mappix() \n"); | Plog(1,"sa_finish_mappix() \n"); | |||
while (sa_Nstack) // find all pixels within enclosed area(s) | while (sa_Nstack) // find all pixels within enclosed area(s) | |||
{ | { | |||
kk = sa_Nstack - 1; // get last pixel in stack | kk = sa_Nstack - 1; // get last pixel in stack | |||
ii = sa_stack[kk]; | ii = sa_stack[kk]; | |||
direc = sa_stackdirec[kk]; | direc = sa_stackdirec[kk]; | |||
py = ii / Fpxb->ww; // reconstruct px, py | py = ii / Fpxb->ww; // reconstruct px, py | |||
skipping to change at line 1865 | skipping to change at line 1862 | |||
if (zd_sela) zdialog_stuff(zd_sela,"blendwidth",0); | if (zd_sela) zdialog_stuff(zd_sela,"blendwidth",0); | |||
Fpaint2(); | Fpaint2(); | |||
return; | return; | |||
} | } | |||
/******************************************************************************* */ | /******************************************************************************* */ | |||
// Find the edge pixels surrounding the clicked pixel location. | // Find the edge pixels surrounding the clicked pixel location. | |||
// Trace around the edge outline to see if there is a gap. | // Trace around the edge outline to see if there is a gap. | |||
void m_select_find_gap(GtkWidget *, cchar *menu) | void m_select_find_gap(GtkWidget *, ch *menu) | |||
{ | { | |||
int sa_find_gap_dialog_event(zdialog *zd, cchar *event); | int sa_find_gap_dialog_event(zdialog *zd, ch *event); | |||
void sa_find_gap_mousefunc(); | void sa_find_gap_mousefunc(); | |||
cchar *fmess = "Click near any position on the area outline. \n" | ch *fmess = "Click near any position on the area outline. \n" | |||
"Possible gaps in the outline will be found. \n" | "Possible gaps in the outline will be found. \n" | |||
"Press F1 for help"; | "Press F1 for help"; | |||
zdialog *zd; | zdialog *zd; | |||
F1_help_topic = "find area gap"; | F1_help_topic = "find area gap"; | |||
Plog(1,"m_select_find_gap \n"); | Plog(1,"m_select_find_gap \n"); | |||
if (FGWM != 'F') return; | if (FGWM != 'F') return; | |||
skipping to change at line 1903 | skipping to change at line 1900 | |||
zdialog_add_widget(zd,"hbox","hbmess","dialog",0,"space=3"); // each enclosed area | zdialog_add_widget(zd,"hbox","hbmess","dialog",0,"space=3"); // each enclosed area | |||
zdialog_add_widget(zd,"label","fmess","hbmess",fmess,"space=5"); | zdialog_add_widget(zd,"label","fmess","hbmess",fmess,"space=5"); | |||
zdialog_run(zd,sa_find_gap_dialog_event,"save"); // run dialog | zdialog_run(zd,sa_find_gap_dialog_event,"save"); // run dialog | |||
takeMouse(sa_find_gap_mousefunc,dragcursor); // connect mouse function | takeMouse(sa_find_gap_mousefunc,dragcursor); // connect mouse function | |||
return; | return; | |||
} | } | |||
// dialog event and completion function | // dialog event and completion function | |||
int sa_find_gap_dialog_event(zdialog *zd, cchar *event) | int sa_find_gap_dialog_event(zdialog *zd, ch *event) | |||
{ | { | |||
void sa_find_gap_mousefunc(); | void sa_find_gap_mousefunc(); | |||
if (strmatch(event,"escape")) zd->zstat = -2; // escape key | if (strmatch(event,"escape")) zd->zstat = -2; // escape key | |||
if (strmatch(event,"focus")) | if (strmatch(event,"focus")) | |||
takeMouse(sa_find_gap_mousefunc,dragcursor); // connect mouse function | takeMouse(sa_find_gap_mousefunc,dragcursor); // connect mouse function | |||
if (! zd->zstat) return 1; // wait for completion | if (! zd->zstat) return 1; // wait for completion | |||
zdialog_free(zd); | zdialog_free(zd); | |||
skipping to change at line 1929 | skipping to change at line 1926 | |||
// mouse function - search area outline surrounding mouse click position | // mouse function - search area outline surrounding mouse click position | |||
void sa_find_gap_mousefunc() | void sa_find_gap_mousefunc() | |||
{ | { | |||
int rad, ii, jj, kk, nn, ff, np1, np2, npx; | int rad, ii, jj, kk, nn, ff, np1, np2, npx; | |||
static int Fbusy = 0; | static int Fbusy = 0; | |||
float angle; | float angle; | |||
int ww, hh, cc; | int ww, hh, cc; | |||
int mx, my, px, py, rx, ry; | int mx, my, px, py, rx, ry; | |||
char *pixmark = 0; | ch *pixmark = 0; | |||
cairo_t *cr = 0; | cairo_t *cr = 0; | |||
if (! sa_stat) return; | if (! sa_stat) return; | |||
if (! LMclick) return; // no left mouse click data | if (! LMclick) return; // no left mouse click data | |||
LMclick = 0; | LMclick = 0; | |||
sa_map_pixels(); // find edge pixels | sa_map_pixels(); // find edge pixels | |||
if (! sa_Npixel) return; | if (! sa_Npixel) return; | |||
skipping to change at line 1997 | skipping to change at line 1994 | |||
if (nn != 2 || np1 == 0 || np2 == 0) { // no edge pixel with 2 neighbor | if (nn != 2 || np1 == 0 || np2 == 0) { // no edge pixel with 2 neighbor | |||
zmessage_post_bold(Mwin,"20/20",3,"cannot find area outline"); // edge pixels was found | zmessage_post_bold(Mwin,"20/20",3,"cannot find area outline"); // edge pixels was found | |||
goto cleanup; | goto cleanup; | |||
} | } | |||
sa_show(0,0); // hide area | sa_show(0,0); // hide area | |||
Fpaintnow(); | Fpaintnow(); | |||
cr = draw_context_create(gdkwin,draw_context); | cr = draw_context_create(gdkwin,draw_context); | |||
pixmark = (char *) zmalloc(cc,"select_area"); // create pixel mark map | pixmark = (ch *) zmalloc(cc,"select_area"); // create pixel mark map | |||
for (ff = 0; ff < 2; ff++) | for (ff = 0; ff < 2; ff++) | |||
{ | { | |||
memset(pixmark,0,cc); // clear all pixel marks | memset(pixmark,0,cc); // clear all pixel marks | |||
pixmark[ii] = 1; // mark edge pixel | pixmark[ii] = 1; // mark edge pixel | |||
sa_stack[0] = np1; // put neighbor 1 pixel into stack | sa_stack[0] = np1; // put neighbor 1 pixel into stack | |||
sa_Nstack = 1; // stack count | sa_Nstack = 1; // stack count | |||
while (sa_Nstack) | while (sa_Nstack) | |||
skipping to change at line 2069 | skipping to change at line 2066 | |||
namespace edgeblend_names | namespace edgeblend_names | |||
{ | { | |||
editfunc EFedgeblend; // edit function data | editfunc EFedgeblend; // edit function data | |||
int Eww, Ehh; // image dimensions | int Eww, Ehh; // image dimensions | |||
int radius, blend; | int radius, blend; | |||
} | } | |||
// menu function | // menu function | |||
void m_select_edgeblend(GtkWidget *, const char *menu) | void m_select_edgeblend(GtkWidget *, ch *menu) | |||
{ | { | |||
using namespace edgeblend_names; | using namespace edgeblend_names; | |||
int edgeblend_dialog_event(zdialog* zd, const char *event); | int edgeblend_dialog_event(zdialog* zd, ch *event); | |||
void edgeblend_mousefunc(); | void edgeblend_mousefunc(); | |||
cchar *helptext = "Left-drag mouse along area \n" | ch *helptext = "Left-drag mouse along area \n" | |||
"edge to blend-out area edits. \n" | "edge to blend-out area edits. \n" | |||
"Right-drag to restore edits."; | "Right-drag to restore edits."; | |||
char text[40]; | ch text[40]; | |||
F1_help_topic = "edge blend"; | F1_help_topic = "edge blend"; | |||
Plog(1,"m_select_edgeblend \n"); | Plog(1,"m_select_edgeblend \n"); | |||
if (CEF) { | if (CEF) { | |||
zmessageACK(Mwin,"finish current edit first"); | zmessageACK(Mwin,"finish current edit first"); | |||
return; | return; | |||
} | } | |||
skipping to change at line 2179 | skipping to change at line 2176 | |||
zdialog_fetch(zd,"blend",blend); | zdialog_fetch(zd,"blend",blend); | |||
takeMouse(edgeblend_mousefunc,0); // take mouse | takeMouse(edgeblend_mousefunc,0); // take mouse | |||
zdialog_run(zd,edgeblend_dialog_event,"save"); // run dialog - parallel | zdialog_run(zd,edgeblend_dialog_event,"save"); // run dialog - parallel | |||
return; | return; | |||
} | } | |||
// edgeblend dialog event and completion function | // edgeblend dialog event and completion function | |||
int edgeblend_dialog_event(zdialog *zd, const char *event) // edgeblend dialog event function | int edgeblend_dialog_event(zdialog *zd, ch *event) // edgeblend dialog event function | |||
{ | { | |||
using namespace edgeblend_names; | using namespace edgeblend_names; | |||
void edgeblend_mousefunc(); | void edgeblend_mousefunc(); | |||
char text[40]; | ch text[40]; | |||
int nn; | int nn; | |||
if (sa_stat < 3) { | if (sa_stat < 3) { | |||
zmessageACK(Mwin,"select area missing or not finished"); | zmessageACK(Mwin,"select area missing or not finished"); | |||
zd->zstat = -2; | zd->zstat = -2; | |||
} | } | |||
if (! sa_edgecalc_done) sa_edgecalc(); | if (! sa_edgecalc_done) sa_edgecalc(); | |||
if (strmatch(event,"escape")) zd->zstat = -2; // escape key - quit | if (strmatch(event,"escape")) zd->zstat = -2; // escape key - quit | |||
skipping to change at line 2356 | skipping to change at line 2353 | |||
GdkPixbuf *pxbdsel; // pixbuf to show match colo rs | GdkPixbuf *pxbdsel; // pixbuf to show match colo rs | |||
int pxbsize, pxbmid, rs; // " size, middle pixel, r ow stride | int pxbsize, pxbmid, rs; // " size, middle pixel, r ow stride | |||
uint8 *pixels; // " pixel data | uint8 *pixels; // " pixel data | |||
float retRGB[3]; // retouch color for pixels retained | float retRGB[3]; // retouch color for pixels retained | |||
int Fretactive; // retouce color active or n ot | int Fretactive; // retouce color active or n ot | |||
int saveFBrgb[3]; // save/restore window backg round color | int saveFBrgb[3]; // save/restore window backg round color | |||
} | } | |||
// menu function | // menu function | |||
void m_copy_complex(GtkWidget *, cchar *) // 22.16 | void m_copy_complex(GtkWidget *, ch *) // 22.16 | |||
{ | { | |||
using namespace copy_complex; | using namespace copy_complex; | |||
int copy_complex_dialog_event(zdialog *zd, cchar *event); | int copy_complex_dialog_event(zdialog *zd, ch *event); | |||
void copy_complex_mousefunc(); | void copy_complex_mousefunc(); | |||
cchar *title = "Select/Copy Complex Shape"; | ch *title = "Select/Copy Complex Shape"; | |||
cchar *rettip = "shift + left-click on image to set retouch color"; | ch *rettip = "shift + left-click on image to set retouch color"; | |||
F1_help_topic = "copy/complex"; | F1_help_topic = "copy/complex"; | |||
Plog(1,"m_copy_complex \n"); | Plog(1,"m_copy_complex \n"); | |||
if (FGWM != 'F') return; | if (FGWM != 'F') return; | |||
if (CEF) { | if (CEF) { | |||
zmessageACK(Mwin,"complete pending edit first"); | zmessageACK(Mwin,"complete pending edit first"); | |||
return; | return; | |||
skipping to change at line 2453 | skipping to change at line 2450 | |||
zdialog_add_widget(zd,"hbox","hbmrad","dialog",0,"space=3"); | zdialog_add_widget(zd,"hbox","hbmrad","dialog",0,"space=3"); | |||
zdialog_add_widget(zd,"label","labmrad","hbmrad","Mouse Radius","space=3"); | zdialog_add_widget(zd,"label","labmrad","hbmrad","Mouse Radius","space=3"); | |||
zdialog_add_widget(zd,"hscale","mouserad","hbmrad","3|200|1|30","expand"); | zdialog_add_widget(zd,"hscale","mouserad","hbmrad","3|200|1|30","expand"); | |||
zdialog_add_widget(zd,"label","mouserad2","hbmrad","30","space=3"); | zdialog_add_widget(zd,"label","mouserad2","hbmrad","30","space=3"); | |||
zdialog_add_widget(zd,"hbox","hbdes","dialog",0,"space=3"); | zdialog_add_widget(zd,"hbox","hbdes","dialog",0,"space=3"); | |||
zdialog_add_widget(zd,"label","labdsel","hbdes","deselect colors","space=3"); | zdialog_add_widget(zd,"label","labdsel","hbdes","deselect colors","space=3"); | |||
zdialog_add_widget(zd,"hscale","dmatchlev","hbdes","10|99|1|85","expand"); | zdialog_add_widget(zd,"hscale","dmatchlev","hbdes","10|99|1|85","expand"); | |||
zdialog_add_widget(zd,"label","dmatchlev2","hbdes","85","space=3"); | zdialog_add_widget(zd,"label","dmatchlev2","hbdes","85","space=3"); | |||
zdialog_add_widget(zd,"image","dcolors","hbdes",(cchar *) pxbdsel); | zdialog_add_widget(zd,"image","dcolors","hbdes",(ch *) pxbdsel); | |||
zdialog_add_widget(zd,"hbox","hbret","dialog",0,"space=3"); | zdialog_add_widget(zd,"hbox","hbret","dialog",0,"space=3"); | |||
zdialog_add_widget(zd,"label","labret","hbret","retouch color","space=3"); | zdialog_add_widget(zd,"label","labret","hbret","retouch color","space=3"); | |||
zdialog_add_widget(zd,"colorbutt","retRGB","hbret","0|0|0"); | zdialog_add_widget(zd,"colorbutt","retRGB","hbret","0|0|0"); | |||
zdialog_add_widget(zd,"label","space","hbret",0,"space=8"); | zdialog_add_widget(zd,"label","space","hbret",0,"space=8"); | |||
zdialog_add_widget(zd,"check","retactive","hbret","activate"); | zdialog_add_widget(zd,"check","retactive","hbret","activate"); | |||
zdialog_add_widget(zd,"hbox","hbtip","dialog"); | zdialog_add_widget(zd,"hbox","hbtip","dialog"); | |||
zdialog_add_widget(zd,"label","labtip","hbtip",rettip,"space=3"); | zdialog_add_widget(zd,"label","labtip","hbtip",rettip,"space=3"); | |||
zdialog_add_widget(zd,"hbox","hbtran","dialog",0,"space=15"); | zdialog_add_widget(zd,"hbox","hbtran","dialog",0,"space=15"); | |||
skipping to change at line 2484 | skipping to change at line 2481 | |||
zdialog_resize(zd,300,0); // run dialog | zdialog_resize(zd,300,0); // run dialog | |||
zdialog_run(zd,copy_complex_dialog_event,"save"); | zdialog_run(zd,copy_complex_dialog_event,"save"); | |||
takeMouse(copy_complex_mousefunc,dragcursor); // capture mouse | takeMouse(copy_complex_mousefunc,dragcursor); // capture mouse | |||
return; | return; | |||
} | } | |||
// dialog event and completion function | // dialog event and completion function | |||
int copy_complex_dialog_event(zdialog *zd, cchar *event) | int copy_complex_dialog_event(zdialog *zd, ch *event) | |||
{ | { | |||
using namespace copy_complex; | using namespace copy_complex; | |||
void copy_complex_mousefunc(); | void copy_complex_mousefunc(); | |||
int ii, px, py; | int ii, px, py; | |||
char text[20]; | ch text[20]; | |||
cchar *ppc; | ch *ppc; | |||
float *pix0; | float *pix0; | |||
if (strmatch(event,"escape")) zd->zstat = -2; // escape key | if (strmatch(event,"escape")) zd->zstat = -2; // escape key | |||
if (! curr_file) zd->zstat = -2; // image went away | if (! curr_file) zd->zstat = -2; // image went away | |||
if (sa_stat < 3) zd->zstat = -2; // area gone | if (sa_stat < 3) zd->zstat = -2; // area gone | |||
if (strmatch(event,"cancel")) zd->zstat = 4; // from f_open() | if (strmatch(event,"cancel")) zd->zstat = 4; // from f_open() | |||
if (strmatch(event,"focus")) | if (strmatch(event,"focus")) | |||
takeMouse(copy_complex_mousefunc,dragcursor); | takeMouse(copy_complex_mousefunc,dragcursor); | |||
skipping to change at line 2569 | skipping to change at line 2566 | |||
zdialog_stuff(zd,"dmatchlev2",text); | zdialog_stuff(zd,"dmatchlev2",text); | |||
return 1; | return 1; | |||
} | } | |||
// mouse function | // mouse function | |||
void copy_complex_mousefunc() | void copy_complex_mousefunc() | |||
{ | { | |||
using namespace copy_complex; | using namespace copy_complex; | |||
int copy_complex_ucomp(cchar *, cchar*); | int copy_complex_ucomp(ch *, ch *); | |||
int ii, jj, rx, ry, px, py; | int ii, jj, rx, ry, px, py; | |||
int mrad, rrad; | int mrad, rrad; | |||
uint8 *pix; | uint8 *pix; | |||
float *pix0, *pix1; | float *pix0, *pix1; | |||
float pixmatch, bestmatch; | float pixmatch, bestmatch; | |||
float Dmatchlev; | float Dmatchlev; | |||
float Dmatch = 0; | float Dmatch = 0; | |||
float f1, f2, alpha; | float f1, f2, alpha; | |||
char text[20]; | ch text[20]; | |||
GdkPixbuf *pxbtemp = 0; | GdkPixbuf *pxbtemp = 0; | |||
if (LMclick && KBshiftkey) // shift + left mouse click | if (LMclick && KBshiftkey) // shift + left mouse click | |||
{ | { | |||
LMclick = 0; | LMclick = 0; | |||
pix1 = PXMpix(E1pxm,Mxclick,Myclick); // pick new retouch color from image | pix1 = PXMpix(E1pxm,Mxclick,Myclick); // pick new retouch color from image | |||
retRGB[0] = pix1[0]; | retRGB[0] = pix1[0]; | |||
retRGB[1] = pix1[1]; | retRGB[1] = pix1[1]; | |||
retRGB[2] = pix1[2]; | retRGB[2] = pix1[2]; | |||
snprintf(text,20,"%.0f|%.0f|%.0f",retRGB[0],retRGB[1],retRGB[2]); | snprintf(text,20,"%.0f|%.0f|%.0f",retRGB[0],retRGB[1],retRGB[2]); | |||
skipping to change at line 2743 | skipping to change at line 2740 | |||
LMclick = RMclick = Mxdrag = Mydrag = 0; | LMclick = RMclick = Mxdrag = Mydrag = 0; | |||
return; | return; | |||
} | } | |||
/******************************************************************************* */ | /******************************************************************************* */ | |||
// menu function for show, hide, enable, disable, invert, clear | // menu function for show, hide, enable, disable, invert, clear | |||
// (also implemented as buttons in select area dialog) | // (also implemented as buttons in select area dialog) | |||
void m_select_show(GtkWidget *, cchar *menu) | void m_select_show(GtkWidget *, ch *menu) | |||
{ | { | |||
F1_help_topic = "show/hide area"; | F1_help_topic = "show/hide area"; | |||
Plog(1,"m_select_show \n"); | Plog(1,"m_select_show \n"); | |||
if (FGWM != 'F') return; | if (FGWM != 'F') return; | |||
sa_show(1,0); // show area | sa_show(1,0); // show area | |||
return; | return; | |||
} | } | |||
void m_select_hide(GtkWidget *, cchar *menu) | void m_select_hide(GtkWidget *, ch *menu) | |||
{ | { | |||
F1_help_topic = "show/hide area"; | F1_help_topic = "show/hide area"; | |||
Plog(1,"m_select_hide \n"); | Plog(1,"m_select_hide \n"); | |||
if (FGWM != 'F') return; | if (FGWM != 'F') return; | |||
sa_show(0,0); | sa_show(0,0); | |||
return; | return; | |||
} | } | |||
void m_select_enable(GtkWidget *, cchar *menu) | void m_select_enable(GtkWidget *, ch *menu) | |||
{ | { | |||
F1_help_topic = "enable/disable area"; | F1_help_topic = "enable/disable area"; | |||
Plog(1,"m_select_enable \n"); | Plog(1,"m_select_enable \n"); | |||
if (FGWM != 'F') return; | if (FGWM != 'F') return; | |||
sa_enable(); | sa_enable(); | |||
return; | return; | |||
} | } | |||
void m_select_disable(GtkWidget *, cchar *menu) | void m_select_disable(GtkWidget *, ch *menu) | |||
{ | { | |||
F1_help_topic = "enable/disable area"; | F1_help_topic = "enable/disable area"; | |||
Plog(1,"m_select_disable \n"); | Plog(1,"m_select_disable \n"); | |||
if (FGWM != 'F') return; | if (FGWM != 'F') return; | |||
sa_disable(); | sa_disable(); | |||
return; | return; | |||
} | } | |||
void m_select_invert(GtkWidget *, cchar *menu) | void m_select_invert(GtkWidget *, ch *menu) | |||
{ | { | |||
F1_help_topic = "invert area"; | F1_help_topic = "invert area"; | |||
Plog(1,"m_select_invert \n"); | Plog(1,"m_select_invert \n"); | |||
if (FGWM != 'F') return; | if (FGWM != 'F') return; | |||
sa_invert(); | sa_invert(); | |||
return; | return; | |||
} | } | |||
void m_select_clear(GtkWidget *, cchar *menu) // delete the area | void m_select_clear(GtkWidget *, ch *menu) // delete the area | |||
{ | { | |||
F1_help_topic = "clear area"; | F1_help_topic = "clear area"; | |||
Plog(1,"m_select_clear \n"); | Plog(1,"m_select_clear \n"); | |||
if (FGWM != 'F') return; | if (FGWM != 'F') return; | |||
sa_clear(); | sa_clear(); | |||
return; | return; | |||
} | } | |||
/******************************************************************************* */ | /******************************************************************************* */ | |||
skipping to change at line 3057 | skipping to change at line 3054 | |||
Fpaint2(); | Fpaint2(); | |||
return; | return; | |||
} | } | |||
// compute distance from all pixels in area to nearest edge | // compute distance from all pixels in area to nearest edge | |||
// output: sa_pixmap[*] = 0/1/2+ = outside, edge, inside distance from edge | // output: sa_pixmap[*] = 0/1/2+ = outside, edge, inside distance from edge | |||
namespace sa_edgecalc_names | namespace sa_edgecalc_names | |||
{ | { | |||
uint16 *sa_edgepx, *sa_edgepy, *sa_edgedist; | uint16 *sa_edgepx, *sa_edgepy, *sa_edgedist; | |||
int sa_Nedge, edgecalc_thread_busy; | int sa_Nedge; | |||
} | } | |||
void sa_edgecalc() | void sa_edgecalc() | |||
{ | { | |||
using namespace sa_edgecalc_names; | using namespace sa_edgecalc_names; | |||
void * edgecalc_thread(void *arg); | void * edgecalc_thread(void *arg); | |||
int ii, nn, cc, px, py; | int ii, nn, cc, px, py; | |||
zdialog *zdp; | zdialog *zdp; | |||
if (! sa_stat) return; // area gone? | if (! sa_stat) return; // area gone? | |||
if (sa_edgecalc_done) return; // done already | if (sa_edgecalc_done) return; // done already | |||
if (sa_stat < 3) return; // area must be finished | if (sa_stat < 3) return; // area must be finished | |||
if (sa_stat != 3) return; // failed or canceled | if (sa_stat != 3) return; // failed or canceled | |||
if (sa_edgecalc_busy) return; // stop re-entry | if (sa_edgecalc_busy) return; // stop re-entry | |||
zdp = zmessage_post_bold(Mwin,"mouse",0,"edge distance calculation"); | zdp = zmessage_post_bold(Mwin,"mouse",3,"edge distance calculation"); | |||
sa_edgecalc_busy = 1; | sa_edgecalc_busy = 1; | |||
cc = Fpxb->ww * Fpxb->hh * sizeof(uint16); // allocate memory for calculations | cc = Fpxb->ww * Fpxb->hh * sizeof(uint16); // allocate memory for calculations | |||
sa_edgedist = (uint16 *) zmalloc(cc,"select_area"); | sa_edgedist = (uint16 *) zmalloc(cc,"select_area"); | |||
for (ii = nn = 0; ii < Fpxb->ww * Fpxb->hh; ii++) // count edge pixels in select area | for (ii = nn = 0; ii < Fpxb->ww * Fpxb->hh; ii++) // count edge pixels in select area | |||
if (sa_pixmap[ii] == 1) nn++; | if (sa_pixmap[ii] == 1) nn++; | |||
cc = nn * sizeof(uint16); | cc = nn * sizeof(uint16); | |||
skipping to change at line 3121 | skipping to change at line 3118 | |||
sa_edgepx[nn] = px; | sa_edgepx[nn] = px; | |||
sa_edgepy[nn] = py; | sa_edgepy[nn] = py; | |||
nn++; | nn++; | |||
} | } | |||
sa_Nedge = nn; | sa_Nedge = nn; | |||
progress_reset(sa_Npixel); // progress counter goal | progress_reset(sa_Npixel); // progress counter goal | |||
Fescape = 1; | Fwatchescape = 1; | |||
// escapable function 22.50 | // killable with escape key 23.1 | |||
edgecalc_thread_busy = 1; | Fescape = 0; | |||
start_detached_thread(edgecalc_thread,0); | Ffuncbusy = 1; | |||
while (edgecalc_thread_busy) zmainsleep(0.1); | ||||
// keep GTK alive | ||||
progress_reset(0); | start_detached_thread(edgecalc_thread,0); | |||
while (Ffuncbusy) zmainloop(0.1); | ||||
for (int ii = 0; ii < Fpxb->ww * Fpxb->hh; ii++) { | if (Fescape) { | |||
// copy sa_edgedist[] to sa_pixmap[] | // aborted 23.1 | |||
if (sa_pixmap[ii] <= 1) continue; | sa_blendwidth = 0; | |||
// skip outside and edge pixels | // reset blend width | |||
sa_pixmap[ii] = sa_edgedist[ii]; | if (zd_sela) zdialog_stuff(zd_sela,"blendwidth",0); | |||
// interior pixel edge distance | ||||
} | } | |||
Fwatchescape = Fescape = 0; | ||||
progress_reset(0); | ||||
zdialog_free(zdp); | zdialog_free(zdp); | |||
zfree(sa_edgedist); // free memory | zfree(sa_edgedist); // free memory | |||
zfree(sa_edgepx); | zfree(sa_edgepx); | |||
zfree(sa_edgepy); | zfree(sa_edgepy); | |||
sa_edgecalc_done = 1; | ||||
// edge calculation available | ||||
if (Fescape > 1) sa_edgecalc_done = 0; | ||||
// canceled 22.50 | ||||
Fescape = 0; | ||||
sa_edgecalc_busy = 0; | sa_edgecalc_busy = 0; | |||
return; | return; | |||
} | } | |||
void * edgecalc_thread(void *arg) // edgecalc thread function | void * edgecalc_thread(void *arg) // edgecalc thread function | |||
{ | { | |||
using namespace sa_edgecalc_names; | using namespace sa_edgecalc_names; | |||
void * edgecalc_wthread(void *arg); | void * edgecalc_wthread(void *arg); | |||
do_wthreads(edgecalc_wthread,NWT); // do worker threads | do_wthreads(edgecalc_wthread,NWT); // do worker threads | |||
edgecalc_thread_busy = 0; | ||||
if (! Fescape) | ||||
// not cancelled 23.1 | ||||
{ | ||||
sa_edgecalc_done = 1; | ||||
// edge calc. done | ||||
for (int ii = 0; ii < Fpxb->ww * Fpxb->hh; ii++) { | ||||
// copy sa_edgedist[] to sa_pixmap[] | ||||
if (sa_pixmap[ii] <= 1) continue; | ||||
// skip outside and edge pixels | ||||
sa_pixmap[ii] = sa_edgedist[ii]; | ||||
// interior pixel edge distance | ||||
} | ||||
} | ||||
Ffuncbusy = 0; | ||||
return 0; | return 0; | |||
} | } | |||
void * edgecalc_wthread(void *arg) // edgecalc worker thread function | void * edgecalc_wthread(void *arg) // edgecalc worker thread function | |||
{ | { | |||
using namespace sa_edgecalc_names; | using namespace sa_edgecalc_names; | |||
void edgecalc_func(int px, int py); | void edgecalc_func(int px, int py); | |||
int index = *((int *) arg); | int index = *((int *) arg); | |||
skipping to change at line 3187 | skipping to change at line 3196 | |||
{ | { | |||
for (px = midx-rad; px <= midx+rad; px += 2 * rad) // edges only, interior already done | for (px = midx-rad; px <= midx+rad; px += 2 * rad) // edges only, interior already done | |||
for (py = midy-rad+index; py <= midy+rad; py += NWT) | for (py = midy-rad+index; py <= midy+rad; py += NWT) | |||
{ | { | |||
if (px < 0 || px > Fpxb->ww-1) continue; | if (px < 0 || px > Fpxb->ww-1) continue; | |||
if (py < 0 || py > Fpxb->hh-1) continue; | if (py < 0 || py > Fpxb->hh-1) continue; | |||
ii = py * Fpxb->ww + px; | ii = py * Fpxb->ww + px; | |||
if (! sa_pixmap[ii]) continue; | if (! sa_pixmap[ii]) continue; | |||
if (sa_edgedist[ii]) continue; | if (sa_edgedist[ii]) continue; | |||
edgecalc_func(px,py); | edgecalc_func(px,py); | |||
if (Fescape > 1) break; // killed | if (Fescape) break; // killed | |||
} | } | |||
for (py = midy-rad; py <= midy+rad; py += 2 * rad) | for (py = midy-rad; py <= midy+rad; py += 2 * rad) | |||
for (px = midx-rad+index; px <= midx+rad; px += NWT) | for (px = midx-rad+index; px <= midx+rad; px += NWT) | |||
{ | { | |||
if (px < 0 || px > Fpxb->ww-1) continue; | if (px < 0 || px > Fpxb->ww-1) continue; | |||
if (py < 0 || py > Fpxb->hh-1) continue; | if (py < 0 || py > Fpxb->hh-1) continue; | |||
ii = py * Fpxb->ww + px; | ii = py * Fpxb->ww + px; | |||
if (! sa_pixmap[ii]) continue; | if (! sa_pixmap[ii]) continue; | |||
if (sa_edgedist[ii]) continue; | if (sa_edgedist[ii]) continue; | |||
edgecalc_func(px,py); | edgecalc_func(px,py); | |||
if (Fescape > 1) break; // killed | if (Fescape) break; // killed | |||
} | } | |||
} | } | |||
return 0; | return 0; | |||
} | } | |||
// Find the nearest edge pixel for a given pixel. | // Find the nearest edge pixel for a given pixel. | |||
// For all pixels in a line from the given pixel to the edge pixel, | // For all pixels in a line from the given pixel to the edge pixel, | |||
// the same edge pixel is used to compute edge distance. | // the same edge pixel is used to compute edge distance. | |||
skipping to change at line 3377 | skipping to change at line 3386 | |||
int sacp_porgx, sacp_porgy; // pasted area origin in image | int sacp_porgx, sacp_porgy; // pasted area origin in image | |||
int sacp_pww, sacp_phh; // pasted area dimensions | int sacp_pww, sacp_phh; // pasted area dimensions | |||
editfunc EFpaste; | editfunc EFpaste; | |||
} | } | |||
// Save a select area in memory to a disk PNG file. | // Save a select area in memory to a disk PNG file. | |||
// For menu "Copy" use default file: ~/.fotoxx/saved_areas/copied_area.png | // For menu "Copy" use default file: ~/.fotoxx/saved_areas/copied_area.png | |||
// For menu "Save Area" use file name from user input. | // For menu "Save Area" use file name from user input. | |||
void m_select_copysave(GtkWidget *, cchar *menu); | void m_select_copysave(GtkWidget *, ch *menu); | |||
void m_select_copy(GtkWidget *, cchar *) | void m_select_copy(GtkWidget *, ch *) | |||
{ | { | |||
Plog(1,"m_select_copy \n"); | Plog(1,"m_select_copy \n"); | |||
m_select_copysave(0,"copy"); | m_select_copysave(0,"copy"); | |||
return; | return; | |||
} | } | |||
void m_select_save(GtkWidget *, cchar *) | void m_select_save(GtkWidget *, ch *) | |||
{ | { | |||
Plog(1,"m_select_save \n"); | Plog(1,"m_select_save \n"); | |||
m_select_copysave(0,"save"); | m_select_copysave(0,"save"); | |||
return; | return; | |||
} | } | |||
void m_select_copysave(GtkWidget *, cchar *menu) | void m_select_copysave(GtkWidget *, ch *menu) | |||
{ | { | |||
using namespace sa_diskfile; | using namespace sa_diskfile; | |||
int ii, px1, py1, px2, py2, dist; | int ii, px1, py1, px2, py2, dist; | |||
int ww, nc, pcc; | int ww, nc, pcc; | |||
float *pix1, *pix2; | float *pix1, *pix2; | |||
char *pp, *file; | ch *pp, *file; | |||
char filename[100]; | ch filename[200]; | |||
if (strmatch(menu,"copy")) | if (strmatch(menu,"copy")) | |||
F1_help_topic = "copy/paste area"; | F1_help_topic = "copy/paste area"; | |||
else if (strmatch(menu,"save")) | else if (strmatch(menu,"save")) | |||
F1_help_topic = "load/save area"; | F1_help_topic = "load/save area"; | |||
else Plog(0,"F1 topic error \n"); | else Plog(0,"F1 topic error \n"); | |||
if (FGWM != 'F') return; | if (FGWM != 'F') return; | |||
if (! sa_stat) return; // no selected area | if (! sa_stat) return; // no selected area | |||
skipping to change at line 3449 | skipping to change at line 3458 | |||
pix1 = PXMpix(E0pxm,px1,py1); // copy to area PXM | pix1 = PXMpix(E0pxm,px1,py1); // copy to area PXM | |||
pix2 = PXMpix(sacp_pxm,px2,py2); | pix2 = PXMpix(sacp_pxm,px2,py2); | |||
memcpy(pix2,pix1,pcc); // copy RGB(A) data | memcpy(pix2,pix1,pcc); // copy RGB(A) data | |||
ii = py1 * ww + px1; | ii = py1 * ww + px1; | |||
dist = sa_pixmap[ii]; // 0/1/2+ = outside/edge/inside edge dist. | dist = sa_pixmap[ii]; // 0/1/2+ = outside/edge/inside edge dist. | |||
if (dist == 0) pix2[3] = 0; // outside pixel, transparent | if (dist == 0) pix2[3] = 0; // outside pixel, transparent | |||
else pix2[3] = 255; // edge or inside, opaque | else pix2[3] = 255; // edge or inside, opaque | |||
} | } | |||
if (strmatch(menu,"copy")) { | if (strmatch(menu,"copy")) { | |||
snprintf(filename,100,"%s/copied_area.png",saved_areas_folder); // save to default PNG file | snprintf(filename,200,"%s/copied_area.png",saved_areas_folder); // save to default PNG file | |||
PXM_PNG_save(sacp_pxm,filename,16); | PXM_PNG_save(sacp_pxm,filename,16); | |||
return; | return; | |||
} | } | |||
pp = zgetfile("save area as a PNG file",MWIN,"save",saved_areas_folder); // get file name from user | pp = zgetfile("save area as a PNG file",MWIN,"save",saved_areas_folder); // get file name from user | |||
if (! pp) return; | if (! pp) return; | |||
file = zstrdup(pp,"select_area",8); | file = zstrdup(pp,"select_area",8); | |||
zfree(pp); | zfree(pp); | |||
pp = strrchr(file,'/'); | pp = strrchr(file,'/'); | |||
pp = strcasestr(pp,".png"); | pp = strcasestr(pp,".png"); | |||
if (! pp) strcat(file,".png"); | if (! pp) strcat(file,".png"); | |||
PXM_PNG_save(sacp_pxm,file,16); // use PNG-16 file | PXM_PNG_save(sacp_pxm,file,16); // use PNG-16 file | |||
zfree(file); | zfree(file); | |||
return; | return; | |||
} | } | |||
// Read a select area from a disk PNG file. | // Read a select area from a disk PNG file. | |||
void m_select_load(GtkWidget *, cchar *menu) | void m_select_load(GtkWidget *, ch *menu) | |||
{ | { | |||
using namespace sa_diskfile; | using namespace sa_diskfile; | |||
void select_paste(GtkWidget *, cchar *); | void select_paste(GtkWidget *, ch *); | |||
PXM *pxmtemp; | PXM *pxmtemp; | |||
char *file; | ch *file; | |||
float *pix1, *pix2; | float *pix1, *pix2; | |||
int px, py, nc, pcc; | int px, py, nc, pcc; | |||
F1_help_topic = "load/save area"; | F1_help_topic = "load/save area"; | |||
Plog(1,"m_select_load \n"); | Plog(1,"m_select_load \n"); | |||
if (FGWM != 'F') return; | if (FGWM != 'F') return; | |||
PXM_free(sacp_pxm); // free prior if any | PXM_free(sacp_pxm); // free prior if any | |||
skipping to change at line 3521 | skipping to change at line 3530 | |||
} | } | |||
PXM_free(pxmtemp); | PXM_free(pxmtemp); | |||
select_paste(0,"paste area"); // interactive move/resize area image | select_paste(0,"paste area"); // interactive move/resize area image | |||
return; | return; | |||
} | } | |||
// paste the area last copied on to the current image | // paste the area last copied on to the current image | |||
// uses the default file from "copy area" menu (above) | // uses the default file from "copy area" menu (above) | |||
void m_select_paste(GtkWidget *, cchar *menu) | void m_select_paste(GtkWidget *, ch *menu) | |||
{ | { | |||
using namespace sa_diskfile; | using namespace sa_diskfile; | |||
void select_paste(GtkWidget *, cchar *); | void select_paste(GtkWidget *, ch *); | |||
PXM *pxmtemp; | PXM *pxmtemp; | |||
char filename[100]; | ch filename[200]; | |||
float *pix1, *pix2; | float *pix1, *pix2; | |||
int px, py, nc, pcc; | int px, py, nc, pcc; | |||
F1_help_topic = "copy/paste area"; | F1_help_topic = "copy/paste area"; | |||
Plog(1,"m_select_paste \n"); | Plog(1,"m_select_paste \n"); | |||
if (FGWM != 'F') return; | if (FGWM != 'F') return; | |||
PXM_free(sacp_pxm); // free prior if any | PXM_free(sacp_pxm); // free prior if any | |||
PXM_free(sacpR_pxm); | PXM_free(sacpR_pxm); | |||
snprintf(filename,100,"%s/copied_area.png",saved_areas_folder); | snprintf(filename,200,"%s/copied_area.png",saved_areas_folder); | |||
pxmtemp = PXM_load(filename,1); // load image file | pxmtemp = PXM_load(filename,1); // load image file | |||
if (! pxmtemp) return; | if (! pxmtemp) return; | |||
nc = pxmtemp->nc; | nc = pxmtemp->nc; | |||
pcc = nc * sizeof(float); | pcc = nc * sizeof(float); | |||
sacp_ww = pxmtemp->ww; // image dimensiona | sacp_ww = pxmtemp->ww; // image dimensiona | |||
sacp_hh = pxmtemp->hh; | sacp_hh = pxmtemp->hh; | |||
sacp_pxm = PXM_make(sacp_ww,sacp_hh,4); // alpha channel | sacp_pxm = PXM_make(sacp_ww,sacp_hh,4); // alpha channel | |||
skipping to change at line 3571 | skipping to change at line 3580 | |||
} | } | |||
PXM_free(pxmtemp); | PXM_free(pxmtemp); | |||
select_paste(0,"paste area"); // interactive move/resize area image | select_paste(0,"paste area"); // interactive move/resize area image | |||
return; | return; | |||
} | } | |||
// paste select area in memory into current image | // paste select area in memory into current image | |||
// this is an edit function - select area image is copied into main image | // this is an edit function - select area image is copied into main image | |||
void select_paste(GtkWidget *, cchar *menu) | void select_paste(GtkWidget *, ch *menu) | |||
{ | { | |||
using namespace sa_diskfile; | using namespace sa_diskfile; | |||
void select_paste_image(); | void select_paste_image(); | |||
int select_paste_dialog_event(zdialog *, cchar *event); | int select_paste_dialog_event(zdialog *, ch *event); | |||
void select_paste_mousefunc(); | void select_paste_mousefunc(); | |||
cchar *dragmess = "position with mouse click/drag"; | ch *dragmess = "position with mouse click/drag"; | |||
if (sa_edgecalc_busy) return; // wait until done | if (sa_edgecalc_busy) return; // wait until done | |||
if (! sacp_pxm) return; // nothing to paste | if (! sacp_pxm) return; // nothing to paste | |||
sa_clear(); // clear area if present | sa_clear(); // clear area if present | |||
EFpaste.menufunc = select_paste; | EFpaste.menufunc = select_paste; | |||
EFpaste.menuname = "paste area"; | EFpaste.menuname = "paste area"; | |||
EFpaste.Frestart = 1; // make restartable | EFpaste.Frestart = 1; // make restartable | |||
skipping to change at line 3685 | skipping to change at line 3694 | |||
takeMouse(select_paste_mousefunc,0); // connect mouse function | takeMouse(select_paste_mousefunc,0); // connect mouse function | |||
return; | return; | |||
} | } | |||
// Dialog event and completion callback function. | // Dialog event and completion callback function. | |||
// Get dialog values and convert image. When done, commit edited image | // Get dialog values and convert image. When done, commit edited image | |||
// (with pasted area) and set up a new select area for the pasted area, | // (with pasted area) and set up a new select area for the pasted area, | |||
// allowing further editing of the area. | // allowing further editing of the area. | |||
int select_paste_dialog_event(zdialog *zd, cchar *event) | int select_paste_dialog_event(zdialog *zd, ch *event) | |||
{ | { | |||
using namespace sa_diskfile; | using namespace sa_diskfile; | |||
void select_paste_mousefunc(); | void select_paste_mousefunc(); | |||
void select_paste_image(); | void select_paste_image(); | |||
void select_paste_adjust(); | void select_paste_adjust(); | |||
int ww, hh; | int ww, hh; | |||
PXM *pxm_temp; | PXM *pxm_temp; | |||
End of changes. 73 change blocks. | ||||
95 lines changed or deleted | 105 lines changed or added |