image.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555
  1. /*
  2. * CDE - Common Desktop Environment
  3. *
  4. * Copyright (c) 1993-2012, The Open Group. All rights reserved.
  5. *
  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)
  10. * any later version.
  11. *
  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
  16. * details.
  17. *
  18. * You should have received a copy of the GNU Lesser General Public
  19. * License along with these librararies and programs; if not, write
  20. * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
  21. * Floor, Boston, MA 02110-1301 USA
  22. */
  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
  29. * Novell, Inc.
  30. **********************************************************************/
  31. /******************************************************************************
  32. ** Program: dticon
  33. **
  34. ** Description: X11-based multi-color icon editor
  35. **
  36. ** File: Image.c, containing the following subroutines/functions:
  37. ** Mirror_Image()
  38. ** Block_Rotate()
  39. ** Scale_Image()
  40. ** Flood_Region()
  41. ** Flood_Fill()
  42. **
  43. ******************************************************************************
  44. **
  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.
  49. **
  50. ** Hewlett-Packard makes no representations about the suitibility of this
  51. ** software for any purpose. It is provided "as is" without express or
  52. ** implied warranty.
  53. **
  54. ******************************************************************************/
  55. #include <stdio.h>
  56. #include "externals.h"
  57. int flood_min_x, flood_min_y, flood_max_x, flood_max_y;
  58. /***************************************************************************
  59. * *
  60. * Routine: Mirror_Image *
  61. * *
  62. * Purpose: Pick "horizontal" or "vertical" from a submenu. Then pick *
  63. * the rectangle to be flopped. Create a mirror image (either *
  64. * top-to-bottom or left-to-right) and prompt the user for *
  65. * placement of the result. *
  66. * *
  67. *X11***********************************************************************/
  68. int
  69. Mirror_Image(
  70. int orientation )
  71. {
  72. XRectangle tmp_box;
  73. XImage *new_image, *old_image, *new_mono, *old_mono;
  74. unsigned long n;
  75. int i, j;
  76. #ifdef DEBUG
  77. if (debug)
  78. stat_out("Entering Mirror_Image\n");
  79. #endif
  80. if (!Selected)
  81. return (False);
  82. /*--- get src. & dst. images from both color and monochrome icons ---*/
  83. old_image = XGetImage(dpy, color_icon, select_box.x, select_box.y,
  84. select_box.width, select_box.height, AllPlanes, format);
  85. if (old_image == NULL)
  86. return (False);
  87. new_image = XGetImage(dpy, color_icon, select_box.x, select_box.y,
  88. select_box.width, select_box.height, AllPlanes, format);
  89. if (new_image == NULL) {
  90. XDestroyImage(old_image);
  91. return (False);
  92. }
  93. old_mono = XGetImage(dpy, mono_icon, select_box.x, select_box.y,
  94. select_box.width, select_box.height, AllPlanes, format);
  95. if (old_mono == NULL) {
  96. XDestroyImage(old_image);
  97. XDestroyImage(new_image);
  98. return (False);
  99. }
  100. new_mono = XGetImage(dpy, mono_icon, select_box.x, select_box.y,
  101. select_box.width, select_box.height, AllPlanes, format);
  102. if (new_mono == NULL) {
  103. XDestroyImage(old_image);
  104. XDestroyImage(new_image);
  105. XDestroyImage(old_mono);
  106. return (False);
  107. }
  108. #ifdef DEBUG
  109. if (debug)
  110. stat_out(" - got the images\n");
  111. #endif
  112. for (i=0; i<(int)select_box.width; i++)
  113. for (j=0; j<(int)select_box.height; j++) {
  114. if (orientation == VERTICAL) {
  115. n = XGetPixel(old_image, i, j);
  116. XPutPixel(new_image, i, (select_box.height-1)-j, n);
  117. n = XGetPixel(old_mono, i, j);
  118. XPutPixel(new_mono, i, (select_box.height-1)-j, n);
  119. }
  120. else {
  121. n = XGetPixel(old_image, i, j);
  122. XPutPixel(new_image, (select_box.width-1)-i, j, n);
  123. n = XGetPixel(old_mono, i, j);
  124. XPutPixel(new_mono, (select_box.width-1)-i, j, n);
  125. }
  126. } /* for(j...) */
  127. XFlush(dpy);
  128. XPutImage(dpy, color_icon, Color_gc, new_image, 0, 0,
  129. select_box.x, select_box.y,
  130. select_box.width, select_box.height);
  131. XPutImage(dpy, XtWindow(iconImage), Color_gc, new_image, 0, 0,
  132. select_box.x, select_box.y,
  133. select_box.width, select_box.height);
  134. XPutImage(dpy, mono_icon, Mono_gc, new_mono, 0, 0,
  135. select_box.x, select_box.y,
  136. select_box.width, select_box.height);
  137. XPutImage(dpy, XtWindow(monoImage), Mono_gc, new_mono, 0, 0,
  138. select_box.x, select_box.y,
  139. select_box.width, select_box.height);
  140. Transfer_Back_Image(select_box.x, select_box.y,
  141. (select_box.x+select_box.width-1),
  142. (select_box.y+select_box.height-1),
  143. FILL);
  144. XDestroyImage(new_image);
  145. XDestroyImage(old_image);
  146. XDestroyImage(new_mono);
  147. XDestroyImage(old_mono);
  148. #ifdef DEBUG
  149. if (debug)
  150. stat_out("Leaving Mirror_Image\n");
  151. #endif
  152. return (True);
  153. }
  154. /***************************************************************************
  155. * *
  156. * Routine: Block_Rotate *
  157. * *
  158. * Purpose: Given source and destination pixmaps of the correct size, *
  159. * and the type of rotation to do, do a block rotation (90 *
  160. * degrees clockwise or counterclockwise) from the source to *
  161. * the destination. *
  162. * *
  163. *X11***********************************************************************/
  164. int
  165. Block_Rotate(
  166. XImage *src_image,
  167. XImage *dst_image,
  168. int rtype )
  169. {
  170. int i, j, width, height;
  171. unsigned long n;
  172. #ifdef DEBUG
  173. if (debug)
  174. stat_out("Entering Block_Rotate\n");
  175. #endif
  176. width = src_image->width;
  177. height = src_image->height;
  178. switch (rtype) {
  179. case ROTATE_L : for (i=0; i<width; i++)
  180. for (j=0; j<height; j++) {
  181. n = XGetPixel(src_image, i, j);
  182. XPutPixel(dst_image, j, (width-1)-i, n);
  183. }
  184. break;
  185. case ROTATE_R : for (i=0; i<width; i++)
  186. for (j=0; j<height; j++) {
  187. n = XGetPixel(src_image, i, j);
  188. XPutPixel(dst_image, (height-1)-j, i, n);
  189. }
  190. break;
  191. } /* switch */
  192. XFlush(dpy);
  193. #ifdef DEBUG
  194. if (debug)
  195. stat_out("Leaving Block_Rotate\n");
  196. #endif
  197. return (True);
  198. }
  199. /***************************************************************************
  200. * *
  201. * Routine: Scale_Image *
  202. * *
  203. * Purpose: Given a scr. and dst. XImage pair, scale the src. image to *
  204. * the size of the dst. image. *
  205. * *
  206. *X11***********************************************************************/
  207. void
  208. Scale_Image( void )
  209. {
  210. XImage *old_img, *old_mono;
  211. int old_x, old_y, new_x, new_y;
  212. int old_width, old_height, new_width, new_height;
  213. int min_x, min_y, max_x, max_y;
  214. #ifdef DEBUG
  215. if (debug)
  216. stat_out("Entering Scale_Image\n");
  217. #endif
  218. min_x = min(ix, last_ix);
  219. min_y = min(iy, last_iy);
  220. max_x = max(ix, last_ix);
  221. max_y = max(iy, last_iy);
  222. /*** make sure all four points are on the tablet ***/
  223. if (min_x < 0)
  224. min_x = 0;
  225. if (min_y < 0)
  226. min_y = 0;
  227. if ((max_x) >= icon_width)
  228. max_x = icon_width-1;
  229. if ((max_y) >= icon_height)
  230. max_y = icon_height-1;
  231. old_img = XGetImage(dpy, color_icon, select_box.x, select_box.y,
  232. select_box.width, select_box.height,
  233. AllPlanes, format);
  234. old_mono = XGetImage(dpy, mono_icon, select_box.x, select_box.y,
  235. select_box.width, select_box.height,
  236. AllPlanes, format);
  237. Scale = XGetImage(dpy, color_icon, min_x, min_y,
  238. (max_x-min_x+1), (max_y-min_y+1), AllPlanes, format);
  239. Scale_mono = XGetImage(dpy, mono_icon, min_x, min_y,
  240. (max_x-min_x+1), (max_y-min_y+1), AllPlanes, format);
  241. old_width = old_img->width;
  242. old_height = old_img->height;
  243. new_width = Scale->width;
  244. new_height = Scale->height;
  245. for (new_y=0; new_y<new_height; new_y++) {
  246. old_y = (old_height * new_y) / new_height;
  247. for (new_x=0; new_x<new_width; new_x++) {
  248. old_x = (old_width * new_x) / new_width;
  249. XPutPixel(Scale, new_x, new_y, XGetPixel(old_img, old_x, old_y));
  250. XPutPixel(Scale_mono, new_x, new_y, XGetPixel(old_mono, old_x, old_y));
  251. }
  252. }
  253. XDestroyImage(old_img);
  254. XDestroyImage(old_mono);
  255. #ifdef DEBUG
  256. if (debug)
  257. stat_out("Leaving Scale_Image\n");
  258. #endif
  259. }
  260. /***************************************************************************
  261. * *
  262. * Routine: Flood_Region *
  263. * *
  264. * Purpose: Pick the (rectangular) region to be flooded by a new color. *
  265. * Then pick an old color (pixel) in that region to be replaced *
  266. * by the new color (left button = current foreground, right *
  267. * button = current background). *
  268. * *
  269. *X11***********************************************************************/
  270. int
  271. Flood_Region(
  272. int flood_x,
  273. int flood_y )
  274. {
  275. XImage *ImagePix, *MonoPix;
  276. unsigned long new_pixel, new_mono;
  277. #ifdef DEBUG
  278. int i, j;
  279. unsigned long old_pixel;
  280. if (debug)
  281. stat_out("Entering Flood_Region\n");
  282. #endif
  283. /*--- get the image from the (adjusted) box ---*/
  284. ImagePix = XGetImage(dpy, color_icon, 0, 0, icon_width, icon_height,
  285. AllPlanes, format);
  286. if (ImagePix == NULL)
  287. return (False);
  288. MonoPix = XGetImage(dpy, mono_icon, 0, 0, icon_width, icon_height,
  289. AllPlanes, format);
  290. if (MonoPix == NULL)
  291. return (False);
  292. #ifdef DEBUG
  293. if (debug)
  294. stat_out(" - got the image\n");
  295. #endif
  296. if (ColorBlock == STATIC_COLOR) {
  297. new_pixel = StaticPen[CurrentColor];
  298. new_mono = StaticMono[CurrentColor];
  299. }
  300. else {
  301. new_pixel = DynamicPen[CurrentColor];
  302. new_mono = DynamicMono[CurrentColor];
  303. }
  304. #ifdef DEBUG
  305. if (debug) {
  306. for (i=0; i<icon_width; i++)
  307. for (j=0; j<icon_height; j++) {
  308. old_pixel = XGetPixel(ImagePix, i, j);
  309. if ((old_pixel < 0) || (old_pixel > 255))
  310. stat_out(" BAD PIXEL VALUE (%d) AT [%d,%d]\n", old_pixel, i, j);
  311. }
  312. stat_out(" SUCCESSFULLY accessed each pixel in the image\n");
  313. }
  314. #endif
  315. flood_min_x = icon_width;
  316. flood_min_y = icon_height;
  317. flood_max_x = 0;
  318. flood_max_y = 0;
  319. Flood_Fill(ImagePix, MonoPix, flood_x, flood_y, ImagePix->width,
  320. ImagePix->height, new_pixel, new_mono);
  321. XFlush(dpy);
  322. Backup_Icons();
  323. XPutImage(dpy, color_icon, Color_gc, ImagePix, 0, 0, 0, 0,
  324. icon_width, icon_height);
  325. XPutImage(dpy, XtWindow(iconImage), Color_gc, ImagePix,
  326. 0, 0, 0, 0, icon_width, icon_height);
  327. XPutImage(dpy, mono_icon, Mono_gc, MonoPix, 0, 0, 0, 0,
  328. icon_width, icon_height);
  329. XPutImage(dpy, XtWindow(monoImage), Mono_gc, MonoPix,
  330. 0, 0, 0, 0, icon_width, icon_height);
  331. Transfer_Back_Image(flood_min_x, flood_min_y,
  332. flood_max_x, flood_max_y, FILL);
  333. XDestroyImage(ImagePix);
  334. XDestroyImage(MonoPix);
  335. #ifdef DEBUG
  336. if (debug)
  337. stat_out("Leaving Flood_Region\n");
  338. #endif
  339. return (True);
  340. }
  341. /***************************************************************************
  342. * *
  343. * Routine: Set_FloodLimits *
  344. * *
  345. * Purpose: Given the current [x,y] of a pixel about to be modified by *
  346. * a flood-fill operation, compare it's location against the *
  347. * limits of the area already affected by the flood-fill. If *
  348. * the pixel is outside the already modified area, adjust the *
  349. * flood_min_x, flood_min_y, flood_max_x, and flood_min_y, so *
  350. * that the current pixel is within the area defined by those *
  351. * four variables. When the flood-fill is completed, the *
  352. * final values for those four variables will be used (by the *
  353. * Transfer_Back_Image() call in Flood_Region()) to minimize *
  354. * the size of the sub-image tranferred back to the tablet *
  355. * from the color icon pixmap. This process slows down the *
  356. * actual flooding operation, but can significantly speed up *
  357. * the transfer_back operation, so there is a net performance *
  358. * gain (potentially, a large one). *
  359. * *
  360. *X11***********************************************************************/
  361. void
  362. Set_FloodLimits(
  363. int x,
  364. int y )
  365. {
  366. if (x < flood_min_x)
  367. flood_min_x = x;
  368. if (x > flood_max_x)
  369. flood_max_x = x;
  370. if (y < flood_min_y)
  371. flood_min_y = y;
  372. if (y > flood_max_y)
  373. flood_max_y = y;
  374. }
  375. /***************************************************************************
  376. * *
  377. * Routine: Flood_Fill *
  378. * *
  379. * Purpose: Interatively examine each pixel within a bounded area, *
  380. * replacing the old-colored pixels encountered with *
  381. * new-colored pixels. *
  382. * *
  383. ***************************************************************************
  384. * one page seed fill program, 1 channel frame buffer version *
  385. * *
  386. * doesn't read each pixel twice like the BASICFILL algorithm in *
  387. * Alvy Ray Smith, "Tint Fill", SIGGRAPH '79 *
  388. * *
  389. * Paul Heckbert 13 Sept 1982, 28 Jan 1987 *
  390. * PIXAR 415-499-3600 *
  391. * P.O. Box 13719 UUCP: {sun,ucbvax}!pixar!ph *
  392. * San Rafael, CA 94913 ARPA: ph%pixar.uucp@ucbvax.berkeley.edu *
  393. *X11***********************************************************************/
  394. /*
  395. * segment of scan line y for xl<=x<=xr was filled,
  396. * now explore adjacent pixels in scan line y+dy
  397. */
  398. struct seg {short y, xl, xr, dy;};
  399. /*********************************************************
  400. #define MAX 10000
  401. *********************************************************/
  402. #define MAX 20000 /* max depth of stack */
  403. #define PUSH(Y, XL, XR, DY) \
  404. if (sp<stack+MAX && Y+(DY)>=0 && Y+(DY)<height) \
  405. {sp->y = Y; sp->xl = XL; sp->xr = XR; sp->dy = DY; sp++;}
  406. #define POP(Y, XL, XR, DY) \
  407. {sp--; Y = sp->y+(DY = sp->dy); XL = sp->xl; XR = sp->xr;}
  408. #ifdef DEBUG
  409. int local_debug=False, p_cnt;
  410. #endif
  411. int
  412. Flood_Fill(
  413. XImage *color_image,
  414. XImage *mono_image,
  415. int x,
  416. int y,
  417. int width,
  418. int height,
  419. unsigned long new_pixel,
  420. unsigned long new_mono )
  421. {
  422. int l, x1, x2, dy;
  423. unsigned long old_pixel;
  424. struct seg stack[MAX], *sp = stack;
  425. old_pixel = XGetPixel(color_image, x, y); /* read pv at seed point */
  426. if (old_pixel==new_pixel || x<0 || x>width || y<0 || y>height) return 0;
  427. PUSH(y, x, x, 1); /* needed in some cases */
  428. PUSH(y+1, x, x, -1); /* seed segment (popped 1st) */
  429. #ifdef DEBUG
  430. if (local_debug)
  431. p_cnt = 0;
  432. #endif
  433. while (sp>stack) {
  434. /* pop segment off stack and fill a neighboring scan line */
  435. POP(y, x1, x2, dy);
  436. for (x=x1; x>=0 && XGetPixel(color_image, x, y)==old_pixel; x--)
  437. {
  438. #ifdef DEBUG
  439. if (local_debug) {
  440. stat_out("+[%d,%d] ", x, y);
  441. p_cnt++;
  442. if (p_cnt == 8) {
  443. stat_out("\n");
  444. p_cnt = 0;
  445. }
  446. }
  447. #endif
  448. Set_FloodLimits(x, y);
  449. XPutPixel(color_image, x, y, new_pixel);
  450. XPutPixel(mono_image, x, y, new_mono);
  451. }
  452. if (x>=x1) goto skip;
  453. l = x+1;
  454. if (l<x1) PUSH(y, l, x1-1, -dy); /* leak on left? */
  455. x = x1+1;
  456. do {
  457. for (; x<width && XGetPixel(color_image, x, y)==old_pixel; x++)/**TAG**/
  458. {
  459. #ifdef DEBUG
  460. if (local_debug) {
  461. stat_out("-[%d,%d] ", x, y);
  462. p_cnt++;
  463. if (p_cnt == 8) {
  464. stat_out("\n");
  465. p_cnt = 0;
  466. }
  467. }
  468. #endif
  469. Set_FloodLimits(x, y);
  470. XPutPixel(color_image, x, y, new_pixel);
  471. XPutPixel(mono_image, x, y, new_mono);
  472. }
  473. PUSH(y, l, x-1, dy);
  474. if (x>x2+1) PUSH(y, x2+1, x-1, -dy); /* leak on right? */
  475. skip: for (x++; x<=x2 && XGetPixel(color_image, x, y)!=old_pixel; x++)
  476. {
  477. #ifdef DEBUG
  478. if (local_debug) {
  479. stat_out(" [%d,%d] ", x, y);
  480. p_cnt++;
  481. if (p_cnt == 8) {
  482. stat_out("\n");
  483. p_cnt = 0;
  484. }
  485. }
  486. #endif
  487. }
  488. l = x;
  489. } while (x<=x2);
  490. }
  491. }