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