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