📄 tinyjpeg.cxx
字号:
* use a multiplication rather than a division.
*/
int i, j;
static const double aanscalefactor[8] = {
1.0, 1.387039845, 1.306562965, 1.175875602,
1.0, 0.785694958, 0.541196100, 0.275899379
};
const unsigned char *zz = zigzag;
for (i=0; i<8; i++) {
for (j=0; j<8; j++) {
*qtable++ = ref_table[*zz++] * aanscalefactor[i] * aanscalefactor[j];
}
}
}
static int parse_DQT(struct jdec_private *priv, const unsigned char *stream)
{
int length, qi;
float *table;
trace("> DQT marker\n");
length = be16_to_cpu(stream) - 2;
stream += 2; /* Skip length */
while (length>0)
{
qi = *stream++;
#if SANITY_CHECK
if (qi>>4)
error("16 bits quantization table is not supported\n");
if (qi>4)
error("No more 4 quantization table is supported (got %d)\n", qi);
#endif
table = priv->Q_tables[qi];
build_quantization_table(table, stream);
stream += 64;
length -= 65;
}
return 0;
}
static int parse_SOF(struct jdec_private *priv, const unsigned char *stream)
{
int i, width, height, nr_components, cid, sampling_factor;
int Q_table;
struct component *c;
print_SOF(stream);
height = be16_to_cpu(stream+3);
width = be16_to_cpu(stream+5);
nr_components = stream[7];
#if SANITY_CHECK
if (stream[2] != 8)
error("Precision other than 8 is not supported\n");
if (width>2048 || height>2048)
error("Width and Height (%dx%d) seems suspicious\n", width, height);
if (nr_components != 3)
error("We only support YUV images\n");
if (height%16)
error("Height need to be a multiple of 16 (current height is %d)\n", height);
if (width%16)
error("Width need to be a multiple of 16 (current Width is %d)\n", width);
#endif
stream += 8;
for (i=0; i<nr_components; i++) {
cid = *stream++;
sampling_factor = *stream++;
Q_table = *stream++;
c = &priv->component_infos[cid];
c->Vfactor = sampling_factor&0xf;
c->Hfactor = sampling_factor>>4;
c->Q_table = priv->Q_tables[Q_table];
trace("Component:%d factor:%dx%d Quantization table:%d\n",
cid, c->Hfactor, c->Hfactor, Q_table );
}
priv->width = width;
priv->height = height;
return 0;
}
static int parse_SOS(struct jdec_private *priv, const unsigned char *stream)
{
unsigned int i, cid, table;
unsigned int nr_components = stream[2];
trace("> SOS marker\n");
#if SANITY_CHECK
if (nr_components != 3)
error("We only support YUV image\n");
#endif
stream += 3;
for (i=0;i<nr_components;i++) {
cid = *stream++;
table = *stream++;
#if SANITY_CHECK
if ((table&0xf)>=4)
error("We do not support more than 2 AC Huffman table\n");
if ((table>>4)>=4)
error("We do not support more than 2 DC Huffman table\n");
trace("ComponentId:%d tableAC:%d tableDC:%d\n", cid, table&0xf, table>>4);
#endif
priv->component_infos[cid].AC_table = &priv->HTAC[table&0xf];
priv->component_infos[cid].DC_table = &priv->HTDC[table>>4];
}
priv->stream = stream+3;
return 0;
}
static int parse_DHT(struct jdec_private *priv, const unsigned char *stream)
{
unsigned int count, i;
unsigned char huff_bits[17];
int length, index;
length = be16_to_cpu(stream) - 2;
stream += 2; /* Skip length */
trace("> DHT marker (length=%d)\n", length);
while (length>0) {
index = *stream++;
/* We need to calculate the number of bytes 'vals' will takes */
huff_bits[0] = 0;
count = 0;
for (i=1; i<17; i++) {
huff_bits[i] = *stream++;
count += huff_bits[i];
}
#if SANITY_CHECK
if (count > 1024)
error("No more than 1024 bytes is allowed to describe a huffman table");
if ( (index &0xf) >= HUFFMAN_TABLES)
error("No mode than %d Huffman tables is supported\n", HUFFMAN_TABLES);
trace("Huffman table %s n%d\n", (index&0xf0)?"AC":"DC", index&0xf);
trace("Length of the table: %d\n", count);
#endif
if (index & 0xf0 )
build_huffman_table(huff_bits, stream, &priv->HTAC[index&0xf]);
else
build_huffman_table(huff_bits, stream, &priv->HTDC[index&0xf]);
length -= 1;
length -= 16;
length -= count;
stream += count;
}
trace("< DHT marker\n");
return 0;
}
static void resync(struct jdec_private *priv)
{
int i;
/* Init DC coefficients */
for (i=0; i<COMPONENTS; i++)
priv->component_infos[i].previous_DC = 0;
priv->reservoir = 0;
priv->nbits_in_reservoir = 0;
}
static int parse_JFIF(struct jdec_private *priv, const unsigned char *stream)
{
int chuck_len;
int marker;
int sos_marker_found = 0;
int dht_marker_found = 0;
const unsigned char *next_chunck;
/* Parse marker */
while (!sos_marker_found)
{
if (*stream++ != 0xff)
goto bogus_jpeg_format;
/* Skip any padding ff byte (this is normal) */
while (*stream == 0xff)
stream++;
marker = *stream++;
chuck_len = be16_to_cpu(stream);
next_chunck = stream + chuck_len;
switch (marker)
{
case SOF:
if (parse_SOF(priv, stream) < 0)
return -1;
break;
case DQT:
if (parse_DQT(priv, stream) < 0)
return -1;
break;
case SOS:
if (parse_SOS(priv, stream) < 0)
return -1;
sos_marker_found = 1;
break;
case DHT:
if (parse_DHT(priv, stream) < 0)
return -1;
dht_marker_found = 1;
break;
default:
trace("> Unknown marker %2.2x\n", marker);
break;
}
stream = next_chunck;
}
if (!dht_marker_found) {
trace("No Huffman table loaded, using the default one\n");
build_default_huffman_tables(priv);
}
#ifdef SANITY_CHECK
if ( (priv->component_infos[cY].Hfactor < priv->component_infos[cCb].Hfactor)
|| (priv->component_infos[cY].Hfactor < priv->component_infos[cCr].Hfactor))
error("Horizontal sampling factor for Y should be greater than horitontal sampling factor for Cb or Cr\n");
if ( (priv->component_infos[cY].Vfactor < priv->component_infos[cCb].Vfactor)
|| (priv->component_infos[cY].Vfactor < priv->component_infos[cCr].Vfactor))
error("Vertical sampling factor for Y should be greater than vertical sampling factor for Cb or Cr\n");
if ( (priv->component_infos[cCb].Hfactor!=1)
|| (priv->component_infos[cCr].Hfactor!=1)
|| (priv->component_infos[cCb].Vfactor!=1)
|| (priv->component_infos[cCr].Vfactor!=1))
error("Sampling other than 1x1 for Cr and Cb is not supported");
#endif
return 0;
bogus_jpeg_format:
trace("Bogus jpeg format\n");
return -1;
}
/*
*
* Export functions
*
*/
/*******************************************************************************
*
* Functions exported of the library.
*
* Note: Some applications can access directly to internal pointer of the
* structure. It's is not recommended, but if you have many images to
* uncompress with the same parameters, some functions can be called to speedup
* the decoding.
*
******************************************************************************/
/**
* Allocate a new tinyjpeg decoder object.
*
* Before calling any other functions, an object need to be called.
*/
struct jdec_private *tinyjpeg_init(void)
{
struct jdec_private *priv;
priv = (struct jdec_private *)calloc(1, sizeof(struct jdec_private));
if (priv == NULL)
return NULL;
return priv;
}
/**
* Free a tinyjpeg object.
*
* No others function can be called after this one.
*/
void tinyjpeg_free(struct jdec_private *priv)
{
int i;
for (i=0; i<COMPONENTS; i++) {
if (priv->components[i])
free(priv->components[i]);
priv->components[i] = NULL;
}
free(priv);
}
/**
* Initialize the tinyjpeg object and prepare the decoding of the stream.
*
* Check if the jpeg can be decoded with this jpeg decoder.
* Fill some table used for preprocessing.
*/
int tinyjpeg_parse_header(struct jdec_private *priv, const unsigned char *buf, unsigned int size)
{
int ret;
/* Identify the file */
if ((buf[0] != 0xFF) || (buf[1] != SOI))
error("Not a JPG file ?\n");
priv->stream_begin = buf+2;
priv->stream_length = size-2;
priv->stream_end = priv->stream_begin + priv->stream_length;
ret = parse_JFIF(priv, priv->stream_begin);
return ret;
}
static const decode_MCU_fct decode_mcu_3comp_table[4] = {
decode_MCU_1x1_3planes,
decode_MCU_1x2_3planes,
decode_MCU_2x1_3planes,
decode_MCU_2x2_3planes,
};
static const decode_MCU_fct decode_mcu_1comp_table[4] = {
decode_MCU_1x1_1plane,
decode_MCU_1x2_1plane,
decode_MCU_2x1_1plane,
decode_MCU_2x2_1plane,
};
static const convert_colorspace_fct convert_colorspace_yuv420p[4] = {
YCrCB_to_YUV420P_1x1,
YCrCB_to_YUV420P_1x2,
YCrCB_to_YUV420P_2x1,
YCrCB_to_YUV420P_2x2,
};
static const convert_colorspace_fct convert_colorspace_rgb24[4] = {
YCrCB_to_RGB24_1x1,
YCrCB_to_RGB24_1x2,
YCrCB_to_RGB24_2x1,
YCrCB_to_RGB24_2x2,
};
static const convert_colorspace_fct convert_colorspace_bgr24[4] = {
YCrCB_to_BGR24_1x1,
YCrCB_to_BGR24_1x2,
YCrCB_to_BGR24_2x1,
YCrCB_to_BGR24_2x2,
};
static const convert_colorspace_fct convert_colorspace_grey[4] = {
YCrCB_to_Grey_1x1,
YCrCB_to_Grey_1x2,
YCrCB_to_Grey_2x1,
YCrCB_to_Grey_2x2,
};
/**
* Decode and convert the jpeg image into @pixfmt@ image
*
* Note: components will be automaticaly allocated if no memory is attached.
*/
int tinyjpeg_decode(struct jdec_private *priv, int pixfmt)
{
unsigned int x, y, xstride_by_mcu, ystride_by_mcu;
unsigned int bytes_per_blocklines[3], bytes_per_mcu[3];
decode_MCU_fct decode_MCU;
const decode_MCU_fct *decode_mcu_table;
const convert_colorspace_fct *colorspace_array_conv;
convert_colorspace_fct convert_to_pixfmt;
if (setjmp(priv->jump_state))
return -1;
/* To keep gcc happy initialize some array */
bytes_per_mcu[1] = 0;
bytes_per_mcu[2] = 0;
bytes_per_blocklines[1] = 0;
bytes_per_blocklines[2] = 0;
decode_mcu_table = decode_mcu_3comp_table;
switch (pixfmt) {
case TINYJPEG_FMT_YUV420P:
colorspace_array_conv = convert_colorspace_yuv420p;
if (priv->components[0] == NULL)
priv->components[0] = (uint8_t *)malloc(priv->width * priv->height);
if (priv->components[1] == NULL)
priv->components[1] = (uint8_t *)malloc(priv->width * priv->height/4);
if (priv->components[2] == NULL)
priv->components[2] = (uint8_t *)malloc(priv->width * priv->height/4);
bytes_per_blocklines[0] = priv->width;
bytes_per_blocklines[1] = priv->width/4;
bytes_per_blocklines[2] = priv->width/4;
bytes_per_mcu[0] = 8;
bytes_per_mcu[1] = 4;
bytes_per_mcu[2] = 4;
break;
case TINYJPEG_FMT_RGB24:
colorspace_array_conv = convert_colorspace_rgb24;
if (priv->components[0] == NULL)
priv->components[0] = (uint8_t *)malloc(priv->width * priv->height * 3);
bytes_per_blocklines[0] = priv->width * 3;
bytes_per_mcu[0] = 3*8;
break;
case TINYJPEG_FMT_BGR24:
colorspace_array_conv = convert_colorspace_bgr24;
if (priv->components[0] == NULL)
priv->components[0] = (uint8_t *)malloc(priv->width * priv->height * 3);
bytes_per_blocklines[0] = priv->width * 3;
bytes_per_mcu[0] = 3*8;
break;
case TINYJPEG_FMT_GREY:
decode_mcu_table = decode_mcu_1comp_table;
colorspace_array_conv = convert_colorspace_grey;
if (priv->components[0] == NULL)
priv->components[0] = (uint8_t *)malloc(priv->width * priv->height);
bytes_per_blocklines[0] = priv->width;
bytes_per_mcu[0] = 8;
break;
default:
trace("Bad pixel format\n");
return -1;
}
xstride_by_mcu = ystride_by_mcu = 8;
if ((priv->component_infos[cY].Hfactor | priv->component_infos[cY].Vfactor) == 1) {
decode_MCU = decode_mcu_table[0];
convert_to_pixfmt = colorspace_array_conv[0];
trace("Use decode 1x1 sampling\n");
} else if (priv->component_infos[cY].Hfactor == 1) {
decode_MCU = decode_mcu_table[1];
convert_to_pixfmt = colorspace_array_conv[1];
ystride_by_mcu = 16;
trace("Use decode 1x2 sampling (not supported)\n");
} else if (priv->component_infos[cY].Vfactor == 2) {
decode_MCU = decode_mcu_table[3];
convert_to_pixfmt = colorspace_array_conv[3];
xstride_by_mcu = 16;
ystride_by_mcu = 16;
trace("Use decode 2x2 sampling\n");
} else {
decode_MCU = decode_mcu_table[2];
convert_to_pixfmt = colorspace_array_conv[2];
xstride_by_mcu = 16;
trace("Use decode 2x1 sampling\n");
}
resync(priv);
/* Don't forget to that block can be either 8 or 16 lines */
bytes_per_blocklines[0] *= ystride_by_mcu;
bytes_per_blocklines[1] *= ystride_by_mcu;
bytes_per_blocklines[2] *= ystride_by_mcu;
bytes_per_mcu[0] *= xstride_by_mcu/8;
bytes_per_mcu[1] *= xstride_by_mcu/8;
bytes_per_mcu[2] *= xstride_by_mcu/8;
/* Just the decode the image by macroblock (size is 8x8, 8x16, or 16x16) */
for (y=0; y < priv->height/ystride_by_mcu; y++)
{
//trace("Decoding row %d\n", y);
priv->plane[0] = priv->components[0] + (y * bytes_per_blocklines[0]);
priv->plane[1] = priv->components[1] + (y * bytes_per_blocklines[1]);
priv->plane[2] = priv->components[2] + (y * bytes_per_blocklines[2]);
for (x=0; x < priv->width; x+=xstride_by_mcu)
{
decode_MCU(priv);
convert_to_pixfmt(priv);
priv->plane[0] += bytes_per_mcu[0];
priv->plane[1] += bytes_per_mcu[1];
priv->plane[2] += bytes_per_mcu[2];
}
}
return 0;
}
const char *tinyjpeg_get_errorstring(struct jdec_private *priv)
{
return error_string;
}
void tinyjpeg_get_size(struct jdec_private *priv, unsigned int *width, unsigned int *height)
{
*width = priv->width;
*height = priv->height;
}
int tinyjpeg_get_components(struct jdec_private *priv, unsigned char **components)
{
int i;
for (i=0; priv->components[i] && i<COMPONENTS; i++)
components[i] = priv->components[i];
return 0;
}
int tinyjpeg_set_components(struct jdec_private *priv, unsigned char **components, unsigned int ncomponents)
{
unsigned int i;
if (ncomponents > COMPONENTS)
ncomponents = COMPONENTS;
for (i=0; i<ncomponents; i++)
priv->components[i] = components[i];
return 0;
}
int tinyjpeg_set_flags(struct jdec_private *priv, int flags)
{
int oldflags = priv->flags;
priv->flags = flags;
return oldflags;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -