2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these libraries and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
23 /* $XConsortium: image.c /main/4 1995/11/02 14:05:39 rswiston $ */
24 /*********************************************************************
25 * (c) Copyright 1993, 1994 Hewlett-Packard Company
26 * (c) Copyright 1993, 1994 International Business Machines Corp.
27 * (c) Copyright 1993, 1994 Sun Microsystems, Inc.
28 * (c) Copyright 1993, 1994 Unix System Labs, Inc., a subsidiary of
30 **********************************************************************/
31 /******************************************************************************
34 ** Description: X11-based multi-color icon editor
36 ** File: Image.c, containing the following subroutines/functions:
43 ******************************************************************************
45 ** Copyright Hewlett-Packard Company, 1990, 1991, 1992.
46 ** All rights are reserved. Copying or reproduction of this program,
47 ** except for archival purposes, is prohibited without prior written
48 ** consent of Hewlett-Packard Company.
50 ** Hewlett-Packard makes no representations about the suitibility of this
51 ** software for any purpose. It is provided "as is" without express or
54 ******************************************************************************/
56 #include "externals.h"
58 int flood_min_x, flood_min_y, flood_max_x, flood_max_y;
61 /***************************************************************************
63 * Routine: Mirror_Image *
65 * Purpose: Pick "horizontal" or "vertical" from a submenu. Then pick *
66 * the rectangle to be flopped. Create a mirror image (either *
67 * top-to-bottom or left-to-right) and prompt the user for *
68 * placement of the result. *
70 *X11***********************************************************************/
77 XImage *new_image, *old_image, *new_mono, *old_mono;
83 stat_out("Entering Mirror_Image\n");
88 /*--- get src. & dst. images from both color and monochrome icons ---*/
90 old_image = XGetImage(dpy, color_icon, select_box.x, select_box.y,
91 select_box.width, select_box.height, AllPlanes, format);
92 if (old_image == NULL)
94 new_image = XGetImage(dpy, color_icon, select_box.x, select_box.y,
95 select_box.width, select_box.height, AllPlanes, format);
96 if (new_image == NULL) {
97 XDestroyImage(old_image);
101 old_mono = XGetImage(dpy, mono_icon, select_box.x, select_box.y,
102 select_box.width, select_box.height, AllPlanes, format);
103 if (old_mono == NULL) {
104 XDestroyImage(old_image);
105 XDestroyImage(new_image);
108 new_mono = XGetImage(dpy, mono_icon, select_box.x, select_box.y,
109 select_box.width, select_box.height, AllPlanes, format);
110 if (new_mono == NULL) {
111 XDestroyImage(old_image);
112 XDestroyImage(new_image);
113 XDestroyImage(old_mono);
119 stat_out(" - got the images\n");
122 for (i=0; i<(int)select_box.width; i++)
123 for (j=0; j<(int)select_box.height; j++) {
124 if (orientation == VERTICAL) {
125 n = XGetPixel(old_image, i, j);
126 XPutPixel(new_image, i, (select_box.height-1)-j, n);
127 n = XGetPixel(old_mono, i, j);
128 XPutPixel(new_mono, i, (select_box.height-1)-j, n);
131 n = XGetPixel(old_image, i, j);
132 XPutPixel(new_image, (select_box.width-1)-i, j, n);
133 n = XGetPixel(old_mono, i, j);
134 XPutPixel(new_mono, (select_box.width-1)-i, j, n);
139 XPutImage(dpy, color_icon, Color_gc, new_image, 0, 0,
140 select_box.x, select_box.y,
141 select_box.width, select_box.height);
142 XPutImage(dpy, XtWindow(iconImage), Color_gc, new_image, 0, 0,
143 select_box.x, select_box.y,
144 select_box.width, select_box.height);
146 XPutImage(dpy, mono_icon, Mono_gc, new_mono, 0, 0,
147 select_box.x, select_box.y,
148 select_box.width, select_box.height);
149 XPutImage(dpy, XtWindow(monoImage), Mono_gc, new_mono, 0, 0,
150 select_box.x, select_box.y,
151 select_box.width, select_box.height);
152 Transfer_Back_Image(select_box.x, select_box.y,
153 (select_box.x+select_box.width-1),
154 (select_box.y+select_box.height-1),
157 XDestroyImage(new_image);
158 XDestroyImage(old_image);
159 XDestroyImage(new_mono);
160 XDestroyImage(old_mono);
164 stat_out("Leaving Mirror_Image\n");
171 /***************************************************************************
173 * Routine: Block_Rotate *
175 * Purpose: Given source and destination pixmaps of the correct size, *
176 * and the type of rotation to do, do a block rotation (90 *
177 * degrees clockwise or counterclockwise) from the source to *
180 *X11***********************************************************************/
188 int i, j, width, height;
193 stat_out("Entering Block_Rotate\n");
196 width = src_image->width;
197 height = src_image->height;
200 case ROTATE_L : for (i=0; i<width; i++)
201 for (j=0; j<height; j++) {
202 n = XGetPixel(src_image, i, j);
203 XPutPixel(dst_image, j, (width-1)-i, n);
206 case ROTATE_R : for (i=0; i<width; i++)
207 for (j=0; j<height; j++) {
208 n = XGetPixel(src_image, i, j);
209 XPutPixel(dst_image, (height-1)-j, i, n);
217 stat_out("Leaving Block_Rotate\n");
224 /***************************************************************************
226 * Routine: Scale_Image *
228 * Purpose: Given a scr. and dst. XImage pair, scale the src. image to *
229 * the size of the dst. image. *
231 *X11***********************************************************************/
236 XImage *old_img, *old_mono;
237 int old_x, old_y, new_x, new_y;
238 int old_width, old_height, new_width, new_height;
239 int min_x, min_y, max_x, max_y;
243 stat_out("Entering Scale_Image\n");
246 min_x = min(ix, last_ix);
247 min_y = min(iy, last_iy);
248 max_x = max(ix, last_ix);
249 max_y = max(iy, last_iy);
251 /*** make sure all four points are on the tablet ***/
257 if ((max_x) >= icon_width)
258 max_x = icon_width-1;
259 if ((max_y) >= icon_height)
260 max_y = icon_height-1;
262 old_img = XGetImage(dpy, color_icon, select_box.x, select_box.y,
263 select_box.width, select_box.height,
265 old_mono = XGetImage(dpy, mono_icon, select_box.x, select_box.y,
266 select_box.width, select_box.height,
269 Scale = XGetImage(dpy, color_icon, min_x, min_y,
270 (max_x-min_x+1), (max_y-min_y+1), AllPlanes, format);
271 Scale_mono = XGetImage(dpy, mono_icon, min_x, min_y,
272 (max_x-min_x+1), (max_y-min_y+1), AllPlanes, format);
274 old_width = old_img->width;
275 old_height = old_img->height;
276 new_width = Scale->width;
277 new_height = Scale->height;
278 for (new_y=0; new_y<new_height; new_y++) {
279 old_y = (old_height * new_y) / new_height;
280 for (new_x=0; new_x<new_width; new_x++) {
281 old_x = (old_width * new_x) / new_width;
282 XPutPixel(Scale, new_x, new_y, XGetPixel(old_img, old_x, old_y));
283 XPutPixel(Scale_mono, new_x, new_y, XGetPixel(old_mono, old_x, old_y));
287 XDestroyImage(old_img);
288 XDestroyImage(old_mono);
292 stat_out("Leaving Scale_Image\n");
298 /***************************************************************************
300 * Routine: Flood_Region *
302 * Purpose: Pick the (rectangular) region to be flooded by a new color. *
303 * Then pick an old color (pixel) in that region to be replaced *
304 * by the new color (left button = current foreground, right *
305 * button = current background). *
307 *X11***********************************************************************/
314 XImage *ImagePix, *MonoPix;
315 unsigned long new_pixel, new_mono;
319 unsigned long old_pixel;
322 stat_out("Entering Flood_Region\n");
325 /*--- get the image from the (adjusted) box ---*/
327 ImagePix = XGetImage(dpy, color_icon, 0, 0, icon_width, icon_height,
329 if (ImagePix == NULL)
331 MonoPix = XGetImage(dpy, mono_icon, 0, 0, icon_width, icon_height,
338 stat_out(" - got the image\n");
341 if (ColorBlock == STATIC_COLOR) {
342 new_pixel = StaticPen[CurrentColor];
343 new_mono = StaticMono[CurrentColor];
346 new_pixel = DynamicPen[CurrentColor];
347 new_mono = DynamicMono[CurrentColor];
352 for (i=0; i<icon_width; i++)
353 for (j=0; j<icon_height; j++) {
354 old_pixel = XGetPixel(ImagePix, i, j);
355 if ((old_pixel < 0) || (old_pixel > 255))
356 stat_out(" BAD PIXEL VALUE (%d) AT [%d,%d]\n", old_pixel, i, j);
358 stat_out(" SUCCESSFULLY accessed each pixel in the image\n");
362 flood_min_x = icon_width;
363 flood_min_y = icon_height;
367 Flood_Fill(ImagePix, MonoPix, flood_x, flood_y, ImagePix->width,
368 ImagePix->height, new_pixel, new_mono);
372 XPutImage(dpy, color_icon, Color_gc, ImagePix, 0, 0, 0, 0,
373 icon_width, icon_height);
374 XPutImage(dpy, XtWindow(iconImage), Color_gc, ImagePix,
375 0, 0, 0, 0, icon_width, icon_height);
376 XPutImage(dpy, mono_icon, Mono_gc, MonoPix, 0, 0, 0, 0,
377 icon_width, icon_height);
378 XPutImage(dpy, XtWindow(monoImage), Mono_gc, MonoPix,
379 0, 0, 0, 0, icon_width, icon_height);
380 Transfer_Back_Image(flood_min_x, flood_min_y,
381 flood_max_x, flood_max_y, FILL);
382 XDestroyImage(ImagePix);
383 XDestroyImage(MonoPix);
387 stat_out("Leaving Flood_Region\n");
395 /***************************************************************************
397 * Routine: Set_FloodLimits *
399 * Purpose: Given the current [x,y] of a pixel about to be modified by *
400 * a flood-fill operation, compare it's location against the *
401 * limits of the area already affected by the flood-fill. If *
402 * the pixel is outside the already modified area, adjust the *
403 * flood_min_x, flood_min_y, flood_max_x, and flood_min_y, so *
404 * that the current pixel is within the area defined by those *
405 * four variables. When the flood-fill is completed, the *
406 * final values for those four variables will be used (by the *
407 * Transfer_Back_Image() call in Flood_Region()) to minimize *
408 * the size of the sub-image tranferred back to the tablet *
409 * from the color icon pixmap. This process slows down the *
410 * actual flooding operation, but can significantly speed up *
411 * the transfer_back operation, so there is a net performance *
412 * gain (potentially, a large one). *
414 *X11***********************************************************************/
432 /***************************************************************************
434 * Routine: Flood_Fill *
436 * Purpose: Interatively examine each pixel within a bounded area, *
437 * replacing the old-colored pixels encountered with *
438 * new-colored pixels. *
440 ***************************************************************************
441 * one page seed fill program, 1 channel frame buffer version *
443 * doesn't read each pixel twice like the BASICFILL algorithm in *
444 * Alvy Ray Smith, "Tint Fill", SIGGRAPH '79 *
446 * Paul Heckbert 13 Sept 1982, 28 Jan 1987 *
447 * PIXAR 415-499-3600 *
448 * P.O. Box 13719 UUCP: {sun,ucbvax}!pixar!ph *
449 * San Rafael, CA 94913 ARPA: ph%pixar.uucp@ucbvax.berkeley.edu *
450 *X11***********************************************************************/
453 * segment of scan line y for xl<=x<=xr was filled,
454 * now explore adjacent pixels in scan line y+dy
456 struct seg {short y, xl, xr, dy;};
457 /*********************************************************
459 *********************************************************/
460 #define MAX 20000 /* max depth of stack */
462 #define PUSH(Y, XL, XR, DY) \
463 if (sp<stack+MAX && Y+(DY)>=0 && Y+(DY)<height) \
464 {sp->y = Y; sp->xl = XL; sp->xr = XR; sp->dy = DY; sp++;}
466 #define POP(Y, XL, XR, DY) \
467 {sp--; Y = sp->y+(DY = sp->dy); XL = sp->xl; XR = sp->xr;}
470 int local_debug=False, p_cnt;
481 unsigned long new_pixel,
482 unsigned long new_mono )
485 unsigned long old_pixel;
486 struct seg stack[MAX], *sp = stack;
488 old_pixel = XGetPixel(color_image, x, y); /* read pv at seed point */
489 if (old_pixel==new_pixel || x<0 || x>width || y<0 || y>height) return 0;
490 PUSH(y, x, x, 1); /* needed in some cases */
491 PUSH(y+1, x, x, -1); /* seed segment (popped 1st) */
498 /* pop segment off stack and fill a neighboring scan line */
500 for (x=x1; x>=0 && XGetPixel(color_image, x, y)==old_pixel; x--)
504 stat_out("+[%d,%d] ", x, y);
512 Set_FloodLimits(x, y);
513 XPutPixel(color_image, x, y, new_pixel);
514 XPutPixel(mono_image, x, y, new_mono);
516 if (x>=x1) goto skip;
518 if (l<x1) PUSH(y, l, x1-1, -dy); /* leak on left? */
521 for (; x<width && XGetPixel(color_image, x, y)==old_pixel; x++)/**TAG**/
525 stat_out("-[%d,%d] ", x, y);
533 Set_FloodLimits(x, y);
534 XPutPixel(color_image, x, y, new_pixel);
535 XPutPixel(mono_image, x, y, new_mono);
538 if (x>x2+1) PUSH(y, x2+1, x-1, -dy); /* leak on right? */
539 skip: for (x++; x<=x2 && XGetPixel(color_image, x, y)!=old_pixel; x++)
543 stat_out(" [%d,%d] ", x, y);