1 /* $XConsortium: ilX.c /main/11 1996/11/12 05:02:17 pascale $ */
2 /**---------------------------------------------------------------------
4 *** (c)Copyright 1991 Hewlett-Packard Co.
6 *** RESTRICTED RIGHTS LEGEND
7 *** Use, duplication, or disclosure by the U.S. Government is subject to
8 *** restrictions as set forth in sub-paragraph (c)(1)(ii) of the Rights in
9 *** Technical Data and Computer Software clause in DFARS 252.227-7013.
10 *** Hewlett-Packard Company
11 *** 3000 Hanover Street
12 *** Palo Alto, CA 94304 U.S.A.
13 *** Rights for non-DOD U.S. Government Departments and Agencies are as set
14 *** forth in FAR 52.227-19(c)(1,2).
16 ***-------------------------------------------------------------------*/
19 #include "ilcontext.h"
22 #include <X11/Xutil.h>
23 #include "ilpipelem.h"
27 #define X_COLOR_MAX 65535 /* max value for X colormap RGB
30 /* Buffer allocation checks. Buffers are allocated for example when
31 writing to a 24 bit drawable: the pipe image pixels are converted
32 from 3 bytes to 4 bytes (CARD32).
34 #define MAX_IMAGE_BUFFER_SIZE 100000 /* force strips if larger than
36 #define BEST_IMAGE_BUFFER_SIZE 50000 /* to strips of this size */
38 /* Masks for ilFreeColorData(); see below.
40 #define IL_FREE_XCOLORS (1<<0)
41 #define IL_FREE_XGRAYS (1<<1)
43 /* Codes for view of X , in "ilXWCRec.i.visualType". When the visual is
44 unsupported or an insufficient # of colors can be allocated from the
45 colormap, the drawable defaults to IL_XWC_BITONAL. Images rendered
46 to such an XWC are converted to bitonal, then XPutImage() of an
47 XYBitmap is done - the XWC GC's foreground/background colors are used
50 #define IL_X_MAX_VISUAL_TYPE 3 /* max value of IL_XWC_BITONAL
53 /* Default # of grays or dither colors to allocate for pseudo-color. */
54 #define IL_DEFAULT_X_GRAYS 32
59 /* Internals of an XWC (X Write Context), an IL object created by
61 An XWC is associated with the visual "visual" and "colormap".
62 "i" contains basic information returned by ilQueryXWC().
63 If pColors is non-null, it points to a list of length "nColors",
64 of colors allocated from "colormap". "pad" in each colorcell is
66 == 0 if color not allocated, else color was sucessfully allocated.
67 If non-null, colorMapImage is an image for mapping to X images
69 For example, for 8 bit pseudo-color when 484 color handling is used,
70 "pColors" points to 128 colors, and "colorMapImage" points to a 256
71 pixel image where each entry is the pixel to use for color
72 (red*4*8 + green*8 + blue).
73 If "colorMapImage" is null then the alloc failed or has not been tried.
74 Note: above applies also to Direct/TrueColor visuals, with the same
76 The above also applies to the "gray" fields, with the "gray" names.
79 ilObjectRec o; /* std header: MUST BE FIRST */
80 ilXWCInfo i; /* see above */
81 XVisualInfo visualInfo; /* X info on "visual" */
82 XColor *pColors; /* ptr to list of allocated
84 int nColors; /* size of *pColors list */
85 ilClientImage colorMapImage; /* see above */
86 ilBool mapDirect; /* ilMap(colorMapImage),
88 XColor *pGrays; /* ptr to list of allocated grays
90 int nGrays; /* size of *pGrays list */
91 ilClientImage grayMapImage; /* same as colorMapImage, but for
93 } ilXWCRec, *ilXWCPtr;
95 typedef ilError (*executeFunctionType)();
97 /* ------------------------ ilFreeColorData ---------------------- */
98 /* Free the color list and translation table in the given XWC if
99 present. "freeMasks" indicates which should be freed:
100 IL_FREE_XCOLORS/XGRAYS, or ~0 for everything.
102 static void ilFreeColorData (
103 register ilXWCPtr pXWC,
104 unsigned long freeMask
110 /* If color list present: free each color if allocated (pad != 0);
113 if (freeMask & IL_FREE_XCOLORS) {
115 for (i = 0, pColor = pXWC->pColors; i < pXWC->nColors; i++) {
117 XFreeColors (pXWC->i.display, pXWC->i.colormap,
118 &pColor->pixel, 1, 0L);
121 IL_FREE (pXWC->pColors);
122 pXWC->pColors = (XColor *)NULL;
125 if (pXWC->colorMapImage) {
126 ilDestroyObject (pXWC->colorMapImage);
127 pXWC->colorMapImage = (ilClientImage)NULL;
131 /* Same for gray list
133 if (freeMask & IL_FREE_XGRAYS) {
135 for (i = 0, pColor = pXWC->pGrays; i < pXWC->nGrays; i++) {
137 XFreeColors (pXWC->i.display, pXWC->i.colormap,
138 &pColor->pixel, 1, 0L);
141 IL_FREE (pXWC->pGrays);
142 pXWC->pGrays = (XColor *)NULL;
145 if (pXWC->grayMapImage) {
146 ilDestroyObject (pXWC->grayMapImage);
147 pXWC->grayMapImage = (ilClientImage)NULL;
152 /* ----------------------- ilDestroyXWC -------------------------- */
153 /* Destroy() function for XWC objects. Free the color list if
155 The GC for the default XWC will be destroyed when the context is
156 freed, by ilXDestroyContext() below.
158 static void ilDestroyXWC (
162 ilObject object = (ilObject)pPrivate;
163 register ilXWCPtr pXWC;
165 pXWC = (ilXWCPtr)object;
167 /* ~ on signed integer is not recommended, play it safe here */
168 ilFreeColorData (pXWC, ~(0UL));
172 /* --------------------- ilGammaCorrect -------------------------- */
173 /* Returns a value from 0..scaleValue, given "value", from
174 0.."maxValue" - 1, scaled up to "scaleValue" (e.g. 65535 for
176 Currently a misnomer - not doing any gamma correction
179 static int ilGammaCorrect (
185 register int allocValue;
189 else if (value == (maxValue - 1))
190 allocValue = scaleValue;
192 allocValue = value * scaleValue / (maxValue-1);
195 else if (allocValue > scaleValue)
196 allocValue = scaleValue;
202 /* --------------------- ilAllocateXDitherColors ------------------ */
203 /* Internal function to ilCreateXWC(). Attempts to allocate enough
204 colors in pXWC->i.colormap to support the visual as a 484
206 An error code is returned to the given context if an error
207 (e.g. malloc) error occurs; IL_OK if the grays could not be
208 alloc'd (but false is returned).
210 static ilBool ilAllocateXDitherColors (
212 register ilXWCPtr pXWC
216 int i, red, green, blue;
219 ilImageInfo imageInfo, *pImageInfo;
221 context->error = IL_OK; /* assume no errors */
222 if (pXWC->colorMapImage)
223 return TRUE; /* already alloc'd; EXIT */
225 /* Allocate a client image to use as LUT for mapping to X's
227 Point pTranslate to the allocated pixels.
229 imageInfo.pDes = IL_DES_GRAY;
230 imageInfo.pFormat = IL_FORMAT_BYTE;
231 imageInfo.width = 256;
232 imageInfo.height = 1;
233 imageInfo.clientPixels = FALSE;
234 pXWC->colorMapImage = ilCreateClientImage (context, &imageInfo, 0);
235 if (!pXWC->colorMapImage)
236 return FALSE; /* EXIT */
237 ilQueryClientImage (pXWC->colorMapImage, &pImageInfo, 0);
238 pTranslate = pImageInfo->plane[0].pPixels;
240 pXWC->nColors = NRED * NGREEN * NBLUE;
241 pXWC->pColors = (XColor *)IL_MALLOC (pXWC->nColors * sizeof(XColor));
242 if (!pXWC->pColors) {
243 ilDestroyObject (pXWC->colorMapImage);
244 pXWC->colorMapImage = (ilClientImage)NULL;
245 context->error = IL_ERROR_MALLOC;
246 return FALSE; /* EXIT */
248 for (i = 0, pColor = pXWC->pColors; i < pXWC->nColors; i++, pColor++)
249 pColor->pad = FALSE; /* init pad, in case below fails */
251 /* Allocate 484 colors (128 in all) */
252 pColor = pXWC->pColors;
253 for (red = 0; red < NRED; red++)
254 for (green = 0; green < NGREEN; green++)
255 for (blue = 0; blue < NBLUE; blue++) {
256 pColor->red = ilGammaCorrect (X_COLOR_MAX, red, NRED);
257 pColor->green = ilGammaCorrect (X_COLOR_MAX, green, NGREEN);
258 pColor->blue = ilGammaCorrect (X_COLOR_MAX, blue, NBLUE);
259 if (!XAllocColor (pXWC->i.display, pXWC->i.colormap, pColor)) {
260 ilFreeColorData (pXWC, IL_FREE_XCOLORS);
263 pTranslate [red*(NGREEN*NBLUE) + green*NBLUE + blue] =
265 pColor->pad = TRUE; /* mark as alloc'd */
269 return TRUE; /* colors successfully alloc'd */
273 /* ---------------------------- ilAllocateXGrays ---------------------- */
274 /* Allocate "nGrays" from the colormap associated with the given XWC or
276 The grays are ramped evenly from 0..nGrays-1. If there are "nGrays"
277 existing grays, they are used, else if not nGrays, they are
279 An error code is returned to the given context if an error
280 (e.g. malloc) error occurs; IL_OK if the grays could not be alloc'd
281 (but false is returned).
283 static ilBool ilAllocateXGrays (
285 register ilXWCPtr pXWC,
292 ilImageInfo imageInfo, *pImageInfo;
295 /* Use the grays if the same number, else deallocate them.
297 context->error = IL_OK; /* assume no errors */
299 if (pXWC->nGrays == nGrays)
301 else ilFreeColorData (pXWC, IL_FREE_XGRAYS);
304 return FALSE; /* EXIT */
306 /* Allocate a client image to use as LUT for mapping to X's colors.
307 Point pTranslate to the allocated pixels.
309 imageInfo.pDes = IL_DES_GRAY;
310 imageInfo.pFormat = IL_FORMAT_BYTE;
311 imageInfo.width = 256;
312 imageInfo.height = 1;
313 imageInfo.clientPixels = FALSE;
314 pXWC->grayMapImage = ilCreateClientImage (context, &imageInfo, 0);
315 if (!pXWC->grayMapImage)
316 return FALSE; /* EXIT */
317 ilQueryClientImage (pXWC->grayMapImage, &pImageInfo, 0);
318 pTranslate = pImageInfo->plane[0].pPixels;
320 pXWC->nGrays = nGrays;
321 pXWC->pGrays = (XColor *)IL_MALLOC (pXWC->nGrays * sizeof(XColor));
323 ilDestroyObject (pXWC->grayMapImage);
324 pXWC->colorMapImage = (ilClientImage)NULL;
325 context->error = IL_ERROR_MALLOC;
326 return FALSE; /* EXIT */
328 for (i = 0, pColor = pXWC->pGrays; i < pXWC->nGrays; i++, pColor++)
329 pColor->pad = FALSE; /* init pad, in case below fails */
331 /* Allocate the grays; return error on any failure. */
332 for (i = 0; i < nGrays; i++) {
333 pColor = &pXWC->pGrays [i];
334 pColor->red = pColor->green = pColor->blue =
335 ilGammaCorrect (X_COLOR_MAX, i, nGrays);
336 if (!XAllocColor (pXWC->i.display, pXWC->i.colormap, pColor)) {
338 ilFreeColorData (pXWC, IL_FREE_XGRAYS);
339 return FALSE; /* EXIT */
344 /* Grays allocated ok; spread the allocated colors over the whole 256
345 area. In effect, color-slam all 256-level gray images into nGrays.
346 NOTE: gray images with other than 256 levels could be supported in
349 spreadFactor = ((double)(nGrays - 1)) / (double)255;
350 pColor = pXWC->pGrays;
351 for (i = 0; i < 256; i++) {
352 index = spreadFactor * (double)i + 0.5;
353 if (index > (nGrays - 1))
355 pTranslate [i] = pColor [index].pixel;
362 /* ---------------------- ilAllocateXDirectColors --------------------- */
363 /* Allocate "nLevels" levels of each of RGB for a DirectColor or a
365 "nLevels" should be passed as 256; it becomes 1/2 of that if failure
366 occurs this function recurses on failure until an unacceptable # of
369 static ilBool ilAllocateXDirectColors (
370 register ilXWCPtr pXWC,
374 int i, j, pixel, red, green, blue, nReplicate;
377 ilImageInfo imageInfo, *pImageInfo;
379 #define MIN_DIRECT_LEVELS 32 /* min # of acceptable levels */
381 if (pXWC->colorMapImage)
382 return TRUE; /* already alloc'd; EXIT */
384 /* Create a 256x1 3 byte/pixel map image. */
385 context = pXWC->o.p.context;
386 imageInfo.pDes = IL_DES_RGB;
387 imageInfo.pFormat = IL_FORMAT_3BYTE_PIXEL;
388 imageInfo.width = 256;
389 imageInfo.height = 1;
390 imageInfo.clientPixels = FALSE;
391 pXWC->colorMapImage = ilCreateClientImage (context, &imageInfo, 0);
392 if (!pXWC->colorMapImage)
394 ilQueryClientImage (pXWC->colorMapImage, &pImageInfo, 0);
395 pTranslate = pImageInfo->plane[0].pPixels;
397 /* Try to allocate nLevels read-only levels each of RGB, in a logical
398 ramp order. Set pXWC->mapDirect to false if pixel value != RGB
399 value, in which case pipe image pixels must be ilMap()'d to X
401 If can't allocate, try to allocate nLevels/2 unless that is too
402 few colors, in which we fail. Spread the X pixels into the 256
405 pXWC->nColors = nLevels;
406 pXWC->pColors = (XColor *)IL_MALLOC_ZERO (pXWC->nColors * sizeof(XColor));
407 if (!pXWC->pColors) {
408 ilDestroyObject (pXWC->colorMapImage);
409 pXWC->colorMapImage = (ilClientImage)NULL;
410 context->error = IL_ERROR_MALLOC;
414 pXWC->mapDirect = FALSE;
415 nReplicate = 256 / nLevels; /* # of times to replicate pixel into map
417 for (i = 0, pColor = pXWC->pColors; i < nLevels; i++, pColor++) {
418 pColor->red = pColor->green = pColor->blue =
419 ilGammaCorrect (X_COLOR_MAX, i, nLevels);
420 pColor->flags = DoRed | DoGreen | DoBlue;
421 if (!XAllocColor (pXWC->i.display, pXWC->i.colormap, pColor)) {
422 ilFreeColorData (pXWC, IL_FREE_XCOLORS);
423 if (nLevels <= MIN_DIRECT_LEVELS)
425 else return ilAllocateXDirectColors (pXWC, nLevels / 2);
427 pColor->pad = TRUE; /* mark as alloc'd */
428 pixel = pColor->pixel;
429 red = (pixel >> 16) & 0xff;
430 green = (pixel >> 8) & 0xff;
432 if ((red != i) || (green != i) || (blue != i))
433 pXWC->mapDirect = TRUE;
434 for (j = 0; j < nReplicate; j++) { /* replicate into map image */
436 *pTranslate++ = green;
437 *pTranslate++ = blue;
445 /* ------------------------ ilChangeXWC --------------------------- */
446 /* Public function; see spec.
454 register ilXWCPtr pXWC;
455 register ilContext context;
457 pXWC = (ilXWCPtr)XWC;
458 context = pXWC->o.p.context;
459 context->error = IL_OK; /* assume no error */
460 if (pXWC->o.p.objectType != IL_XWC) {
461 context->error = IL_ERROR_OBJECT_TYPE;
462 return FALSE; /* EXIT */
467 /* Allocate grays: allocate grays if gray or pseudo-color, else
468 return true if gray display supported (e.g. to True/DirectColor).
470 case IL_XWC_ALLOC_GRAYS:
472 context->error = IL_ERROR_OPTION_DATA;
475 switch (pXWC->i.visualType) {
480 if (ilAllocateXGrays (context, pXWC, IL_DEFAULT_X_GRAYS))
483 case IL_XWC_COLOR_24:
487 /* Allocate colors: 8 and 24 bit color only */
488 case IL_XWC_ALLOC_COLORS:
490 context->error = IL_ERROR_OPTION_DATA;
493 if ((pXWC->i.visualType == IL_XWC_COLOR_8)
494 && ilAllocateXDitherColors (context, pXWC))
496 else if ((pXWC->i.visualType == IL_XWC_COLOR_24)
497 && ilAllocateXDirectColors (pXWC, 256))
501 case IL_XWC_FREE_GRAYS:
503 context->error = IL_ERROR_OPTION_DATA;
506 ilFreeColorData (pXWC, IL_FREE_XGRAYS);
509 /* Free colors if 8 or 24 bit color */
510 case IL_XWC_FREE_COLORS:
512 context->error = IL_ERROR_OPTION_DATA;
515 if ((pXWC->i.visualType == IL_XWC_COLOR_8)
516 || (pXWC->i.visualType == IL_XWC_COLOR_24))
517 ilFreeColorData (pXWC, IL_FREE_XCOLORS);
520 case IL_XWC_SET_DITHER_METHOD:
521 { unsigned int ditherMethod;
522 ditherMethod = *((unsigned int *)pData);
523 if ((ditherMethod != IL_AREA_DITHER)
524 && (ditherMethod != IL_DIFFUSION)
525 && (ditherMethod != IL_QUICK_DIFFUSION)) {
526 context->error = IL_ERROR_OPTION_DATA;
529 pXWC->i.ditherMethod = ditherMethod;
533 case IL_XWC_SET_RAW_MODE:
534 pXWC->i.rawMode = *((ilBool *)pData);
538 context->error = IL_ERROR_INVALID_OPTION;
540 } /* END switch code */
546 /* ------------------------ ilQueryXWC --------------------------- */
547 /* Public function; see spec.
554 register ilXWCPtr pXWC;
556 pXWC = (ilXWCPtr)XWC;
557 if (pXWC->o.p.objectType != IL_XWC) {
558 pXWC->o.p.context->error = IL_ERROR_OBJECT_TYPE;
559 return FALSE; /* EXIT */
563 pXWC->o.p.context->error = IL_OK;
568 /* ------------------------ ilCreateXWC ------------------------- */
569 /* Public function; see spec.
570 Return an error if no (null) display in this context.
579 unsigned long mustBeZero1,
580 unsigned long mustBeZero2
583 register ilXWCPtr pXWC;
584 XVisualInfo template, *pVisualInfo;
587 if ((mustBeZero1 != 0) || (mustBeZero2 != 0)) {
588 context->error = IL_ERROR_PAR_NOT_ZERO;
589 return (ilXWC)NULL; /* EXIT */
592 /* A null visual or colormap means output will be to bitmap, else
593 get the info for the given visual; exit if not found.
595 if (!visual || !colormap) {
596 visual = (Visual *)NULL;
597 colormap = (Colormap)0;
600 template.visualid = XVisualIDFromVisual (visual);
601 pVisualInfo = XGetVisualInfo (display, VisualIDMask, &template,
604 context->error = IL_ERROR_X_RESOURCE;
605 return (ilXWC)NULL; /* EXIT */
609 /* Create an XWC object and fill it in.
611 pXWC = (ilXWCPtr)_ilCreateObject (context, IL_XWC, ilDestroyXWC,
614 return (ilXWC)NULL; /* EXIT */
616 pXWC->i.display = display;
617 pXWC->i.visual = visual;
619 pXWC->visualInfo = *pVisualInfo;
620 free (pVisualInfo); /* free list from XGetVisualInfo() */
623 pXWC->i.colormap = colormap;
624 pXWC->pColors = (XColor *)NULL;
626 pXWC->colorMapImage = (ilClientImage)NULL;
627 pXWC->pGrays = (XColor *)NULL;
629 pXWC->grayMapImage = (ilClientImage)NULL;
630 pXWC->i.ditherMethod = IL_AREA_DITHER;
631 pXWC->i.rawMode = FALSE;
633 /* Check the class of the given visual and fill in XWC des and format.
634 If visual class not supported default to bitonal.
635 May also default to bitonal (or color demote to gray) later if
636 insufficient colors or grays can be allocated.
637 If null visual, do bitonal output.
639 pXWC->i.staticVisual = TRUE; /* assume non-writeable colormap */
641 pXWC->i.visualType = IL_XWC_BITONAL;
642 else switch (pXWC->visualInfo.class) {
644 pXWC->i.staticVisual = FALSE;
646 if (pXWC->visualInfo.depth == 8)
647 pXWC->i.visualType = IL_XWC_COLOR_8;
648 else pXWC->i.visualType = IL_XWC_BITONAL;
651 /* Support True/DirectColor if 32 bits format
652 = "<unused 8><8R><8G><8B>". */
654 pXWC->i.staticVisual = FALSE;
656 if ((pXWC->visualInfo.depth == 24)
657 && (pXWC->visualInfo.red_mask == 0xff0000)
658 && (pXWC->visualInfo.green_mask == 0xff00)
659 && (pXWC->visualInfo.blue_mask == 0xff))
660 pXWC->i.visualType = IL_XWC_COLOR_24;
661 else pXWC->i.visualType = IL_XWC_BITONAL;
665 pXWC->i.staticVisual = FALSE;
667 if (pXWC->visualInfo.depth == 8)
668 pXWC->i.visualType = IL_XWC_GRAY_8;
669 else pXWC->i.visualType = IL_XWC_BITONAL;
671 } /* END switch visual class */
673 /* If a bitonal visual, mark as static (non-allocatable colors) */
674 if (pXWC->i.visualType == IL_XWC_BITONAL)
675 pXWC->i.staticVisual = TRUE;
677 context->error = IL_OK;
683 /* ======================== WRITE X DRAWABLE CODE ======================== */
685 /* Private block for ilRead/WriteXDrawable pipe element. Notes:
686 Inited by ilWriteXDrawable():
687 imageDepth depth of image to create - set into pPriv when added
688 imageFormat X format of image: XYBitmap (bitonal) or ZPixmap
689 isLongImage if true: image is 32bits/pixel: set image rowBytes
691 If false: set image rowBytes to row bytes of
693 bufferSize size of buffer to create and attach to Ximage.
694 pXWC ptr to XWC for this operation
695 drawable id of X drawable (Window or Pixmap) to read or write
696 x, y read: src (x,y).
697 write: dst (x,y) from caller
699 Inited by ilWriteXInit():
700 Ximage a temp XImage created by Init. Its data ptr is
701 pointed directly at the read/write buffer, or
703 pBuffer ptr to buffer allocated, if bufferSize > 0
704 linesDone zeroed by Init(): # of lines written / read so far,
705 i.e. y + linesDone is next line to read / write.
711 unsigned long bufferSize;
718 } ilXPrivRec, *ilXPrivPtr;
721 /* ----------------------- ilXDestroy ----------------------------- */
722 /* Destroy() function for ilWriteXDrawable() pipe element.
723 "Destroys" the associated XWC, whose refCount must have been
724 incremented when the element was successfully added to the pipe -
725 Destroy downcounts it.
727 static ilError ilXDestroy (
731 ilXPrivPtr pPriv = (ilXPrivPtr)pPrivate;
732 ilDestroyObject ((ilObject)pPriv->pXWC);
738 /* ------------------------- ilWriteXInit ------------------------- */
739 /* Init() function for ilWriteXDrawable() for all src image types.
740 Creates an XImage, which is just a data structure - creates no
742 The XImage is freed by ilWriteXCleanup().
744 static ilError ilWriteXInit (
746 ilImageInfo *pSrcImage,
747 ilImageInfo *pDstImage /* ignored */
750 register ilXPrivPtr pPriv = (ilXPrivPtr)pPrivate;
751 register ilXWCPtr pXWC;
752 register XImage *pXImage;
754 /* Create a temp buffer for image pixels if requested. */
755 if (pPriv->bufferSize > 0) {
756 pPriv->pBuffer = (ilPtr)IL_MALLOC (pPriv->bufferSize);
758 return IL_ERROR_MALLOC; /* EXIT */
760 else pPriv->pBuffer = NULL;
762 /* Create an XImage that will be pointed to each buffer (strip) to
765 pXImage = XCreateImage (pXWC->i.display, pXWC->i.visual,
766 pPriv->imageDepth, pPriv->imageFormat, 0,
767 (char *)pPriv->pBuffer, pSrcImage->width,
768 pSrcImage->height, pSrcImage->pFormat->rowBitAlign,
769 (pPriv->isLongImage) ? (pSrcImage->width * 4) :
770 pSrcImage->plane[0].nBytesPerRow);
772 return IL_ERROR_MALLOC; /* EXIT */
774 /* Set bit/byte order to MSBFirst.
775 NOTE: byte order should be set to byte order of client machine!!!
779 pXImage->byte_order = LSBFirst;
781 pXImage->byte_order = MSBFirst;
783 pXImage->bitmap_bit_order = MSBFirst;
784 pPriv->pXImage = pXImage;
785 pPriv->linesDone = 0;
790 /* --------------------- ilWriteXCleanup -------------------------- */
791 /* Cleanup() function for ilWriteXDrawable() for all src image types.
792 Flushes the output if not aborted; frees the XImage created by
795 static ilError ilWriteXCleanup (
800 /* Flush if not aborting. Null the "data" field in image or else
801 XDestroyImage() will try to free the pixels; destroy the image,
804 register ilXPrivPtr pPriv = (ilXPrivPtr)pPrivate;
806 XFlush (pPriv->pXWC->i.display);
808 IL_FREE (pPriv->pBuffer);
809 pPriv->pXImage->data = (char *)NULL;
810 XDestroyImage (pPriv->pXImage);
814 /* --------------------- ilWriteXExecute ------------------------- */
815 /* Execute() function for ilWriteXDrawable(), for rendering bit or
817 Points an XImage created by ilWriteXInit() to the src image bits
818 and does an XPutImage(), then bumps a line count so next strip is
819 written *pNLines below this one in the drawable.
821 static ilError ilWriteXExecute (
822 register ilExecuteData *pData,
828 register ilXPrivPtr pPriv;
829 register XImage *pXImage;
831 unsigned int nSrcLines;
832 unsigned int scaledWidth,scaledHeight;
833 int scaledX, scaledY;
835 pPriv = (ilXPrivPtr)pData->pPrivate;
836 nSrcLines = *pNLines;
837 pXImage = pPriv->pXImage;
838 pXImage->height = nSrcLines;
839 pXImage->data = (char *)(pData->pSrcImage->plane[0].pPixels +
840 pData->srcLine * pData->pSrcImage->plane[0].nBytesPerRow);
844 scaledWidth = pXImage->width * ratio + 0.5;
845 scaledX = pPriv->x * ratio + 0.5;
846 scaledY = (pPriv->y + pPriv->linesDone) * ratio + 0.5;
847 /* we have to think about rounding problem, so recalculate every time. */
848 scaledHeight = ((nSrcLines + pPriv->linesDone) * ratio + 0.5)
851 _XmPutScaledImage (pXWC->i.display, pPriv->drawable,
853 0, 0, scaledX, scaledY,
854 pXImage->width, nSrcLines,
855 scaledWidth,scaledHeight);
857 pPriv->linesDone += nSrcLines;
862 /* ------------------- ilWriteXOptLongExecute --------------------- */
863 /* Execute() function for ilWriteXDrawable(), for display to optimal
864 4 bytes pixel frame buffers. "Optimal" means the 4 bytes (CARD32)
865 = "<unused 8> <8 R> <8 G> <8 B>",
866 which is the format most commonly used right now.
867 Reformat the pipe image pixels, which are 3byte pixel RGB (as
868 required by pXWC->format), into 4 bytes words and do the
869 XPutImage(), then bump linesDone.
871 static ilError ilWriteXOptLongExecute (
872 register ilExecuteData *pData,
879 ilImageInfo *pSrcImage;
883 long srcRowBytes, width, nSrcLines, nLinesM1;
884 register long nLongsM1;
886 register CARD32 *pDst, temp;
887 unsigned int scaledWidth,scaledHeight;
888 int scaledX, scaledY ;
890 nSrcLines = *pNLines;
892 return; /* no lines, EXIT */
893 pPriv = (ilXPrivPtr)pData->pPrivate;
894 pSrcImage = pData->pSrcImage;
895 width = pSrcImage->width;
897 return; /* no width, EXIT */
898 srcRowBytes = pSrcImage->plane[0].nBytesPerRow;
899 pSrcLine = (ilPtr)(pSrcImage->plane[0].pPixels +
900 pData->srcLine * srcRowBytes);
901 pXImage = pPriv->pXImage;
902 pXImage->height = nSrcLines;
903 pXImage->data = (char *)pPriv->pBuffer;
904 pDst = (CARD32 *)pPriv->pBuffer;
906 /* pSrcLine points to first line of pipe image; pDst to buffer of
908 Convert 3 byte pipe image to CARD32 X buffer image. Dont need
909 dstRowBytes because buffer is exactly "width" longs wide (we
912 nLinesM1 = nSrcLines - 1;
915 pSrcLine += srcRowBytes;
916 nLongsM1 = width - 1;
924 } while (--nLongsM1 >= 0);
925 } while (--nLinesM1 >= 0);
929 scaledWidth = pXImage->width * ratio;
930 scaledHeight = nSrcLines * ratio;
931 scaledX = pPriv->x * ratio ;
932 scaledY = (pPriv->y + pPriv->linesDone)* ratio ;
934 _XmPutScaledImage (pXWC->i.display, pPriv->drawable, pXWC->i.gc, pXImage,
935 0, 0, scaledX, scaledY,
936 pXImage->width, nSrcLines,
937 scaledWidth,scaledHeight);
939 pPriv->linesDone += nSrcLines;
945 /* ------------------------ ilConvertForXWrite -------------------- */
946 /* Public function; see spec.
947 Side effect: set pXWC->i.writeType, code for how it will render.
949 ilBool ilConvertForXWrite (
953 unsigned long mustBeZero,
959 ilImageFormat format;
960 unsigned int writeType;
961 register ilXWCPtr pXWC;
963 /* Table indexed by [dst visual type], yielding writeType when in raw
965 static unsigned int rawWriteMethodTable [(IL_X_MAX_VISUAL_TYPE + 1)] = {
966 IL_XWC_WRITE_BITONAL, /* IL_XWC_BITONAL */
967 IL_XWC_WRITE_GRAY, /* IL_XWC_GRAY_8 */
968 IL_XWC_WRITE_COLOR_DITHER, /* IL_XWC_COLOR_8 */
969 IL_XWC_WRITE_COLOR /* IL_XWC_COLOR_24 */ };
971 /* Table indexed by [image type, dst visual type], yielding writeType,
972 assuming best case: colors/grays alloc'd succesfully; else writeType
975 static unsigned int writeTypeTable [(IL_MAX_TYPE + 1) *
976 (IL_X_MAX_VISUAL_TYPE + 1)] =
977 { /* (src) image type (dst) visual type writeType */
979 /* IL_BITONAL IL_XWC_BITONAL */ IL_XWC_WRITE_BITONAL,
980 /* IL_XWC_GRAY_8 */ IL_XWC_WRITE_BITONAL,
981 /* IL_XWC_COLOR_8 */ IL_XWC_WRITE_BITONAL,
982 /* IL_XWC_COLOR_24 */ IL_XWC_WRITE_BITONAL,
984 /* IL_GRAY IL_XWC_BITONAL */ IL_XWC_WRITE_BITONAL,
985 /* IL_XWC_GRAY_8 */ IL_XWC_WRITE_GRAY,
986 /* IL_XWC_COLOR_8 */ IL_XWC_WRITE_GRAY,
987 /* IL_XWC_COLOR_24 */ IL_XWC_WRITE_COLOR,
989 /* IL_PALETTE IL_XWC_BITONAL */ IL_XWC_WRITE_BITONAL,
990 /* IL_XWC_GRAY_8 */ IL_XWC_WRITE_GRAY,
991 /* IL_XWC_COLOR_8 */ IL_XWC_WRITE_COLOR_DITHER,
992 /* IL_XWC_COLOR_24 */ IL_XWC_WRITE_COLOR,
994 /* IL_RGB IL_XWC_BITONAL */ IL_XWC_WRITE_BITONAL,
995 /* IL_XWC_GRAY_8 */ IL_XWC_WRITE_GRAY,
996 /* IL_XWC_COLOR_8 */ IL_XWC_WRITE_COLOR_DITHER,
997 /* IL_XWC_COLOR_24 */ IL_XWC_WRITE_COLOR,
999 /* IL_YCBCR IL_XWC_BITONAL */ IL_XWC_WRITE_BITONAL,
1000 /* IL_XWC_GRAY_8 */ IL_XWC_WRITE_GRAY,
1001 /* IL_XWC_COLOR_8 */ IL_XWC_WRITE_COLOR_DITHER,
1002 /* IL_XWC_COLOR_24 */ IL_XWC_WRITE_COLOR
1007 if (pipe->objectType != IL_PIPE) {
1008 pipe->context->error = IL_ERROR_OBJECT_TYPE;
1011 if (mustBeZero || mustBeNull)
1012 return ilDeclarePipeInvalid (pipe, IL_ERROR_PAR_NOT_ZERO);
1014 /* Validate that given XWC is one, and is same context as pipe. */
1015 pXWC = (ilXWCPtr)XWC;
1016 if (pXWC->o.p.objectType != IL_XWC)
1017 return ilDeclarePipeInvalid (pipe, IL_ERROR_OBJECT_TYPE);
1018 if (pXWC->o.p.context != pipe->context)
1019 return ilDeclarePipeInvalid (pipe, IL_ERROR_CONTEXT_MISMATCH);
1021 /* Get pipe info and decompress; if pipe not in IL_PIPE_FORMING state,
1023 if (ilGetPipeInfo (pipe, TRUE, &info, &des, &format) != IL_PIPE_FORMING) {
1024 if (!pipe->context->error)
1025 ilDeclarePipeInvalid (pipe, IL_ERROR_PIPE_STATE);
1029 /* If raw mode, allocate no colors, output based on dst visual type,
1030 except for bit/pixel images: output using bitonal approach; else:
1031 get "writeType" based on des.type (private types not supported)
1032 and pXWC->i.visualType. Check for allocated dither colors
1033 (default to gray if not enough) and grays (default to bitonal if
1035 Pretend YCbCr is RGB - an ilConvert() to RGB will be done below
1038 if (pXWC->i.rawMode) {
1039 if ((des.nSamplesPerPixel == 1) && (format.nBitsPerSample[0] == 1))
1040 writeType = IL_XWC_WRITE_BITONAL;
1041 else writeType = rawWriteMethodTable [pXWC->i.visualType];
1044 if (des.type > IL_MAX_TYPE)
1045 return ilDeclarePipeInvalid (pipe, IL_ERROR_IMAGE_TYPE);
1046 if (des.type == IL_YCBCR)
1049 writeType = writeTypeTable
1050 [des.type * (IL_X_MAX_VISUAL_TYPE + 1) + pXWC->i.visualType];
1051 if (writeType == IL_XWC_WRITE_COLOR_DITHER) {
1052 if (!pXWC->colorMapImage)
1053 ilChangeXWC ((ilXWC)pXWC, IL_XWC_ALLOC_DITHER_COLORS,
1055 if (!pXWC->colorMapImage)
1056 writeType = IL_XWC_WRITE_GRAY;
1058 if (writeType == IL_XWC_WRITE_GRAY) {
1059 if (!pXWC->grayMapImage)
1060 ilChangeXWC ((ilXWC)pXWC, IL_XWC_ALLOC_GRAYS, (ilPtr)NULL);
1061 if (!pXWC->grayMapImage)
1062 writeType = IL_XWC_WRITE_BITONAL;
1065 /* If RGB display alloc colors or dflt to bitonal. */
1066 if (writeType == IL_XWC_WRITE_COLOR) {
1067 if (!pXWC->colorMapImage)
1068 if (!ilAllocateXDirectColors (pXWC, 256))
1069 writeType = IL_XWC_WRITE_BITONAL;
1071 } /* END not raw mode */
1073 /* Do ilConvert() and add filter(s) based on "writeType". */
1074 switch (writeType) {
1076 /* Bitonal: do an XPutImage() with XYBitmap, which renders image 0's
1077 with GC background color, 1's with foreground, as defined by IL
1079 If rawMode, must be bit/pixel.
1081 case IL_XWC_WRITE_BITONAL:
1082 if (pXWC->i.rawMode) {
1083 if ((des.nSamplesPerPixel != 1) || (format.nBitsPerSample[0] != 1))
1084 return ilDeclarePipeInvalid (pipe, IL_ERROR_RAW_MODE);
1086 else if (!ilConvert (pipe, IL_DES_BITONAL, IL_FORMAT_BIT, 0, NULL))
1090 /* Gray: do ilMap() which maps 256 gray shades to the equivalent
1091 X pixel values, possibly using fewer shades of gray (slam; not
1092 dithered to lesser # grays).
1094 case IL_XWC_WRITE_GRAY:
1095 if (pXWC->i.rawMode) {
1096 if ((des.nSamplesPerPixel != 1) || (format.nBitsPerSample[0] != 8))
1097 return ilDeclarePipeInvalid (pipe, IL_ERROR_RAW_MODE);
1100 if (!ilConvert (pipe, IL_DES_GRAY, IL_FORMAT_BYTE, 0, NULL))
1103 if (!ilMap (pipe, pXWC->grayMapImage))
1108 /* Dithered RGB: if raw mode, accept if byte/pixel;
1109 if a pre-dithered palette image in pipe, ilMap() to map colors to
1111 otherwise dither cvt to palette w/ map to the allocated colors.
1113 case IL_XWC_WRITE_COLOR_DITHER:
1114 if (pXWC->i.rawMode) {
1115 if ((des.nSamplesPerPixel != 1) || (format.nBitsPerSample[0] != 8))
1116 return ilDeclarePipeInvalid (pipe, IL_ERROR_RAW_MODE);
1118 else if ((des.flags & IL_DITHERED_PALETTE)
1119 && (des.typeInfo.palette.levels[0] == NRED)
1120 && (des.typeInfo.palette.levels[1] == NGREEN)
1121 && (des.typeInfo.palette.levels[2] == NBLUE)) {
1122 if ((format.nBitsPerSample[0] != 8)
1123 && !ilConvert (pipe, (ilImageDes *)NULL, IL_FORMAT_BYTE, 0,
1127 if (!ilMap (pipe, pXWC->colorMapImage))
1131 ilConvertToPaletteInfo cvt;
1132 cvt.method = pXWC->i.ditherMethod;
1133 cvt.levels[0] = NRED;
1134 cvt.levels[1] = NGREEN;
1135 cvt.levels[2] = NBLUE;
1138 cvt.dstType = IL_GRAY; /* any type other than IL_PALETTE */
1139 cvt.mapImage = pXWC->colorMapImage;
1142 cvt.dstType = IL_PALETTE;
1143 cvt.mapImage = (ilClientImage)NULL;
1145 if (!ilConvert (pipe, IL_DES_PALETTE, IL_FORMAT_BYTE,
1146 IL_CONVERT_TO_PALETTE, &cvt))
1151 /* RGB: if raw mode, check format, else convert to RGB, and if
1152 mapPixels and map needed (ramp not 0..255 each component) do
1155 case IL_XWC_WRITE_COLOR:
1157 if (pXWC->i.rawMode) {
1158 if ((des.nSamplesPerPixel != 3)
1159 || (format.nBitsPerSample[0] != 8)
1160 || (format.nBitsPerSample[1] != 8)
1161 || (format.nBitsPerSample[2] != 8)
1162 || (format.sampleOrder != IL_SAMPLE_PIXELS))
1163 return ilDeclarePipeInvalid (pipe, IL_ERROR_RAW_MODE);
1166 if (!ilConvert (pipe, IL_DES_RGB, IL_FORMAT_3BYTE_PIXEL, 0, NULL))
1168 if (mapPixels && pXWC->mapDirect)
1169 if (!ilMap (pipe, pXWC->colorMapImage))
1174 } /* END switch writeType */
1176 pXWC->i.writeType = writeType; /* set method of writing to be used */
1177 pipe->context->error = IL_OK;
1182 /* ------------------------ ilWriteXDrawable ---------------------- */
1183 /* Public function; see spec.
1185 ilBool ilWriteXDrawable (
1192 unsigned long mustBeZero
1196 register ilXWCPtr pXWC;
1197 register ilXPrivPtr pPriv;
1198 ilSrcElementData *pSrcData, srcData;
1199 unsigned long bufferSize;
1201 ** We need to use the execute fucntion with the ratio parameter.
1203 ilError (*executeFunction)( register ilExecuteData *,
1208 /* If a src clip rect, insert an ilCrop() element before us.
1209 In the future, should look at pipe and handle some cases directly.
1211 if (pSrcRect && !ilCrop (pipe, pSrcRect))
1214 /* Convert as necessary, mapping pixels to X pixels and get
1215 pXWC->i.writeType */
1216 pXWC = (ilXWCPtr)XWC;
1217 if (!ilConvertForXWrite (pipe, (ilXWC)pXWC, TRUE, 0, NULL))
1220 ilGetPipeInfo (pipe, FALSE, &info, (ilImageDes *)NULL,
1221 (ilImageFormat *)NULL);
1223 /* If writing 24 bits: use separate executeFunction, set "bufferSize"
1224 to buffer to be allocated, and if too large force pipe to give us
1227 if (pXWC->i.writeType == IL_XWC_WRITE_COLOR) {
1228 bufferSize = (info.width * 4) * info.stripHeight;
1229 if (bufferSize > MAX_IMAGE_BUFFER_SIZE) {
1230 srcData.consumerImage = (ilObject)NULL;
1231 srcData.stripHeight = BEST_IMAGE_BUFFER_SIZE / (4 * info.width);
1232 if (srcData.stripHeight < 1)
1233 srcData.stripHeight = 1;
1234 srcData.constantStrip = FALSE;
1235 srcData.minBufferHeight = 0;
1236 pSrcData = &srcData;
1238 else pSrcData = (ilSrcElementData *)NULL;
1239 executeFunction = ilWriteXOptLongExecute;
1242 pSrcData = (ilSrcElementData *)NULL;
1243 executeFunction = ilWriteXExecute;
1246 /* Add a consumer which does an XPutImage() using the pipe data
1248 Increment the XWC refCount; element's Destroy() function
1249 ilXDestroy() will decrement it when this pipe element is removed.
1251 pPriv = (ilXPrivPtr)ilAddPipeElement (pipe, IL_CONSUMER,
1252 sizeof(ilXPrivRec), 0, pSrcData, (ilDstElementData *)NULL,
1253 ilWriteXInit, ilWriteXCleanup, ilXDestroy, NULL, executeFunction, 0);
1254 if (!pPriv) return FALSE; /* EXIT */
1257 pPriv->drawable = drawable;
1262 /* Set writeType-specific values in *pPriv */
1263 switch (pXWC->i.writeType) {
1264 case IL_XWC_WRITE_BITONAL:
1265 pPriv->imageDepth = 1;
1266 pPriv->imageFormat = XYBitmap;
1267 pPriv->isLongImage = FALSE;
1268 pPriv->bufferSize = 0;
1270 case IL_XWC_WRITE_GRAY:
1271 pPriv->imageDepth = 8;
1272 pPriv->imageFormat = ZPixmap;
1273 pPriv->isLongImage = FALSE;
1274 pPriv->bufferSize = 0;
1276 case IL_XWC_WRITE_COLOR_DITHER:
1277 pPriv->imageDepth = 8;
1278 pPriv->imageFormat = ZPixmap;
1279 pPriv->isLongImage = FALSE;
1280 pPriv->bufferSize = 0;
1282 case IL_XWC_WRITE_COLOR:
1283 pPriv->bufferSize = bufferSize; /* from above */
1284 pPriv->imageDepth = 24;
1285 pPriv->imageFormat = ZPixmap;
1286 pPriv->isLongImage = TRUE;
1290 pipe->context->error = IL_OK;