mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-07-12 16:45:59 +02:00
286 lines
8.4 KiB
ObjectPascal
286 lines
8.4 KiB
ObjectPascal
Unit wrtarga;
|
|
|
|
{ Copyright (C) 1991-1996, Thomas G. Lane.
|
|
Based on code contributed by Lee Daniel Crocker.
|
|
|
|
This file contains routines to write output images in Targa format. }
|
|
|
|
interface
|
|
|
|
{$I jconfig.inc}
|
|
|
|
uses
|
|
jmorecfg,
|
|
jpeglib,
|
|
jdeferr,
|
|
jerror,
|
|
jinclude,
|
|
jdmaster,
|
|
cdjpeg; { Common decls for cjpeg/djpeg applications }
|
|
|
|
function jinit_write_targa (cinfo : j_decompress_ptr) : djpeg_dest_ptr;
|
|
|
|
implementation
|
|
|
|
{ To support 12-bit JPEG data, we'd have to scale output down to 8 bits.
|
|
This is not yet implemented. }
|
|
|
|
{$ifndef BITS_IN_JSAMPLE_IS_8}
|
|
Sorry, this code only copes with 8-bit JSAMPLEs. { deliberate syntax err }
|
|
{$endif}
|
|
|
|
{ The output buffer needs to be writable by fwrite(). On PCs, we must
|
|
allocate the buffer in near data space, because we are assuming small-data
|
|
memory model, wherein fwrite() can't reach far memory. If you need to
|
|
process very wide images on a PC, you might have to compile in large-memory
|
|
model, or else replace fwrite() with a putc() loop --- which will be much
|
|
slower. }
|
|
|
|
|
|
{ Private version of data destination object }
|
|
|
|
type
|
|
tga_dest_ptr = ^tga_dest_struct;
|
|
tga_dest_struct = record
|
|
pub : djpeg_dest_struct; { public fields }
|
|
|
|
iobuffer : byteptr; { physical I/O buffer }
|
|
buffer_width : JDIMENSION; { width of one row }
|
|
end;
|
|
|
|
{LOCAL}
|
|
procedure write_header (cinfo : j_decompress_ptr;
|
|
dinfo : djpeg_dest_ptr;
|
|
num_colors : int);
|
|
{ Create and write a Targa header }
|
|
var
|
|
targaheader : array[0..18-1] of byte;
|
|
begin
|
|
{ Set unused fields of header to 0 }
|
|
MEMZERO(@targaheader, SIZEOF(targaheader));
|
|
|
|
if (num_colors > 0) then
|
|
begin
|
|
targaheader[1] := 1; { color map type 1 }
|
|
targaheader[5] := byte (num_colors and $FF);
|
|
targaheader[6] := byte (num_colors shr 8);
|
|
targaheader[7] := 24; { 24 bits per cmap entry }
|
|
end;
|
|
|
|
targaheader[12] := byte (cinfo^.output_width and $FF);
|
|
targaheader[13] := byte (cinfo^.output_width shr 8);
|
|
targaheader[14] := byte (cinfo^.output_height and $FF);
|
|
targaheader[15] := byte (cinfo^.output_height shr 8);
|
|
targaheader[17] := $20; { Top-down, non-interlaced }
|
|
|
|
if (cinfo^.out_color_space = JCS_GRAYSCALE) then
|
|
begin
|
|
targaheader[2] := 3; { image type := uncompressed gray-scale }
|
|
targaheader[16] := 8; { bits per pixel }
|
|
end
|
|
else
|
|
begin { must be RGB }
|
|
if (num_colors > 0) then
|
|
begin
|
|
targaheader[2] := 1; { image type = colormapped RGB }
|
|
targaheader[16] := 8;
|
|
end
|
|
else
|
|
begin
|
|
targaheader[2] := 2; { image type = uncompressed RGB }
|
|
targaheader[16] := 24;
|
|
end;
|
|
end;
|
|
|
|
if (JFWRITE(dinfo^.output_file, @targaheader, 18) <> size_t (18)) then
|
|
ERREXIT(j_common_ptr(cinfo), JERR_FILE_WRITE);
|
|
end;
|
|
|
|
{ Write some pixel data.
|
|
In this module rows_supplied will always be 1. }
|
|
|
|
{METHODDEF}
|
|
procedure put_pixel_rows (cinfo : j_decompress_ptr;
|
|
dinfo : djpeg_dest_ptr;
|
|
rows_supplied : JDIMENSION); far;
|
|
{ used for unquantized full-color output }
|
|
var
|
|
dest : tga_dest_ptr;
|
|
{register} inptr : RGBptr;
|
|
{register} outptr : BGRptr;
|
|
{register} col : JDIMENSION;
|
|
begin
|
|
dest := tga_dest_ptr (dinfo);
|
|
|
|
inptr := RGBptr(dest^.pub.buffer^[0]);
|
|
outptr := BGRptr(dest^.iobuffer);
|
|
for col := pred(cinfo^.output_width) downto 0 do
|
|
begin
|
|
outptr^.b := byte (GETJSAMPLE(inptr^.b)); { RGB to BGR order }
|
|
outptr^.g := byte (GETJSAMPLE(inptr^.g));
|
|
outptr^.r := byte (GETJSAMPLE(inptr^.r));
|
|
Inc(inptr);
|
|
Inc(outptr);
|
|
end;
|
|
{void} JFWRITE(dest^.pub.output_file, dest^.iobuffer, dest^.buffer_width);
|
|
end;
|
|
|
|
{METHODDEF}
|
|
procedure put_gray_rows (cinfo : j_decompress_ptr;
|
|
dinfo : djpeg_dest_ptr;
|
|
rows_supplied : JDIMENSION); far;
|
|
{ used for grayscale OR quantized color output }
|
|
var
|
|
dest : tga_dest_ptr;
|
|
{register} inptr : JSAMPLE_PTR;
|
|
{register} outptr : byteptr;
|
|
{register} col : JDIMENSION;
|
|
begin
|
|
dest := tga_dest_ptr (dinfo);
|
|
|
|
inptr := JSAMPLE_PTR(dest^.pub.buffer^[0]);
|
|
outptr := dest^.iobuffer;
|
|
for col := pred(cinfo^.output_width) downto 0 do
|
|
begin
|
|
outptr^ := byte( GETJSAMPLE(inptr^) );
|
|
Inc(inptr);
|
|
Inc(outptr);
|
|
end;
|
|
{void} JFWRITE(dest^.pub.output_file, dest^.iobuffer, dest^.buffer_width);
|
|
end;
|
|
|
|
|
|
{ Write some demapped pixel data when color quantization is in effect.
|
|
For Targa, this is only applied to grayscale data. }
|
|
|
|
{METHODDEF}
|
|
procedure put_demapped_gray (cinfo : j_decompress_ptr;
|
|
dinfo : djpeg_dest_ptr;
|
|
rows_supplied : JDIMENSION); far;
|
|
var
|
|
dest : tga_dest_ptr;
|
|
{register} inptr : JSAMPLE_PTR;
|
|
{register} outptr : byteptr;
|
|
{register} color_map0 : JSAMPROW;
|
|
{register} col : JDIMENSION;
|
|
begin
|
|
dest := tga_dest_ptr (dinfo);
|
|
color_map0 := cinfo^.colormap^[0];
|
|
|
|
inptr := JSAMPLE_PTR(dest^.pub.buffer^[0]);
|
|
outptr := dest^.iobuffer;
|
|
for col := pred(cinfo^.output_width) downto 0 do
|
|
begin
|
|
outptr^ := byte( GETJSAMPLE(color_map0^[GETJSAMPLE(inptr^)]) );
|
|
Inc(inptr);
|
|
Inc(outptr);
|
|
end;
|
|
{void} JFWRITE(dest^.pub.output_file, dest^.iobuffer, dest^.buffer_width);
|
|
end;
|
|
|
|
|
|
{ Startup: write the file header. }
|
|
|
|
{METHODDEF}
|
|
procedure start_output_tga (cinfo : j_decompress_ptr;
|
|
dinfo : djpeg_dest_ptr); far;
|
|
var
|
|
dest : tga_dest_ptr;
|
|
num_colors, i : int;
|
|
outfile : FILEptr;
|
|
var
|
|
output_color_map : Array[0..255] of BGRtype;
|
|
begin
|
|
dest := tga_dest_ptr (dinfo);
|
|
|
|
if (cinfo^.out_color_space = JCS_GRAYSCALE) then
|
|
begin
|
|
{ Targa doesn't have a mapped grayscale format, so we will }
|
|
{ demap quantized gray output. Never emit a colormap. }
|
|
write_header(cinfo, dinfo, 0);
|
|
if (cinfo^.quantize_colors) then
|
|
dest^.pub.put_pixel_rows := put_demapped_gray
|
|
else
|
|
dest^.pub.put_pixel_rows := put_gray_rows;
|
|
end
|
|
else
|
|
if (cinfo^.out_color_space = JCS_RGB) then
|
|
begin
|
|
if (cinfo^.quantize_colors) then
|
|
begin
|
|
{ We only support 8-bit colormap indexes, so only 256 colors }
|
|
num_colors := cinfo^.actual_number_of_colors;
|
|
if (num_colors > 256) then
|
|
ERREXIT1(j_common_ptr(cinfo), JERR_TOO_MANY_COLORS, num_colors);
|
|
write_header(cinfo, dinfo, num_colors);
|
|
{ Write the colormap. Note Targa uses BGR byte order }
|
|
outfile := dest^.pub.output_file;
|
|
for i := 0 to pred(num_colors) do
|
|
begin
|
|
output_color_map[i].b := cinfo^.colormap^[2]^[i];
|
|
output_color_map[i].g := cinfo^.colormap^[1]^[i];
|
|
output_color_map[i].r := cinfo^.colormap^[0]^[i];
|
|
end;
|
|
JFWRITE(outfile, @output_color_map, num_colors*3);
|
|
dest^.pub.put_pixel_rows := put_gray_rows;
|
|
end
|
|
else
|
|
begin
|
|
write_header(cinfo, dinfo, 0);
|
|
dest^.pub.put_pixel_rows := put_pixel_rows;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
ERREXIT(j_common_ptr(cinfo), JERR_TGA_COLORSPACE);
|
|
end;
|
|
end;
|
|
|
|
|
|
{ Finish up at the end of the file. }
|
|
|
|
{METHODDEF}
|
|
procedure finish_output_tga (cinfo : j_decompress_ptr;
|
|
dinfo : djpeg_dest_ptr); far;
|
|
begin
|
|
{ Make sure we wrote the output file OK }
|
|
{fflush(dinfo^.output_file^);
|
|
if (ferror(dinfo^.output_file)) then
|
|
ERREXIT(j_common_ptr(cinfo), JERR_FILE_WRITE);
|
|
}
|
|
end;
|
|
|
|
|
|
{ The module selection routine for Targa format output. }
|
|
|
|
{GLOBAL}
|
|
function jinit_write_targa (cinfo : j_decompress_ptr) : djpeg_dest_ptr;
|
|
var
|
|
dest : tga_dest_ptr;
|
|
begin
|
|
{ Create module interface object, fill in method pointers }
|
|
dest := tga_dest_ptr(
|
|
cinfo^.mem^.alloc_small (j_common_ptr (cinfo), JPOOL_IMAGE,
|
|
SIZEOF(tga_dest_struct)) );
|
|
dest^.pub.start_output := start_output_tga;
|
|
dest^.pub.finish_output := finish_output_tga;
|
|
|
|
{ Calculate output image dimensions so we can allocate space }
|
|
jpeg_calc_output_dimensions(cinfo);
|
|
|
|
{ Create I/O buffer. Note we make this near on a PC. }
|
|
dest^.buffer_width := cinfo^.output_width * cinfo^.output_components;
|
|
dest^.iobuffer := byteptr(
|
|
cinfo^.mem^.alloc_small (j_common_ptr (cinfo), JPOOL_IMAGE,
|
|
size_t (dest^.buffer_width * SIZEOF(byte))));
|
|
|
|
{ Create decompressor output buffer. }
|
|
dest^.pub.buffer := cinfo^.mem^.alloc_sarray
|
|
(j_common_ptr (cinfo), JPOOL_IMAGE, dest^.buffer_width, JDIMENSION (1));
|
|
dest^.pub.buffer_height := 1;
|
|
|
|
jinit_write_targa := djpeg_dest_ptr (dest);
|
|
end;
|
|
|
|
end. { TARGA_SUPPORTED }
|