xref: /aosp_15_r20/external/libjpeg-turbo/rdbmp.c (revision dfc6aa5c1cfd4bc4e2018dc74aa96e29ee49c6da)
1*dfc6aa5cSAndroid Build Coastguard Worker /*
2*dfc6aa5cSAndroid Build Coastguard Worker  * rdbmp.c
3*dfc6aa5cSAndroid Build Coastguard Worker  *
4*dfc6aa5cSAndroid Build Coastguard Worker  * This file was part of the Independent JPEG Group's software:
5*dfc6aa5cSAndroid Build Coastguard Worker  * Copyright (C) 1994-1996, Thomas G. Lane.
6*dfc6aa5cSAndroid Build Coastguard Worker  * Modified 2009-2017 by Guido Vollbeding.
7*dfc6aa5cSAndroid Build Coastguard Worker  * libjpeg-turbo Modifications:
8*dfc6aa5cSAndroid Build Coastguard Worker  * Modified 2011 by Siarhei Siamashka.
9*dfc6aa5cSAndroid Build Coastguard Worker  * Copyright (C) 2015, 2017-2018, 2021-2022, D. R. Commander.
10*dfc6aa5cSAndroid Build Coastguard Worker  * For conditions of distribution and use, see the accompanying README.ijg
11*dfc6aa5cSAndroid Build Coastguard Worker  * file.
12*dfc6aa5cSAndroid Build Coastguard Worker  *
13*dfc6aa5cSAndroid Build Coastguard Worker  * This file contains routines to read input images in Microsoft "BMP"
14*dfc6aa5cSAndroid Build Coastguard Worker  * format (MS Windows 3.x, OS/2 1.x, and OS/2 2.x flavors).
15*dfc6aa5cSAndroid Build Coastguard Worker  * Currently, only 8-, 24-, and 32-bit images are supported, not 1-bit or
16*dfc6aa5cSAndroid Build Coastguard Worker  * 4-bit (feeding such low-depth images into JPEG would be silly anyway).
17*dfc6aa5cSAndroid Build Coastguard Worker  * Also, we don't support RLE-compressed files.
18*dfc6aa5cSAndroid Build Coastguard Worker  *
19*dfc6aa5cSAndroid Build Coastguard Worker  * These routines may need modification for non-Unix environments or
20*dfc6aa5cSAndroid Build Coastguard Worker  * specialized applications.  As they stand, they assume input from
21*dfc6aa5cSAndroid Build Coastguard Worker  * an ordinary stdio stream.  They further assume that reading begins
22*dfc6aa5cSAndroid Build Coastguard Worker  * at the start of the file; start_input may need work if the
23*dfc6aa5cSAndroid Build Coastguard Worker  * user interface has already read some data (e.g., to determine that
24*dfc6aa5cSAndroid Build Coastguard Worker  * the file is indeed BMP format).
25*dfc6aa5cSAndroid Build Coastguard Worker  *
26*dfc6aa5cSAndroid Build Coastguard Worker  * This code contributed by James Arthur Boucher.
27*dfc6aa5cSAndroid Build Coastguard Worker  */
28*dfc6aa5cSAndroid Build Coastguard Worker 
29*dfc6aa5cSAndroid Build Coastguard Worker #include "cmyk.h"
30*dfc6aa5cSAndroid Build Coastguard Worker #include "cdjpeg.h"             /* Common decls for cjpeg/djpeg applications */
31*dfc6aa5cSAndroid Build Coastguard Worker 
32*dfc6aa5cSAndroid Build Coastguard Worker #ifdef BMP_SUPPORTED
33*dfc6aa5cSAndroid Build Coastguard Worker 
34*dfc6aa5cSAndroid Build Coastguard Worker 
35*dfc6aa5cSAndroid Build Coastguard Worker /* Macros to deal with unsigned chars as efficiently as compiler allows */
36*dfc6aa5cSAndroid Build Coastguard Worker 
37*dfc6aa5cSAndroid Build Coastguard Worker typedef unsigned char U_CHAR;
38*dfc6aa5cSAndroid Build Coastguard Worker #define UCH(x)  ((int)(x))
39*dfc6aa5cSAndroid Build Coastguard Worker 
40*dfc6aa5cSAndroid Build Coastguard Worker 
41*dfc6aa5cSAndroid Build Coastguard Worker #define ReadOK(file, buffer, len) \
42*dfc6aa5cSAndroid Build Coastguard Worker   (fread(buffer, 1, len, file) == ((size_t)(len)))
43*dfc6aa5cSAndroid Build Coastguard Worker 
44*dfc6aa5cSAndroid Build Coastguard Worker static int alpha_index[JPEG_NUMCS] = {
45*dfc6aa5cSAndroid Build Coastguard Worker   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 3, 3, 0, 0, -1
46*dfc6aa5cSAndroid Build Coastguard Worker };
47*dfc6aa5cSAndroid Build Coastguard Worker 
48*dfc6aa5cSAndroid Build Coastguard Worker 
49*dfc6aa5cSAndroid Build Coastguard Worker /* Private version of data source object */
50*dfc6aa5cSAndroid Build Coastguard Worker 
51*dfc6aa5cSAndroid Build Coastguard Worker typedef struct _bmp_source_struct *bmp_source_ptr;
52*dfc6aa5cSAndroid Build Coastguard Worker 
53*dfc6aa5cSAndroid Build Coastguard Worker typedef struct _bmp_source_struct {
54*dfc6aa5cSAndroid Build Coastguard Worker   struct cjpeg_source_struct pub; /* public fields */
55*dfc6aa5cSAndroid Build Coastguard Worker 
56*dfc6aa5cSAndroid Build Coastguard Worker   j_compress_ptr cinfo;         /* back link saves passing separate parm */
57*dfc6aa5cSAndroid Build Coastguard Worker 
58*dfc6aa5cSAndroid Build Coastguard Worker   JSAMPARRAY colormap;          /* BMP colormap (converted to my format) */
59*dfc6aa5cSAndroid Build Coastguard Worker 
60*dfc6aa5cSAndroid Build Coastguard Worker   jvirt_sarray_ptr whole_image; /* Needed to reverse row order */
61*dfc6aa5cSAndroid Build Coastguard Worker   JDIMENSION source_row;        /* Current source row number */
62*dfc6aa5cSAndroid Build Coastguard Worker   JDIMENSION row_width;         /* Physical width of scanlines in file */
63*dfc6aa5cSAndroid Build Coastguard Worker 
64*dfc6aa5cSAndroid Build Coastguard Worker   int bits_per_pixel;           /* remembers 8-, 24-, or 32-bit format */
65*dfc6aa5cSAndroid Build Coastguard Worker   int cmap_length;              /* colormap length */
66*dfc6aa5cSAndroid Build Coastguard Worker 
67*dfc6aa5cSAndroid Build Coastguard Worker   boolean use_inversion_array;  /* TRUE = preload the whole image, which is
68*dfc6aa5cSAndroid Build Coastguard Worker                                    stored in bottom-up order, and feed it to
69*dfc6aa5cSAndroid Build Coastguard Worker                                    the calling program in top-down order
70*dfc6aa5cSAndroid Build Coastguard Worker 
71*dfc6aa5cSAndroid Build Coastguard Worker                                    FALSE = the calling program will maintain
72*dfc6aa5cSAndroid Build Coastguard Worker                                    its own image buffer and read the rows in
73*dfc6aa5cSAndroid Build Coastguard Worker                                    bottom-up order */
74*dfc6aa5cSAndroid Build Coastguard Worker 
75*dfc6aa5cSAndroid Build Coastguard Worker   U_CHAR *iobuffer;             /* I/O buffer (used to buffer a single row from
76*dfc6aa5cSAndroid Build Coastguard Worker                                    disk if use_inversion_array == FALSE) */
77*dfc6aa5cSAndroid Build Coastguard Worker } bmp_source_struct;
78*dfc6aa5cSAndroid Build Coastguard Worker 
79*dfc6aa5cSAndroid Build Coastguard Worker 
80*dfc6aa5cSAndroid Build Coastguard Worker LOCAL(int)
read_byte(bmp_source_ptr sinfo)81*dfc6aa5cSAndroid Build Coastguard Worker read_byte(bmp_source_ptr sinfo)
82*dfc6aa5cSAndroid Build Coastguard Worker /* Read next byte from BMP file */
83*dfc6aa5cSAndroid Build Coastguard Worker {
84*dfc6aa5cSAndroid Build Coastguard Worker   register FILE *infile = sinfo->pub.input_file;
85*dfc6aa5cSAndroid Build Coastguard Worker   register int c;
86*dfc6aa5cSAndroid Build Coastguard Worker 
87*dfc6aa5cSAndroid Build Coastguard Worker   if ((c = getc(infile)) == EOF)
88*dfc6aa5cSAndroid Build Coastguard Worker     ERREXIT(sinfo->cinfo, JERR_INPUT_EOF);
89*dfc6aa5cSAndroid Build Coastguard Worker   return c;
90*dfc6aa5cSAndroid Build Coastguard Worker }
91*dfc6aa5cSAndroid Build Coastguard Worker 
92*dfc6aa5cSAndroid Build Coastguard Worker 
93*dfc6aa5cSAndroid Build Coastguard Worker LOCAL(void)
read_colormap(bmp_source_ptr sinfo,int cmaplen,int mapentrysize)94*dfc6aa5cSAndroid Build Coastguard Worker read_colormap(bmp_source_ptr sinfo, int cmaplen, int mapentrysize)
95*dfc6aa5cSAndroid Build Coastguard Worker /* Read the colormap from a BMP file */
96*dfc6aa5cSAndroid Build Coastguard Worker {
97*dfc6aa5cSAndroid Build Coastguard Worker   int i, gray = 1;
98*dfc6aa5cSAndroid Build Coastguard Worker 
99*dfc6aa5cSAndroid Build Coastguard Worker   switch (mapentrysize) {
100*dfc6aa5cSAndroid Build Coastguard Worker   case 3:
101*dfc6aa5cSAndroid Build Coastguard Worker     /* BGR format (occurs in OS/2 files) */
102*dfc6aa5cSAndroid Build Coastguard Worker     for (i = 0; i < cmaplen; i++) {
103*dfc6aa5cSAndroid Build Coastguard Worker       sinfo->colormap[2][i] = (JSAMPLE)read_byte(sinfo);
104*dfc6aa5cSAndroid Build Coastguard Worker       sinfo->colormap[1][i] = (JSAMPLE)read_byte(sinfo);
105*dfc6aa5cSAndroid Build Coastguard Worker       sinfo->colormap[0][i] = (JSAMPLE)read_byte(sinfo);
106*dfc6aa5cSAndroid Build Coastguard Worker       if (sinfo->colormap[2][i] != sinfo->colormap[1][i] ||
107*dfc6aa5cSAndroid Build Coastguard Worker           sinfo->colormap[1][i] != sinfo->colormap[0][i])
108*dfc6aa5cSAndroid Build Coastguard Worker         gray = 0;
109*dfc6aa5cSAndroid Build Coastguard Worker     }
110*dfc6aa5cSAndroid Build Coastguard Worker     break;
111*dfc6aa5cSAndroid Build Coastguard Worker   case 4:
112*dfc6aa5cSAndroid Build Coastguard Worker     /* BGR0 format (occurs in MS Windows files) */
113*dfc6aa5cSAndroid Build Coastguard Worker     for (i = 0; i < cmaplen; i++) {
114*dfc6aa5cSAndroid Build Coastguard Worker       sinfo->colormap[2][i] = (JSAMPLE)read_byte(sinfo);
115*dfc6aa5cSAndroid Build Coastguard Worker       sinfo->colormap[1][i] = (JSAMPLE)read_byte(sinfo);
116*dfc6aa5cSAndroid Build Coastguard Worker       sinfo->colormap[0][i] = (JSAMPLE)read_byte(sinfo);
117*dfc6aa5cSAndroid Build Coastguard Worker       (void)read_byte(sinfo);
118*dfc6aa5cSAndroid Build Coastguard Worker       if (sinfo->colormap[2][i] != sinfo->colormap[1][i] ||
119*dfc6aa5cSAndroid Build Coastguard Worker           sinfo->colormap[1][i] != sinfo->colormap[0][i])
120*dfc6aa5cSAndroid Build Coastguard Worker         gray = 0;
121*dfc6aa5cSAndroid Build Coastguard Worker     }
122*dfc6aa5cSAndroid Build Coastguard Worker     break;
123*dfc6aa5cSAndroid Build Coastguard Worker   default:
124*dfc6aa5cSAndroid Build Coastguard Worker     ERREXIT(sinfo->cinfo, JERR_BMP_BADCMAP);
125*dfc6aa5cSAndroid Build Coastguard Worker     break;
126*dfc6aa5cSAndroid Build Coastguard Worker   }
127*dfc6aa5cSAndroid Build Coastguard Worker 
128*dfc6aa5cSAndroid Build Coastguard Worker   if ((sinfo->cinfo->in_color_space == JCS_UNKNOWN ||
129*dfc6aa5cSAndroid Build Coastguard Worker        sinfo->cinfo->in_color_space == JCS_RGB) && gray)
130*dfc6aa5cSAndroid Build Coastguard Worker     sinfo->cinfo->in_color_space = JCS_GRAYSCALE;
131*dfc6aa5cSAndroid Build Coastguard Worker 
132*dfc6aa5cSAndroid Build Coastguard Worker   if (sinfo->cinfo->in_color_space == JCS_GRAYSCALE && !gray)
133*dfc6aa5cSAndroid Build Coastguard Worker     ERREXIT(sinfo->cinfo, JERR_BAD_IN_COLORSPACE);
134*dfc6aa5cSAndroid Build Coastguard Worker }
135*dfc6aa5cSAndroid Build Coastguard Worker 
136*dfc6aa5cSAndroid Build Coastguard Worker 
137*dfc6aa5cSAndroid Build Coastguard Worker /*
138*dfc6aa5cSAndroid Build Coastguard Worker  * Read one row of pixels.
139*dfc6aa5cSAndroid Build Coastguard Worker  * The image has been read into the whole_image array, but is otherwise
140*dfc6aa5cSAndroid Build Coastguard Worker  * unprocessed.  We must read it out in top-to-bottom row order, and if
141*dfc6aa5cSAndroid Build Coastguard Worker  * it is an 8-bit image, we must expand colormapped pixels to 24bit format.
142*dfc6aa5cSAndroid Build Coastguard Worker  */
143*dfc6aa5cSAndroid Build Coastguard Worker 
144*dfc6aa5cSAndroid Build Coastguard Worker METHODDEF(JDIMENSION)
get_8bit_row(j_compress_ptr cinfo,cjpeg_source_ptr sinfo)145*dfc6aa5cSAndroid Build Coastguard Worker get_8bit_row(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
146*dfc6aa5cSAndroid Build Coastguard Worker /* This version is for reading 8-bit colormap indexes */
147*dfc6aa5cSAndroid Build Coastguard Worker {
148*dfc6aa5cSAndroid Build Coastguard Worker   bmp_source_ptr source = (bmp_source_ptr)sinfo;
149*dfc6aa5cSAndroid Build Coastguard Worker   register JSAMPARRAY colormap = source->colormap;
150*dfc6aa5cSAndroid Build Coastguard Worker   int cmaplen = source->cmap_length;
151*dfc6aa5cSAndroid Build Coastguard Worker   JSAMPARRAY image_ptr;
152*dfc6aa5cSAndroid Build Coastguard Worker   register int t;
153*dfc6aa5cSAndroid Build Coastguard Worker   register JSAMPROW inptr, outptr;
154*dfc6aa5cSAndroid Build Coastguard Worker   register JDIMENSION col;
155*dfc6aa5cSAndroid Build Coastguard Worker 
156*dfc6aa5cSAndroid Build Coastguard Worker   if (source->use_inversion_array) {
157*dfc6aa5cSAndroid Build Coastguard Worker     /* Fetch next row from virtual array */
158*dfc6aa5cSAndroid Build Coastguard Worker     source->source_row--;
159*dfc6aa5cSAndroid Build Coastguard Worker     image_ptr = (*cinfo->mem->access_virt_sarray)
160*dfc6aa5cSAndroid Build Coastguard Worker       ((j_common_ptr)cinfo, source->whole_image,
161*dfc6aa5cSAndroid Build Coastguard Worker        source->source_row, (JDIMENSION)1, FALSE);
162*dfc6aa5cSAndroid Build Coastguard Worker     inptr = image_ptr[0];
163*dfc6aa5cSAndroid Build Coastguard Worker   } else {
164*dfc6aa5cSAndroid Build Coastguard Worker     if (!ReadOK(source->pub.input_file, source->iobuffer, source->row_width))
165*dfc6aa5cSAndroid Build Coastguard Worker       ERREXIT(cinfo, JERR_INPUT_EOF);
166*dfc6aa5cSAndroid Build Coastguard Worker     inptr = source->iobuffer;
167*dfc6aa5cSAndroid Build Coastguard Worker   }
168*dfc6aa5cSAndroid Build Coastguard Worker 
169*dfc6aa5cSAndroid Build Coastguard Worker   /* Expand the colormap indexes to real data */
170*dfc6aa5cSAndroid Build Coastguard Worker   outptr = source->pub.buffer[0];
171*dfc6aa5cSAndroid Build Coastguard Worker   if (cinfo->in_color_space == JCS_GRAYSCALE) {
172*dfc6aa5cSAndroid Build Coastguard Worker     for (col = cinfo->image_width; col > 0; col--) {
173*dfc6aa5cSAndroid Build Coastguard Worker       t = *inptr++;
174*dfc6aa5cSAndroid Build Coastguard Worker       if (t >= cmaplen)
175*dfc6aa5cSAndroid Build Coastguard Worker         ERREXIT(cinfo, JERR_BMP_OUTOFRANGE);
176*dfc6aa5cSAndroid Build Coastguard Worker       *outptr++ = colormap[0][t];
177*dfc6aa5cSAndroid Build Coastguard Worker     }
178*dfc6aa5cSAndroid Build Coastguard Worker   } else if (cinfo->in_color_space == JCS_CMYK) {
179*dfc6aa5cSAndroid Build Coastguard Worker     for (col = cinfo->image_width; col > 0; col--) {
180*dfc6aa5cSAndroid Build Coastguard Worker       t = *inptr++;
181*dfc6aa5cSAndroid Build Coastguard Worker       if (t >= cmaplen)
182*dfc6aa5cSAndroid Build Coastguard Worker         ERREXIT(cinfo, JERR_BMP_OUTOFRANGE);
183*dfc6aa5cSAndroid Build Coastguard Worker       rgb_to_cmyk(colormap[0][t], colormap[1][t], colormap[2][t], outptr,
184*dfc6aa5cSAndroid Build Coastguard Worker                   outptr + 1, outptr + 2, outptr + 3);
185*dfc6aa5cSAndroid Build Coastguard Worker       outptr += 4;
186*dfc6aa5cSAndroid Build Coastguard Worker     }
187*dfc6aa5cSAndroid Build Coastguard Worker   } else {
188*dfc6aa5cSAndroid Build Coastguard Worker     register int rindex = rgb_red[cinfo->in_color_space];
189*dfc6aa5cSAndroid Build Coastguard Worker     register int gindex = rgb_green[cinfo->in_color_space];
190*dfc6aa5cSAndroid Build Coastguard Worker     register int bindex = rgb_blue[cinfo->in_color_space];
191*dfc6aa5cSAndroid Build Coastguard Worker     register int aindex = alpha_index[cinfo->in_color_space];
192*dfc6aa5cSAndroid Build Coastguard Worker     register int ps = rgb_pixelsize[cinfo->in_color_space];
193*dfc6aa5cSAndroid Build Coastguard Worker 
194*dfc6aa5cSAndroid Build Coastguard Worker     if (aindex >= 0) {
195*dfc6aa5cSAndroid Build Coastguard Worker       for (col = cinfo->image_width; col > 0; col--) {
196*dfc6aa5cSAndroid Build Coastguard Worker         t = *inptr++;
197*dfc6aa5cSAndroid Build Coastguard Worker         if (t >= cmaplen)
198*dfc6aa5cSAndroid Build Coastguard Worker           ERREXIT(cinfo, JERR_BMP_OUTOFRANGE);
199*dfc6aa5cSAndroid Build Coastguard Worker         outptr[rindex] = colormap[0][t];
200*dfc6aa5cSAndroid Build Coastguard Worker         outptr[gindex] = colormap[1][t];
201*dfc6aa5cSAndroid Build Coastguard Worker         outptr[bindex] = colormap[2][t];
202*dfc6aa5cSAndroid Build Coastguard Worker         outptr[aindex] = 0xFF;
203*dfc6aa5cSAndroid Build Coastguard Worker         outptr += ps;
204*dfc6aa5cSAndroid Build Coastguard Worker       }
205*dfc6aa5cSAndroid Build Coastguard Worker     } else {
206*dfc6aa5cSAndroid Build Coastguard Worker       for (col = cinfo->image_width; col > 0; col--) {
207*dfc6aa5cSAndroid Build Coastguard Worker         t = *inptr++;
208*dfc6aa5cSAndroid Build Coastguard Worker         if (t >= cmaplen)
209*dfc6aa5cSAndroid Build Coastguard Worker           ERREXIT(cinfo, JERR_BMP_OUTOFRANGE);
210*dfc6aa5cSAndroid Build Coastguard Worker         outptr[rindex] = colormap[0][t];
211*dfc6aa5cSAndroid Build Coastguard Worker         outptr[gindex] = colormap[1][t];
212*dfc6aa5cSAndroid Build Coastguard Worker         outptr[bindex] = colormap[2][t];
213*dfc6aa5cSAndroid Build Coastguard Worker         outptr += ps;
214*dfc6aa5cSAndroid Build Coastguard Worker       }
215*dfc6aa5cSAndroid Build Coastguard Worker     }
216*dfc6aa5cSAndroid Build Coastguard Worker   }
217*dfc6aa5cSAndroid Build Coastguard Worker 
218*dfc6aa5cSAndroid Build Coastguard Worker   return 1;
219*dfc6aa5cSAndroid Build Coastguard Worker }
220*dfc6aa5cSAndroid Build Coastguard Worker 
221*dfc6aa5cSAndroid Build Coastguard Worker 
222*dfc6aa5cSAndroid Build Coastguard Worker METHODDEF(JDIMENSION)
get_24bit_row(j_compress_ptr cinfo,cjpeg_source_ptr sinfo)223*dfc6aa5cSAndroid Build Coastguard Worker get_24bit_row(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
224*dfc6aa5cSAndroid Build Coastguard Worker /* This version is for reading 24-bit pixels */
225*dfc6aa5cSAndroid Build Coastguard Worker {
226*dfc6aa5cSAndroid Build Coastguard Worker   bmp_source_ptr source = (bmp_source_ptr)sinfo;
227*dfc6aa5cSAndroid Build Coastguard Worker   JSAMPARRAY image_ptr;
228*dfc6aa5cSAndroid Build Coastguard Worker   register JSAMPROW inptr, outptr;
229*dfc6aa5cSAndroid Build Coastguard Worker   register JDIMENSION col;
230*dfc6aa5cSAndroid Build Coastguard Worker 
231*dfc6aa5cSAndroid Build Coastguard Worker   if (source->use_inversion_array) {
232*dfc6aa5cSAndroid Build Coastguard Worker     /* Fetch next row from virtual array */
233*dfc6aa5cSAndroid Build Coastguard Worker     source->source_row--;
234*dfc6aa5cSAndroid Build Coastguard Worker     image_ptr = (*cinfo->mem->access_virt_sarray)
235*dfc6aa5cSAndroid Build Coastguard Worker       ((j_common_ptr)cinfo, source->whole_image,
236*dfc6aa5cSAndroid Build Coastguard Worker        source->source_row, (JDIMENSION)1, FALSE);
237*dfc6aa5cSAndroid Build Coastguard Worker     inptr = image_ptr[0];
238*dfc6aa5cSAndroid Build Coastguard Worker   } else {
239*dfc6aa5cSAndroid Build Coastguard Worker     if (!ReadOK(source->pub.input_file, source->iobuffer, source->row_width))
240*dfc6aa5cSAndroid Build Coastguard Worker       ERREXIT(cinfo, JERR_INPUT_EOF);
241*dfc6aa5cSAndroid Build Coastguard Worker     inptr = source->iobuffer;
242*dfc6aa5cSAndroid Build Coastguard Worker   }
243*dfc6aa5cSAndroid Build Coastguard Worker 
244*dfc6aa5cSAndroid Build Coastguard Worker   /* Transfer data.  Note source values are in BGR order
245*dfc6aa5cSAndroid Build Coastguard Worker    * (even though Microsoft's own documents say the opposite).
246*dfc6aa5cSAndroid Build Coastguard Worker    */
247*dfc6aa5cSAndroid Build Coastguard Worker   outptr = source->pub.buffer[0];
248*dfc6aa5cSAndroid Build Coastguard Worker   if (cinfo->in_color_space == JCS_EXT_BGR) {
249*dfc6aa5cSAndroid Build Coastguard Worker     memcpy(outptr, inptr, source->row_width);
250*dfc6aa5cSAndroid Build Coastguard Worker   } else if (cinfo->in_color_space == JCS_CMYK) {
251*dfc6aa5cSAndroid Build Coastguard Worker     for (col = cinfo->image_width; col > 0; col--) {
252*dfc6aa5cSAndroid Build Coastguard Worker       JSAMPLE b = *inptr++, g = *inptr++, r = *inptr++;
253*dfc6aa5cSAndroid Build Coastguard Worker       rgb_to_cmyk(r, g, b, outptr, outptr + 1, outptr + 2, outptr + 3);
254*dfc6aa5cSAndroid Build Coastguard Worker       outptr += 4;
255*dfc6aa5cSAndroid Build Coastguard Worker     }
256*dfc6aa5cSAndroid Build Coastguard Worker   } else {
257*dfc6aa5cSAndroid Build Coastguard Worker     register int rindex = rgb_red[cinfo->in_color_space];
258*dfc6aa5cSAndroid Build Coastguard Worker     register int gindex = rgb_green[cinfo->in_color_space];
259*dfc6aa5cSAndroid Build Coastguard Worker     register int bindex = rgb_blue[cinfo->in_color_space];
260*dfc6aa5cSAndroid Build Coastguard Worker     register int aindex = alpha_index[cinfo->in_color_space];
261*dfc6aa5cSAndroid Build Coastguard Worker     register int ps = rgb_pixelsize[cinfo->in_color_space];
262*dfc6aa5cSAndroid Build Coastguard Worker 
263*dfc6aa5cSAndroid Build Coastguard Worker     if (aindex >= 0) {
264*dfc6aa5cSAndroid Build Coastguard Worker       for (col = cinfo->image_width; col > 0; col--) {
265*dfc6aa5cSAndroid Build Coastguard Worker         outptr[bindex] = *inptr++;
266*dfc6aa5cSAndroid Build Coastguard Worker         outptr[gindex] = *inptr++;
267*dfc6aa5cSAndroid Build Coastguard Worker         outptr[rindex] = *inptr++;
268*dfc6aa5cSAndroid Build Coastguard Worker         outptr[aindex] = 0xFF;
269*dfc6aa5cSAndroid Build Coastguard Worker         outptr += ps;
270*dfc6aa5cSAndroid Build Coastguard Worker       }
271*dfc6aa5cSAndroid Build Coastguard Worker     } else {
272*dfc6aa5cSAndroid Build Coastguard Worker       for (col = cinfo->image_width; col > 0; col--) {
273*dfc6aa5cSAndroid Build Coastguard Worker         outptr[bindex] = *inptr++;
274*dfc6aa5cSAndroid Build Coastguard Worker         outptr[gindex] = *inptr++;
275*dfc6aa5cSAndroid Build Coastguard Worker         outptr[rindex] = *inptr++;
276*dfc6aa5cSAndroid Build Coastguard Worker         outptr += ps;
277*dfc6aa5cSAndroid Build Coastguard Worker       }
278*dfc6aa5cSAndroid Build Coastguard Worker     }
279*dfc6aa5cSAndroid Build Coastguard Worker   }
280*dfc6aa5cSAndroid Build Coastguard Worker 
281*dfc6aa5cSAndroid Build Coastguard Worker   return 1;
282*dfc6aa5cSAndroid Build Coastguard Worker }
283*dfc6aa5cSAndroid Build Coastguard Worker 
284*dfc6aa5cSAndroid Build Coastguard Worker 
285*dfc6aa5cSAndroid Build Coastguard Worker METHODDEF(JDIMENSION)
get_32bit_row(j_compress_ptr cinfo,cjpeg_source_ptr sinfo)286*dfc6aa5cSAndroid Build Coastguard Worker get_32bit_row(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
287*dfc6aa5cSAndroid Build Coastguard Worker /* This version is for reading 32-bit pixels */
288*dfc6aa5cSAndroid Build Coastguard Worker {
289*dfc6aa5cSAndroid Build Coastguard Worker   bmp_source_ptr source = (bmp_source_ptr)sinfo;
290*dfc6aa5cSAndroid Build Coastguard Worker   JSAMPARRAY image_ptr;
291*dfc6aa5cSAndroid Build Coastguard Worker   register JSAMPROW inptr, outptr;
292*dfc6aa5cSAndroid Build Coastguard Worker   register JDIMENSION col;
293*dfc6aa5cSAndroid Build Coastguard Worker 
294*dfc6aa5cSAndroid Build Coastguard Worker   if (source->use_inversion_array) {
295*dfc6aa5cSAndroid Build Coastguard Worker     /* Fetch next row from virtual array */
296*dfc6aa5cSAndroid Build Coastguard Worker     source->source_row--;
297*dfc6aa5cSAndroid Build Coastguard Worker     image_ptr = (*cinfo->mem->access_virt_sarray)
298*dfc6aa5cSAndroid Build Coastguard Worker       ((j_common_ptr)cinfo, source->whole_image,
299*dfc6aa5cSAndroid Build Coastguard Worker        source->source_row, (JDIMENSION)1, FALSE);
300*dfc6aa5cSAndroid Build Coastguard Worker     inptr = image_ptr[0];
301*dfc6aa5cSAndroid Build Coastguard Worker   } else {
302*dfc6aa5cSAndroid Build Coastguard Worker     if (!ReadOK(source->pub.input_file, source->iobuffer, source->row_width))
303*dfc6aa5cSAndroid Build Coastguard Worker       ERREXIT(cinfo, JERR_INPUT_EOF);
304*dfc6aa5cSAndroid Build Coastguard Worker     inptr = source->iobuffer;
305*dfc6aa5cSAndroid Build Coastguard Worker   }
306*dfc6aa5cSAndroid Build Coastguard Worker 
307*dfc6aa5cSAndroid Build Coastguard Worker   /* Transfer data.  Note source values are in BGR order
308*dfc6aa5cSAndroid Build Coastguard Worker    * (even though Microsoft's own documents say the opposite).
309*dfc6aa5cSAndroid Build Coastguard Worker    */
310*dfc6aa5cSAndroid Build Coastguard Worker   outptr = source->pub.buffer[0];
311*dfc6aa5cSAndroid Build Coastguard Worker   if (cinfo->in_color_space == JCS_EXT_BGRX ||
312*dfc6aa5cSAndroid Build Coastguard Worker       cinfo->in_color_space == JCS_EXT_BGRA) {
313*dfc6aa5cSAndroid Build Coastguard Worker     memcpy(outptr, inptr, source->row_width);
314*dfc6aa5cSAndroid Build Coastguard Worker   } else if (cinfo->in_color_space == JCS_CMYK) {
315*dfc6aa5cSAndroid Build Coastguard Worker     for (col = cinfo->image_width; col > 0; col--) {
316*dfc6aa5cSAndroid Build Coastguard Worker       JSAMPLE b = *inptr++, g = *inptr++, r = *inptr++;
317*dfc6aa5cSAndroid Build Coastguard Worker       rgb_to_cmyk(r, g, b, outptr, outptr + 1, outptr + 2, outptr + 3);
318*dfc6aa5cSAndroid Build Coastguard Worker       inptr++;                          /* skip the 4th byte (Alpha channel) */
319*dfc6aa5cSAndroid Build Coastguard Worker       outptr += 4;
320*dfc6aa5cSAndroid Build Coastguard Worker     }
321*dfc6aa5cSAndroid Build Coastguard Worker   } else {
322*dfc6aa5cSAndroid Build Coastguard Worker     register int rindex = rgb_red[cinfo->in_color_space];
323*dfc6aa5cSAndroid Build Coastguard Worker     register int gindex = rgb_green[cinfo->in_color_space];
324*dfc6aa5cSAndroid Build Coastguard Worker     register int bindex = rgb_blue[cinfo->in_color_space];
325*dfc6aa5cSAndroid Build Coastguard Worker     register int aindex = alpha_index[cinfo->in_color_space];
326*dfc6aa5cSAndroid Build Coastguard Worker     register int ps = rgb_pixelsize[cinfo->in_color_space];
327*dfc6aa5cSAndroid Build Coastguard Worker 
328*dfc6aa5cSAndroid Build Coastguard Worker     if (aindex >= 0) {
329*dfc6aa5cSAndroid Build Coastguard Worker       for (col = cinfo->image_width; col > 0; col--) {
330*dfc6aa5cSAndroid Build Coastguard Worker         outptr[bindex] = *inptr++;
331*dfc6aa5cSAndroid Build Coastguard Worker         outptr[gindex] = *inptr++;
332*dfc6aa5cSAndroid Build Coastguard Worker         outptr[rindex] = *inptr++;
333*dfc6aa5cSAndroid Build Coastguard Worker         outptr[aindex] = *inptr++;
334*dfc6aa5cSAndroid Build Coastguard Worker         outptr += ps;
335*dfc6aa5cSAndroid Build Coastguard Worker       }
336*dfc6aa5cSAndroid Build Coastguard Worker     } else {
337*dfc6aa5cSAndroid Build Coastguard Worker       for (col = cinfo->image_width; col > 0; col--) {
338*dfc6aa5cSAndroid Build Coastguard Worker         outptr[bindex] = *inptr++;
339*dfc6aa5cSAndroid Build Coastguard Worker         outptr[gindex] = *inptr++;
340*dfc6aa5cSAndroid Build Coastguard Worker         outptr[rindex] = *inptr++;
341*dfc6aa5cSAndroid Build Coastguard Worker         inptr++;                        /* skip the 4th byte (Alpha channel) */
342*dfc6aa5cSAndroid Build Coastguard Worker         outptr += ps;
343*dfc6aa5cSAndroid Build Coastguard Worker       }
344*dfc6aa5cSAndroid Build Coastguard Worker     }
345*dfc6aa5cSAndroid Build Coastguard Worker   }
346*dfc6aa5cSAndroid Build Coastguard Worker 
347*dfc6aa5cSAndroid Build Coastguard Worker   return 1;
348*dfc6aa5cSAndroid Build Coastguard Worker }
349*dfc6aa5cSAndroid Build Coastguard Worker 
350*dfc6aa5cSAndroid Build Coastguard Worker 
351*dfc6aa5cSAndroid Build Coastguard Worker /*
352*dfc6aa5cSAndroid Build Coastguard Worker  * This method loads the image into whole_image during the first call on
353*dfc6aa5cSAndroid Build Coastguard Worker  * get_pixel_rows.  The get_pixel_rows pointer is then adjusted to call
354*dfc6aa5cSAndroid Build Coastguard Worker  * get_8bit_row, get_24bit_row, or get_32bit_row on subsequent calls.
355*dfc6aa5cSAndroid Build Coastguard Worker  */
356*dfc6aa5cSAndroid Build Coastguard Worker 
357*dfc6aa5cSAndroid Build Coastguard Worker METHODDEF(JDIMENSION)
preload_image(j_compress_ptr cinfo,cjpeg_source_ptr sinfo)358*dfc6aa5cSAndroid Build Coastguard Worker preload_image(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
359*dfc6aa5cSAndroid Build Coastguard Worker {
360*dfc6aa5cSAndroid Build Coastguard Worker   bmp_source_ptr source = (bmp_source_ptr)sinfo;
361*dfc6aa5cSAndroid Build Coastguard Worker   register FILE *infile = source->pub.input_file;
362*dfc6aa5cSAndroid Build Coastguard Worker   register JSAMPROW out_ptr;
363*dfc6aa5cSAndroid Build Coastguard Worker   JSAMPARRAY image_ptr;
364*dfc6aa5cSAndroid Build Coastguard Worker   JDIMENSION row;
365*dfc6aa5cSAndroid Build Coastguard Worker   cd_progress_ptr progress = (cd_progress_ptr)cinfo->progress;
366*dfc6aa5cSAndroid Build Coastguard Worker 
367*dfc6aa5cSAndroid Build Coastguard Worker   /* Read the data into a virtual array in input-file row order. */
368*dfc6aa5cSAndroid Build Coastguard Worker   for (row = 0; row < cinfo->image_height; row++) {
369*dfc6aa5cSAndroid Build Coastguard Worker     if (progress != NULL) {
370*dfc6aa5cSAndroid Build Coastguard Worker       progress->pub.pass_counter = (long)row;
371*dfc6aa5cSAndroid Build Coastguard Worker       progress->pub.pass_limit = (long)cinfo->image_height;
372*dfc6aa5cSAndroid Build Coastguard Worker       (*progress->pub.progress_monitor) ((j_common_ptr)cinfo);
373*dfc6aa5cSAndroid Build Coastguard Worker     }
374*dfc6aa5cSAndroid Build Coastguard Worker     image_ptr = (*cinfo->mem->access_virt_sarray)
375*dfc6aa5cSAndroid Build Coastguard Worker       ((j_common_ptr)cinfo, source->whole_image, row, (JDIMENSION)1, TRUE);
376*dfc6aa5cSAndroid Build Coastguard Worker     out_ptr = image_ptr[0];
377*dfc6aa5cSAndroid Build Coastguard Worker     if (fread(out_ptr, 1, source->row_width, infile) != source->row_width) {
378*dfc6aa5cSAndroid Build Coastguard Worker       if (feof(infile))
379*dfc6aa5cSAndroid Build Coastguard Worker         ERREXIT(cinfo, JERR_INPUT_EOF);
380*dfc6aa5cSAndroid Build Coastguard Worker       else
381*dfc6aa5cSAndroid Build Coastguard Worker         ERREXIT(cinfo, JERR_FILE_READ);
382*dfc6aa5cSAndroid Build Coastguard Worker     }
383*dfc6aa5cSAndroid Build Coastguard Worker   }
384*dfc6aa5cSAndroid Build Coastguard Worker   if (progress != NULL)
385*dfc6aa5cSAndroid Build Coastguard Worker     progress->completed_extra_passes++;
386*dfc6aa5cSAndroid Build Coastguard Worker 
387*dfc6aa5cSAndroid Build Coastguard Worker   /* Set up to read from the virtual array in top-to-bottom order */
388*dfc6aa5cSAndroid Build Coastguard Worker   switch (source->bits_per_pixel) {
389*dfc6aa5cSAndroid Build Coastguard Worker   case 8:
390*dfc6aa5cSAndroid Build Coastguard Worker     source->pub.get_pixel_rows = get_8bit_row;
391*dfc6aa5cSAndroid Build Coastguard Worker     break;
392*dfc6aa5cSAndroid Build Coastguard Worker   case 24:
393*dfc6aa5cSAndroid Build Coastguard Worker     source->pub.get_pixel_rows = get_24bit_row;
394*dfc6aa5cSAndroid Build Coastguard Worker     break;
395*dfc6aa5cSAndroid Build Coastguard Worker   case 32:
396*dfc6aa5cSAndroid Build Coastguard Worker     source->pub.get_pixel_rows = get_32bit_row;
397*dfc6aa5cSAndroid Build Coastguard Worker     break;
398*dfc6aa5cSAndroid Build Coastguard Worker   default:
399*dfc6aa5cSAndroid Build Coastguard Worker     ERREXIT(cinfo, JERR_BMP_BADDEPTH);
400*dfc6aa5cSAndroid Build Coastguard Worker   }
401*dfc6aa5cSAndroid Build Coastguard Worker   source->source_row = cinfo->image_height;
402*dfc6aa5cSAndroid Build Coastguard Worker 
403*dfc6aa5cSAndroid Build Coastguard Worker   /* And read the first row */
404*dfc6aa5cSAndroid Build Coastguard Worker   return (*source->pub.get_pixel_rows) (cinfo, sinfo);
405*dfc6aa5cSAndroid Build Coastguard Worker }
406*dfc6aa5cSAndroid Build Coastguard Worker 
407*dfc6aa5cSAndroid Build Coastguard Worker 
408*dfc6aa5cSAndroid Build Coastguard Worker /*
409*dfc6aa5cSAndroid Build Coastguard Worker  * Read the file header; return image size and component count.
410*dfc6aa5cSAndroid Build Coastguard Worker  */
411*dfc6aa5cSAndroid Build Coastguard Worker 
412*dfc6aa5cSAndroid Build Coastguard Worker METHODDEF(void)
start_input_bmp(j_compress_ptr cinfo,cjpeg_source_ptr sinfo)413*dfc6aa5cSAndroid Build Coastguard Worker start_input_bmp(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
414*dfc6aa5cSAndroid Build Coastguard Worker {
415*dfc6aa5cSAndroid Build Coastguard Worker   bmp_source_ptr source = (bmp_source_ptr)sinfo;
416*dfc6aa5cSAndroid Build Coastguard Worker   U_CHAR bmpfileheader[14];
417*dfc6aa5cSAndroid Build Coastguard Worker   U_CHAR bmpinfoheader[64];
418*dfc6aa5cSAndroid Build Coastguard Worker 
419*dfc6aa5cSAndroid Build Coastguard Worker #define GET_2B(array, offset) \
420*dfc6aa5cSAndroid Build Coastguard Worker   ((unsigned short)UCH(array[offset]) + \
421*dfc6aa5cSAndroid Build Coastguard Worker    (((unsigned short)UCH(array[offset + 1])) << 8))
422*dfc6aa5cSAndroid Build Coastguard Worker #define GET_4B(array, offset) \
423*dfc6aa5cSAndroid Build Coastguard Worker   ((unsigned int)UCH(array[offset]) + \
424*dfc6aa5cSAndroid Build Coastguard Worker    (((unsigned int)UCH(array[offset + 1])) << 8) + \
425*dfc6aa5cSAndroid Build Coastguard Worker    (((unsigned int)UCH(array[offset + 2])) << 16) + \
426*dfc6aa5cSAndroid Build Coastguard Worker    (((unsigned int)UCH(array[offset + 3])) << 24))
427*dfc6aa5cSAndroid Build Coastguard Worker 
428*dfc6aa5cSAndroid Build Coastguard Worker   int bfOffBits;
429*dfc6aa5cSAndroid Build Coastguard Worker   int headerSize;
430*dfc6aa5cSAndroid Build Coastguard Worker   int biWidth;
431*dfc6aa5cSAndroid Build Coastguard Worker   int biHeight;
432*dfc6aa5cSAndroid Build Coastguard Worker   unsigned short biPlanes;
433*dfc6aa5cSAndroid Build Coastguard Worker   unsigned int biCompression;
434*dfc6aa5cSAndroid Build Coastguard Worker   int biXPelsPerMeter, biYPelsPerMeter;
435*dfc6aa5cSAndroid Build Coastguard Worker   int biClrUsed = 0;
436*dfc6aa5cSAndroid Build Coastguard Worker   int mapentrysize = 0;         /* 0 indicates no colormap */
437*dfc6aa5cSAndroid Build Coastguard Worker   int bPad;
438*dfc6aa5cSAndroid Build Coastguard Worker   JDIMENSION row_width = 0;
439*dfc6aa5cSAndroid Build Coastguard Worker 
440*dfc6aa5cSAndroid Build Coastguard Worker   /* Read and verify the bitmap file header */
441*dfc6aa5cSAndroid Build Coastguard Worker   if (!ReadOK(source->pub.input_file, bmpfileheader, 14))
442*dfc6aa5cSAndroid Build Coastguard Worker     ERREXIT(cinfo, JERR_INPUT_EOF);
443*dfc6aa5cSAndroid Build Coastguard Worker   if (GET_2B(bmpfileheader, 0) != 0x4D42) /* 'BM' */
444*dfc6aa5cSAndroid Build Coastguard Worker     ERREXIT(cinfo, JERR_BMP_NOT);
445*dfc6aa5cSAndroid Build Coastguard Worker   bfOffBits = GET_4B(bmpfileheader, 10);
446*dfc6aa5cSAndroid Build Coastguard Worker   /* We ignore the remaining fileheader fields */
447*dfc6aa5cSAndroid Build Coastguard Worker 
448*dfc6aa5cSAndroid Build Coastguard Worker   /* The infoheader might be 12 bytes (OS/2 1.x), 40 bytes (Windows),
449*dfc6aa5cSAndroid Build Coastguard Worker    * or 64 bytes (OS/2 2.x).  Check the first 4 bytes to find out which.
450*dfc6aa5cSAndroid Build Coastguard Worker    */
451*dfc6aa5cSAndroid Build Coastguard Worker   if (!ReadOK(source->pub.input_file, bmpinfoheader, 4))
452*dfc6aa5cSAndroid Build Coastguard Worker     ERREXIT(cinfo, JERR_INPUT_EOF);
453*dfc6aa5cSAndroid Build Coastguard Worker   headerSize = GET_4B(bmpinfoheader, 0);
454*dfc6aa5cSAndroid Build Coastguard Worker   if (headerSize < 12 || headerSize > 64 || (headerSize + 14) > bfOffBits)
455*dfc6aa5cSAndroid Build Coastguard Worker     ERREXIT(cinfo, JERR_BMP_BADHEADER);
456*dfc6aa5cSAndroid Build Coastguard Worker   if (!ReadOK(source->pub.input_file, bmpinfoheader + 4, headerSize - 4))
457*dfc6aa5cSAndroid Build Coastguard Worker     ERREXIT(cinfo, JERR_INPUT_EOF);
458*dfc6aa5cSAndroid Build Coastguard Worker 
459*dfc6aa5cSAndroid Build Coastguard Worker   switch (headerSize) {
460*dfc6aa5cSAndroid Build Coastguard Worker   case 12:
461*dfc6aa5cSAndroid Build Coastguard Worker     /* Decode OS/2 1.x header (Microsoft calls this a BITMAPCOREHEADER) */
462*dfc6aa5cSAndroid Build Coastguard Worker     biWidth = (int)GET_2B(bmpinfoheader, 4);
463*dfc6aa5cSAndroid Build Coastguard Worker     biHeight = (int)GET_2B(bmpinfoheader, 6);
464*dfc6aa5cSAndroid Build Coastguard Worker     biPlanes = GET_2B(bmpinfoheader, 8);
465*dfc6aa5cSAndroid Build Coastguard Worker     source->bits_per_pixel = (int)GET_2B(bmpinfoheader, 10);
466*dfc6aa5cSAndroid Build Coastguard Worker 
467*dfc6aa5cSAndroid Build Coastguard Worker     switch (source->bits_per_pixel) {
468*dfc6aa5cSAndroid Build Coastguard Worker     case 8:                     /* colormapped image */
469*dfc6aa5cSAndroid Build Coastguard Worker       mapentrysize = 3;         /* OS/2 uses RGBTRIPLE colormap */
470*dfc6aa5cSAndroid Build Coastguard Worker       TRACEMS2(cinfo, 1, JTRC_BMP_OS2_MAPPED, biWidth, biHeight);
471*dfc6aa5cSAndroid Build Coastguard Worker       break;
472*dfc6aa5cSAndroid Build Coastguard Worker     case 24:                    /* RGB image */
473*dfc6aa5cSAndroid Build Coastguard Worker     case 32:                    /* RGB image + Alpha channel */
474*dfc6aa5cSAndroid Build Coastguard Worker       TRACEMS3(cinfo, 1, JTRC_BMP_OS2, biWidth, biHeight,
475*dfc6aa5cSAndroid Build Coastguard Worker                source->bits_per_pixel);
476*dfc6aa5cSAndroid Build Coastguard Worker       break;
477*dfc6aa5cSAndroid Build Coastguard Worker     default:
478*dfc6aa5cSAndroid Build Coastguard Worker       ERREXIT(cinfo, JERR_BMP_BADDEPTH);
479*dfc6aa5cSAndroid Build Coastguard Worker       break;
480*dfc6aa5cSAndroid Build Coastguard Worker     }
481*dfc6aa5cSAndroid Build Coastguard Worker     break;
482*dfc6aa5cSAndroid Build Coastguard Worker   case 40:
483*dfc6aa5cSAndroid Build Coastguard Worker   case 64:
484*dfc6aa5cSAndroid Build Coastguard Worker     /* Decode Windows 3.x header (Microsoft calls this a BITMAPINFOHEADER) */
485*dfc6aa5cSAndroid Build Coastguard Worker     /* or OS/2 2.x header, which has additional fields that we ignore */
486*dfc6aa5cSAndroid Build Coastguard Worker     biWidth = (int)GET_4B(bmpinfoheader, 4);
487*dfc6aa5cSAndroid Build Coastguard Worker     biHeight = (int)GET_4B(bmpinfoheader, 8);
488*dfc6aa5cSAndroid Build Coastguard Worker     biPlanes = GET_2B(bmpinfoheader, 12);
489*dfc6aa5cSAndroid Build Coastguard Worker     source->bits_per_pixel = (int)GET_2B(bmpinfoheader, 14);
490*dfc6aa5cSAndroid Build Coastguard Worker     biCompression = GET_4B(bmpinfoheader, 16);
491*dfc6aa5cSAndroid Build Coastguard Worker     biXPelsPerMeter = (int)GET_4B(bmpinfoheader, 24);
492*dfc6aa5cSAndroid Build Coastguard Worker     biYPelsPerMeter = (int)GET_4B(bmpinfoheader, 28);
493*dfc6aa5cSAndroid Build Coastguard Worker     biClrUsed = GET_4B(bmpinfoheader, 32);
494*dfc6aa5cSAndroid Build Coastguard Worker     /* biSizeImage, biClrImportant fields are ignored */
495*dfc6aa5cSAndroid Build Coastguard Worker 
496*dfc6aa5cSAndroid Build Coastguard Worker     switch (source->bits_per_pixel) {
497*dfc6aa5cSAndroid Build Coastguard Worker     case 8:                     /* colormapped image */
498*dfc6aa5cSAndroid Build Coastguard Worker       mapentrysize = 4;         /* Windows uses RGBQUAD colormap */
499*dfc6aa5cSAndroid Build Coastguard Worker       TRACEMS2(cinfo, 1, JTRC_BMP_MAPPED, biWidth, biHeight);
500*dfc6aa5cSAndroid Build Coastguard Worker       break;
501*dfc6aa5cSAndroid Build Coastguard Worker     case 24:                    /* RGB image */
502*dfc6aa5cSAndroid Build Coastguard Worker     case 32:                    /* RGB image + Alpha channel */
503*dfc6aa5cSAndroid Build Coastguard Worker       TRACEMS3(cinfo, 1, JTRC_BMP, biWidth, biHeight, source->bits_per_pixel);
504*dfc6aa5cSAndroid Build Coastguard Worker       break;
505*dfc6aa5cSAndroid Build Coastguard Worker     default:
506*dfc6aa5cSAndroid Build Coastguard Worker       ERREXIT(cinfo, JERR_BMP_BADDEPTH);
507*dfc6aa5cSAndroid Build Coastguard Worker       break;
508*dfc6aa5cSAndroid Build Coastguard Worker     }
509*dfc6aa5cSAndroid Build Coastguard Worker     if (biCompression != 0)
510*dfc6aa5cSAndroid Build Coastguard Worker       ERREXIT(cinfo, JERR_BMP_COMPRESSED);
511*dfc6aa5cSAndroid Build Coastguard Worker 
512*dfc6aa5cSAndroid Build Coastguard Worker     if (biXPelsPerMeter > 0 && biYPelsPerMeter > 0) {
513*dfc6aa5cSAndroid Build Coastguard Worker       /* Set JFIF density parameters from the BMP data */
514*dfc6aa5cSAndroid Build Coastguard Worker       cinfo->X_density = (UINT16)(biXPelsPerMeter / 100); /* 100 cm per meter */
515*dfc6aa5cSAndroid Build Coastguard Worker       cinfo->Y_density = (UINT16)(biYPelsPerMeter / 100);
516*dfc6aa5cSAndroid Build Coastguard Worker       cinfo->density_unit = 2;  /* dots/cm */
517*dfc6aa5cSAndroid Build Coastguard Worker     }
518*dfc6aa5cSAndroid Build Coastguard Worker     break;
519*dfc6aa5cSAndroid Build Coastguard Worker   default:
520*dfc6aa5cSAndroid Build Coastguard Worker     ERREXIT(cinfo, JERR_BMP_BADHEADER);
521*dfc6aa5cSAndroid Build Coastguard Worker     return;
522*dfc6aa5cSAndroid Build Coastguard Worker   }
523*dfc6aa5cSAndroid Build Coastguard Worker 
524*dfc6aa5cSAndroid Build Coastguard Worker   if (biWidth <= 0 || biHeight <= 0)
525*dfc6aa5cSAndroid Build Coastguard Worker     ERREXIT(cinfo, JERR_BMP_EMPTY);
526*dfc6aa5cSAndroid Build Coastguard Worker #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
527*dfc6aa5cSAndroid Build Coastguard Worker   if (sinfo->max_pixels &&
528*dfc6aa5cSAndroid Build Coastguard Worker       (unsigned long long)biWidth * biHeight > sinfo->max_pixels)
529*dfc6aa5cSAndroid Build Coastguard Worker     ERREXIT(cinfo, JERR_WIDTH_OVERFLOW);
530*dfc6aa5cSAndroid Build Coastguard Worker #endif
531*dfc6aa5cSAndroid Build Coastguard Worker   if (biPlanes != 1)
532*dfc6aa5cSAndroid Build Coastguard Worker     ERREXIT(cinfo, JERR_BMP_BADPLANES);
533*dfc6aa5cSAndroid Build Coastguard Worker 
534*dfc6aa5cSAndroid Build Coastguard Worker   /* Compute distance to bitmap data --- will adjust for colormap below */
535*dfc6aa5cSAndroid Build Coastguard Worker   bPad = bfOffBits - (headerSize + 14);
536*dfc6aa5cSAndroid Build Coastguard Worker 
537*dfc6aa5cSAndroid Build Coastguard Worker   /* Read the colormap, if any */
538*dfc6aa5cSAndroid Build Coastguard Worker   if (mapentrysize > 0) {
539*dfc6aa5cSAndroid Build Coastguard Worker     if (biClrUsed <= 0)
540*dfc6aa5cSAndroid Build Coastguard Worker       biClrUsed = 256;          /* assume it's 256 */
541*dfc6aa5cSAndroid Build Coastguard Worker     else if (biClrUsed > 256)
542*dfc6aa5cSAndroid Build Coastguard Worker       ERREXIT(cinfo, JERR_BMP_BADCMAP);
543*dfc6aa5cSAndroid Build Coastguard Worker     /* Allocate space to store the colormap */
544*dfc6aa5cSAndroid Build Coastguard Worker     source->colormap = (*cinfo->mem->alloc_sarray)
545*dfc6aa5cSAndroid Build Coastguard Worker       ((j_common_ptr)cinfo, JPOOL_IMAGE, (JDIMENSION)biClrUsed, (JDIMENSION)3);
546*dfc6aa5cSAndroid Build Coastguard Worker     source->cmap_length = (int)biClrUsed;
547*dfc6aa5cSAndroid Build Coastguard Worker     /* and read it from the file */
548*dfc6aa5cSAndroid Build Coastguard Worker     read_colormap(source, (int)biClrUsed, mapentrysize);
549*dfc6aa5cSAndroid Build Coastguard Worker     /* account for size of colormap */
550*dfc6aa5cSAndroid Build Coastguard Worker     bPad -= biClrUsed * mapentrysize;
551*dfc6aa5cSAndroid Build Coastguard Worker   }
552*dfc6aa5cSAndroid Build Coastguard Worker 
553*dfc6aa5cSAndroid Build Coastguard Worker   /* Skip any remaining pad bytes */
554*dfc6aa5cSAndroid Build Coastguard Worker   if (bPad < 0)                 /* incorrect bfOffBits value? */
555*dfc6aa5cSAndroid Build Coastguard Worker     ERREXIT(cinfo, JERR_BMP_BADHEADER);
556*dfc6aa5cSAndroid Build Coastguard Worker   while (--bPad >= 0) {
557*dfc6aa5cSAndroid Build Coastguard Worker     (void)read_byte(source);
558*dfc6aa5cSAndroid Build Coastguard Worker   }
559*dfc6aa5cSAndroid Build Coastguard Worker 
560*dfc6aa5cSAndroid Build Coastguard Worker   /* Compute row width in file, including padding to 4-byte boundary */
561*dfc6aa5cSAndroid Build Coastguard Worker   switch (source->bits_per_pixel) {
562*dfc6aa5cSAndroid Build Coastguard Worker   case 8:
563*dfc6aa5cSAndroid Build Coastguard Worker     if (cinfo->in_color_space == JCS_UNKNOWN)
564*dfc6aa5cSAndroid Build Coastguard Worker       cinfo->in_color_space = JCS_EXT_RGB;
565*dfc6aa5cSAndroid Build Coastguard Worker     if (IsExtRGB(cinfo->in_color_space))
566*dfc6aa5cSAndroid Build Coastguard Worker       cinfo->input_components = rgb_pixelsize[cinfo->in_color_space];
567*dfc6aa5cSAndroid Build Coastguard Worker     else if (cinfo->in_color_space == JCS_GRAYSCALE)
568*dfc6aa5cSAndroid Build Coastguard Worker       cinfo->input_components = 1;
569*dfc6aa5cSAndroid Build Coastguard Worker     else if (cinfo->in_color_space == JCS_CMYK)
570*dfc6aa5cSAndroid Build Coastguard Worker       cinfo->input_components = 4;
571*dfc6aa5cSAndroid Build Coastguard Worker     else
572*dfc6aa5cSAndroid Build Coastguard Worker       ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE);
573*dfc6aa5cSAndroid Build Coastguard Worker     row_width = (JDIMENSION)biWidth;
574*dfc6aa5cSAndroid Build Coastguard Worker     break;
575*dfc6aa5cSAndroid Build Coastguard Worker   case 24:
576*dfc6aa5cSAndroid Build Coastguard Worker     if (cinfo->in_color_space == JCS_UNKNOWN)
577*dfc6aa5cSAndroid Build Coastguard Worker       cinfo->in_color_space = JCS_EXT_BGR;
578*dfc6aa5cSAndroid Build Coastguard Worker     if (IsExtRGB(cinfo->in_color_space))
579*dfc6aa5cSAndroid Build Coastguard Worker       cinfo->input_components = rgb_pixelsize[cinfo->in_color_space];
580*dfc6aa5cSAndroid Build Coastguard Worker     else if (cinfo->in_color_space == JCS_CMYK)
581*dfc6aa5cSAndroid Build Coastguard Worker       cinfo->input_components = 4;
582*dfc6aa5cSAndroid Build Coastguard Worker     else
583*dfc6aa5cSAndroid Build Coastguard Worker       ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE);
584*dfc6aa5cSAndroid Build Coastguard Worker     if ((unsigned long long)biWidth * 3ULL > 0xFFFFFFFFULL)
585*dfc6aa5cSAndroid Build Coastguard Worker       ERREXIT(cinfo, JERR_WIDTH_OVERFLOW);
586*dfc6aa5cSAndroid Build Coastguard Worker     row_width = (JDIMENSION)biWidth * 3;
587*dfc6aa5cSAndroid Build Coastguard Worker     break;
588*dfc6aa5cSAndroid Build Coastguard Worker   case 32:
589*dfc6aa5cSAndroid Build Coastguard Worker     if (cinfo->in_color_space == JCS_UNKNOWN)
590*dfc6aa5cSAndroid Build Coastguard Worker       cinfo->in_color_space = JCS_EXT_BGRA;
591*dfc6aa5cSAndroid Build Coastguard Worker     if (IsExtRGB(cinfo->in_color_space))
592*dfc6aa5cSAndroid Build Coastguard Worker       cinfo->input_components = rgb_pixelsize[cinfo->in_color_space];
593*dfc6aa5cSAndroid Build Coastguard Worker     else if (cinfo->in_color_space == JCS_CMYK)
594*dfc6aa5cSAndroid Build Coastguard Worker       cinfo->input_components = 4;
595*dfc6aa5cSAndroid Build Coastguard Worker     else
596*dfc6aa5cSAndroid Build Coastguard Worker       ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE);
597*dfc6aa5cSAndroid Build Coastguard Worker     if ((unsigned long long)biWidth * 4ULL > 0xFFFFFFFFULL)
598*dfc6aa5cSAndroid Build Coastguard Worker       ERREXIT(cinfo, JERR_WIDTH_OVERFLOW);
599*dfc6aa5cSAndroid Build Coastguard Worker     row_width = (JDIMENSION)biWidth * 4;
600*dfc6aa5cSAndroid Build Coastguard Worker     break;
601*dfc6aa5cSAndroid Build Coastguard Worker   default:
602*dfc6aa5cSAndroid Build Coastguard Worker     ERREXIT(cinfo, JERR_BMP_BADDEPTH);
603*dfc6aa5cSAndroid Build Coastguard Worker   }
604*dfc6aa5cSAndroid Build Coastguard Worker   while ((row_width & 3) != 0) row_width++;
605*dfc6aa5cSAndroid Build Coastguard Worker   source->row_width = row_width;
606*dfc6aa5cSAndroid Build Coastguard Worker 
607*dfc6aa5cSAndroid Build Coastguard Worker   if (source->use_inversion_array) {
608*dfc6aa5cSAndroid Build Coastguard Worker     /* Allocate space for inversion array, prepare for preload pass */
609*dfc6aa5cSAndroid Build Coastguard Worker     source->whole_image = (*cinfo->mem->request_virt_sarray)
610*dfc6aa5cSAndroid Build Coastguard Worker       ((j_common_ptr)cinfo, JPOOL_IMAGE, FALSE,
611*dfc6aa5cSAndroid Build Coastguard Worker        row_width, (JDIMENSION)biHeight, (JDIMENSION)1);
612*dfc6aa5cSAndroid Build Coastguard Worker     source->pub.get_pixel_rows = preload_image;
613*dfc6aa5cSAndroid Build Coastguard Worker     if (cinfo->progress != NULL) {
614*dfc6aa5cSAndroid Build Coastguard Worker       cd_progress_ptr progress = (cd_progress_ptr)cinfo->progress;
615*dfc6aa5cSAndroid Build Coastguard Worker       progress->total_extra_passes++; /* count file input as separate pass */
616*dfc6aa5cSAndroid Build Coastguard Worker     }
617*dfc6aa5cSAndroid Build Coastguard Worker   } else {
618*dfc6aa5cSAndroid Build Coastguard Worker     source->iobuffer = (U_CHAR *)
619*dfc6aa5cSAndroid Build Coastguard Worker       (*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE, row_width);
620*dfc6aa5cSAndroid Build Coastguard Worker     switch (source->bits_per_pixel) {
621*dfc6aa5cSAndroid Build Coastguard Worker     case 8:
622*dfc6aa5cSAndroid Build Coastguard Worker       source->pub.get_pixel_rows = get_8bit_row;
623*dfc6aa5cSAndroid Build Coastguard Worker       break;
624*dfc6aa5cSAndroid Build Coastguard Worker     case 24:
625*dfc6aa5cSAndroid Build Coastguard Worker       source->pub.get_pixel_rows = get_24bit_row;
626*dfc6aa5cSAndroid Build Coastguard Worker       break;
627*dfc6aa5cSAndroid Build Coastguard Worker     case 32:
628*dfc6aa5cSAndroid Build Coastguard Worker       source->pub.get_pixel_rows = get_32bit_row;
629*dfc6aa5cSAndroid Build Coastguard Worker       break;
630*dfc6aa5cSAndroid Build Coastguard Worker     default:
631*dfc6aa5cSAndroid Build Coastguard Worker       ERREXIT(cinfo, JERR_BMP_BADDEPTH);
632*dfc6aa5cSAndroid Build Coastguard Worker     }
633*dfc6aa5cSAndroid Build Coastguard Worker   }
634*dfc6aa5cSAndroid Build Coastguard Worker 
635*dfc6aa5cSAndroid Build Coastguard Worker   /* Ensure that biWidth * cinfo->input_components doesn't exceed the maximum
636*dfc6aa5cSAndroid Build Coastguard Worker      value of the JDIMENSION type.  This is only a danger with BMP files, since
637*dfc6aa5cSAndroid Build Coastguard Worker      their width and height fields are 32-bit integers. */
638*dfc6aa5cSAndroid Build Coastguard Worker   if ((unsigned long long)biWidth *
639*dfc6aa5cSAndroid Build Coastguard Worker       (unsigned long long)cinfo->input_components > 0xFFFFFFFFULL)
640*dfc6aa5cSAndroid Build Coastguard Worker     ERREXIT(cinfo, JERR_WIDTH_OVERFLOW);
641*dfc6aa5cSAndroid Build Coastguard Worker   /* Allocate one-row buffer for returned data */
642*dfc6aa5cSAndroid Build Coastguard Worker   source->pub.buffer = (*cinfo->mem->alloc_sarray)
643*dfc6aa5cSAndroid Build Coastguard Worker     ((j_common_ptr)cinfo, JPOOL_IMAGE,
644*dfc6aa5cSAndroid Build Coastguard Worker      (JDIMENSION)biWidth * (JDIMENSION)cinfo->input_components, (JDIMENSION)1);
645*dfc6aa5cSAndroid Build Coastguard Worker   source->pub.buffer_height = 1;
646*dfc6aa5cSAndroid Build Coastguard Worker 
647*dfc6aa5cSAndroid Build Coastguard Worker   cinfo->data_precision = 8;
648*dfc6aa5cSAndroid Build Coastguard Worker   cinfo->image_width = (JDIMENSION)biWidth;
649*dfc6aa5cSAndroid Build Coastguard Worker   cinfo->image_height = (JDIMENSION)biHeight;
650*dfc6aa5cSAndroid Build Coastguard Worker }
651*dfc6aa5cSAndroid Build Coastguard Worker 
652*dfc6aa5cSAndroid Build Coastguard Worker 
653*dfc6aa5cSAndroid Build Coastguard Worker /*
654*dfc6aa5cSAndroid Build Coastguard Worker  * Finish up at the end of the file.
655*dfc6aa5cSAndroid Build Coastguard Worker  */
656*dfc6aa5cSAndroid Build Coastguard Worker 
657*dfc6aa5cSAndroid Build Coastguard Worker METHODDEF(void)
finish_input_bmp(j_compress_ptr cinfo,cjpeg_source_ptr sinfo)658*dfc6aa5cSAndroid Build Coastguard Worker finish_input_bmp(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
659*dfc6aa5cSAndroid Build Coastguard Worker {
660*dfc6aa5cSAndroid Build Coastguard Worker   /* no work */
661*dfc6aa5cSAndroid Build Coastguard Worker }
662*dfc6aa5cSAndroid Build Coastguard Worker 
663*dfc6aa5cSAndroid Build Coastguard Worker 
664*dfc6aa5cSAndroid Build Coastguard Worker /*
665*dfc6aa5cSAndroid Build Coastguard Worker  * The module selection routine for BMP format input.
666*dfc6aa5cSAndroid Build Coastguard Worker  */
667*dfc6aa5cSAndroid Build Coastguard Worker 
668*dfc6aa5cSAndroid Build Coastguard Worker GLOBAL(cjpeg_source_ptr)
jinit_read_bmp(j_compress_ptr cinfo,boolean use_inversion_array)669*dfc6aa5cSAndroid Build Coastguard Worker jinit_read_bmp(j_compress_ptr cinfo, boolean use_inversion_array)
670*dfc6aa5cSAndroid Build Coastguard Worker {
671*dfc6aa5cSAndroid Build Coastguard Worker   bmp_source_ptr source;
672*dfc6aa5cSAndroid Build Coastguard Worker 
673*dfc6aa5cSAndroid Build Coastguard Worker   /* Create module interface object */
674*dfc6aa5cSAndroid Build Coastguard Worker   source = (bmp_source_ptr)
675*dfc6aa5cSAndroid Build Coastguard Worker     (*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
676*dfc6aa5cSAndroid Build Coastguard Worker                                 sizeof(bmp_source_struct));
677*dfc6aa5cSAndroid Build Coastguard Worker   source->cinfo = cinfo;        /* make back link for subroutines */
678*dfc6aa5cSAndroid Build Coastguard Worker   /* Fill in method ptrs, except get_pixel_rows which start_input sets */
679*dfc6aa5cSAndroid Build Coastguard Worker   source->pub.start_input = start_input_bmp;
680*dfc6aa5cSAndroid Build Coastguard Worker   source->pub.finish_input = finish_input_bmp;
681*dfc6aa5cSAndroid Build Coastguard Worker #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
682*dfc6aa5cSAndroid Build Coastguard Worker   source->pub.max_pixels = 0;
683*dfc6aa5cSAndroid Build Coastguard Worker #endif
684*dfc6aa5cSAndroid Build Coastguard Worker 
685*dfc6aa5cSAndroid Build Coastguard Worker   source->use_inversion_array = use_inversion_array;
686*dfc6aa5cSAndroid Build Coastguard Worker 
687*dfc6aa5cSAndroid Build Coastguard Worker   return (cjpeg_source_ptr)source;
688*dfc6aa5cSAndroid Build Coastguard Worker }
689*dfc6aa5cSAndroid Build Coastguard Worker 
690*dfc6aa5cSAndroid Build Coastguard Worker #endif /* BMP_SUPPORTED */
691