Angband 3.0.9b.
[angband.git] / src / maid-x11.c
blob71a07bac7a61d579701862e703a0ba76c58c13f2
1 /* File: maid-x11.c */
3 /*
4 * Copyright (c) 1997 Ben Harrison, and others
6 * This software may be copied and distributed for educational, research,
7 * and not for profit purposes provided that this copyright and statement
8 * are included in all such copies.
9 */
13 * This file defines some "XImage" manipulation functions for X11.
15 * Original code by Desvignes Sebastien (desvigne@solar12.eerie.fr).
17 * BMP format support by Denis Eropkin (denis@dream.homepage.ru).
19 * Major fixes and cleanup by Ben Harrison (benh@phial.com).
21 * This file is designed to be "included" by "main-x11.c" or "main-xaw.c",
22 * which will have already "included" several relevant header files.
25 #include "angband.h"
27 #if defined(USE_X11) || defined(USE_XAW) || defined(USE_XPJ) || defined(USE_GTK)
29 #ifndef __MAKEDEPEND__
30 #include <X11/Xlib.h>
31 #include <X11/Xutil.h>
32 #include <X11/keysym.h>
33 #include <X11/keysymdef.h>
34 #endif /* __MAKEDEPEND__ */
36 /* Include our headers */
37 #include "maid-x11.h"
40 #ifdef SUPPORT_GAMMA
41 static bool gamma_table_ready = FALSE;
42 static int gamma_val = 0;
43 #endif /* SUPPORT_GAMMA */
47 * Hack -- Convert an RGB value to an X11 Pixel, or die.
49 u32b create_pixel(Display *dpy, byte red, byte green, byte blue)
51 Colormap cmap = DefaultColormapOfScreen(DefaultScreenOfDisplay(dpy));
53 XColor xcolour;
55 #ifdef SUPPORT_GAMMA
57 if (!gamma_table_ready)
59 cptr str = getenv("ANGBAND_X11_GAMMA");
60 if (str != NULL) gamma_val = atoi(str);
62 gamma_table_ready = TRUE;
64 /* Only need to build the table if gamma exists */
65 if (gamma_val) build_gamma_table(gamma_val);
68 /* Hack -- Gamma Correction */
69 if (gamma_val > 0)
71 red = gamma_table[red];
72 green = gamma_table[green];
73 blue = gamma_table[blue];
76 #endif /* SUPPORT_GAMMA */
78 /* Build the color */
80 xcolour.red = red * 255;
81 xcolour.green = green * 255;
82 xcolour.blue = blue * 255;
83 xcolour.flags = DoRed | DoGreen | DoBlue;
85 /* Attempt to Allocate the Parsed color */
86 if (!(XAllocColor(dpy, cmap, &xcolour)))
88 quit_fmt("Couldn't allocate bitmap color #%04x%04x%04x\n",
89 xcolour.red, xcolour.green, xcolour.blue);
92 return (xcolour.pixel);
97 * Get the name of the default font to use for the term.
99 cptr get_default_font(int term_num)
101 cptr font;
103 char buf[80];
105 /* Window specific font name */
106 strnfmt(buf, sizeof(buf), "ANGBAND_X11_FONT_%d", term_num);
108 /* Check environment for that font */
109 font = getenv(buf);
111 /* Check environment for "base" font */
112 if (!font) font = getenv("ANGBAND_X11_FONT");
114 /* No environment variables, use default font */
115 if (!font)
117 switch (term_num)
119 case 0:
121 font = DEFAULT_X11_FONT_0;
123 break;
124 case 1:
126 font = DEFAULT_X11_FONT_1;
128 break;
129 case 2:
131 font = DEFAULT_X11_FONT_2;
133 break;
134 case 3:
136 font = DEFAULT_X11_FONT_3;
138 break;
139 case 4:
141 font = DEFAULT_X11_FONT_4;
143 break;
144 case 5:
146 font = DEFAULT_X11_FONT_5;
148 break;
149 case 6:
151 font = DEFAULT_X11_FONT_6;
153 break;
154 case 7:
156 font = DEFAULT_X11_FONT_7;
158 break;
159 default:
161 font = DEFAULT_X11_FONT;
166 return (font);
170 #ifdef USE_GRAPHICS
173 * The Win32 "BITMAPFILEHEADER" type.
175 typedef struct BITMAPFILEHEADER
177 u16b bfType;
178 u32b bfSize;
179 u16b bfReserved1;
180 u16b bfReserved2;
181 u32b bfOffBits;
182 } BITMAPFILEHEADER;
186 * The Win32 "BITMAPINFOHEADER" type.
188 typedef struct BITMAPINFOHEADER
190 u32b biSize;
191 u32b biWidth;
192 u32b biHeight;
193 u16b biPlanes;
194 u16b biBitCount;
195 u32b biCompresion;
196 u32b biSizeImage;
197 u32b biXPelsPerMeter;
198 u32b biYPelsPerMeter;
199 u32b biClrUsed;
200 u32b biClrImportand;
201 } BITMAPINFOHEADER;
204 * The Win32 "RGBQUAD" type.
206 typedef struct RGBQUAD
208 unsigned char b, g, r;
209 unsigned char filler;
210 } RGBQUAD;
213 /*** Helper functions for system independent file loading. ***/
215 static byte get_byte(FILE *fff)
217 /* Get a character, and return it */
218 return (getc(fff) & 0xFF);
221 static void rd_byte(FILE *fff, byte *ip)
223 *ip = get_byte(fff);
226 static void rd_u16b(FILE *fff, u16b *ip)
228 (*ip) = get_byte(fff);
229 (*ip) |= ((u16b)(get_byte(fff)) << 8);
232 static void rd_u32b(FILE *fff, u32b *ip)
234 (*ip) = get_byte(fff);
235 (*ip) |= ((u32b)(get_byte(fff)) << 8);
236 (*ip) |= ((u32b)(get_byte(fff)) << 16);
237 (*ip) |= ((u32b)(get_byte(fff)) << 24);
242 * Read a Win32 BMP file.
244 * This function replaces the old ReadRaw and RemapColors functions.
246 * Assumes that the bitmap has a size such that no padding is needed in
247 * various places. Currently only handles bitmaps with 3 to 256 colors.
249 XImage *ReadBMP(Display *dpy, char *Name)
251 Visual *visual = DefaultVisual(dpy, DefaultScreen(dpy));
253 int depth = DefaultDepth(dpy, DefaultScreen(dpy));
255 FILE *f;
257 BITMAPFILEHEADER fileheader;
258 BITMAPINFOHEADER infoheader;
260 XImage *Res = NULL;
262 char *Data;
264 int ncol;
266 int total;
268 int i, j;
270 u32b x, y;
272 unsigned long clr_pixels[256];
275 /* Open the BMP file */
276 f = fopen(Name, "r");
278 /* No such file */
279 if (f == NULL)
281 return (NULL);
284 /* Read the "BITMAPFILEHEADER" */
285 rd_u16b(f, &(fileheader.bfType));
286 rd_u32b(f, &(fileheader.bfSize));
287 rd_u16b(f, &(fileheader.bfReserved1));
288 rd_u16b(f, &(fileheader.bfReserved2));
289 rd_u32b(f, &(fileheader.bfOffBits));
291 /* Read the "BITMAPINFOHEADER" */
292 rd_u32b(f, &(infoheader.biSize));
293 rd_u32b(f, &(infoheader.biWidth));
294 rd_u32b(f, &(infoheader.biHeight));
295 rd_u16b(f, &(infoheader.biPlanes));
296 rd_u16b(f, &(infoheader.biBitCount));
297 rd_u32b(f, &(infoheader.biCompresion));
298 rd_u32b(f, &(infoheader.biSizeImage));
299 rd_u32b(f, &(infoheader.biXPelsPerMeter));
300 rd_u32b(f, &(infoheader.biYPelsPerMeter));
301 rd_u32b(f, &(infoheader.biClrUsed));
302 rd_u32b(f, &(infoheader.biClrImportand));
304 /* Verify the header */
305 if (feof(f) ||
306 (fileheader.bfType != 19778) ||
307 (infoheader.biSize != 40))
309 quit_fmt("Incorrect BMP file format %s", Name);
312 /* The two headers above occupy 54 bytes total */
313 /* The "bfOffBits" field says where the data starts */
314 /* The "biClrUsed" field does not seem to be reliable */
315 /* Compute number of colors recorded */
316 ncol = (fileheader.bfOffBits - 54) / 4;
318 for (i = 0; i < ncol; i++)
320 RGBQUAD clrg;
322 /* Read an "RGBQUAD" */
323 rd_byte(f, &(clrg.b));
324 rd_byte(f, &(clrg.g));
325 rd_byte(f, &(clrg.r));
326 rd_byte(f, &(clrg.filler));
328 /* Analyze the color */
329 clr_pixels[i] = create_pixel(dpy, clrg.r, clrg.g, clrg.b);
332 /* Determine total bytes needed for image */
333 i = 1;
334 j = (depth - 1) >> 2;
335 while (j >>= 1) i <<= 1;
336 total = infoheader.biWidth * infoheader.biHeight * i;
338 /* Allocate image memory */
339 C_MAKE(Data, total, char);
341 Res = XCreateImage(dpy, visual, depth, ZPixmap, 0 /*offset*/,
342 Data, infoheader.biWidth, infoheader.biHeight,
343 32 /*bitmap_pad*/, 0 /*bytes_per_line*/);
345 /* Failure */
346 if (Res == NULL)
348 KILL(Data);
349 fclose(f);
350 return (NULL);
353 for (y = 0; y < infoheader.biHeight; y++)
355 u32b y2 = infoheader.biHeight - y - 1;
357 for (x = 0; x < infoheader.biWidth; x++)
359 int ch = getc(f);
361 /* Verify not at end of file XXX XXX */
362 if (feof(f)) quit_fmt("Unexpected end of file in %s", Name);
364 if (infoheader.biBitCount == 24)
366 int c3, c2 = getc(f);
368 /* Verify not at end of file XXX XXX */
369 if (feof(f)) quit_fmt("Unexpected end of file in %s", Name);
371 c3 = getc(f);
373 /* Verify not at end of file XXX XXX */
374 if (feof(f)) quit_fmt("Unexpected end of file in %s", Name);
376 XPutPixel(Res, x, y2, create_pixel(dpy, ch, c2, c3));
378 else if (infoheader.biBitCount == 8)
380 XPutPixel(Res, x, y2, clr_pixels[ch]);
382 else if (infoheader.biBitCount == 4)
384 XPutPixel(Res, x, y2, clr_pixels[ch / 16]);
385 x++;
386 XPutPixel(Res, x, y2, clr_pixels[ch % 16]);
388 else
390 /* Technically 1 bit is legal too */
391 quit_fmt("Illegal biBitCount %d in %s",
392 infoheader.biBitCount, Name);
397 fclose(f);
399 return Res;
403 /* ========================================================*/
404 /* Code for smooth icon rescaling from Uwe Siems, Jan 2000 */
405 /* ========================================================*/
408 * to save ourselves some labour, define a maximum expected icon width here:
410 #define MAX_ICON_WIDTH 32
413 /* some static variables for composing and decomposing pixel values into
414 * red, green and blue values
416 static unsigned long redMask, greenMask, blueMask;
417 static int redShift, greenShift, blueShift;
421 * Use smooth rescaling?
423 bool smoothRescaling = TRUE;
427 * GetScaledRow reads a scan from the given XImage, scales it smoothly
428 * and returns the red, green and blue values in arrays.
429 * The values in this arrays must be divided by a certain value that is
430 * calculated in ScaleIcon.
431 * x, y is the position, iw is the input width and ow the output width
432 * redScan, greenScan and blueScan must be sufficiently sized
434 static void GetScaledRow(XImage *Im, int x, int y, int iw, int ow,
435 unsigned long *redScan, unsigned long *greenScan,
436 unsigned long *blueScan)
438 int xi, si, sifrac, ci, cifrac, addWhole, addFrac;
439 unsigned long pix;
440 int prevRed, prevGreen, prevBlue, nextRed, nextGreen, nextBlue;
441 bool getNextPix;
443 if (iw == ow)
445 /* unscaled */
446 for (xi = 0; xi < ow; xi++)
448 pix = XGetPixel(Im, x + xi, y);
449 redScan [xi] = (pix >> redShift) & redMask;
450 greenScan [xi] = (pix >> greenShift) & greenMask;
451 blueScan [xi] = (pix >> blueShift) & blueMask;
454 else if (iw < ow)
456 /* scaling by subsampling (grow) */
457 iw--;
458 ow--;
459 /* read first pixel: */
460 pix = XGetPixel(Im, x, y);
461 nextRed = (pix >> redShift) & redMask;
462 nextGreen = (pix >> greenShift) & greenMask;
463 nextBlue = (pix >> blueShift) & blueMask;
464 prevRed = nextRed;
465 prevGreen = nextGreen;
466 prevBlue = nextBlue;
467 /* si and sifrac give the subsampling position: */
468 si = x;
469 sifrac = 0;
470 /* getNextPix tells us, that we need the next pixel */
471 getNextPix = TRUE;
473 for (xi = 0; xi <= ow; xi++)
475 if (getNextPix)
477 prevRed = nextRed;
478 prevGreen = nextGreen;
479 prevBlue = nextBlue;
480 if (xi < ow)
482 /* only get next pixel if in same icon */
483 pix = XGetPixel(Im, si + 1, y);
484 nextRed = (pix >> redShift) & redMask;
485 nextGreen = (pix >> greenShift) & greenMask;
486 nextBlue = (pix >> blueShift) & blueMask;
490 /* calculate subsampled color values: */
491 /* division by ow occurs in ScaleIcon */
492 redScan [xi] = prevRed * (ow - sifrac) + nextRed * sifrac;
493 greenScan [xi] = prevGreen * (ow - sifrac) + nextGreen * sifrac;
494 blueScan [xi] = prevBlue * (ow - sifrac) + nextBlue * sifrac;
496 /* advance sampling position: */
497 sifrac += iw;
498 if (sifrac >= ow)
500 si++;
501 sifrac -= ow;
502 getNextPix = TRUE;
504 else
506 getNextPix = FALSE;
511 else
513 /* scaling by averaging (shrink) */
514 /* width of an output pixel in input pixels: */
515 addWhole = iw / ow;
516 addFrac = iw % ow;
517 /* start position of the first output pixel: */
518 si = x;
519 sifrac = 0;
520 /* get first input pixel: */
521 pix = XGetPixel(Im, x, y);
522 nextRed = (pix >> redShift) & redMask;
523 nextGreen = (pix >> greenShift) & greenMask;
524 nextBlue = (pix >> blueShift) & blueMask;
525 for (xi = 0; xi < ow; xi++)
527 /* find endpoint of the current output pixel: */
528 ci = si + addWhole;
529 cifrac = sifrac + addFrac;
530 if (cifrac >= ow)
532 ci++;
533 cifrac -= ow;
535 /* take fraction of current input pixel (starting segment): */
536 redScan[xi] = nextRed * (ow - sifrac);
537 greenScan[xi] = nextGreen * (ow - sifrac);
538 blueScan[xi] = nextBlue * (ow - sifrac);
539 si++;
540 /* add values for whole pixels: */
541 while (si < ci)
543 pix = XGetPixel(Im, si, y);
544 redScan[xi] += ((pix >> redShift) & redMask) *ow;
545 greenScan[xi] += ((pix >> greenShift) & greenMask) *ow;
546 blueScan[xi] += ((pix >> blueShift) & blueMask) *ow;
547 si++;
549 /* add fraction of current input pixel (ending segment): */
550 if (xi < ow - 1)
552 /* only get next pixel if still in icon: */
553 pix = XGetPixel(Im, si, y);
554 nextRed = (pix >> redShift) & redMask;
555 nextGreen = (pix >> greenShift) & greenMask;
556 nextBlue = (pix >> blueShift) & blueMask;
558 sifrac = cifrac;
559 if (sifrac > 0)
561 redScan[xi] += nextRed * sifrac;
562 greenScan[xi] += nextGreen * sifrac;
563 blueScan[xi] += nextBlue * sifrac;
571 * PutRGBScan takes arrays for red, green and blue and writes pixel values
572 * according to this values in the XImage-structure. w is the number of
573 * pixels to write and div is the value by which all red/green/blue values
574 * are divided first.
576 static void PutRGBScan(XImage *Im, int x, int y, int w, int div,
577 unsigned long *redScan, unsigned long *greenScan,
578 unsigned long *blueScan)
580 int xi;
581 unsigned long pix;
582 unsigned long adj = div / 2;
583 for (xi = 0; xi < w; xi++)
585 pix = (((((redScan[xi] + adj) / div) & redMask) << redShift) +
586 ((((greenScan[xi] + adj) / div) & greenMask) << greenShift) +
587 ((((blueScan[xi] + adj) / div) & blueMask) << blueShift));
588 XPutPixel(Im, x + xi, y, pix);
594 * ScaleIcon transfers an area from XImage ImIn, locate (x1,y1) to ImOut,
595 * locate (x2, y2).
596 * Source size is (ix, iy) and destination size is (ox, oy).
597 * It does this by getting icon scan line from GetScaledScan and handling
598 * them the same way as pixels are handled in GetScaledScan.
599 * This even allows icons to be scaled differently in horizontal and
600 * vertical directions (eg. shrink horizontal, grow vertical).
602 static void ScaleIcon(XImage *ImIn, XImage *ImOut,
603 int x1, int y1, int x2, int y2,
604 int ix, int iy, int ox, int oy)
606 int div;
607 int xi, yi, si, sifrac, ci, cifrac, addWhole, addFrac;
609 /* buffers for pixel rows: */
610 unsigned long prevRed [MAX_ICON_WIDTH];
611 unsigned long prevGreen [MAX_ICON_WIDTH];
612 unsigned long prevBlue [MAX_ICON_WIDTH];
613 unsigned long nextRed [MAX_ICON_WIDTH];
614 unsigned long nextGreen [MAX_ICON_WIDTH];
615 unsigned long nextBlue [MAX_ICON_WIDTH];
616 unsigned long tempRed [MAX_ICON_WIDTH];
617 unsigned long tempGreen [MAX_ICON_WIDTH];
618 unsigned long tempBlue [MAX_ICON_WIDTH];
620 bool getNextRow;
622 /* get divider value for the horizontal scaling: */
623 if (ix == ox)
624 div = 1;
625 else if (ix < ox)
626 div = ox - 1;
627 else
628 div = ix;
630 if (iy == oy)
632 /* no scaling needed vertically: */
633 for (yi = 0; yi < oy; yi++)
635 GetScaledRow(ImIn, x1, y1 + yi, ix, ox,
636 tempRed, tempGreen, tempBlue);
637 PutRGBScan(ImOut, x2, y2 + yi, ox, div,
638 tempRed, tempGreen, tempBlue);
641 else if (iy < oy)
643 /* scaling by subsampling (grow): */
644 iy--;
645 oy--;
646 div *= oy;
648 /* get first row: */
649 GetScaledRow(ImIn, x1, y1, ix, ox, nextRed, nextGreen, nextBlue);
651 /* si and sifrac give the subsampling position: */
652 si = y1;
653 sifrac = 0;
655 /* getNextRow tells us, that we need the next row */
656 getNextRow = TRUE;
658 for (yi = 0; yi <= oy; yi++)
660 if (getNextRow)
662 for (xi = 0; xi < ox; xi++)
664 prevRed[xi] = nextRed[xi];
665 prevGreen[xi] = nextGreen[xi];
666 prevBlue[xi] = nextBlue[xi];
669 if (yi < oy)
671 /* only get next row if in same icon */
672 GetScaledRow(ImIn, x1, si + 1, ix, ox,
673 nextRed, nextGreen, nextBlue);
677 /* calculate subsampled color values: */
678 /* division by oy occurs in PutRGBScan */
679 for (xi = 0; xi < ox; xi++)
681 tempRed[xi] = (prevRed[xi] * (oy - sifrac) +
682 nextRed[xi] * sifrac);
683 tempGreen[xi] = (prevGreen[xi] * (oy - sifrac) +
684 nextGreen[xi] * sifrac);
685 tempBlue[xi] = (prevBlue[xi] * (oy - sifrac) +
686 nextBlue[xi] * sifrac);
689 /* write row to output image: */
690 PutRGBScan(ImOut, x2, y2 + yi, ox, div,
691 tempRed, tempGreen, tempBlue);
693 /* advance sampling position: */
694 sifrac += iy;
695 if (sifrac >= oy)
697 si++;
698 sifrac -= oy;
699 getNextRow = TRUE;
701 else
703 getNextRow = FALSE;
707 else
709 /* scaling by averaging (shrink) */
710 div *= iy;
712 /* height of a output row in input rows: */
713 addWhole = iy / oy;
714 addFrac = iy % oy;
716 /* start position of the first output row: */
717 si = y1;
718 sifrac = 0;
720 /* get first input row: */
721 GetScaledRow(ImIn, x1, y1, ix, ox, nextRed, nextGreen, nextBlue);
723 for (yi = 0; yi < oy; yi++)
725 /* find endpoint of the current output row: */
726 ci = si + addWhole;
727 cifrac = sifrac + addFrac;
729 if (cifrac >= oy)
731 ci++;
732 cifrac -= oy;
735 /* take fraction of current input row (starting segment): */
736 for (xi = 0; xi < ox; xi++)
738 tempRed[xi] = nextRed[xi] * (oy - sifrac);
739 tempGreen[xi] = nextGreen[xi] * (oy - sifrac);
740 tempBlue[xi] = nextBlue[xi] * (oy - sifrac);
743 si++;
745 /* add values for whole pixels: */
746 while (si < ci)
748 GetScaledRow(ImIn, x1, si, ix, ox,
749 nextRed, nextGreen, nextBlue);
751 for (xi = 0; xi < ox; xi++)
753 tempRed[xi] += nextRed[xi] * oy;
754 tempGreen[xi] += nextGreen[xi] * oy;
755 tempBlue[xi] += nextBlue[xi] * oy;
757 si++;
760 /* add fraction of current input row (ending segment): */
761 if (yi < oy - 1)
763 /* only get next row if still in icon: */
764 GetScaledRow(ImIn, x1, si, ix, ox,
765 nextRed, nextGreen, nextBlue);
768 sifrac = cifrac;
770 for (xi = 0; xi < ox; xi++)
772 tempRed[xi] += nextRed[xi] * sifrac;
773 tempGreen[xi] += nextGreen[xi] * sifrac;
774 tempBlue[xi] += nextBlue[xi] * sifrac;
777 /* write row to output image: */
778 PutRGBScan(ImOut, x2, y2 + yi, ox, div,
779 tempRed, tempGreen, tempBlue);
786 static XImage *ResizeImageSmooth(Display *dpy, XImage *Im,
787 int ix, int iy, int ox, int oy)
789 Visual *visual = DefaultVisual(dpy, DefaultScreen(dpy));
791 int width1, height1, width2, height2;
792 int x1, x2, y1, y2;
794 XImage *Tmp;
796 char *Data;
798 width1 = Im->width;
799 height1 = Im->height;
801 width2 = ox * width1 / ix;
802 height2 = oy * height1 / iy;
804 Data = (char *)malloc(width2 * height2 * Im->bits_per_pixel / 8);
806 Tmp = XCreateImage(dpy, visual,
807 Im->depth, ZPixmap, 0, Data, width2, height2,
808 32, 0);
810 /* compute values for decomposing pixel into color values: */
811 redMask = Im->red_mask;
812 redShift = 0;
814 while ((redMask & 1) == 0)
816 redShift++;
817 redMask >>= 1;
820 greenMask = Im->green_mask;
821 greenShift = 0;
823 while ((greenMask & 1) == 0)
825 greenShift++;
826 greenMask >>= 1;
829 blueMask = Im->blue_mask;
830 blueShift = 0;
832 while ((blueMask & 1) == 0)
834 blueShift++;
835 blueMask >>= 1;
838 /* scale each icon: */
839 for (y1 = 0, y2 = 0; (y1 < height1) && (y2 < height2); y1 += iy, y2 += oy)
841 for (x1 = 0, x2 = 0; (x1 < width1) && (x2 < width2); x1 += ix, x2 += ox)
843 ScaleIcon(Im, Tmp, x1, y1, x2, y2,
844 ix, iy, ox, oy);
848 return Tmp;
853 * Resize an image.
855 XImage *ResizeImage(Display *dpy, XImage *Im,
856 int ix, int iy, int ox, int oy)
858 Visual *visual = DefaultVisual(dpy, DefaultScreen(dpy));
860 int width1, height1, width2, height2;
861 int x1, x2, y1, y2, Tx, Ty;
862 int *px1, *px2, *dx1, *dx2;
863 int *py1, *py2, *dy1, *dy2;
865 XImage *Tmp;
867 char *Data;
869 if (smoothRescaling && (ix != ox || iy != oy) &&
870 (visual->class == TrueColor))
872 return ResizeImageSmooth(dpy, Im, ix, iy, ox, oy);
875 width1 = Im->width;
876 height1 = Im->height;
878 width2 = ox * width1 / ix;
879 height2 = oy * height1 / iy;
881 Data = (char *)malloc(width2 * height2 * Im->bits_per_pixel / 8);
883 Tmp = XCreateImage(dpy, visual,
884 Im->depth, ZPixmap, 0, Data, width2, height2,
885 32, 0);
887 if (ix > ox)
889 px1 = &x1;
890 px2 = &x2;
891 dx1 = &ix;
892 dx2 = &ox;
894 else
896 px1 = &x2;
897 px2 = &x1;
898 dx1 = &ox;
899 dx2 = &ix;
902 if (iy > oy)
904 py1 = &y1;
905 py2 = &y2;
906 dy1 = &iy;
907 dy2 = &oy;
909 else
911 py1 = &y2;
912 py2 = &y1;
913 dy1 = &oy;
914 dy2 = &iy;
917 Ty = *dy1/2;
919 for (y1 = 0, y2 = 0; (y1 < height1) && (y2 < height2); )
921 Tx = *dx1/2;
923 for (x1 = 0, x2 = 0; (x1 < width1) && (x2 < width2); )
925 XPutPixel(Tmp, x2, y2, XGetPixel(Im, x1, y1));
927 (*px1)++;
929 Tx -= *dx2;
930 if (Tx < 0)
932 Tx += *dx1;
933 (*px2)++;
937 (*py1)++;
939 Ty -= *dy2;
940 if (Ty < 0)
942 Ty += *dy1;
943 (*py2)++;
947 return Tmp;
950 #endif /* USE_GRAPHICS */
952 #endif /* USE_X11 || USE_XAW || USE_XPJ || USE_GTK */