Mercurial > hgrepos > Python2 > PyMuPDF
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 : */ |
