wrppm.pas 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. Unit WrPPM;
  2. { wrppm.c
  3. Copyright (C) 1991-1996, Thomas G. Lane.
  4. This file is part of the Independent JPEG Group's software.
  5. For conditions of distribution and use, see the accompanying README file.
  6. This file contains routines to write output images in PPM/PGM format.
  7. The extended 2-byte-per-sample raw PPM/PGM formats are supported.
  8. The PBMPLUS library is NOT required to compile this software
  9. (but it is highly useful as a set of PPM image manipulation programs).
  10. These routines may need modification for non-Unix environments or
  11. specialized applications. As they stand, they assume output to
  12. an ordinary stdio stream. }
  13. interface
  14. {$I jconfig.inc}
  15. uses
  16. jdeferr,
  17. jmorecfg,
  18. jerror,
  19. jpeglib,
  20. jinclude,
  21. jdmaster,
  22. cdjpeg; { Common decls for cjpeg/djpeg applications }
  23. {GLOBAL}
  24. function jinit_write_ppm (cinfo : j_decompress_ptr) : djpeg_dest_ptr;
  25. implementation
  26. { For 12-bit JPEG data, we either downscale the values to 8 bits
  27. (to write standard byte-per-sample PPM/PGM files), or output
  28. nonstandard word-per-sample PPM/PGM files. Downscaling is done
  29. if PPM_NORAWWORD is defined (this can be done in the Makefile
  30. or in jconfig.h).
  31. (When the core library supports data precision reduction, a cleaner
  32. implementation will be to ask for that instead.) }
  33. type
  34. CharPtr = ^char;
  35. {$ifdef BITS_IN_JSAMPLE_IS_8}
  36. procedure PUTPPMSAMPLE(var ptr : CharPtr; v : byte);
  37. begin
  38. ptr^ := char(v);
  39. Inc(ptr);
  40. end;
  41. const
  42. BYTESPERSAMPLE = 1;
  43. PPM_MAXVAL = 255;
  44. {$else}
  45. {$ifdef PPM_NORAWWORD}
  46. procedure PUTPPMSAMPLE(var ptr : CharPtr; v : byte);
  47. begin
  48. ptr^ := char (v shr (BITS_IN_JSAMPLE-8));
  49. Inc(ptr);
  50. end;
  51. const
  52. BYTESPERSAMPLE = 1;
  53. PPM_MAXVAL = 255;
  54. {$else}
  55. { The word-per-sample format always puts the LSB first. }
  56. procedure PUTPPMSAMPLE(var ptr : CharPtr; v : int);
  57. var
  58. {register} val_ : int;
  59. begin
  60. val_ := v;
  61. ptr^ := char (val_ and $FF);
  62. Inc(ptr);
  63. ptr^ := char ((val_ shr 8) and $FF);
  64. Inc(ptr);
  65. end;
  66. const
  67. BYTESPERSAMPLE = 2;
  68. PPM_MAXVAL = (1 shl BITS_IN_JSAMPLE)-1;
  69. {$endif}
  70. {$endif}
  71. { When JSAMPLE is the same size as char, we can just fwrite() the
  72. decompressed data to the PPM or PGM file. On PCs, in order to make this
  73. work the output buffer must be allocated in near data space, because we are
  74. assuming small-data memory model wherein fwrite() can't reach far memory.
  75. If you need to process very wide images on a PC, you might have to compile
  76. in large-memory model, or else replace fwrite() with a putc() loop ---
  77. which will be much slower. }
  78. { Private version of data destination object }
  79. type
  80. ppm_dest_ptr = ^ppm_dest_struct;
  81. ppm_dest_struct = record
  82. pub : djpeg_dest_struct; { public fields }
  83. { Usually these two pointers point to the same place: }
  84. iobuffer : CharPtr; { fwrite's I/O buffer }
  85. pixrow : JSAMPROW; { decompressor output buffer }
  86. buffer_width : size_t; { width of I/O buffer }
  87. samples_per_row : JDIMENSION; { JSAMPLEs per output row }
  88. end;
  89. { Write some pixel data.
  90. In this module rows_supplied will always be 1.
  91. put_pixel_rows handles the "normal" 8-bit case where the decompressor
  92. output buffer is physically the same as the fwrite buffer. }
  93. {METHODDEF}
  94. procedure put_pixel_rows (cinfo : j_decompress_ptr;
  95. dinfo : djpeg_dest_ptr;
  96. rows_supplied : JDIMENSION); far;
  97. var
  98. dest : ppm_dest_ptr;
  99. begin
  100. dest := ppm_dest_ptr(dinfo);
  101. {void} JFWRITE(dest^.pub.output_file, dest^.iobuffer, dest^.buffer_width);
  102. end;
  103. { This code is used when we have to copy the data and apply a pixel
  104. format translation. Typically this only happens in 12-bit mode. }
  105. {METHODDEF}
  106. procedure copy_pixel_rows (cinfo : j_decompress_ptr;
  107. dinfo : djpeg_dest_ptr;
  108. rows_supplied : JDIMENSION); far;
  109. var
  110. dest : ppm_dest_ptr;
  111. {register} bufferptr : CharPtr;
  112. {register} ptr : JSAMPLE_PTR;
  113. {register} col : JDIMENSION;
  114. begin
  115. dest := ppm_dest_ptr(dinfo);
  116. ptr := JSAMPLE_PTR(dest^.pub.buffer^[0]);
  117. bufferptr := dest^.iobuffer;
  118. for col := pred(dest^.samples_per_row) downto 0 do
  119. begin
  120. PUTPPMSAMPLE(bufferptr, GETJSAMPLE(ptr^));
  121. Inc(ptr);
  122. end;
  123. {void} JFWRITE(dest^.pub.output_file, dest^.iobuffer, dest^.buffer_width);
  124. end;
  125. { Write some pixel data when color quantization is in effect.
  126. We have to demap the color index values to straight data. }
  127. {METHODDEF}
  128. procedure put_demapped_rgb (cinfo : j_decompress_ptr;
  129. dinfo : djpeg_dest_ptr;
  130. rows_supplied : JDIMENSION); far;
  131. var
  132. dest : ppm_dest_ptr;
  133. {register} bufferptr : CharPtr;
  134. {register} ptr : JSAMPLE_PTR;
  135. {register} col : JDIMENSION;
  136. {register} pixval : int;
  137. {register} color_map0 : JSAMPROW;
  138. {register} color_map1 : JSAMPROW;
  139. {register} color_map2 : JSAMPROW;
  140. begin
  141. dest := ppm_dest_ptr(dinfo);
  142. ptr := JSAMPLE_PTR(dest^.pub.buffer^[0]);
  143. bufferptr := dest^.iobuffer;
  144. color_map0 := cinfo^.colormap^[0];
  145. color_map1 := cinfo^.colormap^[1];
  146. color_map2 := cinfo^.colormap^[2];
  147. for col := pred(cinfo^.output_width) downto 0 do
  148. begin
  149. pixval := GETJSAMPLE(ptr^);
  150. Inc(ptr);
  151. PUTPPMSAMPLE(bufferptr, GETJSAMPLE(color_map0^[pixval]));
  152. PUTPPMSAMPLE(bufferptr, GETJSAMPLE(color_map1^[pixval]));
  153. PUTPPMSAMPLE(bufferptr, GETJSAMPLE(color_map2^[pixval]));
  154. end;
  155. {void} JFWRITE(dest^.pub.output_file, dest^.iobuffer, dest^.buffer_width);
  156. end;
  157. {METHODDEF}
  158. procedure put_demapped_gray (cinfo : j_decompress_ptr;
  159. dinfo : djpeg_dest_ptr;
  160. rows_supplied : JDIMENSION); far;
  161. var
  162. dest : ppm_dest_ptr;
  163. {register} bufferptr : CharPtr;
  164. {register} ptr : JSAMPLE_PTR;
  165. {register} color_map : JSAMPROW;
  166. {register} col : JDIMENSION;
  167. begin
  168. dest := ppm_dest_ptr(dinfo);
  169. color_map := cinfo^.colormap^[0];
  170. ptr := JSAMPLE_PTR(dest^.pub.buffer^[0]);
  171. bufferptr := dest^.iobuffer;
  172. for col := pred(cinfo^.output_width) downto 0 do
  173. begin
  174. PUTPPMSAMPLE(bufferptr, GETJSAMPLE(color_map^[GETJSAMPLE(ptr^)]));
  175. Inc(ptr);
  176. end;
  177. {void} JFWRITE(dest^.pub.output_file, dest^.iobuffer, dest^.buffer_width);
  178. end;
  179. { Startup: write the file header. }
  180. {METHODDEF}
  181. procedure start_output_ppm (cinfo : j_decompress_ptr;
  182. dinfo : djpeg_dest_ptr); far;
  183. const
  184. LF = #10;
  185. var
  186. dest : ppm_dest_ptr;
  187. var
  188. header : string[200];
  189. function LongToStr(l : long) : string;
  190. var
  191. helpstr : string[20];
  192. begin
  193. Str(l, helpstr);
  194. LongToStr := helpstr;
  195. end;
  196. begin
  197. dest := ppm_dest_ptr(dinfo);
  198. { Emit file header }
  199. case (cinfo^.out_color_space) of
  200. JCS_GRAYSCALE:
  201. begin
  202. { emit header for raw PGM format }
  203. header := 'P5'+LF+LongToStr(cinfo^.output_width)+' '+
  204. LongToStr(cinfo^.output_height)+LF+
  205. LongToStr(Long(PPM_MAXVAL)) + LF;
  206. JFWRITE(dest^.pub.output_file, @header[1], Length(header));
  207. end;
  208. JCS_RGB:
  209. begin
  210. { emit header for raw PPM format }
  211. header := 'P6'+LF+LongToStr(cinfo^.output_width)+' '+
  212. LongToStr(cinfo^.output_height)+LF+
  213. LongToStr(Long(PPM_MAXVAL)) + LF;
  214. JFWRITE(dest^.pub.output_file, @header[1], Length(header));
  215. end;
  216. else
  217. ERREXIT(j_common_ptr(cinfo), JERR_PPM_COLORSPACE);
  218. end;
  219. end;
  220. { Finish up at the end of the file. }
  221. {METHODDEF}
  222. procedure finish_output_ppm (cinfo : j_decompress_ptr;
  223. dinfo : djpeg_dest_ptr); far;
  224. begin
  225. { Make sure we wrote the output file OK }
  226. {Flush(dinfo^.output_file^);}
  227. if (IOresult <> 0) then
  228. ERREXIT(j_common_ptr(cinfo), JERR_FILE_WRITE);
  229. end;
  230. { The module selection routine for PPM format output. }
  231. {GLOBAL}
  232. function jinit_write_ppm (cinfo : j_decompress_ptr) : djpeg_dest_ptr;
  233. var
  234. dest : ppm_dest_ptr;
  235. begin
  236. { Create module interface object, fill in method pointers }
  237. dest := ppm_dest_ptr (
  238. cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE,
  239. SIZEOF(ppm_dest_struct)) );
  240. dest^.pub.start_output := start_output_ppm;
  241. dest^.pub.finish_output := finish_output_ppm;
  242. { Calculate output image dimensions so we can allocate space }
  243. jpeg_calc_output_dimensions(cinfo);
  244. { Create physical I/O buffer. Note we make this near on a PC. }
  245. dest^.samples_per_row := cinfo^.output_width * cinfo^.out_color_components;
  246. dest^.buffer_width := dest^.samples_per_row * (BYTESPERSAMPLE * SIZEOF(char));
  247. dest^.iobuffer := CharPtr( cinfo^.mem^.alloc_small
  248. (j_common_ptr(cinfo), JPOOL_IMAGE, dest^.buffer_width) );
  249. if (cinfo^.quantize_colors) or (BITS_IN_JSAMPLE <> 8) or
  250. (SIZEOF(JSAMPLE) <> SIZEOF(char)) then
  251. begin
  252. { When quantizing, we need an output buffer for colormap indexes
  253. that's separate from the physical I/O buffer. We also need a
  254. separate buffer if pixel format translation must take place. }
  255. dest^.pub.buffer := cinfo^.mem^.alloc_sarray
  256. (j_common_ptr(cinfo), JPOOL_IMAGE,
  257. cinfo^.output_width * cinfo^.output_components, JDIMENSION(1));
  258. dest^.pub.buffer_height := 1;
  259. if (not cinfo^.quantize_colors) then
  260. dest^.pub.put_pixel_rows := copy_pixel_rows
  261. else
  262. if (cinfo^.out_color_space = JCS_GRAYSCALE) then
  263. dest^.pub.put_pixel_rows := put_demapped_gray
  264. else
  265. dest^.pub.put_pixel_rows := put_demapped_rgb;
  266. end
  267. else
  268. begin
  269. { We will fwrite() directly from decompressor output buffer. }
  270. { Synthesize a JSAMPARRAY pointer structure }
  271. { Cast here implies near^.far pointer conversion on PCs }
  272. dest^.pixrow := JSAMPROW(dest^.iobuffer);
  273. dest^.pub.buffer := JSAMPARRAY (@dest^.pixrow);
  274. dest^.pub.buffer_height := 1;
  275. dest^.pub.put_pixel_rows := put_pixel_rows;
  276. end;
  277. jinit_write_ppm := djpeg_dest_ptr(dest);
  278. end;
  279. end.