blob: 4f8063225ee273d85c7d59258e99da5383d5628d [file] [log] [blame]
/*
* 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 <stdio.h>
#include <string.h>
#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 */
}