123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580 |
- Unit rdppm;
- { rdppm.c
- Copyright (C) 1991-1997, Thomas G. Lane.
- This file is part of the Independent JPEG Group's software.
- For conditions of distribution and use, see the accompanying README file.
- This file contains routines to read input images in PPM/PGM format.
- The extended 2-byte-per-sample raw PPM/PGM formats are supported.
- The PBMPLUS library is NOT required to compile this software
- (but it is highly useful as a set of PPM image manipulation programs).
- These routines may need modification for non-Unix environments or
- specialized applications. As they stand, they assume input from
- an ordinary stdio stream. They further assume that reading begins
- at the start of the file; start_input may need work if the
- user interface has already read some data (e.g., to determine that
- the file is indeed PPM format).
- }
- interface
- {$define CHAR_IS_UNSIGNED}
- {$I jconfig.inc}
- uses
- jdeferr,
- jmorecfg,
- jerror,
- jpeglib,
- jinclude,
- cdjpeg; { Common decls for cjpeg/djpeg applications }
- {GLOBAL}
- function jinit_read_ppm (cinfo : j_compress_ptr) : cjpeg_source_ptr;
- implementation
- { Portions of this code are based on the PBMPLUS library, which is:
- *
- * Copyright (C) 1988 by Jef Poskanzer.
- *
- * Permission to use, copy, modify, and distribute this software and its
- * documentation for any purpose and without fee is hereby granted, provided
- * that the above copyright notice appear in all copies and that both that
- * copyright notice and this permission notice appear in supporting
- * documentation. This software is provided "as is" without express or
- * implied warranty.
- }
- { Macros to deal with unsigned chars as efficiently as compiler allows }
- {$ifdef HAVE_UNSIGNED_CHAR}
- type
- U_CHAR = unsigned char;
- UCH = int;
- {$else} { !HAVE_UNSIGNED_CHAR }
- {$ifdef CHAR_IS_UNSIGNED}
- type
- U_CHAR = byte;
- U_CHARptr = ^U_CHAR;
- UCH = int;
- {$else}
- type
- U_CHAR = char;
- UCH(x) = int (x and $FF)
- {$endif}
- {$endif} { HAVE_UNSIGNED_CHAR }
- { macro }
- function ReadOK(f : FILEptr; buffer : pointer; len : size_t) : boolean;
- begin
- ReadOK := JFREAD(f, buffer,len) = size_t(len);
- end;
- {
- On most systems, reading individual bytes with getc() is drastically less
- efficient than buffering a row at a time with fread(). On PCs, we must
- allocate the buffer in near data space, because we are assuming small-data
- memory model, wherein fread() 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 fread() with a getc() loop --- which will be much
- slower.
- }
- { Private version of data source object }
- type
- ppm_source_ptr = ^ppm_source_struct;
- ppm_source_struct = record
- pub : cjpeg_source_struct; { public fields }
- iobuffer : U_CHARptr; { non-FAR pointer to I/O buffer }
- pixrow : JSAMPROW; { FAR pointer to same }
- buffer_width : size_t; { width of I/O buffer }
- rescale : JSAMPROW; { => maxval-remapping array, or NIL }
- end;
- const
- LF = #10;
- CR = #13;
- {LOCAL}
- function pbm_getc (var infile : file) : char;
- { Read next char, skipping over any comments }
- { A comment/newline sequence is returned as a newline }
- var
- {register} ch : char;
- begin
- {getch} BlockRead(infile, ch, 1);
- if (ch = '#') then
- begin
- repeat
- BlockRead(infile, ch, 1);
- until (ch = LF) or eof(infile);
- end;
- pbm_getc := ch;
- end;
- {LOCAL}
- function read_pbm_integer (cinfo : j_compress_ptr; var infile : file) : uint;
- { Read an unsigned decimal integer from the PPM file }
- { Swallows one trailing character after the integer }
- { Note that on a 16-bit-int machine, only values up to 64k can be read. }
- { This should not be a problem in practice. }
- const
- TAB = ^I;
- var
- {register} ch : char;
- {register} val : uint;
- begin
- { Skip any leading whitespace }
- repeat
- ch := pbm_getc(infile);
- if eof(infile) then
- ERREXIT(j_common_ptr(cinfo), JERR_INPUT_EOF);
- until (ch <> ' ') and (ch <> TAB) and (ch <> LF) and (ch <> CR);
- if (ch < '0') or (ch > '9') then
- ERREXIT(j_common_ptr(cinfo), JERR_PPM_NONNUMERIC);
- val := ord(ch) - ord('0');
- repeat
- ch := pbm_getc(infile);
- if (ch >= '0') and (ch <= '9') then
- begin
- val := val * 10;
- Inc(val, ord(ch) - ord('0'));
- end
- else
- break;
- until FALSE;
- read_pbm_integer := val;
- end;
- { Read one row of pixels.
- We provide several different versions depending on input file format.
- In all cases, input is scaled to the size of JSAMPLE.
- A really fast path is provided for reading byte/sample raw files with
- maxval := MAXJSAMPLE, which is the normal case for 8-bit data. }
- {METHODDEF}
- function get_text_gray_row (cinfo : j_compress_ptr;
- sinfo : cjpeg_source_ptr) : JDIMENSION; far;
- { This version is for reading text-format PGM files with any maxval }
- var
- source : ppm_source_ptr;
- infile : FILEptr;
- {register} ptr : JSAMPLE_PTR;
- {register} rescale : JSAMPROW;
- col : JDIMENSION;
- begin
- source := ppm_source_ptr(sinfo);
- infile := source^.pub.input_file;
- rescale := source^.rescale;
- ptr := JSAMPLE_PTR(source^.pub.buffer^[0]);
- for col := pred(cinfo^.image_width) downto 0 do
- begin
- ptr^ := rescale^[read_pbm_integer(cinfo, infile^)];
- Inc(ptr);
- end;
- get_text_gray_row := 1;
- end;
- {METHODDEF}
- function get_text_rgb_row (cinfo : j_compress_ptr;
- sinfo : cjpeg_source_ptr) : JDIMENSION; far;
- { This version is for reading text-format PPM files with any maxval }
- var
- source : ppm_source_ptr;
- infile : FILEptr;
- {register} ptr : JSAMPLE_PTR;
- {register} rescale : JSAMPROW;
- col : JDIMENSION;
- begin
- source := ppm_source_ptr(sinfo);
- infile := source^.pub.input_file;
- rescale := source^.rescale;
- ptr := JSAMPLE_PTR(source^.pub.buffer^[0]);
- for col := pred(cinfo^.image_width) downto 0 do
- begin
- ptr^ := rescale^[read_pbm_integer(cinfo, infile^)];
- Inc(ptr);
- ptr^ := rescale^[read_pbm_integer(cinfo, infile^)];
- Inc(ptr);
- ptr^ := rescale^[read_pbm_integer(cinfo, infile^)];
- Inc(ptr);
- end;
- get_text_rgb_row := 1;
- end;
- {METHODDEF}
- function get_scaled_gray_row (cinfo : j_compress_ptr;
- sinfo : cjpeg_source_ptr) : JDIMENSION; far;
- { This version is for reading raw-byte-format PGM files with any maxval }
- var
- source : ppm_source_ptr;
- {register} ptr : JSAMPLE_PTR;
- {register} bufferptr : U_CHARptr ;
- {register} rescale : JSAMPROW;
- col : JDIMENSION;
- begin
- source := ppm_source_ptr(sinfo);
- rescale := source^.rescale;
- if not ReadOK(source^.pub.input_file, source^.iobuffer,
- source^.buffer_width) then
- ERREXIT(j_common_ptr(cinfo), JERR_INPUT_EOF);
- ptr := JSAMPLE_PTR(source^.pub.buffer^[0]);
- bufferptr := source^.iobuffer;
- for col := pred(cinfo^.image_width) downto 0 do
- begin
- ptr^ := rescale^[UCH(bufferptr^)];
- Inc(ptr);
- Inc(bufferptr);
- end;
- get_scaled_gray_row := 1;
- end;
- {METHODDEF}
- function get_scaled_rgb_row (cinfo : j_compress_ptr;
- sinfo : cjpeg_source_ptr) : JDIMENSION; far;
- { This version is for reading raw-byte-format PPM files with any maxval }
- var
- source : ppm_source_ptr;
- {register} ptr : JSAMPLE_PTR;
- {register} bufferptr : U_CHARptr ;
- {register} rescale : JSAMPROW;
- col : JDIMENSION;
- begin
- source := ppm_source_ptr (sinfo);
- rescale := source^.rescale;
- if not ReadOK(source^.pub.input_file, source^.iobuffer,
- source^.buffer_width) then
- ERREXIT(j_common_ptr(cinfo), JERR_INPUT_EOF);
- ptr := JSAMPLE_PTR(source^.pub.buffer^[0]);
- bufferptr := source^.iobuffer;
- for col := pred(cinfo^.image_width) downto 0 do
- begin
- ptr^ := rescale^[UCH(bufferptr^)];
- Inc(ptr);
- Inc(bufferptr);
- ptr^ := rescale^[UCH(bufferptr^)];
- Inc(ptr);
- Inc(bufferptr);
- ptr^ := rescale^[UCH(bufferptr^)];
- Inc(ptr);
- Inc(bufferptr);
- end;
- get_scaled_rgb_row := 1;
- end;
- {METHODDEF}
- function get_raw_row (cinfo : j_compress_ptr;
- sinfo : cjpeg_source_ptr) : JDIMENSION; far;
- { This version is for reading raw-byte-format files with maxval := MAXJSAMPLE.
- In this case we just read right into the JSAMPLE buffer!
- Note that same code works for PPM and PGM files. }
- var
- source : ppm_source_ptr;
- begin
- source := ppm_source_ptr(sinfo);
- if not ReadOK(source^.pub.input_file, source^.iobuffer,
- source^.buffer_width) then
- ERREXIT(j_common_ptr(cinfo), JERR_INPUT_EOF);
- get_raw_row := 1;
- end;
- {METHODDEF}
- function get_word_gray_row (cinfo : j_compress_ptr;
- sinfo : cjpeg_source_ptr) : JDIMENSION; far;
- { This version is for reading raw-word-format PGM files with any maxval }
- var
- source : ppm_source_ptr;
- {register} ptr : JSAMPLE_PTR;
- {register} bufferptr : U_CHARptr;
- {register} rescale : JSAMPROW;
- col : JDIMENSION;
- var
- {register} temp : int;
- begin
- source := ppm_source_ptr (sinfo);
- rescale := source^.rescale;
- if not ReadOK(source^.pub.input_file, source^.iobuffer,
- source^.buffer_width) then
- ERREXIT(j_common_ptr(cinfo), JERR_INPUT_EOF);
- ptr := JSAMPLE_PTR(source^.pub.buffer^[0]);
- bufferptr := source^.iobuffer;
- for col := pred(cinfo^.image_width) downto 0 do
- begin
- temp := UCH(bufferptr^);
- Inc(bufferptr);
- temp := temp or (UCH(bufferptr^) shl 8);
- Inc(bufferptr);
- ptr^ := rescale^[temp];
- Inc(ptr);
- end;
- get_word_gray_row := 1;
- end;
- {METHODDEF}
- function get_word_rgb_row (cinfo : j_compress_ptr;
- sinfo : cjpeg_source_ptr) : JDIMENSION; far;
- { This version is for reading raw-word-format PPM files with any maxval }
- var
- source : ppm_source_ptr;
- {register} ptr : JSAMPLE_PTR;
- {register} bufferptr : U_CHARptr;
- {register} rescale : JSAMPROW;
- col : JDIMENSION;
- var
- {register} temp : int;
- begin
- source := ppm_source_ptr(sinfo);
- rescale := source^.rescale;
- if not ReadOK(source^.pub.input_file, source^.iobuffer,
- source^.buffer_width) then
- ERREXIT(j_common_ptr(cinfo), JERR_INPUT_EOF);
- ptr := JSAMPLE_PTR(source^.pub.buffer^[0]);
- bufferptr := source^.iobuffer;
- for col := pred(cinfo^.image_width) downto 0 do
- begin
- temp := UCH(bufferptr^);
- Inc(bufferptr);
- temp := temp or (UCH(bufferptr^) shl 8);
- Inc(bufferptr);
- ptr^ := rescale^[temp];
- Inc(ptr);
- temp := UCH(bufferptr^);
- Inc(bufferptr);
- temp := temp or (UCH(bufferptr^) shl 8);
- Inc(bufferptr);
- ptr^ := rescale^[temp];
- Inc(ptr);
- temp := UCH(bufferptr^);
- Inc(bufferptr);
- temp := temp or (UCH(bufferptr^) shl 8);
- Inc(bufferptr);
- ptr^ := rescale^[temp];
- Inc(ptr);
- end;
- get_word_rgb_row := 1;
- end;
- { Read the file header; return image size and component count. }
- {METHODDEF}
- procedure start_input_ppm (cinfo : j_compress_ptr;
- sinfo : cjpeg_source_ptr); far;
- var
- source : ppm_source_ptr;
- c : char;
- w, h, maxval : uint;
- need_iobuffer, use_raw_buffer, need_rescale : boolean;
- var
- val, half_maxval : INT32;
- begin
- source := ppm_source_ptr(sinfo);
- {getch} BlockRead(source^.pub.input_file^, c, 1);
- if (c <> 'P') then
- ERREXIT(j_common_ptr(cinfo), JERR_PPM_NOT);
- {getch} BlockRead(source^.pub.input_file^, c, 1);
- { subformat discriminator character }
- { detect unsupported variants (ie, PBM) before trying to read header }
- case (c) of
- '2', { it's a text-format PGM file }
- '3', { it's a text-format PPM file }
- '5', { it's a raw-format PGM file }
- '6':; { it's a raw-format PPM file }
- else
- ERREXIT(j_common_ptr(cinfo), JERR_PPM_NOT);
- end;
- { fetch the remaining header info }
- w := read_pbm_integer(cinfo, source^.pub.input_file^);
- h := read_pbm_integer(cinfo, source^.pub.input_file^);
- maxval := read_pbm_integer(cinfo, source^.pub.input_file^);
- if (w <= 0) or (h <= 0) or (maxval <= 0) then { error check }
- ERREXIT(j_common_ptr(cinfo), JERR_PPM_NOT);
- cinfo^.data_precision := BITS_IN_JSAMPLE; { we always rescale data to this }
- cinfo^.image_width := JDIMENSION (w);
- cinfo^.image_height := JDIMENSION (h);
- { initialize flags to most common settings }
- need_iobuffer := TRUE; { do we need an I/O buffer? }
- use_raw_buffer := FALSE; { do we map input buffer onto I/O buffer? }
- need_rescale := TRUE; { do we need a rescale array? }
- case (c) of
- '2': { it's a text-format PGM file }
- begin
- cinfo^.input_components := 1;
- cinfo^.in_color_space := JCS_GRAYSCALE;
- {$IFDEF DEBUG}
- TRACEMS2(j_common_ptr(cinfo), 1, JTRC_PGM_TEXT, w, h);
- {$ENDIF}
- source^.pub.get_pixel_rows := get_text_gray_row;
- need_iobuffer := FALSE;
- end;
- '3': { it's a text-format PPM file }
- begin
- cinfo^.input_components := 3;
- cinfo^.in_color_space := JCS_RGB;
- {$IFDEF DEBUG}
- TRACEMS2(j_common_ptr(cinfo), 1, JTRC_PPM_TEXT, w, h);
- {$ENDIF}
- source^.pub.get_pixel_rows := get_text_rgb_row;
- need_iobuffer := FALSE;
- end;
- '5': { it's a raw-format PGM file }
- begin
- cinfo^.input_components := 1;
- cinfo^.in_color_space := JCS_GRAYSCALE;
- TRACEMS2(j_common_ptr(cinfo), 1, JTRC_PGM, w, h);
- if (maxval > 255) then
- begin
- source^.pub.get_pixel_rows := get_word_gray_row;
- end
- else
- if (maxval = MAXJSAMPLE) and (SIZEOF(JSAMPLE) = SIZEOF(U_CHAR)) then
- begin
- source^.pub.get_pixel_rows := get_raw_row;
- use_raw_buffer := TRUE;
- need_rescale := FALSE;
- end
- else
- begin
- source^.pub.get_pixel_rows := get_scaled_gray_row;
- end;
- end;
- '6': { it's a raw-format PPM file }
- begin
- cinfo^.input_components := 3;
- cinfo^.in_color_space := JCS_RGB;
- {$IFDEF DEBUG}
- TRACEMS2(j_common_ptr(cinfo), 1, JTRC_PPM, w, h);
- {$ENDIF}
- if (maxval > 255) then
- begin
- source^.pub.get_pixel_rows := get_word_rgb_row;
- end
- else
- if (maxval = MAXJSAMPLE) and (SIZEOF(JSAMPLE) = SIZEOF(U_CHAR)) then
- begin
- source^.pub.get_pixel_rows := get_raw_row;
- use_raw_buffer := TRUE;
- need_rescale := FALSE;
- end
- else
- begin
- source^.pub.get_pixel_rows := get_scaled_rgb_row;
- end;
- end;
- end;
- { Allocate space for I/O buffer: 1 or 3 bytes or words/pixel. }
- if (need_iobuffer) then
- begin
- if (maxval<=255) then
- source^.buffer_width := size_t ( w * cinfo^.input_components *
- SIZEOF(U_CHAR) )
- else
- source^.buffer_width := size_t ( w * cinfo^.input_components *
- (2*SIZEOF(U_CHAR)) );
- source^.iobuffer := U_CHARptr (
- cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE,
- source^.buffer_width) );
- end;
- { Create compressor input buffer. }
- if (use_raw_buffer) then
- begin
- { For unscaled raw-input case, we can just map it onto the I/O buffer. }
- { Synthesize a JSAMPARRAY pointer structure }
- { Cast here implies near^.far pointer conversion on PCs }
- source^.pixrow := JSAMPROW (source^.iobuffer);
- source^.pub.buffer := JSAMPARRAY(@source^.pixrow);
- source^.pub.buffer_height := 1;
- end
- else
- begin
- { Need to translate anyway, so make a separate sample buffer. }
- source^.pub.buffer := cinfo^.mem^.alloc_sarray
- (j_common_ptr(cinfo), JPOOL_IMAGE,
- JDIMENSION (w * cinfo^.input_components), JDIMENSION(1) );
- source^.pub.buffer_height := 1;
- end;
- { Compute the rescaling array if required. }
- if (need_rescale) then
- begin
- { On 16-bit-int machines we have to be careful of maxval := 65535 }
- source^.rescale := JSAMPROW (
- cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE,
- size_t ((long(maxval) + long(1)) * SIZEOF(JSAMPLE))) );
- half_maxval := maxval div 2;
- for val := 0 to INT32(maxval) do
- begin
- { The multiplication here must be done in 32 bits to avoid overflow }
- source^.rescale^[val] := JSAMPLE ((val*MAXJSAMPLE + half_maxval) div maxval);
- end;
- end;
- end;
- { Finish up at the end of the file. }
- {METHODDEF}
- procedure finish_input_ppm (cinfo : j_compress_ptr;
- sinfo : cjpeg_source_ptr); far;
- begin
- { no work }
- end;
- { The module selection routine for PPM format input. }
- {GLOBAL}
- function jinit_read_ppm (cinfo : j_compress_ptr) : cjpeg_source_ptr;
- var
- source : ppm_source_ptr;
- begin
- { Create module interface object }
- source := ppm_source_ptr (
- cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE,
- SIZEOF(ppm_source_struct)) );
- { Fill in method ptrs, except get_pixel_rows which start_input sets }
- source^.pub.start_input := start_input_ppm;
- source^.pub.finish_input := finish_input_ppm;
- jinit_read_ppm := cjpeg_source_ptr(source);
- end;
- end.
|