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