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