Path: blob/master/modules/imgcodecs/src/grfmt_jpeg.cpp
16337 views
/*M///////////////////////////////////////////////////////////////////////////////////////1//2// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.3//4// By downloading, copying, installing or using the software you agree to this license.5// If you do not agree to this license, do not download, install,6// copy or use the software.7//8//9// Intel License Agreement10// For Open Source Computer Vision Library11//12// Copyright (C) 2000, Intel Corporation, all rights reserved.13// Third party copyrights are property of their respective owners.14//15// Redistribution and use in source and binary forms, with or without modification,16// are permitted provided that the following conditions are met:17//18// * Redistribution's of source code must retain the above copyright notice,19// this list of conditions and the following disclaimer.20//21// * Redistribution's in binary form must reproduce the above copyright notice,22// this list of conditions and the following disclaimer in the documentation23// and/or other materials provided with the distribution.24//25// * The name of Intel Corporation may not be used to endorse or promote products26// derived from this software without specific prior written permission.27//28// This software is provided by the copyright holders and contributors "as is" and29// any express or implied warranties, including, but not limited to, the implied30// warranties of merchantability and fitness for a particular purpose are disclaimed.31// In no event shall the Intel Corporation or contributors be liable for any direct,32// indirect, incidental, special, exemplary, or consequential damages33// (including, but not limited to, procurement of substitute goods or services;34// loss of use, data, or profits; or business interruption) however caused35// and on any theory of liability, whether in contract, strict liability,36// or tort (including negligence or otherwise) arising in any way out of37// the use of this software, even if advised of the possibility of such damage.38//39//M*/4041#include "precomp.hpp"42#include "grfmt_jpeg.hpp"4344#ifdef HAVE_JPEG4546#ifdef _MSC_VER47//interaction between '_setjmp' and C++ object destruction is non-portable48#pragma warning(disable: 4611)49#endif5051#include <stdio.h>52#include <setjmp.h>5354// the following defines are a hack to avoid multiple problems with frame ponter handling and setjmp55// see http://gcc.gnu.org/ml/gcc/2011-10/msg00324.html for some details56#define mingw_getsp(...) 057#define __builtin_frame_address(...) 05859#ifdef _WIN326061#define XMD_H // prevent redefinition of INT3262#undef FAR // prevent FAR redefinition6364#endif6566#if defined _WIN32 && defined __GNUC__67typedef unsigned char boolean;68#endif6970#undef FALSE71#undef TRUE7273extern "C" {74#include "jpeglib.h"75}7677namespace cv78{7980struct JpegErrorMgr81{82struct jpeg_error_mgr pub;83jmp_buf setjmp_buffer;84};8586struct JpegSource87{88struct jpeg_source_mgr pub;89int skip;90};9192struct JpegState93{94jpeg_decompress_struct cinfo; // IJG JPEG codec structure95JpegErrorMgr jerr; // error processing manager state96JpegSource source; // memory buffer source97};9899/////////////////////// Error processing /////////////////////100101METHODDEF(void)102stub(j_decompress_ptr)103{104}105106METHODDEF(boolean)107fill_input_buffer(j_decompress_ptr)108{109return FALSE;110}111112// emulating memory input stream113114METHODDEF(void)115skip_input_data(j_decompress_ptr cinfo, long num_bytes)116{117JpegSource* source = (JpegSource*) cinfo->src;118119if( num_bytes > (long)source->pub.bytes_in_buffer )120{121// We need to skip more data than we have in the buffer.122// This will force the JPEG library to suspend decoding.123source->skip = (int)(num_bytes - source->pub.bytes_in_buffer);124source->pub.next_input_byte += source->pub.bytes_in_buffer;125source->pub.bytes_in_buffer = 0;126}127else128{129// Skip portion of the buffer130source->pub.bytes_in_buffer -= num_bytes;131source->pub.next_input_byte += num_bytes;132source->skip = 0;133}134}135136137static void jpeg_buffer_src(j_decompress_ptr cinfo, JpegSource* source)138{139cinfo->src = &source->pub;140141// Prepare for suspending reader142source->pub.init_source = stub;143source->pub.fill_input_buffer = fill_input_buffer;144source->pub.skip_input_data = skip_input_data;145source->pub.resync_to_restart = jpeg_resync_to_restart;146source->pub.term_source = stub;147source->pub.bytes_in_buffer = 0; // forces fill_input_buffer on first read148149source->skip = 0;150}151152153METHODDEF(void)154error_exit( j_common_ptr cinfo )155{156JpegErrorMgr* err_mgr = (JpegErrorMgr*)(cinfo->err);157158/* Return control to the setjmp point */159longjmp( err_mgr->setjmp_buffer, 1 );160}161162163/////////////////////// JpegDecoder ///////////////////164165166JpegDecoder::JpegDecoder()167{168m_signature = "\xFF\xD8\xFF";169m_state = 0;170m_f = 0;171m_buf_supported = true;172}173174175JpegDecoder::~JpegDecoder()176{177close();178}179180181void JpegDecoder::close()182{183if( m_state )184{185JpegState* state = (JpegState*)m_state;186jpeg_destroy_decompress( &state->cinfo );187delete state;188m_state = 0;189}190191if( m_f )192{193fclose( m_f );194m_f = 0;195}196197m_width = m_height = 0;198m_type = -1;199}200201ImageDecoder JpegDecoder::newDecoder() const202{203return makePtr<JpegDecoder>();204}205206bool JpegDecoder::readHeader()207{208volatile bool result = false;209close();210211JpegState* state = new JpegState;212m_state = state;213state->cinfo.err = jpeg_std_error(&state->jerr.pub);214state->jerr.pub.error_exit = error_exit;215216if( setjmp( state->jerr.setjmp_buffer ) == 0 )217{218jpeg_create_decompress( &state->cinfo );219220if( !m_buf.empty() )221{222jpeg_buffer_src(&state->cinfo, &state->source);223state->source.pub.next_input_byte = m_buf.ptr();224state->source.pub.bytes_in_buffer = m_buf.cols*m_buf.rows*m_buf.elemSize();225}226else227{228m_f = fopen( m_filename.c_str(), "rb" );229if( m_f )230jpeg_stdio_src( &state->cinfo, m_f );231}232233if (state->cinfo.src != 0)234{235jpeg_read_header( &state->cinfo, TRUE );236237state->cinfo.scale_num=1;238state->cinfo.scale_denom = m_scale_denom;239m_scale_denom=1; // trick! to know which decoder used scale_denom see imread_240jpeg_calc_output_dimensions(&state->cinfo);241m_width = state->cinfo.output_width;242m_height = state->cinfo.output_height;243m_type = state->cinfo.num_components > 1 ? CV_8UC3 : CV_8UC1;244result = true;245}246}247248if( !result )249close();250251return result;252}253254/***************************************************************************255* following code is for supporting MJPEG image files256* based on a message of Laurent Pinchart on the video4linux mailing list257***************************************************************************/258259/* JPEG DHT Segment for YCrCb omitted from MJPEG data */260static261unsigned char my_jpeg_odml_dht[0x1a4] = {2620xff, 0xc4, 0x01, 0xa2,2632640x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00,2650x00, 0x00, 0x00, 0x00, 0x00,2660x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,2672680x01, 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,2690x00, 0x00, 0x00, 0x00, 0x00,2700x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,2712720x10, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, 0x05, 0x05, 0x04,2730x04, 0x00, 0x00, 0x01, 0x7d,2740x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06,2750x13, 0x51, 0x61, 0x07,2760x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, 0x23, 0x42, 0xb1, 0xc1,2770x15, 0x52, 0xd1, 0xf0,2780x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, 0x17, 0x18, 0x19, 0x1a,2790x25, 0x26, 0x27, 0x28,2800x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45,2810x46, 0x47, 0x48, 0x49,2820x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65,2830x66, 0x67, 0x68, 0x69,2840x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x83, 0x84, 0x85,2850x86, 0x87, 0x88, 0x89,2860x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3,2870xa4, 0xa5, 0xa6, 0xa7,2880xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba,2890xc2, 0xc3, 0xc4, 0xc5,2900xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8,2910xd9, 0xda, 0xe1, 0xe2,2920xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf1, 0xf2, 0xf3, 0xf4,2930xf5, 0xf6, 0xf7, 0xf8,2940xf9, 0xfa,2952960x11, 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x07, 0x05, 0x04,2970x04, 0x00, 0x01, 0x02, 0x77,2980x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41,2990x51, 0x07, 0x61, 0x71,3000x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xa1, 0xb1, 0xc1, 0x09,3010x23, 0x33, 0x52, 0xf0,3020x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1, 0x17,3030x18, 0x19, 0x1a, 0x26,3040x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44,3050x45, 0x46, 0x47, 0x48,3060x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64,3070x65, 0x66, 0x67, 0x68,3080x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x82, 0x83,3090x84, 0x85, 0x86, 0x87,3100x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a,3110xa2, 0xa3, 0xa4, 0xa5,3120xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8,3130xb9, 0xba, 0xc2, 0xc3,3140xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6,3150xd7, 0xd8, 0xd9, 0xda,3160xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4,3170xf5, 0xf6, 0xf7, 0xf8,3180xf9, 0xfa319};320321/*322* Parse the DHT table.323* This code comes from jpeg6b (jdmarker.c).324*/325static326int my_jpeg_load_dht (struct jpeg_decompress_struct *info, unsigned char *dht,327JHUFF_TBL *ac_tables[], JHUFF_TBL *dc_tables[])328{329unsigned int length = (dht[2] << 8) + dht[3] - 2;330unsigned int pos = 4;331unsigned int count, i;332int index;333334JHUFF_TBL **hufftbl;335unsigned char bits[17];336unsigned char huffval[256] = {0};337338while (length > 16)339{340bits[0] = 0;341index = dht[pos++];342count = 0;343for (i = 1; i <= 16; ++i)344{345bits[i] = dht[pos++];346count += bits[i];347}348length -= 17;349350if (count > 256 || count > length)351return -1;352353for (i = 0; i < count; ++i)354huffval[i] = dht[pos++];355length -= count;356357if (index & 0x10)358{359index &= ~0x10;360hufftbl = &ac_tables[index];361}362else363hufftbl = &dc_tables[index];364365if (index < 0 || index >= NUM_HUFF_TBLS)366return -1;367368if (*hufftbl == NULL)369*hufftbl = jpeg_alloc_huff_table ((j_common_ptr)info);370if (*hufftbl == NULL)371return -1;372373memcpy ((*hufftbl)->bits, bits, sizeof (*hufftbl)->bits);374memcpy ((*hufftbl)->huffval, huffval, sizeof (*hufftbl)->huffval);375}376377if (length != 0)378return -1;379380return 0;381}382383/***************************************************************************384* end of code for supportting MJPEG image files385* based on a message of Laurent Pinchart on the video4linux mailing list386***************************************************************************/387388bool JpegDecoder::readData( Mat& img )389{390volatile bool result = false;391size_t step = img.step;392bool color = img.channels() > 1;393394if( m_state && m_width && m_height )395{396jpeg_decompress_struct* cinfo = &((JpegState*)m_state)->cinfo;397JpegErrorMgr* jerr = &((JpegState*)m_state)->jerr;398JSAMPARRAY buffer = 0;399400if( setjmp( jerr->setjmp_buffer ) == 0 )401{402/* check if this is a mjpeg image format */403if ( cinfo->ac_huff_tbl_ptrs[0] == NULL &&404cinfo->ac_huff_tbl_ptrs[1] == NULL &&405cinfo->dc_huff_tbl_ptrs[0] == NULL &&406cinfo->dc_huff_tbl_ptrs[1] == NULL )407{408/* yes, this is a mjpeg image format, so load the correct409huffman table */410my_jpeg_load_dht( cinfo,411my_jpeg_odml_dht,412cinfo->ac_huff_tbl_ptrs,413cinfo->dc_huff_tbl_ptrs );414}415416if( color )417{418if( cinfo->num_components != 4 )419{420cinfo->out_color_space = JCS_RGB;421cinfo->out_color_components = 3;422}423else424{425cinfo->out_color_space = JCS_CMYK;426cinfo->out_color_components = 4;427}428}429else430{431if( cinfo->num_components != 4 )432{433cinfo->out_color_space = JCS_GRAYSCALE;434cinfo->out_color_components = 1;435}436else437{438cinfo->out_color_space = JCS_CMYK;439cinfo->out_color_components = 4;440}441}442443jpeg_start_decompress( cinfo );444445buffer = (*cinfo->mem->alloc_sarray)((j_common_ptr)cinfo,446JPOOL_IMAGE, m_width*4, 1 );447448uchar* data = img.ptr();449for( ; m_height--; data += step )450{451jpeg_read_scanlines( cinfo, buffer, 1 );452if( color )453{454if( cinfo->out_color_components == 3 )455icvCvt_RGB2BGR_8u_C3R( buffer[0], 0, data, 0, cvSize(m_width,1) );456else457icvCvt_CMYK2BGR_8u_C4C3R( buffer[0], 0, data, 0, cvSize(m_width,1) );458}459else460{461if( cinfo->out_color_components == 1 )462memcpy( data, buffer[0], m_width );463else464icvCvt_CMYK2Gray_8u_C4C1R( buffer[0], 0, data, 0, cvSize(m_width,1) );465}466}467468result = true;469jpeg_finish_decompress( cinfo );470}471}472473close();474return result;475}476477478/////////////////////// JpegEncoder ///////////////////479480struct JpegDestination481{482struct jpeg_destination_mgr pub;483std::vector<uchar> *buf, *dst;484};485486METHODDEF(void)487stub(j_compress_ptr)488{489}490491METHODDEF(void)492term_destination (j_compress_ptr cinfo)493{494JpegDestination* dest = (JpegDestination*)cinfo->dest;495size_t sz = dest->dst->size(), bufsz = dest->buf->size() - dest->pub.free_in_buffer;496if( bufsz > 0 )497{498dest->dst->resize(sz + bufsz);499memcpy( &(*dest->dst)[0] + sz, &(*dest->buf)[0], bufsz);500}501}502503METHODDEF(boolean)504empty_output_buffer (j_compress_ptr cinfo)505{506JpegDestination* dest = (JpegDestination*)cinfo->dest;507size_t sz = dest->dst->size(), bufsz = dest->buf->size();508dest->dst->resize(sz + bufsz);509memcpy( &(*dest->dst)[0] + sz, &(*dest->buf)[0], bufsz);510511dest->pub.next_output_byte = &(*dest->buf)[0];512dest->pub.free_in_buffer = bufsz;513return TRUE;514}515516static void jpeg_buffer_dest(j_compress_ptr cinfo, JpegDestination* destination)517{518cinfo->dest = &destination->pub;519520destination->pub.init_destination = stub;521destination->pub.empty_output_buffer = empty_output_buffer;522destination->pub.term_destination = term_destination;523}524525526JpegEncoder::JpegEncoder()527{528m_description = "JPEG files (*.jpeg;*.jpg;*.jpe)";529m_buf_supported = true;530}531532533JpegEncoder::~JpegEncoder()534{535}536537ImageEncoder JpegEncoder::newEncoder() const538{539return makePtr<JpegEncoder>();540}541542bool JpegEncoder::write( const Mat& img, const std::vector<int>& params )543{544m_last_error.clear();545546struct fileWrapper547{548FILE* f;549550fileWrapper() : f(0) {}551~fileWrapper() { if(f) fclose(f); }552};553volatile bool result = false;554fileWrapper fw;555int width = img.cols, height = img.rows;556557std::vector<uchar> out_buf(1 << 12);558AutoBuffer<uchar> _buffer;559uchar* buffer;560561struct jpeg_compress_struct cinfo;562JpegErrorMgr jerr;563JpegDestination dest;564565jpeg_create_compress(&cinfo);566cinfo.err = jpeg_std_error(&jerr.pub);567jerr.pub.error_exit = error_exit;568569if( !m_buf )570{571fw.f = fopen( m_filename.c_str(), "wb" );572if( !fw.f )573goto _exit_;574jpeg_stdio_dest( &cinfo, fw.f );575}576else577{578dest.dst = m_buf;579dest.buf = &out_buf;580581jpeg_buffer_dest( &cinfo, &dest );582583dest.pub.next_output_byte = &out_buf[0];584dest.pub.free_in_buffer = out_buf.size();585}586587if( setjmp( jerr.setjmp_buffer ) == 0 )588{589cinfo.image_width = width;590cinfo.image_height = height;591592int _channels = img.channels();593int channels = _channels > 1 ? 3 : 1;594cinfo.input_components = channels;595cinfo.in_color_space = channels > 1 ? JCS_RGB : JCS_GRAYSCALE;596597int quality = 95;598int progressive = 0;599int optimize = 0;600int rst_interval = 0;601int luma_quality = -1;602int chroma_quality = -1;603604for( size_t i = 0; i < params.size(); i += 2 )605{606if( params[i] == CV_IMWRITE_JPEG_QUALITY )607{608quality = params[i+1];609quality = MIN(MAX(quality, 0), 100);610}611612if( params[i] == CV_IMWRITE_JPEG_PROGRESSIVE )613{614progressive = params[i+1];615}616617if( params[i] == CV_IMWRITE_JPEG_OPTIMIZE )618{619optimize = params[i+1];620}621622if( params[i] == CV_IMWRITE_JPEG_LUMA_QUALITY )623{624if (params[i+1] >= 0)625{626luma_quality = MIN(MAX(params[i+1], 0), 100);627628quality = luma_quality;629630if (chroma_quality < 0)631{632chroma_quality = luma_quality;633}634}635}636637if( params[i] == CV_IMWRITE_JPEG_CHROMA_QUALITY )638{639if (params[i+1] >= 0)640{641chroma_quality = MIN(MAX(params[i+1], 0), 100);642}643}644645if( params[i] == CV_IMWRITE_JPEG_RST_INTERVAL )646{647rst_interval = params[i+1];648rst_interval = MIN(MAX(rst_interval, 0), 65535L);649}650}651652jpeg_set_defaults( &cinfo );653cinfo.restart_interval = rst_interval;654655jpeg_set_quality( &cinfo, quality,656TRUE /* limit to baseline-JPEG values */ );657if( progressive )658jpeg_simple_progression( &cinfo );659if( optimize )660cinfo.optimize_coding = TRUE;661662#if JPEG_LIB_VERSION >= 70663if (luma_quality >= 0 && chroma_quality >= 0)664{665cinfo.q_scale_factor[0] = jpeg_quality_scaling(luma_quality);666cinfo.q_scale_factor[1] = jpeg_quality_scaling(chroma_quality);667if ( luma_quality != chroma_quality )668{669/* disable subsampling - ref. Libjpeg.txt */670cinfo.comp_info[0].v_samp_factor = 1;671cinfo.comp_info[0].h_samp_factor = 1;672cinfo.comp_info[1].v_samp_factor = 1;673cinfo.comp_info[1].h_samp_factor = 1;674}675jpeg_default_qtables( &cinfo, TRUE );676}677#endif // #if JPEG_LIB_VERSION >= 70678679jpeg_start_compress( &cinfo, TRUE );680681if( channels > 1 )682_buffer.allocate(width*channels);683buffer = _buffer.data();684685for( int y = 0; y < height; y++ )686{687uchar *data = img.data + img.step*y, *ptr = data;688689if( _channels == 3 )690{691icvCvt_BGR2RGB_8u_C3R( data, 0, buffer, 0, cvSize(width,1) );692ptr = buffer;693}694else if( _channels == 4 )695{696icvCvt_BGRA2BGR_8u_C4C3R( data, 0, buffer, 0, cvSize(width,1), 2 );697ptr = buffer;698}699700jpeg_write_scanlines( &cinfo, &ptr, 1 );701}702703jpeg_finish_compress( &cinfo );704result = true;705}706707_exit_:708709if(!result)710{711char jmsg_buf[JMSG_LENGTH_MAX];712jerr.pub.format_message((j_common_ptr)&cinfo, jmsg_buf);713m_last_error = jmsg_buf;714}715716jpeg_destroy_compress( &cinfo );717718return result;719}720721}722723#endif724725/* End of file. */726727728