comparison mupdf-source/thirdparty/zint/backend/tif.c @ 2:b50eed0cc0ef upstream

ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4. The directory name has changed: no version number in the expanded directory now.
author Franz Glasner <fzglas.hg@dom66.de>
date Mon, 15 Sep 2025 11:43:07 +0200
parents
children
comparison
equal deleted inserted replaced
1:1d09e1dec1d9 2:b50eed0cc0ef
1 /* tif.c - Aldus Tagged Image File Format support */
2 /*
3 libzint - the open source barcode library
4 Copyright (C) 2016-2024 Robin Stuart <rstuart114@gmail.com>
5
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions
8 are met:
9
10 1. Redistributions of source code must retain the above copyright
11 notice, this list of conditions and the following disclaimer.
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in the
14 documentation and/or other materials provided with the distribution.
15 3. Neither the name of the project nor the names of its contributors
16 may be used to endorse or promote products derived from this software
17 without specific prior written permission.
18
19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
23 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 SUCH DAMAGE.
30 */
31 /* SPDX-License-Identifier: BSD-3-Clause */
32
33 #include <assert.h>
34 #include <errno.h>
35 #include <math.h>
36 #include <stdio.h>
37 #include "common.h"
38 #include "filemem.h"
39 #include "output.h"
40 #include "tif.h"
41 #include "tif_lzw.h"
42
43 /* PhotometricInterpretation */
44 #define TIF_PMI_WHITEISZERO 0
45 #define TIF_PMI_BLACKISZERO 1
46 #define TIF_PMI_RGB 2
47 #define TIF_PMI_PALETTE_COLOR 3
48 #define TIF_PMI_SEPARATED 5 /* CMYK */
49
50 /* Compression */
51 #define TIF_NO_COMPRESSION 1
52 #define TIF_LZW 5
53
54 static void to_color_map(const unsigned char rgb[4], tiff_color_t *color_map_entry) {
55 color_map_entry->red = (rgb[0] << 8) | rgb[0];
56 color_map_entry->green = (rgb[1] << 8) | rgb[1];
57 color_map_entry->blue = (rgb[2] << 8) | rgb[2];
58 }
59
60 static void to_cmyk(const char *colour, unsigned char *cmyk) {
61 int cyan, magenta, yellow, black;
62 unsigned char alpha;
63
64 (void) out_colour_get_cmyk(colour, &cyan, &magenta, &yellow, &black, &alpha);
65 cmyk[0] = (unsigned char) roundf(cyan * 0xFF / 100.0f);
66 cmyk[1] = (unsigned char) roundf(magenta * 0xFF / 100.0f);
67 cmyk[2] = (unsigned char) roundf(yellow * 0xFF / 100.0f);
68 cmyk[3] = (unsigned char) roundf(black * 0xFF / 100.0f);
69 cmyk[4] = alpha;
70 }
71
72 /* TIFF Revision 6.0 https://www.adobe.io/content/dam/udp/en/open/standards/tiff/TIFF6.pdf */
73 INTERNAL int tif_pixel_plot(struct zint_symbol *symbol, const unsigned char *pixelbuf) {
74 unsigned char fg[4], bg[4];
75 int i;
76 int pmi; /* PhotometricInterpretation */
77 int rows_per_strip, strip_count;
78 int rows_last_strip;
79 int bytes_per_strip;
80 uint16_t bits_per_sample;
81 int samples_per_pixel;
82 int pixels_per_sample;
83 unsigned char map[128];
84 tiff_color_t color_map[256] = {{0}};
85 unsigned char palette[32][5];
86 int color_map_size = 0;
87 int extra_samples = 0;
88 size_t free_memory;
89 int row, column, strip;
90 int strip_row;
91 unsigned int bytes_put;
92 long total_bytes_put;
93 struct filemem fm;
94 struct filemem *const fmp = &fm;
95 const unsigned char *pb;
96 int compression = TIF_NO_COMPRESSION;
97 tif_lzw_state lzw_state;
98 long file_pos;
99 const int output_to_stdout = symbol->output_options & BARCODE_STDOUT;
100 uint32_t *strip_offset;
101 uint32_t *strip_bytes;
102 unsigned char *strip_buf;
103
104 tiff_header_t header;
105 uint16_t entries = 0;
106 tiff_tag_t tags[20];
107 uint32_t offset = 0;
108 int update_offsets[20];
109 int offsets = 0;
110 int ifd_size;
111 uint32_t temp32;
112 uint16_t temp16;
113
114 (void) out_colour_get_rgb(symbol->fgcolour, &fg[0], &fg[1], &fg[2], &fg[3]);
115 (void) out_colour_get_rgb(symbol->bgcolour, &bg[0], &bg[1], &bg[2], &bg[3]);
116
117 if (symbol->symbology == BARCODE_ULTRA) {
118 static const unsigned char ultra_chars[8] = { 'W', 'C', 'B', 'M', 'R', 'Y', 'G', 'K' };
119
120 if (symbol->output_options & CMYK_COLOUR) {
121 static const unsigned char ultra_cmyks[8][4] = {
122 { 0, 0, 0, 0 }, /* White */
123 { 0xFF, 0, 0, 0 }, /* Cyan */
124 { 0xFF, 0xFF, 0, 0 }, /* Blue */
125 { 0, 0xFF, 0, 0 }, /* Magenta */
126 { 0, 0xFF, 0xFF, 0 }, /* Red */
127 { 0, 0, 0xFF, 0 }, /* Yellow */
128 { 0xFF, 0, 0xFF, 0 }, /* Green */
129 { 0, 0, 0, 0xFF }, /* Black */
130 };
131 for (i = 0; i < 8; i++) {
132 map[ultra_chars[i]] = i;
133 memcpy(palette[i], ultra_cmyks[i], 4);
134 palette[i][4] = fg[3];
135 }
136 map['0'] = 8;
137 to_cmyk(symbol->bgcolour, palette[8]);
138 map['1'] = 9;
139 to_cmyk(symbol->fgcolour, palette[9]);
140
141 pmi = TIF_PMI_SEPARATED;
142 bits_per_sample = 8;
143 if (fg[3] == 0xff && bg[3] == 0xff) { /* If no alpha */
144 samples_per_pixel = 4;
145 } else {
146 samples_per_pixel = 5;
147 extra_samples = 1; /* Associated alpha */
148 }
149 pixels_per_sample = 1;
150 } else {
151 static const unsigned char ultra_rgbs[8][3] = {
152 { 0xff, 0xff, 0xff, }, /* White */
153 { 0, 0xff, 0xff, }, /* Cyan */
154 { 0, 0, 0xff, }, /* Blue */
155 { 0xff, 0, 0xff, }, /* Magenta */
156 { 0xff, 0, 0, }, /* Red */
157 { 0xff, 0xff, 0, }, /* Yellow */
158 { 0, 0xff, 0, }, /* Green */
159 { 0, 0, 0, }, /* Black */
160 };
161 for (i = 0; i < 8; i++) {
162 map[ultra_chars[i]] = i;
163 memcpy(palette[i], ultra_rgbs[i], 3);
164 palette[i][3] = fg[3];
165 }
166 map['0'] = 8;
167 memcpy(palette[8], bg, 4);
168 map['1'] = 9;
169 memcpy(palette[9], fg, 4);
170
171 if (fg[3] == 0xff && bg[3] == 0xff) { /* If no alpha */
172 pmi = TIF_PMI_PALETTE_COLOR;
173 for (i = 0; i < 10; i++) {
174 to_color_map(palette[i], &color_map[i]);
175 }
176 bits_per_sample = 4;
177 samples_per_pixel = 1;
178 pixels_per_sample = 2;
179 color_map_size = 16; /* 2**BitsPerSample */
180 } else {
181 pmi = TIF_PMI_RGB;
182 bits_per_sample = 8;
183 samples_per_pixel = 4;
184 pixels_per_sample = 1;
185 extra_samples = 1; /* Associated alpha */
186 }
187 }
188 } else { /* fg/bg only */
189 if (symbol->output_options & CMYK_COLOUR) {
190 map['0'] = 0;
191 to_cmyk(symbol->bgcolour, palette[0]);
192 map['1'] = 1;
193 to_cmyk(symbol->fgcolour, palette[1]);
194
195 pmi = TIF_PMI_SEPARATED;
196 bits_per_sample = 8;
197 if (fg[3] == 0xff && bg[3] == 0xff) { /* If no alpha */
198 samples_per_pixel = 4;
199 } else {
200 samples_per_pixel = 5;
201 extra_samples = 1; /* Associated alpha */
202 }
203 pixels_per_sample = 1;
204 } else if (bg[0] == 0xff && bg[1] == 0xff && bg[2] == 0xff && bg[3] == 0xff
205 && fg[0] == 0 && fg[1] == 0 && fg[2] == 0 && fg[3] == 0xff) {
206 map['0'] = 0;
207 map['1'] = 1;
208
209 pmi = TIF_PMI_WHITEISZERO;
210 bits_per_sample = 1;
211 samples_per_pixel = 1;
212 pixels_per_sample = 8;
213 } else if (bg[0] == 0 && bg[1] == 0 && bg[2] == 0 && bg[3] == 0xff
214 && fg[0] == 0xff && fg[1] == 0xff && fg[2] == 0xff && fg[3] == 0xff) {
215 map['0'] = 0;
216 map['1'] = 1;
217
218 pmi = TIF_PMI_BLACKISZERO;
219 bits_per_sample = 1;
220 samples_per_pixel = 1;
221 pixels_per_sample = 8;
222 } else {
223 map['0'] = 0;
224 memcpy(palette[0], bg, 4);
225 map['1'] = 1;
226 memcpy(palette[1], fg, 4);
227
228 pmi = TIF_PMI_PALETTE_COLOR;
229 for (i = 0; i < 2; i++) {
230 to_color_map(palette[i], &color_map[i]);
231 }
232 if (fg[3] == 0xff && bg[3] == 0xff) { /* If no alpha */
233 bits_per_sample = 4;
234 samples_per_pixel = 1;
235 pixels_per_sample = 2;
236 color_map_size = 16; /* 2**BitsPerSample */
237 } else {
238 bits_per_sample = 8;
239 samples_per_pixel = 2;
240 pixels_per_sample = 1;
241 color_map_size = 256; /* 2**BitsPerSample */
242 extra_samples = 1; /* Associated alpha */
243 }
244 }
245 }
246
247 /* TIFF Rev 6 Section 7 p.27 "Set RowsPerStrip such that the size of each strip is about 8K bytes...
248 * Note that extremely wide high resolution images may have rows larger than 8K bytes; in this case,
249 * RowsPerStrip should be 1, and the strip will be larger than 8K." */
250 rows_per_strip = (8192 * pixels_per_sample) / (symbol->bitmap_width * samples_per_pixel);
251 if (rows_per_strip == 0) {
252 rows_per_strip = 1;
253 }
254
255 /* Suppresses clang-tidy clang-analyzer-core.VLASize warning */
256 assert(symbol->bitmap_height > 0);
257
258 if (rows_per_strip >= symbol->bitmap_height) {
259 strip_count = 1;
260 rows_per_strip = rows_last_strip = symbol->bitmap_height;
261 } else {
262 strip_count = symbol->bitmap_height / rows_per_strip;
263 rows_last_strip = symbol->bitmap_height % rows_per_strip;
264 if (rows_last_strip != 0) {
265 strip_count++;
266 }
267 if (rows_per_strip > symbol->bitmap_height) {
268 rows_per_strip = rows_last_strip = symbol->bitmap_height;
269 }
270 }
271 assert(strip_count > 0); /* Suppress clang-analyzer-core.UndefinedBinaryOperatorResult */
272
273 if (symbol->debug & ZINT_DEBUG_PRINT) {
274 printf("TIFF (%dx%d) Strip Count %d, Rows Per Strip %d, Pixels Per Sample %d, Samples Per Pixel %d, PMI %d\n",
275 symbol->bitmap_width, symbol->bitmap_height, strip_count, rows_per_strip, pixels_per_sample,
276 samples_per_pixel, pmi);
277 }
278
279 bytes_per_strip = rows_per_strip * ((symbol->bitmap_width + pixels_per_sample - 1) / pixels_per_sample)
280 * samples_per_pixel;
281
282 strip_offset = (uint32_t *) z_alloca(sizeof(uint32_t) * strip_count);
283 strip_bytes = (uint32_t *) z_alloca(sizeof(uint32_t) * strip_count);
284 strip_buf = (unsigned char *) z_alloca(bytes_per_strip + 1);
285
286 free_memory = sizeof(tiff_header_t);
287
288 for (i = 0; i < strip_count; i++) {
289 strip_offset[i] = (uint32_t) free_memory;
290 if (i != (strip_count - 1)) {
291 strip_bytes[i] = bytes_per_strip;
292 } else {
293 if (rows_last_strip) {
294 strip_bytes[i] = rows_last_strip
295 * ((symbol->bitmap_width + pixels_per_sample - 1) / pixels_per_sample)
296 * samples_per_pixel;
297 } else {
298 strip_bytes[i] = bytes_per_strip;
299 }
300 }
301 free_memory += strip_bytes[i];
302 }
303 if (free_memory & 1) {
304 free_memory++; /* IFD must be on word boundary */
305 }
306
307 if (free_memory > 0xffff0000) {
308 return errtxt(ZINT_ERROR_MEMORY, symbol, 670, "TIF output file size too big");
309 }
310
311 /* Open output file in binary mode */
312 if (!fm_open(fmp, symbol, "wb")) {
313 return errtxtf(ZINT_ERROR_FILE_ACCESS, symbol, 672, "Could not open TIF output file (%1$d: %2$s)", fmp->err,
314 strerror(fmp->err));
315 }
316 if (!output_to_stdout) {
317 compression = TIF_LZW;
318 tif_lzw_init(&lzw_state);
319 }
320
321 /* Header */
322 out_le_u16(header.byte_order, 0x4949); /* "II" little-endian */
323 out_le_u16(header.identity, 42);
324 out_le_u32(header.offset, free_memory);
325
326 fm_write(&header, sizeof(tiff_header_t), 1, fmp);
327 total_bytes_put = sizeof(tiff_header_t);
328
329 /* Pixel data */
330 pb = pixelbuf;
331 strip = 0;
332 strip_row = 0;
333 bytes_put = 0;
334 for (row = 0; row < symbol->bitmap_height; row++) {
335 if (samples_per_pixel == 1) {
336 if (bits_per_sample == 1) { /* WHITEISZERO or BLACKISZERO */
337 for (column = 0; column < symbol->bitmap_width; column += 8) {
338 unsigned char byte = 0;
339 for (i = 0; i < 8 && column + i < symbol->bitmap_width; i++, pb++) {
340 byte |= map[*pb] << (7 - i);
341 }
342 strip_buf[bytes_put++] = byte;
343 }
344 } else { /* bits_per_sample == 4, PALETTE_COLOR with no alpha */
345 for (column = 0; column < symbol->bitmap_width; column += 2) {
346 unsigned char byte = map[*pb++] << 4;
347 if (column + 1 < symbol->bitmap_width) {
348 byte |= map[*pb++];
349 }
350 strip_buf[bytes_put++] = byte;
351 }
352 }
353 } else if (samples_per_pixel == 2) { /* PALETTE_COLOR with alpha */
354 for (column = 0; column < symbol->bitmap_width; column++) {
355 const int idx = map[*pb++];
356 strip_buf[bytes_put++] = idx;
357 strip_buf[bytes_put++] = palette[idx][3];
358 }
359 } else { /* samples_per_pixel >= 4, RGB with alpha (4) or CMYK with (5) or without (4) alpha */
360 for (column = 0; column < symbol->bitmap_width; column++) {
361 const int idx = map[*pb++];
362 memcpy(&strip_buf[bytes_put], &palette[idx], samples_per_pixel);
363 bytes_put += samples_per_pixel;
364 }
365 }
366
367 strip_row++;
368
369 if (strip_row == rows_per_strip || (strip == strip_count - 1 && strip_row == rows_last_strip)) {
370 /* End of strip */
371 if (compression == TIF_LZW) {
372 file_pos = fm_tell(fmp);
373 if (!tif_lzw_encode(&lzw_state, fmp, strip_buf, bytes_put)) { /* Only fails if can't malloc */
374 tif_lzw_cleanup(&lzw_state);
375 (void) fm_close(fmp, symbol);
376 return errtxt(ZINT_ERROR_MEMORY, symbol, 673, "Insufficient memory for TIF LZW hash table");
377 }
378 bytes_put = fm_tell(fmp) - file_pos;
379 if (bytes_put != strip_bytes[strip]) {
380 const int diff = bytes_put - strip_bytes[strip];
381 strip_bytes[strip] = bytes_put;
382 for (i = strip + 1; i < strip_count; i++) {
383 strip_offset[i] += diff;
384 }
385 }
386 } else {
387 fm_write(strip_buf, 1, bytes_put, fmp);
388 }
389 strip++;
390 total_bytes_put += bytes_put;
391 bytes_put = 0;
392 strip_row = 0;
393 /* Suppress clang-analyzer-core.UndefinedBinaryOperatorResult */
394 assert(strip < strip_count || row + 1 == symbol->bitmap_height);
395 }
396 }
397
398 if (total_bytes_put & 1) {
399 fm_putc(0, fmp); /* IFD must be on word boundary */
400 total_bytes_put++;
401 }
402
403 if (compression == TIF_LZW) {
404 tif_lzw_cleanup(&lzw_state);
405
406 file_pos = fm_tell(fmp);
407 fm_seek(fmp, 4, SEEK_SET);
408 free_memory = file_pos;
409 temp32 = (uint32_t) free_memory;
410 /* Shouldn't happen as `free_memory` checked above to be <= 0xffff0000 & should only decrease */
411 if (free_memory != temp32 || (long) free_memory != file_pos) {
412 (void) fm_close(fmp, symbol);
413 return errtxt(ZINT_ERROR_MEMORY, symbol, 982, "TIF output file size too big");
414 }
415 out_le_u32(temp32, temp32);
416 fm_write(&temp32, 4, 1, fmp);
417 fm_seek(fmp, file_pos, SEEK_SET);
418 }
419
420 /* Image File Directory */
421 out_le_u16(tags[entries].tag, 0x0100); /* ImageWidth */
422 out_le_u16(tags[entries].type, 3); /* SHORT */
423 out_le_u32(tags[entries].count, 1);
424 out_le_u32(tags[entries++].offset, symbol->bitmap_width);
425
426 out_le_u16(tags[entries].tag, 0x0101); /* ImageLength - number of rows */
427 out_le_u16(tags[entries].type, 3); /* SHORT */
428 out_le_u32(tags[entries].count, 1);
429 out_le_u32(tags[entries++].offset, symbol->bitmap_height);
430
431 if (samples_per_pixel != 1 || bits_per_sample != 1) {
432 out_le_u16(tags[entries].tag, 0x0102); /* BitsPerSample */
433 out_le_u16(tags[entries].type, 3); /* SHORT */
434 out_le_u32(tags[entries].count, samples_per_pixel);
435 if (samples_per_pixel == 1) {
436 out_le_u32(tags[entries++].offset, bits_per_sample);
437 } else if (samples_per_pixel == 2) { /* 2 SHORTS fit into LONG offset so packed into offset */
438 out_le_u32(tags[entries++].offset, (bits_per_sample << 16) | bits_per_sample);
439 } else {
440 update_offsets[offsets++] = entries;
441 tags[entries++].offset = (uint32_t) free_memory;
442 free_memory += samples_per_pixel * 2;
443 }
444 }
445
446 out_le_u16(tags[entries].tag, 0x0103); /* Compression */
447 out_le_u16(tags[entries].type, 3); /* SHORT */
448 out_le_u32(tags[entries].count, 1);
449 out_le_u32(tags[entries++].offset, compression);
450
451 out_le_u16(tags[entries].tag, 0x0106); /* PhotometricInterpretation */
452 out_le_u16(tags[entries].type, 3); /* SHORT */
453 out_le_u32(tags[entries].count, 1);
454 out_le_u32(tags[entries++].offset, pmi);
455
456 out_le_u16(tags[entries].tag, 0x0111); /* StripOffsets */
457 out_le_u16(tags[entries].type, 4); /* LONG */
458 out_le_u32(tags[entries].count, strip_count);
459 if (strip_count == 1) {
460 out_le_u32(tags[entries++].offset, strip_offset[0]);
461 } else {
462 update_offsets[offsets++] = entries;
463 tags[entries++].offset = (uint32_t) free_memory;
464 free_memory += strip_count * 4;
465 }
466
467 if (samples_per_pixel > 1) {
468 out_le_u16(tags[entries].tag, 0x0115); /* SamplesPerPixel */
469 out_le_u16(tags[entries].type, 3); /* SHORT */
470 out_le_u32(tags[entries].count, 1);
471 out_le_u32(tags[entries++].offset, samples_per_pixel);
472 }
473
474 out_le_u16(tags[entries].tag, 0x0116); /* RowsPerStrip */
475 out_le_u16(tags[entries].type, 4); /* LONG */
476 out_le_u32(tags[entries].count, 1);
477 out_le_u32(tags[entries++].offset, rows_per_strip);
478
479 out_le_u16(tags[entries].tag, 0x0117); /* StripByteCounts */
480 out_le_u16(tags[entries].type, 4); /* LONG */
481 out_le_u32(tags[entries].count, strip_count);
482 if (strip_count == 1) {
483 out_le_u32(tags[entries++].offset, strip_bytes[0]);
484 } else {
485 update_offsets[offsets++] = entries;
486 tags[entries++].offset = (uint32_t) free_memory;
487 free_memory += strip_count * 4;
488 }
489
490 out_le_u16(tags[entries].tag, 0x011a); /* XResolution */
491 out_le_u16(tags[entries].type, 5); /* RATIONAL */
492 out_le_u32(tags[entries].count, 1);
493 update_offsets[offsets++] = entries;
494 tags[entries++].offset = (uint32_t) free_memory;
495 free_memory += 8;
496
497 out_le_u16(tags[entries].tag, 0x011b); /* YResolution */
498 out_le_u16(tags[entries].type, 5); /* RATIONAL */
499 out_le_u32(tags[entries].count, 1);
500 update_offsets[offsets++] = entries;
501 tags[entries++].offset = (uint32_t) free_memory;
502 free_memory += 8;
503
504 out_le_u16(tags[entries].tag, 0x0128); /* ResolutionUnit */
505 out_le_u16(tags[entries].type, 3); /* SHORT */
506 out_le_u32(tags[entries].count, 1);
507 if (symbol->dpmm) {
508 out_le_u32(tags[entries++].offset, 3); /* Centimetres */
509 } else {
510 out_le_u32(tags[entries++].offset, 2); /* Inches */
511 }
512
513 if (color_map_size) {
514 out_le_u16(tags[entries].tag, 0x0140); /* ColorMap */
515 out_le_u16(tags[entries].type, 3); /* SHORT */
516 out_le_u32(tags[entries].count, color_map_size * 3);
517 update_offsets[offsets++] = entries;
518 tags[entries++].offset = (uint32_t) free_memory;
519 /* free_memory += color_map_size * 3 * 2; Unnecessary as long as last use */
520 }
521
522 if (extra_samples) {
523 out_le_u16(tags[entries].tag, 0x0152); /* ExtraSamples */
524 out_le_u16(tags[entries].type, 3); /* SHORT */
525 out_le_u32(tags[entries].count, 1);
526 out_le_u32(tags[entries++].offset, extra_samples);
527 }
528
529 ifd_size = sizeof(entries) + sizeof(tiff_tag_t) * entries + sizeof(offset);
530 for (i = 0; i < offsets; i++) {
531 out_le_u32(tags[update_offsets[i]].offset, tags[update_offsets[i]].offset + ifd_size);
532 }
533
534 out_le_u16(temp16, entries);
535 fm_write(&temp16, sizeof(entries), 1, fmp);
536 fm_write(&tags, sizeof(tiff_tag_t), entries, fmp);
537 out_le_u32(offset, offset);
538 fm_write(&offset, sizeof(offset), 1, fmp);
539 total_bytes_put += ifd_size;
540
541 if (samples_per_pixel > 2) {
542 out_le_u16(bits_per_sample, bits_per_sample);
543 for (i = 0; i < samples_per_pixel; i++) {
544 fm_write(&bits_per_sample, sizeof(bits_per_sample), 1, fmp);
545 }
546 total_bytes_put += sizeof(bits_per_sample) * samples_per_pixel;
547 }
548
549 if (strip_count != 1) {
550 /* Strip offsets */
551 for (i = 0; i < strip_count; i++) {
552 out_le_u32(temp32, strip_offset[i]);
553 fm_write(&temp32, 4, 1, fmp);
554 }
555
556 /* Strip byte lengths */
557 for (i = 0; i < strip_count; i++) {
558 out_le_u32(temp32, strip_bytes[i]);
559 fm_write(&temp32, 4, 1, fmp);
560 }
561 total_bytes_put += strip_count * 8;
562 }
563
564 /* XResolution */
565 out_le_u32(temp32, symbol->dpmm ? symbol->dpmm : 72);
566 fm_write(&temp32, 4, 1, fmp);
567 out_le_u32(temp32, symbol->dpmm ? 10 /*cm*/ : 1);
568 fm_write(&temp32, 4, 1, fmp);
569 total_bytes_put += 8;
570
571 /* YResolution */
572 out_le_u32(temp32, symbol->dpmm ? symbol->dpmm : 72);
573 fm_write(&temp32, 4, 1, fmp);
574 out_le_u32(temp32, symbol->dpmm ? 10 /*cm*/ : 1);
575 fm_write(&temp32, 4, 1, fmp);
576 total_bytes_put += 8;
577
578 if (color_map_size) {
579 for (i = 0; i < color_map_size; i++) {
580 fm_write(&color_map[i].red, 2, 1, fmp);
581 }
582 for (i = 0; i < color_map_size; i++) {
583 fm_write(&color_map[i].green, 2, 1, fmp);
584 }
585 for (i = 0; i < color_map_size; i++) {
586 fm_write(&color_map[i].blue, 2, 1, fmp);
587 }
588 total_bytes_put += 6 * color_map_size;
589 }
590
591 if (fm_error(fmp)) {
592 errtxtf(0, symbol, 679, "Incomplete write of TIF output (%1$d: %2$s)", fmp->err, strerror(fmp->err));
593 (void) fm_close(fmp, symbol);
594 return ZINT_ERROR_FILE_WRITE;
595 }
596
597 if (!output_to_stdout) {
598 if (fm_tell(fmp) != total_bytes_put) {
599 (void) fm_close(fmp, symbol);
600 return errtxt(ZINT_ERROR_FILE_WRITE, symbol, 674, "Failed to write all TIF output");
601 }
602 }
603 if (!fm_close(fmp, symbol)) {
604 return errtxtf(ZINT_ERROR_FILE_WRITE, symbol, 981, "Failure on closing TIF output file (%1$d: %2$s)",
605 fmp->err, strerror(fmp->err));
606 }
607
608 return 0;
609 }
610
611 /* vim: set ts=4 sw=4 et : */