/* * pngxrjpg.c - libpng external I/O: JPEG reader stub. * Copyright (C) 2006-2011 Cosmin Truta. * * From the information-theoretic point of view, JPEG-to-PNG conversion * is not a worthwhile task. Moreover, a JPEG decoder would add a * significant overhead to the application. As such, we provide a stub * that recognizes the JPEG format, without actually processing it. */ #include "pngxtern.h" #include #include #define PNGX_INTERNAL #include "pngxpriv.h" /* * These are the various JPEG format signatures. * * FF D8 FF E0 ........................... JFIF * FF D8 FF E1 ........................... EXIF * FF D8 FF F7 ........................... JPEG-LS * FF 4F FF 51 ........................... JPEG-2000 codestream * 00 00 00 0C 6A 50 20 20 0D 0A 87 0A ... JPEG-2000 .jp2 * 8B 4A 4E 47 0D 0A 1A 0A ............... JNG * 00 00 00 10 4A 48 44 52 ............... JNG datastream * etc. */ #define JPEG_SIG_JP2_SIZE 12 #define JPEG_SIG_JPC_SIZE 4 #define JPEG_SIG_JNG_SIZE 8 #define JPEG_SIG_SIZE_MAX 12 static const png_byte jpeg_sig_jp2[JPEG_SIG_JP2_SIZE] = { 0x00, 0x00, 0x00, 0x0c, 0x6a, 0x50, 0x20, 0x20, 0x0d, 0x0a, 0x87, 0x0a }; static const png_byte jpeg_sig_jpc[JPEG_SIG_JPC_SIZE] = { 0xff, 0x4f, 0xff, 0x51 }; static const png_byte jpeg_sig_jng[JPEG_SIG_JNG_SIZE] = { 0x8b, 0x4a, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a }; static const png_byte jpeg_sig_jng_jhdr[JPEG_SIG_JNG_SIZE] = { 0x00, 0x00, 0x00, 0x1a, 0x4a, 0x48, 0x44, 0x52 }; int /* PRIVATE */ pngx_sig_is_jpeg(png_bytep sig, size_t sig_size, png_const_charpp fmt_name_ptr, png_const_charpp fmt_long_name_ptr) { const char *fmt; unsigned int marker; int result; if (sig_size < JPEG_SIG_SIZE_MAX) return -1; if (sig[0] == 0xff && sig[1] == 0xd8 && sig[2] == 0xff) { marker = 0xff00U | sig[3]; if ((marker >= 0xffc0U && marker <= 0xffcfU) || (marker >= 0xffdaU && marker <= 0xfffeU)) { fmt = "JPEG"; result = 1; /* JFIF, EXIF, JPEG-LS, codestream, etc. */ } else return 0; /* not JPEG */ } else if (memcmp(sig, jpeg_sig_jp2, JPEG_SIG_JP2_SIZE) == 0 || memcmp(sig, jpeg_sig_jpc, JPEG_SIG_JPC_SIZE) == 0) { fmt = "JPEG-2000"; result = 2; /* .jp2 or JPEG-2000 codestream */ } else if (memcmp(sig, jpeg_sig_jng, JPEG_SIG_JNG_SIZE) == 0 || memcmp(sig, jpeg_sig_jng_jhdr, JPEG_SIG_JNG_SIZE) == 0) { fmt = "JNG"; result = 3; /* JNG, standalone or datastream */ } else return 0; /* not JPEG */ /* Store the format name. */ if (fmt_name_ptr != NULL) *fmt_name_ptr = fmt; if (fmt_long_name_ptr != NULL) *fmt_long_name_ptr = fmt; return result; } int /* PRIVATE */ pngx_read_jpeg(png_structp png_ptr, png_infop info_ptr, FILE *stream) { png_byte buf[JPEG_SIG_SIZE_MAX]; int sig_code; if (fread(buf, JPEG_SIG_SIZE_MAX, 1, stream) != 1) return 0; /* not a JPEG file */ sig_code = pngx_sig_is_jpeg(buf, JPEG_SIG_SIZE_MAX, NULL, NULL); /* TODO: Use the format names passed by pngx_sig_is_jpeg. */ switch (sig_code) { case 1: png_error(png_ptr, "JPEG decoding is not supported"); /* NOTREACHED */ break; case 2: png_error(png_ptr, "JPEG-2000 decoding is not supported"); /* NOTREACHED */ break; case 3: png_error(png_ptr, "JNG (JPEG) decoding is not supported"); /* NOTREACHED */ break; } if (info_ptr == NULL) /* dummy, keep compilers happy */ return 0; return 0; /* always fail */ }