PageRenderTime 22ms CodeModel.GetById 17ms app.highlight 2ms RepoModel.GetById 0ms app.codeStats 1ms

/packages/pasjpeg/examples/rdtarga.pas

https://github.com/slibre/freepascal
Pascal | 559 lines | 387 code | 80 blank | 92 comment | 27 complexity | 62fa236ed644c100dad19916c259f715 MD5 | raw file
Possible License(s): LGPL-2.0, LGPL-2.1, LGPL-3.0
  1Unit RdTarga;
  2
  3{ rdtarga.c ;  Copyright (C) 1991-1996, Thomas G. Lane.
  4
  5  These routines may need modification for non-Unix environments or
  6  specialized applications.  As they stand, they assume input from
  7  an ordinary stdio stream.  They further assume that reading begins
  8  at the start of the file; start_input may need work if the
  9  user interface has already read some data (e.g., to determine that
 10  the file is indeed Targa format).
 11
 12  Based on code contributed by Lee Daniel Crocker. }
 13
 14interface
 15
 16{$I jconfig.inc}
 17
 18uses
 19  jmorecfg,
 20  jpeglib,
 21  jinclude,
 22  jdeferr,
 23  jerror,
 24  cdjpeg;               { Common decls for cjpeg/djpeg applications }
 25
 26
 27{ The module selection routine for Targa format input. }
 28
 29{GLOBAL}
 30function jinit_read_targa (cinfo : j_compress_ptr) : cjpeg_source_ptr;
 31
 32implementation
 33
 34{ Macros to deal with unsigned chars as efficiently as compiler allows }
 35
 36type
 37  U_CHAR = byte;
 38  UCH = int;
 39(*type
 40{$ifdef CHAR_IS_UNSIGNED}
 41  UCH = int;
 42{$else}
 43  UCH = int (x and $FF);
 44{$endif}
 45*)
 46{ Private version of data source object }
 47
 48type
 49  tga_source_ptr = ^tga_source_struct;
 50  tga_source_struct = record
 51    pub : cjpeg_source_struct; { public fields }
 52
 53    cinfo : j_compress_ptr;             { back link saves passing separate parm }
 54
 55    colormap : JSAMPARRAY;              { Targa colormap (converted to my format) }
 56
 57    whole_image : jvirt_sarray_ptr;     { Needed if funny input row order }
 58    current_row : JDIMENSION;           { Current logical row number to read }
 59
 60    { Pointer to routine to extract next Targa pixel from input file }
 61    read_pixel : procedure (sinfo : tga_source_ptr);
 62
 63    { Result of read_pixel is delivered here: }
 64    tga_pixel : array[0..4-1] of U_CHAR;
 65
 66    pixel_size : int;                   { Bytes per Targa pixel (1 to 4) }
 67
 68    { State info for reading RLE-coded pixels; both counts must be init to 0 }
 69    block_count : int;          { # of pixels remaining in RLE block }
 70    dup_pixel_count : int;      { # of times to duplicate previous pixel }
 71
 72    { This saves the correct pixel-row-expansion method for preload_image }
 73    get_pixel_rows : function(cinfo : j_compress_ptr;
 74                              sinfo : cjpeg_source_ptr) : JDIMENSION;
 75  end;
 76
 77{ For expanding 5-bit pixel values to 8-bit with best rounding }
 78
 79const
 80  c5to8bits : array[0..32-1] of UINT8 =
 81               (  0,   8,  16,  25,  33,  41,  49,  58,
 82                 66,  74,  82,  90,  99, 107, 115, 123,
 83                132, 140, 148, 156, 165, 173, 181, 189,
 84                197, 206, 214, 222, 230, 239, 247, 255);
 85
 86function getc(f : fileptr) : byte;
 87begin
 88  getc := 0;
 89end;
 90const
 91  EOF = byte(26);  { ^Z }
 92
 93{LOCAL}
 94function read_byte (sinfo : tga_source_ptr) : int;
 95{ Read next byte from Targa file }
 96var
 97  {register} infile : FILEptr;
 98  {register} c : int;
 99begin
100  infile := sinfo^.pub.input_file;
101  c := getc(infile);
102  if (c = EOF) then
103    ERREXIT(j_common_ptr(sinfo^.cinfo), JERR_INPUT_EOF);
104  read_byte := c;
105end;
106
107
108{LOCAL}
109procedure read_colormap (sinfo : tga_source_ptr;
110                         cmaplen : int;
111                         mapentrysize : int);
112{ Read the colormap from a Targa file }
113var
114  i : int;
115begin
116  { Presently only handles 24-bit BGR format }
117  if (mapentrysize <> 24) then
118    ERREXIT(j_common_ptr(sinfo^.cinfo), JERR_TGA_BADCMAP);
119
120  for i := 0 to pred(cmaplen) do
121  begin
122    sinfo^.colormap^[2]^[i] := JSAMPLE (read_byte(sinfo));
123    sinfo^.colormap^[1]^[i] := JSAMPLE (read_byte(sinfo));
124    sinfo^.colormap^[0]^[i] := JSAMPLE (read_byte(sinfo));
125  end;
126end;
127
128
129{ read_pixel methods: get a single pixel from Targa file into tga_pixel[] }
130
131{METHODDEF}
132procedure read_non_rle_pixel (sinfo : tga_source_ptr); far;
133{ Read one Targa pixel from the input file; no RLE expansion }
134var
135  {register} infile : FILEptr;
136  {register} i : int;
137begin
138  infile := sinfo^.pub.input_file;
139  for i := 0 to pred(sinfo^.pixel_size) do
140  begin
141    sinfo^.tga_pixel[i] := U_CHAR (getc(infile));
142  end;
143end;
144
145
146{METHODDEF}
147procedure read_rle_pixel (sinfo : tga_source_ptr); far;
148{ Read one Targa pixel from the input file, expanding RLE data as needed }
149var
150  {register} infile : FILEptr;
151  {register} i : int;
152begin
153  infile := sinfo^.pub.input_file;
154
155  { Duplicate previously read pixel? }
156  if (sinfo^.dup_pixel_count > 0) then
157  begin
158    Dec(sinfo^.dup_pixel_count);
159    exit;
160  end;
161
162  { Time to read RLE block header? }
163  Dec(sinfo^.block_count);
164  if (sinfo^.block_count < 0) then
165  begin { decrement pixels remaining in block }
166    i := read_byte(sinfo);
167    if (i and $80) <> 0 then
168    begin               { Start of duplicate-pixel block? }
169      sinfo^.dup_pixel_count := i and $7F; { number of dups after this one }
170      sinfo^.block_count := 0;  { then read new block header }
171    end
172    else
173    begin
174      sinfo^.block_count := i and $7F; { number of pixels after this one }
175    end;
176  end;
177
178  { Read next pixel }
179  for i := 0 to pred(sinfo^.pixel_size) do
180  begin
181    sinfo^.tga_pixel[i] := U_CHAR (getc(infile));
182  end;
183end;
184
185
186{ Read one row of pixels.
187
188  We provide several different versions depending on input file format. }
189
190{METHODDEF}
191function get_8bit_gray_row (cinfo : j_compress_ptr;
192                            sinfo : cjpeg_source_ptr) : JDIMENSION; far;
193{ This version is for reading 8-bit grayscale pixels }
194var
195  source : tga_source_ptr;
196  {register} ptr : JSAMPLE_PTR;
197  {register} col : JDIMENSION;
198begin
199  source := tga_source_ptr (sinfo);
200  ptr := JSAMPLE_PTR(source^.pub.buffer^[0]);
201  for col := pred(cinfo^.image_width) downto 0 do
202  begin
203    source^.read_pixel (source); { Load next pixel into tga_pixel }
204    ptr^ := JSAMPLE (UCH(source^.tga_pixel[0]));
205    Inc(ptr);
206  end;
207  get_8bit_gray_row  := 1;
208end;
209
210{METHODDEF}
211function get_8bit_row (cinfo : j_compress_ptr;
212                       sinfo : cjpeg_source_ptr) : JDIMENSION; far;
213{ This version is for reading 8-bit colormap indexes }
214var
215  source : tga_source_ptr;
216  {register} t : int;
217  {register} ptr : JSAMPLE_PTR;
218  {register} col : JDIMENSION;
219  {register} colormap : JSAMPARRAY;
220begin
221  source := tga_source_ptr (sinfo);
222  colormap := source^.colormap;
223
224  ptr := JSAMPLE_PTR(source^.pub.buffer^[0]);
225  for col := pred(cinfo^.image_width) downto 0 do
226  begin
227    source^.read_pixel (source); { Load next pixel into tga_pixel }
228    t := UCH(source^.tga_pixel[0]);
229    ptr^ := colormap^[0]^[t];
230    Inc(ptr);
231    ptr^ := colormap^[1]^[t];
232    Inc(ptr);
233    ptr^ := colormap^[2]^[t];
234    Inc(ptr);
235  end;
236  get_8bit_row  := 1;
237end;
238
239{METHODDEF}
240function get_16bit_row (cinfo : j_compress_ptr;
241                        sinfo : cjpeg_source_ptr) : JDIMENSION; far;
242{ This version is for reading 16-bit pixels }
243var
244  source : tga_source_ptr;
245
246  {register} t : int;
247  {register} ptr : JSAMPROW;
248  {register} col : JDIMENSION;
249begin
250  source := tga_source_ptr (sinfo);
251
252  ptr := source^.pub.buffer^[0];
253  for col := pred(cinfo^.image_width) downto 0 do
254  begin
255    source^.read_pixel (source); { Load next pixel into tga_pixel }
256    t := UCH(source^.tga_pixel[0]);
257    Inc(t, UCH(source^.tga_pixel[1]) shr 8);
258    { We expand 5 bit data to 8 bit sample width.
259      The format of the 16-bit (LSB first) input word is
260          xRRRRRGGGGGBBBBB
261     }
262    ptr^[2] := JSAMPLE (c5to8bits[t and $1F]);
263    t := t shr 5;
264    ptr^[1] := JSAMPLE (c5to8bits[t and $1F]);
265    t := t shr 5;
266    ptr^[0] := JSAMPLE (c5to8bits[t and $1F]);
267    Inc(JSAMPLE_PTR(ptr), 3);
268  end;
269  get_16bit_row  :=1;
270end;
271
272{METHODDEF}
273function get_24bit_row (cinfo : j_compress_ptr;
274                        sinfo : cjpeg_source_ptr) : JDIMENSION; far;
275{ This version is for reading 24-bit pixels }
276var
277  source : tga_source_ptr;
278
279  {register} ptr : JSAMPLE_PTR;
280  {register} col : JDIMENSION;
281begin
282  source := tga_source_ptr (sinfo);
283  ptr := JSAMPLE_PTR(source^.pub.buffer^[0]);
284  for col := pred(cinfo^.image_width) downto 0 do
285  begin
286    source^.read_pixel (source); { Load next pixel into tga_pixel }
287    ptr^ := JSAMPLE (UCH(source^.tga_pixel[2])); { change BGR to RGB order }
288    Inc(ptr);
289    ptr^ := JSAMPLE (UCH(source^.tga_pixel[1]));
290    Inc(ptr);
291    ptr^ := JSAMPLE (UCH(source^.tga_pixel[0]));
292    Inc(ptr);
293  end;
294  get_24bit_row := 1;
295end;
296
297{ Targa also defines a 32-bit pixel format with order B,G,R,A.
298  We presently ignore the attribute byte, so the code for reading
299  these pixels is identical to the 24-bit routine above.
300  This works because the actual pixel length is only known to read_pixel. }
301
302const
303  get_32bit_row : function (cinfo : j_compress_ptr;
304                          sinfo : cjpeg_source_ptr) : JDIMENSION
305   = get_24bit_row;
306
307
308{ This method is for re-reading the input data in standard top-down
309  row order.  The entire image has already been read into whole_image
310  with proper conversion of pixel format, but it's in a funny row order. }
311
312{METHODDEF}
313function get_memory_row (cinfo : j_compress_ptr;
314                         sinfo : cjpeg_source_ptr) : JDIMENSION; far;
315var
316  source : tga_source_ptr;
317  source_row : JDIMENSION;
318begin
319  source := tga_source_ptr (sinfo);
320  { Compute row of source that maps to current_row of normal order }
321  { For now, assume image is bottom-up and not interlaced. }
322  { NEEDS WORK to support interlaced images! }
323  source_row := cinfo^.image_height - source^.current_row - 1;
324
325  { Fetch that row from virtual array }
326  source^.pub.buffer := cinfo^.mem^.access_virt_sarray
327                        (j_common_ptr (cinfo), source^.whole_image,
328                        source_row, JDIMENSION (1), FALSE);
329
330  Inc(source^.current_row);
331  get_memory_row := 1;
332end;
333
334
335{ This method loads the image into whole_image during the first call on
336  get_pixel_rows.  The get_pixel_rows pointer is then adjusted to call
337  get_memory_row on subsequent calls. }
338
339{METHODDEF}
340function preload_image (cinfo : j_compress_ptr;
341                        sinfo : cjpeg_source_ptr) : JDIMENSION; far;
342var
343  source : tga_source_ptr;
344  row : JDIMENSION;
345  progress : cd_progress_ptr;
346begin
347  source := tga_source_ptr (sinfo);
348  progress := cd_progress_ptr (cinfo^.progress);
349
350  { Read the data into a virtual array in input-file row order. }
351  for row := 0 to pred(cinfo^.image_height) do
352  begin
353    if (progress <> NIL) then
354    begin
355      progress^.pub.pass_counter := long (row);
356      progress^.pub.pass_limit := long (cinfo^.image_height);
357      progress^.pub.progress_monitor (j_common_ptr (cinfo));
358    end;
359    source^.pub.buffer := cinfo^.mem^.access_virt_sarray
360      (j_common_ptr(cinfo), source^.whole_image, row, JDIMENSION(1), TRUE);
361    source^.get_pixel_rows (cinfo, sinfo);
362  end;
363  if (progress <> NIL) then
364    Inc(progress^.completed_extra_passes);
365
366  { Set up to read from the virtual array in unscrambled order }
367  source^.pub.get_pixel_rows := get_memory_row;
368  source^.current_row := 0;
369  { And read the first row }
370  preload_image := get_memory_row(cinfo, sinfo);
371end;
372
373
374{ Read the file header; return image size and component count. }
375
376{METHODDEF}
377procedure start_input_tga (cinfo : j_compress_ptr;
378                           sinfo : cjpeg_source_ptr); far;
379var
380  source : tga_source_ptr;
381  targaheader : array[0..18-1] of U_CHAR;
382  idlen, cmaptype, subtype, flags, interlace_type, components : int;
383  width, height, maplen : uInt;
384  is_bottom_up : boolean;
385var
386  progress : cd_progress_ptr;
387begin
388  source := tga_source_ptr (sinfo);
389
390  if JFREAD(source^.pub.input_file, @targaheader, 18) <> size_t(18) then
391    ERREXIT(j_common_ptr(cinfo), JERR_INPUT_EOF);
392
393  { Pretend "15-bit" pixels are 16-bit --- we ignore attribute bit anyway }
394  if (targaheader[16] = 15) then
395    targaheader[16] := 16;
396
397  idlen := UCH(targaheader[0]);
398  cmaptype := UCH(targaheader[1]);
399  subtype := UCH(targaheader[2]);
400  maplen := {GET_2B(5);}
401            uInt (UCH(targaheader[5])) +
402            ( uInt (UCH(targaheader[5+1])) ) shl 8;
403  width := {GET_2B(12);}
404           ( uInt(UCH(targaheader[12])) +
405           ( uInt(UCH(targaheader[12+1])) ) shl 8);
406  height := {GET_2B(14);}
407           ( uInt(UCH(targaheader[14])) +
408           ( uInt(UCH(targaheader[14+1])) ) shl 8);
409
410  source^.pixel_size := UCH(targaheader[16]) shl 3;
411  flags := UCH(targaheader[17]);        { Image Descriptor byte }
412
413  is_bottom_up := (flags and $20) = 0;  { bit 5 set => top-down }
414  interlace_type := flags shl 6;        { bits 6/7 are interlace code }
415
416  if (cmaptype > 1) or                  { cmaptype must be 0 or 1 }
417     (source^.pixel_size < 1) or (source^.pixel_size > 4) or
418     ((UCH(targaheader[16]) and 7) <> 0) or { bits/pixel must be multiple of 8 }
419     (interlace_type <> 0) then  { currently don't allow interlaced image }
420    ERREXIT(j_common_ptr(cinfo), JERR_TGA_BADPARMS);
421
422  if (subtype > 8) then
423  begin
424    { It's an RLE-coded file }
425    source^.read_pixel := read_rle_pixel;
426    source^.block_count := 0;
427    source^.dup_pixel_count := 0;
428    Dec(subtype, 8);
429  end
430  else
431  begin
432    { Non-RLE file }
433    source^.read_pixel := read_non_rle_pixel;
434  end;
435
436  { Now should have subtype 1, 2, or 3 }
437  components := 3;              { until proven different }
438  cinfo^.in_color_space := JCS_RGB;
439
440  case (subtype) of
441  1:begin  { Colormapped image }
442      if (source^.pixel_size = 1) and (cmaptype = 1) then
443        source^.get_pixel_rows := get_8bit_row
444      else
445        ERREXIT(j_common_ptr(cinfo), JERR_TGA_BADPARMS);
446      TRACEMS2(j_common_ptr(cinfo), 1, JTRC_TGA_MAPPED, width, height);
447    end;
448  2:begin  { RGB image }
449      case (source^.pixel_size) of
450      2: source^.get_pixel_rows := get_16bit_row;
451      3: source^.get_pixel_rows := get_24bit_row;
452      4: source^.get_pixel_rows := get_32bit_row;
453      else
454        ERREXIT(j_common_ptr(cinfo), JERR_TGA_BADPARMS);
455      end;
456      TRACEMS2(j_common_ptr(cinfo), 1, JTRC_TGA, width, height);
457    end;
458  3:begin       { Grayscale image }
459      components := 1;
460      cinfo^.in_color_space := JCS_GRAYSCALE;
461      if (source^.pixel_size = 1) then
462        source^.get_pixel_rows := get_8bit_gray_row
463      else
464        ERREXIT(j_common_ptr(cinfo), JERR_TGA_BADPARMS);
465      TRACEMS2(j_common_ptr(cinfo), 1, JTRC_TGA_GRAY, width, height);
466    end;
467  else
468    ERREXIT(j_common_ptr(cinfo), JERR_TGA_BADPARMS);
469  end;
470
471  if (is_bottom_up) then
472  begin
473    { Create a virtual array to buffer the upside-down image. }
474    source^.whole_image := cinfo^.mem^.request_virt_sarray
475      (j_common_ptr (cinfo), JPOOL_IMAGE, FALSE,
476       JDIMENSION(width * components), JDIMENSION (height), JDIMENSION (1));
477    if (cinfo^.progress <> NIL) then
478    begin
479      progress := cd_progress_ptr (cinfo^.progress);
480      Inc(progress^.total_extra_passes); { count file input as separate pass }
481    end;
482    { source^.pub.buffer will point to the virtual array. }
483    source^.pub.buffer_height := 1; { in case anyone looks at it }
484    source^.pub.get_pixel_rows := preload_image;
485  end
486  else
487  begin
488    { Don't need a virtual array, but do need a one-row input buffer. }
489    source^.whole_image := NIL;
490    source^.pub.buffer := cinfo^.mem^.alloc_sarray (
491       j_common_ptr (cinfo), JPOOL_IMAGE,
492       JDIMENSION (width * components), JDIMENSION (1)) ;
493    source^.pub.buffer_height := 1;
494    source^.pub.get_pixel_rows := source^.get_pixel_rows;
495  end;
496
497  while (idlen > 0) do  { Throw away ID field }
498  begin
499    Dec(idlen);
500    {void} read_byte(source);
501  end;
502
503  if (maplen > 0) then
504  begin
505    if (maplen > 256) or {GET_2B(3) <> 0}
506       ( (uInt (UCH(targaheader[3])) +
507         (uInt (UCH(targaheader[3+1])) ) shl 8) <> 0) then
508      ERREXIT(j_common_ptr(cinfo), JERR_TGA_BADCMAP);
509    { Allocate space to store the colormap }
510    source^.colormap := cinfo^.mem^.alloc_sarray (
511                        j_common_ptr (cinfo), JPOOL_IMAGE,
512                        JDIMENSION (maplen), JDIMENSION (3));
513    { and read it from the file }
514    read_colormap(source, int (maplen), UCH(targaheader[7]));
515  end
516  else
517  begin
518    if (cmaptype <> 0) then         { but you promised a cmap! }
519      ERREXIT(j_common_ptr(cinfo), JERR_TGA_BADPARMS);
520    source^.colormap := NIL;
521  end;
522
523  cinfo^.input_components := components;
524  cinfo^.data_precision := 8;
525  cinfo^.image_width := width;
526  cinfo^.image_height := height;
527end;
528
529
530{ Finish up at the end of the file. }
531
532{METHODDEF}
533procedure finish_input_tga (cinfo : j_compress_ptr;
534                            sinfo : cjpeg_source_ptr); far;
535begin
536  { no work }
537end;
538
539
540{ The module selection routine for Targa format input. }
541
542{GLOBAL}
543function jinit_read_targa (cinfo : j_compress_ptr) : cjpeg_source_ptr;
544var
545  source : tga_source_ptr;
546begin
547  { Create module interface object }
548  source := tga_source_ptr (
549      cinfo^.mem^.alloc_small (j_common_ptr (cinfo), JPOOL_IMAGE,
550                                  SIZEOF(tga_source_struct)) );
551  source^.cinfo := cinfo;       { make back link for subroutines }
552  { Fill in method ptrs, except get_pixel_rows which start_input sets }
553  source^.pub.start_input := start_input_tga;
554  source^.pub.finish_input := finish_input_tga;
555
556  jinit_read_targa  := cjpeg_source_ptr (source);
557end;
558
559end. { TARGA_SUPPORTED }