/packages/pasjpeg/examples/rdtarga.pas
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 }