wrbmp.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493
  1. /*
  2. * wrbmp.c
  3. *
  4. * This file was part of the Independent JPEG Group's software:
  5. * Copyright (C) 1994-1996, Thomas G. Lane.
  6. * libjpeg-turbo Modifications:
  7. * Copyright (C) 2013, Linaro Limited.
  8. * Copyright (C) 2014-2015, D. R. Commander.
  9. * For conditions of distribution and use, see the accompanying README.ijg
  10. * file.
  11. *
  12. * This file contains routines to write output images in Microsoft "BMP"
  13. * format (MS Windows 3.x and OS/2 1.x flavors).
  14. * Either 8-bit colormapped or 24-bit full-color format can be written.
  15. * No compression is supported.
  16. *
  17. * These routines may need modification for non-Unix environments or
  18. * specialized applications. As they stand, they assume output to
  19. * an ordinary stdio stream.
  20. *
  21. * This code contributed by James Arthur Boucher.
  22. */
  23. #include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
  24. #include "jconfigint.h"
  25. #ifdef BMP_SUPPORTED
  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. #if BITS_IN_JSAMPLE != 8
  31. Sorry, this code only copes with 8-bit JSAMPLEs. /* deliberate syntax err */
  32. #endif
  33. /*
  34. * Since BMP stores scanlines bottom-to-top, we have to invert the image
  35. * from JPEG's top-to-bottom order. To do this, we save the outgoing data
  36. * in a virtual array during put_pixel_row calls, then actually emit the
  37. * BMP file during finish_output. The virtual array contains one JSAMPLE per
  38. * pixel if the output is grayscale or colormapped, three if it is full color.
  39. */
  40. /* Private version of data destination object */
  41. typedef struct {
  42. struct djpeg_dest_struct pub; /* public fields */
  43. boolean is_os2; /* saves the OS2 format request flag */
  44. jvirt_sarray_ptr whole_image; /* needed to reverse row order */
  45. JDIMENSION data_width; /* JSAMPLEs per row */
  46. JDIMENSION row_width; /* physical width of one row in the BMP file */
  47. int pad_bytes; /* number of padding bytes needed per row */
  48. JDIMENSION cur_output_row; /* next row# to write to virtual array */
  49. } bmp_dest_struct;
  50. typedef bmp_dest_struct *bmp_dest_ptr;
  51. /* Forward declarations */
  52. LOCAL(void) write_colormap
  53. (j_decompress_ptr cinfo, bmp_dest_ptr dest, int map_colors,
  54. int map_entry_size);
  55. static INLINE boolean is_big_endian(void)
  56. {
  57. int test_value = 1;
  58. if(*(char *)&test_value != 1)
  59. return TRUE;
  60. return FALSE;
  61. }
  62. /*
  63. * Write some pixel data.
  64. * In this module rows_supplied will always be 1.
  65. */
  66. METHODDEF(void)
  67. put_pixel_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
  68. JDIMENSION rows_supplied)
  69. /* This version is for writing 24-bit pixels */
  70. {
  71. bmp_dest_ptr dest = (bmp_dest_ptr) dinfo;
  72. JSAMPARRAY image_ptr;
  73. register JSAMPROW inptr, outptr;
  74. register JDIMENSION col;
  75. int pad;
  76. /* Access next row in virtual array */
  77. image_ptr = (*cinfo->mem->access_virt_sarray)
  78. ((j_common_ptr) cinfo, dest->whole_image,
  79. dest->cur_output_row, (JDIMENSION) 1, TRUE);
  80. dest->cur_output_row++;
  81. /* Transfer data. Note destination values must be in BGR order
  82. * (even though Microsoft's own documents say the opposite).
  83. */
  84. inptr = dest->pub.buffer[0];
  85. outptr = image_ptr[0];
  86. if(cinfo->out_color_space == JCS_RGB565) {
  87. boolean big_endian = is_big_endian();
  88. unsigned short *inptr2 = (unsigned short *)inptr;
  89. for (col = cinfo->output_width; col > 0; col--) {
  90. if (big_endian) {
  91. outptr[0] = (*inptr2 >> 5) & 0xF8;
  92. outptr[1] = ((*inptr2 << 5) & 0xE0) | ((*inptr2 >> 11) & 0x1C);
  93. outptr[2] = *inptr2 & 0xF8;
  94. } else {
  95. outptr[0] = (*inptr2 << 3) & 0xF8;
  96. outptr[1] = (*inptr2 >> 3) & 0xFC;
  97. outptr[2] = (*inptr2 >> 8) & 0xF8;
  98. }
  99. outptr += 3;
  100. inptr2++;
  101. }
  102. } else {
  103. for (col = cinfo->output_width; col > 0; col--) {
  104. outptr[2] = *inptr++; /* can omit GETJSAMPLE() safely */
  105. outptr[1] = *inptr++;
  106. outptr[0] = *inptr++;
  107. outptr += 3;
  108. }
  109. }
  110. /* Zero out the pad bytes. */
  111. pad = dest->pad_bytes;
  112. while (--pad >= 0)
  113. *outptr++ = 0;
  114. }
  115. METHODDEF(void)
  116. put_gray_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
  117. JDIMENSION rows_supplied)
  118. /* This version is for grayscale OR quantized color output */
  119. {
  120. bmp_dest_ptr dest = (bmp_dest_ptr) dinfo;
  121. JSAMPARRAY image_ptr;
  122. register JSAMPROW inptr, outptr;
  123. register JDIMENSION col;
  124. int pad;
  125. /* Access next row in virtual array */
  126. image_ptr = (*cinfo->mem->access_virt_sarray)
  127. ((j_common_ptr) cinfo, dest->whole_image,
  128. dest->cur_output_row, (JDIMENSION) 1, TRUE);
  129. dest->cur_output_row++;
  130. /* Transfer data. */
  131. inptr = dest->pub.buffer[0];
  132. outptr = image_ptr[0];
  133. for (col = cinfo->output_width; col > 0; col--) {
  134. *outptr++ = *inptr++; /* can omit GETJSAMPLE() safely */
  135. }
  136. /* Zero out the pad bytes. */
  137. pad = dest->pad_bytes;
  138. while (--pad >= 0)
  139. *outptr++ = 0;
  140. }
  141. /*
  142. * Startup: normally writes the file header.
  143. * In this module we may as well postpone everything until finish_output.
  144. */
  145. METHODDEF(void)
  146. start_output_bmp (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)
  147. {
  148. /* no work here */
  149. }
  150. /*
  151. * Finish up at the end of the file.
  152. *
  153. * Here is where we really output the BMP file.
  154. *
  155. * First, routines to write the Windows and OS/2 variants of the file header.
  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. long headersize, bfSize;
  172. int bits_per_pixel, cmap_entries;
  173. /* Compute colormap size and total file size */
  174. if (cinfo->out_color_space == JCS_RGB) {
  175. if (cinfo->quantize_colors) {
  176. /* Colormapped RGB */
  177. bits_per_pixel = 8;
  178. cmap_entries = 256;
  179. } else {
  180. /* Unquantized, full color RGB */
  181. bits_per_pixel = 24;
  182. cmap_entries = 0;
  183. }
  184. } else if (cinfo->out_color_space == JCS_RGB565) {
  185. bits_per_pixel = 24;
  186. cmap_entries = 0;
  187. } else {
  188. /* Grayscale output. We need to fake a 256-entry colormap. */
  189. bits_per_pixel = 8;
  190. cmap_entries = 256;
  191. }
  192. /* File size */
  193. headersize = 14 + 40 + cmap_entries * 4; /* Header and colormap */
  194. bfSize = headersize + (long) dest->row_width * (long) cinfo->output_height;
  195. /* Set unused fields of header to 0 */
  196. MEMZERO(bmpfileheader, sizeof(bmpfileheader));
  197. MEMZERO(bmpinfoheader, sizeof(bmpinfoheader));
  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. /* Fill the info header (Microsoft calls this a BITMAPINFOHEADER) */
  205. PUT_2B(bmpinfoheader, 0, 40); /* biSize */
  206. PUT_4B(bmpinfoheader, 4, cinfo->output_width); /* biWidth */
  207. PUT_4B(bmpinfoheader, 8, cinfo->output_height); /* biHeight */
  208. PUT_2B(bmpinfoheader, 12, 1); /* biPlanes - must be 1 */
  209. PUT_2B(bmpinfoheader, 14, bits_per_pixel); /* biBitCount */
  210. /* we leave biCompression = 0, for none */
  211. /* we leave biSizeImage = 0; this is correct for uncompressed data */
  212. if (cinfo->density_unit == 2) { /* if have density in dots/cm, then */
  213. PUT_4B(bmpinfoheader, 24, (long) (cinfo->X_density*100)); /* XPels/M */
  214. PUT_4B(bmpinfoheader, 28, (long) (cinfo->Y_density*100)); /* XPels/M */
  215. }
  216. PUT_2B(bmpinfoheader, 32, cmap_entries); /* biClrUsed */
  217. /* we leave biClrImportant = 0 */
  218. if (JFWRITE(dest->pub.output_file, bmpfileheader, 14) != (size_t) 14)
  219. ERREXIT(cinfo, JERR_FILE_WRITE);
  220. if (JFWRITE(dest->pub.output_file, bmpinfoheader, 40) != (size_t) 40)
  221. ERREXIT(cinfo, JERR_FILE_WRITE);
  222. if (cmap_entries > 0)
  223. write_colormap(cinfo, dest, cmap_entries, 4);
  224. }
  225. LOCAL(void)
  226. write_os2_header (j_decompress_ptr cinfo, bmp_dest_ptr dest)
  227. /* Write an OS2-style BMP file header, including colormap if needed */
  228. {
  229. char bmpfileheader[14];
  230. char bmpcoreheader[12];
  231. long headersize, bfSize;
  232. int bits_per_pixel, cmap_entries;
  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 if (cinfo->out_color_space == JCS_RGB565) {
  245. bits_per_pixel = 24;
  246. cmap_entries = 0;
  247. } else {
  248. /* Grayscale output. We need to fake a 256-entry colormap. */
  249. bits_per_pixel = 8;
  250. cmap_entries = 256;
  251. }
  252. /* File size */
  253. headersize = 14 + 12 + cmap_entries * 3; /* Header and colormap */
  254. bfSize = headersize + (long) dest->row_width * (long) cinfo->output_height;
  255. /* Set unused fields of header to 0 */
  256. MEMZERO(bmpfileheader, sizeof(bmpfileheader));
  257. MEMZERO(bmpcoreheader, sizeof(bmpcoreheader));
  258. /* Fill the file header */
  259. bmpfileheader[0] = 0x42; /* first 2 bytes are ASCII 'B', 'M' */
  260. bmpfileheader[1] = 0x4D;
  261. PUT_4B(bmpfileheader, 2, bfSize); /* bfSize */
  262. /* we leave bfReserved1 & bfReserved2 = 0 */
  263. PUT_4B(bmpfileheader, 10, headersize); /* bfOffBits */
  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. if (JFWRITE(dest->pub.output_file, bmpfileheader, 14) != (size_t) 14)
  271. ERREXIT(cinfo, JERR_FILE_WRITE);
  272. if (JFWRITE(dest->pub.output_file, bmpcoreheader, 12) != (size_t) 12)
  273. ERREXIT(cinfo, JERR_FILE_WRITE);
  274. if (cmap_entries > 0)
  275. write_colormap(cinfo, dest, cmap_entries, 3);
  276. }
  277. /*
  278. * Write the colormap.
  279. * Windows uses BGR0 map entries; OS/2 uses BGR entries.
  280. */
  281. LOCAL(void)
  282. write_colormap (j_decompress_ptr cinfo, bmp_dest_ptr dest,
  283. int map_colors, int map_entry_size)
  284. {
  285. JSAMPARRAY colormap = cinfo->colormap;
  286. int num_colors = cinfo->actual_number_of_colors;
  287. FILE *outfile = dest->pub.output_file;
  288. int i;
  289. if (colormap != NULL) {
  290. if (cinfo->out_color_components == 3) {
  291. /* Normal case with RGB colormap */
  292. for (i = 0; i < num_colors; i++) {
  293. putc(GETJSAMPLE(colormap[2][i]), outfile);
  294. putc(GETJSAMPLE(colormap[1][i]), outfile);
  295. putc(GETJSAMPLE(colormap[0][i]), outfile);
  296. if (map_entry_size == 4)
  297. putc(0, outfile);
  298. }
  299. } else {
  300. /* Grayscale colormap (only happens with grayscale quantization) */
  301. for (i = 0; i < num_colors; i++) {
  302. putc(GETJSAMPLE(colormap[0][i]), outfile);
  303. putc(GETJSAMPLE(colormap[0][i]), outfile);
  304. putc(GETJSAMPLE(colormap[0][i]), outfile);
  305. if (map_entry_size == 4)
  306. putc(0, outfile);
  307. }
  308. }
  309. } else {
  310. /* If no colormap, must be grayscale data. Generate a linear "map". */
  311. for (i = 0; i < 256; i++) {
  312. putc(i, outfile);
  313. putc(i, outfile);
  314. putc(i, outfile);
  315. if (map_entry_size == 4)
  316. putc(0, outfile);
  317. }
  318. }
  319. /* Pad colormap with zeros to ensure specified number of colormap entries */
  320. if (i > map_colors)
  321. ERREXIT1(cinfo, JERR_TOO_MANY_COLORS, i);
  322. for (; i < map_colors; i++) {
  323. putc(0, outfile);
  324. putc(0, outfile);
  325. putc(0, outfile);
  326. if (map_entry_size == 4)
  327. putc(0, outfile);
  328. }
  329. }
  330. METHODDEF(void)
  331. finish_output_bmp (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)
  332. {
  333. bmp_dest_ptr dest = (bmp_dest_ptr) dinfo;
  334. register FILE *outfile = dest->pub.output_file;
  335. JSAMPARRAY image_ptr;
  336. register JSAMPROW data_ptr;
  337. JDIMENSION row;
  338. register JDIMENSION col;
  339. cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;
  340. /* Write the header and colormap */
  341. if (dest->is_os2)
  342. write_os2_header(cinfo, dest);
  343. else
  344. write_bmp_header(cinfo, dest);
  345. /* Write the file body from our virtual array */
  346. for (row = cinfo->output_height; row > 0; row--) {
  347. if (progress != NULL) {
  348. progress->pub.pass_counter = (long) (cinfo->output_height - row);
  349. progress->pub.pass_limit = (long) cinfo->output_height;
  350. (*progress->pub.progress_monitor) ((j_common_ptr) cinfo);
  351. }
  352. image_ptr = (*cinfo->mem->access_virt_sarray)
  353. ((j_common_ptr) cinfo, dest->whole_image, row-1, (JDIMENSION) 1, FALSE);
  354. data_ptr = image_ptr[0];
  355. for (col = dest->row_width; col > 0; col--) {
  356. putc(GETJSAMPLE(*data_ptr), outfile);
  357. data_ptr++;
  358. }
  359. }
  360. if (progress != NULL)
  361. progress->completed_extra_passes++;
  362. /* Make sure we wrote the output file OK */
  363. fflush(outfile);
  364. if (ferror(outfile))
  365. ERREXIT(cinfo, JERR_FILE_WRITE);
  366. }
  367. /*
  368. * The module selection routine for BMP format output.
  369. */
  370. GLOBAL(djpeg_dest_ptr)
  371. jinit_write_bmp (j_decompress_ptr cinfo, boolean is_os2)
  372. {
  373. bmp_dest_ptr dest;
  374. JDIMENSION row_width;
  375. /* Create module interface object, fill in method pointers */
  376. dest = (bmp_dest_ptr)
  377. (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
  378. sizeof(bmp_dest_struct));
  379. dest->pub.start_output = start_output_bmp;
  380. dest->pub.finish_output = finish_output_bmp;
  381. dest->is_os2 = is_os2;
  382. if (cinfo->out_color_space == JCS_GRAYSCALE) {
  383. dest->pub.put_pixel_rows = put_gray_rows;
  384. } else if (cinfo->out_color_space == JCS_RGB) {
  385. if (cinfo->quantize_colors)
  386. dest->pub.put_pixel_rows = put_gray_rows;
  387. else
  388. dest->pub.put_pixel_rows = put_pixel_rows;
  389. } else if(cinfo->out_color_space == JCS_RGB565 ) {
  390. dest->pub.put_pixel_rows = put_pixel_rows;
  391. } else {
  392. ERREXIT(cinfo, JERR_BMP_COLORSPACE);
  393. }
  394. /* Calculate output image dimensions so we can allocate space */
  395. jpeg_calc_output_dimensions(cinfo);
  396. /* Determine width of rows in the BMP file (padded to 4-byte boundary). */
  397. if (cinfo->out_color_space == JCS_RGB565) {
  398. row_width = cinfo->output_width * 2;
  399. dest->row_width = dest->data_width = cinfo->output_width * 3;
  400. } else {
  401. row_width = cinfo->output_width * cinfo->output_components;
  402. dest->row_width = dest->data_width = row_width;
  403. }
  404. while ((dest->row_width & 3) != 0) dest->row_width++;
  405. dest->pad_bytes = (int) (dest->row_width - dest->data_width);
  406. if (cinfo->out_color_space == JCS_RGB565) {
  407. while ((row_width & 3) != 0) row_width++;
  408. } else {
  409. row_width = dest->row_width;
  410. }
  411. /* Allocate space for inversion array, prepare for write pass */
  412. dest->whole_image = (*cinfo->mem->request_virt_sarray)
  413. ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE,
  414. dest->row_width, cinfo->output_height, (JDIMENSION) 1);
  415. dest->cur_output_row = 0;
  416. if (cinfo->progress != NULL) {
  417. cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;
  418. progress->total_extra_passes++; /* count file input as separate pass */
  419. }
  420. /* Create decompressor output buffer. */
  421. dest->pub.buffer = (*cinfo->mem->alloc_sarray)
  422. ((j_common_ptr) cinfo, JPOOL_IMAGE, row_width, (JDIMENSION) 1);
  423. dest->pub.buffer_height = 1;
  424. return (djpeg_dest_ptr) dest;
  425. }
  426. #endif /* BMP_SUPPORTED */