xref: /aosp_15_r20/external/libjpeg-turbo/wrbmp.c (revision dfc6aa5c1cfd4bc4e2018dc74aa96e29ee49c6da)
1*dfc6aa5cSAndroid Build Coastguard Worker /*
2*dfc6aa5cSAndroid Build Coastguard Worker  * wrbmp.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  * libjpeg-turbo Modifications:
7*dfc6aa5cSAndroid Build Coastguard Worker  * Copyright (C) 2013, Linaro Limited.
8*dfc6aa5cSAndroid Build Coastguard Worker  * Copyright (C) 2014-2015, 2017, 2019, 2022, D. R. Commander.
9*dfc6aa5cSAndroid Build Coastguard Worker  * For conditions of distribution and use, see the accompanying README.ijg
10*dfc6aa5cSAndroid Build Coastguard Worker  * file.
11*dfc6aa5cSAndroid Build Coastguard Worker  *
12*dfc6aa5cSAndroid Build Coastguard Worker  * This file contains routines to write output images in Microsoft "BMP"
13*dfc6aa5cSAndroid Build Coastguard Worker  * format (MS Windows 3.x and OS/2 1.x flavors).
14*dfc6aa5cSAndroid Build Coastguard Worker  * Either 8-bit colormapped or 24-bit full-color format can be written.
15*dfc6aa5cSAndroid Build Coastguard Worker  * No compression is supported.
16*dfc6aa5cSAndroid Build Coastguard Worker  *
17*dfc6aa5cSAndroid Build Coastguard Worker  * These routines may need modification for non-Unix environments or
18*dfc6aa5cSAndroid Build Coastguard Worker  * specialized applications.  As they stand, they assume output to
19*dfc6aa5cSAndroid Build Coastguard Worker  * an ordinary stdio stream.
20*dfc6aa5cSAndroid Build Coastguard Worker  *
21*dfc6aa5cSAndroid Build Coastguard Worker  * This code contributed by James Arthur Boucher.
22*dfc6aa5cSAndroid Build Coastguard Worker  */
23*dfc6aa5cSAndroid Build Coastguard Worker 
24*dfc6aa5cSAndroid Build Coastguard Worker #include "cmyk.h"
25*dfc6aa5cSAndroid Build Coastguard Worker #include "cdjpeg.h"             /* Common decls for cjpeg/djpeg applications */
26*dfc6aa5cSAndroid Build Coastguard Worker #include "jconfigint.h"
27*dfc6aa5cSAndroid Build Coastguard Worker 
28*dfc6aa5cSAndroid Build Coastguard Worker #ifdef BMP_SUPPORTED
29*dfc6aa5cSAndroid Build Coastguard Worker 
30*dfc6aa5cSAndroid Build Coastguard Worker 
31*dfc6aa5cSAndroid Build Coastguard Worker /*
32*dfc6aa5cSAndroid Build Coastguard Worker  * To support 12-bit JPEG data, we'd have to scale output down to 8 bits.
33*dfc6aa5cSAndroid Build Coastguard Worker  * This is not yet implemented.
34*dfc6aa5cSAndroid Build Coastguard Worker  */
35*dfc6aa5cSAndroid Build Coastguard Worker 
36*dfc6aa5cSAndroid Build Coastguard Worker #if BITS_IN_JSAMPLE != 8
37*dfc6aa5cSAndroid Build Coastguard Worker   Sorry, this code only copes with 8-bit JSAMPLEs. /* deliberate syntax err */
38*dfc6aa5cSAndroid Build Coastguard Worker #endif
39*dfc6aa5cSAndroid Build Coastguard Worker 
40*dfc6aa5cSAndroid Build Coastguard Worker /*
41*dfc6aa5cSAndroid Build Coastguard Worker  * Since BMP stores scanlines bottom-to-top, we have to invert the image
42*dfc6aa5cSAndroid Build Coastguard Worker  * from JPEG's top-to-bottom order.  To do this, we save the outgoing data
43*dfc6aa5cSAndroid Build Coastguard Worker  * in a virtual array during put_pixel_row calls, then actually emit the
44*dfc6aa5cSAndroid Build Coastguard Worker  * BMP file during finish_output.  The virtual array contains one JSAMPLE per
45*dfc6aa5cSAndroid Build Coastguard Worker  * pixel if the output is grayscale or colormapped, three if it is full color.
46*dfc6aa5cSAndroid Build Coastguard Worker  */
47*dfc6aa5cSAndroid Build Coastguard Worker 
48*dfc6aa5cSAndroid Build Coastguard Worker /* Private version of data destination object */
49*dfc6aa5cSAndroid Build Coastguard Worker 
50*dfc6aa5cSAndroid Build Coastguard Worker typedef struct {
51*dfc6aa5cSAndroid Build Coastguard Worker   struct djpeg_dest_struct pub; /* public fields */
52*dfc6aa5cSAndroid Build Coastguard Worker 
53*dfc6aa5cSAndroid Build Coastguard Worker   boolean is_os2;               /* saves the OS2 format request flag */
54*dfc6aa5cSAndroid Build Coastguard Worker 
55*dfc6aa5cSAndroid Build Coastguard Worker   jvirt_sarray_ptr whole_image; /* needed to reverse row order */
56*dfc6aa5cSAndroid Build Coastguard Worker   JDIMENSION data_width;        /* JSAMPLEs per row */
57*dfc6aa5cSAndroid Build Coastguard Worker   JDIMENSION row_width;         /* physical width of one row in the BMP file */
58*dfc6aa5cSAndroid Build Coastguard Worker   int pad_bytes;                /* number of padding bytes needed per row */
59*dfc6aa5cSAndroid Build Coastguard Worker   JDIMENSION cur_output_row;    /* next row# to write to virtual array */
60*dfc6aa5cSAndroid Build Coastguard Worker 
61*dfc6aa5cSAndroid Build Coastguard Worker   boolean use_inversion_array;  /* TRUE = buffer the whole image, which is
62*dfc6aa5cSAndroid Build Coastguard Worker                                    stored to disk in bottom-up order, and
63*dfc6aa5cSAndroid Build Coastguard Worker                                    receive rows from the calling program in
64*dfc6aa5cSAndroid Build Coastguard Worker                                    top-down order
65*dfc6aa5cSAndroid Build Coastguard Worker 
66*dfc6aa5cSAndroid Build Coastguard Worker                                    FALSE = the calling program will maintain
67*dfc6aa5cSAndroid Build Coastguard Worker                                    its own image buffer and write the rows in
68*dfc6aa5cSAndroid Build Coastguard Worker                                    bottom-up order */
69*dfc6aa5cSAndroid Build Coastguard Worker 
70*dfc6aa5cSAndroid Build Coastguard Worker   JSAMPLE *iobuffer;            /* I/O buffer (used to buffer a single row to
71*dfc6aa5cSAndroid Build Coastguard Worker                                    disk if use_inversion_array == FALSE) */
72*dfc6aa5cSAndroid Build Coastguard Worker } bmp_dest_struct;
73*dfc6aa5cSAndroid Build Coastguard Worker 
74*dfc6aa5cSAndroid Build Coastguard Worker typedef bmp_dest_struct *bmp_dest_ptr;
75*dfc6aa5cSAndroid Build Coastguard Worker 
76*dfc6aa5cSAndroid Build Coastguard Worker 
77*dfc6aa5cSAndroid Build Coastguard Worker /* Forward declarations */
78*dfc6aa5cSAndroid Build Coastguard Worker LOCAL(void) write_colormap(j_decompress_ptr cinfo, bmp_dest_ptr dest,
79*dfc6aa5cSAndroid Build Coastguard Worker                            int map_colors, int map_entry_size);
80*dfc6aa5cSAndroid Build Coastguard Worker 
81*dfc6aa5cSAndroid Build Coastguard Worker 
is_big_endian(void)82*dfc6aa5cSAndroid Build Coastguard Worker static INLINE boolean is_big_endian(void)
83*dfc6aa5cSAndroid Build Coastguard Worker {
84*dfc6aa5cSAndroid Build Coastguard Worker   int test_value = 1;
85*dfc6aa5cSAndroid Build Coastguard Worker   if (*(char *)&test_value != 1)
86*dfc6aa5cSAndroid Build Coastguard Worker     return TRUE;
87*dfc6aa5cSAndroid Build Coastguard Worker   return FALSE;
88*dfc6aa5cSAndroid Build Coastguard Worker }
89*dfc6aa5cSAndroid Build Coastguard Worker 
90*dfc6aa5cSAndroid Build Coastguard Worker 
91*dfc6aa5cSAndroid Build Coastguard Worker /*
92*dfc6aa5cSAndroid Build Coastguard Worker  * Write some pixel data.
93*dfc6aa5cSAndroid Build Coastguard Worker  * In this module rows_supplied will always be 1.
94*dfc6aa5cSAndroid Build Coastguard Worker  */
95*dfc6aa5cSAndroid Build Coastguard Worker 
96*dfc6aa5cSAndroid Build Coastguard Worker METHODDEF(void)
put_pixel_rows(j_decompress_ptr cinfo,djpeg_dest_ptr dinfo,JDIMENSION rows_supplied)97*dfc6aa5cSAndroid Build Coastguard Worker put_pixel_rows(j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
98*dfc6aa5cSAndroid Build Coastguard Worker                JDIMENSION rows_supplied)
99*dfc6aa5cSAndroid Build Coastguard Worker /* This version is for writing 24-bit pixels */
100*dfc6aa5cSAndroid Build Coastguard Worker {
101*dfc6aa5cSAndroid Build Coastguard Worker   bmp_dest_ptr dest = (bmp_dest_ptr)dinfo;
102*dfc6aa5cSAndroid Build Coastguard Worker   JSAMPARRAY image_ptr;
103*dfc6aa5cSAndroid Build Coastguard Worker   register JSAMPROW inptr, outptr;
104*dfc6aa5cSAndroid Build Coastguard Worker   register JDIMENSION col;
105*dfc6aa5cSAndroid Build Coastguard Worker   int pad;
106*dfc6aa5cSAndroid Build Coastguard Worker 
107*dfc6aa5cSAndroid Build Coastguard Worker   if (dest->use_inversion_array) {
108*dfc6aa5cSAndroid Build Coastguard Worker     /* Access next row in virtual array */
109*dfc6aa5cSAndroid Build Coastguard Worker     image_ptr = (*cinfo->mem->access_virt_sarray)
110*dfc6aa5cSAndroid Build Coastguard Worker       ((j_common_ptr)cinfo, dest->whole_image,
111*dfc6aa5cSAndroid Build Coastguard Worker        dest->cur_output_row, (JDIMENSION)1, TRUE);
112*dfc6aa5cSAndroid Build Coastguard Worker     dest->cur_output_row++;
113*dfc6aa5cSAndroid Build Coastguard Worker     outptr = image_ptr[0];
114*dfc6aa5cSAndroid Build Coastguard Worker   } else {
115*dfc6aa5cSAndroid Build Coastguard Worker     outptr = dest->iobuffer;
116*dfc6aa5cSAndroid Build Coastguard Worker   }
117*dfc6aa5cSAndroid Build Coastguard Worker 
118*dfc6aa5cSAndroid Build Coastguard Worker   /* Transfer data.  Note destination values must be in BGR order
119*dfc6aa5cSAndroid Build Coastguard Worker    * (even though Microsoft's own documents say the opposite).
120*dfc6aa5cSAndroid Build Coastguard Worker    */
121*dfc6aa5cSAndroid Build Coastguard Worker   inptr = dest->pub.buffer[0];
122*dfc6aa5cSAndroid Build Coastguard Worker 
123*dfc6aa5cSAndroid Build Coastguard Worker   if (cinfo->out_color_space == JCS_EXT_BGR) {
124*dfc6aa5cSAndroid Build Coastguard Worker     memcpy(outptr, inptr, dest->row_width);
125*dfc6aa5cSAndroid Build Coastguard Worker     outptr += cinfo->output_width * 3;
126*dfc6aa5cSAndroid Build Coastguard Worker   } else if (cinfo->out_color_space == JCS_RGB565) {
127*dfc6aa5cSAndroid Build Coastguard Worker     boolean big_endian = is_big_endian();
128*dfc6aa5cSAndroid Build Coastguard Worker     unsigned short *inptr2 = (unsigned short *)inptr;
129*dfc6aa5cSAndroid Build Coastguard Worker     for (col = cinfo->output_width; col > 0; col--) {
130*dfc6aa5cSAndroid Build Coastguard Worker       if (big_endian) {
131*dfc6aa5cSAndroid Build Coastguard Worker         outptr[0] = (*inptr2 >> 5) & 0xF8;
132*dfc6aa5cSAndroid Build Coastguard Worker         outptr[1] = ((*inptr2 << 5) & 0xE0) | ((*inptr2 >> 11) & 0x1C);
133*dfc6aa5cSAndroid Build Coastguard Worker         outptr[2] = *inptr2 & 0xF8;
134*dfc6aa5cSAndroid Build Coastguard Worker       } else {
135*dfc6aa5cSAndroid Build Coastguard Worker         outptr[0] = (*inptr2 << 3) & 0xF8;
136*dfc6aa5cSAndroid Build Coastguard Worker         outptr[1] = (*inptr2 >> 3) & 0xFC;
137*dfc6aa5cSAndroid Build Coastguard Worker         outptr[2] = (*inptr2 >> 8) & 0xF8;
138*dfc6aa5cSAndroid Build Coastguard Worker       }
139*dfc6aa5cSAndroid Build Coastguard Worker       outptr += 3;
140*dfc6aa5cSAndroid Build Coastguard Worker       inptr2++;
141*dfc6aa5cSAndroid Build Coastguard Worker     }
142*dfc6aa5cSAndroid Build Coastguard Worker   } else if (cinfo->out_color_space == JCS_CMYK) {
143*dfc6aa5cSAndroid Build Coastguard Worker     for (col = cinfo->output_width; col > 0; col--) {
144*dfc6aa5cSAndroid Build Coastguard Worker       JSAMPLE c = *inptr++, m = *inptr++, y = *inptr++, k = *inptr++;
145*dfc6aa5cSAndroid Build Coastguard Worker       cmyk_to_rgb(c, m, y, k, outptr + 2, outptr + 1, outptr);
146*dfc6aa5cSAndroid Build Coastguard Worker       outptr += 3;
147*dfc6aa5cSAndroid Build Coastguard Worker     }
148*dfc6aa5cSAndroid Build Coastguard Worker   } else {
149*dfc6aa5cSAndroid Build Coastguard Worker     register int rindex = rgb_red[cinfo->out_color_space];
150*dfc6aa5cSAndroid Build Coastguard Worker     register int gindex = rgb_green[cinfo->out_color_space];
151*dfc6aa5cSAndroid Build Coastguard Worker     register int bindex = rgb_blue[cinfo->out_color_space];
152*dfc6aa5cSAndroid Build Coastguard Worker     register int ps = rgb_pixelsize[cinfo->out_color_space];
153*dfc6aa5cSAndroid Build Coastguard Worker 
154*dfc6aa5cSAndroid Build Coastguard Worker     for (col = cinfo->output_width; col > 0; col--) {
155*dfc6aa5cSAndroid Build Coastguard Worker       outptr[0] = inptr[bindex];
156*dfc6aa5cSAndroid Build Coastguard Worker       outptr[1] = inptr[gindex];
157*dfc6aa5cSAndroid Build Coastguard Worker       outptr[2] = inptr[rindex];
158*dfc6aa5cSAndroid Build Coastguard Worker       outptr += 3;  inptr += ps;
159*dfc6aa5cSAndroid Build Coastguard Worker     }
160*dfc6aa5cSAndroid Build Coastguard Worker   }
161*dfc6aa5cSAndroid Build Coastguard Worker 
162*dfc6aa5cSAndroid Build Coastguard Worker   /* Zero out the pad bytes. */
163*dfc6aa5cSAndroid Build Coastguard Worker   pad = dest->pad_bytes;
164*dfc6aa5cSAndroid Build Coastguard Worker   while (--pad >= 0)
165*dfc6aa5cSAndroid Build Coastguard Worker     *outptr++ = 0;
166*dfc6aa5cSAndroid Build Coastguard Worker 
167*dfc6aa5cSAndroid Build Coastguard Worker   if (!dest->use_inversion_array)
168*dfc6aa5cSAndroid Build Coastguard Worker     fwrite(dest->iobuffer, 1, dest->row_width, dest->pub.output_file);
169*dfc6aa5cSAndroid Build Coastguard Worker }
170*dfc6aa5cSAndroid Build Coastguard Worker 
171*dfc6aa5cSAndroid Build Coastguard Worker METHODDEF(void)
put_gray_rows(j_decompress_ptr cinfo,djpeg_dest_ptr dinfo,JDIMENSION rows_supplied)172*dfc6aa5cSAndroid Build Coastguard Worker put_gray_rows(j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
173*dfc6aa5cSAndroid Build Coastguard Worker               JDIMENSION rows_supplied)
174*dfc6aa5cSAndroid Build Coastguard Worker /* This version is for grayscale OR quantized color output */
175*dfc6aa5cSAndroid Build Coastguard Worker {
176*dfc6aa5cSAndroid Build Coastguard Worker   bmp_dest_ptr dest = (bmp_dest_ptr)dinfo;
177*dfc6aa5cSAndroid Build Coastguard Worker   JSAMPARRAY image_ptr;
178*dfc6aa5cSAndroid Build Coastguard Worker   register JSAMPROW inptr, outptr;
179*dfc6aa5cSAndroid Build Coastguard Worker   int pad;
180*dfc6aa5cSAndroid Build Coastguard Worker 
181*dfc6aa5cSAndroid Build Coastguard Worker   if (dest->use_inversion_array) {
182*dfc6aa5cSAndroid Build Coastguard Worker     /* Access next row in virtual array */
183*dfc6aa5cSAndroid Build Coastguard Worker     image_ptr = (*cinfo->mem->access_virt_sarray)
184*dfc6aa5cSAndroid Build Coastguard Worker       ((j_common_ptr)cinfo, dest->whole_image,
185*dfc6aa5cSAndroid Build Coastguard Worker        dest->cur_output_row, (JDIMENSION)1, TRUE);
186*dfc6aa5cSAndroid Build Coastguard Worker     dest->cur_output_row++;
187*dfc6aa5cSAndroid Build Coastguard Worker     outptr = image_ptr[0];
188*dfc6aa5cSAndroid Build Coastguard Worker   } else {
189*dfc6aa5cSAndroid Build Coastguard Worker     outptr = dest->iobuffer;
190*dfc6aa5cSAndroid Build Coastguard Worker   }
191*dfc6aa5cSAndroid Build Coastguard Worker 
192*dfc6aa5cSAndroid Build Coastguard Worker   /* Transfer data. */
193*dfc6aa5cSAndroid Build Coastguard Worker   inptr = dest->pub.buffer[0];
194*dfc6aa5cSAndroid Build Coastguard Worker   memcpy(outptr, inptr, cinfo->output_width);
195*dfc6aa5cSAndroid Build Coastguard Worker   outptr += cinfo->output_width;
196*dfc6aa5cSAndroid Build Coastguard Worker 
197*dfc6aa5cSAndroid Build Coastguard Worker   /* Zero out the pad bytes. */
198*dfc6aa5cSAndroid Build Coastguard Worker   pad = dest->pad_bytes;
199*dfc6aa5cSAndroid Build Coastguard Worker   while (--pad >= 0)
200*dfc6aa5cSAndroid Build Coastguard Worker     *outptr++ = 0;
201*dfc6aa5cSAndroid Build Coastguard Worker 
202*dfc6aa5cSAndroid Build Coastguard Worker   if (!dest->use_inversion_array)
203*dfc6aa5cSAndroid Build Coastguard Worker     fwrite(dest->iobuffer, 1, dest->row_width, dest->pub.output_file);
204*dfc6aa5cSAndroid Build Coastguard Worker }
205*dfc6aa5cSAndroid Build Coastguard Worker 
206*dfc6aa5cSAndroid Build Coastguard Worker 
207*dfc6aa5cSAndroid Build Coastguard Worker /*
208*dfc6aa5cSAndroid Build Coastguard Worker  * Finish up at the end of the file.
209*dfc6aa5cSAndroid Build Coastguard Worker  *
210*dfc6aa5cSAndroid Build Coastguard Worker  * Here is where we really output the BMP file.
211*dfc6aa5cSAndroid Build Coastguard Worker  *
212*dfc6aa5cSAndroid Build Coastguard Worker  * First, routines to write the Windows and OS/2 variants of the file header.
213*dfc6aa5cSAndroid Build Coastguard Worker  */
214*dfc6aa5cSAndroid Build Coastguard Worker 
215*dfc6aa5cSAndroid Build Coastguard Worker LOCAL(void)
write_bmp_header(j_decompress_ptr cinfo,bmp_dest_ptr dest)216*dfc6aa5cSAndroid Build Coastguard Worker write_bmp_header(j_decompress_ptr cinfo, bmp_dest_ptr dest)
217*dfc6aa5cSAndroid Build Coastguard Worker /* Write a Windows-style BMP file header, including colormap if needed */
218*dfc6aa5cSAndroid Build Coastguard Worker {
219*dfc6aa5cSAndroid Build Coastguard Worker   char bmpfileheader[14];
220*dfc6aa5cSAndroid Build Coastguard Worker   char bmpinfoheader[40];
221*dfc6aa5cSAndroid Build Coastguard Worker 
222*dfc6aa5cSAndroid Build Coastguard Worker #define PUT_2B(array, offset, value) \
223*dfc6aa5cSAndroid Build Coastguard Worker   (array[offset] = (char)((value) & 0xFF), \
224*dfc6aa5cSAndroid Build Coastguard Worker    array[offset + 1] = (char)(((value) >> 8) & 0xFF))
225*dfc6aa5cSAndroid Build Coastguard Worker #define PUT_4B(array, offset, value) \
226*dfc6aa5cSAndroid Build Coastguard Worker   (array[offset] = (char)((value) & 0xFF), \
227*dfc6aa5cSAndroid Build Coastguard Worker    array[offset + 1] = (char)(((value) >> 8) & 0xFF), \
228*dfc6aa5cSAndroid Build Coastguard Worker    array[offset + 2] = (char)(((value) >> 16) & 0xFF), \
229*dfc6aa5cSAndroid Build Coastguard Worker    array[offset + 3] = (char)(((value) >> 24) & 0xFF))
230*dfc6aa5cSAndroid Build Coastguard Worker 
231*dfc6aa5cSAndroid Build Coastguard Worker   long headersize, bfSize;
232*dfc6aa5cSAndroid Build Coastguard Worker   int bits_per_pixel, cmap_entries;
233*dfc6aa5cSAndroid Build Coastguard Worker 
234*dfc6aa5cSAndroid Build Coastguard Worker   /* Compute colormap size and total file size */
235*dfc6aa5cSAndroid Build Coastguard Worker   if (IsExtRGB(cinfo->out_color_space)) {
236*dfc6aa5cSAndroid Build Coastguard Worker     if (cinfo->quantize_colors) {
237*dfc6aa5cSAndroid Build Coastguard Worker       /* Colormapped RGB */
238*dfc6aa5cSAndroid Build Coastguard Worker       bits_per_pixel = 8;
239*dfc6aa5cSAndroid Build Coastguard Worker       cmap_entries = 256;
240*dfc6aa5cSAndroid Build Coastguard Worker     } else {
241*dfc6aa5cSAndroid Build Coastguard Worker       /* Unquantized, full color RGB */
242*dfc6aa5cSAndroid Build Coastguard Worker       bits_per_pixel = 24;
243*dfc6aa5cSAndroid Build Coastguard Worker       cmap_entries = 0;
244*dfc6aa5cSAndroid Build Coastguard Worker     }
245*dfc6aa5cSAndroid Build Coastguard Worker   } else if (cinfo->out_color_space == JCS_RGB565 ||
246*dfc6aa5cSAndroid Build Coastguard Worker              cinfo->out_color_space == JCS_CMYK) {
247*dfc6aa5cSAndroid Build Coastguard Worker     bits_per_pixel = 24;
248*dfc6aa5cSAndroid Build Coastguard Worker     cmap_entries   = 0;
249*dfc6aa5cSAndroid Build Coastguard Worker   } else {
250*dfc6aa5cSAndroid Build Coastguard Worker     /* Grayscale output.  We need to fake a 256-entry colormap. */
251*dfc6aa5cSAndroid Build Coastguard Worker     bits_per_pixel = 8;
252*dfc6aa5cSAndroid Build Coastguard Worker     cmap_entries = 256;
253*dfc6aa5cSAndroid Build Coastguard Worker   }
254*dfc6aa5cSAndroid Build Coastguard Worker   /* File size */
255*dfc6aa5cSAndroid Build Coastguard Worker   headersize = 14 + 40 + cmap_entries * 4; /* Header and colormap */
256*dfc6aa5cSAndroid Build Coastguard Worker   bfSize = headersize + (long)dest->row_width * (long)cinfo->output_height;
257*dfc6aa5cSAndroid Build Coastguard Worker 
258*dfc6aa5cSAndroid Build Coastguard Worker   /* Set unused fields of header to 0 */
259*dfc6aa5cSAndroid Build Coastguard Worker   memset(bmpfileheader, 0, sizeof(bmpfileheader));
260*dfc6aa5cSAndroid Build Coastguard Worker   memset(bmpinfoheader, 0, sizeof(bmpinfoheader));
261*dfc6aa5cSAndroid Build Coastguard Worker 
262*dfc6aa5cSAndroid Build Coastguard Worker   /* Fill the file header */
263*dfc6aa5cSAndroid Build Coastguard Worker   bmpfileheader[0] = 0x42;      /* first 2 bytes are ASCII 'B', 'M' */
264*dfc6aa5cSAndroid Build Coastguard Worker   bmpfileheader[1] = 0x4D;
265*dfc6aa5cSAndroid Build Coastguard Worker   PUT_4B(bmpfileheader, 2, bfSize); /* bfSize */
266*dfc6aa5cSAndroid Build Coastguard Worker   /* we leave bfReserved1 & bfReserved2 = 0 */
267*dfc6aa5cSAndroid Build Coastguard Worker   PUT_4B(bmpfileheader, 10, headersize); /* bfOffBits */
268*dfc6aa5cSAndroid Build Coastguard Worker 
269*dfc6aa5cSAndroid Build Coastguard Worker   /* Fill the info header (Microsoft calls this a BITMAPINFOHEADER) */
270*dfc6aa5cSAndroid Build Coastguard Worker   PUT_2B(bmpinfoheader, 0, 40); /* biSize */
271*dfc6aa5cSAndroid Build Coastguard Worker   PUT_4B(bmpinfoheader, 4, cinfo->output_width); /* biWidth */
272*dfc6aa5cSAndroid Build Coastguard Worker   PUT_4B(bmpinfoheader, 8, cinfo->output_height); /* biHeight */
273*dfc6aa5cSAndroid Build Coastguard Worker   PUT_2B(bmpinfoheader, 12, 1); /* biPlanes - must be 1 */
274*dfc6aa5cSAndroid Build Coastguard Worker   PUT_2B(bmpinfoheader, 14, bits_per_pixel); /* biBitCount */
275*dfc6aa5cSAndroid Build Coastguard Worker   /* we leave biCompression = 0, for none */
276*dfc6aa5cSAndroid Build Coastguard Worker   /* we leave biSizeImage = 0; this is correct for uncompressed data */
277*dfc6aa5cSAndroid Build Coastguard Worker   if (cinfo->density_unit == 2) { /* if have density in dots/cm, then */
278*dfc6aa5cSAndroid Build Coastguard Worker     PUT_4B(bmpinfoheader, 24, (long)(cinfo->X_density * 100)); /* XPels/M */
279*dfc6aa5cSAndroid Build Coastguard Worker     PUT_4B(bmpinfoheader, 28, (long)(cinfo->Y_density * 100)); /* XPels/M */
280*dfc6aa5cSAndroid Build Coastguard Worker   }
281*dfc6aa5cSAndroid Build Coastguard Worker   PUT_2B(bmpinfoheader, 32, cmap_entries); /* biClrUsed */
282*dfc6aa5cSAndroid Build Coastguard Worker   /* we leave biClrImportant = 0 */
283*dfc6aa5cSAndroid Build Coastguard Worker 
284*dfc6aa5cSAndroid Build Coastguard Worker   if (fwrite(bmpfileheader, 1, 14, dest->pub.output_file) != (size_t)14)
285*dfc6aa5cSAndroid Build Coastguard Worker     ERREXIT(cinfo, JERR_FILE_WRITE);
286*dfc6aa5cSAndroid Build Coastguard Worker   if (fwrite(bmpinfoheader, 1, 40, dest->pub.output_file) != (size_t)40)
287*dfc6aa5cSAndroid Build Coastguard Worker     ERREXIT(cinfo, JERR_FILE_WRITE);
288*dfc6aa5cSAndroid Build Coastguard Worker 
289*dfc6aa5cSAndroid Build Coastguard Worker   if (cmap_entries > 0)
290*dfc6aa5cSAndroid Build Coastguard Worker     write_colormap(cinfo, dest, cmap_entries, 4);
291*dfc6aa5cSAndroid Build Coastguard Worker }
292*dfc6aa5cSAndroid Build Coastguard Worker 
293*dfc6aa5cSAndroid Build Coastguard Worker 
294*dfc6aa5cSAndroid Build Coastguard Worker LOCAL(void)
write_os2_header(j_decompress_ptr cinfo,bmp_dest_ptr dest)295*dfc6aa5cSAndroid Build Coastguard Worker write_os2_header(j_decompress_ptr cinfo, bmp_dest_ptr dest)
296*dfc6aa5cSAndroid Build Coastguard Worker /* Write an OS2-style BMP file header, including colormap if needed */
297*dfc6aa5cSAndroid Build Coastguard Worker {
298*dfc6aa5cSAndroid Build Coastguard Worker   char bmpfileheader[14];
299*dfc6aa5cSAndroid Build Coastguard Worker   char bmpcoreheader[12];
300*dfc6aa5cSAndroid Build Coastguard Worker   long headersize, bfSize;
301*dfc6aa5cSAndroid Build Coastguard Worker   int bits_per_pixel, cmap_entries;
302*dfc6aa5cSAndroid Build Coastguard Worker 
303*dfc6aa5cSAndroid Build Coastguard Worker   /* Compute colormap size and total file size */
304*dfc6aa5cSAndroid Build Coastguard Worker   if (IsExtRGB(cinfo->out_color_space)) {
305*dfc6aa5cSAndroid Build Coastguard Worker     if (cinfo->quantize_colors) {
306*dfc6aa5cSAndroid Build Coastguard Worker       /* Colormapped RGB */
307*dfc6aa5cSAndroid Build Coastguard Worker       bits_per_pixel = 8;
308*dfc6aa5cSAndroid Build Coastguard Worker       cmap_entries = 256;
309*dfc6aa5cSAndroid Build Coastguard Worker     } else {
310*dfc6aa5cSAndroid Build Coastguard Worker       /* Unquantized, full color RGB */
311*dfc6aa5cSAndroid Build Coastguard Worker       bits_per_pixel = 24;
312*dfc6aa5cSAndroid Build Coastguard Worker       cmap_entries = 0;
313*dfc6aa5cSAndroid Build Coastguard Worker     }
314*dfc6aa5cSAndroid Build Coastguard Worker   } else if (cinfo->out_color_space == JCS_RGB565 ||
315*dfc6aa5cSAndroid Build Coastguard Worker              cinfo->out_color_space == JCS_CMYK) {
316*dfc6aa5cSAndroid Build Coastguard Worker     bits_per_pixel = 24;
317*dfc6aa5cSAndroid Build Coastguard Worker     cmap_entries   = 0;
318*dfc6aa5cSAndroid Build Coastguard Worker   } else {
319*dfc6aa5cSAndroid Build Coastguard Worker     /* Grayscale output.  We need to fake a 256-entry colormap. */
320*dfc6aa5cSAndroid Build Coastguard Worker     bits_per_pixel = 8;
321*dfc6aa5cSAndroid Build Coastguard Worker     cmap_entries = 256;
322*dfc6aa5cSAndroid Build Coastguard Worker   }
323*dfc6aa5cSAndroid Build Coastguard Worker   /* File size */
324*dfc6aa5cSAndroid Build Coastguard Worker   headersize = 14 + 12 + cmap_entries * 3; /* Header and colormap */
325*dfc6aa5cSAndroid Build Coastguard Worker   bfSize = headersize + (long)dest->row_width * (long)cinfo->output_height;
326*dfc6aa5cSAndroid Build Coastguard Worker 
327*dfc6aa5cSAndroid Build Coastguard Worker   /* Set unused fields of header to 0 */
328*dfc6aa5cSAndroid Build Coastguard Worker   memset(bmpfileheader, 0, sizeof(bmpfileheader));
329*dfc6aa5cSAndroid Build Coastguard Worker   memset(bmpcoreheader, 0, sizeof(bmpcoreheader));
330*dfc6aa5cSAndroid Build Coastguard Worker 
331*dfc6aa5cSAndroid Build Coastguard Worker   /* Fill the file header */
332*dfc6aa5cSAndroid Build Coastguard Worker   bmpfileheader[0] = 0x42;      /* first 2 bytes are ASCII 'B', 'M' */
333*dfc6aa5cSAndroid Build Coastguard Worker   bmpfileheader[1] = 0x4D;
334*dfc6aa5cSAndroid Build Coastguard Worker   PUT_4B(bmpfileheader, 2, bfSize); /* bfSize */
335*dfc6aa5cSAndroid Build Coastguard Worker   /* we leave bfReserved1 & bfReserved2 = 0 */
336*dfc6aa5cSAndroid Build Coastguard Worker   PUT_4B(bmpfileheader, 10, headersize); /* bfOffBits */
337*dfc6aa5cSAndroid Build Coastguard Worker 
338*dfc6aa5cSAndroid Build Coastguard Worker   /* Fill the info header (Microsoft calls this a BITMAPCOREHEADER) */
339*dfc6aa5cSAndroid Build Coastguard Worker   PUT_2B(bmpcoreheader, 0, 12); /* bcSize */
340*dfc6aa5cSAndroid Build Coastguard Worker   PUT_2B(bmpcoreheader, 4, cinfo->output_width); /* bcWidth */
341*dfc6aa5cSAndroid Build Coastguard Worker   PUT_2B(bmpcoreheader, 6, cinfo->output_height); /* bcHeight */
342*dfc6aa5cSAndroid Build Coastguard Worker   PUT_2B(bmpcoreheader, 8, 1);  /* bcPlanes - must be 1 */
343*dfc6aa5cSAndroid Build Coastguard Worker   PUT_2B(bmpcoreheader, 10, bits_per_pixel); /* bcBitCount */
344*dfc6aa5cSAndroid Build Coastguard Worker 
345*dfc6aa5cSAndroid Build Coastguard Worker   if (fwrite(bmpfileheader, 1, 14, dest->pub.output_file) != (size_t)14)
346*dfc6aa5cSAndroid Build Coastguard Worker     ERREXIT(cinfo, JERR_FILE_WRITE);
347*dfc6aa5cSAndroid Build Coastguard Worker   if (fwrite(bmpcoreheader, 1, 12, dest->pub.output_file) != (size_t)12)
348*dfc6aa5cSAndroid Build Coastguard Worker     ERREXIT(cinfo, JERR_FILE_WRITE);
349*dfc6aa5cSAndroid Build Coastguard Worker 
350*dfc6aa5cSAndroid Build Coastguard Worker   if (cmap_entries > 0)
351*dfc6aa5cSAndroid Build Coastguard Worker     write_colormap(cinfo, dest, cmap_entries, 3);
352*dfc6aa5cSAndroid Build Coastguard Worker }
353*dfc6aa5cSAndroid Build Coastguard Worker 
354*dfc6aa5cSAndroid Build Coastguard Worker 
355*dfc6aa5cSAndroid Build Coastguard Worker /*
356*dfc6aa5cSAndroid Build Coastguard Worker  * Write the colormap.
357*dfc6aa5cSAndroid Build Coastguard Worker  * Windows uses BGR0 map entries; OS/2 uses BGR entries.
358*dfc6aa5cSAndroid Build Coastguard Worker  */
359*dfc6aa5cSAndroid Build Coastguard Worker 
360*dfc6aa5cSAndroid Build Coastguard Worker LOCAL(void)
write_colormap(j_decompress_ptr cinfo,bmp_dest_ptr dest,int map_colors,int map_entry_size)361*dfc6aa5cSAndroid Build Coastguard Worker write_colormap(j_decompress_ptr cinfo, bmp_dest_ptr dest, int map_colors,
362*dfc6aa5cSAndroid Build Coastguard Worker                int map_entry_size)
363*dfc6aa5cSAndroid Build Coastguard Worker {
364*dfc6aa5cSAndroid Build Coastguard Worker   JSAMPARRAY colormap = cinfo->colormap;
365*dfc6aa5cSAndroid Build Coastguard Worker   int num_colors = cinfo->actual_number_of_colors;
366*dfc6aa5cSAndroid Build Coastguard Worker   FILE *outfile = dest->pub.output_file;
367*dfc6aa5cSAndroid Build Coastguard Worker   int i;
368*dfc6aa5cSAndroid Build Coastguard Worker 
369*dfc6aa5cSAndroid Build Coastguard Worker   if (colormap != NULL) {
370*dfc6aa5cSAndroid Build Coastguard Worker     if (cinfo->out_color_components == 3) {
371*dfc6aa5cSAndroid Build Coastguard Worker       /* Normal case with RGB colormap */
372*dfc6aa5cSAndroid Build Coastguard Worker       for (i = 0; i < num_colors; i++) {
373*dfc6aa5cSAndroid Build Coastguard Worker         putc(colormap[2][i], outfile);
374*dfc6aa5cSAndroid Build Coastguard Worker         putc(colormap[1][i], outfile);
375*dfc6aa5cSAndroid Build Coastguard Worker         putc(colormap[0][i], outfile);
376*dfc6aa5cSAndroid Build Coastguard Worker         if (map_entry_size == 4)
377*dfc6aa5cSAndroid Build Coastguard Worker           putc(0, outfile);
378*dfc6aa5cSAndroid Build Coastguard Worker       }
379*dfc6aa5cSAndroid Build Coastguard Worker     } else {
380*dfc6aa5cSAndroid Build Coastguard Worker       /* Grayscale colormap (only happens with grayscale quantization) */
381*dfc6aa5cSAndroid Build Coastguard Worker       for (i = 0; i < num_colors; i++) {
382*dfc6aa5cSAndroid Build Coastguard Worker         putc(colormap[0][i], outfile);
383*dfc6aa5cSAndroid Build Coastguard Worker         putc(colormap[0][i], outfile);
384*dfc6aa5cSAndroid Build Coastguard Worker         putc(colormap[0][i], outfile);
385*dfc6aa5cSAndroid Build Coastguard Worker         if (map_entry_size == 4)
386*dfc6aa5cSAndroid Build Coastguard Worker           putc(0, outfile);
387*dfc6aa5cSAndroid Build Coastguard Worker       }
388*dfc6aa5cSAndroid Build Coastguard Worker     }
389*dfc6aa5cSAndroid Build Coastguard Worker   } else {
390*dfc6aa5cSAndroid Build Coastguard Worker     /* If no colormap, must be grayscale data.  Generate a linear "map". */
391*dfc6aa5cSAndroid Build Coastguard Worker     for (i = 0; i < 256; i++) {
392*dfc6aa5cSAndroid Build Coastguard Worker       putc(i, outfile);
393*dfc6aa5cSAndroid Build Coastguard Worker       putc(i, outfile);
394*dfc6aa5cSAndroid Build Coastguard Worker       putc(i, outfile);
395*dfc6aa5cSAndroid Build Coastguard Worker       if (map_entry_size == 4)
396*dfc6aa5cSAndroid Build Coastguard Worker         putc(0, outfile);
397*dfc6aa5cSAndroid Build Coastguard Worker     }
398*dfc6aa5cSAndroid Build Coastguard Worker   }
399*dfc6aa5cSAndroid Build Coastguard Worker   /* Pad colormap with zeros to ensure specified number of colormap entries */
400*dfc6aa5cSAndroid Build Coastguard Worker   if (i > map_colors)
401*dfc6aa5cSAndroid Build Coastguard Worker     ERREXIT1(cinfo, JERR_TOO_MANY_COLORS, i);
402*dfc6aa5cSAndroid Build Coastguard Worker   for (; i < map_colors; i++) {
403*dfc6aa5cSAndroid Build Coastguard Worker     putc(0, outfile);
404*dfc6aa5cSAndroid Build Coastguard Worker     putc(0, outfile);
405*dfc6aa5cSAndroid Build Coastguard Worker     putc(0, outfile);
406*dfc6aa5cSAndroid Build Coastguard Worker     if (map_entry_size == 4)
407*dfc6aa5cSAndroid Build Coastguard Worker       putc(0, outfile);
408*dfc6aa5cSAndroid Build Coastguard Worker   }
409*dfc6aa5cSAndroid Build Coastguard Worker }
410*dfc6aa5cSAndroid Build Coastguard Worker 
411*dfc6aa5cSAndroid Build Coastguard Worker 
412*dfc6aa5cSAndroid Build Coastguard Worker /*
413*dfc6aa5cSAndroid Build Coastguard Worker  * Startup: write the file header unless the inversion array is being used.
414*dfc6aa5cSAndroid Build Coastguard Worker  */
415*dfc6aa5cSAndroid Build Coastguard Worker 
416*dfc6aa5cSAndroid Build Coastguard Worker METHODDEF(void)
start_output_bmp(j_decompress_ptr cinfo,djpeg_dest_ptr dinfo)417*dfc6aa5cSAndroid Build Coastguard Worker start_output_bmp(j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)
418*dfc6aa5cSAndroid Build Coastguard Worker {
419*dfc6aa5cSAndroid Build Coastguard Worker   bmp_dest_ptr dest = (bmp_dest_ptr)dinfo;
420*dfc6aa5cSAndroid Build Coastguard Worker 
421*dfc6aa5cSAndroid Build Coastguard Worker   if (!dest->use_inversion_array) {
422*dfc6aa5cSAndroid Build Coastguard Worker     /* Write the header and colormap */
423*dfc6aa5cSAndroid Build Coastguard Worker     if (dest->is_os2)
424*dfc6aa5cSAndroid Build Coastguard Worker       write_os2_header(cinfo, dest);
425*dfc6aa5cSAndroid Build Coastguard Worker     else
426*dfc6aa5cSAndroid Build Coastguard Worker       write_bmp_header(cinfo, dest);
427*dfc6aa5cSAndroid Build Coastguard Worker   }
428*dfc6aa5cSAndroid Build Coastguard Worker }
429*dfc6aa5cSAndroid Build Coastguard Worker 
430*dfc6aa5cSAndroid Build Coastguard Worker 
431*dfc6aa5cSAndroid Build Coastguard Worker METHODDEF(void)
finish_output_bmp(j_decompress_ptr cinfo,djpeg_dest_ptr dinfo)432*dfc6aa5cSAndroid Build Coastguard Worker finish_output_bmp(j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)
433*dfc6aa5cSAndroid Build Coastguard Worker {
434*dfc6aa5cSAndroid Build Coastguard Worker   bmp_dest_ptr dest = (bmp_dest_ptr)dinfo;
435*dfc6aa5cSAndroid Build Coastguard Worker   register FILE *outfile = dest->pub.output_file;
436*dfc6aa5cSAndroid Build Coastguard Worker   JSAMPARRAY image_ptr;
437*dfc6aa5cSAndroid Build Coastguard Worker   register JSAMPROW data_ptr;
438*dfc6aa5cSAndroid Build Coastguard Worker   JDIMENSION row;
439*dfc6aa5cSAndroid Build Coastguard Worker   cd_progress_ptr progress = (cd_progress_ptr)cinfo->progress;
440*dfc6aa5cSAndroid Build Coastguard Worker 
441*dfc6aa5cSAndroid Build Coastguard Worker   if (dest->use_inversion_array) {
442*dfc6aa5cSAndroid Build Coastguard Worker     /* Write the header and colormap */
443*dfc6aa5cSAndroid Build Coastguard Worker     if (dest->is_os2)
444*dfc6aa5cSAndroid Build Coastguard Worker       write_os2_header(cinfo, dest);
445*dfc6aa5cSAndroid Build Coastguard Worker     else
446*dfc6aa5cSAndroid Build Coastguard Worker       write_bmp_header(cinfo, dest);
447*dfc6aa5cSAndroid Build Coastguard Worker 
448*dfc6aa5cSAndroid Build Coastguard Worker     /* Write the file body from our virtual array */
449*dfc6aa5cSAndroid Build Coastguard Worker     for (row = cinfo->output_height; row > 0; row--) {
450*dfc6aa5cSAndroid Build Coastguard Worker       if (progress != NULL) {
451*dfc6aa5cSAndroid Build Coastguard Worker         progress->pub.pass_counter = (long)(cinfo->output_height - row);
452*dfc6aa5cSAndroid Build Coastguard Worker         progress->pub.pass_limit = (long)cinfo->output_height;
453*dfc6aa5cSAndroid Build Coastguard Worker         (*progress->pub.progress_monitor) ((j_common_ptr)cinfo);
454*dfc6aa5cSAndroid Build Coastguard Worker       }
455*dfc6aa5cSAndroid Build Coastguard Worker       image_ptr = (*cinfo->mem->access_virt_sarray)
456*dfc6aa5cSAndroid Build Coastguard Worker         ((j_common_ptr)cinfo, dest->whole_image, row - 1, (JDIMENSION)1,
457*dfc6aa5cSAndroid Build Coastguard Worker          FALSE);
458*dfc6aa5cSAndroid Build Coastguard Worker       data_ptr = image_ptr[0];
459*dfc6aa5cSAndroid Build Coastguard Worker       fwrite(data_ptr, 1, dest->row_width, outfile);
460*dfc6aa5cSAndroid Build Coastguard Worker     }
461*dfc6aa5cSAndroid Build Coastguard Worker     if (progress != NULL)
462*dfc6aa5cSAndroid Build Coastguard Worker       progress->completed_extra_passes++;
463*dfc6aa5cSAndroid Build Coastguard Worker   }
464*dfc6aa5cSAndroid Build Coastguard Worker 
465*dfc6aa5cSAndroid Build Coastguard Worker   /* Make sure we wrote the output file OK */
466*dfc6aa5cSAndroid Build Coastguard Worker   fflush(outfile);
467*dfc6aa5cSAndroid Build Coastguard Worker   if (ferror(outfile))
468*dfc6aa5cSAndroid Build Coastguard Worker     ERREXIT(cinfo, JERR_FILE_WRITE);
469*dfc6aa5cSAndroid Build Coastguard Worker }
470*dfc6aa5cSAndroid Build Coastguard Worker 
471*dfc6aa5cSAndroid Build Coastguard Worker 
472*dfc6aa5cSAndroid Build Coastguard Worker /*
473*dfc6aa5cSAndroid Build Coastguard Worker  * The module selection routine for BMP format output.
474*dfc6aa5cSAndroid Build Coastguard Worker  */
475*dfc6aa5cSAndroid Build Coastguard Worker 
476*dfc6aa5cSAndroid Build Coastguard Worker GLOBAL(djpeg_dest_ptr)
jinit_write_bmp(j_decompress_ptr cinfo,boolean is_os2,boolean use_inversion_array)477*dfc6aa5cSAndroid Build Coastguard Worker jinit_write_bmp(j_decompress_ptr cinfo, boolean is_os2,
478*dfc6aa5cSAndroid Build Coastguard Worker                 boolean use_inversion_array)
479*dfc6aa5cSAndroid Build Coastguard Worker {
480*dfc6aa5cSAndroid Build Coastguard Worker   bmp_dest_ptr dest;
481*dfc6aa5cSAndroid Build Coastguard Worker   JDIMENSION row_width;
482*dfc6aa5cSAndroid Build Coastguard Worker 
483*dfc6aa5cSAndroid Build Coastguard Worker   /* Create module interface object, fill in method pointers */
484*dfc6aa5cSAndroid Build Coastguard Worker   dest = (bmp_dest_ptr)
485*dfc6aa5cSAndroid Build Coastguard Worker     (*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
486*dfc6aa5cSAndroid Build Coastguard Worker                                 sizeof(bmp_dest_struct));
487*dfc6aa5cSAndroid Build Coastguard Worker   dest->pub.start_output = start_output_bmp;
488*dfc6aa5cSAndroid Build Coastguard Worker   dest->pub.finish_output = finish_output_bmp;
489*dfc6aa5cSAndroid Build Coastguard Worker   dest->pub.calc_buffer_dimensions = NULL;
490*dfc6aa5cSAndroid Build Coastguard Worker   dest->is_os2 = is_os2;
491*dfc6aa5cSAndroid Build Coastguard Worker 
492*dfc6aa5cSAndroid Build Coastguard Worker   if (cinfo->out_color_space == JCS_GRAYSCALE) {
493*dfc6aa5cSAndroid Build Coastguard Worker     dest->pub.put_pixel_rows = put_gray_rows;
494*dfc6aa5cSAndroid Build Coastguard Worker   } else if (IsExtRGB(cinfo->out_color_space)) {
495*dfc6aa5cSAndroid Build Coastguard Worker     if (cinfo->quantize_colors)
496*dfc6aa5cSAndroid Build Coastguard Worker       dest->pub.put_pixel_rows = put_gray_rows;
497*dfc6aa5cSAndroid Build Coastguard Worker     else
498*dfc6aa5cSAndroid Build Coastguard Worker       dest->pub.put_pixel_rows = put_pixel_rows;
499*dfc6aa5cSAndroid Build Coastguard Worker   } else if (!cinfo->quantize_colors &&
500*dfc6aa5cSAndroid Build Coastguard Worker              (cinfo->out_color_space == JCS_RGB565 ||
501*dfc6aa5cSAndroid Build Coastguard Worker               cinfo->out_color_space == JCS_CMYK)) {
502*dfc6aa5cSAndroid Build Coastguard Worker     dest->pub.put_pixel_rows = put_pixel_rows;
503*dfc6aa5cSAndroid Build Coastguard Worker   } else {
504*dfc6aa5cSAndroid Build Coastguard Worker     ERREXIT(cinfo, JERR_BMP_COLORSPACE);
505*dfc6aa5cSAndroid Build Coastguard Worker   }
506*dfc6aa5cSAndroid Build Coastguard Worker 
507*dfc6aa5cSAndroid Build Coastguard Worker   /* Calculate output image dimensions so we can allocate space */
508*dfc6aa5cSAndroid Build Coastguard Worker   jpeg_calc_output_dimensions(cinfo);
509*dfc6aa5cSAndroid Build Coastguard Worker 
510*dfc6aa5cSAndroid Build Coastguard Worker   /* Determine width of rows in the BMP file (padded to 4-byte boundary). */
511*dfc6aa5cSAndroid Build Coastguard Worker   if (cinfo->out_color_space == JCS_RGB565) {
512*dfc6aa5cSAndroid Build Coastguard Worker     row_width = cinfo->output_width * 2;
513*dfc6aa5cSAndroid Build Coastguard Worker     dest->row_width = dest->data_width = cinfo->output_width * 3;
514*dfc6aa5cSAndroid Build Coastguard Worker     while ((row_width & 3) != 0) row_width++;
515*dfc6aa5cSAndroid Build Coastguard Worker   } else if (!cinfo->quantize_colors &&
516*dfc6aa5cSAndroid Build Coastguard Worker              (IsExtRGB(cinfo->out_color_space) ||
517*dfc6aa5cSAndroid Build Coastguard Worker               cinfo->out_color_space == JCS_CMYK)) {
518*dfc6aa5cSAndroid Build Coastguard Worker     row_width = cinfo->output_width * cinfo->output_components;
519*dfc6aa5cSAndroid Build Coastguard Worker     dest->row_width = dest->data_width = cinfo->output_width * 3;
520*dfc6aa5cSAndroid Build Coastguard Worker   } else {
521*dfc6aa5cSAndroid Build Coastguard Worker     row_width = cinfo->output_width * cinfo->output_components;
522*dfc6aa5cSAndroid Build Coastguard Worker     dest->row_width = dest->data_width = row_width;
523*dfc6aa5cSAndroid Build Coastguard Worker   }
524*dfc6aa5cSAndroid Build Coastguard Worker   while ((dest->row_width & 3) != 0) dest->row_width++;
525*dfc6aa5cSAndroid Build Coastguard Worker   dest->pad_bytes = (int)(dest->row_width - dest->data_width);
526*dfc6aa5cSAndroid Build Coastguard Worker 
527*dfc6aa5cSAndroid Build Coastguard Worker 
528*dfc6aa5cSAndroid Build Coastguard Worker   if (use_inversion_array) {
529*dfc6aa5cSAndroid Build Coastguard Worker     /* Allocate space for inversion array, prepare for write pass */
530*dfc6aa5cSAndroid Build Coastguard Worker     dest->whole_image = (*cinfo->mem->request_virt_sarray)
531*dfc6aa5cSAndroid Build Coastguard Worker       ((j_common_ptr)cinfo, JPOOL_IMAGE, FALSE,
532*dfc6aa5cSAndroid Build Coastguard Worker        dest->row_width, cinfo->output_height, (JDIMENSION)1);
533*dfc6aa5cSAndroid Build Coastguard Worker     dest->cur_output_row = 0;
534*dfc6aa5cSAndroid Build Coastguard Worker     if (cinfo->progress != NULL) {
535*dfc6aa5cSAndroid Build Coastguard Worker       cd_progress_ptr progress = (cd_progress_ptr)cinfo->progress;
536*dfc6aa5cSAndroid Build Coastguard Worker       progress->total_extra_passes++; /* count file input as separate pass */
537*dfc6aa5cSAndroid Build Coastguard Worker     }
538*dfc6aa5cSAndroid Build Coastguard Worker   } else {
539*dfc6aa5cSAndroid Build Coastguard Worker     dest->iobuffer = (JSAMPLE *)(*cinfo->mem->alloc_small)
540*dfc6aa5cSAndroid Build Coastguard Worker       ((j_common_ptr)cinfo, JPOOL_IMAGE, dest->row_width);
541*dfc6aa5cSAndroid Build Coastguard Worker   }
542*dfc6aa5cSAndroid Build Coastguard Worker   dest->use_inversion_array = use_inversion_array;
543*dfc6aa5cSAndroid Build Coastguard Worker 
544*dfc6aa5cSAndroid Build Coastguard Worker   /* Create decompressor output buffer. */
545*dfc6aa5cSAndroid Build Coastguard Worker   dest->pub.buffer = (*cinfo->mem->alloc_sarray)
546*dfc6aa5cSAndroid Build Coastguard Worker     ((j_common_ptr)cinfo, JPOOL_IMAGE, row_width, (JDIMENSION)1);
547*dfc6aa5cSAndroid Build Coastguard Worker   dest->pub.buffer_height = 1;
548*dfc6aa5cSAndroid Build Coastguard Worker 
549*dfc6aa5cSAndroid Build Coastguard Worker   return (djpeg_dest_ptr)dest;
550*dfc6aa5cSAndroid Build Coastguard Worker }
551*dfc6aa5cSAndroid Build Coastguard Worker 
552*dfc6aa5cSAndroid Build Coastguard Worker #endif /* BMP_SUPPORTED */
553