1
/* Copyright (C) 2001-2006 Artifex Software, Inc.
4
This software is provided AS-IS with no warranty, either express or
7
This software is distributed under license and may not be copied, modified
8
or distributed except as expressly authorized under the terms of that
9
license. Refer to licensing information at http://www.artifex.com/
10
or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134,
11
San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information.
14
/* $Id: gdevtifs.c 8250 2007-09-25 13:31:24Z giles $ */
15
/* TIFF-writing substructure */
24
* Define the standard contents of a TIFF directory.
25
* Clients may add more items, also sorted in increasing tag order.
27
typedef struct TIFF_std_directory_entries_s {
28
TIFF_dir_entry SubFileType;
29
TIFF_dir_entry ImageWidth;
30
TIFF_dir_entry ImageLength;
31
TIFF_dir_entry StripOffsets;
32
TIFF_dir_entry Orientation;
33
TIFF_dir_entry RowsPerStrip;
34
TIFF_dir_entry StripByteCounts;
35
TIFF_dir_entry XResolution;
36
TIFF_dir_entry YResolution;
37
TIFF_dir_entry PlanarConfig;
38
TIFF_dir_entry ResolutionUnit;
39
TIFF_dir_entry PageNumber;
40
TIFF_dir_entry Software;
41
TIFF_dir_entry DateTime;
42
} TIFF_std_directory_entries;
44
/* Define values that follow the directory entries. */
45
typedef struct TIFF_std_directory_values_s {
46
TIFF_ulong diroff; /* offset to next directory */
47
TIFF_ulong xresValue[2]; /* XResolution indirect value */
48
TIFF_ulong yresValue[2]; /* YResolution indirect value */
49
#define maxSoftware 40
50
char softwareValue[maxSoftware]; /* Software indirect value */
51
char dateTimeValue[20]; /* DateTime indirect value */
52
} TIFF_std_directory_values;
53
static const TIFF_std_directory_entries std_entries_initial =
55
{TIFFTAG_SubFileType, TIFF_LONG, 1, SubFileType_page},
56
{TIFFTAG_ImageWidth, TIFF_LONG, 1},
57
{TIFFTAG_ImageLength, TIFF_LONG, 1},
58
{TIFFTAG_StripOffsets, TIFF_LONG, 1},
59
{TIFFTAG_Orientation, TIFF_SHORT, 1, Orientation_top_left},
60
{TIFFTAG_RowsPerStrip, TIFF_LONG, 1},
61
{TIFFTAG_StripByteCounts, TIFF_LONG, 1},
62
{TIFFTAG_XResolution, TIFF_RATIONAL | TIFF_INDIRECT, 1,
63
offset_of(TIFF_std_directory_values, xresValue[0])},
64
{TIFFTAG_YResolution, TIFF_RATIONAL | TIFF_INDIRECT, 1,
65
offset_of(TIFF_std_directory_values, yresValue[0])},
66
{TIFFTAG_PlanarConfig, TIFF_SHORT, 1, PlanarConfig_contig},
67
{TIFFTAG_ResolutionUnit, TIFF_SHORT, 1, ResolutionUnit_inch},
68
{TIFFTAG_PageNumber, TIFF_SHORT, 2},
69
{TIFFTAG_Software, TIFF_ASCII | TIFF_INDIRECT, 0,
70
offset_of(TIFF_std_directory_values, softwareValue[0])},
71
{TIFFTAG_DateTime, TIFF_ASCII | TIFF_INDIRECT, 20,
72
offset_of(TIFF_std_directory_values, dateTimeValue[0])}
74
static const TIFF_std_directory_values std_values_initial =
83
/* Fix up tag values on big-endian machines if necessary. */
84
#if arch_is_big_endian
86
tiff_fixup_tag(TIFF_dir_entry * dp)
91
/* We may have two shorts packed into a TIFF_ulong. */
92
dp->value = (dp->value << 16) + (dp->value >> 16);
101
# define tiff_fixup_tag(dp) DO_NOTHING
104
/* Begin a TIFF page. */
106
gdev_tiff_begin_page(gx_device_printer * pdev, gdev_tiff_state * tifs,
108
const TIFF_dir_entry * entries, int entry_count,
109
const byte * values, int value_size, long max_strip_size)
111
gs_memory_t *mem = pdev->memory;
112
TIFF_std_directory_entries std_entries;
113
const TIFF_dir_entry *pse;
114
const TIFF_dir_entry *pce;
115
TIFF_dir_entry entry;
116
#define std_entry_count\
117
(sizeof(TIFF_std_directory_entries) / sizeof(TIFF_dir_entry))
119
TIFF_std_directory_values std_values;
121
#define std_value_size sizeof(TIFF_std_directory_values)
124
if (gdev_prn_file_is_new(pdev)) {
125
/* This is a new file; write the TIFF header. */
126
static const TIFF_header hdr = {
127
#if arch_is_big_endian
128
TIFF_magic_big_endian,
130
TIFF_magic_little_endian,
136
fwrite((const char *)&hdr, sizeof(hdr), 1, fp);
138
} else { /* Patch pointer to this directory from previous. */
139
TIFF_ulong offset = (TIFF_ulong) tifs->dir_off;
141
fseek(fp, tifs->prev_dir, SEEK_SET);
142
fwrite((char *)&offset, sizeof(offset), 1, fp);
143
fseek(fp, tifs->dir_off, SEEK_SET);
146
/* We're going to shuffle the two tag lists together. */
147
/* Both lists are sorted; entries in the client list */
148
/* replace entries with the same tag in the standard list. */
149
for (ntags = 0, pse = (const TIFF_dir_entry *)&std_entries_initial,
150
nse = std_entry_count, pce = entries, nce = entry_count;
153
if (pse->tag < pce->tag)
155
else if (pce->tag < pse->tag)
158
++pse, --nse, ++pce, --nce;
163
/* Write count of tags in directory. */
165
TIFF_short dircount = ntags;
167
fwrite((char *)&dircount, sizeof(dircount), 1, fp);
169
tifs->dir_off = ftell(fp);
171
/* Fill in standard directory tags. */
172
std_entries = std_entries_initial;
173
std_values = std_values_initial;
174
std_entries.ImageWidth.value = pdev->width;
175
std_entries.ImageLength.value = pdev->height;
176
if (max_strip_size == 0) {
177
tifs->strip_count = 1;
178
tifs->rows = pdev->height;
179
std_entries.RowsPerStrip.value = pdev->height;
182
max_strip_size / gdev_mem_bytes_per_scan_line((gx_device *)pdev);
183
int rps = max(1, max_strip_rows);
185
tifs->strip_count = (pdev->height + rps - 1) / rps;
187
std_entries.RowsPerStrip.value = rps;
188
std_entries.StripOffsets.count = tifs->strip_count;
189
std_entries.StripByteCounts.count = tifs->strip_count;
191
tifs->StripOffsets = (TIFF_ulong *)gs_alloc_bytes(mem,
192
(tifs->strip_count)*2*sizeof(TIFF_ulong),
193
"gdev_tiff_begin_page(StripOffsets)");
194
tifs->StripByteCounts = &(tifs->StripOffsets[tifs->strip_count]);
195
if (tifs->StripOffsets == 0)
196
return_error(gs_error_VMerror);
197
std_entries.PageNumber.value = (TIFF_ulong) pdev->PageCount;
198
std_values.xresValue[0] = (TIFF_ulong)pdev->x_pixels_per_inch;
199
std_values.yresValue[0] = (TIFF_ulong)pdev->y_pixels_per_inch;
203
strncpy(std_values.softwareValue, gs_product, maxSoftware);
204
std_values.softwareValue[maxSoftware - 1] = 0;
205
sprintf(revs, " %1.2f", gs_revision / 100.0);
206
strncat(std_values.softwareValue, revs,
207
maxSoftware - strlen(std_values.softwareValue) - 1);
208
std_entries.Software.count =
209
strlen(std_values.softwareValue) + 1;
216
tms = *localtime(&t);
217
sprintf(std_values.dateTimeValue,
218
"%04d:%02d:%02d %02d:%02d:%02d",
219
tms.tm_year + 1900, tms.tm_mon + 1, tms.tm_mday,
220
tms.tm_hour, tms.tm_min, tms.tm_sec);
223
/* Write the merged directory. */
224
for (pse = (const TIFF_dir_entry *)&std_entries,
225
nse = std_entry_count, pce = entries, nce = entry_count;
230
if (nce == 0 || (nse != 0 && pse->tag < pce->tag))
231
std = true, entry = *pse++, --nse;
232
else if (nse == 0 || (nce != 0 && pce->tag < pse->tag))
233
std = false, entry = *pce++, --nce;
235
std = false, ++pse, --nse, entry = *pce++, --nce;
236
if (entry.tag == TIFFTAG_StripOffsets) {
237
if (tifs->strip_count > 1) {
238
tifs->offset_StripOffsets = tifs->dir_off +
239
(ntags * sizeof(TIFF_dir_entry)) + std_value_size + value_size;
240
entry.value = tifs->offset_StripOffsets;
242
tifs->offset_StripOffsets = ftell(fp) +
243
offset_of(TIFF_dir_entry, value);
246
if (entry.tag == TIFFTAG_StripByteCounts) {
247
if (tifs->strip_count > 1) {
248
tifs->offset_StripByteCounts = tifs->dir_off +
249
(ntags * sizeof(TIFF_dir_entry)) + std_value_size + value_size +
250
(sizeof(TIFF_ulong) * tifs->strip_count);
251
entry.value = tifs->offset_StripByteCounts;
253
tifs->offset_StripByteCounts = ftell(fp) +
254
offset_of(TIFF_dir_entry, value);
257
tiff_fixup_tag(&entry); /* don't fix up indirects */
258
if (entry.type & TIFF_INDIRECT) {
259
/* Fix up the offset for an indirect value. */
260
entry.type -= TIFF_INDIRECT;
262
tifs->dir_off + ntags * sizeof(TIFF_dir_entry) +
263
(std ? 0 : std_value_size);
265
fwrite((char *)&entry, sizeof(entry), 1, fp);
268
/* Write the indirect values. */
269
fwrite((const char *)&std_values, sizeof(std_values), 1, fp);
270
fwrite((const char *)values, value_size, 1, fp);
271
/* Write placeholders for the strip offsets. */
272
fwrite(tifs->StripOffsets, sizeof(TIFF_ulong), 2 * tifs->strip_count, fp);
273
tifs->strip_index = 0;
274
tifs->StripOffsets[0] = ftell(fp);
278
/* End a TIFF strip. */
279
/* Record the size of the current strip, update the */
280
/* start of the next strip and bump the strip_index */
282
gdev_tiff_end_strip(gdev_tiff_state * tifs, FILE * fp)
284
TIFF_ulong strip_size;
285
TIFF_ulong next_strip_start;
288
next_strip_start = (TIFF_ulong)ftell(fp);
289
strip_size = next_strip_start - tifs->StripOffsets[tifs->strip_index];
290
if (next_strip_start & 1) {
291
next_strip_start++; /* WORD alignment */
292
fwrite(&pad, 1, 1, fp);
294
tifs->StripByteCounts[tifs->strip_index++] = strip_size;
295
if (tifs->strip_index < tifs->strip_count)
296
tifs->StripOffsets[tifs->strip_index] = next_strip_start;
300
/* End a TIFF page. */
302
gdev_tiff_end_page(gdev_tiff_state * tifs, FILE * fp)
304
gs_memory_t *mem = tifs->mem;
305
long dir_off = tifs->dir_off;
306
int tags_size = tifs->ntags * sizeof(TIFF_dir_entry);
309
dir_off + tags_size + offset_of(TIFF_std_directory_values, diroff);
310
tifs->dir_off = ftell(fp);
311
/* Patch strip byte counts and offsets values. */
312
/* The offset in the file was determined at begin_page and may be indirect */
313
fseek(fp, tifs->offset_StripOffsets, SEEK_SET);
314
fwrite(tifs->StripOffsets, sizeof(TIFF_ulong), tifs->strip_count, fp);
315
fseek(fp, tifs->offset_StripByteCounts, SEEK_SET);
316
fwrite(tifs->StripByteCounts, sizeof(TIFF_ulong), tifs->strip_count, fp);
317
gs_free_object(mem, tifs->StripOffsets, "gdev_tiff_begin_page(StripOffsets)");