bool JpegEncoder::write( const Mat& img, const vector<int>& params ) { m_last_error.clear(); struct fileWrapper { FILE* f; fileWrapper() : f(0) {} ~fileWrapper() { if(f) fclose(f); } }; bool result = false; fileWrapper fw; int width = img.cols, height = img.rows; vector<uchar> out_buf(1 << 12); AutoBuffer<uchar> _buffer; uchar* buffer; struct jpeg_compress_struct cinfo; JpegErrorMgr jerr; JpegDestination dest; jpeg_create_compress(&cinfo); cinfo.err = jpeg_std_error(&jerr.pub); jerr.pub.error_exit = error_exit; if( !m_buf ) { fw.f = fopen( m_filename.c_str(), "wb" ); if( !fw.f ) goto _exit_; jpeg_stdio_dest( &cinfo, fw.f ); } else { dest.dst = m_buf; dest.buf = &out_buf; jpeg_buffer_dest( &cinfo, &dest ); dest.pub.next_output_byte = &out_buf[0]; dest.pub.free_in_buffer = out_buf.size(); } if( setjmp( jerr.setjmp_buffer ) == 0 ) { cinfo.image_width = width; cinfo.image_height = height; int _channels = img.channels(); int channels = _channels > 1 ? 3 : 1; cinfo.input_components = channels; cinfo.in_color_space = channels > 1 ? JCS_RGB : JCS_GRAYSCALE; int quality = 95; for( size_t i = 0; i < params.size(); i += 2 ) { if( params[i] == CV_IMWRITE_JPEG_QUALITY ) { quality = params[i+1]; quality = MIN(MAX(quality, 0), 100); } } jpeg_set_defaults( &cinfo ); jpeg_set_quality( &cinfo, quality, TRUE /* limit to baseline-JPEG values */ ); jpeg_start_compress( &cinfo, TRUE ); if( channels > 1 ) _buffer.allocate(width*channels); buffer = _buffer; for( int y = 0; y < height; y++ ) { uchar *data = img.data + img.step*y, *ptr = data; if( _channels == 3 ) { icvCvt_BGR2RGB_8u_C3R( data, 0, buffer, 0, cvSize(width,1) ); ptr = buffer; } else if( _channels == 4 ) { icvCvt_BGRA2BGR_8u_C4C3R( data, 0, buffer, 0, cvSize(width,1), 2 ); ptr = buffer; } jpeg_write_scanlines( &cinfo, &ptr, 1 ); } jpeg_finish_compress( &cinfo ); result = true; } _exit_: if(!result) { char jmsg_buf[JMSG_LENGTH_MAX]; jerr.pub.format_message((j_common_ptr)&cinfo, jmsg_buf); m_last_error = jmsg_buf; } jpeg_destroy_compress( &cinfo ); return result; }
bool TiffEncoder::write( const Mat& img, const vector<int>& /*params*/) #endif { int channels = img.channels(); int width = img.cols, height = img.rows; int depth = img.depth(); if (depth != CV_8U && depth != CV_16U) return false; int bytesPerChannel = depth == CV_8U ? 1 : 2; int fileStep = width * channels * bytesPerChannel; WLByteStream strm; if( m_buf ) { if( !strm.open(*m_buf) ) return false; } else { #ifdef HAVE_TIFF return writeLibTiff(img, params); #else if( !strm.open(m_filename) ) return false; #endif } int rowsPerStrip = (1 << 13)/fileStep; if( rowsPerStrip < 1 ) rowsPerStrip = 1; if( rowsPerStrip > height ) rowsPerStrip = height; int i, stripCount = (height + rowsPerStrip - 1) / rowsPerStrip; if( m_buf ) m_buf->reserve( alignSize(stripCount*8 + fileStep*height + 256, 256) ); /*#if defined _DEBUG || !defined WIN32 int uncompressedRowSize = rowsPerStrip * fileStep; #endif*/ int directoryOffset = 0; AutoBuffer<int> stripOffsets(stripCount); AutoBuffer<short> stripCounts(stripCount); AutoBuffer<uchar> _buffer(fileStep+32); uchar* buffer = _buffer; int stripOffsetsOffset = 0; int stripCountsOffset = 0; int bitsPerSample = 8 * bytesPerChannel; int y = 0; strm.putBytes( fmtSignTiffII, 4 ); strm.putDWord( directoryOffset ); // write an image data first (the most reasonable way // for compressed images) for( i = 0; i < stripCount; i++ ) { int limit = y + rowsPerStrip; if( limit > height ) limit = height; stripOffsets[i] = strm.getPos(); for( ; y < limit; y++ ) { if( channels == 3 ) { if (depth == CV_8U) icvCvt_BGR2RGB_8u_C3R( img.data + img.step*y, 0, buffer, 0, cvSize(width,1) ); else icvCvt_BGR2RGB_16u_C3R( (const ushort*)(img.data + img.step*y), 0, (ushort*)buffer, 0, cvSize(width,1) ); } else { if( channels == 4 ) { if (depth == CV_8U) icvCvt_BGRA2RGBA_8u_C4R( img.data + img.step*y, 0, buffer, 0, cvSize(width,1) ); else icvCvt_BGRA2RGBA_16u_C4R( (const ushort*)(img.data + img.step*y), 0, (ushort*)buffer, 0, cvSize(width,1) ); } } strm.putBytes( channels > 1 ? buffer : img.data + img.step*y, fileStep ); } stripCounts[i] = (short)(strm.getPos() - stripOffsets[i]); /*assert( stripCounts[i] == uncompressedRowSize || stripCounts[i] < uncompressedRowSize && i == stripCount - 1);*/ } if( stripCount > 2 ) { stripOffsetsOffset = strm.getPos(); for( i = 0; i < stripCount; i++ ) strm.putDWord( stripOffsets[i] ); stripCountsOffset = strm.getPos(); for( i = 0; i < stripCount; i++ ) strm.putWord( stripCounts[i] ); } else if(stripCount == 2) { stripOffsetsOffset = strm.getPos(); for (i = 0; i < stripCount; i++) { strm.putDWord (stripOffsets [i]); } stripCountsOffset = stripCounts [0] + (stripCounts [1] << 16); } else { stripOffsetsOffset = stripOffsets[0]; stripCountsOffset = stripCounts[0]; } if( channels > 1 ) { int bitsPerSamplePos = strm.getPos(); strm.putWord(bitsPerSample); strm.putWord(bitsPerSample); strm.putWord(bitsPerSample); if( channels == 4 ) strm.putWord(bitsPerSample); bitsPerSample = bitsPerSamplePos; } directoryOffset = strm.getPos(); // write header strm.putWord( 9 ); /* warning: specification 5.0 of Tiff want to have tags in ascending order. This is a non-fatal error, but this cause warning with some tools. So, keep this in ascending order */ writeTag( strm, TIFF_TAG_WIDTH, TIFF_TYPE_LONG, 1, width ); writeTag( strm, TIFF_TAG_HEIGHT, TIFF_TYPE_LONG, 1, height ); writeTag( strm, TIFF_TAG_BITS_PER_SAMPLE, TIFF_TYPE_SHORT, channels, bitsPerSample ); writeTag( strm, TIFF_TAG_COMPRESSION, TIFF_TYPE_LONG, 1, TIFF_UNCOMP ); writeTag( strm, TIFF_TAG_PHOTOMETRIC, TIFF_TYPE_SHORT, 1, channels > 1 ? 2 : 1 ); writeTag( strm, TIFF_TAG_STRIP_OFFSETS, TIFF_TYPE_LONG, stripCount, stripOffsetsOffset ); writeTag( strm, TIFF_TAG_SAMPLES_PER_PIXEL, TIFF_TYPE_SHORT, 1, channels ); writeTag( strm, TIFF_TAG_ROWS_PER_STRIP, TIFF_TYPE_LONG, 1, rowsPerStrip ); writeTag( strm, TIFF_TAG_STRIP_COUNTS, stripCount > 1 ? TIFF_TYPE_SHORT : TIFF_TYPE_LONG, stripCount, stripCountsOffset ); strm.putDWord(0); strm.close(); if( m_buf ) { (*m_buf)[4] = (uchar)directoryOffset; (*m_buf)[5] = (uchar)(directoryOffset >> 8); (*m_buf)[6] = (uchar)(directoryOffset >> 16); (*m_buf)[7] = (uchar)(directoryOffset >> 24); } else {
bool PxMEncoder::write( const Mat& img, const std::vector<int>& params ) { bool isBinary = true; int width = img.cols, height = img.rows; int _channels = img.channels(), depth = (int)img.elemSize1()*8; int channels = _channels > 1 ? 3 : 1; int fileStep = width*(int)img.elemSize(); int x, y; for( size_t i = 0; i < params.size(); i += 2 ) if( params[i] == CV_IMWRITE_PXM_BINARY ) isBinary = params[i+1] != 0; WLByteStream strm; if( m_buf ) { if( !strm.open(*m_buf) ) return false; int t = CV_MAKETYPE(img.depth(), channels); m_buf->reserve( alignSize(256 + (isBinary ? fileStep*height : ((t == CV_8UC1 ? 4 : t == CV_8UC3 ? 4*3+2 : t == CV_16UC1 ? 6 : 6*3+2)*width+1)*height), 256)); } else if( !strm.open(m_filename) ) return false; int lineLength; int bufferSize = 128; // buffer that should fit a header if( isBinary ) lineLength = width * (int)img.elemSize(); else lineLength = (6 * channels + (channels > 1 ? 2 : 0)) * width + 32; if( bufferSize < lineLength ) bufferSize = lineLength; AutoBuffer<char> _buffer(bufferSize); char* buffer = _buffer; // write header; sprintf( buffer, "P%c\n%d %d\n%d\n", '2' + (channels > 1 ? 1 : 0) + (isBinary ? 3 : 0), width, height, (1 << depth) - 1 ); strm.putBytes( buffer, (int)strlen(buffer) ); for( y = 0; y < height; y++ ) { uchar* data = img.data + img.step*y; if( isBinary ) { if( _channels == 3 ) { if( depth == 8 ) icvCvt_BGR2RGB_8u_C3R( (uchar*)data, 0, (uchar*)buffer, 0, cvSize(width,1) ); else icvCvt_BGR2RGB_16u_C3R( (ushort*)data, 0, (ushort*)buffer, 0, cvSize(width,1) ); } // swap endianness if necessary if( depth == 16 && !isBigEndian() ) { if( _channels == 1 ) memcpy( buffer, data, fileStep ); for( x = 0; x < width*channels*2; x += 2 ) { uchar v = buffer[x]; buffer[x] = buffer[x + 1]; buffer[x + 1] = v; } } strm.putBytes( (channels > 1 || depth > 8) ? buffer : (char*)data, fileStep ); } else { char* ptr = buffer; if( channels > 1 ) { if( depth == 8 ) { for( x = 0; x < width*channels; x += channels ) { sprintf( ptr, "% 4d", data[x + 2] ); ptr += 4; sprintf( ptr, "% 4d", data[x + 1] ); ptr += 4; sprintf( ptr, "% 4d", data[x] ); ptr += 4; *ptr++ = ' '; *ptr++ = ' '; } } else { for( x = 0; x < width*channels; x += channels ) { sprintf( ptr, "% 6d", ((ushort *)data)[x + 2] ); ptr += 6; sprintf( ptr, "% 6d", ((ushort *)data)[x + 1] ); ptr += 6; sprintf( ptr, "% 6d", ((ushort *)data)[x] ); ptr += 6; *ptr++ = ' '; *ptr++ = ' '; } } } else { if( depth == 8 ) { for( x = 0; x < width; x++ ) { sprintf( ptr, "% 4d", data[x] ); ptr += 4; } } else { for( x = 0; x < width; x++ ) { sprintf( ptr, "% 6d", ((ushort *)data)[x] ); ptr += 6; } } } *ptr++ = '\n'; strm.putBytes( buffer, (int)(ptr - buffer) ); } } strm.close(); return true; }
bool TiffEncoder::writeLibTiff( const Mat& img, const vector<int>& /*params*/) { int channels = img.channels(); int width = img.cols, height = img.rows; int depth = img.depth(); int bitsPerChannel = -1; switch (depth) { case CV_8U: { bitsPerChannel = 8; break; } case CV_16U: { bitsPerChannel = 16; break; } default: { return false; } } const int bitsPerByte = 8; size_t fileStep = (width * channels * bitsPerChannel) / bitsPerByte; int rowsPerStrip = (int)((1 << 13)/fileStep); if( rowsPerStrip < 1 ) rowsPerStrip = 1; if( rowsPerStrip > height ) rowsPerStrip = height; // do NOT put "wb" as the mode, because the b means "big endian" mode, not "binary" mode. // http://www.remotesensing.org/libtiff/man/TIFFOpen.3tiff.html TIFF* pTiffHandle = TIFFOpen(m_filename.c_str(), "w"); if (!pTiffHandle) { return false; } // defaults for now, maybe base them on params in the future int compression = COMPRESSION_LZW; int predictor = PREDICTOR_HORIZONTAL; int colorspace = channels > 1 ? PHOTOMETRIC_RGB : PHOTOMETRIC_MINISBLACK; if ( !TIFFSetField(pTiffHandle, TIFFTAG_IMAGEWIDTH, width) || !TIFFSetField(pTiffHandle, TIFFTAG_IMAGELENGTH, height) || !TIFFSetField(pTiffHandle, TIFFTAG_BITSPERSAMPLE, bitsPerChannel) || !TIFFSetField(pTiffHandle, TIFFTAG_COMPRESSION, compression) || !TIFFSetField(pTiffHandle, TIFFTAG_PHOTOMETRIC, colorspace) || !TIFFSetField(pTiffHandle, TIFFTAG_SAMPLESPERPIXEL, channels) || !TIFFSetField(pTiffHandle, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG) || !TIFFSetField(pTiffHandle, TIFFTAG_ROWSPERSTRIP, rowsPerStrip) || !TIFFSetField(pTiffHandle, TIFFTAG_PREDICTOR, predictor) ) { TIFFClose(pTiffHandle); return false; } // row buffer, because TIFFWriteScanline modifies the original data! size_t scanlineSize = TIFFScanlineSize(pTiffHandle); AutoBuffer<uchar> _buffer(scanlineSize+32); uchar* buffer = _buffer; if (!buffer) { TIFFClose(pTiffHandle); return false; } for (int y = 0; y < height; ++y) { switch(channels) { case 1: { memcpy(buffer, img.data + img.step * y, scanlineSize); break; } case 3: { if (depth == CV_8U) icvCvt_BGR2RGB_8u_C3R( img.data + img.step*y, 0, buffer, 0, cvSize(width,1) ); else icvCvt_BGR2RGB_16u_C3R( (const ushort*)(img.data + img.step*y), 0, (ushort*)buffer, 0, cvSize(width,1) ); break; } case 4: { if (depth == CV_8U) icvCvt_BGRA2RGBA_8u_C4R( img.data + img.step*y, 0, buffer, 0, cvSize(width,1) ); else icvCvt_BGRA2RGBA_16u_C4R( (const ushort*)(img.data + img.step*y), 0, (ushort*)buffer, 0, cvSize(width,1) ); break; } default: { TIFFClose(pTiffHandle); return false; } } int writeResult = TIFFWriteScanline(pTiffHandle, buffer, y, 0); if (writeResult != 1) { TIFFClose(pTiffHandle); return false; } } TIFFClose(pTiffHandle); return true; }
bool JpegEncoder::write( const Mat& img, const std::vector<int>& params ) { m_last_error.clear(); struct fileWrapper { FILE* f; fileWrapper() : f(0) {} ~fileWrapper() { if(f) fclose(f); } }; volatile bool result = false; fileWrapper fw; int width = img.cols, height = img.rows; std::vector<uchar> out_buf(1 << 12); AutoBuffer<uchar> _buffer; uchar* buffer; struct jpeg_compress_struct cinfo; JpegErrorMgr jerr; JpegDestination dest; jpeg_create_compress(&cinfo); cinfo.err = jpeg_std_error(&jerr.pub); jerr.pub.error_exit = error_exit; if( !m_buf ) { fw.f = fopen( m_filename.c_str(), "wb" ); if( !fw.f ) goto _exit_; jpeg_stdio_dest( &cinfo, fw.f ); } else { dest.dst = m_buf; dest.buf = &out_buf; jpeg_buffer_dest( &cinfo, &dest ); dest.pub.next_output_byte = &out_buf[0]; dest.pub.free_in_buffer = out_buf.size(); } if( setjmp( jerr.setjmp_buffer ) == 0 ) { cinfo.image_width = width; cinfo.image_height = height; int _channels = img.channels(); int channels = _channels > 1 ? 3 : 1; cinfo.input_components = channels; cinfo.in_color_space = channels > 1 ? JCS_RGB : JCS_GRAYSCALE; int quality = 95; int progressive = 0; int optimize = 0; int rst_interval = 0; int luma_quality = -1; int chroma_quality = -1; for( size_t i = 0; i < params.size(); i += 2 ) { if( params[i] == CV_IMWRITE_JPEG_QUALITY ) { quality = params[i+1]; quality = MIN(MAX(quality, 0), 100); } if( params[i] == CV_IMWRITE_JPEG_PROGRESSIVE ) { progressive = params[i+1]; } if( params[i] == CV_IMWRITE_JPEG_OPTIMIZE ) { optimize = params[i+1]; } if( params[i] == CV_IMWRITE_JPEG_LUMA_QUALITY ) { if (params[i+1] >= 0) { luma_quality = MIN(MAX(params[i+1], 0), 100); quality = luma_quality; if (chroma_quality < 0) { chroma_quality = luma_quality; } } } if( params[i] == CV_IMWRITE_JPEG_CHROMA_QUALITY ) { if (params[i+1] >= 0) { chroma_quality = MIN(MAX(params[i+1], 0), 100); } } if( params[i] == CV_IMWRITE_JPEG_RST_INTERVAL ) { rst_interval = params[i+1]; rst_interval = MIN(MAX(rst_interval, 0), 65535L); } } jpeg_set_defaults( &cinfo ); cinfo.restart_interval = rst_interval; jpeg_set_quality( &cinfo, quality, TRUE /* limit to baseline-JPEG values */ ); if( progressive ) jpeg_simple_progression( &cinfo ); if( optimize ) cinfo.optimize_coding = TRUE; #if JPEG_LIB_VERSION >= 70 if (luma_quality >= 0 && chroma_quality >= 0) { cinfo.q_scale_factor[0] = jpeg_quality_scaling(luma_quality); cinfo.q_scale_factor[1] = jpeg_quality_scaling(chroma_quality); if ( luma_quality != chroma_quality ) { /* disable subsampling - ref. Libjpeg.txt */ cinfo.comp_info[0].v_samp_factor = 1; cinfo.comp_info[0].h_samp_factor = 1; cinfo.comp_info[1].v_samp_factor = 1; cinfo.comp_info[1].h_samp_factor = 1; } jpeg_default_qtables( &cinfo, TRUE ); } #endif // #if JPEG_LIB_VERSION >= 70 jpeg_start_compress( &cinfo, TRUE ); if( channels > 1 ) _buffer.allocate(width*channels); buffer = _buffer; for( int y = 0; y < height; y++ ) { uchar *data = img.data + img.step*y, *ptr = data; if( _channels == 3 ) { icvCvt_BGR2RGB_8u_C3R( data, 0, buffer, 0, cvSize(width,1) ); ptr = buffer; } else if( _channels == 4 ) { icvCvt_BGRA2BGR_8u_C4C3R( data, 0, buffer, 0, cvSize(width,1), 2 ); ptr = buffer; } jpeg_write_scanlines( &cinfo, &ptr, 1 ); } jpeg_finish_compress( &cinfo ); result = true; } _exit_: if(!result) { char jmsg_buf[JMSG_LENGTH_MAX]; jerr.pub.format_message((j_common_ptr)&cinfo, jmsg_buf); m_last_error = jmsg_buf; } jpeg_destroy_compress( &cinfo ); return result; }