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 libraries 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: iltiffwrite.c /main/4 1996/01/08 12:17:15 lehors $ */
24 /* /ilc/iltiffwrite.c : Code for ilWriteFileImage(); add a consumer to the pipe
25 to write to a TIFF file. See also /ilc/iltiff.c and /ilc/iltiffread.c .
28 #include "iltiffint.h"
29 #include "ilpipelem.h"
30 #include "iljpgencode.h"
33 /* Tag info summary, private to ilWriteFileImage(). Encapsulates the user and std
34 tag info. Contains ptrs to data which is created when the pipe element is added
35 and freed when pipe emptied (Destroy() function).
36 "pTagOffsets" points to an array of offsets, in the same order as the tags at
37 "pTagWriteData" + 2 (bytes). For each tag, if the offset is zero (0), the tag
38 data is in the tag, already byte-flipped. If non-zero, it is the offset of the
39 tag data from pTagWriteData. The file offset where the data at pTagWriteData
40 will be written must be added to this offset and inserted into the tag byte-flipped.
41 See ilMergeWriteTags() for details.
44 ilPtr pAlloc; /* ptr to whole mess to deallocate */
45 CARD32 *pTagOffsets; /* see above */
46 ilPtr pTagWriteData; /* ptr to data to write to file */
47 long tagWriteSize; /* size in bytes of data to write */
48 ilFileOffset *pStripOffsets; /* ptr to strip offset list in memory */
49 INT32 *pStripByteCounts; /* ptr to strip byte count list in memory */
50 ilFileOffset *pJIF; /* (JIF only): offset in memory */
51 long *pJIFLength; /* (JIF only): length in memory */
52 unsigned short *pJPEGRestart; /* (JPEG only): restart interval in memory */
53 long *pJPEGQTables; /* (JPEG only): Q tables in memory */
54 long *pJPEGDCTables; /* (JPEG only): DC tables in memory */
55 long *pJPEGACTables; /* (JPEG only): AC tables in memory */
56 unsigned short *pPalette; /* ptr to pal; null if not palette image */
57 int nPaletteColors; /* # of RGB triplets at pPalette */
58 int tagCount; /* # of tags to write */
59 } ilTagInfoRec, *ilTagInfoPtr;
63 /* Data set into private when element added */
64 ilFilePtr pFile; /* ptr to file being written */
65 ilTagInfoRec tagInfo; /* see above */
66 ilBool bigEndian; /* true if MM byte order file */
67 unsigned int compression; /* type of compression being written */
68 long nStrips; /* # of strips which should be written */
69 ilFileOffset tailPtrOffset; /* "next ptr" to point to this image */
70 ilFileImageRec fileImage; /* data for file image being added */
72 /* Data set/inited by ilWriteFileInit() */
73 ilFileOffset *pStripOffset; /* next in-memory strip offset to store */
74 INT32 *pStripByteCount; /* same for byte count (# bytes written) */
75 long nStripsSoFar; /* # of strips written so far */
76 long nLinesSoFar; /* # of lines written so far */
77 long nBytesSoFar; /* # of bytes written so far (JPEG only) */
78 } ilWriteFilePrivRec, *ilWriteFilePrivPtr;
81 /* Copy 4 bytes of a long byte-flipped based on given "bigEndian" flag, to
82 the given ptr which must be of type ilPtr. Same for a short.
84 #define IL_WRITE_FLIP_LONG(_bigEndian, _long, _ptr) { \
86 *(_ptr)++ = (_long) >> 24; \
87 *(_ptr)++ = ((_long) >> 16) & 0xff; \
88 *(_ptr)++ = ((_long) >> 8) & 0xff; \
89 *(_ptr)++ = (_long) & 0xff; \
92 *(_ptr)++ = (_long) & 0xff; \
93 *(_ptr)++ = ((_long) >> 8) & 0xff; \
94 *(_ptr)++ = ((_long) >> 16) & 0xff; \
95 *(_ptr)++ = (_long) >> 24; \
99 #define IL_WRITE_FLIP_SHORT(_bigEndian, _short, _ptr) { \
101 *(_ptr)++ = ((_short) >> 8) & 0xff; \
102 *(_ptr)++ = (_short) & 0xff; \
105 *(_ptr)++ = (_short) & 0xff; \
106 *(_ptr)++ = ((_short) >> 8) & 0xff; \
110 /* --------------------- ilWriteFileInit -------------------------- */
111 /* Init() function for ilWriteFileImage().
113 static ilError ilWriteFileInit (
114 ilWriteFilePrivPtr pPriv,
115 ilImageInfo *pSrcImage,
116 ilImageInfo *pDstImage
119 /* Point to beginning of strip offset/byte count memory buffers. */
120 pPriv->pStripOffset = pPriv->tagInfo.pStripOffsets;
121 pPriv->pStripByteCount = pPriv->tagInfo.pStripByteCounts;
123 pPriv->nStripsSoFar = 0;
124 pPriv->nLinesSoFar = 0;
125 pPriv->nBytesSoFar = 0;
131 /* --------------------- ilWriteFileCleanup -------------------------- */
132 /* Cleanup() function for ilWriteFileImage().
134 static ilError ilWriteFileCleanup (
135 ilWriteFilePrivPtr pPriv,
140 ilFileOffset position;
141 ilByte fourBytes[4], nextBytes[4];
143 CARD32 *pTagOffsets, l;
146 /* If aborting pipe, just exit. The net effect is that if
147 some image strips are written and the pipe aborted before completion,
148 the image strips are there but not pointed to by anything.
151 return IL_OK; /* EXIT */
153 /* Make sure the proper # of lines and strips have been written or error. */
154 if ((pPriv->nStripsSoFar != pPriv->nStrips)
155 || (pPriv->nLinesSoFar != pPriv->fileImage.p.height))
156 return IL_ERROR_MALFORMED_FILE_WRITE;
157 pFile = pPriv->pFile;
159 /* Read "offset to next" that will be pointed to this image; set as "offset to
160 next" for this image (IFDOffset), following tag info; see ilMergeWriteTags().
162 if (!IL_SEEK (pFile, pPriv->tailPtrOffset) || !IL_READ (pFile, 4, nextBytes))
163 return IL_ERROR_FILE_IO;
164 pBytes = pPriv->tagInfo.pTagWriteData + pPriv->tagInfo.tagCount * IL_TAG_SIZE + 2;
165 *pBytes++ = nextBytes[0];
166 *pBytes++ = nextBytes[1];
167 *pBytes++ = nextBytes[2];
168 *pBytes++ = nextBytes[3];
170 /* Position to EOF; save file position in "position". Update tags whose values
171 did not fit in the tag; they have a non-zero value in the array @pTagOffsets;
172 the value is the offset from the beginning of the data to be written to the
175 if (fseek (pFile->stream, 0, 2)) /* seek to EOF (2); return != 0 is error */
176 return IL_ERROR_FILE_IO;
177 position = ftell (pFile->stream) - pFile->offset;
179 pTagOffsets = pPriv->tagInfo.pTagOffsets;
180 pTag = pPriv->tagInfo.pTagWriteData + 2;
181 for (i = 0; i < pPriv->tagInfo.tagCount; i++, pTagOffsets++, pTag += IL_TAG_SIZE)
183 l = position + *pTagOffsets;
184 pBytes = pTag + 8; /* point to offset field of the tag */
185 IL_WRITE_FLIP_LONG (pPriv->bigEndian, l, pBytes)
188 /* Write out the tag data to add the image to the file. Patch location at
189 "tailPtrOffset" in file to point to this image to link image into list.
191 if (fwrite ((char *)pPriv->tagInfo.pTagWriteData, pPriv->tagInfo.tagWriteSize, 1,
193 return IL_ERROR_FILE_IO;
195 /* compatibility problem with long or unsigned long data fields */
196 IL_WRITE_FLIP_LONG (pPriv->bigEndian, (CARD32)position, pBytes)
197 if (!IL_SEEK (pFile, pPriv->tailPtrOffset) || !IL_WRITE (pFile, 4, fourBytes))
198 return IL_ERROR_FILE_IO;
199 fflush (pFile->stream); /* flush all buffers; image now in file */
201 /* If this image is now last in file (its next offset is null), update file's
202 offset to last image's offset to next, and copy of same in private.
204 if (!nextBytes[0] && !nextBytes[1] && !nextBytes[2] && !nextBytes[3]) {
205 pFile->IFDTailPtrOffset = position + pPriv->tagInfo.tagCount * IL_TAG_SIZE + 2;
206 pPriv->tailPtrOffset = pFile->IFDTailPtrOffset;
209 /* Mark file image list as invalid, so this image will show up next time. */
210 pFile->haveImageList = FALSE;
216 /* ------------------------ ilWriteFileDestroy ----------------------------- */
217 /* Destroy() function for ilWriteFileImage().
219 static ilError ilWriteFileDestroy (
220 ilWriteFilePrivPtr pPriv
223 /* Free the tag data malloc'd by ilMergeWriteTags() when element added. */
224 IL_FREE (pPriv->tagInfo.pAlloc);
228 /* --------------------- ilCopyPalette -------------------------- */
229 /* Called by Execute() function before writing first strip to copy the palette
230 into the tag memory buffer, so it will be written out by ilWriteFileCleanup().
232 static void ilCopyPalette (
233 ilWriteFilePrivPtr pPriv,
234 unsigned short *pSrcPalette
237 unsigned short *pDstPalette;
239 /* Since using IL_WRITE_FLIP_SHORT, palEntry should be unsigned short */
240 unsigned short palEntry;
241 unsigned long greenOffset, blueOffset;
244 /* Copy palette into the in-memory tag area, byte-flipped.
245 It will be written out along with all the tags and tag data during Cleanup().
246 TIFF palettes are the same as IL: all the red, then green, then blue values,
247 each a short, except in TIFF each is "2 ** nBits" entries
248 (pPriv->nPaletteColors) in length; in the IL they are always 256 entries.
250 pDstPalette = pPriv->tagInfo.pPalette;
252 greenOffset = pPriv->tagInfo.nPaletteColors;
253 blueOffset = pPriv->tagInfo.nPaletteColors * 2;
254 for (i = 0; i < pPriv->tagInfo.nPaletteColors; i++, pSrcPalette++, pDstPalette++) {
255 palEntry = *pSrcPalette;
256 pBytes = (ilPtr)pDstPalette;
257 IL_WRITE_FLIP_SHORT (pPriv->bigEndian, palEntry, pBytes)
258 palEntry = *(pSrcPalette + 256);
259 pBytes = (ilPtr)(pDstPalette + greenOffset);
260 IL_WRITE_FLIP_SHORT (pPriv->bigEndian, palEntry, pBytes)
261 palEntry = *(pSrcPalette + 512);
262 pBytes = (ilPtr)(pDstPalette + blueOffset);
263 IL_WRITE_FLIP_SHORT (pPriv->bigEndian, palEntry, pBytes)
269 /* --------------------- ilWriteFileExecute -------------------------- */
270 /* Execute() for ilWriteFileImage().
272 static ilError ilWriteFileExecute (
273 ilExecuteData *pData,
278 ilWriteFilePrivPtr pPriv;
280 unsigned long nBytes, rowBytes;
286 pPriv = (ilWriteFilePrivPtr)pData->pPrivate;
287 pFile = pPriv->pFile;
289 /* If first strip and a palette image copy the palette into tag data */
290 if ((pPriv->nStripsSoFar <= 0) && pPriv->tagInfo.pPalette)
291 ilCopyPalette (pPriv, pData->pSrcImage->pPalette);
293 /* Check for too many lines/strips or inconstant strips (except last). */
294 pPriv->nLinesSoFar += *pNLines;
295 pPriv->nStripsSoFar++;
296 if ((pPriv->nStripsSoFar > pPriv->nStrips)
297 || (pPriv->nLinesSoFar > pPriv->fileImage.p.height)
298 || ((pPriv->nLinesSoFar != pPriv->fileImage.p.height) /* not last strip */
299 && (*pNLines != pPriv->fileImage.p.stripHeight)))
300 return IL_ERROR_MALFORMED_FILE_WRITE;
302 /* Write one strip of data to the end of the file, after saving "position". */
303 if (fseek (pFile->stream, 0, 2)) /* seek to EOF (2); return != 0 is error */
304 return IL_ERROR_FILE_IO; /* EXIT */
305 position = ftell (pFile->stream) - pFile->offset;
306 if (pPriv->compression == IL_UNCOMPRESSED) {
307 rowBytes = pData->pSrcImage->plane[0].nBytesPerRow;
308 nBytes = rowBytes * *pNLines;
309 pBytes = pData->pSrcImage->plane[0].pPixels + pData->srcLine * rowBytes;
312 nBytes = pData->compressed.nBytesToRead;
313 pBytes = pData->pSrcImage->plane[0].pPixels + pData->compressed.srcOffset;
315 if (fwrite ((char *)pBytes, nBytes, 1, pFile->stream) != 1)
316 return IL_ERROR_FILE_IO; /* EXIT */
318 /* Store byte-flipped the offset within the file (position) and size
319 (nBytes) of the strip just written.
321 pBytes = (ilPtr)pPriv->pStripOffset;
322 pPriv->pStripOffset++;
323 /* compatibility problem with long or unsigned long data fields */
324 IL_WRITE_FLIP_LONG (pPriv->bigEndian, (CARD32)position, pBytes)
325 pBytes = (ilPtr)pPriv->pStripByteCount;
326 pPriv->pStripByteCount++;
327 /* compatibility problem with long or unsigned long data fields */
328 IL_WRITE_FLIP_LONG (pPriv->bigEndian, (CARD32)nBytes, pBytes)
334 /* --------------------------- ilWriteJIFData -------------------------------- */
335 /* Called by ilWriteJPEGExecute() when first strip encountered, to encode
336 and write a JIF header into the TIFF file.
338 static ilError ilWriteJIFData (
339 ilWriteFilePrivPtr pPriv,
344 iljpgJIFOffsetsRec offsets;
347 long position, nBytes, i, j;
348 ilJPEGEncodeStream streamRec;
349 ilJPEGData *pCompData;
351 long mcuWidth, mcuHeight;
355 /* Init streamRec so output is written into malloc'd memory, and encode
356 a JIF image into that memory. For restartInterval value: if a single strip
357 use value from raw data (== 0 if no restart markers), otherwise calculate
358 it from strip size. If multi-strip and non-zero restartMarker in raw data
359 a JIF image cannot be created - see below.
361 pCompData = (ilJPEGData *)pImage->pCompData;
362 _ilJPEGDataIn (pImage->pDes, pPriv->fileImage.p.width, pPriv->fileImage.p.height,
364 _ilJPEGTablesIn (pCompData, &data);
366 if (pPriv->nStrips != 1) { /* else data.restartInterval = raw already */
367 mcuWidth = 8 * data.maxHoriFactor;
368 mcuHeight = 8 * data.maxVertFactor;
369 data.restartInterval = /* # of mcus across * # down */
370 ((pPriv->fileImage.p.width + mcuWidth - 1) / mcuWidth) *
371 ((pPriv->fileImage.p.stripHeight + mcuHeight - 1) / mcuHeight);
374 streamRec.pBuffer = streamRec.pDst = streamRec.pPastEndBuffer = (ilPtr)NULL;
375 if (error = iljpgEncodeJIF (&streamRec, &data, &offsets))
378 /* Write JIF header to end of file, at "position". */
379 if (fseek (pFile->stream, 0, 2)) /* seek to EOF (2); != 0 is error */
380 return IL_ERROR_FILE_IO;
381 position = ftell (pFile->stream) - pFile->offset;
382 nBytes = streamRec.pDst - streamRec.pBuffer;
383 if (fwrite ((char *)streamRec.pBuffer, nBytes, 1, pFile->stream) != 1)
384 return IL_ERROR_FILE_IO;
385 IL_FREE (streamRec.pBuffer); /* free malloc'd buffer space */
386 pPriv->nBytesSoFar = nBytes; /* JIF data size so far */
388 /* Update in-memory values for tags that point to JIF data and to
389 the Q/DC/AC tables, returned by iljpgEncodeJIF() above.
390 Write restartInterval: if 0, no restart markers. If non-zero,
391 then there must be only one strip in image or it cannot be encoded as
392 as a JIF image, because restart markers need to be written between the
393 strips and would not mesh with restart markers already in the data;
394 so in that case write JIF pointer marker = 0 => not JIF.
395 The resulting file will be able to be read by IL2.1 and later but not by
396 earlier IL versions or by other software that relies on JIF.
398 pBytes = (ilPtr)pPriv->tagInfo.pJPEGRestart;
399 /* type cast from int to short before FLIP */
400 IL_WRITE_FLIP_SHORT (pPriv->bigEndian, (short)pCompData->restartInterval, pBytes)
402 if (pCompData->restartInterval && (pPriv->nStrips != 1))
403 JIFOffset = 0; /* not valid JIF; write 0 ptr */
404 else JIFOffset = position;
405 pBytes = (ilPtr)pPriv->tagInfo.pJIF;
406 /* compatibility problem with long or unsigned long data fields */
407 IL_WRITE_FLIP_LONG (pPriv->bigEndian, (CARD32)position, pBytes)
409 /* Write offsets to Q tables for each component: table offset for each
410 table, indexed by component table index, plus file to offset to JIF hdr.
412 pBytes = (ilPtr)pPriv->tagInfo.pJPEGQTables;
413 for (i = 0; i < pPriv->fileImage.p.des.nSamplesPerPixel; i++) {
414 j = offsets.QTables[data.comp[i].QTableIndex];
415 if (!j) /* no Q table defined for that index */
416 return IL_ERROR_COMPRESSED_DATA;
417 j += position; /* now offset from start of "file" */
418 /* compatibility problem with long or unsigned long data fields */
419 IL_WRITE_FLIP_LONG (pPriv->bigEndian, (INT32)j, pBytes)
422 /* Same thing for DC and AC tables */
423 pBytes = (ilPtr)pPriv->tagInfo.pJPEGDCTables;
424 for (i = 0; i < pPriv->fileImage.p.des.nSamplesPerPixel; i++) {
425 j = offsets.DCTables[data.comp[i].DCTableIndex];
427 return IL_ERROR_COMPRESSED_DATA;
429 /* compatibility problem with long or unsigned long data fields */
430 IL_WRITE_FLIP_LONG (pPriv->bigEndian, (INT32)j, pBytes)
433 pBytes = (ilPtr)pPriv->tagInfo.pJPEGACTables;
434 for (i = 0; i < pPriv->fileImage.p.des.nSamplesPerPixel; i++) {
435 j = offsets.ACTables[data.comp[i].ACTableIndex];
437 return IL_ERROR_COMPRESSED_DATA;
439 /* compatibility problem with long or unsigned long data fields */
440 IL_WRITE_FLIP_LONG (pPriv->bigEndian, (INT32)j, pBytes)
446 /* --------------------- ilWriteJPEGExecute -------------------------- */
447 /* Execute() for ilWriteFileImage() when writing JPEG-compressed data.
449 static ilError ilWriteJPEGExecute (
450 ilExecuteData *pData,
455 ilWriteFilePrivPtr pPriv;
458 long position, nBytes, i, j;
462 /* The overall approach is to write a JIF image into the file plus strips.
463 The data written will be the JIF "header", followed by strips of JPEG
464 data, separated by restart markers. Each strip will pointed to by
465 the normal TIFF strip offset/byte counts. The resulting data can then
466 be read either as a JIF image (using the JPEGInterchangeFormat/Length
467 tags - how IL2.0 and earlier versions read it) or as a "raw" image using
468 the other JPEG tags (how later versions read it).
470 pPriv = (ilWriteFilePrivPtr)pData->pPrivate;
471 pFile = pPriv->pFile;
473 /* Check for too many lines/strips or inconstant strips (except last). */
474 pPriv->nLinesSoFar += *pNLines;
475 pPriv->nStripsSoFar++;
476 if ((pPriv->nStripsSoFar > pPriv->nStrips)
477 || (pPriv->nLinesSoFar > pPriv->fileImage.p.height)
478 || ((pPriv->nLinesSoFar != pPriv->fileImage.p.height) /* not last strip */
479 && (*pNLines != pPriv->fileImage.p.stripHeight)))
480 return IL_ERROR_MALFORMED_FILE_WRITE;
482 /* If first strip: encode a JIF header and write it to file.
483 Init streamRec so output is written into malloc'd memory, and encode
484 a JIF image into that memory.
486 if (pPriv->nStripsSoFar <= 1) /* first strip; inc'd above */
487 if (error = ilWriteJIFData (pPriv, pFile, pData->pSrcImage))
490 /* Write one strip of data to end of the TIFF file, after saving "position". */
491 if (fseek (pFile->stream, 0, 2)) /* seek to EOF (2); return != 0 is error */
492 return IL_ERROR_FILE_IO;
493 position = ftell (pFile->stream) - pFile->offset;
494 nBytes = pData->compressed.nBytesToRead;
495 pBytes = pData->pSrcImage->plane[0].pPixels + pData->compressed.srcOffset;
496 if (fwrite ((char *)pBytes, nBytes, 1, pFile->stream) != 1)
497 return IL_ERROR_FILE_IO;
498 pPriv->nBytesSoFar += nBytes + 2; /* # bytes in strip + 2 for marker below */
500 /* Store byte-flipped the offset within the file (position) and size
501 (nBytes) of the strip just written.
503 pBytes = (ilPtr)pPriv->pStripOffset;
504 pPriv->pStripOffset++;
505 /* compatibility problem with long or unsigned long data fields */
506 IL_WRITE_FLIP_LONG (pPriv->bigEndian, (CARD32)position, pBytes)
507 pBytes = (ilPtr)pPriv->pStripByteCount;
508 pPriv->pStripByteCount++;
509 /* compatibility problem with long or unsigned long data fields */
510 IL_WRITE_FLIP_LONG (pPriv->bigEndian, (INT32)nBytes, pBytes)
512 /* If last strip, add an EOI marker to end and store JIF length tag value;
513 otherwise add a restart marker, with strip count modulo 8 in it.
516 if (pPriv->nStripsSoFar >= pPriv->nStrips) {
517 marker[1] = ILJPGM_EOI;
518 pBytes = (ilPtr)pPriv->tagInfo.pJIFLength;
519 /* compatibility problem with long or unsigned long data fields */
520 IL_WRITE_FLIP_LONG (pPriv->bigEndian, (INT32)pPriv->nBytesSoFar, pBytes)
522 else marker[1] = ILJPGM_RST0 | ((pPriv->nStripsSoFar - 1) & 7);
524 /* Write two byte restart or end of image (EOI) marker */
525 if (fseek (pFile->stream, 0, 2))
526 return IL_ERROR_FILE_IO;
527 if (fwrite ((char *)marker, 2, 1, pFile->stream) != 1)
528 return IL_ERROR_FILE_IO;
534 /* --------------------- ilMergeWriteTags ----------------------------------- */
535 /* Called by ilWriteFileImage(). Merge the user and std tag info, copy the
536 tag data (flipped) and return into to *pInfo.
538 static ilError ilMergeWriteTags (
539 ilBool bigEndian, /* byte order to be written */
540 int nStdTags, /* # of std (IL) tags */
541 ilFileTag *pStdTags, /* ptr to std tags */
542 int nUserTags, /* # of user (IL) tags */
543 ilFileTag *pUserTags, /* ptr to user tags */
544 ilTagInfoPtr pInfo) /* returned tag info */
546 ilFileTag **ppTagsInit, **ppLastTag;
547 ilFileTag **ppTag, **ppTagTemp, *pTag;
548 ilPtr pTagData, pFileTags;
549 long tagArraySize, tagDataSize, l;
550 CARD32 *pTagOffsets, *pLong;
552 unsigned short tagType, *pShort;
555 /* Allocate and null an array of ptrs to tags, size = # user + std tags, + 1
556 so that there is at least one guaranteed null tag ptr, for "end of array".
558 tagArraySize = nStdTags + nUserTags + 1;
559 ppTagsInit = (ilFileTag **)IL_MALLOC (tagArraySize * sizeof (ilFileTag **));
561 return IL_ERROR_MALLOC;
562 ppLastTag = ppTagsInit + tagArraySize - 1;
563 for (ppTag = ppTagsInit; ppTag <= ppLastTag; ppTag++)
564 *ppTag = (ilFileTag *)NULL;
566 /* Fill in array with ptrs to tags, sorted in ascending numeric order (required
567 by TIFF!), with duplicates eliminated. Do the user tags, then the std tags,
568 so that the std tag values overwrite the user if duplicates present.
569 Sort by insertion sort: find tag with number >= this tag's number, or end
570 of list (null ptr). If greater, shift all values up one; then insert this tag
572 for (i = 0, pTag = pUserTags, nTags = nUserTags; i < 2;
573 i++, pTag = pStdTags, nTags = nStdTags) {
574 while (nTags-- > 0) {
576 while (*ppTag && ((*ppTag)->number < pTag->number))
578 if (*ppTag && ((*ppTag)->number > pTag->number)) {
579 ppTagTemp = ppLastTag;
580 while (ppTagTemp > ppTag) {
581 *ppTagTemp = *(ppTagTemp - 1);
590 /* Set "nTags" to the resulting number of tags, and "tagDataSize" to the size
591 of tag data which does not fit in the tag itself (rounded to mult of 2).
593 for (tagDataSize = 0, nTags = 0, ppTag = ppTagsInit; *ppTag; nTags++, ppTag++) {
595 tagType = pTag->type;
596 if ((tagType == 0) || (tagType > IL_MAX_TAG_TYPE)) {
597 IL_FREE (ppTagsInit);
598 return IL_ERROR_FILE_TAG_TYPE;
600 if (pTag->nItems > _ilTagTypeItemsThatFit [tagType])
601 tagDataSize += (_ilTagTypeItemSizes [tagType] * pTag->nItems + 1) & ~1;
604 /* Alloc room on heap for: an array of offsets to tag data for each tag, or 0
605 if tag data fits in tag; the # of tags (2 bytes); the tags themselves; the
606 next IFD offset (4 bytes); and the tag data that does not fit in the tags.
607 pInfo->pAlloc will point to it all:
608 -----------------------------
609 | offset to data for each | <- pTagOffsets (not written)
610 | tag or 0 if data in tag | (rest is written to TIFF, and is
611 | | "tagWriteSize" bytes in size
612 -----------------------------
613 | # of tags (short) | <- pTagWriteData
614 -----------------------------
615 | tag info for each tag | +2
616 | (of type ilTIFFTagRec) |
617 -----------------------------
618 | ptr to next IFD | + # tags * IL_TAG_SIZE + 2
619 -----------------------------
620 | tag data external to tags | + # tags * IL_TAG_SIZE + 6
621 -----------------------------
623 pInfo->tagCount = nTags;
624 pInfo->tagWriteSize = nTags * IL_TAG_SIZE + 2 + tagDataSize + 4;
625 pInfo->pAlloc = (ilPtr)IL_MALLOC_ZERO (nTags * sizeof(INT32) + pInfo->tagWriteSize);
626 if (!pInfo->pAlloc) {
627 IL_FREE (ppTagsInit);
628 return IL_ERROR_MALLOC;
630 pInfo->pTagOffsets = (CARD32 *)pInfo->pAlloc;
631 pInfo->pTagWriteData = pInfo->pAlloc + nTags * sizeof(INT32);
632 pTagData = (ilPtr)pInfo->pTagWriteData + nTags * IL_TAG_SIZE + 6;
634 /* Write the # of tags byte-flipped, point "pFileTags" to tag data write area.
635 For byte/ascii data: "nItems" is length of string, including trailing null
636 for ascii. Round up to even byte boundary (TIFF requirement).
638 pFileTags = (ilPtr)pInfo->pTagWriteData;
639 IL_WRITE_FLIP_SHORT (bigEndian, (unsigned short)nTags, pFileTags)
641 for (ppTag = ppTagsInit, pTagOffsets = pInfo->pTagOffsets; *ppTag; ppTag++) {
645 tagType = pTag->type;
646 IL_WRITE_FLIP_SHORT (bigEndian, pTag->number, pFileTags)
647 IL_WRITE_FLIP_SHORT (bigEndian, tagType, pFileTags)
648 /* compatibility problem with long or unsigned long data fields */
649 IL_WRITE_FLIP_LONG (bigEndian, (CARD32)pTag->nItems, pFileTags)
650 if (pTag->nItems > _ilTagTypeItemsThatFit [tagType]) {
651 *pTagOffsets++ = pTagData - pInfo->pTagWriteData;
653 pTagData += (_ilTagTypeItemSizes [tagType] * pTag->nItems + 1) & ~1UL;
659 pFileTags += 4; /* skip one TIFF long */
661 /* Copy the data at "*pTag->pItems" to "pWrite", with byte-flip.
662 pWrite points to 4 byte area in tag if items fit, else to area in pTagData.
663 NOTE: handle strip offsets/byte counts specially: pItems is ignored.
665 tagNumber = pTag->number;
666 if (tagNumber == IL_TAG_STRIP_OFFSETS)
667 pInfo->pStripOffsets = (ilFileOffset *)pWrite;
668 else if (tagNumber == IL_TAG_STRIP_BYTE_COUNTS)
669 pInfo->pStripByteCounts = (INT32 *)pWrite;
670 else if (tagNumber == IL_TAG_COLOR_MAP)
671 pInfo->pPalette = (unsigned short *)pWrite;
672 else if (tagNumber == IL_TAG_JPEG_INTERCHANGE_FORMAT)
673 pInfo->pJIF = (ilFileOffset *)pWrite;
674 else if (tagNumber == IL_TAG_JPEG_INTERCHANGE_FORMAT_LENGTH)
675 pInfo->pJIFLength = (long *)pWrite;
676 else if (tagNumber == IL_TAG_JPEG_RESTART_INTERVAL)
677 pInfo->pJPEGRestart = (unsigned short *)pWrite;
678 else if (tagNumber == IL_TAG_JPEG_Q_TABLES)
679 pInfo->pJPEGQTables = (long *)pWrite;
680 else if (tagNumber == IL_TAG_JPEG_DC_TABLES)
681 pInfo->pJPEGDCTables = (long *)pWrite;
682 else if (tagNumber == IL_TAG_JPEG_AC_TABLES)
683 pInfo->pJPEGACTables = (long *)pWrite;
684 else switch (tagType) {
687 bcopy ((char *)pTag->pItems, (char *)pWrite, pTag->nItems);
690 for (i = 0, pShort = (unsigned short *)pTag->pItems;
691 i < pTag->nItems; i++, pShort++)
692 IL_WRITE_FLIP_SHORT (bigEndian, *pShort, pWrite)
695 /* compatibility problem with long or unsigned long data fields */
696 for (i = 0, pLong = (CARD32 *)pTag->pItems;
697 i < pTag->nItems; i++, pLong++)
698 IL_WRITE_FLIP_LONG (bigEndian, *pLong, pWrite)
700 case IL_TAG_RATIONAL:
701 /* compatibility problem with long or unsigned long data fields */
702 for (i = 0, pLong = (CARD32 *)pTag->pItems; i < pTag->nItems; i++) {
703 IL_WRITE_FLIP_LONG (bigEndian, *pLong, pWrite)
705 IL_WRITE_FLIP_LONG (bigEndian, *pLong, pWrite)
710 } /* END for one tag */
712 /* Fill in ptr to next IFD (= 0, null), free temp alloc space and exit.
714 /* compatibility problem with long or unsigned long data fields */
715 IL_WRITE_FLIP_LONG (bigEndian, 0, pFileTags)
716 IL_FREE (ppTagsInit);
720 /* ---------------------- ilFormatPipeImage --------------------------------- */
721 /* Reformat and compress the pipe image as necessary. On entry, pStripHeight
722 must point to the callers requested stripHeight; on return it is the new
723 (constant) stripHeight to use to write.
724 On entry, pInfo/pDes/pFormat must point to the current pipe values;
725 on return they are the new pipe values. Returns false if an error occurs.
727 static ilBool ilFormatPipeImage (
729 unsigned int compression,
734 ilImageFormat *pFormat
737 #define IL_WRITE_TIFF_STRIP_SIZE (16 * 1024) /* write 16KB strips as default */
741 unsigned long g3Flags, g4Flags;
742 ilJPEGEncodeControl jpegEncode;
744 /* If compression is "use current compression" (which makes it easier for
745 caller to copy images), then set compression to current pipe compression,
746 and point pCompData to compression-specific current pipe data.
748 if (compression == IL_WRITE_CURRENT_COMPRESSION) {
749 compression = pDes->compression;
750 if (compression == IL_G3) {
751 g3Flags = pDes->compInfo.g3.flags;
752 pCompData = (ilPtr)&g3Flags;
754 else if (compression == IL_G4) {
755 g4Flags = pDes->compInfo.g4.flags;
756 pCompData = (ilPtr)&g4Flags;
760 /* Compare the levels/sample to bits/sample, and scale up if levels != 2**bits.
761 This is because the IL separates bits and levels, but TIFF assumes # levels
762 = 2**bits. A 16 level 8 bit gray image must be level-scaled up to 256 or
763 else the reader will assume 256 level and display it too dark.
764 However, bitonal must be bit/pixel, and for palette, levels is ignored.
765 NOTE: the right thing to do is to convert the format (e.g. change 16
766 level 8 bit gray to 4 bit gray), but ilConvert() does not handle this yet!
768 switch (pDes->type) {
770 if (pFormat->nBitsPerSample[0] != 1) {
771 pFormat->nBitsPerSample[0] = 1;
772 if (!ilConvert (pipe, (ilImageDes *)NULL, pFormat, 0, NULL))
776 case IL_PALETTE: /* ignore nLevels for palette images */
778 default: /* continuous tone: match levels to bits */
779 for (i = 0, mustConvert = FALSE; i < pDes->nSamplesPerPixel; i++) {
780 nLevels = 1 << pFormat->nBitsPerSample[i];
781 if (pDes->nLevelsPerSample[i] != nLevels) {
782 pDes->nLevelsPerSample[i] = nLevels;
787 if (!ilConvert (pipe, pDes, pFormat, 0, (ilPtr)NULL))
792 /* Convert to pixel order and reget pipe info if multi-sample and planar.
793 However, leave planar if JPEG compression - keep YCbCr subsampled if so.
795 if (pDes->nSamplesPerPixel == 1)
796 pFormat->sampleOrder = IL_SAMPLE_PIXELS;
797 else if ((pFormat->sampleOrder != IL_SAMPLE_PIXELS) && (compression != IL_JPEG)) {
798 pFormat->sampleOrder = IL_SAMPLE_PIXELS;
799 if (!ilConvert (pipe, (ilImageDes *)NULL, pFormat, 0, NULL))
801 ilGetPipeInfo (pipe, FALSE, pInfo, pDes, pFormat);
804 /* If writing uncompressed, force rowBitAlign of 8 (required by TIFF);
805 else compress to stripHeight, using the given compression & data.
806 If stripHeight is 0 use default TIFF write size, based on uncompressed size.
808 stripHeight = *pStripHeight;
810 if (compression == IL_UNCOMPRESSED) {
811 ilGetPipeInfo (pipe, TRUE, pInfo, pDes, pFormat); /* force decompression */
812 if (pFormat->rowBitAlign != 8) {
813 pFormat->rowBitAlign = 8;
814 if (!ilConvert (pipe, (ilImageDes *)NULL, pFormat, 0, (ilPtr)NULL))
816 ilGetPipeInfo (pipe, FALSE, pInfo, pDes, pFormat);
818 if (stripHeight <= 0) {
819 long bytesPerRow [IL_MAX_SAMPLES];
820 ilGetBytesPerRow (pDes, pFormat, pInfo->width, bytesPerRow);
821 stripHeight = IL_WRITE_TIFF_STRIP_SIZE / bytesPerRow[0];
823 if (stripHeight <= 0)
825 else if (stripHeight > pInfo->height)
826 stripHeight = pInfo->height;
827 *pStripHeight = stripHeight; /* write with desired strip height */
830 /* If compressing JPEG, force "raw" format; get caller's Q (dflt = 0).
831 Compress with desired strip height, unless already JPEG compressed,
832 in which case use 0 strip height: accept current strip height.
834 if (compression == IL_JPEG) {
835 jpegEncode.mustbezero = IL_JPEGM_RAW;
837 jpegEncode.Q = ((ilJPEGEncodeControl *)pCompData)->Q;
838 else jpegEncode.Q = 0;
839 pCompData = (ilPtr)&jpegEncode;
840 if (pDes->compression == IL_JPEG)
841 stripHeight = 0; /* accept current strip height */
843 if (!ilCompress (pipe, compression, pCompData, stripHeight, 0))
845 ilGetPipeInfo (pipe, FALSE, pInfo, pDes, pFormat);
846 *pStripHeight = pInfo->stripHeight; /* strip height determined by compression */
853 /* ---------------------- ilWriteFileImage ---------------------------------- */
854 /* Public function: see spec.
855 Adds a consumer to the given pipe to write the current pipe image.
858 IL_EXTERN char _ilVersionString[]; /* in /ilc/ilversion.c ; written for "software" tag */
860 ilBool ilWriteFileImage (
864 ilFileImage fileImage,
865 unsigned int compression,
873 ilFileTag *pUserTags,
874 unsigned long mustBeZero
877 #define MAX_WRITE_TAGS 50 /* max # of std (non-user) tags added here */
879 #define TW_ADD_TAG(_number, _type, _nItems, _pItems) { \
880 pTag->number = (_number); \
881 pTag->type = (_type); \
882 pTag->nItems = (_nItems); \
883 pTag->pItems = (ilPtr)(_pItems); \
888 long nStripsPerImage;
889 ilFileTag tags [MAX_WRITE_TAGS];
892 ilTagInfoRec tagInfo;
896 ilImageFormat format;
899 ilWriteFilePrivPtr pPriv;
900 ilSrcElementData srcData;
901 unsigned long group3Options, group4Options;
902 ilFileImageRelation writeMethod;
903 ilFileOffset tailPtrOffset;
905 /* NOTE: below data types (sizes) FIXED! - tied to TIFF type (short/long) */
906 short ditherLevels[IL_TAG_P0_DITHER_LEVELS_LENGTH];
907 short bitsPerSample [IL_MAX_SAMPLES], TIFFcompression, photo;
908 short nSamplesPerPixel, resolutionUnit, planarConfiguration;
909 short pageInfo[2], predictor, fillOrder;
910 short jpegProc, subsample[2], positioning;
911 long width, height, newSubFileType;
912 long xResolution[2], yResolution[2], coeff[6], refBW[12];
914 #define VERSION_LENGTH 18 /* length includes trailing null */
915 char versionName [VERSION_LENGTH];
918 /* Get pipe state - must be IL_PIPE_FORMING or declare an error. */
919 pFile = (ilFilePtr)file;
920 context = pFile->o.p.context;
921 if (ilGetPipeInfo (pipe, FALSE, &info, &des, &format) != IL_PIPE_FORMING) {
923 ilDeclarePipeInvalid (pipe, IL_ERROR_PIPE_STATE);
928 return ilDeclarePipeInvalid (pipe, IL_ERROR_PAR_NOT_ZERO);
929 if (context != pipe->context)
930 return ilDeclarePipeInvalid (pipe, IL_ERROR_CONTEXT_MISMATCH);
932 /* Force the file image list to be formed if not already; exit on error. */
933 ilListFileImages (file, 0);
935 return ilDeclarePipeInvalid (pipe, context->error);
937 /* Handle "method" set "writeMethod", "newSubFileType". */
939 case IL_WRITE_MAIN: /* no parent, add as last image */
940 writeMethod = mainImage;
942 fileImage = (ilFileImage)NULL;
945 /* Transparency mask: error if no parent, or parent already has or is a mask, or
949 if (!fileImage /* no parent */
950 || (fileImage->file != file) /* not from file being written */
951 || fileImage->pMask /* parent already has a mask */
952 || (((ilFileImagePtr)fileImage)->imageType == maskImage)
953 || (des.nSamplesPerPixel != 1) /* not bitonal */
954 || (format.nBitsPerSample[0] != 1))
955 return ilDeclarePipeInvalid (pipe, IL_ERROR_FILE_WRITE_METHOD);
956 writeMethod = maskImage;
957 newSubFileType = 4; /* TIFF transparency mask */
960 /* Child image: must have non-mask parent fileImage with same file or error.
961 Point to last image associated with parent: find last child (its mask if
962 it has one), so that child images are in order written, and masks "bind"
963 closest to image that they are a mask of.
966 writeMethod = childImage;
967 newSubFileType = 1; /* TIFF reduced resolution image */
968 if (!fileImage /* no parent */
969 || (fileImage->file != file) /* not from file being written */
970 || (((ilFileImagePtr)fileImage)->imageType == maskImage))
971 return ilDeclarePipeInvalid (pipe, IL_ERROR_FILE_WRITE_METHOD);
972 while (fileImage->pChild)
973 fileImage = fileImage->pChild;
974 if (fileImage->pMask)
975 fileImage = fileImage->pMask; /* write after the mask image */
979 return ilDeclarePipeInvalid (pipe, IL_ERROR_FILE_WRITE_METHOD);
983 /* Reformat and compress the pipe image as necessary. Return the stripHeight
984 to use, and the new pipe info/des/format.
986 if (!ilFormatPipeImage (pipe, compression, pCompData, &stripHeight,
987 &info, &des, &format))
990 /* Form the tags to be written for this file image. */
994 /* Write the 1st part of the IL version string as the "software" tag, starting 4
995 chars into string (past '@(#)') - remember length includes trailing null!
997 bcopy (&_ilVersionString[4], versionName, VERSION_LENGTH - 1);
998 versionName [VERSION_LENGTH-1] = 0;
999 TW_ADD_TAG (IL_TAG_SOFTWARE, IL_TAG_ASCII, VERSION_LENGTH, versionName)
1002 newSubFileType |= 2; /* mark as multi-page image */
1003 TW_ADD_TAG (IL_TAG_NEW_SUBFILE_TYPE, IL_TAG_LONG, 1, &newSubFileType)
1006 TW_ADD_TAG (IL_TAG_IMAGE_WIDTH, IL_TAG_LONG, 1, &width)
1008 height = info.height;
1009 TW_ADD_TAG (IL_TAG_IMAGE_LENGTH, IL_TAG_LONG, 1, &height)
1011 for (i = 0; i < des.nSamplesPerPixel; i++)
1012 bitsPerSample [i] = format.nBitsPerSample [i];
1013 TW_ADD_TAG (IL_TAG_BITS_PER_SAMPLE, IL_TAG_SHORT, des.nSamplesPerPixel, bitsPerSample)
1015 /* Determine TIFF compression tag based on pipe image compression and possibly
1016 des.compInfo. Ensure pCompData null if not used.
1018 switch (des.compression) {
1019 case IL_UNCOMPRESSED:
1020 TIFFcompression = 1;
1023 /* Group 3: use des.compInfo.g3.flags.
1024 If 0, write TIFF G3 (code 2), else code 3: must have EOL_MARKERS; init
1025 group3Options to be written below, and write FillOrder tag (required for
1026 Class F; not recommended for other uses in TIFF).
1027 Add group 3 options tag only if "true" (not TIFF) G3 (TIFFcompression == 3)
1030 { unsigned long userOptions;
1031 userOptions = des.compInfo.g3.flags;
1032 if (userOptions == 0)
1033 TIFFcompression = 2;
1035 if (userOptions & ~0x3f) /* unhandled bits set: error */
1036 return ilDeclarePipeInvalid (pipe, IL_ERROR_COMPRESSION);
1038 fillOrder = (userOptions & IL_G3M_LSB_FIRST) ? 2 : 1;
1039 TW_ADD_TAG (IL_TAG_FILL_ORDER, IL_TAG_SHORT, 1, &fillOrder)
1041 if (userOptions & IL_G3M_2D)
1043 if (userOptions & IL_G3M_UNCOMPRESSED)
1045 if (!(userOptions & IL_G3M_EOL_MARKERS))
1046 return ilDeclarePipeInvalid (pipe, IL_ERROR_COMPRESSION);
1047 if (!(userOptions & IL_G3M_EOL_UNALIGNED))
1049 TW_ADD_TAG (IL_TAG_GROUP_3_OPTIONS, IL_TAG_LONG, 1, &group3Options)
1050 TIFFcompression = 3;
1056 { unsigned long userOptions;
1057 userOptions = des.compInfo.g4.flags;
1058 fillOrder = (userOptions & IL_G4M_LSB_FIRST) ? 2 : 1;
1059 TW_ADD_TAG (IL_TAG_FILL_ORDER, IL_TAG_SHORT, 1, &fillOrder)
1062 TW_ADD_TAG (IL_TAG_GROUP_4_OPTIONS, IL_TAG_LONG, 1, &group4Options)
1063 TIFFcompression = 4;
1068 return ilDeclarePipeInvalid (pipe, IL_ERROR_COMPRESSION);
1069 TIFFcompression = 5;
1072 /* JPEG: write JIF with restart markers between strips.
1073 For JIF-in-TIFF: add tags for a file ptr and length of the JIF image,
1074 and the restart interval, but don't know value until JIF image received.
1077 jpegProc = 1; /* baseline sequential process */
1078 TW_ADD_TAG (IL_TAG_JPEG_PROC, IL_TAG_SHORT, 1, &jpegProc)
1079 TW_ADD_TAG (IL_TAG_JPEG_INTERCHANGE_FORMAT, IL_TAG_LONG, 1, NULL)
1080 TW_ADD_TAG (IL_TAG_JPEG_INTERCHANGE_FORMAT_LENGTH, IL_TAG_LONG, 1, NULL)
1081 TW_ADD_TAG (IL_TAG_JPEG_RESTART_INTERVAL, IL_TAG_SHORT, 1, NULL)
1082 TW_ADD_TAG (IL_TAG_JPEG_Q_TABLES, IL_TAG_LONG, des.nSamplesPerPixel, NULL)
1083 TW_ADD_TAG (IL_TAG_JPEG_DC_TABLES, IL_TAG_LONG, des.nSamplesPerPixel, NULL)
1084 TW_ADD_TAG (IL_TAG_JPEG_AC_TABLES, IL_TAG_LONG, des.nSamplesPerPixel, NULL)
1086 TIFFcompression = 6;
1091 return ilDeclarePipeInvalid (pipe, IL_ERROR_COMPRESSION);
1092 TIFFcompression = 32773;
1096 return ilDeclarePipeInvalid (pipe, IL_ERROR_COMPRESSION);
1098 TW_ADD_TAG (IL_TAG_COMPRESSION, IL_TAG_SHORT, 1, &TIFFcompression)
1100 /* Image type-specific code: set PhotometricInterpretation: to 4 (transparency
1101 mask) if a maskImage, else based on image type.
1103 if (writeMethod == maskImage)
1104 photo = 4; /* special code for transparency mask images */
1105 else switch (des.type) {
1107 case IL_GRAY: photo = (des.blackIsZero) ? 1 : 0; break;
1108 case IL_PALETTE: photo = 3; break;
1109 case IL_RGB: photo = 2; break;
1111 /* YCbCr subsampling currently supported only if JPEG/JIF compressed. */
1113 /* Add the YCbCr-specific tags: coefficients as fractions of 10000 */
1114 coeff[0] = des.typeInfo.YCbCr.lumaRed;
1115 coeff[2] = des.typeInfo.YCbCr.lumaGreen;
1116 coeff[4] = des.typeInfo.YCbCr.lumaBlue;
1117 coeff[1] = coeff[3] = coeff[5] = 10000;
1118 TW_ADD_TAG (IL_TAG_YCBCR_COEFFICIENTS, IL_TAG_RATIONAL, 3, coeff)
1120 /* TIFF only allows subsampling as follows: Y = 1, Cr/Cb = 1,2,4 but
1121 Cr and CB equal to each other; vert <= horiz.
1123 { ilYCbCrSampleInfo *pSample = des.typeInfo.YCbCr.sample;
1125 if ((pSample[0].subsampleHoriz != 1)
1126 || (pSample[0].subsampleVert != 1)
1127 || (pSample[1].subsampleHoriz != pSample[2].subsampleHoriz)
1128 || (pSample[1].subsampleVert != pSample[2].subsampleVert)
1129 || (pSample[1].subsampleVert > pSample[2].subsampleHoriz))
1130 return ilDeclarePipeInvalid (pipe, IL_ERROR_YCBCR_TIFF);
1131 subsample[0] = pSample[1].subsampleHoriz;
1132 subsample[1] = pSample[1].subsampleVert;
1133 TW_ADD_TAG (IL_TAG_YCBCR_SUBSAMPLING, IL_TAG_SHORT, 2, subsample)
1135 /* Set positioning - ? is centered correct ? */
1137 TW_ADD_TAG (IL_TAG_YCBCR_POSITIONING, IL_TAG_SHORT, 1, &positioning)
1139 refBW[0] = pSample[0].refBlack; refBW[1] = 1;
1140 refBW[2] = pSample[0].refWhite; refBW[3] = 1;
1141 refBW[4] = pSample[1].refBlack; refBW[5] = 1;
1142 refBW[6] = pSample[1].refWhite; refBW[7] = 1;
1143 refBW[8] = pSample[2].refBlack; refBW[9] = 1;
1144 refBW[10] = pSample[2].refWhite; refBW[11] = 1;
1145 TW_ADD_TAG (IL_TAG_REFERENCE_BLACK_WHITE, IL_TAG_RATIONAL, 6, refBW)
1151 return ilDeclarePipeInvalid (pipe, IL_ERROR_IMAGE_TYPE);
1153 TW_ADD_TAG (IL_TAG_PHOTOMETRIC_INTERPRETATION, IL_TAG_SHORT, 1, &photo)
1155 /* Write # strips stripOffsets/ByteCounts, but supply no data - called
1156 function handles these specially and creates blank space, filled in later.
1158 nStripsPerImage = (info.height + stripHeight - 1) / stripHeight;
1159 TW_ADD_TAG (IL_TAG_STRIP_OFFSETS, IL_TAG_LONG, nStripsPerImage, NULL)
1160 TW_ADD_TAG (IL_TAG_STRIP_BYTE_COUNTS, IL_TAG_LONG, nStripsPerImage, NULL)
1162 nSamplesPerPixel = des.nSamplesPerPixel;
1163 TW_ADD_TAG (IL_TAG_SAMPLES_PER_PIXEL, IL_TAG_SHORT, 1, &nSamplesPerPixel)
1165 TW_ADD_TAG (IL_TAG_ROWS_PER_STRIP, IL_TAG_LONG, 1, &stripHeight);
1167 /* Write x/yRes: specified in dpi * 2; default to 300 dpi if not given. */
1169 TW_ADD_TAG (IL_TAG_RESOLUTION_UNIT, IL_TAG_SHORT, 1, &resolutionUnit)
1170 if (xRes <= 0) xRes = 600;
1171 xResolution [0] = xRes;
1172 xResolution [1] = 2;
1173 TW_ADD_TAG (IL_TAG_X_RESOLUTION, IL_TAG_RATIONAL, 1, xResolution)
1174 if (yRes <= 0) yRes = 600;
1175 yResolution [0] = yRes;
1176 yResolution [1] = 2;
1177 TW_ADD_TAG (IL_TAG_Y_RESOLUTION, IL_TAG_RATIONAL, 1, yResolution)
1179 /* As per TIFF spec, write planarConfiguration tag only if # samples > 1. */
1180 if (des.nSamplesPerPixel > 1) {
1181 planarConfiguration = (format.sampleOrder == IL_SAMPLE_PIXELS) ? 1 : 2;
1182 TW_ADD_TAG (IL_TAG_PLANAR_CONFIGURATION, IL_TAG_SHORT, 1, &planarConfiguration)
1185 if (page >= 0) { /* else no page tag written */
1187 pageInfo[1] = nPages;
1188 TW_ADD_TAG (IL_TAG_PAGE_NUMBER, IL_TAG_SHORT, 2, pageInfo)
1191 if (des.compression == IL_LZW) {
1193 TW_ADD_TAG (IL_TAG_PREDICTOR, IL_TAG_SHORT, 1, &predictor)
1196 /* If a palette entry, add a colorMap tag; # colors = 2 ** # bits.
1197 If dithered flags bit set, write private tag to mark it as such.
1199 if (des.type == IL_PALETTE) {
1200 tagInfo.nPaletteColors = 1 << format.nBitsPerSample [0];
1201 TW_ADD_TAG (IL_TAG_COLOR_MAP, IL_TAG_SHORT, 3 * tagInfo.nPaletteColors, NULL)
1203 if (des.flags & IL_DITHERED_PALETTE) {
1204 ditherLevels[0] = IL_TAG_P0_FLAG_DITHER_LEVELS;
1205 ditherLevels[1] = des.typeInfo.palette.levels[0];
1206 ditherLevels[2] = des.typeInfo.palette.levels[1];
1207 ditherLevels[3] = des.typeInfo.palette.levels[2];
1208 TW_ADD_TAG (IL_TAG_PRIVATE_0, IL_TAG_SHORT, IL_TAG_P0_DITHER_LEVELS_LENGTH,
1212 else tagInfo.pPalette = (unsigned short *)NULL;
1214 /* Merge the user tags with the tags formed above, convert the data to
1215 the proper byte order and return the allocated info to "tagInfo" or error.
1217 if (error = ilMergeWriteTags (pFile->bigEndian, nTags, tags, nUserTags, pUserTags,
1219 return ilDeclarePipeInvalid (pipe, error);
1221 /* Add consumer pipe element, forcing constant "stripHeight" - ignored if pipe
1222 image is compressed - stripHeight was forced above by call to ilCompress().
1223 Use separate function for when writing JPEG.
1225 srcData.consumerImage = (ilObject)NULL;
1226 srcData.stripHeight = stripHeight;
1227 srcData.constantStrip = TRUE;
1228 srcData.minBufferHeight = 0;
1229 pPriv = (ilWriteFilePrivPtr)ilAddPipeElement (pipe, IL_CONSUMER,
1230 sizeof(ilWriteFilePrivRec), 0, &srcData, (ilDstElementData *)NULL,
1231 ilWriteFileInit, ilWriteFileCleanup, ilWriteFileDestroy,
1232 (des.compression == IL_JPEG) ? ilWriteJPEGExecute : ilWriteFileExecute, 0);
1236 /* Fill in private (*pPriv), including template for file image to be added. */
1237 pPriv->pFile = pFile;
1238 pPriv->tagInfo = tagInfo;
1239 pPriv->bigEndian = pFile->bigEndian;
1240 pPriv->compression = des.compression;
1241 pPriv->nStrips = nStripsPerImage;
1243 /* Point pPriv->tailPtrOffset to location in file to point to this image: "ptr
1244 to next" of last image in file (if main image) else ptr to next of parent.
1246 if (fileImage) /* have parent: child or mask image */
1247 pPriv->tailPtrOffset = ((ilFileImagePtr)fileImage)->tagOffset +
1248 ((ilFileImagePtr)fileImage)->tagCount * IL_TAG_SIZE;
1249 else pPriv->tailPtrOffset = pFile->IFDTailPtrOffset;
1251 pPriv->fileImage.p.file = (ilFile)pFile;
1252 pPriv->fileImage.p.pNext = pPriv->fileImage.p.pPrev =
1253 pPriv->fileImage.p.pChild = pPriv->fileImage.p.pMask = (ilFileImage)NULL;
1254 pPriv->fileImage.p.width = info.width;
1255 pPriv->fileImage.p.height = info.height;
1256 pPriv->fileImage.p.xRes = xRes;
1257 pPriv->fileImage.p.yRes = yRes;
1258 pPriv->fileImage.p.page = page;
1259 pPriv->fileImage.p.nPages = nPages;
1260 pPriv->fileImage.p.des = des;
1261 pPriv->fileImage.p.format = format;
1262 pPriv->fileImage.p.stripHeight = stripHeight;
1263 pPriv->fileImage.context = pFile->o.p.context;
1264 pPriv->fileImage.tagCount = tagInfo.tagCount;
1266 pipe->context->error = IL_OK;
1271 /* ---------------------- ilInitFile ---------------------------------- */
1272 /* Public function: see spec.
1273 Writes a TIFF file header at position "offset" of file "stream" using
1274 Motorola order (MM) if "MSBIsFirst", else Intel order (II).
1281 unsigned long mustBeZero
1287 static ilByte MSBFirstHeader[] = { 'M', 'M', 0, 42, 0, 0, 0, 0 };
1288 static ilByte LSBFirstHeader[] = { 'I', 'I', 42, 0, 0, 0, 0, 0 };
1290 if (fseek (stream, offset, 0)) { /* nonzero means error for fseek */
1291 context->error = IL_ERROR_FILE_IO;
1295 pHeader = (MSBIsFirst) ? MSBFirstHeader : LSBFirstHeader;
1296 if (fwrite ((char *)pHeader, sizeof (MSBFirstHeader), 1, stream) != 1) {
1297 context->error = IL_ERROR_FILE_IO;
1300 fflush (stream); /* flush header out to file */
1302 context->error = IL_OK;