Logo Search packages:      
Sourcecode: jpeg2ps version File versions  Download package

readjpeg.c

/* ------------------------- readjpeg.c ------------------------- */
/* (C) Thomas Merz 1994-2002 */

#include <stdio.h>
#include <string.h>

/* try to identify Mac compilers */
#ifdef __MWERKS__
#if __POWERPC__ || __CFM68K__ || __MC68K_
#define MAC
#else
#define DOS
#endif
#endif /* __MWERKS__ */

#ifndef DOS
#include <unistd.h>
#endif

#include "psimage.h"

/* The following enum is stolen from the IJG JPEG library
 * Comments added by tm
 * This table contains far too many names since jpeg2ps
 * is rather simple-minded about markers
 */

extern BOOL quiet;

typedef enum {          /* JPEG marker codes                */
  M_SOF0  = 0xc0, /* baseline DCT                     */
  M_SOF1  = 0xc1, /* extended sequential DCT          */
  M_SOF2  = 0xc2, /* progressive DCT                  */
  M_SOF3  = 0xc3, /* lossless (sequential)            */
  
  M_SOF5  = 0xc5, /* differential sequential DCT            */
  M_SOF6  = 0xc6, /* differential progressive DCT           */
  M_SOF7  = 0xc7, /* differential lossless            */
  
  M_JPG   = 0xc8, /* JPEG extensions                  */
  M_SOF9  = 0xc9, /* extended sequential DCT          */
  M_SOF10 = 0xca, /* progressive DCT                  */
  M_SOF11 = 0xcb, /* lossless (sequential)            */
  
  M_SOF13 = 0xcd, /* differential sequential DCT            */
  M_SOF14 = 0xce, /* differential progressive DCT           */
  M_SOF15 = 0xcf, /* differential lossless            */
  
  M_DHT   = 0xc4, /* define Huffman tables            */
  
  M_DAC   = 0xcc, /* define arithmetic conditioning table   */
  
  M_RST0  = 0xd0, /* restart                    */
  M_RST1  = 0xd1, /* restart                    */
  M_RST2  = 0xd2, /* restart                    */
  M_RST3  = 0xd3, /* restart                    */
  M_RST4  = 0xd4, /* restart                    */
  M_RST5  = 0xd5, /* restart                    */
  M_RST6  = 0xd6, /* restart                    */
  M_RST7  = 0xd7, /* restart                    */
  
  M_SOI   = 0xd8, /* start of image             */
  M_EOI   = 0xd9, /* end of image                     */
  M_SOS   = 0xda, /* start of scan              */
  M_DQT   = 0xdb, /* define quantization tables       */
  M_DNL   = 0xdc, /* define number of lines           */
  M_DRI   = 0xdd, /* define restart interval          */
  M_DHP   = 0xde, /* define hierarchical progression  */
  M_EXP   = 0xdf, /* expand reference image(s)        */
  
  M_APP0  = 0xe0, /* application marker, used for JFIF      */
  M_APP1  = 0xe1, /* application marker               */
  M_APP2  = 0xe2, /* application marker               */
  M_APP3  = 0xe3, /* application marker               */
  M_APP4  = 0xe4, /* application marker               */
  M_APP5  = 0xe5, /* application marker               */
  M_APP6  = 0xe6, /* application marker               */
  M_APP7  = 0xe7, /* application marker               */
  M_APP8  = 0xe8, /* application marker               */
  M_APP9  = 0xe9, /* application marker               */
  M_APP10 = 0xea, /* application marker               */
  M_APP11 = 0xeb, /* application marker               */
  M_APP12 = 0xec, /* application marker               */
  M_APP13 = 0xed, /* application marker               */
  M_APP14 = 0xee, /* application marker, used by Adobe      */
  M_APP15 = 0xef, /* application marker               */
  
  M_JPG0  = 0xf0, /* reserved for JPEG extensions           */
  M_JPG13 = 0xfd, /* reserved for JPEG extensions           */
  M_COM   = 0xfe, /* comment                    */
  
  M_TEM   = 0x01, /* temporary use              */

  M_ERROR = 0x100 /* dummy marker, internal use only  */
} JPEG_MARKER;

/*
 * The following routine used to be a macro in its first incarnation:
 *  #define get_2bytes(fp) ((unsigned int) (getc(fp) << 8) + getc(fp))
 * However, this is bad programming since C doesn't guarantee
 * the evaluation order of the getc() calls! As suggested by
 * Murphy's law, there are indeed compilers which produce the wrong
 * order of the getc() calls, e.g. the Metrowerks C compilers for BeOS
 * and Macintosh.
 * Since there are only few calls we don't care about the performance 
 * penalty and use a simplistic C function.
 */

/* read two byte parameter, MSB first */
static unsigned int
get_2bytes(FILE *fp)
{
    unsigned int val;
    val = (unsigned int) (getc(fp) << 8);
    val += (unsigned int) (getc(fp));
    return val;
}

static int 
next_marker(FILE *fp)
{ /* look for next JPEG Marker  */
  int c, nbytes = 0;

  if (feof(fp))
    return M_ERROR;                 /* dummy marker               */

  do {
    do {                            /* skip to FF             */
      nbytes++;
      c = getc(fp);
    } while (c != 0xFF);
    do {                            /* skip repeated FFs      */
      c = getc(fp);
    } while (c == 0xFF);
  } while (c == 0);                 /* repeat if FF/00                    */

  return c;
}

/* analyze JPEG marker */
BOOL AnalyzeJPEG(imagedata *image) {
  int b, c, unit;
  unsigned long i, length = 0;
#define APP_MAX 255
  unsigned char appstring[APP_MAX];
  BOOL SOF_done = FALSE;

  /* Tommy's special trick for Macintosh JPEGs: simply skip some  */
  /* hundred bytes at the beginning of the file!              */
  do {
    do {                            /* skip if not FF               */
      c = getc(image->fp);
    } while (!feof(image->fp) && c != 0xFF);

    do {                            /* skip repeated FFs      */
      c = getc(image->fp);
    } while (c == 0xFF);

    /* remember start position */
    if ((image->startpos = ftell(image->fp)) < 0L) {
      fprintf(stderr, "Error: internal error in ftell()!\n");
      return FALSE;
    }
    image->startpos -= 2;           /* subtract marker length     */

    if (c == M_SOI) {
      fseek(image->fp, image->startpos, SEEK_SET);
      break;
    }
  } while (!feof(image->fp));

  if (feof(image->fp)) {
    fprintf(stderr, "Error: SOI marker not found!\n");
    return FALSE;
  }

  if (image->startpos > 0L && !quiet) {
    fprintf(stderr, "Note: skipped %ld bytes ", image->startpos);
    fprintf(stderr, "Probably Macintosh JPEG file?\n");
  }

  /* process JPEG markers */
  while (!SOF_done && (c = next_marker(image->fp)) != M_EOI) {
    switch (c) {
      case M_ERROR:
      fprintf(stderr, "Error: unexpected end of JPEG file!\n");
      return FALSE;

      /* The following are not officially supported in PostScript level 2 */
      case M_SOF2:
      case M_SOF3:
      case M_SOF5:
      case M_SOF6:
      case M_SOF7:
      case M_SOF9:
      case M_SOF10:
      case M_SOF11:
      case M_SOF13:
      case M_SOF14:
      case M_SOF15:
      fprintf(stderr, 
         "Warning: JPEG file uses compression method %X - proceeding anyway.\n",
              c);
        fprintf(stderr, 
            "PostScript output does not work on all PS interpreters!\n");
      /* FALLTHROUGH */

      case M_SOF0:
      case M_SOF1:
      length = get_2bytes(image->fp);    /* read segment length  */

      image->bits_per_component = getc(image->fp);
      image->height             = (int) get_2bytes(image->fp);
      image->width              = (int) get_2bytes(image->fp);
      image->components         = getc(image->fp);

      SOF_done = TRUE;
      break;

      case M_APP0:            /* check for JFIF marker with resolution */
      length = get_2bytes(image->fp);

      for (i = 0; i < length-2; i++) {    /* get contents of marker */
        b = getc(image->fp);
        if (i < APP_MAX)                  /* store marker in appstring */
          appstring[i] = (unsigned char) b;
      }

      /* Check for JFIF application marker and read density values
       * per JFIF spec version 1.02.
       * We only check X resolution, assuming X and Y resolution are equal.
       * Use values only if resolution not preset by user or to be ignored.
       */

#define ASPECT_RATIO    0     /* JFIF unit byte: aspect ratio only */
#define DOTS_PER_INCH   1     /* JFIF unit byte: dots per inch     */
#define DOTS_PER_CM     2     /* JFIF unit byte: dots per cm       */

      if (image->dpi == DPI_USE_FILE && length >= 14 &&
          !strncmp((const char *)appstring, "JFIF", 4)) {
        unit = appstring[7];                /* resolution unit */
                                    /* resolution value */
        image->dpi = (float) ((appstring[8]<<8) + appstring[9]);

        if (image->dpi == 0.0) {
          image->dpi = DPI_USE_FILE;
          break;
        }

        switch (unit) {
          /* tell the caller we didn't find a resolution value */
          case ASPECT_RATIO:
            image->dpi = DPI_USE_FILE;
            break;

          case DOTS_PER_INCH:
            break;

          case DOTS_PER_CM:
            image->dpi *= (float) 2.54;
            break;

          default:                        /* unknown ==> ignore */
            fprintf(stderr, 
            "Warning: JPEG file contains unknown JFIF resolution unit - ignored!\n");
            image->dpi = DPI_IGNORE;
            break;
        }
      }
        break;

      case M_APP14:                       /* check for Adobe marker */
      length = get_2bytes(image->fp);

      for (i = 0; i < length-2; i++) {    /* get contents of marker */
        b = getc(image->fp);
        if (i < APP_MAX)                  /* store marker in appstring */
          appstring[i] = (unsigned char) b;
      }

      /* Check for Adobe application marker. It is known (per Adobe's TN5116)
       * to contain the string "Adobe" at the start of the APP14 marker.
       */
      if (length >= 12 && !strncmp((const char *) appstring, "Adobe", 5))
        image->adobe = TRUE;              /* set Adobe flag */

      break;

      case M_SOI:       /* ignore markers without parameters */
      case M_EOI:
      case M_TEM:
      case M_RST0:
      case M_RST1:
      case M_RST2:
      case M_RST3:
      case M_RST4:
      case M_RST5:
      case M_RST6:
      case M_RST7:
      break;

      default:                /* skip variable length markers */
      length = get_2bytes(image->fp);
      for (length -= 2; length > 0; length--)
        (void) getc(image->fp);
      break;
    }
  }

  /* do some sanity checks with the parameters */
  if (image->height <= 0 || image->width <= 0 || image->components <= 0) {
    fprintf(stderr, "Error: DNL marker not supported in PostScript Level 2!\n");
    return FALSE;
  }

  /* some broken JPEG files have this but they print anyway... */
  if (length != (unsigned int) (image->components * 3 + 8))
    fprintf(stderr, "Warning: SOF marker has incorrect length - ignored!\n");

  if (image->bits_per_component != 8) {
    fprintf(stderr, "Error: %d bits per color component ",
      image->bits_per_component);
    fprintf(stderr, "not supported in PostScript level 2!\n");
    return FALSE;
  }

  if (image->components!=1 && image->components!=3 && image->components!=4) {
    fprintf(stderr, "Error: unknown color space (%d components)!\n",
      image->components);
    return FALSE;
  }

  return TRUE;
}

Generated by  Doxygen 1.6.0   Back to index