ReactOS  0.4.15-dev-439-g292f67a
wrbmp.c
Go to the documentation of this file.
1 /*
2  * wrbmp.c
3  *
4  * Copyright (C) 1994-1996, Thomas G. Lane.
5  * Modified 2017-2019 by Guido Vollbeding.
6  * This file is part of the Independent JPEG Group's software.
7  * For conditions of distribution and use, see the accompanying README file.
8  *
9  * This file contains routines to write output images in Microsoft "BMP"
10  * format (MS Windows 3.x and OS/2 1.x flavors).
11  * Either 8-bit colormapped or 24-bit full-color format can be written.
12  * No compression is supported.
13  *
14  * These routines may need modification for non-Unix environments or
15  * specialized applications. As they stand, they assume output to
16  * an ordinary stdio stream.
17  *
18  * This code contributed by James Arthur Boucher.
19  */
20 
21 #include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
22 
23 #ifdef BMP_SUPPORTED
24 
25 
26 /*
27  * To support 12-bit JPEG data, we'd have to scale output down to 8 bits.
28  * This is not yet implemented.
29  */
30 
31 #if BITS_IN_JSAMPLE != 8
32  Sorry, this code only copes with 8-bit JSAMPLEs. /* deliberate syntax err */
33 #endif
34 
35 /*
36  * Since BMP stores scanlines bottom-to-top, we have to invert the image
37  * from JPEG's top-to-bottom order. To do this, we save the outgoing data
38  * in a virtual array during put_pixel_row calls, then actually emit the
39  * BMP file during finish_output. The virtual array contains one JSAMPLE per
40  * pixel if the output is grayscale or colormapped, three if it is full color.
41  */
42 
43 /* Private version of data destination object */
44 
45 typedef struct {
46  struct djpeg_dest_struct pub; /* public fields */
47 
48  boolean is_os2; /* saves the OS2 format request flag */
49 
50  jvirt_sarray_ptr whole_image; /* needed to reverse row order */
51  JDIMENSION data_width; /* JSAMPLEs per row */
52  JDIMENSION row_width; /* physical width of one row in the BMP file */
53  int pad_bytes; /* number of padding bytes needed per row */
54  JDIMENSION cur_output_row; /* next row# to write to virtual array */
55 } bmp_dest_struct;
56 
57 typedef bmp_dest_struct * bmp_dest_ptr;
58 
59 
60 /* Forward declarations */
61 LOCAL(void) write_colormap
62  JPP((j_decompress_ptr cinfo, bmp_dest_ptr dest,
63  int map_colors, int map_entry_size));
64 
65 
66 /*
67  * Write some pixel data.
68  * In this module rows_supplied will always be 1.
69  */
70 
71 METHODDEF(void)
72 put_pixel_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
73  JDIMENSION rows_supplied)
74 /* This version is for writing 24-bit pixels */
75 {
76  bmp_dest_ptr dest = (bmp_dest_ptr) dinfo;
77  register JSAMPROW inptr, outptr;
78  register JDIMENSION col;
79  int pad;
80 
81  /* Access next row in virtual array */
82  outptr = * (*cinfo->mem->access_virt_sarray) ((j_common_ptr) cinfo,
83  dest->whole_image, dest->cur_output_row, (JDIMENSION) 1, TRUE);
84  dest->cur_output_row++;
85 
86  /* Transfer data. Note destination values must be in BGR order
87  * (even though Microsoft's own documents say the opposite).
88  */
89  inptr = dest->pub.buffer[0];
90  for (col = cinfo->output_width; col > 0; col--) {
91  outptr[2] = *inptr++; /* can omit GETJSAMPLE() safely */
92  outptr[1] = *inptr++;
93  outptr[0] = *inptr++;
94  outptr += 3;
95  }
96 
97  /* Zero out the pad bytes. */
98  pad = dest->pad_bytes;
99  while (--pad >= 0)
100  *outptr++ = 0;
101 }
102 
103 METHODDEF(void)
104 put_gray_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
105  JDIMENSION rows_supplied)
106 /* This version is for grayscale OR quantized color output */
107 {
108  bmp_dest_ptr dest = (bmp_dest_ptr) dinfo;
109  register JSAMPROW inptr, outptr;
110  register JDIMENSION col;
111  int pad;
112 
113  /* Access next row in virtual array */
114  outptr = * (*cinfo->mem->access_virt_sarray) ((j_common_ptr) cinfo,
115  dest->whole_image, dest->cur_output_row, (JDIMENSION) 1, TRUE);
116  dest->cur_output_row++;
117 
118  /* Transfer data. */
119  inptr = dest->pub.buffer[0];
120  for (col = cinfo->output_width; col > 0; col--) {
121  *outptr++ = *inptr++; /* can omit GETJSAMPLE() safely */
122  }
123 
124  /* Zero out the pad bytes. */
125  pad = dest->pad_bytes;
126  while (--pad >= 0)
127  *outptr++ = 0;
128 }
129 
130 
131 /*
132  * Startup: normally writes the file header.
133  * In this module we may as well postpone everything until finish_output.
134  */
135 
136 METHODDEF(void)
137 start_output_bmp (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)
138 {
139  /* no work here */
140 }
141 
142 
143 /*
144  * Finish up at the end of the file.
145  *
146  * Here is where we really output the BMP file.
147  *
148  * First, routines to write the Windows and OS/2 variants of the file header.
149  */
150 
151 LOCAL(void)
152 write_bmp_header (j_decompress_ptr cinfo, bmp_dest_ptr dest)
153 /* Write a Windows-style BMP file header, including colormap if needed */
154 {
155  char bmpfileheader[14];
156  char bmpinfoheader[40];
157 #define PUT_2B(array, offset, value) \
158  (array[offset] = (char) ((value) & 0xFF), \
159  array[offset+1] = (char) (((value) >> 8) & 0xFF))
160 #define PUT_4B(array, offset, value) \
161  (array[offset] = (char) ((value) & 0xFF), \
162  array[offset+1] = (char) (((value) >> 8) & 0xFF), \
163  array[offset+2] = (char) (((value) >> 16) & 0xFF), \
164  array[offset+3] = (char) (((value) >> 24) & 0xFF))
165  INT32 headersize, bfSize;
166  int bits_per_pixel, cmap_entries;
167 
168  /* Compute colormap size and total file size */
169  if (cinfo->out_color_space == JCS_RGB) {
170  if (cinfo->quantize_colors) {
171  /* Colormapped RGB */
172  bits_per_pixel = 8;
173  cmap_entries = 256;
174  } else {
175  /* Unquantized, full color RGB */
176  bits_per_pixel = 24;
177  cmap_entries = 0;
178  }
179  } else {
180  /* Grayscale output. We need to fake a 256-entry colormap. */
181  bits_per_pixel = 8;
182  cmap_entries = 256;
183  }
184  /* File size */
185  headersize = 14 + 40 + cmap_entries * 4; /* Header and colormap */
186  bfSize = headersize + (INT32) dest->row_width * (INT32) cinfo->output_height;
187 
188  /* Set unused fields of header to 0 */
189  MEMZERO(bmpfileheader, SIZEOF(bmpfileheader));
190  MEMZERO(bmpinfoheader, SIZEOF(bmpinfoheader));
191 
192  /* Fill the file header */
193  bmpfileheader[0] = 0x42; /* first 2 bytes are ASCII 'B', 'M' */
194  bmpfileheader[1] = 0x4D;
195  PUT_4B(bmpfileheader, 2, bfSize); /* bfSize */
196  /* we leave bfReserved1 & bfReserved2 = 0 */
197  PUT_4B(bmpfileheader, 10, headersize); /* bfOffBits */
198 
199  /* Fill the info header (Microsoft calls this a BITMAPINFOHEADER) */
200  PUT_2B(bmpinfoheader, 0, 40); /* biSize */
201  PUT_4B(bmpinfoheader, 4, cinfo->output_width); /* biWidth */
202  PUT_4B(bmpinfoheader, 8, cinfo->output_height); /* biHeight */
203  PUT_2B(bmpinfoheader, 12, 1); /* biPlanes - must be 1 */
204  PUT_2B(bmpinfoheader, 14, bits_per_pixel); /* biBitCount */
205  /* we leave biCompression = 0, for none */
206  /* we leave biSizeImage = 0; this is correct for uncompressed data */
207  if (cinfo->density_unit == 2) { /* if have density in dots/cm, then */
208  PUT_4B(bmpinfoheader, 24, (INT32) (cinfo->X_density*100)); /* XPels/M */
209  PUT_4B(bmpinfoheader, 28, (INT32) (cinfo->Y_density*100)); /* XPels/M */
210  }
211  PUT_2B(bmpinfoheader, 32, cmap_entries); /* biClrUsed */
212  /* we leave biClrImportant = 0 */
213 
214  if (JFWRITE(dest->pub.output_file, bmpfileheader, 14) != (size_t) 14)
215  ERREXIT(cinfo, JERR_FILE_WRITE);
216  if (JFWRITE(dest->pub.output_file, bmpinfoheader, 40) != (size_t) 40)
217  ERREXIT(cinfo, JERR_FILE_WRITE);
218 
219  if (cmap_entries > 0)
220  write_colormap(cinfo, dest, cmap_entries, 4);
221 }
222 
223 
224 LOCAL(void)
225 write_os2_header (j_decompress_ptr cinfo, bmp_dest_ptr dest)
226 /* Write an OS2-style BMP file header, including colormap if needed */
227 {
228  char bmpfileheader[14];
229  char bmpcoreheader[12];
230  INT32 headersize, bfSize;
231  int bits_per_pixel, cmap_entries;
232 
233  /* Compute colormap size and total file size */
234  if (cinfo->out_color_space == JCS_RGB) {
235  if (cinfo->quantize_colors) {
236  /* Colormapped RGB */
237  bits_per_pixel = 8;
238  cmap_entries = 256;
239  } else {
240  /* Unquantized, full color RGB */
241  bits_per_pixel = 24;
242  cmap_entries = 0;
243  }
244  } else {
245  /* Grayscale output. We need to fake a 256-entry colormap. */
246  bits_per_pixel = 8;
247  cmap_entries = 256;
248  }
249  /* File size */
250  headersize = 14 + 12 + cmap_entries * 3; /* Header and colormap */
251  bfSize = headersize + (INT32) dest->row_width * (INT32) cinfo->output_height;
252 
253  /* Set unused fields of header to 0 */
254  MEMZERO(bmpfileheader, SIZEOF(bmpfileheader));
255  MEMZERO(bmpcoreheader, SIZEOF(bmpcoreheader));
256 
257  /* Fill the file header */
258  bmpfileheader[0] = 0x42; /* first 2 bytes are ASCII 'B', 'M' */
259  bmpfileheader[1] = 0x4D;
260  PUT_4B(bmpfileheader, 2, bfSize); /* bfSize */
261  /* we leave bfReserved1 & bfReserved2 = 0 */
262  PUT_4B(bmpfileheader, 10, headersize); /* bfOffBits */
263 
264  /* Fill the info header (Microsoft calls this a BITMAPCOREHEADER) */
265  PUT_2B(bmpcoreheader, 0, 12); /* bcSize */
266  PUT_2B(bmpcoreheader, 4, cinfo->output_width); /* bcWidth */
267  PUT_2B(bmpcoreheader, 6, cinfo->output_height); /* bcHeight */
268  PUT_2B(bmpcoreheader, 8, 1); /* bcPlanes - must be 1 */
269  PUT_2B(bmpcoreheader, 10, bits_per_pixel); /* bcBitCount */
270 
271  if (JFWRITE(dest->pub.output_file, bmpfileheader, 14) != (size_t) 14)
272  ERREXIT(cinfo, JERR_FILE_WRITE);
273  if (JFWRITE(dest->pub.output_file, bmpcoreheader, 12) != (size_t) 12)
274  ERREXIT(cinfo, JERR_FILE_WRITE);
275 
276  if (cmap_entries > 0)
277  write_colormap(cinfo, dest, cmap_entries, 3);
278 }
279 
280 
281 /*
282  * Write the colormap.
283  * Windows uses BGR0 map entries; OS/2 uses BGR entries.
284  */
285 
286 LOCAL(void)
287 write_colormap (j_decompress_ptr cinfo, bmp_dest_ptr dest,
288  int map_colors, int map_entry_size)
289 {
290  JSAMPARRAY colormap = cinfo->colormap;
291  int num_colors = cinfo->actual_number_of_colors;
292  FILE * outfile = dest->pub.output_file;
293  int i;
294 
295  if (colormap != NULL) {
296  if (cinfo->out_color_components == 3) {
297  /* Normal case with RGB colormap */
298  for (i = 0; i < num_colors; i++) {
299  putc(GETJSAMPLE(colormap[2][i]), outfile);
300  putc(GETJSAMPLE(colormap[1][i]), outfile);
301  putc(GETJSAMPLE(colormap[0][i]), outfile);
302  if (map_entry_size == 4)
303  putc(0, outfile);
304  }
305  } else {
306  /* Grayscale colormap (only happens with grayscale quantization) */
307  for (i = 0; i < num_colors; i++) {
308  putc(GETJSAMPLE(colormap[0][i]), outfile);
309  putc(GETJSAMPLE(colormap[0][i]), outfile);
310  putc(GETJSAMPLE(colormap[0][i]), outfile);
311  if (map_entry_size == 4)
312  putc(0, outfile);
313  }
314  }
315  } else {
316  /* If no colormap, must be grayscale data. Generate a linear "map". */
317  for (i = 0; i < 256; i++) {
318  putc(i, outfile);
319  putc(i, outfile);
320  putc(i, outfile);
321  if (map_entry_size == 4)
322  putc(0, outfile);
323  }
324  }
325  /* Pad colormap to ensure specified number of colormap entries */
326  if (i > map_colors)
327  ERREXIT1(cinfo, JERR_TOO_MANY_COLORS, i);
328  for (; i < map_colors; i++) {
332  if (map_entry_size == 4)
333  putc(0, outfile);
334  }
335 }
336 
337 
338 METHODDEF(void)
339 finish_output_bmp (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)
340 {
341  bmp_dest_ptr dest = (bmp_dest_ptr) dinfo;
342  register FILE * outfile = dest->pub.output_file;
343  register JSAMPROW data_ptr;
344  JDIMENSION row;
345  register JDIMENSION col;
346  cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;
347 
348  /* Write the header and colormap */
349  if (dest->is_os2)
350  write_os2_header(cinfo, dest);
351  else
352  write_bmp_header(cinfo, dest);
353 
354  /* Write the file body from our virtual array */
355  for (row = cinfo->output_height; row > 0; row--) {
356  if (progress != NULL) {
357  progress->pub.pass_counter = (long) (cinfo->output_height - row);
358  progress->pub.pass_limit = (long) cinfo->output_height;
359  (*progress->pub.progress_monitor) ((j_common_ptr) cinfo);
360  }
361  data_ptr = * (*cinfo->mem->access_virt_sarray) ((j_common_ptr) cinfo,
362  dest->whole_image, row - 1, (JDIMENSION) 1, FALSE);
363  for (col = dest->row_width; col > 0; col--) {
364  putc(GETJSAMPLE(*data_ptr), outfile);
365  data_ptr++;
366  }
367  }
368  if (progress != NULL)
370 
371  /* Make sure we wrote the output file OK */
372  JFFLUSH(outfile);
373  if (JFERROR(outfile))
374  ERREXIT(cinfo, JERR_FILE_WRITE);
375 }
376 
377 
378 /*
379  * The module selection routine for BMP format output.
380  */
381 
383 jinit_write_bmp (j_decompress_ptr cinfo, boolean is_os2)
384 {
385  bmp_dest_ptr dest;
386  JDIMENSION row_width;
387 
388  /* Create module interface object, fill in method pointers */
389  dest = (bmp_dest_ptr) (*cinfo->mem->alloc_small)
390  ((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(bmp_dest_struct));
391  dest->pub.start_output = start_output_bmp;
392  dest->pub.finish_output = finish_output_bmp;
393  dest->is_os2 = is_os2;
394 
395  switch (cinfo->out_color_space) {
396  case JCS_GRAYSCALE:
397  dest->pub.put_pixel_rows = put_gray_rows;
398  break;
399  case JCS_RGB:
400  if (cinfo->quantize_colors)
401  dest->pub.put_pixel_rows = put_gray_rows;
402  else
403  dest->pub.put_pixel_rows = put_pixel_rows;
404  break;
405  default:
406  ERREXIT(cinfo, JERR_BMP_COLORSPACE);
407  }
408 
409  /* Calculate output image dimensions so we can allocate space */
411 
412  /* Determine width of rows in the BMP file (padded to 4-byte boundary). */
413  row_width = cinfo->output_width * cinfo->output_components;
414  dest->data_width = row_width;
415  while ((row_width & 3) != 0) row_width++;
416  dest->row_width = row_width;
417  dest->pad_bytes = (int) (row_width - dest->data_width);
418 
419  /* Allocate space for inversion array, prepare for write pass */
420  dest->whole_image = (*cinfo->mem->request_virt_sarray)
421  ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE,
422  row_width, cinfo->output_height, (JDIMENSION) 1);
423  dest->cur_output_row = 0;
424  if (cinfo->progress != NULL) {
425  cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;
426  progress->total_extra_passes++; /* count file input as separate pass */
427  }
428 
429  /* Create decompressor output buffer. */
430  dest->pub.buffer = (*cinfo->mem->alloc_sarray)
431  ((j_common_ptr) cinfo, JPOOL_IMAGE, row_width, (JDIMENSION) 1);
432  dest->pub.buffer_height = 1;
433 
434  return &dest->pub;
435 }
436 
437 #endif /* BMP_SUPPORTED */
#define CENTERJSAMPLE
Definition: jmorecfg.h:84
#define TRUE
Definition: types.h:120
JDIMENSION output_height
Definition: jpeglib.h:508
JSAMPLE FAR * JSAMPROW
Definition: jpeglib.h:75
#define ERREXIT(msg)
Definition: rdjpgcom.c:72
struct jpeg_common_struct * j_common_ptr
Definition: jpeglib.h:284
boolean quantize_colors
Definition: jpeglib.h:491
#define GETJSAMPLE(value)
Definition: jmorecfg.h:78
#define MEMZERO(addr, type, size)
Definition: svc_dg.c:324
static FILE * outfile
Definition: wrjpgcom.c:81
JDIMENSION output_width
Definition: jpeglib.h:507
#define JFERROR(file)
Definition: jinclude.h:97
#define JFWRITE(file, buf, sizeofbuf)
Definition: jinclude.h:94
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
#define SIZEOF(_ar)
Definition: calc.h:97
jpeg_calc_output_dimensions(j_decompress_ptr cinfo)
Definition: jdmaster.c:101
#define JPOOL_IMAGE
Definition: jpeglib.h:808
J_COLOR_SPACE out_color_space
Definition: jpeglib.h:478
int total_extra_passes
Definition: cdjpeg.h:85
#define JFFLUSH(file)
Definition: jinclude.h:96
smooth NULL
Definition: ftsmooth.c:416
#define LOCAL(type)
Definition: jmorecfg.h:289
_Check_return_opt_ _CRTIMP int __cdecl putc(_In_ int _Ch, _Inout_ FILE *_File)
if(!(yy_init))
Definition: macro.lex.yy.c:714
struct jpeg_progress_mgr pub
Definition: cdjpeg.h:83
#define JPP(arglist)
Definition: jpeglib.h:877
#define ERREXIT1(cinfo, code, p1)
Definition: jerror.h:212
JSAMPARRAY colormap
Definition: jpeglib.h:527
JSAMPROW * JSAMPARRAY
Definition: jpeglib.h:76
#define GLOBAL(type)
Definition: jmorecfg.h:291
#define METHODDEF(type)
Definition: jmorecfg.h:287
int completed_extra_passes
Definition: cdjpeg.h:84
#define long
Definition: qsort.c:33
cd_progress_ptr progress
Definition: cdjpeg.h:152
unsigned int JDIMENSION
Definition: jmorecfg.h:229
struct cdjpeg_progress_mgr * cd_progress_ptr
Definition: cdjpeg.h:90
signed int INT32
static char * dest
Definition: rtl.c:135
boolean is_os2
Definition: cdjpeg.h:123
Sorry
Definition: jdcolor.c:19
struct png_info_def *typedef unsigned char **typedef struct png_info_def *typedef struct png_info_def *typedef struct png_info_def *typedef unsigned char ** row
Definition: typeof.h:78
unsigned int(__cdecl typeof(jpeg_read_scanlines))(struct jpeg_decompress_struct *
Definition: typeof.h:31