static int scan_JPEG_header (int verbose) { int marker; /* Expect SOI at start of file */ if (first_marker() != M_SOI) ERREXIT("Expected SOI marker first"); /* Scan miscellaneous markers until we reach SOS. */ for (;;) { marker = next_marker(); switch (marker) { case M_SOF0: /* Baseline */ case M_SOF1: /* Extended sequential, Huffman */ case M_SOF2: /* Progressive, Huffman */ case M_SOF3: /* Lossless, Huffman */ case M_SOF5: /* Differential sequential, Huffman */ case M_SOF6: /* Differential progressive, Huffman */ case M_SOF7: /* Differential lossless, Huffman */ case M_SOF9: /* Extended sequential, arithmetic */ case M_SOF10: /* Progressive, arithmetic */ case M_SOF11: /* Lossless, arithmetic */ case M_SOF13: /* Differential sequential, arithmetic */ case M_SOF14: /* Differential progressive, arithmetic */ case M_SOF15: /* Differential lossless, arithmetic */ if (verbose) process_SOFn(marker); else skip_variable(); break; case M_SOS: /* stop before hitting compressed data */ return marker; case M_EOI: /* in case it's a tables-only JPEG stream */ return marker; case M_COM: process_COM(); break; default: /* Anything else just gets skipped */ skip_variable(); /* we assume it has a parameter count... */ break; } } /* end loop */ }
static int get_jpeg_image_dimensions(ImageSize *is, int *width, int *height) { int marker = -1, jpeg_ok = 0; *width = *height = -1; if (is->infile || !is->file) { /* Expect SOI at start of file */ if (first_marker(is) == M_SOI) { jpeg_ok = 1; /* Scan miscellaneous markers until we reach SOS. */ for (; marker != M_SOS && marker != M_EOI; ) { marker = next_marker(is); switch (marker) { /* Note that marker codes 0xC4, 0xC8, 0xCC are not, and must not be, * treated as SOFn. C4 in particular is actually DHT. */ case M_SOF0: /* Baseline */ case M_SOF1: /* Extended sequential, Huffman */ case M_SOF2: /* Progressive, Huffman */ case M_SOF3: /* Lossless, Huffman */ case M_SOF5: /* Differential sequential, Huffman */ case M_SOF6: /* Differential progressive, Huffman */ case M_SOF7: /* Differential lossless, Huffman */ case M_SOF9: /* Extended sequential, arithmetic */ case M_SOF10: /* Progressive, arithmetic */ case M_SOF11: /* Lossless, arithmetic */ case M_SOF13: /* Differential sequential, arithmetic */ case M_SOF14: /* Differential progressive, arithmetic */ case M_SOF15: /* Differential lossless, arithmetic */ get_image_dimensions(is, width, height); break; default: /* Anything else just gets skipped */ if (skip_variable(is) < 0) return -1; break; } } } } return jpeg_ok; }
static int scan_JPEG_header (int verbose) { int marker; /* Expect SOI at start of file */ if (first_marker() != M_SOI) ERREXIT("Expected SOI marker first"); /* Scan miscellaneous markers until we reach SOS. */ for (;;) { marker = next_marker(); switch (marker) { /* Note that marker codes 0xC4, 0xC8, 0xCC are not, and must not be, * treated as SOFn. C4 in particular is actually DHT. */ case M_SOF0: /* Baseline */ case M_SOF1: /* Extended sequential, Huffman */ case M_SOF2: /* Progressive, Huffman */ case M_SOF3: /* Lossless, Huffman */ case M_SOF5: /* Differential sequential, Huffman */ case M_SOF6: /* Differential progressive, Huffman */ case M_SOF7: /* Differential lossless, Huffman */ case M_SOF9: /* Extended sequential, arithmetic */ case M_SOF10: /* Progressive, arithmetic */ case M_SOF11: /* Lossless, arithmetic */ case M_SOF13: /* Differential sequential, arithmetic */ case M_SOF14: /* Differential progressive, arithmetic */ case M_SOF15: /* Differential lossless, arithmetic */ if (verbose) process_SOFn(marker); else skip_variable(); break; case M_SOS: /* stop before hitting compressed data */ return marker; case M_EOI: /* in case it's a tables-only JPEG stream */ return marker; case M_COM: process_COM(); break; case M_APP12: /* Some digital camera makers put useful textual information into * APP12 markers, so we print those out too when in -verbose mode. */ if (verbose) { printf("APP12 contains:\n"); process_COM(); } else skip_variable(); break; default: /* Anything else just gets skipped */ skip_variable(); /* we assume it has a parameter count... */ break; } } /* end loop */ }
/** Read image info * @param info the information structure * @param comm (output) pointer to the comment structure (optional) * @param file the file pointer to the image * @return NULL on success, error message on failure */ const char* readinfo (struct imageinfo* info, struct comment** comm, FILE* file) { memset (info, 0, sizeof *info); if (read_word (file) != 0xffd8) return "not a JPEG image file"; /* scan markers until SOS */ for (;;) { unsigned length; int marker = next_marker (file); if (marker == EOF) { eof: return "premature end of file"; } if ((marker & 0xf0) == 0xc0 && marker != 0xc4 && marker != 0xcc) { /* start of frame marker (image dimensions) */ /** number of colour components */ int c; length = read_word (file); if (length < 2) goto invalid_length; (void) getc (file); /* skip data precision */ info->height = read_word (file); info->width = read_word (file); c = getc (file); if (c == EOF) goto eof; if (length != (8 + ((unsigned) c) * 3)) return "inconsistent SOF marker length"; while (c--) if (getc (file) == EOF /* component ID code */ || getc (file) == EOF /* sampling factors */ || getc (file) == EOF /* quantization table number */) goto eof; continue; } else switch (marker) { case 0xfe: if (!comm) goto skip_marker; /* comment */ length = read_word (file); if (length < 2) goto invalid_length; else { /* read the image comment */ struct comment* comment = malloc (length + sizeof *comment); if (!comment) return "out of memory"; length -= 2; comment->next = 0; if (length != fread (comment->text, 1, length, file)) { free (comment); goto eof; } comment->text[length] = 0; /* append the comment to the list */ if (!*comm) *comm = comment; else { struct comment* c; for (c = *comm; c->next; c = c->next); c->next = comment; } } continue; case 0xda: /* start of scan (compressed data) */ case 0xd9: /* end of image */ return 0; } if (feof (file)) goto eof; skip_marker: /* skip the rest of the marker */ length = read_word (file); if (length < 2) { invalid_length: return "erroneous JPEG marker length"; } length -= 2; while (length--) if (getc (file) == EOF) goto eof; } }
/* analyze JPEG marker */ BOOL AnalyzeJPEG P1(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 = get_2bytes(image->fp); image->width = 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] = 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] = 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; }