wrrle.c 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. /*
  2. * wrrle.c
  3. *
  4. * Copyright (C) 1991-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 RLE format.
  10. * The Utah Raster Toolkit library is required (version 3.1 or later).
  11. *
  12. * These routines may need modification for non-Unix environments or
  13. * specialized applications. As they stand, they assume output to
  14. * an ordinary stdio stream.
  15. *
  16. * Based on code contributed by Mike Lijewski,
  17. * with updates from Robert Hutchinson.
  18. */
  19. #include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
  20. #ifdef RLE_SUPPORTED
  21. /* rle.h is provided by the Utah Raster Toolkit. */
  22. #include <rle.h>
  23. /*
  24. * We assume that JSAMPLE has the same representation as rle_pixel,
  25. * to wit, "unsigned char". Hence we can't cope with 12- or 16-bit samples.
  26. */
  27. #if BITS_IN_JSAMPLE != 8
  28. Sorry, this code only copes with 8-bit JSAMPLEs. /* deliberate syntax err */
  29. #endif
  30. /*
  31. * Since RLE stores scanlines bottom-to-top, we have to invert the image
  32. * from JPEG's top-to-bottom order. To do this, we save the outgoing data
  33. * in a virtual array during put_pixel_row calls, then actually emit the
  34. * RLE file during finish_output.
  35. */
  36. /*
  37. * For now, if we emit an RLE color map then it is always 256 entries long,
  38. * though not all of the entries need be used.
  39. */
  40. #define CMAPBITS 8
  41. #define CMAPLENGTH (1<<(CMAPBITS))
  42. typedef struct {
  43. struct djpeg_dest_struct pub; /* public fields */
  44. jvirt_sarray_ptr image; /* virtual array to store the output image */
  45. rle_map *colormap; /* RLE-style color map, or NULL if none */
  46. rle_pixel **rle_row; /* To pass rows to rle_putrow() */
  47. } rle_dest_struct;
  48. typedef rle_dest_struct * rle_dest_ptr;
  49. /* Forward declarations */
  50. METHODDEF(void) rle_put_pixel_rows
  51. JPP((j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
  52. JDIMENSION rows_supplied));
  53. /*
  54. * Write the file header.
  55. *
  56. * In this module it's easier to wait till finish_output to write anything.
  57. */
  58. METHODDEF(void)
  59. start_output_rle (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)
  60. {
  61. rle_dest_ptr dest = (rle_dest_ptr) dinfo;
  62. size_t cmapsize;
  63. int ci, i;
  64. #ifdef PROGRESS_REPORT
  65. cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;
  66. #endif
  67. /*
  68. * Make sure the image can be stored in RLE format.
  69. *
  70. * - RLE stores image dimensions as *signed* 16 bit integers. JPEG
  71. * uses unsigned, so we have to check the width.
  72. *
  73. * - Colorspace is expected to be grayscale or RGB.
  74. *
  75. * - The number of channels (components) is expected to be 1 (grayscale/
  76. * pseudocolor) or 3 (truecolor/directcolor).
  77. * (could be 2 or 4 if using an alpha channel, but we aren't)
  78. */
  79. if (cinfo->output_width > 32767 || cinfo->output_height > 32767)
  80. ERREXIT2(cinfo, JERR_RLE_DIMENSIONS, cinfo->output_width,
  81. cinfo->output_height);
  82. if (cinfo->out_color_space != JCS_GRAYSCALE &&
  83. cinfo->out_color_space != JCS_RGB)
  84. ERREXIT(cinfo, JERR_RLE_COLORSPACE);
  85. if (cinfo->output_components != 1 && cinfo->output_components != 3)
  86. ERREXIT1(cinfo, JERR_RLE_TOOMANYCHANNELS, cinfo->num_components);
  87. /* Convert colormap, if any, to RLE format. */
  88. dest->colormap = NULL;
  89. if (cinfo->quantize_colors) {
  90. /* Allocate storage for RLE-style cmap, zero any extra entries */
  91. cmapsize = cinfo->out_color_components * CMAPLENGTH * SIZEOF(rle_map);
  92. dest->colormap = (rle_map *) (*cinfo->mem->alloc_small)
  93. ((j_common_ptr) cinfo, JPOOL_IMAGE, cmapsize);
  94. MEMZERO(dest->colormap, cmapsize);
  95. /* Save away data in RLE format --- note 8-bit left shift! */
  96. /* Shifting would need adjustment for JSAMPLEs wider than 8 bits. */
  97. for (ci = 0; ci < cinfo->out_color_components; ci++) {
  98. for (i = 0; i < cinfo->actual_number_of_colors; i++) {
  99. dest->colormap[ci * CMAPLENGTH + i] =
  100. GETJSAMPLE(cinfo->colormap[ci][i]) << 8;
  101. }
  102. }
  103. }
  104. /* Set the output buffer to the first row */
  105. dest->pub.buffer = (*cinfo->mem->access_virt_sarray)
  106. ((j_common_ptr) cinfo, dest->image, (JDIMENSION) 0, (JDIMENSION) 1, TRUE);
  107. dest->pub.buffer_height = 1;
  108. dest->pub.put_pixel_rows = rle_put_pixel_rows;
  109. #ifdef PROGRESS_REPORT
  110. if (progress != NULL) {
  111. progress->total_extra_passes++; /* count file writing as separate pass */
  112. }
  113. #endif
  114. }
  115. /*
  116. * Write some pixel data.
  117. *
  118. * This routine just saves the data away in a virtual array.
  119. */
  120. METHODDEF(void)
  121. rle_put_pixel_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
  122. JDIMENSION rows_supplied)
  123. {
  124. rle_dest_ptr dest = (rle_dest_ptr) dinfo;
  125. if (cinfo->output_scanline < cinfo->output_height) {
  126. dest->pub.buffer = (*cinfo->mem->access_virt_sarray)
  127. ((j_common_ptr) cinfo, dest->image,
  128. cinfo->output_scanline, (JDIMENSION) 1, TRUE);
  129. }
  130. }
  131. /*
  132. * Finish up at the end of the file.
  133. *
  134. * Here is where we really output the RLE file.
  135. */
  136. METHODDEF(void)
  137. finish_output_rle (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)
  138. {
  139. rle_dest_ptr dest = (rle_dest_ptr) dinfo;
  140. rle_hdr header; /* Output file information */
  141. rle_pixel **rle_row, *red_ptr, *green_ptr, *blue_ptr;
  142. JSAMPROW output_row;
  143. char cmapcomment[80];
  144. int row, col;
  145. int ci;
  146. #ifdef PROGRESS_REPORT
  147. cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;
  148. #endif
  149. /* Initialize the header info */
  150. header = *rle_hdr_init(NULL);
  151. header.rle_file = dest->pub.output_file;
  152. header.xmin = 0;
  153. header.xmax = cinfo->output_width - 1;
  154. header.ymin = 0;
  155. header.ymax = cinfo->output_height - 1;
  156. header.alpha = 0;
  157. header.ncolors = cinfo->output_components;
  158. for (ci = 0; ci < cinfo->output_components; ci++) {
  159. RLE_SET_BIT(header, ci);
  160. }
  161. if (cinfo->quantize_colors) {
  162. header.ncmap = cinfo->out_color_components;
  163. header.cmaplen = CMAPBITS;
  164. header.cmap = dest->colormap;
  165. /* Add a comment to the output image with the true colormap length. */
  166. sprintf(cmapcomment, "color_map_length=%d", cinfo->actual_number_of_colors);
  167. rle_putcom(cmapcomment, &header);
  168. }
  169. /* Emit the RLE header and color map (if any) */
  170. rle_put_setup(&header);
  171. /* Now output the RLE data from our virtual array.
  172. * We assume here that (a) rle_pixel is represented the same as JSAMPLE,
  173. * and (b) we are not on a machine where FAR pointers differ from regular.
  174. */
  175. #ifdef PROGRESS_REPORT
  176. if (progress != NULL) {
  177. progress->pub.pass_limit = cinfo->output_height;
  178. progress->pub.pass_counter = 0;
  179. (*progress->pub.progress_monitor) ((j_common_ptr) cinfo);
  180. }
  181. #endif
  182. if (cinfo->output_components == 1) {
  183. for (row = cinfo->output_height - 1; row >= 0; row--) {
  184. rle_row = (rle_pixel **) (*cinfo->mem->access_virt_sarray)
  185. ((j_common_ptr) cinfo, dest->image,
  186. (JDIMENSION) row, (JDIMENSION) 1, FALSE);
  187. rle_putrow(rle_row, (int) cinfo->output_width, &header);
  188. #ifdef PROGRESS_REPORT
  189. if (progress != NULL) {
  190. progress->pub.pass_counter++;
  191. (*progress->pub.progress_monitor) ((j_common_ptr) cinfo);
  192. }
  193. #endif
  194. }
  195. } else {
  196. for (row = cinfo->output_height - 1; row >= 0; row--) {
  197. output_row = * (*cinfo->mem->access_virt_sarray)
  198. ((j_common_ptr) cinfo, dest->image,
  199. (JDIMENSION) row, (JDIMENSION) 1, FALSE);
  200. rle_row = dest->rle_row;
  201. red_ptr = rle_row[0];
  202. green_ptr = rle_row[1];
  203. blue_ptr = rle_row[2];
  204. for (col = cinfo->output_width; col > 0; col--) {
  205. *red_ptr++ = GETJSAMPLE(*output_row++);
  206. *green_ptr++ = GETJSAMPLE(*output_row++);
  207. *blue_ptr++ = GETJSAMPLE(*output_row++);
  208. }
  209. rle_putrow(rle_row, (int) cinfo->output_width, &header);
  210. #ifdef PROGRESS_REPORT
  211. if (progress != NULL) {
  212. progress->pub.pass_counter++;
  213. (*progress->pub.progress_monitor) ((j_common_ptr) cinfo);
  214. }
  215. #endif
  216. }
  217. }
  218. #ifdef PROGRESS_REPORT
  219. if (progress != NULL)
  220. progress->completed_extra_passes++;
  221. #endif
  222. /* Emit file trailer */
  223. rle_puteof(&header);
  224. JFFLUSH(dest->pub.output_file);
  225. if (JFERROR(dest->pub.output_file))
  226. ERREXIT(cinfo, JERR_FILE_WRITE);
  227. }
  228. /*
  229. * The module selection routine for RLE format output.
  230. */
  231. GLOBAL(djpeg_dest_ptr)
  232. jinit_write_rle (j_decompress_ptr cinfo)
  233. {
  234. rle_dest_ptr dest;
  235. /* Create module interface object, fill in method pointers */
  236. dest = (rle_dest_ptr) (*cinfo->mem->alloc_small)
  237. ((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(rle_dest_struct));
  238. dest->pub.start_output = start_output_rle;
  239. dest->pub.finish_output = finish_output_rle;
  240. /* Calculate output image dimensions so we can allocate space */
  241. jpeg_calc_output_dimensions(cinfo);
  242. /* Allocate a work array for output to the RLE library. */
  243. dest->rle_row = (*cinfo->mem->alloc_sarray) ((j_common_ptr) cinfo,
  244. JPOOL_IMAGE, cinfo->output_width, (JDIMENSION) cinfo->output_components);
  245. /* Allocate a virtual array to hold the image. */
  246. dest->image = (*cinfo->mem->request_virt_sarray)
  247. ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE,
  248. cinfo->output_width * (JDIMENSION) cinfo->output_components,
  249. cinfo->output_height, (JDIMENSION) 1);
  250. return &dest->pub;
  251. }
  252. #endif /* RLE_SUPPORTED */