ReactOS  0.4.14-dev-606-g14ebc0b
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 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  JSAMPARRAY image_ptr;
78  register JSAMPROW inptr, outptr;
79  register JDIMENSION col;
80  int pad;
81 
82  /* Access next row in virtual array */
83  image_ptr = (*cinfo->mem->access_virt_sarray)
84  ((j_common_ptr) cinfo, dest->whole_image,
85  dest->cur_output_row, (JDIMENSION) 1, TRUE);
86  dest->cur_output_row++;
87 
88  /* Transfer data. Note destination values must be in BGR order
89  * (even though Microsoft's own documents say the opposite).
90  */
91  inptr = dest->pub.buffer[0];
92  outptr = image_ptr[0];
93  for (col = cinfo->output_width; col > 0; col--) {
94  outptr[2] = *inptr++; /* can omit GETJSAMPLE() safely */
95  outptr[1] = *inptr++;
96  outptr[0] = *inptr++;
97  outptr += 3;
98  }
99 
100  /* Zero out the pad bytes. */
101  pad = dest->pad_bytes;
102  while (--pad >= 0)
103  *outptr++ = 0;
104 }
105 
106 METHODDEF(void)
107 put_gray_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
108  JDIMENSION rows_supplied)
109 /* This version is for grayscale OR quantized color output */
110 {
111  bmp_dest_ptr dest = (bmp_dest_ptr) dinfo;
112  JSAMPARRAY image_ptr;
113  register JSAMPROW inptr, outptr;
114  register JDIMENSION col;
115  int pad;
116 
117  /* Access next row in virtual array */
118  image_ptr = (*cinfo->mem->access_virt_sarray)
119  ((j_common_ptr) cinfo, dest->whole_image,
120  dest->cur_output_row, (JDIMENSION) 1, TRUE);
121  dest->cur_output_row++;
122 
123  /* Transfer data. */
124  inptr = dest->pub.buffer[0];
125  outptr = image_ptr[0];
126  for (col = cinfo->output_width; col > 0; col--) {
127  *outptr++ = *inptr++; /* can omit GETJSAMPLE() safely */
128  }
129 
130  /* Zero out the pad bytes. */
131  pad = dest->pad_bytes;
132  while (--pad >= 0)
133  *outptr++ = 0;
134 }
135 
136 
137 /*
138  * Startup: normally writes the file header.
139  * In this module we may as well postpone everything until finish_output.
140  */
141 
142 METHODDEF(void)
143 start_output_bmp (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)
144 {
145  /* no work here */
146 }
147 
148 
149 /*
150  * Finish up at the end of the file.
151  *
152  * Here is where we really output the BMP file.
153  *
154  * First, routines to write the Windows and OS/2 variants of the file header.
155  */
156 
157 LOCAL(void)
158 write_bmp_header (j_decompress_ptr cinfo, bmp_dest_ptr dest)
159 /* Write a Windows-style BMP file header, including colormap if needed */
160 {
161  char bmpfileheader[14];
162  char bmpinfoheader[40];
163 #define PUT_2B(array,offset,value) \
164  (array[offset] = (char) ((value) & 0xFF), \
165  array[offset+1] = (char) (((value) >> 8) & 0xFF))
166 #define PUT_4B(array,offset,value) \
167  (array[offset] = (char) ((value) & 0xFF), \
168  array[offset+1] = (char) (((value) >> 8) & 0xFF), \
169  array[offset+2] = (char) (((value) >> 16) & 0xFF), \
170  array[offset+3] = (char) (((value) >> 24) & 0xFF))
171  INT32 headersize, bfSize;
172  int bits_per_pixel, cmap_entries;
173 
174  /* Compute colormap size and total file size */
175  if (cinfo->out_color_space == JCS_RGB) {
176  if (cinfo->quantize_colors) {
177  /* Colormapped RGB */
178  bits_per_pixel = 8;
179  cmap_entries = 256;
180  } else {
181  /* Unquantized, full color RGB */
182  bits_per_pixel = 24;
183  cmap_entries = 0;
184  }
185  } else {
186  /* Grayscale output. We need to fake a 256-entry colormap. */
187  bits_per_pixel = 8;
188  cmap_entries = 256;
189  }
190  /* File size */
191  headersize = 14 + 40 + cmap_entries * 4; /* Header and colormap */
192  bfSize = headersize + (INT32) dest->row_width * (INT32) cinfo->output_height;
193 
194  /* Set unused fields of header to 0 */
195  MEMZERO(bmpfileheader, SIZEOF(bmpfileheader));
196  MEMZERO(bmpinfoheader, SIZEOF(bmpinfoheader));
197 
198  /* Fill the file header */
199  bmpfileheader[0] = 0x42; /* first 2 bytes are ASCII 'B', 'M' */
200  bmpfileheader[1] = 0x4D;
201  PUT_4B(bmpfileheader, 2, bfSize); /* bfSize */
202  /* we leave bfReserved1 & bfReserved2 = 0 */
203  PUT_4B(bmpfileheader, 10, headersize); /* bfOffBits */
204 
205  /* Fill the info header (Microsoft calls this a BITMAPINFOHEADER) */
206  PUT_2B(bmpinfoheader, 0, 40); /* biSize */
207  PUT_4B(bmpinfoheader, 4, cinfo->output_width); /* biWidth */
208  PUT_4B(bmpinfoheader, 8, cinfo->output_height); /* biHeight */
209  PUT_2B(bmpinfoheader, 12, 1); /* biPlanes - must be 1 */
210  PUT_2B(bmpinfoheader, 14, bits_per_pixel); /* biBitCount */
211  /* we leave biCompression = 0, for none */
212  /* we leave biSizeImage = 0; this is correct for uncompressed data */
213  if (cinfo->density_unit == 2) { /* if have density in dots/cm, then */
214  PUT_4B(bmpinfoheader, 24, (INT32) (cinfo->X_density*100)); /* XPels/M */
215  PUT_4B(bmpinfoheader, 28, (INT32) (cinfo->Y_density*100)); /* XPels/M */
216  }
217  PUT_2B(bmpinfoheader, 32, cmap_entries); /* biClrUsed */
218  /* we leave biClrImportant = 0 */
219 
220  if (JFWRITE(dest->pub.output_file, bmpfileheader, 14) != (size_t) 14)
221  ERREXIT(cinfo, JERR_FILE_WRITE);
222  if (JFWRITE(dest->pub.output_file, bmpinfoheader, 40) != (size_t) 40)
223  ERREXIT(cinfo, JERR_FILE_WRITE);
224 
225  if (cmap_entries > 0)
226  write_colormap(cinfo, dest, cmap_entries, 4);
227 }
228 
229 
230 LOCAL(void)
231 write_os2_header (j_decompress_ptr cinfo, bmp_dest_ptr dest)
232 /* Write an OS2-style BMP file header, including colormap if needed */
233 {
234  char bmpfileheader[14];
235  char bmpcoreheader[12];
236  INT32 headersize, bfSize;
237  int bits_per_pixel, cmap_entries;
238 
239  /* Compute colormap size and total file size */
240  if (cinfo->out_color_space == JCS_RGB) {
241  if (cinfo->quantize_colors) {
242  /* Colormapped RGB */
243  bits_per_pixel = 8;
244  cmap_entries = 256;
245  } else {
246  /* Unquantized, full color RGB */
247  bits_per_pixel = 24;
248  cmap_entries = 0;
249  }
250  } else {
251  /* Grayscale output. We need to fake a 256-entry colormap. */
252  bits_per_pixel = 8;
253  cmap_entries = 256;
254  }
255  /* File size */
256  headersize = 14 + 12 + cmap_entries * 3; /* Header and colormap */
257  bfSize = headersize + (INT32) dest->row_width * (INT32) cinfo->output_height;
258 
259  /* Set unused fields of header to 0 */
260  MEMZERO(bmpfileheader, SIZEOF(bmpfileheader));
261  MEMZERO(bmpcoreheader, SIZEOF(bmpcoreheader));
262 
263  /* Fill the file header */
264  bmpfileheader[0] = 0x42; /* first 2 bytes are ASCII 'B', 'M' */
265  bmpfileheader[1] = 0x4D;
266  PUT_4B(bmpfileheader, 2, bfSize); /* bfSize */
267  /* we leave bfReserved1 & bfReserved2 = 0 */
268  PUT_4B(bmpfileheader, 10, headersize); /* bfOffBits */
269 
270  /* Fill the info header (Microsoft calls this a BITMAPCOREHEADER) */
271  PUT_2B(bmpcoreheader, 0, 12); /* bcSize */
272  PUT_2B(bmpcoreheader, 4, cinfo->output_width); /* bcWidth */
273  PUT_2B(bmpcoreheader, 6, cinfo->output_height); /* bcHeight */
274  PUT_2B(bmpcoreheader, 8, 1); /* bcPlanes - must be 1 */
275  PUT_2B(bmpcoreheader, 10, bits_per_pixel); /* bcBitCount */
276 
277  if (JFWRITE(dest->pub.output_file, bmpfileheader, 14) != (size_t) 14)
278  ERREXIT(cinfo, JERR_FILE_WRITE);
279  if (JFWRITE(dest->pub.output_file, bmpcoreheader, 12) != (size_t) 12)
280  ERREXIT(cinfo, JERR_FILE_WRITE);
281 
282  if (cmap_entries > 0)
283  write_colormap(cinfo, dest, cmap_entries, 3);
284 }
285 
286 
287 /*
288  * Write the colormap.
289  * Windows uses BGR0 map entries; OS/2 uses BGR entries.
290  */
291 
292 LOCAL(void)
293 write_colormap (j_decompress_ptr cinfo, bmp_dest_ptr dest,
294  int map_colors, int map_entry_size)
295 {
296  JSAMPARRAY colormap = cinfo->colormap;
297  int num_colors = cinfo->actual_number_of_colors;
298  FILE * outfile = dest->pub.output_file;
299  int i;
300 
301  if (colormap != NULL) {
302  if (cinfo->out_color_components == 3) {
303  /* Normal case with RGB colormap */
304  for (i = 0; i < num_colors; i++) {
305  putc(GETJSAMPLE(colormap[2][i]), outfile);
306  putc(GETJSAMPLE(colormap[1][i]), outfile);
307  putc(GETJSAMPLE(colormap[0][i]), outfile);
308  if (map_entry_size == 4)
309  putc(0, outfile);
310  }
311  } else {
312  /* Grayscale colormap (only happens with grayscale quantization) */
313  for (i = 0; i < num_colors; i++) {
314  putc(GETJSAMPLE(colormap[0][i]), outfile);
315  putc(GETJSAMPLE(colormap[0][i]), outfile);
316  putc(GETJSAMPLE(colormap[0][i]), outfile);
317  if (map_entry_size == 4)
318  putc(0, outfile);
319  }
320  }
321  } else {
322  /* If no colormap, must be grayscale data. Generate a linear "map". */
323  for (i = 0; i < 256; i++) {
324  putc(i, outfile);
325  putc(i, outfile);
326  putc(i, outfile);
327  if (map_entry_size == 4)
328  putc(0, outfile);
329  }
330  }
331  /* Pad colormap with zeros to ensure specified number of colormap entries */
332  if (i > map_colors)
333  ERREXIT1(cinfo, JERR_TOO_MANY_COLORS, i);
334  for (; i < map_colors; i++) {
335  putc(0, outfile);
336  putc(0, outfile);
337  putc(0, outfile);
338  if (map_entry_size == 4)
339  putc(0, outfile);
340  }
341 }
342 
343 
344 METHODDEF(void)
345 finish_output_bmp (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)
346 {
347  bmp_dest_ptr dest = (bmp_dest_ptr) dinfo;
348  register FILE * outfile = dest->pub.output_file;
349  JSAMPARRAY image_ptr;
350  register JSAMPROW data_ptr;
351  JDIMENSION row;
352  register JDIMENSION col;
353  cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;
354 
355  /* Write the header and colormap */
356  if (dest->is_os2)
357  write_os2_header(cinfo, dest);
358  else
359  write_bmp_header(cinfo, dest);
360 
361  /* Write the file body from our virtual array */
362  for (row = cinfo->output_height; row > 0; row--) {
363  if (progress != NULL) {
364  progress->pub.pass_counter = (long) (cinfo->output_height - row);
365  progress->pub.pass_limit = (long) cinfo->output_height;
366  (*progress->pub.progress_monitor) ((j_common_ptr) cinfo);
367  }
368  image_ptr = (*cinfo->mem->access_virt_sarray)
369  ((j_common_ptr) cinfo, dest->whole_image, row-1, (JDIMENSION) 1, FALSE);
370  data_ptr = image_ptr[0];
371  for (col = dest->row_width; col > 0; col--) {
372  putc(GETJSAMPLE(*data_ptr), outfile);
373  data_ptr++;
374  }
375  }
376  if (progress != NULL)
378 
379  /* Make sure we wrote the output file OK */
380  JFFLUSH(outfile);
381  if (JFERROR(outfile))
382  ERREXIT(cinfo, JERR_FILE_WRITE);
383 }
384 
385 
386 /*
387  * The module selection routine for BMP format output.
388  */
389 
391 jinit_write_bmp (j_decompress_ptr cinfo, boolean is_os2)
392 {
393  bmp_dest_ptr dest;
394  JDIMENSION row_width;
395 
396  /* Create module interface object, fill in method pointers */
397  dest = (bmp_dest_ptr)
398  (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
399  SIZEOF(bmp_dest_struct));
400  dest->pub.start_output = start_output_bmp;
401  dest->pub.finish_output = finish_output_bmp;
402  dest->is_os2 = is_os2;
403 
404  if (cinfo->out_color_space == JCS_GRAYSCALE) {
405  dest->pub.put_pixel_rows = put_gray_rows;
406  } else if (cinfo->out_color_space == JCS_RGB) {
407  if (cinfo->quantize_colors)
408  dest->pub.put_pixel_rows = put_gray_rows;
409  else
410  dest->pub.put_pixel_rows = put_pixel_rows;
411  } else {
412  ERREXIT(cinfo, JERR_BMP_COLORSPACE);
413  }
414 
415  /* Calculate output image dimensions so we can allocate space */
417 
418  /* Determine width of rows in the BMP file (padded to 4-byte boundary). */
419  row_width = cinfo->output_width * cinfo->output_components;
420  dest->data_width = row_width;
421  while ((row_width & 3) != 0) row_width++;
422  dest->row_width = row_width;
423  dest->pad_bytes = (int) (row_width - dest->data_width);
424 
425  /* Allocate space for inversion array, prepare for write pass */
426  dest->whole_image = (*cinfo->mem->request_virt_sarray)
427  ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE,
428  row_width, cinfo->output_height, (JDIMENSION) 1);
429  dest->cur_output_row = 0;
430  if (cinfo->progress != NULL) {
431  cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;
432  progress->total_extra_passes++; /* count file input as separate pass */
433  }
434 
435  /* Create decompressor output buffer. */
436  dest->pub.buffer = (*cinfo->mem->alloc_sarray)
437  ((j_common_ptr) cinfo, JPOOL_IMAGE, row_width, (JDIMENSION) 1);
438  dest->pub.buffer_height = 1;
439 
440  return &dest->pub;
441 }
442 
443 #endif /* BMP_SUPPORTED */
#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:84
#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:82
#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:83
#define long
Definition: qsort.c:33
cd_progress_ptr progress
Definition: cdjpeg.h:150
unsigned int JDIMENSION
Definition: jmorecfg.h:229
struct cdjpeg_progress_mgr * cd_progress_ptr
Definition: cdjpeg.h:89
signed int INT32
static char * dest
Definition: rtl.c:135
boolean is_os2
Definition: cdjpeg.h:122
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