/* * CDE - Common Desktop Environment * * Copyright (c) 1993-2012, The Open Group. All rights reserved. * * These libraries and programs are free software; you can * redistribute them and/or modify them under the terms of the GNU * Lesser General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * These libraries and programs are distributed in the hope that * they will be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public * License along with these libraries and programs; if not, write * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth * Floor, Boston, MA 02110-1301 USA */ /* $XConsortium: ilX.c /main/11 1996/11/12 05:02:17 pascale $ */ /**--------------------------------------------------------------------- *** *** (c)Copyright 1991 Hewlett-Packard Co. *** *** RESTRICTED RIGHTS LEGEND *** Use, duplication, or disclosure by the U.S. Government is subject to *** restrictions as set forth in sub-paragraph (c)(1)(ii) of the Rights in *** Technical Data and Computer Software clause in DFARS 252.227-7013. *** Hewlett-Packard Company *** 3000 Hanover Street *** Palo Alto, CA 94304 U.S.A. *** Rights for non-DOD U.S. Government Departments and Agencies are as set *** forth in FAR 52.227-19(c)(1,2). *** ***-------------------------------------------------------------------*/ #include "ilint.h" #include "ilcontext.h" #include "ilX.h" #include #include #include #include "ilpipelem.h" #include "ilerrors.h" #include #define X_COLOR_MAX 65535 /* max value for X colormap RGB value */ /* Buffer allocation checks. Buffers are allocated for example when writing to a 24 bit drawable: the pipe image pixels are converted from 3 bytes to 4 bytes (CARD32). */ #define MAX_IMAGE_BUFFER_SIZE 100000 /* force strips if larger than this ... */ #define BEST_IMAGE_BUFFER_SIZE 50000 /* to strips of this size */ /* Masks for ilFreeColorData(); see below. */ #define IL_FREE_XCOLORS (1<<0) #define IL_FREE_XGRAYS (1<<1) /* Codes for view of X , in "ilXWCRec.i.visualType". When the visual is unsupported or an insufficient # of colors can be allocated from the colormap, the drawable defaults to IL_XWC_BITONAL. Images rendered to such an XWC are converted to bitonal, then XPutImage() of an XYBitmap is done - the XWC GC's foreground/background colors are used for black/white. */ #define IL_X_MAX_VISUAL_TYPE 3 /* max value of IL_XWC_BITONAL et al*/ /* Default # of grays or dither colors to allocate for pseudo-color. */ #define IL_DEFAULT_X_GRAYS 32 #define NRED 4 #define NGREEN 8 #define NBLUE 4 /* Internals of an XWC (X Write Context), an IL object created by ilCreateXWC(). An XWC is associated with the visual "visual" and "colormap". "i" contains basic information returned by ilQueryXWC(). If pColors is non-null, it points to a list of length "nColors", of colors allocated from "colormap". "pad" in each colorcell is used as a flag: == 0 if color not allocated, else color was sucessfully allocated. If non-null, colorMapImage is an image for mapping to X images using ilMap(). For example, for 8 bit pseudo-color when 484 color handling is used, "pColors" points to 128 colors, and "colorMapImage" points to a 256 pixel image where each entry is the pixel to use for color (red*4*8 + green*8 + blue). If "colorMapImage" is null then the alloc failed or has not been tried. Note: above applies also to Direct/TrueColor visuals, with the same names. The above also applies to the "gray" fields, with the "gray" names. */ typedef struct { ilObjectRec o; /* std header: MUST BE FIRST */ ilXWCInfo i; /* see above */ XVisualInfo visualInfo; /* X info on "visual" */ XColor *pColors; /* ptr to list of allocated colors or null */ int nColors; /* size of *pColors list */ ilClientImage colorMapImage; /* see above */ ilBool mapDirect; /* ilMap(colorMapImage), Direct/TrueColor */ XColor *pGrays; /* ptr to list of allocated grays or null */ int nGrays; /* size of *pGrays list */ ilClientImage grayMapImage; /* same as colorMapImage, but for grays */ } ilXWCRec, *ilXWCPtr; typedef ilError (*executeFunctionType)(); /* ------------------------ ilFreeColorData ---------------------- */ /* Free the color list and translation table in the given XWC if present. "freeMasks" indicates which should be freed: IL_FREE_XCOLORS/XGRAYS, or ~0 for everything. */ static void ilFreeColorData ( ilXWCPtr pXWC, unsigned long freeMask ) { int i; XColor *pColor; /* If color list present: free each color if allocated (pad != 0); free list. */ if (freeMask & IL_FREE_XCOLORS) { if (pXWC->pColors) { for (i = 0, pColor = pXWC->pColors; i < pXWC->nColors; i++) { if (pColor->pad) XFreeColors (pXWC->i.display, pXWC->i.colormap, &pColor->pixel, 1, 0L); pColor++; } IL_FREE (pXWC->pColors); pXWC->pColors = (XColor *)NULL; pXWC->nColors = 0; } if (pXWC->colorMapImage) { ilDestroyObject (pXWC->colorMapImage); pXWC->colorMapImage = (ilClientImage)NULL; } } /* Same for gray list */ if (freeMask & IL_FREE_XGRAYS) { if (pXWC->pGrays) { for (i = 0, pColor = pXWC->pGrays; i < pXWC->nGrays; i++) { if (pColor->pad) XFreeColors (pXWC->i.display, pXWC->i.colormap, &pColor->pixel, 1, 0L); pColor++; } IL_FREE (pXWC->pGrays); pXWC->pGrays = (XColor *)NULL; pXWC->nGrays = 0; } if (pXWC->grayMapImage) { ilDestroyObject (pXWC->grayMapImage); pXWC->grayMapImage = (ilClientImage)NULL; } } } /* ----------------------- ilDestroyXWC -------------------------- */ /* Destroy() function for XWC objects. Free the color list if present. The GC for the default XWC will be destroyed when the context is freed, by ilXDestroyContext() below. */ static void ilDestroyXWC ( ilPtr pPrivate ) { ilObject object = (ilObject)pPrivate; ilXWCPtr pXWC; pXWC = (ilXWCPtr)object; /* ~ on signed integer is not recommended, play it safe here */ ilFreeColorData (pXWC, ~(0UL)); } /* --------------------- ilGammaCorrect -------------------------- */ /* Returns a value from 0..scaleValue, given "value", from 0.."maxValue" - 1, scaled up to "scaleValue" (e.g. 65535 for X color values). Currently a misnomer - not doing any gamma correction (gamma = 1.0). */ static int ilGammaCorrect ( long scaleValue, int value, int maxValue ) { int allocValue; if (value == 0) allocValue = 0; else if (value == (maxValue - 1)) allocValue = scaleValue; else { allocValue = value * scaleValue / (maxValue-1); if (allocValue < 0) allocValue = 0; else if (allocValue > scaleValue) allocValue = scaleValue; } return allocValue; } /* --------------------- ilAllocateXDitherColors ------------------ */ /* Internal function to ilCreateXWC(). Attempts to allocate enough colors in pXWC->i.colormap to support the visual as a 484 pseudo-color visual. An error code is returned to the given context if an error (e.g. malloc) error occurs; IL_OK if the grays could not be alloc'd (but false is returned). */ static ilBool ilAllocateXDitherColors ( ilContext context, ilXWCPtr pXWC ) { int i, red, green, blue; XColor *pColor; ilPtr pTranslate; ilImageInfo imageInfo, *pImageInfo; context->error = IL_OK; /* assume no errors */ if (pXWC->colorMapImage) return TRUE; /* already alloc'd; EXIT */ /* Allocate a client image to use as LUT for mapping to X's colors. Point pTranslate to the allocated pixels. */ imageInfo.pDes = IL_DES_GRAY; imageInfo.pFormat = IL_FORMAT_BYTE; imageInfo.width = 256; imageInfo.height = 1; imageInfo.clientPixels = FALSE; pXWC->colorMapImage = ilCreateClientImage (context, &imageInfo, 0); if (!pXWC->colorMapImage) return FALSE; /* EXIT */ ilQueryClientImage (pXWC->colorMapImage, &pImageInfo, 0); pTranslate = pImageInfo->plane[0].pPixels; pXWC->nColors = NRED * NGREEN * NBLUE; pXWC->pColors = (XColor *)IL_MALLOC (pXWC->nColors * sizeof(XColor)); if (!pXWC->pColors) { ilDestroyObject (pXWC->colorMapImage); pXWC->colorMapImage = (ilClientImage)NULL; context->error = IL_ERROR_MALLOC; return FALSE; /* EXIT */ } for (i = 0, pColor = pXWC->pColors; i < pXWC->nColors; i++, pColor++) pColor->pad = FALSE; /* init pad, in case below fails */ /* Allocate 484 colors (128 in all) */ pColor = pXWC->pColors; for (red = 0; red < NRED; red++) for (green = 0; green < NGREEN; green++) for (blue = 0; blue < NBLUE; blue++) { pColor->red = ilGammaCorrect (X_COLOR_MAX, red, NRED); pColor->green = ilGammaCorrect (X_COLOR_MAX, green, NGREEN); pColor->blue = ilGammaCorrect (X_COLOR_MAX, blue, NBLUE); if (!XAllocColor (pXWC->i.display, pXWC->i.colormap, pColor)) { ilFreeColorData (pXWC, IL_FREE_XCOLORS); return FALSE; } pTranslate [red*(NGREEN*NBLUE) + green*NBLUE + blue] = pColor->pixel; pColor->pad = TRUE; /* mark as alloc'd */ pColor++; } return TRUE; /* colors successfully alloc'd */ } /* ---------------------------- ilAllocateXGrays ---------------------- */ /* Allocate "nGrays" from the colormap associated with the given XWC or return error. The grays are ramped evenly from 0..nGrays-1. If there are "nGrays" existing grays, they are used, else if not nGrays, they are deallocated. An error code is returned to the given context if an error (e.g. malloc) error occurs; IL_OK if the grays could not be alloc'd (but false is returned). */ static ilBool ilAllocateXGrays ( ilContext context, ilXWCPtr pXWC, int nGrays ) { int i, index; XColor *pColor; ilPtr pTranslate; ilImageInfo imageInfo, *pImageInfo; double spreadFactor; /* Use the grays if the same number, else deallocate them. */ context->error = IL_OK; /* assume no errors */ if (pXWC->pGrays) { if (pXWC->nGrays == nGrays) return TRUE; else ilFreeColorData (pXWC, IL_FREE_XGRAYS); } if (nGrays > 256) return FALSE; /* EXIT */ /* Allocate a client image to use as LUT for mapping to X's colors. Point pTranslate to the allocated pixels. */ imageInfo.pDes = IL_DES_GRAY; imageInfo.pFormat = IL_FORMAT_BYTE; imageInfo.width = 256; imageInfo.height = 1; imageInfo.clientPixels = FALSE; pXWC->grayMapImage = ilCreateClientImage (context, &imageInfo, 0); if (!pXWC->grayMapImage) return FALSE; /* EXIT */ ilQueryClientImage (pXWC->grayMapImage, &pImageInfo, 0); pTranslate = pImageInfo->plane[0].pPixels; pXWC->nGrays = nGrays; pXWC->pGrays = (XColor *)IL_MALLOC (pXWC->nGrays * sizeof(XColor)); if (!pXWC->pGrays) { ilDestroyObject (pXWC->grayMapImage); pXWC->colorMapImage = (ilClientImage)NULL; context->error = IL_ERROR_MALLOC; return FALSE; /* EXIT */ } for (i = 0, pColor = pXWC->pGrays; i < pXWC->nGrays; i++, pColor++) pColor->pad = FALSE; /* init pad, in case below fails */ /* Allocate the grays; return error on any failure. */ for (i = 0; i < nGrays; i++) { pColor = &pXWC->pGrays [i]; pColor->red = pColor->green = pColor->blue = ilGammaCorrect (X_COLOR_MAX, i, nGrays); if (!XAllocColor (pXWC->i.display, pXWC->i.colormap, pColor)) { pColor->pad = FALSE; ilFreeColorData (pXWC, IL_FREE_XGRAYS); return FALSE; /* EXIT */ } pColor->pad = TRUE; } /* Grays allocated ok; spread the allocated colors over the whole 256 area. In effect, color-slam all 256-level gray images into nGrays. NOTE: gray images with other than 256 levels could be supported in future! */ spreadFactor = ((double)(nGrays - 1)) / (double)255; pColor = pXWC->pGrays; for (i = 0; i < 256; i++) { index = spreadFactor * (double)i + 0.5; if (index > (nGrays - 1)) index = nGrays - 1; pTranslate [i] = pColor [index].pixel; } return TRUE; } /* ---------------------- ilAllocateXDirectColors --------------------- */ /* Allocate "nLevels" levels of each of RGB for a DirectColor or a TrueColor visual. "nLevels" should be passed as 256; it becomes 1/2 of that if failure occurs this function recurses on failure until an unacceptable # of levels not alloc'd. */ static ilBool ilAllocateXDirectColors ( ilXWCPtr pXWC, int nLevels ) { int i, j, pixel, red, green, blue, nReplicate; XColor *pColor; ilPtr pTranslate; ilImageInfo imageInfo, *pImageInfo; ilContext context; #define MIN_DIRECT_LEVELS 32 /* min # of acceptable levels */ if (pXWC->colorMapImage) return TRUE; /* already alloc'd; EXIT */ /* Create a 256x1 3 byte/pixel map image. */ context = pXWC->o.p.context; imageInfo.pDes = IL_DES_RGB; imageInfo.pFormat = IL_FORMAT_3BYTE_PIXEL; imageInfo.width = 256; imageInfo.height = 1; imageInfo.clientPixels = FALSE; pXWC->colorMapImage = ilCreateClientImage (context, &imageInfo, 0); if (!pXWC->colorMapImage) return FALSE; ilQueryClientImage (pXWC->colorMapImage, &pImageInfo, 0); pTranslate = pImageInfo->plane[0].pPixels; /* Try to allocate nLevels read-only levels each of RGB, in a logical ramp order. Set pXWC->mapDirect to false if pixel value != RGB value, in which case pipe image pixels must be ilMap()'d to X pixel values. If can't allocate, try to allocate nLevels/2 unless that is too few colors, in which we fail. Spread the X pixels into the 256 entry map image. */ pXWC->nColors = nLevels; pXWC->pColors = (XColor *)IL_MALLOC_ZERO (pXWC->nColors * sizeof(XColor)); if (!pXWC->pColors) { ilDestroyObject (pXWC->colorMapImage); pXWC->colorMapImage = (ilClientImage)NULL; context->error = IL_ERROR_MALLOC; return FALSE; } pXWC->mapDirect = FALSE; nReplicate = 256 / nLevels; /* # of times to replicate pixel into map image */ for (i = 0, pColor = pXWC->pColors; i < nLevels; i++, pColor++) { pColor->red = pColor->green = pColor->blue = ilGammaCorrect (X_COLOR_MAX, i, nLevels); pColor->flags = DoRed | DoGreen | DoBlue; if (!XAllocColor (pXWC->i.display, pXWC->i.colormap, pColor)) { ilFreeColorData (pXWC, IL_FREE_XCOLORS); if (nLevels <= MIN_DIRECT_LEVELS) return FALSE; else return ilAllocateXDirectColors (pXWC, nLevels / 2); } pColor->pad = TRUE; /* mark as alloc'd */ pixel = pColor->pixel; red = (pixel >> 16) & 0xff; green = (pixel >> 8) & 0xff; blue = pixel & 0xff; if ((red != i) || (green != i) || (blue != i)) pXWC->mapDirect = TRUE; for (j = 0; j < nReplicate; j++) { /* replicate into map image */ *pTranslate++ = red; *pTranslate++ = green; *pTranslate++ = blue; } } return TRUE; } /* ------------------------ ilChangeXWC --------------------------- */ /* Public function; see spec. */ ilBool ilChangeXWC ( ilXWC XWC, unsigned int code, void *pData ) { ilXWCPtr pXWC; ilContext context; pXWC = (ilXWCPtr)XWC; context = pXWC->o.p.context; context->error = IL_OK; /* assume no error */ if (pXWC->o.p.objectType != IL_XWC) { context->error = IL_ERROR_OBJECT_TYPE; return FALSE; /* EXIT */ } switch (code) { /* Allocate grays: allocate grays if gray or pseudo-color, else return true if gray display supported (e.g. to True/DirectColor). */ case IL_XWC_ALLOC_GRAYS: if (pData) { context->error = IL_ERROR_OPTION_DATA; return FALSE; } switch (pXWC->i.visualType) { case IL_XWC_BITONAL: return FALSE; case IL_XWC_GRAY_8: case IL_XWC_COLOR_8: if (ilAllocateXGrays (context, pXWC, IL_DEFAULT_X_GRAYS)) return TRUE; else return FALSE; case IL_XWC_COLOR_24: return TRUE; } /* Allocate colors: 8 and 24 bit color only */ case IL_XWC_ALLOC_COLORS: if (pData) { context->error = IL_ERROR_OPTION_DATA; return FALSE; } if ((pXWC->i.visualType == IL_XWC_COLOR_8) && ilAllocateXDitherColors (context, pXWC)) return TRUE; else if ((pXWC->i.visualType == IL_XWC_COLOR_24) && ilAllocateXDirectColors (pXWC, 256)) return TRUE; else return FALSE; case IL_XWC_FREE_GRAYS: if (pData) { context->error = IL_ERROR_OPTION_DATA; return FALSE; } ilFreeColorData (pXWC, IL_FREE_XGRAYS); break; /* Free colors if 8 or 24 bit color */ case IL_XWC_FREE_COLORS: if (pData) { context->error = IL_ERROR_OPTION_DATA; return FALSE; } if ((pXWC->i.visualType == IL_XWC_COLOR_8) || (pXWC->i.visualType == IL_XWC_COLOR_24)) ilFreeColorData (pXWC, IL_FREE_XCOLORS); break; case IL_XWC_SET_DITHER_METHOD: { unsigned int ditherMethod; ditherMethod = *((unsigned int *)pData); if ((ditherMethod != IL_AREA_DITHER) && (ditherMethod != IL_DIFFUSION) && (ditherMethod != IL_QUICK_DIFFUSION)) { context->error = IL_ERROR_OPTION_DATA; return FALSE; } pXWC->i.ditherMethod = ditherMethod; break; } case IL_XWC_SET_RAW_MODE: pXWC->i.rawMode = *((ilBool *)pData); break; default: context->error = IL_ERROR_INVALID_OPTION; return FALSE; } /* END switch code */ return TRUE; } /* ------------------------ ilQueryXWC --------------------------- */ /* Public function; see spec. */ ilBool ilQueryXWC ( ilXWC XWC, ilXWCInfo *pInfo ) { ilXWCPtr pXWC; pXWC = (ilXWCPtr)XWC; if (pXWC->o.p.objectType != IL_XWC) { pXWC->o.p.context->error = IL_ERROR_OBJECT_TYPE; return FALSE; /* EXIT */ } *pInfo = pXWC->i; pXWC->o.p.context->error = IL_OK; return TRUE; } /* ------------------------ ilCreateXWC ------------------------- */ /* Public function; see spec. Return an error if no (null) display in this context. */ ilXWC ilCreateXWC ( ilContext context, Display *display, Visual *visual, Colormap colormap, GC gc, unsigned long mustBeZero1, unsigned long mustBeZero2 ) { ilXWCPtr pXWC; XVisualInfo template, *pVisualInfo; int notUsed; if ((mustBeZero1 != 0) || (mustBeZero2 != 0)) { context->error = IL_ERROR_PAR_NOT_ZERO; return (ilXWC)NULL; /* EXIT */ } /* A null visual or colormap means output will be to bitmap, else get the info for the given visual; exit if not found. */ if (!visual || !colormap) { visual = (Visual *)NULL; colormap = (Colormap)0; } else { template.visualid = XVisualIDFromVisual (visual); pVisualInfo = XGetVisualInfo (display, VisualIDMask, &template, ¬Used); if (!pVisualInfo) { context->error = IL_ERROR_X_RESOURCE; return (ilXWC)NULL; /* EXIT */ } } /* Create an XWC object and fill it in. */ pXWC = (ilXWCPtr)_ilCreateObject (context, IL_XWC, ilDestroyXWC, sizeof (ilXWCRec)); if (!pXWC) return (ilXWC)NULL; /* EXIT */ pXWC->i.display = display; pXWC->i.visual = visual; if (visual) { pXWC->visualInfo = *pVisualInfo; free (pVisualInfo); /* free list from XGetVisualInfo() */ } pXWC->i.gc = gc; pXWC->i.colormap = colormap; pXWC->pColors = (XColor *)NULL; pXWC->nColors = 0; pXWC->colorMapImage = (ilClientImage)NULL; pXWC->pGrays = (XColor *)NULL; pXWC->nGrays = 0; pXWC->grayMapImage = (ilClientImage)NULL; pXWC->i.ditherMethod = IL_AREA_DITHER; pXWC->i.rawMode = FALSE; /* Check the class of the given visual and fill in XWC des and format. If visual class not supported default to bitonal. May also default to bitonal (or color demote to gray) later if insufficient colors or grays can be allocated. If null visual, do bitonal output. */ pXWC->i.staticVisual = TRUE; /* assume non-writeable colormap */ if (!visual) pXWC->i.visualType = IL_XWC_BITONAL; else switch (pXWC->visualInfo.class) { case PseudoColor: pXWC->i.staticVisual = FALSE; case StaticColor: if (pXWC->visualInfo.depth == 8) pXWC->i.visualType = IL_XWC_COLOR_8; else pXWC->i.visualType = IL_XWC_BITONAL; break; /* Support True/DirectColor if 32 bits format = "<8R><8G><8B>". */ case DirectColor: pXWC->i.staticVisual = FALSE; case TrueColor: if ((pXWC->visualInfo.depth == 24) && (pXWC->visualInfo.red_mask == 0xff0000) && (pXWC->visualInfo.green_mask == 0xff00) && (pXWC->visualInfo.blue_mask == 0xff)) pXWC->i.visualType = IL_XWC_COLOR_24; else pXWC->i.visualType = IL_XWC_BITONAL; break; case GrayScale: pXWC->i.staticVisual = FALSE; case StaticGray: if (pXWC->visualInfo.depth == 8) pXWC->i.visualType = IL_XWC_GRAY_8; else pXWC->i.visualType = IL_XWC_BITONAL; break; } /* END switch visual class */ /* If a bitonal visual, mark as static (non-allocatable colors) */ if (pXWC->i.visualType == IL_XWC_BITONAL) pXWC->i.staticVisual = TRUE; context->error = IL_OK; return (ilXWC)pXWC; } /* ======================== WRITE X DRAWABLE CODE ======================== */ /* Private block for ilRead/WriteXDrawable pipe element. Notes: Inited by ilWriteXDrawable(): imageDepth depth of image to create - set into pPriv when added imageFormat X format of image: XYBitmap (bitonal) or ZPixmap isLongImage if true: image is 32bits/pixel: set image rowBytes to width*4. If false: set image rowBytes to row bytes of pSrcImage. bufferSize size of buffer to create and attach to Ximage. pXWC ptr to XWC for this operation drawable id of X drawable (Window or Pixmap) to read or write x, y read: src (x,y). write: dst (x,y) from caller Inited by ilWriteXInit(): Ximage a temp XImage created by Init. Its data ptr is pointed directly at the read/write buffer, or equals "pBuffer" pBuffer ptr to buffer allocated, if bufferSize > 0 linesDone zeroed by Init(): # of lines written / read so far, i.e. y + linesDone is next line to read / write. */ typedef struct { int imageDepth; int imageFormat; ilBool isLongImage; unsigned long bufferSize; ilXWCPtr pXWC; Drawable drawable; ilPtr pBuffer; XImage *pXImage; int x, y; long linesDone; } ilXPrivRec, *ilXPrivPtr; /* ----------------------- ilXDestroy ----------------------------- */ /* Destroy() function for ilWriteXDrawable() pipe element. "Destroys" the associated XWC, whose refCount must have been incremented when the element was successfully added to the pipe - Destroy downcounts it. */ static ilError ilXDestroy ( ilPtr pPrivate ) { ilXPrivPtr pPriv = (ilXPrivPtr)pPrivate; ilDestroyObject ((ilObject)pPriv->pXWC); return IL_OK; } /* ------------------------- ilWriteXInit ------------------------- */ /* Init() function for ilWriteXDrawable() for all src image types. Creates an XImage, which is just a data structure - creates no pixel buffer. The XImage is freed by ilWriteXCleanup(). */ static ilError ilWriteXInit ( ilPtr pPrivate, ilImageInfo *pSrcImage, ilImageInfo *pDstImage /* ignored */ ) { ilXPrivPtr pPriv = (ilXPrivPtr)pPrivate; ilXWCPtr pXWC; XImage *pXImage; /* Create a temp buffer for image pixels if requested. */ if (pPriv->bufferSize > 0) { pPriv->pBuffer = (ilPtr)IL_MALLOC (pPriv->bufferSize); if (!pPriv->pBuffer) return IL_ERROR_MALLOC; /* EXIT */ } else pPriv->pBuffer = NULL; /* Create an XImage that will be pointed to each buffer (strip) to write. */ pXWC = pPriv->pXWC; pXImage = XCreateImage (pXWC->i.display, pXWC->i.visual, pPriv->imageDepth, pPriv->imageFormat, 0, (char *)pPriv->pBuffer, pSrcImage->width, pSrcImage->height, pSrcImage->pFormat->rowBitAlign, (pPriv->isLongImage) ? (pSrcImage->width * 4) : pSrcImage->plane[0].nBytesPerRow); if (!pXImage) return IL_ERROR_MALLOC; /* EXIT */ /* Set bit/byte order to MSBFirst. NOTE: byte order should be set to byte order of client machine!!! */ #ifdef LSB_BIT_ORDER pXImage->byte_order = LSBFirst; #else pXImage->byte_order = MSBFirst; #endif pXImage->bitmap_bit_order = MSBFirst; pPriv->pXImage = pXImage; pPriv->linesDone = 0; return IL_OK; } /* --------------------- ilWriteXCleanup -------------------------- */ /* Cleanup() function for ilWriteXDrawable() for all src image types. Flushes the output if not aborted; frees the XImage created by Init() below. */ static ilError ilWriteXCleanup ( ilPtr pPrivate, ilBool aborting ) { /* Flush if not aborting. Null the "data" field in image or else XDestroyImage() will try to free the pixels; destroy the image, created by Init(). */ ilXPrivPtr pPriv = (ilXPrivPtr)pPrivate; if (!aborting) XFlush (pPriv->pXWC->i.display); if (pPriv->pBuffer) IL_FREE (pPriv->pBuffer); pPriv->pXImage->data = (char *)NULL; XDestroyImage (pPriv->pXImage); return IL_OK; } /* --------------------- ilWriteXExecute ------------------------- */ /* Execute() function for ilWriteXDrawable(), for rendering bit or byte data. Points an XImage created by ilWriteXInit() to the src image bits and does an XPutImage(), then bumps a line count so next strip is written *pNLines below this one in the drawable. */ static ilError ilWriteXExecute ( ilExecuteData *pData, long dstLine, long *pNLines, float ratio ) { ilXPrivPtr pPriv; XImage *pXImage; ilXWCPtr pXWC; unsigned int nSrcLines; unsigned int scaledWidth,scaledHeight; int scaledX, scaledY; pPriv = (ilXPrivPtr)pData->pPrivate; nSrcLines = *pNLines; pXImage = pPriv->pXImage; pXImage->height = nSrcLines; pXImage->data = (char *)(pData->pSrcImage->plane[0].pPixels + pData->srcLine * pData->pSrcImage->plane[0].nBytesPerRow); pXWC = pPriv->pXWC; scaledWidth = pXImage->width * ratio + 0.5; scaledX = pPriv->x * ratio + 0.5; scaledY = (pPriv->y + pPriv->linesDone) * ratio + 0.5; /* we have to think about rounding problem, so recalculate every time. */ scaledHeight = ((nSrcLines + pPriv->linesDone) * ratio + 0.5) - scaledY; _XmPutScaledImage (pXWC->i.display, pPriv->drawable, pXWC->i.gc, pXImage, 0, 0, scaledX, scaledY, pXImage->width, nSrcLines, scaledWidth,scaledHeight); pPriv->linesDone += nSrcLines; return IL_OK; } /* ------------------- ilWriteXOptLongExecute --------------------- */ /* Execute() function for ilWriteXDrawable(), for display to optimal 4 bytes pixel frame buffers. "Optimal" means the 4 bytes (CARD32) = " <8 R> <8 G> <8 B>", which is the format most commonly used right now. Reformat the pipe image pixels, which are 3byte pixel RGB (as required by pXWC->format), into 4 bytes words and do the XPutImage(), then bump linesDone. */ static ilError ilWriteXOptLongExecute ( ilExecuteData *pData, long dstLine, long *pNLines, float ratio ) { ilXPrivPtr pPriv; ilImageInfo *pSrcImage; XImage *pXImage; ilXWCPtr pXWC; ilPtr pSrcLine; long srcRowBytes, width, nSrcLines, nLinesM1; long nLongsM1; ilPtr pSrc; CARD32 *pDst, temp; unsigned int scaledWidth,scaledHeight; int scaledX, scaledY ; nSrcLines = *pNLines; if (nSrcLines <= 0) return 0; /* no lines, EXIT */ pPriv = (ilXPrivPtr)pData->pPrivate; pSrcImage = pData->pSrcImage; width = pSrcImage->width; if (width <= 0) return 0; /* no width, EXIT */ srcRowBytes = pSrcImage->plane[0].nBytesPerRow; pSrcLine = (ilPtr)(pSrcImage->plane[0].pPixels + pData->srcLine * srcRowBytes); pXImage = pPriv->pXImage; pXImage->height = nSrcLines; pXImage->data = (char *)pPriv->pBuffer; pDst = (CARD32 *)pPriv->pBuffer; /* pSrcLine points to first line of pipe image; pDst to buffer of X image. Convert 3 byte pipe image to CARD32 X buffer image. Dont need dstRowBytes because buffer is exactly "width" longs wide (we created it.) */ nLinesM1 = nSrcLines - 1; do { pSrc = pSrcLine; pSrcLine += srcRowBytes; nLongsM1 = width - 1; do { temp = *pSrc++; temp <<= 8; temp |= *pSrc++; temp <<= 8; temp |= *pSrc++; *pDst++ = temp; } while (--nLongsM1 >= 0); } while (--nLinesM1 >= 0); pXWC = pPriv->pXWC; scaledWidth = pXImage->width * ratio; scaledHeight = nSrcLines * ratio; scaledX = pPriv->x * ratio ; scaledY = (pPriv->y + pPriv->linesDone)* ratio ; _XmPutScaledImage (pXWC->i.display, pPriv->drawable, pXWC->i.gc, pXImage, 0, 0, scaledX, scaledY, pXImage->width, nSrcLines, scaledWidth,scaledHeight); pPriv->linesDone += nSrcLines; return IL_OK; } /* ------------------------ ilConvertForXWrite -------------------- */ /* Public function; see spec. Side effect: set pXWC->i.writeType, code for how it will render. */ ilBool ilConvertForXWrite ( ilPipe pipe, ilXWC XWC, ilBool mapPixels, unsigned long mustBeZero, void *mustBeNull ) { ilPipeInfo info; ilImageDes des; ilImageFormat format; unsigned int writeType; ilXWCPtr pXWC; /* Table indexed by [dst visual type], yielding writeType when in raw mode */ static unsigned int rawWriteMethodTable [(IL_X_MAX_VISUAL_TYPE + 1)] = { IL_XWC_WRITE_BITONAL, /* IL_XWC_BITONAL */ IL_XWC_WRITE_GRAY, /* IL_XWC_GRAY_8 */ IL_XWC_WRITE_COLOR_DITHER, /* IL_XWC_COLOR_8 */ IL_XWC_WRITE_COLOR /* IL_XWC_COLOR_24 */ }; /* Table indexed by [image type, dst visual type], yielding writeType, assuming best case: colors/grays alloc'd successfully; else writeType degrades. */ static unsigned int writeTypeTable [(IL_MAX_TYPE + 1) * (IL_X_MAX_VISUAL_TYPE + 1)] = { /* (src) image type (dst) visual type writeType */ /* IL_BITONAL IL_XWC_BITONAL */ IL_XWC_WRITE_BITONAL, /* IL_XWC_GRAY_8 */ IL_XWC_WRITE_BITONAL, /* IL_XWC_COLOR_8 */ IL_XWC_WRITE_BITONAL, /* IL_XWC_COLOR_24 */ IL_XWC_WRITE_BITONAL, /* IL_GRAY IL_XWC_BITONAL */ IL_XWC_WRITE_BITONAL, /* IL_XWC_GRAY_8 */ IL_XWC_WRITE_GRAY, /* IL_XWC_COLOR_8 */ IL_XWC_WRITE_GRAY, /* IL_XWC_COLOR_24 */ IL_XWC_WRITE_COLOR, /* IL_PALETTE IL_XWC_BITONAL */ IL_XWC_WRITE_BITONAL, /* IL_XWC_GRAY_8 */ IL_XWC_WRITE_GRAY, /* IL_XWC_COLOR_8 */ IL_XWC_WRITE_COLOR_DITHER, /* IL_XWC_COLOR_24 */ IL_XWC_WRITE_COLOR, /* IL_RGB IL_XWC_BITONAL */ IL_XWC_WRITE_BITONAL, /* IL_XWC_GRAY_8 */ IL_XWC_WRITE_GRAY, /* IL_XWC_COLOR_8 */ IL_XWC_WRITE_COLOR_DITHER, /* IL_XWC_COLOR_24 */ IL_XWC_WRITE_COLOR, /* IL_YCBCR IL_XWC_BITONAL */ IL_XWC_WRITE_BITONAL, /* IL_XWC_GRAY_8 */ IL_XWC_WRITE_GRAY, /* IL_XWC_COLOR_8 */ IL_XWC_WRITE_COLOR_DITHER, /* IL_XWC_COLOR_24 */ IL_XWC_WRITE_COLOR }; if (pipe->objectType != IL_PIPE) { pipe->context->error = IL_ERROR_OBJECT_TYPE; return FALSE; } if (mustBeZero || mustBeNull) return ilDeclarePipeInvalid (pipe, IL_ERROR_PAR_NOT_ZERO); /* Validate that given XWC is one, and is same context as pipe. */ pXWC = (ilXWCPtr)XWC; if (pXWC->o.p.objectType != IL_XWC) return ilDeclarePipeInvalid (pipe, IL_ERROR_OBJECT_TYPE); if (pXWC->o.p.context != pipe->context) return ilDeclarePipeInvalid (pipe, IL_ERROR_CONTEXT_MISMATCH); /* Get pipe info and decompress; if pipe not in IL_PIPE_FORMING state, error. */ if (ilGetPipeInfo (pipe, TRUE, &info, &des, &format) != IL_PIPE_FORMING) { if (!pipe->context->error) ilDeclarePipeInvalid (pipe, IL_ERROR_PIPE_STATE); return FALSE; } /* If raw mode, allocate no colors, output based on dst visual type, except for bit/pixel images: output using bitonal approach; else: get "writeType" based on des.type (private types not supported) and pXWC->i.visualType. Check for allocated dither colors (default to gray if not enough) and grays (default to bitonal if not enough). Pretend YCbCr is RGB - an ilConvert() to RGB will be done below anyway. */ if (pXWC->i.rawMode) { if ((des.nSamplesPerPixel == 1) && (format.nBitsPerSample[0] == 1)) writeType = IL_XWC_WRITE_BITONAL; else writeType = rawWriteMethodTable [pXWC->i.visualType]; } else { if (des.type > IL_MAX_TYPE) return ilDeclarePipeInvalid (pipe, IL_ERROR_IMAGE_TYPE); if (des.type == IL_YCBCR) des.type = IL_RGB; writeType = writeTypeTable [des.type * (IL_X_MAX_VISUAL_TYPE + 1) + pXWC->i.visualType]; if (writeType == IL_XWC_WRITE_COLOR_DITHER) { if (!pXWC->colorMapImage) ilChangeXWC ((ilXWC)pXWC, IL_XWC_ALLOC_DITHER_COLORS, (ilPtr)NULL); if (!pXWC->colorMapImage) writeType = IL_XWC_WRITE_GRAY; } if (writeType == IL_XWC_WRITE_GRAY) { if (!pXWC->grayMapImage) ilChangeXWC ((ilXWC)pXWC, IL_XWC_ALLOC_GRAYS, (ilPtr)NULL); if (!pXWC->grayMapImage) writeType = IL_XWC_WRITE_BITONAL; } /* If RGB display alloc colors or dflt to bitonal. */ if (writeType == IL_XWC_WRITE_COLOR) { if (!pXWC->colorMapImage) if (!ilAllocateXDirectColors (pXWC, 256)) writeType = IL_XWC_WRITE_BITONAL; } } /* END not raw mode */ /* Do ilConvert() and add filter(s) based on "writeType". */ switch (writeType) { /* Bitonal: do an XPutImage() with XYBitmap, which renders image 0's with GC background color, 1's with foreground, as defined by IL spec. If rawMode, must be bit/pixel. */ case IL_XWC_WRITE_BITONAL: if (pXWC->i.rawMode) { if ((des.nSamplesPerPixel != 1) || (format.nBitsPerSample[0] != 1)) return ilDeclarePipeInvalid (pipe, IL_ERROR_RAW_MODE); } else if (!ilConvert (pipe, IL_DES_BITONAL, IL_FORMAT_BIT, 0, NULL)) return FALSE; break; /* Gray: do ilMap() which maps 256 gray shades to the equivalent X pixel values, possibly using fewer shades of gray (slam; not dithered to lesser # grays). */ case IL_XWC_WRITE_GRAY: if (pXWC->i.rawMode) { if ((des.nSamplesPerPixel != 1) || (format.nBitsPerSample[0] != 8)) return ilDeclarePipeInvalid (pipe, IL_ERROR_RAW_MODE); } else { if (!ilConvert (pipe, IL_DES_GRAY, IL_FORMAT_BYTE, 0, NULL)) return FALSE; if (mapPixels) if (!ilMap (pipe, pXWC->grayMapImage)) return FALSE; } break; /* Dithered RGB: if raw mode, accept if byte/pixel; if a pre-dithered palette image in pipe, ilMap() to map colors to X pixels; otherwise dither cvt to palette w/ map to the allocated colors. */ case IL_XWC_WRITE_COLOR_DITHER: if (pXWC->i.rawMode) { if ((des.nSamplesPerPixel != 1) || (format.nBitsPerSample[0] != 8)) return ilDeclarePipeInvalid (pipe, IL_ERROR_RAW_MODE); } else if ((des.flags & IL_DITHERED_PALETTE) && (des.typeInfo.palette.levels[0] == NRED) && (des.typeInfo.palette.levels[1] == NGREEN) && (des.typeInfo.palette.levels[2] == NBLUE)) { if ((format.nBitsPerSample[0] != 8) && !ilConvert (pipe, (ilImageDes *)NULL, IL_FORMAT_BYTE, 0, NULL)) return FALSE; if (mapPixels) if (!ilMap (pipe, pXWC->colorMapImage)) return FALSE; } else { ilConvertToPaletteInfo cvt; cvt.method = pXWC->i.ditherMethod; cvt.levels[0] = NRED; cvt.levels[1] = NGREEN; cvt.levels[2] = NBLUE; cvt.kernelSize = 8; if (mapPixels) { cvt.dstType = IL_GRAY; /* any type other than IL_PALETTE */ cvt.mapImage = pXWC->colorMapImage; } else { cvt.dstType = IL_PALETTE; cvt.mapImage = (ilClientImage)NULL; } if (!ilConvert (pipe, IL_DES_PALETTE, IL_FORMAT_BYTE, IL_CONVERT_TO_PALETTE, &cvt)) return FALSE; } break; /* RGB: if raw mode, check format, else convert to RGB, and if mapPixels and map needed (ramp not 0..255 each component) do an ilMap(). */ case IL_XWC_WRITE_COLOR: { if (pXWC->i.rawMode) { if ((des.nSamplesPerPixel != 3) || (format.nBitsPerSample[0] != 8) || (format.nBitsPerSample[1] != 8) || (format.nBitsPerSample[2] != 8) || (format.sampleOrder != IL_SAMPLE_PIXELS)) return ilDeclarePipeInvalid (pipe, IL_ERROR_RAW_MODE); } else { if (!ilConvert (pipe, IL_DES_RGB, IL_FORMAT_3BYTE_PIXEL, 0, NULL)) return FALSE; if (mapPixels && pXWC->mapDirect) if (!ilMap (pipe, pXWC->colorMapImage)) return FALSE; } } break; } /* END switch writeType */ pXWC->i.writeType = writeType; /* set method of writing to be used */ pipe->context->error = IL_OK; return TRUE; } /* ------------------------ ilWriteXDrawable ---------------------- */ /* Public function; see spec. */ ilBool ilWriteXDrawable ( ilPipe pipe, Drawable drawable, ilXWC XWC, ilRect *pSrcRect, int dstX, int dstY, unsigned long mustBeZero ) { ilPipeInfo info; ilXWCPtr pXWC; ilXPrivPtr pPriv; ilSrcElementData *pSrcData, srcData; unsigned long bufferSize = 0; /* ** We need to use the execute fucntion with the ratio parameter. */ ilError (*executeFunction)( ilExecuteData *, long, long *, float); /* If a src clip rect, insert an ilCrop() element before us. In the future, should look at pipe and handle some cases directly. */ if (pSrcRect && !ilCrop (pipe, pSrcRect)) return FALSE; /* Convert as necessary, mapping pixels to X pixels and get pXWC->i.writeType */ pXWC = (ilXWCPtr)XWC; if (!ilConvertForXWrite (pipe, (ilXWC)pXWC, TRUE, 0, NULL)) return FALSE; ilGetPipeInfo (pipe, FALSE, &info, (ilImageDes *)NULL, (ilImageFormat *)NULL); /* If writing 24 bits: use separate executeFunction, set "bufferSize" to buffer to be allocated, and if too large force pipe to give us smaller strips. */ if (pXWC->i.writeType == IL_XWC_WRITE_COLOR) { bufferSize = (info.width * 4) * info.stripHeight; if (bufferSize > MAX_IMAGE_BUFFER_SIZE) { srcData.consumerImage = (ilObject)NULL; srcData.stripHeight = BEST_IMAGE_BUFFER_SIZE / (4 * info.width); if (srcData.stripHeight < 1) srcData.stripHeight = 1; srcData.constantStrip = FALSE; srcData.minBufferHeight = 0; pSrcData = &srcData; } else pSrcData = (ilSrcElementData *)NULL; executeFunction = ilWriteXOptLongExecute; } else { pSrcData = (ilSrcElementData *)NULL; executeFunction = ilWriteXExecute; } /* Add a consumer which does an XPutImage() using the pipe data cvt'd above. Increment the XWC refCount; element's Destroy() function ilXDestroy() will decrement it when this pipe element is removed. */ pPriv = (ilXPrivPtr)ilAddPipeElement (pipe, IL_CONSUMER, sizeof(ilXPrivRec), 0, pSrcData, (ilDstElementData *)NULL, ilWriteXInit, ilWriteXCleanup, ilXDestroy, NULL, executeFunction, 0); if (!pPriv) return FALSE; /* EXIT */ pPriv->pXWC = pXWC; pPriv->drawable = drawable; pPriv->x = dstX; pPriv->y = dstY; pXWC->o.refCount++; /* Set writeType-specific values in *pPriv */ switch (pXWC->i.writeType) { case IL_XWC_WRITE_BITONAL: pPriv->imageDepth = 1; pPriv->imageFormat = XYBitmap; pPriv->isLongImage = FALSE; pPriv->bufferSize = 0; break; case IL_XWC_WRITE_GRAY: pPriv->imageDepth = 8; pPriv->imageFormat = ZPixmap; pPriv->isLongImage = FALSE; pPriv->bufferSize = 0; break; case IL_XWC_WRITE_COLOR_DITHER: pPriv->imageDepth = 8; pPriv->imageFormat = ZPixmap; pPriv->isLongImage = FALSE; pPriv->bufferSize = 0; break; case IL_XWC_WRITE_COLOR: pPriv->bufferSize = bufferSize; /* from above */ pPriv->imageDepth = 24; pPriv->imageFormat = ZPixmap; pPriv->isLongImage = TRUE; break; } pipe->context->error = IL_OK; return TRUE; }