Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

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