Line data Source code
1 : /*
2 : * Copyright (c) 1991-1997 Sam Leffler
3 : * Copyright (c) 1991-1997 Silicon Graphics, Inc.
4 : *
5 : * Permission to use, copy, modify, distribute, and sell this software and
6 : * its documentation for any purpose is hereby granted without fee, provided
7 : * that (i) the above copyright notices and this permission notice appear in
8 : * all copies of the software and related documentation, and (ii) the names of
9 : * Sam Leffler and Silicon Graphics may not be used in any advertising or
10 : * publicity relating to the software without the specific, prior written
11 : * permission of Sam Leffler and Silicon Graphics.
12 : *
13 : * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
14 : * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
15 : * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
16 : *
17 : * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
18 : * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
19 : * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
20 : * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
21 : * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
22 : * OF THIS SOFTWARE.
23 : */
24 :
25 : /*
26 : * TIFF Library
27 : *
28 : * Read and return a packed RGBA image.
29 : */
30 : #include "tiffiop.h"
31 : #include <limits.h>
32 : #include <math.h>
33 : #include <stdio.h>
34 :
35 : static int gtTileContig(TIFFRGBAImage *, uint32_t *, uint32_t, uint32_t);
36 : static int gtTileSeparate(TIFFRGBAImage *, uint32_t *, uint32_t, uint32_t);
37 : static int gtStripContig(TIFFRGBAImage *, uint32_t *, uint32_t, uint32_t);
38 : static int gtStripSeparate(TIFFRGBAImage *, uint32_t *, uint32_t, uint32_t);
39 : static int PickContigCase(TIFFRGBAImage *);
40 : static int PickSeparateCase(TIFFRGBAImage *);
41 :
42 : static int BuildMapUaToAa(TIFFRGBAImage *img);
43 : static int BuildMapBitdepth16To8(TIFFRGBAImage *img);
44 :
45 : static const char photoTag[] = "PhotometricInterpretation";
46 :
47 : /*
48 : * Helper constants used in Orientation tag handling
49 : */
50 : #define FLIP_VERTICALLY 0x01
51 : #define FLIP_HORIZONTALLY 0x02
52 :
53 : #define EMSG_BUF_SIZE 1024
54 :
55 : /*
56 : * Color conversion constants. We will define display types here.
57 : */
58 :
59 : static const TIFFDisplay display_sRGB = {
60 : {/* XYZ -> luminance matrix */
61 : {3.2410f, -1.5374f, -0.4986f},
62 : {-0.9692f, 1.8760f, 0.0416f},
63 : {0.0556f, -0.2040f, 1.0570f}},
64 : 100.0f,
65 : 100.0f,
66 : 100.0f, /* Light o/p for reference white */
67 : 255,
68 : 255,
69 : 255, /* Pixel values for ref. white */
70 : 1.0f,
71 : 1.0f,
72 : 1.0f, /* Residual light o/p for black pixel */
73 : 2.4f,
74 : 2.4f,
75 : 2.4f, /* Gamma values for the three guns */
76 : };
77 :
78 : /*
79 : * Check the image to see if TIFFReadRGBAImage can deal with it.
80 : * 1/0 is returned according to whether or not the image can
81 : * be handled. If 0 is returned, emsg contains the reason
82 : * why it is being rejected.
83 : */
84 98 : int TIFFRGBAImageOK(TIFF *tif, char emsg[EMSG_BUF_SIZE])
85 : {
86 98 : TIFFDirectory *td = &tif->tif_dir;
87 : uint16_t photometric;
88 : int colorchannels;
89 :
90 98 : if (!tif->tif_decodestatus)
91 : {
92 0 : snprintf(emsg, EMSG_BUF_SIZE,
93 : "Sorry, requested compression method is not configured");
94 0 : return (0);
95 : }
96 98 : switch (td->td_bitspersample)
97 : {
98 98 : case 1:
99 : case 2:
100 : case 4:
101 : case 8:
102 : case 16:
103 98 : break;
104 0 : default:
105 0 : snprintf(emsg, EMSG_BUF_SIZE,
106 : "Sorry, can not handle images with %" PRIu16
107 : "-bit samples",
108 0 : td->td_bitspersample);
109 0 : return (0);
110 : }
111 98 : if (td->td_sampleformat == SAMPLEFORMAT_IEEEFP)
112 : {
113 0 : snprintf(
114 : emsg, EMSG_BUF_SIZE,
115 : "Sorry, can not handle images with IEEE floating-point samples");
116 0 : return (0);
117 : }
118 98 : colorchannels = td->td_samplesperpixel - td->td_extrasamples;
119 98 : if (!TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &photometric))
120 : {
121 0 : switch (colorchannels)
122 : {
123 0 : case 1:
124 0 : photometric = PHOTOMETRIC_MINISBLACK;
125 0 : break;
126 0 : case 3:
127 0 : photometric = PHOTOMETRIC_RGB;
128 0 : break;
129 0 : default:
130 0 : snprintf(emsg, EMSG_BUF_SIZE, "Missing needed %s tag",
131 : photoTag);
132 0 : return (0);
133 : }
134 98 : }
135 98 : switch (photometric)
136 : {
137 16 : case PHOTOMETRIC_MINISWHITE:
138 : case PHOTOMETRIC_MINISBLACK:
139 : case PHOTOMETRIC_PALETTE:
140 16 : if (td->td_planarconfig == PLANARCONFIG_CONTIG &&
141 12 : td->td_samplesperpixel != 1 && td->td_bitspersample < 8)
142 : {
143 0 : snprintf(
144 : emsg, EMSG_BUF_SIZE,
145 : "Sorry, can not handle contiguous data with %s=%" PRIu16
146 : ", "
147 : "and %s=%" PRIu16 " and Bits/Sample=%" PRIu16 "",
148 : photoTag, photometric, "Samples/pixel",
149 0 : td->td_samplesperpixel, td->td_bitspersample);
150 0 : return (0);
151 : }
152 : /*
153 : * We should likely validate that any extra samples are either
154 : * to be ignored, or are alpha, and if alpha we should try to use
155 : * them. But for now we won't bother with this.
156 : */
157 16 : break;
158 30 : case PHOTOMETRIC_YCBCR:
159 : /*
160 : * TODO: if at all meaningful and useful, make more complete
161 : * support check here, or better still, refactor to let supporting
162 : * code decide whether there is support and what meaningful
163 : * error to return
164 : */
165 30 : break;
166 32 : case PHOTOMETRIC_RGB:
167 32 : if (colorchannels < 3)
168 : {
169 0 : snprintf(emsg, EMSG_BUF_SIZE,
170 : "Sorry, can not handle RGB image with %s=%d",
171 : "Color channels", colorchannels);
172 0 : return (0);
173 : }
174 32 : break;
175 16 : case PHOTOMETRIC_SEPARATED:
176 : {
177 : uint16_t inkset;
178 16 : TIFFGetFieldDefaulted(tif, TIFFTAG_INKSET, &inkset);
179 16 : if (inkset != INKSET_CMYK)
180 : {
181 0 : snprintf(emsg, EMSG_BUF_SIZE,
182 : "Sorry, can not handle separated image with %s=%d",
183 : "InkSet", inkset);
184 0 : return 0;
185 : }
186 16 : if (td->td_samplesperpixel < 4)
187 : {
188 0 : snprintf(
189 : emsg, EMSG_BUF_SIZE,
190 : "Sorry, can not handle separated image with %s=%" PRIu16,
191 0 : "Samples/pixel", td->td_samplesperpixel);
192 0 : return 0;
193 : }
194 16 : break;
195 : }
196 2 : case PHOTOMETRIC_LOGL:
197 2 : if (td->td_compression != COMPRESSION_SGILOG)
198 : {
199 0 : snprintf(emsg, EMSG_BUF_SIZE,
200 : "Sorry, LogL data must have %s=%d", "Compression",
201 : COMPRESSION_SGILOG);
202 0 : return (0);
203 : }
204 2 : break;
205 0 : case PHOTOMETRIC_LOGLUV:
206 0 : if (td->td_compression != COMPRESSION_SGILOG &&
207 0 : td->td_compression != COMPRESSION_SGILOG24)
208 : {
209 0 : snprintf(emsg, EMSG_BUF_SIZE,
210 : "Sorry, LogLuv data must have %s=%d or %d",
211 : "Compression", COMPRESSION_SGILOG,
212 : COMPRESSION_SGILOG24);
213 0 : return (0);
214 : }
215 0 : if (td->td_planarconfig != PLANARCONFIG_CONTIG)
216 : {
217 0 : snprintf(emsg, EMSG_BUF_SIZE,
218 : "Sorry, can not handle LogLuv images with %s=%" PRIu16,
219 0 : "Planarconfiguration", td->td_planarconfig);
220 0 : return (0);
221 : }
222 0 : if (td->td_samplesperpixel != 3 || colorchannels != 3)
223 : {
224 0 : snprintf(emsg, EMSG_BUF_SIZE,
225 : "Sorry, can not handle image with %s=%" PRIu16
226 : ", %s=%d",
227 0 : "Samples/pixel", td->td_samplesperpixel,
228 : "colorchannels", colorchannels);
229 0 : return 0;
230 : }
231 0 : break;
232 2 : case PHOTOMETRIC_CIELAB:
233 2 : if (td->td_samplesperpixel != 3 || colorchannels != 3 ||
234 2 : (td->td_bitspersample != 8 && td->td_bitspersample != 16))
235 : {
236 0 : snprintf(emsg, EMSG_BUF_SIZE,
237 : "Sorry, can not handle image with %s=%" PRIu16
238 : ", %s=%d and %s=%" PRIu16,
239 0 : "Samples/pixel", td->td_samplesperpixel,
240 : "colorchannels", colorchannels, "Bits/sample",
241 0 : td->td_bitspersample);
242 0 : return 0;
243 : }
244 2 : break;
245 0 : default:
246 0 : snprintf(emsg, EMSG_BUF_SIZE,
247 : "Sorry, can not handle image with %s=%" PRIu16, photoTag,
248 : photometric);
249 0 : return (0);
250 : }
251 98 : return (1);
252 : }
253 :
254 63 : void TIFFRGBAImageEnd(TIFFRGBAImage *img)
255 : {
256 63 : if (img->Map)
257 : {
258 0 : _TIFFfreeExt(img->tif, img->Map);
259 0 : img->Map = NULL;
260 : }
261 63 : if (img->BWmap)
262 : {
263 9 : _TIFFfreeExt(img->tif, img->BWmap);
264 9 : img->BWmap = NULL;
265 : }
266 63 : if (img->PALmap)
267 : {
268 1 : _TIFFfreeExt(img->tif, img->PALmap);
269 1 : img->PALmap = NULL;
270 : }
271 63 : if (img->ycbcr)
272 : {
273 17 : _TIFFfreeExt(img->tif, img->ycbcr);
274 17 : img->ycbcr = NULL;
275 : }
276 63 : if (img->cielab)
277 : {
278 1 : _TIFFfreeExt(img->tif, img->cielab);
279 1 : img->cielab = NULL;
280 : }
281 63 : if (img->UaToAa)
282 : {
283 13 : _TIFFfreeExt(img->tif, img->UaToAa);
284 13 : img->UaToAa = NULL;
285 : }
286 63 : if (img->Bitdepth16To8)
287 : {
288 0 : _TIFFfreeExt(img->tif, img->Bitdepth16To8);
289 0 : img->Bitdepth16To8 = NULL;
290 : }
291 :
292 63 : if (img->redcmap)
293 : {
294 1 : _TIFFfreeExt(img->tif, img->redcmap);
295 1 : _TIFFfreeExt(img->tif, img->greencmap);
296 1 : _TIFFfreeExt(img->tif, img->bluecmap);
297 1 : img->redcmap = img->greencmap = img->bluecmap = NULL;
298 : }
299 63 : }
300 :
301 0 : static int isCCITTCompression(TIFF *tif)
302 : {
303 : uint16_t compress;
304 0 : TIFFGetField(tif, TIFFTAG_COMPRESSION, &compress);
305 0 : return (compress == COMPRESSION_CCITTFAX3 ||
306 0 : compress == COMPRESSION_CCITTFAX4 ||
307 0 : compress == COMPRESSION_CCITTRLE ||
308 0 : compress == COMPRESSION_CCITTRLEW);
309 : }
310 :
311 63 : int TIFFRGBAImageBegin(TIFFRGBAImage *img, TIFF *tif, int stop,
312 : char emsg[EMSG_BUF_SIZE])
313 : {
314 : uint16_t *sampleinfo;
315 : uint16_t extrasamples;
316 : uint16_t planarconfig;
317 : uint16_t compress;
318 : int colorchannels;
319 : uint16_t *red_orig, *green_orig, *blue_orig;
320 : uint32_t n_color;
321 :
322 63 : if (!TIFFRGBAImageOK(tif, emsg))
323 0 : return 0;
324 :
325 : /* Initialize to normal values */
326 63 : img->row_offset = 0;
327 63 : img->col_offset = 0;
328 63 : img->redcmap = NULL;
329 63 : img->greencmap = NULL;
330 63 : img->bluecmap = NULL;
331 63 : img->Map = NULL;
332 63 : img->BWmap = NULL;
333 63 : img->PALmap = NULL;
334 63 : img->ycbcr = NULL;
335 63 : img->cielab = NULL;
336 63 : img->UaToAa = NULL;
337 63 : img->Bitdepth16To8 = NULL;
338 63 : img->req_orientation = ORIENTATION_BOTLEFT; /* It is the default */
339 :
340 63 : img->tif = tif;
341 63 : img->stoponerr = stop;
342 63 : TIFFGetFieldDefaulted(tif, TIFFTAG_BITSPERSAMPLE, &img->bitspersample);
343 63 : switch (img->bitspersample)
344 : {
345 63 : case 1:
346 : case 2:
347 : case 4:
348 : case 8:
349 : case 16:
350 63 : break;
351 0 : default:
352 0 : snprintf(emsg, EMSG_BUF_SIZE,
353 : "Sorry, can not handle images with %" PRIu16
354 : "-bit samples",
355 0 : img->bitspersample);
356 0 : goto fail_return;
357 : }
358 63 : img->alpha = 0;
359 63 : TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLESPERPIXEL, &img->samplesperpixel);
360 63 : TIFFGetFieldDefaulted(tif, TIFFTAG_EXTRASAMPLES, &extrasamples,
361 : &sampleinfo);
362 63 : if (extrasamples >= 1)
363 : {
364 33 : switch (sampleinfo[0])
365 : {
366 14 : case EXTRASAMPLE_UNSPECIFIED: /* Workaround for some images without
367 : */
368 14 : if (img->samplesperpixel >
369 : 3) /* correct info about alpha channel */
370 13 : img->alpha = EXTRASAMPLE_ASSOCALPHA;
371 14 : break;
372 19 : case EXTRASAMPLE_ASSOCALPHA: /* data is pre-multiplied */
373 : case EXTRASAMPLE_UNASSALPHA: /* data is not pre-multiplied */
374 19 : img->alpha = sampleinfo[0];
375 19 : break;
376 0 : default:
377 0 : break;
378 : }
379 30 : }
380 :
381 : #ifdef DEFAULT_EXTRASAMPLE_AS_ALPHA
382 63 : if (!TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &img->photometric))
383 0 : img->photometric = PHOTOMETRIC_MINISWHITE;
384 :
385 63 : if (extrasamples == 0 && img->samplesperpixel == 4 &&
386 6 : img->photometric == PHOTOMETRIC_RGB)
387 : {
388 0 : img->alpha = EXTRASAMPLE_ASSOCALPHA;
389 0 : extrasamples = 1;
390 : }
391 : #endif
392 :
393 63 : colorchannels = img->samplesperpixel - extrasamples;
394 63 : TIFFGetFieldDefaulted(tif, TIFFTAG_COMPRESSION, &compress);
395 63 : TIFFGetFieldDefaulted(tif, TIFFTAG_PLANARCONFIG, &planarconfig);
396 63 : if (!TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &img->photometric))
397 : {
398 0 : switch (colorchannels)
399 : {
400 0 : case 1:
401 0 : if (isCCITTCompression(tif))
402 0 : img->photometric = PHOTOMETRIC_MINISWHITE;
403 : else
404 0 : img->photometric = PHOTOMETRIC_MINISBLACK;
405 0 : break;
406 0 : case 3:
407 0 : img->photometric = PHOTOMETRIC_RGB;
408 0 : break;
409 0 : default:
410 0 : snprintf(emsg, EMSG_BUF_SIZE, "Missing needed %s tag",
411 : photoTag);
412 0 : goto fail_return;
413 : }
414 63 : }
415 63 : switch (img->photometric)
416 : {
417 1 : case PHOTOMETRIC_PALETTE:
418 1 : if (!TIFFGetField(tif, TIFFTAG_COLORMAP, &red_orig, &green_orig,
419 : &blue_orig))
420 : {
421 0 : snprintf(emsg, EMSG_BUF_SIZE,
422 : "Missing required \"Colormap\" tag");
423 0 : goto fail_return;
424 : }
425 :
426 : /* copy the colormaps so we can modify them */
427 1 : n_color = (uint32_t)(1U << img->bitspersample);
428 2 : img->redcmap = (uint16_t *)_TIFFmallocExt(
429 1 : tif, (tmsize_t)(sizeof(uint16_t) * (size_t)n_color));
430 2 : img->greencmap = (uint16_t *)_TIFFmallocExt(
431 1 : tif, (tmsize_t)(sizeof(uint16_t) * (size_t)n_color));
432 2 : img->bluecmap = (uint16_t *)_TIFFmallocExt(
433 1 : tif, (tmsize_t)(sizeof(uint16_t) * (size_t)n_color));
434 1 : if (!img->redcmap || !img->greencmap || !img->bluecmap)
435 : {
436 0 : snprintf(emsg, EMSG_BUF_SIZE,
437 : "Out of memory for colormap copy");
438 0 : goto fail_return;
439 : }
440 :
441 1 : _TIFFmemcpy(img->redcmap, red_orig, n_color * 2);
442 1 : _TIFFmemcpy(img->greencmap, green_orig, n_color * 2);
443 1 : _TIFFmemcpy(img->bluecmap, blue_orig, n_color * 2);
444 :
445 : /* fall through... */
446 10 : case PHOTOMETRIC_MINISWHITE:
447 : case PHOTOMETRIC_MINISBLACK:
448 10 : if (planarconfig == PLANARCONFIG_CONTIG &&
449 8 : img->samplesperpixel != 1 && img->bitspersample < 8)
450 : {
451 0 : snprintf(
452 : emsg, EMSG_BUF_SIZE,
453 : "Sorry, can not handle contiguous data with %s=%" PRIu16
454 : ", "
455 : "and %s=%" PRIu16 " and Bits/Sample=%" PRIu16,
456 0 : photoTag, img->photometric, "Samples/pixel",
457 0 : img->samplesperpixel, img->bitspersample);
458 0 : goto fail_return;
459 : }
460 10 : break;
461 17 : case PHOTOMETRIC_YCBCR:
462 : /* It would probably be nice to have a reality check here. */
463 17 : if (planarconfig == PLANARCONFIG_CONTIG)
464 : /* can rely on libjpeg to convert to RGB */
465 : /* XXX should restore current state on exit */
466 17 : switch (compress)
467 : {
468 0 : case COMPRESSION_JPEG:
469 : /*
470 : * TODO: when complete tests verify complete
471 : * desubsampling and YCbCr handling, remove use of
472 : * TIFFTAG_JPEGCOLORMODE in favor of tif_getimage.c
473 : * native handling
474 : */
475 0 : TIFFSetField(tif, TIFFTAG_JPEGCOLORMODE,
476 : JPEGCOLORMODE_RGB);
477 0 : img->photometric = PHOTOMETRIC_RGB;
478 0 : break;
479 17 : default:
480 : /* do nothing */;
481 17 : break;
482 : }
483 : /*
484 : * TODO: if at all meaningful and useful, make more complete
485 : * support check here, or better still, refactor to let supporting
486 : * code decide whether there is support and what meaningful
487 : * error to return
488 : */
489 17 : break;
490 28 : case PHOTOMETRIC_RGB:
491 28 : if (colorchannels < 3)
492 : {
493 0 : snprintf(emsg, EMSG_BUF_SIZE,
494 : "Sorry, can not handle RGB image with %s=%d",
495 : "Color channels", colorchannels);
496 0 : goto fail_return;
497 : }
498 28 : break;
499 6 : case PHOTOMETRIC_SEPARATED:
500 : {
501 : uint16_t inkset;
502 6 : TIFFGetFieldDefaulted(tif, TIFFTAG_INKSET, &inkset);
503 6 : if (inkset != INKSET_CMYK)
504 : {
505 0 : snprintf(
506 : emsg, EMSG_BUF_SIZE,
507 : "Sorry, can not handle separated image with %s=%" PRIu16,
508 : "InkSet", inkset);
509 0 : goto fail_return;
510 : }
511 6 : if (img->samplesperpixel < 4)
512 : {
513 0 : snprintf(
514 : emsg, EMSG_BUF_SIZE,
515 : "Sorry, can not handle separated image with %s=%" PRIu16,
516 0 : "Samples/pixel", img->samplesperpixel);
517 0 : goto fail_return;
518 : }
519 : }
520 6 : break;
521 1 : case PHOTOMETRIC_LOGL:
522 1 : if (compress != COMPRESSION_SGILOG)
523 : {
524 0 : snprintf(emsg, EMSG_BUF_SIZE,
525 : "Sorry, LogL data must have %s=%d", "Compression",
526 : COMPRESSION_SGILOG);
527 0 : goto fail_return;
528 : }
529 1 : TIFFSetField(tif, TIFFTAG_SGILOGDATAFMT, SGILOGDATAFMT_8BIT);
530 1 : img->photometric = PHOTOMETRIC_MINISBLACK; /* little white lie */
531 1 : img->bitspersample = 8;
532 1 : break;
533 0 : case PHOTOMETRIC_LOGLUV:
534 0 : if (compress != COMPRESSION_SGILOG &&
535 0 : compress != COMPRESSION_SGILOG24)
536 : {
537 0 : snprintf(emsg, EMSG_BUF_SIZE,
538 : "Sorry, LogLuv data must have %s=%d or %d",
539 : "Compression", COMPRESSION_SGILOG,
540 : COMPRESSION_SGILOG24);
541 0 : goto fail_return;
542 : }
543 0 : if (planarconfig != PLANARCONFIG_CONTIG)
544 : {
545 0 : snprintf(emsg, EMSG_BUF_SIZE,
546 : "Sorry, can not handle LogLuv images with %s=%" PRIu16,
547 : "Planarconfiguration", planarconfig);
548 0 : return (0);
549 : }
550 0 : TIFFSetField(tif, TIFFTAG_SGILOGDATAFMT, SGILOGDATAFMT_8BIT);
551 0 : img->photometric = PHOTOMETRIC_RGB; /* little white lie */
552 0 : img->bitspersample = 8;
553 0 : break;
554 1 : case PHOTOMETRIC_CIELAB:
555 1 : break;
556 0 : default:
557 0 : snprintf(emsg, EMSG_BUF_SIZE,
558 : "Sorry, can not handle image with %s=%" PRIu16, photoTag,
559 0 : img->photometric);
560 0 : goto fail_return;
561 : }
562 63 : TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &img->width);
563 63 : TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &img->height);
564 63 : TIFFGetFieldDefaulted(tif, TIFFTAG_ORIENTATION, &img->orientation);
565 63 : img->isContig =
566 63 : !(planarconfig == PLANARCONFIG_SEPARATE && img->samplesperpixel > 1);
567 63 : if (img->isContig)
568 : {
569 60 : if (!PickContigCase(img))
570 : {
571 6 : snprintf(emsg, EMSG_BUF_SIZE, "Sorry, can not handle image");
572 6 : goto fail_return;
573 : }
574 : }
575 : else
576 : {
577 3 : if (!PickSeparateCase(img))
578 : {
579 0 : snprintf(emsg, EMSG_BUF_SIZE, "Sorry, can not handle image");
580 0 : goto fail_return;
581 : }
582 : }
583 57 : return 1;
584 :
585 6 : fail_return:
586 6 : TIFFRGBAImageEnd(img);
587 6 : return 0;
588 : }
589 :
590 57 : int TIFFRGBAImageGet(TIFFRGBAImage *img, uint32_t *raster, uint32_t w,
591 : uint32_t h)
592 : {
593 57 : if (img->get == NULL)
594 : {
595 0 : TIFFErrorExtR(img->tif, TIFFFileName(img->tif),
596 : "No \"get\" routine setup");
597 0 : return (0);
598 : }
599 57 : if (img->put.any == NULL)
600 : {
601 0 : TIFFErrorExtR(
602 : img->tif, TIFFFileName(img->tif),
603 : "No \"put\" routine setupl; probably can not handle image format");
604 0 : return (0);
605 : }
606 : /* Verify raster height against image height.
607 : * Width is checked in img->get() function individually. */
608 57 : if (0 <= img->row_offset && (uint32_t)img->row_offset < img->height)
609 57 : {
610 57 : uint32_t hx = img->height - (uint32_t)img->row_offset;
611 57 : if (h > hx)
612 : {
613 : /* Adapt parameters to read only available lines and put image
614 : * at the bottom of the raster. */
615 0 : raster += (size_t)(h - hx) * w;
616 0 : h = hx;
617 : }
618 : }
619 : else
620 : {
621 0 : TIFFErrorExtR(img->tif, TIFFFileName(img->tif),
622 : "Error in TIFFRGBAImageGet: row offset %d exceeds "
623 : "image height %u",
624 : img->row_offset, img->height);
625 0 : return 0;
626 : }
627 57 : return (*img->get)(img, raster, w, h);
628 : }
629 :
630 : /*
631 : * Read the specified image into an ABGR-format rastertaking in account
632 : * specified orientation.
633 : */
634 0 : int TIFFReadRGBAImageOriented(TIFF *tif, uint32_t rwidth, uint32_t rheight,
635 : uint32_t *raster, int orientation, int stop)
636 : {
637 0 : char emsg[EMSG_BUF_SIZE] = "";
638 : TIFFRGBAImage img;
639 : int ok;
640 :
641 0 : if (TIFFRGBAImageBegin(&img, tif, stop, emsg))
642 : {
643 0 : img.req_orientation = (uint16_t)orientation;
644 0 : ok = TIFFRGBAImageGet(&img, raster, rwidth, rheight);
645 0 : TIFFRGBAImageEnd(&img);
646 : }
647 : else
648 : {
649 0 : TIFFErrorExtR(tif, TIFFFileName(tif), "%s", emsg);
650 0 : ok = 0;
651 : }
652 0 : return (ok);
653 : }
654 :
655 : /*
656 : * Read the specified image into an ABGR-format raster. Use bottom left
657 : * origin for raster by default.
658 : */
659 0 : int TIFFReadRGBAImage(TIFF *tif, uint32_t rwidth, uint32_t rheight,
660 : uint32_t *raster, int stop)
661 : {
662 0 : return TIFFReadRGBAImageOriented(tif, rwidth, rheight, raster,
663 : ORIENTATION_BOTLEFT, stop);
664 : }
665 :
666 57 : static int setorientation(TIFFRGBAImage *img)
667 : {
668 57 : switch (img->orientation)
669 : {
670 57 : case ORIENTATION_TOPLEFT:
671 : case ORIENTATION_LEFTTOP:
672 57 : if (img->req_orientation == ORIENTATION_TOPRIGHT ||
673 57 : img->req_orientation == ORIENTATION_RIGHTTOP)
674 0 : return FLIP_HORIZONTALLY;
675 57 : else if (img->req_orientation == ORIENTATION_BOTRIGHT ||
676 57 : img->req_orientation == ORIENTATION_RIGHTBOT)
677 0 : return FLIP_HORIZONTALLY | FLIP_VERTICALLY;
678 57 : else if (img->req_orientation == ORIENTATION_BOTLEFT ||
679 0 : img->req_orientation == ORIENTATION_LEFTBOT)
680 57 : return FLIP_VERTICALLY;
681 : else
682 0 : return 0;
683 0 : case ORIENTATION_TOPRIGHT:
684 : case ORIENTATION_RIGHTTOP:
685 0 : if (img->req_orientation == ORIENTATION_TOPLEFT ||
686 0 : img->req_orientation == ORIENTATION_LEFTTOP)
687 0 : return FLIP_HORIZONTALLY;
688 0 : else if (img->req_orientation == ORIENTATION_BOTRIGHT ||
689 0 : img->req_orientation == ORIENTATION_RIGHTBOT)
690 0 : return FLIP_VERTICALLY;
691 0 : else if (img->req_orientation == ORIENTATION_BOTLEFT ||
692 0 : img->req_orientation == ORIENTATION_LEFTBOT)
693 0 : return FLIP_HORIZONTALLY | FLIP_VERTICALLY;
694 : else
695 0 : return 0;
696 0 : case ORIENTATION_BOTRIGHT:
697 : case ORIENTATION_RIGHTBOT:
698 0 : if (img->req_orientation == ORIENTATION_TOPLEFT ||
699 0 : img->req_orientation == ORIENTATION_LEFTTOP)
700 0 : return FLIP_HORIZONTALLY | FLIP_VERTICALLY;
701 0 : else if (img->req_orientation == ORIENTATION_TOPRIGHT ||
702 0 : img->req_orientation == ORIENTATION_RIGHTTOP)
703 0 : return FLIP_VERTICALLY;
704 0 : else if (img->req_orientation == ORIENTATION_BOTLEFT ||
705 0 : img->req_orientation == ORIENTATION_LEFTBOT)
706 0 : return FLIP_HORIZONTALLY;
707 : else
708 0 : return 0;
709 0 : case ORIENTATION_BOTLEFT:
710 : case ORIENTATION_LEFTBOT:
711 0 : if (img->req_orientation == ORIENTATION_TOPLEFT ||
712 0 : img->req_orientation == ORIENTATION_LEFTTOP)
713 0 : return FLIP_VERTICALLY;
714 0 : else if (img->req_orientation == ORIENTATION_TOPRIGHT ||
715 0 : img->req_orientation == ORIENTATION_RIGHTTOP)
716 0 : return FLIP_HORIZONTALLY | FLIP_VERTICALLY;
717 0 : else if (img->req_orientation == ORIENTATION_BOTRIGHT ||
718 0 : img->req_orientation == ORIENTATION_RIGHTBOT)
719 0 : return FLIP_HORIZONTALLY;
720 : else
721 0 : return 0;
722 0 : default: /* NOTREACHED */
723 0 : return 0;
724 : }
725 : }
726 :
727 : /*
728 : * Get an tile-organized image that has
729 : * PlanarConfiguration contiguous if SamplesPerPixel > 1
730 : * or
731 : * SamplesPerPixel == 1
732 : */
733 3 : static int gtTileContig(TIFFRGBAImage *img, uint32_t *raster, uint32_t w,
734 : uint32_t h)
735 : {
736 3 : TIFF *tif = img->tif;
737 3 : tileContigRoutine put = img->put.contig;
738 : uint32_t col, row, y, rowstoread;
739 : tmsize_t pos;
740 : uint32_t tw, th;
741 3 : unsigned char *buf = NULL;
742 : int32_t fromskew, toskew;
743 : uint32_t nrow;
744 3 : int ret = 1, flip;
745 : uint32_t this_tw, tocol;
746 : int32_t this_toskew, leftmost_toskew;
747 : int32_t leftmost_fromskew;
748 : uint32_t leftmost_tw;
749 : tmsize_t bufsize;
750 :
751 : /* If the raster is smaller than the image,
752 : * or if there is a col_offset, adapt the samples to be copied per row. */
753 : uint32_t wmin;
754 :
755 3 : if (0 <= img->col_offset && (uint32_t)img->col_offset < img->width)
756 : {
757 3 : wmin = TIFFmin(w, img->width - (uint32_t)img->col_offset);
758 : }
759 : else
760 : {
761 0 : TIFFErrorExtR(tif, TIFFFileName(tif),
762 : "Error in gtTileContig: column offset %d exceeds "
763 : "image width %u",
764 : img->col_offset, img->width);
765 0 : return 0;
766 : }
767 3 : bufsize = TIFFTileSize(tif);
768 3 : if (bufsize == 0)
769 : {
770 0 : TIFFErrorExtR(tif, TIFFFileName(tif), "%s", "No space for tile buffer");
771 0 : return (0);
772 : }
773 :
774 3 : TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tw);
775 3 : TIFFGetField(tif, TIFFTAG_TILELENGTH, &th);
776 :
777 3 : flip = setorientation(img);
778 3 : if (flip & FLIP_VERTICALLY)
779 : {
780 3 : if (((int64_t)tw + w) > INT_MAX)
781 : {
782 0 : TIFFErrorExtR(tif, TIFFFileName(tif), "%s",
783 : "unsupported tile size (too wide)");
784 0 : return (0);
785 : }
786 3 : y = h - 1;
787 3 : toskew = -(int32_t)(tw + w);
788 : }
789 : else
790 : {
791 0 : if (tw > ((int64_t)INT_MAX + w) || w > ((int64_t)INT_MAX + tw))
792 : {
793 0 : TIFFErrorExtR(tif, TIFFFileName(tif), "%s",
794 : "unsupported tile size (too wide)");
795 0 : return (0);
796 : }
797 0 : y = 0;
798 0 : toskew = -(int32_t)(tw - w);
799 : }
800 :
801 3 : if (tw == 0 || th == 0)
802 : {
803 0 : TIFFErrorExtR(tif, TIFFFileName(tif), "tile width or height is zero");
804 0 : return (0);
805 : }
806 :
807 : /*
808 : * Leftmost tile is clipped on left side if col_offset > 0.
809 : */
810 3 : leftmost_fromskew = (int32_t)((uint32_t)img->col_offset % tw);
811 3 : leftmost_tw = (uint32_t)((int32_t)tw - leftmost_fromskew);
812 3 : int64_t skew_i64 = (int64_t)toskew + (int64_t)(int32_t)leftmost_fromskew;
813 3 : if (skew_i64 > INT_MAX || skew_i64 < INT_MIN)
814 : {
815 0 : TIFFErrorExtR(tif, TIFFFileName(tif), "%s %" PRId64, "Invalid skew",
816 : skew_i64);
817 0 : return (0);
818 : }
819 3 : leftmost_toskew = (int32_t)skew_i64;
820 6 : for (row = 0; ret != 0 && row < h; row += nrow)
821 : {
822 3 : rowstoread = th - ((uint32_t)row + (uint32_t)img->row_offset) % th;
823 3 : nrow = (row + rowstoread > h ? h - row : rowstoread);
824 3 : fromskew = leftmost_fromskew;
825 3 : this_tw = leftmost_tw;
826 3 : this_toskew = leftmost_toskew;
827 3 : tocol = 0;
828 3 : col = (uint32_t)img->col_offset;
829 : /* wmin: only write imagewidth if raster is bigger. */
830 5 : while (tocol < wmin)
831 : {
832 3 : if (_TIFFReadTileAndAllocBuffer(tif, (void **)&buf, bufsize, col,
833 : (uint32_t)row +
834 3 : (uint32_t)img->row_offset,
835 1 : 0, 0) == (tmsize_t)(-1) &&
836 1 : (buf == NULL || img->stoponerr))
837 : {
838 1 : ret = 0;
839 1 : break;
840 : }
841 4 : pos = (((uint32_t)row + (uint32_t)img->row_offset) % th) *
842 2 : TIFFTileRowSize(tif) +
843 2 : ((tmsize_t)fromskew * img->samplesperpixel);
844 2 : if (tocol + this_tw > wmin)
845 : {
846 : /*
847 : * Rightmost tile is clipped on right side.
848 : */
849 2 : fromskew = (int32_t)(tw - (wmin - tocol));
850 2 : this_tw = (uint32_t)((int32_t)tw - fromskew);
851 2 : this_toskew = (int32_t)(toskew + (int32_t)(uint32_t)fromskew);
852 : }
853 2 : tmsize_t roffset = (tmsize_t)y * w + tocol;
854 2 : (*put)(img, raster + roffset, tocol, y, this_tw, nrow, fromskew,
855 : this_toskew, buf + pos);
856 2 : tocol += this_tw;
857 2 : col += this_tw;
858 : /*
859 : * After the leftmost tile, tiles are no longer clipped on left
860 : * side.
861 : */
862 2 : fromskew = 0;
863 2 : this_tw = tw;
864 2 : this_toskew = toskew;
865 : }
866 :
867 3 : y += (uint32_t)((flip & FLIP_VERTICALLY) ? -(int32_t)nrow
868 : : (int32_t)nrow);
869 : }
870 3 : _TIFFfreeExt(img->tif, buf);
871 :
872 3 : if (flip & FLIP_HORIZONTALLY)
873 : {
874 : uint32_t line;
875 :
876 0 : for (line = 0; line < h; line++)
877 : {
878 0 : uint32_t *left = raster + (size_t)line * w;
879 : /* Use wmin to only flip horizontally data in place and not complete
880 : * raster-row. */
881 0 : uint32_t *right = left + wmin - 1;
882 :
883 0 : while (left < right)
884 : {
885 0 : uint32_t temp = *left;
886 0 : *left = *right;
887 0 : *right = temp;
888 0 : left++;
889 0 : right--;
890 : }
891 : }
892 : }
893 :
894 3 : return (ret);
895 : }
896 :
897 : /*
898 : * Get an tile-organized image that has
899 : * SamplesPerPixel > 1
900 : * PlanarConfiguration separated
901 : * We assume that all such images are RGB.
902 : */
903 1 : static int gtTileSeparate(TIFFRGBAImage *img, uint32_t *raster, uint32_t w,
904 : uint32_t h)
905 : {
906 1 : TIFF *tif = img->tif;
907 1 : tileSeparateRoutine put = img->put.separate;
908 : uint32_t col, row, y, rowstoread;
909 : tmsize_t pos;
910 : uint32_t tw, th;
911 1 : unsigned char *buf = NULL;
912 1 : unsigned char *p0 = NULL;
913 1 : unsigned char *p1 = NULL;
914 1 : unsigned char *p2 = NULL;
915 1 : unsigned char *pa = NULL;
916 : tmsize_t tilesize;
917 : tmsize_t bufsize;
918 : int32_t fromskew, toskew;
919 1 : int alpha = img->alpha;
920 : uint32_t nrow;
921 1 : int ret = 1, flip;
922 : uint16_t colorchannels;
923 : uint32_t this_tw, tocol;
924 : int32_t this_toskew, leftmost_toskew;
925 : int32_t leftmost_fromskew;
926 : uint32_t leftmost_tw;
927 :
928 : /* If the raster is smaller than the image,
929 : * or if there is a col_offset, adapt the samples to be copied per row. */
930 : uint32_t wmin;
931 1 : if (0 <= img->col_offset && (uint32_t)img->col_offset < img->width)
932 : {
933 1 : wmin = TIFFmin(w, img->width - (uint32_t)img->col_offset);
934 : }
935 : else
936 : {
937 0 : TIFFErrorExtR(tif, TIFFFileName(tif),
938 : "Error in gtTileSeparate: column offset %d exceeds "
939 : "image width %u",
940 : img->col_offset, img->width);
941 0 : return 0;
942 : }
943 :
944 1 : tilesize = TIFFTileSize(tif);
945 : bufsize =
946 1 : _TIFFMultiplySSize(tif, alpha ? 4 : 3, tilesize, "gtTileSeparate");
947 1 : if (bufsize == 0)
948 : {
949 0 : return (0);
950 : }
951 :
952 1 : TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tw);
953 1 : TIFFGetField(tif, TIFFTAG_TILELENGTH, &th);
954 :
955 1 : flip = setorientation(img);
956 1 : if (flip & FLIP_VERTICALLY)
957 : {
958 1 : if (((int64_t)tw + w) > INT_MAX)
959 : {
960 0 : TIFFErrorExtR(tif, TIFFFileName(tif), "%s",
961 : "unsupported tile size (too wide)");
962 0 : return (0);
963 : }
964 1 : y = h - 1;
965 1 : toskew = -(int32_t)(tw + w);
966 : }
967 : else
968 : {
969 0 : if (tw > ((int64_t)INT_MAX + w) || w > ((int64_t)INT_MAX + tw))
970 : {
971 0 : TIFFErrorExtR(tif, TIFFFileName(tif), "%s",
972 : "unsupported tile size (too wide)");
973 0 : return (0);
974 : }
975 0 : y = 0;
976 0 : toskew = -(int32_t)(tw - w);
977 : }
978 :
979 1 : switch (img->photometric)
980 : {
981 0 : case PHOTOMETRIC_MINISWHITE:
982 : case PHOTOMETRIC_MINISBLACK:
983 : case PHOTOMETRIC_PALETTE:
984 0 : colorchannels = 1;
985 0 : break;
986 :
987 1 : default:
988 1 : colorchannels = 3;
989 1 : break;
990 : }
991 :
992 1 : if (tw == 0 || th == 0)
993 : {
994 0 : TIFFErrorExtR(tif, TIFFFileName(tif), "tile width or height is zero");
995 0 : return (0);
996 : }
997 :
998 : /*
999 : * Leftmost tile is clipped on left side if col_offset > 0.
1000 : */
1001 1 : leftmost_fromskew = (int32_t)((uint32_t)img->col_offset % tw);
1002 1 : leftmost_tw = (uint32_t)((int32_t)tw - leftmost_fromskew);
1003 1 : int64_t skew_i64 = (int64_t)toskew + (int64_t)(int32_t)leftmost_fromskew;
1004 1 : if (skew_i64 > INT_MAX || skew_i64 < INT_MIN)
1005 : {
1006 0 : TIFFErrorExtR(tif, TIFFFileName(tif), "%s %" PRId64, "Invalid skew",
1007 : skew_i64);
1008 0 : return (0);
1009 : }
1010 1 : leftmost_toskew = (int32_t)skew_i64;
1011 2 : for (row = 0; ret != 0 && row < h; row += nrow)
1012 : {
1013 1 : rowstoread = th - ((uint32_t)row + (uint32_t)img->row_offset) % th;
1014 1 : nrow = (row + rowstoread > h ? h - row : rowstoread);
1015 1 : fromskew = leftmost_fromskew;
1016 1 : this_tw = leftmost_tw;
1017 1 : this_toskew = leftmost_toskew;
1018 1 : tocol = 0;
1019 1 : col = (uint32_t)img->col_offset;
1020 : /* wmin: only write imagewidth if raster is bigger. */
1021 2 : while (tocol < wmin)
1022 : {
1023 1 : if (buf == NULL)
1024 : {
1025 1 : if (_TIFFReadTileAndAllocBuffer(
1026 : tif, (void **)&buf, bufsize, col,
1027 1 : (uint32_t)((int32_t)row + img->row_offset), 0,
1028 0 : 0) == (tmsize_t)(-1) &&
1029 0 : (buf == NULL || img->stoponerr))
1030 : {
1031 0 : ret = 0;
1032 0 : break;
1033 : }
1034 1 : p0 = buf;
1035 1 : if (colorchannels == 1)
1036 : {
1037 0 : p2 = p1 = p0;
1038 0 : pa = (alpha ? (p0 + 3 * tilesize) : NULL);
1039 : }
1040 : else
1041 : {
1042 1 : p1 = p0 + tilesize;
1043 1 : p2 = p1 + tilesize;
1044 1 : pa = (alpha ? (p2 + tilesize) : NULL);
1045 : }
1046 : }
1047 0 : else if (TIFFReadTile(tif, p0, col,
1048 0 : (uint32_t)((int32_t)row + img->row_offset), 0,
1049 0 : 0) == (tmsize_t)(-1) &&
1050 0 : img->stoponerr)
1051 : {
1052 0 : ret = 0;
1053 0 : break;
1054 : }
1055 2 : if (colorchannels > 1 &&
1056 1 : TIFFReadTile(tif, p1, col,
1057 1 : (uint32_t)((int32_t)row + img->row_offset), 0,
1058 0 : (uint16_t)1) == (tmsize_t)(-1) &&
1059 0 : img->stoponerr)
1060 : {
1061 0 : ret = 0;
1062 0 : break;
1063 : }
1064 2 : if (colorchannels > 1 &&
1065 1 : TIFFReadTile(tif, p2, col,
1066 1 : (uint32_t)((int32_t)row + img->row_offset), 0,
1067 0 : (uint16_t)2) == (tmsize_t)(-1) &&
1068 0 : img->stoponerr)
1069 : {
1070 0 : ret = 0;
1071 0 : break;
1072 : }
1073 1 : if (alpha &&
1074 0 : TIFFReadTile(tif, pa, col,
1075 0 : (uint32_t)((int32_t)row + img->row_offset), 0,
1076 0 : (uint16_t)colorchannels) == (tmsize_t)(-1) &&
1077 0 : img->stoponerr)
1078 : {
1079 0 : ret = 0;
1080 0 : break;
1081 : }
1082 :
1083 : /* For SEPARATE the pos-offset is per sample and should not be
1084 : * multiplied by img->samplesperpixel. */
1085 2 : pos = (tmsize_t)((uint32_t)((int32_t)row + img->row_offset) % th) *
1086 1 : TIFFTileRowSize(tif) +
1087 1 : (tmsize_t)fromskew;
1088 1 : if (tocol + this_tw > wmin)
1089 : {
1090 : /*
1091 : * Rightmost tile is clipped on right side.
1092 : */
1093 1 : fromskew = (int32_t)(tw - (wmin - tocol));
1094 1 : this_tw = (uint32_t)((int32_t)tw - fromskew);
1095 1 : this_toskew = (int32_t)(toskew + (int32_t)(uint32_t)fromskew);
1096 : }
1097 1 : tmsize_t roffset = (tmsize_t)y * w + tocol;
1098 1 : (*put)(img, raster + roffset, tocol, y, this_tw, nrow, fromskew,
1099 : this_toskew, p0 + pos, p1 + pos, p2 + pos,
1100 0 : (alpha ? (pa + pos) : NULL));
1101 1 : tocol += this_tw;
1102 1 : col += this_tw;
1103 : /*
1104 : * After the leftmost tile, tiles are no longer clipped on left
1105 : * side.
1106 : */
1107 1 : fromskew = 0;
1108 1 : this_tw = tw;
1109 1 : this_toskew = toskew;
1110 : }
1111 :
1112 1 : y += (uint32_t)((flip & FLIP_VERTICALLY) ? -(int32_t)nrow
1113 : : (int32_t)nrow);
1114 : }
1115 :
1116 1 : if (flip & FLIP_HORIZONTALLY)
1117 : {
1118 : uint32_t line;
1119 :
1120 0 : for (line = 0; line < h; line++)
1121 : {
1122 0 : uint32_t *left = raster + (size_t)line * w;
1123 : /* Use wmin to only flip horizontally data in place and not complete
1124 : * raster-row. */
1125 0 : uint32_t *right = left + wmin - 1;
1126 :
1127 0 : while (left < right)
1128 : {
1129 0 : uint32_t temp = *left;
1130 0 : *left = *right;
1131 0 : *right = temp;
1132 0 : left++;
1133 0 : right--;
1134 : }
1135 : }
1136 : }
1137 :
1138 1 : _TIFFfreeExt(img->tif, buf);
1139 1 : return (ret);
1140 : }
1141 :
1142 : /*
1143 : * Get a strip-organized image that has
1144 : * PlanarConfiguration contiguous if SamplesPerPixel > 1
1145 : * or
1146 : * SamplesPerPixel == 1
1147 : */
1148 51 : static int gtStripContig(TIFFRGBAImage *img, uint32_t *raster, uint32_t w,
1149 : uint32_t h)
1150 : {
1151 51 : TIFF *tif = img->tif;
1152 51 : tileContigRoutine put = img->put.contig;
1153 : uint32_t row, y, nrow, nrowsub, rowstoread;
1154 : tmsize_t pos;
1155 51 : unsigned char *buf = NULL;
1156 : uint32_t rowsperstrip;
1157 : uint16_t subsamplinghor, subsamplingver;
1158 51 : uint32_t imagewidth = img->width;
1159 : tmsize_t scanline;
1160 : /* fromskew, toskew are the increments within the input image or the raster
1161 : * from the end of a line to the start of the next line to read or write. */
1162 : int32_t fromskew, toskew;
1163 51 : int ret = 1, flip;
1164 : tmsize_t maxstripsize;
1165 :
1166 : /* If the raster is smaller than the image,
1167 : * or if there is a col_offset, adapt the samples to be copied per row. */
1168 : uint32_t wmin;
1169 51 : if (0 <= img->col_offset && (uint32_t)img->col_offset < imagewidth)
1170 : {
1171 51 : wmin = TIFFmin(w, imagewidth - (uint32_t)img->col_offset);
1172 : }
1173 : else
1174 : {
1175 0 : TIFFErrorExtR(tif, TIFFFileName(tif),
1176 : "Error in gtStripContig: column offset %d exceeds "
1177 : "image width %u",
1178 : img->col_offset, imagewidth);
1179 0 : return 0;
1180 : }
1181 :
1182 51 : TIFFGetFieldDefaulted(tif, TIFFTAG_YCBCRSUBSAMPLING, &subsamplinghor,
1183 : &subsamplingver);
1184 51 : if (subsamplingver == 0)
1185 : {
1186 0 : TIFFErrorExtR(tif, TIFFFileName(tif),
1187 : "Invalid vertical YCbCr subsampling");
1188 0 : return (0);
1189 : }
1190 :
1191 51 : maxstripsize = TIFFStripSize(tif);
1192 :
1193 51 : flip = setorientation(img);
1194 51 : if (flip & FLIP_VERTICALLY)
1195 : {
1196 51 : if (w > INT_MAX / 2)
1197 : {
1198 0 : TIFFErrorExtR(tif, TIFFFileName(tif), "Width overflow");
1199 0 : return (0);
1200 : }
1201 51 : y = h - 1;
1202 : /* Skew back to the raster row before the currently written row
1203 : * -> one raster width plus copied image pixels. */
1204 51 : toskew = -(int32_t)(w + wmin);
1205 : }
1206 : else
1207 : {
1208 0 : y = 0;
1209 : /* Skew forward to the end of the raster width of the row currently
1210 : * copied. */
1211 0 : toskew = (int32_t)(w - wmin);
1212 : }
1213 :
1214 51 : TIFFGetFieldDefaulted(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
1215 51 : if (rowsperstrip == 0)
1216 : {
1217 0 : TIFFErrorExtR(tif, TIFFFileName(tif), "rowsperstrip is zero");
1218 0 : return (0);
1219 : }
1220 :
1221 51 : scanline = TIFFScanlineSize(tif);
1222 51 : fromskew = (int32_t)(w < imagewidth ? imagewidth - w : 0);
1223 102 : for (row = 0; row < h; row += nrow)
1224 : {
1225 : uint32_t temp;
1226 51 : rowstoread = rowsperstrip -
1227 51 : (uint32_t)((int32_t)row + img->row_offset) % rowsperstrip;
1228 51 : nrow = (row + rowstoread > h ? h - row : rowstoread);
1229 51 : nrowsub = nrow;
1230 51 : if ((nrowsub % subsamplingver) != 0)
1231 11 : nrowsub += subsamplingver - nrowsub % subsamplingver;
1232 51 : temp =
1233 51 : (uint32_t)((int32_t)row + img->row_offset) % rowsperstrip + nrowsub;
1234 51 : if (scanline > 0 && temp > (size_t)(TIFF_TMSIZE_T_MAX / scanline))
1235 : {
1236 0 : TIFFErrorExtR(tif, TIFFFileName(tif),
1237 : "Integer overflow in gtStripContig");
1238 0 : return 0;
1239 : }
1240 51 : if (_TIFFReadEncodedStripAndAllocBuffer(
1241 : tif,
1242 : TIFFComputeStrip(tif,
1243 51 : (uint32_t)((int32_t)row + img->row_offset), 0),
1244 : (void **)(&buf), maxstripsize,
1245 51 : (tmsize_t)((size_t)temp * (size_t)scanline)) ==
1246 0 : (tmsize_t)(-1) &&
1247 0 : (buf == NULL || img->stoponerr))
1248 : {
1249 0 : ret = 0;
1250 0 : break;
1251 : }
1252 :
1253 51 : pos = (tmsize_t)((uint32_t)((int32_t)row + img->row_offset) %
1254 51 : rowsperstrip) *
1255 : scanline +
1256 51 : ((tmsize_t)img->col_offset * img->samplesperpixel);
1257 51 : tmsize_t roffset = (tmsize_t)y * w;
1258 51 : (*put)(img, raster + roffset, 0, y, wmin, nrow, fromskew, toskew,
1259 : buf + pos);
1260 51 : y += (uint32_t)((flip & FLIP_VERTICALLY) ? -(int32_t)nrow
1261 : : (int32_t)nrow);
1262 : }
1263 :
1264 51 : if (flip & FLIP_HORIZONTALLY)
1265 : {
1266 : /* Flips the complete raster matrix horizontally. If raster width is
1267 : * larger than image width, data are moved horizontally to the right
1268 : * side.
1269 : * Use wmin to only flip data in place. */
1270 : uint32_t line;
1271 :
1272 0 : for (line = 0; line < h; line++)
1273 : {
1274 0 : uint32_t *left = raster + (size_t)line * w;
1275 : /* Use wmin to only flip horizontally data in place and not complete
1276 : * raster-row. */
1277 0 : uint32_t *right = left + wmin - 1;
1278 :
1279 0 : while (left < right)
1280 : {
1281 0 : uint32_t temp = *left;
1282 0 : *left = *right;
1283 0 : *right = temp;
1284 0 : left++;
1285 0 : right--;
1286 : }
1287 : }
1288 : }
1289 :
1290 51 : _TIFFfreeExt(img->tif, buf);
1291 51 : return (ret);
1292 : }
1293 :
1294 : /*
1295 : * Get a strip-organized image with
1296 : * SamplesPerPixel > 1
1297 : * PlanarConfiguration separated
1298 : * We assume that all such images are RGB.
1299 : */
1300 2 : static int gtStripSeparate(TIFFRGBAImage *img, uint32_t *raster, uint32_t w,
1301 : uint32_t h)
1302 : {
1303 2 : TIFF *tif = img->tif;
1304 2 : tileSeparateRoutine put = img->put.separate;
1305 2 : unsigned char *buf = NULL;
1306 2 : unsigned char *p0 = NULL, *p1 = NULL, *p2 = NULL, *pa = NULL;
1307 : uint32_t row, y, nrow, rowstoread;
1308 : tmsize_t pos;
1309 : tmsize_t scanline;
1310 : uint32_t rowsperstrip, offset_row;
1311 2 : uint32_t imagewidth = img->width;
1312 : tmsize_t stripsize;
1313 : tmsize_t bufsize;
1314 : int32_t fromskew, toskew;
1315 2 : int alpha = img->alpha;
1316 2 : int ret = 1, flip;
1317 : uint16_t colorchannels;
1318 :
1319 : /* If the raster is smaller than the image,
1320 : * or if there is a col_offset, adapt the samples to be copied per row. */
1321 : uint32_t wmin;
1322 2 : if (0 <= img->col_offset && (uint32_t)img->col_offset < imagewidth)
1323 : {
1324 2 : wmin = TIFFmin(w, imagewidth - (uint32_t)img->col_offset);
1325 : }
1326 : else
1327 : {
1328 0 : TIFFErrorExtR(tif, TIFFFileName(tif),
1329 : "Error in gtStripSeparate: column offset %d exceeds "
1330 : "image width %u",
1331 : img->col_offset, imagewidth);
1332 0 : return 0;
1333 : }
1334 :
1335 2 : stripsize = TIFFStripSize(tif);
1336 : bufsize =
1337 2 : _TIFFMultiplySSize(tif, alpha ? 4 : 3, stripsize, "gtStripSeparate");
1338 2 : if (bufsize == 0)
1339 : {
1340 0 : return (0);
1341 : }
1342 :
1343 2 : flip = setorientation(img);
1344 2 : if (flip & FLIP_VERTICALLY)
1345 : {
1346 2 : if (w > INT_MAX / 2)
1347 : {
1348 0 : TIFFErrorExtR(tif, TIFFFileName(tif), "Width overflow");
1349 0 : return (0);
1350 : }
1351 2 : y = h - 1;
1352 : /* Skew back to the raster row before the currently written row
1353 : * -> one raster width plus one image width. */
1354 2 : toskew = -(int32_t)(w + wmin);
1355 : }
1356 : else
1357 : {
1358 0 : y = 0;
1359 : /* Skew forward to the end of the raster width of the row currently
1360 : * written. */
1361 0 : toskew = (int32_t)(w - wmin);
1362 : }
1363 :
1364 2 : switch (img->photometric)
1365 : {
1366 1 : case PHOTOMETRIC_MINISWHITE:
1367 : case PHOTOMETRIC_MINISBLACK:
1368 : case PHOTOMETRIC_PALETTE:
1369 1 : colorchannels = 1;
1370 1 : break;
1371 :
1372 1 : default:
1373 1 : colorchannels = 3;
1374 1 : break;
1375 : }
1376 :
1377 2 : TIFFGetFieldDefaulted(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
1378 2 : if (rowsperstrip == 0)
1379 : {
1380 0 : TIFFErrorExtR(tif, TIFFFileName(tif), "rowsperstrip is zero");
1381 0 : return (0);
1382 : }
1383 :
1384 2 : scanline = TIFFScanlineSize(tif);
1385 2 : fromskew = (int32_t)(w < imagewidth ? imagewidth - w : 0);
1386 4 : for (row = 0; row < h; row += nrow)
1387 : {
1388 : uint32_t temp;
1389 2 : rowstoread =
1390 2 : rowsperstrip -
1391 2 : ((uint32_t)((int32_t)row + img->row_offset) % rowsperstrip);
1392 2 : nrow = (row + rowstoread > h ? h - row : rowstoread);
1393 2 : offset_row = (uint32_t)((int32_t)row + img->row_offset);
1394 2 : temp = (uint32_t)((int32_t)row + img->row_offset) % rowsperstrip + nrow;
1395 2 : if (scanline > 0 && temp > (size_t)(TIFF_TMSIZE_T_MAX / scanline))
1396 : {
1397 0 : TIFFErrorExtR(tif, TIFFFileName(tif),
1398 : "Integer overflow in gtStripSeparate");
1399 0 : return 0;
1400 : }
1401 2 : if (buf == NULL)
1402 : {
1403 2 : if (_TIFFReadEncodedStripAndAllocBuffer(
1404 : tif, TIFFComputeStrip(tif, offset_row, 0), (void **)&buf,
1405 0 : bufsize, temp * scanline) == (tmsize_t)(-1) &&
1406 0 : (buf == NULL || img->stoponerr))
1407 : {
1408 0 : ret = 0;
1409 0 : break;
1410 : }
1411 2 : p0 = buf;
1412 2 : if (colorchannels == 1)
1413 : {
1414 1 : p2 = p1 = p0;
1415 1 : pa = (alpha ? (p0 + 3 * stripsize) : NULL);
1416 : }
1417 : else
1418 : {
1419 1 : p1 = p0 + stripsize;
1420 1 : p2 = p1 + stripsize;
1421 1 : pa = (alpha ? (p2 + stripsize) : NULL);
1422 : }
1423 : }
1424 0 : else if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, offset_row, 0),
1425 0 : p0, temp * scanline) == (tmsize_t)(-1) &&
1426 0 : img->stoponerr)
1427 : {
1428 0 : ret = 0;
1429 0 : break;
1430 : }
1431 3 : if (colorchannels > 1 &&
1432 1 : TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, offset_row, 1), p1,
1433 0 : temp * scanline) == (tmsize_t)(-1) &&
1434 0 : img->stoponerr)
1435 : {
1436 0 : ret = 0;
1437 0 : break;
1438 : }
1439 3 : if (colorchannels > 1 &&
1440 1 : TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, offset_row, 2), p2,
1441 0 : temp * scanline) == (tmsize_t)(-1) &&
1442 0 : img->stoponerr)
1443 : {
1444 0 : ret = 0;
1445 0 : break;
1446 : }
1447 2 : if (alpha)
1448 : {
1449 0 : if (TIFFReadEncodedStrip(
1450 : tif, TIFFComputeStrip(tif, offset_row, colorchannels), pa,
1451 0 : temp * scanline) == (tmsize_t)(-1) &&
1452 0 : img->stoponerr)
1453 : {
1454 0 : ret = 0;
1455 0 : break;
1456 : }
1457 : }
1458 :
1459 : /* For SEPARATE the pos-offset is per sample and should not be
1460 : * multiplied by img->samplesperpixel. */
1461 2 : pos = (tmsize_t)((uint32_t)((int32_t)row + img->row_offset) %
1462 2 : rowsperstrip) *
1463 : scanline +
1464 2 : (tmsize_t)img->col_offset;
1465 2 : tmsize_t roffset = (tmsize_t)y * w;
1466 2 : (*put)(img, raster + roffset, 0, y, wmin, nrow, fromskew, toskew,
1467 0 : p0 + pos, p1 + pos, p2 + pos, (alpha ? (pa + pos) : NULL));
1468 2 : y += (uint32_t)((flip & FLIP_VERTICALLY) ? -(int32_t)nrow
1469 : : (int32_t)nrow);
1470 : }
1471 :
1472 2 : if (flip & FLIP_HORIZONTALLY)
1473 : {
1474 : uint32_t line;
1475 :
1476 0 : for (line = 0; line < h; line++)
1477 : {
1478 0 : uint32_t *left = raster + (size_t)line * w;
1479 : /* Use wmin to only flip horizontally data in place and not complete
1480 : * raster-row. */
1481 0 : uint32_t *right = left + wmin - 1;
1482 :
1483 0 : while (left < right)
1484 : {
1485 0 : uint32_t temp = *left;
1486 0 : *left = *right;
1487 0 : *right = temp;
1488 0 : left++;
1489 0 : right--;
1490 : }
1491 : }
1492 : }
1493 :
1494 2 : _TIFFfreeExt(img->tif, buf);
1495 2 : return (ret);
1496 : }
1497 :
1498 : /*
1499 : * The following routines move decoded data returned
1500 : * from the TIFF library into rasters filled with packed
1501 : * ABGR pixels (i.e. suitable for passing to lrecwrite.)
1502 : *
1503 : * The routines have been created according to the most
1504 : * important cases and optimized. PickContigCase and
1505 : * PickSeparateCase analyze the parameters and select
1506 : * the appropriate "get" and "put" routine to use.
1507 : */
1508 : #define REPEAT8(op) \
1509 : REPEAT4(op); \
1510 : REPEAT4(op)
1511 : #define REPEAT4(op) \
1512 : REPEAT2(op); \
1513 : REPEAT2(op)
1514 : #define REPEAT2(op) \
1515 : op; \
1516 : op
1517 : #define CASE8(x, op) \
1518 : switch (x) \
1519 : { \
1520 : case 7: \
1521 : op; /*-fallthrough*/ \
1522 : case 6: \
1523 : op; /*-fallthrough*/ \
1524 : case 5: \
1525 : op; /*-fallthrough*/ \
1526 : case 4: \
1527 : op; /*-fallthrough*/ \
1528 : case 3: \
1529 : op; /*-fallthrough*/ \
1530 : case 2: \
1531 : op; /*-fallthrough*/ \
1532 : case 1: \
1533 : op; \
1534 : break; \
1535 : default: \
1536 : break; \
1537 : }
1538 : #define CASE4(x, op) \
1539 : switch (x) \
1540 : { \
1541 : case 3: \
1542 : op; /*-fallthrough*/ \
1543 : case 2: \
1544 : op; /*-fallthrough*/ \
1545 : case 1: \
1546 : op; \
1547 : break; \
1548 : default: \
1549 : break; \
1550 : }
1551 : #define NOP
1552 :
1553 : #define UNROLL8(w, op1, op2) \
1554 : { \
1555 : uint32_t _x; \
1556 : for (_x = w; _x >= 8; _x -= 8) \
1557 : { \
1558 : op1; \
1559 : REPEAT8(op2); \
1560 : } \
1561 : if (_x > 0) \
1562 : { \
1563 : op1; \
1564 : CASE8(_x, op2); \
1565 : } \
1566 : }
1567 : #define UNROLL4(w, op1, op2) \
1568 : { \
1569 : uint32_t _x; \
1570 : for (_x = w; _x >= 4; _x -= 4) \
1571 : { \
1572 : op1; \
1573 : REPEAT4(op2); \
1574 : } \
1575 : if (_x > 0) \
1576 : { \
1577 : op1; \
1578 : CASE4(_x, op2); \
1579 : } \
1580 : }
1581 : #define UNROLL2(w, op1, op2) \
1582 : { \
1583 : uint32_t _x; \
1584 : for (_x = w; _x >= 2; _x -= 2) \
1585 : { \
1586 : op1; \
1587 : REPEAT2(op2); \
1588 : } \
1589 : if (_x) \
1590 : { \
1591 : op1; \
1592 : op2; \
1593 : } \
1594 : }
1595 :
1596 : #define SKEW(r, g, b, skew) \
1597 : { \
1598 : r += skew; \
1599 : g += skew; \
1600 : b += skew; \
1601 : }
1602 : #define SKEW4(r, g, b, a, skew) \
1603 : { \
1604 : r += skew; \
1605 : g += skew; \
1606 : b += skew; \
1607 : a += skew; \
1608 : }
1609 :
1610 : #define A1 (((uint32_t)0xffL) << 24)
1611 : #define PACK(r, g, b) \
1612 : ((uint32_t)(r) | ((uint32_t)(g) << 8) | ((uint32_t)(b) << 16) | A1)
1613 : #define PACK4(r, g, b, a) \
1614 : ((uint32_t)(r) | ((uint32_t)(g) << 8) | ((uint32_t)(b) << 16) | \
1615 : ((uint32_t)(a) << 24))
1616 :
1617 : #define DECLAREContigPutFunc(name) \
1618 : static void name(TIFFRGBAImage *img, uint32_t *cp, uint32_t x, uint32_t y, \
1619 : uint32_t w, uint32_t h, int32_t fromskew, int32_t toskew, \
1620 : unsigned char *pp)
1621 :
1622 : /*
1623 : * 8-bit palette => colormap/RGB
1624 : */
1625 1 : DECLAREContigPutFunc(put8bitcmaptile)
1626 : {
1627 1 : uint32_t **PALmap = img->PALmap;
1628 1 : int samplesperpixel = img->samplesperpixel;
1629 : /* Convert pixel skew to byte skew (8-bit samples) */
1630 1 : const tmsize_t fromskewLocal =
1631 1 : (tmsize_t)fromskew * +(tmsize_t)samplesperpixel;
1632 :
1633 : (void)y;
1634 21 : for (; h > 0; --h)
1635 : {
1636 420 : for (x = w; x > 0; --x)
1637 : {
1638 400 : *cp++ = PALmap[*pp][0];
1639 400 : pp += samplesperpixel;
1640 : }
1641 20 : cp += toskew;
1642 20 : pp += fromskewLocal;
1643 : }
1644 1 : }
1645 :
1646 : /*
1647 : * 4-bit palette => colormap/RGB
1648 : */
1649 0 : DECLAREContigPutFunc(put4bitcmaptile)
1650 : {
1651 0 : uint32_t **PALmap = img->PALmap;
1652 :
1653 : (void)x;
1654 : (void)y;
1655 0 : fromskew /= 2;
1656 0 : for (; h > 0; --h)
1657 : {
1658 : uint32_t *bw;
1659 0 : UNROLL2(w, bw = PALmap[*pp++], *cp++ = *bw++);
1660 0 : cp += toskew;
1661 0 : pp += fromskew;
1662 : }
1663 0 : }
1664 :
1665 : /*
1666 : * 2-bit palette => colormap/RGB
1667 : */
1668 0 : DECLAREContigPutFunc(put2bitcmaptile)
1669 : {
1670 0 : uint32_t **PALmap = img->PALmap;
1671 :
1672 : (void)x;
1673 : (void)y;
1674 0 : fromskew /= 4;
1675 0 : for (; h > 0; --h)
1676 : {
1677 : uint32_t *bw;
1678 0 : UNROLL4(w, bw = PALmap[*pp++], *cp++ = *bw++);
1679 0 : cp += toskew;
1680 0 : pp += fromskew;
1681 : }
1682 0 : }
1683 :
1684 : /*
1685 : * 1-bit palette => colormap/RGB
1686 : */
1687 0 : DECLAREContigPutFunc(put1bitcmaptile)
1688 : {
1689 0 : uint32_t **PALmap = img->PALmap;
1690 :
1691 : (void)x;
1692 : (void)y;
1693 0 : fromskew /= 8;
1694 0 : for (; h > 0; --h)
1695 : {
1696 : uint32_t *bw;
1697 0 : UNROLL8(w, bw = PALmap[*pp++], *cp++ = *bw++);
1698 0 : cp += toskew;
1699 0 : pp += fromskew;
1700 : }
1701 0 : }
1702 :
1703 : /*
1704 : * 8-bit greyscale => colormap/RGB
1705 : */
1706 3 : DECLAREContigPutFunc(putgreytile)
1707 : {
1708 3 : int samplesperpixel = img->samplesperpixel;
1709 3 : uint32_t **BWmap = img->BWmap;
1710 : /* Convert pixel skew to byte skew (8-bit samples) */
1711 3 : const tmsize_t fromskewLocal =
1712 3 : (tmsize_t)fromskew * +(tmsize_t)samplesperpixel;
1713 :
1714 : (void)y;
1715 63 : for (; h > 0; --h)
1716 : {
1717 1260 : for (x = w; x > 0; --x)
1718 : {
1719 1200 : *cp++ = BWmap[*pp][0];
1720 1200 : pp += samplesperpixel;
1721 : }
1722 60 : cp += toskew;
1723 60 : pp += fromskewLocal;
1724 : }
1725 3 : }
1726 :
1727 : /*
1728 : * 8-bit greyscale with associated alpha => colormap/RGBA
1729 : */
1730 6 : DECLAREContigPutFunc(putagreytile)
1731 : {
1732 6 : int samplesperpixel = img->samplesperpixel;
1733 6 : uint32_t **BWmap = img->BWmap;
1734 : /* Convert pixel skew to byte skew (8-bit samples) */
1735 6 : const tmsize_t fromskewLocal =
1736 6 : (tmsize_t)fromskew * +(tmsize_t)samplesperpixel;
1737 :
1738 : (void)y;
1739 156 : for (; h > 0; --h)
1740 : {
1741 24450 : for (x = w; x > 0; --x)
1742 : {
1743 24300 : *cp++ = BWmap[*pp][0] & ((uint32_t)*(pp + 1) << 24 | ~A1);
1744 24300 : pp += samplesperpixel;
1745 : }
1746 150 : cp += toskew;
1747 150 : pp += fromskewLocal;
1748 : }
1749 6 : }
1750 :
1751 : /*
1752 : * 16-bit greyscale => colormap/RGB
1753 : */
1754 0 : DECLAREContigPutFunc(put16bitbwtile)
1755 : {
1756 0 : int samplesperpixel = img->samplesperpixel;
1757 0 : uint32_t **BWmap = img->BWmap;
1758 : /* Convert pixel skew to byte skew (16-bit samples) */
1759 0 : const tmsize_t fromskewLocal =
1760 0 : (tmsize_t)fromskew * (tmsize_t)(2 * samplesperpixel);
1761 :
1762 : (void)y;
1763 0 : for (; h > 0; --h)
1764 : {
1765 0 : uint16_t *wp = (uint16_t *)pp;
1766 :
1767 0 : for (x = w; x > 0; --x)
1768 : {
1769 : /* use high order byte of 16bit value */
1770 :
1771 0 : *cp++ = BWmap[*wp >> 8][0];
1772 0 : pp += 2 * samplesperpixel;
1773 0 : wp += samplesperpixel;
1774 : }
1775 0 : cp += toskew;
1776 0 : pp += fromskewLocal;
1777 : }
1778 0 : }
1779 :
1780 : /*
1781 : * 1-bit bilevel => colormap/RGB
1782 : */
1783 0 : DECLAREContigPutFunc(put1bitbwtile)
1784 : {
1785 0 : uint32_t **BWmap = img->BWmap;
1786 :
1787 : (void)x;
1788 : (void)y;
1789 0 : fromskew /= 8;
1790 0 : for (; h > 0; --h)
1791 : {
1792 : uint32_t *bw;
1793 0 : UNROLL8(w, bw = BWmap[*pp++], *cp++ = *bw++);
1794 0 : cp += toskew;
1795 0 : pp += fromskew;
1796 : }
1797 0 : }
1798 :
1799 : /*
1800 : * 2-bit greyscale => colormap/RGB
1801 : */
1802 0 : DECLAREContigPutFunc(put2bitbwtile)
1803 : {
1804 0 : uint32_t **BWmap = img->BWmap;
1805 :
1806 : (void)x;
1807 : (void)y;
1808 0 : fromskew /= 4;
1809 0 : for (; h > 0; --h)
1810 : {
1811 : uint32_t *bw;
1812 0 : UNROLL4(w, bw = BWmap[*pp++], *cp++ = *bw++);
1813 0 : cp += toskew;
1814 0 : pp += fromskew;
1815 : }
1816 0 : }
1817 :
1818 : /*
1819 : * 4-bit greyscale => colormap/RGB
1820 : */
1821 0 : DECLAREContigPutFunc(put4bitbwtile)
1822 : {
1823 0 : uint32_t **BWmap = img->BWmap;
1824 :
1825 : (void)x;
1826 : (void)y;
1827 0 : fromskew /= 2;
1828 0 : for (; h > 0; --h)
1829 : {
1830 : uint32_t *bw;
1831 0 : UNROLL2(w, bw = BWmap[*pp++], *cp++ = *bw++);
1832 0 : cp += toskew;
1833 0 : pp += fromskew;
1834 : }
1835 0 : }
1836 :
1837 : /*
1838 : * 8-bit packed samples, no Map => RGB
1839 : */
1840 0 : DECLAREContigPutFunc(putRGBcontig8bittile)
1841 : {
1842 0 : int samplesperpixel = img->samplesperpixel;
1843 :
1844 : (void)x;
1845 : (void)y;
1846 0 : const tmsize_t fromskewLocal =
1847 0 : (tmsize_t)fromskew * (tmsize_t)samplesperpixel;
1848 0 : for (; h > 0; --h)
1849 : {
1850 0 : UNROLL8(w, NOP, *cp++ = PACK(pp[0], pp[1], pp[2]);
1851 : pp += samplesperpixel);
1852 0 : cp += toskew;
1853 0 : pp += fromskewLocal;
1854 : }
1855 0 : }
1856 :
1857 : /*
1858 : * 8-bit packed samples => RGBA w/ associated alpha
1859 : * (known to have Map == NULL)
1860 : */
1861 13 : DECLAREContigPutFunc(putRGBAAcontig8bittile)
1862 : {
1863 13 : int samplesperpixel = img->samplesperpixel;
1864 :
1865 : (void)x;
1866 : (void)y;
1867 13 : const tmsize_t fromskewLocal =
1868 13 : (tmsize_t)fromskew * (tmsize_t)samplesperpixel;
1869 163 : for (; h > 0; --h)
1870 : {
1871 3150 : UNROLL8(w, NOP, *cp++ = PACK4(pp[0], pp[1], pp[2], pp[3]);
1872 : pp += samplesperpixel);
1873 150 : cp += toskew;
1874 150 : pp += fromskewLocal;
1875 : }
1876 13 : }
1877 :
1878 : /*
1879 : * 8-bit packed samples => RGBA w/ unassociated alpha
1880 : * (known to have Map == NULL)
1881 : */
1882 13 : DECLAREContigPutFunc(putRGBUAcontig8bittile)
1883 : {
1884 13 : int samplesperpixel = img->samplesperpixel;
1885 : (void)y;
1886 13 : const tmsize_t fromskewLocal =
1887 13 : (tmsize_t)fromskew * (tmsize_t)samplesperpixel;
1888 163 : for (; h > 0; --h)
1889 : {
1890 : uint32_t r, g, b, a;
1891 : uint8_t *m;
1892 24450 : for (x = w; x > 0; --x)
1893 : {
1894 24300 : a = pp[3];
1895 24300 : m = img->UaToAa + ((size_t)a << 8);
1896 24300 : r = m[pp[0]];
1897 24300 : g = m[pp[1]];
1898 24300 : b = m[pp[2]];
1899 24300 : *cp++ = PACK4(r, g, b, a);
1900 24300 : pp += samplesperpixel;
1901 : }
1902 150 : cp += toskew;
1903 150 : pp += fromskewLocal;
1904 : }
1905 13 : }
1906 :
1907 : /*
1908 : * 16-bit packed samples => RGB
1909 : */
1910 0 : DECLAREContigPutFunc(putRGBcontig16bittile)
1911 : {
1912 0 : int samplesperpixel = img->samplesperpixel;
1913 0 : uint16_t *wp = (uint16_t *)pp;
1914 : (void)y;
1915 0 : const tmsize_t fromskewLocal =
1916 0 : (tmsize_t)fromskew * (tmsize_t)samplesperpixel;
1917 0 : for (; h > 0; --h)
1918 : {
1919 0 : for (x = w; x > 0; --x)
1920 : {
1921 0 : *cp++ = PACK(img->Bitdepth16To8[wp[0]], img->Bitdepth16To8[wp[1]],
1922 : img->Bitdepth16To8[wp[2]]);
1923 0 : wp += samplesperpixel;
1924 : }
1925 0 : cp += toskew;
1926 0 : wp += fromskewLocal;
1927 : }
1928 0 : }
1929 :
1930 : /*
1931 : * 16-bit packed samples => RGBA w/ associated alpha
1932 : * (known to have Map == NULL)
1933 : */
1934 0 : DECLAREContigPutFunc(putRGBAAcontig16bittile)
1935 : {
1936 0 : int samplesperpixel = img->samplesperpixel;
1937 0 : uint16_t *wp = (uint16_t *)pp;
1938 : (void)y;
1939 0 : const tmsize_t fromskewLocal =
1940 0 : (tmsize_t)fromskew * (tmsize_t)samplesperpixel;
1941 0 : for (; h > 0; --h)
1942 : {
1943 0 : for (x = w; x > 0; --x)
1944 : {
1945 0 : *cp++ = PACK4(img->Bitdepth16To8[wp[0]], img->Bitdepth16To8[wp[1]],
1946 : img->Bitdepth16To8[wp[2]], img->Bitdepth16To8[wp[3]]);
1947 0 : wp += samplesperpixel;
1948 : }
1949 0 : cp += toskew;
1950 0 : wp += fromskewLocal;
1951 : }
1952 0 : }
1953 :
1954 : /*
1955 : * 16-bit packed samples => RGBA w/ unassociated alpha
1956 : * (known to have Map == NULL)
1957 : */
1958 0 : DECLAREContigPutFunc(putRGBUAcontig16bittile)
1959 : {
1960 0 : int samplesperpixel = img->samplesperpixel;
1961 0 : uint16_t *wp = (uint16_t *)pp;
1962 : (void)y;
1963 0 : const tmsize_t fromskewLocal =
1964 0 : (tmsize_t)fromskew * (tmsize_t)samplesperpixel;
1965 0 : for (; h > 0; --h)
1966 : {
1967 : uint32_t r, g, b, a;
1968 : uint8_t *m;
1969 0 : for (x = w; x > 0; --x)
1970 : {
1971 0 : a = img->Bitdepth16To8[wp[3]];
1972 0 : m = img->UaToAa + ((size_t)a << 8);
1973 0 : r = m[img->Bitdepth16To8[wp[0]]];
1974 0 : g = m[img->Bitdepth16To8[wp[1]]];
1975 0 : b = m[img->Bitdepth16To8[wp[2]]];
1976 0 : *cp++ = PACK4(r, g, b, a);
1977 0 : wp += samplesperpixel;
1978 : }
1979 0 : cp += toskew;
1980 0 : wp += fromskewLocal;
1981 : }
1982 0 : }
1983 :
1984 : /*
1985 : * 8-bit packed CMYK samples w/o Map => RGB
1986 : *
1987 : * NB: The conversion of CMYK->RGB is *very* crude.
1988 : */
1989 6 : DECLAREContigPutFunc(putRGBcontig8bitCMYKtile)
1990 : {
1991 6 : int samplesperpixel = img->samplesperpixel;
1992 : uint16_t r, g, b, k;
1993 :
1994 : (void)x;
1995 : (void)y;
1996 6 : const tmsize_t fromskewLocal =
1997 6 : (tmsize_t)fromskew * (tmsize_t)samplesperpixel;
1998 156 : for (; h > 0; --h)
1999 : {
2000 1050 : UNROLL8(w, NOP, k = (uint16_t)(255 - pp[3]);
2001 : r = (uint16_t)((k * (uint16_t)(255 - pp[0])) / 255);
2002 : g = (uint16_t)((k * (uint16_t)(255 - pp[1])) / 255);
2003 : b = (uint16_t)((k * (uint16_t)(255 - pp[2])) / 255);
2004 : *cp++ = PACK(r, g, b); pp += samplesperpixel);
2005 150 : cp += toskew;
2006 150 : pp += fromskewLocal;
2007 : }
2008 6 : }
2009 :
2010 : /*
2011 : * 8-bit packed CMYK samples w/Map => RGB
2012 : *
2013 : * NB: The conversion of CMYK->RGB is *very* crude.
2014 : */
2015 0 : DECLAREContigPutFunc(putRGBcontig8bitCMYKMaptile)
2016 : {
2017 0 : int samplesperpixel = img->samplesperpixel;
2018 0 : TIFFRGBValue *Map = img->Map;
2019 : unsigned int r, g, b, k;
2020 :
2021 : (void)y;
2022 0 : const tmsize_t fromskewLocal =
2023 0 : (tmsize_t)fromskew * (tmsize_t)samplesperpixel;
2024 0 : for (; h > 0; --h)
2025 : {
2026 0 : for (x = w; x > 0; --x)
2027 : {
2028 0 : k = 255U - pp[3];
2029 0 : r = (k * (255U - pp[0])) / 255U;
2030 0 : g = (k * (255U - pp[1])) / 255U;
2031 0 : b = (k * (255U - pp[2])) / 255U;
2032 0 : *cp++ = PACK(Map[r], Map[g], Map[b]);
2033 0 : pp += samplesperpixel;
2034 : }
2035 0 : pp += fromskewLocal;
2036 0 : cp += toskew;
2037 : }
2038 0 : }
2039 :
2040 : #define DECLARESepPutFunc(name) \
2041 : static void name(TIFFRGBAImage *img, uint32_t *cp, uint32_t x, uint32_t y, \
2042 : uint32_t w, uint32_t h, int32_t fromskew, int32_t toskew, \
2043 : unsigned char *r, unsigned char *g, unsigned char *b, \
2044 : unsigned char *a)
2045 :
2046 : /*
2047 : * 8-bit unpacked samples => RGB
2048 : */
2049 3 : DECLARESepPutFunc(putRGBseparate8bittile)
2050 : {
2051 : (void)img;
2052 : (void)x;
2053 : (void)y;
2054 : (void)a;
2055 153 : for (; h > 0; --h)
2056 : {
2057 1050 : UNROLL8(w, NOP, *cp++ = PACK(*r++, *g++, *b++));
2058 150 : SKEW(r, g, b, fromskew);
2059 150 : cp += toskew;
2060 : }
2061 3 : }
2062 :
2063 : /*
2064 : * 8-bit unpacked samples => RGBA w/ associated alpha
2065 : */
2066 0 : DECLARESepPutFunc(putRGBAAseparate8bittile)
2067 : {
2068 : (void)img;
2069 : (void)x;
2070 : (void)y;
2071 0 : for (; h > 0; --h)
2072 : {
2073 0 : UNROLL8(w, NOP, *cp++ = PACK4(*r++, *g++, *b++, *a++));
2074 0 : SKEW4(r, g, b, a, fromskew);
2075 0 : cp += toskew;
2076 : }
2077 0 : }
2078 :
2079 : /*
2080 : * 8-bit unpacked CMYK samples => RGBA
2081 : */
2082 0 : DECLARESepPutFunc(putCMYKseparate8bittile)
2083 : {
2084 : (void)img;
2085 : (void)y;
2086 0 : for (; h > 0; --h)
2087 : {
2088 : unsigned int rv, gv, bv, kv;
2089 0 : for (x = w; x > 0; --x)
2090 : {
2091 0 : kv = 255U - *a++;
2092 0 : rv = (kv * (255U - *r++)) / 255U;
2093 0 : gv = (kv * (255U - *g++)) / 255U;
2094 0 : bv = (kv * (255U - *b++)) / 255U;
2095 0 : *cp++ = PACK4(rv, gv, bv, 255);
2096 : }
2097 0 : SKEW4(r, g, b, a, fromskew);
2098 0 : cp += toskew;
2099 : }
2100 0 : }
2101 :
2102 : /*
2103 : * 8-bit unpacked samples => RGBA w/ unassociated alpha
2104 : */
2105 0 : DECLARESepPutFunc(putRGBUAseparate8bittile)
2106 : {
2107 : (void)img;
2108 : (void)y;
2109 0 : for (; h > 0; --h)
2110 : {
2111 : uint32_t rv, gv, bv, av;
2112 : uint8_t *m;
2113 0 : for (x = w; x > 0; --x)
2114 : {
2115 0 : av = *a++;
2116 0 : m = img->UaToAa + ((size_t)av << 8);
2117 0 : rv = m[*r++];
2118 0 : gv = m[*g++];
2119 0 : bv = m[*b++];
2120 0 : *cp++ = PACK4(rv, gv, bv, av);
2121 : }
2122 0 : SKEW4(r, g, b, a, fromskew);
2123 0 : cp += toskew;
2124 : }
2125 0 : }
2126 :
2127 : /*
2128 : * 16-bit unpacked samples => RGB
2129 : */
2130 0 : DECLARESepPutFunc(putRGBseparate16bittile)
2131 : {
2132 0 : uint16_t *wr = (uint16_t *)r;
2133 0 : uint16_t *wg = (uint16_t *)g;
2134 0 : uint16_t *wb = (uint16_t *)b;
2135 : (void)img;
2136 : (void)y;
2137 : (void)a;
2138 0 : for (; h > 0; --h)
2139 : {
2140 0 : for (x = 0; x < w; x++)
2141 0 : *cp++ = PACK(img->Bitdepth16To8[*wr++], img->Bitdepth16To8[*wg++],
2142 : img->Bitdepth16To8[*wb++]);
2143 0 : SKEW(wr, wg, wb, fromskew);
2144 0 : cp += toskew;
2145 : }
2146 0 : }
2147 :
2148 : /*
2149 : * 16-bit unpacked samples => RGBA w/ associated alpha
2150 : */
2151 0 : DECLARESepPutFunc(putRGBAAseparate16bittile)
2152 : {
2153 0 : uint16_t *wr = (uint16_t *)r;
2154 0 : uint16_t *wg = (uint16_t *)g;
2155 0 : uint16_t *wb = (uint16_t *)b;
2156 0 : uint16_t *wa = (uint16_t *)a;
2157 : (void)img;
2158 : (void)y;
2159 0 : for (; h > 0; --h)
2160 : {
2161 0 : for (x = 0; x < w; x++)
2162 0 : *cp++ = PACK4(img->Bitdepth16To8[*wr++], img->Bitdepth16To8[*wg++],
2163 : img->Bitdepth16To8[*wb++], img->Bitdepth16To8[*wa++]);
2164 0 : SKEW4(wr, wg, wb, wa, fromskew);
2165 0 : cp += toskew;
2166 : }
2167 0 : }
2168 :
2169 : /*
2170 : * 16-bit unpacked samples => RGBA w/ unassociated alpha
2171 : */
2172 0 : DECLARESepPutFunc(putRGBUAseparate16bittile)
2173 : {
2174 0 : uint16_t *wr = (uint16_t *)r;
2175 0 : uint16_t *wg = (uint16_t *)g;
2176 0 : uint16_t *wb = (uint16_t *)b;
2177 0 : uint16_t *wa = (uint16_t *)a;
2178 : (void)img;
2179 : (void)y;
2180 0 : for (; h > 0; --h)
2181 : {
2182 : uint32_t r2, g2, b2, a2;
2183 : uint8_t *m;
2184 0 : for (x = w; x > 0; --x)
2185 : {
2186 0 : a2 = img->Bitdepth16To8[*wa++];
2187 0 : m = img->UaToAa + ((size_t)a2 << 8);
2188 0 : r2 = m[img->Bitdepth16To8[*wr++]];
2189 0 : g2 = m[img->Bitdepth16To8[*wg++]];
2190 0 : b2 = m[img->Bitdepth16To8[*wb++]];
2191 0 : *cp++ = PACK4(r2, g2, b2, a2);
2192 : }
2193 0 : SKEW4(wr, wg, wb, wa, fromskew);
2194 0 : cp += toskew;
2195 : }
2196 0 : }
2197 :
2198 : /*
2199 : * 8-bit packed CIE L*a*b 1976 samples => RGB
2200 : */
2201 1 : DECLAREContigPutFunc(putcontig8bitCIELab8)
2202 : {
2203 : float X, Y, Z;
2204 : uint32_t r, g, b;
2205 : (void)y;
2206 1 : const tmsize_t fromskewLocal = (tmsize_t)fromskew * (tmsize_t)3;
2207 2 : for (; h > 0; --h)
2208 : {
2209 2 : for (x = w; x > 0; --x)
2210 : {
2211 1 : TIFFCIELabToXYZ(img->cielab, (unsigned char)pp[0],
2212 1 : (signed char)pp[1], (signed char)pp[2], &X, &Y, &Z);
2213 1 : TIFFXYZToRGB(img->cielab, X, Y, Z, &r, &g, &b);
2214 1 : *cp++ = PACK(r, g, b);
2215 1 : pp += 3;
2216 : }
2217 1 : cp += toskew;
2218 1 : pp += fromskewLocal;
2219 : }
2220 1 : }
2221 :
2222 : /*
2223 : * 16-bit packed CIE L*a*b 1976 samples => RGB
2224 : */
2225 0 : DECLAREContigPutFunc(putcontig8bitCIELab16)
2226 : {
2227 : float X, Y, Z;
2228 : uint32_t r, g, b;
2229 0 : uint16_t *wp = (uint16_t *)pp;
2230 : (void)y;
2231 0 : const tmsize_t fromskewLocal = (tmsize_t)fromskew * (tmsize_t)3;
2232 0 : for (; h > 0; --h)
2233 : {
2234 0 : for (x = w; x > 0; --x)
2235 : {
2236 0 : TIFFCIELab16ToXYZ(img->cielab, (uint16_t)wp[0], (int16_t)wp[1],
2237 0 : (int16_t)wp[2], &X, &Y, &Z);
2238 0 : TIFFXYZToRGB(img->cielab, X, Y, Z, &r, &g, &b);
2239 0 : *cp++ = PACK(r, g, b);
2240 0 : wp += 3;
2241 : }
2242 0 : cp += toskew;
2243 0 : wp += fromskewLocal;
2244 : }
2245 0 : }
2246 :
2247 : /*
2248 : * YCbCr -> RGB conversion and packing routines.
2249 : */
2250 :
2251 : #define YCbCrtoRGB(dst, Y) \
2252 : { \
2253 : uint32_t r, g, b; \
2254 : TIFFYCbCrtoRGB(img->ycbcr, (Y), (int32_t)Cb, (int32_t)Cr, &r, &g, &b); \
2255 : dst = PACK(r, g, b); \
2256 : }
2257 :
2258 : /*
2259 : * 8-bit packed YCbCr samples w/ 4,4 subsampling => RGB
2260 : */
2261 2 : DECLAREContigPutFunc(putcontig8bitYCbCr44tile)
2262 : {
2263 2 : uint32_t *cp1 = cp + w + toskew;
2264 2 : uint32_t *cp2 = cp1 + w + toskew;
2265 2 : uint32_t *cp3 = cp2 + w + toskew;
2266 2 : const tmsize_t incr = 3 * (tmsize_t)w + 4 * (tmsize_t)toskew;
2267 :
2268 : (void)y;
2269 : /* adjust fromskew */
2270 2 : const tmsize_t fromskewLocal =
2271 2 : (tmsize_t)(fromskew / 4) * (tmsize_t)(4 * 4 + 2);
2272 2 : if ((h & 3) == 0 && (w & 3) == 0)
2273 : {
2274 13 : for (; h >= 4; h -= 4)
2275 : {
2276 12 : x = w >> 2;
2277 : do
2278 : {
2279 144 : int32_t Cb = pp[16];
2280 144 : int32_t Cr = pp[17];
2281 :
2282 144 : YCbCrtoRGB(cp[0], pp[0]);
2283 144 : YCbCrtoRGB(cp[1], pp[1]);
2284 144 : YCbCrtoRGB(cp[2], pp[2]);
2285 144 : YCbCrtoRGB(cp[3], pp[3]);
2286 144 : YCbCrtoRGB(cp1[0], pp[4]);
2287 144 : YCbCrtoRGB(cp1[1], pp[5]);
2288 144 : YCbCrtoRGB(cp1[2], pp[6]);
2289 144 : YCbCrtoRGB(cp1[3], pp[7]);
2290 144 : YCbCrtoRGB(cp2[0], pp[8]);
2291 144 : YCbCrtoRGB(cp2[1], pp[9]);
2292 144 : YCbCrtoRGB(cp2[2], pp[10]);
2293 144 : YCbCrtoRGB(cp2[3], pp[11]);
2294 144 : YCbCrtoRGB(cp3[0], pp[12]);
2295 144 : YCbCrtoRGB(cp3[1], pp[13]);
2296 144 : YCbCrtoRGB(cp3[2], pp[14]);
2297 144 : YCbCrtoRGB(cp3[3], pp[15]);
2298 :
2299 144 : cp += 4;
2300 144 : cp1 += 4;
2301 144 : cp2 += 4;
2302 144 : cp3 += 4;
2303 144 : pp += 18;
2304 144 : } while (--x);
2305 12 : cp += incr;
2306 12 : cp1 += incr;
2307 12 : cp2 += incr;
2308 12 : cp3 += incr;
2309 12 : pp += fromskewLocal;
2310 : }
2311 : }
2312 : else
2313 : {
2314 10 : while (h > 0)
2315 : {
2316 110 : for (x = w; x > 0;)
2317 : {
2318 100 : int32_t Cb = pp[16];
2319 100 : int32_t Cr = pp[17];
2320 100 : switch (x)
2321 : {
2322 90 : default:
2323 90 : switch (h)
2324 : {
2325 81 : default:
2326 81 : YCbCrtoRGB(cp3[3], pp[15]); /* FALLTHROUGH */
2327 90 : case 3:
2328 90 : YCbCrtoRGB(cp2[3], pp[11]); /* FALLTHROUGH */
2329 90 : case 2:
2330 90 : YCbCrtoRGB(cp1[3], pp[7]); /* FALLTHROUGH */
2331 90 : case 1:
2332 90 : YCbCrtoRGB(cp[3], pp[3]); /* FALLTHROUGH */
2333 : } /* FALLTHROUGH */
2334 100 : case 3:
2335 100 : switch (h)
2336 : {
2337 90 : default:
2338 90 : YCbCrtoRGB(cp3[2], pp[14]); /* FALLTHROUGH */
2339 100 : case 3:
2340 100 : YCbCrtoRGB(cp2[2], pp[10]); /* FALLTHROUGH */
2341 100 : case 2:
2342 100 : YCbCrtoRGB(cp1[2], pp[6]); /* FALLTHROUGH */
2343 100 : case 1:
2344 100 : YCbCrtoRGB(cp[2], pp[2]); /* FALLTHROUGH */
2345 : } /* FALLTHROUGH */
2346 100 : case 2:
2347 100 : switch (h)
2348 : {
2349 90 : default:
2350 90 : YCbCrtoRGB(cp3[1], pp[13]); /* FALLTHROUGH */
2351 100 : case 3:
2352 100 : YCbCrtoRGB(cp2[1], pp[9]); /* FALLTHROUGH */
2353 100 : case 2:
2354 100 : YCbCrtoRGB(cp1[1], pp[5]); /* FALLTHROUGH */
2355 100 : case 1:
2356 100 : YCbCrtoRGB(cp[1], pp[1]); /* FALLTHROUGH */
2357 : } /* FALLTHROUGH */
2358 100 : case 1:
2359 100 : switch (h)
2360 : {
2361 90 : default:
2362 90 : YCbCrtoRGB(cp3[0], pp[12]); /* FALLTHROUGH */
2363 100 : case 3:
2364 100 : YCbCrtoRGB(cp2[0], pp[8]); /* FALLTHROUGH */
2365 100 : case 2:
2366 100 : YCbCrtoRGB(cp1[0], pp[4]); /* FALLTHROUGH */
2367 100 : case 1:
2368 100 : YCbCrtoRGB(cp[0], pp[0]); /* FALLTHROUGH */
2369 : } /* FALLTHROUGH */
2370 : }
2371 100 : if (x < 4)
2372 : {
2373 10 : cp += x;
2374 10 : cp1 += x;
2375 10 : cp2 += x;
2376 10 : cp3 += x;
2377 10 : x = 0;
2378 : }
2379 : else
2380 : {
2381 90 : cp += 4;
2382 90 : cp1 += 4;
2383 90 : cp2 += 4;
2384 90 : cp3 += 4;
2385 90 : x -= 4;
2386 : }
2387 100 : pp += 18;
2388 : }
2389 10 : if (h <= 4)
2390 1 : break;
2391 9 : h -= 4;
2392 9 : cp += incr;
2393 9 : cp1 += incr;
2394 9 : cp2 += incr;
2395 9 : cp3 += incr;
2396 9 : pp += fromskewLocal;
2397 : }
2398 : }
2399 2 : }
2400 :
2401 : /*
2402 : * 8-bit packed YCbCr samples w/ 4,2 subsampling => RGB
2403 : */
2404 2 : DECLAREContigPutFunc(putcontig8bitYCbCr42tile)
2405 : {
2406 2 : uint32_t *cp1 = cp + w + toskew;
2407 2 : const tmsize_t incr = 2 * (tmsize_t)toskew + (tmsize_t)w;
2408 :
2409 : (void)y;
2410 2 : const tmsize_t fromskewLocal =
2411 2 : (tmsize_t)(fromskew / 4) * (tmsize_t)(4 * 2 + 2);
2412 2 : if ((w & 3) == 0 && (h & 1) == 0)
2413 : {
2414 25 : for (; h >= 2; h -= 2)
2415 : {
2416 24 : x = w >> 2;
2417 : do
2418 : {
2419 288 : int32_t Cb = pp[8];
2420 288 : int32_t Cr = pp[9];
2421 :
2422 288 : YCbCrtoRGB(cp[0], pp[0]);
2423 288 : YCbCrtoRGB(cp[1], pp[1]);
2424 288 : YCbCrtoRGB(cp[2], pp[2]);
2425 288 : YCbCrtoRGB(cp[3], pp[3]);
2426 288 : YCbCrtoRGB(cp1[0], pp[4]);
2427 288 : YCbCrtoRGB(cp1[1], pp[5]);
2428 288 : YCbCrtoRGB(cp1[2], pp[6]);
2429 288 : YCbCrtoRGB(cp1[3], pp[7]);
2430 :
2431 288 : cp += 4;
2432 288 : cp1 += 4;
2433 288 : pp += 10;
2434 288 : } while (--x);
2435 24 : cp += incr;
2436 24 : cp1 += incr;
2437 24 : pp += fromskewLocal;
2438 : }
2439 : }
2440 : else
2441 : {
2442 20 : while (h > 0)
2443 : {
2444 220 : for (x = w; x > 0;)
2445 : {
2446 200 : int32_t Cb = pp[8];
2447 200 : int32_t Cr = pp[9];
2448 200 : switch (x)
2449 : {
2450 180 : default:
2451 180 : switch (h)
2452 : {
2453 171 : default:
2454 171 : YCbCrtoRGB(cp1[3], pp[7]); /* FALLTHROUGH */
2455 180 : case 1:
2456 180 : YCbCrtoRGB(cp[3], pp[3]); /* FALLTHROUGH */
2457 : } /* FALLTHROUGH */
2458 200 : case 3:
2459 200 : switch (h)
2460 : {
2461 190 : default:
2462 190 : YCbCrtoRGB(cp1[2], pp[6]); /* FALLTHROUGH */
2463 200 : case 1:
2464 200 : YCbCrtoRGB(cp[2], pp[2]); /* FALLTHROUGH */
2465 : } /* FALLTHROUGH */
2466 200 : case 2:
2467 200 : switch (h)
2468 : {
2469 190 : default:
2470 190 : YCbCrtoRGB(cp1[1], pp[5]); /* FALLTHROUGH */
2471 200 : case 1:
2472 200 : YCbCrtoRGB(cp[1], pp[1]); /* FALLTHROUGH */
2473 : } /* FALLTHROUGH */
2474 200 : case 1:
2475 200 : switch (h)
2476 : {
2477 190 : default:
2478 190 : YCbCrtoRGB(cp1[0], pp[4]); /* FALLTHROUGH */
2479 200 : case 1:
2480 200 : YCbCrtoRGB(cp[0], pp[0]); /* FALLTHROUGH */
2481 : } /* FALLTHROUGH */
2482 : }
2483 200 : if (x < 4)
2484 : {
2485 20 : cp += x;
2486 20 : cp1 += x;
2487 20 : x = 0;
2488 : }
2489 : else
2490 : {
2491 180 : cp += 4;
2492 180 : cp1 += 4;
2493 180 : x -= 4;
2494 : }
2495 200 : pp += 10;
2496 : }
2497 20 : if (h <= 2)
2498 1 : break;
2499 19 : h -= 2;
2500 19 : cp += incr;
2501 19 : cp1 += incr;
2502 19 : pp += fromskewLocal;
2503 : }
2504 : }
2505 2 : }
2506 :
2507 : /*
2508 : * 8-bit packed YCbCr samples w/ 4,1 subsampling => RGB
2509 : */
2510 1 : DECLAREContigPutFunc(putcontig8bitYCbCr41tile)
2511 : {
2512 : (void)y;
2513 1 : const tmsize_t fromskewLocal =
2514 1 : (tmsize_t)(fromskew / 4) * (tmsize_t)(4 * 1 + 2);
2515 : do
2516 : {
2517 39 : x = w >> 2;
2518 390 : while (x > 0)
2519 : {
2520 351 : int32_t Cb = pp[4];
2521 351 : int32_t Cr = pp[5];
2522 :
2523 351 : YCbCrtoRGB(cp[0], pp[0]);
2524 351 : YCbCrtoRGB(cp[1], pp[1]);
2525 351 : YCbCrtoRGB(cp[2], pp[2]);
2526 351 : YCbCrtoRGB(cp[3], pp[3]);
2527 :
2528 351 : cp += 4;
2529 351 : pp += 6;
2530 351 : x--;
2531 : }
2532 :
2533 39 : if ((w & 3) != 0)
2534 : {
2535 39 : int32_t Cb = pp[4];
2536 39 : int32_t Cr = pp[5];
2537 :
2538 39 : switch ((w & 3))
2539 : {
2540 39 : case 3:
2541 39 : YCbCrtoRGB(cp[2], pp[2]); /*-fallthrough*/
2542 39 : case 2:
2543 39 : YCbCrtoRGB(cp[1], pp[1]); /*-fallthrough*/
2544 39 : case 1:
2545 39 : YCbCrtoRGB(cp[0], pp[0]); /*-fallthrough*/
2546 39 : case 0:
2547 39 : break;
2548 0 : default:
2549 0 : break;
2550 : }
2551 :
2552 39 : cp += (w & 3);
2553 39 : pp += 6;
2554 : }
2555 :
2556 39 : cp += toskew;
2557 39 : pp += fromskewLocal;
2558 39 : } while (--h);
2559 1 : }
2560 :
2561 : /*
2562 : * 8-bit packed YCbCr samples w/ 2,2 subsampling => RGB
2563 : */
2564 2 : DECLAREContigPutFunc(putcontig8bitYCbCr22tile)
2565 : {
2566 : uint32_t *cp2;
2567 2 : const tmsize_t incr = 2 * (tmsize_t)toskew + (tmsize_t)w;
2568 : (void)y;
2569 2 : const tmsize_t fromskewLocal =
2570 2 : (tmsize_t)(fromskew / 2) * (tmsize_t)(2 * 2 + 2);
2571 2 : cp2 = cp + w + toskew;
2572 127 : while (h >= 2)
2573 : {
2574 125 : x = w;
2575 12888 : while (x >= 2)
2576 : {
2577 12763 : uint32_t Cb = pp[4];
2578 12763 : uint32_t Cr = pp[5];
2579 12763 : YCbCrtoRGB(cp[0], pp[0]);
2580 12763 : YCbCrtoRGB(cp[1], pp[1]);
2581 12763 : YCbCrtoRGB(cp2[0], pp[2]);
2582 12763 : YCbCrtoRGB(cp2[1], pp[3]);
2583 12763 : cp += 2;
2584 12763 : cp2 += 2;
2585 12763 : pp += 6;
2586 12763 : x -= 2;
2587 : }
2588 125 : if (x == 1)
2589 : {
2590 19 : uint32_t Cb = pp[4];
2591 19 : uint32_t Cr = pp[5];
2592 19 : YCbCrtoRGB(cp[0], pp[0]);
2593 19 : YCbCrtoRGB(cp2[0], pp[2]);
2594 19 : cp++;
2595 19 : cp2++;
2596 19 : pp += 6;
2597 : }
2598 125 : cp += incr;
2599 125 : cp2 += incr;
2600 125 : pp += fromskewLocal;
2601 125 : h -= 2;
2602 : }
2603 2 : if (h == 1)
2604 : {
2605 2 : x = w;
2606 138 : while (x >= 2)
2607 : {
2608 136 : uint32_t Cb = pp[4];
2609 136 : uint32_t Cr = pp[5];
2610 136 : YCbCrtoRGB(cp[0], pp[0]);
2611 136 : YCbCrtoRGB(cp[1], pp[1]);
2612 136 : cp += 2;
2613 136 : cp2 += 2;
2614 136 : pp += 6;
2615 136 : x -= 2;
2616 : }
2617 2 : if (x == 1)
2618 : {
2619 1 : uint32_t Cb = pp[4];
2620 1 : uint32_t Cr = pp[5];
2621 1 : YCbCrtoRGB(cp[0], pp[0]);
2622 : }
2623 : }
2624 2 : }
2625 :
2626 : /*
2627 : * 8-bit packed YCbCr samples w/ 2,1 subsampling => RGB
2628 : */
2629 1 : DECLAREContigPutFunc(putcontig8bitYCbCr21tile)
2630 : {
2631 : (void)y;
2632 1 : const tmsize_t fromskewLocal =
2633 1 : (tmsize_t)(fromskew / 2) * (tmsize_t)(2 * 1 + 2);
2634 : do
2635 : {
2636 39 : x = w >> 1;
2637 780 : while (x > 0)
2638 : {
2639 741 : int32_t Cb = pp[2];
2640 741 : int32_t Cr = pp[3];
2641 :
2642 741 : YCbCrtoRGB(cp[0], pp[0]);
2643 741 : YCbCrtoRGB(cp[1], pp[1]);
2644 :
2645 741 : cp += 2;
2646 741 : pp += 4;
2647 741 : x--;
2648 : }
2649 :
2650 39 : if ((w & 1) != 0)
2651 : {
2652 39 : int32_t Cb = pp[2];
2653 39 : int32_t Cr = pp[3];
2654 :
2655 39 : YCbCrtoRGB(cp[0], pp[0]);
2656 :
2657 39 : cp += 1;
2658 39 : pp += 4;
2659 : }
2660 :
2661 39 : cp += toskew;
2662 39 : pp += fromskewLocal;
2663 39 : } while (--h);
2664 1 : }
2665 :
2666 : /*
2667 : * 8-bit packed YCbCr samples w/ 1,2 subsampling => RGB
2668 : */
2669 1 : DECLAREContigPutFunc(putcontig8bitYCbCr12tile)
2670 : {
2671 : uint32_t *cp2;
2672 1 : const tmsize_t incr = 2 * (tmsize_t)toskew + (tmsize_t)w;
2673 : (void)y;
2674 1 : const tmsize_t fromskewLocal =
2675 1 : (tmsize_t)(fromskew / 1) * (tmsize_t)(1 * 2 + 2);
2676 1 : cp2 = cp + w + toskew;
2677 20 : while (h >= 2)
2678 : {
2679 19 : x = w;
2680 : do
2681 : {
2682 741 : uint32_t Cb = pp[2];
2683 741 : uint32_t Cr = pp[3];
2684 741 : YCbCrtoRGB(cp[0], pp[0]);
2685 741 : YCbCrtoRGB(cp2[0], pp[1]);
2686 741 : cp++;
2687 741 : cp2++;
2688 741 : pp += 4;
2689 741 : } while (--x);
2690 19 : cp += incr;
2691 19 : cp2 += incr;
2692 19 : pp += fromskewLocal;
2693 19 : h -= 2;
2694 : }
2695 1 : if (h == 1)
2696 : {
2697 1 : x = w;
2698 : do
2699 : {
2700 39 : uint32_t Cb = pp[2];
2701 39 : uint32_t Cr = pp[3];
2702 39 : YCbCrtoRGB(cp[0], pp[0]);
2703 39 : cp++;
2704 39 : pp += 4;
2705 39 : } while (--x);
2706 : }
2707 1 : }
2708 :
2709 : /*
2710 : * 8-bit packed YCbCr samples w/ no subsampling => RGB
2711 : */
2712 1 : DECLAREContigPutFunc(putcontig8bitYCbCr11tile)
2713 : {
2714 : (void)y;
2715 1 : const tmsize_t fromskewLocal =
2716 1 : (tmsize_t)(fromskew / 1) * (tmsize_t)(1 * 1 + 2);
2717 : do
2718 : {
2719 39 : x = w; /* was x = w>>1; patched 2000/09/25 warmerda@home.com */
2720 : do
2721 : {
2722 1521 : int32_t Cb = pp[1];
2723 1521 : int32_t Cr = pp[2];
2724 :
2725 1521 : YCbCrtoRGB(*cp++, pp[0]);
2726 :
2727 1521 : pp += 3;
2728 1521 : } while (--x);
2729 39 : cp += toskew;
2730 39 : pp += fromskewLocal;
2731 39 : } while (--h);
2732 1 : }
2733 :
2734 : /*
2735 : * 8-bit packed YCbCr samples w/ no subsampling => RGB
2736 : */
2737 0 : DECLARESepPutFunc(putseparate8bitYCbCr11tile)
2738 : {
2739 : (void)y;
2740 : (void)a;
2741 : /* TODO: naming of input vars is still off, change obfuscating declaration
2742 : * inside define, or resolve obfuscation */
2743 0 : for (; h > 0; --h)
2744 : {
2745 0 : x = w;
2746 : do
2747 : {
2748 : uint32_t dr, dg, db;
2749 0 : TIFFYCbCrtoRGB(img->ycbcr, *r++, *g++, *b++, &dr, &dg, &db);
2750 0 : *cp++ = PACK(dr, dg, db);
2751 0 : } while (--x);
2752 0 : SKEW(r, g, b, fromskew);
2753 0 : cp += toskew;
2754 : }
2755 0 : }
2756 : #undef YCbCrtoRGB
2757 :
2758 102 : static int isInRefBlackWhiteRange(float f)
2759 : {
2760 102 : return f > (float)(-0x7FFFFFFF + 128) && f < (float)0x7FFFFFFF;
2761 : }
2762 :
2763 17 : static int initYCbCrConversion(TIFFRGBAImage *img)
2764 : {
2765 : static const char module[] = "initYCbCrConversion";
2766 :
2767 : float *luma, *refBlackWhite;
2768 :
2769 17 : if (img->ycbcr == NULL)
2770 : {
2771 17 : img->ycbcr = (TIFFYCbCrToRGB *)_TIFFmallocExt(
2772 : img->tif, TIFFroundup_32(sizeof(TIFFYCbCrToRGB), sizeof(long)) +
2773 : 4 * 256 * sizeof(TIFFRGBValue) +
2774 : 2 * 256 * sizeof(int) + 3 * 256 * sizeof(int32_t));
2775 17 : if (img->ycbcr == NULL)
2776 : {
2777 0 : TIFFErrorExtR(img->tif, module,
2778 : "No space for YCbCr->RGB conversion state");
2779 0 : return (0);
2780 : }
2781 : }
2782 :
2783 17 : TIFFGetFieldDefaulted(img->tif, TIFFTAG_YCBCRCOEFFICIENTS, &luma);
2784 17 : TIFFGetFieldDefaulted(img->tif, TIFFTAG_REFERENCEBLACKWHITE,
2785 : &refBlackWhite);
2786 :
2787 : /* Do some validation to avoid later issues. Detect NaN for now */
2788 : /* and also if lumaGreen is zero since we divide by it later */
2789 17 : if (isnan(luma[0]) || isnan(luma[1]) || TIFF_FLOAT_EQ(luma[1], 0.0f) ||
2790 17 : isnan(luma[2]))
2791 : {
2792 0 : TIFFErrorExtR(img->tif, module,
2793 : "Invalid values for YCbCrCoefficients tag");
2794 0 : return (0);
2795 : }
2796 :
2797 34 : if (!isInRefBlackWhiteRange(refBlackWhite[0]) ||
2798 34 : !isInRefBlackWhiteRange(refBlackWhite[1]) ||
2799 34 : !isInRefBlackWhiteRange(refBlackWhite[2]) ||
2800 34 : !isInRefBlackWhiteRange(refBlackWhite[3]) ||
2801 34 : !isInRefBlackWhiteRange(refBlackWhite[4]) ||
2802 17 : !isInRefBlackWhiteRange(refBlackWhite[5]))
2803 : {
2804 0 : TIFFErrorExtR(img->tif, module,
2805 : "Invalid values for ReferenceBlackWhite tag");
2806 0 : return (0);
2807 : }
2808 :
2809 17 : if (TIFFYCbCrToRGBInit(img->ycbcr, luma, refBlackWhite) < 0)
2810 0 : return (0);
2811 17 : return (1);
2812 : }
2813 :
2814 1 : static tileContigRoutine initCIELabConversion(TIFFRGBAImage *img)
2815 : {
2816 : static const char module[] = "initCIELabConversion";
2817 :
2818 : float *whitePoint;
2819 : float refWhite[3];
2820 :
2821 1 : TIFFGetFieldDefaulted(img->tif, TIFFTAG_WHITEPOINT, &whitePoint);
2822 1 : if (TIFF_FLOAT_EQ(whitePoint[1], 0.0f))
2823 : {
2824 0 : TIFFErrorExtR(img->tif, module, "Invalid value for WhitePoint tag.");
2825 0 : return NULL;
2826 : }
2827 :
2828 1 : if (!img->cielab)
2829 : {
2830 1 : img->cielab = (TIFFCIELabToRGB *)_TIFFmallocExt(
2831 : img->tif, sizeof(TIFFCIELabToRGB));
2832 1 : if (!img->cielab)
2833 : {
2834 0 : TIFFErrorExtR(img->tif, module,
2835 : "No space for CIE L*a*b*->RGB conversion state.");
2836 0 : return NULL;
2837 : }
2838 : }
2839 :
2840 1 : refWhite[1] = 100.0f;
2841 1 : refWhite[0] = whitePoint[0] / whitePoint[1] * refWhite[1];
2842 1 : refWhite[2] =
2843 1 : (1.0f - whitePoint[0] - whitePoint[1]) / whitePoint[1] * refWhite[1];
2844 1 : if (TIFFCIELabToRGBInit(img->cielab, &display_sRGB, refWhite) < 0)
2845 : {
2846 0 : TIFFErrorExtR(img->tif, module,
2847 : "Failed to initialize CIE L*a*b*->RGB conversion state.");
2848 0 : _TIFFfreeExt(img->tif, img->cielab);
2849 0 : return NULL;
2850 : }
2851 :
2852 1 : if (img->bitspersample == 8)
2853 1 : return putcontig8bitCIELab8;
2854 0 : else if (img->bitspersample == 16)
2855 0 : return putcontig8bitCIELab16;
2856 0 : return NULL;
2857 : }
2858 :
2859 : /*
2860 : * Greyscale images with less than 8 bits/sample are handled
2861 : * with a table to avoid lots of shifts and masks. The table
2862 : * is setup so that put*bwtile (below) can retrieve 8/bitspersample
2863 : * pixel values simply by indexing into the table with one
2864 : * number.
2865 : */
2866 9 : static int makebwmap(TIFFRGBAImage *img)
2867 : {
2868 9 : TIFFRGBValue *Map = img->Map;
2869 9 : int bitspersample = img->bitspersample;
2870 9 : int nsamples = 8 / bitspersample;
2871 : int i;
2872 : uint32_t *p;
2873 :
2874 9 : if (nsamples == 0)
2875 0 : nsamples = 1;
2876 :
2877 18 : img->BWmap = (uint32_t **)_TIFFmallocExt(
2878 : img->tif,
2879 9 : (tmsize_t)((size_t)256 * sizeof(uint32_t *) +
2880 9 : ((size_t)256 * (size_t)nsamples * sizeof(uint32_t))));
2881 9 : if (img->BWmap == NULL)
2882 : {
2883 0 : TIFFErrorExtR(img->tif, TIFFFileName(img->tif),
2884 : "No space for B&W mapping table");
2885 0 : return (0);
2886 : }
2887 9 : p = (uint32_t *)(img->BWmap + 256);
2888 2313 : for (i = 0; i < 256; i++)
2889 : {
2890 : TIFFRGBValue c;
2891 2304 : img->BWmap[i] = p;
2892 2304 : switch (bitspersample)
2893 : {
2894 : #define GREY(x) \
2895 : c = Map[x]; \
2896 : *p++ = PACK(c, c, c);
2897 0 : case 1:
2898 0 : GREY(i >> 7);
2899 0 : GREY((i >> 6) & 1);
2900 0 : GREY((i >> 5) & 1);
2901 0 : GREY((i >> 4) & 1);
2902 0 : GREY((i >> 3) & 1);
2903 0 : GREY((i >> 2) & 1);
2904 0 : GREY((i >> 1) & 1);
2905 0 : GREY(i & 1);
2906 0 : break;
2907 0 : case 2:
2908 0 : GREY(i >> 6);
2909 0 : GREY((i >> 4) & 3);
2910 0 : GREY((i >> 2) & 3);
2911 0 : GREY(i & 3);
2912 0 : break;
2913 0 : case 4:
2914 0 : GREY(i >> 4);
2915 0 : GREY(i & 0xf);
2916 0 : break;
2917 2304 : case 8:
2918 : case 16:
2919 2304 : GREY(i);
2920 2304 : break;
2921 0 : default:
2922 0 : break;
2923 : }
2924 : #undef GREY
2925 : }
2926 9 : return (1);
2927 : }
2928 :
2929 : /*
2930 : * Construct a mapping table to convert from the range
2931 : * of the data samples to [0,255] --for display. This
2932 : * process also handles inverting B&W images when needed.
2933 : */
2934 9 : static int setupMap(TIFFRGBAImage *img)
2935 : {
2936 : int32_t x, range;
2937 :
2938 9 : range = (int32_t)((1U << img->bitspersample) - 1U);
2939 :
2940 : /* treat 16 bit the same as eight bit */
2941 9 : if (img->bitspersample == 16)
2942 0 : range = 255;
2943 :
2944 18 : img->Map = (TIFFRGBValue *)_TIFFmallocExt(
2945 9 : img->tif, (tmsize_t)((size_t)(range + 1) * sizeof(TIFFRGBValue)));
2946 9 : if (img->Map == NULL)
2947 : {
2948 0 : TIFFErrorExtR(img->tif, TIFFFileName(img->tif),
2949 : "No space for photometric conversion table");
2950 0 : return (0);
2951 : }
2952 9 : if (img->photometric == PHOTOMETRIC_MINISWHITE)
2953 : {
2954 0 : for (x = 0; x <= range; x++)
2955 0 : img->Map[x] = (TIFFRGBValue)(((range - x) * 255) / range);
2956 : }
2957 : else
2958 : {
2959 2313 : for (x = 0; x <= range; x++)
2960 2304 : img->Map[x] = (TIFFRGBValue)((x * 255) / range);
2961 : }
2962 9 : if (img->bitspersample <= 16 &&
2963 9 : (img->photometric == PHOTOMETRIC_MINISBLACK ||
2964 0 : img->photometric == PHOTOMETRIC_MINISWHITE))
2965 : {
2966 : /*
2967 : * Use photometric mapping table to construct
2968 : * unpacking tables for samples <= 8 bits.
2969 : */
2970 9 : if (!makebwmap(img))
2971 0 : return (0);
2972 : /* no longer need Map, free it */
2973 9 : _TIFFfreeExt(img->tif, img->Map);
2974 9 : img->Map = NULL;
2975 : }
2976 9 : return (1);
2977 : }
2978 :
2979 1 : static int checkcmap(TIFFRGBAImage *img)
2980 : {
2981 1 : uint16_t *r = img->redcmap;
2982 1 : uint16_t *g = img->greencmap;
2983 1 : uint16_t *b = img->bluecmap;
2984 1 : long n = 1L << img->bitspersample;
2985 :
2986 2 : while (n-- > 0)
2987 2 : if (*r++ >= 256 || *g++ >= 256 || *b++ >= 256)
2988 1 : return (16);
2989 0 : return (8);
2990 : }
2991 :
2992 1 : static void cvtcmap(TIFFRGBAImage *img)
2993 : {
2994 1 : uint16_t *r = img->redcmap;
2995 1 : uint16_t *g = img->greencmap;
2996 1 : uint16_t *b = img->bluecmap;
2997 : long i;
2998 :
2999 257 : for (i = (1L << img->bitspersample) - 1; i >= 0; i--)
3000 : {
3001 : #define CVT(x) ((uint16_t)((x) >> 8))
3002 256 : r[i] = CVT(r[i]);
3003 256 : g[i] = CVT(g[i]);
3004 256 : b[i] = CVT(b[i]);
3005 : #undef CVT
3006 : }
3007 1 : }
3008 :
3009 : /*
3010 : * Palette images with <= 8 bits/sample are handled
3011 : * with a table to avoid lots of shifts and masks. The table
3012 : * is setup so that put*cmaptile (below) can retrieve 8/bitspersample
3013 : * pixel values simply by indexing into the table with one
3014 : * number.
3015 : */
3016 1 : static int makecmap(TIFFRGBAImage *img)
3017 : {
3018 1 : int bitspersample = img->bitspersample;
3019 1 : int nsamples = 8 / bitspersample;
3020 1 : uint16_t *r = img->redcmap;
3021 1 : uint16_t *g = img->greencmap;
3022 1 : uint16_t *b = img->bluecmap;
3023 : uint32_t *p;
3024 : int i;
3025 :
3026 2 : img->PALmap = (uint32_t **)_TIFFmallocExt(
3027 : img->tif,
3028 1 : (tmsize_t)((size_t)256 * sizeof(uint32_t *) +
3029 1 : ((size_t)256 * (size_t)nsamples * sizeof(uint32_t))));
3030 1 : if (img->PALmap == NULL)
3031 : {
3032 0 : TIFFErrorExtR(img->tif, TIFFFileName(img->tif),
3033 : "No space for Palette mapping table");
3034 0 : return (0);
3035 : }
3036 1 : p = (uint32_t *)(img->PALmap + 256);
3037 257 : for (i = 0; i < 256; i++)
3038 : {
3039 : TIFFRGBValue c;
3040 256 : img->PALmap[i] = p;
3041 : #define CMAP(x) \
3042 : c = (TIFFRGBValue)x; \
3043 : *p++ = PACK(r[c] & 0xff, g[c] & 0xff, b[c] & 0xff);
3044 256 : switch (bitspersample)
3045 : {
3046 0 : case 1:
3047 0 : CMAP(i >> 7);
3048 0 : CMAP((i >> 6) & 1);
3049 0 : CMAP((i >> 5) & 1);
3050 0 : CMAP((i >> 4) & 1);
3051 0 : CMAP((i >> 3) & 1);
3052 0 : CMAP((i >> 2) & 1);
3053 0 : CMAP((i >> 1) & 1);
3054 0 : CMAP(i & 1);
3055 0 : break;
3056 0 : case 2:
3057 0 : CMAP(i >> 6);
3058 0 : CMAP((i >> 4) & 3);
3059 0 : CMAP((i >> 2) & 3);
3060 0 : CMAP(i & 3);
3061 0 : break;
3062 0 : case 4:
3063 0 : CMAP(i >> 4);
3064 0 : CMAP(i & 0xf);
3065 0 : break;
3066 256 : case 8:
3067 256 : CMAP(i);
3068 256 : break;
3069 0 : default:
3070 0 : break;
3071 : }
3072 : #undef CMAP
3073 : }
3074 1 : return (1);
3075 : }
3076 :
3077 : /*
3078 : * Construct any mapping table used
3079 : * by the associated put routine.
3080 : */
3081 17 : static int buildMap(TIFFRGBAImage *img)
3082 : {
3083 17 : switch (img->photometric)
3084 : {
3085 6 : case PHOTOMETRIC_RGB:
3086 : case PHOTOMETRIC_YCBCR:
3087 : case PHOTOMETRIC_SEPARATED:
3088 6 : if (img->bitspersample == 8)
3089 6 : break;
3090 : /* fall through... */
3091 : case PHOTOMETRIC_MINISBLACK:
3092 : case PHOTOMETRIC_MINISWHITE:
3093 9 : if (!setupMap(img))
3094 0 : return (0);
3095 9 : break;
3096 1 : case PHOTOMETRIC_PALETTE:
3097 : /*
3098 : * Convert 16-bit colormap to 8-bit (unless it looks
3099 : * like an old-style 8-bit colormap).
3100 : */
3101 1 : if (checkcmap(img) == 16)
3102 1 : cvtcmap(img);
3103 : else
3104 0 : TIFFWarningExtR(img->tif, TIFFFileName(img->tif),
3105 : "Assuming 8-bit colormap");
3106 : /*
3107 : * Use mapping table and colormap to construct
3108 : * unpacking tables for samples < 8 bits.
3109 : */
3110 1 : if (img->bitspersample <= 8 && !makecmap(img))
3111 0 : return (0);
3112 1 : break;
3113 1 : default:
3114 1 : break;
3115 : }
3116 17 : return (1);
3117 : }
3118 :
3119 : /*
3120 : * Select the appropriate conversion routine for packed data.
3121 : */
3122 60 : static int PickContigCase(TIFFRGBAImage *img)
3123 : {
3124 60 : img->get = TIFFIsTiled(img->tif) ? gtTileContig : gtStripContig;
3125 60 : img->put.contig = NULL;
3126 60 : switch (img->photometric)
3127 : {
3128 26 : case PHOTOMETRIC_RGB:
3129 26 : switch (img->bitspersample)
3130 : {
3131 26 : case 8:
3132 26 : if (img->alpha == EXTRASAMPLE_ASSOCALPHA &&
3133 13 : img->samplesperpixel >= 4)
3134 13 : img->put.contig = putRGBAAcontig8bittile;
3135 13 : else if (img->alpha == EXTRASAMPLE_UNASSALPHA &&
3136 13 : img->samplesperpixel >= 4)
3137 : {
3138 13 : if (BuildMapUaToAa(img))
3139 13 : img->put.contig = putRGBUAcontig8bittile;
3140 : }
3141 0 : else if (img->samplesperpixel >= 3)
3142 0 : img->put.contig = putRGBcontig8bittile;
3143 26 : break;
3144 0 : case 16:
3145 0 : if (img->alpha == EXTRASAMPLE_ASSOCALPHA &&
3146 0 : img->samplesperpixel >= 4)
3147 : {
3148 0 : if (BuildMapBitdepth16To8(img))
3149 0 : img->put.contig = putRGBAAcontig16bittile;
3150 : }
3151 0 : else if (img->alpha == EXTRASAMPLE_UNASSALPHA &&
3152 0 : img->samplesperpixel >= 4)
3153 : {
3154 0 : if (BuildMapBitdepth16To8(img) && BuildMapUaToAa(img))
3155 0 : img->put.contig = putRGBUAcontig16bittile;
3156 : }
3157 0 : else if (img->samplesperpixel >= 3)
3158 : {
3159 0 : if (BuildMapBitdepth16To8(img))
3160 0 : img->put.contig = putRGBcontig16bittile;
3161 : }
3162 0 : break;
3163 0 : default:
3164 0 : break;
3165 : }
3166 26 : break;
3167 6 : case PHOTOMETRIC_SEPARATED:
3168 6 : if (img->samplesperpixel >= 4 && buildMap(img))
3169 : {
3170 6 : if (img->bitspersample == 8)
3171 : {
3172 6 : if (!img->Map)
3173 6 : img->put.contig = putRGBcontig8bitCMYKtile;
3174 : else
3175 0 : img->put.contig = putRGBcontig8bitCMYKMaptile;
3176 : }
3177 : }
3178 6 : break;
3179 1 : case PHOTOMETRIC_PALETTE:
3180 1 : if (buildMap(img))
3181 : {
3182 1 : switch (img->bitspersample)
3183 : {
3184 1 : case 8:
3185 1 : img->put.contig = put8bitcmaptile;
3186 1 : break;
3187 0 : case 4:
3188 0 : img->put.contig = put4bitcmaptile;
3189 0 : break;
3190 0 : case 2:
3191 0 : img->put.contig = put2bitcmaptile;
3192 0 : break;
3193 0 : case 1:
3194 0 : img->put.contig = put1bitcmaptile;
3195 0 : break;
3196 0 : default:
3197 0 : break;
3198 : }
3199 0 : }
3200 1 : break;
3201 9 : case PHOTOMETRIC_MINISWHITE:
3202 : case PHOTOMETRIC_MINISBLACK:
3203 9 : if (buildMap(img))
3204 : {
3205 9 : switch (img->bitspersample)
3206 : {
3207 0 : case 16:
3208 0 : img->put.contig = put16bitbwtile;
3209 0 : break;
3210 9 : case 8:
3211 9 : if (img->alpha && img->samplesperpixel == 2)
3212 6 : img->put.contig = putagreytile;
3213 : else
3214 3 : img->put.contig = putgreytile;
3215 9 : break;
3216 0 : case 4:
3217 0 : img->put.contig = put4bitbwtile;
3218 0 : break;
3219 0 : case 2:
3220 0 : img->put.contig = put2bitbwtile;
3221 0 : break;
3222 0 : case 1:
3223 0 : img->put.contig = put1bitbwtile;
3224 0 : break;
3225 0 : default:
3226 0 : break;
3227 : }
3228 0 : }
3229 9 : break;
3230 17 : case PHOTOMETRIC_YCBCR:
3231 17 : if ((img->bitspersample == 8) && (img->samplesperpixel == 3))
3232 : {
3233 17 : if (initYCbCrConversion(img) != 0)
3234 : {
3235 : /*
3236 : * The 6.0 spec says that subsampling must be
3237 : * one of 1, 2, or 4, and that vertical subsampling
3238 : * must always be <= horizontal subsampling; so
3239 : * there are only a few possibilities and we just
3240 : * enumerate the cases.
3241 : * Joris: added support for the [1,2] case, nonetheless, to
3242 : * accommodate some OJPEG files
3243 : */
3244 : uint16_t SubsamplingHor;
3245 : uint16_t SubsamplingVer;
3246 17 : TIFFGetFieldDefaulted(img->tif, TIFFTAG_YCBCRSUBSAMPLING,
3247 : &SubsamplingHor, &SubsamplingVer);
3248 : /* Validate that the image dimensions are compatible with
3249 : the subsampling block. All putcontig8bitYCbCrXYtile routines
3250 : assume width >= X and height >= Y. */
3251 17 : if (img->width < SubsamplingHor ||
3252 17 : img->height < SubsamplingVer)
3253 : {
3254 0 : TIFFErrorExtR(img->tif, TIFFFileName(img->tif),
3255 : "YCbCr subsampling (%u,%u) incompatible "
3256 : "with image size %ux%u",
3257 : SubsamplingHor, SubsamplingVer,
3258 : img->width, img->height);
3259 0 : return (0);
3260 : }
3261 17 : switch ((SubsamplingHor << 4) | SubsamplingVer)
3262 : {
3263 2 : case 0x44:
3264 2 : img->put.contig = putcontig8bitYCbCr44tile;
3265 2 : break;
3266 2 : case 0x42:
3267 2 : img->put.contig = putcontig8bitYCbCr42tile;
3268 2 : break;
3269 1 : case 0x41:
3270 1 : img->put.contig = putcontig8bitYCbCr41tile;
3271 1 : break;
3272 3 : case 0x22:
3273 3 : img->put.contig = putcontig8bitYCbCr22tile;
3274 3 : break;
3275 1 : case 0x21:
3276 1 : img->put.contig = putcontig8bitYCbCr21tile;
3277 1 : break;
3278 1 : case 0x12:
3279 1 : img->put.contig = putcontig8bitYCbCr12tile;
3280 1 : break;
3281 1 : case 0x11:
3282 1 : img->put.contig = putcontig8bitYCbCr11tile;
3283 1 : break;
3284 6 : default:
3285 6 : break;
3286 : }
3287 : }
3288 : }
3289 17 : break;
3290 1 : case PHOTOMETRIC_CIELAB:
3291 1 : if (img->samplesperpixel == 3 && buildMap(img))
3292 : {
3293 1 : if (img->bitspersample == 8 || img->bitspersample == 16)
3294 1 : img->put.contig = initCIELabConversion(img);
3295 1 : break;
3296 : }
3297 0 : break;
3298 0 : default:
3299 0 : break;
3300 : }
3301 60 : return ((img->get != NULL) && (img->put.contig != NULL));
3302 : }
3303 :
3304 : /*
3305 : * Select the appropriate conversion routine for unpacked data.
3306 : *
3307 : * NB: we assume that unpacked single channel data is directed
3308 : * to the "packed routines.
3309 : */
3310 3 : static int PickSeparateCase(TIFFRGBAImage *img)
3311 : {
3312 3 : img->get = TIFFIsTiled(img->tif) ? gtTileSeparate : gtStripSeparate;
3313 3 : img->put.separate = NULL;
3314 3 : switch (img->photometric)
3315 : {
3316 3 : case PHOTOMETRIC_MINISWHITE:
3317 : case PHOTOMETRIC_MINISBLACK:
3318 : /* greyscale images processed pretty much as RGB by gtTileSeparate
3319 : */
3320 : case PHOTOMETRIC_RGB:
3321 3 : switch (img->bitspersample)
3322 : {
3323 3 : case 8:
3324 3 : if (img->alpha == EXTRASAMPLE_ASSOCALPHA)
3325 0 : img->put.separate = putRGBAAseparate8bittile;
3326 3 : else if (img->alpha == EXTRASAMPLE_UNASSALPHA)
3327 : {
3328 0 : if (BuildMapUaToAa(img))
3329 0 : img->put.separate = putRGBUAseparate8bittile;
3330 : }
3331 : else
3332 3 : img->put.separate = putRGBseparate8bittile;
3333 3 : break;
3334 0 : case 16:
3335 0 : if (img->alpha == EXTRASAMPLE_ASSOCALPHA)
3336 : {
3337 0 : if (BuildMapBitdepth16To8(img))
3338 0 : img->put.separate = putRGBAAseparate16bittile;
3339 : }
3340 0 : else if (img->alpha == EXTRASAMPLE_UNASSALPHA)
3341 : {
3342 0 : if (BuildMapBitdepth16To8(img) && BuildMapUaToAa(img))
3343 0 : img->put.separate = putRGBUAseparate16bittile;
3344 : }
3345 : else
3346 : {
3347 0 : if (BuildMapBitdepth16To8(img))
3348 0 : img->put.separate = putRGBseparate16bittile;
3349 : }
3350 0 : break;
3351 0 : default:
3352 0 : break;
3353 : }
3354 3 : break;
3355 0 : case PHOTOMETRIC_SEPARATED:
3356 0 : if (img->bitspersample == 8 && img->samplesperpixel == 4)
3357 : {
3358 : /* Not alpha, but seems like the only way to get 4th band */
3359 0 : img->alpha = 1;
3360 0 : img->put.separate = putCMYKseparate8bittile;
3361 : }
3362 0 : break;
3363 0 : case PHOTOMETRIC_YCBCR:
3364 0 : if ((img->bitspersample == 8) && (img->samplesperpixel == 3))
3365 : {
3366 0 : if (initYCbCrConversion(img) != 0)
3367 : {
3368 : uint16_t hs, vs;
3369 0 : TIFFGetFieldDefaulted(img->tif, TIFFTAG_YCBCRSUBSAMPLING,
3370 : &hs, &vs);
3371 0 : switch ((hs << 4) | vs)
3372 : {
3373 0 : case 0x11:
3374 0 : img->put.separate = putseparate8bitYCbCr11tile;
3375 0 : break;
3376 : /* TODO: add other cases here */
3377 0 : default:
3378 0 : break;
3379 : }
3380 : }
3381 : }
3382 0 : break;
3383 0 : default:
3384 0 : break;
3385 : }
3386 3 : return ((img->get != NULL) && (img->put.separate != NULL));
3387 : }
3388 :
3389 13 : static int BuildMapUaToAa(TIFFRGBAImage *img)
3390 : {
3391 : static const char module[] = "BuildMapUaToAa";
3392 : uint8_t *m;
3393 : uint16_t na, nv;
3394 13 : assert(img->UaToAa == NULL);
3395 13 : img->UaToAa = (uint8_t *)_TIFFmallocExt(img->tif, 65536);
3396 13 : if (img->UaToAa == NULL)
3397 : {
3398 0 : TIFFErrorExtR(img->tif, module, "Out of memory");
3399 0 : return (0);
3400 : }
3401 13 : m = img->UaToAa;
3402 3341 : for (na = 0; na < 256; na++)
3403 : {
3404 855296 : for (nv = 0; nv < 256; nv++)
3405 851968 : *m++ = (uint8_t)((nv * na + 127) / 255);
3406 : }
3407 13 : return (1);
3408 : }
3409 :
3410 0 : static int BuildMapBitdepth16To8(TIFFRGBAImage *img)
3411 : {
3412 : static const char module[] = "BuildMapBitdepth16To8";
3413 : uint8_t *m;
3414 : uint32_t n;
3415 0 : assert(img->Bitdepth16To8 == NULL);
3416 0 : img->Bitdepth16To8 = (uint8_t *)_TIFFmallocExt(img->tif, 65536);
3417 0 : if (img->Bitdepth16To8 == NULL)
3418 : {
3419 0 : TIFFErrorExtR(img->tif, module, "Out of memory");
3420 0 : return (0);
3421 : }
3422 0 : m = img->Bitdepth16To8;
3423 0 : for (n = 0; n < 65536; n++)
3424 0 : *m++ = (uint8_t)((n + 128) / 257);
3425 0 : return (1);
3426 : }
3427 :
3428 : /*
3429 : * Read a whole strip off data from the file, and convert to RGBA form.
3430 : * If this is the last strip, then it will only contain the portion of
3431 : * the strip that is actually within the image space. The result is
3432 : * organized in bottom to top form.
3433 : */
3434 :
3435 0 : int TIFFReadRGBAStrip(TIFF *tif, uint32_t row, uint32_t *raster)
3436 :
3437 : {
3438 0 : return TIFFReadRGBAStripExt(tif, row, raster, 0);
3439 : }
3440 :
3441 59 : int TIFFReadRGBAStripExt(TIFF *tif, uint32_t row, uint32_t *raster,
3442 : int stop_on_error)
3443 :
3444 : {
3445 59 : char emsg[EMSG_BUF_SIZE] = "";
3446 : TIFFRGBAImage img;
3447 : int ok;
3448 : uint32_t rowsperstrip, rows_to_read;
3449 :
3450 59 : if (TIFFIsTiled(tif))
3451 : {
3452 0 : TIFFErrorExtR(tif, TIFFFileName(tif),
3453 : "Can't use TIFFReadRGBAStrip() with tiled file.");
3454 0 : return (0);
3455 : }
3456 :
3457 59 : TIFFGetFieldDefaulted(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
3458 :
3459 59 : if (rowsperstrip == 0)
3460 : {
3461 0 : TIFFErrorExtR(tif, TIFFFileName(tif), "rowsperstrip is zero");
3462 0 : return (0);
3463 : }
3464 :
3465 59 : if ((row % rowsperstrip) != 0)
3466 : {
3467 0 : TIFFErrorExtR(
3468 : tif, TIFFFileName(tif),
3469 : "Row passed to TIFFReadRGBAStrip() must be first in a strip.");
3470 0 : return (0);
3471 : }
3472 :
3473 59 : if (TIFFRGBAImageBegin(&img, tif, stop_on_error, emsg))
3474 : {
3475 53 : if (row >= img.height)
3476 : {
3477 0 : TIFFErrorExtR(tif, TIFFFileName(tif),
3478 : "Invalid row passed to TIFFReadRGBAStrip().");
3479 0 : TIFFRGBAImageEnd(&img);
3480 0 : return (0);
3481 : }
3482 :
3483 53 : img.row_offset = (int)row;
3484 53 : img.col_offset = 0;
3485 :
3486 53 : if (row + rowsperstrip > img.height)
3487 14 : rows_to_read = img.height - row;
3488 : else
3489 39 : rows_to_read = rowsperstrip;
3490 :
3491 53 : ok = TIFFRGBAImageGet(&img, raster, img.width, rows_to_read);
3492 :
3493 53 : TIFFRGBAImageEnd(&img);
3494 : }
3495 : else
3496 : {
3497 6 : TIFFErrorExtR(tif, TIFFFileName(tif), "%s", emsg);
3498 6 : ok = 0;
3499 : }
3500 :
3501 59 : return (ok);
3502 : }
3503 :
3504 : /*
3505 : * Read a whole tile off data from the file, and convert to RGBA form.
3506 : * The returned RGBA data is organized from bottom to top of tile,
3507 : * and may include zeroed areas if the tile extends off the image.
3508 : */
3509 :
3510 0 : int TIFFReadRGBATile(TIFF *tif, uint32_t col, uint32_t row, uint32_t *raster)
3511 :
3512 : {
3513 0 : return TIFFReadRGBATileExt(tif, col, row, raster, 0);
3514 : }
3515 :
3516 4 : int TIFFReadRGBATileExt(TIFF *tif, uint32_t col, uint32_t row, uint32_t *raster,
3517 : int stop_on_error)
3518 : {
3519 4 : char emsg[EMSG_BUF_SIZE] = "";
3520 : TIFFRGBAImage img;
3521 : int ok;
3522 : uint32_t tile_xsize, tile_ysize;
3523 : uint32_t read_xsize, read_ysize;
3524 : uint32_t i_row;
3525 :
3526 : /*
3527 : * Verify that our request is legal - on a tile file, and on a
3528 : * tile boundary.
3529 : */
3530 :
3531 4 : if (!TIFFIsTiled(tif))
3532 : {
3533 0 : TIFFErrorExtR(tif, TIFFFileName(tif),
3534 : "Can't use TIFFReadRGBATile() with striped file.");
3535 0 : return (0);
3536 : }
3537 :
3538 4 : TIFFGetFieldDefaulted(tif, TIFFTAG_TILEWIDTH, &tile_xsize);
3539 4 : TIFFGetFieldDefaulted(tif, TIFFTAG_TILELENGTH, &tile_ysize);
3540 4 : if (tile_xsize == 0 || tile_ysize == 0)
3541 : {
3542 0 : TIFFErrorExtR(tif, TIFFFileName(tif),
3543 : "tile_xsize or tile_ysize is zero");
3544 0 : return (0);
3545 : }
3546 :
3547 4 : if ((col % tile_xsize) != 0 || (row % tile_ysize) != 0)
3548 : {
3549 0 : TIFFErrorExtR(tif, TIFFFileName(tif),
3550 : "Row/col passed to TIFFReadRGBATile() must be top"
3551 : "left corner of a tile.");
3552 0 : return (0);
3553 : }
3554 :
3555 : /*
3556 : * Setup the RGBA reader.
3557 : */
3558 :
3559 4 : if (!TIFFRGBAImageBegin(&img, tif, stop_on_error, emsg))
3560 : {
3561 0 : TIFFErrorExtR(tif, TIFFFileName(tif), "%s", emsg);
3562 0 : return (0);
3563 : }
3564 :
3565 4 : if (col >= img.width || row >= img.height)
3566 : {
3567 0 : TIFFErrorExtR(tif, TIFFFileName(tif),
3568 : "Invalid row/col passed to TIFFReadRGBATile().");
3569 0 : TIFFRGBAImageEnd(&img);
3570 0 : return (0);
3571 : }
3572 :
3573 : /*
3574 : * The TIFFRGBAImageGet() function doesn't allow us to get off the
3575 : * edge of the image, even to fill an otherwise valid tile. So we
3576 : * figure out how much we can read, and fix up the tile buffer to
3577 : * a full tile configuration afterwards.
3578 : */
3579 :
3580 4 : if (row + tile_ysize > img.height)
3581 4 : read_ysize = img.height - row;
3582 : else
3583 0 : read_ysize = tile_ysize;
3584 :
3585 4 : if (col + tile_xsize > img.width)
3586 4 : read_xsize = img.width - col;
3587 : else
3588 0 : read_xsize = tile_xsize;
3589 :
3590 : /*
3591 : * Read the chunk of imagery.
3592 : */
3593 :
3594 4 : img.row_offset = (int)row;
3595 4 : img.col_offset = (int)col;
3596 :
3597 4 : ok = TIFFRGBAImageGet(&img, raster, read_xsize, read_ysize);
3598 :
3599 4 : TIFFRGBAImageEnd(&img);
3600 :
3601 : /*
3602 : * If our read was incomplete we will need to fix up the tile by
3603 : * shifting the data around as if a full tile of data is being returned.
3604 : *
3605 : * This is all the more complicated because the image is organized in
3606 : * bottom to top format.
3607 : */
3608 :
3609 4 : if (read_xsize == tile_xsize && read_ysize == tile_ysize)
3610 0 : return (ok);
3611 :
3612 500 : for (i_row = 0; i_row < read_ysize; i_row++)
3613 : {
3614 496 : memmove(raster + (size_t)(tile_ysize - i_row - 1) * tile_xsize,
3615 496 : raster + (size_t)(read_ysize - i_row - 1) * read_xsize,
3616 : read_xsize * sizeof(uint32_t));
3617 496 : _TIFFmemset(
3618 496 : raster + (size_t)(tile_ysize - i_row - 1) * tile_xsize + read_xsize,
3619 : 0,
3620 496 : (tmsize_t)(sizeof(uint32_t) * (size_t)(tile_xsize - read_xsize)));
3621 : }
3622 :
3623 468 : for (i_row = read_ysize; i_row < tile_ysize; i_row++)
3624 : {
3625 464 : _TIFFmemset(raster + (size_t)(tile_ysize - i_row - 1) * tile_xsize, 0,
3626 464 : (tmsize_t)(sizeof(uint32_t) * (size_t)tile_xsize));
3627 : }
3628 :
3629 4 : return (ok);
3630 : }
|