rdppm.pas 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580
  1. Unit rdppm;
  2. { rdppm.c
  3. Copyright (C) 1991-1997, Thomas G. Lane.
  4. This file is part of the Independent JPEG Group's software.
  5. For conditions of distribution and use, see the accompanying README file.
  6. This file contains routines to read input images in PPM/PGM format.
  7. The extended 2-byte-per-sample raw PPM/PGM formats are supported.
  8. The PBMPLUS library is NOT required to compile this software
  9. (but it is highly useful as a set of PPM image manipulation programs).
  10. These routines may need modification for non-Unix environments or
  11. specialized applications. As they stand, they assume input from
  12. an ordinary stdio stream. They further assume that reading begins
  13. at the start of the file; start_input may need work if the
  14. user interface has already read some data (e.g., to determine that
  15. the file is indeed PPM format).
  16. }
  17. interface
  18. {$define CHAR_IS_UNSIGNED}
  19. {$I jconfig.inc}
  20. uses
  21. jdeferr,
  22. jmorecfg,
  23. jerror,
  24. jpeglib,
  25. jinclude,
  26. cdjpeg; { Common decls for cjpeg/djpeg applications }
  27. {GLOBAL}
  28. function jinit_read_ppm (cinfo : j_compress_ptr) : cjpeg_source_ptr;
  29. implementation
  30. { Portions of this code are based on the PBMPLUS library, which is:
  31. *
  32. * Copyright (C) 1988 by Jef Poskanzer.
  33. *
  34. * Permission to use, copy, modify, and distribute this software and its
  35. * documentation for any purpose and without fee is hereby granted, provided
  36. * that the above copyright notice appear in all copies and that both that
  37. * copyright notice and this permission notice appear in supporting
  38. * documentation. This software is provided "as is" without express or
  39. * implied warranty.
  40. }
  41. { Macros to deal with unsigned chars as efficiently as compiler allows }
  42. {$ifdef HAVE_UNSIGNED_CHAR}
  43. type
  44. U_CHAR = unsigned char;
  45. UCH = int;
  46. {$else} { !HAVE_UNSIGNED_CHAR }
  47. {$ifdef CHAR_IS_UNSIGNED}
  48. type
  49. U_CHAR = byte;
  50. U_CHARptr = ^U_CHAR;
  51. UCH = int;
  52. {$else}
  53. type
  54. U_CHAR = char;
  55. UCH(x) = int (x and $FF)
  56. {$endif}
  57. {$endif} { HAVE_UNSIGNED_CHAR }
  58. { macro }
  59. function ReadOK(f : FILEptr; buffer : pointer; len : size_t) : boolean;
  60. begin
  61. ReadOK := JFREAD(f, buffer,len) = size_t(len);
  62. end;
  63. {
  64. On most systems, reading individual bytes with getc() is drastically less
  65. efficient than buffering a row at a time with fread(). On PCs, we must
  66. allocate the buffer in near data space, because we are assuming small-data
  67. memory model, wherein fread() can't reach far memory. If you need to
  68. process very wide images on a PC, you might have to compile in large-memory
  69. model, or else replace fread() with a getc() loop --- which will be much
  70. slower.
  71. }
  72. { Private version of data source object }
  73. type
  74. ppm_source_ptr = ^ppm_source_struct;
  75. ppm_source_struct = record
  76. pub : cjpeg_source_struct; { public fields }
  77. iobuffer : U_CHARptr; { non-FAR pointer to I/O buffer }
  78. pixrow : JSAMPROW; { FAR pointer to same }
  79. buffer_width : size_t; { width of I/O buffer }
  80. rescale : JSAMPROW; { => maxval-remapping array, or NIL }
  81. end;
  82. const
  83. LF = #10;
  84. CR = #13;
  85. {LOCAL}
  86. function pbm_getc (var infile : file) : char;
  87. { Read next char, skipping over any comments }
  88. { A comment/newline sequence is returned as a newline }
  89. var
  90. {register} ch : char;
  91. begin
  92. {getch} BlockRead(infile, ch, 1);
  93. if (ch = '#') then
  94. begin
  95. repeat
  96. BlockRead(infile, ch, 1);
  97. until (ch = LF) or eof(infile);
  98. end;
  99. pbm_getc := ch;
  100. end;
  101. {LOCAL}
  102. function read_pbm_integer (cinfo : j_compress_ptr; var infile : file) : uint;
  103. { Read an unsigned decimal integer from the PPM file }
  104. { Swallows one trailing character after the integer }
  105. { Note that on a 16-bit-int machine, only values up to 64k can be read. }
  106. { This should not be a problem in practice. }
  107. const
  108. TAB = ^I;
  109. var
  110. {register} ch : char;
  111. {register} val : uint;
  112. begin
  113. { Skip any leading whitespace }
  114. repeat
  115. ch := pbm_getc(infile);
  116. if eof(infile) then
  117. ERREXIT(j_common_ptr(cinfo), JERR_INPUT_EOF);
  118. until (ch <> ' ') and (ch <> TAB) and (ch <> LF) and (ch <> CR);
  119. if (ch < '0') or (ch > '9') then
  120. ERREXIT(j_common_ptr(cinfo), JERR_PPM_NONNUMERIC);
  121. val := ord(ch) - ord('0');
  122. repeat
  123. ch := pbm_getc(infile);
  124. if (ch >= '0') and (ch <= '9') then
  125. begin
  126. val := val * 10;
  127. Inc(val, ord(ch) - ord('0'));
  128. end
  129. else
  130. break;
  131. until FALSE;
  132. read_pbm_integer := val;
  133. end;
  134. { Read one row of pixels.
  135. We provide several different versions depending on input file format.
  136. In all cases, input is scaled to the size of JSAMPLE.
  137. A really fast path is provided for reading byte/sample raw files with
  138. maxval := MAXJSAMPLE, which is the normal case for 8-bit data. }
  139. {METHODDEF}
  140. function get_text_gray_row (cinfo : j_compress_ptr;
  141. sinfo : cjpeg_source_ptr) : JDIMENSION; far;
  142. { This version is for reading text-format PGM files with any maxval }
  143. var
  144. source : ppm_source_ptr;
  145. infile : FILEptr;
  146. {register} ptr : JSAMPLE_PTR;
  147. {register} rescale : JSAMPROW;
  148. col : JDIMENSION;
  149. begin
  150. source := ppm_source_ptr(sinfo);
  151. infile := source^.pub.input_file;
  152. rescale := source^.rescale;
  153. ptr := JSAMPLE_PTR(source^.pub.buffer^[0]);
  154. for col := pred(cinfo^.image_width) downto 0 do
  155. begin
  156. ptr^ := rescale^[read_pbm_integer(cinfo, infile^)];
  157. Inc(ptr);
  158. end;
  159. get_text_gray_row := 1;
  160. end;
  161. {METHODDEF}
  162. function get_text_rgb_row (cinfo : j_compress_ptr;
  163. sinfo : cjpeg_source_ptr) : JDIMENSION; far;
  164. { This version is for reading text-format PPM files with any maxval }
  165. var
  166. source : ppm_source_ptr;
  167. infile : FILEptr;
  168. {register} ptr : JSAMPLE_PTR;
  169. {register} rescale : JSAMPROW;
  170. col : JDIMENSION;
  171. begin
  172. source := ppm_source_ptr(sinfo);
  173. infile := source^.pub.input_file;
  174. rescale := source^.rescale;
  175. ptr := JSAMPLE_PTR(source^.pub.buffer^[0]);
  176. for col := pred(cinfo^.image_width) downto 0 do
  177. begin
  178. ptr^ := rescale^[read_pbm_integer(cinfo, infile^)];
  179. Inc(ptr);
  180. ptr^ := rescale^[read_pbm_integer(cinfo, infile^)];
  181. Inc(ptr);
  182. ptr^ := rescale^[read_pbm_integer(cinfo, infile^)];
  183. Inc(ptr);
  184. end;
  185. get_text_rgb_row := 1;
  186. end;
  187. {METHODDEF}
  188. function get_scaled_gray_row (cinfo : j_compress_ptr;
  189. sinfo : cjpeg_source_ptr) : JDIMENSION; far;
  190. { This version is for reading raw-byte-format PGM files with any maxval }
  191. var
  192. source : ppm_source_ptr;
  193. {register} ptr : JSAMPLE_PTR;
  194. {register} bufferptr : U_CHARptr ;
  195. {register} rescale : JSAMPROW;
  196. col : JDIMENSION;
  197. begin
  198. source := ppm_source_ptr(sinfo);
  199. rescale := source^.rescale;
  200. if not ReadOK(source^.pub.input_file, source^.iobuffer,
  201. source^.buffer_width) then
  202. ERREXIT(j_common_ptr(cinfo), JERR_INPUT_EOF);
  203. ptr := JSAMPLE_PTR(source^.pub.buffer^[0]);
  204. bufferptr := source^.iobuffer;
  205. for col := pred(cinfo^.image_width) downto 0 do
  206. begin
  207. ptr^ := rescale^[UCH(bufferptr^)];
  208. Inc(ptr);
  209. Inc(bufferptr);
  210. end;
  211. get_scaled_gray_row := 1;
  212. end;
  213. {METHODDEF}
  214. function get_scaled_rgb_row (cinfo : j_compress_ptr;
  215. sinfo : cjpeg_source_ptr) : JDIMENSION; far;
  216. { This version is for reading raw-byte-format PPM files with any maxval }
  217. var
  218. source : ppm_source_ptr;
  219. {register} ptr : JSAMPLE_PTR;
  220. {register} bufferptr : U_CHARptr ;
  221. {register} rescale : JSAMPROW;
  222. col : JDIMENSION;
  223. begin
  224. source := ppm_source_ptr (sinfo);
  225. rescale := source^.rescale;
  226. if not ReadOK(source^.pub.input_file, source^.iobuffer,
  227. source^.buffer_width) then
  228. ERREXIT(j_common_ptr(cinfo), JERR_INPUT_EOF);
  229. ptr := JSAMPLE_PTR(source^.pub.buffer^[0]);
  230. bufferptr := source^.iobuffer;
  231. for col := pred(cinfo^.image_width) downto 0 do
  232. begin
  233. ptr^ := rescale^[UCH(bufferptr^)];
  234. Inc(ptr);
  235. Inc(bufferptr);
  236. ptr^ := rescale^[UCH(bufferptr^)];
  237. Inc(ptr);
  238. Inc(bufferptr);
  239. ptr^ := rescale^[UCH(bufferptr^)];
  240. Inc(ptr);
  241. Inc(bufferptr);
  242. end;
  243. get_scaled_rgb_row := 1;
  244. end;
  245. {METHODDEF}
  246. function get_raw_row (cinfo : j_compress_ptr;
  247. sinfo : cjpeg_source_ptr) : JDIMENSION; far;
  248. { This version is for reading raw-byte-format files with maxval := MAXJSAMPLE.
  249. In this case we just read right into the JSAMPLE buffer!
  250. Note that same code works for PPM and PGM files. }
  251. var
  252. source : ppm_source_ptr;
  253. begin
  254. source := ppm_source_ptr(sinfo);
  255. if not ReadOK(source^.pub.input_file, source^.iobuffer,
  256. source^.buffer_width) then
  257. ERREXIT(j_common_ptr(cinfo), JERR_INPUT_EOF);
  258. get_raw_row := 1;
  259. end;
  260. {METHODDEF}
  261. function get_word_gray_row (cinfo : j_compress_ptr;
  262. sinfo : cjpeg_source_ptr) : JDIMENSION; far;
  263. { This version is for reading raw-word-format PGM files with any maxval }
  264. var
  265. source : ppm_source_ptr;
  266. {register} ptr : JSAMPLE_PTR;
  267. {register} bufferptr : U_CHARptr;
  268. {register} rescale : JSAMPROW;
  269. col : JDIMENSION;
  270. var
  271. {register} temp : int;
  272. begin
  273. source := ppm_source_ptr (sinfo);
  274. rescale := source^.rescale;
  275. if not ReadOK(source^.pub.input_file, source^.iobuffer,
  276. source^.buffer_width) then
  277. ERREXIT(j_common_ptr(cinfo), JERR_INPUT_EOF);
  278. ptr := JSAMPLE_PTR(source^.pub.buffer^[0]);
  279. bufferptr := source^.iobuffer;
  280. for col := pred(cinfo^.image_width) downto 0 do
  281. begin
  282. temp := UCH(bufferptr^);
  283. Inc(bufferptr);
  284. temp := temp or (UCH(bufferptr^) shl 8);
  285. Inc(bufferptr);
  286. ptr^ := rescale^[temp];
  287. Inc(ptr);
  288. end;
  289. get_word_gray_row := 1;
  290. end;
  291. {METHODDEF}
  292. function get_word_rgb_row (cinfo : j_compress_ptr;
  293. sinfo : cjpeg_source_ptr) : JDIMENSION; far;
  294. { This version is for reading raw-word-format PPM files with any maxval }
  295. var
  296. source : ppm_source_ptr;
  297. {register} ptr : JSAMPLE_PTR;
  298. {register} bufferptr : U_CHARptr;
  299. {register} rescale : JSAMPROW;
  300. col : JDIMENSION;
  301. var
  302. {register} temp : int;
  303. begin
  304. source := ppm_source_ptr(sinfo);
  305. rescale := source^.rescale;
  306. if not ReadOK(source^.pub.input_file, source^.iobuffer,
  307. source^.buffer_width) then
  308. ERREXIT(j_common_ptr(cinfo), JERR_INPUT_EOF);
  309. ptr := JSAMPLE_PTR(source^.pub.buffer^[0]);
  310. bufferptr := source^.iobuffer;
  311. for col := pred(cinfo^.image_width) downto 0 do
  312. begin
  313. temp := UCH(bufferptr^);
  314. Inc(bufferptr);
  315. temp := temp or (UCH(bufferptr^) shl 8);
  316. Inc(bufferptr);
  317. ptr^ := rescale^[temp];
  318. Inc(ptr);
  319. temp := UCH(bufferptr^);
  320. Inc(bufferptr);
  321. temp := temp or (UCH(bufferptr^) shl 8);
  322. Inc(bufferptr);
  323. ptr^ := rescale^[temp];
  324. Inc(ptr);
  325. temp := UCH(bufferptr^);
  326. Inc(bufferptr);
  327. temp := temp or (UCH(bufferptr^) shl 8);
  328. Inc(bufferptr);
  329. ptr^ := rescale^[temp];
  330. Inc(ptr);
  331. end;
  332. get_word_rgb_row := 1;
  333. end;
  334. { Read the file header; return image size and component count. }
  335. {METHODDEF}
  336. procedure start_input_ppm (cinfo : j_compress_ptr;
  337. sinfo : cjpeg_source_ptr); far;
  338. var
  339. source : ppm_source_ptr;
  340. c : char;
  341. w, h, maxval : uint;
  342. need_iobuffer, use_raw_buffer, need_rescale : boolean;
  343. var
  344. val, half_maxval : INT32;
  345. begin
  346. source := ppm_source_ptr(sinfo);
  347. {getch} BlockRead(source^.pub.input_file^, c, 1);
  348. if (c <> 'P') then
  349. ERREXIT(j_common_ptr(cinfo), JERR_PPM_NOT);
  350. {getch} BlockRead(source^.pub.input_file^, c, 1);
  351. { subformat discriminator character }
  352. { detect unsupported variants (ie, PBM) before trying to read header }
  353. case (c) of
  354. '2', { it's a text-format PGM file }
  355. '3', { it's a text-format PPM file }
  356. '5', { it's a raw-format PGM file }
  357. '6':; { it's a raw-format PPM file }
  358. else
  359. ERREXIT(j_common_ptr(cinfo), JERR_PPM_NOT);
  360. end;
  361. { fetch the remaining header info }
  362. w := read_pbm_integer(cinfo, source^.pub.input_file^);
  363. h := read_pbm_integer(cinfo, source^.pub.input_file^);
  364. maxval := read_pbm_integer(cinfo, source^.pub.input_file^);
  365. if (w <= 0) or (h <= 0) or (maxval <= 0) then { error check }
  366. ERREXIT(j_common_ptr(cinfo), JERR_PPM_NOT);
  367. cinfo^.data_precision := BITS_IN_JSAMPLE; { we always rescale data to this }
  368. cinfo^.image_width := JDIMENSION (w);
  369. cinfo^.image_height := JDIMENSION (h);
  370. { initialize flags to most common settings }
  371. need_iobuffer := TRUE; { do we need an I/O buffer? }
  372. use_raw_buffer := FALSE; { do we map input buffer onto I/O buffer? }
  373. need_rescale := TRUE; { do we need a rescale array? }
  374. case (c) of
  375. '2': { it's a text-format PGM file }
  376. begin
  377. cinfo^.input_components := 1;
  378. cinfo^.in_color_space := JCS_GRAYSCALE;
  379. {$IFDEF DEBUG}
  380. TRACEMS2(j_common_ptr(cinfo), 1, JTRC_PGM_TEXT, w, h);
  381. {$ENDIF}
  382. source^.pub.get_pixel_rows := get_text_gray_row;
  383. need_iobuffer := FALSE;
  384. end;
  385. '3': { it's a text-format PPM file }
  386. begin
  387. cinfo^.input_components := 3;
  388. cinfo^.in_color_space := JCS_RGB;
  389. {$IFDEF DEBUG}
  390. TRACEMS2(j_common_ptr(cinfo), 1, JTRC_PPM_TEXT, w, h);
  391. {$ENDIF}
  392. source^.pub.get_pixel_rows := get_text_rgb_row;
  393. need_iobuffer := FALSE;
  394. end;
  395. '5': { it's a raw-format PGM file }
  396. begin
  397. cinfo^.input_components := 1;
  398. cinfo^.in_color_space := JCS_GRAYSCALE;
  399. TRACEMS2(j_common_ptr(cinfo), 1, JTRC_PGM, w, h);
  400. if (maxval > 255) then
  401. begin
  402. source^.pub.get_pixel_rows := get_word_gray_row;
  403. end
  404. else
  405. if (maxval = MAXJSAMPLE) and (SIZEOF(JSAMPLE) = SIZEOF(U_CHAR)) then
  406. begin
  407. source^.pub.get_pixel_rows := get_raw_row;
  408. use_raw_buffer := TRUE;
  409. need_rescale := FALSE;
  410. end
  411. else
  412. begin
  413. source^.pub.get_pixel_rows := get_scaled_gray_row;
  414. end;
  415. end;
  416. '6': { it's a raw-format PPM file }
  417. begin
  418. cinfo^.input_components := 3;
  419. cinfo^.in_color_space := JCS_RGB;
  420. {$IFDEF DEBUG}
  421. TRACEMS2(j_common_ptr(cinfo), 1, JTRC_PPM, w, h);
  422. {$ENDIF}
  423. if (maxval > 255) then
  424. begin
  425. source^.pub.get_pixel_rows := get_word_rgb_row;
  426. end
  427. else
  428. if (maxval = MAXJSAMPLE) and (SIZEOF(JSAMPLE) = SIZEOF(U_CHAR)) then
  429. begin
  430. source^.pub.get_pixel_rows := get_raw_row;
  431. use_raw_buffer := TRUE;
  432. need_rescale := FALSE;
  433. end
  434. else
  435. begin
  436. source^.pub.get_pixel_rows := get_scaled_rgb_row;
  437. end;
  438. end;
  439. end;
  440. { Allocate space for I/O buffer: 1 or 3 bytes or words/pixel. }
  441. if (need_iobuffer) then
  442. begin
  443. if (maxval<=255) then
  444. source^.buffer_width := size_t ( w * cinfo^.input_components *
  445. SIZEOF(U_CHAR) )
  446. else
  447. source^.buffer_width := size_t ( w * cinfo^.input_components *
  448. (2*SIZEOF(U_CHAR)) );
  449. source^.iobuffer := U_CHARptr (
  450. cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE,
  451. source^.buffer_width) );
  452. end;
  453. { Create compressor input buffer. }
  454. if (use_raw_buffer) then
  455. begin
  456. { For unscaled raw-input case, we can just map it onto the I/O buffer. }
  457. { Synthesize a JSAMPARRAY pointer structure }
  458. { Cast here implies near^.far pointer conversion on PCs }
  459. source^.pixrow := JSAMPROW (source^.iobuffer);
  460. source^.pub.buffer := JSAMPARRAY(@source^.pixrow);
  461. source^.pub.buffer_height := 1;
  462. end
  463. else
  464. begin
  465. { Need to translate anyway, so make a separate sample buffer. }
  466. source^.pub.buffer := cinfo^.mem^.alloc_sarray
  467. (j_common_ptr(cinfo), JPOOL_IMAGE,
  468. JDIMENSION (w * cinfo^.input_components), JDIMENSION(1) );
  469. source^.pub.buffer_height := 1;
  470. end;
  471. { Compute the rescaling array if required. }
  472. if (need_rescale) then
  473. begin
  474. { On 16-bit-int machines we have to be careful of maxval := 65535 }
  475. source^.rescale := JSAMPROW (
  476. cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE,
  477. size_t ((long(maxval) + long(1)) * SIZEOF(JSAMPLE))) );
  478. half_maxval := maxval div 2;
  479. for val := 0 to INT32(maxval) do
  480. begin
  481. { The multiplication here must be done in 32 bits to avoid overflow }
  482. source^.rescale^[val] := JSAMPLE ((val*MAXJSAMPLE + half_maxval) div maxval);
  483. end;
  484. end;
  485. end;
  486. { Finish up at the end of the file. }
  487. {METHODDEF}
  488. procedure finish_input_ppm (cinfo : j_compress_ptr;
  489. sinfo : cjpeg_source_ptr); far;
  490. begin
  491. { no work }
  492. end;
  493. { The module selection routine for PPM format input. }
  494. {GLOBAL}
  495. function jinit_read_ppm (cinfo : j_compress_ptr) : cjpeg_source_ptr;
  496. var
  497. source : ppm_source_ptr;
  498. begin
  499. { Create module interface object }
  500. source := ppm_source_ptr (
  501. cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE,
  502. SIZEOF(ppm_source_struct)) );
  503. { Fill in method ptrs, except get_pixel_rows which start_input sets }
  504. source^.pub.start_input := start_input_ppm;
  505. source^.pub.finish_input := finish_input_ppm;
  506. jinit_read_ppm := cjpeg_source_ptr(source);
  507. end;
  508. end.