1 /*
2 * Author: William Chia-Wei Cheng (bill.cheng@acm.org)
3 *
4 * Copyright (C) 2001-2009, William Chia-Wei Cheng.
5 *
6 * This file may be distributed under the terms of the Q Public License
7 * as defined by Trolltech AS of Norway and appearing in the file
8 * LICENSE.QPL included in the packaging of this file.
9 *
10 * THIS FILE IS PROVIDED AS IS WITH NO WARRANTY OF ANY KIND, INCLUDING
11 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
12 * PURPOSE. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL,
13 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
14 * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
15 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
16 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 *
18 * @(#)$Header: /mm2/home/cvs/bc-src/tgif/imgproc.c,v 1.82 2011/05/25 16:54:27 cvsps Exp $
19 */
20
21 #define _INCLUDE_FROM_IMGPROC_C_
22
23 #include "tgifdefs.h"
24 #include "cmdids.h"
25
26 #include "auxtext.e"
27 #include "choice.e"
28 #include "cmd.e"
29 #include "color.e"
30 #include "cursor.e"
31 #include "dialog.e"
32 #include "drawing.e"
33 #include "dup.e"
34 #include "file.e"
35 #include "grid.e"
36 #include "hash.e"
37 #include "imgproc.e"
38 #include "list.e"
39 #include "mainloop.e"
40 #include "mainmenu.e"
41 #include "mark.e"
42 #include "menu.e"
43 #include "menuinfo.e"
44 #include "move.e"
45 #include "msg.e"
46 #include "names.e"
47 #include "navigate.e"
48 #include "obj.e"
49 #include "page.e"
50 #include "pngtrans.e"
51 #include "poly.e"
52 #include "polygon.e"
53 #include "raster.e"
54 #include "rect.e"
55 #include "remote.e"
56 #include "ruler.e"
57 #include "select.e"
58 #include "setup.e"
59 #include "special.e"
60 #include "strtbl.e"
61 #include "util.e"
62 #include "xbitmap.e"
63 #include "xpixmap.e"
64 #include "z_intrf.e"
65
66 #define HISTOGRAMCOUNT(i) (gpHistogram[(i)].pixel)
67 #define HISTOGRAMRED(i) (gpHistogram[(i)].red)
68 #define HISTOGRAMGREEN(i) (gpHistogram[(i)].green)
69 #define HISTOGRAMBLUE(i) (gpHistogram[(i)].blue)
70
71 #define MAXIMAGEPROCS 34
72
73 int numImageProc=MAXIMAGEPROCS;
74 int gnInImageProc=FALSE;
75 int gnConvolving=FALSE;
76 int gnNumNewColorsInPixmapFile=0;
77
78 char gszImageProcXPmFile[MAXPATHLENGTH+1];
79
80 float gfVectorWarpSoftness=2.0;
81
82 int threshFillReplaceEnabled=FALSE;
83 int fillReplaceRedThresh=15;
84 int fillReplaceGreenThresh=15;
85 int fillReplaceBlueThresh=15;
86
87 static NLFN *gpImageMapColorFunc=NULL;
88 static NLFN *gpConvolveFunc=NULL;
89 static int gpConvolveCmdID=(-1);
90 static int gnCombining=FALSE;
91
92 static int gnCombineW=0, gnCombineH=0;
93
94 static char bggenToXpmCmd[MAXSTRING+1];
95 static char bggenToPpm6Cmd[MAXSTRING+1];
96 static char ppmquantCmd[MAXSTRING+1];
97 static char ppmFSquantCmd[MAXSTRING+1];
98
99 static XColor gDefErrorDiffuseLevel;
100
101 static struct ObjRec *gpFgObj=NULL, *gpBgObj=NULL, *gpAlphaObj=NULL;
102 static struct BBRec gTotalCombineBBox;
103 static struct BBRec gFgCombineBBox, gBgCombineBBox, gAlphaCombineBBox;
104 static XImage *gpFgImage=NULL, *gpBgImage=NULL, *gpAlphaImage=NULL;
105 static XImage *gpFgBitmapImage=NULL, *gpBgBitmapImage=NULL,
106 *gpAlphaBitmapImage=NULL;
107
108 typedef struct tagConvExtraInfo {
109 FILE *fp; /* non-NULL only if (fullTrueColorMode && HasZlibSupport()) */
110 XColor my_bg_xcolor;
111 int alpha_combine;
112 /* if alpha_combine is TRUE, these are for the foreground object */
113 int image_w, image_h;
114 XImage *image, *bitmap_image;
115 XColor **xcolors;
116 /* if alpha_combine is not TRUE, everything below are not used */
117 int final_w, final_h;
118 int alpha_image_w, alpha_image_h, bg_image_w, bg_image_h;
119 XImage *alpha_image, *alpha_bitmap_image, *bg_image, *bg_bitmap_image;
120 XColor **alpha_xcolors, **bg_xcolors;
121 } ConvExtraInfo;
122
123 static ConvExtraInfo gConvExtraInfo;
124 static TrueColorInfo gTrueColorInfo;
125
126 typedef struct tagThreshFillReplaceInfo {
127 int use_thresholding;
128 /* for true color */
129 int min_r, max_r, min_g, max_g, min_b, max_b;
130 TrueColorInfo tci;
131 /* for non-true color */
132 TgHash hash_table;
133 int *within_threshold;
134 } ThreshFillReplaceInfo;
135
136 static ThreshFillReplaceInfo gThreshFillReplaceInfo;
137
138 static
ParseThreshFillReplaceSpec(spec)139 int ParseThreshFillReplaceSpec(spec)
140 char *spec;
141 {
142 char *psz=NULL, sz_spec_copy[MAXSTRING];
143 int red=0, green=0, blue=0;
144
145 *sz_spec_copy = '\0';
146 UtilStrCpyN(sz_spec_copy, sizeof(sz_spec_copy), spec);
147 UtilTrimBlanks(sz_spec_copy);
148
149 if ((psz=strtok(sz_spec_copy, " ,\t\n\r")) == NULL ||
150 sscanf(psz, "%d", &red) != 1) {
151 sprintf(gszMsgBox, TgLoadString(STID_ERR_PARSE_THRESH_COLORS), spec);
152 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
153 return FALSE;
154 }
155 if (red < 0) red = 0;
156 if (red > 255) red = 255;
157
158 psz = strtok(NULL, " ,\t\n\r");
159 if (psz == NULL) {
160 fillReplaceRedThresh = fillReplaceGreenThresh = fillReplaceBlueThresh =
161 red;
162 return TRUE;
163 }
164 if (sscanf(psz, "%d", &green) != 1) {
165 sprintf(gszMsgBox, TgLoadString(STID_ERR_PARSE_THRESH_COLORS), spec);
166 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
167 return FALSE;
168 }
169 if (green < 0) green = 0;
170 if (green > 255) green = 255;
171
172 psz = strtok(NULL, " ,\t\n\r");
173 if (psz == NULL || sscanf(psz, "%d", &blue) != 1) {
174 sprintf(gszMsgBox, TgLoadString(STID_ERR_PARSE_THRESH_COLORS), spec);
175 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
176 return FALSE;
177 }
178 if (blue < 0) blue = 0;
179 if (blue > 255) blue = 255;
180
181 psz = strtok(NULL, " ,\t\n\r");
182 if (psz != NULL) {
183 sprintf(gszMsgBox, TgLoadString(STID_ERR_PARSE_THRESH_COLORS), spec);
184 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
185 return FALSE;
186 }
187 fillReplaceRedThresh = red;
188 fillReplaceGreenThresh = green;
189 fillReplaceBlueThresh = blue;
190
191 return TRUE;
192 }
193
194 static
ResetThreshFillReplaceInfo()195 void ResetThreshFillReplaceInfo()
196 {
197 if (threshFillReplaceEnabled) {
198 gThreshFillReplaceInfo.use_thresholding = TRUE;
199 if (fullTrueColorMode) {
200 SetupTrueColorInfo(&gThreshFillReplaceInfo.tci);
201 }
202 } else {
203 gThreshFillReplaceInfo.use_thresholding = FALSE;
204 }
205 }
206
207 static
TrueColorPixelWithinRange(pixel,ptfri)208 int TrueColorPixelWithinRange(pixel, ptfri)
209 int pixel;
210 ThreshFillReplaceInfo *ptfri;
211 {
212 uint32_t pix=(uint32_t)pixel;
213 unsigned int r=0, g=0, b=0;
214 double dr=(double)0, dg=(double)0, db=(double)0;
215 TrueColorInfo *ptci=(&ptfri->tci);
216 XColor xcolor;
217
218 r = (pix & ptci->r_mask) >> ptci->r_shift;
219 g = (pix & ptci->g_mask) >> ptci->g_shift;
220 b = (pix & ptci->b_mask) >> ptci->b_shift;
221 dr = ((double)r) / ptci->dr_maxval_div255;
222 dg = ((double)g) / ptci->dg_maxval_div255;
223 db = ((double)b) / ptci->db_maxval_div255;
224 xcolor.red = round(dr);
225 xcolor.green = round(dg);
226 xcolor.blue = round(db);
227 if (xcolor.red > 255) xcolor.red = 255;
228 if (xcolor.green > 255) xcolor.green = 255;
229 if (xcolor.blue > 255) xcolor.blue = 255;
230
231 return (xcolor.red >= ptfri->min_r && xcolor.red <= ptfri->max_r &&
232 xcolor.green >= ptfri->min_g && xcolor.green <= ptfri->max_g &&
233 xcolor.blue >= ptfri->min_b && xcolor.blue <= ptfri->max_b);
234 }
235
236 static
OtherPixelWithinRange(pixel,ptfri)237 int OtherPixelWithinRange(pixel, ptfri)
238 int pixel;
239 ThreshFillReplaceInfo *ptfri;
240 {
241 double dr=(double)0, dg=(double)0, db=(double)0;
242 XColor xcolor;
243 int global_color_index=(-1);
244
245 if (!HashLookUpInt(&ptfri->hash_table, (char*)(&pixel), sizeof(int),
246 &global_color_index)) {
247 return FALSE;
248 }
249 if (global_color_index == (-1)) {
250 return FALSE;
251 }
252 memcpy(&xcolor, &tgifColors[global_color_index], sizeof(XColor));
253
254 dr = ((double)xcolor.red) / ((double)maxRGB) * ((double)255);
255 dg = ((double)xcolor.green) / ((double)maxRGB) * ((double)255);
256 db = ((double)xcolor.blue) / ((double)maxRGB) * ((double)255);
257 xcolor.red = round(dr);
258 xcolor.green = round(dg);
259 xcolor.blue = round(db);
260 if (xcolor.red > 255) xcolor.red = 255;
261 if (xcolor.green > 255) xcolor.green = 255;
262 if (xcolor.blue > 255) xcolor.blue = 255;
263
264 return (xcolor.red >= ptfri->min_r && xcolor.red <= ptfri->max_r &&
265 xcolor.green >= ptfri->min_g && xcolor.green <= ptfri->max_g &&
266 xcolor.blue >= ptfri->min_b && xcolor.blue <= ptfri->max_b);
267 }
268
269 static
GetPixelRGB(ptfri,pixel,pxc_pixel)270 int GetPixelRGB(ptfri, pixel, pxc_pixel)
271 ThreshFillReplaceInfo *ptfri;
272 int pixel;
273 XColor *pxc_pixel;
274 {
275 if (fullTrueColorMode) {
276 uint32_t pix=(uint32_t)pixel;
277 unsigned int r=0, g=0, b=0;
278 double dr=(double)0, dg=(double)0, db=(double)0;
279 TrueColorInfo *ptci=(&ptfri->tci);
280 XColor xcolor;
281
282 r = (pix & ptci->r_mask) >> ptci->r_shift;
283 g = (pix & ptci->g_mask) >> ptci->g_shift;
284 b = (pix & ptci->b_mask) >> ptci->b_shift;
285 dr = ((double)r) / ptci->dr_maxval_div255;
286 dg = ((double)g) / ptci->dg_maxval_div255;
287 db = ((double)b) / ptci->db_maxval_div255;
288 pxc_pixel->red = round(dr);
289 pxc_pixel->green = round(dg);
290 pxc_pixel->blue = round(db);
291 if (pxc_pixel->red > 255) pxc_pixel->red = 255;
292 if (pxc_pixel->green > 255) pxc_pixel->green = 255;
293 if (pxc_pixel->blue > 255) xcolor.blue = 255;
294 } else {
295 int i=0, global_color_index=(-1);
296
297 for (i=0; i < maxColors; i++) {
298 if (pixel == colorPixels[i]) {
299 global_color_index = i;
300 break;
301 }
302 }
303 if (global_color_index != (-1)) {
304 double dr=(double)0, dg=(double)0, db=(double)0;
305
306 memcpy(pxc_pixel, &tgifColors[global_color_index], sizeof(XColor));
307 dr = ((double)pxc_pixel->red) / ((double)maxRGB) * ((double)255);
308 dg = ((double)pxc_pixel->green) / ((double)maxRGB) * ((double)255);
309 db = ((double)pxc_pixel->blue) / ((double)maxRGB) * ((double)255);
310 pxc_pixel->red = round(dr);
311 pxc_pixel->green = round(dg);
312 pxc_pixel->blue = round(db);
313 if (pxc_pixel->red > 255) pxc_pixel->red = 255;
314 if (pxc_pixel->green > 255) pxc_pixel->green = 255;
315 if (pxc_pixel->blue > 255) pxc_pixel->blue = 255;
316 } else {
317 #ifdef _TGIF_DBG /* debug, do not translate */
318 fprintf(stderr,
319 "Canot find pixel indel for pixel=0x%08x in GetPixelRGB().\n",
320 pixel);
321 #endif /* _TGIF_DBG */
322 return FALSE;
323 }
324 }
325 return TRUE;
326 }
327
328 static
SetupThreshFillReplaceInfo(ptfri,pixel,pxc_pixel)329 int SetupThreshFillReplaceInfo(ptfri, pixel, pxc_pixel)
330 ThreshFillReplaceInfo *ptfri;
331 int pixel;
332 XColor *pxc_pixel;
333 {
334 if (fullTrueColorMode) {
335 if (!GetPixelRGB(ptfri, pixel, pxc_pixel)) return FALSE;
336
337 ptfri->min_r = (int)(pxc_pixel->red) - fillReplaceRedThresh;
338 ptfri->max_r = (int)(pxc_pixel->red) + fillReplaceRedThresh;
339 if (ptfri->min_r < 0) ptfri->min_r = 0;
340 if (ptfri->max_r > 255) ptfri->max_r = 255;
341
342 ptfri->min_g = (int)(pxc_pixel->green) - fillReplaceGreenThresh;
343 ptfri->max_g = (int)(pxc_pixel->green) + fillReplaceGreenThresh;
344 if (ptfri->min_g < 0) ptfri->min_g = 0;
345 if (ptfri->max_g > 255) ptfri->max_g = 255;
346
347 ptfri->min_b = (int)(pxc_pixel->blue) - fillReplaceBlueThresh;
348 ptfri->max_b = (int)(pxc_pixel->blue) + fillReplaceBlueThresh;
349 if (ptfri->min_b < 0) ptfri->min_b = 0;
350 if (ptfri->max_b > 255) ptfri->max_b = 255;
351 } else {
352 int i=0;
353 TgHash *pth=(&ptfri->hash_table);
354 int global_color_index=(-1);
355
356 InitHash(pth, TG_HASH_SIZE_LARGE);
357 for (i=0; i < maxColors; i++) {
358 HashStoreInt(pth, (char*)(&colorPixels[i]), sizeof(int), i);
359 }
360 if (HashLookUpInt(pth, (char*)(&pixel), sizeof(int),
361 &global_color_index)) {
362 double dr=(double)0, dg=(double)0, db=(double)0;
363 XColor xcolor;
364
365 ptfri->within_threshold = (int*)malloc(maxColors*sizeof(int));
366 if (ptfri->within_threshold == NULL) FailAllocMessage();
367 memset(ptfri->within_threshold, 0, maxColors*sizeof(int));
368
369 memcpy(&xcolor, &tgifColors[global_color_index], sizeof(XColor));
370 dr = ((double)xcolor.red) / ((double)maxRGB) * ((double)255);
371 dg = ((double)xcolor.green) / ((double)maxRGB) * ((double)255);
372 db = ((double)xcolor.blue) / ((double)maxRGB) * ((double)255);
373 xcolor.red = round(dr);
374 xcolor.green = round(dg);
375 xcolor.blue = round(db);
376 if (xcolor.red > 255) xcolor.red = 255;
377 if (xcolor.green > 255) xcolor.green = 255;
378 if (xcolor.blue > 255) xcolor.blue = 255;
379
380 ptfri->min_r = (int)(xcolor.red) - fillReplaceRedThresh;
381 ptfri->max_r = (int)(xcolor.red) + fillReplaceRedThresh;
382 if (ptfri->min_r < 0) ptfri->min_r = 0;
383 if (ptfri->max_r > 255) ptfri->max_r = 255;
384
385 ptfri->min_g = (int)(xcolor.green) - fillReplaceGreenThresh;
386 ptfri->max_g = (int)(xcolor.green) + fillReplaceGreenThresh;
387 if (ptfri->min_g < 0) ptfri->min_g = 0;
388 if (ptfri->max_g > 255) ptfri->max_g = 255;
389
390 ptfri->min_b = (int)(xcolor.blue) - fillReplaceBlueThresh;
391 ptfri->max_b = (int)(xcolor.blue) + fillReplaceBlueThresh;
392 if (ptfri->min_b < 0) ptfri->min_b = 0;
393 if (ptfri->max_b > 255) ptfri->max_b = 255;
394
395 for (i=0; i < maxColors; i++) {
396 ptfri->within_threshold[i] =
397 OtherPixelWithinRange(colorPixels[i], ptfri);
398 }
399 } else {
400 #ifdef _TGIF_DBG /* debug, do not translate */
401 fprintf(stderr,
402 "HashLookup() failed in SetupThreshFillReplaceInfo() for pixel=0x%08x.\n",
403 pixel);
404 #endif /* _TGIF_DBG */
405 return FALSE;
406 }
407 }
408 return TRUE;
409 }
410
411 static
DoPpm6(xpm_ptr)412 int DoPpm6(xpm_ptr)
413 struct XPmRec *xpm_ptr;
414 {
415 if (gnCombining || xpm_ptr == NULL) {
416 return (fullTrueColorMode && HasZlibSupport());
417 } else if (xpm_ptr != NULL && (xpm_ptr->real_type == PPM_TRUE ||
418 xpm_ptr->real_type == XPM_JPEG) && xpm_ptr->ppm_mask_data == NULL &&
419 fullTrueColorMode && HasZlibSupport()) {
420 return TRUE;
421 }
422 return FALSE;
423 }
424
425 static
FreePreprocessPixels(h,xcolors)426 int FreePreprocessPixels(h, xcolors)
427 int h;
428 XColor **xcolors;
429 {
430 int i=0;
431
432 for (i=0; i < h; i++) {
433 if (xcolors[i] != NULL) {
434 free(xcolors[i]);
435 } else {
436 break;
437 }
438 }
439 free(xcolors);
440 gConvExtraInfo.xcolors = NULL;
441
442 return FALSE;
443 }
444
445 static
ClearConvExtraInfo()446 void ClearConvExtraInfo()
447 {
448 if (gConvExtraInfo.xcolors != NULL) {
449 FreePreprocessPixels(gConvExtraInfo.image_h, gConvExtraInfo.xcolors);
450 }
451 if (gConvExtraInfo.alpha_xcolors != NULL) {
452 FreePreprocessPixels(gConvExtraInfo.alpha_image_h,
453 gConvExtraInfo.alpha_xcolors);
454 }
455 if (gConvExtraInfo.bg_xcolors != NULL) {
456 FreePreprocessPixels(gConvExtraInfo.bg_image_h,
457 gConvExtraInfo.bg_xcolors);
458 }
459 memset(&gConvExtraInfo, 0, sizeof(ConvExtraInfo));
460 }
461
462 static
PreprocessOneImagePixels(w,h,image,bitmap_image)463 XColor **PreprocessOneImagePixels(w, h, image, bitmap_image)
464 int w, h;
465 XImage *image, *bitmap_image;
466 {
467 int i=0;
468 XColor **xcolors=NULL;
469 ProgressInfo pi;
470
471 xcolors = (XColor**)malloc(h*sizeof(XColor*));
472 if (xcolors == NULL) {
473 FailAllocMessage();
474 return NULL;
475 }
476 memset(xcolors, 0, h*sizeof(XColor*));
477
478 for (i=0; i < h; i++) {
479 xcolors[i] = (XColor*)malloc(w*sizeof(XColor));
480 if (xcolors[i] == NULL) {
481 FailAllocMessage();
482 FreePreprocessPixels(h, xcolors);
483 return NULL;
484 }
485 memset(xcolors[i], 0, w*sizeof(XColor));
486 }
487 BeginProgress(&pi, h);
488 for (i=0; i < h; i++) {
489 int j=0;
490
491 UpdateProgress(&pi, i);
492 for (j=0; j < w; j++) {
493 if (bitmap_image != NULL && XGetPixel(bitmap_image,j,i) == 0) {
494 TgAssert(FALSE, "transparent pixel not supported", NULL);
495 FreePreprocessPixels(h, xcolors);
496 return NULL;
497 } else {
498 unsigned int pixel=(unsigned int)XGetPixel(image,j,i);
499 uint32_t pix=(uint32_t)pixel;
500 unsigned int r=0, g=0, b=0;
501 double dr=(double)0, dg=(double)0, db=(double)0;
502
503 r = (pix & gTrueColorInfo.r_mask) >> gTrueColorInfo.r_shift;
504 g = (pix & gTrueColorInfo.g_mask) >> gTrueColorInfo.g_shift;
505 b = (pix & gTrueColorInfo.b_mask) >> gTrueColorInfo.b_shift;
506 dr = ((double)r) / gTrueColorInfo.dr_maxval_div255;
507 dg = ((double)g) / gTrueColorInfo.dg_maxval_div255;
508 db = ((double)b) / gTrueColorInfo.db_maxval_div255;
509 xcolors[i][j].red = round(dr);
510 xcolors[i][j].green = round(dg);
511 xcolors[i][j].blue = round(db);
512 if (xcolors[i][j].red > 255) xcolors[i][j].red = 255;
513 if (xcolors[i][j].green > 255) xcolors[i][j].green = 255;
514 if (xcolors[i][j].blue > 255) xcolors[i][j].blue = 255;
515 xcolors[i][j].pixel = pixel;
516 }
517 }
518 }
519 return xcolors;
520 }
521
522 static
PreprocessPixels()523 int PreprocessPixels()
524 {
525 if (gConvExtraInfo.alpha_combine) {
526 memset(&gConvExtraInfo.my_bg_xcolor, 0, sizeof(XColor));
527 unsigned int r=(unsigned int)myBgColor.red;
528 unsigned int g=(unsigned int)myBgColor.green;
529 unsigned int b=(unsigned int)myBgColor.blue;
530 double dr=((double)r)/((double)maxRGB)*((double)255);
531 double dg=((double)g)/((double)maxRGB)*((double)255);
532 double db=((double)b)/((double)maxRGB)*((double)255);
533
534 gConvExtraInfo.my_bg_xcolor.red = round(dr);
535 gConvExtraInfo.my_bg_xcolor.green = round(dg);
536 gConvExtraInfo.my_bg_xcolor.blue = round(db);
537 gConvExtraInfo.my_bg_xcolor.pixel = myBgPixel;
538
539 /* foreground object */
540 gConvExtraInfo.xcolors = PreprocessOneImagePixels(
541 gConvExtraInfo.image_w, gConvExtraInfo.image_h,
542 gConvExtraInfo.image, gConvExtraInfo.bitmap_image);
543 if (gConvExtraInfo.xcolors == NULL) {
544 return FALSE;
545 }
546 /* background object */
547 gConvExtraInfo.bg_xcolors = PreprocessOneImagePixels(
548 gConvExtraInfo.bg_image_w, gConvExtraInfo.bg_image_h,
549 gConvExtraInfo.bg_image, gConvExtraInfo.bg_bitmap_image);
550 if (gConvExtraInfo.bg_xcolors == NULL) {
551 return FALSE;
552 }
553 if (gpConvolveCmdID == CMDID_ALPHACOMBINE) {
554 gConvExtraInfo.alpha_xcolors = PreprocessOneImagePixels(
555 gConvExtraInfo.alpha_image_w, gConvExtraInfo.alpha_image_h,
556 gConvExtraInfo.alpha_image, gConvExtraInfo.alpha_bitmap_image);
557 if (gConvExtraInfo.alpha_xcolors == NULL) {
558 return FALSE;
559 }
560 }
561 } else {
562 gConvExtraInfo.xcolors = PreprocessOneImagePixels(gConvExtraInfo.image_w,
563 gConvExtraInfo.image_h, gConvExtraInfo.image,
564 gConvExtraInfo.bitmap_image);
565 if (gConvExtraInfo.xcolors == NULL) {
566 return FALSE;
567 }
568 if (gpConvolveCmdID == CMDID_VECTORWARP) {
569 gConvExtraInfo.bg_xcolors = PreprocessOneImagePixels(
570 gConvExtraInfo.image_w, gConvExtraInfo.image_h,
571 gConvExtraInfo.image, gConvExtraInfo.bitmap_image);
572 if (gConvExtraInfo.bg_xcolors == NULL) {
573 return FALSE;
574 }
575 }
576 }
577 return TRUE;
578 }
579
580 static
SetConvExtraInfo(fp,image_w,image_h,image,bitmap_image)581 int SetConvExtraInfo(fp, image_w, image_h, image, bitmap_image)
582 FILE *fp;
583 int image_w, image_h;
584 XImage *image, *bitmap_image;
585 {
586 memset(&gConvExtraInfo, 0, sizeof(ConvExtraInfo));
587 gConvExtraInfo.fp = fp;
588 gConvExtraInfo.image_w = gConvExtraInfo.bg_image_w = image_w;
589 gConvExtraInfo.image_h = gConvExtraInfo.bg_image_h = image_h;
590 gConvExtraInfo.image = image;
591 gConvExtraInfo.bitmap_image = bitmap_image;
592
593 switch (gpConvolveCmdID) {
594 case CMDID_EDGEDETECT:
595 case CMDID_EMBOSS:
596 case CMDID_SPREAD:
597 case CMDID_SHARPEN:
598 case CMDID_BLUR3:
599 case CMDID_VECTORWARP:
600 if (!PreprocessPixels()) {
601 return FALSE;
602 }
603 break;
604 case CMDID_SUBTRACT:
605 case CMDID_XORCOLORS:
606 gConvExtraInfo.alpha_combine = TRUE;
607
608 gConvExtraInfo.final_w = gnCombineW;
609 gConvExtraInfo.final_h = gnCombineH;
610
611 gConvExtraInfo.image_w = gFgCombineBBox.rbx-gFgCombineBBox.ltx;
612 gConvExtraInfo.image_h = gFgCombineBBox.rby-gFgCombineBBox.lty;
613 gConvExtraInfo.image = gpFgImage;
614 gConvExtraInfo.bitmap_image = gpFgBitmapImage;
615
616 if (!InitTrueColorInfo(gConvExtraInfo.image, &gTrueColorInfo,
617 gConvExtraInfo.image_w)) {
618 sprintf(gszMsgBox, TgLoadString(STID_CANNOT_GET_IMAGE_OF_SIZE),
619 gConvExtraInfo.image_w, gConvExtraInfo.image_h);
620 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
621 return FALSE;
622 }
623 gConvExtraInfo.bg_image_w = gBgCombineBBox.rbx-gBgCombineBBox.ltx;
624 gConvExtraInfo.bg_image_h = gBgCombineBBox.rby-gBgCombineBBox.lty;
625 gConvExtraInfo.bg_image = gpBgImage;
626 gConvExtraInfo.bg_bitmap_image = gpBgBitmapImage;
627 if (!PreprocessPixels()) {
628 return FALSE;
629 }
630 break;
631 case CMDID_ALPHACOMBINE:
632 gConvExtraInfo.alpha_combine = TRUE;
633
634 gConvExtraInfo.final_w = gnCombineW;
635 gConvExtraInfo.final_h = gnCombineH;
636
637 gConvExtraInfo.image_w = gFgCombineBBox.rbx-gFgCombineBBox.ltx;
638 gConvExtraInfo.image_h = gFgCombineBBox.rby-gFgCombineBBox.lty;
639 gConvExtraInfo.image = gpFgImage;
640 gConvExtraInfo.bitmap_image = gpFgBitmapImage;
641
642 if (!InitTrueColorInfo(gConvExtraInfo.image, &gTrueColorInfo,
643 gConvExtraInfo.image_w)) {
644 sprintf(gszMsgBox, TgLoadString(STID_CANNOT_GET_IMAGE_OF_SIZE),
645 gConvExtraInfo.image_w, gConvExtraInfo.image_h);
646 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
647 return FALSE;
648 }
649 gConvExtraInfo.alpha_image_w =
650 gAlphaCombineBBox.rbx-gAlphaCombineBBox.ltx;
651 gConvExtraInfo.alpha_image_h =
652 gAlphaCombineBBox.rby-gAlphaCombineBBox.lty;
653 gConvExtraInfo.alpha_image = gpAlphaImage;
654 gConvExtraInfo.alpha_bitmap_image = gpAlphaBitmapImage;
655
656 gConvExtraInfo.bg_image_w = gBgCombineBBox.rbx-gBgCombineBBox.ltx;
657 gConvExtraInfo.bg_image_h = gBgCombineBBox.rby-gBgCombineBBox.lty;
658 gConvExtraInfo.bg_image = gpBgImage;
659 gConvExtraInfo.bg_bitmap_image = gpBgBitmapImage;
660 if (!PreprocessPixels()) {
661 return FALSE;
662 }
663 break;
664 default: break;
665 }
666 return TRUE;
667 }
668
669 static
GetImageProcName(nCmdId)670 char *GetImageProcName(nCmdId)
671 int nCmdId;
672 {
673 TgMenuItemInfo *item_info=NULL;
674
675 for (item_info=imageProcMenuInfo.items; item_info->menu_str != NULL;
676 item_info++) {
677 if (item_info->menu_str != TGMUITEM_SEPARATOR &&
678 item_info->cmdid == nCmdId) {
679 /* must use gettext() here */
680 return _(item_info->menu_str);
681 } else if (item_info->shortcut_str == TGMUITEM_SUBMENU) {
682 TgMenuInfo *submenu_info=item_info->submenu_info;
683 TgMenuItemInfo *submenu_item_info=NULL;
684
685 for (submenu_item_info=submenu_info->items;
686 submenu_item_info->menu_str != NULL;
687 submenu_item_info++) {
688 if (submenu_item_info->menu_str != TGMUITEM_SEPARATOR &&
689 submenu_item_info->cmdid == nCmdId) {
690 /* must use gettext() here */
691 return _(submenu_item_info->menu_str);
692 }
693 }
694 }
695 }
696 return TgLoadCachedString(CSTID_PARANED_UNKNOWN);
697 }
698
699 static
TrueColorTransPixelCheck(obj_ptr,cmdid)700 int TrueColorTransPixelCheck(obj_ptr, cmdid)
701 struct ObjRec *obj_ptr;
702 int cmdid;
703 {
704 if (ObjHasTrueColorTransPixel(obj_ptr, NULL, NULL, NULL)) {
705 sprintf(gszMsgBox, TgLoadString(STID_BAD_CMD_FOR_TRANS_PPMTRUE),
706 GetImageProcName(cmdid));
707 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
708 return TRUE;
709 }
710 return FALSE;
711 }
712
713 static
CurColorIsTranscolor(trans_color_r,trans_color_g,trans_color_b)714 int CurColorIsTranscolor(trans_color_r, trans_color_g, trans_color_b)
715 unsigned char trans_color_r, trans_color_g, trans_color_b;
716 {
717 TrueColorInfo tci;
718 unsigned int r=0, g=0, b=0;
719 double dr=(double)0, dg=(double)0, db=(double)0;
720 uint32_t pixel=0;
721 double dmaxval=(double)255;
722
723 if (!SetupTrueColorInfo(&tci)) return FALSE;
724
725 r = (unsigned int)trans_color_r;
726 g = (unsigned int)trans_color_g;
727 b = (unsigned int)trans_color_b;
728 dr = ((double)r) / dmaxval * tci.dr_maxval;
729 dg = ((double)g) / dmaxval * tci.dg_maxval;
730 db = ((double)b) / dmaxval * tci.db_maxval;
731 r = round(dr);
732 g = round(dg);
733 b = round(db);
734 pixel = ((r << tci.r_shift) & mainVisual->red_mask) |
735 ((g << tci.g_shift) & mainVisual->green_mask) |
736 ((b << tci.b_shift) & mainVisual->blue_mask) ;
737
738 return (((int)pixel) == colorPixels[colorIndex]);
739 }
740
741 static
CheckSelectionForImageProc(cmdid)742 int CheckSelectionForImageProc(cmdid)
743 int cmdid;
744 {
745 char szBuf[MAXSTRING+1];
746
747 UtilStrCpyN(szBuf, sizeof(szBuf), GetImageProcName(cmdid));
748 if (topSel == NULL || topSel != botSel || topSel->obj->type != OBJ_XPM) {
749 sprintf(gszMsgBox, TgLoadString(STID_SINGLE_XPM_IMGPROC), szBuf);
750 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
751 return FALSE;
752 }
753 if (topSel->obj->fattr != NULL) {
754 sprintf(gszMsgBox, TgLoadString(STID_XPM_HAS_ATTR_IMGPROC), szBuf);
755 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
756 return FALSE;
757 }
758 return TRUE;
759 }
760
761 #define LONG_AXIS_IS_RED 0
762 #define LONG_AXIS_IS_GREEN 1
763 #define LONG_AXIS_IS_BLUE 2
764
765 typedef struct CubeRec { /* not really a ``cube'' */
766 int min_index, max_index, level, long_axis;
767 unsigned long num_points;
768 unsigned short red_length, green_length, blue_length;
769 } *CubePointer;
770
771 typedef struct HGBucketRec {
772 int index;
773 struct HGBucketRec *next;
774 } *HGBucketPoiner;
775
776 static struct HGBucketRec *gaHGBucket[256];
777
778 typedef struct tagTmpBucketInfo {
779 int pixel;
780 int index;
781 struct tagTmpBucketInfo *next;
782 } TmpBucketInfo;
783
784 static XColor *gpHistogram=NULL;
785 static int *gpnSortedIndex=NULL;
786 static int **gnOrigImageIndex=NULL, **gnFinalImageIndex=NULL;
787 static int gnImageW=(-1), gnImageH=(-1);
788 static int *gpnPixelToIndexMap=NULL, gnPixelToIndexMapSize=0;
789 static int gnHistogramEntries=0, gnHistogramSize=0;
790 static int gnQuantizingLevels=222, gnUserSpecifiedLevels=(-1);
791 static struct CubeRec *gpCube=NULL;
792 static int gnCubeEntries=0;
793 static int gnTransparentIndex=(-1);
794
795 static
GetXPmImages(xpm_ptr,p_image,p_bitmap_image)796 int GetXPmImages(xpm_ptr, p_image, p_bitmap_image)
797 struct XPmRec *xpm_ptr;
798 XImage **p_image, **p_bitmap_image;
799 {
800 Pixmap pixmap=xpm_ptr->pixmap, bitmap=xpm_ptr->bitmap;
801 int image_w=xpm_ptr->image_w, image_h=xpm_ptr->image_h;
802
803 *p_image = XGetImage(mainDisplay, pixmap, 0, 0, image_w, image_h, AllPlanes,
804 ZPixmap);
805 if (bitmap != None) {
806 *p_bitmap_image = XGetImage(mainDisplay, bitmap, 0, 0, image_w, image_h,
807 1, ZPixmap);
808 } else {
809 *p_bitmap_image = NULL;
810 }
811 if ((*p_image) == NULL || (bitmap != None && (*p_bitmap_image) == NULL)) {
812 sprintf(gszMsgBox, TgLoadString(STID_CANNOT_GET_IMAGE_OF_SIZE),
813 image_w, image_h);
814 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
815 return FALSE;
816 }
817 return TRUE;
818 }
819
820 static
CleanUpTmpBuckets()821 void CleanUpTmpBuckets()
822 {
823 if (gpnPixelToIndexMap != NULL) {
824 int i=0;
825 TmpBucketInfo **buckets=(TmpBucketInfo**)gpnPixelToIndexMap;
826
827 for (i=0; i < gnPixelToIndexMapSize; i++) {
828 TmpBucketInfo *ptbi=NULL, *ptbi_next=NULL;
829
830 for (ptbi=buckets[i]; ptbi != NULL; ptbi=ptbi_next) {
831 ptbi_next = ptbi->next;
832 free(ptbi);
833 }
834 }
835 free(buckets);
836 gpnPixelToIndexMap = NULL;
837 }
838 gnPixelToIndexMapSize = 0;
839 }
840
841 static
CleanUpIndexOfPixel()842 void CleanUpIndexOfPixel()
843 {
844 if (mainVisual->class == TrueColor) {
845 CleanUpTmpBuckets();
846 } else {
847 if (gpnPixelToIndexMap != NULL) free(gpnPixelToIndexMap);
848 gpnPixelToIndexMap = NULL;
849 gnPixelToIndexMapSize = 0;
850 }
851 }
852
CleanUpConvolution()853 void CleanUpConvolution()
854 {
855 register int i;
856
857 CleanUpIndexOfPixel();
858
859 if (gpHistogram != NULL) {
860 free(gpHistogram);
861 gpHistogram = NULL;
862 }
863 if (gpnSortedIndex != NULL) {
864 free(gpnSortedIndex);
865 gpnSortedIndex = NULL;
866 }
867 gnHistogramEntries = gnHistogramSize = 0;
868
869 if (gpCube != NULL) {
870 free(gpCube);
871 gpCube = NULL;
872 }
873 gnCubeEntries = 0;
874 if (gnOrigImageIndex != NULL) {
875 for (i=0; i < gnImageH; i++) {
876 if (gnOrigImageIndex[i] != NULL) {
877 free(gnOrigImageIndex[i]);
878 } else {
879 break;
880 }
881 }
882 free(gnOrigImageIndex);
883 gnOrigImageIndex = NULL;
884 }
885 if (gnFinalImageIndex != NULL) {
886 for (i=0; i < gnImageH; i++) {
887 if (gnFinalImageIndex[i] != NULL) {
888 free(gnFinalImageIndex[i]);
889 } else {
890 break;
891 }
892 }
893 free(gnFinalImageIndex);
894 gnFinalImageIndex = NULL;
895 }
896 gnImageW = gnImageH = (-1);
897
898 for (i=0; i < 256; i++) {
899 if (gaHGBucket[i] != NULL) {
900 struct HGBucketRec *bucket_ptr=gaHGBucket[i], *next_bucket;
901
902 for ( ; bucket_ptr != NULL; bucket_ptr=next_bucket) {
903 next_bucket = bucket_ptr->next;
904 free(bucket_ptr);
905 }
906 gaHGBucket[i] = NULL;
907 }
908 }
909 }
910
911 static
GetOrAllocHistogramIndex(pcolor)912 int GetOrAllocHistogramIndex(pcolor)
913 XColor *pcolor;
914 {
915 int hashvalue=0;
916
917 if (pcolor == NULL) {
918 if (gnTransparentIndex != (-1)) return gnTransparentIndex;
919 } else {
920 struct HGBucketRec *bucket_ptr;
921
922 hashvalue = (int)((pcolor->red ^ pcolor->green ^ pcolor->blue) & 0xff);
923 if (gaHGBucket[hashvalue] != NULL) {
924 struct HGBucketRec *bucket_ptr=gaHGBucket[hashvalue];
925
926 for ( ; bucket_ptr != NULL; bucket_ptr=bucket_ptr->next) {
927 int i=bucket_ptr->index;
928
929 if (gpHistogram[i].red == pcolor->red &&
930 gpHistogram[i].green == pcolor->green &&
931 gpHistogram[i].blue == pcolor->blue) {
932 HISTOGRAMCOUNT(i)++;
933 return i;
934 }
935 }
936 }
937 bucket_ptr = (struct HGBucketRec *)malloc(sizeof(struct HGBucketRec));
938 if (bucket_ptr == NULL) {
939 FailAllocMessage();
940 return (-1);
941 }
942 bucket_ptr->index = gnHistogramEntries;
943 bucket_ptr->next = gaHGBucket[hashvalue];
944 gaHGBucket[hashvalue] = bucket_ptr;
945 }
946 if (gnHistogramEntries >= gnHistogramSize) {
947 gnHistogramSize += 256;
948 if ((gpHistogram=(XColor*)realloc(gpHistogram,
949 gnHistogramSize*sizeof(XColor))) == NULL) {
950 FailAllocMessage();
951 return (-1);
952 }
953 }
954 memset(&gpHistogram[gnHistogramEntries], 0, sizeof(XColor));
955 HISTOGRAMCOUNT(gnHistogramEntries) = 1;
956 if (pcolor == NULL) {
957 gpHistogram[gnHistogramEntries].red = 0;
958 gpHistogram[gnHistogramEntries].green = 0;
959 gpHistogram[gnHistogramEntries].blue = 0;
960 } else {
961 gpHistogram[gnHistogramEntries].red = pcolor->red;
962 gpHistogram[gnHistogramEntries].green = pcolor->green;
963 gpHistogram[gnHistogramEntries].blue = pcolor->blue;
964 }
965 return (gnHistogramEntries++);
966 }
967
968 static
PixelToIndexHash(pixel)969 int PixelToIndexHash(pixel)
970 int pixel;
971 {
972 return (((pixel)==(-1)) ? (gnPixelToIndexMapSize-1) :
973 (pixel % gnPixelToIndexMapSize));
974 }
975
976 static
GetIndexOfPixel(pixel)977 int GetIndexOfPixel(pixel)
978 int pixel;
979 {
980 if (mainVisual->class == TrueColor) {
981 TmpBucketInfo **buckets=(TmpBucketInfo**)gpnPixelToIndexMap, *ptbi=NULL;
982 int bucket=PixelToIndexHash(pixel);
983
984 for (ptbi=buckets[bucket]; ptbi != NULL; ptbi=ptbi->next) {
985 if (ptbi->pixel == pixel) {
986 return ptbi->index;
987 }
988 }
989 return INVALID;
990 } else {
991 return gpnPixelToIndexMap[pixel];
992 }
993 }
994
995 static
UpdatePixelToIndexMapping(buckets,pixel,index)996 void UpdatePixelToIndexMapping(buckets, pixel, index)
997 TmpBucketInfo **buckets;
998 int pixel, index;
999 {
1000 int bucket=PixelToIndexHash(pixel);
1001 TmpBucketInfo *ptbi=NULL;
1002
1003 for (ptbi=buckets[bucket]; ptbi != NULL; ptbi=ptbi->next) {
1004 if (ptbi->pixel == pixel) {
1005 return;
1006 }
1007 }
1008 ptbi = (TmpBucketInfo *)malloc(sizeof(TmpBucketInfo));
1009 if (ptbi == NULL) FailAllocMessage();
1010 memset(ptbi, 0, sizeof(TmpBucketInfo));
1011 ptbi->next = buckets[bucket];
1012 buckets[bucket] = ptbi;
1013 ptbi->pixel = pixel;
1014 ptbi->index = index;
1015 }
1016
1017 static
AllocTmpBuckets(populate_with_color_pixels)1018 int AllocTmpBuckets(populate_with_color_pixels)
1019 int populate_with_color_pixels;
1020 {
1021 TmpBucketInfo **buckets=(TmpBucketInfo **)gpnPixelToIndexMap;
1022
1023 gnPixelToIndexMapSize = 257;
1024 buckets = (TmpBucketInfo**)malloc(gnPixelToIndexMapSize *
1025 sizeof(TmpBucketInfo*));
1026 if (buckets == NULL) {
1027 FailAllocMessage();
1028 return FALSE;
1029 }
1030 memset(buckets, 0, gnPixelToIndexMapSize*sizeof(TmpBucketInfo*));
1031
1032 gpnPixelToIndexMap = (int*)buckets;
1033 if (populate_with_color_pixels) {
1034 int i=0;
1035
1036 for (i=0; i < maxColors; i++) {
1037 UpdatePixelToIndexMapping(buckets, colorPixels[i], i);
1038 }
1039 }
1040 return TRUE;
1041 }
1042
1043 static
CreatePixelToIndexMapping()1044 int CreatePixelToIndexMapping()
1045 {
1046 register int i=0;
1047
1048 if (mainVisual->class == TrueColor) {
1049 if (!AllocTmpBuckets(TRUE)) {
1050 CleanUpConvolution();
1051 return FALSE;
1052 }
1053 } else {
1054 int max_pixel=(-1);
1055
1056 for (i=0; i < maxColors; i++) {
1057 if (colorPixels[i] > max_pixel) {
1058 max_pixel = colorPixels[i];
1059 }
1060 }
1061 if (max_pixel == (-1)) return FALSE;
1062
1063 gpnPixelToIndexMap = (int*)malloc((max_pixel+1)*sizeof(int));
1064 if (gpnPixelToIndexMap == NULL) {
1065 FailAllocMessage();
1066 CleanUpConvolution();
1067 return FALSE;
1068 }
1069 memset(gpnPixelToIndexMap, (-1), (max_pixel+1)*sizeof(int));
1070 for (i=0; i < maxColors; i++) {
1071 gpnPixelToIndexMap[colorPixels[i]] = i;
1072 }
1073 }
1074 return TRUE;
1075 }
1076
1077 static
CreateObjPixelToIndexMapping(xpm_ptr)1078 int CreateObjPixelToIndexMapping(xpm_ptr)
1079 struct XPmRec *xpm_ptr;
1080 {
1081 register int i=0;
1082
1083 gnTransparentIndex = (-1);
1084
1085 if (mainVisual->class == TrueColor) {
1086 int start_index=0;
1087 XColor *xcolors=NULL;
1088
1089 xcolors = (XColor*)malloc(xpm_ptr->ncolors*sizeof(XColor));
1090 if (xcolors == NULL) FailAllocMessage();
1091 memset(xcolors, 0, xpm_ptr->ncolors*sizeof(XColor));
1092 if (!AllocTmpBuckets(TRUE)) {
1093 free(xcolors);
1094 CleanUpConvolution();
1095 return FALSE;
1096 }
1097 start_index = (xpm_ptr->first_pixel_is_bg ? 1 : 0);
1098 for (i=start_index; i < xpm_ptr->ncolors; i++) {
1099 int pixel=xpm_ptr->pixels[i];
1100
1101 /* do not translate -- program constants */
1102 if (UtilStrICmp(xpm_ptr->color_str[i], "None") == 0) {
1103 if (gnTransparentIndex == (-1)) {
1104 gnTransparentIndex = GetOrAllocHistogramIndex(NULL);
1105 }
1106 } else {
1107 ((ImageMapColorFunc*)gpImageMapColorFunc)(GetIndexOfPixel(pixel),
1108 &xcolors[i]);
1109 }
1110 }
1111 CleanUpTmpBuckets();
1112 if (!AllocTmpBuckets(FALSE)) {
1113 free(xcolors);
1114 CleanUpConvolution();
1115 return FALSE;
1116 }
1117 for (i=start_index; i < xpm_ptr->ncolors; i++) {
1118 UpdatePixelToIndexMapping((TmpBucketInfo**)gpnPixelToIndexMap,
1119 xpm_ptr->pixels[i], GetOrAllocHistogramIndex(&xcolors[i]));
1120 }
1121 free(xcolors);
1122 } else {
1123 int max_pixel=(-1), start_index, *pixel_to_index_map=NULL;
1124
1125 for (i=0; i < maxColors; i++) {
1126 if (colorPixels[i] > max_pixel) {
1127 max_pixel = colorPixels[i];
1128 }
1129 }
1130 if (max_pixel == (-1)) return FALSE;
1131
1132 gpnPixelToIndexMap = (int*)malloc((max_pixel+1)*sizeof(int));
1133 pixel_to_index_map = (int*)malloc((max_pixel+1)*sizeof(int));
1134 if (gpnPixelToIndexMap == NULL || pixel_to_index_map == NULL) {
1135 if (gpnPixelToIndexMap != NULL) free(gpnPixelToIndexMap);
1136 if (pixel_to_index_map != NULL) free(pixel_to_index_map);
1137 gpnPixelToIndexMap = NULL;
1138 FailAllocMessage();
1139 CleanUpConvolution();
1140 return FALSE;
1141 }
1142 memset(gpnPixelToIndexMap, (-1), (max_pixel+1)*sizeof(int));
1143 memset(pixel_to_index_map, (-1), (max_pixel+1)*sizeof(int));
1144 for (i=0; i < maxColors; i++) {
1145 pixel_to_index_map[colorPixels[i]] = i;
1146 }
1147 start_index = (xpm_ptr->first_pixel_is_bg ? 1 : 0);
1148 for (i=start_index; i < xpm_ptr->ncolors; i++) {
1149 XColor xcolor;
1150 int pixel=xpm_ptr->pixels[i];
1151
1152 memset(&xcolor, 0, sizeof(XColor));
1153 /* do not translate -- program constants */
1154 if (UtilStrICmp(xpm_ptr->color_str[i], "None") == 0) {
1155 if (gnTransparentIndex == (-1)) {
1156 gnTransparentIndex = GetOrAllocHistogramIndex(NULL);
1157 }
1158 } else {
1159 ((ImageMapColorFunc*)gpImageMapColorFunc)(pixel_to_index_map[pixel],
1160 &xcolor);
1161 gpnPixelToIndexMap[pixel] = GetOrAllocHistogramIndex(&xcolor);
1162 }
1163 }
1164 free(pixel_to_index_map);
1165 }
1166 return TRUE;
1167 }
1168
1169 static
DumpConvolution(fp)1170 int DumpConvolution(fp)
1171 FILE *fp;
1172 {
1173 register int j, i;
1174 int chars_per_pixel=(gnHistogramEntries > 20 ? 2 : 1);
1175 char c0[27], c1[11];
1176 ProgressInfo pi;
1177
1178 /* do not translate -- program constants */
1179 strcpy(c0, "abcdefghijklmnopqrstuvwxyz");
1180 strcpy(c1, "0123456789");
1181 if (fprintf(fp, "#define conv_format 1\n") == EOF ||
1182 fprintf(fp, "#define conv_width %1d\n", gnImageW) == EOF ||
1183 fprintf(fp, "#define conv_height %1d\n", gnImageH) == EOF ||
1184 fprintf(fp, "#define conv_ncolors %1d\n", gnHistogramEntries) == EOF ||
1185 fprintf(fp, "#define conv_chars_per_pixel %1d\n",
1186 chars_per_pixel) == EOF ||
1187 fprintf(fp, "static char *conv_colors[] = {\n") == EOF) {
1188 writeFileFailed = TRUE;
1189 }
1190 for (j=0; j < gnHistogramEntries; j++) {
1191 int red=(int)gpHistogram[j].red;
1192 int green=(int)gpHistogram[j].green;
1193 int blue=(int)gpHistogram[j].blue;
1194
1195 /* do not translate -- program constants */
1196 if (gnTransparentIndex == j) {
1197 if (chars_per_pixel == 1) {
1198 if (fprintf(fp, " \"%c\", \"None\"", c0[j]) == EOF) {
1199 writeFileFailed = TRUE;
1200 }
1201 } else {
1202 if (fprintf(fp, " \"%c%c\", \"None\"",
1203 c0[(int)(j/10)], c1[j % 10]) == EOF) {
1204 writeFileFailed = TRUE;
1205 }
1206 }
1207 } else {
1208 if (chars_per_pixel == 1) {
1209 if (fprintf(fp, " \"%c\", \"#%04x%04x%04x\"",
1210 c0[j], red&0x0ffff, green&0x0ffff, blue&0x0ffff) == EOF) {
1211 writeFileFailed = TRUE;
1212 }
1213 } else {
1214 if (fprintf(fp, " \"%c%c\", \"#%04x%04x%04x\"",
1215 c0[(int)(j/10)], c1[j % 10],
1216 red&0x0ffff, green&0x0ffff, blue&0x0ffff) == EOF) {
1217 writeFileFailed = TRUE;
1218 }
1219 }
1220 }
1221 if (j == gnHistogramEntries-1) {
1222 fprintf(fp, "\n};\n");
1223 } else {
1224 fprintf(fp, ",\n");
1225 }
1226 }
1227 if (fprintf(fp, "static char *conv_pixels[] = {\n") == EOF) {
1228 writeFileFailed = TRUE;
1229 }
1230 BeginProgress(&pi, gnImageH);
1231 for (i=0; i < gnImageH; i++) {
1232 UpdateProgress(&pi, i);
1233 fprintf(fp, "\"");
1234 for (j=0; j < gnImageW; j++) {
1235 int index=gnFinalImageIndex[i][j];
1236
1237 if (chars_per_pixel == 1) {
1238 if (fprintf(fp, "%c", c0[index]) == EOF) {
1239 writeFileFailed = TRUE;
1240 }
1241 } else {
1242 if (fprintf(fp, "%c%c",
1243 c0[(int)(index/10)], c1[index % 10]) == EOF) {
1244 writeFileFailed = TRUE;
1245 }
1246 }
1247 }
1248 if (i == gnImageH-1) {
1249 if (fprintf(fp, "\"\n};\n") == EOF) writeFileFailed = TRUE;
1250 } else {
1251 if (fprintf(fp, "\",\n") == EOF) writeFileFailed = TRUE;
1252 }
1253 }
1254 return TRUE;
1255 }
1256
1257 static int gnDebugQuantization=FALSE;
1258
1259 static
DumpQuantizedConvolution(fp)1260 int DumpQuantizedConvolution(fp)
1261 FILE *fp;
1262 {
1263 register int j, i;
1264 int chars_per_pixel=(gnCubeEntries > 20 ? 2 : 1);
1265 char c0[27], c1[11];
1266 ProgressInfo pi;
1267
1268 /* do not translate -- program constants */
1269 strcpy(c0, "abcdefghijklmnopqrstuvwxyz");
1270 strcpy(c1, "0123456789");
1271 if (fprintf(fp, "#define conv_format 1\n") == EOF ||
1272 fprintf(fp, "#define conv_width %1d\n", gnImageW) == EOF ||
1273 fprintf(fp, "#define conv_height %1d\n", gnImageH) == EOF ||
1274 fprintf(fp, "#define conv_ncolors %1d\n", gnCubeEntries) == EOF ||
1275 fprintf(fp, "#define conv_chars_per_pixel %1d\n",
1276 chars_per_pixel) == EOF ||
1277 fprintf(fp, "static char *conv_colors[] = {\n") == EOF) {
1278 writeFileFailed = TRUE;
1279 }
1280 if (gnDebugQuantization) { /* debug, do not translate */
1281 fprintf(stderr, "Dumping colors...\n");
1282 }
1283 for (j=0; j < gnCubeEntries; j++) {
1284 int min_index=gpCube[j].min_index;
1285 int max_index=gpCube[j].max_index;
1286 int idx=gpnSortedIndex[min_index];
1287 double num_points=(double)HISTOGRAMCOUNT(idx);
1288 double red=((double)HISTOGRAMRED(idx))*num_points;
1289 double green=((double)HISTOGRAMGREEN(idx))*num_points;
1290 double blue=((double)HISTOGRAMBLUE(idx))*num_points;
1291 long lred, lgreen, lblue;
1292
1293 for (i=min_index+1; i <= max_index; i++) {
1294 double n;
1295
1296 idx = gpnSortedIndex[i];
1297 n = (double)HISTOGRAMCOUNT(idx);
1298 num_points += n;
1299 red += ((long)HISTOGRAMRED(idx))*n;
1300 green += ((long)HISTOGRAMGREEN(idx))*n;
1301 blue += ((long)HISTOGRAMBLUE(idx))*n;
1302 }
1303 red /= num_points; green /= num_points; blue /= num_points;
1304 lred = (long)red; lgreen = (long)green; lblue = (long)blue;
1305 if (gnDebugQuantization) {
1306 fprintf(stderr, "\t#%02x%02x%02x %6ld\n",
1307 (int)((lred>>8) & 0xff), (int)((lgreen>>8) & 0xff),
1308 (int)((lblue>>8) & 0xff), (long)num_points);
1309 }
1310 if (chars_per_pixel == 1) {
1311 if (fprintf(fp, " \"%c\", \"#%04x%04x%04x\"",
1312 c0[j], (int)(lred&0x0ffff), (int)(lgreen&0x0ffff),
1313 (int)(lblue&0x0ffff)) == EOF) {
1314 writeFileFailed = TRUE;
1315 }
1316 } else {
1317 if (fprintf(fp, " \"%c%c\", \"#%04x%04x%04x\"",
1318 c0[(int)(j/10)], c1[j % 10], (int)(lred&0x0ffff),
1319 (int)(lgreen&0x0ffff), (int)(lblue&0x0ffff)) == EOF) {
1320 writeFileFailed = TRUE;
1321 }
1322 }
1323 if (j == gnCubeEntries-1) {
1324 fprintf(fp, "\n};\n");
1325 } else {
1326 fprintf(fp, ",\n");
1327 }
1328 /*
1329 * use the gpHistogram[*].pixel as the reverse color index
1330 */
1331 for (i=min_index; i <= max_index; i++) {
1332 HISTOGRAMCOUNT(gpnSortedIndex[i]) = (long)j;
1333 }
1334 }
1335 if (fprintf(fp, "static char *conv_pixels[] = {\n") == EOF) {
1336 writeFileFailed = TRUE;
1337 }
1338 BeginProgress(&pi, gnImageH);
1339 for (i=0; i < gnImageH; i++) {
1340 UpdateProgress(&pi, i);
1341 fprintf(fp, "\"");
1342 for (j=0; j < gnImageW; j++) {
1343 int orig_index=gnFinalImageIndex[i][j];
1344 int index=HISTOGRAMCOUNT(orig_index);
1345
1346 if (chars_per_pixel == 1) {
1347 if (fprintf(fp, "%c", c0[index]) == EOF) {
1348 writeFileFailed = TRUE;
1349 }
1350 } else {
1351 if (fprintf(fp, "%c%c",
1352 c0[(int)(index/10)], c1[index % 10]) == EOF) {
1353 writeFileFailed = TRUE;
1354 }
1355 }
1356 }
1357 if (i == gnImageH-1) {
1358 if (fprintf(fp, "\"\n};\n") == EOF) writeFileFailed = TRUE;
1359 } else {
1360 if (fprintf(fp, "\",\n") == EOF) writeFileFailed = TRUE;
1361 }
1362 }
1363 return TRUE;
1364 }
1365
1366 static
AlreadySorted(nMinIndex,nMaxIndex,nLongAxis)1367 int AlreadySorted(nMinIndex, nMaxIndex, nLongAxis)
1368 int nMinIndex, nMaxIndex, nLongAxis;
1369 {
1370 register int i;
1371
1372 switch (nLongAxis) {
1373 case LONG_AXIS_IS_RED:
1374 for (i=nMinIndex; i < nMaxIndex; i++) {
1375 if (HISTOGRAMRED(gpnSortedIndex[i]) <
1376 HISTOGRAMRED(gpnSortedIndex[i+1])) {
1377 return FALSE;
1378 }
1379 }
1380 break;
1381 case LONG_AXIS_IS_GREEN:
1382 for (i=nMinIndex; i < nMaxIndex; i++) {
1383 if (HISTOGRAMGREEN(gpnSortedIndex[i]) <
1384 HISTOGRAMGREEN(gpnSortedIndex[i+1])) {
1385 return FALSE;
1386 }
1387 }
1388 break;
1389 case LONG_AXIS_IS_BLUE:
1390 for (i=nMinIndex; i < nMaxIndex; i++) {
1391 if (HISTOGRAMBLUE(gpnSortedIndex[i]) <
1392 HISTOGRAMBLUE(gpnSortedIndex[i+1])) {
1393 return FALSE;
1394 }
1395 }
1396 break;
1397 }
1398 return TRUE;
1399 }
1400
1401 static
DebugSortACube(nMinIndex,nMaxIndex,nLevel,nLongAxis)1402 void DebugSortACube(nMinIndex, nMaxIndex, nLevel, nLongAxis)
1403 int nMinIndex, nMaxIndex, nLevel, nLongAxis;
1404 {
1405 register int i;
1406 int sorted=TRUE;
1407
1408 /* debug, do not translate */
1409 fprintf(stderr, "Level %1d done (long axis is '%s'):\n", nLevel,
1410 (nLongAxis==LONG_AXIS_IS_RED ? "red" :
1411 (nLongAxis==LONG_AXIS_IS_GREEN ? "green" : "blue")));
1412 for (i=nMinIndex; i <= nMaxIndex; i++) {
1413 fprintf(stderr, "\t%6ld: %6d %6d %6d\n",
1414 (long)HISTOGRAMCOUNT(gpnSortedIndex[i]),
1415 (int)HISTOGRAMRED(gpnSortedIndex[i]),
1416 (int)HISTOGRAMGREEN(gpnSortedIndex[i]),
1417 (int)HISTOGRAMBLUE(gpnSortedIndex[i]));
1418 switch (nLongAxis) {
1419 case LONG_AXIS_IS_RED:
1420 if (sorted && i != nMinIndex && HISTOGRAMRED(gpnSortedIndex[i-1]) <
1421 HISTOGRAMRED(gpnSortedIndex[i])) {
1422 sorted = FALSE;
1423 }
1424 break;
1425 case LONG_AXIS_IS_GREEN:
1426 if (sorted && i != nMinIndex && HISTOGRAMGREEN(gpnSortedIndex[i-1]) <
1427 HISTOGRAMGREEN(gpnSortedIndex[i])) {
1428 sorted = FALSE;
1429 }
1430 break;
1431 case LONG_AXIS_IS_BLUE:
1432 if (sorted && i != nMinIndex && HISTOGRAMBLUE(gpnSortedIndex[i-1]) <
1433 HISTOGRAMBLUE(gpnSortedIndex[i])) {
1434 sorted = FALSE;
1435 }
1436 break;
1437 }
1438 }
1439 if (!sorted) fprintf(stderr, "Not sorted!\n");
1440 }
1441
1442 /*
1443 static
1444 void DisplaySortACube(nMinIndex, nMaxIndex)
1445 int nMinIndex, nMaxIndex;
1446 {
1447 register int i;
1448 int sorted=TRUE;
1449
1450 for (i=nMinIndex; i <= nMaxIndex; i++) {
1451 fprintf(stderr, "\t%6ld %6d %6d %6d %6d %3d\n",
1452 (long)HISTOGRAMCOUNT(gpnSortedIndex[i]),
1453 (int)HISTOGRAMRED(gpnSortedIndex[i]),
1454 (int)HISTOGRAMGREEN(gpnSortedIndex[i]),
1455 (int)HISTOGRAMBLUE(gpnSortedIndex[i]),
1456 gpnSortedIndex[i], i);
1457 }
1458 if (!sorted) fprintf(stderr, "Not sorted!\n");
1459 }
1460 */
1461
1462 static int dbg_sort=FALSE;
1463
1464 static
QuickSortACube(nMinIndex,nMaxIndex,nLevel,nLongAxis)1465 void QuickSortACube(nMinIndex, nMaxIndex, nLevel, nLongAxis)
1466 int nMinIndex, nMaxIndex, nLevel, nLongAxis;
1467 {
1468 register int i, j;
1469 int pivot_index, tmp, something_swapped;
1470 unsigned long pivot_value=0;
1471
1472 if (nMinIndex > nMaxIndex) return;
1473 if (AlreadySorted(nMinIndex, nMaxIndex, nLongAxis)) return;
1474
1475 pivot_index = nMaxIndex;
1476 switch (nLongAxis) {
1477 case LONG_AXIS_IS_RED:
1478 pivot_value = HISTOGRAMRED(gpnSortedIndex[pivot_index]);
1479 break;
1480 case LONG_AXIS_IS_GREEN:
1481 pivot_value = HISTOGRAMGREEN(gpnSortedIndex[pivot_index]);
1482 break;
1483 case LONG_AXIS_IS_BLUE:
1484 pivot_value = HISTOGRAMBLUE(gpnSortedIndex[pivot_index]);
1485 break;
1486 }
1487 i = nMinIndex;
1488 j = nMaxIndex-1;
1489 something_swapped = FALSE;
1490 do {
1491 switch (nLongAxis) {
1492 case LONG_AXIS_IS_RED:
1493 while (HISTOGRAMRED(gpnSortedIndex[i]) > pivot_value) i++;
1494 while (j > i && HISTOGRAMRED(gpnSortedIndex[j]) < pivot_value) j--;
1495 break;
1496 case LONG_AXIS_IS_GREEN:
1497 while (HISTOGRAMGREEN(gpnSortedIndex[i]) > pivot_value) i++;
1498 while (j > i && HISTOGRAMGREEN(gpnSortedIndex[j]) < pivot_value) j--;
1499 break;
1500 case LONG_AXIS_IS_BLUE:
1501 while (HISTOGRAMBLUE(gpnSortedIndex[i]) > pivot_value) i++;
1502 while (j > i && HISTOGRAMBLUE(gpnSortedIndex[j]) < pivot_value) j--;
1503 break;
1504 }
1505 if (j > i) {
1506 tmp = gpnSortedIndex[j];
1507 gpnSortedIndex[j] = gpnSortedIndex[i];
1508 gpnSortedIndex[i] = tmp;
1509 if (something_swapped == FALSE) {
1510 something_swapped = TRUE;
1511 }
1512 if (j == i+1) break;
1513 i++; j--;
1514 } else {
1515 break;
1516 }
1517 } while (TRUE);
1518 if (i == nMaxIndex) {
1519 /* pivot_value is the smallest */
1520 if (something_swapped) {
1521 #ifdef _TGIF_DBG /* debug, do not translate */
1522 fprintf(stderr, "Huh? nMinIndex=%1d, nMaxIndex=%1d, nLevel=%1d\n",
1523 nMinIndex, nMaxIndex, nLevel);
1524 #endif /* _TGIF_DBG */
1525 } else {
1526 QuickSortACube(nMinIndex, j, nLevel+1, nLongAxis);
1527 }
1528 } else if (j > i) {
1529 tmp = gpnSortedIndex[nMaxIndex];
1530 gpnSortedIndex[nMaxIndex] = gpnSortedIndex[j];
1531 gpnSortedIndex[j] = tmp;
1532 QuickSortACube(nMinIndex, j-1, nLevel+1, nLongAxis);
1533 QuickSortACube(j+1, nMaxIndex, nLevel+1, nLongAxis);
1534 } else {
1535 tmp = gpnSortedIndex[nMaxIndex];
1536 gpnSortedIndex[nMaxIndex] = gpnSortedIndex[i];
1537 gpnSortedIndex[i] = tmp;
1538 QuickSortACube(nMinIndex, i-1, nLevel+1, nLongAxis);
1539 QuickSortACube(i+1, nMaxIndex, nLevel+1, nLongAxis);
1540 }
1541 if (dbg_sort) {
1542 DebugSortACube(nMinIndex, nMaxIndex, nLevel, nLongAxis);
1543 }
1544 }
1545
1546 static
SweepACube(cube_index)1547 void SweepACube(cube_index)
1548 int cube_index;
1549 {
1550 register int i;
1551 int min_index=gpCube[cube_index].min_index;
1552 int max_index=gpCube[cube_index].max_index;
1553 unsigned short min_r, max_r, min_g, max_g, min_b, max_b;
1554
1555 min_r = max_r = gpHistogram[gpnSortedIndex[min_index]].red;
1556 min_g = max_g = gpHistogram[gpnSortedIndex[min_index]].green;
1557 min_b = max_b = gpHistogram[gpnSortedIndex[min_index]].blue;
1558 gpCube[cube_index].num_points = HISTOGRAMCOUNT(gpnSortedIndex[min_index]);
1559 for (i=min_index+1; i <= max_index; i++) {
1560 unsigned short red=gpHistogram[gpnSortedIndex[i]].red;
1561 unsigned short green=gpHistogram[gpnSortedIndex[i]].green;
1562 unsigned short blue=gpHistogram[gpnSortedIndex[i]].blue;
1563
1564 gpCube[cube_index].num_points += HISTOGRAMCOUNT(gpnSortedIndex[i]);
1565 if (red < min_r) min_r = red;
1566 if (red > max_r) max_r = red;
1567 if (green < min_g) min_g = green;
1568 if (green > max_g) max_g = green;
1569 if (blue < min_b) min_b = blue;
1570 if (blue > max_b) max_b = blue;
1571 }
1572 gpCube[cube_index].red_length = max_r-min_r;
1573 gpCube[cube_index].green_length = max_g-min_g;
1574 gpCube[cube_index].blue_length = max_b-min_b;
1575 if (gpCube[cube_index].red_length >= gpCube[cube_index].green_length) {
1576 if (gpCube[cube_index].red_length >= gpCube[cube_index].blue_length) {
1577 gpCube[cube_index].long_axis = LONG_AXIS_IS_RED;
1578 } else {
1579 gpCube[cube_index].long_axis = LONG_AXIS_IS_BLUE;
1580 }
1581 } else {
1582 if (gpCube[cube_index].green_length >= gpCube[cube_index].blue_length) {
1583 gpCube[cube_index].long_axis = LONG_AXIS_IS_GREEN;
1584 } else {
1585 gpCube[cube_index].long_axis = LONG_AXIS_IS_BLUE;
1586 }
1587 }
1588 }
1589
1590 static
SplitACube(cube_index,pul_before_count,pul_after_count)1591 int SplitACube(cube_index, pul_before_count, pul_after_count)
1592 int cube_index;
1593 unsigned long *pul_before_count, *pul_after_count;
1594 /*
1595 * cube to be split into (min_index,return_index)
1596 * and (return_index+1,max_index)
1597 */
1598 {
1599 register int i;
1600 int min_index=gpCube[cube_index].min_index;
1601 int max_index=gpCube[cube_index].max_index;
1602 unsigned long count;
1603 unsigned long half_num_points;
1604
1605 if (max_index == min_index+1) {
1606 *pul_before_count = HISTOGRAMCOUNT(gpnSortedIndex[min_index]);
1607 *pul_after_count = HISTOGRAMCOUNT(gpnSortedIndex[max_index]);
1608 return min_index;
1609 }
1610 count = 0;
1611 half_num_points = (gpCube[cube_index].num_points>>1);
1612 for (i=min_index; i <= max_index; i++) {
1613 unsigned long inc=HISTOGRAMCOUNT(gpnSortedIndex[i]);
1614
1615 if (count+inc >= half_num_points) {
1616 if (i == min_index) {
1617 *pul_before_count = inc;
1618 *pul_after_count = gpCube[cube_index].num_points-inc;
1619 return i;
1620 } else if (i == max_index) {
1621 *pul_before_count = count;
1622 *pul_after_count = gpCube[cube_index].num_points-count;
1623 return i-1;
1624 } else if (count+inc == half_num_points) {
1625 *pul_before_count = count+inc;
1626 *pul_after_count = gpCube[cube_index].num_points-count-inc;
1627 return i;
1628 } else if (half_num_points-count >= count+inc-half_num_points) {
1629 if (i+1 == max_index) {
1630 *pul_before_count = count;
1631 *pul_after_count = gpCube[cube_index].num_points-count;
1632 return i;
1633 } else {
1634 *pul_before_count = count+inc;
1635 *pul_after_count = gpCube[cube_index].num_points-count-inc;
1636 return i+1;
1637 }
1638 } else {
1639 *pul_before_count = count;
1640 *pul_after_count = gpCube[cube_index].num_points-count;
1641 return i;
1642 }
1643 }
1644 count += inc;
1645 }
1646 count = HISTOGRAMCOUNT(gpnSortedIndex[max_index-1]);
1647 *pul_before_count = gpCube[cube_index].num_points-count;
1648 *pul_after_count = count;
1649 return max_index-1;
1650 }
1651
1652 static
Quantize()1653 int Quantize()
1654 /* median-cut quantization */
1655 {
1656 int smallest_level=0, max_level=0, cube_index;
1657
1658 gpCube = (struct CubeRec *)malloc(gnQuantizingLevels*sizeof(struct CubeRec));
1659 if (gpCube == NULL) {
1660 FailAllocMessage();
1661 return FALSE;
1662 }
1663 memset(gpCube, 0, gnQuantizingLevels*sizeof(struct CubeRec));
1664 gnCubeEntries = 1;
1665 gpCube[0].min_index = 0;
1666 gpCube[0].max_index = gnHistogramEntries-1;
1667 gpCube[0].level = 0;
1668 cube_index = 0;
1669 SweepACube(0);
1670 if (gnDebugQuantization) {
1671 int i;
1672
1673 /* debug, do not translate */
1674 fprintf(stderr, "Original histogram in Quantize():\n");
1675 for (i=0; i < gnHistogramEntries; i++) {
1676 unsigned long count=(int)HISTOGRAMCOUNT(gpnSortedIndex[i]);
1677 int red=(int)((HISTOGRAMRED(gpnSortedIndex[i])>>8) & 0xff);
1678 int green=(int)((HISTOGRAMGREEN(gpnSortedIndex[i])>>8) & 0xff);
1679 int blue=(int)((HISTOGRAMBLUE(gpnSortedIndex[i])>>8) & 0xff);
1680
1681 fprintf(stderr, "\t#%02x%02x%02x %6ld\n",
1682 red&0x0ff, green&0x0ff, blue&0x0ff, count);
1683 }
1684 }
1685 while (gnCubeEntries < gnQuantizingLevels) {
1686 unsigned long before_count, after_count;
1687 int split_index, new_level;
1688
1689 while (smallest_level <= max_level) {
1690 int saved_cube_index=cube_index, found=FALSE;
1691
1692 for ( ; cube_index < gnCubeEntries; cube_index++) {
1693 if (gpCube[cube_index].min_index != gpCube[cube_index].max_index &&
1694 gpCube[cube_index].level == smallest_level) {
1695 found = TRUE;
1696 break;
1697 }
1698 }
1699 if (found) break;
1700 for (cube_index=0; cube_index < saved_cube_index; cube_index++) {
1701 if (gpCube[cube_index].min_index != gpCube[cube_index].max_index &&
1702 gpCube[cube_index].level == smallest_level) {
1703 found = TRUE;
1704 break;
1705 }
1706 }
1707 if (found) break;
1708 smallest_level++;
1709 }
1710 if (smallest_level > max_level) break;
1711
1712 /*
1713 * determine which is the longest axis
1714 */
1715 QuickSortACube(gpCube[cube_index].min_index, gpCube[cube_index].max_index,
1716 0, gpCube[cube_index].long_axis);
1717 /*
1718 * cube to be split into (min_index,split_index)
1719 * and (split_index+1,max_index)
1720 */
1721 split_index = SplitACube(cube_index, &before_count, &after_count);
1722 new_level = gpCube[cube_index].level+1;
1723 if (gnDebugQuantization) {
1724 /* debug, do not translate */
1725 fprintf(stderr,
1726 "Level %2d (%2d): [%3d,%3d] -> %6ld/[%3d,%3d] %6ld/[%3d,%3d]\n",
1727 gpCube[cube_index].level, cube_index,
1728 gpCube[cube_index].min_index, gpCube[cube_index].max_index,
1729 before_count, gpCube[cube_index].min_index, split_index,
1730 after_count, split_index+1, gpCube[cube_index].max_index);
1731 }
1732 gpCube[gnCubeEntries].min_index = split_index+1;
1733 gpCube[gnCubeEntries].max_index = gpCube[cube_index].max_index;
1734 gpCube[gnCubeEntries].level = new_level;
1735 gpCube[gnCubeEntries].num_points = after_count;
1736 SweepACube(gnCubeEntries);
1737 gnCubeEntries++;
1738
1739 gpCube[cube_index].min_index = gpCube[cube_index].min_index;
1740 gpCube[cube_index].max_index = split_index;
1741 gpCube[cube_index].level = new_level;
1742 gpCube[cube_index].num_points = before_count;
1743 SweepACube(cube_index);
1744
1745 if (max_level < new_level) max_level = new_level;
1746
1747 cube_index++;
1748 }
1749 if (gnDebugQuantization) {
1750 for (cube_index=0; cube_index < gnCubeEntries; cube_index++) {
1751 int i;
1752
1753 /* debug, do not translate */
1754 fprintf(stderr, "cube %3d: (%3d) [%3d,%3d] %6ld\n",
1755 cube_index, gpCube[cube_index].level,
1756 gpCube[cube_index].min_index, gpCube[cube_index].max_index,
1757 (long)gpCube[cube_index].num_points);
1758 for (i=gpCube[cube_index].min_index; i <= gpCube[cube_index].max_index;
1759 i++) {
1760 unsigned long count=(int)HISTOGRAMCOUNT(gpnSortedIndex[i]);
1761 int red=(int)((HISTOGRAMRED(gpnSortedIndex[i])>>8) & 0xff);
1762 int green=(int)((HISTOGRAMGREEN(gpnSortedIndex[i])>>8) & 0xff);
1763 int blue=(int)((HISTOGRAMBLUE(gpnSortedIndex[i])>>8) & 0xff);
1764
1765 fprintf(stderr, "\t#%02x%02x%02x %6ld\n",
1766 red&0x0ff, green&0x0ff, blue&0x0ff, count);
1767 }
1768 }
1769 }
1770 return TRUE;
1771 }
1772
DoConvolution(fp,image,bitmap_image,w,h,xpm_ptr)1773 int DoConvolution(fp, image, bitmap_image, w, h, xpm_ptr)
1774 FILE *fp;
1775 XImage *image, *bitmap_image;
1776 int w, h;
1777 struct XPmRec *xpm_ptr;
1778 {
1779 register int j, i;
1780 int interrupted=FALSE, rc;
1781 ProgressInfo pi;
1782
1783 if (gpConvolveFunc == NULL) {
1784 return FALSE;
1785 }
1786 memset(gaHGBucket, 0, sizeof(gaHGBucket));
1787 gnHistogramEntries = 0;
1788
1789 if (DoPpm6(xpm_ptr)) {
1790 writeFileFailed = FALSE;
1791 if (fprintf(fp, "P6\n%1d %1d\n255\n", w, h) == EOF) {
1792 writeFileFailed = TRUE;
1793 }
1794 if (gpConvolveCmdID == CMDID_VECTORWARP) {
1795 /* already initialized in ComputeVectorWarpData(), except for fp */
1796 gConvExtraInfo.fp = fp;
1797 } else {
1798 if (!SetConvExtraInfo(fp, w, h, image, bitmap_image)) {
1799 CleanUpConvolution();
1800 return FALSE;
1801 }
1802 }
1803 ShowInterrupt(1);
1804 BeginProgress(&pi, h);
1805 for (i=0; i < h; i++) {
1806 UpdateProgress(&pi, i);
1807
1808 if (ESCPressed() || CheckInterrupt(TRUE)) {
1809 Msg(TgLoadString(STID_USER_INTR));
1810 interrupted = TRUE;
1811 break;
1812 }
1813 for (j=0; j < w; j++) {
1814 ((ConvolveFunc*)gpConvolveFunc)(j, i);
1815 }
1816 }
1817 HideInterrupt();
1818 ClearConvExtraInfo();
1819 if (interrupted) {
1820 CleanUpConvolution();
1821 return FALSE;
1822 }
1823 CleanUpConvolution();
1824
1825 return (writeFileFailed == FALSE);
1826 }
1827 SetStringStatus(TgLoadCachedString(CSTID_BUILDING_HISTOGRAM_DOTS));
1828 XSync(mainDisplay, False);
1829 if (!CreatePixelToIndexMapping()) {
1830 return FALSE;
1831 }
1832 gnHistogramSize = 256;
1833 gpHistogram = (XColor*)malloc(gnHistogramSize*sizeof(XColor));
1834 if (gpHistogram == NULL) {
1835 FailAllocMessage();
1836 CleanUpConvolution();
1837 return FALSE;
1838 }
1839 gnImageW = w;
1840 gnImageH = h;
1841 gnOrigImageIndex = (int**)malloc(h*sizeof(int*));
1842 if (gnOrigImageIndex == NULL) {
1843 FailAllocMessage();
1844 CleanUpConvolution();
1845 return FALSE;
1846 }
1847 memset(gnOrigImageIndex, 0, h*sizeof(int*));
1848 for (i=0; i < h; i++) {
1849 gnOrigImageIndex[i] = (int*)malloc(w*sizeof(int));
1850 if (gnOrigImageIndex[i] == NULL) {
1851 FailAllocMessage();
1852 CleanUpConvolution();
1853 return FALSE;
1854 }
1855 }
1856 if (image != NULL) {
1857 BeginProgress(&pi, h);
1858 for (i=0; i < h; i++) {
1859 UpdateProgress(&pi, i);
1860 for (j=0; j < w; j++) {
1861 /* int pixel=XGetPixel(image,j,i); */
1862 /* int index=pnPixelToIndexMap[pixel]; */
1863
1864 gnOrigImageIndex[i][j] = GetIndexOfPixel(XGetPixel(image,j,i));
1865 }
1866 }
1867 }
1868 gnFinalImageIndex = (int**)malloc(h*sizeof(int*));
1869 if (gnFinalImageIndex == NULL) {
1870 FailAllocMessage();
1871 CleanUpConvolution();
1872 return FALSE;
1873 }
1874 memset(gnFinalImageIndex, 0, h*sizeof(int*));
1875 for (i=0; i < h; i++) {
1876 gnFinalImageIndex[i] = (int*)malloc(w*sizeof(int));
1877 if (gnFinalImageIndex[i] == NULL) {
1878 FailAllocMessage();
1879 CleanUpConvolution();
1880 return FALSE;
1881 }
1882 }
1883 ShowInterrupt(1);
1884 BeginProgress(&pi, h);
1885 for (i=0; i < h; i++) {
1886 UpdateProgress(&pi, i);
1887 if (ESCPressed() || CheckInterrupt(TRUE)) {
1888 Msg(TgLoadString(STID_USER_INTR));
1889 interrupted = TRUE;
1890 break;
1891 }
1892 for (j=0; j < w; j++) {
1893 gnFinalImageIndex[i][j] = ((ConvolveFunc*)gpConvolveFunc)(j, i);
1894 }
1895 }
1896 HideInterrupt();
1897 if (interrupted) {
1898 CleanUpConvolution();
1899 return FALSE;
1900 }
1901 gpnSortedIndex = (int*)malloc(gnHistogramEntries*sizeof(int));
1902 if (gpnSortedIndex == NULL) {
1903 FailAllocMessage();
1904 CleanUpConvolution();
1905 return FALSE;
1906 }
1907 for (i=0; i < gnHistogramEntries; i++) gpnSortedIndex[i] = i;
1908 if (gnUserSpecifiedLevels != (-1) ||
1909 gnHistogramEntries > gnQuantizingLevels) {
1910 int saved_levels=gnQuantizingLevels;
1911
1912 if (gnUserSpecifiedLevels != (-1)) {
1913 gnQuantizingLevels = gnUserSpecifiedLevels;
1914 }
1915 sprintf(gszMsgBox, TgLoadCachedString(CSTID_QUANTIZING_COLORS_DOTS),
1916 gnHistogramEntries, gnQuantizingLevels);
1917 Msg(gszMsgBox);
1918 SetStringStatus(gszMsgBox);
1919 XSync(mainDisplay, False);
1920 if (Quantize()) {
1921 rc = DumpQuantizedConvolution(fp);
1922 if (gnUserSpecifiedLevels != (-1)) {
1923 gnQuantizingLevels = saved_levels;
1924 }
1925 CleanUpConvolution();
1926 return rc;
1927 }
1928 CleanUpConvolution();
1929 gnQuantizingLevels = saved_levels;;
1930 return FALSE;
1931 }
1932 rc = DumpConvolution(fp);
1933 CleanUpConvolution();
1934 return rc;
1935 }
1936
1937 static
DoColorMapping(fp,image,bitmap_image,w,h,xpm_ptr)1938 int DoColorMapping(fp, image, bitmap_image, w, h, xpm_ptr)
1939 FILE *fp;
1940 XImage *image, *bitmap_image;
1941 int w, h;
1942 struct XPmRec *xpm_ptr;
1943 {
1944 register int j, i;
1945 int interrupted=FALSE, rc;
1946 ProgressInfo pi;
1947
1948 if (gpImageMapColorFunc == NULL) {
1949 return FALSE;
1950 }
1951 SetStringStatus(TgLoadCachedString(CSTID_REMAPPING_COLORS_DOTS));
1952 XSync(mainDisplay, False);
1953
1954 memset(gaHGBucket, 0, sizeof(gaHGBucket));
1955 gnHistogramEntries = 0;
1956
1957 if (DoPpm6(xpm_ptr)) {
1958 writeFileFailed = FALSE;
1959 if (fprintf(fp, "P6\n%1d %1d\n255\n", w, h) == EOF) {
1960 writeFileFailed = TRUE;
1961 }
1962 ShowInterrupt(1);
1963 BeginProgress(&pi, h);
1964 for (i=0; i < h; i++) {
1965 UpdateProgress(&pi, i);
1966
1967 if (ESCPressed() || CheckInterrupt(TRUE)) {
1968 Msg(TgLoadString(STID_USER_INTR));
1969 interrupted = TRUE;
1970 break;
1971 }
1972 for (j=0; j < w; j++) {
1973 if (bitmap_image != NULL && XGetPixel(bitmap_image,j,i) == 0) {
1974 TgAssert(FALSE, "transparent pixel not supported", NULL);
1975 } else {
1976 ((ImageMapColorFunc*)gpImageMapColorFunc)(XGetPixel(image,j,i),
1977 (XColor*)fp);
1978 }
1979 }
1980 }
1981 HideInterrupt();
1982 if (interrupted) {
1983 CleanUpConvolution();
1984 return FALSE;
1985 }
1986 CleanUpConvolution();
1987
1988 return (writeFileFailed == FALSE);
1989 }
1990 gnHistogramSize = 256;
1991 gpHistogram = (XColor*)malloc(gnHistogramSize*sizeof(XColor));
1992 if (gpHistogram == NULL) {
1993 FailAllocMessage();
1994 CleanUpConvolution();
1995 return FALSE;
1996 }
1997 if (!CreateObjPixelToIndexMapping(xpm_ptr)) {
1998 CleanUpConvolution();
1999 return FALSE;
2000 }
2001 gnImageW = w;
2002 gnImageH = h;
2003 gnFinalImageIndex = (int**)malloc(h*sizeof(int*));
2004 if (gnFinalImageIndex == NULL) {
2005 FailAllocMessage();
2006 CleanUpConvolution();
2007 return FALSE;
2008 }
2009 memset(gnFinalImageIndex, 0, h*sizeof(int*));
2010 for (i=0; i < h; i++) {
2011 gnFinalImageIndex[i] = (int*)malloc(w*sizeof(int));
2012 if (gnFinalImageIndex[i] == NULL) {
2013 FailAllocMessage();
2014 CleanUpConvolution();
2015 return FALSE;
2016 }
2017 }
2018 ShowInterrupt(1);
2019 BeginProgress(&pi, h);
2020 for (i=0; i < h; i++) {
2021 UpdateProgress(&pi, i);
2022
2023 if (ESCPressed() || CheckInterrupt(TRUE)) {
2024 Msg(TgLoadString(STID_USER_INTR));
2025 interrupted = TRUE;
2026 break;
2027 }
2028 for (j=0; j < w; j++) {
2029 /* int pixel=XGetPixel(image,j,i); */
2030 /* int index=pnPixelToIndexMap[pixel]; */
2031
2032 if (bitmap_image != NULL && XGetPixel(bitmap_image,j,i) == 0) {
2033 gnFinalImageIndex[i][j] = gnTransparentIndex;
2034 } else {
2035 gnFinalImageIndex[i][j] = GetIndexOfPixel(XGetPixel(image,j,i));
2036 }
2037 }
2038 }
2039 HideInterrupt();
2040 if (interrupted) {
2041 CleanUpConvolution();
2042 return FALSE;
2043 }
2044 rc = DumpConvolution(fp);
2045 CleanUpConvolution();
2046 return rc;
2047 }
2048
2049 /* ----------------------- ProcessImage ----------------------- */
2050
GetImageProcOutputFileName(pszPath,path_buf_sz,pnShortName,ppszRest)2051 FILE *GetImageProcOutputFileName(pszPath, path_buf_sz, pnShortName, ppszRest)
2052 char *pszPath, **ppszRest;
2053 int path_buf_sz, *pnShortName;
2054 {
2055 FILE *fp=NULL;
2056
2057 if (MkTempFile(pszPath, path_buf_sz, tmpDir, TOOL_NAME) == NULL) {
2058 return NULL;
2059 }
2060 if ((*pnShortName=IsPrefix(bootDir, pszPath, ppszRest))) {
2061 *ppszRest = (&(*ppszRest)[1]);
2062 }
2063 if ((fp=fopen(pszPath, "w")) == NULL) {
2064 if (*pnShortName) {
2065 sprintf(gszMsgBox, TgLoadString(STID_CANNOT_OPEN_FILE_FOR_WRITING),
2066 *ppszRest);
2067 } else {
2068 sprintf(gszMsgBox, TgLoadString(STID_CANNOT_OPEN_FILE_FOR_WRITING),
2069 pszPath);
2070 }
2071 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
2072 return NULL;
2073 }
2074 return fp;
2075 }
2076
2077 static
CleanUpProcessImage(fp,image,bitmap_image)2078 int CleanUpProcessImage(fp, image, bitmap_image)
2079 FILE *fp;
2080 XImage *image, *bitmap_image;
2081 {
2082 if (fp != NULL) fclose(fp);
2083 if (image != NULL) XDestroyImage(image);
2084 if (bitmap_image != NULL) XDestroyImage(bitmap_image);
2085 return FALSE;
2086 }
2087
2088 static
ProcessImage()2089 int ProcessImage()
2090 {
2091 int short_name=FALSE, ok=TRUE;
2092 char path[MAXPATHLENGTH+1], *rest=NULL;
2093 Pixmap pixmap=None, bitmap=None;
2094 XImage *image=NULL, *bitmap_image=NULL;
2095 FILE *fp=NULL;
2096 struct ObjRec *obj_ptr=NULL;
2097 int image_w=0, image_h=0;
2098 struct XPmRec *xpm_ptr=NULL;
2099
2100 if ((fp=GetImageProcOutputFileName(path, sizeof(path), &short_name,
2101 &rest)) == NULL) {
2102 return FALSE;
2103 }
2104 if (gnCombining) {
2105 obj_ptr = NULL;
2106 } else {
2107 obj_ptr = topSel->obj;
2108 }
2109 if (obj_ptr == NULL) {
2110 pixmap = None;
2111 bitmap = None;
2112 image_w = gnCombineW;
2113 image_h = gnCombineH;
2114 image = bitmap_image = NULL;
2115 } else if (obj_ptr->type == OBJ_XPM) {
2116 xpm_ptr = obj_ptr->detail.xpm;
2117
2118 pixmap = xpm_ptr->pixmap;
2119 bitmap = xpm_ptr->bitmap;
2120 image_w = xpm_ptr->image_w;
2121 image_h = xpm_ptr->image_h;
2122
2123 image = XGetImage(mainDisplay, pixmap, 0, 0, image_w, image_h, AllPlanes,
2124 ZPixmap);
2125 if (bitmap != None) {
2126 bitmap_image = XGetImage(mainDisplay, bitmap, 0, 0, image_w, image_h,
2127 1, ZPixmap);
2128 }
2129 if (image == NULL || (bitmap != None && bitmap_image == NULL)) {
2130 sprintf(gszMsgBox, TgLoadString(STID_CANNOT_GET_IMAGE_OF_SIZE),
2131 image_w, image_h);
2132 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
2133 return CleanUpProcessImage(fp, image, bitmap_image);
2134 }
2135 if (DoPpm6(xpm_ptr)) {
2136 if (!InitTrueColorInfo(image, &gTrueColorInfo, image_w)) {
2137 sprintf(gszMsgBox, TgLoadString(STID_CANNOT_GET_IMAGE_OF_SIZE),
2138 image_w, image_h);
2139 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
2140 return CleanUpProcessImage(fp, image, bitmap_image);
2141 }
2142 if (gpConvolveCmdID == CMDID_REDUCECOLORS) {
2143 int floyd=FALSE;
2144 char tmp_fname[MAXPATHLENGTH];
2145
2146 switch (MsgBox(TgLoadString(STID_Q_FS_ERROR_DIFFUSE), TOOL_NAME,
2147 YNC_MB)) {
2148 case MB_ID_YES: floyd = TRUE; break;
2149 case MB_ID_NO: floyd = FALSE; break;
2150 case MB_ID_CANCEL:
2151 return CleanUpProcessImage(fp, image, bitmap_image);
2152 }
2153 if (MkTempFile(tmp_fname, sizeof(tmp_fname), tmpDir, TOOL_NAME) ==
2154 NULL) {
2155 return CleanUpProcessImage(fp, image, bitmap_image);
2156 }
2157 if (DumpXImageToPpmFile(image, image_w, image_h, tmp_fname,
2158 FALSE)) {
2159 FILE *pfp=NULL;
2160 char psz_cmd[MAXPATHLENGTH<<1];
2161 int bytes_read=0;
2162
2163 if (floyd) {
2164 snprintf(psz_cmd, sizeof(psz_cmd), ppmFSquantCmd,
2165 gnUserSpecifiedLevels, tmp_fname);
2166 } else {
2167 snprintf(psz_cmd, sizeof(psz_cmd), ppmquantCmd,
2168 gnUserSpecifiedLevels, tmp_fname);
2169 }
2170 if ((pfp=(FILE*)popen(psz_cmd,"r")) == NULL) {
2171 sprintf(gszMsgBox, TgLoadString(STID_FAIL_TO_EXECUTE_CMD),
2172 psz_cmd);
2173 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
2174 unlink(tmp_fname);
2175 return CleanUpProcessImage(fp, image, bitmap_image);
2176 }
2177 writeFileFailed = FALSE;
2178 while ((bytes_read=fread(gszMsgBox, sizeof(char),
2179 sizeof(gszMsgBox), pfp)) > 0) {
2180 if ((int)fwrite(gszMsgBox, sizeof(char), bytes_read,
2181 fp) <= 0) {
2182 writeFileFailed = TRUE;
2183 break;
2184 }
2185 }
2186 pclose(pfp);
2187 if (writeFileFailed) {
2188 FailToWriteFileMessage(short_name ? rest : tmp_fname);
2189 unlink(tmp_fname);
2190 return CleanUpProcessImage(fp, image, bitmap_image);
2191 }
2192 unlink(tmp_fname);
2193 CleanUpProcessImage(fp, image, bitmap_image);
2194 strcpy(gszImageProcXPmFile, path);
2195 if (gnConvolving) {
2196 CleanUpConvolution();
2197 }
2198 return TRUE;
2199 }
2200 }
2201 }
2202 } else {
2203 return CleanUpProcessImage(fp, image, bitmap_image);
2204 }
2205 SaveStatusStrings();
2206 if (gnConvolving) {
2207 ok = DoConvolution(fp, image, bitmap_image, image_w, image_h, xpm_ptr);
2208 } else {
2209 ok = DoColorMapping(fp, image, bitmap_image, image_w, image_h, xpm_ptr);
2210 }
2211 RestoreStatusStrings();
2212 CleanUpProcessImage(fp, image, bitmap_image);
2213 if (!ok) return FALSE;
2214 strcpy(gszImageProcXPmFile, path);
2215 if (gnConvolving) {
2216 CleanUpConvolution();
2217 }
2218 return TRUE;
2219 }
2220
2221 static
DoImageProc(pvImageMapColorFunc)2222 int DoImageProc(pvImageMapColorFunc)
2223 NLFN *pvImageMapColorFunc;
2224 {
2225 int saved_colordump=colorDump, saved_left=leftExportPixelTrim;
2226 int saved_top=topExportPixelTrim, saved_right=rightExportPixelTrim;
2227 int saved_bottom=bottomExportPixelTrim, saved_where_to_print=whereToPrint;
2228 int saved_ltx, saved_lty, saved_cur_file_defined=curFileDefined;
2229 int ltx, lty, rbx, rby, saved_w, saved_h, saved_x=0, saved_y=0;
2230 int w, h, image_w, image_h, ncolors, first_pixel_is_bg, ctm_saved=FALSE;
2231 int rc, chars_per_pixel, *pixels=NULL, retry_count=0;
2232 struct XfrmMtrxRec saved_ctm;
2233 struct BBRec saved_orig_obbox;
2234 XPoint saved_rotated_obbox[5];
2235 char *color_char=NULL, **color_str=NULL, *xpm_data=NULL;
2236 Pixmap pixmap=None, bitmap=None;
2237 XImage *image=NULL, *bitmap_image=NULL;
2238 struct ObjRec *obj_ptr;
2239 struct AttrRec *saved_fattr=NULL, *saved_lattr=NULL;
2240 struct XPmRec *xpm_ptr=NULL;
2241
2242 if (gnCombining) {
2243 saved_ltx = selObjLtX;
2244 saved_lty = selObjLtY;
2245 saved_w = selObjRbX - saved_ltx;
2246 saved_h = selObjRbY - saved_lty;
2247 ltx = selLtX;
2248 lty = selLtY;
2249 rbx = selRbX;
2250 rby = selRbY;
2251 } else {
2252 if (topSel->obj->ctm != NULL) {
2253 ctm_saved = TRUE;
2254 saved_x = topSel->obj->x;
2255 saved_y = topSel->obj->y;
2256 memcpy(&saved_ctm, topSel->obj->ctm,
2257 sizeof(struct XfrmMtrxRec));
2258
2259 memcpy(&saved_orig_obbox, &topSel->obj->orig_obbox,
2260 sizeof(struct BBRec));
2261 memcpy(saved_rotated_obbox, topSel->obj->rotated_obbox,
2262 5*sizeof(XPoint));
2263 }
2264 saved_ltx = topSel->obj->obbox.ltx;
2265 saved_lty = topSel->obj->obbox.lty;
2266 saved_w = topSel->obj->obbox.rbx - saved_ltx;
2267 saved_h = topSel->obj->obbox.rby - saved_lty;
2268 ltx = topSel->obj->bbox.ltx;
2269 lty = topSel->obj->bbox.lty;
2270 rbx = topSel->obj->bbox.rbx;
2271 rby = topSel->obj->bbox.rby;
2272 }
2273 leftExportPixelTrim = topExportPixelTrim = rightExportPixelTrim =
2274 bottomExportPixelTrim = 0;
2275 *gszImageProcXPmFile = '\0';
2276
2277 curFileDefined = TRUE;
2278 whereToPrint = XBM_FILE;
2279 colorDump = TRUE;
2280 gnInImageProc = TRUE;
2281 gpImageMapColorFunc = (NLFN*)pvImageMapColorFunc;
2282
2283 SetWatchCursor(drawWindow);
2284 SetWatchCursor(mainWindow);
2285 ProcessImage();
2286 SetDefaultCursor(mainWindow);
2287 ShowCursor();
2288
2289 gpImageMapColorFunc = NULL;
2290 colorDump = saved_colordump;
2291 whereToPrint = saved_where_to_print;
2292 curFileDefined = saved_cur_file_defined;
2293 leftExportPixelTrim = saved_left;
2294 topExportPixelTrim = saved_top;
2295 rightExportPixelTrim = saved_right;
2296 bottomExportPixelTrim = saved_bottom;
2297
2298 if (*gszImageProcXPmFile == '\0') {
2299 gnInImageProc = FALSE;
2300 return FALSE;
2301 }
2302 if (gnCombining) {
2303 struct SelRec *sel_ptr;
2304
2305 HighLightReverse();
2306 PrepareToRecord(CMD_REPLACE, topSel, botSel, numObjSelected);
2307
2308 obj_ptr = NULL;
2309 for (sel_ptr=botSel; sel_ptr != NULL; sel_ptr=sel_ptr->prev) {
2310 UnlinkObj(sel_ptr->obj);
2311 FreeObj(sel_ptr->obj);
2312 }
2313 RemoveAllSel();
2314 } else {
2315 HighLightReverse();
2316 PrepareToRecord(CMD_REPLACE, topSel, botSel, numObjSelected);
2317
2318 obj_ptr = topSel->obj;
2319 xpm_ptr = obj_ptr->detail.xpm;
2320 saved_fattr = obj_ptr->fattr;
2321 saved_lattr = obj_ptr->lattr;
2322 obj_ptr->fattr = obj_ptr->lattr = NULL;
2323 RemoveAllSel();
2324 }
2325 gnInImageProc = FALSE;
2326 if (DoPpm6(xpm_ptr)) {
2327 char deflated_fname[MAXPATHLENGTH+1];
2328
2329 if (obj_ptr != NULL) UnlinkObj(obj_ptr);
2330 if (obj_ptr != NULL) FreeObj(obj_ptr);
2331
2332 ResetPngHeaderInfo(&gPngHeaderInfo);
2333 obj_ptr = CreatePpmTrueObjFromFile(gszImageProcXPmFile);
2334 if (obj_ptr != NULL &&
2335 MkTempFile(deflated_fname, sizeof(deflated_fname), tmpDir,
2336 TOOL_NAME) != NULL &&
2337 DeflateFile(gszImageProcXPmFile, deflated_fname)) {
2338 /* good */
2339 } else {
2340 FreeObj(obj_ptr);
2341
2342 sprintf(gszMsgBox, TgLoadString(STID_CANNOT_IMPORT_GIVEN_PPM),
2343 gszImageProcXPmFile);
2344 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
2345 unlink(gszImageProcXPmFile);
2346 *gszImageProcXPmFile = '\0';
2347 AbortPrepareCmd(CMD_REPLACE);
2348
2349 return FALSE;
2350 }
2351 xpm_ptr = obj_ptr->detail.xpm;
2352 xpm_ptr->real_type = PPM_TRUE;
2353 xpm_ptr->ppm_data_compress = PPM_DATA_DEFLATED;
2354 xpm_ptr->ppm_data = ReadFileIntoBuf(deflated_fname,
2355 &xpm_ptr->ppm_data_size);
2356 xpm_ptr->ppm_mask_data = NULL;
2357 xpm_ptr->ppm_mask_size = 0;
2358 unlink(deflated_fname);
2359 } else {
2360 do {
2361 int new_colormap_used=newColormapUsed;
2362
2363 if (obj_ptr != NULL) UnlinkObj(obj_ptr);
2364 if (obj_ptr != NULL) FreeObj(obj_ptr);
2365
2366 gnInImageProc = TRUE;
2367 if (FlushColormap()) {
2368 Msg(TgLoadString(STID_COLORMAP_FLUSHED));
2369 }
2370 gnInImageProc = FALSE;
2371
2372 allocColorFailed = FALSE;
2373 SetWatchCursor(drawWindow);
2374 SetWatchCursor(mainWindow);
2375 rc = MyReadPixmapFile(gszImageProcXPmFile, &image_w, &image_h, &w, &h,
2376 &pixmap, &image, &bitmap, &bitmap_image, &ncolors,
2377 &chars_per_pixel, &first_pixel_is_bg, &color_char, &color_str,
2378 &pixels, &xpm_data);
2379 SetDefaultCursor(mainWindow);
2380 ShowCursor();
2381
2382 if (rc != BitmapSuccess) {
2383 sprintf(gszMsgBox, TgLoadString(STID_CANNOT_IMPORT_XPM_FILE),
2384 gszImageProcXPmFile);
2385 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
2386 unlink(gszImageProcXPmFile);
2387 *gszImageProcXPmFile = '\0';
2388 if (!PRTGIF && colorLayers && needToRedrawColorWindow) {
2389 RedrawColorWindow();
2390 }
2391 AbortPrepareCmd(CMD_REPLACE);
2392
2393 return FALSE;
2394 }
2395 obj_ptr = CreateXPmObj(image_w, image_h, w, h, pixmap, image, bitmap,
2396 bitmap_image, ncolors, chars_per_pixel, FALSE, color_char,
2397 color_str, pixels, xpm_data);
2398 if (!new_colormap_used && newColormapUsed && allocColorFailed) {
2399 if (retry_count > 1) {
2400 break;
2401 }
2402 if (MsgBox(TgLoadString(STID_MAY_USED_UP_COLORS_RETRY), TOOL_NAME,
2403 YNC_MB) != MB_ID_YES) {
2404 break;
2405 }
2406 retry_count++;
2407 if (saved_fattr != NULL) {
2408 obj_ptr->fattr = obj_ptr->lattr = NULL;
2409 }
2410 } else {
2411 break;
2412 }
2413 } while (retry_count > 0);
2414 }
2415 unlink(gszImageProcXPmFile);
2416 *gszImageProcXPmFile = '\0';
2417
2418 obj_ptr->obbox.rbx = obj_ptr->obbox.ltx+saved_w;
2419 obj_ptr->obbox.rby = obj_ptr->obbox.lty+saved_h;
2420 AdjObjBBox(obj_ptr);
2421 AddObj(NULL, topObj, obj_ptr);
2422 MoveObj(obj_ptr, saved_ltx-obj_ptr->obbox.ltx,
2423 saved_lty-obj_ptr->obbox.lty);
2424 if (ctm_saved) {
2425 obj_ptr->x = saved_x;
2426 obj_ptr->y = saved_y;
2427 obj_ptr->ctm =
2428 (struct XfrmMtrxRec*)malloc(sizeof(struct XfrmMtrxRec));
2429 if (obj_ptr->ctm == NULL) FailAllocMessage();
2430 memcpy(obj_ptr->ctm, &saved_ctm, sizeof(struct XfrmMtrxRec));
2431
2432 memcpy(&obj_ptr->orig_obbox, &saved_orig_obbox,
2433 sizeof(struct BBRec));
2434 memcpy(obj_ptr->rotated_obbox, saved_rotated_obbox,
2435 5*sizeof(XPoint));
2436 }
2437 if (saved_fattr != NULL) {
2438 obj_ptr->fattr = saved_fattr;
2439 obj_ptr->lattr = saved_lattr;
2440 }
2441 RedrawAreas(botObj, ltx-GRID_ABS_SIZE(1), lty-GRID_ABS_SIZE(1),
2442 rbx+GRID_ABS_SIZE(1), rby+GRID_ABS_SIZE(1),
2443 obj_ptr->bbox.ltx-GRID_ABS_SIZE(1),
2444 obj_ptr->bbox.lty-GRID_ABS_SIZE(1),
2445 obj_ptr->bbox.rbx+GRID_ABS_SIZE(1),
2446 obj_ptr->bbox.rby+GRID_ABS_SIZE(1));
2447
2448 if (saved_fattr != NULL && topObj->fattr == NULL) {
2449 topObj->fattr = saved_fattr;
2450 topObj->lattr = saved_lattr;
2451 }
2452 if (!PRTGIF && colorLayers && needToRedrawColorWindow) {
2453 RedrawColorWindow();
2454 }
2455 if (gnCombining) {
2456 SelectTopObj();
2457
2458 recordCmdUsesNewColormap = TRUE;
2459 RecordCmd(CMD_MANY_TO_ONE, NULL, topSel, botSel, 1);
2460 recordCmdUsesNewColormap = FALSE;
2461 } else {
2462 SelectTopObj();
2463
2464 recordCmdUsesNewColormap = TRUE;
2465 RecordCmd(CMD_REPLACE, NULL, topSel, botSel, numObjSelected);
2466 recordCmdUsesNewColormap = FALSE;
2467 }
2468 SetFileModified(TRUE);
2469 justDupped = FALSE;
2470 return TRUE;
2471 }
2472
2473 /* ----------------------- MakeGray ----------------------- */
2474
2475 static
ChangeToGray(nColorIndex,pColor)2476 void ChangeToGray(nColorIndex, pColor)
2477 int nColorIndex;
2478 XColor *pColor;
2479 {
2480 struct XPmRec *xpm_ptr=topObj->detail.xpm;
2481
2482 if (DoPpm6(xpm_ptr)) {
2483 int pixel=nColorIndex;
2484 FILE *fp=(FILE*)pColor;
2485 uint32_t pix=(uint32_t)(unsigned int)pixel;
2486 unsigned int r=0, g=0, b=0, igray=0;
2487 double dr=(double)0, dg=(double)0, db=(double)0;
2488 double dgray=(double)0;
2489 unsigned char buf[3];
2490
2491 r = (pix & gTrueColorInfo.r_mask) >> gTrueColorInfo.r_shift;
2492 g = (pix & gTrueColorInfo.g_mask) >> gTrueColorInfo.g_shift;
2493 b = (pix & gTrueColorInfo.b_mask) >> gTrueColorInfo.b_shift;
2494 dr = ((double)r) / gTrueColorInfo.dr_maxval;
2495 dg = ((double)g) / gTrueColorInfo.dg_maxval;
2496 db = ((double)b) / gTrueColorInfo.db_maxval;
2497
2498 dgray = ((double)(0.299*dr + 0.587*dg + 0.114*db))*((double)256.0);
2499 igray = (dgray < ((double)0)) ? 0 : ((unsigned int)dgray);
2500 if (igray > 255) igray = 255;
2501 buf[0] = buf[1] = buf[2] = (unsigned char)(igray&0xff);
2502 if ((int)fwrite(buf, sizeof(char), 3, fp) <= 0) writeFileFailed = TRUE;
2503 } else {
2504 int red=(int)tgifColors[nColorIndex].red;
2505 int green=(int)tgifColors[nColorIndex].green;
2506 int blue=(int)tgifColors[nColorIndex].blue;
2507 float gray=0.299*((float)red)+0.587*((float)green)+0.114*((float)blue);
2508 int val=(int)gray;
2509 int real_gray=((val>0x0ffff) ? 0x0ffff : ((val<0) ? 0 : val));
2510
2511 pColor->red = pColor->green = pColor->blue = real_gray;
2512 }
2513 }
2514
MakeGray()2515 void MakeGray()
2516 {
2517 if (!CheckSelectionForImageProc(CMDID_MAKEGRAY)) return;
2518 if (TrueColorTransPixelCheck(topSel->obj, CMDID_MAKEGRAY)) return;
2519
2520 DoImageProc((NLFN*)ChangeToGray);
2521 }
2522
2523 /* ----------------------- InvertColor ----------------------- */
2524
2525 static
ChangeToInvertColor(nColorIndex,pColor)2526 void ChangeToInvertColor(nColorIndex, pColor)
2527 int nColorIndex;
2528 XColor *pColor;
2529 {
2530 struct XPmRec *xpm_ptr=topObj->detail.xpm;
2531
2532 if (DoPpm6(xpm_ptr)) {
2533 int pixel=nColorIndex;
2534 FILE *fp=(FILE*)pColor;
2535 uint32_t pix=(uint32_t)(unsigned int)pixel;
2536 unsigned int r=0, g=0, b=0;
2537 double dr=(double)0, dg=(double)0, db=(double)0;
2538 unsigned char buf[3];
2539
2540 r = (pix & gTrueColorInfo.r_mask) >> gTrueColorInfo.r_shift;
2541 g = (pix & gTrueColorInfo.g_mask) >> gTrueColorInfo.g_shift;
2542 b = (pix & gTrueColorInfo.b_mask) >> gTrueColorInfo.b_shift;
2543 dr = ((double)r) / gTrueColorInfo.dr_maxval;
2544 dg = ((double)g) / gTrueColorInfo.dg_maxval;
2545 db = ((double)b) / gTrueColorInfo.db_maxval;
2546
2547 dr = (((double)1.0) - dr) * ((double)256);
2548 dg = (((double)1.0) - dg) * ((double)256);
2549 db = (((double)1.0) - db) * ((double)256);
2550
2551 r = (dr < ((double)0)) ? 0 : ((unsigned int)dr);
2552 g = (dg < ((double)0)) ? 0 : ((unsigned int)dg);
2553 b = (db < ((double)0)) ? 0 : ((unsigned int)db);
2554 if (r > 255) r = 255;
2555 if (g > 255) g = 255;
2556 if (b > 255) b = 255;
2557 buf[0] = (unsigned char)r;
2558 buf[1] = (unsigned char)g;
2559 buf[2] = (unsigned char)b;
2560 if ((int)fwrite(buf, sizeof(char), 3, fp) <= 0) writeFileFailed = TRUE;
2561 } else {
2562 int red=(int)tgifColors[nColorIndex].red;
2563 int green=(int)tgifColors[nColorIndex].green;
2564 int blue=(int)tgifColors[nColorIndex].blue;
2565
2566 pColor->red = 0x0ffff-((unsigned int)red);
2567 pColor->green = 0x0ffff-((unsigned int)green);
2568 pColor->blue = 0x0ffff-((unsigned int)blue);
2569 }
2570 }
2571
InvertColor()2572 void InvertColor()
2573 {
2574 if (!CheckSelectionForImageProc(CMDID_INVERTCOLOR)) return;
2575 if (TrueColorTransPixelCheck(topSel->obj, CMDID_INVERTCOLOR)) return;
2576
2577 DoImageProc((NLFN*)ChangeToInvertColor);
2578 }
2579
2580 /* ----------------------- InterpolateColor ----------------------- */
2581
2582 static XColor gInterpFromColor, gInterpToColor;
2583
2584 static
ChangeToInterpolateColor(nColorIndex,pColor)2585 void ChangeToInterpolateColor(nColorIndex, pColor)
2586 int nColorIndex;
2587 XColor *pColor;
2588 {
2589 struct XPmRec *xpm_ptr=topObj->detail.xpm;
2590
2591 if (DoPpm6(xpm_ptr)) {
2592 int pixel=nColorIndex;
2593 FILE *fp=(FILE*)pColor;
2594 uint32_t pix=(uint32_t)(unsigned int)pixel;
2595 unsigned int r=0, g=0, b=0;
2596 double dr=(double)0, dg=(double)0, db=(double)0;
2597 unsigned char buf[3];
2598 double dgray=(double)0;
2599
2600 r = (pix & gTrueColorInfo.r_mask) >> gTrueColorInfo.r_shift;
2601 g = (pix & gTrueColorInfo.g_mask) >> gTrueColorInfo.g_shift;
2602 b = (pix & gTrueColorInfo.b_mask) >> gTrueColorInfo.b_shift;
2603 dr = ((double)r) / gTrueColorInfo.dr_maxval;
2604 dg = ((double)g) / gTrueColorInfo.dg_maxval;
2605 db = ((double)b) / gTrueColorInfo.db_maxval;
2606
2607 dgray = (0.299*dr) + (0.587*dg) + (0.114*db);
2608
2609 dr = (((double)gInterpFromColor.red) +
2610 dgray * (((double)gInterpToColor.red) -
2611 ((double)gInterpFromColor.red))) / ((double)256);
2612 dg = (((double)gInterpFromColor.green) +
2613 dgray * (((double)gInterpToColor.green) -
2614 ((double)gInterpFromColor.green))) / ((double)256);
2615 db = (((double)gInterpFromColor.blue) +
2616 dgray * (((double)gInterpToColor.blue) -
2617 ((double)gInterpFromColor.blue))) / ((double)256);
2618
2619 r = (dr < ((double)0)) ? 0 : ((unsigned int)dr);
2620 g = (dg < ((double)0)) ? 0 : ((unsigned int)dg);
2621 b = (db < ((double)0)) ? 0 : ((unsigned int)db);
2622 if (r > 255) r = 255;
2623 if (g > 255) g = 255;
2624 if (b > 255) b = 255;
2625 buf[0] = (unsigned char)r;
2626 buf[1] = (unsigned char)g;
2627 buf[2] = (unsigned char)b;
2628 if ((int)fwrite(buf, sizeof(char), 3, fp) <= 0) writeFileFailed = TRUE;
2629 } else {
2630 int red=(int)tgifColors[nColorIndex].red;
2631 int green=(int)tgifColors[nColorIndex].green;
2632 int blue=(int)tgifColors[nColorIndex].blue;
2633 float gray=(0.299*((float)red)+0.587*((float)green)+0.114*((float)blue)) /
2634 (float)(0x0000ffff), tmp_fval;
2635 int val, real_red, real_green, real_blue;
2636
2637 tmp_fval = ((float)gInterpFromColor.red) +
2638 gray*(((float)gInterpToColor.red)-((float)gInterpFromColor.red));
2639 val = round(tmp_fval);
2640 real_red = ((val>0x0ffff) ? 0x0ffff : ((val<0) ? 0 : val));
2641
2642 tmp_fval = ((float)gInterpFromColor.green) +
2643 gray*(((float)gInterpToColor.green)-((float)gInterpFromColor.green));
2644 val = round(tmp_fval);
2645 real_green = ((val>0x0ffff) ? 0x0ffff : ((val<0) ? 0 : val));
2646
2647 tmp_fval = ((float)gInterpFromColor.blue) +
2648 gray*(((float)gInterpToColor.blue)-((float)gInterpFromColor.blue));
2649 val = round(tmp_fval);
2650 real_blue = ((val>0x0ffff) ? 0x0ffff : ((val<0) ? 0 : val));
2651
2652 pColor->red = (unsigned int)real_red;
2653 pColor->green = (unsigned int)real_green;
2654 pColor->blue = (unsigned int)real_blue;
2655 }
2656 }
2657
InterpolateColor()2658 void InterpolateColor()
2659 {
2660 char *c_ptr, szFrom[MAXSTRING+1], szTo[MAXSTRING+1];
2661 char szSpec[MAXSTRING+1], szSpecCopy[MAXSTRING+1];
2662
2663 if (!CheckSelectionForImageProc(CMDID_INTERPOLATECOLOR)) return;
2664 if (TrueColorTransPixelCheck(topSel->obj, CMDID_INTERPOLATECOLOR)) return;
2665
2666 *szSpec = '\0';
2667 Dialog(TgLoadString(STID_ENTER_PAIR_COLORS_INTERPOLATE),
2668 TgLoadCachedString(CSTID_DLG_ACCEPT_CANCEL), szSpec);
2669 UtilTrimBlanks(szSpec);
2670 if (*szSpec == '\0') return;
2671
2672 strcpy(szSpecCopy, szSpec);
2673 *szFrom = *szTo = '\0';
2674 if ((c_ptr=strtok(szSpec, " ,-\t\n\r")) != NULL) {
2675 strcpy(szFrom, c_ptr);
2676 if ((c_ptr=strtok(NULL, " ,-\t\n\r")) != NULL) {
2677 strcpy(szTo, c_ptr);
2678 }
2679 }
2680 if (*szFrom == '\0' || *szTo == '\0') {
2681 sprintf(gszMsgBox, TgLoadString(STID_INVALID_SPEC), szSpecCopy);
2682 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
2683 return;
2684 }
2685 if (!TgifParseColor(szFrom, &gInterpFromColor)) {
2686 sprintf(gszMsgBox, TgLoadString(STID_GIVEN_IS_NOT_A_VALID_COLOR), szFrom);
2687 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
2688 return;
2689 } else if (!TgifParseColor(szTo, &gInterpToColor)) {
2690 sprintf(gszMsgBox, TgLoadString(STID_GIVEN_IS_NOT_A_VALID_COLOR), szTo);
2691 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
2692 return;
2693 }
2694 DoImageProc((NLFN*)ChangeToInterpolateColor);
2695 }
2696
2697 /* ----------------------- Brighten/Darken ----------------------- */
2698
2699 static double gdBrighten=(double)0;
2700 static int gnBrighten=0;
2701
2702 static
ChangeToBrightenDarken(nColorIndex,pColor)2703 void ChangeToBrightenDarken(nColorIndex, pColor)
2704 int nColorIndex;
2705 XColor *pColor;
2706 {
2707 struct XPmRec *xpm_ptr=topObj->detail.xpm;
2708
2709 if (DoPpm6(xpm_ptr)) {
2710 int pixel=nColorIndex;
2711 FILE *fp=(FILE*)pColor;
2712 uint32_t pix=(uint32_t)(unsigned int)pixel;
2713 unsigned int r=0, g=0, b=0;
2714 double dr=(double)0, dg=(double)0, db=(double)0;
2715 unsigned char buf[3];
2716
2717 r = (pix & gTrueColorInfo.r_mask) >> gTrueColorInfo.r_shift;
2718 g = (pix & gTrueColorInfo.g_mask) >> gTrueColorInfo.g_shift;
2719 b = (pix & gTrueColorInfo.b_mask) >> gTrueColorInfo.b_shift;
2720 dr = ((double)r) / gTrueColorInfo.dr_maxval;
2721 dg = ((double)g) / gTrueColorInfo.dg_maxval;
2722 db = ((double)b) / gTrueColorInfo.db_maxval;
2723
2724 dr = (dr + gdBrighten) * ((double)256);
2725 dg = (dg + gdBrighten) * ((double)256);
2726 db = (db + gdBrighten) * ((double)256);
2727
2728 r = (dr < ((double)0)) ? 0 : ((unsigned int)dr);
2729 g = (dg < ((double)0)) ? 0 : ((unsigned int)dg);
2730 b = (db < ((double)0)) ? 0 : ((unsigned int)db);
2731 if (r > 255) r = 255;
2732 if (g > 255) g = 255;
2733 if (b > 255) b = 255;
2734 buf[0] = (unsigned char)r;
2735 buf[1] = (unsigned char)g;
2736 buf[2] = (unsigned char)b;
2737 if ((int)fwrite(buf, sizeof(char), 3, fp) <= 0) writeFileFailed = TRUE;
2738 } else {
2739 int red=((int)tgifColors[nColorIndex].red)+gnBrighten;
2740 int green=((int)tgifColors[nColorIndex].green)+gnBrighten;
2741 int blue=((int)tgifColors[nColorIndex].blue)+gnBrighten;
2742 int real_red, real_green, real_blue;
2743
2744 real_red = ((red>0x0ffff) ? 0x0ffff : ((red<0) ? 0 : red));
2745 real_green = ((green>0x0ffff) ? 0x0ffff : ((green<0) ? 0 : green));
2746 real_blue = ((blue>0x0ffff) ? 0x0ffff : ((blue<0) ? 0 : blue));
2747
2748 pColor->red = (unsigned int)real_red;
2749 pColor->green = (unsigned int)real_green;
2750 pColor->blue = (unsigned int)real_blue;
2751 }
2752 }
2753
BrightenDarken()2754 void BrightenDarken()
2755 {
2756 char *c_ptr, szValue[MAXSTRING+1];
2757 char szSpec[MAXSTRING+1], szSpecCopy[MAXSTRING+1];
2758 float fVal;
2759
2760 if (!CheckSelectionForImageProc(CMDID_BRIGHTENDARKEN)) return;
2761 if (TrueColorTransPixelCheck(topSel->obj, CMDID_BRIGHTENDARKEN)) return;
2762
2763 *szSpec = '\0';
2764 Dialog(TgLoadString(STID_ENTER_VAL_MINUS_PLUS_ONE_BW),
2765 TgLoadCachedString(CSTID_DLG_ACCEPT_CANCEL), szSpec);
2766 UtilTrimBlanks(szSpec);
2767 if (*szSpec == '\0') return;
2768
2769 strcpy(szSpecCopy, szSpec);
2770 if ((c_ptr=strtok(szSpec, " ,\t\n\r")) == NULL) return;
2771 strcpy(szValue, c_ptr);
2772 if (sscanf(szValue, "%f", &fVal) != 1) {
2773 sprintf(gszMsgBox, TgLoadString(STID_FAIL_TO_PARSE_FOR_A_VAL),
2774 szSpecCopy);
2775 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
2776 return;
2777 }
2778 gdBrighten = ((double)fVal);
2779 gnBrighten = (int)round(gdBrighten*((double)0x0000ffff));
2780
2781 DoImageProc((NLFN*)ChangeToBrightenDarken);
2782 }
2783
2784 /* ----------------------- ChangeSaturation ----------------------- */
2785
2786 /*
2787 * 0 65535 spread
2788 * |--------------------r-----| s = -------- * 65535
2789 * |---g----------------------| v
2790 * |-----------b--------------|
2791 * |<---------v-------->| x
2792 * |<----spread---->| h = -------- * 60
2793 * |<--x-->| spread
2794 *
2795 * 0 60 120 180 240 300 360
2796 * |--r--|--g--|--g--|--b--|--b--|--r--|
2797 */
2798
2799 static double gfSaturation=(double)0.0;
2800
RGBtoHSV(r,g,b,h,s,v)2801 void RGBtoHSV(r, g, b, h, s, v)
2802 int r, g, b, *h, *v;
2803 double *s;
2804 /* 0 <= r,g,b <= 0x0ffff */
2805 /* 0 <= *h < 360 */
2806 /* 0 <= *s,*v <= 0x0ffff */
2807 {
2808 int max_val=max(r,max(g,b)), min_val=min(r,min(g,b));
2809 double spread=(double)(max_val-min_val);
2810
2811 *v = max_val;
2812 if (max_val == 0) {
2813 *s = (double)0.0;
2814 } else {
2815 *s = (double)((spread*((double)0x0ffff))/((double)max_val));
2816 }
2817 if (*s < (double)0.0) *s = (double)0.0;
2818 if (*s > INT_TOL) {
2819 int hue=0;
2820
2821 if (r == max_val) {
2822 hue = (int)(((double)(g-b))/spread*((double)60.0));
2823 if (hue < -60) hue = -60;
2824 if (hue < 0) {
2825 hue += 360;
2826 } else if (hue > 60) {
2827 hue = 60;
2828 }
2829 } else if (g == max_val) {
2830 hue = (int)(((double)120.0) + (((double)(b-r))/spread*((double)60.0)));
2831 if (hue < 60) hue = 60;
2832 if (hue > 180) hue = 180;
2833 } else if (b == max_val) {
2834 hue = (int)(((double)240.0) + (((double)(r-g))/spread*((double)60.0)));
2835 if (hue < 180) hue = 180;
2836 if (hue > 300) hue = 300;
2837 }
2838 *h = hue;
2839 } else {
2840 *h = 0;
2841 }
2842 }
2843
2844 #define R_IS_MAX 0
2845 #define G_IS_MAX 1
2846 #define B_IS_MAX 2
2847
HSVtoRGB(h,s,v,r,g,b)2848 void HSVtoRGB(h, s, v, r, g, b)
2849 double s;
2850 int h, v, *r, *g, *b;
2851 /* 0 <= *r,*g,*b <= 0x0ffff */
2852 /* 0 <= h < 360 */
2853 /* 0 <= s,v <= 0x0ffff */
2854 {
2855 if (s <= INT_TOL) {
2856 *r = *g = *b = v;
2857 } else {
2858 double frac, spread;
2859 int which, min_val, mid_val;
2860
2861 if (h >= 300) {
2862 frac = (((double)(360-h))/((double)60.0));
2863 which = R_IS_MAX;
2864 } else if (h >= 240) {
2865 frac = (((double)(h-240))/((double)60.0));
2866 which = B_IS_MAX;
2867 } else if (h >= 180) {
2868 frac = (((double)(240-h))/((double)60.0));
2869 which = B_IS_MAX;
2870 } else if (h >= 120) {
2871 frac = (((double)(h-120))/((double)60.0));
2872 which = G_IS_MAX;
2873 } else if (h >= 60) {
2874 frac = (((double)(120-h))/((double)60.0));
2875 which = G_IS_MAX;
2876 } else {
2877 frac = (((double)h)/((double)60.0));
2878 which = R_IS_MAX;
2879 }
2880 spread = (((double)v)*s/((double)0x0ffff));
2881 min_val = (int)(v-spread);
2882 mid_val = min_val+((int)(frac*spread));
2883
2884 switch (which) {
2885 case R_IS_MAX:
2886 *r = v;
2887 if (h >= 300) {
2888 /* g < b */ *g = min_val; *b = mid_val;
2889 } else {
2890 /* g >= b */ *g = mid_val; *b = min_val;
2891 }
2892 break;
2893 case G_IS_MAX:
2894 *g = v;
2895 if (h >= 120) {
2896 /* b >= r */ *b = mid_val; *r = min_val;
2897 } else {
2898 /* b < r */ *b = min_val; *r = mid_val;
2899 }
2900 break;
2901 case B_IS_MAX:
2902 *b = v;
2903 if (h >= 240) {
2904 /* r >= g */ *r = mid_val; *g = min_val;
2905 } else {
2906 /* r < g */ *r = min_val; *g = mid_val;
2907 }
2908 break;
2909 }
2910 }
2911 }
2912
2913 static
ChangeToChangeSaturation(nColorIndex,pColor)2914 void ChangeToChangeSaturation(nColorIndex, pColor)
2915 int nColorIndex;
2916 XColor *pColor;
2917 {
2918 struct XPmRec *xpm_ptr=topObj->detail.xpm;
2919
2920 if (DoPpm6(xpm_ptr)) {
2921 int pixel=nColorIndex;
2922 FILE *fp=(FILE*)pColor;
2923 uint32_t pix=(uint32_t)(unsigned int)pixel;
2924 unsigned int r=0, g=0, b=0;
2925 double dr=(double)0, dg=(double)0, db=(double)0;
2926 unsigned char buf[3];
2927 int h=0, v=0;
2928 double s=(double)0;
2929
2930 r = (pix & gTrueColorInfo.r_mask) >> gTrueColorInfo.r_shift;
2931 g = (pix & gTrueColorInfo.g_mask) >> gTrueColorInfo.g_shift;
2932 b = (pix & gTrueColorInfo.b_mask) >> gTrueColorInfo.b_shift;
2933 dr = ((double)r) / gTrueColorInfo.dr_maxval;
2934 dg = ((double)g) / gTrueColorInfo.dg_maxval;
2935 db = ((double)b) / gTrueColorInfo.db_maxval;
2936
2937 dr *= ((double)0x10000);
2938 dg *= ((double)0x10000);
2939 db *= ((double)0x10000);
2940
2941 r = (dr < ((double)0)) ? 0 : ((unsigned int)dr);
2942 g = (dg < ((double)0)) ? 0 : ((unsigned int)dg);
2943 b = (db < ((double)0)) ? 0 : ((unsigned int)db);
2944 if (r > 0x0ffff) r = 0x0ffff;
2945 if (g > 0x0ffff) g = 0x0ffff;
2946 if (b > 0x0ffff) b = 0x0ffff;
2947
2948 RGBtoHSV(r, g, b, &h, &s, &v);
2949 s = s * (((double)1.0)+gfSaturation);
2950 if (s > (double)0x0ffff) s = (double)0x0ffff;
2951 if (s < (double)0.0) s = (double)0.0;
2952 HSVtoRGB(h, s, v, (int*)(&r), (int*)(&g), (int*)(&b));
2953
2954
2955 dr = ((double)r) / ((double)256);
2956 dg = ((double)g) / ((double)256);
2957 db = ((double)b) / ((double)256);
2958
2959 r = (dr < ((double)0)) ? 0 : ((unsigned int)dr);
2960 g = (dg < ((double)0)) ? 0 : ((unsigned int)dg);
2961 b = (db < ((double)0)) ? 0 : ((unsigned int)db);
2962 if (r > 255) r = 255;
2963 if (g > 255) g = 255;
2964 if (b > 255) b = 255;
2965 buf[0] = (unsigned char)r;
2966 buf[1] = (unsigned char)g;
2967 buf[2] = (unsigned char)b;
2968 if ((int)fwrite(buf, sizeof(char), 3, fp) <= 0) writeFileFailed = TRUE;
2969 } else {
2970 int red=((int)tgifColors[nColorIndex].red);
2971 int green=((int)tgifColors[nColorIndex].green);
2972 int blue=((int)tgifColors[nColorIndex].blue);
2973 int h, v, real_red, real_green, real_blue;
2974 double s=(double)0;
2975
2976 RGBtoHSV(red, green, blue, &h, &s, &v);
2977 s = s * (((double)1.0)+gfSaturation);
2978 if (s > (double)0x0ffff) s = (double)0x0ffff;
2979 if (s < (double)0.0) s = (double)0.0;
2980 HSVtoRGB(h, s, v, &red, &green, &blue);
2981
2982 real_red = ((red>0x0ffff) ? 0x0ffff : ((red<0) ? 0 : red));
2983 real_green = ((green>0x0ffff) ? 0x0ffff : ((green<0) ? 0 : green));
2984 real_blue = ((blue>0x0ffff) ? 0x0ffff : ((blue<0) ? 0 : blue));
2985
2986 pColor->red = (unsigned int)real_red;
2987 pColor->green = (unsigned int)real_green;
2988 pColor->blue = (unsigned int)real_blue;
2989 }
2990 }
2991
ChangeSaturation()2992 void ChangeSaturation()
2993 {
2994 char *c_ptr, szValue[MAXSTRING+1];
2995 char szSpec[MAXSTRING+1], szSpecCopy[MAXSTRING+1];
2996 float fVal;
2997
2998 if (!CheckSelectionForImageProc(CMDID_CHANGESATURATION)) return;
2999 if (TrueColorTransPixelCheck(topSel->obj, CMDID_CHANGESATURATION)) return;
3000
3001 *szSpec = '\0';
3002 Dialog(TgLoadString(STID_ENTER_VAL_MINUS_PLUS_ONE_SAT),
3003 TgLoadCachedString(CSTID_DLG_ACCEPT_CANCEL), szSpec);
3004 UtilTrimBlanks(szSpec);
3005 if (*szSpec == '\0') return;
3006
3007 strcpy(szSpecCopy, szSpec);
3008 if ((c_ptr=strtok(szSpec, " ,\t\n\r")) == NULL) return;
3009 strcpy(szValue, c_ptr);
3010 if (sscanf(szValue, "%f", &fVal) != 1) {
3011 sprintf(gszMsgBox, TgLoadString(STID_FAIL_TO_PARSE_FOR_A_VAL),
3012 szSpecCopy);
3013 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
3014 return;
3015 }
3016 if (fVal > (float)1.0) fVal = (float)1.0;
3017 if (fVal < (float)(-1.0)) fVal = (float)(-1.0);
3018 gfSaturation = fVal;
3019
3020 DoImageProc((NLFN*)ChangeToChangeSaturation);
3021 }
3022
3023 /* ----------------------- ChangeHue ----------------------- */
3024
3025 static int gnFromHue=0, gnToHue=0;
3026 static float gfFromAngle=(float)0.0, gfToAngle=(float)0.0;
3027 static float gfFromStart=(float)0.0, gfToStart=(float)0.0;
3028 static float gfFromEnd=(float)0.0, gfToEnd=(float)0.0;
3029
3030 static
HueInFromRange(fHue)3031 int HueInFromRange(fHue)
3032 float fHue;
3033 {
3034 if (gfFromStart >= gfFromEnd) {
3035 if (gfFromEnd <= fHue && fHue <= gfFromStart) {
3036 return TRUE;
3037 }
3038 } else {
3039 if (gfFromStart <= fHue && fHue <= gfFromEnd) {
3040 return TRUE;
3041 }
3042 }
3043 return FALSE;
3044 }
3045
3046 static
ChangeToChangeHue(nColorIndex,pColor)3047 void ChangeToChangeHue(nColorIndex, pColor)
3048 int nColorIndex;
3049 XColor *pColor;
3050 {
3051 struct XPmRec *xpm_ptr=topObj->detail.xpm;
3052
3053 if (DoPpm6(xpm_ptr)) {
3054 int pixel=nColorIndex;
3055 FILE *fp=(FILE*)pColor;
3056 uint32_t pix=(uint32_t)(unsigned int)pixel;
3057 unsigned int r=0, g=0, b=0;
3058 double dr=(double)0, dg=(double)0, db=(double)0;
3059 unsigned char buf[3];
3060 int h=0, v=0;
3061 double s=(double)0;
3062
3063 r = (pix & gTrueColorInfo.r_mask) >> gTrueColorInfo.r_shift;
3064 g = (pix & gTrueColorInfo.g_mask) >> gTrueColorInfo.g_shift;
3065 b = (pix & gTrueColorInfo.b_mask) >> gTrueColorInfo.b_shift;
3066 dr = ((double)r) / gTrueColorInfo.dr_maxval;
3067 dg = ((double)g) / gTrueColorInfo.dg_maxval;
3068 db = ((double)b) / gTrueColorInfo.db_maxval;
3069
3070 dr *= ((double)0x10000);
3071 dg *= ((double)0x10000);
3072 db *= ((double)0x10000);
3073
3074 r = (dr < ((double)0)) ? 0 : ((unsigned int)dr);
3075 g = (dg < ((double)0)) ? 0 : ((unsigned int)dg);
3076 b = (db < ((double)0)) ? 0 : ((unsigned int)db);
3077 if (r > 0x0ffff) r = 0x0ffff;
3078 if (g > 0x0ffff) g = 0x0ffff;
3079 if (b > 0x0ffff) b = 0x0ffff;
3080
3081 RGBtoHSV(r, g, b, &h, &s, &v);
3082 if (s > INT_TOL && h > 300) h -= 360;
3083 if (s > INT_TOL && HueInFromRange((double)h)) {
3084 double fFraction=(double)0.0;
3085
3086 if (fabs(gfFromAngle) > INT_TOL) {
3087 fFraction = (((double)h)-gfFromStart)/(gfFromAngle*((double)2.0));
3088 }
3089 h = (int)(fFraction*gfToAngle*((double)2.0) + gfToStart);
3090 while (h >= 360) h -= 360;
3091 while (h < 0) h += 360;
3092 HSVtoRGB(h, s, v, (int*)(&r), (int*)(&g), (int*)(&b));
3093 }
3094 dr = ((double)r) / ((double)256);
3095 dg = ((double)g) / ((double)256);
3096 db = ((double)b) / ((double)256);
3097
3098 r = (dr < ((double)0)) ? 0 : ((unsigned int)dr);
3099 g = (dg < ((double)0)) ? 0 : ((unsigned int)dg);
3100 b = (db < ((double)0)) ? 0 : ((unsigned int)db);
3101 if (r > 255) r = 255;
3102 if (g > 255) g = 255;
3103 if (b > 255) b = 255;
3104 buf[0] = (unsigned char)r;
3105 buf[1] = (unsigned char)g;
3106 buf[2] = (unsigned char)b;
3107 if ((int)fwrite(buf, sizeof(char), 3, fp) <= 0) writeFileFailed = TRUE;
3108 } else {
3109 int red=((int)tgifColors[nColorIndex].red);
3110 int green=((int)tgifColors[nColorIndex].green);
3111 int blue=((int)tgifColors[nColorIndex].blue);
3112 int h, v, real_red, real_green, real_blue;
3113 double s=(double)0;
3114
3115 RGBtoHSV(red, green, blue, &h, &s, &v);
3116 if (s > INT_TOL && h > 300) h -= 360;
3117 if (s > INT_TOL && HueInFromRange((double)h)) {
3118 double fFraction=(double)0.0;
3119
3120 if (fabs(gfFromAngle) > INT_TOL) {
3121 fFraction = (((double)h)-gfFromStart)/(gfFromAngle*((double)2.0));
3122 }
3123 h = (int)(fFraction*gfToAngle*((double)2.0) + gfToStart);
3124 while (h >= 360) h -= 360;
3125 while (h < 0) h += 360;
3126 HSVtoRGB(h, s, v, &red, &green, &blue);
3127
3128 real_red = ((red>0x0ffff) ? 0x0ffff : ((red<0) ? 0 : red));
3129 real_green = ((green>0x0ffff) ? 0x0ffff : ((green<0) ? 0 : green));
3130 real_blue = ((blue>0x0ffff) ? 0x0ffff : ((blue<0) ? 0 : blue));
3131
3132 pColor->red = (unsigned int)real_red;
3133 pColor->green = (unsigned int)real_green;
3134 pColor->blue = (unsigned int)real_blue;
3135 } else {
3136 pColor->red = (unsigned int)red;
3137 pColor->green = (unsigned int)green;
3138 pColor->blue = (unsigned int)blue;
3139 }
3140 }
3141 }
3142
ChangeHue()3143 void ChangeHue()
3144 {
3145 char *szFrom=NULL, *szFromAngle=NULL, *szTo=NULL, *szToAngle=NULL;
3146 char szSpec[MAXSTRING+1], szSpecCopy[MAXSTRING+1], szValue[MAXSTRING+1];
3147 double sVal=(double)0, dVal=(double)0;
3148 int vVal;
3149 XColor xcolor;
3150
3151 if (!CheckSelectionForImageProc(CMDID_CHANGEHUE)) return;
3152 if (TrueColorTransPixelCheck(topSel->obj, CMDID_CHANGEHUE)) return;
3153
3154 *szSpec = '\0';
3155 Dialog(TgLoadString(STID_ENTER_VAL_FOR_CHANGE_HUE), NULL, szSpec);
3156 UtilTrimBlanks(szSpec);
3157 if (*szSpec == '\0') return;
3158
3159 strcpy(szSpecCopy, szSpec);
3160 if ((szFrom=strtok(szSpec, " ,\t\n\r")) == NULL ||
3161 (szFromAngle=strtok(NULL, " ,\t\n\r")) == NULL ||
3162 (szTo=strtok(NULL, " ,\t\n\r")) == NULL ||
3163 (szToAngle=strtok(NULL, " ,\t\n\r")) == NULL) {
3164 sprintf(gszMsgBox, TgLoadString(STID_FAIL_TO_PARSE_FOR_4_VAL),
3165 szSpecCopy);
3166 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
3167 return;
3168 }
3169 if (!TgifParseColor(szFrom, &xcolor)) {
3170 sprintf(gszMsgBox, TgLoadString(STID_GIVEN_IS_NOT_A_VALID_COLOR), szFrom);
3171 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
3172 return;
3173 }
3174 RGBtoHSV(((int)xcolor.red), ((int)xcolor.green), ((int)xcolor.blue),
3175 &gnFromHue, &sVal, &vVal);
3176 if (!TgifParseColor(szTo, &xcolor)) {
3177 sprintf(gszMsgBox, TgLoadString(STID_GIVEN_IS_NOT_A_VALID_COLOR), szTo);
3178 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
3179 return;
3180 }
3181 RGBtoHSV(((int)xcolor.red), ((int)xcolor.green), ((int)xcolor.blue),
3182 &gnToHue, &sVal, &vVal);
3183
3184 strcpy(szValue, szFromAngle);
3185 if (sscanf(szValue, "%lf", &dVal) != 1) {
3186 sprintf(gszMsgBox, TgLoadString(STID_FAIL_TO_PARSE_FOR_A_VAL),
3187 szFromAngle);
3188 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
3189 return;
3190 }
3191 if (dVal > (double)180.0) dVal = (double)180.0;
3192 if (dVal < (double)(-180.0)) dVal = (double)(-180.0);
3193 gfFromAngle = (float)dVal;
3194 gfFromStart = ((double)gnFromHue)-gfFromAngle;
3195 gfFromEnd = ((double)gnFromHue)+gfFromAngle;
3196
3197 strcpy(szValue, szToAngle);
3198 if (sscanf(szValue, "%lf", &dVal) != 1) {
3199 sprintf(gszMsgBox, TgLoadString(STID_FAIL_TO_PARSE_FOR_A_VAL), szToAngle);
3200 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
3201 return;
3202 }
3203 if (dVal > (double)180.0) dVal = (double)180.0;
3204 if (dVal < (double)(-180.0)) dVal = (double)(-180.0);
3205 gfToAngle = (float)dVal;
3206 gfToStart = ((double)gnToHue)-gfToAngle;
3207 gfToEnd = ((double)gnToHue)+gfToAngle;
3208
3209 DoImageProc((NLFN*)ChangeToChangeHue);
3210 }
3211
3212 /* ----------------------- ContrastEnhance ----------------------- */
3213
3214 static float gfContrastFactor=1.0;
3215
3216 static
ChangeToContrastEnhance(nColorIndex,pColor)3217 void ChangeToContrastEnhance(nColorIndex, pColor)
3218 int nColorIndex;
3219 XColor *pColor;
3220 {
3221 struct XPmRec *xpm_ptr=topObj->detail.xpm;
3222
3223 if (DoPpm6(xpm_ptr)) {
3224 int pixel=nColorIndex;
3225 FILE *fp=(FILE*)pColor;
3226 uint32_t pix=(uint32_t)(unsigned int)pixel;
3227 unsigned int r=0, g=0, b=0;
3228 double dr=(double)0, dg=(double)0, db=(double)0;
3229 unsigned char buf[3];
3230
3231 r = (pix & gTrueColorInfo.r_mask) >> gTrueColorInfo.r_shift;
3232 g = (pix & gTrueColorInfo.g_mask) >> gTrueColorInfo.g_shift;
3233 b = (pix & gTrueColorInfo.b_mask) >> gTrueColorInfo.b_shift;
3234 dr = ((double)r) / gTrueColorInfo.dr_maxval;
3235 dg = ((double)g) / gTrueColorInfo.dg_maxval;
3236 db = ((double)b) / gTrueColorInfo.db_maxval;
3237
3238 dr = ((dr-0.5) * ((double)gfContrastFactor) + 0.5) * 256.0;
3239 dg = ((dg-0.5) * ((double)gfContrastFactor) + 0.5) * 256.0;
3240 db = ((db-0.5) * ((double)gfContrastFactor) + 0.5) * 256.0;
3241
3242 r = (dr < ((double)0)) ? 0 : ((unsigned int)dr);
3243 g = (dg < ((double)0)) ? 0 : ((unsigned int)dg);
3244 b = (db < ((double)0)) ? 0 : ((unsigned int)db);
3245 if (r > 255) r = 255;
3246 if (g > 255) g = 255;
3247 if (b > 255) b = 255;
3248 buf[0] = (unsigned char)r;
3249 buf[1] = (unsigned char)g;
3250 buf[2] = (unsigned char)b;
3251 if ((int)fwrite(buf, sizeof(char), 3, fp) <= 0) writeFileFailed = TRUE;
3252 } else {
3253 int red=(int)tgifColors[nColorIndex].red;
3254 int green=(int)tgifColors[nColorIndex].green;
3255 int blue=(int)tgifColors[nColorIndex].blue;
3256 int ival, real_red, real_green, real_blue;
3257 float fval;
3258
3259 fval = ((float)(red-0x8000))*gfContrastFactor + ((float)0x8000);
3260 ival = round(fval);
3261 real_red = ((ival>0x0ffff) ? 0x0ffff : ((ival<0) ? 0 : ival));
3262 fval = ((float)(green-0x8000))*gfContrastFactor + ((float)0x8000);
3263 ival = round(fval);
3264 real_green = ((ival>0x0ffff) ? 0x0ffff : ((ival<0) ? 0 : ival));
3265 fval = ((float)(blue-0x8000))*gfContrastFactor + ((float)0x8000);
3266 ival = round(fval);
3267 real_blue = ((ival>0x0ffff) ? 0x0ffff : ((ival<0) ? 0 : ival));
3268
3269 pColor->red = (unsigned int)real_red;
3270 pColor->green = (unsigned int)real_green;
3271 pColor->blue = (unsigned int)real_blue;
3272 }
3273 }
3274
ContrastEnhance()3275 void ContrastEnhance()
3276 {
3277 char *c_ptr, szValue[MAXSTRING+1];
3278 char szSpec[MAXSTRING+1], szSpecCopy[MAXSTRING+1];
3279 float fVal;
3280
3281 if (!CheckSelectionForImageProc(CMDID_CONTRASTENHANCE)) return;
3282 if (TrueColorTransPixelCheck(topSel->obj, CMDID_CONTRASTENHANCE)) return;
3283
3284 *szSpec = '\0';
3285 Dialog(TgLoadString(STID_ENTER_VAL_FOR_CONTRAST_ENH),
3286 TgLoadCachedString(CSTID_DLG_ACCEPT_CANCEL), szSpec);
3287 UtilTrimBlanks(szSpec);
3288 if (*szSpec == '\0') return;
3289
3290 strcpy(szSpecCopy, szSpec);
3291 if ((c_ptr=strtok(szSpec, " ,\t\n\r")) == NULL) return;
3292 strcpy(szValue, c_ptr);
3293 if (strcmp(szValue, "1.0") == 0 || strcmp(szValue, "1") == 0 ||
3294 strcmp(szValue, "1.") == 0) {
3295 return;
3296 } else if (sscanf(szValue, "%f", &fVal) != 1) {
3297 sprintf(gszMsgBox, TgLoadString(STID_FAIL_TO_PARSE_FOR_A_VAL),
3298 szSpecCopy);
3299 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
3300 return;
3301 } else if (fVal < (float)0.0) {
3302 sprintf(gszMsgBox, TgLoadString(STID_GIVEN_NEG_VAL_NOT_ALLOWED),
3303 szSpecCopy);
3304 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
3305 return;
3306 }
3307 gfContrastFactor = fVal;
3308
3309 DoImageProc((NLFN*)ChangeToContrastEnhance);
3310 }
3311
3312 /* ----------------------- ColorBalance ----------------------- */
3313
3314 static float gfRedBalanceFactor=1.0;
3315 static float gfGreenBalanceFactor=1.0;
3316 static float gfBlueBalanceFactor=1.0;
3317
3318 static
ChangeToColorBalance(nColorIndex,pColor)3319 void ChangeToColorBalance(nColorIndex, pColor)
3320 int nColorIndex;
3321 XColor *pColor;
3322 {
3323 struct XPmRec *xpm_ptr=topObj->detail.xpm;
3324
3325 if (DoPpm6(xpm_ptr)) {
3326 int pixel=nColorIndex;
3327 FILE *fp=(FILE*)pColor;
3328 uint32_t pix=(uint32_t)(unsigned int)pixel;
3329 unsigned int r=0, g=0, b=0;
3330 double dr=(double)0, dg=(double)0, db=(double)0;
3331 unsigned char buf[3];
3332
3333 r = (pix & gTrueColorInfo.r_mask) >> gTrueColorInfo.r_shift;
3334 g = (pix & gTrueColorInfo.g_mask) >> gTrueColorInfo.g_shift;
3335 b = (pix & gTrueColorInfo.b_mask) >> gTrueColorInfo.b_shift;
3336 dr = ((double)r) / gTrueColorInfo.dr_maxval;
3337 dg = ((double)g) / gTrueColorInfo.dg_maxval;
3338 db = ((double)b) / gTrueColorInfo.db_maxval;
3339
3340 dr = dr * gfRedBalanceFactor * ((double)256);
3341 dg = dg * gfGreenBalanceFactor * ((double)256);
3342 db = db * gfBlueBalanceFactor * ((double)256);
3343
3344 r = (dr < ((double)0)) ? 0 : ((unsigned int)dr);
3345 g = (dg < ((double)0)) ? 0 : ((unsigned int)dg);
3346 b = (db < ((double)0)) ? 0 : ((unsigned int)db);
3347 if (r > 255) r = 255;
3348 if (g > 255) g = 255;
3349 if (b > 255) b = 255;
3350 buf[0] = (unsigned char)r;
3351 buf[1] = (unsigned char)g;
3352 buf[2] = (unsigned char)b;
3353 if ((int)fwrite(buf, sizeof(char), 3, fp) <= 0) writeFileFailed = TRUE;
3354 } else {
3355 int red=(int)tgifColors[nColorIndex].red;
3356 int green=(int)tgifColors[nColorIndex].green;
3357 int blue=(int)tgifColors[nColorIndex].blue;
3358 int ival, real_red, real_green, real_blue;
3359 float fval;
3360
3361 fval = ((float)red) * gfRedBalanceFactor;
3362 ival = round(fval);
3363 real_red = ((ival>0x0ffff) ? 0x0ffff : ((ival<0) ? 0 : ival));
3364 fval = ((float)green) * gfGreenBalanceFactor;
3365 ival = round(fval);
3366 real_green = ((ival>0x0ffff) ? 0x0ffff : ((ival<0) ? 0 : ival));
3367 fval = ((float)blue) * gfBlueBalanceFactor;
3368 ival = round(fval);
3369 real_blue = ((ival>0x0ffff) ? 0x0ffff : ((ival<0) ? 0 : ival));
3370
3371 pColor->red = (unsigned int)real_red;
3372 pColor->green = (unsigned int)real_green;
3373 pColor->blue = (unsigned int)real_blue;
3374 }
3375 }
3376
ColorBalance()3377 void ColorBalance()
3378 {
3379 char *c_ptr, szRed[MAXSTRING+1], szGreen[MAXSTRING+1], szBlue[MAXSTRING+1];
3380 char szSpec[MAXSTRING+1], szSpecCopy[MAXSTRING+1];
3381
3382 if (!CheckSelectionForImageProc(CMDID_COLORBALANCE)) return;
3383 if (TrueColorTransPixelCheck(topSel->obj, CMDID_COLORBALANCE)) return;
3384
3385 *szSpec = '\0';
3386 Dialog(TgLoadString(STID_ENTER_VAL_FOR_COLOR_BAL),
3387 TgLoadCachedString(CSTID_DLG_ACCEPT_CANCEL), szSpec);
3388 UtilTrimBlanks(szSpec);
3389 if (*szSpec == '\0') return;
3390
3391 strcpy(szSpecCopy, szSpec);
3392 *szRed = *szGreen = *szBlue = '\0';
3393 if ((c_ptr=strtok(szSpec, " ,\t\n\r")) != NULL) {
3394 strcpy(szRed, c_ptr);
3395 if ((c_ptr=strtok(NULL, " ,\t\n\r")) != NULL) {
3396 strcpy(szGreen, c_ptr);
3397 if ((c_ptr=strtok(NULL, " ,\t\n\r")) != NULL) {
3398 strcpy(szBlue, c_ptr);
3399 }
3400 }
3401 }
3402 if (*szRed == '\0' || *szGreen == '\0' || *szBlue == '\0' ||
3403 sscanf(szRed, "%f", &gfRedBalanceFactor) != 1 ||
3404 sscanf(szGreen, "%f", &gfGreenBalanceFactor) != 1 ||
3405 sscanf(szBlue, "%f", &gfBlueBalanceFactor) != 1) {
3406 sprintf(gszMsgBox, TgLoadString(STID_FAIL_TO_PARSE_FOR_3_VAL),
3407 szSpecCopy);
3408 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
3409 return;
3410 } else if (gfRedBalanceFactor < (float)0.0 ||
3411 gfGreenBalanceFactor < (float)0.0 ||
3412 gfBlueBalanceFactor < (float)0.0) {
3413 sprintf(gszMsgBox, TgLoadString(STID_GIVEN_NEG_VAL_NOT_ALLOWED),
3414 szSpecCopy);
3415 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
3416 return;
3417 }
3418
3419 DoImageProc((NLFN*)ChangeToColorBalance);
3420 }
3421
3422 /* ----------------------- Gamma ----------------------- */
3423
3424 static float gfOneOverGamma=1.0;
3425
3426 static
ChangeToGamma(nColorIndex,pColor)3427 void ChangeToGamma(nColorIndex, pColor)
3428 int nColorIndex;
3429 XColor *pColor;
3430 {
3431 struct XPmRec *xpm_ptr=topObj->detail.xpm;
3432
3433 if (DoPpm6(xpm_ptr)) {
3434 int pixel=nColorIndex;
3435 FILE *fp=(FILE*)pColor;
3436 uint32_t pix=(uint32_t)(unsigned int)pixel;
3437 unsigned int r=0, g=0, b=0;
3438 double dr=(double)0, dg=(double)0, db=(double)0;
3439 unsigned char buf[3];
3440
3441 r = (pix & gTrueColorInfo.r_mask) >> gTrueColorInfo.r_shift;
3442 g = (pix & gTrueColorInfo.g_mask) >> gTrueColorInfo.g_shift;
3443 b = (pix & gTrueColorInfo.b_mask) >> gTrueColorInfo.b_shift;
3444 dr = ((double)r) / gTrueColorInfo.dr_maxval;
3445 dg = ((double)g) / gTrueColorInfo.dg_maxval;
3446 db = ((double)b) / gTrueColorInfo.db_maxval;
3447
3448 dr = pow(dr, (double)gfOneOverGamma) * ((double)256);
3449 dg = pow(dg, (double)gfOneOverGamma) * ((double)256);
3450 db = pow(db, (double)gfOneOverGamma) * ((double)256);
3451
3452 r = (dr < ((double)0)) ? 0 : ((unsigned int)dr);
3453 g = (dg < ((double)0)) ? 0 : ((unsigned int)dg);
3454 b = (db < ((double)0)) ? 0 : ((unsigned int)db);
3455 if (r > 255) r = 255;
3456 if (g > 255) g = 255;
3457 if (b > 255) b = 255;
3458 buf[0] = (unsigned char)r;
3459 buf[1] = (unsigned char)g;
3460 buf[2] = (unsigned char)b;
3461 if ((int)fwrite(buf, sizeof(char), 3, fp) <= 0) writeFileFailed = TRUE;
3462 } else {
3463 double red=((double)tgifColors[nColorIndex].red)/((double)0x0ffff);
3464 double green=((double)tgifColors[nColorIndex].green)/((double)0x0ffff);
3465 double blue=((double)tgifColors[nColorIndex].blue)/((double)0x0ffff);
3466 int ival, real_red, real_green, real_blue;
3467 double dval;
3468
3469 dval = pow(red, (double)gfOneOverGamma) * ((double)0x010000);
3470 ival = round(dval);
3471 real_red = ((ival>0x0ffff) ? 0x0ffff : ((ival<0) ? 0 : ival));
3472 dval = pow(green, (double)gfOneOverGamma) * ((double)0x010000);
3473 ival = round(dval);
3474 real_green = ((ival>0x0ffff) ? 0x0ffff : ((ival<0) ? 0 : ival));
3475 dval = pow(blue, (double)gfOneOverGamma) * ((double)0x010000);
3476 ival = round(dval);
3477 real_blue = ((ival>0x0ffff) ? 0x0ffff : ((ival<0) ? 0 : ival));
3478
3479 pColor->red = (unsigned int)real_red;
3480 pColor->green = (unsigned int)real_green;
3481 pColor->blue = (unsigned int)real_blue;
3482 }
3483 }
3484
Gamma(buf)3485 void Gamma(buf)
3486 char *buf;
3487 {
3488 char *c_ptr, szValue[MAXSTRING+1];
3489 char szSpec[MAXSTRING+1], szSpecCopy[MAXSTRING+1];
3490 float gamma=0.0;
3491
3492 if (!CheckSelectionForImageProc(CMDID_GAMMA)) return;
3493 if (TrueColorTransPixelCheck(topSel->obj, CMDID_GAMMA)) return;
3494
3495 if (buf != NULL) {
3496 strcpy(szSpec, buf);
3497 } else {
3498 *szSpec = '\0';
3499 Dialog(TgLoadString(STID_ENTER_VAL_FOR_GAMMA),
3500 TgLoadCachedString(CSTID_DLG_ACCEPT_CANCEL), szSpec);
3501 }
3502 UtilTrimBlanks(szSpec);
3503 if (*szSpec == '\0') return;
3504
3505 strcpy(szSpecCopy, szSpec);
3506 *szValue = '\0';
3507 if ((c_ptr=strtok(szSpec, " ,\t\n\r")) != NULL) {
3508 strcpy(szValue, c_ptr);
3509 }
3510 if (*szValue == '\0' || sscanf(szValue, "%f", &gamma) != 1) {
3511 sprintf(gszMsgBox, TgLoadString(STID_FAIL_TO_PARSE_FOR_A_VAL),
3512 szSpecCopy);
3513 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
3514 return;
3515 } else if (gamma < (float)INT_TOL) {
3516 sprintf(gszMsgBox, TgLoadString(STID_GIVEN_NEG_VAL_NOT_ALLOWED),
3517 szSpecCopy);
3518 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
3519 return;
3520 }
3521 gfOneOverGamma = (float)1.0 / gamma;
3522
3523 DoImageProc((NLFN*)ChangeToGamma);
3524 }
3525
3526 /* ----------------------- Convolution Required ----------------------- */
3527
3528 /* ----------------------- EdgeDetect ----------------------- */
3529
3530 #ifdef NOT_DEFINED
3531 static
3532 int tx=50, ty=16;
3533 #endif /* NOT_DEFINED */
3534
3535 static
ConvolveToEdgeDetect(x,y)3536 int ConvolveToEdgeDetect(x, y)
3537 int x, y;
3538 /*
3539 * [ -1 0 +1 ] [ -1 -2 -1 ]
3540 * horizontally: [ -2 0 +2 ] vertically: [ 0 0 0 ]
3541 * [ -2 0 +1 ] [ +1 +2 +1 ]
3542 */
3543 {
3544 if (gConvExtraInfo.fp != NULL) {
3545 XColor **xcolors=gConvExtraInfo.xcolors;
3546 FILE *fp=gConvExtraInfo.fp;
3547 int w=gConvExtraInfo.image_w, h=gConvExtraInfo.image_h;
3548 unsigned char buf[3];
3549
3550 if (x == 0 || x == w-1 || y == 0 || y == h-1) {
3551 buf[0] = (unsigned char)xcolors[y][x].red;
3552 buf[1] = (unsigned char)xcolors[y][x].green;
3553 buf[2] = (unsigned char)xcolors[y][x].blue;
3554 } else {
3555 unsigned int r=0, g=0, b=0;
3556 double rx=0, gx=0, bx=0, ry=0, gy=0, by=0;
3557 double ddr, ddg, ddb;
3558
3559 /*
3560 * Thinning is not implemented!
3561 */
3562 rx = (double)(
3563 ((int)xcolors[y][x+1].red) +
3564 ((int)xcolors[y][x+1].red) +
3565 ((int)xcolors[y-1][x+1].red) +
3566 ((int)xcolors[y+1][x+1].red) -
3567 ((int)xcolors[y][x-1].red) -
3568 ((int)xcolors[y][x-1].red) -
3569 ((int)xcolors[y-1][x-1].red) -
3570 ((int)xcolors[y+1][x-1].red));
3571 gx = (double)(
3572 ((int)xcolors[y][x+1].green) +
3573 ((int)xcolors[y][x+1].green) +
3574 ((int)xcolors[y-1][x+1].green) +
3575 ((int)xcolors[y+1][x+1].green) -
3576 ((int)xcolors[y][x-1].green) -
3577 ((int)xcolors[y][x-1].green) -
3578 ((int)xcolors[y-1][x-1].green) -
3579 ((int)xcolors[y+1][x-1].green));
3580 bx = (double)(
3581 ((int)xcolors[y][x+1].blue) +
3582 ((int)xcolors[y][x+1].blue) +
3583 ((int)xcolors[y-1][x+1].blue) +
3584 ((int)xcolors[y+1][x+1].blue) -
3585 ((int)xcolors[y][x-1].blue) -
3586 ((int)xcolors[y][x-1].blue) -
3587 ((int)xcolors[y-1][x-1].blue) -
3588 ((int)xcolors[y+1][x-1].blue));
3589
3590 #ifdef NOT_DEFINED
3591 if (x == tx && y == ty) {
3592 fprintf(stderr, "x = %1d, y = %1d\n", x, y);
3593 fprintf(stderr, "rx = %g, gx = %g, bx = %g\n", rx, gx, bx);
3594 fflush(stderr);
3595 fprintf(stderr, "\n");
3596 }
3597 #endif /* NOT_DEFINED */
3598
3599 ry = (double)(
3600 ((int)xcolors[y+1][x].red) +
3601 ((int)xcolors[y+1][x].red) +
3602 ((int)xcolors[y+1][x-1].red) +
3603 ((int)xcolors[y+1][x+1].red) -
3604 ((int)xcolors[y-1][x].red) -
3605 ((int)xcolors[y-1][x].red) -
3606 ((int)xcolors[y-1][x-1].red) -
3607 ((int)xcolors[y-1][x+1].red));
3608 gy = (double)(
3609 ((int)xcolors[y+1][x].green) +
3610 ((int)xcolors[y+1][x].green) +
3611 ((int)xcolors[y+1][x-1].green) +
3612 ((int)xcolors[y+1][x+1].green) -
3613 ((int)xcolors[y-1][x].green) -
3614 ((int)xcolors[y-1][x].green) -
3615 ((int)xcolors[y-1][x-1].green) -
3616 ((int)xcolors[y-1][x+1].green));
3617 by = (double)(
3618 ((int)xcolors[y+1][x].blue) +
3619 ((int)xcolors[y+1][x].blue) +
3620 ((int)xcolors[y+1][x-1].blue) +
3621 ((int)xcolors[y+1][x+1].blue) -
3622 ((int)xcolors[y-1][x].blue) -
3623 ((int)xcolors[y-1][x].blue) -
3624 ((int)xcolors[y-1][x-1].blue) -
3625 ((int)xcolors[y-1][x+1].blue));
3626
3627 if (rx == 0 && ry == 0 && gx == 0 && gy == 0 && bx == 0 && by == 0) {
3628 buf[0] = (unsigned char)255;
3629 buf[1] = (unsigned char)255;
3630 buf[2] = (unsigned char)255;
3631 } else {
3632 ddr = sqrt(rx*rx + ry*ry);
3633 ddg = sqrt(gx*gx + gy*gy);
3634 ddb = sqrt(bx*bx + by*by);
3635 r = (unsigned int)ddr;
3636 g = (unsigned int)ddg;
3637 b = (unsigned int)ddb;
3638 if (r > 255) r = 255;
3639 if (g > 255) g = 255;
3640 if (b > 255) b = 255;
3641 r = 255 - r;
3642 g = 255 - g;
3643 b = 255 - b;
3644
3645 buf[0] = (unsigned char)r;
3646 buf[1] = (unsigned char)g;
3647 buf[2] = (unsigned char)b;
3648 }
3649 }
3650 if ((int)fwrite(buf, sizeof(char), 3, fp) <= 0) writeFileFailed = TRUE;
3651
3652 return TRUE;
3653 } else {
3654 XColor xcolor;
3655 long red, green, blue;
3656
3657 if (x == 0 || x == gnImageW-1 || y == 0 || y == gnImageH-1) {
3658 return GetOrAllocHistogramIndex(&tgifColors[gnOrigImageIndex[y][x]]);
3659 }
3660 memset(&xcolor, 0, sizeof(XColor));
3661 red = (((((long)tgifColors[gnOrigImageIndex[y][x]].red)<<2) -
3662 ((long)tgifColors[gnOrigImageIndex[y][x-1]].red) -
3663 ((long)tgifColors[gnOrigImageIndex[y][x+1]].red) -
3664 ((long)tgifColors[gnOrigImageIndex[y-1][x]].red) -
3665 ((long)tgifColors[gnOrigImageIndex[y+1][x]].red))>>2);
3666 green = (((((long)tgifColors[gnOrigImageIndex[y][x]].green)<<2) -
3667 ((long)tgifColors[gnOrigImageIndex[y][x-1]].green) -
3668 ((long)tgifColors[gnOrigImageIndex[y][x+1]].green) -
3669 ((long)tgifColors[gnOrigImageIndex[y-1][x]].green) -
3670 ((long)tgifColors[gnOrigImageIndex[y+1][x]].green))>>2);
3671 blue = (((((long)tgifColors[gnOrigImageIndex[y][x]].blue)<<2) -
3672 ((long)tgifColors[gnOrigImageIndex[y][x-1]].blue) -
3673 ((long)tgifColors[gnOrigImageIndex[y][x+1]].blue) -
3674 ((long)tgifColors[gnOrigImageIndex[y-1][x]].blue) -
3675 ((long)tgifColors[gnOrigImageIndex[y+1][x]].blue))>>2);
3676 xcolor.red = (red > 0L ?
3677 (red > 0x0000ffff ? 0x0ffff : (unsigned int)(red&0xffff)) : 0);
3678 xcolor.green = (green > 0L ?
3679 (green > 0x0000ffff ? 0x0ffff : (unsigned int)(green&0xffff)) : 0);
3680 xcolor.blue = (blue > 0L ?
3681 (blue > 0x0000ffff ? 0x0ffff : (unsigned int)(blue&0xffff)) : 0);
3682 return GetOrAllocHistogramIndex(&xcolor);
3683 }
3684 }
3685
EdgeDetect()3686 void EdgeDetect()
3687 {
3688 if (!CheckSelectionForImageProc(CMDID_EDGEDETECT)) {
3689 return;
3690 }
3691 if (topSel->obj->detail.xpm->image_w < 2 ||
3692 topSel->obj->detail.xpm->image_h < 2) {
3693 MsgBox(TgLoadString(STID_SEL_TOO_THIN_FLAT_FOR_EDGE), TOOL_NAME, INFO_MB);
3694 return;
3695 }
3696 gpConvolveFunc = (NLFN*)ConvolveToEdgeDetect;
3697 gpConvolveCmdID = CMDID_EDGEDETECT;
3698 gnConvolving = TRUE;
3699 DoImageProc(NULL);
3700 gnConvolving = FALSE;
3701 gpConvolveFunc = NULL;
3702 gpConvolveCmdID = (-1);
3703 }
3704
3705 /* ----------------------- Emboss ----------------------- */
3706
3707 static
ConvolveToEmboss(x,y)3708 int ConvolveToEmboss(x, y)
3709 int x, y;
3710 {
3711 if (gConvExtraInfo.fp != NULL) {
3712 XColor **xcolors=gConvExtraInfo.xcolors;
3713 FILE *fp=gConvExtraInfo.fp;
3714 int w=gConvExtraInfo.image_w, h=gConvExtraInfo.image_h;
3715 unsigned char buf[3];
3716
3717 if (x == 0 || x == w-1 || y == 0 || y == h-1) {
3718 double dgray=(double)0;
3719 int gray=0;
3720
3721 dgray = 0.299*((double)xcolors[y][x].red) +
3722 0.587*((double)xcolors[y][x].green) +
3723 0.144*((double)xcolors[y][x].blue);
3724 gray = (int)round(dgray);
3725 if (gray < 0) gray = 0;
3726 if (gray > 255) gray = 255;
3727 buf[0] = buf[1] = buf[2] = (unsigned char)(unsigned int)gray;
3728 } else {
3729 double d_lt_gray=(double)0, d_rb_gray=(double)0, dgray=(double)0;
3730 int gray=0;
3731
3732 d_lt_gray = 0.299*((double)xcolors[y-1][x-1].red) +
3733 0.587*((double)xcolors[y-1][x-1].green) +
3734 0.144*((double)xcolors[y-1][x-1].blue);
3735 d_rb_gray = 0.299*((double)xcolors[y+1][x+1].red) +
3736 0.587*((double)xcolors[y+1][x+1].green) +
3737 0.144*((double)xcolors[y+1][x+1].blue);
3738 dgray = 128.0 + ((d_rb_gray - d_lt_gray) / 2.0);
3739 gray = (int)round(dgray);
3740 if (gray < 0) gray = 0;
3741 if (gray > 255) gray = 255;
3742 buf[0] = buf[1] = buf[2] = (unsigned char)(unsigned int)gray;
3743 }
3744 if ((int)fwrite(buf, sizeof(char), 3, fp) <= 0) writeFileFailed = TRUE;
3745
3746 return TRUE;
3747 } else {
3748 XColor xcolor;
3749
3750 memset(&xcolor, 0, sizeof(XColor));
3751 if (x == 0 || x == gnImageW-1 || y == 0 || y == gnImageH-1) {
3752 float gray=0.299*((float)tgifColors[gnOrigImageIndex[y][x]].red) +
3753 0.587*((float)tgifColors[gnOrigImageIndex[y][x]].green) +
3754 0.144*((float)tgifColors[gnOrigImageIndex[y][x]].blue);
3755
3756 xcolor.red = xcolor.green = xcolor.blue = (unsigned short)gray;
3757 return GetOrAllocHistogramIndex(&xcolor);
3758 } else {
3759 float lt_gray, rb_gray;
3760 int val;
3761
3762 lt_gray=0.299*((float)tgifColors[gnOrigImageIndex[y-1][x-1]].red) +
3763 0.587*((float)tgifColors[gnOrigImageIndex[y-1][x-1]].green) +
3764 0.144*((float)tgifColors[gnOrigImageIndex[y-1][x-1]].blue);
3765 rb_gray=0.299*((float)tgifColors[gnOrigImageIndex[y+1][x+1]].red) +
3766 0.587*((float)tgifColors[gnOrigImageIndex[y+1][x+1]].green) +
3767 0.144*((float)tgifColors[gnOrigImageIndex[y+1][x+1]].blue);
3768 val = 0x7fff +
3769 (int)((rb_gray - lt_gray) / 2.0);
3770 val = ((val>0x0ffff) ? 0x0ffff : ((val<0) ? 0 : val));
3771 xcolor.red = xcolor.green = xcolor.blue = (unsigned short)val;
3772 return GetOrAllocHistogramIndex(&xcolor);
3773 }
3774 }
3775 }
3776
Emboss()3777 void Emboss()
3778 {
3779 if (!CheckSelectionForImageProc(CMDID_EMBOSS)) return;
3780
3781 if (topSel->obj->detail.xpm->image_w < 2 ||
3782 topSel->obj->detail.xpm->image_h < 2) {
3783 MsgBox(TgLoadString(STID_SEL_TOO_THIN_FLAT_FOR_EMBOSS), TOOL_NAME,
3784 INFO_MB);
3785 return;
3786 }
3787 gpConvolveFunc = (NLFN*)ConvolveToEmboss;
3788 gpConvolveCmdID = CMDID_EMBOSS;
3789 gnConvolving = TRUE;
3790 DoImageProc(NULL);
3791 gnConvolving = FALSE;
3792 gpConvolveFunc = NULL;
3793 gpConvolveCmdID = (-1);
3794 }
3795
3796 /* ----------------------- ReduceColors ----------------------- */
3797
3798 static
ConvolveToReduceColors(x,y)3799 int ConvolveToReduceColors(x, y)
3800 int x, y;
3801 {
3802 return GetOrAllocHistogramIndex(&tgifColors[gnOrigImageIndex[y][x]]);
3803 }
3804
ReduceColors()3805 void ReduceColors()
3806 {
3807 char *c_ptr, szSpec[MAXSTRING+1], szSpecCopy[MAXSTRING+1];
3808 int colors_to_reduce_to=0;
3809 struct XPmRec *xpm_ptr=NULL;
3810
3811 if (!CheckSelectionForImageProc(CMDID_REDUCECOLORS)) {
3812 return;
3813 }
3814 sprintf(gszMsgBox, TgLoadString(STID_ENTER_NUM_COLORS_TO_REDUCE_TO),
3815 topSel->obj->detail.xpm->ncolors);
3816 *szSpec = '\0';
3817 Dialog(gszMsgBox, TgLoadCachedString(CSTID_DLG_ACCEPT_CANCEL), szSpec);
3818 UtilTrimBlanks(szSpec);
3819 if (*szSpec == '\0') return;
3820
3821 xpm_ptr = topSel->obj->detail.xpm;
3822 strcpy(szSpecCopy, szSpec);
3823 if ((c_ptr=strtok(szSpec, " ,\t\n\r")) == NULL) return;
3824 colors_to_reduce_to = atoi(c_ptr);
3825 if (DoPpm6(xpm_ptr)) {
3826 if (colors_to_reduce_to < 2 ||
3827 colors_to_reduce_to > 256) {
3828 sprintf(gszMsgBox, TgLoadString(STID_NUM_COLORS_BETWEEN_2_N_GIVEN),
3829 szSpecCopy, 256);
3830 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
3831 return;
3832 }
3833 } else {
3834 if (colors_to_reduce_to < 2 ||
3835 colors_to_reduce_to > topSel->obj->detail.xpm->ncolors) {
3836 sprintf(gszMsgBox, TgLoadString(STID_NUM_COLORS_BETWEEN_2_N_GIVEN),
3837 szSpecCopy, topSel->obj->detail.xpm->ncolors);
3838 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
3839 return;
3840 }
3841 }
3842 gnUserSpecifiedLevels = colors_to_reduce_to;
3843 gpConvolveFunc = (NLFN*)ConvolveToReduceColors;
3844 gpConvolveCmdID = CMDID_REDUCECOLORS;
3845 gnConvolving = TRUE;
3846 DoImageProc(NULL);
3847 gnConvolving = FALSE;
3848 gpConvolveFunc = NULL;
3849 gpConvolveCmdID = (-1);
3850 gnUserSpecifiedLevels = (-1);
3851 }
3852
3853 /* ----------------------- ReduceToPixmapColors ----------------------- */
3854
3855 static struct XPmRec gXPmTarget;
3856 static XColor *gTargetColors=NULL;
3857 static int *gTargetColorValid=NULL;
3858 static int *gnObjectColorsToTargetColorMapping=NULL;
3859 static int *gnTgifColorsToObjectColorMapping=NULL;
3860
3861 static int gnFloyd=FALSE;
3862 static int **gnImageTargetColor=NULL;
3863 static XImage *gpTargetImage=NULL, *gpTargetBitmapImage=NULL;
3864
3865 static
FreeTargetColors(ncolors)3866 void FreeTargetColors(ncolors)
3867 int ncolors;
3868 {
3869 if (gTargetColors != NULL) {
3870 free(gTargetColors);
3871 gTargetColors = NULL;
3872 }
3873 if (gTargetColorValid != NULL) {
3874 free(gTargetColorValid);
3875 gTargetColorValid = NULL;
3876 }
3877 }
3878
3879 static
AllocTargetColors(ncolors)3880 int AllocTargetColors(ncolors)
3881 int ncolors;
3882 {
3883 int i=0;
3884
3885 gTargetColors = (XColor*)malloc(ncolors*sizeof(XColor));
3886 if (gTargetColors == NULL) FailAllocMessage();
3887 memset(gTargetColors, 0, ncolors*sizeof(XColor));
3888
3889 gTargetColorValid = (int*)malloc(ncolors*sizeof(int));
3890 if (gTargetColorValid == NULL) FailAllocMessage();
3891 for (i=0; i < ncolors; i++) {
3892 gTargetColorValid[i] = TRUE;
3893 }
3894 return TRUE;
3895 }
3896
3897 static
GetClosestColorIndex(red_bits,green_bits,blue_bits,red,green,blue,target_ncolors)3898 int GetClosestColorIndex(red_bits, green_bits, blue_bits, red, green, blue,
3899 target_ncolors)
3900 int red_bits, green_bits, blue_bits, red, green, blue, target_ncolors;
3901 {
3902 int min_index=0;
3903 unsigned long dr=(double)0, dg=(double)0, db=(double)0, min_dist=(double)0;
3904
3905 if (gXPmTarget.color_str != NULL ||
3906 gXPmTarget.userdata == (void*)CMDID_REDUCETOMOBILEWEBCOLORS) {
3907 /* ReduceToPixmapColors() or ReduceToMobileWebSafeColors() */
3908 int j=0;
3909
3910 for (j=0; j < target_ncolors; j++) {
3911 if (gTargetColorValid[j]) {
3912 dr = (unsigned long)abs(red-(int)(gTargetColors[j].red));
3913 dg = (unsigned long)abs(green-(int)(gTargetColors[j].green));
3914 db = (unsigned long)abs(blue-(int)(gTargetColors[j].blue));
3915 dr >>= 4; dg >>= 4; db >>= 4;
3916 break;
3917 }
3918 }
3919 min_index = j;
3920 min_dist = dr*dr + dg*dg + db*db;
3921 for (j++; j < target_ncolors; j++) {
3922 if (gTargetColorValid[j]) {
3923 unsigned long new_dist;
3924
3925 dr = (unsigned long)abs(red-(int)(gTargetColors[j].red));
3926 dg = (unsigned long)abs(green-(int)(gTargetColors[j].green));
3927 db = (unsigned long)abs(blue-(int)(gTargetColors[j].blue));
3928 dr >>= 4; dg >>= 4; db >>= 4;
3929 new_dist = dr*dr + dg*dg + db*db;
3930
3931 if (new_dist < min_dist) {
3932 min_index = j;
3933 min_dist = new_dist;
3934 }
3935 }
3936 }
3937 } else if (gXPmTarget.userdata == (void*)CMDID_REDUCETOMOBILEWEBCOLORS) {
3938 /* ReduceToDefaultColors() or DefaultErrorDiffuse() */
3939 int k, j, i;
3940 int red_max=(1<<red_bits);
3941 int green_max=(1<<green_bits);
3942 int blue_max=(1<<blue_bits);
3943 int red_index=(red >> (16-red_bits));
3944 int green_index=(green >> (16-green_bits));
3945 int blue_index=(blue >> (16-blue_bits));
3946
3947 min_index = 0;
3948 dr = (unsigned long)abs(red-(int)(gTargetColors[min_index].red));
3949 dg = (unsigned long)abs(green-(int)(gTargetColors[min_index].green));
3950 db = (unsigned long)abs(blue-(int)(gTargetColors[min_index].blue));
3951 dr >>= 4; dg >>= 4; db >>= 4;
3952
3953 min_dist = dr*dr + dg*dg + db*db;
3954 for (i=red_index-1; i <= red_index+1; i++) {
3955 if (i >= 0 && i < red_max) {
3956 for (j=green_index-1; j <= green_index+1; j++) {
3957 if (j >= 0 && j < green_max) {
3958 for (k=blue_index-1; k <= blue_index+1; k++) {
3959 if (k >= 0 && k < blue_max) {
3960 if (i!=red_index || j!=green_index || k!=blue_index) {
3961 int index=(((i << green_bits) + j) << blue_bits) + k;
3962 unsigned long new_dist;
3963
3964 dr = (unsigned long)abs(red -
3965 (int)(gTargetColors[index].red));
3966 dg = (unsigned long)abs(green -
3967 (int)(gTargetColors[index].green));
3968 db = (unsigned long)abs(blue -
3969 (int)(gTargetColors[index].blue));
3970 dr >>= 4; dg >>= 4; db >>= 4;
3971 new_dist = dr*dr + dg*dg + db*db;
3972 if (new_dist < min_dist) {
3973 min_index = index;
3974 min_dist = new_dist;
3975 }
3976 }
3977 }
3978 }
3979 }
3980 }
3981 }
3982 }
3983 } else {
3984 /* ReduceToDefaultColors() or DefaultErrorDiffuse() */
3985 int k, j, i;
3986 int red_max=(1<<red_bits);
3987 int green_max=(1<<green_bits);
3988 int blue_max=(1<<blue_bits);
3989 int red_index=(red >> (16-red_bits));
3990 int green_index=(green >> (16-green_bits));
3991 int blue_index=(blue >> (16-blue_bits));
3992
3993 min_index = (((red_index << green_bits) + green_index) << blue_bits) +
3994 blue_index;
3995 dr = (unsigned long)abs(red-(int)(gTargetColors[min_index].red));
3996 dg = (unsigned long)abs(green-(int)(gTargetColors[min_index].green));
3997 db = (unsigned long)abs(blue-(int)(gTargetColors[min_index].blue));
3998 dr >>= 4; dg >>= 4; db >>= 4;
3999
4000 min_dist = dr*dr + dg*dg + db*db;
4001 for (i=red_index-1; i <= red_index+1; i++) {
4002 if (i >= 0 && i < red_max) {
4003 for (j=green_index-1; j <= green_index+1; j++) {
4004 if (j >= 0 && j < green_max) {
4005 for (k=blue_index-1; k <= blue_index+1; k++) {
4006 if (k >= 0 && k < blue_max) {
4007 if (i!=red_index || j!=green_index || k!=blue_index) {
4008 int index=(((i << green_bits) + j) << blue_bits) + k;
4009 unsigned long new_dist;
4010
4011 dr = (unsigned long)abs(red -
4012 (int)(gTargetColors[index].red));
4013 dg = (unsigned long)abs(green -
4014 (int)(gTargetColors[index].green));
4015 db = (unsigned long)abs(blue -
4016 (int)(gTargetColors[index].blue));
4017 dr >>= 4; dg >>= 4; db >>= 4;
4018 new_dist = dr*dr + dg*dg + db*db;
4019 if (new_dist < min_dist) {
4020 min_index = index;
4021 min_dist = new_dist;
4022 }
4023 }
4024 }
4025 }
4026 }
4027 }
4028 }
4029 }
4030 }
4031 return min_index;
4032 }
4033 static
ConvolveToErrorDiffuse(x,y)4034 int ConvolveToErrorDiffuse(x, y)
4035 int x, y;
4036 {
4037 int targetcolor_index=gnImageTargetColor[y][x];
4038
4039 if (gConvExtraInfo.fp != NULL) {
4040 FILE *fp=gConvExtraInfo.fp;
4041 double dr=(double)0, dg=(double)0, db=(double)0;
4042 unsigned char buf[3];
4043 unsigned int r=(unsigned int)(gTargetColors[targetcolor_index].red);
4044 unsigned int g=(unsigned int)(gTargetColors[targetcolor_index].green);
4045 unsigned int b=(unsigned int)(gTargetColors[targetcolor_index].blue);
4046
4047 dr = ((double)r) / maxRGB * ((double)255);
4048 dg = ((double)g) / maxRGB * ((double)255);
4049 db = ((double)b) / maxRGB * ((double)255);
4050 r = (dr < ((double)0)) ? 0 : ((unsigned int)dr);
4051 g = (dg < ((double)0)) ? 0 : ((unsigned int)dg);
4052 b = (db < ((double)0)) ? 0 : ((unsigned int)db);
4053 if (r > 255) r = 255;
4054 if (g > 255) g = 255;
4055 if (b > 255) b = 255;
4056 buf[0] = (unsigned char)r;
4057 buf[1] = (unsigned char)g;
4058 buf[2] = (unsigned char)b;
4059 if ((int)fwrite(buf, sizeof(char), 3, fp) <= 0) writeFileFailed = TRUE;
4060
4061 return TRUE;
4062 } else {
4063 return GetOrAllocHistogramIndex(&gTargetColors[targetcolor_index]);
4064 }
4065 }
4066
4067 static
ConvolveToReduceToPixmapColors(x,y)4068 int ConvolveToReduceToPixmapColors(x, y)
4069 int x, y;
4070 {
4071 if (gConvExtraInfo.fp != NULL) {
4072 int index=0, pixel=XGetPixel(gConvExtraInfo.image,x,y);
4073 FILE *fp=gConvExtraInfo.fp;
4074 uint32_t pix=(uint32_t)(unsigned int)pixel;
4075 unsigned int r=0, g=0, b=0;
4076 double dr=(double)0, dg=(double)0, db=(double)0;
4077 unsigned char buf[3];
4078
4079 r = (pix & gTrueColorInfo.r_mask) >> gTrueColorInfo.r_shift;
4080 g = (pix & gTrueColorInfo.g_mask) >> gTrueColorInfo.g_shift;
4081 b = (pix & gTrueColorInfo.b_mask) >> gTrueColorInfo.b_shift;
4082 dr = ((double)r) / gTrueColorInfo.dr_maxval * ((double)maxRGB);
4083 dg = ((double)g) / gTrueColorInfo.dg_maxval * ((double)maxRGB);
4084 db = ((double)b) / gTrueColorInfo.db_maxval * ((double)maxRGB);
4085
4086 r = (dr < ((double)0)) ? 0 : ((unsigned int)dr);
4087 g = (dg < ((double)0)) ? 0 : ((unsigned int)dg);
4088 b = (db < ((double)0)) ? 0 : ((unsigned int)db);
4089 if (r > maxRGB) r = maxRGB;
4090 if (g > maxRGB) g = maxRGB;
4091 if (b > maxRGB) b = maxRGB;
4092
4093 index = GetClosestColorIndex(gDefErrorDiffuseLevel.red,
4094 gDefErrorDiffuseLevel.green, gDefErrorDiffuseLevel.blue,
4095 (int)r, (int)g, (int)b, gnUserSpecifiedLevels);
4096
4097 r = (unsigned int)(gTargetColors[index].red);
4098 g = (unsigned int)(gTargetColors[index].green);
4099 b = (unsigned int)(gTargetColors[index].blue);
4100
4101 dr = ((double)r) / maxRGB * ((double)255);
4102 dg = ((double)g) / maxRGB * ((double)255);
4103 db = ((double)b) / maxRGB * ((double)255);
4104 r = (dr < ((double)0)) ? 0 : ((unsigned int)dr);
4105 g = (dg < ((double)0)) ? 0 : ((unsigned int)dg);
4106 b = (db < ((double)0)) ? 0 : ((unsigned int)db);
4107 if (r > 255) r = 255;
4108 if (g > 255) g = 255;
4109 if (b > 255) b = 255;
4110 buf[0] = (unsigned char)r;
4111 buf[1] = (unsigned char)g;
4112 buf[2] = (unsigned char)b;
4113 if ((int)fwrite(buf, sizeof(char), 3, fp) <= 0) writeFileFailed = TRUE;
4114
4115 return TRUE;
4116 } else {
4117 int tgifcolor_index=gnOrigImageIndex[y][x]; /* index into tgifColors */
4118 int objcolor_index=gnTgifColorsToObjectColorMapping[tgifcolor_index];
4119 int targetcolor_index=gnObjectColorsToTargetColorMapping[objcolor_index];
4120
4121 return GetOrAllocHistogramIndex(&gTargetColors[targetcolor_index]);
4122 }
4123 }
4124
4125 static
GetIntensity(index,max_levels)4126 int GetIntensity(index, max_levels)
4127 int index, max_levels; /* 0 < max_levels <= 255 */
4128 /*
4129 * May be it should be like the following:
4130 *
4131 * int ival=(int)(((double)index)/((double)max_levels)*((double)maxRGB));
4132 *
4133 * return (ival < 0 ? 0 : (ival > maxRGB ? maxRGB : ival));
4134 */
4135 {
4136 int ival=(int)(((double)index)/((double)max_levels)*((double)255));
4137
4138 return ((ival < 0 ? 0 : (ival > 0xff ? 0xff : ival))<<8);
4139 }
4140
4141 #define FS_SCALE 0x400
4142 #define HALF_FS_SCALE 0x200
4143
4144 static
DoPrepareForErrorDiffuse(xpm_ptr)4145 int DoPrepareForErrorDiffuse(xpm_ptr)
4146 struct XPmRec *xpm_ptr;
4147 {
4148 int j, i, target_ncolors=gXPmTarget.ncolors, fs_forward=TRUE;
4149 int image_w=xpm_ptr->image_w, image_h=xpm_ptr->image_h;
4150 int red_bits=0, green_bits=0, blue_bits=0;
4151 long *this_r_err, *this_g_err, *this_b_err, *tmp_err;
4152 long *next_r_err, *next_g_err, *next_b_err;
4153 ProgressInfo pi;
4154
4155 if (!CreatePixelToIndexMapping()) return FALSE;
4156 if (gXPmTarget.color_str != NULL) {
4157 for (i=0; i < target_ncolors; i++) {
4158 if (!TgifParseColor(gXPmTarget.color_str[i], &gTargetColors[i])) {
4159 gTargetColorValid[i] = FALSE;
4160 }
4161 }
4162 } else {
4163 red_bits = gDefErrorDiffuseLevel.red;
4164 green_bits = gDefErrorDiffuseLevel.green;
4165 blue_bits = gDefErrorDiffuseLevel.blue;
4166 }
4167 if (!GetXPmImages(xpm_ptr, &gpTargetImage, &gpTargetBitmapImage)) {
4168 return FALSE;
4169 }
4170 gnImageTargetColor = (int**)malloc(image_h*sizeof(int*));
4171 if (gnImageTargetColor == NULL) return FailAllocMessage();
4172 for (i=0; i < image_h; i++) {
4173 if ((gnImageTargetColor[i]=(int*)malloc(image_w*sizeof(int))) == NULL) {
4174 for (j=0; j < i; j++) free(gnImageTargetColor[j]);
4175 free(gnImageTargetColor);
4176 gnImageTargetColor = NULL;
4177 return FailAllocMessage();
4178 }
4179 }
4180 this_r_err = (long*)malloc((image_w+2)*sizeof(long));
4181 this_g_err = (long*)malloc((image_w+2)*sizeof(long));
4182 this_b_err = (long*)malloc((image_w+2)*sizeof(long));
4183 next_r_err = (long*)malloc((image_w+2)*sizeof(long));
4184 next_g_err = (long*)malloc((image_w+2)*sizeof(long));
4185 next_b_err = (long*)malloc((image_w+2)*sizeof(long));
4186 if (this_r_err==NULL || this_g_err==NULL || this_b_err==NULL ||
4187 next_r_err==NULL || next_g_err==NULL || next_b_err==NULL) {
4188 if (this_r_err != NULL) free(this_r_err);
4189 if (this_g_err != NULL) free(this_g_err);
4190 if (this_b_err != NULL) free(this_b_err);
4191 if (next_r_err != NULL) free(next_r_err);
4192 if (next_g_err != NULL) free(next_g_err);
4193 if (next_b_err != NULL) free(next_b_err);
4194 return FALSE;
4195 }
4196 srand(0);
4197 for (j=0; j < image_w+2; j++) {
4198 this_r_err[j] = (rand() % FS_SCALE - HALF_FS_SCALE) << 4;
4199 this_g_err[j] = (rand() % FS_SCALE - HALF_FS_SCALE) << 4;
4200 this_b_err[j] = (rand() % FS_SCALE - HALF_FS_SCALE) << 4;
4201 }
4202
4203 BeginProgress(&pi, image_h);
4204 for (i=0; i < image_h; i++) {
4205 int col, limitcol;
4206
4207 UpdateProgress(&pi, i);
4208 /*--------------------------------------------------------*/
4209 /* the error diffusion code is adapted from 'ppmquant.c', */
4210 /* which is part of the netpbm package. */
4211 /* */
4212 /* Copyright (C) 1989, 1991 by Jef Poskanzer */
4213 /*--------------------------------------------------------*/
4214 col = (fs_forward ? 0 : image_w-1);
4215 limitcol = (fs_forward ? image_w : (-1));
4216 for (j=0; j < image_w+2; j++) {
4217 next_r_err[j] = next_g_err[j] = next_b_err[j] = 0L;
4218 }
4219 do {
4220 int red, green, blue, err, min_index=0;
4221 int pixel=XGetPixel(gpTargetImage, col, i);
4222
4223 if (DoPpm6(xpm_ptr)) {
4224 uint32_t pix=(uint32_t)(unsigned int)pixel;
4225 unsigned int r=0, g=0, b=0;
4226 double dr=(double)0, dg=(double)0, db=(double)0;
4227
4228 r = (pix & gTrueColorInfo.r_mask) >> gTrueColorInfo.r_shift;
4229 g = (pix & gTrueColorInfo.g_mask) >> gTrueColorInfo.g_shift;
4230 b = (pix & gTrueColorInfo.b_mask) >> gTrueColorInfo.b_shift;
4231 dr = ((double)r) / gTrueColorInfo.dr_maxval * ((double)65535);
4232 dg = ((double)g) / gTrueColorInfo.dg_maxval * ((double)65535);
4233 db = ((double)b) / gTrueColorInfo.db_maxval * ((double)65535);
4234
4235 r = (dr < ((double)0)) ? 0 : ((unsigned int)dr);
4236 g = (dg < ((double)0)) ? 0 : ((unsigned int)dg);
4237 b = (db < ((double)0)) ? 0 : ((unsigned int)db);
4238 if (r > 65535) r = 65535;
4239 if (g > 65535) g = 65535;
4240 if (b > 65535) b = 65535;
4241
4242 red = (int)(r) + this_r_err[col+1];
4243 green = (int)(g) + this_g_err[col+1];
4244 blue = (int)(b) + this_b_err[col+1];
4245 if (red < 0) red = 0; if (red > 65535) red = 65535;
4246 if (green < 0) green = 0; if (green > 65535) green = 65535;
4247 if (blue < 0) blue = 0; if (blue > 65535) blue = 65535;
4248
4249 min_index = GetClosestColorIndex(gDefErrorDiffuseLevel.red,
4250 gDefErrorDiffuseLevel.green, gDefErrorDiffuseLevel.blue,
4251 (int)red, (int)green, (int)blue, target_ncolors);
4252 } else {
4253 int index=GetIndexOfPixel(pixel);
4254
4255 red = (int)(tgifColors[index].red) + this_r_err[col+1];
4256 green = (int)(tgifColors[index].green) + this_g_err[col+1];
4257 blue = (int)(tgifColors[index].blue) + this_b_err[col+1];
4258 if (red < 0) red = 0; if (red > 65535) red = 65535;
4259 if (green < 0) green = 0; if (green > 65535) green = 65535;
4260 if (blue < 0) blue = 0; if (blue > 65535) blue = 65535;
4261
4262 min_index = GetClosestColorIndex(red_bits, green_bits, blue_bits,
4263 red, green, blue, target_ncolors);
4264 }
4265 gnImageTargetColor[i][col] = min_index;
4266 if (fs_forward) {
4267 err = (red - gTargetColors[min_index].red); /* * FS_SCALE; */
4268 this_r_err[col+2] += (err*7) >> 4;
4269 next_r_err[col ] += (err*3) >> 4;
4270 next_r_err[col+1] += (err*5) >> 4;
4271 next_r_err[col+2] += (err ) >> 4;
4272 err = (green - gTargetColors[min_index].green); /* * FS_SCALE; */
4273 this_g_err[col+2] += (err*7) >> 4;
4274 next_g_err[col ] += (err*3) >> 4;
4275 next_g_err[col+1] += (err*5) >> 4;
4276 next_g_err[col+2] += (err ) >> 4;
4277 err = (blue - gTargetColors[min_index].blue); /* * FS_SCALE; */
4278 this_b_err[col+2] += (err*7) >> 4;
4279 next_b_err[col ] += (err*3) >> 4;
4280 next_b_err[col+1] += (err*5) >> 4;
4281 next_b_err[col+2] += (err ) >> 4;
4282
4283 col++;
4284 } else {
4285 err = (red - gTargetColors[min_index].red); /* * FS_SCALE; */
4286 this_r_err[col ] += (err*7) >> 4;
4287 next_r_err[col+2] += (err*3) >> 4;
4288 next_r_err[col+1] += (err*5) >> 4;
4289 next_r_err[col ] += (err ) >> 4;
4290 err = (green - gTargetColors[min_index].green); /* * FS_SCALE; */
4291 this_g_err[col ] += (err*7) >> 4;
4292 next_g_err[col+2] += (err*3) >> 4;
4293 next_g_err[col+1] += (err*5) >> 4;
4294 next_g_err[col ] += (err ) >> 4;
4295 err = (blue - gTargetColors[min_index].blue); /* * FS_SCALE; */
4296 this_b_err[col ] += (err*7) >> 4;
4297 next_b_err[col+2] += (err*3) >> 4;
4298 next_b_err[col+1] += (err*5) >> 4;
4299 next_b_err[col ] += (err ) >> 4;
4300
4301 col--;
4302 }
4303 } while (col != limitcol);
4304 tmp_err = this_r_err; this_r_err = next_r_err; next_r_err = tmp_err;
4305 tmp_err = this_g_err; this_g_err = next_g_err; next_g_err = tmp_err;
4306 tmp_err = this_b_err; this_b_err = next_b_err; next_b_err = tmp_err;
4307 fs_forward = !fs_forward;
4308 }
4309 free(this_r_err); free(this_g_err); free(this_b_err);
4310 free(next_r_err); free(next_g_err); free(next_b_err);
4311
4312 return TRUE;
4313 }
4314
4315 static
PrepareForErrorDiffuse(xpm_ptr)4316 int PrepareForErrorDiffuse(xpm_ptr)
4317 struct XPmRec *xpm_ptr;
4318 {
4319 int rc;
4320
4321 SaveStatusStrings();
4322 SetWatchCursor(drawWindow);
4323 SetWatchCursor(mainWindow);
4324 rc = DoPrepareForErrorDiffuse(xpm_ptr);
4325 SetDefaultCursor(mainWindow);
4326 ShowCursor();
4327 RestoreStatusStrings();
4328 return rc;
4329 }
4330
4331 static
MapTargetColors(xpm_ptr)4332 int MapTargetColors(xpm_ptr)
4333 struct XPmRec *xpm_ptr;
4334 {
4335 int i, target_ncolors=gXPmTarget.ncolors;
4336 int red_bits=0, green_bits=0, blue_bits=0;
4337
4338 if (gXPmTarget.color_str != NULL) {
4339 for (i=0; i < target_ncolors; i++) {
4340 if (!TgifParseColor(gXPmTarget.color_str[i], &gTargetColors[i])) {
4341 gTargetColorValid[i] = FALSE;
4342 }
4343 }
4344 } else {
4345 red_bits = gDefErrorDiffuseLevel.red;
4346 green_bits = gDefErrorDiffuseLevel.green;
4347 blue_bits = gDefErrorDiffuseLevel.blue;
4348 }
4349 gnTgifColorsToObjectColorMapping = (int*)malloc(maxColors*sizeof(int));
4350 if (gnTgifColorsToObjectColorMapping == NULL) {
4351 FailAllocMessage();
4352 return FALSE;
4353 }
4354 memset(gnTgifColorsToObjectColorMapping, (-1), maxColors*sizeof(int));
4355
4356 for (i=0; i < maxColors; i++) {
4357 int cur_pixel=colorPixels[i], ncolors=xpm_ptr->ncolors;
4358 int found_index, *pixels=xpm_ptr->pixels;
4359 int red, green, blue, min_index;
4360
4361 for (found_index=0; found_index < ncolors; found_index++) {
4362 if (pixels[found_index] == cur_pixel) {
4363 break;
4364 }
4365 }
4366 if (found_index >= ncolors) {
4367 continue;
4368 }
4369 gnTgifColorsToObjectColorMapping[i] = found_index;
4370
4371 red = (int)(tgifColors[i].red);
4372 green = (int)(tgifColors[i].green);
4373 blue = (int)(tgifColors[i].blue);
4374
4375 min_index = GetClosestColorIndex(red_bits, green_bits, blue_bits,
4376 red, green, blue, target_ncolors);
4377
4378 gnObjectColorsToTargetColorMapping[found_index] = min_index;
4379 }
4380 return TRUE;
4381 }
4382
ReduceToPixmapColors()4383 void ReduceToPixmapColors()
4384 {
4385 int i, ok=TRUE, rc, short_name=FALSE;
4386 char xpm_fname[MAXPATHLENGTH+1], *rest=NULL, tmp_fname[MAXPATHLENGTH+1];
4387 XEvent ev;
4388 int ncolors=0, chars_per_pixel=0, first_pixel_is_bg=0, remote_file=FALSE;
4389 char *color_char=NULL, **color_str=NULL, *xpm_data=NULL;
4390 struct XPmRec *xpm_ptr=NULL;
4391
4392 if (!CheckSelectionForImageProc(CMDID_REDUCETOPIXMAPCOLORS)) {
4393 return;
4394 }
4395 importingFile = TRUE;
4396 *xpm_fname = *tmp_fname = '\0';
4397 gnObjectColorsToTargetColorMapping = NULL;
4398 if (importFromLibrary) {
4399 char name[MAXSTRING+1], path[MAXSTRING+1];
4400
4401 if (SelectFromLibrary(TgLoadString(STID_SEL_XPM_FILE_FOR_RED_COLORS),
4402 XPM_FILE_EXT, name, path) == INVALID) {
4403 ok = FALSE;
4404 } else {
4405 sprintf(xpm_fname, "%s%c%s", path, DIR_SEP, name);
4406 }
4407 } else if (SelectFileNameToImport(
4408 TgLoadString(STID_SEL_XPM_FILE_FOR_RED_COLORS), XPM_FILE_EXT,
4409 xpm_fname) == INVALID) {
4410 ok = FALSE;
4411 } else if (FileIsRemote(xpm_fname)) {
4412 int is_html=FALSE;
4413
4414 if (!DownloadRemoteFile(xpm_fname, NULL, NULL, &is_html, tmp_fname, NULL,
4415 0) || *tmp_fname == '\0') {
4416 ok = FALSE;
4417 } else {
4418 remote_file = TRUE;
4419 }
4420 }
4421 importingFile = FALSE;
4422 if (!ok) {
4423 if (remote_file) unlink(tmp_fname);
4424 return;
4425 }
4426 XSync(mainDisplay, False);
4427 if (XCheckMaskEvent(mainDisplay, ExposureMask, &ev)) {
4428 ExposeEventHandler(&ev, TRUE);
4429 }
4430 xpm_ptr = topSel->obj->detail.xpm;
4431 if (DoPpm6(xpm_ptr)) {
4432 gnObjectColorsToTargetColorMapping = NULL;
4433 } else {
4434 gnObjectColorsToTargetColorMapping =
4435 (int*)malloc(xpm_ptr->ncolors*sizeof(int));
4436 if (gnObjectColorsToTargetColorMapping == NULL) {
4437 FailAllocMessage();
4438 if (remote_file) unlink(tmp_fname);
4439 return;
4440 }
4441 memset(gnObjectColorsToTargetColorMapping, 0,
4442 xpm_ptr->ncolors*sizeof(int));
4443 }
4444 SetWatchCursor(drawWindow);
4445 SetWatchCursor(mainWindow);
4446 rc = MyReadPixmapFile(remote_file ? tmp_fname : xpm_fname, NULL, NULL, NULL,
4447 NULL, NULL, NULL, NULL, NULL, &ncolors, &chars_per_pixel,
4448 &first_pixel_is_bg, &color_char, &color_str, NULL, &xpm_data);
4449 SetDefaultCursor(mainWindow);
4450 ShowCursor();
4451
4452 if (remote_file) {
4453 short_name = FALSE;
4454 } else {
4455 if ((short_name=IsPrefix(bootDir, xpm_fname, &rest))) ++rest;
4456 }
4457 if (rc != BitmapSuccess) {
4458 sprintf(gszMsgBox, TgLoadString(STID_INVALID_GIVEN_XPM_FILE),
4459 (short_name ? rest : xpm_fname));
4460 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
4461 if (gnObjectColorsToTargetColorMapping != NULL) {
4462 free(gnObjectColorsToTargetColorMapping);
4463 gnObjectColorsToTargetColorMapping = NULL;
4464 }
4465 if (remote_file) unlink(tmp_fname);
4466 return;
4467 }
4468 gXPmTarget.ncolors = ncolors;
4469 gXPmTarget.chars_per_pixel = chars_per_pixel;
4470 gXPmTarget.first_pixel_is_bg = first_pixel_is_bg;
4471 gXPmTarget.color_char = color_char;
4472 gXPmTarget.color_str = color_str;
4473 gXPmTarget.data = xpm_data;
4474 gXPmTarget.userdata = (void*)CMDID_REDUCETOPIXMAPCOLORS;
4475
4476 if (ncolors <= 0) {
4477 sprintf(gszMsgBox, TgLoadString(STID_INVALID_GIVEN_XPM_FILE),
4478 (short_name ? rest : xpm_fname));
4479 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
4480 } else {
4481 int image_h=xpm_ptr->image_h;
4482
4483 rc = MsgBox(TgLoadString(STID_Q_FS_ERROR_DIFFUSE), TOOL_NAME, YNC_MB);
4484 switch (rc) {
4485 case MB_ID_YES: gnFloyd = TRUE; break;
4486 case MB_ID_NO: gnFloyd = FALSE; break;
4487 case MB_ID_CANCEL:
4488 if (gnObjectColorsToTargetColorMapping != NULL) {
4489 free(gnObjectColorsToTargetColorMapping);
4490 gnObjectColorsToTargetColorMapping = NULL;
4491 }
4492 if (remote_file) unlink(tmp_fname);
4493 return;
4494 }
4495 AllocTargetColors(ncolors);
4496 if (gnFloyd) {
4497 if (DoPpm6(xpm_ptr)) {
4498 if (!InitTrueColorInfo(xpm_ptr->image, &gTrueColorInfo,
4499 xpm_ptr->image_w)) {
4500 sprintf(gszMsgBox, TgLoadString(STID_CANNOT_GET_IMAGE_OF_SIZE),
4501 xpm_ptr->image_w, xpm_ptr->image_h);
4502 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
4503 if (gnObjectColorsToTargetColorMapping != NULL) {
4504 free(gnObjectColorsToTargetColorMapping);
4505 gnObjectColorsToTargetColorMapping = NULL;
4506 }
4507 if (remote_file) unlink(tmp_fname);
4508 return;
4509 }
4510 }
4511 rc = PrepareForErrorDiffuse(xpm_ptr);
4512 CleanUpIndexOfPixel();
4513 if (gpTargetImage != NULL) XDestroyImage(gpTargetImage);
4514 if (gpTargetBitmapImage != NULL) XDestroyImage(gpTargetBitmapImage);
4515 gpTargetImage = gpTargetBitmapImage = NULL;
4516 } else {
4517 if (DoPpm6(xpm_ptr)) {
4518 if (gXPmTarget.color_str != NULL) {
4519 for (i=0; i < ncolors; i++) {
4520 if (!TgifParseColor(gXPmTarget.color_str[i],
4521 &gTargetColors[i])) {
4522 gTargetColorValid[i] = FALSE;
4523 }
4524 }
4525 }
4526 rc = TRUE;
4527 } else {
4528 rc = MapTargetColors(xpm_ptr);
4529 }
4530 }
4531 if (rc) {
4532 gnUserSpecifiedLevels = ncolors;
4533 if (gnFloyd) {
4534 gpConvolveFunc = (NLFN*)ConvolveToErrorDiffuse;
4535 gpConvolveCmdID = CMDID_REDUCETOPIXMAPCOLORS;
4536 } else {
4537 gpConvolveFunc = (NLFN*)ConvolveToReduceToPixmapColors;
4538 gpConvolveCmdID = CMDID_REDUCETOPIXMAPCOLORS;
4539 }
4540 gnConvolving = TRUE;
4541 DoImageProc(NULL);
4542 gnConvolving = FALSE;
4543 gpConvolveFunc = NULL;
4544 gpConvolveCmdID = (-1);
4545 gnUserSpecifiedLevels = (-1);
4546 }
4547 FreeTargetColors();
4548 if (gnFloyd) {
4549 if (gnImageTargetColor != NULL) {
4550 for (i=0; i < image_h; i++) free(gnImageTargetColor[i]);
4551 free(gnImageTargetColor);
4552 gnImageTargetColor = NULL;
4553 }
4554 }
4555 gnFloyd = FALSE;
4556 }
4557 if (gXPmTarget.color_char != NULL) free(gXPmTarget.color_char);
4558 if (gXPmTarget.color_str != NULL) {
4559 for (i=0; i < gXPmTarget.ncolors; i++) free(gXPmTarget.color_str[i]);
4560 free(gXPmTarget.color_str);
4561 }
4562 if (gXPmTarget.data != NULL) free(gXPmTarget.data);
4563 memset(&gXPmTarget, 0, sizeof(struct XPmRec));
4564
4565 if (gnObjectColorsToTargetColorMapping != NULL) {
4566 free(gnObjectColorsToTargetColorMapping);
4567 gnObjectColorsToTargetColorMapping = NULL;
4568 }
4569 if (gnTgifColorsToObjectColorMapping != NULL) {
4570 free(gnTgifColorsToObjectColorMapping);
4571 gnTgifColorsToObjectColorMapping = NULL;
4572 }
4573 if (remote_file) unlink(tmp_fname);
4574 }
4575
4576 /* ---------------------- ReduceToMobileWebSafeColors ---------------------- */
4577
4578 static
GetMobileWebSafeIntensity(index)4579 int GetMobileWebSafeIntensity(index)
4580 int index;
4581 {
4582 switch (index) {
4583 case 0: return 0x00000;
4584 case 1: return 0x03300;
4585 case 2: return 0x06600;
4586 case 3: return 0x09900;
4587 case 4: return 0x0cc00;
4588 case 5: return 0x0ff00;
4589 }
4590 TgAssert(FALSE, "invalid parameter passed to GetMobileWebSafeIntensity()",
4591 NULL);
4592 return (-1);
4593 }
4594
ReduceToMobileWebSafeColors()4595 void ReduceToMobileWebSafeColors()
4596 {
4597 int i, red=0, rc=FALSE, ncolors=0, image_h=0;
4598 struct XPmRec *xpm_ptr=NULL;
4599
4600 if (!CheckSelectionForImageProc(CMDID_REDUCETOMOBILEWEBCOLORS)) {
4601 return;
4602 }
4603 xpm_ptr = topSel->obj->detail.xpm;
4604 image_h = xpm_ptr->image_h;
4605
4606 if (DoPpm6(xpm_ptr)) {
4607 gnObjectColorsToTargetColorMapping = NULL;
4608 } else {
4609 gnObjectColorsToTargetColorMapping =
4610 (int*)malloc(xpm_ptr->ncolors*sizeof(int));
4611 if (gnObjectColorsToTargetColorMapping == NULL) {
4612 FailAllocMessage();
4613 return;
4614 }
4615 memset(gnObjectColorsToTargetColorMapping, 0,
4616 xpm_ptr->ncolors*sizeof(int));
4617 }
4618 ncolors = 6*6*6;
4619
4620 memset(&gXPmTarget, 0, sizeof(struct XPmRec));
4621 gXPmTarget.ncolors = ncolors;
4622 gXPmTarget.userdata = (void*)CMDID_REDUCETOMOBILEWEBCOLORS;
4623
4624 rc = MsgBox(TgLoadString(STID_Q_FS_ERROR_DIFFUSE), TOOL_NAME, YNC_MB);
4625 switch (rc) {
4626 case MB_ID_YES: gnFloyd = TRUE; break;
4627 case MB_ID_NO: gnFloyd = FALSE; break;
4628 case MB_ID_CANCEL:
4629 if (gnObjectColorsToTargetColorMapping != NULL) {
4630 free(gnObjectColorsToTargetColorMapping);
4631 gnObjectColorsToTargetColorMapping = NULL;
4632 }
4633 return;
4634 }
4635 AllocTargetColors(ncolors);
4636 i = 0;
4637 for (red=0; red < 6; red++) {
4638 int red_intensity=GetMobileWebSafeIntensity(red), green;
4639
4640 for (green=0; green < 6; green++) {
4641 int green_intensity=GetMobileWebSafeIntensity(green), blue;
4642
4643 for (blue=0; blue < 6; blue++) {
4644 int blue_intensity=GetMobileWebSafeIntensity(blue);
4645
4646 gTargetColors[i].red = red_intensity;
4647 gTargetColors[i].green = green_intensity;
4648 gTargetColors[i].blue = blue_intensity;
4649 i++;
4650 }
4651 }
4652 }
4653 if (gnFloyd) {
4654 if (DoPpm6(xpm_ptr)) {
4655 if (!InitTrueColorInfo(xpm_ptr->image, &gTrueColorInfo,
4656 xpm_ptr->image_w)) {
4657 sprintf(gszMsgBox, TgLoadString(STID_CANNOT_GET_IMAGE_OF_SIZE),
4658 xpm_ptr->image_w, xpm_ptr->image_h);
4659 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
4660 if (gnObjectColorsToTargetColorMapping != NULL) {
4661 free(gnObjectColorsToTargetColorMapping);
4662 gnObjectColorsToTargetColorMapping = NULL;
4663 }
4664 return;
4665 }
4666 }
4667 rc = PrepareForErrorDiffuse(xpm_ptr);
4668 CleanUpIndexOfPixel();
4669 if (gpTargetImage != NULL) XDestroyImage(gpTargetImage);
4670 if (gpTargetBitmapImage != NULL) XDestroyImage(gpTargetBitmapImage);
4671 gpTargetImage = gpTargetBitmapImage = NULL;
4672 } else {
4673 if (DoPpm6(xpm_ptr)) {
4674 rc = TRUE;
4675 } else {
4676 rc = MapTargetColors(xpm_ptr);
4677 }
4678 }
4679 if (rc) {
4680 gnUserSpecifiedLevels = ncolors;
4681 if (gnFloyd) {
4682 gpConvolveFunc = (NLFN*)ConvolveToErrorDiffuse;
4683 gpConvolveCmdID = CMDID_REDUCETOMOBILEWEBCOLORS;
4684 } else {
4685 gpConvolveFunc = (NLFN*)ConvolveToReduceToPixmapColors;
4686 gpConvolveCmdID = CMDID_REDUCETOMOBILEWEBCOLORS;
4687 }
4688 gnConvolving = TRUE;
4689 DoImageProc(NULL);
4690 gnConvolving = FALSE;
4691 gpConvolveFunc = NULL;
4692 gpConvolveCmdID = (-1);
4693 gnUserSpecifiedLevels = (-1);
4694 }
4695 FreeTargetColors();
4696 if (gnFloyd) {
4697 if (gnImageTargetColor != NULL) {
4698 for (i=0; i < image_h; i++) free(gnImageTargetColor[i]);
4699 free(gnImageTargetColor);
4700 gnImageTargetColor = NULL;
4701 }
4702 }
4703 memset(&gXPmTarget, 0, sizeof(struct XPmRec));
4704
4705 if (gnObjectColorsToTargetColorMapping != NULL) {
4706 free(gnObjectColorsToTargetColorMapping);
4707 gnObjectColorsToTargetColorMapping = NULL;
4708 }
4709 if (gnTgifColorsToObjectColorMapping != NULL) {
4710 free(gnTgifColorsToObjectColorMapping);
4711 gnTgifColorsToObjectColorMapping = NULL;
4712 }
4713 }
4714
4715 /* ----------------------- SetDefaultColorLevels ----------------------- */
4716
4717 #define PDCL_OK 0
4718 #define PDCL_TOO_LARGE 1
4719 #define PDCL_TOO_SMALL 2
4720 #define PDCL_BAD_FORMAT 3
4721
4722 static
ParseDefaultColorLevels(buf,p_xcolor)4723 int ParseDefaultColorLevels(buf, p_xcolor)
4724 char *buf;
4725 XColor *p_xcolor;
4726 {
4727 char *red_ptr, *green_ptr, *blue_ptr;
4728
4729 if ((red_ptr=strtok(buf, " ,:\t\n\r")) != NULL &&
4730 (green_ptr=strtok(NULL, " ,:\t\n\r")) != NULL &&
4731 (blue_ptr=strtok(NULL, " ,:\t\n\r")) != NULL) {
4732 int red, green, blue;
4733
4734 red = atoi(red_ptr);
4735 green = atoi(green_ptr);
4736 blue = atoi(blue_ptr);
4737 if (red+green+blue > 8) {
4738 return PDCL_TOO_LARGE;
4739 } else if (red <= 0 || green <= 0 || blue <= 0) {
4740 return PDCL_TOO_SMALL;
4741 } else {
4742 p_xcolor->red = red;
4743 p_xcolor->green = green;
4744 p_xcolor->blue = blue;
4745 return PDCL_OK;
4746 }
4747 }
4748 return PDCL_BAD_FORMAT;
4749 }
4750
SetDefaultColorLevels()4751 void SetDefaultColorLevels()
4752 {
4753 char szSpec[MAXSTRING+1], szSpecCopy[MAXSTRING+1];
4754 XColor xcolor;
4755
4756 sprintf(gszMsgBox, TgLoadString(STID_ENTER_NUM_BITS_IN_RGB),
4757 (int)gDefErrorDiffuseLevel.red, (int)gDefErrorDiffuseLevel.green,
4758 (int)gDefErrorDiffuseLevel.blue);
4759 *szSpec = '\0';
4760 Dialog(gszMsgBox, TgLoadCachedString(CSTID_DLG_ACCEPT_CANCEL), szSpec);
4761 UtilTrimBlanks(szSpec);
4762 if (*szSpec == '\0') return;
4763
4764 strcpy(szSpecCopy, szSpec);
4765 switch (ParseDefaultColorLevels(szSpecCopy, &xcolor)) {
4766 case PDCL_OK:
4767 gDefErrorDiffuseLevel.red = xcolor.red;
4768 gDefErrorDiffuseLevel.green = xcolor.green;
4769 gDefErrorDiffuseLevel.blue = xcolor.blue;
4770 Msg(TgLoadString(STID_RGB_LEVELS_CHANGED_TO));
4771 break;
4772 case PDCL_TOO_LARGE:
4773 sprintf(gszMsgBox, TgLoadString(STID_BAD_VAL_SUM_RGB_LEVEL), szSpec);
4774 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
4775 break;
4776 case PDCL_TOO_SMALL:
4777 sprintf(gszMsgBox, TgLoadString(STID_BAD_VAL_GT_0_RGB_LEVEL), szSpec);
4778 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
4779 break;
4780 case PDCL_BAD_FORMAT:
4781 sprintf(gszMsgBox, TgLoadString(STID_FAIL_TO_PARSE_FOR_3_VAL), szSpec);
4782 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
4783 break;
4784 }
4785 }
4786
4787 /* ----------------------- ReduceToDefaultColors ----------------------- */
4788
ReduceToDefaultColors()4789 void ReduceToDefaultColors()
4790 {
4791 int i, red=0, rc=FALSE, ncolors=0, image_h=0;
4792 int red_bits, green_bits, blue_bits, red_levels, green_levels, blue_levels;
4793 struct XPmRec *xpm_ptr=NULL;
4794
4795 if (!CheckSelectionForImageProc(CMDID_DEFAULTERRORDIFFUSE)) {
4796 return;
4797 }
4798 xpm_ptr = topSel->obj->detail.xpm;
4799 image_h = xpm_ptr->image_h;
4800
4801 if (DoPpm6(xpm_ptr)) {
4802 gnObjectColorsToTargetColorMapping = NULL;
4803 } else {
4804 gnObjectColorsToTargetColorMapping =
4805 (int*)malloc(xpm_ptr->ncolors*sizeof(int));
4806 if (gnObjectColorsToTargetColorMapping == NULL) {
4807 FailAllocMessage();
4808 return;
4809 }
4810 memset(gnObjectColorsToTargetColorMapping, 0,
4811 xpm_ptr->ncolors*sizeof(int));
4812 }
4813 red_bits = gDefErrorDiffuseLevel.red;
4814 green_bits = gDefErrorDiffuseLevel.green;
4815 blue_bits = gDefErrorDiffuseLevel.blue;
4816 sprintf(gszMsgBox, TgLoadString(STID_RGB_LEVELS_ARE),
4817 red_bits, green_bits, blue_bits);
4818 Msg(gszMsgBox);
4819 red_levels = (1 << red_bits);
4820 green_levels = (1 << green_bits);
4821 blue_levels = (1 << blue_bits);
4822 ncolors = (1 << (red_bits+green_bits+blue_bits));
4823 if (ncolors > 0x100) ncolors = 0x100;
4824
4825 memset(&gXPmTarget, 0, sizeof(struct XPmRec));
4826 gXPmTarget.ncolors = ncolors;
4827 gXPmTarget.userdata = (void*)CMDID_DEFAULTERRORDIFFUSE;
4828
4829 AllocTargetColors(ncolors);
4830 i = 0;
4831 for (red=0; red < red_levels; red++) {
4832 int red_intensity=GetIntensity(red, red_levels-1), green;
4833
4834 for (green=0; green < green_levels; green++) {
4835 int green_intensity=GetIntensity(green, green_levels-1), blue;
4836
4837 for (blue=0; blue < blue_levels; blue++) {
4838 int blue_intensity=GetIntensity(blue, blue_levels-1);
4839
4840 gTargetColors[i].red = red_intensity;
4841 gTargetColors[i].green = green_intensity;
4842 gTargetColors[i].blue = blue_intensity;
4843 i++;
4844 }
4845 }
4846 }
4847 if (DoPpm6(xpm_ptr)) {
4848 rc = TRUE;
4849 } else {
4850 rc = MapTargetColors(xpm_ptr);
4851 }
4852 if (rc) {
4853 gnUserSpecifiedLevels = ncolors;
4854 gpConvolveFunc = (NLFN*)ConvolveToReduceToPixmapColors;
4855 gpConvolveCmdID = CMDID_DEFAULTERRORDIFFUSE;
4856 gnConvolving = TRUE;
4857 DoImageProc(NULL);
4858 gnConvolving = FALSE;
4859 gpConvolveFunc = NULL;
4860 gpConvolveCmdID = (-1);
4861 gnUserSpecifiedLevels = (-1);
4862 }
4863 FreeTargetColors();
4864 memset(&gXPmTarget, 0, sizeof(struct XPmRec));
4865
4866 if (gnObjectColorsToTargetColorMapping != NULL) {
4867 free(gnObjectColorsToTargetColorMapping);
4868 gnObjectColorsToTargetColorMapping = NULL;
4869 }
4870 if (gnTgifColorsToObjectColorMapping != NULL) {
4871 free(gnTgifColorsToObjectColorMapping);
4872 gnTgifColorsToObjectColorMapping = NULL;
4873 }
4874 }
4875
4876 /* ----------------------- DefaultErrorDiffuse ----------------------- */
4877
DefaultErrorDiffuse()4878 void DefaultErrorDiffuse()
4879 {
4880 int i, red, rc, ncolors, image_h;
4881 int red_bits, green_bits, blue_bits, red_levels, green_levels, blue_levels;
4882 struct XPmRec *xpm_ptr=NULL;
4883
4884 if (!CheckSelectionForImageProc(CMDID_DEFAULTERRORDIFFUSE)) {
4885 return;
4886 }
4887 xpm_ptr = topSel->obj->detail.xpm;
4888 image_h = xpm_ptr->image_h;
4889
4890 red_bits = gDefErrorDiffuseLevel.red;
4891 green_bits = gDefErrorDiffuseLevel.green;
4892 blue_bits = gDefErrorDiffuseLevel.blue;
4893 sprintf(gszMsgBox, TgLoadString(STID_RGB_LEVELS_ARE),
4894 red_bits, green_bits, blue_bits);
4895 Msg(gszMsgBox);
4896 red_levels = (1 << red_bits);
4897 green_levels = (1 << green_bits);
4898 blue_levels = (1 << blue_bits);
4899 ncolors = (1 << (red_bits+green_bits+blue_bits));
4900 if (ncolors > 0x100) ncolors = 0x100;
4901
4902 memset(&gXPmTarget, 0, sizeof(struct XPmRec));
4903 gXPmTarget.ncolors = ncolors;
4904 gXPmTarget.userdata = (void*)CMDID_DEFAULTERRORDIFFUSE;
4905
4906 gnFloyd = TRUE;
4907
4908 AllocTargetColors(ncolors);
4909 i = 0;
4910 for (red=0; red < red_levels; red++) {
4911 int red_intensity=GetIntensity(red, red_levels-1), green;
4912
4913 for (green=0; green < green_levels; green++) {
4914 int green_intensity=GetIntensity(green, green_levels-1), blue;
4915
4916 for (blue=0; blue < blue_levels; blue++) {
4917 int blue_intensity=GetIntensity(blue, blue_levels-1);
4918
4919 gTargetColors[i].red = red_intensity;
4920 gTargetColors[i].green = green_intensity;
4921 gTargetColors[i].blue = blue_intensity;
4922 i++;
4923 }
4924 }
4925 }
4926 if (DoPpm6(xpm_ptr)) {
4927 if (!InitTrueColorInfo(xpm_ptr->image, &gTrueColorInfo,
4928 xpm_ptr->image_w)) {
4929 sprintf(gszMsgBox, TgLoadString(STID_CANNOT_GET_IMAGE_OF_SIZE),
4930 xpm_ptr->image_w, xpm_ptr->image_h);
4931 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
4932 return;
4933 }
4934 }
4935 rc = PrepareForErrorDiffuse(xpm_ptr);
4936
4937 CleanUpIndexOfPixel();
4938 if (gpTargetImage != NULL) XDestroyImage(gpTargetImage);
4939 if (gpTargetBitmapImage != NULL) XDestroyImage(gpTargetBitmapImage);
4940 gpTargetImage = gpTargetBitmapImage = NULL;
4941
4942 if (rc) {
4943 gnUserSpecifiedLevels = ncolors;
4944 gpConvolveFunc = (NLFN*)ConvolveToErrorDiffuse;
4945 gpConvolveCmdID = CMDID_DEFAULTERRORDIFFUSE;
4946 gnConvolving = TRUE;
4947 DoImageProc(NULL);
4948 gnConvolving = FALSE;
4949 gpConvolveFunc = NULL;
4950 gpConvolveCmdID = (-1);
4951 gnUserSpecifiedLevels = (-1);
4952 }
4953 FreeTargetColors();
4954 if (gnImageTargetColor != NULL) {
4955 for (i=0; i < image_h; i++) free(gnImageTargetColor[i]);
4956 free(gnImageTargetColor);
4957 gnImageTargetColor = NULL;
4958 }
4959 gnFloyd = FALSE;
4960 memset(&gXPmTarget, 0, sizeof(struct XPmRec));
4961 }
4962
4963 /* ----------------------- Spread ----------------------- */
4964
4965 static int gnAmountToSpread=0;
4966 static int **gnSpreadImageIndex=NULL;
4967
4968 static
ConvolveToSpread(x,y)4969 int ConvolveToSpread(x, y)
4970 int x, y;
4971 {
4972 if (gConvExtraInfo.fp != NULL) {
4973 XColor **xcolors=gConvExtraInfo.xcolors;
4974 FILE *fp=gConvExtraInfo.fp;
4975 int w=gConvExtraInfo.image_w, h=gConvExtraInfo.image_h;
4976 unsigned char buf[3];
4977
4978 if (x == 0 && y == 0) {
4979 int r=0;
4980
4981 srand(0);
4982 for (r=0; r < h; r++) {
4983 int c=0;
4984
4985 for (c=0; c < w; c++) {
4986 int dx=(rand() % gnAmountToSpread) - (gnAmountToSpread>>1);
4987 int dy=(rand() % gnAmountToSpread) - (gnAmountToSpread>>1);
4988 int tmp_y=r+dy, tmp_x=c+dx;
4989
4990 if (tmp_x >= 0 && tmp_x < w && tmp_y >= 0 && tmp_y < h) {
4991 XColor tmp_xcolor;
4992
4993 memcpy(&tmp_xcolor, &xcolors[r][c], sizeof(XColor));
4994 memcpy(&xcolors[r][c], &xcolors[tmp_y][tmp_x],
4995 sizeof(XColor));
4996 memcpy(&xcolors[tmp_y][tmp_x], &tmp_xcolor, sizeof(XColor));
4997 }
4998 }
4999 }
5000 }
5001 buf[0] = (unsigned char)xcolors[y][x].red;
5002 buf[1] = (unsigned char)xcolors[y][x].green;
5003 buf[2] = (unsigned char)xcolors[y][x].blue;
5004 if ((int)fwrite(buf, sizeof(char), 3, fp) <= 0) writeFileFailed = TRUE;
5005
5006 return TRUE;
5007 } else {
5008 return GetOrAllocHistogramIndex(&tgifColors[gnSpreadImageIndex[y][x]]);
5009 }
5010 }
5011
5012 static
CleanUpSpreadData()5013 void CleanUpSpreadData()
5014 {
5015 int i, image_h=topSel->obj->detail.xpm->image_h;
5016
5017 if (gnSpreadImageIndex != NULL) {
5018 for (i=0; i < image_h; i++) free(gnSpreadImageIndex[i]);
5019 free(gnSpreadImageIndex);
5020 gnSpreadImageIndex = NULL;
5021 }
5022 }
5023
5024 static
ComputeSpreadData()5025 int ComputeSpreadData()
5026 {
5027 struct XPmRec *xpm_ptr=topSel->obj->detail.xpm;
5028 int i, image_w=xpm_ptr->image_w, image_h=xpm_ptr->image_h;
5029 ProgressInfo pi;
5030 Pixmap pixmap=xpm_ptr->pixmap;
5031 XImage *image=XGetImage(mainDisplay, pixmap, 0, 0, image_w, image_h,
5032 AllPlanes, ZPixmap);
5033
5034 if (image == NULL) {
5035 FailAllocMessage();
5036 return FALSE;
5037 }
5038 if (!CreatePixelToIndexMapping()) {
5039 XDestroyImage(image);
5040 return FALSE;
5041 }
5042 gnSpreadImageIndex = (int**)malloc(image_h*sizeof(int*));
5043 if (gnSpreadImageIndex == NULL) {
5044 FailAllocMessage();
5045 XDestroyImage(image);
5046 CleanUpIndexOfPixel();
5047 return FALSE;
5048 }
5049 gnAmountToSpread++;
5050 BeginProgress(&pi, image_h);
5051 for (i=0; i < image_h; i++) {
5052 int j;
5053
5054 UpdateProgress(&pi, i);
5055 gnSpreadImageIndex[i] = (int*)malloc(image_w*sizeof(int));
5056 if (gnSpreadImageIndex[i] == NULL) {
5057 FailAllocMessage();
5058 for (j=0; j < i; j++) free(gnSpreadImageIndex[j]);
5059 free(gnSpreadImageIndex);
5060 gnSpreadImageIndex = NULL;
5061 XDestroyImage(image);
5062 CleanUpIndexOfPixel();
5063 return FALSE;
5064 }
5065 for (j=0; j < image_w; j++) {
5066 gnSpreadImageIndex[i][j] = GetIndexOfPixel(XGetPixel(image,j,i));
5067 }
5068 }
5069 BeginProgress(&pi, image_h);
5070 srand(0);
5071 for (i=0; i < image_h; i++) {
5072 int j;
5073
5074 UpdateProgress(&pi, i);
5075 for (j=0; j < image_w; j++) {
5076 int dx=(rand() % gnAmountToSpread) - (gnAmountToSpread>>1);
5077 int dy=(rand() % gnAmountToSpread) - (gnAmountToSpread>>1);
5078 int y=i+dy, x=j+dx, tmp_index;
5079
5080 if (x >= 0 && x < image_w && y >= 0 && y < image_h) {
5081 tmp_index = gnSpreadImageIndex[i][j];
5082 gnSpreadImageIndex[i][j] = gnSpreadImageIndex[y][x];
5083 gnSpreadImageIndex[y][x] = tmp_index;
5084 }
5085 }
5086 }
5087 XDestroyImage(image);
5088 CleanUpIndexOfPixel();
5089
5090 return TRUE;
5091 }
5092
Spread()5093 void Spread()
5094 {
5095 char *c_ptr=NULL, szSpec[MAXSTRING+1], szSpecCopy[MAXSTRING+1];
5096
5097 if (!CheckSelectionForImageProc(CMDID_SPREAD)) {
5098 return;
5099 }
5100 *szSpec = '\0';
5101 Dialog(TgLoadString(STID_ENTER_INT_AMT_TO_SPREAD),
5102 TgLoadCachedString(CSTID_DLG_ACCEPT_CANCEL), szSpec);
5103 UtilTrimBlanks(szSpec);
5104 if (*szSpec == '\0') return;
5105
5106 strcpy(szSpecCopy, szSpec);
5107 if ((c_ptr=strtok(szSpec, " ,\t\n\r")) == NULL) return;
5108 gnAmountToSpread = atoi(c_ptr);
5109 if (gnAmountToSpread <= 0) {
5110 sprintf(gszMsgBox, TgLoadString(STID_INVALID_SPEC), szSpecCopy);
5111 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
5112 return;
5113 }
5114 if (!DoPpm6(topSel->obj->detail.xpm)) {
5115 if (!ComputeSpreadData()) {
5116 return;
5117 }
5118 }
5119 gpConvolveFunc = (NLFN*)ConvolveToSpread;
5120 gpConvolveCmdID = CMDID_SPREAD;
5121 gnConvolving = TRUE;
5122 DoImageProc(NULL);
5123 gnConvolving = FALSE;
5124 gpConvolveFunc = NULL;
5125 gpConvolveCmdID = (-1);
5126
5127 CleanUpSpreadData();
5128 }
5129
5130 /* ----------------------- Sharpen ----------------------- */
5131
5132 static
ConvolveToSharpen(x,y)5133 int ConvolveToSharpen(x, y)
5134 int x, y;
5135 /*
5136 * [ 0 -1 0 ]
5137 * [ -1 5 -1 ]
5138 * [ 0 -1 0 ]
5139 */
5140 {
5141 if (gConvExtraInfo.fp != NULL) {
5142 XColor **xcolors=gConvExtraInfo.xcolors;
5143 FILE *fp=gConvExtraInfo.fp;
5144 int w=gConvExtraInfo.image_w, h=gConvExtraInfo.image_h;
5145 unsigned char buf[3];
5146
5147 if (x == 0 || x == w-1 || y == 0 || y == h-1) {
5148 buf[0] = (unsigned char)xcolors[y][x].red;
5149 buf[1] = (unsigned char)xcolors[y][x].green;
5150 buf[2] = (unsigned char)xcolors[y][x].blue;
5151 } else {
5152 int r=0, g=0, b=0;
5153
5154 r = (int)(
5155 (((int)xcolors[y][x].red)<<3) -
5156 ((int)xcolors[y][x-1].red) -
5157 ((int)xcolors[y][x+1].red) -
5158 ((int)xcolors[y-1][x].red) -
5159 ((int)xcolors[y+1][x].red));
5160 g = (int)(
5161 (((int)xcolors[y][x].green)<<3) -
5162 ((int)xcolors[y][x-1].green) -
5163 ((int)xcolors[y][x+1].green) -
5164 ((int)xcolors[y-1][x].green) -
5165 ((int)xcolors[y+1][x].green));
5166 b = (int)(
5167 (((int)xcolors[y][x].blue)<<3) -
5168 ((int)xcolors[y][x-1].blue) -
5169 ((int)xcolors[y][x+1].blue) -
5170 ((int)xcolors[y-1][x].blue) -
5171 ((int)xcolors[y+1][x].blue));
5172 r >>= 2;
5173 g >>= 2;
5174 b >>= 2;
5175 if (r < 0) r = 0;
5176 if (g < 0) g = 0;
5177 if (b < 0) b = 0;
5178 if (r > 255) r = 255;
5179 if (g > 255) g = 255;
5180 if (b > 255) b = 255;
5181
5182 buf[0] = (unsigned char)(unsigned int)r;
5183 buf[1] = (unsigned char)(unsigned int)g;
5184 buf[2] = (unsigned char)(unsigned int)b;
5185 }
5186 if ((int)fwrite(buf, sizeof(char), 3, fp) <= 0) writeFileFailed = TRUE;
5187
5188 return TRUE;
5189 } else {
5190 register long red, green, blue;
5191 XColor xcolor, *color_ptr;
5192
5193 if (x == 0 || x == gnImageW-1 || y == 0 || y == gnImageH-1) {
5194 return GetOrAllocHistogramIndex(&tgifColors[gnOrigImageIndex[y][x]]);
5195 }
5196 color_ptr = (&tgifColors[gnOrigImageIndex[y][x]]);
5197 red = ((long)color_ptr->red) << 3;
5198 green = ((long)color_ptr->green) << 3;
5199 blue = ((long)color_ptr->blue) << 3;
5200 color_ptr = (&tgifColors[gnOrigImageIndex[y][x-1]]);
5201 red -= ((long)color_ptr->red);
5202 green -= ((long)color_ptr->green);
5203 blue -= ((long)color_ptr->blue);
5204 color_ptr = (&tgifColors[gnOrigImageIndex[y][x+1]]);
5205 red -= ((long)color_ptr->red);
5206 green -= ((long)color_ptr->green);
5207 blue -= ((long)color_ptr->blue);
5208 color_ptr = (&tgifColors[gnOrigImageIndex[y-1][x]]);
5209 red -= ((long)color_ptr->red);
5210 green -= ((long)color_ptr->green);
5211 blue -= ((long)color_ptr->blue);
5212 color_ptr = (&tgifColors[gnOrigImageIndex[y+1][x]]);
5213 red = (red - ((long)color_ptr->red)) >> 2;
5214 green = (green - ((long)color_ptr->green)) >> 2;
5215 blue = (blue - ((long)color_ptr->blue)) >> 2;
5216
5217 memset(&xcolor, 0, sizeof(XColor));
5218 xcolor.red = (red > 0L ?
5219 (red > 0x0000ffff ? 0x0ffff : (unsigned int)(red&0xffff)) : 0);
5220 xcolor.green = (green > 0L ?
5221 (green > 0x0000ffff ? 0x0ffff : (unsigned int)(green&0xffff)) : 0);
5222 xcolor.blue = (blue > 0L ?
5223 (blue > 0x0000ffff ? 0x0ffff : (unsigned int)(blue&0xffff)) : 0);
5224 return GetOrAllocHistogramIndex(&xcolor);
5225 }
5226 }
5227
Sharpen()5228 void Sharpen()
5229 {
5230 if (!CheckSelectionForImageProc(CMDID_SHARPEN)) return;
5231 if (topSel->obj->detail.xpm->image_w < 2 ||
5232 topSel->obj->detail.xpm->image_h < 2) {
5233 MsgBox(TgLoadString(STID_SEL_TOO_THIN_FLAT_FOR_SHARPEN), TOOL_NAME,
5234 INFO_MB);
5235 return;
5236 }
5237 gpConvolveFunc = (NLFN*)ConvolveToSharpen;
5238 gpConvolveCmdID = CMDID_SHARPEN;
5239 gnConvolving = TRUE;
5240 DoImageProc(NULL);
5241 gnConvolving = FALSE;
5242 gpConvolveFunc = NULL;
5243 gpConvolveCmdID = (-1);
5244 }
5245
5246 /* ----------------------- Blur3, Blur5, Blur7 ----------------------- */
5247
5248 static int gnBlurSize=1;
5249
5250 static
ConvolveToBlur(x,y)5251 int ConvolveToBlur(x, y)
5252 int x, y;
5253 /*
5254 * [ 1/25 1/25 1/25 ]
5255 * [ 1/9 1/9 1/9 ] [ 1/25 1/25 1/25 ]
5256 * [ 1/9 1/9 1/9 ] [ 1/25 1/25 1/25 ] ...
5257 * [ 1/9 1/9 1/9 ] [ 1/25 1/25 1/25 ]
5258 * [ 1/25 1/25 1/25 ]
5259 */
5260 {
5261 if (gConvExtraInfo.fp != NULL) {
5262 XColor **xcolors=gConvExtraInfo.xcolors;
5263 FILE *fp=gConvExtraInfo.fp;
5264 int w=gConvExtraInfo.image_w, h=gConvExtraInfo.image_h;
5265 unsigned char buf[3];
5266
5267 unsigned int r=0, g=0, b=0;
5268 double dr=(double)0, dg=(double)0, db=(double)0;
5269 int x_index=0, num_cells=0;
5270
5271 for (x_index=x-gnBlurSize; x_index <= x+gnBlurSize; x_index++) {
5272 int y_index=0;
5273
5274 if (x_index >= 0 && x_index < w) {
5275 for (y_index=y-gnBlurSize; y_index <= y+gnBlurSize; y_index++) {
5276 if (y_index >= 0 && y_index < h) {
5277 r += ((int)xcolors[y_index][x_index].red);
5278 g += ((int)xcolors[y_index][x_index].green);
5279 b += ((int)xcolors[y_index][x_index].blue);
5280 num_cells++;
5281 }
5282 }
5283 }
5284 }
5285 dr = ((double)r) / ((double)num_cells);
5286 dg = ((double)g) / ((double)num_cells);
5287 db = ((double)b) / ((double)num_cells);
5288 r = (unsigned int)round(dr);
5289 g = (unsigned int)round(dg);
5290 b = (unsigned int)round(db);
5291 if (r > 255) r = 255;
5292 if (g > 255) g = 255;
5293 if (b > 255) b = 255;
5294
5295 buf[0] = (unsigned char)r;
5296 buf[1] = (unsigned char)g;
5297 buf[2] = (unsigned char)b;
5298
5299 if ((int)fwrite(buf, sizeof(char), 3, fp) <= 0) writeFileFailed = TRUE;
5300
5301 return TRUE;
5302 } else {
5303 register long red=0L, green=0L, blue=0L;
5304 XColor xcolor;
5305 int x_index, array_size=((gnBlurSize<<1)+1);
5306
5307 if (x < gnBlurSize || x >= gnImageW-gnBlurSize ||
5308 y < gnBlurSize || y >= gnImageH-gnBlurSize) {
5309 return GetOrAllocHistogramIndex(&tgifColors[gnOrigImageIndex[y][x]]);
5310 }
5311 for (x_index=x-gnBlurSize; x_index <= x+gnBlurSize; x_index++) {
5312 int y_index;
5313
5314 for (y_index=y-gnBlurSize; y_index <= y+gnBlurSize; y_index++) {
5315 register XColor *color_ptr;
5316
5317 color_ptr = (&tgifColors[gnOrigImageIndex[y_index][x_index]]);
5318 red += ((long)color_ptr->red);
5319 green += ((long)color_ptr->green);
5320 blue += ((long)color_ptr->blue);
5321 }
5322 }
5323 array_size *= array_size;
5324 red /= array_size;
5325 green /= array_size;
5326 blue /= array_size;
5327
5328 memset(&xcolor, 0, sizeof(XColor));
5329 xcolor.red = (red > 0L ?
5330 (red > 0x0000ffff ? 0x0ffff : (unsigned int)(red&0xffff)) : 0);
5331 xcolor.green = (green > 0L ?
5332 (green > 0x0000ffff ? 0x0ffff : (unsigned int)(green&0xffff)) : 0);
5333 xcolor.blue = (blue > 0L ?
5334 (blue > 0x0000ffff ? 0x0ffff : (unsigned int)(blue&0xffff)) : 0);
5335 return GetOrAllocHistogramIndex(&xcolor);
5336 }
5337 }
5338
5339 static
Blur(nSize)5340 void Blur(nSize)
5341 int nSize;
5342 {
5343 int cmdid=CMDID_BLUR3;
5344
5345 switch (nSize) {
5346 case 3: cmdid=CMDID_BLUR3; break;
5347 case 5: cmdid=CMDID_BLUR5; break;
5348 case 7: cmdid=CMDID_BLUR7; break;
5349 }
5350 gnBlurSize = ((nSize-1)>>1);
5351 if (!CheckSelectionForImageProc(cmdid)) return;
5352 if (topSel->obj->detail.xpm->image_w <= gnBlurSize ||
5353 topSel->obj->detail.xpm->image_h <= gnBlurSize) {
5354 sprintf(gszMsgBox, TgLoadString(STID_SEL_TOO_THIN_FLAT_FOR_BLUR),
5355 nSize, nSize);
5356 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
5357 return;
5358 }
5359 gpConvolveFunc = (NLFN*)ConvolveToBlur;
5360 gpConvolveCmdID = CMDID_BLUR3;
5361 gnConvolving = TRUE;
5362 DoImageProc(NULL);
5363 gnConvolving = FALSE;
5364 gpConvolveFunc = NULL;
5365 gpConvolveCmdID = (-1);
5366 }
5367
Blur3()5368 void Blur3() { Blur(3); }
Blur5()5369 void Blur5() { Blur(5); }
Blur7()5370 void Blur7() { Blur(7); }
5371
5372 /* ----------------------- AlphaCombine ----------------------- */
5373
5374 static
PointInRect(x,y,p_bbox)5375 int PointInRect(x, y, p_bbox)
5376 int x, y;
5377 struct BBRec *p_bbox;
5378 {
5379 return (x>=p_bbox->ltx && y>=p_bbox->lty && x<p_bbox->rbx && y<p_bbox->rby);
5380 }
5381
5382 #define INSIDE_NONE 0x0
5383 #define INSIDE_FG 0x1
5384 #define INSIDE_BG 0x2
5385 #define INSIDE_ALPHA 0x4
5386
5387 static
ConvolveToAlphaCombine(x,y)5388 int ConvolveToAlphaCombine(x, y)
5389 int x, y;
5390 {
5391 XColor fg_xcolor, bg_xcolor, alpha_xcolor, xcolor;
5392 int inside_flag=INSIDE_NONE, pixel;
5393 double alpha=(double)0, beta=(double)0;
5394 long red=0L, green=0L, blue=0L;
5395
5396 if (PointInRect(x, y, &gAlphaCombineBBox)) inside_flag |= INSIDE_ALPHA;
5397 if (PointInRect(x, y, &gFgCombineBBox)) inside_flag |= INSIDE_FG;
5398 if (PointInRect(x, y, &gBgCombineBBox)) inside_flag |= INSIDE_BG;
5399
5400 if (gConvExtraInfo.fp != NULL) {
5401 FILE *fp=gConvExtraInfo.fp;
5402 XColor **xcolors=NULL;
5403 int image_x=0, image_y=0;
5404 unsigned int r=0, g=0, b=0;
5405 unsigned char buf[3];
5406
5407 switch (inside_flag) {
5408 case 0x0:
5409 case 0x4: /* INSIDE_ALPHA */
5410 buf[0] = (unsigned char)gConvExtraInfo.my_bg_xcolor.red;
5411 buf[1] = (unsigned char)gConvExtraInfo.my_bg_xcolor.green;
5412 buf[2] = (unsigned char)gConvExtraInfo.my_bg_xcolor.blue;
5413 break;
5414 case 0x1: /* INSIDE_FG */
5415 case 0x3: /* INSIDE_BG | INSIDE_FG */
5416 case 0x5: /* INSIDE_ALPHA | INSIDE_FG */
5417 xcolors = gConvExtraInfo.xcolors;
5418 image_x = x-gFgCombineBBox.ltx;
5419 image_y = y-gFgCombineBBox.lty;
5420 buf[0] = (unsigned char)xcolors[image_y][image_x].red;
5421 buf[1] = (unsigned char)xcolors[image_y][image_x].green;
5422 buf[2] = (unsigned char)xcolors[image_y][image_x].blue;
5423 break;
5424 case 0x2: /* INSIDE_BG */
5425 case 0x6: /* INSIDE_ALPHA | INSIDE_BG */
5426 xcolors = gConvExtraInfo.bg_xcolors;
5427 image_x = x-gBgCombineBBox.ltx;
5428 image_y = y-gBgCombineBBox.lty;
5429 buf[0] = (unsigned char)xcolors[image_y][image_x].red;
5430 buf[1] = (unsigned char)xcolors[image_y][image_x].green;
5431 buf[2] = (unsigned char)xcolors[image_y][image_x].blue;
5432 break;
5433 case 0x7: /* INSIDE_ALPHA | INSIDE_BG | INSIDE_FG */
5434 xcolors = gConvExtraInfo.xcolors;
5435 image_x = x-gFgCombineBBox.ltx;
5436 image_y = y-gFgCombineBBox.lty;
5437 memcpy(&fg_xcolor, &xcolors[image_y][image_x], sizeof(XColor));
5438 xcolors = gConvExtraInfo.bg_xcolors;
5439 image_x = x-gBgCombineBBox.ltx;
5440 image_y = y-gBgCombineBBox.lty;
5441 memcpy(&bg_xcolor, &xcolors[image_y][image_x], sizeof(XColor));
5442 xcolors = gConvExtraInfo.alpha_xcolors;
5443 image_x = x-gAlphaCombineBBox.ltx;
5444 image_y = y-gAlphaCombineBBox.lty;
5445 memcpy(&alpha_xcolor, &xcolors[image_y][image_x], sizeof(XColor));
5446 alpha = (0.299*((double)alpha_xcolor.red) +
5447 0.587*((double)alpha_xcolor.green) +
5448 0.114*((double)alpha_xcolor.blue)) / 255.0;
5449 beta = ((double)1) - alpha;
5450 r = ((double)(fg_xcolor.red)) * alpha +
5451 ((double)(bg_xcolor.red)) * beta;
5452 g = ((double)(fg_xcolor.green)) * alpha +
5453 ((double)(bg_xcolor.green)) * beta;
5454 b = ((double)(fg_xcolor.blue)) * alpha +
5455 ((double)(bg_xcolor.blue)) * beta;
5456 if (r < 0) r = 0;
5457 if (g < 0) g = 0;
5458 if (b < 0) b = 0;
5459 if (r > 255) r = 255;
5460 if (g > 255) g = 255;
5461 if (b > 255) b = 255;
5462 buf[0] = (unsigned char)r;
5463 buf[1] = (unsigned char)g;
5464 buf[2] = (unsigned char)b;
5465 break;
5466 }
5467 if ((int)fwrite(buf, sizeof(char), 3, fp) <= 0) writeFileFailed = TRUE;
5468
5469 return TRUE;
5470 } else {
5471 switch (inside_flag) {
5472 case 0x0:
5473 case 0x4: /* INSIDE_ALPHA */
5474 if (myFileBgColorStr == NULL) {
5475 return GetOrAllocHistogramIndex(&myBgColor);
5476 } else {
5477 return GetOrAllocHistogramIndex(&myFileBgColor);
5478 }
5479 case 0x1:
5480 case 0x3: /* INSIDE_BG | INSIDE_FG */
5481 case 0x5: /* INSIDE_ALPHA | INSIDE_FG */
5482 /* INSIDE_FG */
5483 pixel = XGetPixel(gpFgImage, x-gFgCombineBBox.ltx,
5484 y-gFgCombineBBox.lty);
5485 return GetOrAllocHistogramIndex(&tgifColors[GetIndexOfPixel(pixel)]);
5486 case 0x2: /* INSIDE_BG */
5487 case 0x6: /* INSIDE_ALPHA | INSIDE_BG */
5488 pixel = XGetPixel(gpBgImage, x-gBgCombineBBox.ltx,
5489 y-gBgCombineBBox.lty);
5490 return GetOrAllocHistogramIndex(&tgifColors[GetIndexOfPixel(pixel)]);
5491 case 0x7:
5492 /* INSIDE_ALPHA | INSIDE_BG | INSIDE_FG */
5493 pixel = XGetPixel(gpFgImage, x-gFgCombineBBox.ltx,
5494 y-gFgCombineBBox.lty);
5495 memcpy(&fg_xcolor, &tgifColors[GetIndexOfPixel(pixel)],
5496 sizeof(XColor));
5497 pixel = XGetPixel(gpBgImage, x-gBgCombineBBox.ltx,
5498 y-gBgCombineBBox.lty);
5499 memcpy(&bg_xcolor, &tgifColors[GetIndexOfPixel(pixel)],
5500 sizeof(XColor));
5501 pixel = XGetPixel(gpAlphaImage, x-gAlphaCombineBBox.ltx,
5502 y-gAlphaCombineBBox.lty);
5503 memcpy(&alpha_xcolor, &tgifColors[GetIndexOfPixel(pixel)],
5504 sizeof(XColor));
5505 alpha = ((double)(0.299*((double)alpha_xcolor.red) +
5506 0.587*((double)alpha_xcolor.green) +
5507 0.114*((double)alpha_xcolor.blue))) / 65536.0;
5508 beta = 1.0 - alpha;
5509 red = (long)(((double)fg_xcolor.red)*alpha +
5510 ((double)bg_xcolor.red)*beta);
5511 green = (long)(((double)fg_xcolor.green)*alpha +
5512 ((double)bg_xcolor.green)*beta);
5513 blue = (long)(((double)fg_xcolor.blue)*alpha +
5514 ((double)bg_xcolor.blue)*beta);
5515 break;
5516 }
5517 memset(&xcolor, 0, sizeof(XColor));
5518 xcolor.red = (red > 0L ?
5519 (red > 0x0000ffff ? 0x0ffff : (unsigned int)(red&0xffff)) : 0);
5520 xcolor.green = (green > 0L ?
5521 (green > 0x0000ffff ? 0x0ffff : (unsigned int)(green&0xffff)) : 0);
5522 xcolor.blue = (blue > 0L ?
5523 (blue > 0x0000ffff ? 0x0ffff : (unsigned int)(blue&0xffff)) : 0);
5524 return GetOrAllocHistogramIndex(&xcolor);
5525 }
5526 }
5527
5528 static
OffsetRect(p_bbox,dx,dy)5529 void OffsetRect(p_bbox, dx, dy)
5530 struct BBRec *p_bbox;
5531 int dx, dy;
5532 {
5533 p_bbox->ltx += dx; p_bbox->lty += dy;
5534 p_bbox->rbx += dx; p_bbox->rby += dy;
5535 }
5536
5537 static
CleanUpAlphaCombine()5538 void CleanUpAlphaCombine()
5539 {
5540 if (gpFgImage != NULL) XDestroyImage(gpFgImage);
5541 if (gpBgImage != NULL) XDestroyImage(gpBgImage);
5542 if (gpAlphaImage != NULL) XDestroyImage(gpAlphaImage);
5543 if (gpFgBitmapImage != NULL) XDestroyImage(gpFgBitmapImage);
5544 if (gpBgBitmapImage != NULL) XDestroyImage(gpBgBitmapImage);
5545 if (gpAlphaBitmapImage != NULL) XDestroyImage(gpAlphaBitmapImage);
5546 gpFgImage = gpBgImage = gpAlphaImage =
5547 gpFgBitmapImage = gpBgBitmapImage = gpAlphaBitmapImage = NULL;
5548 gpFgObj = gpBgObj = gpAlphaObj = NULL;
5549 }
5550
5551 static
PrepareForAlphaCombine()5552 int PrepareForAlphaCombine()
5553 {
5554 memcpy(&gFgCombineBBox, &gpFgObj->obbox, sizeof(struct BBRec));
5555 memcpy(&gBgCombineBBox, &gpBgObj->obbox, sizeof(struct BBRec));
5556 if (gpAlphaObj != NULL) {
5557 memcpy(&gAlphaCombineBBox, &gpAlphaObj->obbox, sizeof(struct BBRec));
5558 }
5559 UnionRect(&gFgCombineBBox, &gBgCombineBBox, &gTotalCombineBBox);
5560 if (gpAlphaObj != NULL) {
5561 UnionRect(&gAlphaCombineBBox, &gTotalCombineBBox, &gTotalCombineBBox);
5562 }
5563 gnCombineW = gTotalCombineBBox.rbx - gTotalCombineBBox.ltx;
5564 gnCombineH = gTotalCombineBBox.rby - gTotalCombineBBox.lty;
5565 OffsetRect(&gFgCombineBBox, -gTotalCombineBBox.ltx, -gTotalCombineBBox.lty);
5566 OffsetRect(&gBgCombineBBox, -gTotalCombineBBox.ltx, -gTotalCombineBBox.lty);
5567 if (gpAlphaObj != NULL) {
5568 OffsetRect(&gAlphaCombineBBox,
5569 -gTotalCombineBBox.ltx, -gTotalCombineBBox.lty);
5570 }
5571 gpAlphaImage = gpAlphaBitmapImage = NULL;
5572 if (!GetXPmImages(gpFgObj->detail.xpm, &gpFgImage, &gpFgBitmapImage) ||
5573 !GetXPmImages(gpBgObj->detail.xpm, &gpBgImage, &gpBgBitmapImage) ||
5574 (gpAlphaObj != NULL && !GetXPmImages(gpAlphaObj->detail.xpm,
5575 &gpAlphaImage, &gpAlphaBitmapImage))) {
5576 return FALSE;
5577 }
5578 return TRUE;
5579 }
5580
AlphaCombine()5581 void AlphaCombine()
5582 {
5583 char szBuf[MAXSTRING+1];
5584 int num_objs=0;
5585
5586 strcpy(szBuf, GetImageProcName(CMDID_ALPHACOMBINE));
5587 gpFgObj = gpBgObj = gpAlphaObj = NULL;
5588 if (curChoice == NOTHING && numObjSelected == 3) {
5589 struct SelRec *sel_ptr;
5590 struct ObjRec *obj_ptr;
5591 int ok=TRUE;
5592
5593 for (obj_ptr=topObj; ok && obj_ptr != NULL; obj_ptr=obj_ptr->next) {
5594 for (sel_ptr=topSel; sel_ptr != NULL; sel_ptr=sel_ptr->next) {
5595 if (obj_ptr == sel_ptr->obj) {
5596 if (obj_ptr->type == OBJ_XPM) {
5597 struct XPmRec *xpm_ptr=obj_ptr->detail.xpm;
5598 int image_w=obj_ptr->obbox.rbx-obj_ptr->obbox.ltx;
5599 int image_h=obj_ptr->obbox.rby-obj_ptr->obbox.lty;
5600
5601 if (obj_ptr->ctm != NULL || xpm_ptr->image_w != image_w ||
5602 xpm_ptr->image_h != image_h) {
5603 char szBuf1[MAXSTRING+1];
5604
5605 strcpy(szBuf1,
5606 GetImageProcName(CMDID_REGENERATEIMAGE));
5607 sprintf(gszMsgBox,
5608 TgLoadString(STID_IMAGE_PROC_CANT_USE_XFORMED),
5609 szBuf, szBuf1);
5610 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
5611 return;
5612 }
5613 switch (num_objs++) {
5614 case 0: gpFgObj = obj_ptr; break;
5615 case 1: gpAlphaObj = obj_ptr; break;
5616 case 2: gpBgObj = obj_ptr; break;
5617 }
5618 } else {
5619 ok = FALSE;
5620 break;
5621 }
5622 }
5623 }
5624 }
5625 if (!ok) num_objs = 0;
5626 }
5627 if (num_objs != 3) {
5628 sprintf(gszMsgBox, TgLoadString(STID_SEL_3_XPM_FOR_IMAGEPROC_CMD), szBuf);
5629 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
5630 return;
5631 }
5632 if (PrepareForAlphaCombine()) {
5633 gnCombining = TRUE;
5634 gpConvolveFunc = (NLFN*)ConvolveToAlphaCombine;
5635 gpConvolveCmdID = CMDID_ALPHACOMBINE;
5636 gnConvolving = TRUE;
5637 DoImageProc(NULL);
5638 gnConvolving = FALSE;
5639 gpConvolveFunc = NULL;
5640 gpConvolveCmdID = (-1);
5641 gnCombining = FALSE;
5642 }
5643 CleanUpAlphaCombine();
5644 }
5645
5646 /* ----------------------- Subtract ----------------------- */
5647
5648 static
ConvolveToSubtract(x,y)5649 int ConvolveToSubtract(x, y)
5650 int x, y;
5651 {
5652 XColor fg_xcolor, bg_xcolor, xcolor;
5653 int inside_flag=INSIDE_NONE, pixel;
5654 long red=0L, green=0L, blue=0L;
5655
5656 if (PointInRect(x, y, &gFgCombineBBox)) inside_flag |= INSIDE_FG;
5657 if (PointInRect(x, y, &gBgCombineBBox)) inside_flag |= INSIDE_BG;
5658
5659 if (gConvExtraInfo.fp != NULL) {
5660 FILE *fp=gConvExtraInfo.fp;
5661 XColor **xcolors=NULL;
5662 int r=0, g=0, b=0, image_x=0, image_y=0;
5663 unsigned char buf[3];
5664
5665 switch (inside_flag) {
5666 case 0x0:
5667 buf[0] = (unsigned char)gConvExtraInfo.my_bg_xcolor.red;
5668 buf[1] = (unsigned char)gConvExtraInfo.my_bg_xcolor.green;
5669 buf[2] = (unsigned char)gConvExtraInfo.my_bg_xcolor.blue;
5670 break;
5671 case 0x1:
5672 /* INSIDE_FG */
5673 xcolors = gConvExtraInfo.xcolors;
5674 image_x = x-gFgCombineBBox.ltx;
5675 image_y = y-gFgCombineBBox.lty;
5676 buf[0] = (unsigned char)xcolors[image_y][image_x].red;
5677 buf[1] = (unsigned char)xcolors[image_y][image_x].green;
5678 buf[2] = (unsigned char)xcolors[image_y][image_x].blue;
5679 break;
5680 case 0x2:
5681 /* INSIDE_BG */
5682 xcolors = gConvExtraInfo.bg_xcolors;
5683 image_x = x-gBgCombineBBox.ltx;
5684 image_y = y-gBgCombineBBox.lty;
5685 buf[0] = (unsigned char)xcolors[image_y][image_x].red;
5686 buf[1] = (unsigned char)xcolors[image_y][image_x].green;
5687 buf[2] = (unsigned char)xcolors[image_y][image_x].blue;
5688 break;
5689 case 0x3:
5690 /* INSIDE_BG | INSIDE_FG */
5691 xcolors = gConvExtraInfo.xcolors;
5692 image_x = x-gFgCombineBBox.ltx;
5693 image_y = y-gFgCombineBBox.lty;
5694 memcpy(&fg_xcolor, &xcolors[image_y][image_x], sizeof(XColor));
5695 xcolors = gConvExtraInfo.bg_xcolors;
5696 image_x = x-gBgCombineBBox.ltx;
5697 image_y = y-gBgCombineBBox.lty;
5698 memcpy(&bg_xcolor, &xcolors[image_y][image_x], sizeof(XColor));
5699 r = ((int)fg_xcolor.red) - ((int)bg_xcolor.red);
5700 g = ((int)fg_xcolor.green) - ((int)bg_xcolor.green);
5701 b = ((int)fg_xcolor.blue) - ((int)bg_xcolor.blue);
5702 if (r < 0) r = 0;
5703 if (g < 0) g = 0;
5704 if (b < 0) b = 0;
5705 if (r > 255) r = 255;
5706 if (g > 255) g = 255;
5707 if (b > 255) b = 255;
5708 buf[0] = (unsigned char)r;
5709 buf[1] = (unsigned char)g;
5710 buf[2] = (unsigned char)b;
5711 break;
5712 }
5713 if ((int)fwrite(buf, sizeof(char), 3, fp) <= 0) writeFileFailed = TRUE;
5714
5715 return TRUE;
5716 } else {
5717 switch (inside_flag) {
5718 case 0x0:
5719 if (myFileBgColorStr == NULL) {
5720 return GetOrAllocHistogramIndex(&myBgColor);
5721 } else {
5722 return GetOrAllocHistogramIndex(&myFileBgColor);
5723 }
5724 case 0x1:
5725 /* INSIDE_FG */
5726 pixel = XGetPixel(gpFgImage, x-gFgCombineBBox.ltx,
5727 y-gFgCombineBBox.lty);
5728 memcpy(&fg_xcolor, &tgifColors[GetIndexOfPixel(pixel)],
5729 sizeof(XColor));
5730 red = (long)fg_xcolor.red;
5731 green = (long)fg_xcolor.green;
5732 blue = (long)fg_xcolor.blue;
5733 break;
5734 case 0x2:
5735 /* INSIDE_BG */
5736 pixel = XGetPixel(gpBgImage, x-gBgCombineBBox.ltx,
5737 y-gBgCombineBBox.lty);
5738 memcpy(&bg_xcolor, &tgifColors[GetIndexOfPixel(pixel)],
5739 sizeof(XColor));
5740 red = (long)bg_xcolor.red;
5741 green = (long)bg_xcolor.green;
5742 blue = (long)bg_xcolor.blue;
5743 break;
5744 case 0x3:
5745 /* INSIDE_BG | INSIDE_FG */
5746 pixel = XGetPixel(gpFgImage, x-gFgCombineBBox.ltx,
5747 y-gFgCombineBBox.lty);
5748 memcpy(&fg_xcolor, &tgifColors[GetIndexOfPixel(pixel)],
5749 sizeof(XColor));
5750 pixel = XGetPixel(gpBgImage, x-gBgCombineBBox.ltx,
5751 y-gBgCombineBBox.lty);
5752 memcpy(&bg_xcolor, &tgifColors[GetIndexOfPixel(pixel)],
5753 sizeof(XColor));
5754 red = ((long)fg_xcolor.red) - ((long)bg_xcolor.red);
5755 green = ((long)fg_xcolor.green) - ((long)bg_xcolor.green);
5756 blue = ((long)fg_xcolor.blue) - ((long)bg_xcolor.blue);
5757 break;
5758 }
5759 memset(&xcolor, 0, sizeof(XColor));
5760 xcolor.red = (red > 0L ?
5761 (red > 0x0000ffff ? 0x0ffff : (unsigned int)(red&0xffff)) : 0);
5762 xcolor.green = (green > 0L ?
5763 (green > 0x0000ffff ? 0x0ffff : (unsigned int)(green&0xffff)) : 0);
5764 xcolor.blue = (blue > 0L ?
5765 (blue > 0x0000ffff ? 0x0ffff : (unsigned int)(blue&0xffff)) : 0);
5766 return GetOrAllocHistogramIndex(&xcolor);
5767 }
5768 }
5769
Subtract()5770 void Subtract()
5771 {
5772 char szBuf[MAXSTRING+1];
5773 int num_objs=0;
5774
5775 strcpy(szBuf, GetImageProcName(CMDID_SUBTRACT));
5776 gpFgObj = gpBgObj = gpAlphaObj = NULL;
5777 if (curChoice == NOTHING && numObjSelected == 2) {
5778 struct SelRec *sel_ptr;
5779 struct ObjRec *obj_ptr;
5780 int ok=TRUE;
5781
5782 for (obj_ptr=topObj; ok && obj_ptr != NULL; obj_ptr=obj_ptr->next) {
5783 for (sel_ptr=topSel; sel_ptr != NULL; sel_ptr=sel_ptr->next) {
5784 if (obj_ptr == sel_ptr->obj) {
5785 if (obj_ptr->type == OBJ_XPM) {
5786 struct XPmRec *xpm_ptr=obj_ptr->detail.xpm;
5787 int image_w=obj_ptr->obbox.rbx-obj_ptr->obbox.ltx;
5788 int image_h=obj_ptr->obbox.rby-obj_ptr->obbox.lty;
5789
5790 if (obj_ptr->ctm != NULL || xpm_ptr->image_w != image_w ||
5791 xpm_ptr->image_h != image_h) {
5792 char szBuf1[MAXSTRING+1];
5793
5794 strcpy(szBuf1,
5795 GetImageProcName(CMDID_REGENERATEIMAGE));
5796 sprintf(gszMsgBox,
5797 TgLoadString(STID_IMAGE_PROC_CANT_USE_XFORMED),
5798 szBuf, szBuf1);
5799 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
5800 return;
5801 }
5802 switch (num_objs++) {
5803 case 0: gpFgObj = obj_ptr; break;
5804 case 1: gpBgObj = obj_ptr; break;
5805 }
5806 } else {
5807 ok = FALSE;
5808 break;
5809 }
5810 }
5811 }
5812 }
5813 if (!ok) num_objs = 0;
5814 }
5815 if (num_objs != 2) {
5816 sprintf(gszMsgBox, TgLoadString(STID_SEL_2_XPM_FOR_IMAGEPROC_CMD), szBuf);
5817 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
5818 return;
5819 }
5820 if (PrepareForAlphaCombine()) {
5821 gnCombining = TRUE;
5822 gpConvolveFunc = (NLFN*)ConvolveToSubtract;
5823 gpConvolveCmdID = CMDID_SUBTRACT;
5824 gnConvolving = TRUE;
5825 DoImageProc(NULL);
5826 gnConvolving = FALSE;
5827 gpConvolveFunc = NULL;
5828 gpConvolveCmdID = (-1);
5829 gnCombining = FALSE;
5830 }
5831 CleanUpAlphaCombine();
5832 }
5833
5834 /* ----------------------- XorColors ----------------------- */
5835
5836 static
ConvolveToXorColors(x,y)5837 int ConvolveToXorColors(x, y)
5838 int x, y;
5839 {
5840 XColor fg_xcolor, bg_xcolor, xcolor;
5841 int inside_flag=INSIDE_NONE, pixel=0;
5842
5843 memset(&xcolor, 0, sizeof(XColor));
5844
5845 if (PointInRect(x, y, &gFgCombineBBox)) inside_flag |= INSIDE_FG;
5846 if (PointInRect(x, y, &gBgCombineBBox)) inside_flag |= INSIDE_BG;
5847
5848 if (gConvExtraInfo.fp != NULL) {
5849 FILE *fp=gConvExtraInfo.fp;
5850 XColor **xcolors=NULL;
5851 int image_x=0, image_y=0;
5852 unsigned int r=0, g=0, b=0;
5853 unsigned char buf[3];
5854
5855 switch (inside_flag) {
5856 case 0x0:
5857 buf[0] = (unsigned char)gConvExtraInfo.my_bg_xcolor.red;
5858 buf[1] = (unsigned char)gConvExtraInfo.my_bg_xcolor.green;
5859 buf[2] = (unsigned char)gConvExtraInfo.my_bg_xcolor.blue;
5860 break;
5861 case 0x1:
5862 /* INSIDE_FG */
5863 xcolors = gConvExtraInfo.xcolors;
5864 image_x = x-gFgCombineBBox.ltx;
5865 image_y = y-gFgCombineBBox.lty;
5866 buf[0] = (unsigned char)xcolors[image_y][image_x].red;
5867 buf[1] = (unsigned char)xcolors[image_y][image_x].green;
5868 buf[2] = (unsigned char)xcolors[image_y][image_x].blue;
5869 break;
5870 case 0x2:
5871 /* INSIDE_BG */
5872 xcolors = gConvExtraInfo.bg_xcolors;
5873 image_x = x-gBgCombineBBox.ltx;
5874 image_y = y-gBgCombineBBox.lty;
5875 buf[0] = (unsigned char)xcolors[image_y][image_x].red;
5876 buf[1] = (unsigned char)xcolors[image_y][image_x].green;
5877 buf[2] = (unsigned char)xcolors[image_y][image_x].blue;
5878 break;
5879 case 0x3:
5880 /* INSIDE_BG | INSIDE_FG */
5881 xcolors = gConvExtraInfo.xcolors;
5882 image_x = x-gFgCombineBBox.ltx;
5883 image_y = y-gFgCombineBBox.lty;
5884 memcpy(&fg_xcolor, &xcolors[image_y][image_x], sizeof(XColor));
5885 xcolors = gConvExtraInfo.bg_xcolors;
5886 image_x = x-gBgCombineBBox.ltx;
5887 image_y = y-gBgCombineBBox.lty;
5888 memcpy(&bg_xcolor, &xcolors[image_y][image_x], sizeof(XColor));
5889 r = (unsigned int)((fg_xcolor.red) ^ (bg_xcolor.red));
5890 g = (unsigned int)((fg_xcolor.green) ^ (bg_xcolor.green));
5891 b = (unsigned int)((fg_xcolor.blue) ^ (bg_xcolor.blue));
5892 if (r < 0) r = 0;
5893 if (g < 0) g = 0;
5894 if (b < 0) b = 0;
5895 if (r > 255) r = 255;
5896 if (g > 255) g = 255;
5897 if (b > 255) b = 255;
5898 buf[0] = (unsigned char)r;
5899 buf[1] = (unsigned char)g;
5900 buf[2] = (unsigned char)b;
5901 break;
5902 }
5903 if ((int)fwrite(buf, sizeof(char), 3, fp) <= 0) writeFileFailed = TRUE;
5904
5905 return TRUE;
5906 } else {
5907 switch (inside_flag) {
5908 case 0x0:
5909 if (myFileBgColorStr == NULL) {
5910 return GetOrAllocHistogramIndex(&myBgColor);
5911 } else {
5912 return GetOrAllocHistogramIndex(&myFileBgColor);
5913 }
5914 case 0x1:
5915 /* INSIDE_FG */
5916 pixel = XGetPixel(gpFgImage, x-gFgCombineBBox.ltx,
5917 y-gFgCombineBBox.lty);
5918 memcpy(&fg_xcolor, &tgifColors[GetIndexOfPixel(pixel)],
5919 sizeof(XColor));
5920 xcolor.red = fg_xcolor.red;
5921 xcolor.green = fg_xcolor.green;
5922 xcolor.blue = fg_xcolor.blue;
5923 break;
5924 case 0x2:
5925 /* INSIDE_BG */
5926 pixel = XGetPixel(gpBgImage, x-gBgCombineBBox.ltx,
5927 y-gBgCombineBBox.lty);
5928 memcpy(&bg_xcolor, &tgifColors[GetIndexOfPixel(pixel)],
5929 sizeof(XColor));
5930 xcolor.red = bg_xcolor.red;
5931 xcolor.green = bg_xcolor.green;
5932 xcolor.blue = bg_xcolor.blue;
5933 break;
5934 case 0x3:
5935 /* INSIDE_BG | INSIDE_FG */
5936 pixel = XGetPixel(gpFgImage, x-gFgCombineBBox.ltx,
5937 y-gFgCombineBBox.lty);
5938 memcpy(&fg_xcolor, &tgifColors[GetIndexOfPixel(pixel)],
5939 sizeof(XColor));
5940 pixel = XGetPixel(gpBgImage, x-gBgCombineBBox.ltx,
5941 y-gBgCombineBBox.lty);
5942 memcpy(&bg_xcolor, &tgifColors[GetIndexOfPixel(pixel)],
5943 sizeof(XColor));
5944 xcolor.red = (fg_xcolor.red) ^ (bg_xcolor.red);
5945 xcolor.green = (fg_xcolor.green) ^ (bg_xcolor.green);
5946 xcolor.blue = (fg_xcolor.blue) ^ (bg_xcolor.blue);
5947 break;
5948 }
5949 return GetOrAllocHistogramIndex(&xcolor);
5950 }
5951 }
5952
XorColors()5953 void XorColors()
5954 {
5955 char szBuf[MAXSTRING+1];
5956 int num_objs=0;
5957
5958 strcpy(szBuf, GetImageProcName(CMDID_XORCOLORS));
5959 gpFgObj = gpBgObj = gpAlphaObj = NULL;
5960 if (curChoice == NOTHING && numObjSelected == 2) {
5961 struct SelRec *sel_ptr;
5962 struct ObjRec *obj_ptr;
5963 int ok=TRUE;
5964
5965 for (obj_ptr=topObj; ok && obj_ptr != NULL; obj_ptr=obj_ptr->next) {
5966 for (sel_ptr=topSel; sel_ptr != NULL; sel_ptr=sel_ptr->next) {
5967 if (obj_ptr == sel_ptr->obj) {
5968 if (obj_ptr->type == OBJ_XPM) {
5969 struct XPmRec *xpm_ptr=obj_ptr->detail.xpm;
5970 int image_w=obj_ptr->obbox.rbx-obj_ptr->obbox.ltx;
5971 int image_h=obj_ptr->obbox.rby-obj_ptr->obbox.lty;
5972
5973 if (obj_ptr->ctm != NULL || xpm_ptr->image_w != image_w ||
5974 xpm_ptr->image_h != image_h) {
5975 char szBuf1[MAXSTRING+1];
5976
5977 strcpy(szBuf1,
5978 GetImageProcName(CMDID_REGENERATEIMAGE));
5979 sprintf(gszMsgBox,
5980 TgLoadString(STID_IMAGE_PROC_CANT_USE_XFORMED),
5981 szBuf, szBuf1);
5982 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
5983 return;
5984 }
5985 switch (num_objs++) {
5986 case 0: gpFgObj = obj_ptr; break;
5987 case 1: gpBgObj = obj_ptr; break;
5988 }
5989 } else {
5990 ok = FALSE;
5991 break;
5992 }
5993 }
5994 }
5995 }
5996 if (!ok) num_objs = 0;
5997 }
5998 if (num_objs != 2) {
5999 sprintf(gszMsgBox, TgLoadString(STID_SEL_2_XPM_FOR_IMAGEPROC_CMD), szBuf);
6000 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
6001 return;
6002 }
6003 if (PrepareForAlphaCombine()) {
6004 gnCombining = TRUE;
6005 gpConvolveFunc = (NLFN*)ConvolveToXorColors;
6006 gpConvolveCmdID = CMDID_XORCOLORS;
6007 gnConvolving = TRUE;
6008 DoImageProc(NULL);
6009 gnConvolving = FALSE;
6010 gpConvolveFunc = NULL;
6011 gpConvolveCmdID = (-1);
6012 gnCombining = FALSE;
6013 }
6014 CleanUpAlphaCombine();
6015 }
6016
6017 /* ======================= Image Warping ======================= */
6018
6019 /* ----------------------- VectorWarp ----------------------- */
6020
6021 typedef struct RevWarpXformRec {
6022 /*
6023 * x = X + x_coef ( X + w - f(x)W ) ( Y + h - g(y)H )
6024 * y = Y + y_coef ( X + w - f(x)W ) ( Y + h - g(y)H )
6025 *
6026 * [ 00 | 10 ]
6027 * where f(x)g(y) = [ ---+--- ]
6028 * [ 01 | 11 ]
6029 *
6030 * X and Y are in the warped domain and x and y are in the original domain
6031 *
6032 * x_coef = -dw / ( ( w + dw - f(x)W ) ( h + dh - g(y)H ) )
6033 * y_coef = -dh / ( ( w + dw - f(x)W ) ( h + dh - g(y)H ) )
6034 *
6035 * Nevertheless, this structure is not used!
6036 */
6037 double x_coef, y_coef;
6038 } RevWarpXform;
6039
6040 static IntPoint gaTrapMapPt[5];
6041 static TrapMapSeg gaTrapMapSeg[4];
6042 static int gaTrapMapLeaf[4];
6043
6044 static TrapMapSpec gLeftTrapMapSpec[] = {
6045 /*
6046 * In-order specification of the trapezoidal map for Cx < Tx.
6047 */
6048 { TRAP_NODE_PT, TRAP_PT_C },
6049 { TRAP_NODE_SEG, TRAP_SEG_L },
6050 { TRAP_NODE_LEAF, TRAP_LEAF_LT },
6051 { TRAP_NODE_LEAF, TRAP_LEAF_LB },
6052 { TRAP_NODE_PT, TRAP_PT_T },
6053 { TRAP_NODE_SEG, TRAP_SEG_T },
6054 { TRAP_NODE_LEAF, TRAP_LEAF_LT },
6055 { TRAP_NODE_SEG, TRAP_SEG_R },
6056 { TRAP_NODE_LEAF, TRAP_LEAF_RT },
6057 { TRAP_NODE_SEG, TRAP_SEG_B },
6058 { TRAP_NODE_LEAF, TRAP_LEAF_RB },
6059 { TRAP_NODE_LEAF, TRAP_LEAF_LB },
6060 { TRAP_NODE_SEG, TRAP_SEG_R },
6061 { TRAP_NODE_LEAF, TRAP_LEAF_RT },
6062 { TRAP_NODE_LEAF, TRAP_LEAF_RB },
6063 { -1, -1 }
6064 };
6065
6066 static TrapMapSpec gRightTrapMapSpec[] = {
6067 /*
6068 * In-order specification of the trapezoidal map for Cx > Tx.
6069 */
6070 { TRAP_NODE_PT, TRAP_PT_T },
6071 { TRAP_NODE_SEG, TRAP_SEG_L },
6072 { TRAP_NODE_LEAF, TRAP_LEAF_LT },
6073 { TRAP_NODE_LEAF, TRAP_LEAF_LB },
6074 { TRAP_NODE_PT, TRAP_PT_C },
6075 { TRAP_NODE_SEG, TRAP_SEG_T },
6076 { TRAP_NODE_LEAF, TRAP_LEAF_RT },
6077 { TRAP_NODE_SEG, TRAP_SEG_L },
6078 { TRAP_NODE_LEAF, TRAP_LEAF_LT },
6079 { TRAP_NODE_SEG, TRAP_SEG_B },
6080 { TRAP_NODE_LEAF, TRAP_LEAF_LB },
6081 { TRAP_NODE_LEAF, TRAP_LEAF_RB },
6082 { TRAP_NODE_SEG, TRAP_SEG_R },
6083 { TRAP_NODE_LEAF, TRAP_LEAF_RT },
6084 { TRAP_NODE_LEAF, TRAP_LEAF_RB },
6085 { -1, -1 }
6086 };
6087
6088 static TrapMapSpec gCenterTrapMapSpec[] = {
6089 /*
6090 * In-order specification of the trapezoidal map for Cx == Tx.
6091 */
6092 { TRAP_NODE_PT, TRAP_PT_T },
6093 { TRAP_NODE_SEG, TRAP_SEG_L },
6094 { TRAP_NODE_LEAF, TRAP_LEAF_LT },
6095 { TRAP_NODE_LEAF, TRAP_LEAF_LB },
6096 { TRAP_NODE_SEG, TRAP_SEG_R },
6097 { TRAP_NODE_LEAF, TRAP_LEAF_RT },
6098 { TRAP_NODE_LEAF, TRAP_LEAF_RB },
6099 { -1, -1 }
6100 };
6101
6102 static TrapMap *gpTrapMap=NULL;
6103 static TrapMapSpec *gpTrapMapSpec=NULL;
6104 static int **gpSegYIntersects=NULL;
6105 static int **gpExtraYIntersects=NULL;
6106
6107 static
CleanTrapMapNode(pTrapMapNode)6108 void CleanTrapMapNode(pTrapMapNode)
6109 TrapMap *pTrapMapNode;
6110 {
6111 switch (pTrapMapNode->type) {
6112 case TRAP_NODE_LEAF: break;
6113 case TRAP_NODE_PT:
6114 if (pTrapMapNode->detail.pt.left != NULL) {
6115 CleanTrapMapNode(pTrapMapNode->detail.pt.left);
6116 }
6117 if (pTrapMapNode->detail.pt.right != NULL) {
6118 CleanTrapMapNode(pTrapMapNode->detail.pt.right);
6119 }
6120 break;
6121 case TRAP_NODE_SEG:
6122 if (pTrapMapNode->detail.seg.above != NULL) {
6123 CleanTrapMapNode(pTrapMapNode->detail.seg.above);
6124 }
6125 if (pTrapMapNode->detail.seg.below != NULL) {
6126 CleanTrapMapNode(pTrapMapNode->detail.seg.below);
6127 }
6128 break;
6129 }
6130 free(pTrapMapNode);
6131 }
6132
6133 static
CleanTrapMap()6134 void CleanTrapMap()
6135 {
6136 if (gpTrapMap != NULL) {
6137 CleanTrapMapNode(gpTrapMap);
6138 }
6139 gpTrapMap = NULL;
6140 if (gpSegYIntersects != NULL) {
6141 int i;
6142
6143 for (i=0; i < 4; i++) {
6144 if (gpSegYIntersects[i] != NULL) {
6145 free(gpSegYIntersects[i]);
6146 }
6147 }
6148 free(gpSegYIntersects);
6149 gpSegYIntersects = NULL;
6150 }
6151 if (gpExtraYIntersects != NULL) {
6152 int i;
6153
6154 for (i=0; i < 4; i++) {
6155 if (gpExtraYIntersects[i] != NULL) {
6156 free(gpExtraYIntersects[i]);
6157 }
6158 }
6159 free(gpExtraYIntersects);
6160 gpExtraYIntersects = NULL;
6161 }
6162 }
6163
6164 static
SetTrapMapLeaf(pTrapMapSpecRoot,pnIndex,pTrapMapNode,nWhich)6165 int SetTrapMapLeaf(pTrapMapSpecRoot, pnIndex, pTrapMapNode, nWhich)
6166 TrapMapSpec *pTrapMapSpecRoot;
6167 int *pnIndex;
6168 TrapMap *pTrapMapNode;
6169 int nWhich;
6170 {
6171 pTrapMapNode->type = TRAP_NODE_LEAF;
6172 pTrapMapNode->detail.leaf.which = nWhich;
6173 pTrapMapNode->detail.leaf.data = (&gaTrapMapLeaf[nWhich]);
6174 return TRUE;
6175 }
6176
6177 static
SetTrapMapPt(pTrapMapSpecRoot,pnIndex,pTrapMapNode,nWhich)6178 int SetTrapMapPt(pTrapMapSpecRoot, pnIndex, pTrapMapNode, nWhich)
6179 TrapMapSpec *pTrapMapSpecRoot;
6180 int *pnIndex;
6181 TrapMap *pTrapMapNode;
6182 int nWhich;
6183 {
6184 pTrapMapNode->type = TRAP_NODE_PT;
6185 pTrapMapNode->detail.pt.which = nWhich;
6186 pTrapMapNode->detail.pt.data = (&gaTrapMapPt[nWhich]);
6187 pTrapMapNode->detail.pt.left = (TrapMap*)malloc(sizeof(TrapMap));
6188 pTrapMapNode->detail.pt.right = (TrapMap*)malloc(sizeof(TrapMap));
6189 if (pTrapMapNode->detail.pt.left == NULL ||
6190 pTrapMapNode->detail.pt.right == NULL) {
6191 FailAllocMessage();
6192 }
6193 memset(pTrapMapNode->detail.pt.left, 0, sizeof(TrapMap));
6194 memset(pTrapMapNode->detail.pt.right, 0, sizeof(TrapMap));
6195 (*pnIndex)++;
6196 if (!BuildTrapMapNode(pTrapMapSpecRoot, pnIndex,
6197 pTrapMapNode->detail.pt.left)) {
6198 return FALSE;
6199 }
6200 (*pnIndex)++;
6201 if (!BuildTrapMapNode(pTrapMapSpecRoot, pnIndex,
6202 pTrapMapNode->detail.pt.right)) {
6203 return FALSE;
6204 }
6205 return TRUE;
6206 }
6207
6208 static
SetTrapMapSeg(pTrapMapSpecRoot,pnIndex,pTrapMapNode,nWhich)6209 int SetTrapMapSeg(pTrapMapSpecRoot, pnIndex, pTrapMapNode, nWhich)
6210 TrapMapSpec *pTrapMapSpecRoot;
6211 int *pnIndex;
6212 TrapMap *pTrapMapNode;
6213 int nWhich;
6214 {
6215 pTrapMapNode->type = TRAP_NODE_SEG;
6216 pTrapMapNode->detail.seg.which = nWhich;
6217 pTrapMapNode->detail.seg.data = (&gaTrapMapSeg[nWhich]);
6218 pTrapMapNode->detail.seg.above = (TrapMap*)malloc(sizeof(TrapMap));
6219 pTrapMapNode->detail.seg.below = (TrapMap*)malloc(sizeof(TrapMap));
6220 if (pTrapMapNode->detail.seg.above == NULL ||
6221 pTrapMapNode->detail.seg.below == NULL) {
6222 FailAllocMessage();
6223 }
6224 memset(pTrapMapNode->detail.seg.above, 0, sizeof(TrapMap));
6225 memset(pTrapMapNode->detail.seg.below, 0, sizeof(TrapMap));
6226 (*pnIndex)++;
6227 if (!BuildTrapMapNode(pTrapMapSpecRoot, pnIndex,
6228 pTrapMapNode->detail.seg.above)) {
6229 return FALSE;
6230 }
6231 (*pnIndex)++;
6232 if (!BuildTrapMapNode(pTrapMapSpecRoot, pnIndex,
6233 pTrapMapNode->detail.seg.below)) {
6234 return FALSE;
6235 }
6236 return TRUE;
6237 }
6238
BuildTrapMapNode(pTrapMapSpecRoot,pnIndex,pTrapMapNode)6239 int BuildTrapMapNode(pTrapMapSpecRoot, pnIndex, pTrapMapNode)
6240 TrapMapSpec *pTrapMapSpecRoot;
6241 int *pnIndex;
6242 TrapMap *pTrapMapNode;
6243 {
6244 TrapMapSpec *pTrapMapSpec=(&pTrapMapSpecRoot[*pnIndex]);
6245
6246 switch (pTrapMapSpec->type) {
6247 case TRAP_NODE_LEAF:
6248 return SetTrapMapLeaf(pTrapMapSpecRoot, pnIndex, pTrapMapNode,
6249 pTrapMapSpec->which);
6250 case TRAP_NODE_PT:
6251 return SetTrapMapPt(pTrapMapSpecRoot, pnIndex, pTrapMapNode,
6252 pTrapMapSpec->which);
6253 case TRAP_NODE_SEG:
6254 return SetTrapMapSeg(pTrapMapSpecRoot, pnIndex, pTrapMapNode,
6255 pTrapMapSpec->which);
6256 default: break;
6257 }
6258 return TRUE;
6259 }
6260
6261 static
BuildTrapMap(pTrapMapSpec)6262 int BuildTrapMap(pTrapMapSpec)
6263 TrapMapSpec *pTrapMapSpec;
6264 {
6265 int nIndex=0;
6266
6267 gpTrapMap = (TrapMap*)malloc(sizeof(TrapMap));
6268 if (gpTrapMap == NULL) FailAllocMessage();
6269 memset(gpTrapMap, 0, sizeof(TrapMap));
6270 if (BuildTrapMapNode(pTrapMapSpec, &nIndex, gpTrapMap)) {
6271 return TRUE;
6272 }
6273 CleanTrapMap();
6274 return FALSE;
6275 }
6276
6277 /*
6278 * L, T, R, B, C are points. Left subtree are to the left of the point.
6279 * sL, sT, sR, sB are line segments. Left subtree are above the line segment.
6280 * lt, rt, lb, rb are the quardrants (leaves of the tree).
6281 *
6282 * If Cx == Tx && Cy == Ly: Do not warp.
6283 *
6284 * If Cx < Tx:
6285 *
6286 * +-------T-------+ C
6287 * | | / \
6288 * | sT | / \
6289 * | | / \
6290 * | C sR | sL T
6291 * L sL R / \ / \
6292 * | | lt lb / \
6293 * | sB | / \
6294 * | | sT sR
6295 * | | / \ / \
6296 * +-------B-------+ lt sR rt rb
6297 * / \
6298 * rt sB
6299 * / \
6300 * rb lb
6301 * If Cx > Tx:
6302 *
6303 * +-------T-------+ T
6304 * | | / \
6305 * | sT | / \
6306 * | | / \
6307 * | sL C | sL C
6308 * L sR R / \ / \
6309 * | | lt lb / \
6310 * | sB | / \
6311 * | | sT sR
6312 * | | / \ / \
6313 * +-------B-------+ rt sL rt rb
6314 * / \
6315 * lt sB
6316 * / \
6317 * lb rb
6318 * If Cx == Tx:
6319 *
6320 * +-------T-------+ T
6321 * | | / \
6322 * | sT | / \
6323 * | | / \
6324 * | sL C sR | sL sR
6325 * L R / \ / \
6326 * | | lt lb rt rb
6327 * | sB |
6328 * | |
6329 * | |
6330 * +-------B-------+
6331 */
6332
6333 static int **gnVectorWarpImageSrcIndex=NULL;
6334 static int **gnVectorWarpImageDestIndex=NULL;
6335
6336 static
ConvolveToVectorWarp(x,y)6337 int ConvolveToVectorWarp(x, y)
6338 int x, y;
6339 {
6340 if (gConvExtraInfo.fp != NULL) {
6341 XColor **xcolors=gConvExtraInfo.xcolors;
6342 FILE *fp=gConvExtraInfo.fp;
6343 unsigned char buf[3];
6344
6345 buf[0] = (unsigned char)xcolors[y][x].red;
6346 buf[1] = (unsigned char)xcolors[y][x].green;
6347 buf[2] = (unsigned char)xcolors[y][x].blue;
6348
6349 if ((int)fwrite(buf, sizeof(char), 3, fp) <= 0) writeFileFailed = TRUE;
6350
6351 return TRUE;
6352 } else {
6353 return GetOrAllocHistogramIndex(
6354 &tgifColors[gnVectorWarpImageDestIndex[y][x]]);
6355 }
6356 }
6357
6358 static
CleanUpVectorWarpData()6359 void CleanUpVectorWarpData()
6360 {
6361 int i, image_h=topSel->obj->detail.xpm->image_h;
6362
6363 if (gnVectorWarpImageSrcIndex != NULL) {
6364 for (i=0; i < image_h; i++) {
6365 if (gnVectorWarpImageSrcIndex[i] != NULL) {
6366 free(gnVectorWarpImageSrcIndex[i]);
6367 }
6368 }
6369 free(gnVectorWarpImageSrcIndex);
6370 gnVectorWarpImageSrcIndex = NULL;
6371 }
6372 if (gnVectorWarpImageDestIndex != NULL) {
6373 for (i=0; i < image_h; i++) {
6374 if (gnVectorWarpImageDestIndex[i] != NULL) {
6375 free(gnVectorWarpImageDestIndex[i]);
6376 }
6377 }
6378 free(gnVectorWarpImageDestIndex);
6379 gnVectorWarpImageDestIndex = NULL;
6380 }
6381 }
6382
6383 static
SetTrapMapSegValue(nSegIndex,nPtIndex,w)6384 void SetTrapMapSegValue(nSegIndex, nPtIndex, w)
6385 int nSegIndex, nPtIndex, w;
6386 {
6387 int i;
6388 double dx=(double)0.0, dy, m, b;
6389
6390 dy = (double)(gaTrapMapPt[TRAP_PT_C].y - gaTrapMapPt[nPtIndex].y);
6391 if (gaTrapMapPt[TRAP_PT_C].x == gaTrapMapPt[nPtIndex].x) {
6392 dx = (double)0.0;
6393 m = (double)0.0;
6394 } else {
6395 dx = (double)(gaTrapMapPt[TRAP_PT_C].x - gaTrapMapPt[nPtIndex].x);
6396 m = ((double)dy) / ((double)dx);
6397 }
6398 b = ((double)(gaTrapMapPt[TRAP_PT_C].y)) -
6399 m * ((double)(gaTrapMapPt[TRAP_PT_C].x));
6400 gaTrapMapSeg[nSegIndex].m = m;
6401 gaTrapMapSeg[nSegIndex].b = b;
6402 for (i=0; i < w; i++) {
6403 double y=m*((double)(i))+b;
6404
6405 gpSegYIntersects[nSegIndex][i] = round(y);
6406 }
6407 }
6408
6409 static
SetTrapMapExtraValue(nLeafIndex,end_x,end_y,w)6410 void SetTrapMapExtraValue(nLeafIndex, end_x, end_y, w)
6411 int nLeafIndex, end_x, end_y, w;
6412 {
6413 int i;
6414 double dx=(double)0.0, dy, m, b;
6415
6416 dy = (double)(gaTrapMapPt[TRAP_PT_C].y - end_y);
6417 if (gaTrapMapPt[TRAP_PT_C].x == end_x) {
6418 dx = (double)0.0;
6419 m = (double)0.0;
6420 } else {
6421 dx = (double)(gaTrapMapPt[TRAP_PT_C].x - end_x);
6422 m = ((double)dy) / ((double)dx);
6423 }
6424 b = ((double)(gaTrapMapPt[TRAP_PT_C].y)) -
6425 m * ((double)(gaTrapMapPt[TRAP_PT_C].x));
6426 for (i=0; i < w; i++) {
6427 double y=m*((double)(i))+b;
6428
6429 gpExtraYIntersects[nLeafIndex][i] = round(y);
6430 }
6431 }
6432
6433 static
CheckVectorWarpCoords(pFromPt,pToPt,dx,dy,image_w,image_h,pBBox)6434 int CheckVectorWarpCoords(pFromPt, pToPt, dx, dy, image_w, image_h, pBBox)
6435 IntPoint *pFromPt, *pToPt;
6436 int dx, dy, image_w, image_h;
6437 struct BBRec *pBBox;
6438 {
6439 IntPoint to_pt;
6440 double ddx, ddy, d;
6441 int i, diam, ltx, lty, rbx, rby, w, h;
6442 char szBuf[MAXSTRING+1];
6443
6444 strcpy(szBuf, GetImageProcName(CMDID_VECTORWARP));
6445 if (pFromPt->x < topSel->obj->obbox.ltx ||
6446 pFromPt->y < topSel->obj->obbox.lty ||
6447 pFromPt->x >= topSel->obj->obbox.rbx ||
6448 pFromPt->y >= topSel->obj->obbox.rby) {
6449 MsgBox(TgLoadString(STID_PICK_PT_WITHIN_IMAGE_BOUND), TOOL_NAME, INFO_MB);
6450 return FALSE;
6451 } else if (image_w <= 4 || image_h <= 4) {
6452 sprintf(gszMsgBox, TgLoadString(STID_IMG_TOO_SMALL_IMAGEPROC_CMD), szBuf);
6453 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
6454 return FALSE;
6455 }
6456 to_pt.x = pFromPt->x+dx;
6457 to_pt.y = pFromPt->y+dy;
6458 if (to_pt.x < topSel->obj->obbox.ltx ||
6459 to_pt.y < topSel->obj->obbox.lty ||
6460 to_pt.x >= topSel->obj->obbox.rbx ||
6461 to_pt.y >= topSel->obj->obbox.rby) {
6462 if (dx == 0) {
6463 if (dy > 0) {
6464 to_pt.y = topSel->obj->obbox.rby-1;
6465 } else {
6466 to_pt.y = topSel->obj->obbox.lty;
6467 }
6468 } else {
6469 double m, b, x_intersect, y_intersect;
6470 int intersect=CORNER_TOP;
6471
6472 m = ((double)dy) / ((double)dx);
6473 b = ((double)(pFromPt->y)) - m * ((double)(pFromPt->x));
6474 if (dx < 0) {
6475 y_intersect = m * ((double)(topSel->obj->obbox.ltx)) + b;
6476 if (y_intersect < topSel->obj->obbox.lty) {
6477 intersect = CORNER_TOP;
6478 } else if (y_intersect > topSel->obj->obbox.rby-1) {
6479 intersect = CORNER_BOTTOM;
6480 } else {
6481 intersect = CORNER_LEFT;
6482 }
6483 } else {
6484 y_intersect = m * ((double)(topSel->obj->obbox.rbx-1)) + b;
6485 if (y_intersect < topSel->obj->obbox.lty) {
6486 intersect = CORNER_TOP;
6487 } else if (y_intersect > topSel->obj->obbox.rby-1) {
6488 intersect = CORNER_BOTTOM;
6489 } else {
6490 intersect = CORNER_RIGHT;
6491 }
6492 }
6493 switch (intersect) {
6494 case CORNER_TOP:
6495 /* intersects the obbox at the top */
6496 to_pt.y = topSel->obj->obbox.lty;
6497 x_intersect = (((double)(to_pt.y)) - b) / m;
6498 to_pt.x = round(x_intersect);
6499 if (to_pt.x < topSel->obj->obbox.ltx) {
6500 to_pt.x = topSel->obj->obbox.ltx;
6501 } else if (to_pt.x >= topSel->obj->obbox.rbx) {
6502 to_pt.x = topSel->obj->obbox.rbx-1;
6503 }
6504 break;
6505 case CORNER_BOTTOM:
6506 /* intersects the obbox at the bottom */
6507 to_pt.y = topSel->obj->obbox.rby;
6508 x_intersect = (((double)(to_pt.y)) - b) / m;
6509 to_pt.x = round(x_intersect);
6510 if (to_pt.x < topSel->obj->obbox.ltx) {
6511 to_pt.x = topSel->obj->obbox.ltx;
6512 } else if (to_pt.x >= topSel->obj->obbox.rbx) {
6513 to_pt.x = topSel->obj->obbox.rbx-1;
6514 }
6515 break;
6516 case CORNER_LEFT:
6517 /* intersects the obbox at the left */
6518 to_pt.x = topSel->obj->obbox.lty;
6519 y_intersect = (m * ((double)(to_pt.x))) + b;
6520 to_pt.y = round(y_intersect);
6521 if (to_pt.y < topSel->obj->obbox.lty) {
6522 to_pt.y = topSel->obj->obbox.lty;
6523 } else if (to_pt.y >= topSel->obj->obbox.rby) {
6524 to_pt.y = topSel->obj->obbox.rby-1;
6525 }
6526 break;
6527 case CORNER_RIGHT:
6528 /* intersects the obbox at the right */
6529 to_pt.x = topSel->obj->obbox.rby;
6530 y_intersect = (m * ((double)(to_pt.x))) + b;
6531 to_pt.y = round(y_intersect);
6532 if (to_pt.y < topSel->obj->obbox.lty) {
6533 to_pt.y = topSel->obj->obbox.lty;
6534 } else if (to_pt.y >= topSel->obj->obbox.rby) {
6535 to_pt.y = topSel->obj->obbox.rby-1;
6536 }
6537 break;
6538 }
6539 }
6540 }
6541 ddx = (double)(to_pt.x - pFromPt->x);
6542 ddy = (double)(to_pt.y - pFromPt->y);
6543 d = ((double)gfVectorWarpSoftness)*(double)sqrt((double)(ddx*ddx+ddy*ddy));
6544 diam = round(d);
6545 ltx = pFromPt->x-diam - topSel->obj->obbox.ltx;
6546 lty = pFromPt->y-diam - topSel->obj->obbox.lty;
6547 rbx = pFromPt->x+diam - topSel->obj->obbox.ltx;
6548 rby = pFromPt->y+diam - topSel->obj->obbox.lty;
6549 if (ltx < 0) ltx = 0;
6550 if (lty < 0) lty = 0;
6551 if (rbx >= image_w) rbx = image_w;
6552 if (rby >= image_h) rby = image_h;
6553 pBBox->ltx = ltx; pBBox->lty = lty;
6554 pBBox->rbx = rbx; pBBox->rby = rby;
6555 pFromPt->x -= topSel->obj->obbox.ltx;
6556 pFromPt->y -= topSel->obj->obbox.lty;
6557 pToPt->x = to_pt.x - topSel->obj->obbox.ltx;
6558 pToPt->y = to_pt.y - topSel->obj->obbox.lty;
6559 if (pToPt->x == pFromPt->x) {
6560 if (pToPt->y == pFromPt->y) {
6561 Msg(TgLoadString(STID_NO_WARPING));
6562 return FALSE;
6563 }
6564 gpTrapMapSpec = gCenterTrapMapSpec;
6565 } else if (pToPt->x < pFromPt->x) {
6566 gpTrapMapSpec = gLeftTrapMapSpec;
6567 } else {
6568 gpTrapMapSpec = gRightTrapMapSpec;
6569 }
6570 w = pBBox->rbx-pBBox->ltx;
6571 h = pBBox->rby-pBBox->lty;
6572
6573 gpSegYIntersects = (int**)malloc(4*sizeof(int*));
6574 gpExtraYIntersects = (int**)malloc(4*sizeof(int*));
6575 if (gpSegYIntersects == NULL || gpExtraYIntersects == NULL) {
6576 FailAllocMessage();
6577 if (gpSegYIntersects != NULL) free(gpSegYIntersects);
6578 if (gpExtraYIntersects != NULL) free(gpExtraYIntersects);
6579 return FALSE;
6580 }
6581 for (i=0; i < 4; i++) {
6582 gpSegYIntersects[i] = (int*)malloc(w*sizeof(int));
6583 gpExtraYIntersects[i] = (int*)malloc(w*sizeof(int));
6584 if (gpSegYIntersects[i] == NULL || gpExtraYIntersects[i] == NULL) {
6585 FailAllocMessage();
6586 return FALSE;
6587 }
6588 memset(gpSegYIntersects[i], 0, w*sizeof(int));
6589 memset(gpExtraYIntersects[i], 0, w*sizeof(int));
6590 }
6591
6592 /* sets L, T, R, B, and C points */
6593 gaTrapMapPt[TRAP_PT_L].x = pBBox->ltx - pBBox->ltx;
6594 gaTrapMapPt[TRAP_PT_L].y = pFromPt->y - pBBox->lty;
6595 gaTrapMapPt[TRAP_PT_T].x = pFromPt->x - pBBox->ltx;
6596 gaTrapMapPt[TRAP_PT_T].y = pBBox->lty - pBBox->lty;
6597 gaTrapMapPt[TRAP_PT_R].x = pBBox->rbx - pBBox->ltx;
6598 gaTrapMapPt[TRAP_PT_R].y = pFromPt->y - pBBox->lty;
6599 gaTrapMapPt[TRAP_PT_B].x = pFromPt->x - pBBox->ltx;
6600 gaTrapMapPt[TRAP_PT_B].y = pBBox->rby - pBBox->lty;
6601 gaTrapMapPt[TRAP_PT_C].x = pToPt->x - pBBox->ltx;
6602 gaTrapMapPt[TRAP_PT_C].y = pToPt->y - pBBox->lty;
6603
6604 /* sets sL, sT, sR, and sB line segments */
6605 SetTrapMapSegValue(TRAP_SEG_L, TRAP_PT_L, w);
6606 SetTrapMapSegValue(TRAP_SEG_T, TRAP_PT_T, w);
6607 SetTrapMapSegValue(TRAP_SEG_R, TRAP_PT_R, w);
6608 SetTrapMapSegValue(TRAP_SEG_B, TRAP_PT_B, w);
6609
6610 /* sets sL, sT, sR, and sB line segments */
6611 SetTrapMapExtraValue(TRAP_LEAF_LT, 0, 0, w);
6612 SetTrapMapExtraValue(TRAP_LEAF_RT, w, 0, w);
6613 SetTrapMapExtraValue(TRAP_LEAF_LB, 0, h, w);
6614 SetTrapMapExtraValue(TRAP_LEAF_RB, w, h, w);
6615
6616 /* sets lt, rt, lb, rb quardrants */
6617 gaTrapMapLeaf[TRAP_LEAF_LT] = TRAP_LEAF_LT;
6618 gaTrapMapLeaf[TRAP_LEAF_RT] = TRAP_LEAF_RT;
6619 gaTrapMapLeaf[TRAP_LEAF_LB] = TRAP_LEAF_LB;
6620 gaTrapMapLeaf[TRAP_LEAF_RB] = TRAP_LEAF_RB;
6621
6622 return TRUE;
6623 }
6624
6625 static
GetQuadrant(pTrapMap,x,y)6626 int GetQuadrant(pTrapMap, x, y)
6627 TrapMap *pTrapMap;
6628 int x, y;
6629 /* returns one of the TRAP_LEAF_*'s */
6630 {
6631 switch (pTrapMap->type) {
6632 case TRAP_NODE_LEAF:
6633 return pTrapMap->detail.leaf.which;
6634 case TRAP_NODE_PT:
6635 if (x < pTrapMap->detail.pt.data->x) {
6636 return GetQuadrant(pTrapMap->detail.pt.left, x, y);
6637 }
6638 return GetQuadrant(pTrapMap->detail.pt.right, x, y);
6639 case TRAP_NODE_SEG:
6640 if (y < gpSegYIntersects[pTrapMap->detail.seg.which][x]) {
6641 return GetQuadrant(pTrapMap->detail.seg.above, x, y);
6642 }
6643 return GetQuadrant(pTrapMap->detail.seg.below, x, y);
6644 }
6645 return (-1);
6646 }
6647
6648 /*
6649 * w w dw
6650 * +-----+ +-----+------+
6651 * | o | warp | \
6652 * h|(x,y)| ======> h| o \
6653 * | | | (X,Y) \ X is also known as x_hat
6654 * +-----+ +__ \ Y is also known as y_hat
6655 * | \__ \
6656 * dh| \__ \
6657 * + \___\
6658 *
6659 * w -> x_off, w+dw -> d_new_w, W -> d_bbox_w, x_hat -> new_x
6660 * h -> y_off, h+dh -> d_new_h, H -> d_bbox_h, y_hat -> new_y
6661 */
6662
6663 static
ComputeVectorWarpData(pFromPt,dx,dy)6664 int ComputeVectorWarpData(pFromPt, dx, dy)
6665 IntPoint *pFromPt;
6666 int dx, dy;
6667 {
6668 struct XPmRec *xpm_ptr=topSel->obj->detail.xpm;
6669 int i, image_w=xpm_ptr->image_w, image_h=xpm_ptr->image_h;
6670 int bbox_w, bbox_h, x_off, y_off, ppm6=FALSE;
6671 double d_bbox_w, d_bbox_h, d_x_off, d_y_off, d_new_w, d_new_h, ddw, ddh;
6672 Pixmap pixmap=xpm_ptr->pixmap;
6673 XImage *image=NULL;
6674 struct BBRec bbox; /* only points within bbox need to be warped */
6675 IntPoint to_pt;
6676 XColor **xcolors=NULL, **bg_xcolors=NULL;
6677 ProgressInfo pi;
6678
6679 if (!CheckVectorWarpCoords(pFromPt, &to_pt, dx, dy, image_w, image_h,
6680 &bbox)) {
6681 return FALSE;
6682 }
6683 ppm6 = DoPpm6(xpm_ptr);
6684 /*
6685 * w -> x_off, w+dw -> new_w, W -> bbox_w, x_hat -> new_x
6686 * h -> y_off, h+dh -> new_h, H -> bbox_h, y_hat -> new_y
6687 */
6688 bbox_w = bbox.rbx - bbox.ltx; d_bbox_w = (double)bbox_w;
6689 bbox_h = bbox.rby - bbox.lty; d_bbox_h = (double)bbox_h;
6690 x_off = pFromPt->x - bbox.ltx; d_x_off = (double)x_off;
6691 y_off = pFromPt->y - bbox.lty; d_y_off = (double)y_off;
6692 d_new_w = (double)(to_pt.x - bbox.ltx);
6693 d_new_h = (double)(to_pt.y - bbox.lty);
6694 ddw = d_new_w - ((double)x_off);
6695 ddh = d_new_h - ((double)y_off);
6696
6697 if (!BuildTrapMap(gpTrapMapSpec)) {
6698 return FALSE;
6699 }
6700 image = XGetImage(mainDisplay, pixmap, 0, 0, image_w, image_h, AllPlanes,
6701 ZPixmap);
6702 if (image == NULL) {
6703 FailAllocMessage();
6704 return FALSE;
6705 }
6706 if (ppm6) {
6707 if (!InitTrueColorInfo(image, &gTrueColorInfo, image_w)) {
6708 sprintf(gszMsgBox, TgLoadString(STID_CANNOT_GET_IMAGE_OF_SIZE),
6709 image_w, image_h);
6710 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
6711 XDestroyImage(image);
6712 return FALSE;
6713 }
6714 if (!SetConvExtraInfo(NULL, image_w, image_h, image, NULL)) {
6715 XDestroyImage(image);
6716 return FALSE;
6717 }
6718 xcolors = gConvExtraInfo.xcolors;
6719 bg_xcolors = gConvExtraInfo.bg_xcolors;
6720 } else {
6721 if (!CreatePixelToIndexMapping()) {
6722 XDestroyImage(image);
6723 return FALSE;
6724 }
6725 gnVectorWarpImageSrcIndex = (int**)malloc(image_h*sizeof(int*));
6726 gnVectorWarpImageDestIndex = (int**)malloc(image_h*sizeof(int*));
6727 if (gnVectorWarpImageSrcIndex == NULL ||
6728 gnVectorWarpImageDestIndex == NULL) {
6729 if (gnVectorWarpImageSrcIndex != NULL) free(gnVectorWarpImageSrcIndex);
6730 if (gnVectorWarpImageDestIndex != NULL) {
6731 free(gnVectorWarpImageDestIndex);
6732 }
6733 FailAllocMessage();
6734 XDestroyImage(image);
6735 CleanUpIndexOfPixel();
6736
6737 return FALSE;
6738 }
6739 memset(gnVectorWarpImageSrcIndex, 0, image_h*sizeof(int*));
6740 memset(gnVectorWarpImageDestIndex, 0, image_h*sizeof(int*));
6741 BeginProgress(&pi, image_h);
6742 for (i=0; i < image_h; i++) {
6743 int j;
6744
6745 UpdateProgress(&pi, i);
6746 gnVectorWarpImageSrcIndex[i] = (int*)malloc(image_w*sizeof(int));
6747 gnVectorWarpImageDestIndex[i] = (int*)malloc(image_w*sizeof(int));
6748 if (gnVectorWarpImageSrcIndex[i] == NULL ||
6749 gnVectorWarpImageDestIndex[i] == NULL) {
6750 FailAllocMessage();
6751 for (j=0; j < i; j++) {
6752 if (gnVectorWarpImageSrcIndex[j] != NULL) {
6753 free(gnVectorWarpImageSrcIndex[j]);
6754 }
6755 }
6756 free(gnVectorWarpImageSrcIndex);
6757 gnVectorWarpImageSrcIndex = NULL;
6758 for (j=0; j < i; j++) {
6759 if (gnVectorWarpImageDestIndex[j] != NULL) {
6760 free(gnVectorWarpImageDestIndex[j]);
6761 }
6762 }
6763 free(gnVectorWarpImageDestIndex);
6764 gnVectorWarpImageDestIndex = NULL;
6765 XDestroyImage(image);
6766 CleanUpIndexOfPixel();
6767
6768 return FALSE;
6769 }
6770 for (j=0; j < image_w; j++) {
6771 gnVectorWarpImageSrcIndex[i][j] = gnVectorWarpImageDestIndex[i][j] =
6772 GetIndexOfPixel(XGetPixel(image,j,i));
6773 }
6774 }
6775 }
6776 BeginProgress(&pi, image_h);
6777 srand(0);
6778 for (i=0; i < image_h; i++) {
6779 int j;
6780
6781 UpdateProgress(&pi, i);
6782 if (i < bbox.lty || i >= bbox.rby) continue;
6783 for (j=0; j < image_w; j++) {
6784 int quadrant, new_x, new_y;
6785
6786 if (j < bbox.ltx || j >= bbox.rbx) continue;
6787
6788 new_x = j - bbox.ltx;
6789 new_y = i - bbox.lty;
6790 quadrant = GetQuadrant(gpTrapMap, new_x, new_y);
6791 if (quadrant != -1) {
6792 double d_new_x=(double)new_x, d_new_y=(double)new_y;
6793 double ddx=(double)0.0, ddy=(double)0.0, frac;
6794 int x, y, above;
6795
6796 above = (new_y < gpExtraYIntersects[quadrant][new_x]);
6797
6798 switch (quadrant) {
6799 case TRAP_LEAF_LT:
6800 if (above) {
6801 ddx = d_new_x - ddw*d_new_y/d_new_h;
6802 ddy = d_y_off*d_new_y/d_new_h;
6803 } else {
6804 ddx = d_x_off*d_new_x/d_new_w;
6805 ddy = d_new_y - ddh*d_new_x/d_new_w;
6806 }
6807 break;
6808 case TRAP_LEAF_RT:
6809 if (above) {
6810 ddx = d_new_x - ddw*d_new_y/d_new_h;
6811 ddy = d_y_off*d_new_y/d_new_h;
6812 } else {
6813 frac = (d_new_x-d_bbox_w)/(d_new_w-d_bbox_w);
6814 ddx = d_bbox_w - (d_bbox_w-d_x_off)*frac;
6815 ddy = d_new_y - ddh*frac;
6816 }
6817 break;
6818 case TRAP_LEAF_LB:
6819 if (above) {
6820 ddx = d_x_off*d_new_x/d_new_w;
6821 ddy = d_new_y - ddh*d_new_x/d_new_w;
6822 } else {
6823 frac = (d_new_y-d_bbox_h)/(d_new_h-d_bbox_h);
6824 ddx = d_new_x - ddw*frac;
6825 ddy = d_bbox_h - (d_bbox_h-d_y_off)*frac;
6826 }
6827 break;
6828 case TRAP_LEAF_RB:
6829 if (above) {
6830 frac = (d_new_x-d_bbox_w)/(d_new_w-d_bbox_w);
6831 ddx = d_bbox_w - (d_bbox_w-d_x_off)*frac;
6832 ddy = d_new_y - ddh*frac;
6833 } else {
6834 frac = (d_new_y-d_bbox_h)/(d_new_h-d_bbox_h);
6835 ddx = d_new_x - ddw*frac;
6836 ddy = d_bbox_h - (d_bbox_h-d_y_off)*frac;
6837 }
6838 break;
6839 }
6840 x = round(ddx);
6841 y = round(ddy);
6842 x += bbox.ltx;
6843 y += bbox.lty;
6844 if (x < bbox.ltx) x = bbox.ltx;
6845 if (x >= bbox.rbx) x = bbox.rbx-1;
6846 if (y < bbox.lty) y = bbox.lty;
6847 if (y >= bbox.rby) y = bbox.rby-1;
6848 if (ppm6) {
6849 xcolors[i][j] = bg_xcolors[y][x];
6850 } else {
6851 gnVectorWarpImageDestIndex[i][j] =
6852 gnVectorWarpImageSrcIndex[y][x];
6853 }
6854 }
6855 }
6856 }
6857 XDestroyImage(image);
6858 CleanUpIndexOfPixel();
6859
6860 return TRUE;
6861 }
6862
6863 static
SpecifyLineSeg(pnFromAbsX,pnFromAbsY,pnToAbsX,pnToAbsY)6864 int SpecifyLineSeg(pnFromAbsX, pnFromAbsY, pnToAbsX, pnToAbsY)
6865 int *pnFromAbsX, *pnFromAbsY, *pnToAbsX, *pnToAbsY;
6866 {
6867 int started=FALSE, done=FALSE, orig_x=0, orig_y=0, grid_x=0, grid_y=0;
6868 int root_x, root_y, saved_snap_on=snapOn;
6869 char buf[80];
6870 unsigned int status;
6871 Window root_win, child_win;
6872
6873 snapOn = FALSE;
6874 *buf = '\0';
6875 SetMouseStatus(TgLoadString(STID_START_LINE_SEG_DOTS),
6876 TgLoadCachedString(CSTID_FINISH), TgLoadCachedString(CSTID_FINISH));
6877 XGrabPointer(mainDisplay, drawWindow, FALSE,
6878 PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
6879 GrabModeAsync, GrabModeAsync, None, handCursor, CurrentTime);
6880 XQueryPointer(mainDisplay, drawWindow, &root_win, &child_win,
6881 &root_x, &root_y, &orig_x, &orig_y, &status);
6882 GridXY(orig_x, orig_y, &grid_x, &grid_y);
6883 MarkRulers(grid_x, grid_y);
6884 orig_x = grid_x;
6885 orig_y = grid_y;
6886 while (!done) {
6887 XEvent input;
6888
6889 XNextEvent(mainDisplay, &input);
6890 switch (input.type) {
6891 case Expose: ExposeEventHandler(&input, TRUE); break;
6892 case VisibilityNotify: ExposeEventHandler(&input, TRUE); break;
6893 case ButtonPress:
6894 if (input.xbutton.button == Button1) {
6895 MarkRulers(grid_x, grid_y);
6896 SetMouseStatus(TgLoadString(STID_ENDT_LINE_SEG_DOTS), "", "");
6897 GridXY(input.xbutton.x, input.xbutton.y, &grid_x, &grid_y);
6898 orig_x = grid_x;
6899 orig_y = grid_y;
6900 XDrawLine(mainDisplay, drawWindow, revDefaultGC, orig_x, orig_y,
6901 grid_x, grid_y);
6902 MarkRulers(grid_x, grid_y);
6903 started = TRUE;
6904 } else {
6905 XUngrabPointer(mainDisplay, CurrentTime);
6906 XSync(mainDisplay, False);
6907 done = TRUE;
6908 started = FALSE;
6909 }
6910 break;
6911 case MotionNotify:
6912 MarkRulers(grid_x, grid_y);
6913 if (started) {
6914 XDrawLine(mainDisplay, drawWindow, revDefaultGC, orig_x, orig_y,
6915 grid_x, grid_y);
6916 }
6917 GridXY(input.xmotion.x, input.xmotion.y, &grid_x, &grid_y);
6918 if (started) {
6919 XDrawLine(mainDisplay, drawWindow, revDefaultGC, orig_x, orig_y,
6920 grid_x, grid_y);
6921 }
6922 MarkRulers(grid_x, grid_y);
6923 break;
6924 case ButtonRelease:
6925 XUngrabPointer(mainDisplay, CurrentTime);
6926 XSync(mainDisplay, False);
6927 done = TRUE;
6928 MarkRulers(grid_x, grid_y);
6929 XDrawLine(mainDisplay, drawWindow, revDefaultGC, orig_x, orig_y,
6930 grid_x, grid_y);
6931 }
6932 }
6933 snapOn = saved_snap_on;
6934 if (started && !(orig_x == grid_x && orig_y == grid_y)) {
6935 *pnFromAbsX = ABS_X(orig_x);
6936 *pnFromAbsY = ABS_Y(orig_y);
6937 *pnToAbsX = ABS_X(grid_x);
6938 *pnToAbsY = ABS_Y(grid_y);
6939 return TRUE;
6940 }
6941 return FALSE;
6942 }
6943
VectorWarp()6944 void VectorWarp()
6945 {
6946 int ok=TRUE;
6947 IntPoint from_pt, to_pt;
6948
6949 if (!CheckSelectionForImageProc(CMDID_VECTORWARP)) {
6950 return;
6951 }
6952 memset(&from_pt, 0, sizeof(IntPoint));
6953 memset(&to_pt, 0, sizeof(IntPoint));
6954 SaveStatusStrings();
6955 while (ok) {
6956 if (somethingHighLighted) HighLightReverse();
6957 ok = SpecifyLineSeg(&from_pt.x, &from_pt.y, &to_pt.x, &to_pt.y);
6958 if (!somethingHighLighted) HighLightForward();
6959
6960 if (!ok) break;
6961
6962 gpConvolveCmdID = CMDID_VECTORWARP;
6963 if (!ComputeVectorWarpData(&from_pt, to_pt.x-from_pt.x,
6964 to_pt.y-from_pt.y)) {
6965 CleanTrapMap();
6966 gpConvolveCmdID = (-1);
6967 break;
6968 }
6969 CleanTrapMap();
6970
6971 gpConvolveFunc = (NLFN*)ConvolveToVectorWarp;
6972 gpConvolveCmdID = CMDID_VECTORWARP;
6973 gnConvolving = TRUE;
6974 DoImageProc(NULL);
6975 gnConvolving = FALSE;
6976 gpConvolveFunc = NULL;
6977 gpConvolveCmdID = (-1);
6978
6979 CleanUpVectorWarpData();
6980 }
6981 RestoreStatusStrings();
6982 }
6983
6984 /* ======================= Non-Image Processing ======================= */
6985
6986 /* ----------------------- RunBggen ----------------------- */
6987
6988 static
GetBggenImageSize(p_image_w,p_image_h)6989 int GetBggenImageSize(p_image_w, p_image_h)
6990 int *p_image_w, *p_image_h;
6991 {
6992 char spec[MAXSTRING+1], *dup_spec=NULL, *part1=NULL, *part2=NULL;
6993 int ok=TRUE;
6994
6995 *spec = '\0';
6996 if (Dialog(TgLoadString(STID_ENTER_IMAGE_SIZE_IN_PIX_RC),
6997 TgLoadCachedString(CSTID_DLG_ACCEPT_CANCEL), spec)==INVALID) {
6998 return FALSE;
6999 }
7000 UtilTrimBlanks(spec);
7001 if (*spec == '\0') return FALSE;
7002 if ((dup_spec=UtilStrDup(spec)) == NULL) {
7003 FailAllocMessage();
7004 return FALSE;
7005 }
7006 if ((part1=strtok(dup_spec, " ,xX[]")) != NULL &&
7007 (part2=strtok(NULL, " ,xX[]")) != NULL) {
7008 *p_image_w = atoi(part1);
7009 *p_image_h = atoi(part2);
7010 if ((*p_image_w) <= 0 || (*p_image_h) <= 0) {
7011 ok = FALSE;
7012 }
7013 } else {
7014 ok = FALSE;
7015 }
7016 if (!ok) {
7017 sprintf(gszMsgBox, TgLoadString(STID_INVALID_SPEC), dup_spec);
7018 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
7019 }
7020 free(dup_spec);
7021 return ok;
7022 }
7023
7024 static
BggenGenerateXpm(image_w,image_h,sz_spec,sz_path,path_buf_sz)7025 int BggenGenerateXpm(image_w, image_h, sz_spec, sz_path, path_buf_sz)
7026 int image_w, image_h, path_buf_sz;
7027 char *sz_spec, *sz_path;
7028 {
7029 char *psz_cmd, sz_geom[MAXSTRING+1];
7030 FILE *pFile, *pPipe;
7031 int bytes_read;
7032
7033 if (MkTempFile(sz_path, path_buf_sz, tmpDir, TOOL_NAME) == NULL) {
7034 return FALSE;
7035 }
7036 sprintf(sz_geom, "%1dx%1d", image_w, image_h);
7037 if (fullTrueColorMode && HasZlibSupport()) {
7038 sprintf(gszMsgBox, bggenToPpm6Cmd, sz_spec, sz_geom);
7039 } else {
7040 sprintf(gszMsgBox, bggenToXpmCmd, sz_spec, sz_geom);
7041 }
7042 if ((psz_cmd=UtilStrDup(gszMsgBox)) == NULL) {
7043 return FailAllocMessage();
7044 }
7045 if (!FindProgramInPath(psz_cmd, NULL, FALSE)) {
7046 free(psz_cmd);
7047 return FALSE;
7048 }
7049 if ((pFile=fopen(sz_path,"w")) == NULL) {
7050 sprintf(gszMsgBox, TgLoadString(STID_CANNOT_OPEN_FILE_FOR_WRITING),
7051 sz_path);
7052 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
7053 free(psz_cmd);
7054 return FALSE;
7055 }
7056 Msg("Executing:");
7057 sprintf(gszMsgBox, " %s", psz_cmd);
7058 Msg(gszMsgBox);
7059 sprintf(gszMsgBox, "Executing '%s'...", psz_cmd);
7060 SetStringStatus(gszMsgBox);
7061 XSync(mainDisplay, False);
7062 if ((pPipe=(FILE*)popen(psz_cmd,"r")) == NULL) {
7063 sprintf(gszMsgBox, TgLoadString(STID_FAIL_TO_EXECUTE_CMD), psz_cmd);
7064 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
7065 free(psz_cmd);
7066 fclose(pFile);
7067 unlink(sz_path);
7068 return FALSE;
7069 }
7070 writeFileFailed = FALSE;
7071 while ((bytes_read=fread(gszMsgBox, sizeof(char), sizeof(gszMsgBox),
7072 pPipe)) > 0) {
7073 if ((int)fwrite(gszMsgBox, sizeof(char), bytes_read, pFile) <= 0) {
7074 writeFileFailed = TRUE;
7075 break;
7076 }
7077 }
7078 pclose(pPipe);
7079 SetStringStatus(TgLoadCachedString(CSTID_DOTS_DONE));
7080 free(psz_cmd);
7081 fclose(pFile);
7082 if (writeFileFailed) {
7083 FailToWriteFileMessage(sz_path);
7084 unlink(sz_path);
7085 return FALSE;
7086 }
7087 return TRUE;
7088 }
7089
RunBggen()7090 void RunBggen()
7091 {
7092 int image_w=0, image_h=0, w, h, short_name, rc, use_obj_pos=FALSE;
7093 int ltx=0, lty=0;
7094 int ncolors=0, chars_per_pixel=0, first_pixel_is_bg=0, *pixels=NULL;
7095 char szSpec[MAXSTRING+1], szPath[MAXPATHLENGTH+1], *rest;
7096 char *color_char=NULL, **color_str=NULL, *xpm_data=NULL;
7097 struct ObjRec *obj_ptr;
7098 Pixmap pixmap=None, bitmap=None;
7099 XImage *image=NULL, *bitmap_image=NULL;
7100
7101 if (curChoice != NOTHING || topSel == NULL) {
7102 MakeQuiescent();
7103 if (!GetBggenImageSize(&image_w, &image_h)) {
7104 return;
7105 }
7106 } else if (!CheckSelectionForImageProc(CMDID_RUNBGGEN)) {
7107 return;
7108 } else {
7109 obj_ptr = topSel->obj;
7110 ltx = obj_ptr->obbox.ltx;
7111 lty = obj_ptr->obbox.lty;
7112 image_w = obj_ptr->obbox.rbx - ltx;
7113 image_h = obj_ptr->obbox.rby - lty;
7114 use_obj_pos = TRUE;
7115 HighLightReverse();
7116 }
7117 *szSpec = '\0';
7118 Dialog(TgLoadString(STID_ENTER_CMD_OP_FOR_BGGEN),
7119 TgLoadCachedString(CSTID_DLG_ACCEPT_CANCEL), szSpec);
7120 UtilTrimBlanks(szSpec);
7121 if (*szSpec == '\0') {
7122 if (use_obj_pos) HighLightForward();
7123 return;
7124 }
7125 SaveStatusStrings();
7126 if (!BggenGenerateXpm(image_w, image_h, szSpec, szPath, sizeof(szPath))) {
7127 RestoreStatusStrings();
7128 if (use_obj_pos) HighLightForward();
7129 return;
7130 }
7131 RestoreStatusStrings();
7132
7133 if (fullTrueColorMode && HasZlibSupport()) {
7134 char deflated_fname[MAXPATHLENGTH+1];
7135 struct XPmRec *xpm_ptr=NULL;
7136
7137 ResetPngHeaderInfo(&gPngHeaderInfo);
7138 obj_ptr = CreatePpmTrueObjFromFile(szPath);
7139 if (obj_ptr != NULL &&
7140 MkTempFile(deflated_fname, sizeof(deflated_fname), tmpDir,
7141 TOOL_NAME) != NULL &&
7142 DeflateFile(szPath, deflated_fname)) {
7143 /* good */
7144 } else {
7145 FreeObj(obj_ptr);
7146
7147 sprintf(gszMsgBox, TgLoadString(STID_CANNOT_IMPORT_GIVEN_PPM), szPath);
7148 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
7149 unlink(szPath);
7150 return;
7151 }
7152 xpm_ptr = obj_ptr->detail.xpm;
7153 xpm_ptr->real_type = PPM_TRUE;
7154 xpm_ptr->ppm_data_compress = PPM_DATA_DEFLATED;
7155 xpm_ptr->ppm_data = ReadFileIntoBuf(deflated_fname,
7156 &xpm_ptr->ppm_data_size);
7157 xpm_ptr->ppm_mask_data = NULL;
7158 xpm_ptr->ppm_mask_size = 0;
7159 unlink(deflated_fname);
7160 } else {
7161 SetWatchCursor(drawWindow);
7162 SetWatchCursor(mainWindow);
7163 rc = MyReadPixmapFile(szPath, &image_w, &image_h, &w, &h, &pixmap,
7164 &image, &bitmap, &bitmap_image, &ncolors, &chars_per_pixel,
7165 &first_pixel_is_bg, &color_char, &color_str, &pixels, &xpm_data);
7166 SetDefaultCursor(mainWindow);
7167 ShowCursor();
7168
7169 if ((short_name=IsPrefix(bootDir, szPath, &rest))) ++rest;
7170 if (rc != BitmapSuccess) {
7171 if (use_obj_pos) HighLightForward();
7172 sprintf(gszMsgBox, TgLoadString(STID_CANNOT_IMPORT_XPM_FILE),
7173 (short_name ? rest : szPath));
7174 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
7175 unlink(szPath);
7176 return;
7177 }
7178 obj_ptr = CreateXPmObj(image_w, image_h, w, h, pixmap, image, bitmap,
7179 bitmap_image, ncolors, chars_per_pixel, first_pixel_is_bg,
7180 color_char, color_str, pixels, xpm_data);
7181 }
7182 unlink(szPath);
7183 AddObj(NULL, topObj, obj_ptr);
7184 if (use_obj_pos) {
7185 RemoveAllSel();
7186 MoveObj(obj_ptr, ltx-obj_ptr->obbox.ltx, lty-obj_ptr->obbox.lty);
7187 numRedrawBBox = 0;
7188 obj_ptr->tmp_parent = NULL;
7189 DrawObj(drawWindow, obj_ptr);
7190 } else {
7191 PlaceTopObj(obj_ptr, NULL, NULL);
7192 }
7193 SelectTopObj();
7194 RecordNewObjCmd();
7195 SetFileModified(TRUE);
7196 justDupped = FALSE;
7197 if (!PRTGIF && colorLayers && needToRedrawColorWindow) {
7198 RedrawColorWindow();
7199 }
7200 sprintf(gszMsgBox, TgLoadString(STID_NEW_XPM_WH_GENERATED),
7201 image_w, image_h);
7202 Msg(gszMsgBox);
7203 }
7204
7205 /* ----------------------- CircularBggen ----------------------- */
7206
7207 static
CircularBggenGenerateXpm(image_w,image_h,ncolors,sz_path,path_buf_sz)7208 int CircularBggenGenerateXpm(image_w, image_h, ncolors, sz_path, path_buf_sz)
7209 int image_w, image_h, ncolors, path_buf_sz;
7210 char *sz_path;
7211 {
7212 FILE *pFile=NULL;
7213 int i=0, cx=0, cy=0;
7214 float fval=(float)0, finc=65535.0/((float)(ncolors-1));
7215 double max_dist=(double)0;
7216 ProgressInfo pi;
7217
7218 if (MkTempFile(sz_path, path_buf_sz, tmpDir, TOOL_NAME) == NULL) {
7219 return FALSE;
7220 }
7221 gpHistogram = (XColor*)malloc(ncolors*sizeof(XColor));
7222 if (gpHistogram == NULL) return FailAllocMessage();
7223 memset(gpHistogram, 0, ncolors*sizeof(XColor));
7224
7225 for (i=0, fval=0.0; i < ncolors; i++, fval+=finc) {
7226 int ival;
7227
7228 ival = round(fval);
7229 HISTOGRAMRED(i) = HISTOGRAMGREEN(i) = HISTOGRAMBLUE(i) =
7230 (unsigned int)ival;
7231 }
7232 i--;
7233 HISTOGRAMRED(i) = HISTOGRAMGREEN(i) = HISTOGRAMBLUE(i) = 65535;
7234
7235 cx = (image_w>>1);
7236 cy = (image_h>>1);
7237 max_dist=(double)sqrt((double)(cx*cx+cy*cy));
7238
7239 if (fullTrueColorMode && HasZlibSupport()) {
7240 if ((pFile=fopen(sz_path,"w")) == NULL) {
7241 sprintf(gszMsgBox, TgLoadString(STID_CANNOT_OPEN_FILE_FOR_WRITING),
7242 sz_path);
7243 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
7244 free(gpHistogram);
7245 gpHistogram = NULL;
7246 return FALSE;
7247 }
7248 writeFileFailed = FALSE;
7249 if (fprintf(pFile, "P6\n%1d %1d\n255\n", image_w, image_h) == EOF) {
7250 writeFileFailed = TRUE;
7251 }
7252 } else {
7253 gnFinalImageIndex = (int**)malloc(image_h*sizeof(int*));
7254 if (gnFinalImageIndex == NULL) {
7255 free(gpHistogram);
7256 gpHistogram = NULL;
7257 return FailAllocMessage();
7258 }
7259 memset(gnFinalImageIndex, 0, image_h*sizeof(int*));
7260 }
7261 BeginProgress(&pi, image_h);
7262 for (i=0; i < image_h; i++) {
7263 int j, dy2=(i-cy)*(i-cy);
7264
7265 UpdateProgress(&pi, i);
7266 if (fullTrueColorMode && HasZlibSupport()) {
7267 /* don't allocate */
7268 } else {
7269 if ((gnFinalImageIndex[i]=(int*)malloc(image_w*sizeof(int))) == NULL) {
7270 for (j=0; j < i; j++) free(gnFinalImageIndex[j]);
7271 free(gnFinalImageIndex);
7272 free(gpHistogram);
7273 gnFinalImageIndex = NULL;
7274 gpHistogram = NULL;
7275 return FailAllocMessage();
7276 }
7277 }
7278 for (j=0; j < image_w; j++) {
7279 int dx2=(j-cx)*(j-cx);
7280 double dist=(double)sqrt((double)(dx2+dy2));
7281 double dgray=((double)ncolors)*dist/max_dist+0.5;
7282 int index=round(dgray);
7283
7284 if (index < 0) index = 0;
7285 if (index >= ncolors) index = ncolors-1;
7286 if (fullTrueColorMode && HasZlibSupport()) {
7287 unsigned int gray=0;
7288 unsigned char buf[3];
7289
7290 gray = (unsigned int)HISTOGRAMRED(ncolors-1-index);
7291 gray >>= 8;
7292 buf[0] = buf[1] = buf[2] = (unsigned char)gray;
7293 if ((int)fwrite(buf, sizeof(char), 3, pFile) <= 0) {
7294 writeFileFailed = TRUE;
7295 }
7296 } else {
7297 gnFinalImageIndex[i][j] = ncolors-1-index;
7298 }
7299 }
7300 }
7301 gnTransparentIndex = (-1);
7302 if (fullTrueColorMode && HasZlibSupport()) {
7303 fclose(pFile);
7304 } else {
7305 if ((pFile=fopen(sz_path,"w")) == NULL) {
7306 sprintf(gszMsgBox, TgLoadString(STID_CANNOT_OPEN_FILE_FOR_WRITING),
7307 sz_path);
7308 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
7309 for (i=0; i < image_h; i++) free(gnFinalImageIndex[i]);
7310 free(gnFinalImageIndex);
7311 free(gpHistogram);
7312 gnFinalImageIndex = NULL;
7313 gpHistogram = NULL;
7314 return FALSE;
7315 }
7316 gnImageW = image_w;
7317 gnImageH = image_h;
7318 gnHistogramEntries = ncolors;
7319 writeFileFailed = FALSE;
7320 DumpConvolution(pFile);
7321 fclose(pFile);
7322 for (i=0; i < image_h; i++) free(gnFinalImageIndex[i]);
7323 free(gnFinalImageIndex);
7324 }
7325 free(gpHistogram);
7326 gnFinalImageIndex = NULL;
7327 gpHistogram = NULL;
7328 if (writeFileFailed) {
7329 FailToWriteFileMessage(sz_path);
7330 unlink(sz_path);
7331 return FALSE;
7332 }
7333 return TRUE;
7334 }
7335
CircularBggen()7336 void CircularBggen()
7337 {
7338 int image_w=0, image_h=0, w, h, short_name, rc, use_obj_pos=FALSE;
7339 int ltx=0, lty=0;
7340 int ncolors=0, chars_per_pixel=0, first_pixel_is_bg=0, *pixels=NULL;
7341 char szSpec[MAXSTRING+1], szPath[MAXPATHLENGTH+1], *rest;
7342 char *color_char=NULL, **color_str=NULL, *xpm_data=NULL;
7343 struct ObjRec *obj_ptr;
7344 Pixmap pixmap=None, bitmap=None;
7345 XImage *image=NULL, *bitmap_image=NULL;
7346
7347 if (curChoice != NOTHING || topSel == NULL) {
7348 MakeQuiescent();
7349 if (!GetBggenImageSize(&image_w, &image_h)) {
7350 return;
7351 }
7352 } else if (!CheckSelectionForImageProc(CMDID_CIRCULARBGGEN)) {
7353 return;
7354 } else {
7355 obj_ptr = topSel->obj;
7356 ltx = obj_ptr->obbox.ltx;
7357 lty = obj_ptr->obbox.lty;
7358 image_w = obj_ptr->obbox.rbx - ltx;
7359 image_h = obj_ptr->obbox.rby - lty;
7360 use_obj_pos = TRUE;
7361 HighLightReverse();
7362 }
7363 *szSpec = '\0';
7364 Dialog(TgLoadString(STID_ENTER_GRAY_LEVELS_222),
7365 TgLoadCachedString(CSTID_DLG_ACCEPT_CANCEL), szSpec);
7366 UtilTrimBlanks(szSpec);
7367 if (*szSpec == '\0') {
7368 if (use_obj_pos) HighLightForward();
7369 return;
7370 }
7371 ncolors = atoi(szSpec);
7372 if (ncolors < 2 || ncolors > 222) {
7373 sprintf(gszMsgBox, TgLoadString(STID_INVALID_GIVEN_VALUE_ENTERED),
7374 szSpec);
7375 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
7376 if (use_obj_pos) HighLightForward();
7377 return;
7378 }
7379 SaveStatusStrings();
7380 if (!CircularBggenGenerateXpm(image_w, image_h, ncolors, szPath,
7381 sizeof(szPath))) {
7382 RestoreStatusStrings();
7383 if (use_obj_pos) HighLightForward();
7384 return;
7385 }
7386 RestoreStatusStrings();
7387
7388 if (fullTrueColorMode && HasZlibSupport()) {
7389 char deflated_fname[MAXPATHLENGTH+1];
7390 struct XPmRec *xpm_ptr=NULL;
7391
7392 ResetPngHeaderInfo(&gPngHeaderInfo);
7393 obj_ptr = CreatePpmTrueObjFromFile(szPath);
7394 if (obj_ptr != NULL &&
7395 MkTempFile(deflated_fname, sizeof(deflated_fname), tmpDir,
7396 TOOL_NAME) != NULL &&
7397 DeflateFile(szPath, deflated_fname)) {
7398 /* good */
7399 } else {
7400 FreeObj(obj_ptr);
7401
7402 sprintf(gszMsgBox, TgLoadString(STID_CANNOT_IMPORT_GIVEN_PPM), szPath);
7403 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
7404 unlink(szPath);
7405 return;
7406 }
7407 xpm_ptr = obj_ptr->detail.xpm;
7408 xpm_ptr->real_type = PPM_TRUE;
7409 xpm_ptr->ppm_data_compress = PPM_DATA_DEFLATED;
7410 xpm_ptr->ppm_data = ReadFileIntoBuf(deflated_fname,
7411 &xpm_ptr->ppm_data_size);
7412 xpm_ptr->ppm_mask_data = NULL;
7413 xpm_ptr->ppm_mask_size = 0;
7414 unlink(deflated_fname);
7415 } else {
7416 SetWatchCursor(drawWindow);
7417 SetWatchCursor(mainWindow);
7418 rc = MyReadPixmapFile(szPath, &image_w, &image_h, &w, &h, &pixmap,
7419 &image, &bitmap, &bitmap_image, &ncolors, &chars_per_pixel,
7420 &first_pixel_is_bg, &color_char, &color_str, &pixels, &xpm_data);
7421 SetDefaultCursor(mainWindow);
7422 ShowCursor();
7423
7424 if ((short_name=IsPrefix(bootDir, szPath, &rest))) ++rest;
7425 if (rc != BitmapSuccess) {
7426 if (use_obj_pos) HighLightForward();
7427 sprintf(gszMsgBox, TgLoadString(STID_CANNOT_IMPORT_XPM_FILE),
7428 (short_name ? rest : szPath));
7429 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
7430 unlink(szPath);
7431 return;
7432 }
7433 obj_ptr = CreateXPmObj(image_w, image_h, w, h, pixmap, image, bitmap,
7434 bitmap_image, ncolors, chars_per_pixel, first_pixel_is_bg,
7435 color_char, color_str, pixels, xpm_data);
7436 }
7437 unlink(szPath);
7438 AddObj(NULL, topObj, obj_ptr);
7439 if (use_obj_pos) {
7440 RemoveAllSel();
7441 MoveObj(obj_ptr, ltx-obj_ptr->obbox.ltx, lty-obj_ptr->obbox.lty);
7442 numRedrawBBox = 0;
7443 obj_ptr->tmp_parent = NULL;
7444 DrawObj(drawWindow, obj_ptr);
7445 } else {
7446 PlaceTopObj(obj_ptr, NULL, NULL);
7447 }
7448 SelectTopObj();
7449 RecordNewObjCmd();
7450 SetFileModified(TRUE);
7451 justDupped = FALSE;
7452 if (!PRTGIF && colorLayers && needToRedrawColorWindow) {
7453 RedrawColorWindow();
7454 }
7455 sprintf(gszMsgBox, TgLoadString(STID_NEW_XPM_WH_GENERATED),
7456 image_w, image_h);
7457 Msg(gszMsgBox);
7458 }
7459
7460 /* ----------------------- SimpleRectBggen ----------------------- */
7461
7462 static
SimpleRectBggenGenerateXpm(image_w,image_h,pxcolor,sz_path,path_buf_sz)7463 int SimpleRectBggenGenerateXpm(image_w, image_h, pxcolor, sz_path, path_buf_sz)
7464 int image_w, image_h, path_buf_sz;
7465 XColor *pxcolor;
7466 char *sz_path;
7467 {
7468 FILE *pFile=NULL;
7469 int i=0;
7470 ProgressInfo pi;
7471
7472 if (MkTempFile(sz_path, path_buf_sz, tmpDir, TOOL_NAME) == NULL) {
7473 return FALSE;
7474 }
7475 gpHistogram = (XColor*)malloc(sizeof(XColor));
7476 if (gpHistogram == NULL) return FailAllocMessage();
7477 memset(gpHistogram, 0, sizeof(XColor));
7478
7479 HISTOGRAMRED(0) = pxcolor->red;
7480 HISTOGRAMGREEN(0) = pxcolor->green;
7481 HISTOGRAMBLUE(0) = pxcolor->blue;
7482
7483 if (fullTrueColorMode && HasZlibSupport()) {
7484 if ((pFile=fopen(sz_path,"w")) == NULL) {
7485 sprintf(gszMsgBox, TgLoadString(STID_CANNOT_OPEN_FILE_FOR_WRITING),
7486 sz_path);
7487 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
7488 free(gpHistogram);
7489 gpHistogram = NULL;
7490 return FALSE;
7491 }
7492 writeFileFailed = FALSE;
7493 if (fprintf(pFile, "P6\n%1d %1d\n255\n", image_w, image_h) == EOF) {
7494 writeFileFailed = TRUE;
7495 }
7496 } else {
7497 gnFinalImageIndex = (int**)malloc(image_h*sizeof(int*));
7498 if (gnFinalImageIndex == NULL) {
7499 free(gpHistogram);
7500 gpHistogram = NULL;
7501 return FailAllocMessage();
7502 }
7503 memset(gnFinalImageIndex, 0, image_h*sizeof(int*));
7504 }
7505 BeginProgress(&pi, image_h);
7506 for (i=0; i < image_h; i++) {
7507 int j;
7508
7509 UpdateProgress(&pi, i);
7510 if (fullTrueColorMode && HasZlibSupport()) {
7511 unsigned char buf[3];
7512 unsigned int r=0, g=0, b=0;
7513
7514 r = (unsigned int)(pxcolor->red);
7515 g = (unsigned int)(pxcolor->green);
7516 b = (unsigned int)(pxcolor->blue);
7517 buf[0] = (unsigned char)((r>>8)&0x0ff);
7518 buf[1] = (unsigned char)((g>>8)&0x0ff);
7519 buf[2] = (unsigned char)((b>>8)&0x0ff);
7520 for (j=0; j < image_w; j++) {
7521 if ((int)fwrite(buf, sizeof(char), 3, pFile) <= 0) {
7522 writeFileFailed = TRUE;
7523 }
7524 }
7525 } else {
7526 if ((gnFinalImageIndex[i]=(int*)malloc(image_w*sizeof(int))) == NULL) {
7527 for (j=0; j < i; j++) free(gnFinalImageIndex[j]);
7528 free(gnFinalImageIndex);
7529 free(gpHistogram);
7530 gnFinalImageIndex = NULL;
7531 gpHistogram = NULL;
7532 return FailAllocMessage();
7533 }
7534 memset(gnFinalImageIndex[i], 0, image_w*sizeof(int));
7535 }
7536 }
7537 gnTransparentIndex = (-1);
7538 if (fullTrueColorMode && HasZlibSupport()) {
7539 fclose(pFile);
7540 } else {
7541 if ((pFile=fopen(sz_path,"w")) == NULL) {
7542 sprintf(gszMsgBox, TgLoadString(STID_CANNOT_OPEN_FILE_FOR_WRITING),
7543 sz_path);
7544 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
7545 for (i=0; i < image_h; i++) free(gnFinalImageIndex[i]);
7546 free(gnFinalImageIndex);
7547 free(gpHistogram);
7548 gnFinalImageIndex = NULL;
7549 gpHistogram = NULL;
7550 return FALSE;
7551 }
7552 gnImageW = image_w;
7553 gnImageH = image_h;
7554 gnHistogramEntries = 1;
7555 writeFileFailed = FALSE;
7556 DumpConvolution(pFile);
7557 fclose(pFile);
7558 for (i=0; i < image_h; i++) free(gnFinalImageIndex[i]);
7559 free(gnFinalImageIndex);
7560 }
7561 free(gpHistogram);
7562 gnFinalImageIndex = NULL;
7563 gpHistogram = NULL;
7564 if (writeFileFailed) {
7565 FailToWriteFileMessage(sz_path);
7566 unlink(sz_path);
7567 return FALSE;
7568 }
7569 return TRUE;
7570 }
7571
SimpleRectBggen()7572 void SimpleRectBggen()
7573 {
7574 int image_w=0, image_h=0, w, h, short_name, rc, use_obj_pos=FALSE;
7575 int ltx=0, lty=0;
7576 int ncolors=0, chars_per_pixel=0, first_pixel_is_bg=0, *pixels=NULL;
7577 char szSpec[MAXSTRING+1], szPath[MAXPATHLENGTH+1], *rest;
7578 char *color_char=NULL, **color_str=NULL, *xpm_data=NULL;
7579 struct ObjRec *obj_ptr;
7580 XColor xcolor;
7581 Pixmap pixmap=None, bitmap=None;
7582 XImage *image=NULL, *bitmap_image=NULL;
7583
7584 if (curChoice != NOTHING || topSel == NULL) {
7585 MakeQuiescent();
7586 if (!GetBggenImageSize(&image_w, &image_h)) {
7587 return;
7588 }
7589 } else if (!CheckSelectionForImageProc(CMDID_CIRCULARBGGEN)) {
7590 return;
7591 } else {
7592 obj_ptr = topSel->obj;
7593 ltx = obj_ptr->obbox.ltx;
7594 lty = obj_ptr->obbox.lty;
7595 image_w = obj_ptr->obbox.rbx - ltx;
7596 image_h = obj_ptr->obbox.rby - lty;
7597 use_obj_pos = TRUE;
7598 HighLightReverse();
7599 }
7600 *szSpec = '\0';
7601 Dialog(TgLoadString(STID_ENTER_COLOR_FOR_RECT_BGGEN),
7602 TgLoadCachedString(CSTID_DLG_ACCEPT_CANCEL), szSpec);
7603 UtilTrimBlanks(szSpec);
7604 if (*szSpec == '\0') {
7605 if (use_obj_pos) HighLightForward();
7606 return;
7607 }
7608 if (!TgifParseColor(szSpec, &xcolor)) {
7609 sprintf(gszMsgBox, TgLoadString(STID_CANNOT_PARSE_NAMED_COLOR), szSpec);
7610 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
7611 if (use_obj_pos) HighLightForward();
7612 return;
7613 }
7614 SaveStatusStrings();
7615 if (!SimpleRectBggenGenerateXpm(image_w, image_h, &xcolor, szPath,
7616 sizeof(szPath))) {
7617 RestoreStatusStrings();
7618 if (use_obj_pos) HighLightForward();
7619 return;
7620 }
7621 RestoreStatusStrings();
7622
7623 if (fullTrueColorMode && HasZlibSupport()) {
7624 char deflated_fname[MAXPATHLENGTH+1];
7625 struct XPmRec *xpm_ptr=NULL;
7626
7627 ResetPngHeaderInfo(&gPngHeaderInfo);
7628 obj_ptr = CreatePpmTrueObjFromFile(szPath);
7629 if (obj_ptr != NULL &&
7630 MkTempFile(deflated_fname, sizeof(deflated_fname), tmpDir,
7631 TOOL_NAME) != NULL &&
7632 DeflateFile(szPath, deflated_fname)) {
7633 /* good */
7634 } else {
7635 FreeObj(obj_ptr);
7636
7637 sprintf(gszMsgBox, TgLoadString(STID_CANNOT_IMPORT_GIVEN_PPM), szPath);
7638 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
7639 unlink(szPath);
7640 return;
7641 }
7642 xpm_ptr = obj_ptr->detail.xpm;
7643 xpm_ptr->real_type = PPM_TRUE;
7644 xpm_ptr->ppm_data_compress = PPM_DATA_DEFLATED;
7645 xpm_ptr->ppm_data = ReadFileIntoBuf(deflated_fname,
7646 &xpm_ptr->ppm_data_size);
7647 xpm_ptr->ppm_mask_data = NULL;
7648 xpm_ptr->ppm_mask_size = 0;
7649 unlink(deflated_fname);
7650 } else {
7651 SetWatchCursor(drawWindow);
7652 SetWatchCursor(mainWindow);
7653 rc = MyReadPixmapFile(szPath, &image_w, &image_h, &w, &h, &pixmap,
7654 &image, &bitmap, &bitmap_image, &ncolors, &chars_per_pixel,
7655 &first_pixel_is_bg, &color_char, &color_str, &pixels, &xpm_data);
7656 SetDefaultCursor(mainWindow);
7657 ShowCursor();
7658
7659 if ((short_name=IsPrefix(bootDir, szPath, &rest))) ++rest;
7660 if (rc != BitmapSuccess) {
7661 if (use_obj_pos) HighLightForward();
7662 sprintf(gszMsgBox, TgLoadString(STID_CANNOT_IMPORT_XPM_FILE),
7663 (short_name ? rest : szPath));
7664 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
7665 unlink(szPath);
7666 return;
7667 }
7668 obj_ptr = CreateXPmObj(image_w, image_h, w, h, pixmap, image, bitmap,
7669 bitmap_image, ncolors, chars_per_pixel, first_pixel_is_bg,
7670 color_char, color_str, pixels, xpm_data);
7671 }
7672 unlink(szPath);
7673 AddObj(NULL, topObj, obj_ptr);
7674 if (use_obj_pos) {
7675 RemoveAllSel();
7676 MoveObj(obj_ptr, ltx-obj_ptr->obbox.ltx, lty-obj_ptr->obbox.lty);
7677 numRedrawBBox = 0;
7678 obj_ptr->tmp_parent = NULL;
7679 DrawObj(drawWindow, obj_ptr);
7680 } else {
7681 PlaceTopObj(obj_ptr, NULL, NULL);
7682 }
7683 SelectTopObj();
7684 RecordNewObjCmd();
7685 SetFileModified(TRUE);
7686 justDupped = FALSE;
7687 if (!PRTGIF && colorLayers && needToRedrawColorWindow) {
7688 RedrawColorWindow();
7689 }
7690 sprintf(gszMsgBox, TgLoadString(STID_NEW_XPM_WH_GENERATED),
7691 image_w, image_h);
7692 Msg(gszMsgBox);
7693 }
7694
7695 /* ----------------------- RegenerateImage ----------------------- */
7696
7697 static
RegenerateImageFile(pszPath,xpm_ptr)7698 int RegenerateImageFile(pszPath, xpm_ptr)
7699 char *pszPath;
7700 struct XPmRec *xpm_ptr;
7701 {
7702 int saved_colordump=colorDump, saved_left=leftExportPixelTrim;
7703 int saved_top=topExportPixelTrim, saved_right=rightExportPixelTrim;
7704 int saved_bottom=bottomExportPixelTrim, saved_where_to_print=whereToPrint;
7705 int dump_ppm_preferred=FALSE;
7706
7707 leftExportPixelTrim = topExportPixelTrim = rightExportPixelTrim =
7708 bottomExportPixelTrim = 0;
7709 *gszImageProcXPmFile = '\0';
7710 gnConvolving = FALSE;
7711
7712 colorDump = TRUE;
7713 if (xpm_ptr == NULL) {
7714 /* called from CreatePixmapFromSelected() */
7715 if (fullTrueColorMode && HasZlibSupport()) {
7716 whereToPrint = PPM_FILE;
7717 dump_ppm_preferred = TRUE;
7718 } else {
7719 whereToPrint = XBM_FILE;
7720 }
7721 } else {
7722 /* called from RegenerateImage() or CropImage() */
7723 if (DoPpm6(xpm_ptr)) {
7724 whereToPrint = PPM_FILE;
7725 dump_ppm_preferred = TRUE;
7726 } else if (xpm_ptr->real_type == XPM_XPM &&
7727 fullTrueColorMode && HasZlibSupport()) {
7728 whereToPrint = PPM_FILE;
7729 dump_ppm_preferred = TRUE;
7730 } else {
7731 whereToPrint = XBM_FILE;
7732 }
7733 }
7734 gnInImageProc = TRUE;
7735 gpImageMapColorFunc = NULL;
7736
7737 SetWatchCursor(drawWindow);
7738 SetWatchCursor(mainWindow);
7739 DumpXBitmapFile(gnInImageProc, dump_ppm_preferred, FALSE);
7740 SetDefaultCursor(mainWindow);
7741 ShowCursor();
7742
7743 gnInImageProc = FALSE;
7744 whereToPrint = saved_where_to_print;
7745 colorDump = saved_colordump;
7746 leftExportPixelTrim = saved_left;
7747 topExportPixelTrim = saved_top;
7748 rightExportPixelTrim = saved_right;
7749 bottomExportPixelTrim = saved_bottom;
7750 if (*gszImageProcXPmFile == '\0') return FALSE;
7751 strcpy(pszPath, gszImageProcXPmFile);
7752 return TRUE;
7753 }
7754
RegenerateImage()7755 void RegenerateImage()
7756 {
7757 int image_w=0, image_h=0, w, h, short_name, rc;
7758 int ltx=0, lty=0, ppm6=FALSE;
7759 int ncolors=0, chars_per_pixel=0, first_pixel_is_bg=0, *pixels=NULL;
7760 char *color_char=NULL, **color_str=NULL, *xpm_data=NULL, *rest;
7761 char szPath[MAXPATHLENGTH+1];
7762 struct ObjRec *obj_ptr=NULL, *saved_top_obj=NULL, *saved_bot_obj=NULL;
7763 struct SelRec *top_sel_ptr=NULL, *bot_sel_ptr=NULL;
7764 Pixmap pixmap=None, bitmap=None;
7765 XImage *image=NULL, *bitmap_image=NULL;
7766 struct XPmRec *xpm_ptr=NULL;
7767
7768 if (!CheckSelectionForImageProc(CMDID_REGENERATEIMAGE)) {
7769 return;
7770 }
7771 obj_ptr = topSel->obj;
7772 xpm_ptr = obj_ptr->detail.xpm;
7773 if (obj_ptr->ctm == NULL) {
7774 if (MsgBox(TgLoadString(STID_XPM_NOT_XFORMED_REGEN_ANYWAY), TOOL_NAME,
7775 YNC_MB) != MB_ID_YES) {
7776 return;
7777 }
7778 }
7779 if (DoPpm6(xpm_ptr)) {
7780 ppm6 = TRUE;
7781 } else if (xpm_ptr->real_type == XPM_XPM &&
7782 fullTrueColorMode && HasZlibSupport()) {
7783 ppm6 = TRUE;
7784 }
7785 ltx = obj_ptr->obbox.ltx;
7786 lty = obj_ptr->obbox.lty;
7787
7788 HighLightReverse();
7789 PrepareToReplaceAnObj(obj_ptr);
7790 PushPageInfo();
7791 saved_top_obj = topObj;
7792 saved_bot_obj = botObj;
7793
7794 JustDupSelObj(&top_sel_ptr, &bot_sel_ptr);
7795 curPage->top = topObj = top_sel_ptr->obj;
7796 curPage->bot = botObj = bot_sel_ptr->obj;
7797 CopyObjId(topSel->obj, topObj);
7798 CopyObjLocks(topSel->obj, topObj);
7799
7800 rc = RegenerateImageFile(szPath, topObj->detail.xpm);
7801
7802 DelAllObj();
7803 free(top_sel_ptr);
7804 PopPageInfo();
7805 curPage->top = topObj = saved_top_obj;
7806 curPage->bot = botObj = saved_bot_obj;
7807 RedrawAnArea(botObj, selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1),
7808 selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1));
7809 if (!rc) {
7810 HighLightForward();
7811 AbortPrepareCmd(CMD_REPLACE);
7812 return;
7813 }
7814 UnlinkObj(obj_ptr);
7815 FreeObj(obj_ptr);
7816 RemoveAllSel();
7817
7818 if (ppm6) {
7819 char deflated_fname[MAXPATHLENGTH+1];
7820 struct XPmRec *xpm_ptr=NULL;
7821
7822 ResetPngHeaderInfo(&gPngHeaderInfo);
7823 obj_ptr = CreatePpmTrueObjFromFile(szPath);
7824 if (obj_ptr != NULL &&
7825 MkTempFile(deflated_fname, sizeof(deflated_fname), tmpDir,
7826 TOOL_NAME) != NULL &&
7827 DeflateFile(szPath, deflated_fname)) {
7828 /* good */
7829 } else {
7830 FreeObj(obj_ptr);
7831
7832 sprintf(gszMsgBox, TgLoadString(STID_CANNOT_IMPORT_GIVEN_PPM), szPath);
7833 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
7834 unlink(szPath);
7835 AbortPrepareCmd(CMD_REPLACE);
7836
7837 return;
7838 }
7839 xpm_ptr = obj_ptr->detail.xpm;
7840 xpm_ptr->real_type = PPM_TRUE;
7841 xpm_ptr->ppm_data_compress = PPM_DATA_DEFLATED;
7842 xpm_ptr->ppm_data = ReadFileIntoBuf(deflated_fname,
7843 &xpm_ptr->ppm_data_size);
7844 xpm_ptr->ppm_mask_data = NULL;
7845 xpm_ptr->ppm_mask_size = 0;
7846 unlink(deflated_fname);
7847 } else {
7848 SetWatchCursor(drawWindow);
7849 SetWatchCursor(mainWindow);
7850 rc = MyReadPixmapFile(szPath, &image_w, &image_h, &w, &h, &pixmap,
7851 &image, &bitmap, &bitmap_image, &ncolors, &chars_per_pixel,
7852 &first_pixel_is_bg, &color_char, &color_str, &pixels, &xpm_data);
7853 SetDefaultCursor(mainWindow);
7854 ShowCursor();
7855
7856 if ((short_name=IsPrefix(bootDir, szPath, &rest))) ++rest;
7857 if (rc != BitmapSuccess) {
7858 AbortPrepareCmd(CMD_REPLACE);
7859 sprintf(gszMsgBox, TgLoadString(STID_CANNOT_IMPORT_XPM_FILE),
7860 (short_name ? rest : szPath));
7861 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
7862 unlink(szPath);
7863 return;
7864 }
7865 obj_ptr = CreateXPmObj(image_w, image_h, w, h, pixmap, image, bitmap,
7866 bitmap_image, ncolors, chars_per_pixel, first_pixel_is_bg,
7867 color_char, color_str, pixels, xpm_data);
7868 if (obj_ptr == NULL) return;
7869 }
7870 unlink(szPath);
7871 AddObj(NULL, topObj, obj_ptr);
7872 MoveObj(obj_ptr, ltx-obj_ptr->obbox.ltx, lty-obj_ptr->obbox.lty);
7873 numRedrawBBox = 0;
7874 obj_ptr->tmp_parent = NULL;
7875 DrawObj(drawWindow, obj_ptr);
7876 SelectTopObj();
7877 RecordReplaceAnObj(topObj);
7878 SetFileModified(TRUE);
7879 justDupped = FALSE;
7880 if (!PRTGIF && colorLayers && needToRedrawColorWindow) {
7881 RedrawColorWindow();
7882 }
7883 sprintf(gszMsgBox, TgLoadString(STID_NEW_XPM_WH_GENERATED),
7884 image_w, image_h);
7885 Msg(gszMsgBox);
7886 }
7887
7888 /* ----------------------- CreatePixmapFromSelected ----------------------- */
7889
CreatePixmapFromSelected()7890 void CreatePixmapFromSelected()
7891 {
7892 int image_w=0, image_h=0, w=0, h=0, short_name=FALSE, rc=0;
7893 int ltx=0, lty=0, ppm6=FALSE;
7894 int ncolors=0, chars_per_pixel=0, first_pixel_is_bg=0, *pixels=NULL;
7895 char *color_char=NULL, **color_str=NULL, *xpm_data=NULL, *rest;
7896 char szPath[MAXPATHLENGTH+1];
7897 struct ObjRec *obj_ptr=NULL, *saved_top_obj=NULL, *saved_bot_obj=NULL;
7898 struct SelRec *top_sel_ptr=NULL, *bot_sel_ptr=NULL, *sel_ptr=NULL;
7899 struct SelRec *next_sel=NULL;
7900 Pixmap pixmap=None, bitmap=None;
7901 XImage *image=NULL, *bitmap_image=NULL;
7902
7903 if (topSel == NULL) {
7904 MsgBox(TgLoadCachedString(CSTID_NO_OBJ_SELECTED), TOOL_NAME, INFO_MB);
7905 return;
7906 }
7907 if (topSel == botSel && topSel->obj->type == OBJ_XPM) {
7908 RegenerateImage();
7909 return;
7910 }
7911 if (fullTrueColorMode && HasZlibSupport()) {
7912 ppm6 = TRUE;
7913 }
7914 ltx = selLtX;
7915 lty = selLtY;
7916
7917 HighLightReverse();
7918 PushPageInfo();
7919 saved_top_obj = topObj;
7920 saved_bot_obj = botObj;
7921
7922 JustDupSelObj(&top_sel_ptr, &bot_sel_ptr);
7923 curPage->top = topObj = top_sel_ptr->obj;
7924 curPage->bot = botObj = bot_sel_ptr->obj;
7925 for (sel_ptr=topSel, obj_ptr=topObj; obj_ptr!=NULL;
7926 sel_ptr=sel_ptr->next, obj_ptr=obj_ptr->next) {
7927 CopyObjId(sel_ptr->obj, obj_ptr);
7928 CopyObjLocks(sel_ptr->obj, obj_ptr);
7929 }
7930 rc = RegenerateImageFile(szPath, NULL);
7931
7932 DelAllObj();
7933 for (sel_ptr=top_sel_ptr; sel_ptr != NULL; sel_ptr=next_sel) {
7934 next_sel = sel_ptr->next;
7935 free(sel_ptr);
7936 }
7937 PopPageInfo();
7938 curPage->top = topObj = saved_top_obj;
7939 curPage->bot = botObj = saved_bot_obj;
7940 RedrawAnArea(botObj, selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1),
7941 selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1));
7942 if (!rc) {
7943 HighLightForward();
7944 return;
7945 }
7946 RemoveAllSel();
7947
7948 if (ppm6) {
7949 char deflated_fname[MAXPATHLENGTH+1];
7950 struct XPmRec *xpm_ptr=NULL;
7951
7952 ResetPngHeaderInfo(&gPngHeaderInfo);
7953 obj_ptr = CreatePpmTrueObjFromFile(szPath);
7954 if (obj_ptr != NULL &&
7955 MkTempFile(deflated_fname, sizeof(deflated_fname), tmpDir,
7956 TOOL_NAME) != NULL &&
7957 DeflateFile(szPath, deflated_fname)) {
7958 /* good */
7959 } else {
7960 FreeObj(obj_ptr);
7961
7962 sprintf(gszMsgBox, TgLoadString(STID_CANNOT_IMPORT_GIVEN_PPM), szPath);
7963 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
7964 unlink(szPath);
7965 AbortPrepareCmd(CMD_REPLACE);
7966
7967 return;
7968 }
7969 xpm_ptr = obj_ptr->detail.xpm;
7970 xpm_ptr->real_type = PPM_TRUE;
7971 xpm_ptr->ppm_data_compress = PPM_DATA_DEFLATED;
7972 xpm_ptr->ppm_data = ReadFileIntoBuf(deflated_fname,
7973 &xpm_ptr->ppm_data_size);
7974 xpm_ptr->ppm_mask_data = NULL;
7975 xpm_ptr->ppm_mask_size = 0;
7976 unlink(deflated_fname);
7977 } else {
7978 SetWatchCursor(drawWindow);
7979 SetWatchCursor(mainWindow);
7980 rc = MyReadPixmapFile(szPath, &image_w, &image_h, &w, &h, &pixmap,
7981 &image, &bitmap, &bitmap_image, &ncolors, &chars_per_pixel,
7982 &first_pixel_is_bg, &color_char, &color_str, &pixels, &xpm_data);
7983 SetDefaultCursor(mainWindow);
7984 ShowCursor();
7985
7986 if ((short_name=IsPrefix(bootDir, szPath, &rest))) ++rest;
7987 if (rc != BitmapSuccess) {
7988 AbortPrepareCmd(CMD_REPLACE);
7989 sprintf(gszMsgBox, TgLoadString(STID_CANNOT_IMPORT_XPM_FILE),
7990 (short_name ? rest : szPath));
7991 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
7992 unlink(szPath);
7993 return;
7994 }
7995 obj_ptr = CreateXPmObj(image_w, image_h, w, h, pixmap, image, bitmap,
7996 bitmap_image, ncolors, chars_per_pixel, first_pixel_is_bg,
7997 color_char, color_str, pixels, xpm_data);
7998 if (obj_ptr == NULL) return;
7999 }
8000 unlink(szPath);
8001 AddObj(NULL, topObj, obj_ptr);
8002 MoveObj(obj_ptr, ltx-obj_ptr->obbox.ltx, lty-obj_ptr->obbox.lty);
8003 numRedrawBBox = 0;
8004 obj_ptr->tmp_parent = NULL;
8005 DrawObj(drawWindow, obj_ptr);
8006 SelectTopObj();
8007 RecordNewObjCmd();
8008 SetFileModified(TRUE);
8009 justDupped = FALSE;
8010 if (!PRTGIF && colorLayers && needToRedrawColorWindow) {
8011 RedrawColorWindow();
8012 }
8013 sprintf(gszMsgBox, TgLoadString(STID_NEW_XPM_WH_GENERATED),
8014 image_w, image_h);
8015 Msg(gszMsgBox);
8016 }
8017
8018 /* ----------------------- CropImage ----------------------- */
8019
8020 static
ContinueCrop(nObjAbsLtX,nObjAbsLtY,nStartXOff,nStartYOff,pnEndXOff,pnEndYOff)8021 void ContinueCrop(nObjAbsLtX, nObjAbsLtY, nStartXOff, nStartYOff,
8022 pnEndXOff, pnEndYOff)
8023 int nObjAbsLtX, nObjAbsLtY, nStartXOff, nStartYOff, *pnEndXOff, *pnEndYOff;
8024 {
8025 int end_x, end_y, cropping=TRUE;
8026 char buf[80], w_buf[80], h_buf[80], x_buf[80], y_buf[80];
8027
8028 end_x = nStartXOff;
8029 end_y = nStartYOff;
8030 SelBox(drawWindow, revDefaultGC, nStartXOff, nStartYOff, end_x, end_y);
8031 PixelToMeasurementUnit(w_buf, 0);
8032 PixelToMeasurementUnit(h_buf, 0);
8033 PixelToMeasurementUnit(x_buf, ABS_X(end_x)-nObjAbsLtX);
8034 PixelToMeasurementUnit(y_buf, ABS_Y(end_y)-nObjAbsLtY);
8035 sprintf(buf, "w=%s\nh=%s\nx=%s\ny=%s", w_buf, h_buf, x_buf, y_buf);
8036 StartShowMeasureCursor(end_x, end_y, buf, TRUE);
8037 XGrabPointer(mainDisplay, drawWindow, False,
8038 PointerMotionMask | ButtonReleaseMask,
8039 GrabModeAsync, GrabModeAsync, None, handCursor, CurrentTime);
8040
8041 while (cropping) {
8042 XEvent input;
8043
8044 XNextEvent(mainDisplay, &input);
8045
8046 if (input.type == Expose || input.type == VisibilityNotify) {
8047 ExposeEventHandler(&input, TRUE);
8048 } else if (input.type == ButtonRelease) {
8049 XUngrabPointer(mainDisplay, CurrentTime);
8050 PixelToMeasurementUnit(w_buf, ABS_SIZE(abs(end_x-nStartXOff)));
8051 PixelToMeasurementUnit(h_buf, ABS_SIZE(abs(end_y-nStartYOff)));
8052 PixelToMeasurementUnit(x_buf, ABS_X(end_x)-nObjAbsLtX);
8053 PixelToMeasurementUnit(y_buf, ABS_Y(end_y)-nObjAbsLtY);
8054 sprintf(buf, "w=%s\nh=%s\nx=%s\ny=%s", w_buf, h_buf, x_buf, y_buf);
8055 EndShowMeasureCursor(end_x, end_y, buf, TRUE);
8056 SelBox(drawWindow, revDefaultGC, nStartXOff, nStartYOff, end_x, end_y);
8057 cropping = FALSE;
8058 } else if (input.type == MotionNotify) {
8059 int new_end_x, new_end_y;
8060 XMotionEvent *motion_ev;
8061 XEvent ev;
8062
8063 motion_ev = &(input.xmotion);
8064 new_end_x = motion_ev->x;
8065 new_end_y = motion_ev->y;
8066
8067 PixelToMeasurementUnit(w_buf, ABS_SIZE(abs(end_x-nStartXOff)));
8068 PixelToMeasurementUnit(h_buf, ABS_SIZE(abs(end_y-nStartYOff)));
8069 PixelToMeasurementUnit(x_buf, ABS_X(end_x)-nObjAbsLtX);
8070 PixelToMeasurementUnit(y_buf, ABS_Y(end_y)-nObjAbsLtY);
8071 sprintf(buf, "w=%s\nh=%s\nx=%s\ny=%s", w_buf, h_buf, x_buf, y_buf);
8072 ShowMeasureCursor(end_x, end_y, buf, TRUE);
8073 SelBox(drawWindow, revDefaultGC, nStartXOff, nStartYOff, end_x, end_y);
8074 end_x = new_end_x; end_y = new_end_y;
8075 SelBox(drawWindow, revDefaultGC, nStartXOff, nStartYOff, end_x, end_y);
8076 PixelToMeasurementUnit(w_buf, ABS_SIZE(abs(end_x-nStartXOff)));
8077 PixelToMeasurementUnit(h_buf, ABS_SIZE(abs(end_y-nStartYOff)));
8078 PixelToMeasurementUnit(x_buf, ABS_X(end_x)-nObjAbsLtX);
8079 PixelToMeasurementUnit(y_buf, ABS_Y(end_y)-nObjAbsLtY);
8080 sprintf(buf, "w=%s\nh=%s\nx=%s\ny=%s", w_buf, h_buf, x_buf, y_buf);
8081 ShowMeasureCursor(end_x, end_y, buf, TRUE);
8082
8083 MarkRulers(end_x, end_y);
8084 while (XCheckMaskEvent(mainDisplay, PointerMotionMask, &ev)) ;
8085 }
8086 }
8087 *pnEndXOff = end_x;
8088 *pnEndYOff = end_y;
8089 }
8090
8091 static
GetCropArea(obj_abs_ltx,obj_abs_lty,pbbox)8092 int GetCropArea(obj_abs_ltx, obj_abs_lty, pbbox)
8093 int obj_abs_ltx, obj_abs_lty;
8094 struct BBRec *pbbox;
8095 {
8096 unsigned int button;
8097 int mouse_x=0, mouse_y=0, rc=TRUE;
8098
8099 SaveStatusStrings();
8100 Msg(TgLoadString(STID_DRAG_A_RECT_TO_CROP));
8101 SetMouseStatus(TgLoadString(STID_START_CROP_IMAGE),
8102 TgLoadString(STID_ABORT_CROP_IMAGE),
8103 TgLoadString(STID_ABORT_CROP_IMAGE));
8104 button = DrawWindowLoop(&mouse_x, &mouse_y, cornerCursor, FALSE);
8105 if (button == Button1) {
8106 int end_x=mouse_x, end_y=mouse_y;
8107
8108 ContinueCrop(obj_abs_ltx, obj_abs_lty, mouse_x, mouse_y, &end_x, &end_y);
8109 if (pbbox != NULL) {
8110 CalcBBox(mouse_x, mouse_y, end_x, end_y,
8111 &pbbox->ltx, &pbbox->lty, &pbbox->rbx, &pbbox->rby);
8112 }
8113 } else {
8114 rc = FALSE;
8115 }
8116 Msg("");
8117 RestoreStatusStrings();
8118 return rc;
8119 }
8120
CropImage()8121 void CropImage()
8122 {
8123 int image_w=0, image_h=0, w, h, short_name, rc, ppm6=FALSE;
8124 int ltx=0, lty=0, crop_x=0, crop_y=0, crop_w=0, crop_h=0;
8125 int ncolors=0, chars_per_pixel=0, first_pixel_is_bg=0, *pixels=NULL;
8126 int saved_ltx=selLtX, saved_lty=selLtY, saved_rbx=selRbX, saved_rby=selRbY;
8127 char *color_char=NULL, **color_str=NULL, *xpm_data=NULL, *rest;
8128 char szPath[MAXPATHLENGTH+1];
8129 struct ObjRec *obj_ptr=NULL, *saved_top_obj=NULL, *saved_bot_obj=NULL;
8130 struct SelRec *top_sel_ptr=NULL, *bot_sel_ptr=NULL;
8131 Pixmap pixmap=None, bitmap=None;
8132 XImage *image=NULL, *bitmap_image=NULL;
8133 struct AttrRec *saved_fattr=NULL, *saved_lattr=NULL;
8134 struct BBRec crop_bbox;
8135
8136 if (!CheckSelectionForImageProc(CMDID_CROPIMAGE)) {
8137 return;
8138 }
8139 obj_ptr = topSel->obj;
8140 if (DoPpm6(obj_ptr->detail.xpm)) {
8141 ppm6 = TRUE;
8142 }
8143 ltx = obj_ptr->obbox.ltx;
8144 lty = obj_ptr->obbox.lty;
8145
8146 HighLightReverse();
8147 XSync(mainDisplay, False);
8148 if (!GetCropArea(ltx, lty, &crop_bbox)) {
8149 return;
8150 }
8151 if (somethingHighLighted) {
8152 HighLightReverse();
8153 }
8154 XSync(mainDisplay, False);
8155 crop_bbox.ltx = ABS_X(crop_bbox.ltx); crop_bbox.lty = ABS_Y(crop_bbox.lty);
8156 crop_bbox.rbx = ABS_X(crop_bbox.rbx); crop_bbox.rby = ABS_Y(crop_bbox.rby);
8157 if (!BBoxIntersect(crop_bbox, obj_ptr->obbox)) {
8158 HighLightForward();
8159 MsgBox(TgLoadString(STID_SEL_AREA_NOT_INTERSECT_IMAGE), TOOL_NAME,
8160 INFO_MB);
8161 return;
8162 } else {
8163 crop_bbox.ltx = max(crop_bbox.ltx, obj_ptr->obbox.ltx);
8164 crop_bbox.lty = max(crop_bbox.lty, obj_ptr->obbox.lty);
8165 crop_bbox.rbx = min(crop_bbox.rbx, obj_ptr->obbox.rbx);
8166 crop_bbox.rby = min(crop_bbox.rby, obj_ptr->obbox.rby);
8167 crop_x = crop_bbox.ltx-obj_ptr->obbox.ltx;
8168 crop_y = crop_bbox.lty-obj_ptr->obbox.lty;
8169 crop_w = crop_bbox.rbx-crop_bbox.ltx;
8170 crop_h = crop_bbox.rby-crop_bbox.lty;
8171 if (crop_x == 0 && crop_y == 0 &&
8172 crop_w == (obj_ptr->obbox.rbx-obj_ptr->obbox.ltx) &&
8173 crop_h == (obj_ptr->obbox.rby-obj_ptr->obbox.lty)) {
8174 HighLightForward();
8175 return;
8176 }
8177 if (crop_w == 0 || crop_h == 0) {
8178 MsgBox(TgLoadString(STID_XPM_CANT_HAVE_0_W_OR_H), TOOL_NAME, INFO_MB);
8179 HighLightForward();
8180 return;
8181 }
8182 }
8183 if (obj_ptr->ctm == NULL) {
8184 HighLightForward();
8185 CutXPixmap(NULL, &crop_x, &crop_y, &crop_w, &crop_h);
8186 return;
8187 }
8188 PrepareToReplaceAnObj(obj_ptr);
8189 PushPageInfo();
8190 saved_top_obj = topObj;
8191 saved_bot_obj = botObj;
8192
8193 JustDupSelObj(&top_sel_ptr, &bot_sel_ptr);
8194 curPage->top = topObj = top_sel_ptr->obj;
8195 curPage->bot = botObj = bot_sel_ptr->obj;
8196 CopyObjId(topSel->obj, topObj);
8197 CopyObjLocks(topSel->obj, topObj);
8198
8199 rc = RegenerateImageFile(szPath, topObj->detail.xpm);
8200
8201 DelAllObj();
8202 free(top_sel_ptr);
8203 PopPageInfo();
8204 curPage->top = topObj = saved_top_obj;
8205 curPage->bot = botObj = saved_bot_obj;
8206 RedrawAnArea(botObj, saved_ltx-GRID_ABS_SIZE(1),
8207 saved_lty-GRID_ABS_SIZE(1), saved_rbx+GRID_ABS_SIZE(1),
8208 saved_rby+GRID_ABS_SIZE(1));
8209 if (!rc) {
8210 HighLightForward();
8211 AbortPrepareCmd(CMD_REPLACE);
8212 return;
8213 }
8214 if (ppm6) {
8215 char deflated_fname[MAXPATHLENGTH+1];
8216 struct XPmRec *xpm_ptr=NULL;
8217 struct ObjRec *tmp_obj_ptr=NULL;
8218
8219 ResetPngHeaderInfo(&gPngHeaderInfo);
8220 tmp_obj_ptr = CreatePpmTrueObjFromFile(szPath);
8221 if (tmp_obj_ptr != NULL &&
8222 MkTempFile(deflated_fname, sizeof(deflated_fname), tmpDir,
8223 TOOL_NAME) != NULL &&
8224 DeflateFile(szPath, deflated_fname)) {
8225 /* good */
8226 } else {
8227 FreeObj(tmp_obj_ptr);
8228
8229 sprintf(gszMsgBox, TgLoadString(STID_CANNOT_IMPORT_GIVEN_PPM), szPath);
8230 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
8231 unlink(szPath);
8232 AbortPrepareCmd(CMD_REPLACE);
8233
8234 return;
8235 }
8236 xpm_ptr = tmp_obj_ptr->detail.xpm;
8237 xpm_ptr->real_type = PPM_TRUE;
8238 xpm_ptr->ppm_data_compress = PPM_DATA_DEFLATED;
8239 xpm_ptr->ppm_data = ReadFileIntoBuf(deflated_fname,
8240 &xpm_ptr->ppm_data_size);
8241 xpm_ptr->ppm_mask_data = NULL;
8242 xpm_ptr->ppm_mask_size = 0;
8243 unlink(deflated_fname);
8244
8245 if (tmp_obj_ptr == NULL) {
8246 return;
8247 } else {
8248 struct ObjRec *new_obj_ptr=CutXPixmap(tmp_obj_ptr, &crop_x, &crop_y,
8249 &crop_w, &crop_h);
8250
8251 if (new_obj_ptr == NULL || new_obj_ptr == tmp_obj_ptr) {
8252 FreeObj(tmp_obj_ptr);
8253 HighLightForward();
8254 AbortPrepareCmd(CMD_REPLACE);
8255 return;
8256 }
8257 FreeObj(tmp_obj_ptr);
8258
8259 UnlinkObj(obj_ptr);
8260 FreeObj(obj_ptr);
8261 RemoveAllSel();
8262 obj_ptr = new_obj_ptr;
8263 }
8264 /* drop through */
8265 } else {
8266 SetWatchCursor(drawWindow);
8267 SetWatchCursor(mainWindow);
8268 rc = MyReadPixmapFile(szPath, &image_w, &image_h, &w, &h, &pixmap,
8269 &image, &bitmap, &bitmap_image, &ncolors, &chars_per_pixel,
8270 &first_pixel_is_bg, &color_char, &color_str, &pixels, &xpm_data);
8271 SetDefaultCursor(mainWindow);
8272 ShowCursor();
8273 if (rc == BitmapSuccess) {
8274 Pixmap dest_pixmap=None, dest_bitmap=None;
8275 XImage *dest_image=NULL, *dest_bitmap_image=NULL;
8276 int ok;
8277
8278 ok = ExtractPixmap(pixmap, image, bitmap,
8279 bitmap_image, crop_x, crop_y, crop_w, crop_h,
8280 &dest_pixmap, &dest_image, &dest_bitmap, &dest_bitmap_image);
8281 if (ok) {
8282 XFreePixmap(mainDisplay, pixmap);
8283 XFreePixmap(mainDisplay, bitmap);
8284 XDestroyImage(image);
8285 XDestroyImage(bitmap_image);
8286 pixmap = dest_pixmap;
8287 bitmap = dest_bitmap;
8288 image = dest_image;
8289 bitmap_image = dest_bitmap_image;
8290 } else {
8291 rc = BitmapFileInvalid;
8292 }
8293 }
8294 if (rc == BitmapSuccess) {
8295 saved_fattr = obj_ptr->fattr;
8296 saved_lattr = obj_ptr->lattr;
8297 obj_ptr->fattr = obj_ptr->lattr = NULL;
8298 UnlinkObj(obj_ptr);
8299 FreeObj(obj_ptr);
8300 RemoveAllSel();
8301 }
8302 if ((short_name=IsPrefix(bootDir, szPath, &rest))) ++rest;
8303 if (rc != BitmapSuccess) {
8304 AbortPrepareCmd(CMD_REPLACE);
8305 sprintf(gszMsgBox, TgLoadString(STID_CANNOT_IMPORT_XPM_FILE),
8306 (short_name ? rest : szPath));
8307 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
8308 unlink(szPath);
8309 return;
8310 }
8311 obj_ptr = CreateXPmObj(crop_w, crop_h, crop_w, crop_h, pixmap, image,
8312 bitmap, bitmap_image, ncolors, chars_per_pixel, first_pixel_is_bg,
8313 color_char, color_str, pixels, xpm_data);
8314 }
8315 unlink(szPath);
8316 AddObj(NULL, topObj, obj_ptr);
8317 MoveObj(obj_ptr, ltx-obj_ptr->obbox.ltx+crop_x,
8318 lty-obj_ptr->obbox.lty+crop_y);
8319 if (saved_fattr != NULL) {
8320 obj_ptr->fattr = saved_fattr;
8321 obj_ptr->lattr = saved_lattr;
8322 }
8323 RecordReplaceAnObj(topObj);
8324 RedrawAnArea(botObj, saved_ltx-GRID_ABS_SIZE(1), saved_lty-GRID_ABS_SIZE(1),
8325 saved_rbx+GRID_ABS_SIZE(1), saved_rby+GRID_ABS_SIZE(1));
8326 SelectTopObj();
8327 SetFileModified(TRUE);
8328 justDupped = FALSE;
8329 if (!PRTGIF && colorLayers && needToRedrawColorWindow) {
8330 RedrawColorWindow();
8331 }
8332 sprintf(gszMsgBox, TgLoadString(STID_NEW_XPM_WH_GENERATED),
8333 image_w, image_h);
8334 Msg(gszMsgBox);
8335 }
8336
8337 /* ----------------------- GetColor ----------------------- */
8338
8339 static
SetCurrentColor(xpm_ptr,image,bitmap_image,image_x,image_y)8340 void SetCurrentColor(xpm_ptr, image, bitmap_image, image_x, image_y)
8341 struct XPmRec *xpm_ptr;
8342 XImage *image, *bitmap_image;
8343 int image_x, image_y;
8344 {
8345 int pixel=(-1);
8346
8347 if (bitmap_image == NULL) {
8348 pixel = XGetPixel(image, image_x, image_y);
8349 } else {
8350 if (XGetPixel(bitmap_image, image_x, image_y) == 0) {
8351 /* transparent */
8352 } else {
8353 pixel = XGetPixel(image, image_x, image_y);
8354 }
8355 }
8356 if (pixel == (-1)) {
8357 } else if (DoPpm6(xpm_ptr)) {
8358 uint32_t pix=(uint32_t)(unsigned int)pixel;
8359 unsigned int r=0, g=0, b=0;
8360 double dr=(double)0, dg=(double)0, db=(double)0;
8361 char color_s[40];
8362 int color_index=0, new_alloc=FALSE;
8363
8364 r = (pix & gTrueColorInfo.r_mask) >> gTrueColorInfo.r_shift;
8365 g = (pix & gTrueColorInfo.g_mask) >> gTrueColorInfo.g_shift;
8366 b = (pix & gTrueColorInfo.b_mask) >> gTrueColorInfo.b_shift;
8367 dr = ((double)r) / gTrueColorInfo.dr_maxval * ((double)256);
8368 dg = ((double)g) / gTrueColorInfo.dg_maxval * ((double)256);
8369 db = ((double)b) / gTrueColorInfo.db_maxval * ((double)256);
8370 r = (dr < ((double)0)) ? 0 : ((unsigned int)dr);
8371 g = (dg < ((double)0)) ? 0 : ((unsigned int)dg);
8372 b = (db < ((double)0)) ? 0 : ((unsigned int)db);
8373 if (r > 255) r = 255;
8374 if (g > 255) g = 255;
8375 if (b > 255) b = 255;
8376 sprintf(color_s, "#%02x%02x%02x", r, g, b);
8377 color_index = QuickFindColorIndex(NULL, color_s, &new_alloc, FALSE);
8378 if (color_index != INVALID) {
8379 ChangeAllSelColor(color_index, FALSE);
8380 }
8381 } else {
8382 int i;
8383
8384 for (i=0; i < maxColors; i++) {
8385 if (colorPixels[i] == pixel) {
8386 struct SelRec *saved_top_sel=topSel, *saved_bot_sel=botSel;
8387
8388 topSel = botSel = NULL;
8389 ChangeAllSelColor(i, FALSE);
8390 topSel = saved_top_sel;
8391 botSel = saved_bot_sel;
8392 break;
8393 }
8394 }
8395 }
8396 }
8397
8398 static
DoGetColor(obj_ptr)8399 void DoGetColor(obj_ptr)
8400 struct ObjRec *obj_ptr;
8401 {
8402 int image_w, image_h, done=FALSE;
8403 struct XPmRec *xpm_ptr=obj_ptr->detail.xpm;
8404 XImage *image, *bitmap_image;
8405
8406 image_w = xpm_ptr->image_w;
8407 image_h = xpm_ptr->image_h;
8408 image = xpm_ptr->image;
8409 bitmap_image = xpm_ptr->bitmap_image;
8410 if (image == NULL) {
8411 image = xpm_ptr->image = XGetImage(mainDisplay, xpm_ptr->pixmap, 0, 0,
8412 image_w, image_h, AllPlanes, ZPixmap);
8413 if (image == NULL) FailAllocMessage();
8414 }
8415 if (xpm_ptr->bitmap != None && bitmap_image == NULL) {
8416 bitmap_image = xpm_ptr->bitmap_image = XGetImage(mainDisplay,
8417 xpm_ptr->bitmap, 0, 0, image_w, image_h, AllPlanes, ZPixmap);
8418 if (bitmap_image == NULL) FailAllocMessage();
8419 }
8420 if (DoPpm6(xpm_ptr)) {
8421 if (!InitTrueColorInfo(image, &gTrueColorInfo, image_w)) {
8422 sprintf(gszMsgBox, TgLoadString(STID_CANNOT_GET_IMAGE_OF_SIZE),
8423 image_w, image_h);
8424 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
8425 return;
8426 }
8427 }
8428 SaveStatusStrings();
8429 Msg(TgLoadString(STID_SEL_A_COLOR_TO_USE_AS_CUR));
8430 SetMouseStatus(TgLoadString(STID_SELECT_A_COLOR),
8431 TgLoadCachedString(CSTID_FINISH), TgLoadCachedString(CSTID_FINISH));
8432 while (!done) {
8433 int mouse_x=0, mouse_y=0;
8434 unsigned int button=PickAPoint(&mouse_x, &mouse_y, dripCursor);
8435
8436 if (button == Button1) {
8437 int abs_x=ABS_X(mouse_x), abs_y=ABS_Y(mouse_y), found=FALSE;
8438 int image_x=0, image_y=0;
8439
8440 if (obj_ptr->ctm == NULL) {
8441 if (abs_x >= obj_ptr->obbox.ltx && abs_y >= obj_ptr->obbox.lty &&
8442 abs_x < obj_ptr->obbox.rbx && abs_y < obj_ptr->obbox.rby) {
8443 image_x = abs_x-obj_ptr->obbox.ltx;
8444 image_y = abs_y-obj_ptr->obbox.lty;
8445 found = TRUE;
8446 } else {
8447 SetStringStatus(TgLoadString(STID_SEL_PT_NOT_ON_IMAGE));
8448 }
8449 } else {
8450 struct XPmRec *xpm_ptr=obj_ptr->detail.xpm;
8451 double tmp_dx=(double)0, tmp_dy=(double)0;
8452
8453 ReverseTransformDoublePointThroughCTM(
8454 ((double)(abs_x-obj_ptr->x)+0.5),
8455 ((double)(abs_y-obj_ptr->y)+0.5),
8456 obj_ptr->ctm, &tmp_dx, &tmp_dy);
8457 tmp_dx += (double)(obj_ptr->x-obj_ptr->orig_obbox.ltx);
8458 tmp_dy += (double)(obj_ptr->y-obj_ptr->orig_obbox.lty);
8459 if (tmp_dx >= ((double)0) && tmp_dx < ((double)xpm_ptr->image_w) &&
8460 tmp_dy >= ((double)0) &&
8461 tmp_dy < ((double)xpm_ptr->image_h)) {
8462 int tmp_x=(int)tmp_dx, tmp_y=(int)tmp_dy;
8463
8464 if (tmp_x < 0) tmp_x = 0;
8465 if (tmp_x >= xpm_ptr->image_w) tmp_x = xpm_ptr->image_w-1;
8466 if (tmp_y < 0) tmp_y = 0;
8467 if (tmp_y >= xpm_ptr->image_h) tmp_y = xpm_ptr->image_h-1;
8468 image_x = tmp_x;
8469 image_y = tmp_y;
8470 found = TRUE;
8471 } else {
8472 SetStringStatus(TgLoadString(STID_SEL_PT_NOT_ON_IMAGE));
8473 }
8474 }
8475 if (found) {
8476 SetCurrentColor(xpm_ptr, image, bitmap_image, image_x, image_y);
8477 }
8478 } else {
8479 done = TRUE;
8480 }
8481 }
8482 RestoreStatusStrings();
8483 }
8484
GetColor()8485 void GetColor()
8486 {
8487 int i, pixel;
8488 char szBuf[MAXSTRING+1];
8489 struct ObjRec *obj_ptr;
8490
8491 strcpy(szBuf, GetImageProcName(CMDID_GETCOLOR));
8492 if (!(curChoice == NOTHING || curChoice == ROTATEMODE) || topSel == NULL ||
8493 topSel != botSel) {
8494 sprintf(gszMsgBox, TgLoadString(STID_ONE_PRIM_FOR_IMAGEPROC_CMD), szBuf);
8495 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
8496 return;
8497 }
8498 obj_ptr = topSel->obj;
8499 switch (obj_ptr->type) {
8500 case OBJ_GROUP:
8501 case OBJ_ICON:
8502 case OBJ_SYM:
8503 case OBJ_PIN:
8504 sprintf(gszMsgBox, TgLoadString(STID_ONE_PRIM_FOR_IMAGEPROC_CMD), szBuf);
8505 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
8506 break;
8507 case OBJ_XPM:
8508 HighLightReverse();
8509 XSync(mainDisplay, False);
8510 DoGetColor(obj_ptr);
8511 if (!somethingHighLighted) HighLightForward();
8512 break;
8513 default:
8514 pixel = colorPixels[obj_ptr->color];
8515 for (i=0; i < maxColors; i++) {
8516 if (colorPixels[i] == pixel) {
8517 struct SelRec *saved_top_sel=topSel, *saved_bot_sel=botSel;
8518
8519 topSel = botSel = NULL;
8520 ChangeAllSelColor(i, FALSE);
8521 topSel = saved_top_sel;
8522 botSel = saved_bot_sel;
8523 break;
8524 }
8525 }
8526 break;
8527 }
8528 }
8529
8530 /* ----------------------- ReplaceColor ----------------------- */
8531
8532 typedef struct tagReplaceColorInfo {
8533 int cmdid;
8534 int has_pixel_for_trans;
8535 int pixel_for_trans;
8536 int index_for_trans;
8537 struct XPmRec *xpm_ptr;
8538 TrueColorInfo tci;
8539 } ReplaceColorInfo;
8540
8541 static ReplaceColorInfo gReplaceColorInfo;
8542
8543 static
FillReplacePickAPoint(OrigX,OrigY,EndX,EndY,AllowDrag,cursor)8544 unsigned int FillReplacePickAPoint(OrigX, OrigY, EndX, EndY, AllowDrag, cursor)
8545 int *OrigX, *OrigY, *EndX, *EndY, AllowDrag;
8546 /* if AllowDrag is TRUE, EndX and EndY must not be NULL */
8547 Cursor cursor;
8548 {
8549 unsigned int button=(unsigned int)(-1);
8550 int dragging=FALSE;
8551 XEvent input;
8552
8553 if (!debugNoPointerGrab) {
8554 XGrabPointer(mainDisplay, drawWindow, False,
8555 PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
8556 GrabModeAsync, GrabModeAsync, None, cursor, CurrentTime);
8557 }
8558 for (;;) {
8559 XNextEvent(mainDisplay, &input);
8560
8561 if (TgWindowIsPinnedMenu(input.xany.window, MENU_COLOR)) {
8562 SaveStatusStrings();
8563 TgHandlePinnedMenuEvent(input.xany.window, MENU_COLOR, &input);
8564 RestoreStatusStrings();
8565 } else if (TgIsCmdEvent(&input)) {
8566 TgHandleCmdEvent(&input);
8567 } else if (input.type == Expose || input.type == VisibilityNotify) {
8568 ExposeEventHandler(&input, TRUE);
8569 } else if (input.type == ButtonPress) {
8570 button = input.xbutton.button;
8571 *OrigX = input.xbutton.x;
8572 *OrigY = input.xbutton.y;
8573 if (AllowDrag && button == Button3) {
8574 *EndX = *OrigX;
8575 *EndY = *OrigY;
8576 SelBox(drawWindow, revDefaultGC, *OrigX, *OrigY, *EndX, *EndY);
8577 dragging = TRUE;
8578 SaveStatusStrings();
8579 SetStringStatus(TgLoadString(STID_DARG_TO_FILL_AN_AREA));
8580 } else {
8581 XUngrabPointer(mainDisplay, CurrentTime);
8582 XSync(mainDisplay, False);
8583 return button;
8584 }
8585 } else if (AllowDrag && dragging && input.type == ButtonRelease) {
8586 SelBox(drawWindow, revDefaultGC, *OrigX, *OrigY, *EndX, *EndY);
8587 XUngrabPointer(mainDisplay, CurrentTime);
8588 XSync(mainDisplay, False);
8589 *EndX = input.xbutton.x;
8590 *EndY = input.xbutton.y;
8591 RestoreStatusStrings();
8592 XSync(mainDisplay, False);
8593 return button;
8594 } else if (AllowDrag && dragging && input.type == MotionNotify) {
8595 SelBox(drawWindow, revDefaultGC, *OrigX, *OrigY, *EndX, *EndY);
8596 *EndX = input.xmotion.x;
8597 *EndY = input.xmotion.y;
8598 SelBox(drawWindow, revDefaultGC, *OrigX, *OrigY, *EndX, *EndY);
8599 } else if (input.type == KeyPress) {
8600 if (KeyPressEventIsEscape(&input.xkey)) {
8601 if (AllowDrag && dragging) {
8602 SelBox(drawWindow, revDefaultGC, *OrigX, *OrigY, *EndX, *EndY);
8603 RestoreStatusStrings();
8604 }
8605 XUngrabPointer(mainDisplay, CurrentTime);
8606 XSync(mainDisplay, False);
8607 return (unsigned int)(-1);
8608 }
8609 }
8610 }
8611 }
8612
8613 static
DoReplaceAColor(obj_ptr,image,bitmap_image,image_x,image_y,image_w,image_h)8614 void DoReplaceAColor(obj_ptr, image, bitmap_image, image_x, image_y,
8615 image_w, image_h)
8616 struct ObjRec *obj_ptr;
8617 XImage *image, *bitmap_image;
8618 int image_x, image_y, image_w, image_h;
8619 {
8620 struct XPmRec *xpm_ptr=obj_ptr->detail.xpm;
8621 int pixel=(-1);
8622 XColor pixel_color;
8623
8624 memset(&pixel_color, 0, sizeof(XColor));
8625 if (bitmap_image == NULL) {
8626 pixel = XGetPixel(image, image_x, image_y);
8627 } else {
8628 if (XGetPixel(bitmap_image, image_x, image_y) == 0) {
8629 /* transparent */
8630 } else {
8631 pixel = XGetPixel(image, image_x, image_y);
8632 }
8633 }
8634 if (pixel != (-1) && gThreshFillReplaceInfo.use_thresholding) {
8635 if (!SetupThreshFillReplaceInfo(&gThreshFillReplaceInfo, pixel, &pixel_color)) {
8636 return;
8637 }
8638 }
8639 SetWatchCursor(drawWindow);
8640 SetWatchCursor(mainWindow);
8641 if (pixel == (-1)) {
8642 } else {
8643 int i, r, *pixels=xpm_ptr->pixels, ncolors=xpm_ptr->ncolors;
8644 char **color_str=xpm_ptr->color_str;
8645
8646 if (gThreshFillReplaceInfo.use_thresholding) {
8647 if (fullTrueColorMode) {
8648 for (r=0; r < image_h; r++) {
8649 int c;
8650
8651 for (c=0; c < image_w; c++) {
8652 int pix=XGetPixel(image, c, r);
8653
8654 if (pix != (-1) && TrueColorPixelWithinRange(pix,
8655 &gThreshFillReplaceInfo)) {
8656 if (gReplaceColorInfo.cmdid == CMDID_REPLACECOLORWITHTRANS) {
8657 XPutPixel(image, c, r, gReplaceColorInfo.pixel_for_trans);
8658 XPutPixel(bitmap_image, c, r, 0);
8659 } else {
8660 XPutPixel(image, c, r, colorPixels[colorIndex]);
8661 }
8662 }
8663 }
8664 }
8665 } else {
8666 for (r=0; r < image_h; r++) {
8667 int c;
8668
8669 for (c=0; c < image_w; c++) {
8670 int pix=XGetPixel(image, c, r), global_color_index=(-1);
8671
8672 if (pix != (-1) && HashLookUpInt(
8673 &gThreshFillReplaceInfo.hash_table, (char*)(&pix),
8674 sizeof(int), &global_color_index)) {
8675 if (global_color_index != (-1) &&
8676 gThreshFillReplaceInfo.within_threshold[global_color_index]) {
8677 if (gReplaceColorInfo.cmdid == CMDID_REPLACECOLORWITHTRANS) {
8678 XPutPixel(image, c, r, colorPixels[gReplaceColorInfo.index_for_trans]);
8679 XPutPixel(bitmap_image, c, r, 0);
8680 } else {
8681 XPutPixel(image, c, r, colorPixels[colorIndex]);
8682 }
8683 }
8684 }
8685 }
8686 }
8687 if (gThreshFillReplaceInfo.within_threshold != NULL) {
8688 free(gThreshFillReplaceInfo.within_threshold);
8689 gThreshFillReplaceInfo.within_threshold = NULL;
8690 }
8691 }
8692 } else {
8693 if (fullTrueColorMode) {
8694 for (r=0; r < image_h; r++) {
8695 int c;
8696
8697 for (c=0; c < image_w; c++) {
8698 if (XGetPixel(image, c, r) == pixel) {
8699 if (gReplaceColorInfo.cmdid == CMDID_REPLACECOLORWITHTRANS) {
8700 XPutPixel(image, c, r, gReplaceColorInfo.pixel_for_trans);
8701 XPutPixel(bitmap_image, c, r, 0);
8702 } else {
8703 XPutPixel(image, c, r, colorPixels[colorIndex]);
8704 }
8705 }
8706 }
8707 }
8708 } else {
8709 for (r=0; r < image_h; r++) {
8710 int c;
8711
8712 for (c=0; c < image_w; c++) {
8713 if (XGetPixel(image, c, r) == pixel) {
8714 if (gReplaceColorInfo.cmdid == CMDID_REPLACECOLORWITHTRANS) {
8715 XPutPixel(image, c, r, colorPixels[gReplaceColorInfo.index_for_trans]);
8716 XPutPixel(bitmap_image, c, r, 0);
8717 } else {
8718 XPutPixel(image, c, r, colorPixels[colorIndex]);
8719 }
8720 }
8721 }
8722 }
8723 }
8724 for (i=0; i < ncolors; i++) {
8725 if (pixels[i] == pixel) {
8726 pixels[i] = colorPixels[colorIndex];
8727 if (color_str[i] != NULL) free(color_str[i]);
8728 color_str[i] = UtilStrDup(colorMenuItems[colorIndex]);
8729 if (color_str[i] == NULL) FailAllocMessage();
8730 }
8731 }
8732 }
8733 if (xpm_ptr->data != NULL) {
8734 #ifdef _TGIF_DBG /* debug, do not translate */
8735 fprintf(stderr,
8736 "In ReplaceAColor(), unexpected xpm_ptr->data != NULL.\n");
8737 #endif /* _TGIF_DBG */
8738 }
8739 }
8740 SetDefaultCursor(mainWindow);
8741 ShowCursor();
8742
8743 XPutImage(mainDisplay, xpm_ptr->pixmap, xpmGC, image, 0, 0, 0, 0,
8744 image_w, image_h);
8745 if (bitmap_image != NULL) {
8746 XPutImage(mainDisplay, xpm_ptr->bitmap, xbmGC, bitmap_image, 0, 0, 0, 0,
8747 image_w, image_h);
8748 }
8749 if (xpm_ptr->cached_pixmap != None) {
8750 XFreePixmap(mainDisplay, xpm_ptr->cached_pixmap);
8751 xpm_ptr->cached_pixmap = None;
8752 }
8753 if (xpm_ptr->cached_bitmap != None) {
8754 XFreePixmap(mainDisplay, xpm_ptr->cached_bitmap);
8755 xpm_ptr->cached_bitmap = None;
8756 }
8757 if ((xpm_ptr->real_type == XPM_JPEG ||
8758 xpm_ptr->real_type == PPM_TRUE) &&
8759 fullTrueColorMode && HasZlibSupport()) {
8760 unsigned int ppm_data_size=0;
8761 char tmp_fname[MAXPATHLENGTH], ext[MAXPATHLENGTH];
8762 char *ppm_data=NULL;
8763
8764 *tmp_fname = *ext = '\0';
8765 if (MkTempFile(tmp_fname, sizeof(tmp_fname), tmpDir,
8766 TOOL_NAME) == NULL) {
8767 /* print error message? */
8768 return;
8769 }
8770 if (!DumpXImageToFile(xpm_ptr->image, xpm_ptr->image_w,
8771 xpm_ptr->image_h, tmp_fname, ext)) {
8772 /* print error message? */
8773 return;
8774 }
8775 if (strcmp(ext, ".ppm.z") == 0) {
8776 char deflated_fname[MAXPATHLENGTH];
8777
8778 snprintf(deflated_fname, sizeof(deflated_fname), "%s%s",
8779 tmp_fname, ext);
8780 ppm_data = ReadFileIntoBuf(deflated_fname, &ppm_data_size);
8781 unlink(deflated_fname);
8782 }
8783 if (ppm_data != NULL) {
8784 if (xpm_ptr->ppm_data != NULL) free(xpm_ptr->ppm_data);
8785 if (xpm_ptr->ppm_mask_data != NULL) {
8786 free(xpm_ptr->ppm_mask_data);
8787 }
8788 xpm_ptr->real_type = PPM_TRUE;
8789 xpm_ptr->ppm_data = ppm_data;
8790 xpm_ptr->ppm_data_size = ppm_data_size;
8791 xpm_ptr->ppm_mask_data = NULL;
8792 xpm_ptr->ppm_mask_size = 0;
8793 xpm_ptr->ppm_data_compress = PPM_DATA_DEFLATED;
8794 }
8795 }
8796 AdjObjCache(obj_ptr);
8797 RedrawAnArea(botObj, selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1),
8798 selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1));
8799 SetFileModified(TRUE);
8800 justDupped = FALSE;
8801 }
8802
8803 static
ContinueReplaceColor(obj_ptr)8804 int ContinueReplaceColor(obj_ptr)
8805 struct ObjRec *obj_ptr;
8806 {
8807 int done=FALSE, image_w, image_h, changed=FALSE;
8808 struct XPmRec *xpm_ptr=obj_ptr->detail.xpm;
8809 XImage *image, *bitmap_image;
8810
8811 xpm_ptr = obj_ptr->detail.xpm;
8812 image_w = xpm_ptr->image_w;
8813 image_h = xpm_ptr->image_h;
8814 image = xpm_ptr->image;
8815 bitmap_image = xpm_ptr->bitmap_image;
8816 if (image == NULL) {
8817 image = xpm_ptr->image = XGetImage(mainDisplay, xpm_ptr->pixmap, 0, 0,
8818 image_w, image_h, AllPlanes, ZPixmap);
8819 if (image == NULL) FailAllocMessage();
8820 }
8821 if (xpm_ptr->bitmap != None && bitmap_image == NULL) {
8822 bitmap_image = xpm_ptr->bitmap_image = XGetImage(mainDisplay,
8823 xpm_ptr->bitmap, 0, 0, image_w, image_h, AllPlanes, ZPixmap);
8824 if (bitmap_image == NULL) FailAllocMessage();
8825 }
8826 SaveStatusStrings();
8827 Msg(TgLoadString(STID_SEL_A_COLOR_TO_BE_REPLACED));
8828 SetMouseStatus(TgLoadString(STID_SEL_A_COLOR_TO_REPLACE),
8829 TgLoadCachedString(CSTID_FINISH), TgLoadCachedString(CSTID_FINISH));
8830 while (!done) {
8831 int mouse_x=0, mouse_y=0;
8832 unsigned int button=FillReplacePickAPoint(&mouse_x, &mouse_y, NULL, NULL,
8833 FALSE, floodCursor);
8834
8835 if (button == Button1) {
8836 int abs_x=ABS_X(mouse_x), abs_y=ABS_Y(mouse_y), found=FALSE;
8837 int image_x=0, image_y=0;
8838
8839 if (obj_ptr->ctm == NULL) {
8840 if (abs_x >= obj_ptr->obbox.ltx && abs_y >= obj_ptr->obbox.lty &&
8841 abs_x < obj_ptr->obbox.rbx && abs_y < obj_ptr->obbox.rby) {
8842 image_x = abs_x-obj_ptr->obbox.ltx;
8843 image_y = abs_y-obj_ptr->obbox.lty;
8844 if (image_x >= 0 && image_y >= 0 &&
8845 image_x < image_w && image_y < image_h) {
8846 found = TRUE;
8847 }
8848 }
8849 } else {
8850 double image_dx=(double)0, image_dy=(double)0;
8851
8852 ReverseTransformDoublePointThroughCTM(
8853 ((double)(abs_x-obj_ptr->x)+0.5),
8854 ((double)(abs_y-obj_ptr->y)+0.5),
8855 obj_ptr->ctm, &image_dx, &image_dy);
8856 image_dx += (double)(obj_ptr->x-obj_ptr->orig_obbox.ltx);
8857 image_dy += (double)(obj_ptr->y-obj_ptr->orig_obbox.lty);
8858 if (image_dx >= ((double)0) && image_dy >= ((double)0) &&
8859 image_dx < ((double)image_w) &&
8860 image_dy < ((double)image_h)) {
8861 image_x = (int)image_dx;
8862 image_y = (int)image_dy;
8863 if (image_x < 0) image_x = 0;
8864 if (image_x >= image_w) image_x = image_w-1;
8865 if (image_y < 0) image_y = 0;
8866 if (image_y >= image_h) image_y = image_h-1;
8867 found = TRUE;
8868 }
8869 }
8870 if (found) {
8871 changed = TRUE;
8872 if (somethingHighLighted) HighLightReverse();
8873 DoReplaceAColor(obj_ptr, image, bitmap_image, image_x, image_y,
8874 image_w, image_h);
8875 if (!somethingHighLighted) HighLightForward();
8876 } else {
8877 SetStringStatus(TgLoadString(STID_SEL_PT_NOT_ON_IMAGE));
8878 }
8879 } else {
8880 done = TRUE;
8881 }
8882 }
8883 RestoreStatusStrings();
8884 return changed;
8885 }
8886
ReplaceColor()8887 void ReplaceColor()
8888 {
8889 struct ObjRec *obj_ptr=NULL;
8890 unsigned char trans_color_r='\0', trans_color_g='\0', trans_color_b='\0';
8891
8892 if (!CheckSelectionForImageProc(CMDID_REPLACECOLOR)) {
8893 return;
8894 }
8895 obj_ptr = topSel->obj;
8896 if (ObjHasTrueColorTransPixel(obj_ptr, &trans_color_r, &trans_color_g,
8897 &trans_color_b)) {
8898 if (CurColorIsTranscolor(trans_color_r, trans_color_g, trans_color_b)) {
8899 sprintf(gszMsgBox, TgLoadString(STID_CUR_COLOR_IS_TRANS_PIXEL),
8900 colorMenuItems[colorIndex],
8901 GetImageProcName(CMDID_REPLACECOLOR));
8902 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
8903 return;
8904 }
8905 }
8906 memset(&gReplaceColorInfo, 0, sizeof(ReplaceColorInfo));
8907 gReplaceColorInfo.cmdid = CMDID_REPLACECOLOR;
8908
8909 if (somethingHighLighted) HighLightReverse();
8910 XSync(mainDisplay, False);
8911 PrepareToReplaceAnObj(obj_ptr);
8912
8913 ResetThreshFillReplaceInfo();
8914 if (!ContinueReplaceColor(obj_ptr)) {
8915 AbortPrepareCmd(CMD_REPLACE);
8916 } else {
8917 RecordReplaceAnObj(obj_ptr);
8918 }
8919 if (!somethingHighLighted) HighLightForward();
8920 }
8921
8922 /* ----------------------- ReplaceColorWithTrans ----------------------- */
8923
8924 static
SetupReplaceColorInfo(obj_ptr,prci)8925 int SetupReplaceColorInfo(obj_ptr, prci)
8926 struct ObjRec *obj_ptr;
8927 ReplaceColorInfo *prci;
8928 {
8929 struct XPmRec *xpm_ptr=obj_ptr->detail.xpm;
8930 int i=0, ncolors=xpm_ptr->ncolors, index=(-1);
8931 int image_w=xpm_ptr->image_w, image_h=xpm_ptr->image_h;
8932 unsigned char trans_color_r='\0', trans_color_g='\0', trans_color_b='\0';
8933 XImage *image=NULL;
8934 TrueColorInfo *ptci=(&prci->tci);
8935
8936 prci->xpm_ptr = xpm_ptr;
8937
8938 switch (xpm_ptr->real_type) {
8939 case XPM_XPM:
8940 if (!ObjHasIndexedTransPixel(obj_ptr, &index)) {
8941 int chars_per_pixel=xpm_ptr->chars_per_pixel;
8942
8943 xpm_ptr->pixels = (int*)realloc(xpm_ptr->pixels, sizeof(int)*(ncolors+1));
8944 if (xpm_ptr->pixels == NULL) FailAllocMessage();
8945 xpm_ptr->pixels[ncolors] = (-1);
8946
8947 xpm_ptr->color_str = (char**)realloc(xpm_ptr->color_str, sizeof(char*)*(ncolors+1));
8948 if (xpm_ptr->color_str == NULL) FailAllocMessage();
8949 xpm_ptr->color_str[ncolors] = UtilStrDup("None");
8950 if (xpm_ptr->color_str[ncolors] == NULL) FailAllocMessage();
8951
8952 if (chars_per_pixel == 1 && ncolors >= 20) {
8953 /* needs to go from 1 chars_per_pixel to 2 chars_per_pixel */
8954 char *color_char=(char*)malloc(((ncolors+1)<<1)*sizeof(char));
8955
8956 if (color_char == NULL) FailAllocMessage();
8957 for (i=0; i < ncolors+1; i++) {
8958 if (i == 0 && xpm_ptr->color_char[0] == '`') {
8959 color_char[i<<1] = color_char[(i<<1)+1] = '`';
8960 } else {
8961 color_char[i<<1] = (char)(((int)('a'))+(int)(i/10));
8962 color_char[(i<<1)+1] = (char)(((int)('0'))+(int)(i%10));
8963 }
8964 }
8965 free(xpm_ptr->color_char);
8966 xpm_ptr->color_char = color_char;
8967 xpm_ptr->chars_per_pixel = 2;
8968 } else {
8969 char *color_char=NULL;
8970
8971 xpm_ptr->color_char = color_char =
8972 (char*)realloc(xpm_ptr->color_char,
8973 sizeof(char)*chars_per_pixel*(ncolors+1));
8974 if (color_char == NULL) FailAllocMessage();
8975 if (chars_per_pixel == 1) {
8976 for (i=0; i < ncolors+1; i++) {
8977 if (i == 0 && xpm_ptr->color_char[0] == '`') {
8978 color_char[i] = '`';
8979 } else {
8980 color_char[i] = (char)(((int)('a'))+i-1);
8981 }
8982 }
8983 } else {
8984 for (i=0; i < ncolors+1; i++) {
8985 if (i == 0 && xpm_ptr->color_char[0] == '`' &&
8986 xpm_ptr->color_char[1] == '`') {
8987 color_char[i<<1] = color_char[(i<<1)+1] = '`';
8988 } else {
8989 color_char[i<<1] = (char)(((int)('a'))+(int)(i/10));
8990 color_char[(i<<1)+1] = (char)(((int)('0'))+(int)(i%10));
8991 }
8992 }
8993 }
8994 }
8995 xpm_ptr->ncolors++;
8996
8997 index = ncolors;
8998 }
8999 prci->index_for_trans = index;
9000 prci->has_pixel_for_trans = TRUE;
9001 break;
9002 case XPM_JPEG: break;
9003 case PPM_TRUE:
9004 image = XGetImage(mainDisplay, xpm_ptr->pixmap, 0, 0, image_w, image_h, AllPlanes, ZPixmap);
9005
9006 if (image == NULL || !InitTrueColorInfo(image, &prci->tci, image_w)) {
9007 sprintf(gszMsgBox, TgLoadString(STID_CANNOT_GET_IMAGE_OF_SIZE), image_w, image_h);
9008 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
9009 XDestroyImage(image);
9010 return FALSE;
9011 }
9012 if (ObjHasTrueColorTransPixel(obj_ptr, &trans_color_r, &trans_color_g, &trans_color_b)) {
9013 unsigned int r=(unsigned int)trans_color_r;
9014 unsigned int g=(unsigned int)trans_color_g;
9015 unsigned int b=(unsigned int)trans_color_b;
9016
9017 prci->pixel_for_trans = ((r << ptci->r_shift) & mainVisual->red_mask) |
9018 ((g << ptci->g_shift) & mainVisual->green_mask) |
9019 ((b << ptci->b_shift) & mainVisual->blue_mask) ;
9020 } else {
9021 unsigned char has_r[256], has_g[256], has_b[256];
9022 unsigned char can_have_r[256], can_have_g[256], can_have_b[256];
9023 int row=0, found=FALSE;
9024 XImage *image=XGetImage(mainDisplay, xpm_ptr->pixmap, 0, 0, image_w, image_h, AllPlanes, ZPixmap);
9025 unsigned int r_maxval=((ptci->r_mask)>>ptci->r_shift);
9026 unsigned int g_maxval=((ptci->g_mask)>>ptci->g_shift);
9027 unsigned int b_maxval=((ptci->b_mask)>>ptci->b_shift);
9028
9029 memset(has_r, 0, sizeof(256*sizeof(unsigned char)));
9030 memset(has_g, 0, sizeof(256*sizeof(unsigned char)));
9031 memset(has_b, 0, sizeof(256*sizeof(unsigned char)));
9032 memset(can_have_r, 0, sizeof(256*sizeof(unsigned char)));
9033 memset(can_have_g, 0, sizeof(256*sizeof(unsigned char)));
9034 memset(can_have_b, 0, sizeof(256*sizeof(unsigned char)));
9035 for (i=0; i < r_maxval; i++) {
9036 double dval=((double)i)/ptci->dr_maxval_div255;
9037 unsigned int uval=round(dval);
9038
9039 if (uval > 255) uval = 255;
9040 can_have_r[uval] = 1;
9041 }
9042 for (i=0; i < g_maxval; i++) {
9043 double dval=((double)i)/ptci->dg_maxval_div255;
9044 unsigned int uval=round(dval);
9045
9046 if (uval > 255) uval = 255;
9047 can_have_g[uval] = 1;
9048 }
9049 for (i=0; i < b_maxval; i++) {
9050 double dval=((double)i)/ptci->db_maxval_div255;
9051 unsigned int uval=round(dval);
9052
9053 if (uval > 255) uval = 255;
9054 can_have_b[uval] = 1;
9055 }
9056 for (row=0; row < image_h; row++) {
9057 int col=0;
9058
9059 for (col=0; col < image_w; col++) {
9060 int pixel=XGetPixel(image, col, row);
9061 uint32_t pix=(uint32_t)pixel;
9062 unsigned int r=0, g=0, b=0;
9063 double dr=(double)0, dg=(double)0, db=(double)0;
9064
9065 r = (pix & ptci->r_mask) >> ptci->r_shift;
9066 g = (pix & ptci->g_mask) >> ptci->g_shift;
9067 b = (pix & ptci->b_mask) >> ptci->b_shift;
9068 dr = ((double)r) / ptci->dr_maxval_div255;
9069 dg = ((double)g) / ptci->dg_maxval_div255;
9070 db = ((double)b) / ptci->db_maxval_div255;
9071 r = round(dr);
9072 g = round(dg);
9073 b = round(db);
9074 if (r > 255) r = 255;
9075 if (g > 255) g = 255;
9076 if (b > 255) b = 255;
9077 if (r == 255 && g == 255) has_b[b] = 1;
9078 if (r == 255 && b == 255) has_g[g] = 1;
9079 if (g == 255 && b == 255) has_r[r] = 1;
9080 }
9081 }
9082 XDestroyImage(image);
9083
9084 for (i=255; i >= 0 && !found; i--) {
9085 if (can_have_r[i] && !has_r[i]) {
9086 prci->pixel_for_trans = ((i << ptci->r_shift) & mainVisual->red_mask) |
9087 ((255 << ptci->g_shift) & mainVisual->green_mask) |
9088 ((255 << ptci->b_shift) & mainVisual->blue_mask) ;
9089 found = TRUE;
9090 }
9091 }
9092 for (i=255; i >= 0 && !found; i--) {
9093 if (can_have_g[i] && !has_g[i]) {
9094 prci->pixel_for_trans = ((i << ptci->g_shift) & mainVisual->green_mask);
9095 found = TRUE;
9096 }
9097 }
9098 for (i=255; i >= 0 && !found; i--) {
9099 if (can_have_b[i] && !has_b[i]) {
9100 prci->pixel_for_trans = ((i << ptci->b_shift) & mainVisual->blue_mask);
9101 found = TRUE;
9102 }
9103 }
9104 if (!found) {
9105 snprintf(gszMsgBox, sizeof(gszMsgBox), TgLoadString(STID_CANNOT_FIND_GOOD_TRANSPIX));
9106 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
9107 return FALSE;
9108 }
9109 }
9110 prci->has_pixel_for_trans = TRUE;
9111 break;
9112 }
9113 if (!prci->has_pixel_for_trans) {
9114 return FALSE;
9115 }
9116 #ifdef _TGIF_DBG /* debug, do not translate */
9117 #ifdef NOT_DEFINED
9118 if (prci->xpm_ptr->real_type == XPM_XPM) {
9119 fprintf(stderr, "index_for_trans = %1d\n", prci->index_for_trans);
9120 } else {
9121 fprintf(stderr, "pixel_for_trans = %08x\n", prci->pixel_for_trans);
9122 }
9123 #endif /* NOT_DEFINED */
9124 #endif /* _TGIF_DBG */
9125 return TRUE;
9126 }
9127
ReplaceColorWithTrans()9128 void ReplaceColorWithTrans()
9129 {
9130 struct ObjRec *obj_ptr=NULL;
9131
9132 if (!CheckSelectionForImageProc(CMDID_REPLACECOLORWITHTRANS)) {
9133 return;
9134 }
9135 obj_ptr = topSel->obj;
9136
9137 memset(&gReplaceColorInfo, 0, sizeof(ReplaceColorInfo));
9138 gReplaceColorInfo.cmdid = CMDID_REPLACECOLORWITHTRANS;
9139 if (!SetupReplaceColorInfo(obj_ptr, &gReplaceColorInfo)) {
9140 return;
9141 }
9142 if (somethingHighLighted) HighLightReverse();
9143 XSync(mainDisplay, False);
9144 PrepareToReplaceAnObj(obj_ptr);
9145
9146 ResetThreshFillReplaceInfo();
9147 if (!ContinueReplaceColor(obj_ptr)) {
9148 AbortPrepareCmd(CMD_REPLACE);
9149 } else {
9150 RecordReplaceAnObj(obj_ptr);
9151 }
9152 if (!somethingHighLighted) HighLightForward();
9153 }
9154
9155 /* ----------------------- FloodFill ----------------------- */
9156
9157 #define DIR_NONE 0
9158 #define DIR_UP 1
9159 #define DIR_RIGHT 2
9160 #define DIR_DOWN 3
9161 #define DIR_LEFT 4
9162
9163 /*
9164 * 1
9165 * ^
9166 * |
9167 * 4 <- 0 -> 2
9168 * |
9169 * v
9170 * 3
9171 */
9172
9173 static int gnPixelToFill=(-1);
9174
9175 typedef struct tagCell {
9176 int row;
9177 int col;
9178 int dir; /* direction where it came from */
9179 } Cell;
9180
9181 #define CELL_NOTVISITED(map,c,r,image_w) (map[(c)+(r)*(image_w)]==0)
9182
9183 static
SelectThisPixelForFloodFill(c,r,pixel,image)9184 int SelectThisPixelForFloodFill(c, r, pixel, image)
9185 int c, r, pixel;
9186 XImage *image;
9187 {
9188 int pix=XGetPixel(image, c, r);
9189
9190 if (gThreshFillReplaceInfo.use_thresholding) {
9191 if (fullTrueColorMode) {
9192 if (pix != (-1) && TrueColorPixelWithinRange(pix,
9193 &gThreshFillReplaceInfo)) {
9194 /* skip */
9195 } else {
9196 return FALSE;
9197 }
9198 } else {
9199 int global_color_index=(-1);
9200
9201 if (pix != (-1) && HashLookUpInt(
9202 &gThreshFillReplaceInfo.hash_table, (char*)(&pix),
9203 sizeof(int), &global_color_index)) {
9204 if (global_color_index != (-1) &&
9205 gThreshFillReplaceInfo.within_threshold[global_color_index]) {
9206 /* skip */
9207 } else {
9208 return FALSE;
9209 }
9210 } else {
9211 return FALSE;
9212 }
9213 }
9214 } else {
9215 if (pix != pixel) {
9216 return FALSE;
9217 }
9218 }
9219 return TRUE;
9220 }
9221
9222 static
FloodFillAddToQueue(plist,c,r,dir,pbbox)9223 void FloodFillAddToQueue(plist, c, r, dir, pbbox)
9224 CVList *plist;
9225 int c, r, dir;
9226 struct BBRec *pbbox;
9227 {
9228 Cell *cell=(Cell*)malloc(sizeof(Cell));
9229
9230 if (cell == NULL) FailAllocMessage();
9231 memset(cell, 0, sizeof(Cell));
9232 cell->row = r;
9233 cell->col = c;
9234 cell->dir = dir;
9235
9236 ListAppend(plist, cell);
9237 if (c < pbbox->ltx) pbbox->ltx = c;
9238 if (c > pbbox->rbx) pbbox->rbx = c;
9239 if (r < pbbox->lty) pbbox->lty = r;
9240 if (r > pbbox->rby) pbbox->rby = r;
9241 }
9242
9243 static
FloodFillBFS(image,pixel,image_w,image_h,plist,map,pbbox)9244 void FloodFillBFS(image, pixel, image_w, image_h, plist, map, pbbox)
9245 XImage *image;
9246 int pixel, image_w, image_h;
9247 CVList *plist;
9248 unsigned char *map;
9249 struct BBRec *pbbox;
9250 {
9251 while (!ListEmpty(plist)) {
9252 CVListElem *elem=ListFirst(plist);
9253 Cell *cell=(Cell*)(elem->obj);
9254 int c=cell->col, r=cell->row; /* this pixel must be already selected */
9255 int dir=cell->dir;
9256 int next_r=0, next_c=0, next_dir=0;
9257
9258 ListUnlink(plist, elem);
9259 free(elem);
9260 free(cell);
9261
9262 if (dir != DIR_DOWN && r-1 >= 0) {
9263 next_c = c;
9264 next_r = r-1;
9265 next_dir = DIR_UP;
9266 if (CELL_NOTVISITED(map,next_c,next_r,image_w)) {
9267 if (SelectThisPixelForFloodFill(next_c, next_r, pixel, image)) {
9268 map[next_c+(next_r*image_w)] = 1;
9269 FloodFillAddToQueue(plist, next_c, next_r, next_dir, pbbox);
9270 } else {
9271 map[next_c+(next_r*image_w)] = (-1);
9272 }
9273 }
9274 }
9275 if (dir != DIR_LEFT && c+1 < image_w) {
9276 next_c = c+1;
9277 next_r = r;
9278 next_dir = DIR_RIGHT;
9279 if (CELL_NOTVISITED(map,next_c,next_r,image_w)) {
9280 if (SelectThisPixelForFloodFill(next_c, next_r, pixel, image)) {
9281 map[next_c+(next_r*image_w)] = 1;
9282 FloodFillAddToQueue(plist, next_c, next_r, next_dir, pbbox);
9283 } else {
9284 map[next_c+(next_r*image_w)] = (-1);
9285 }
9286 }
9287 }
9288 if (dir != DIR_UP && r+1 < image_h) {
9289 next_c = c;
9290 next_r = r+1;
9291 next_dir = DIR_DOWN;
9292 if (CELL_NOTVISITED(map,next_c,next_r,image_w)) {
9293 if (SelectThisPixelForFloodFill(next_c, next_r, pixel, image)) {
9294 map[next_c+(next_r*image_w)] = 1;
9295 FloodFillAddToQueue(plist, next_c, next_r, next_dir, pbbox);
9296 } else {
9297 map[next_c+(next_r*image_w)] = (-1);
9298 }
9299 }
9300 }
9301 if (dir != DIR_RIGHT && c-1 >= 0) {
9302 next_c = c-1;
9303 next_r = r;
9304 next_dir = DIR_LEFT;
9305 if (CELL_NOTVISITED(map,next_c,next_r,image_w)) {
9306 if (SelectThisPixelForFloodFill(next_c, next_r, pixel, image)) {
9307 map[next_c+(next_r*image_w)] = 1;
9308 FloodFillAddToQueue(plist, next_c, next_r, next_dir, pbbox);
9309 } else {
9310 map[next_c+(next_r*image_w)] = (-1);
9311 }
9312 }
9313 }
9314 }
9315 }
9316
9317 static
CalcFloodFill(c,r,pixel,image,image_w,image_h,dir,map,pbbox)9318 void CalcFloodFill(c, r, pixel, image, image_w, image_h, dir, map, pbbox)
9319 int c, r, pixel, image_w, image_h, dir;
9320 XImage *image;
9321 unsigned char *map;
9322 struct BBRec *pbbox;
9323 {
9324 CVList list;
9325
9326 CVListInit(&list);
9327
9328 FloodFillAddToQueue(&list, c, r, dir, pbbox);
9329 FloodFillBFS(image, pixel, image_w, image_h, &list, map, pbbox);
9330 }
9331
9332 static
DoFloodFill(image,image_w,map,pbbox)9333 void DoFloodFill(image, image_w, map, pbbox)
9334 XImage *image;
9335 int image_w;
9336 unsigned char *map;
9337 struct BBRec *pbbox;
9338 {
9339 int r=0;
9340
9341 for (r=pbbox->lty; r <= pbbox->rby; r++) {
9342 int c=0;
9343
9344 for (c=pbbox->ltx; c <= pbbox->rbx; c++) {
9345 if (map[c+r*image_w] == 1) {
9346 XPutPixel(image, c, r, gnPixelToFill);
9347 }
9348 }
9349 }
9350 }
9351
9352 static
StartFloodFill(obj_ptr,image,bitmap_image,image_x,image_y,image_w,image_h,do_flood_fill)9353 void StartFloodFill(obj_ptr, image, bitmap_image, image_x, image_y,
9354 image_w, image_h, do_flood_fill)
9355 struct ObjRec *obj_ptr;
9356 XImage *image, *bitmap_image;
9357 int image_x, image_y, image_w, image_h, do_flood_fill;
9358 {
9359 struct XPmRec *xpm_ptr=obj_ptr->detail.xpm;
9360 int pixel=(-1);
9361 XColor pixel_color;
9362
9363 memset(&pixel_color, 0, sizeof(XColor));
9364 if (bitmap_image == NULL) {
9365 pixel = XGetPixel(image, image_x, image_y);
9366 } else {
9367 if (XGetPixel(bitmap_image, image_x, image_y) == 0) {
9368 /* transparent */
9369 } else {
9370 pixel = XGetPixel(image, image_x, image_y);
9371 }
9372 }
9373 if (do_flood_fill && pixel != (-1) && gThreshFillReplaceInfo.use_thresholding) {
9374 if (!SetupThreshFillReplaceInfo(&gThreshFillReplaceInfo, pixel, &pixel_color)) {
9375 return;
9376 }
9377 }
9378 gnPixelToFill = colorPixels[colorIndex];
9379 if (pixel == (-1)) {
9380 } else if (gnPixelToFill != pixel) {
9381 int i, *pixels=xpm_ptr->pixels, ncolors=xpm_ptr->ncolors, found=FALSE;
9382
9383 if (do_flood_fill) {
9384 struct BBRec bbox;
9385 unsigned char *map=(unsigned char *)malloc(image_h*image_w*sizeof(unsigned char));
9386
9387 if (map == NULL) FailAllocMessage();
9388 /* 0 means not visited, 1 means update pixel, otherwise, don't update */
9389 memset(map, 0, image_h*image_w*sizeof(unsigned char));
9390 map[image_x+image_y*image_w] = 1;
9391 bbox.ltx = bbox.rbx = image_x;
9392 bbox.lty = bbox.rby = image_y;
9393 CalcFloodFill(image_x, image_y, pixel, image, image_w, image_h, 0, map, &bbox);
9394 DoFloodFill(image, image_w, map, &bbox);
9395 free(map);
9396
9397 if (gThreshFillReplaceInfo.within_threshold != NULL) {
9398 free(gThreshFillReplaceInfo.within_threshold);
9399 gThreshFillReplaceInfo.within_threshold = NULL;
9400 }
9401 } else {
9402 XPutPixel(image, image_x, image_y, gnPixelToFill);
9403 }
9404 for (i=0; i < ncolors; i++) {
9405 if (pixels[i] == gnPixelToFill) {
9406 found = TRUE;
9407 }
9408 }
9409 if (!found && xpm_ptr->real_type == XPM_XPM) {
9410 int chars_per_pixel=xpm_ptr->chars_per_pixel;
9411
9412 xpm_ptr->pixels = (int*)realloc(xpm_ptr->pixels,
9413 sizeof(int)*(ncolors+1));
9414 if (xpm_ptr->pixels == NULL) FailAllocMessage();
9415 xpm_ptr->pixels[ncolors] = colorPixels[colorIndex];
9416
9417 xpm_ptr->color_str = (char**)realloc(xpm_ptr->color_str,
9418 sizeof(char*)*(ncolors+1));
9419 if (xpm_ptr->color_str == NULL) FailAllocMessage();
9420 xpm_ptr->color_str[ncolors] = UtilStrDup(colorMenuItems[colorIndex]);
9421 if (xpm_ptr->color_str[ncolors] == NULL) FailAllocMessage();
9422
9423 if (chars_per_pixel == 1 && ncolors >= 20) {
9424 /* needs to go from 1 chars_per_pixel to 2 chars_per_pixel */
9425 char *color_char=(char*)malloc(((ncolors+1)<<1)*sizeof(char));
9426
9427 if (color_char == NULL) FailAllocMessage();
9428 for (i=0; i < ncolors+1; i++) {
9429 if (i == 0 && xpm_ptr->color_char[0] == '`') {
9430 color_char[i<<1] = color_char[(i<<1)+1] = '`';
9431 } else {
9432 color_char[i<<1] = (char)(((int)('a'))+(int)(i/10));
9433 color_char[(i<<1)+1] = (char)(((int)('0'))+(int)(i%10));
9434 }
9435 }
9436 free(xpm_ptr->color_char);
9437 xpm_ptr->color_char = color_char;
9438 xpm_ptr->chars_per_pixel = 2;
9439 } else {
9440 char *color_char;
9441
9442 xpm_ptr->color_char = color_char =
9443 (char*)realloc(xpm_ptr->color_char,
9444 sizeof(char)*chars_per_pixel*(ncolors+1));
9445 if (color_char == NULL) FailAllocMessage();
9446 if (chars_per_pixel == 1) {
9447 for (i=0; i < ncolors+1; i++) {
9448 if (i == 0 && xpm_ptr->color_char[0] == '`') {
9449 color_char[i] = '`';
9450 } else {
9451 color_char[i] = (char)(((int)('a'))+i-1);
9452 }
9453 }
9454 } else {
9455 for (i=0; i < ncolors+1; i++) {
9456 if (i == 0 && xpm_ptr->color_char[0] == '`' &&
9457 xpm_ptr->color_char[1] == '`') {
9458 color_char[i<<1] = color_char[(i<<1)+1] = '`';
9459 } else {
9460 color_char[i<<1] = (char)(((int)('a'))+(int)(i/10));
9461 color_char[(i<<1)+1] = (char)(((int)('0'))+(int)(i%10));
9462 }
9463 }
9464 }
9465 }
9466 xpm_ptr->ncolors++;
9467 }
9468 if (xpm_ptr->data != NULL) {
9469 #ifdef _TGIF_DBG /* debug, do not translate */
9470 fprintf(stderr,
9471 "In FloodFill(), unexpected xpm_ptr->data != NULL.\n");
9472 #endif /* _TGIF_DBG */
9473 }
9474 }
9475 }
9476
9477 static
TryFloodFill(obj_ptr,image_w,image_h,image,bitmap_image,button,mouse_x,mouse_y)9478 int TryFloodFill(obj_ptr, image_w, image_h, image, bitmap_image, button,
9479 mouse_x, mouse_y)
9480 struct ObjRec *obj_ptr;
9481 int image_w, image_h, mouse_x, mouse_y;
9482 XImage *image, *bitmap_image;
9483 unsigned int button;
9484 {
9485 int changed=FALSE, abs_x=ABS_X(mouse_x), abs_y=ABS_Y(mouse_y), found=FALSE;
9486 int image_x=0, image_y=0;
9487
9488 if (obj_ptr->ctm == NULL) {
9489 if (abs_x >= obj_ptr->obbox.ltx && abs_y >= obj_ptr->obbox.lty &&
9490 abs_x < obj_ptr->obbox.rbx && abs_y < obj_ptr->obbox.rby) {
9491 image_x = abs_x-obj_ptr->obbox.ltx;
9492 image_y = abs_y-obj_ptr->obbox.lty;
9493 if (image_x >= 0 && image_y >= 0 &&
9494 image_x < image_w && image_y < image_h) {
9495 found = TRUE;
9496 }
9497 }
9498 } else {
9499 double image_dx=(double)0, image_dy=(double)0;
9500
9501 ReverseTransformDoublePointThroughCTM(
9502 ((double)(abs_x-obj_ptr->x)+0.5),
9503 ((double)(abs_y-obj_ptr->y)+0.5),
9504 obj_ptr->ctm, &image_dx, &image_dy);
9505 image_dx += (double)(obj_ptr->x-obj_ptr->orig_obbox.ltx);
9506 image_dy += (double)(obj_ptr->y-obj_ptr->orig_obbox.lty);
9507 if (image_dx >= ((double)0) && image_dy >= ((double)0) &&
9508 image_dx < ((double)image_w) &&
9509 image_dy < ((double)image_h)) {
9510 image_x = (int)image_dx;
9511 image_y = (int)image_dy;
9512 if (image_x < 0) image_x = 0;
9513 if (image_x >= image_w) image_x = image_w-1;
9514 if (image_y < 0) image_y = 0;
9515 if (image_y >= image_h) image_y = image_h-1;
9516 found = TRUE;
9517 }
9518 }
9519 if (found) {
9520 changed = TRUE;
9521 if (somethingHighLighted) HighLightReverse();
9522 StartFloodFill(obj_ptr, image, bitmap_image, image_x, image_y,
9523 image_w, image_h, button==Button1);
9524 if (!somethingHighLighted) HighLightForward();
9525 }
9526 return changed;
9527 }
9528
9529 static
GetUntransformedPoint(obj_ptr,abs_x,abs_y,v)9530 void GetUntransformedPoint(obj_ptr, abs_x, abs_y, v)
9531 struct ObjRec *obj_ptr;
9532 int abs_x, abs_y;
9533 IntPoint *v;
9534 {
9535 double image_dx=(double)0, image_dy=(double)0;
9536
9537 ReverseTransformDoublePointThroughCTM(
9538 ((double)(abs_x-obj_ptr->x)+0.5),
9539 ((double)(abs_y-obj_ptr->y)+0.5),
9540 obj_ptr->ctm, &image_dx, &image_dy);
9541 image_dx += (double)(obj_ptr->x-obj_ptr->orig_obbox.ltx);
9542 image_dy += (double)(obj_ptr->y-obj_ptr->orig_obbox.lty);
9543 v->x = (int)image_dx;
9544 v->y = (int)image_dy;
9545 }
9546
9547 static
ContinueFloodFill(obj_ptr)9548 int ContinueFloodFill(obj_ptr)
9549 struct ObjRec *obj_ptr;
9550 {
9551 int done=FALSE, image_w, image_h, changed=FALSE;
9552 struct XPmRec *xpm_ptr=obj_ptr->detail.xpm;
9553 XImage *image=NULL, *bitmap_image=NULL;
9554
9555 xpm_ptr = obj_ptr->detail.xpm;
9556 image_w = xpm_ptr->image_w;
9557 image_h = xpm_ptr->image_h;
9558 image = xpm_ptr->image;
9559 bitmap_image = xpm_ptr->bitmap_image;
9560 if (image == NULL) {
9561 image = xpm_ptr->image = XGetImage(mainDisplay, xpm_ptr->pixmap, 0, 0,
9562 image_w, image_h, AllPlanes, ZPixmap);
9563 if (image == NULL) FailAllocMessage();
9564 }
9565 if (xpm_ptr->bitmap != None && bitmap_image == NULL) {
9566 bitmap_image = xpm_ptr->bitmap_image = XGetImage(mainDisplay,
9567 xpm_ptr->bitmap, 0, 0, image_w, image_h, AllPlanes, ZPixmap);
9568 if (bitmap_image == NULL) FailAllocMessage();
9569 }
9570 SaveStatusStrings();
9571 sprintf(gszMsgBox, " %s", TgLoadString(STID_ESC_TO_FINISH));
9572 TwoLineMsg(TgLoadString(STID_BTN1_FLOODFILL_BTN3_SET_COLOR), gszMsgBox);
9573 SetMouseStatus(TgLoadString(STID_FLOOD_FILL),
9574 TgLoadCachedString(CSTID_FINISH), TgLoadString(STID_SET_A_PIXEL));
9575 while (!done) {
9576 int mouse_x=0, mouse_y=0, mouse_end_x=0, mouse_end_y=0;
9577 unsigned int button=FillReplacePickAPoint(&mouse_x, &mouse_y,
9578 &mouse_end_x, &mouse_end_y, TRUE, floodCursor);
9579
9580 SetWatchCursor(drawWindow);
9581 SetWatchCursor(mainWindow);
9582 if (button == Button1) {
9583 changed = TryFloodFill(obj_ptr, image_w, image_h, image, bitmap_image,
9584 button, mouse_x, mouse_y);
9585 } else if (button == Button3) {
9586 if (mouse_x == mouse_end_x && mouse_y == mouse_end_y) {
9587 changed = TryFloodFill(obj_ptr, image_w, image_h, image,
9588 bitmap_image, button, mouse_x, mouse_y);
9589 } else if (obj_ptr->ctm == NULL) {
9590 int r=0;
9591 struct BBRec bbox;
9592
9593 SetBBRec(&bbox, mouse_x, mouse_y, mouse_end_x, mouse_end_y);
9594 for (r=bbox.lty; r < bbox.rby; r++) {
9595 int c=0;
9596
9597 for (c=bbox.ltx; c < bbox.rbx; c++) {
9598 if (TryFloodFill(obj_ptr, image_w, image_h, image,
9599 bitmap_image, button, c, r)) {
9600 changed = TRUE;
9601 }
9602 }
9603 }
9604 } else {
9605 int r=0, abs_x=ABS_X(mouse_x), abs_y=ABS_Y(mouse_y);
9606 int abs_end_x=ABS_X(mouse_end_x), abs_end_y=ABS_Y(mouse_end_y);
9607 int ltx=0, lty=0, rbx=0, rby=0;
9608 IntPoint ivs[6];
9609
9610 GetUntransformedPoint(obj_ptr, abs_x, abs_y, &ivs[0]);
9611 GetUntransformedPoint(obj_ptr, abs_x, abs_end_y, &ivs[1]);
9612 GetUntransformedPoint(obj_ptr, abs_end_x, abs_end_y, &ivs[2]);
9613 GetUntransformedPoint(obj_ptr, abs_end_x, abs_y, &ivs[3]);
9614 memcpy(&ivs[4], &ivs[0], sizeof(IntPoint));
9615 ltx = min(min(ivs[0].x, ivs[1].x),min(ivs[2].x, ivs[3].x));
9616 lty = min(min(ivs[0].y, ivs[1].y),min(ivs[2].y, ivs[3].y));
9617 rbx = max(max(ivs[0].x, ivs[1].x),max(ivs[2].x, ivs[3].x));
9618 rby = max(max(ivs[0].y, ivs[1].y),max(ivs[2].y, ivs[3].y));
9619
9620 for (r=lty; r < rby; r++) {
9621 int c=0;
9622
9623 if (r < 0 || r >= image_h) continue;
9624 for (c=ltx; c < rbx; c++) {
9625 if (c < 0 || c >= image_w) continue;
9626
9627 if (PointInIntPolygon(c, r, 5, ivs)) {
9628 StartFloodFill(obj_ptr, image, bitmap_image, c, r,
9629 c, r, FALSE);
9630 changed = TRUE;
9631 }
9632 }
9633 }
9634 }
9635 } else {
9636 done = TRUE;
9637 }
9638 if (!done) {
9639 if (changed) {
9640 XPutImage(mainDisplay, xpm_ptr->pixmap, xpmGC, image, 0, 0, 0, 0,
9641 image_w, image_h);
9642 if (bitmap_image != NULL) {
9643 XPutImage(mainDisplay, xpm_ptr->bitmap, xbmGC, bitmap_image,
9644 0, 0, 0, 0, image_w, image_h);
9645 }
9646 if (xpm_ptr->cached_pixmap != None) {
9647 XFreePixmap(mainDisplay, xpm_ptr->cached_pixmap);
9648 xpm_ptr->cached_pixmap = None;
9649 }
9650 if (xpm_ptr->cached_bitmap != None) {
9651 XFreePixmap(mainDisplay, xpm_ptr->cached_bitmap);
9652 xpm_ptr->cached_bitmap = None;
9653 }
9654 if ((xpm_ptr->real_type == XPM_JPEG ||
9655 xpm_ptr->real_type == PPM_TRUE) &&
9656 fullTrueColorMode && HasZlibSupport()) {
9657 unsigned int ppm_data_size=0;
9658 char tmp_fname[MAXPATHLENGTH], ext[MAXPATHLENGTH];
9659 char *ppm_data=NULL;
9660
9661 *tmp_fname = *ext = '\0';
9662 if (MkTempFile(tmp_fname, sizeof(tmp_fname), tmpDir,
9663 TOOL_NAME) == NULL) {
9664 /* print error message? */
9665 return FALSE;
9666 }
9667 if (!DumpXImageToFile(xpm_ptr->image, xpm_ptr->image_w,
9668 xpm_ptr->image_h, tmp_fname, ext)) {
9669 /* print error message? */
9670 return FALSE;
9671 }
9672 if (strcmp(ext, ".ppm.z") == 0) {
9673 char deflated_fname[MAXPATHLENGTH];
9674
9675 snprintf(deflated_fname, sizeof(deflated_fname), "%s%s",
9676 tmp_fname, ext);
9677 ppm_data = ReadFileIntoBuf(deflated_fname, &ppm_data_size);
9678 unlink(deflated_fname);
9679 }
9680 if (ppm_data != NULL) {
9681 if (xpm_ptr->ppm_data != NULL) free(xpm_ptr->ppm_data);
9682 if (xpm_ptr->ppm_mask_data != NULL) {
9683 free(xpm_ptr->ppm_mask_data);
9684 }
9685 xpm_ptr->real_type = PPM_TRUE;
9686 xpm_ptr->ppm_data = ppm_data;
9687 xpm_ptr->ppm_data_size = ppm_data_size;
9688 xpm_ptr->ppm_mask_data = NULL;
9689 xpm_ptr->ppm_mask_size = 0;
9690 xpm_ptr->ppm_data_compress = PPM_DATA_DEFLATED;
9691 }
9692 }
9693 AdjObjCache(obj_ptr);
9694 if (somethingHighLighted) HighLightReverse();
9695 RedrawAnArea(botObj, selLtX-GRID_ABS_SIZE(1),
9696 selLtY-GRID_ABS_SIZE(1), selRbX+GRID_ABS_SIZE(1),
9697 selRbY+GRID_ABS_SIZE(1));
9698 if (!somethingHighLighted) HighLightForward();
9699 SetFileModified(TRUE);
9700 justDupped = FALSE;
9701 } else {
9702 SetStringStatus(TgLoadString(STID_SEL_PT_NOT_ON_IMAGE));
9703 }
9704 }
9705 SetDefaultCursor(mainWindow);
9706 ShowCursor();
9707 }
9708 RestoreStatusStrings();
9709 return changed;
9710 }
9711
FloodFill()9712 void FloodFill()
9713 {
9714 struct ObjRec *obj_ptr=NULL;
9715 unsigned char trans_color_r='\0', trans_color_g='\0', trans_color_b='\0';
9716
9717 if (!CheckSelectionForImageProc(CMDID_FLOODFILL)) {
9718 return;
9719 }
9720 obj_ptr = topSel->obj;
9721 if (ObjHasTrueColorTransPixel(obj_ptr, &trans_color_r, &trans_color_g,
9722 &trans_color_b)) {
9723 if (CurColorIsTranscolor(trans_color_r, trans_color_g, trans_color_b)) {
9724 sprintf(gszMsgBox, TgLoadString(STID_CUR_COLOR_IS_TRANS_PIXEL),
9725 colorMenuItems[colorIndex],
9726 GetImageProcName(CMDID_FLOODFILL));
9727 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
9728 return;
9729 }
9730 }
9731 if (somethingHighLighted) HighLightReverse();
9732 XSync(mainDisplay, False);
9733 PrepareToReplaceAnObj(obj_ptr);
9734
9735 ResetThreshFillReplaceInfo();
9736 if (ContinueFloodFill(obj_ptr)) {
9737 RecordReplaceAnObj(obj_ptr);
9738 } else {
9739 AbortPrepareCmd(CMD_REPLACE);
9740 }
9741 if (!somethingHighLighted) HighLightForward();
9742 }
9743
9744 /* ----------------------- ToggleFloodReplaceColorThreshold ----------------------- */
9745
ToggleFloodReplaceColorThreshold()9746 void ToggleFloodReplaceColorThreshold()
9747 {
9748 threshFillReplaceEnabled = !threshFillReplaceEnabled;
9749
9750 if (threshFillReplaceEnabled) {
9751 sprintf(gszMsgBox, TgLoadString(STID_FLOOD_REPLACE_ENABLED),
9752 fillReplaceRedThresh, fillReplaceGreenThresh,
9753 fillReplaceBlueThresh);
9754 Msg(gszMsgBox);
9755 } else {
9756 sprintf(gszMsgBox, TgLoadString(STID_FLOOD_REPLACE_DISABLED));
9757 Msg(gszMsgBox);
9758 }
9759 }
9760
9761 /* ----------------------- SetFloodReplaceColorThreshold ----------------------- */
9762
SetFloodReplaceColorThreshold()9763 void SetFloodReplaceColorThreshold()
9764 {
9765 char spec[MAXSTRING];
9766
9767 *spec = '\0';
9768 sprintf(gszMsgBox, TgLoadString(STID_SET_FLOOD_REPLACE_THRESH),
9769 fillReplaceRedThresh, fillReplaceGreenThresh,
9770 fillReplaceBlueThresh);
9771 if (Dialog(gszMsgBox, NULL, spec) == INVALID) return;
9772 UtilTrimBlanks(spec);
9773 if (*spec == '\0') return;
9774
9775 if (ParseThreshFillReplaceSpec(spec)) {
9776 sprintf(gszMsgBox, TgLoadString(STID_FLOOD_REPLACE_THRESH_SET_TO),
9777 fillReplaceRedThresh, fillReplaceGreenThresh,
9778 fillReplaceBlueThresh);
9779 Msg(gszMsgBox);
9780 }
9781 }
9782
9783 /* ----------------------- CreateContour ----------------------- */
9784
9785 /*------------------------------------------------*/
9786 /* the contour code is adapted from Tim Feldman's */
9787 /* contour code in Graphics Gem III */
9788 /*------------------------------------------------*/
9789
9790 typedef struct CDirInfo {
9791 /* 5 6 7 */
9792 /* 4 0 */
9793 /* 3 2 1 */
9794 short dir;
9795 struct CDirInfo *next;
9796 } CDirInfoPtr;
9797
9798 static struct CDirInfo *topOfChain=NULL, *botOfChain=NULL;
9799
9800 static int gnContourX=0, gnContourY=0;
9801 static int gnContourW=0, gnContourH=0;
9802 static unsigned short gnContourRed=0, gnContourGreen=0, gnContourBlue=0;
9803 static int **gnaContourPixels=NULL;
9804 static XImage *gContourImage=NULL, *gContourBitmapImage=NULL;
9805 static struct ObjRec *gpContourObj=NULL;
9806
9807 static
CleanUpContour()9808 void CleanUpContour()
9809 {
9810 if (gnaContourPixels != NULL) {
9811 int i;
9812
9813 for (i=0; i < gnContourH; i++) {
9814 if (gnaContourPixels[i] != NULL) {
9815 free(gnaContourPixels[i]);
9816 } else {
9817 break;
9818 }
9819 }
9820 free(gnaContourPixels);
9821 }
9822 gnaContourPixels = NULL;
9823
9824 for ( ; topOfChain != NULL; topOfChain=botOfChain) {
9825 botOfChain = topOfChain->next;
9826 free(topOfChain);
9827 }
9828 topOfChain = botOfChain = NULL;
9829 }
9830
9831 static
OnContour(x,y)9832 int OnContour(x, y)
9833 int x, y;
9834 {
9835 if (x >= 0 && x < gnContourW && y >= 0 && y < gnContourH) {
9836 int index;
9837
9838 if (gnaContourPixels[y][x] == BAD) {
9839 gnaContourPixels[y][x] = XGetPixel(gContourImage, x, y);
9840 }
9841 index = GetIndexOfPixel(gnaContourPixels[y][x]);
9842 if (tgifColors[index].red == gnContourRed &&
9843 tgifColors[index].green == gnContourGreen &&
9844 tgifColors[index].blue == gnContourBlue) {
9845 return TRUE;
9846 }
9847 }
9848 return FALSE;
9849 }
9850
9851 static
ProbeContour(x,y,dir,pn_new_x,pn_new_y)9852 int ProbeContour(x, y, dir, pn_new_x, pn_new_y)
9853 int x, y, dir, *pn_new_x, *pn_new_y;
9854 {
9855 switch (dir) {
9856 case 0: x++; break;
9857 case 1: x++; y++; break;
9858 case 2: y++; break;
9859 case 3: x--; y++; break;
9860 case 4: x--; break;
9861 case 5: x--; y--; break;
9862 case 6: y--; break;
9863 case 7: x++; y--; break;
9864 }
9865 *pn_new_x = x;
9866 *pn_new_y = y;
9867 return OnContour(x, y);
9868 }
9869
9870 static
ContourNeighbor(x,y,last_dir,pn_new_x,pn_new_y)9871 int ContourNeighbor(x, y, last_dir, pn_new_x, pn_new_y)
9872 int x, y, last_dir, *pn_new_x, *pn_new_y;
9873 /*
9874 * if last vector was 0, start looking at 1
9875 * if last vector was 1, start looking at 3
9876 * if last vector was 2, start looking at 3
9877 * if last vector was 3, start looking at 5
9878 * if last vector was 4, start looking at 5
9879 * if last vector was 5, start looking at 7
9880 * if last vector was 6, start looking at 7
9881 * if last vector was 7, start looking at 1
9882 */
9883 {
9884 int i;
9885
9886 if (last_dir & 0x1) {
9887 last_dir += 2;
9888 } else {
9889 last_dir++;
9890 }
9891 if (last_dir > 7) last_dir -= 8;
9892 for (i=0; i < 8; i++) {
9893 if (ProbeContour(x, y, last_dir, pn_new_x, pn_new_y)) {
9894 return last_dir;
9895 } else {
9896 if (--last_dir < 0) last_dir += 8;
9897 }
9898 }
9899 #ifdef _TGIF_DBG /* debug, do not translate */
9900 fprintf(stderr, "Should not have come here ContourNeighbor()!\n");
9901 #endif /* _TGIF_DBG */
9902 return (-1);
9903 }
9904
9905 static
CreatePolyFromContour(num_pts)9906 int CreatePolyFromContour(num_pts)
9907 int num_pts;
9908 {
9909 int x=gnContourX, y=gnContourY, generate=(num_pts > 2);
9910 struct CDirInfo *pcdi=topOfChain;
9911 struct XfrmMtrxRec *ctm=NULL;
9912
9913 if (generate) {
9914 ResetCreatePolygon();
9915 ctm = gpContourObj->ctm;
9916 } else {
9917 num_pts = 0;
9918 }
9919 while (pcdi != NULL) {
9920 int dir=pcdi->dir, n=1;
9921 struct CDirInfo *pcdi1=pcdi->next;
9922
9923 for ( ; pcdi1 != NULL; pcdi1=pcdi1->next) {
9924 if (pcdi1->dir != dir) {
9925 break;
9926 } else {
9927 n++;
9928 }
9929 }
9930 if (generate) {
9931 if (ctm == NULL) {
9932 AddPtToCreatePolygon(gpContourObj->x+x, gpContourObj->y+y);
9933 } else {
9934 int tmp_x, tmp_y;
9935
9936 TransformPointThroughCTM(x, y, ctm, &tmp_x, &tmp_y);
9937 AddPtToCreatePolygon(gpContourObj->x+tmp_x, gpContourObj->y+tmp_y);
9938 }
9939 } else {
9940 num_pts++;
9941 }
9942 switch (dir) {
9943 case 0: x += n; break;
9944 case 1: x += n; y += n; break;
9945 case 2: y += n; break;
9946 case 3: x -= n; y += n; break;
9947 case 4: x -= n; break;
9948 case 5: x -= n; y -= n; break;
9949 case 6: y -= n; break;
9950 case 7: x += n; y -= n; break;
9951 }
9952 pcdi = pcdi1;
9953 }
9954 if (generate) {
9955 if (ctm == NULL) {
9956 AddPtToCreatePolygon(gpContourObj->x+x, gpContourObj->y+y);
9957 } else {
9958 int tmp_x, tmp_y;
9959
9960 TransformPointThroughCTM(x, y, ctm, &tmp_x, &tmp_y);
9961 AddPtToCreatePolygon(gpContourObj->x+tmp_x, gpContourObj->y+tmp_y);
9962 }
9963 CreatePolygonObj(num_pts, TRUE);
9964 } else {
9965 num_pts++;
9966 }
9967 if (generate) {
9968 return TRUE;
9969 }
9970 return num_pts;
9971 }
9972
9973 static
DoCreateContour()9974 int DoCreateContour()
9975 {
9976 int x, y, dir, new_x, new_y, last_dir, num_pts=0;
9977
9978 while (OnContour(gnContourX, gnContourY)) {
9979 gnContourX--;
9980 }
9981 gnContourX++;
9982 topOfChain = NULL;
9983
9984 x = new_x = gnContourX;
9985 y = new_y = gnContourY;
9986 dir = 0;
9987 for (;;) {
9988 if (ProbeContour(x, y, dir, &new_x, &new_y)) {
9989 break;
9990 } else if (++dir >= 8) {
9991 MsgBox(TgLoadString(STID_NO_CONTOUR_CAN_BE_GEN_HERE), TOOL_NAME,
9992 INFO_MB);
9993 return FALSE;
9994 }
9995 }
9996 last_dir = 1;
9997 for (;;) {
9998 struct CDirInfo *pcdi;
9999
10000 dir = ContourNeighbor(x, y, last_dir, &new_x, &new_y);
10001 pcdi = (struct CDirInfo *)malloc(sizeof(struct CDirInfo));
10002 if (pcdi == NULL) FailAllocMessage();
10003 memset(pcdi, 0, sizeof(struct CDirInfo));
10004 pcdi->dir = dir;
10005 pcdi->next = NULL;
10006 if (botOfChain == NULL) {
10007 topOfChain = pcdi;
10008 } else {
10009 botOfChain->next = pcdi;
10010 }
10011 botOfChain = pcdi;
10012 if (new_x == gnContourX && new_y == gnContourY) {
10013 break;
10014 }
10015 x = new_x;
10016 y = new_y;
10017 last_dir = dir;
10018 }
10019 num_pts = CreatePolyFromContour(0);
10020 if (num_pts > 2) {
10021 return CreatePolyFromContour(num_pts);
10022 }
10023 MsgBox(TgLoadString(STID_NO_CONTOUR_CAN_BE_GEN_HERE), TOOL_NAME, INFO_MB);
10024 return FALSE;
10025 }
10026
10027 static
StartCreateContour(obj_ptr,image,bitmap_image,image_x,image_y,image_w,image_h)10028 int StartCreateContour(obj_ptr, image, bitmap_image, image_x, image_y,
10029 image_w, image_h)
10030 struct ObjRec *obj_ptr;
10031 XImage *image, *bitmap_image;
10032 int image_x, image_y, image_w, image_h;
10033 {
10034 int i, pixel=(-1), created=FALSE;
10035
10036 gnContourX = image_x;
10037 gnContourY = image_y;
10038 gnContourW = image_w;
10039 gnContourH = image_h;
10040 gContourImage = image;
10041 gContourBitmapImage = bitmap_image;
10042 gpContourObj = obj_ptr;
10043
10044 gnaContourPixels = (int**)malloc(image_h*sizeof(int*));
10045 if (gnaContourPixels == NULL) {
10046 return FailAllocMessage();
10047 }
10048 memset(gnaContourPixels, 0, image_h*sizeof(int*));
10049 for (i=0; i < image_h; i++) {
10050 int j;
10051
10052 gnaContourPixels[i] = (int*)malloc(image_w*sizeof(int));
10053 if (gnaContourPixels[i] == NULL) {
10054 FailAllocMessage();
10055 CleanUpContour();
10056 return FALSE;
10057 }
10058 for (j=0; j < image_w; j++) gnaContourPixels[i][j] = BAD;
10059 }
10060 if (!CreatePixelToIndexMapping()) {
10061 CleanUpContour();
10062 return FALSE;
10063 }
10064 if (bitmap_image == NULL) {
10065 pixel = XGetPixel(image, image_x, image_y);
10066 } else {
10067 if (XGetPixel(bitmap_image, image_x, image_y) == 0) {
10068 /* transparent */
10069 } else {
10070 pixel = XGetPixel(image, image_x, image_y);
10071 }
10072 }
10073 SetWatchCursor(drawWindow);
10074 SetWatchCursor(mainWindow);
10075 gnPixelToFill = colorPixels[colorIndex];
10076 if (pixel == (-1)) {
10077 } else {
10078 int index=GetIndexOfPixel(pixel);
10079
10080 gnContourRed = tgifColors[index].red;
10081 gnContourGreen = tgifColors[index].green;
10082 gnContourBlue = tgifColors[index].blue;
10083 created = DoCreateContour();
10084 }
10085 SetDefaultCursor(mainWindow);
10086 ShowCursor();
10087
10088 CleanUpIndexOfPixel();
10089 CleanUpContour();
10090
10091 return created;
10092 }
10093
10094 static
ContinueCreateContour(obj_ptr)10095 int ContinueCreateContour(obj_ptr)
10096 struct ObjRec *obj_ptr;
10097 {
10098 int image_w, image_h, changed=FALSE, mouse_x=0, mouse_y=0;
10099 unsigned int button;
10100 struct XPmRec *xpm_ptr=obj_ptr->detail.xpm;
10101 XImage *image, *bitmap_image;
10102
10103 xpm_ptr = obj_ptr->detail.xpm;
10104 image_w = xpm_ptr->image_w;
10105 image_h = xpm_ptr->image_h;
10106 image = xpm_ptr->image;
10107 bitmap_image = xpm_ptr->bitmap_image;
10108 if (image == NULL) {
10109 image = xpm_ptr->image = XGetImage(mainDisplay, xpm_ptr->pixmap, 0, 0,
10110 image_w, image_h, AllPlanes, ZPixmap);
10111 if (image == NULL) FailAllocMessage();
10112 }
10113 if (xpm_ptr->bitmap != None && bitmap_image == NULL) {
10114 bitmap_image = xpm_ptr->bitmap_image = XGetImage(mainDisplay,
10115 xpm_ptr->bitmap, 0, 0, image_w, image_h, AllPlanes, ZPixmap);
10116 if (bitmap_image == NULL) FailAllocMessage();
10117 }
10118 SaveStatusStrings();
10119 Msg(TgLoadString(STID_SEL_A_COLOR_TO_BE_TRACED));
10120 SetMouseStatus(TgLoadString(STID_START_CONTOUR),
10121 TgLoadCachedString(CSTID_FINISH), TgLoadCachedString(CSTID_FINISH));
10122
10123 button = FillReplacePickAPoint(&mouse_x, &mouse_y, NULL, NULL, FALSE,
10124 handCursor);
10125
10126 if (button == Button1) {
10127 int abs_x=ABS_X(mouse_x), abs_y=ABS_Y(mouse_y), found=FALSE;
10128 int image_x=0, image_y=0;
10129
10130 if (obj_ptr->ctm == NULL) {
10131 if (abs_x >= obj_ptr->obbox.ltx && abs_y >= obj_ptr->obbox.lty &&
10132 abs_x < obj_ptr->obbox.rbx && abs_y < obj_ptr->obbox.rby) {
10133 image_x = abs_x-obj_ptr->obbox.ltx;
10134 image_y = abs_y-obj_ptr->obbox.lty;
10135 if (image_x >= 0 && image_y >= 0 &&
10136 image_x < image_w && image_y < image_h) {
10137 found = TRUE;
10138 }
10139 }
10140 } else {
10141 double image_dx=(double)0, image_dy=(double)0;
10142
10143 ReverseTransformDoublePointThroughCTM(
10144 ((double)(abs_x-obj_ptr->x)+0.5),
10145 ((double)(abs_y-obj_ptr->y)+0.5),
10146 obj_ptr->ctm, &image_dx, &image_dy);
10147 image_x += (double)(obj_ptr->x-obj_ptr->orig_obbox.ltx);
10148 image_y += (double)(obj_ptr->y-obj_ptr->orig_obbox.lty);
10149 if (image_dx >= ((double)0) && image_dy >= ((double)0) &&
10150 image_dx < ((double)image_w) && image_dy < ((double)image_h)) {
10151 image_x = (int)image_dx;
10152 image_y = (int)image_dy;
10153 if (image_x < 0) image_x = 0;
10154 if (image_x >= image_w) image_x = image_w-1;
10155 if (image_y < 0) image_y = 0;
10156 if (image_y >= image_h) image_y = image_h-1;
10157 found = TRUE;
10158 }
10159 }
10160 if (found) {
10161 if (somethingHighLighted) HighLightReverse();
10162 changed = StartCreateContour(obj_ptr, image, bitmap_image, image_x,
10163 image_y, image_w, image_h);
10164 if (!somethingHighLighted) HighLightForward();
10165 } else {
10166 SetStringStatus(TgLoadString(STID_SEL_PT_NOT_ON_IMAGE));
10167 }
10168 }
10169 RestoreStatusStrings();
10170 return changed;
10171 }
10172
CreateContour()10173 void CreateContour()
10174 {
10175 struct ObjRec *obj_ptr;
10176
10177 if (!CheckSelectionForImageProc(CMDID_CREATECONTOUR)) {
10178 return;
10179 }
10180 obj_ptr = topSel->obj;
10181
10182 if (somethingHighLighted) HighLightReverse();
10183 XSync(mainDisplay, False);
10184 if (ContinueCreateContour(obj_ptr)) {
10185 if (somethingHighLighted) HighLightReverse();
10186 RemoveAllSel();
10187 numRedrawBBox = 0;
10188 obj_ptr->tmp_parent = NULL;
10189 DrawObj(drawWindow, topObj);
10190 SelectTopObj();
10191 RecordNewObjCmd();
10192 SetFileModified(TRUE);
10193 justDupped = FALSE;
10194 } else {
10195 if (!somethingHighLighted) HighLightForward();
10196 }
10197 }
10198
10199 /* ----------------------- Init and Clean Up ----------------------- */
10200
CleanUpImageProc()10201 void CleanUpImageProc()
10202 {
10203 CleanUpConvolution();
10204 }
10205
10206 /* do not translate -- program constants */
10207 static char gszDefBggen[]="bggen %s -g %s | ppmquant 64 | ppmtoxpm";
10208 static char gszDefPpm6Bggen[]="bggen %s -g %s";
10209 static char gszDefPpmquant[]="pnmquant %d %s";
10210 static char gszDefPpmFSquant[]="pnmquant -fs %d %s";
10211
InitImageProc()10212 void InitImageProc()
10213 {
10214 char *c_ptr=NULL, spec[MAXSTRING];
10215
10216 memset(&gConvExtraInfo, 0, sizeof(ConvExtraInfo));
10217 memset(&gThreshFillReplaceInfo, 0, sizeof(gThreshFillReplaceInfo));
10218
10219 gnQuantizingLevels = 222;
10220 if ((c_ptr=XGetDefault(mainDisplay,TOOL_NAME,"QuantizingLevels")) != NULL) {
10221 gnQuantizingLevels = atoi(c_ptr);
10222 if (gnQuantizingLevels < 2 || gnQuantizingLevels > 256) {
10223 fprintf(stderr, TgLoadString(STID_INVALID_XDEF_RNG_USE_ALT_VAL),
10224 TOOL_NAME, "QuantizingLevels", c_ptr, 2, 256, 256-maxColors);
10225 gnQuantizingLevels = 256-maxColors;
10226 }
10227 }
10228 strcpy(bggenToXpmCmd, gszDefBggen);
10229 if ((c_ptr=XGetDefault(mainDisplay,TOOL_NAME,"BggenToXpm")) != NULL) {
10230 int count=0;
10231
10232 UtilStrCpyN(bggenToXpmCmd, sizeof(bggenToXpmCmd), c_ptr);
10233 for (c_ptr=strstr(bggenToXpmCmd,"%s"); c_ptr!=NULL;
10234 c_ptr=strstr(++c_ptr,"%s")) {
10235 count++;
10236 }
10237 if (count != 2) {
10238 sprintf(gszMsgBox, TgLoadString(STID_INVALID_XDEF_USE_ALT_STR),
10239 TOOL_NAME, "BggenToXpm", bggenToXpmCmd, gszDefBggen);
10240 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
10241 strcpy(bggenToXpmCmd, gszDefBggen);
10242 }
10243 }
10244 strcpy(bggenToPpm6Cmd, gszDefPpm6Bggen);
10245 if ((c_ptr=XGetDefault(mainDisplay,TOOL_NAME,"BggenToPpm6")) != NULL) {
10246 int count=0;
10247
10248 UtilStrCpyN(bggenToPpm6Cmd, sizeof(bggenToPpm6Cmd), c_ptr);
10249 for (c_ptr=strstr(bggenToPpm6Cmd,"%s"); c_ptr!=NULL;
10250 c_ptr=strstr(++c_ptr,"%s")) {
10251 count++;
10252 }
10253 if (count != 2) {
10254 sprintf(gszMsgBox, TgLoadString(STID_INVALID_XDEF_USE_ALT_STR),
10255 TOOL_NAME, "BggenToPpm6", bggenToPpm6Cmd, gszDefPpm6Bggen);
10256 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
10257 strcpy(bggenToPpm6Cmd, gszDefPpm6Bggen);
10258 }
10259 }
10260 strcpy(ppmquantCmd, gszDefPpmquant);
10261 if ((c_ptr=XGetDefault(mainDisplay,TOOL_NAME,"PpmQuantize")) != NULL) {
10262 int count=0;
10263
10264 UtilStrCpyN(ppmquantCmd, sizeof(ppmquantCmd), c_ptr);
10265 for (c_ptr=strstr(ppmquantCmd,"%s"); c_ptr!=NULL;
10266 c_ptr=strstr(++c_ptr,"%s")) {
10267 count++;
10268 }
10269 if (count != 1) {
10270 sprintf(gszMsgBox, TgLoadString(STID_INVALID_XDEF_USE_ALT_STR),
10271 TOOL_NAME, "PpmQuantize", ppmquantCmd, gszDefPpmquant);
10272 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
10273 strcpy(ppmquantCmd, gszDefPpmquant);
10274 }
10275 for (c_ptr=strstr(ppmquantCmd,"%d"); c_ptr!=NULL;
10276 c_ptr=strstr(++c_ptr,"%d")) {
10277 count++;
10278 }
10279 if (count != 1) {
10280 sprintf(gszMsgBox, TgLoadString(STID_INVALID_XDEF_USE_ALT_STR),
10281 TOOL_NAME, "PpmQuantize", ppmquantCmd, gszDefPpmquant);
10282 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
10283 strcpy(ppmquantCmd, gszDefPpmquant);
10284 }
10285 }
10286 strcpy(ppmFSquantCmd, gszDefPpmFSquant);
10287 if ((c_ptr=XGetDefault(mainDisplay,TOOL_NAME,"PpmFSQuantize")) != NULL) {
10288 int count=0;
10289
10290 UtilStrCpyN(ppmFSquantCmd, sizeof(ppmFSquantCmd), c_ptr);
10291 for (c_ptr=strstr(ppmFSquantCmd,"%s"); c_ptr!=NULL;
10292 c_ptr=strstr(++c_ptr,"%s")) {
10293 count++;
10294 }
10295 if (count != 1) {
10296 sprintf(gszMsgBox, TgLoadString(STID_INVALID_XDEF_USE_ALT_STR),
10297 TOOL_NAME, "PpmQuantize", ppmFSquantCmd, gszDefPpmFSquant);
10298 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
10299 strcpy(ppmFSquantCmd, gszDefPpmFSquant);
10300 }
10301 for (c_ptr=strstr(ppmFSquantCmd,"%d"); c_ptr!=NULL;
10302 c_ptr=strstr(++c_ptr,"%d")) {
10303 count++;
10304 }
10305 if (count != 1) {
10306 sprintf(gszMsgBox, TgLoadString(STID_INVALID_XDEF_USE_ALT_STR),
10307 TOOL_NAME, "PpmQuantize", ppmFSquantCmd, gszDefPpmFSquant);
10308 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
10309 strcpy(ppmFSquantCmd, gszDefPpmFSquant);
10310 }
10311 }
10312 gDefErrorDiffuseLevel.red = gDefErrorDiffuseLevel.green =
10313 gDefErrorDiffuseLevel.blue = 2;
10314 if ((c_ptr=XGetDefault(mainDisplay,TOOL_NAME,"DefaultErrorDiffuseLevels")) !=
10315 NULL) {
10316 XColor xcolor;
10317 char *dup_buf=UtilStrDup(c_ptr);
10318
10319 if (dup_buf == NULL) FailAllocMessage();
10320 switch (ParseDefaultColorLevels(dup_buf, &xcolor)) {
10321 case PDCL_OK:
10322 gDefErrorDiffuseLevel.red = xcolor.red;
10323 gDefErrorDiffuseLevel.green = xcolor.green;
10324 gDefErrorDiffuseLevel.blue = xcolor.blue;
10325 break;
10326 case PDCL_TOO_LARGE:
10327 fprintf(stderr, TgLoadString(STID_VAL_TOO_LARGE_IN_XDEF_USE_ALT),
10328 TOOL_NAME, "DefaultErrorDiffuseLevels", c_ptr, "2 2 2");
10329 fprintf(stderr, "\n");
10330 break;
10331 case PDCL_TOO_SMALL:
10332 fprintf(stderr, TgLoadString(STID_VAL_TOO_SMALL_IN_XDEF_USE_ALT),
10333 TOOL_NAME, "DefaultErrorDiffuseLevels", c_ptr, "2 2 2");
10334 break;
10335 case PDCL_BAD_FORMAT:
10336 fprintf(stderr, TgLoadString(STID_INVALID_XDEF_USE_ALT_STR),
10337 TOOL_NAME, "DefaultErrorDiffuseLevels", c_ptr, "2 2 2");
10338 break;
10339 }
10340 free(dup_buf);
10341 }
10342 memset(gaHGBucket, 0, sizeof(gaHGBucket));
10343 memset(&gTrueColorInfo, 0, sizeof(TrueColorInfo));
10344
10345 threshFillReplaceEnabled = FALSE;
10346 if ((c_ptr=XGetDefault(mainDisplay,TOOL_NAME,
10347 "EnableThresholdFloodReplaceColor")) != NULL &&
10348 UtilStrICmp(c_ptr, "true") == 0) {
10349 threshFillReplaceEnabled = TRUE;
10350 }
10351 *spec = '\0';
10352 if ((c_ptr=XGetDefault(mainDisplay,TOOL_NAME,
10353 "FloodReplaceColorThreshold")) != NULL) {
10354 UtilStrCpyN(spec, sizeof(spec), c_ptr);
10355 UtilTrimBlanks(spec);
10356 if (!ParseThreshFillReplaceSpec(spec)) {
10357 fprintf(stderr, TgLoadString(STID_INVALID_XDEF_USE_ALT_STR),
10358 TOOL_NAME, "FloodReplaceColorThreshold", spec,
10359 "15,15,15");
10360 fprintf(stderr, "\n");
10361 }
10362 }
10363 }
10364
10365 /* ----------------------- Menu Functions ----------------------- */
10366
RefreshImageProcMenu(menu)10367 int RefreshImageProcMenu(menu)
10368 TgMenu *menu;
10369 {
10370 int ok=TRUE;
10371
10372 /* Enable Threshold-based Flood and Replace Colors */
10373 ok &= TgSetMenuItemCheckById(menu, CMDID_TOGGLEFLOODREPLACECOLORTHRESH,
10374 threshFillReplaceEnabled);
10375
10376 /* Set Threshold for Flood and Replace Colors */
10377 ok &= TgEnableMenuItemById(menu, CMDID_SETFLOODREPLACECOLORTHRESH,
10378 threshFillReplaceEnabled);
10379
10380 return ok;
10381 }
10382
CreateImageProcMenu(parent_menu,x,y,menu_info,status_str_xlated)10383 TgMenu *CreateImageProcMenu(parent_menu, x, y, menu_info, status_str_xlated)
10384 TgMenu *parent_menu;
10385 int x, y;
10386 TgMenuInfo *menu_info;
10387 int status_str_xlated; /* ignored, always 0 */
10388 {
10389 TgMenu *menu=TgCreateMenuFromMenuInfo(parent_menu, x, y, menu_info, FALSE);
10390
10391 if (menu != NULL) {
10392 if (!RefreshImageProcMenu(menu)) {
10393 return TgDestroyMenu(menu, TRUE);
10394 }
10395 menu->refresh_proc = ((RefreshMenuFunc*)RefreshImageProcMenu);
10396 }
10397 return menu;
10398 }
10399
ImageProcMenu(X,Y,TrackMenubar)10400 int ImageProcMenu(X, Y, TrackMenubar)
10401 int X, Y, TrackMenubar;
10402 {
10403 int rc=INVALID;
10404 TgMenu *menu=(imageProcMenuInfo.create_proc)(NULL, X, Y, &imageProcMenuInfo,
10405 FALSE);
10406
10407 activeMenu = MENU_IMAGEPROC;
10408 if (menu != NULL) {
10409 menu->track_menubar = TrackMenubar;
10410
10411 rc = TgMenuLoop(menu);
10412 TgDestroyMenu(menu, TRUE);
10413 }
10414 return rc;
10415 }
10416
10417