1 /* $XConsortium: ilwriteimage.c /main/4 1996/01/08 12:17:24 lehors $ */
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 "ilpipelem.h"
22 #include "ilutiljpeg.h"
25 /* Private data for Read/WriteImage pipe functions. */
27 ilImagePtr pImage; /* ptr to image read/written */
28 unsigned short *pPalette; /* ptr to palette or null if not palette image */
29 ilPtr pCompData; /* ptr to comp data or null if none */
30 long nLinesWritten; /* Init(): # of lines written so far */
32 /* Remaining fields used only for compressed images */
33 long nStripsWritten; /* Init(): # of strips written to image */
34 } ilImagePrivRec, *ilImagePrivPtr;
37 /* ------------------------- ilWriteImageInit ----------------------------------- */
38 /* Init() function for ilWriteImage().
40 static ilError ilWriteImageInit (
42 ilImageInfo *pSrcImage,
43 ilImageInfo *pDstImage
46 pPriv->nStripsWritten = 0;
47 pPriv->nLinesWritten = 0;
52 /* ------------------------ ilWriteImageDestroy ------------------------------ */
53 /* Destroy() function for ilWriteImage(). Calls ilDestroyObject() with
54 element's pObject, which should point to the image. The image's refCount
55 is inc'd when pipe element added. ilDestroyObject() will dec it and free
56 the image if the refCount is 0. Using refCount this way prevents the user
57 from destroying an image still attached to a pipe.
59 static ilError ilWriteImageDestroy (
63 ilDestroyObject ((ilObject)pPriv->pImage);
68 /* ============================ WRITE COMPRESSED CODE ============================= */
70 /* ------------------------ ilWriteCompressedCleanup ------------------------- */
71 /* Cleanup() function for ilWriteImage(), writing compressed images.
73 static ilError ilWriteCompressedCleanup (
78 register ilImagePlaneInfo *pImagePlane;
79 register ilImagePtr pImage;
82 pImage = pPriv->pImage;
83 pImagePlane = &pImage->i.plane[0];
85 /* If # of strips written by pipe is not equal to # of strips in image, error */
86 if (!aborting && (pPriv->nStripsWritten != pImage->nStrips)) {
87 aborting = TRUE; /* take error path below */
88 error = IL_ERROR_MALFORMED_IMAGE_WRITE;
92 /* If aborting, free up pixels if they dont belong to client */
94 if (!pImage->i.clientPixels && pImagePlane->pPixels) {
95 IL_FREE (pImagePlane->pPixels);
96 pImagePlane->pPixels = (ilPtr)NULL;
97 pImagePlane->bufferSize = 0;
101 /* Success: realloc (shrink) the image down to the written size (offset to
102 strip past last strip), to free up extra unused-but-allocated space.
104 pImagePlane->bufferSize = pImage->pStripOffsets[pImage->nStrips];
105 if (pImagePlane->pPixels)
106 pImagePlane->pPixels = (ilPtr)IL_REALLOC (pImagePlane->pPixels,
107 pImagePlane->bufferSize);
114 /* ------------------------ ilWriteCompressedExecute ------------------------- */
115 /* Execute() function for ilWriteImage(), writing compressed images.
117 static ilError ilWriteCompressedExecute (
118 register ilExecuteData *pData,
123 register ilImagePrivPtr pPriv;
124 register ilImagePtr pImage;
126 pPriv = (ilImagePrivPtr)pData->pPrivate;
127 pImage = pPriv->pImage;
129 /* If first strip: copy non-null pipe palette (pPriv->pPalette) and comp data
130 (NOTE: assumed to be JPEG!), after freeing old tables, to the image.
132 if (pData->srcLine <= 0) {
134 bcopy ((char *)pPriv->pPalette, (char *)pPriv->pImage->i.pPalette,
135 sizeof (unsigned short) * (3 * 256));
136 if (pPriv->pCompData) {
137 _ilJPEGFreeTables ((ilJPEGData *)pPriv->pImage->i.pCompData);
138 if (!_ilJPEGCopyData ((ilJPEGData *)pPriv->pCompData,
139 (ilJPEGData *)pPriv->pImage->i.pCompData))
140 return IL_ERROR_MALLOC;
144 /* Bump srcLine (index to next line); if > # lines in image, error */
145 pData->srcLine += *pNLines;
146 if (pData->srcLine > pImage->i.height)
147 return IL_ERROR_MALFORMED_IMAGE_WRITE;
149 /* If # lines written != strip size and not last strip, inconstant strips */
150 if ((*pNLines != pImage->stripHeight) && (pData->srcLine != pImage->i.height))
151 return IL_ERROR_MALFORMED_IMAGE_WRITE;
153 /* Store offset to this and next strip; bump offset for next write */
154 pImage->pStripOffsets[pPriv->nStripsWritten++] = pData->compressed.srcOffset;
155 pData->compressed.srcOffset += pData->compressed.nBytesToRead;
156 pImage->pStripOffsets[pPriv->nStripsWritten] = pData->compressed.srcOffset;
162 /* -------------------- ilWriteCompressedImage -------------------- */
163 /* Called by ilWriteImage() to add a consumer to "pipe" which writes compressed
164 data to the given "image". "pipe" and "image" are guaranteed to be the correct
165 object types and to belong to the same context. The pipe is guaranteed to
166 be in the correct state (IL_PIPE_FORMING) and "image" is guaranteed to be the
167 correct size (size of the pipe image).
169 static ilBool ilWriteCompressedImage (
174 register ilImagePtr pImage;
177 ilImageFormat format;
179 register ilImagePrivPtr pPriv;
180 ilSrcElementData srcData;
184 /* Get pipe info, dont force decompression (yet). */
185 ilGetPipeInfo (pipe, FALSE, &info, &des, &format);
187 /* Convert (and decompress) as necessary to dest image des */
188 pImage = (ilImagePtr)image;
190 if ((des.type != pImage->des.type)
191 || (des.blackIsZero != pImage->des.blackIsZero)
192 || (des.nSamplesPerPixel != pImage->des.nSamplesPerPixel))
196 for (plane = 0; plane < des.nSamplesPerPixel; plane++)
197 if ((des.nLevelsPerSample[plane] != pImage->des.nLevelsPerSample[plane])
198 || (format.nBitsPerSample[plane] != pImage->format.nBitsPerSample[plane])) {
205 tempDes = *pImage->i.pDes;
206 tempDes.compression = IL_UNCOMPRESSED; /* ilConvert() error otherwise */
207 if (!ilConvert (pipe, &tempDes, (ilImageFormat *)NULL, 0, (ilPtr)NULL))
209 des.compression = IL_UNCOMPRESSED; /* force recompress below */
212 /* Compress to compression type of image, including type-specific (G3/JPEG)
213 compression data. Compress to image's strip height if is established
214 (pStripOffsets non-null), else set "stripHeight" to 0 and use default.
216 if (pImage->des.compression == IL_G3)
217 pCompData = (ilPtr)&pImage->des.compInfo.g3.flags;
218 else if (pImage->des.compression == IL_G4)
219 pCompData = (ilPtr)&pImage->des.compInfo.g4.flags;
220 else if (pImage->des.compression == IL_JPEG)
221 pCompData = (ilPtr)&pImage->des.compInfo.JPEG;
222 else pCompData = (ilPtr)NULL;
224 stripHeight = (pImage->pStripOffsets) ? pImage->stripHeight : 0;
225 if (!ilCompress (pipe, pImage->des.compression, pCompData, stripHeight, 0))
227 ilGetPipeInfo (pipe, FALSE, &info, (ilImageDes *)NULL, (ilImageFormat *)NULL);
229 /* If image does not yet have a strip height, set it to pipe's strip height */
231 if (!_ilAllocStripOffsets (pImage, info.stripHeight))
232 return ilDeclarePipeInvalid (pipe, pipe->context->error);
234 /* Add a consumer to write to the image - merely bumps offsets. */
235 srcData.consumerImage = (ilObject)pImage;
236 srcData.stripHeight = 0;
237 srcData.constantStrip = FALSE;
238 srcData.minBufferHeight = 0;
239 pPriv = (ilImagePrivPtr)ilAddPipeElement(pipe, IL_CONSUMER, sizeof(ilImagePrivRec), 0,
240 &srcData, (ilDstElementData *)NULL, ilWriteImageInit, ilWriteCompressedCleanup,
241 ilWriteImageDestroy, ilWriteCompressedExecute, 0);
245 pPriv->pImage = pImage;
246 pPriv->pPalette = (pImage->des.type == IL_PALETTE) ? info.pPalette :
247 (unsigned short *)NULL;
249 /* NOTE: assumes JPEG pCompData! Point to pipe comp data if raw JPEG */
250 if ((pImage->des.compression == IL_JPEG)
251 && (pImage->des.compInfo.JPEG.reserved & IL_JPEGM_RAW))
252 pPriv->pCompData = info.pCompData;
253 else pPriv->pCompData = (ilPtr)NULL;
255 pImage->o.refCount++; /* see ilWriteImageDestroy() */
257 pipe->context->error = IL_OK;
263 /* ============================ WRITE UNCOMPRESSED CODE ============================= */
266 /* --------------------- ilWriteImageExecute -------------------------------- */
267 /* Execute() for WriteImage(): merely bumps srcLine by # lines written.
269 static ilError ilWriteImageExecute (
270 register ilExecuteData *pData,
275 ilImagePrivPtr pPriv;
277 pPriv = (ilImagePrivPtr)pData->pPrivate;
279 /* If first strip, copy pipe palette (pPriv->pPalette) to the image palette. */
280 if ((pData->srcLine <= 0) && pPriv->pPalette) {
281 bcopy ((char *)pPriv->pPalette, (char *)pPriv->pImage->i.pPalette,
282 sizeof (unsigned short) * (3 * 256));
285 /* Bump srcLine (index to next line); if > # lines in image, error */
286 pData->srcLine += *pNLines;
287 if (pData->srcLine > pPriv->pImage->i.height)
288 return IL_ERROR_MALFORMED_IMAGE_WRITE;
294 /* ------------------------ ilWriteImage ---------------------------------- */
295 /* Public function: see spec.
296 Adds the given image as a producer of the pipe.
298 ilBool ilWriteImage (
303 register ilImagePtr pImage;
304 register ilImagePrivPtr pPriv;
305 register ilContext context;
307 ilSrcElementData srcData;
309 /* Validate that pipe and image are such, and that they have the same context. */
310 pImage = (ilImagePtr)image;
311 context = pipe->context;
312 if (pipe->objectType != IL_PIPE) {
313 context->error = IL_ERROR_OBJECT_TYPE;
317 if ((pImage->o.p.objectType != IL_INTERNAL_IMAGE)
318 && (pImage->o.p.objectType != IL_CLIENT_IMAGE))
319 return ilDeclarePipeInvalid (pipe, IL_ERROR_OBJECT_TYPE);
321 if (pImage->o.p.context != context)
322 return ilDeclarePipeInvalid (pipe, IL_ERROR_CONTEXT_MISMATCH);
324 /* Get pipe info; if pipe not in IL_PIPE_FORMING state: error.
325 If producerObject is the given image, error: cant read/write same image.
327 if (ilGetPipeInfo (pipe, FALSE, &info,
328 (ilImageDes *)NULL, (ilImageFormat *)NULL) != IL_PIPE_FORMING) {
330 ilDeclarePipeInvalid (pipe, IL_ERROR_PIPE_STATE);
333 if (info.producerObject == (ilObject)pImage)
334 return ilDeclarePipeInvalid (pipe, IL_ERROR_CIRCULAR_PIPE);
336 /* Validate pipe image. width, height and descriptor must be the same. */
337 if ((info.width != pImage->i.width) || (info.height != pImage->i.height))
338 return ilDeclarePipeInvalid (pipe, IL_ERROR_IMAGE_SIZE);
340 /* If a writing to a compressed image, call separate function and exit. */
341 if (pImage->des.compression != IL_UNCOMPRESSED)
342 return ilWriteCompressedImage (pipe, image); /* EXIT */
344 /* Convert des and/or format if not same as the images format; exit if error. */
345 if (!ilConvert (pipe, pImage->i.pDes, pImage->i.pFormat, 0, NULL))
347 ilGetPipeInfo (pipe, TRUE, &info, (ilImageDes *)NULL, (ilImageFormat *)NULL);
349 /* Add a consumer element which writes to the given image.
350 If writing a palette image, supply an Init() function to copy the palette.
352 srcData.consumerImage = (ilObject)pImage;
353 srcData.stripHeight = 0;
354 srcData.constantStrip = FALSE;
355 srcData.minBufferHeight = 0;
356 pPriv = (ilImagePrivPtr)ilAddPipeElement (pipe, IL_CONSUMER, sizeof (ilImagePrivRec),
357 0, &srcData, (ilDstElementData *)NULL, ilWriteImageInit, IL_NPF,
358 ilWriteImageDestroy, ilWriteImageExecute, 0);
362 /* Element succesfully added; setup private data.
363 Increment the refCount in the image; see notes for ilImageDestroy().
365 pPriv->pImage = pImage;
366 pPriv->pPalette = (pImage->des.type == IL_PALETTE) ? info.pPalette :
367 (unsigned short *)NULL;
368 pImage->o.refCount++; /* see ilWriteImageDestroy() */
370 context->error = IL_OK;