wrbmp.pas 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608
  1. Unit wrbmp;
  2. { Copyright (C) 1994-1996, Thomas G. Lane.
  3. This code contributed by James Arthur Boucher.
  4. This file contains routines to write output images in Microsoft "BMP"
  5. format (MS Windows 3.x and OS/2 1.x flavors).
  6. Either 8-bit colormapped or 24-bit full-color format can be written.
  7. No compression is supported. }
  8. interface
  9. {$I jconfig.inc}
  10. uses
  11. jmorecfg,
  12. jpeglib,
  13. jinclude,
  14. jdeferr,
  15. jerror,
  16. jdmaster,
  17. cdjpeg; { Common decls for cjpeg/djpeg applications }
  18. { The module selection routine for BMP format output. }
  19. {GLOBAL}
  20. function jinit_write_bmp (cinfo : j_decompress_ptr;
  21. is_os2 : boolean) : djpeg_dest_ptr;
  22. implementation
  23. { To support 12-bit JPEG data, we'd have to scale output down to 8 bits.
  24. This is not yet implemented. }
  25. {$ifndef BITS_IN_JSAMPLE_IS_8}
  26. Sorry, this code only copes with 8-bit JSAMPLEs. { deliberate syntax err }
  27. {$endif}
  28. { Since BMP stores scanlines bottom-to-top, we have to invert the image
  29. from JPEG's top-to-bottom order. To do this, we save the outgoing data
  30. in a virtual array during put_pixel_row calls, then actually emit the
  31. BMP file during finish_output. The virtual array contains one JSAMPLE per
  32. pixel if the output is grayscale or colormapped, three if it is full color.}
  33. { Private version of data destination object }
  34. type
  35. bmp_dest_ptr = ^bmp_dest_struct;
  36. bmp_dest_struct = record
  37. pub : djpeg_dest_struct; { public fields }
  38. is_os2 : boolean; { saves the OS2 format request flag }
  39. whole_image : jvirt_sarray_ptr; { needed to reverse row order }
  40. data_width : JDIMENSION; { JSAMPLEs per row }
  41. row_width : JDIMENSION; { physical width of one row in the BMP file }
  42. pad_bytes : int; { number of padding bytes needed per row }
  43. cur_output_row : JDIMENSION; { next row# to write to virtual array }
  44. end;
  45. { Forward declarations }
  46. {LOCAL}
  47. procedure write_colormap(cinfo : j_decompress_ptr;
  48. dest : bmp_dest_ptr;
  49. map_colors : int;
  50. map_entry_size : int); forward;
  51. { Write some pixel data.
  52. In this module rows_supplied will always be 1. }
  53. {METHODDEF}
  54. procedure put_pixel_rows (cinfo : j_decompress_ptr;
  55. dinfo : djpeg_dest_ptr;
  56. rows_supplied : JDIMENSION); far;
  57. { This version is for writing 24-bit pixels }
  58. var
  59. dest : bmp_dest_ptr;
  60. image_ptr : JSAMPARRAY;
  61. {register} inptr : JSAMPLE_PTR;
  62. outptr : BGRptr;
  63. {register} col : JDIMENSION;
  64. pad : int;
  65. begin
  66. dest := bmp_dest_ptr (dinfo);
  67. { Access next row in virtual array }
  68. image_ptr := cinfo^.mem^.access_virt_sarray
  69. (j_common_ptr(cinfo), dest^.whole_image,
  70. dest^.cur_output_row, JDIMENSION (1), TRUE);
  71. Inc(dest^.cur_output_row);
  72. { Transfer data. Note destination values must be in BGR order
  73. (even though Microsoft's own documents say the opposite). }
  74. inptr := JSAMPLE_PTR(dest^.pub.buffer^[0]);
  75. outptr := BGRptr(image_ptr^[0]);
  76. for col := pred(cinfo^.output_width) downto 0 do
  77. begin
  78. outptr^.r := inptr^; { can omit GETJSAMPLE() safely }
  79. Inc(inptr);
  80. outptr^.g := inptr^;
  81. Inc(inptr);
  82. outptr^.b := inptr^;
  83. Inc(inptr);
  84. Inc(outptr);
  85. end;
  86. { Zero out the pad bytes. }
  87. pad := dest^.pad_bytes;
  88. while (pad > 0) do
  89. begin
  90. Dec(pad);
  91. JSAMPLE_PTR(outptr)^ := 0;
  92. Inc(JSAMPLE_PTR(outptr));
  93. end;
  94. end;
  95. {METHODDEF}
  96. procedure put_gray_rows (cinfo : j_decompress_ptr;
  97. dinfo : djpeg_dest_ptr;
  98. rows_supplied : JDIMENSION); far;
  99. { This version is for grayscale OR quantized color output }
  100. var
  101. dest : bmp_dest_ptr;
  102. image_ptr : JSAMPARRAY;
  103. {register} inptr, outptr : JSAMPLE_PTR;
  104. {register} col : JDIMENSION;
  105. pad : int;
  106. begin
  107. dest := bmp_dest_ptr (dinfo);
  108. { Access next row in virtual array }
  109. image_ptr := cinfo^.mem^.access_virt_sarray
  110. (j_common_ptr(cinfo), dest^.whole_image,
  111. dest^.cur_output_row, JDIMENSION (1), TRUE);
  112. Inc(dest^.cur_output_row);
  113. { Transfer data. }
  114. inptr := JSAMPLE_PTR(dest^.pub.buffer^[0]);
  115. outptr := JSAMPLE_PTR(image_ptr^[0]);
  116. for col := pred(cinfo^.output_width) downto 0 do
  117. begin
  118. outptr^ := inptr^; { can omit GETJSAMPLE() safely }
  119. Inc(outptr);
  120. Inc(inptr);
  121. end;
  122. { Zero out the pad bytes. }
  123. pad := dest^.pad_bytes;
  124. while (pad > 0) do
  125. begin
  126. Dec(pad);
  127. outptr^ := 0;
  128. Inc(outptr);
  129. end;
  130. end;
  131. { Startup: normally writes the file header.
  132. In this module we may as well postpone everything until finish_output. }
  133. {METHODDEF}
  134. procedure start_output_bmp (cinfo : j_decompress_ptr;
  135. dinfo : djpeg_dest_ptr); far;
  136. begin
  137. { no work here }
  138. end;
  139. { Finish up at the end of the file.
  140. Here is where we really output the BMP file.
  141. First, routines to write the Windows and OS/2 variants of the file header. }
  142. {LOCAL}
  143. procedure write_bmp_header (cinfo : j_decompress_ptr;
  144. dest : bmp_dest_ptr);
  145. { Write a Windows-style BMP file header, including colormap if needed }
  146. var
  147. bmpfileheader : packed array[0..14-1] of byte;
  148. bmpinfoheader : packed array[0..40-1] of byte;
  149. var
  150. headersize, bfSize : INT32 ;
  151. bits_per_pixel, cmap_entries : int;
  152. begin
  153. { Compute colormap size and total file size }
  154. if (cinfo^.out_color_space = JCS_RGB) then
  155. begin
  156. if (cinfo^.quantize_colors) then
  157. begin
  158. { Colormapped RGB }
  159. bits_per_pixel := 8;
  160. cmap_entries := 256;
  161. end
  162. else
  163. begin
  164. { Unquantized, full color RGB }
  165. bits_per_pixel := 24;
  166. cmap_entries := 0;
  167. end;
  168. end
  169. else
  170. begin
  171. { Grayscale output. We need to fake a 256-entry colormap. }
  172. bits_per_pixel := 8;
  173. cmap_entries := 256;
  174. end;
  175. { File size }
  176. headersize := 14 + 40 + cmap_entries * 4; { Header and colormap }
  177. bfSize := headersize + INT32 (dest^.row_width) * INT32 (cinfo^.output_height);
  178. { Set unused fields of header to 0 }
  179. MEMZERO(@bmpfileheader, SIZEOF(bmpfileheader));
  180. MEMZERO(@bmpinfoheader, SIZEOF(bmpinfoheader));
  181. { Fill the file header }
  182. bmpfileheader[0] := $42; { first 2 bytes are ASCII 'B', 'M' }
  183. bmpfileheader[1] := $4D;
  184. {PUT_4B(bmpfileheader, 2, bfSize);} { bfSize }
  185. bmpfileheader[2] := byte ((bfSize) and $FF);
  186. bmpfileheader[2+1] := byte (((bfSize) shr 8) and $FF);
  187. bmpfileheader[2+2] := byte (((bfSize) shr 16) and $FF);
  188. bmpfileheader[2+3] := byte (((bfSize) shr 24) and $FF);
  189. { we leave bfReserved1 & bfReserved2 = 0 }
  190. {PUT_4B(bmpfileheader, 10, headersize);} { bfOffBits }
  191. bmpfileheader[10] := byte (headersize and $FF);
  192. bmpfileheader[10+1] := byte ((headersize shr 8) and $FF);
  193. bmpfileheader[10+2] := byte ((headersize shr 16) and $FF);
  194. bmpfileheader[10+3] := byte ((headersize shr 24) and $FF);
  195. { Fill the info header (Microsoft calls this a BITMAPINFOHEADER) }
  196. {PUT_2B(bmpinfoheader, 0, 40);} { biSize }
  197. bmpinfoheader[0] := byte ((40) and $FF);
  198. bmpinfoheader[0+1] := byte (((40) shr 8) and $FF);
  199. {PUT_4B(bmpinfoheader, 4, cinfo^.output_width);} { biWidth }
  200. bmpinfoheader[4] := byte ((cinfo^.output_width) and $FF);
  201. bmpinfoheader[4+1] := byte ((cinfo^.output_width shr 8) and $FF);
  202. bmpinfoheader[4+2] := byte ((cinfo^.output_width shr 16) and $FF);
  203. bmpinfoheader[4+3] := byte ((cinfo^.output_width shr 24) and $FF);
  204. {PUT_4B(bmpinfoheader, 8, cinfo^.output_height);} { biHeight }
  205. bmpinfoheader[8] := byte (cinfo^.output_height and $FF);
  206. bmpinfoheader[8+1] := byte ((cinfo^.output_height shr 8) and $FF);
  207. bmpinfoheader[8+2] := byte ((cinfo^.output_height shr 16) and $FF);
  208. bmpinfoheader[8+3] := byte ((cinfo^.output_height shr 24) and $FF);
  209. {PUT_2B(bmpinfoheader, 12, 1);} { biPlanes - must be 1 }
  210. bmpinfoheader[12] := byte (1 and $FF);
  211. bmpinfoheader[12+1] := byte ((1 shr 8) and $FF);
  212. {PUT_2B(bmpinfoheader, 14, bits_per_pixel);} { biBitCount }
  213. bmpinfoheader[14] := byte (bits_per_pixel and $FF);
  214. bmpinfoheader[14+1] := byte ((bits_per_pixel shr 8) and $FF);
  215. { we leave biCompression = 0, for none }
  216. { we leave biSizeImage = 0; this is correct for uncompressed data }
  217. if (cinfo^.density_unit = 2) then
  218. begin { if have density in dots/cm, then }
  219. {PUT_4B(bmpinfoheader, 24, INT32 (cinfo^.X_density*100));} { XPels/M }
  220. bmpinfoheader[24] := byte (INT32 (cinfo^.X_density*100) and $FF);
  221. bmpinfoheader[24+1] := byte ((INT32 (cinfo^.X_density*100) shr 8) and $FF);
  222. bmpinfoheader[24+2] := byte ((INT32 (cinfo^.X_density*100) shr 16) and $FF);
  223. bmpinfoheader[24+3] := byte ((INT32 (cinfo^.X_density*100) shr 24) and $FF);
  224. {PUT_4B(bmpinfoheader, 28, INT32 (cinfo^.Y_density*100));} { XPels/M }
  225. bmpinfoheader[28] := byte (INT32 (cinfo^.Y_density*100) and $FF);
  226. bmpinfoheader[28+1] := byte ((INT32 (cinfo^.Y_density*100) shr 8) and $FF);
  227. bmpinfoheader[28+2] := byte ((INT32 (cinfo^.Y_density*100) shr 16) and $FF);
  228. bmpinfoheader[28+3] := byte ((INT32 (cinfo^.Y_density*100) shr 24) and $FF);
  229. end;
  230. {PUT_2B(bmpinfoheader, 32, cmap_entries);} { biClrUsed }
  231. bmpinfoheader[32] := byte (cmap_entries and $FF);
  232. bmpinfoheader[32+1] := byte ((cmap_entries shr 8) and $FF);
  233. { we leave biClrImportant := 0 }
  234. if (JFWRITE(dest^.pub.output_file, @bmpfileheader, 14) <> size_t (14)) then
  235. ERREXIT(j_common_ptr(cinfo), JERR_FILE_WRITE);
  236. if (JFWRITE(dest^.pub.output_file, @bmpinfoheader, 40) <> size_t (40)) then
  237. ERREXIT(j_common_ptr(cinfo), JERR_FILE_WRITE);
  238. if (cmap_entries > 0) then
  239. write_colormap(cinfo, dest, cmap_entries, 4);
  240. end;
  241. {LOCAL}
  242. procedure write_os2_header (cinfo : j_decompress_ptr;
  243. dest : bmp_dest_ptr);
  244. { Write an OS2-style BMP file header, including colormap if needed }
  245. var
  246. bmpfileheader : array[0..14-1] of byte;
  247. bmpcoreheader : array[0..12-1] of byte;
  248. headersize, bfSize : INT32;
  249. bits_per_pixel, cmap_entries : int;
  250. begin
  251. { Compute colormap size and total file size }
  252. if (cinfo^.out_color_space = JCS_RGB) then
  253. begin
  254. if (cinfo^.quantize_colors) then
  255. begin
  256. { Colormapped RGB }
  257. bits_per_pixel := 8;
  258. cmap_entries := 256;
  259. end
  260. else
  261. begin
  262. { Unquantized, full color RGB }
  263. bits_per_pixel := 24;
  264. cmap_entries := 0;
  265. end;
  266. end
  267. else
  268. begin
  269. { Grayscale output. We need to fake a 256-entry colormap. }
  270. bits_per_pixel := 8;
  271. cmap_entries := 256;
  272. end;
  273. { File size }
  274. headersize := 14 + 12 + cmap_entries * 3; { Header and colormap }
  275. bfSize := headersize + INT32 (dest^.row_width) * INT32 (cinfo^.output_height);
  276. { Set unused fields of header to 0 }
  277. MEMZERO(@bmpfileheader, SIZEOF(bmpfileheader));
  278. MEMZERO(@bmpcoreheader, SIZEOF(bmpcoreheader));
  279. { Fill the file header }
  280. bmpfileheader[0] := $42; { first 2 bytes are ASCII 'B', 'M' }
  281. bmpfileheader[1] := $4D;
  282. {PUT_4B(bmpfileheader, 2, bfSize);} { bfSize }
  283. bmpfileheader[2] := byte ((bfSize) and $FF);
  284. bmpfileheader[2+1] := byte (((bfSize) shr 8) and $FF);
  285. bmpfileheader[2+2] := byte (((bfSize) shr 16) and $FF);
  286. bmpfileheader[2+3] := byte (((bfSize) shr 24) and $FF);
  287. { we leave bfReserved1 & bfReserved2 := 0 }
  288. {PUT_4B(bmpfileheader, 10, headersize);} { bfOffBits }
  289. bmpfileheader[10] := byte ((headersize) and $FF);
  290. bmpfileheader[10+1] := byte (((headersize) shr 8) and $FF);
  291. bmpfileheader[10+2] := byte (((headersize) shr 16) and $FF);
  292. bmpfileheader[10+3] := byte (((headersize) shr 24) and $FF);
  293. { Fill the info header (Microsoft calls this a BITMAPCOREHEADER) }
  294. {PUT_2B(bmpcoreheader, 0, 12);} { bcSize }
  295. bmpcoreheader[0] := byte (12 and $FF);
  296. bmpcoreheader[0+1] := byte ((12 shr 8) and $FF);
  297. {PUT_2B(bmpcoreheader, 4, cinfo^.output_width);} { bcWidth }
  298. bmpcoreheader[4] := byte (cinfo^.output_width and $FF);
  299. bmpcoreheader[4+1] := byte ((cinfo^.output_width shr 8) and $FF);
  300. {PUT_2B(bmpcoreheader, 6, cinfo^.output_height);} { bcHeight }
  301. bmpcoreheader[6] := byte (cinfo^.output_height and $FF);
  302. bmpcoreheader[6+1] := byte ((cinfo^.output_height shr 8) and $FF);
  303. {PUT_2B(bmpcoreheader, 8, 1);} { bcPlanes - must be 1 }
  304. bmpcoreheader[8] := byte (1 and $FF);
  305. bmpcoreheader[8+1] := byte ((1 shr 8) and $FF);
  306. {PUT_2B(bmpcoreheader, 10, bits_per_pixel);} { bcBitCount }
  307. bmpcoreheader[10] := byte (bits_per_pixel and $FF);
  308. bmpcoreheader[10+1] := byte ((bits_per_pixel shr 8) and $FF);
  309. if (JFWRITE(dest^.pub.output_file, @bmpfileheader, 14) <> size_t (14)) then
  310. ERREXIT(j_common_ptr(cinfo), JERR_FILE_WRITE);
  311. if (JFWRITE(dest^.pub.output_file, @bmpcoreheader, 12) <> size_t (12)) then
  312. ERREXIT(j_common_ptr(cinfo), JERR_FILE_WRITE);
  313. if (cmap_entries > 0) then
  314. write_colormap(cinfo, dest, cmap_entries, 3);
  315. end;
  316. { Write the colormap.
  317. Windows uses BGR0 map entries; OS/2 uses BGR entries. }
  318. {LOCAL}
  319. procedure write_colormap (cinfo : j_decompress_ptr;
  320. dest : bmp_dest_ptr;
  321. map_colors : int;
  322. map_entry_size : int);
  323. var
  324. colormap : JSAMPARRAY;
  325. num_colors : int;
  326. outfile : FILEptr;
  327. i : int;
  328. var
  329. output_color_map : Array[0..255] of BGRtype;
  330. output_ext_color_map : Array[0..255] of record
  331. b,g,r,a : byte;
  332. end;
  333. begin
  334. colormap := cinfo^.colormap;
  335. num_colors := cinfo^.actual_number_of_colors;
  336. outfile := dest^.pub.output_file;
  337. if (colormap <> NIL) then
  338. begin
  339. if (cinfo^.out_color_components = 3) then
  340. begin
  341. { Normal case with RGB colormap }
  342. if (map_entry_size = 4) then
  343. for i := 0 to pred(num_colors) do
  344. with output_ext_color_map[i] do
  345. begin
  346. b := GETJSAMPLE(cinfo^.colormap^[2]^[i]);
  347. g := GETJSAMPLE(cinfo^.colormap^[1]^[i]);
  348. r := GETJSAMPLE(cinfo^.colormap^[0]^[i]);
  349. a := 0;
  350. end
  351. else
  352. for i := 0 to pred(num_colors) do
  353. with output_color_map[i] do
  354. begin
  355. b := GETJSAMPLE(cinfo^.colormap^[2]^[i]);
  356. g := GETJSAMPLE(cinfo^.colormap^[1]^[i]);
  357. r := GETJSAMPLE(cinfo^.colormap^[0]^[i]);
  358. end;
  359. end
  360. else
  361. begin
  362. { Grayscale colormap (only happens with grayscale quantization) }
  363. if (map_entry_size = 4) then
  364. for i := 0 to pred(num_colors) do
  365. with output_ext_color_map[i] do
  366. begin
  367. b := GETJSAMPLE(cinfo^.colormap^[0]^[i]);
  368. g := GETJSAMPLE(cinfo^.colormap^[0]^[i]);
  369. r := GETJSAMPLE(cinfo^.colormap^[0]^[i]);
  370. a := 0;
  371. end
  372. else
  373. for i := 0 to pred(num_colors) do
  374. with output_color_map[i] do
  375. begin
  376. b := GETJSAMPLE(cinfo^.colormap^[0]^[i]);
  377. g := GETJSAMPLE(cinfo^.colormap^[0]^[i]);
  378. r := GETJSAMPLE(cinfo^.colormap^[0]^[i]);
  379. end;
  380. end;
  381. i := num_colors;
  382. end
  383. else
  384. begin
  385. { If no colormap, must be grayscale data. Generate a linear "map". }
  386. { Nomssi: do not use "num_colors" here, it should be 0 }
  387. if (map_entry_size = 4) then
  388. for i := 0 to pred(256) do
  389. with output_ext_color_map[i] do
  390. begin
  391. b := i;
  392. g := i;
  393. r := i;
  394. a := 0;
  395. end
  396. else
  397. for i := 0 to pred(256) do
  398. with output_color_map[i] do
  399. begin
  400. b := i;
  401. g := i;
  402. r := i;
  403. end;
  404. i := 256;
  405. end;
  406. { Pad colormap with zeros to ensure specified number of colormap entries }
  407. if (i > map_colors) then
  408. ERREXIT1(j_common_ptr(cinfo), JERR_TOO_MANY_COLORS, i);
  409. while (i < map_colors) do
  410. begin
  411. if (map_entry_size = 4) then
  412. with output_ext_color_map[i] do
  413. begin
  414. b := 0;
  415. g := 0;
  416. r := 0;
  417. a := 0;
  418. end
  419. else
  420. with output_color_map[i] do
  421. begin
  422. b := 0;
  423. g := 0;
  424. r := 0;
  425. end;
  426. Inc(i);
  427. end;
  428. if (map_entry_size = 4) then
  429. JFWRITE(outfile, @output_ext_color_map, map_colors*4)
  430. else
  431. JFWRITE(outfile, @output_color_map, map_colors*3);
  432. end;
  433. {METHODDEF}
  434. procedure finish_output_bmp (cinfo : j_decompress_ptr;
  435. dinfo : djpeg_dest_ptr); far;
  436. var
  437. dest : bmp_dest_ptr;
  438. {register} outfile : FILEptr;
  439. image_ptr : JSAMPARRAY;
  440. {register} data_ptr : JSAMPLE_PTR;
  441. row : JDIMENSION;
  442. {register} { col : JDIMENSION; }
  443. progress : cd_progress_ptr;
  444. begin
  445. dest := bmp_dest_ptr (dinfo);
  446. outfile := dest^.pub.output_file;
  447. progress := cd_progress_ptr (cinfo^.progress);
  448. { Write the header and colormap }
  449. if (dest^.is_os2) then
  450. write_os2_header(cinfo, dest)
  451. else
  452. write_bmp_header(cinfo, dest);
  453. { Write the file body from our virtual array }
  454. for row := cinfo^.output_height downto 1 do
  455. begin
  456. if (progress <> NIL) then
  457. begin
  458. progress^.pub.pass_counter := long (cinfo^.output_height - row);
  459. progress^.pub.pass_limit := long (cinfo^.output_height);
  460. progress^.pub.progress_monitor (j_common_ptr(cinfo));
  461. end;
  462. image_ptr := cinfo^.mem^.access_virt_sarray
  463. (j_common_ptr(cinfo), dest^.whole_image, row-1, JDIMENSION(1), FALSE);
  464. data_ptr := JSAMPLE_PTR(image_ptr^[0]);
  465. { Nomssi - This won't work for 12bit samples }
  466. JFWRITE(outfile, data_ptr, dest^.row_width);
  467. {
  468. for col := pred(dest^.row_width) downto 0 do
  469. begin
  470. putc(GETJSAMPLE(data_ptr^), outfile);
  471. Inc(data_ptr);
  472. end;
  473. }
  474. end;
  475. if (progress <> NIL) then
  476. Inc(progress^.completed_extra_passes);
  477. { Make sure we wrote the output file OK }
  478. {fflush(outfile);
  479. if (ferror(outfile)) then
  480. ERREXIT(cinfo, JERR_FILE_WRITE);}
  481. end;
  482. { The module selection routine for BMP format output. }
  483. {GLOBAL}
  484. function jinit_write_bmp (cinfo : j_decompress_ptr;
  485. is_os2 : boolean) : djpeg_dest_ptr;
  486. var
  487. dest : bmp_dest_ptr;
  488. row_width : JDIMENSION;
  489. var
  490. progress : cd_progress_ptr;
  491. begin
  492. { Create module interface object, fill in method pointers }
  493. dest := bmp_dest_ptr (
  494. cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE,
  495. SIZEOF(bmp_dest_struct)) );
  496. dest^.pub.start_output := start_output_bmp;
  497. dest^.pub.finish_output := finish_output_bmp;
  498. dest^.is_os2 := is_os2;
  499. if (cinfo^.out_color_space = JCS_GRAYSCALE) then
  500. begin
  501. dest^.pub.put_pixel_rows := put_gray_rows;
  502. end
  503. else
  504. if (cinfo^.out_color_space = JCS_RGB) then
  505. begin
  506. if (cinfo^.quantize_colors) then
  507. dest^.pub.put_pixel_rows := put_gray_rows
  508. else
  509. dest^.pub.put_pixel_rows := put_pixel_rows;
  510. end
  511. else
  512. ERREXIT(j_common_ptr(cinfo), JERR_BMP_COLORSPACE);
  513. { Calculate output image dimensions so we can allocate space }
  514. jpeg_calc_output_dimensions(cinfo);
  515. { Determine width of rows in the BMP file (padded to 4-byte boundary). }
  516. row_width := cinfo^.output_width * cinfo^.output_components;
  517. dest^.data_width := row_width;
  518. while ((row_width and 3) <> 0) do
  519. Inc(row_width);
  520. dest^.row_width := row_width;
  521. dest^.pad_bytes := int (row_width - dest^.data_width);
  522. { Allocate space for inversion array, prepare for write pass }
  523. dest^.whole_image := cinfo^.mem^.request_virt_sarray
  524. (j_common_ptr(cinfo), JPOOL_IMAGE, FALSE,
  525. row_width, cinfo^.output_height, JDIMENSION (1));
  526. dest^.cur_output_row := 0;
  527. if (cinfo^.progress <> NIL) then
  528. begin
  529. progress := cd_progress_ptr (cinfo^.progress);
  530. Inc(progress^.total_extra_passes); { count file input as separate pass }
  531. end;
  532. { Create decompressor output buffer. }
  533. dest^.pub.buffer := cinfo^.mem^.alloc_sarray
  534. (j_common_ptr(cinfo), JPOOL_IMAGE, row_width, JDIMENSION (1));
  535. dest^.pub.buffer_height := 1;
  536. jinit_write_bmp := djpeg_dest_ptr(dest);
  537. end;
  538. end. { BMP_SUPPORTED }