home *** CD-ROM | disk | FTP | other *** search
/ Encyclopedia of Graphics File Formats Companion / GFF_CD.ISO / software / unix / jpeg / jpegv4a.tar / jrdppm.c < prev    next >
C/C++ Source or Header  |  1992-12-22  |  13KB  |  460 lines

  1. /*
  2.  * jrdppm.c
  3.  *
  4.  * Copyright (C) 1991, 1992, Thomas G. Lane.
  5.  * This file is part of the Independent JPEG Group's software.
  6.  * For conditions of distribution and use, see the accompanying README file.
  7.  *
  8.  * This file contains routines to read input images in PPM format.
  9.  * The PBMPLUS library is NOT required to compile this software,
  10.  * but it is highly useful as a set of PPM image manipulation programs.
  11.  *
  12.  * These routines may need modification for non-Unix environments or
  13.  * specialized applications.  As they stand, they assume input from
  14.  * an ordinary stdio stream.  They further assume that reading begins
  15.  * at the start of the file; input_init may need work if the
  16.  * user interface has already read some data (e.g., to determine that
  17.  * the file is indeed PPM format).
  18.  *
  19.  * These routines are invoked via the methods get_input_row
  20.  * and input_init/term.
  21.  */
  22.  
  23. #include "jinclude.h"
  24.  
  25. #ifdef PPM_SUPPORTED
  26.  
  27.  
  28. /* Portions of this code are based on the PBMPLUS library, which is:
  29. **
  30. ** Copyright (C) 1988 by Jef Poskanzer.
  31. **
  32. ** Permission to use, copy, modify, and distribute this software and its
  33. ** documentation for any purpose and without fee is hereby granted, provided
  34. ** that the above copyright notice appear in all copies and that both that
  35. ** copyright notice and this permission notice appear in supporting
  36. ** documentation.  This software is provided "as is" without express or
  37. ** implied warranty.
  38. */
  39.  
  40.  
  41. /* Macros to deal with unsigned chars as efficiently as compiler allows */
  42.  
  43. #ifdef HAVE_UNSIGNED_CHAR
  44. typedef unsigned char U_CHAR;
  45. #define UCH(x)    ((int) (x))
  46. #else /* !HAVE_UNSIGNED_CHAR */
  47. #ifdef CHAR_IS_UNSIGNED
  48. typedef char U_CHAR;
  49. #define UCH(x)    ((int) (x))
  50. #else
  51. typedef char U_CHAR;
  52. #define UCH(x)    ((int) (x) & 0xFF)
  53. #endif
  54. #endif /* HAVE_UNSIGNED_CHAR */
  55.  
  56.  
  57. #define    ReadOK(file,buffer,len)    (JFREAD(file,buffer,len) == ((size_t) (len)))
  58.  
  59.  
  60. /*
  61.  * On most systems, reading individual bytes with getc() is drastically less
  62.  * efficient than buffering a row at a time with fread().  But we must
  63.  * allocate the row buffer in near data space on PCs, because we are assuming
  64.  * small-data memory model, wherein fread() can't reach far memory.  If you
  65.  * need to process very wide images on a PC, you may have to use the getc()
  66.  * approach.  In that case, define USE_GETC_INPUT.
  67.  */
  68.  
  69. #ifndef USE_GETC_INPUT
  70. static U_CHAR * row_buffer;    /* holds 1 pixel row's worth of raw input */
  71. #endif
  72.  
  73. static JSAMPLE * rescale;    /* => maxval-remapping array, or NULL */
  74.  
  75.  
  76. LOCAL int
  77. pbm_getc (FILE * file)
  78. /* Read next char, skipping over any comments */
  79. /* A comment/newline sequence is returned as a newline */
  80. {
  81.   register int ch;
  82.   
  83.   ch = getc(file);
  84.   if (ch == '#') {
  85.     do {
  86.       ch = getc(file);
  87.     } while (ch != '\n' && ch != EOF);
  88.   }
  89.   return ch;
  90. }
  91.  
  92.  
  93. LOCAL unsigned int
  94. read_pbm_integer (compress_info_ptr cinfo)
  95. /* Read an unsigned decimal integer from the PPM file */
  96. /* Swallows one trailing character after the integer */
  97. /* Note that on a 16-bit-int machine, only values up to 64k can be read. */
  98. /* This should not be a problem in practice. */
  99. {
  100.   register int ch;
  101.   register unsigned int val;
  102.   
  103.   /* Skip any leading whitespace */
  104.   do {
  105.     ch = pbm_getc(cinfo->input_file);
  106.     if (ch == EOF)
  107.       ERREXIT(cinfo->emethods, "Premature EOF in PPM file");
  108.   } while (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r');
  109.   
  110.   if (ch < '0' || ch > '9')
  111.     ERREXIT(cinfo->emethods, "Bogus data in PPM file");
  112.   
  113.   val = ch - '0';
  114.   while ((ch = pbm_getc(cinfo->input_file)) >= '0' && ch <= '9') {
  115.     val *= 10;
  116.     val += ch - '0';
  117.   }
  118.   return val;
  119. }
  120.  
  121.  
  122. /*
  123.  * Read one row of pixels.
  124.  *
  125.  * We provide several different versions depending on input file format.
  126.  * In all cases, input is scaled to the size of JSAMPLE; it's possible that
  127.  * when JSAMPLE is 12 bits, this would not really be desirable.
  128.  *
  129.  * Note that a really fast path is provided for reading raw files with
  130.  * maxval = MAXJSAMPLE, which is the normal case (at least for 8-bit JSAMPLEs).
  131.  */
  132.  
  133.  
  134. METHODDEF void
  135. get_text_gray_row (compress_info_ptr cinfo, JSAMPARRAY pixel_row)
  136. /* This version is for reading text-format PGM files with any maxval */
  137. {
  138.   register JSAMPROW ptr0;
  139.   register unsigned int val;
  140.   register long col;
  141.   
  142.   ptr0 = pixel_row[0];
  143.   for (col = cinfo->image_width; col > 0; col--) {
  144.     val = read_pbm_integer(cinfo);
  145.     if (rescale != NULL)
  146.       val = rescale[val];
  147.     *ptr0++ = (JSAMPLE) val;
  148.   }
  149. }
  150.  
  151.  
  152. METHODDEF void
  153. get_text_rgb_row (compress_info_ptr cinfo, JSAMPARRAY pixel_row)
  154. /* This version is for reading text-format PPM files with any maxval */
  155. {
  156.   register JSAMPROW ptr0, ptr1, ptr2;
  157.   register unsigned int val;
  158.   register long col;
  159.   
  160.   ptr0 = pixel_row[0];
  161.   ptr1 = pixel_row[1];
  162.   ptr2 = pixel_row[2];
  163.   for (col = cinfo->image_width; col > 0; col--) {
  164.     val = read_pbm_integer(cinfo);
  165.     if (rescale != NULL)
  166.       val = rescale[val];
  167.     *ptr0++ = (JSAMPLE) val;
  168.     val = read_pbm_integer(cinfo);
  169.     if (rescale != NULL)
  170.       val = rescale[val];
  171.     *ptr1++ = (JSAMPLE) val;
  172.     val = read_pbm_integer(cinfo);
  173.     if (rescale != NULL)
  174.       val = rescale[val];
  175.     *ptr2++ = (JSAMPLE) val;
  176.   }
  177. }
  178.  
  179.  
  180. #ifdef USE_GETC_INPUT
  181.  
  182.  
  183. METHODDEF void
  184. get_scaled_gray_row (compress_info_ptr cinfo, JSAMPARRAY pixel_row)
  185. /* This version is for reading raw-format PGM files with any maxval */
  186. {
  187.   register FILE * infile = cinfo->input_file;
  188.   register JSAMPROW ptr0;
  189.   register long col;
  190.   
  191.   ptr0 = pixel_row[0];
  192.   for (col = cinfo->image_width; col > 0; col--) {
  193.     *ptr0++ = rescale[getc(infile)];
  194.   }
  195. }
  196.  
  197.  
  198. METHODDEF void
  199. get_scaled_rgb_row (compress_info_ptr cinfo, JSAMPARRAY pixel_row)
  200. /* This version is for reading raw-format PPM files with any maxval */
  201. {
  202.   register FILE * infile = cinfo->input_file;
  203.   register JSAMPROW ptr0, ptr1, ptr2;
  204.   register long col;
  205.   
  206.   ptr0 = pixel_row[0];
  207.   ptr1 = pixel_row[1];
  208.   ptr2 = pixel_row[2];
  209.   for (col = cinfo->image_width; col > 0; col--) {
  210.     *ptr0++ = rescale[getc(infile)];
  211.     *ptr1++ = rescale[getc(infile)];
  212.     *ptr2++ = rescale[getc(infile)];
  213.   }
  214. }
  215.  
  216.  
  217. METHODDEF void
  218. get_raw_gray_row (compress_info_ptr cinfo, JSAMPARRAY pixel_row)
  219. /* This version is for reading raw-format PGM files with maxval = MAXJSAMPLE */
  220. {
  221.   register FILE * infile = cinfo->input_file;
  222.   register JSAMPROW ptr0;
  223.   register long col;
  224.   
  225.   ptr0 = pixel_row[0];
  226.   for (col = cinfo->image_width; col > 0; col--) {
  227.     *ptr0++ = (JSAMPLE) getc(infile);
  228.   }
  229. }
  230.  
  231.  
  232. METHODDEF void
  233. get_raw_rgb_row (compress_info_ptr cinfo, JSAMPARRAY pixel_row)
  234. /* This version is for reading raw-format PPM files with maxval = MAXJSAMPLE */
  235. {
  236.   register FILE * infile = cinfo->input_file;
  237.   register JSAMPROW ptr0, ptr1, ptr2;
  238.   register long col;
  239.   
  240.   ptr0 = pixel_row[0];
  241.   ptr1 = pixel_row[1];
  242.   ptr2 = pixel_row[2];
  243.   for (col = cinfo->image_width; col > 0; col--) {
  244.     *ptr0++ = (JSAMPLE) getc(infile);
  245.     *ptr1++ = (JSAMPLE) getc(infile);
  246.     *ptr2++ = (JSAMPLE) getc(infile);
  247.   }
  248. }
  249.  
  250.  
  251. #else /* use row buffering */
  252.  
  253.  
  254. METHODDEF void
  255. get_scaled_gray_row (compress_info_ptr cinfo, JSAMPARRAY pixel_row)
  256. /* This version is for reading raw-format PGM files with any maxval */
  257. {
  258.   register JSAMPROW ptr0;
  259.   register U_CHAR * row_bufferptr;
  260.   register long col;
  261.   
  262.   if (! ReadOK(cinfo->input_file, row_buffer, cinfo->image_width))
  263.     ERREXIT(cinfo->emethods, "Premature EOF in PPM file");
  264.   ptr0 = pixel_row[0];
  265.   row_bufferptr = row_buffer;
  266.   for (col = cinfo->image_width; col > 0; col--) {
  267.     *ptr0++ = rescale[UCH(*row_bufferptr++)];
  268.   }
  269. }
  270.  
  271.  
  272. METHODDEF void
  273. get_scaled_rgb_row (compress_info_ptr cinfo, JSAMPARRAY pixel_row)
  274. /* This version is for reading raw-format PPM files with any maxval */
  275. {
  276.   register JSAMPROW ptr0, ptr1, ptr2;
  277.   register U_CHAR * row_bufferptr;
  278.   register long col;
  279.   
  280.   if (! ReadOK(cinfo->input_file, row_buffer, 3 * cinfo->image_width))
  281.     ERREXIT(cinfo->emethods, "Premature EOF in PPM file");
  282.   ptr0 = pixel_row[0];
  283.   ptr1 = pixel_row[1];
  284.   ptr2 = pixel_row[2];
  285.   row_bufferptr = row_buffer;
  286.   for (col = cinfo->image_width; col > 0; col--) {
  287.     *ptr0++ = rescale[UCH(*row_bufferptr++)];
  288.     *ptr1++ = rescale[UCH(*row_bufferptr++)];
  289.     *ptr2++ = rescale[UCH(*row_bufferptr++)];
  290.   }
  291. }
  292.  
  293.  
  294. METHODDEF void
  295. get_raw_gray_row (compress_info_ptr cinfo, JSAMPARRAY pixel_row)
  296. /* This version is for reading raw-format PGM files with maxval = MAXJSAMPLE */
  297. {
  298.   register JSAMPROW ptr0;
  299.   register U_CHAR * row_bufferptr;
  300.   register long col;
  301.   
  302.   if (! ReadOK(cinfo->input_file, row_buffer, cinfo->image_width))
  303.     ERREXIT(cinfo->emethods, "Premature EOF in PPM file");
  304.   ptr0 = pixel_row[0];
  305.   row_bufferptr = row_buffer;
  306.   for (col = cinfo->image_width; col > 0; col--) {
  307.     *ptr0++ = (JSAMPLE) UCH(*row_bufferptr++);
  308.   }
  309. }
  310.  
  311.  
  312. METHODDEF void
  313. get_raw_rgb_row (compress_info_ptr cinfo, JSAMPARRAY pixel_row)
  314. /* This version is for reading raw-format PPM files with maxval = MAXJSAMPLE */
  315. {
  316.   register JSAMPROW ptr0, ptr1, ptr2;
  317.   register U_CHAR * row_bufferptr;
  318.   register long col;
  319.   
  320.   if (! ReadOK(cinfo->input_file, row_buffer, 3 * cinfo->image_width))
  321.     ERREXIT(cinfo->emethods, "Premature EOF in PPM file");
  322.   ptr0 = pixel_row[0];
  323.   ptr1 = pixel_row[1];
  324.   ptr2 = pixel_row[2];
  325.   row_bufferptr = row_buffer;
  326.   for (col = cinfo->image_width; col > 0; col--) {
  327.     *ptr0++ = (JSAMPLE) UCH(*row_bufferptr++);
  328.     *ptr1++ = (JSAMPLE) UCH(*row_bufferptr++);
  329.     *ptr2++ = (JSAMPLE) UCH(*row_bufferptr++);
  330.   }
  331. }
  332.  
  333.  
  334. #endif /* USE_GETC_INPUT */
  335.  
  336.  
  337. /*
  338.  * Read the file header; return image size and component count.
  339.  */
  340.  
  341. METHODDEF void
  342. input_init (compress_info_ptr cinfo)
  343. {
  344.   int c;
  345.   unsigned int w, h, maxval;
  346.  
  347.   if (getc(cinfo->input_file) != 'P')
  348.     ERREXIT(cinfo->emethods, "Not a PPM file");
  349.  
  350.   c = getc(cinfo->input_file);    /* save format discriminator for a sec */
  351.  
  352.   w = read_pbm_integer(cinfo);    /* while we fetch the header info */
  353.   h = read_pbm_integer(cinfo);
  354.   maxval = read_pbm_integer(cinfo);
  355.  
  356.   if (w <= 0 || h <= 0 || maxval <= 0) /* error check */
  357.     ERREXIT(cinfo->emethods, "Not a PPM file");
  358.  
  359.   switch (c) {
  360.   case '2':            /* it's a text-format PGM file */
  361.     cinfo->methods->get_input_row = get_text_gray_row;
  362.     cinfo->input_components = 1;
  363.     cinfo->in_color_space = CS_GRAYSCALE;
  364.     TRACEMS2(cinfo->emethods, 1, "%ux%u text PGM image", w, h);
  365.     break;
  366.  
  367.   case '3':            /* it's a text-format PPM file */
  368.     cinfo->methods->get_input_row = get_text_rgb_row;
  369.     cinfo->input_components = 3;
  370.     cinfo->in_color_space = CS_RGB;
  371.     TRACEMS2(cinfo->emethods, 1, "%ux%u text PPM image", w, h);
  372.     break;
  373.  
  374.   case '5':            /* it's a raw-format PGM file */
  375.     if (maxval == MAXJSAMPLE)
  376.       cinfo->methods->get_input_row = get_raw_gray_row;
  377.     else
  378.       cinfo->methods->get_input_row = get_scaled_gray_row;
  379.     cinfo->input_components = 1;
  380.     cinfo->in_color_space = CS_GRAYSCALE;
  381. #ifndef USE_GETC_INPUT
  382.     /* allocate space for row buffer: 1 byte/pixel */
  383.     row_buffer = (U_CHAR *) (*cinfo->emethods->alloc_small)
  384.             ((size_t) (SIZEOF(U_CHAR) * (long) w));
  385. #endif
  386.     TRACEMS2(cinfo->emethods, 1, "%ux%u PGM image", w, h);
  387.     break;
  388.  
  389.   case '6':            /* it's a raw-format PPM file */
  390.     if (maxval == MAXJSAMPLE)
  391.       cinfo->methods->get_input_row = get_raw_rgb_row;
  392.     else
  393.       cinfo->methods->get_input_row = get_scaled_rgb_row;
  394.     cinfo->input_components = 3;
  395.     cinfo->in_color_space = CS_RGB;
  396. #ifndef USE_GETC_INPUT
  397.     /* allocate space for row buffer: 3 bytes/pixel */
  398.     row_buffer = (U_CHAR *) (*cinfo->emethods->alloc_small)
  399.             ((size_t) (3 * SIZEOF(U_CHAR) * (long) w));
  400. #endif
  401.     TRACEMS2(cinfo->emethods, 1, "%ux%u PPM image", w, h);
  402.     break;
  403.  
  404.   default:
  405.     ERREXIT(cinfo->emethods, "Not a PPM file");
  406.     break;
  407.   }
  408.  
  409.   /* Compute the rescaling array if necessary */
  410.   /* This saves per-pixel calculation */
  411.   if (maxval == MAXJSAMPLE)
  412.     rescale = NULL;        /* no rescaling required */
  413.   else {
  414.     INT32 val, half_maxval;
  415.  
  416.     /* On 16-bit-int machines we have to be careful of maxval = 65535 */
  417.     rescale = (JSAMPLE *) (*cinfo->emethods->alloc_small)
  418.             ((size_t) (((long) maxval + 1L) * SIZEOF(JSAMPLE)));
  419.     half_maxval = maxval / 2;
  420.     for (val = 0; val <= (INT32) maxval; val++) {
  421.       /* The multiplication here must be done in 32 bits to avoid overflow */
  422.       rescale[val] = (JSAMPLE) ((val * MAXJSAMPLE + half_maxval) / maxval);
  423.     }
  424.   }
  425.  
  426.   cinfo->image_width = w;
  427.   cinfo->image_height = h;
  428.   cinfo->data_precision = BITS_IN_JSAMPLE;
  429. }
  430.  
  431.  
  432. /*
  433.  * Finish up at the end of the file.
  434.  */
  435.  
  436. METHODDEF void
  437. input_term (compress_info_ptr cinfo)
  438. {
  439.   /* no work (we let free_all release the workspace) */
  440. }
  441.  
  442.  
  443. /*
  444.  * The method selection routine for PPM format input.
  445.  * Note that this must be called by the user interface before calling
  446.  * jpeg_compress.  If multiple input formats are supported, the
  447.  * user interface is responsible for discovering the file format and
  448.  * calling the appropriate method selection routine.
  449.  */
  450.  
  451. GLOBAL void
  452. jselrppm (compress_info_ptr cinfo)
  453. {
  454.   cinfo->methods->input_init = input_init;
  455.   /* cinfo->methods->get_input_row is set by input_init */
  456.   cinfo->methods->input_term = input_term;
  457. }
  458.  
  459. #endif /* PPM_SUPPORTED */
  460.