📄 tinyjpeg.c
字号:
sampling_factor = *stream++; Q_table = *stream++; c = &priv->component_infos[i];#if SANITY_CHECK c->cid = cid; if (Q_table >= COMPONENTS) error("Bad Quantization table index (got %d, max allowed %d)\n", Q_table, COMPONENTS-1);#endif 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; trace("< SOF marker\n"); 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 YCbCr 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"); if (cid != priv->component_infos[i].cid) error("SOS cid order (%d:%d) isn't compatible with the SOF marker (%d:%d)\n", i, cid, i, priv->component_infos[i].cid); trace("ComponentId:%d tableAC:%d tableDC:%d\n", cid, table&0xf, table>>4);#endif priv->component_infos[i].AC_table = &priv->HTAC[table&0xf]; priv->component_infos[i].DC_table = &priv->HTDC[table>>4]; } priv->stream = stream+3; trace("< SOS marker\n"); 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 >= HUFFMAN_BITS_SIZE) error("No more than %d bytes is allowed to describe a huffman table", HUFFMAN_BITS_SIZE); if ( (index &0xf) >= HUFFMAN_TABLES) error("No more than %d Huffman tables is supported (got %d)\n", HUFFMAN_TABLES, index&0xf); trace("Huffman table %s[%d] length=%d\n", (index&0xf0)?"AC":"DC", index&0xf, 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 int parse_DRI(struct jdec_private *priv, const unsigned char *stream){ unsigned int length; trace("> DRI marker\n"); length = be16_to_cpu(stream);#if SANITY_CHECK if (length != 4) error("Length of DRI marker need to be 4\n");#endif priv->restart_interval = be16_to_cpu(stream+2);#if DEBUG trace("Restart interval = %d\n", priv->restart_interval);#endif trace("< DRI 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; if (priv->restart_interval > 0) priv->restarts_to_go = priv->restart_interval; else priv->restarts_to_go = -1;}static int find_next_rst_marker(struct jdec_private *priv){ int rst_marker_found = 0; int marker; const unsigned char *stream = priv->stream; /* Parse marker */ while (!rst_marker_found) { while (*stream++ != 0xff) { if (stream >= priv->stream_end) error("EOF while search for a RST marker."); } /* Skip any padding ff byte (this is normal) */ while (*stream == 0xff) stream++; marker = *stream++; if ((RST+priv->last_rst_marker_seen) == marker) rst_marker_found = 1; else if (marker >= RST && marker <= RST7) error("Wrong Reset marker found, abording"); else if (marker == EOI) return 0; } trace("RST Marker %d found at offset %d\n", priv->last_rst_marker_seen, stream - priv->stream_begin); priv->stream = stream; priv->last_rst_marker_seen++; priv->last_rst_marker_seen &= 7; return 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; case DRI: if (parse_DRI(priv, stream) < 0) return -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;}/******************************************************************************* * * 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]; if (priv->restarts_to_go>0) { priv->restarts_to_go--; if (priv->restarts_to_go == 0) { priv->stream -= (priv->nbits_in_reservoir/8); resync(priv); if (find_next_rst_marker(priv) < 0) return -1; } } } } trace("Input file size: %d\n", priv->stream_length+2); trace("Input bytes actually read: %d\n", priv->stream - priv->stream_begin + 2); return 0;}const char *tinyjpeg_get_errorstring(struct jdec_private *priv){ /* FIXME: the error string must be store in the context */ priv = 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 + -