2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these librararies and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
23 /* $XConsortium: ilwriteimage.c /main/4 1996/01/08 12:17:24 lehors $ */
24 /**---------------------------------------------------------------------
26 *** (c)Copyright 1991 Hewlett-Packard Co.
28 *** RESTRICTED RIGHTS LEGEND
29 *** Use, duplication, or disclosure by the U.S. Government is subject to
30 *** restrictions as set forth in sub-paragraph (c)(1)(ii) of the Rights in
31 *** Technical Data and Computer Software clause in DFARS 252.227-7013.
32 *** Hewlett-Packard Company
33 *** 3000 Hanover Street
34 *** Palo Alto, CA 94304 U.S.A.
35 *** Rights for non-DOD U.S. Government Departments and Agencies are as set
36 *** forth in FAR 52.227-19(c)(1,2).
38 ***-------------------------------------------------------------------*/
41 #include "ilpipelem.h"
44 #include "ilutiljpeg.h"
47 /* Private data for Read/WriteImage pipe functions. */
49 ilImagePtr pImage; /* ptr to image read/written */
50 unsigned short *pPalette; /* ptr to palette or null if not palette image */
51 ilPtr pCompData; /* ptr to comp data or null if none */
52 long nLinesWritten; /* Init(): # of lines written so far */
54 /* Remaining fields used only for compressed images */
55 long nStripsWritten; /* Init(): # of strips written to image */
56 } ilImagePrivRec, *ilImagePrivPtr;
59 /* ------------------------- ilWriteImageInit ----------------------------------- */
60 /* Init() function for ilWriteImage().
62 static ilError ilWriteImageInit (
64 ilImageInfo *pSrcImage,
65 ilImageInfo *pDstImage
68 pPriv->nStripsWritten = 0;
69 pPriv->nLinesWritten = 0;
74 /* ------------------------ ilWriteImageDestroy ------------------------------ */
75 /* Destroy() function for ilWriteImage(). Calls ilDestroyObject() with
76 element's pObject, which should point to the image. The image's refCount
77 is inc'd when pipe element added. ilDestroyObject() will dec it and free
78 the image if the refCount is 0. Using refCount this way prevents the user
79 from destroying an image still attached to a pipe.
81 static ilError ilWriteImageDestroy (
85 ilDestroyObject ((ilObject)pPriv->pImage);
90 /* ============================ WRITE COMPRESSED CODE ============================= */
92 /* ------------------------ ilWriteCompressedCleanup ------------------------- */
93 /* Cleanup() function for ilWriteImage(), writing compressed images.
95 static ilError ilWriteCompressedCleanup (
100 register ilImagePlaneInfo *pImagePlane;
101 register ilImagePtr pImage;
104 pImage = pPriv->pImage;
105 pImagePlane = &pImage->i.plane[0];
107 /* If # of strips written by pipe is not equal to # of strips in image, error */
108 if (!aborting && (pPriv->nStripsWritten != pImage->nStrips)) {
109 aborting = TRUE; /* take error path below */
110 error = IL_ERROR_MALFORMED_IMAGE_WRITE;
114 /* If aborting, free up pixels if they dont belong to client */
116 if (!pImage->i.clientPixels && pImagePlane->pPixels) {
117 IL_FREE (pImagePlane->pPixels);
118 pImagePlane->pPixels = (ilPtr)NULL;
119 pImagePlane->bufferSize = 0;
123 /* Success: realloc (shrink) the image down to the written size (offset to
124 strip past last strip), to free up extra unused-but-allocated space.
126 pImagePlane->bufferSize = pImage->pStripOffsets[pImage->nStrips];
127 if (pImagePlane->pPixels)
128 pImagePlane->pPixels = (ilPtr)IL_REALLOC (pImagePlane->pPixels,
129 pImagePlane->bufferSize);
136 /* ------------------------ ilWriteCompressedExecute ------------------------- */
137 /* Execute() function for ilWriteImage(), writing compressed images.
139 static ilError ilWriteCompressedExecute (
140 register ilExecuteData *pData,
145 register ilImagePrivPtr pPriv;
146 register ilImagePtr pImage;
148 pPriv = (ilImagePrivPtr)pData->pPrivate;
149 pImage = pPriv->pImage;
151 /* If first strip: copy non-null pipe palette (pPriv->pPalette) and comp data
152 (NOTE: assumed to be JPEG!), after freeing old tables, to the image.
154 if (pData->srcLine <= 0) {
156 bcopy ((char *)pPriv->pPalette, (char *)pPriv->pImage->i.pPalette,
157 sizeof (unsigned short) * (3 * 256));
158 if (pPriv->pCompData) {
159 _ilJPEGFreeTables ((ilJPEGData *)pPriv->pImage->i.pCompData);
160 if (!_ilJPEGCopyData ((ilJPEGData *)pPriv->pCompData,
161 (ilJPEGData *)pPriv->pImage->i.pCompData))
162 return IL_ERROR_MALLOC;
166 /* Bump srcLine (index to next line); if > # lines in image, error */
167 pData->srcLine += *pNLines;
168 if (pData->srcLine > pImage->i.height)
169 return IL_ERROR_MALFORMED_IMAGE_WRITE;
171 /* If # lines written != strip size and not last strip, inconstant strips */
172 if ((*pNLines != pImage->stripHeight) && (pData->srcLine != pImage->i.height))
173 return IL_ERROR_MALFORMED_IMAGE_WRITE;
175 /* Store offset to this and next strip; bump offset for next write */
176 pImage->pStripOffsets[pPriv->nStripsWritten++] = pData->compressed.srcOffset;
177 pData->compressed.srcOffset += pData->compressed.nBytesToRead;
178 pImage->pStripOffsets[pPriv->nStripsWritten] = pData->compressed.srcOffset;
184 /* -------------------- ilWriteCompressedImage -------------------- */
185 /* Called by ilWriteImage() to add a consumer to "pipe" which writes compressed
186 data to the given "image". "pipe" and "image" are guaranteed to be the correct
187 object types and to belong to the same context. The pipe is guaranteed to
188 be in the correct state (IL_PIPE_FORMING) and "image" is guaranteed to be the
189 correct size (size of the pipe image).
191 static ilBool ilWriteCompressedImage (
196 register ilImagePtr pImage;
199 ilImageFormat format;
201 register ilImagePrivPtr pPriv;
202 ilSrcElementData srcData;
206 /* Get pipe info, dont force decompression (yet). */
207 ilGetPipeInfo (pipe, FALSE, &info, &des, &format);
209 /* Convert (and decompress) as necessary to dest image des */
210 pImage = (ilImagePtr)image;
212 if ((des.type != pImage->des.type)
213 || (des.blackIsZero != pImage->des.blackIsZero)
214 || (des.nSamplesPerPixel != pImage->des.nSamplesPerPixel))
218 for (plane = 0; plane < des.nSamplesPerPixel; plane++)
219 if ((des.nLevelsPerSample[plane] != pImage->des.nLevelsPerSample[plane])
220 || (format.nBitsPerSample[plane] != pImage->format.nBitsPerSample[plane])) {
227 tempDes = *pImage->i.pDes;
228 tempDes.compression = IL_UNCOMPRESSED; /* ilConvert() error otherwise */
229 if (!ilConvert (pipe, &tempDes, (ilImageFormat *)NULL, 0, (ilPtr)NULL))
231 des.compression = IL_UNCOMPRESSED; /* force recompress below */
234 /* Compress to compression type of image, including type-specific (G3/JPEG)
235 compression data. Compress to image's strip height if is established
236 (pStripOffsets non-null), else set "stripHeight" to 0 and use default.
238 if (pImage->des.compression == IL_G3)
239 pCompData = (ilPtr)&pImage->des.compInfo.g3.flags;
240 else if (pImage->des.compression == IL_G4)
241 pCompData = (ilPtr)&pImage->des.compInfo.g4.flags;
242 else if (pImage->des.compression == IL_JPEG)
243 pCompData = (ilPtr)&pImage->des.compInfo.JPEG;
244 else pCompData = (ilPtr)NULL;
246 stripHeight = (pImage->pStripOffsets) ? pImage->stripHeight : 0;
247 if (!ilCompress (pipe, pImage->des.compression, pCompData, stripHeight, 0))
249 ilGetPipeInfo (pipe, FALSE, &info, (ilImageDes *)NULL, (ilImageFormat *)NULL);
251 /* If image does not yet have a strip height, set it to pipe's strip height */
253 if (!_ilAllocStripOffsets (pImage, info.stripHeight))
254 return ilDeclarePipeInvalid (pipe, pipe->context->error);
256 /* Add a consumer to write to the image - merely bumps offsets. */
257 srcData.consumerImage = (ilObject)pImage;
258 srcData.stripHeight = 0;
259 srcData.constantStrip = FALSE;
260 srcData.minBufferHeight = 0;
261 pPriv = (ilImagePrivPtr)ilAddPipeElement(pipe, IL_CONSUMER, sizeof(ilImagePrivRec), 0,
262 &srcData, (ilDstElementData *)NULL, ilWriteImageInit, ilWriteCompressedCleanup,
263 ilWriteImageDestroy, ilWriteCompressedExecute, 0);
267 pPriv->pImage = pImage;
268 pPriv->pPalette = (pImage->des.type == IL_PALETTE) ? info.pPalette :
269 (unsigned short *)NULL;
271 /* NOTE: assumes JPEG pCompData! Point to pipe comp data if raw JPEG */
272 if ((pImage->des.compression == IL_JPEG)
273 && (pImage->des.compInfo.JPEG.reserved & IL_JPEGM_RAW))
274 pPriv->pCompData = info.pCompData;
275 else pPriv->pCompData = (ilPtr)NULL;
277 pImage->o.refCount++; /* see ilWriteImageDestroy() */
279 pipe->context->error = IL_OK;
285 /* ============================ WRITE UNCOMPRESSED CODE ============================= */
288 /* --------------------- ilWriteImageExecute -------------------------------- */
289 /* Execute() for WriteImage(): merely bumps srcLine by # lines written.
291 static ilError ilWriteImageExecute (
292 register ilExecuteData *pData,
297 ilImagePrivPtr pPriv;
299 pPriv = (ilImagePrivPtr)pData->pPrivate;
301 /* If first strip, copy pipe palette (pPriv->pPalette) to the image palette. */
302 if ((pData->srcLine <= 0) && pPriv->pPalette) {
303 bcopy ((char *)pPriv->pPalette, (char *)pPriv->pImage->i.pPalette,
304 sizeof (unsigned short) * (3 * 256));
307 /* Bump srcLine (index to next line); if > # lines in image, error */
308 pData->srcLine += *pNLines;
309 if (pData->srcLine > pPriv->pImage->i.height)
310 return IL_ERROR_MALFORMED_IMAGE_WRITE;
316 /* ------------------------ ilWriteImage ---------------------------------- */
317 /* Public function: see spec.
318 Adds the given image as a producer of the pipe.
320 ilBool ilWriteImage (
325 register ilImagePtr pImage;
326 register ilImagePrivPtr pPriv;
327 register ilContext context;
329 ilSrcElementData srcData;
331 /* Validate that pipe and image are such, and that they have the same context. */
332 pImage = (ilImagePtr)image;
333 context = pipe->context;
334 if (pipe->objectType != IL_PIPE) {
335 context->error = IL_ERROR_OBJECT_TYPE;
339 if ((pImage->o.p.objectType != IL_INTERNAL_IMAGE)
340 && (pImage->o.p.objectType != IL_CLIENT_IMAGE))
341 return ilDeclarePipeInvalid (pipe, IL_ERROR_OBJECT_TYPE);
343 if (pImage->o.p.context != context)
344 return ilDeclarePipeInvalid (pipe, IL_ERROR_CONTEXT_MISMATCH);
346 /* Get pipe info; if pipe not in IL_PIPE_FORMING state: error.
347 If producerObject is the given image, error: cant read/write same image.
349 if (ilGetPipeInfo (pipe, FALSE, &info,
350 (ilImageDes *)NULL, (ilImageFormat *)NULL) != IL_PIPE_FORMING) {
352 ilDeclarePipeInvalid (pipe, IL_ERROR_PIPE_STATE);
355 if (info.producerObject == (ilObject)pImage)
356 return ilDeclarePipeInvalid (pipe, IL_ERROR_CIRCULAR_PIPE);
358 /* Validate pipe image. width, height and descriptor must be the same. */
359 if ((info.width != pImage->i.width) || (info.height != pImage->i.height))
360 return ilDeclarePipeInvalid (pipe, IL_ERROR_IMAGE_SIZE);
362 /* If a writing to a compressed image, call separate function and exit. */
363 if (pImage->des.compression != IL_UNCOMPRESSED)
364 return ilWriteCompressedImage (pipe, image); /* EXIT */
366 /* Convert des and/or format if not same as the images format; exit if error. */
367 if (!ilConvert (pipe, pImage->i.pDes, pImage->i.pFormat, 0, NULL))
369 ilGetPipeInfo (pipe, TRUE, &info, (ilImageDes *)NULL, (ilImageFormat *)NULL);
371 /* Add a consumer element which writes to the given image.
372 If writing a palette image, supply an Init() function to copy the palette.
374 srcData.consumerImage = (ilObject)pImage;
375 srcData.stripHeight = 0;
376 srcData.constantStrip = FALSE;
377 srcData.minBufferHeight = 0;
378 pPriv = (ilImagePrivPtr)ilAddPipeElement (pipe, IL_CONSUMER, sizeof (ilImagePrivRec),
379 0, &srcData, (ilDstElementData *)NULL, ilWriteImageInit, IL_NPF,
380 ilWriteImageDestroy, ilWriteImageExecute, 0);
384 /* Element succesfully added; setup private data.
385 Increment the refCount in the image; see notes for ilImageDestroy().
387 pPriv->pImage = pImage;
388 pPriv->pPalette = (pImage->des.type == IL_PALETTE) ? info.pPalette :
389 (unsigned short *)NULL;
390 pImage->o.refCount++; /* see ilWriteImageDestroy() */
392 context->error = IL_OK;