csPtr<iDataBuffer> csJNGImageIO::Save (iImage *Image, iImageIO::FileFormatDescription *, const char* extraoptions) { // we need to get a RGB/RGBA version of the image. switch (Image->GetFormat() & CS_IMGFMT_MASK) { case CS_IMGFMT_PALETTED8: //imgRGBA = Image->Clone (); //imgRGBA->SetFormat (CS_IMGFMT_TRUECOLOR | (Image->GetFormat() & CS_IMGFMT_ALPHA)); // act like JPEG plugin; reject paletted image so no // unwanted/unnoticed conversions take place. return 0; break; case CS_IMGFMT_TRUECOLOR: imgRGBA = csRef<iImage>(Image); break; default: // unknown format return 0; } // compression options int quality = 80; bool progressive = false; bool alpha_jpeg = false; int alpha_png_compress = 6; int alpha_jpeg_quality = -1; /* parse output options. options are a comma-separated list and can be either 'option' or 'option=value'. supported options: compress=# image color compression, 0..100 higher values give smaller files but uglier results. progressive progressive encoding. jng_lossy_alpha use lossy JPEG compression for alpha channel (instead of default lossles PNG) jng_alpha_compress alpha channel compression, 0..100 Impact of higher value depends on alpha channel type. JPEG - smaller files, uglier results. PNG - smaller files, longer time to encode. Note: defaults to value for image color compression if lossy alpha is selected. examples: compress=50 progressive,compress=30 */ csImageLoaderOptionsParser optparser (extraoptions); optparser.GetBool ("progressive", progressive); if (optparser.GetInt ("compress", quality)) { quality = 100 - quality; if (quality < 0) quality = 0; if (quality > 100) quality = 100; if (alpha_jpeg_quality == -1) alpha_jpeg_quality = quality; } if (optparser.GetBool ("jng_lossy_alpha", alpha_jpeg)) { if (alpha_jpeg_quality == -1) alpha_jpeg_quality = quality; } if (optparser.GetInt ("jng_alpha_compress", alpha_png_compress)) { alpha_jpeg_quality = 100 - alpha_png_compress; if (alpha_jpeg_quality < 0) alpha_jpeg_quality = 0; if (alpha_jpeg_quality > 100) alpha_jpeg_quality = 100; alpha_png_compress /= 10; if (alpha_png_compress < 0) alpha_png_compress = 0; if (alpha_png_compress > 9) alpha_png_compress = 9; } mng_handle handle = mng_initialize ( mng_ptr(this), cb_alloc, cb_free, MNG_NULL); if (!handle) { Report (object_reg, CS_REPORTER_SEVERITY_WARNING, "failed to initialize libmng"); return 0; } if ((mng_setcb_openstream (handle, cb_openstream) != MNG_NOERROR) || (mng_setcb_closestream (handle, cb_closestream) != MNG_NOERROR) || (mng_setcb_writedata (handle, cb_writedata) != MNG_NOERROR)) { ReportLibmngError (object_reg, handle, "failed to set libmng callbacks"); mng_cleanup (&handle); return 0; } outfile = new csMemFile (); if (mng_create (handle) != MNG_NOERROR) { ReportLibmngError (object_reg, handle, "failed to create new jng"); mng_cleanup (&handle); delete outfile; imgRGBA = 0; return 0; } bool has_alpha = (imgRGBA->GetFormat() & CS_IMGFMT_ALPHA) != 0; if (mng_putchunk_jhdr (handle, imgRGBA->GetWidth(), imgRGBA->GetHeight(), has_alpha ? MNG_COLORTYPE_JPEGCOLORA : MNG_COLORTYPE_JPEGCOLOR, MNG_BITDEPTH_JPEG8, MNG_COMPRESSION_BASELINEJPEG, progressive ? MNG_INTERLACE_PROGRESSIVE : MNG_INTERLACE_SEQUENTIAL, has_alpha?8:0, has_alpha?(alpha_jpeg?8:0):0, 0, 0) != MNG_NOERROR) { ReportLibmngError (object_reg, handle, "failed to put JHDR chunk"); mng_cleanup (&handle); delete outfile; imgRGBA = 0; return 0; } // @@@ chunk data generation. // lots of stuff needs to be done manually. // should be changed as libmng evolves. // write out alpha channel if (has_alpha) { // extract the alpha channel from the image int pixels = imgRGBA->GetWidth() * imgRGBA->GetHeight(); uint8 *alpha = new uint8 [pixels]; uint8 *alphaptr = alpha; csRGBpixel *imgdata = (csRGBpixel*)imgRGBA->GetImageData(); while (pixels>0) { *alphaptr++ = (imgdata++)->alpha; pixels--; } if (alpha_jpeg) { // compress the alpha data as JPEG and write it out. uint8* volatile row = 0; struct jpg_datastore ds; struct jpeg_compress_struct cinfo; struct my_error_mgr jerr; cinfo.err = jpeg_std_error (&jerr.pub); jerr.pub.error_exit = my_error_exit; if (setjmp (jerr.setjmp_buffer)) { Report (object_reg, CS_REPORTER_SEVERITY_WARNING, "failed to JPEG compress alpha data"); mng_cleanup (&handle); delete outfile; delete [] row; delete[] alpha; jpeg_destroy_compress (&cinfo); imgRGBA = 0; return 0; } jpeg_create_compress (&cinfo); jpeg_buffer_dest (&cinfo, &ds); cinfo.image_width = imgRGBA->GetWidth (); cinfo.image_height = imgRGBA->GetHeight (); cinfo.input_components = 1; cinfo.in_color_space = JCS_GRAYSCALE; row = new uint8[cinfo.image_width]; jpeg_set_defaults (&cinfo); jpeg_set_quality (&cinfo, alpha_jpeg_quality, true); jpeg_start_compress (&cinfo, true); JSAMPROW row_pointer[1]; uint8 *image = alpha; row_pointer[0] = (JSAMPLE*)&row[0]; while (cinfo.next_scanline < cinfo.image_height) { for (size_t i=0; i < cinfo.image_width; i++) row[i] = image[cinfo.next_scanline * cinfo.image_width + i]; jpeg_write_scanlines (&cinfo, row_pointer, 1); } jpeg_finish_compress (&cinfo); jpeg_destroy_compress (&cinfo); delete [] row; // funny, mng_putchunk_jdaa is missing from libmng //if (mng_putchunk_jdaa (handle, ds.len, ds.data) != MNG_NOERROR) if (mng_putchunk_unknown (handle, MNG_UINT_JDAA, (mng_uint32)ds.len, ds.data) != MNG_NOERROR) { ReportLibmngError (object_reg, handle, "failed to put JDAA chunk"); mng_cleanup (&handle); delete outfile; delete[] alpha; imgRGBA = 0; return 0; } } else { // generate the IDAT chunk data // we use the "Up" filter. uint8* chunkdata = new uint8[(imgRGBA->GetWidth() + 1) * imgRGBA->GetHeight()]; uint8* lastline = new uint8[imgRGBA->GetWidth()]; uint8* chunkptr = chunkdata; alphaptr = alpha; memset (lastline, 0, imgRGBA->GetWidth()); int lines = imgRGBA->GetHeight(); while (lines > 0) { *chunkptr++ = 2; int pix = 0; while (pix<imgRGBA->GetWidth()) { *chunkptr++ = *alphaptr - lastline[pix]; lastline[pix] = *alphaptr++; pix++; } lines--; } delete[] lastline; // now compress the data z_stream zs; zs.zalloc = (alloc_func) 0; zs.zfree = (free_func) 0; zs.next_in = (Byte *) chunkdata; zs.avail_in = (imgRGBA->GetWidth() + 1) * imgRGBA->GetHeight(); if (deflateInit (&zs, alpha_png_compress) != Z_OK) { Report (object_reg, CS_REPORTER_SEVERITY_WARNING, "deflateInit() failed"); mng_cleanup (&handle); delete outfile; delete[] chunkdata; delete[] alpha; imgRGBA = 0; return 0; } char buff[0x8000]; while (1) { zs.next_out = (Byte *)buff; zs.avail_out = sizeof (buff); int rc = deflate (&zs, Z_FINISH); /* Do actual compression */ size_t size = sizeof (buff) - zs.avail_out; // create a chuk w/compressed data. if (mng_putchunk_idat (handle, (mng_uint32)size, &buff) != MNG_NOERROR) { ReportLibmngError (object_reg, handle, "failed to put IDAT chunk"); deflateEnd (&zs); mng_cleanup (&handle); delete outfile; delete[] chunkdata; delete[] alpha; imgRGBA = 0; return 0; } if (rc == Z_STREAM_END) break; /* finished */ } deflateEnd (&zs); delete[] chunkdata; } delete[] alpha; } // compress the color data as JPEG and write it out. csRGBcolor* volatile row = 0; struct jpg_datastore ds; struct jpeg_compress_struct cinfo; struct my_error_mgr jerr; cinfo.err = jpeg_std_error (&jerr.pub); jerr.pub.error_exit = my_error_exit; if (setjmp (jerr.setjmp_buffer)) { Report (object_reg, CS_REPORTER_SEVERITY_WARNING, "failed to JPEG compress color data"); mng_cleanup (&handle); delete outfile; delete [] row; jpeg_destroy_compress (&cinfo); imgRGBA = 0; return 0; } jpeg_create_compress (&cinfo); jpeg_buffer_dest (&cinfo, &ds); cinfo.image_width = imgRGBA->GetWidth (); cinfo.image_height = imgRGBA->GetHeight (); cinfo.input_components = 3; cinfo.in_color_space = JCS_RGB; row = new csRGBcolor[cinfo.image_width]; jpeg_set_defaults (&cinfo); jpeg_set_quality (&cinfo, quality, true); if (progressive) jpeg_simple_progression (&cinfo); jpeg_start_compress (&cinfo, true); JSAMPROW row_pointer[1]; JSAMPLE *image = (JSAMPLE*)csPackRGB::PackRGBpixelToRGB ((csRGBpixel*)Image->GetImageData (), Image->GetWidth () * Image->GetHeight ()); row_pointer[0] = (JSAMPLE*)&row[0]; while (cinfo.next_scanline < cinfo.image_height) { row_pointer[0] = (JSAMPLE*)&image[cinfo.next_scanline * cinfo.image_width * 3]; jpeg_write_scanlines (&cinfo, row_pointer, 1); } jpeg_finish_compress (&cinfo); jpeg_destroy_compress (&cinfo); delete [] row; if (mng_putchunk_jdat (handle, (mng_uint32)ds.len, ds.data) != MNG_NOERROR) { ReportLibmngError (object_reg, handle, "failed to put JDAT chunk"); mng_cleanup (&handle); delete outfile; imgRGBA = 0; return 0; } imgRGBA = 0; if (mng_putchunk_iend (handle) != MNG_NOERROR) { ReportLibmngError (object_reg, handle, "failed to put IEND chunk"); mng_cleanup (&handle); delete outfile; return 0; } if (mng_write (handle) != MNG_NOERROR) { ReportLibmngError (object_reg, handle, "failed to write out JNG data"); mng_cleanup (&handle); delete outfile; return 0; } mng_cleanup (&handle); csRef<iDataBuffer> db (outfile->GetAllData ()); delete outfile; return csPtr<iDataBuffer> (db); }
int ImagingJpegEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes) { JPEGENCODERSTATE* context = (JPEGENCODERSTATE*) state->context; int ok; if (setjmp(context->error.setjmp_buffer)) { /* JPEG error handler */ jpeg_destroy_compress(&context->cinfo); state->errcode = IMAGING_CODEC_BROKEN; return -1; } if (!state->state) { /* Setup compression context (very similar to the decoder) */ context->cinfo.err = jpeg_std_error(&context->error.pub); context->error.pub.error_exit = error; jpeg_create_compress(&context->cinfo); jpeg_buffer_dest(&context->cinfo, &context->destination); context->extra_offset = 0; /* Ready to encode */ state->state = 1; } /* Load the destination buffer */ context->destination.pub.next_output_byte = buf; context->destination.pub.free_in_buffer = bytes; switch (state->state) { case 1: context->cinfo.image_width = state->xsize; context->cinfo.image_height = state->ysize; switch (state->bits) { case 8: context->cinfo.input_components = 1; context->cinfo.in_color_space = JCS_GRAYSCALE; break; case 24: context->cinfo.input_components = 3; if (strcmp(im->mode, "YCbCr") == 0) context->cinfo.in_color_space = JCS_YCbCr; else context->cinfo.in_color_space = JCS_RGB; break; case 32: context->cinfo.input_components = 4; context->cinfo.in_color_space = JCS_CMYK; break; default: state->errcode = IMAGING_CODEC_CONFIG; return -1; } /* Compressor configuration */ jpeg_set_defaults(&context->cinfo); /* Use custom quantization tables */ if (context->qtables) { int i; int quality = 100; if (context->quality > 0) { quality = context->quality; } for (i = 0; i < sizeof(context->qtables)/sizeof(unsigned int); i++) { // TODO: Should add support for none baseline jpeg_add_quant_table(&context->cinfo, i, context->qtables[i], quality, TRUE); } } else if (context->quality > 0) { jpeg_set_quality(&context->cinfo, context->quality, 1); } /* Set subsampling options */ switch (context->subsampling) { case 0: /* 1x1 1x1 1x1 (4:4:4) : None */ { context->cinfo.comp_info[0].h_samp_factor = 1; context->cinfo.comp_info[0].v_samp_factor = 1; context->cinfo.comp_info[1].h_samp_factor = 1; context->cinfo.comp_info[1].v_samp_factor = 1; context->cinfo.comp_info[2].h_samp_factor = 1; context->cinfo.comp_info[2].v_samp_factor = 1; break; } case 1: /* 2x1, 1x1, 1x1 (4:2:2) : Medium */ { context->cinfo.comp_info[0].h_samp_factor = 2; context->cinfo.comp_info[0].v_samp_factor = 1; context->cinfo.comp_info[1].h_samp_factor = 1; context->cinfo.comp_info[1].v_samp_factor = 1; context->cinfo.comp_info[2].h_samp_factor = 1; context->cinfo.comp_info[2].v_samp_factor = 1; break; } case 2: /* 2x2, 1x1, 1x1 (4:1:1) : High */ { context->cinfo.comp_info[0].h_samp_factor = 2; context->cinfo.comp_info[0].v_samp_factor = 2; context->cinfo.comp_info[1].h_samp_factor = 1; context->cinfo.comp_info[1].v_samp_factor = 1; context->cinfo.comp_info[2].h_samp_factor = 1; context->cinfo.comp_info[2].v_samp_factor = 1; break; } default: { /* Use the lib's default */ break; } } if (context->progressive) jpeg_simple_progression(&context->cinfo); context->cinfo.smoothing_factor = context->smooth; context->cinfo.optimize_coding = (boolean) context->optimize; if (context->xdpi > 0 && context->ydpi > 0) { context->cinfo.density_unit = 1; /* dots per inch */ context->cinfo.X_density = context->xdpi; context->cinfo.Y_density = context->ydpi; } switch (context->streamtype) { case 1: /* tables only -- not yet implemented */ state->errcode = IMAGING_CODEC_CONFIG; return -1; case 2: /* image only */ jpeg_suppress_tables(&context->cinfo, TRUE); jpeg_start_compress(&context->cinfo, FALSE); /* suppress extra section */ context->extra_offset = context->extra_size; //add exif header if (context->rawExifLen > 0) jpeg_write_marker(&context->cinfo, JPEG_APP0+1, (unsigned char*)context->rawExif, context->rawExifLen); break; default: /* interchange stream */ jpeg_start_compress(&context->cinfo, TRUE); //add exif header if (context->rawExifLen > 0) jpeg_write_marker(&context->cinfo, JPEG_APP0+1, (unsigned char*)context->rawExif, context->rawExifLen); break; } state->state++; /* fall through */ case 2: if (context->extra) { /* copy extra buffer to output buffer */ unsigned int n = context->extra_size - context->extra_offset; if (n > context->destination.pub.free_in_buffer) n = context->destination.pub.free_in_buffer; memcpy(context->destination.pub.next_output_byte, context->extra + context->extra_offset, n); context->destination.pub.next_output_byte += n; context->destination.pub.free_in_buffer -= n; context->extra_offset += n; if (context->extra_offset >= context->extra_size) state->state++; else break; } else state->state++; case 3: ok = 1; while (state->y < state->ysize) { state->shuffle(state->buffer, (UINT8*) im->image[state->y + state->yoff] + state->xoff * im->pixelsize, state->xsize); ok = jpeg_write_scanlines(&context->cinfo, &state->buffer, 1); if (ok != 1) break; state->y++; } if (ok != 1) break; state->state++; /* fall through */ case 4: /* Finish compression */ if (context->destination.pub.free_in_buffer < 100) break; jpeg_finish_compress(&context->cinfo); /* Clean up */ if (context->extra) free(context->extra); jpeg_destroy_compress(&context->cinfo); /* if (jerr.pub.num_warnings) return BROKEN; */ state->errcode = IMAGING_CODEC_END; break; } /* Return number of bytes in output buffer */ return context->destination.pub.next_output_byte - buf; }
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; }
void ModeJpeg::jpegCompressForJetReady() { struct jpeg_compress_struct cinfo; struct jpeg_error_mgr jerr; jmp_buf setjmp_buffer; // Use the modified Mojave CSC table hp_rgb_ycc_setup (1); compressedsize = 0; memset (compressBuf, 0xFF, m_max_file_size); cinfo.err = jpeg_std_error (&jerr); jerr.error_exit = HPJpeg_error; if (setjmp (setjmp_buffer)) { jpeg_destroy_compress (&cinfo); return; } jpeg_create_compress (&cinfo); cinfo.in_color_space = (m_iColorMode == 0) ? JCS_RGB : JCS_GRAYSCALE; jpeg_set_defaults (&cinfo); cinfo.image_width = m_iRowWidth / 3; cinfo.image_height = m_iBandHeight; cinfo.input_components = (m_iColorMode == 0) ? 3 : 1; cinfo.data_precision = 8; // Create a static quant table here. static unsigned int mojave_quant_table1[64] = { 2,3,4,5,5,5,5,5, 3,6,5,8,5,8,5,8, 4,5,5,5,5,5,5,5, 5,8,5,8,5,8,5,8, 5,5,5,5,5,5,5,5, 5,8,5,8,5,8,5,8, 5,5,5,5,5,5,5,5, 5,8,5,8,5,8,5,8 }; // // JetReady specific Q-Tables will be added here. We do the following: // 1. Add three Q-Tables. // 2. Scale the Q-Table elemets with the given scale factor. // 3. Check to see if any of the element in the table is greater than 255 // reset that elemet to 255. // 5. There is a specific scaling needed to be done to the first 6 // elements in the matrix. This is required to achieve better // compression ratio. // 4. Check to see if any the of the recently modified element is // greater than 255, reset that to 255. // // Please refer to sRGBLaserHostBasedSoftwareERS.doc v9.0 section 5.2.5.3.1.1 // for more details. // // [NOTE] These loop needs to be further optimized. // for (int i = 0; i < 3; i++) { // Adding Q-Table. jpeg_add_quant_table(&cinfo, i, mojave_quant_table1, 0, FALSE ); // // Scaling the Q-Table elements. // Reset the element to 255, if it is greater than 255. // for(int j = 1; j < 64; j++) { cinfo.quant_tbl_ptrs[i]->quantval[j] = (UINT16)((mojave_quant_table1[j] * m_pQTableInfo->qFactor) & 0xFF); } // for (int j = 1; j < 64; j++) // // Special scaling for first 6 elements in the table. // Reset the specially scaled elements 255, if it is greater than 255. // // // 1st component in the table. Unchanged, I need not change anything here. // cinfo.quant_tbl_ptrs[i]->quantval[0] = (UINT16)mojave_quant_table1[0]; // // 2nd and 3rd components in the zig zag order // // The following dTemp is being used to ceil the vales: e.g 28.5 to 29 // double dTemp = mojave_quant_table1[1] * (1 + 0.25 * (m_pQTableInfo->qFactor - 1)) + 0.5; cinfo.quant_tbl_ptrs[i]->quantval[1] = (UINT16)dTemp & 0xFF; dTemp = mojave_quant_table1[8] * (1 + 0.25 * (m_pQTableInfo->qFactor - 1)) + 0.5; cinfo.quant_tbl_ptrs[i]->quantval[8] = (UINT16)dTemp & 0xFF; // // 4th, 5th and 6th components in the zig zag order // dTemp = mojave_quant_table1[16] * (1 + 0.50 * (m_pQTableInfo->qFactor - 1)) + 0.5; cinfo.quant_tbl_ptrs[i]->quantval[16] = (UINT16)dTemp & 0xFF; dTemp = mojave_quant_table1[9] * (1 + 0.50 * (m_pQTableInfo->qFactor - 1)) + 0.5; cinfo.quant_tbl_ptrs[i]->quantval[9] = (UINT16)dTemp & 0xFF; dTemp = mojave_quant_table1[2] * (1 + 0.50 * (m_pQTableInfo->qFactor - 1)) + 0.5; cinfo.quant_tbl_ptrs[i]->quantval[2] = (UINT16)dTemp & 0xFF; } // for (i = 0; i < 3; i++) // Hard code to use sampling mode 4:4:4 cinfo.comp_info[0].h_samp_factor = 1; cinfo.comp_info[0].v_samp_factor = 1; jpeg_buffer_dest (&cinfo, (JOCTET *) this, (void *) (output_buffer_callback)); int row_width = m_iRowWidth; if (m_iColorMode != 0) { row_width = m_iRowWidth / 3; cinfo.write_JFIF_header = FALSE; cinfo.write_Adobe_marker = FALSE; jpeg_suppress_tables(&cinfo, TRUE); } jpeg_start_compress (&cinfo, TRUE); JSAMPROW pRowArray[1]; BYTE *pScanLine = m_pbyInputBuffer; int i; for (i = 0; i < m_iBandHeight; i++) { pRowArray[0] = (JSAMPROW) pScanLine; jpeg_write_scanlines (&cinfo, pRowArray, 1); pScanLine += (row_width); } jpeg_finish_compress (&cinfo); // Read the quantization table used for this compression if (cinfo.quant_tbl_ptrs[0] != NULL) { // memcpy(m_pQTableInfo->qtable0, cinfo.quant_tbl_ptrs[0]->quantval, QTABLE_SIZE); for (i = 0; i < QTABLE_SIZE; i++) { m_pQTableInfo->qtable0[i] = cinfo.quant_tbl_ptrs[0]->quantval[i]; } } if (cinfo.quant_tbl_ptrs[1] != NULL) { // memcpy(m_pQTableInfo->qtable1, cinfo.quant_tbl_ptrs[1]->quantval, QTABLE_SIZE); for (i = 0; i < QTABLE_SIZE; i++) { m_pQTableInfo->qtable1[i] = cinfo.quant_tbl_ptrs[1]->quantval[i]; } } if (cinfo.quant_tbl_ptrs[2] != NULL) { // memcpy(m_pQTableInfo->qtable2, cinfo.quant_tbl_ptrs[2]->quantval, QTABLE_SIZE); for (i = 0; i < QTABLE_SIZE; i++) { m_pQTableInfo->qtable2[i] = cinfo.quant_tbl_ptrs[2]->quantval[i]; } } jpeg_destroy_compress (&cinfo); if (m_iColorMode != 0) { unsigned int l = 0; while (l < compressedsize) { if (compressBuf[l] == 0xFF && compressBuf[l+1] == 0xDA) break; l++; } if (l != compressedsize) { m_uiGrayscaleOffset = l + 10; } } }
void ModeJpeg::jpegCompressForQuickConnect() { BYTE *p; int iQuality = 100; /* * Convert the byte buffer to jpg, if converted size is greater than 2MB, delete it and * convert with a higher compression factor. */ struct jpeg_compress_struct cinfo; struct jpeg_error_mgr jerr; jmp_buf setjmp_buffer; bool bRedo; // Use the standard RGB to YCC table rather than the modified one for JetReady hp_rgb_ycc_setup (0); do { bRedo = 0; compressedsize = 0; memset (compressBuf, 0xFF, m_max_file_size); p = m_pbyInputBuffer; cinfo.err = jpeg_std_error (&jerr); jerr.error_exit = HPJpeg_error; if (setjmp (setjmp_buffer)) { jpeg_destroy_compress (&cinfo); return; } jpeg_create_compress (&cinfo); cinfo.in_color_space = JCS_RGB; jpeg_set_defaults (&cinfo); cinfo.image_width = m_iRowWidth / 3; cinfo.image_height = m_iRowNumber; cinfo.input_components = 3; cinfo.data_precision = 8; jpeg_set_quality (&cinfo, iQuality, TRUE); jpeg_buffer_dest (&cinfo, (JOCTET *) this, (void *) (output_buffer_callback)); jpeg_start_compress (&cinfo, TRUE); JSAMPROW pRowArray[1]; for (int i = 0; i < m_iRowNumber; i++) { pRowArray[0] = (JSAMPROW) p; jpeg_write_scanlines (&cinfo, pRowArray, 1); p += (m_iRowWidth); if (compressedsize > m_max_file_size) { compressedsize = 0; bRedo = 1; } } jpeg_finish_compress (&cinfo); jpeg_destroy_compress (&cinfo); iQuality -= 10; if (iQuality == 0) { compressedsize = 0; return; } } while (bRedo); return; }
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; }
static int jpeg_image_control(ErlDrvData handle, unsigned int command, char* buf, int count, char** res, int res_size) { JSAMPROW row; ErlDrvBinary* bin = 0; switch (command) { case 0: { /* Read */ struct jpeg_decompress_struct cinfo; int row_stride; /* physical row width in output buffer */ unsigned char* rbuf; struct my_error_mgr jerr; cinfo.err = jpeg_std_error(&jerr.pub); jerr.pub.error_exit = my_error_exit; /* Establish the setjmp return context for my_error_exit to use. */ if (setjmp(jerr.setjmp_buffer)) { /* If we get here, the JPEG code has signaled an error. * We need to clean up the JPEG object, close the input file, and return. */ char buffer[JMSG_LENGTH_MAX]; /* Create the message */ (cinfo.err->format_message)((j_common_ptr) &cinfo, buffer); jpeg_destroy_decompress(&cinfo); bin = driver_alloc_binary(4+strlen(buffer)); rbuf = bin->orig_bytes; ((unsigned *)rbuf)[0] = 0; rbuf += 4; memcpy(rbuf, buffer, strlen(buffer)); *res = (void *) bin; return 0; } jpeg_create_decompress(&cinfo); jpeg_buffer_src(&cinfo, buf, count); (void) jpeg_read_header(&cinfo, TRUE); (void) jpeg_start_decompress(&cinfo); row_stride = cinfo.output_width * cinfo.output_components; res_size = row_stride * cinfo.output_height; bin = driver_alloc_binary(res_size+12); rbuf = bin->orig_bytes; ((unsigned *)rbuf)[0] = cinfo.output_width; ((unsigned *)rbuf)[1] = cinfo.output_height; ((unsigned *)rbuf)[2] = cinfo.output_components; rbuf += 12; while (cinfo.output_scanline < cinfo.output_height) { row = (JSAMPROW) rbuf; (void) jpeg_read_scanlines(&cinfo, &row, 1); rbuf += row_stride; } (void) jpeg_finish_decompress(&cinfo); *res = (void *) bin; return 0; } case 1: { /* Write */ struct jpeg_compress_struct cinfo; struct jpeg_error_mgr jerr; int row_stride; /* physical row width */ bin = driver_alloc_binary(count); cinfo.err = jpeg_std_error(&jerr); jpeg_create_compress(&cinfo); jpeg_buffer_dest(&cinfo, bin); cinfo.image_width = ((unsigned *)buf)[0]; cinfo.image_height = ((unsigned *)buf)[1]; cinfo.input_components = ((unsigned *)buf)[2]; cinfo.in_color_space = JCS_RGB; jpeg_set_defaults(&cinfo); buf += 12; count -= 12; jpeg_start_compress(&cinfo, TRUE); row_stride = cinfo.input_components * cinfo.image_width; while (cinfo.next_scanline < cinfo.image_height) { row = (JSAMPROW) buf; (void) jpeg_write_scanlines(&cinfo, &row, 1); buf += row_stride; } jpeg_finish_compress(&cinfo); bin = jpeg_buffer_dest_get_bin(&cinfo); jpeg_destroy_compress(&cinfo); *res = (void *) bin; return 0; } default: return -1; /* Error return, throws exception in erlang */ } }
csPtr<iDataBuffer> csJPGImageIO::Save(iImage *Image, iImageIO::FileFormatDescription*, const char* extraoptions) { int format = Image->GetFormat (); switch (format & CS_IMGFMT_MASK) { case CS_IMGFMT_TRUECOLOR: break; default: // unknown format return 0; } /* endswitch */ // compression options int quality = 80; bool progressive = false; /* parse output options. options are a comma-separated list and can be either 'option' or 'option=value'. supported options: compress=# image compression, 0..100 higher values give smaller files but uglier results. progressive progressive encoding. examples: compress=50 progressive,compress=30 */ csImageLoaderOptionsParser optparser (extraoptions); optparser.GetBool ("progressive", progressive); if (optparser.GetInt ("compress", quality)) { quality = 100 - quality; if (quality < 0) quality = 0; if (quality > 100) quality = 100; } JSAMPLE* volatile row = 0; struct jpg_datastore ds; struct jpeg_compress_struct cinfo; struct my_error_mgr jerr; cinfo.err = jpeg_std_error (&jerr.pub); jerr.pub.error_exit = my_error_exit; if (setjmp (jerr.setjmp_buffer)) { delete [] row; char errmsg [256]; cinfo.err->format_message ((jpeg_common_struct *)&cinfo, errmsg); Report (object_reg, CS_REPORTER_SEVERITY_WARNING, "%s\n", errmsg); jpeg_destroy_compress (&cinfo); return 0; } jpeg_create_compress (&cinfo); jpeg_buffer_dest (&cinfo, &ds); cinfo.image_width = Image->GetWidth (); cinfo.image_height = Image->GetHeight (); cinfo.input_components = 3; cinfo.in_color_space = JCS_RGB; jpeg_set_defaults (&cinfo); jpeg_set_quality (&cinfo, quality, true); if (progressive) jpeg_simple_progression (&cinfo); jpeg_start_compress (&cinfo, true); JSAMPROW row_pointer[1]; JSAMPLE *image = (JSAMPLE*)csPackRGB::PackRGBpixelToRGB ((csRGBpixel*)Image->GetImageData (), Image->GetWidth () * Image->GetHeight ()); row_pointer[0] = (JSAMPLE*)&row[0]; while (cinfo.next_scanline < cinfo.image_height) { row_pointer[0] = (JSAMPLE*)&image[cinfo.next_scanline * cinfo.image_width * 3]; jpeg_write_scanlines (&cinfo, row_pointer, 1); } jpeg_finish_compress (&cinfo); jpeg_destroy_compress (&cinfo); delete[] image; delete [] row; /* make the iDataBuffer to return */ csDataBuffer *db = new csDataBuffer (ds.len); memcpy (db->GetData (), ds.data, ds.len); return csPtr<iDataBuffer> (db); }