lib/DtHelp/il: remove register keyword
[oweals/cde.git] / cde / lib / DtHelp / il / ilwriteimage.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
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)
10  * any later version.
11  *
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
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these libraries and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* $XConsortium: ilwriteimage.c /main/4 1996/01/08 12:17:24 lehors $ */
24 /**---------------------------------------------------------------------
25 ***     
26 ***    (c)Copyright 1991 Hewlett-Packard Co.
27 ***    
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).
37 ***
38 ***-------------------------------------------------------------------*/
39
40 #include "ilint.h"
41 #include "ilpipelem.h"
42 #include "ilimage.h"
43 #include "ilerrors.h"
44 #include "ilutiljpeg.h"
45
46
47         /*  Private data for Read/WriteImage pipe functions. */
48 typedef struct {
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 */
53
54         /*  Remaining fields used only for compressed images  */
55     long                nStripsWritten; /* Init(): # of strips written to image */
56     } ilImagePrivRec, *ilImagePrivPtr;
57
58
59     /*  ------------------------- ilWriteImageInit ----------------------------------- */
60     /*  Init() function for ilWriteImage().
61     */
62 static ilError ilWriteImageInit (
63     ilImagePrivPtr      pPriv,
64     ilImageInfo        *pSrcImage,
65     ilImageInfo        *pDstImage
66     )
67 {
68     pPriv->nStripsWritten = 0;
69     pPriv->nLinesWritten = 0;
70     return IL_OK;
71 }
72
73
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.
80     */
81 static ilError ilWriteImageDestroy (
82     ilImagePrivPtr      pPriv
83     )
84 {
85     ilDestroyObject ((ilObject)pPriv->pImage);
86     return IL_OK;
87 }
88
89
90 /*  ============================ WRITE COMPRESSED CODE ============================= */
91
92     /*  ------------------------ ilWriteCompressedCleanup ------------------------- */
93     /*  Cleanup() function for ilWriteImage(), writing compressed images.
94     */
95 static ilError ilWriteCompressedCleanup (
96     ilImagePrivPtr      pPriv,
97     ilBool              aborting
98     )
99 {
100 ilImagePlaneInfo *pImagePlane;
101 ilImagePtr     pImage;
102 ilError                 error;
103
104     pImage = pPriv->pImage;
105     pImagePlane = &pImage->i.plane[0];
106
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;
111         }
112     else error = IL_OK;
113
114         /*  If aborting, free up pixels if they don't belong to client */
115     if (aborting) {
116         if (!pImage->i.clientPixels && pImagePlane->pPixels) {
117             IL_FREE (pImagePlane->pPixels);
118             pImagePlane->pPixels = (ilPtr)NULL;
119             pImagePlane->bufferSize = 0;
120             }
121         }
122     else {
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.  
125             */
126         pImagePlane->bufferSize = pImage->pStripOffsets[pImage->nStrips];
127         if (pImagePlane->pPixels) 
128             pImagePlane->pPixels = (ilPtr)IL_REALLOC (pImagePlane->pPixels, 
129                                                       pImagePlane->bufferSize);
130         }
131
132     return error;
133 }
134
135
136     /*  ------------------------ ilWriteCompressedExecute ------------------------- */
137     /*  Execute() function for ilWriteImage(), writing compressed images.
138     */
139 static ilError ilWriteCompressedExecute (
140     ilExecuteData  *pData,
141     long                dstLine,
142     long               *pNLines
143     )
144 {
145 ilImagePrivPtr pPriv;
146 ilImagePtr     pImage;
147
148     pPriv = (ilImagePrivPtr)pData->pPrivate;
149     pImage = pPriv->pImage;
150
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.
153         */
154     if (pData->srcLine <= 0) {
155         if (pPriv->pPalette)
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;
163             }
164         }
165
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;
170
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;
174
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;
179
180     return IL_OK;
181 }
182
183
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).
190     */
191 static ilBool ilWriteCompressedImage (
192     ilPipe              pipe,
193     ilObject            image
194     )
195 {
196 ilImagePtr     pImage;
197 ilPipeInfo              info;                              
198 ilImageDes              des;
199 ilImageFormat           format;
200 ilBool                  mustConvert;
201 ilImagePrivPtr pPriv;
202 ilSrcElementData        srcData;
203 long                    stripHeight;
204 ilPtr                   pCompData;
205
206         /* Get pipe info, don't force decompression (yet). */
207     ilGetPipeInfo (pipe, FALSE, &info, &des, &format);
208
209         /*  Convert (and decompress) as necessary to dest image des */
210     pImage = (ilImagePtr)image;
211     mustConvert = FALSE;
212     if ((des.type != pImage->des.type)
213      || (des.blackIsZero != pImage->des.blackIsZero)
214      || (des.nSamplesPerPixel != pImage->des.nSamplesPerPixel))
215         mustConvert = TRUE;
216     else {
217         int     plane;
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])) {
221                 mustConvert = TRUE;
222                 break;
223                 }
224         }
225     if (mustConvert) {
226         ilImageDes      tempDes;
227         tempDes = *pImage->i.pDes;
228         tempDes.compression = IL_UNCOMPRESSED;      /* ilConvert() error otherwise */
229         if (!ilConvert (pipe, &tempDes, (ilImageFormat *)NULL, 0, (ilPtr)NULL))
230             return FALSE;
231         des.compression = IL_UNCOMPRESSED;          /* force recompress below */
232         }
233
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.
237         */
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;
245
246     stripHeight = (pImage->pStripOffsets) ? pImage->stripHeight : 0;
247     if (!ilCompress (pipe, pImage->des.compression, pCompData, stripHeight, 0))
248         return FALSE;
249     ilGetPipeInfo (pipe, FALSE, &info, (ilImageDes *)NULL, (ilImageFormat *)NULL);                    
250
251         /*  If image does not yet have a strip height, set it to pipe's strip height */
252     if (!stripHeight)
253         if (!_ilAllocStripOffsets (pImage, info.stripHeight))
254             return ilDeclarePipeInvalid (pipe, pipe->context->error);
255
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);
264     if (!pPriv)
265         return FALSE;
266
267     pPriv->pImage = pImage;
268     pPriv->pPalette = (pImage->des.type == IL_PALETTE) ? info.pPalette : 
269                                                          (unsigned short *)NULL;
270
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;
276
277     pImage->o.refCount++;               /* see ilWriteImageDestroy() */
278
279     pipe->context->error = IL_OK;
280     return TRUE;
281 }
282
283
284
285 /*  ============================ WRITE UNCOMPRESSED CODE ============================= */
286
287
288         /*  --------------------- ilWriteImageExecute -------------------------------- */
289         /*  Execute() for WriteImage(): merely bumps srcLine by # lines written.
290         */
291 static ilError ilWriteImageExecute (
292     ilExecuteData  *pData,
293     long                    dstLine,
294     long                   *pNLines
295     )
296 {
297     ilImagePrivPtr      pPriv;
298
299     pPriv = (ilImagePrivPtr)pData->pPrivate;
300
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));
305         }
306
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;
311
312     return IL_OK;
313 }
314
315
316         /*  ------------------------ ilWriteImage ---------------------------------- */
317         /*  Public function: see spec.
318             Adds the given image as a producer of the pipe.
319         */
320 ilBool ilWriteImage (
321     ilPipe              pipe,
322     ilObject            image
323     )
324 {
325 ilImagePtr     pImage;
326 ilImagePrivPtr pPriv;
327 ilContext      context;
328 ilPipeInfo              info;
329 ilSrcElementData        srcData;
330
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;
336         return;
337         }
338
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);
342
343     if (pImage->o.p.context != context)
344         return ilDeclarePipeInvalid (pipe, IL_ERROR_CONTEXT_MISMATCH);
345
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.
348         */                          
349     if (ilGetPipeInfo (pipe, FALSE, &info, 
350                       (ilImageDes *)NULL, (ilImageFormat *)NULL) != IL_PIPE_FORMING) {
351         if (!context->error)
352             ilDeclarePipeInvalid (pipe, IL_ERROR_PIPE_STATE);
353         return FALSE;
354         }
355     if (info.producerObject == (ilObject)pImage)
356         return ilDeclarePipeInvalid (pipe, IL_ERROR_CIRCULAR_PIPE);
357
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);
361
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 */
365
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))
368         return FALSE;
369     ilGetPipeInfo (pipe, TRUE, &info, (ilImageDes *)NULL, (ilImageFormat *)NULL);
370
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.
373         */
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);
381     if (!pPriv)
382         return FALSE;
383
384         /*  Element successfully added; setup private data.
385             Increment the refCount in the image; see notes for ilImageDestroy().
386         */
387     pPriv->pImage = pImage;
388     pPriv->pPalette = (pImage->des.type == IL_PALETTE) ? info.pPalette : 
389                                                          (unsigned short *)NULL;
390     pImage->o.refCount++;               /* see ilWriteImageDestroy() */
391
392     context->error = IL_OK;
393     return TRUE;
394 }
395