ilwriteimage.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395
  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. #include "ilint.h"
  40. #include "ilpipelem.h"
  41. #include "ilimage.h"
  42. #include "ilerrors.h"
  43. #include "ilutiljpeg.h"
  44. /* Private data for Read/WriteImage pipe functions. */
  45. typedef struct {
  46. ilImagePtr pImage; /* ptr to image read/written */
  47. unsigned short *pPalette; /* ptr to palette or null if not palette image */
  48. ilPtr pCompData; /* ptr to comp data or null if none */
  49. long nLinesWritten; /* Init(): # of lines written so far */
  50. /* Remaining fields used only for compressed images */
  51. long nStripsWritten; /* Init(): # of strips written to image */
  52. } ilImagePrivRec, *ilImagePrivPtr;
  53. /* ------------------------- ilWriteImageInit ----------------------------------- */
  54. /* Init() function for ilWriteImage().
  55. */
  56. static ilError ilWriteImageInit (
  57. ilImagePrivPtr pPriv,
  58. ilImageInfo *pSrcImage,
  59. ilImageInfo *pDstImage
  60. )
  61. {
  62. pPriv->nStripsWritten = 0;
  63. pPriv->nLinesWritten = 0;
  64. return IL_OK;
  65. }
  66. /* ------------------------ ilWriteImageDestroy ------------------------------ */
  67. /* Destroy() function for ilWriteImage(). Calls ilDestroyObject() with
  68. element's pObject, which should point to the image. The image's refCount
  69. is inc'd when pipe element added. ilDestroyObject() will dec it and free
  70. the image if the refCount is 0. Using refCount this way prevents the user
  71. from destroying an image still attached to a pipe.
  72. */
  73. static ilError ilWriteImageDestroy (
  74. ilImagePrivPtr pPriv
  75. )
  76. {
  77. ilDestroyObject ((ilObject)pPriv->pImage);
  78. return IL_OK;
  79. }
  80. /* ============================ WRITE COMPRESSED CODE ============================= */
  81. /* ------------------------ ilWriteCompressedCleanup ------------------------- */
  82. /* Cleanup() function for ilWriteImage(), writing compressed images.
  83. */
  84. static ilError ilWriteCompressedCleanup (
  85. ilImagePrivPtr pPriv,
  86. ilBool aborting
  87. )
  88. {
  89. ilImagePlaneInfo *pImagePlane;
  90. ilImagePtr pImage;
  91. ilError error;
  92. pImage = pPriv->pImage;
  93. pImagePlane = &pImage->i.plane[0];
  94. /* If # of strips written by pipe is not equal to # of strips in image, error */
  95. if (!aborting && (pPriv->nStripsWritten != pImage->nStrips)) {
  96. aborting = TRUE; /* take error path below */
  97. error = IL_ERROR_MALFORMED_IMAGE_WRITE;
  98. }
  99. else error = IL_OK;
  100. /* If aborting, free up pixels if they don't belong to client */
  101. if (aborting) {
  102. if (!pImage->i.clientPixels && pImagePlane->pPixels) {
  103. IL_FREE (pImagePlane->pPixels);
  104. pImagePlane->pPixels = (ilPtr)NULL;
  105. pImagePlane->bufferSize = 0;
  106. }
  107. }
  108. else {
  109. /* Success: realloc (shrink) the image down to the written size (offset to
  110. strip past last strip), to free up extra unused-but-allocated space.
  111. */
  112. pImagePlane->bufferSize = pImage->pStripOffsets[pImage->nStrips];
  113. if (pImagePlane->pPixels)
  114. pImagePlane->pPixels = (ilPtr)IL_REALLOC (pImagePlane->pPixels,
  115. pImagePlane->bufferSize);
  116. }
  117. return error;
  118. }
  119. /* ------------------------ ilWriteCompressedExecute ------------------------- */
  120. /* Execute() function for ilWriteImage(), writing compressed images.
  121. */
  122. static ilError ilWriteCompressedExecute (
  123. ilExecuteData *pData,
  124. long dstLine,
  125. long *pNLines
  126. )
  127. {
  128. ilImagePrivPtr pPriv;
  129. ilImagePtr pImage;
  130. pPriv = (ilImagePrivPtr)pData->pPrivate;
  131. pImage = pPriv->pImage;
  132. /* If first strip: copy non-null pipe palette (pPriv->pPalette) and comp data
  133. (NOTE: assumed to be JPEG!), after freeing old tables, to the image.
  134. */
  135. if (pData->srcLine <= 0) {
  136. if (pPriv->pPalette)
  137. bcopy ((char *)pPriv->pPalette, (char *)pPriv->pImage->i.pPalette,
  138. sizeof (unsigned short) * (3 * 256));
  139. if (pPriv->pCompData) {
  140. _ilJPEGFreeTables ((ilJPEGData *)pPriv->pImage->i.pCompData);
  141. if (!_ilJPEGCopyData ((ilJPEGData *)pPriv->pCompData,
  142. (ilJPEGData *)pPriv->pImage->i.pCompData))
  143. return IL_ERROR_MALLOC;
  144. }
  145. }
  146. /* Bump srcLine (index to next line); if > # lines in image, error */
  147. pData->srcLine += *pNLines;
  148. if (pData->srcLine > pImage->i.height)
  149. return IL_ERROR_MALFORMED_IMAGE_WRITE;
  150. /* If # lines written != strip size and not last strip, inconstant strips */
  151. if ((*pNLines != pImage->stripHeight) && (pData->srcLine != pImage->i.height))
  152. 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;
  157. return IL_OK;
  158. }
  159. /* -------------------- ilWriteCompressedImage -------------------- */
  160. /* Called by ilWriteImage() to add a consumer to "pipe" which writes compressed
  161. data to the given "image". "pipe" and "image" are guaranteed to be the correct
  162. object types and to belong to the same context. The pipe is guaranteed to
  163. be in the correct state (IL_PIPE_FORMING) and "image" is guaranteed to be the
  164. correct size (size of the pipe image).
  165. */
  166. static ilBool ilWriteCompressedImage (
  167. ilPipe pipe,
  168. ilObject image
  169. )
  170. {
  171. ilImagePtr pImage;
  172. ilPipeInfo info;
  173. ilImageDes des;
  174. ilImageFormat format;
  175. ilBool mustConvert;
  176. ilImagePrivPtr pPriv;
  177. ilSrcElementData srcData;
  178. long stripHeight;
  179. ilPtr pCompData;
  180. /* Get pipe info, don't force decompression (yet). */
  181. ilGetPipeInfo (pipe, FALSE, &info, &des, &format);
  182. /* Convert (and decompress) as necessary to dest image des */
  183. pImage = (ilImagePtr)image;
  184. mustConvert = FALSE;
  185. if ((des.type != pImage->des.type)
  186. || (des.blackIsZero != pImage->des.blackIsZero)
  187. || (des.nSamplesPerPixel != pImage->des.nSamplesPerPixel))
  188. mustConvert = TRUE;
  189. else {
  190. int plane;
  191. for (plane = 0; plane < des.nSamplesPerPixel; plane++)
  192. if ((des.nLevelsPerSample[plane] != pImage->des.nLevelsPerSample[plane])
  193. || (format.nBitsPerSample[plane] != pImage->format.nBitsPerSample[plane])) {
  194. mustConvert = TRUE;
  195. break;
  196. }
  197. }
  198. if (mustConvert) {
  199. ilImageDes tempDes;
  200. tempDes = *pImage->i.pDes;
  201. tempDes.compression = IL_UNCOMPRESSED; /* ilConvert() error otherwise */
  202. if (!ilConvert (pipe, &tempDes, (ilImageFormat *)NULL, 0, (ilPtr)NULL))
  203. return FALSE;
  204. des.compression = IL_UNCOMPRESSED; /* force recompress below */
  205. }
  206. /* Compress to compression type of image, including type-specific (G3/JPEG)
  207. compression data. Compress to image's strip height if is established
  208. (pStripOffsets non-null), else set "stripHeight" to 0 and use default.
  209. */
  210. if (pImage->des.compression == IL_G3)
  211. pCompData = (ilPtr)&pImage->des.compInfo.g3.flags;
  212. else if (pImage->des.compression == IL_G4)
  213. pCompData = (ilPtr)&pImage->des.compInfo.g4.flags;
  214. else if (pImage->des.compression == IL_JPEG)
  215. pCompData = (ilPtr)&pImage->des.compInfo.JPEG;
  216. else pCompData = (ilPtr)NULL;
  217. stripHeight = (pImage->pStripOffsets) ? pImage->stripHeight : 0;
  218. if (!ilCompress (pipe, pImage->des.compression, pCompData, stripHeight, 0))
  219. return FALSE;
  220. ilGetPipeInfo (pipe, FALSE, &info, (ilImageDes *)NULL, (ilImageFormat *)NULL);
  221. /* If image does not yet have a strip height, set it to pipe's strip height */
  222. if (!stripHeight)
  223. if (!_ilAllocStripOffsets (pImage, info.stripHeight))
  224. return ilDeclarePipeInvalid (pipe, pipe->context->error);
  225. /* Add a consumer to write to the image - merely bumps offsets. */
  226. srcData.consumerImage = (ilObject)pImage;
  227. srcData.stripHeight = 0;
  228. srcData.constantStrip = FALSE;
  229. srcData.minBufferHeight = 0;
  230. pPriv = (ilImagePrivPtr)ilAddPipeElement(pipe, IL_CONSUMER, sizeof(ilImagePrivRec), 0,
  231. &srcData, (ilDstElementData *)NULL, ilWriteImageInit, ilWriteCompressedCleanup,
  232. ilWriteImageDestroy, ilWriteCompressedExecute, 0);
  233. if (!pPriv)
  234. return FALSE;
  235. pPriv->pImage = pImage;
  236. pPriv->pPalette = (pImage->des.type == IL_PALETTE) ? info.pPalette :
  237. (unsigned short *)NULL;
  238. /* NOTE: assumes JPEG pCompData! Point to pipe comp data if raw JPEG */
  239. if ((pImage->des.compression == IL_JPEG)
  240. && (pImage->des.compInfo.JPEG.reserved & IL_JPEGM_RAW))
  241. pPriv->pCompData = info.pCompData;
  242. else pPriv->pCompData = (ilPtr)NULL;
  243. pImage->o.refCount++; /* see ilWriteImageDestroy() */
  244. pipe->context->error = IL_OK;
  245. return TRUE;
  246. }
  247. /* ============================ WRITE UNCOMPRESSED CODE ============================= */
  248. /* --------------------- ilWriteImageExecute -------------------------------- */
  249. /* Execute() for WriteImage(): merely bumps srcLine by # lines written.
  250. */
  251. static ilError ilWriteImageExecute (
  252. ilExecuteData *pData,
  253. long dstLine,
  254. long *pNLines
  255. )
  256. {
  257. ilImagePrivPtr pPriv;
  258. pPriv = (ilImagePrivPtr)pData->pPrivate;
  259. /* If first strip, copy pipe palette (pPriv->pPalette) to the image palette. */
  260. if ((pData->srcLine <= 0) && pPriv->pPalette) {
  261. bcopy ((char *)pPriv->pPalette, (char *)pPriv->pImage->i.pPalette,
  262. sizeof (unsigned short) * (3 * 256));
  263. }
  264. /* Bump srcLine (index to next line); if > # lines in image, error */
  265. pData->srcLine += *pNLines;
  266. if (pData->srcLine > pPriv->pImage->i.height)
  267. return IL_ERROR_MALFORMED_IMAGE_WRITE;
  268. return IL_OK;
  269. }
  270. /* ------------------------ ilWriteImage ---------------------------------- */
  271. /* Public function: see spec.
  272. Adds the given image as a producer of the pipe.
  273. */
  274. ilBool ilWriteImage (
  275. ilPipe pipe,
  276. ilObject image
  277. )
  278. {
  279. ilImagePtr pImage;
  280. ilImagePrivPtr pPriv;
  281. ilContext context;
  282. ilPipeInfo info;
  283. ilSrcElementData srcData;
  284. /* Validate that pipe and image are such, and that they have the same context. */
  285. pImage = (ilImagePtr)image;
  286. context = pipe->context;
  287. if (pipe->objectType != IL_PIPE) {
  288. context->error = IL_ERROR_OBJECT_TYPE;
  289. return;
  290. }
  291. if ((pImage->o.p.objectType != IL_INTERNAL_IMAGE)
  292. && (pImage->o.p.objectType != IL_CLIENT_IMAGE))
  293. return ilDeclarePipeInvalid (pipe, IL_ERROR_OBJECT_TYPE);
  294. if (pImage->o.p.context != context)
  295. return ilDeclarePipeInvalid (pipe, IL_ERROR_CONTEXT_MISMATCH);
  296. /* Get pipe info; if pipe not in IL_PIPE_FORMING state: error.
  297. If producerObject is the given image, error: cant read/write same image.
  298. */
  299. if (ilGetPipeInfo (pipe, FALSE, &info,
  300. (ilImageDes *)NULL, (ilImageFormat *)NULL) != IL_PIPE_FORMING) {
  301. if (!context->error)
  302. ilDeclarePipeInvalid (pipe, IL_ERROR_PIPE_STATE);
  303. return FALSE;
  304. }
  305. if (info.producerObject == (ilObject)pImage)
  306. return ilDeclarePipeInvalid (pipe, IL_ERROR_CIRCULAR_PIPE);
  307. /* Validate pipe image. width, height and descriptor must be the same. */
  308. if ((info.width != pImage->i.width) || (info.height != pImage->i.height))
  309. return ilDeclarePipeInvalid (pipe, IL_ERROR_IMAGE_SIZE);
  310. /* If a writing to a compressed image, call separate function and exit. */
  311. if (pImage->des.compression != IL_UNCOMPRESSED)
  312. return ilWriteCompressedImage (pipe, image); /* EXIT */
  313. /* Convert des and/or format if not same as the images format; exit if error. */
  314. if (!ilConvert (pipe, pImage->i.pDes, pImage->i.pFormat, 0, NULL))
  315. return FALSE;
  316. ilGetPipeInfo (pipe, TRUE, &info, (ilImageDes *)NULL, (ilImageFormat *)NULL);
  317. /* Add a consumer element which writes to the given image.
  318. If writing a palette image, supply an Init() function to copy the palette.
  319. */
  320. srcData.consumerImage = (ilObject)pImage;
  321. srcData.stripHeight = 0;
  322. srcData.constantStrip = FALSE;
  323. srcData.minBufferHeight = 0;
  324. pPriv = (ilImagePrivPtr)ilAddPipeElement (pipe, IL_CONSUMER, sizeof (ilImagePrivRec),
  325. 0, &srcData, (ilDstElementData *)NULL, ilWriteImageInit, IL_NPF,
  326. ilWriteImageDestroy, ilWriteImageExecute, 0);
  327. if (!pPriv)
  328. return FALSE;
  329. /* Element successfully added; setup private data.
  330. Increment the refCount in the image; see notes for ilImageDestroy().
  331. */
  332. pPriv->pImage = pImage;
  333. pPriv->pPalette = (pImage->des.type == IL_PALETTE) ? info.pPalette :
  334. (unsigned short *)NULL;
  335. pImage->o.refCount++; /* see ilWriteImageDestroy() */
  336. context->error = IL_OK;
  337. return TRUE;
  338. }