Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/* Copyright (C) 1994, 1995 Aladdin Enterprises.  All rights reserved.
2
 
3
  This software is provided AS-IS with no warranty, either express or
4
  implied.
5
 
6
  This software is distributed under license and may not be copied,
7
  modified or distributed except as expressly authorized under the terms
8
  of the license contained in the file LICENSE in this distribution.
9
 
10
  For more information about licensing, please refer to
11
  http://www.ghostscript.com/licensing/. For information on
12
  commercial licensing, go to http://www.artifex.com/licensing/ or
13
  contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14
  San Rafael, CA  94903, U.S.A., +1(415)492-9861.
15
*/
16
 
17
/* $Id: gdevtifs.c,v 1.7 2002/10/07 08:28:56 ghostgum Exp $ */
18
/* TIFF-writing substructure */
19
#include "stdio_.h"
20
#include "time_.h"
21
#include "gstypes.h"
22
#include "gscdefs.h"
23
#include "gdevprn.h"
24
#include "gdevtifs.h"
25
 
26
/*
27
 * Define the standard contents of a TIFF directory.
28
 * Clients may add more items, also sorted in increasing tag order.
29
 */
30
typedef struct TIFF_std_directory_entries_s {
31
    TIFF_dir_entry SubFileType;
32
    TIFF_dir_entry ImageWidth;
33
    TIFF_dir_entry ImageLength;
34
    TIFF_dir_entry StripOffsets;
35
    TIFF_dir_entry Orientation;
36
    TIFF_dir_entry RowsPerStrip;
37
    TIFF_dir_entry StripByteCounts;
38
    TIFF_dir_entry XResolution;
39
    TIFF_dir_entry YResolution;
40
    TIFF_dir_entry PlanarConfig;
41
    TIFF_dir_entry ResolutionUnit;
42
    TIFF_dir_entry PageNumber;
43
    TIFF_dir_entry Software;
44
    TIFF_dir_entry DateTime;
45
} TIFF_std_directory_entries;
46
 
47
/* Define values that follow the directory entries. */
48
typedef struct TIFF_std_directory_values_s {
49
    TIFF_ulong diroff;		/* offset to next directory */
50
    TIFF_ulong xresValue[2];	/* XResolution indirect value */
51
    TIFF_ulong yresValue[2];	/* YResolution indirect value */
52
#define maxSoftware 40
53
    char softwareValue[maxSoftware];	/* Software indirect value */
54
    char dateTimeValue[20];	/* DateTime indirect value */
55
} TIFF_std_directory_values;
56
private const TIFF_std_directory_entries std_entries_initial =
57
{
58
    {TIFFTAG_SubFileType, TIFF_LONG, 1, SubFileType_page},
59
    {TIFFTAG_ImageWidth, TIFF_LONG, 1},
60
    {TIFFTAG_ImageLength, TIFF_LONG, 1},
61
    {TIFFTAG_StripOffsets, TIFF_LONG, 1},
62
    {TIFFTAG_Orientation, TIFF_SHORT, 1, Orientation_top_left},
63
    {TIFFTAG_RowsPerStrip, TIFF_LONG, 1},
64
    {TIFFTAG_StripByteCounts, TIFF_LONG, 1},
65
    {TIFFTAG_XResolution, TIFF_RATIONAL | TIFF_INDIRECT, 1,
66
     offset_of(TIFF_std_directory_values, xresValue[0])},
67
    {TIFFTAG_YResolution, TIFF_RATIONAL | TIFF_INDIRECT, 1,
68
     offset_of(TIFF_std_directory_values, yresValue[0])},
69
    {TIFFTAG_PlanarConfig, TIFF_SHORT, 1, PlanarConfig_contig},
70
    {TIFFTAG_ResolutionUnit, TIFF_SHORT, 1, ResolutionUnit_inch},
71
    {TIFFTAG_PageNumber, TIFF_SHORT, 2},
72
    {TIFFTAG_Software, TIFF_ASCII | TIFF_INDIRECT, 0,
73
     offset_of(TIFF_std_directory_values, softwareValue[0])},
74
    {TIFFTAG_DateTime, TIFF_ASCII | TIFF_INDIRECT, 20,
75
     offset_of(TIFF_std_directory_values, dateTimeValue[0])}
76
};
77
private const TIFF_std_directory_values std_values_initial =
78
{
79
    0,
80
    {0, 1},
81
    {0, 1},
82
    {0},
83
    {0, 0}
84
};
85
 
86
/* Fix up tag values on big-endian machines if necessary. */
87
#if arch_is_big_endian
88
private void
89
tiff_fixup_tag(TIFF_dir_entry * dp)
90
{
91
    switch (dp->type) {
92
	case TIFF_SHORT:
93
	case TIFF_SSHORT:
94
	    /* We may have two shorts packed into a TIFF_ulong. */
95
	    dp->value = (dp->value << 16) + (dp->value >> 16);
96
	    break;
97
	case TIFF_BYTE:
98
	case TIFF_SBYTE:
99
	    dp->value <<= 24;
100
	    break;
101
    }
102
}
103
#else
104
#  define tiff_fixup_tag(dp) DO_NOTHING
105
#endif
106
 
107
/* Begin a TIFF page. */
108
int
109
gdev_tiff_begin_page(gx_device_printer * pdev, gdev_tiff_state * tifs,
110
		     FILE * fp,
111
		     const TIFF_dir_entry * entries, int entry_count,
112
		     const byte * values, int value_size, long max_strip_size)
113
{
114
    gs_memory_t *mem = pdev->memory;
115
    TIFF_std_directory_entries std_entries;
116
    const TIFF_dir_entry *pse;
117
    const TIFF_dir_entry *pce;
118
    TIFF_dir_entry entry;
119
#define std_entry_count\
120
  (sizeof(TIFF_std_directory_entries) / sizeof(TIFF_dir_entry))
121
    int nse, nce, ntags;
122
    TIFF_std_directory_values std_values;
123
 
124
#define std_value_size sizeof(TIFF_std_directory_values)
125
 
126
    tifs->mem = mem;
127
    if (gdev_prn_file_is_new(pdev)) {
128
	/* This is a new file; write the TIFF header. */
129
	static const TIFF_header hdr = {
130
#if arch_is_big_endian
131
	    TIFF_magic_big_endian,
132
#else
133
	    TIFF_magic_little_endian,
134
#endif
135
	    TIFF_version_value,
136
	    sizeof(TIFF_header)
137
	};
138
 
139
	fwrite((const char *)&hdr, sizeof(hdr), 1, fp);
140
	tifs->prev_dir = 0;
141
    } else {			/* Patch pointer to this directory from previous. */
142
	TIFF_ulong offset = (TIFF_ulong) tifs->dir_off;
143
 
144
	fseek(fp, tifs->prev_dir, SEEK_SET);
145
	fwrite((char *)&offset, sizeof(offset), 1, fp);
146
	fseek(fp, tifs->dir_off, SEEK_SET);
147
    }
148
 
149
    /* We're going to shuffle the two tag lists together. */
150
    /* Both lists are sorted; entries in the client list */
151
    /* replace entries with the same tag in the standard list. */
152
    for (ntags = 0, pse = (const TIFF_dir_entry *)&std_entries_initial,
153
	 nse = std_entry_count, pce = entries, nce = entry_count;
154
	 nse && nce; ++ntags
155
	) {
156
	if (pse->tag < pce->tag)
157
	    ++pse, --nse;
158
	else if (pce->tag < pse->tag)
159
	    ++pce, --nce;
160
	else
161
	    ++pse, --nse, ++pce, --nce;
162
    }
163
    ntags += nse + nce;
164
    tifs->ntags = ntags;
165
 
166
    /* Write count of tags in directory. */
167
    {
168
	TIFF_short dircount = ntags;
169
 
170
	fwrite((char *)&dircount, sizeof(dircount), 1, fp);
171
    }
172
    tifs->dir_off = ftell(fp);
173
 
174
    /* Fill in standard directory tags. */
175
    std_entries = std_entries_initial;
176
    std_values = std_values_initial;
177
    std_entries.ImageWidth.value = pdev->width;
178
    std_entries.ImageLength.value = pdev->height;
179
    if (max_strip_size == 0) {
180
	tifs->strip_count = 1;
181
	tifs->rows = pdev->height;
182
	std_entries.RowsPerStrip.value = pdev->height;
183
    } else {
184
	int max_strip_rows =
185
	    max_strip_size / gdev_mem_bytes_per_scan_line((gx_device *)pdev);
186
        int rps = max(1, max_strip_rows);
187
 
188
	tifs->strip_count = (pdev->height + rps - 1) / rps;
189
	tifs->rows = rps;
190
	std_entries.RowsPerStrip.value = rps;
191
	std_entries.StripOffsets.count = tifs->strip_count;
192
	std_entries.StripByteCounts.count = tifs->strip_count;
193
    }
194
    tifs->StripOffsets = (TIFF_ulong *)gs_alloc_bytes(mem,
195
    		    (tifs->strip_count)*2*sizeof(TIFF_ulong),
196
		    "gdev_tiff_begin_page(StripOffsets)");
197
    tifs->StripByteCounts = &(tifs->StripOffsets[tifs->strip_count]);
198
    if (tifs->StripOffsets == 0)
199
	return_error(gs_error_VMerror);
200
    std_entries.PageNumber.value = (TIFF_ulong) pdev->PageCount;
201
    std_values.xresValue[0] = (TIFF_ulong)pdev->x_pixels_per_inch;
202
    std_values.yresValue[0] = (TIFF_ulong)pdev->y_pixels_per_inch;
203
    {
204
	char revs[10];
205
 
206
	strncpy(std_values.softwareValue, gs_product, maxSoftware);
207
	std_values.softwareValue[maxSoftware - 1] = 0;
208
	sprintf(revs, " %1.2f", gs_revision / 100.0);
209
	strncat(std_values.softwareValue, revs,
210
		maxSoftware - strlen(std_values.softwareValue) - 1);
211
	std_entries.Software.count =
212
	    strlen(std_values.softwareValue) + 1;
213
    }
214
    {
215
	struct tm tms;
216
	time_t t;
217
 
218
	time(&t);
219
	tms = *localtime(&t);
220
	sprintf(std_values.dateTimeValue,
221
		"%04d:%02d:%02d %02d:%02d:%02d",
222
		tms.tm_year + 1900, tms.tm_mon + 1, tms.tm_mday,
223
		tms.tm_hour, tms.tm_min, tms.tm_sec);
224
    }
225
 
226
    /* Write the merged directory. */
227
    for (pse = (const TIFF_dir_entry *)&std_entries,
228
	 nse = std_entry_count, pce = entries, nce = entry_count;
229
	 nse || nce;
230
	) {
231
	bool std;
232
 
233
	if (nce == 0 || (nse != 0 && pse->tag < pce->tag))
234
	    std = true, entry = *pse++, --nse;
235
	else if (nse == 0 || (nce != 0 && pce->tag < pse->tag))
236
	    std = false, entry = *pce++, --nce;
237
	else
238
	    std = false, ++pse, --nse, entry = *pce++, --nce;
239
	if (entry.tag == TIFFTAG_StripOffsets)  {
240
	    if (tifs->strip_count > 1) {
241
		tifs->offset_StripOffsets = tifs->dir_off +
242
		    (ntags * sizeof(TIFF_dir_entry)) + std_value_size + value_size;
243
		entry.value = tifs->offset_StripOffsets;
244
	    } else {
245
		tifs->offset_StripOffsets = ftell(fp) +
246
		    offset_of(TIFF_dir_entry, value);
247
	    }
248
	}
249
	if (entry.tag == TIFFTAG_StripByteCounts) {
250
	    if (tifs->strip_count > 1) {
251
	        tifs->offset_StripByteCounts = tifs->dir_off +
252
		    (ntags * sizeof(TIFF_dir_entry)) + std_value_size + value_size +
253
		    (sizeof(TIFF_ulong) * tifs->strip_count);
254
	        entry.value = tifs->offset_StripByteCounts;
255
	    } else {
256
		tifs->offset_StripByteCounts = ftell(fp) +
257
		    offset_of(TIFF_dir_entry, value);
258
	    }
259
	}
260
	tiff_fixup_tag(&entry);	/* don't fix up indirects */
261
	if (entry.type & TIFF_INDIRECT) {
262
	    /* Fix up the offset for an indirect value. */
263
	    entry.type -= TIFF_INDIRECT;
264
	    entry.value +=
265
		tifs->dir_off + ntags * sizeof(TIFF_dir_entry) +
266
		(std ? 0 : std_value_size);
267
	}
268
	fwrite((char *)&entry, sizeof(entry), 1, fp);
269
    }
270
 
271
    /* Write the indirect values. */
272
    fwrite((const char *)&std_values, sizeof(std_values), 1, fp);
273
    fwrite((const char *)values, value_size, 1, fp);
274
    /* Write placeholders for the strip offsets. */
275
    fwrite(tifs->StripOffsets, sizeof(TIFF_ulong), 2 * tifs->strip_count, fp);
276
    tifs->strip_index = 0;
277
    tifs->StripOffsets[0] = ftell(fp);
278
    return 0;
279
}
280
 
281
/* End a TIFF strip. */
282
/* Record the size of the current strip, update the	*/
283
/* start of the next strip  and bump the strip_index	*/
284
int
285
gdev_tiff_end_strip(gdev_tiff_state * tifs, FILE * fp)
286
{
287
    TIFF_ulong strip_size;
288
    TIFF_ulong next_strip_start;
289
    int pad = 0;
290
 
291
    next_strip_start = (TIFF_ulong)ftell(fp);
292
    strip_size = next_strip_start - tifs->StripOffsets[tifs->strip_index];
293
    if (next_strip_start & 1) {
294
        next_strip_start++;	/* WORD alignment */
295
	fwrite(&pad, 1, 1, fp);
296
    }
297
    tifs->StripByteCounts[tifs->strip_index++] = strip_size;
298
    if (tifs->strip_index < tifs->strip_count)
299
	tifs->StripOffsets[tifs->strip_index] = next_strip_start;
300
    return 0;
301
}
302
 
303
/* End a TIFF page. */
304
int
305
gdev_tiff_end_page(gdev_tiff_state * tifs, FILE * fp)
306
{
307
    gs_memory_t *mem = tifs->mem;
308
    long dir_off = tifs->dir_off;
309
    int tags_size = tifs->ntags * sizeof(TIFF_dir_entry);
310
 
311
    tifs->prev_dir =
312
	dir_off + tags_size + offset_of(TIFF_std_directory_values, diroff);
313
    tifs->dir_off = ftell(fp);
314
    /* Patch strip byte counts and offsets values. */
315
    /* The offset in the file was determined at begin_page and may be indirect */
316
    fseek(fp, tifs->offset_StripOffsets, SEEK_SET);
317
    fwrite(tifs->StripOffsets, sizeof(TIFF_ulong), tifs->strip_count, fp);
318
    fseek(fp, tifs->offset_StripByteCounts, SEEK_SET);
319
    fwrite(tifs->StripByteCounts, sizeof(TIFF_ulong), tifs->strip_count, fp);
320
    gs_free_object(mem, tifs->StripOffsets, "gdev_tiff_begin_page(StripOffsets)");
321
    return 0;
322
}