// Compress the data from i->_pixbuf to i->data. // Uses libjpeg-turbo if available (JCS_EXTENSIONS) for better performance int image_jpeg_compress(MediaScanImage *i, MediaScanThumbSpec *spec) { struct jpeg_compress_struct cinfo; struct jpeg_error_mgr jerr; struct buf_dst_mgr dst; int quality = spec->jpeg_quality; int x; #ifdef JCS_EXTENSIONS JSAMPROW *data = NULL; #else volatile unsigned char *data = NULL; // volatile = won't be rolled back if longjmp is called JSAMPROW row_pointer[1]; int y, row_stride; #endif if (!i->_pixbuf_size) { LOG_WARN("JPEG compression requires pixbuf data (%s)\n", i->path); exit(-1); return 0; } if (!quality) quality = DEFAULT_JPEG_QUALITY; cinfo.err = jpeg_std_error(&jerr); jpeg_create_compress(&cinfo); image_jpeg_buf_dest(&cinfo, &dst); cinfo.image_width = i->width; cinfo.image_height = i->height; cinfo.input_components = 3; cinfo.in_color_space = JCS_RGB; // output is always RGB even if source was grayscale if (setjmp(setjmp_buffer)) { if (data != NULL) { LOG_MEM("destroy JPEG data row @ %p\n", data); free((void *)data); } return 0; } #ifdef JCS_EXTENSIONS // Use libjpeg-turbo support for direct reading from source buffer cinfo.input_components = 4; cinfo.in_color_space = JCS_EXT_XBGR; #endif jpeg_set_defaults(&cinfo); jpeg_set_quality(&cinfo, quality, TRUE); jpeg_start_compress(&cinfo, TRUE); #ifdef JCS_EXTENSIONS data = (JSAMPROW *)malloc(i->height * sizeof(JSAMPROW)); LOG_MEM("new JPEG data row @ %p\n", data); for (x = 0; x < i->height; x++) data[x] = (JSAMPROW)&i->_pixbuf[x * i->width]; while (cinfo.next_scanline < cinfo.image_height) { jpeg_write_scanlines(&cinfo, &data[cinfo.next_scanline], cinfo.image_height - cinfo.next_scanline); } #else // Normal libjpeg row_stride = cinfo.image_width * 3; data = (unsigned char *)malloc(row_stride); LOG_MEM("new JPEG data row @ %p\n", data); y = 0; while (cinfo.next_scanline < cinfo.image_height) { for (x = 0; x < cinfo.image_width; x++) { data[x + x + x] = COL_RED(i->_pixbuf[y]); data[x + x + x + 1] = COL_GREEN(i->_pixbuf[y]); data[x + x + x + 2] = COL_BLUE(i->_pixbuf[y]); y++; } row_pointer[0] = (unsigned char *)data; jpeg_write_scanlines(&cinfo, row_pointer, 1); } #endif jpeg_finish_compress(&cinfo); LOG_MEM("destroy JPEG data row @ %p\n", data); free((void *)data); jpeg_destroy_compress(&cinfo); // Attach compressed buffer to image i->_dbuf = (void *)dst.dbuf; return 1; }
void banded_float_image_export_as_jpeg(BandedFloatImage *self, const char *output_name) { struct jpeg_compress_struct cinfo; struct jpeg_error_mgr jerr; int i; assert(self->nbands >= 1); float *min, *max, *mean, *stddev, *lin_min, *lin_max; min = MALLOC(sizeof(float)*self->nbands); max = MALLOC(sizeof(float)*self->nbands); mean = MALLOC(sizeof(float)*self->nbands); stddev = MALLOC(sizeof(float)*self->nbands); for (i=0; i<self->nbands; ++i) { float_image_statistics(self->images[i], &min[i], &max[i], &mean[i], &stddev[i], -999); lin_min[i] = mean[i] - 2 * stddev[i]; lin_max[i] = mean[i] + 2 * stddev[i]; } cinfo.err = jpeg_std_error (&jerr); jpeg_create_compress (&cinfo); FILE *ofp = fopen (output_name, "wb"); if ( ofp == NULL ) { asfPrintError("Open of %s for writing failed: %s", output_name, strerror(errno)); } jpeg_stdio_dest (&cinfo, ofp); int nl = banded_float_image_get_size_y(self); int ns = banded_float_image_get_size_x(self); cinfo.image_width = ns; cinfo.image_height = nl; cinfo.input_components = 3; cinfo.in_color_space = JCS_RGB; jpeg_set_defaults (&cinfo); jpeg_start_compress (&cinfo, TRUE); JSAMPLE *jsample_row = MALLOC(sizeof(JSAMPLE)*ns*3); JSAMPROW *row_pointer = MALLOC(sizeof(JSAMPROW)); while (cinfo.next_scanline < cinfo.image_height) { for (i=0; i<ns; ++i) { int band = 0; int r = scale_to_byte(lin_min[band], lin_max[band], banded_float_image_get_pixel(self, band, cinfo.next_scanline, i)); if (band < self->nbands-1) ++band; int g = scale_to_byte(lin_min[band], lin_max[band], banded_float_image_get_pixel(self, band, cinfo.next_scanline, i)); if (band < self->nbands-1) ++band; int b = scale_to_byte(lin_min[band], lin_max[band], banded_float_image_get_pixel(self, band, cinfo.next_scanline, i)); jsample_row[i*3+0] = (JSAMPLE) r; jsample_row[i*3+1] = (JSAMPLE) g; jsample_row[i*3+2] = (JSAMPLE) b; } row_pointer[0] = jsample_row; int written = jpeg_write_scanlines(&cinfo, row_pointer, 1); if (written != 1) asfPrintError("Failed to write the correct number of lines.\n"); asfLineMeter(cinfo.next_scanline, cinfo.image_height); } FREE(row_pointer); FREE(jsample_row); jpeg_finish_compress (&cinfo); FCLOSE (ofp); jpeg_destroy_compress (&cinfo); }
bool CxImageJPG::Encode(CxFile * hFile) { if (EncodeSafeCheck(hFile)) return false; if (head.biClrUsed!=0 && !IsGrayScale()){ strcpy(info.szLastError,"JPEG can save only RGB or GreyScale images"); return false; } // necessary for EXIF, and for roll backs long pos=hFile->Tell(); /* This struct contains the JPEG compression parameters and pointers to * working space (which is allocated as needed by the JPEG library). * It is possible to have several such structures, representing multiple * compression/decompression processes, in existence at once. We refer * to any one struct (and its associated working data) as a "JPEG object". */ struct jpeg_compress_struct cinfo; /* This struct represents a JPEG error handler. It is declared separately * because applications often want to supply a specialized error handler * (see the second half of this file for an example). But here we just * take the easy way out and use the standard error handler, which will * print a message on stderr and call exit() if compression fails. * Note that this struct must live as long as the main JPEG parameter * struct, to avoid dangling-pointer problems. */ //struct jpeg_error_mgr jerr; /* We use our private extension JPEG error handler. <CSC> */ struct jpg_error_mgr jerr; jerr.buffer=info.szLastError; /* More stuff */ int row_stride; /* physical row width in image buffer */ JSAMPARRAY buffer; /* Output row buffer */ /* Step 1: allocate and initialize JPEG compression object */ /* We have to set up the error handler first, in case the initialization * step fails. (Unlikely, but it could happen if you are out of memory.) * This routine fills in the contents of struct jerr, and returns jerr's * address which we place into the link field in cinfo. */ //cinfo.err = jpeg_std_error(&jerr); <CSC> /* We set up the normal JPEG error routines, then override error_exit. */ cinfo.err = jpeg_std_error(&jerr.pub); jerr.pub.error_exit = ima_jpeg_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. */ strcpy(info.szLastError, jerr.buffer); //<CSC> jpeg_destroy_compress(&cinfo); return 0; } /* Now we can initialize the JPEG compression object. */ jpeg_create_compress(&cinfo); /* Step 2: specify data destination (eg, a file) */ /* Note: steps 2 and 3 can be done in either order. */ /* Here we use the library-supplied code to send compressed data to a * stdio stream. You can also write your own code to do something else. * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that * requires it in order to write binary files. */ //jpeg_stdio_dest(&cinfo, outfile); CxFileJpg dest(hFile); cinfo.dest = &dest; /* Step 3: set parameters for compression */ /* First we supply a description of the input image. * Four fields of the cinfo struct must be filled in: */ cinfo.image_width = GetWidth(); // image width and height, in pixels cinfo.image_height = GetHeight(); if (IsGrayScale()){ cinfo.input_components = 1; // # of color components per pixel cinfo.in_color_space = JCS_GRAYSCALE; /* colorspace of input image */ } else { cinfo.input_components = 3; // # of color components per pixel cinfo.in_color_space = JCS_RGB; /* colorspace of input image */ } /* Now use the library's routine to set default compression parameters. * (You must set at least cinfo.in_color_space before calling this, * since the defaults depend on the source color space.) */ jpeg_set_defaults(&cinfo); /* Now you can set any non-default parameters you wish to. * Here we just illustrate the use of quality (quantization table) scaling: */ //#ifdef C_ARITH_CODING_SUPPORTED if ((GetCodecOption(CXIMAGE_FORMAT_JPG) & ENCODE_ARITHMETIC) != 0) cinfo.arith_code = TRUE; //#endif //#ifdef ENTROPY_OPT_SUPPORTED if ((GetCodecOption(CXIMAGE_FORMAT_JPG) & ENCODE_OPTIMIZE) != 0) cinfo.optimize_coding = TRUE; //#endif if ((GetCodecOption(CXIMAGE_FORMAT_JPG) & ENCODE_GRAYSCALE) != 0) jpeg_set_colorspace(&cinfo, JCS_GRAYSCALE); if ((GetCodecOption(CXIMAGE_FORMAT_JPG) & ENCODE_SMOOTHING) != 0) cinfo.smoothing_factor = m_nSmoothing; jpeg_set_quality(&cinfo, GetJpegQuality(), (GetCodecOption(CXIMAGE_FORMAT_JPG) & ENCODE_BASELINE) != 0); //#ifdef C_PROGRESSIVE_SUPPORTED if ((GetCodecOption(CXIMAGE_FORMAT_JPG) & ENCODE_PROGRESSIVE) != 0) jpeg_simple_progression(&cinfo); //#endif #ifdef C_LOSSLESS_SUPPORTED if ((GetCodecOption(CXIMAGE_FORMAT_JPG) & ENCODE_LOSSLESS) != 0) jpeg_simple_lossless(&cinfo, m_nPredictor, m_nPointTransform); #endif cinfo.density_unit=1; cinfo.X_density=(unsigned short)GetXDPI(); cinfo.Y_density=(unsigned short)GetYDPI(); /* Step 4: Start compressor */ /* TRUE ensures that we will write a complete interchange-JPEG file. * Pass TRUE unless you are very sure of what you're doing. */ jpeg_start_compress(&cinfo, TRUE); /* Step 5: while (scan lines remain to be written) */ /* jpeg_write_scanlines(...); */ /* Here we use the library's state variable cinfo.next_scanline as the * loop counter, so that we don't have to keep track ourselves. * To keep things simple, we pass one scanline per call; you can pass * more if you wish, though. */ row_stride = info.dwEffWidth; /* JSAMPLEs per row in image_buffer */ //<DP> "8+row_stride" fix heap deallocation problem during debug??? buffer = (*cinfo.mem->alloc_sarray) ((j_common_ptr) &cinfo, JPOOL_IMAGE, 8+row_stride, 1); CImageIterator iter(this); iter.Upset(); while (cinfo.next_scanline < cinfo.image_height) { // info.nProgress = (long)(100*cinfo.next_scanline/cinfo.image_height); iter.GetRow(buffer[0], row_stride); // not necessary if swapped red and blue definition in jmorecfg.h;ln322 <W. Morrison> if (head.biClrUsed==0){ // swap R & B for RGB images RGBtoBGR(buffer[0], row_stride); // Lance : 1998/09/01 : Bug ID: EXP-2.1.1-9 } iter.PrevRow(); (void) jpeg_write_scanlines(&cinfo, buffer, 1); } /* Step 6: Finish compression */ jpeg_finish_compress(&cinfo); /* Step 7: release JPEG compression object */ /* This is an important step since it will release a good deal of memory. */ jpeg_destroy_compress(&cinfo); #if CXIMAGEJPG_SUPPORT_EXIF if (m_exif && m_exif->m_exifinfo->IsExif){ // discard useless sections (if any) read from original image m_exif->DiscardAllButExif(); // read new created image, to split the sections hFile->Seek(pos,SEEK_SET); m_exif->DecodeExif(hFile,EXIF_READ_IMAGE); // save back the image, adding EXIF section hFile->Seek(pos,SEEK_SET); m_exif->EncodeExif(hFile); } #endif /* And we're done! */ return true; }
// Internal function used to save the Jpeg. ILboolean iSaveJpegInternal() { struct jpeg_compress_struct JpegInfo; struct jpeg_error_mgr Error; JSAMPROW row_pointer[1]; ILimage *TempImage; ILubyte *TempData; ILenum Type = 0; if (iCurImage == NULL) { ilSetError(IL_ILLEGAL_OPERATION); return IL_FALSE; } /*if (iGetHint(IL_COMPRESSION_HINT) == IL_USE_COMPRESSION) Quality = 85; // Not sure how low we should dare go... else Quality = 99;*/ if ((iCurImage->Format != IL_RGB && iCurImage->Format != IL_LUMINANCE) || iCurImage->Bpc != 1) { TempImage = iConvertImage(iCurImage, IL_RGB, IL_UNSIGNED_BYTE); if (TempImage == NULL) { return IL_FALSE; } } else { TempImage = iCurImage; } if (TempImage->Origin == IL_ORIGIN_LOWER_LEFT) { TempData = iGetFlipped(TempImage); if (TempData == NULL) { if (TempImage != iCurImage) ilCloseImage(TempImage); return IL_FALSE; } } else { TempData = TempImage->Data; } JpegInfo.err = jpeg_std_error(&Error); // Now we can initialize the JPEG compression object. jpeg_create_compress(&JpegInfo); //jpeg_stdio_dest(&JpegInfo, JpegFile); devil_jpeg_write_init(&JpegInfo); JpegInfo.image_width = TempImage->Width; // image width and height, in pixels JpegInfo.image_height = TempImage->Height; JpegInfo.input_components = TempImage->Bpp; // # of color components per pixel // John Villar's addition if (TempImage->Bpp == 1) JpegInfo.in_color_space = JCS_GRAYSCALE; else JpegInfo.in_color_space = JCS_RGB; jpeg_set_defaults(&JpegInfo); #ifndef IL_USE_JPEGLIB_UNMODIFIED Type = iGetInt(IL_JPG_SAVE_FORMAT); if (Type == IL_EXIF) { JpegInfo.write_JFIF_header = FALSE; JpegInfo.write_EXIF_header = TRUE; } else if (Type == IL_JFIF) { JpegInfo.write_JFIF_header = TRUE; JpegInfo.write_EXIF_header = FALSE; } #else Type = Type; JpegInfo.write_JFIF_header = TRUE; #endif//IL_USE_JPEGLIB_UNMODIFIED jpeg_set_quality(&JpegInfo, iGetInt(IL_JPG_QUALITY), IL_TRUE); jpeg_start_compress(&JpegInfo, IL_TRUE); //row_stride = image_width * 3; // JSAMPLEs per row in image_buffer while (JpegInfo.next_scanline < JpegInfo.image_height) { // jpeg_write_scanlines expects an array of pointers to scanlines. // Here the array is only one element long, but you could pass // more than one scanline at a time if that's more convenient. row_pointer[0] = &TempData[JpegInfo.next_scanline * TempImage->Bps]; (ILvoid) jpeg_write_scanlines(&JpegInfo, row_pointer, 1); } // Step 6: Finish compression jpeg_finish_compress(&JpegInfo); // Step 7: release JPEG compression object // This is an important step since it will release a good deal of memory. jpeg_destroy_compress(&JpegInfo); if (TempImage->Origin == IL_ORIGIN_LOWER_LEFT) ifree(TempData); if (TempImage != iCurImage) ilCloseImage(TempImage); return IL_TRUE; }
gint xjpg_save_drawable (const char *filename, gint32 image_ID, gint32 drawable_ID, gint save_mode, t_JpegSaveVals *jsvals) { GimpPixelRgn pixel_rgn; GimpDrawable *drawable; GimpImageType drawable_type; struct jpeg_compress_struct cinfo; struct my_error_mgr jerr; FILE * volatile outfile; guchar *temp, *t; guchar *data; guchar *src, *s; int has_alpha; int rowstride, yend; int i, j; int alpha_offset; guchar alpha_byte; guchar volatile l_alpha_sum; alpha_offset = 0; has_alpha = 0; src = NULL; temp = NULL; data = NULL; l_alpha_sum = 0xff; drawable = gimp_drawable_get (drawable_ID); drawable_type = gimp_drawable_type (drawable_ID); switch (drawable_type) { case GIMP_RGB_IMAGE: case GIMP_GRAY_IMAGE: if(save_mode == JSVM_ALPHA) return FALSE; /* there is no alpha to save */ break; case GIMP_RGBA_IMAGE: case GIMP_GRAYA_IMAGE: break; case GIMP_INDEXED_IMAGE: /*g_message ("jpeg: cannot operate on indexed color images");*/ return FALSE; break; default: /*g_message ("jpeg: cannot operate on unknown image types");*/ return FALSE; break; } gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0, drawable->width, drawable->height, FALSE, FALSE); /* Step 1: allocate and initialize JPEG compression object */ /* We have to set up the error handler first, in case the initialization * step fails. (Unlikely, but it could happen if you are out of memory.) * This routine fills in the contents of struct jerr, and returns jerr's * address which we place into the link field in cinfo. */ cinfo.err = jpeg_std_error (&jerr.pub); jerr.pub.error_exit = my_error_exit; outfile = NULL; /* 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. */ jpeg_destroy_compress (&cinfo); if (outfile) fclose (outfile); if (drawable) gimp_drawable_detach (drawable); return FALSE; } /* Now we can initialize the JPEG compression object. */ jpeg_create_compress (&cinfo); /* Step 2: specify data destination (eg, a file) */ /* Note: steps 2 and 3 can be done in either order. */ /* Here we use the library-supplied code to send compressed data to a * stdio stream. You can also write your own code to do something else. * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that * requires it in order to write binary files. */ if ((outfile = g_fopen (filename, "wb")) == NULL) { g_message ("can't open %s\n", filename); return FALSE; } jpeg_stdio_dest (&cinfo, outfile); /* Get the input image and a pointer to its data. */ switch (drawable_type) { case GIMP_RGB_IMAGE: case GIMP_GRAY_IMAGE: /* # of color components per pixel */ cinfo.input_components = drawable->bpp; has_alpha = 0; alpha_offset = 0; break; case GIMP_RGBA_IMAGE: case GIMP_GRAYA_IMAGE: if(save_mode == JSVM_ALPHA) { cinfo.input_components = 1; } else { /* # of color components per pixel (minus the GIMP alpha channel) */ cinfo.input_components = drawable->bpp - 1; } alpha_offset = drawable->bpp -1; has_alpha = 1; break; default: return FALSE; break; } /* Step 3: set parameters for compression */ /* First we supply a description of the input image. * Four fields of the cinfo struct must be filled in: */ /* image width and height, in pixels */ cinfo.image_width = drawable->width; cinfo.image_height = drawable->height; /* colorspace of input image */ cinfo.in_color_space = ( (save_mode != JSVM_ALPHA) && (drawable_type == GIMP_RGB_IMAGE || drawable_type == GIMP_RGBA_IMAGE)) ? JCS_RGB : JCS_GRAYSCALE; /* Now use the library's routine to set default compression parameters. * (You must set at least cinfo.in_color_space before calling this, * since the defaults depend on the source color space.) */ jpeg_set_defaults (&cinfo); /* Now you can set any non-default parameters you wish to. * Here we just illustrate the use of quality (quantization table) scaling: */ jpeg_set_quality (&cinfo, (int) (jsvals->quality * 100), TRUE /* limit to baseline-JPEG values */); cinfo.smoothing_factor = (int) (jsvals->smoothing * 100); cinfo.optimize_coding = jsvals->optimize; /* Step 4: Start compressor */ /* TRUE ensures that we will write a complete interchange-JPEG file. * Pass TRUE unless you are very sure of what you're doing. */ jpeg_start_compress (&cinfo, TRUE); /* Step 5: while (scan lines remain to be written) */ /* jpeg_write_scanlines(...); */ /* Here we use the library's state variable cinfo.next_scanline as the * loop counter, so that we don't have to keep track ourselves. * To keep things simple, we pass one scanline per call; you can pass * more if you wish, though. */ /* JSAMPLEs per row in image_buffer */ rowstride = drawable->bpp * drawable->width; temp = (guchar *) g_malloc (cinfo.image_width * cinfo.input_components); data = (guchar *) g_malloc (rowstride * gimp_tile_height ()); src = data; while (cinfo.next_scanline < cinfo.image_height) { if ((cinfo.next_scanline % gimp_tile_height ()) == 0) { yend = cinfo.next_scanline + gimp_tile_height (); yend = MIN (yend, cinfo.image_height); gimp_pixel_rgn_get_rect (&pixel_rgn, data, 0, cinfo.next_scanline, cinfo.image_width, (yend - cinfo.next_scanline)); src = data; } t = temp; s = src; i = cinfo.image_width; switch(save_mode) { case JSVM_DRAWABLE: if(jsvals->clr_transparent) { /* save drawable (clear pixels where alpha is full transparent) */ while (i--) { alpha_byte = s[cinfo.input_components]; for (j = 0; j < cinfo.input_components; j++) { if(alpha_byte != 0) { *t++ = *s++; } else { *t++ = 0; s++; } } if (has_alpha) /* ignore alpha channel */ { s++; } } } else { /* save the drawable as it is (ignore alpha channel) */ while (i--) { for (j = 0; j < cinfo.input_components; j++) { *t++ = *s++; } if (has_alpha) /* ignore alpha channel */ { s++; } } } break; case JSVM_ALPHA: /* save the drawable's alpha cahnnel */ while (i--) { s += alpha_offset; l_alpha_sum &= (*s); /* check all alpha bytes for full opacity */ *t++ = *s++; } break; } src += rowstride; jpeg_write_scanlines (&cinfo, (JSAMPARRAY) &temp, 1); if ((cinfo.next_scanline % 5) == 0) gimp_progress_update ((double) cinfo.next_scanline / (double) cinfo.image_height); } /* Step 6: Finish compression */ jpeg_finish_compress (&cinfo); /* After finish_compress, we can close the output file. */ fclose (outfile); if((save_mode == JSVM_ALPHA) && (l_alpha_sum == 0xff)) { /* all bytes in the alpha channel are set to 0xff * == full opaque image. We can remove the file * to save diskspace */ g_remove(filename); } /* Step 7: release JPEG compression object */ /* This is an important step since it will release a good deal of memory. */ jpeg_destroy_compress (&cinfo); /* free the temporary buffer */ g_free (temp); g_free (data); gimp_drawable_detach (drawable); return TRUE; } /* end xjpg_save_drawable */
static bool write_jpeg_image(const QImage &image, QIODevice *device, int sourceQuality) { bool success = false; const QVector<QRgb> cmap = image.colorTable(); struct jpeg_compress_struct cinfo; JSAMPROW row_pointer[1]; row_pointer[0] = 0; struct my_jpeg_destination_mgr *iod_dest = new my_jpeg_destination_mgr(device); struct my_error_mgr jerr; cinfo.err = jpeg_std_error(&jerr); jerr.error_exit = my_error_exit; if (!setjmp(jerr.setjmp_buffer)) { // WARNING: // this if loop is inside a setjmp/longjmp branch // do not create C++ temporaries here because the destructor may never be called // if you allocate memory, make sure that you can free it (row_pointer[0]) jpeg_create_compress(&cinfo); cinfo.dest = iod_dest; cinfo.image_width = image.width(); cinfo.image_height = image.height(); bool gray=false; switch (image.format()) { case QImage::Format_Mono: case QImage::Format_MonoLSB: case QImage::Format_Indexed8: gray = true; for (int i = image.colorCount(); gray && i--;) { gray = gray & (qRed(cmap[i]) == qGreen(cmap[i]) && qRed(cmap[i]) == qBlue(cmap[i])); } cinfo.input_components = gray ? 1 : 3; cinfo.in_color_space = gray ? JCS_GRAYSCALE : JCS_RGB; break; default: cinfo.input_components = 3; cinfo.in_color_space = JCS_RGB; } jpeg_set_defaults(&cinfo); qreal diffInch = qAbs(image.dotsPerMeterX()*2.54/100. - qRound(image.dotsPerMeterX()*2.54/100.)) + qAbs(image.dotsPerMeterY()*2.54/100. - qRound(image.dotsPerMeterY()*2.54/100.)); qreal diffCm = (qAbs(image.dotsPerMeterX()/100. - qRound(image.dotsPerMeterX()/100.)) + qAbs(image.dotsPerMeterY()/100. - qRound(image.dotsPerMeterY()/100.)))*2.54; if (diffInch < diffCm) { cinfo.density_unit = 1; // dots/inch cinfo.X_density = qRound(image.dotsPerMeterX()*2.54/100.); cinfo.Y_density = qRound(image.dotsPerMeterY()*2.54/100.); } else { cinfo.density_unit = 2; // dots/cm cinfo.X_density = (image.dotsPerMeterX()+50) / 100; cinfo.Y_density = (image.dotsPerMeterY()+50) / 100; } int quality = sourceQuality >= 0 ? qMin(sourceQuality,100) : 75; jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */); jpeg_start_compress(&cinfo, TRUE); row_pointer[0] = new uchar[cinfo.image_width*cinfo.input_components]; int w = cinfo.image_width; while (cinfo.next_scanline < cinfo.image_height) { uchar *row = row_pointer[0]; switch (image.format()) { case QImage::Format_Mono: case QImage::Format_MonoLSB: if (gray) { const uchar* data = image.constScanLine(cinfo.next_scanline); if (image.format() == QImage::Format_MonoLSB) { for (int i=0; i<w; i++) { bool bit = !!(*(data + (i >> 3)) & (1 << (i & 7))); row[i] = qRed(cmap[bit]); } } else { for (int i=0; i<w; i++) { bool bit = !!(*(data + (i >> 3)) & (1 << (7 -(i & 7)))); row[i] = qRed(cmap[bit]); } } } else { const uchar* data = image.constScanLine(cinfo.next_scanline); if (image.format() == QImage::Format_MonoLSB) { for (int i=0; i<w; i++) { bool bit = !!(*(data + (i >> 3)) & (1 << (i & 7))); *row++ = qRed(cmap[bit]); *row++ = qGreen(cmap[bit]); *row++ = qBlue(cmap[bit]); } } else { for (int i=0; i<w; i++) { bool bit = !!(*(data + (i >> 3)) & (1 << (7 -(i & 7)))); *row++ = qRed(cmap[bit]); *row++ = qGreen(cmap[bit]); *row++ = qBlue(cmap[bit]); } } }
int JpegCompressor::compressRawImage(const void * image, int width, int height, int quality, int useEffect = 0) { void * src = const_cast<void *>(image); uint8_t *yp = static_cast<uint8_t *>(src); struct jpeg_compress_struct cinfo; struct jpeg_error_mgr jerr; JSAMPROW row_pointer[1]; uint8_t *line_buffer; int bufferlen = width*height<<1; line_buffer = (uint8_t*)calloc(width*3,1); mJpegBuffer = new uint8_t[bufferlen]; mJpegSize = 0; if(!line_buffer) { LOGE("@TEI compress_yuv_to_jpeg: line_buffer calloc failed!" ); return -1; } if (!mJpegBuffer) { free(line_buffer); return -1; } cinfo.err = jpeg_std_error (&jerr); jpeg_create_compress (&cinfo); jpeg_nf_stdio_dest(&cinfo,(char*)mJpegBuffer,&bufferlen ); cinfo.image_width = width; cinfo.image_height = height; cinfo.input_components = 3; cinfo.in_color_space = JCS_RGB; jpeg_set_defaults (&cinfo); jpeg_set_quality (&cinfo, quality, TRUE); jpeg_start_compress (&cinfo, TRUE); uint8_t *vp, *up,*vpos, *upos; getYuvOffsets(width, height, yp, &up, &vp); vpos=vp; upos=up; uint32_t rgb = 0xFFFFFFFF; int z = 0; while (cinfo.next_scanline < cinfo.image_height) { unsigned char *ptr = line_buffer; for (int x = 0; x < width; x += 2) { rgb = YUVToRGB32WithEffect(*yp, *up, *vp, useEffect); *ptr++ = R32(rgb); *ptr++ = G32(rgb); *ptr++ = B32(rgb); // yp += mStrides[0]; rgb = YUVToRGB32WithEffect(*yp, *up, *vp, useEffect); *ptr++ = R32(rgb); *ptr++ = G32(rgb); *ptr++ = B32(rgb); // yp += mStrides[0]; up += mStrides[1]; vp += mStrides[2]; } if (mIs420) { if (z == 0) { vp = vpos; up = upos; z++; } else { vpos = vp; upos = up; z--; } } row_pointer[0] = line_buffer; jpeg_write_scanlines (&cinfo, row_pointer, 1); } jpeg_finish_compress (&cinfo); jpeg_destroy_compress (&cinfo); free (line_buffer); mJpegSize = bufferlen; LOGD("====== Jpeg size: %d ======", mJpegSize); return 0; }
/****************************************************************************** Description.: yuv2jpeg function is based on compress_yuyv_to_jpeg written by Gabriel A. Devenyi. It uses the destination manager implemented above to compress YUYV data to JPEG. Most other implementations use the "jpeg_stdio_dest" from libjpeg, which can not store compressed pictures to memory instead of a file. Input Value.: video structure from v4l2uvc.c/h, destination buffer and buffersize the buffer must be large enough, no error/size checking is done! Return Value: the buffer will contain the compressed data ******************************************************************************/ int compress_yuyv_to_jpeg(struct vdIn *vd, unsigned char *buffer, int size, int quality,uint32_t format) { struct jpeg_compress_struct cinfo; struct jpeg_error_mgr jerr; JSAMPROW row_pointer[1]; unsigned char *line_buffer, *yuyv; int z; static int written; line_buffer = calloc(vd->width * 3, 1); yuyv = vd->framebuffer; cinfo.err = jpeg_std_error(&jerr); jpeg_create_compress(&cinfo); /* jpeg_stdio_dest (&cinfo, file); */ dest_buffer(&cinfo, buffer, size, &written); cinfo.image_width = vd->width; cinfo.image_height = vd->height; cinfo.input_components = 3; cinfo.in_color_space = JCS_RGB; jpeg_set_defaults(&cinfo); jpeg_set_quality(&cinfo, quality, TRUE); jpeg_start_compress(&cinfo, TRUE); z = 0; while(cinfo.next_scanline < vd->height) { int x; unsigned char *ptr = line_buffer; /*TODO: make sure you are dealing with V4L2_PIX_FMT_YUYV here */ for(x = 0; x < vd->width; x++) { int r, g, b; int y, u, v; if(!z) y = yuyv[0] << 8; else y = yuyv[2] << 8; u = yuyv[1] - 128; v = yuyv[3] - 128; r = (y + (359 * v)) >> 8; g = (y - (88 * u) - (183 * v)) >> 8; b = (y + (454 * u)) >> 8; *(ptr++) = (r > 255) ? 255 : ((r < 0) ? 0 : r); *(ptr++) = (g > 255) ? 255 : ((g < 0) ? 0 : g); *(ptr++) = (b > 255) ? 255 : ((b < 0) ? 0 : b); if(z++) { z = 0; yuyv += 4; } } row_pointer[0] = line_buffer; jpeg_write_scanlines(&cinfo, row_pointer, 1); } jpeg_finish_compress(&cinfo); jpeg_destroy_compress(&cinfo); free(line_buffer); return (written); }
//============================================================================= // Bitmap2JPG - Enregistre un BITMAP dans un fichier JPEG // // Parametres // HBITMAP hBitmap : Bitmap a convertir (DDB) // LPCTSTR pszFileJPG : Fichier de sortie (.JPG) // int nQualite : Qualite de l'image [0-100] // // Retour // TRUE si ok, FALSE si erreur //============================================================================= BOOL Bitmap2JPG(HBITMAP hBitmap, LPCTSTR pszFileJPG, int nQualite) { struct jpeg_compress_struct cinfo; struct jpeg_error_mgr jerr; struct WIN32_destination_mgr dest; BITMAP bm; BITMAPINFO bi; HANDLE hFile; HDC hdcScr, hdcMem1, hdcMem2; HBITMAP hbmMem, hbmOld1, hbmOld2; JSAMPROW jrows[1], jrow; LPBYTE pPixels; UINT nRowLen; if(!hBitmap) return FALSE; if(!GetObject(hBitmap, sizeof(bm), &bm)) return FALSE; // Creation DIB ------------------------------------- ZeroMemory(&bi, sizeof(bi)); bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bi.bmiHeader.biWidth = bm.bmWidth; bi.bmiHeader.biHeight = bm.bmHeight; bi.bmiHeader.biPlanes = 1; bi.bmiHeader.biBitCount = 24; bi.bmiHeader.biCompression = BI_RGB; hdcScr = GetDC(NULL); hdcMem1 = CreateCompatibleDC(hdcScr); //Asi estaban originalmente v2.9 hbmOld1 = SelectObject(hdcMem1, hBitmap); hbmOld1 = (HBITMAP)::SelectObject(hdcMem1, hBitmap); hdcMem2 = CreateCompatibleDC(hdcScr); hbmMem = CreateDIBSection(hdcScr, &bi, DIB_RGB_COLORS, (LPVOID *)&pPixels, 0, 0); //Asi estaban originalmente v2.9 hbmOld2 = SelectObject(hdcMem2, hbmMem); hbmOld2 = (HBITMAP)::SelectObject(hdcMem2, hbmMem); BitBlt(hdcMem2, 0, 0, bm.bmWidth, bm.bmHeight, hdcMem1, 0, 0, SRCCOPY); SelectObject(hdcMem1, hbmOld1); SelectObject(hdcMem2, hbmOld2); ReleaseDC(NULL, hdcScr); DeleteDC(hdcMem1); DeleteDC(hdcMem2); // Creation fichier JPG ----------------------------- hFile = CreateFile(pszFileJPG, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if(hFile == INVALID_HANDLE_VALUE) return FALSE; cinfo.err = jpeg_std_error(&jerr); jpeg_create_compress(&cinfo); cinfo.dest = WIN32_jpeg_dest(&dest, hFile); cinfo.image_width = bm.bmWidth; cinfo.image_height = bm.bmHeight; cinfo.input_components = 3; cinfo.in_color_space = JCS_RGB; jpeg_set_defaults(&cinfo); jpeg_set_quality(&cinfo, (nQualite < 0 || nQualite > 100) ? 100 : nQualite, TRUE); jpeg_start_compress(&cinfo, TRUE); nRowLen = (((bm.bmWidth * 24) + 31) / 32) * 4; while(cinfo.next_scanline < cinfo.image_height) { int i, j, tmp; jrow = &pPixels[(cinfo.image_height - cinfo.next_scanline - 1) * nRowLen]; for(i = 0; i < cinfo.image_width; i++) { j = i * 3; tmp = jrow[j]; jrow[j] = jrow[j + 2]; jrow[j + 2] = tmp; } jrows[0] = jrow; jpeg_write_scanlines(&cinfo, jrows, 1); } jpeg_finish_compress(&cinfo); jpeg_destroy_compress(&cinfo); CloseHandle(hFile); // v2.9 //Las tres siguientes lineas! son IMPORTANTISIMAS!!!! //Libera la memoria que ocupan esos bitmaps!!! DeleteObject(hbmOld1); DeleteObject(hbmOld2); DeleteObject(hbmMem); return TRUE; }
int main(int argc, char **argv) { struct jpeg_decompress_struct dinfo; struct jpeg_compress_struct cinfo; struct jpeg_error_mgr jerr; char *file1; /* input filename */ char *file2; /* output filename */ FILE *fh1; /* input file handle */ FILE *fh2; /* output file handle */ float *data; /* partially-convolved rows in 4-tuples: r, g, b, sum */ float **ptrs; /* pointers into input buffer, one for each scanline */ JSAMPLE *line; /* input/output buffer */ float *fx,*fy; /* convolution kernel cache */ int mode; /* resize mode (see M_SET_SIZE, etc.) */ int quality; /* jpeg quality: 0 to 100 */ int len; /* length of one line in data */ int w1, h1, z1; /* size of input image */ int w2, h2; /* size of output image */ int w3, h3; /* size of convolution kernel */ int xo, yo; /* number of cols/rows to side of center of kernel */ int y1, n1; /* first row and number of rows loaded into input buffer */ int yc; /* last row loaded from input file */ int x2, y2; /* current location in output image */ float ox, oy; /* offset of origin in input image */ float sx, sy; /* amount to scale horizontal and vertical */ float xf, yf; /* corresponding location in input image */ float ax, ay; /* constants needed for Lanczos kernel */ float extra; /* multiply kernel radius by this to get extra lobes */ int kernel; /* boolean: dump convolution kernel and abort? */ int verbose; /* boolean: verbose mode? */ /* Temporary variables. */ float *ptr1, *ptr2, *ptr3; JSAMPLE *ptr4; int x, y, i, j, k, c; float f, r, g, b, s, *accum; /* Print help message. */ if (argc <= 1 || get_flag(argv, &argc, "-h", "--help")) { printf("\n"); printf("USAGE\n"); printf(" %s\n", USAGE); printf("\n"); printf("OPTIONS\n"); printf(" <w>x<h> Width and height of output image, e.g., '200x200'.\n"); printf(" <input.jpg> Input image. Must be 'normal' RGB color JPEG.\n"); printf(" <output.jpg> Output image. Clobbers any existing file.\n"); printf("\n"); printf(" --set-size Default mode: set to given size, ignoring aspect ratio.\n"); printf(" --set-area Keep aspect ratio, reducing/enlarging to area of given box.\n"); printf(" --max-size Keep aspect ratio, reducing to within given box.\n"); printf(" --max-area Keep aspect ratio, reducing to area of given box.\n"); printf(" --min-size Keep aspect ratio, enlarging to contain given box.\n"); printf(" --min-area Keep aspect ratio, enlarging to area of given box.\n"); printf(" --crop Reduce/enlarge, cropping to get correct ratio.\n"); printf("\n"); printf(" -q --quality <pct> JPEG quality of output image; default depends on size.\n"); printf(" -r --radius <n> Radius of convolution kernel, > 0; default is 1.0.\n"); printf(" -s --sharp <n> Amount to sharpen output, >= 0; default is 0.2.\n"); printf("\n"); printf(" --flat Average pixels within box of given radius.\n"); printf(" --linear Weight pixels within box linearly by closeness.\n"); printf(" --hermite Hermite cubic spline filter; similar to Gaussian.\n"); printf(" --catrom [<M>] Catmull-Rom cubic spline; default is M = 0.5 at R = 1.\n"); printf(" --mitchell Mitchell-Netravali filter (see Keys filter).\n"); printf(" --keys [<B> <C>] Keys family filters; default is B = C = 1/3 (Mitchell).\n"); printf(" --lanczos [<N>] Lanczos windowed sinc filter; default is N = 3 lobes.\n"); printf("\n"); printf(" -h --help Print this message.\n"); printf(" -v --verbose Verbose / debug mode.\n"); printf(" -k --kernel Dump convolution kernel without processing image.\n"); printf("\n"); exit(1); } /* Get command line args. */ get_size(argv, &argc, &w2, &h2); quality = get_value(argv, &argc, "-q", "--quality", default_quality(w2, h2)); radius = get_value(argv, &argc, "-r", "--radius", 1.0); sharp = get_value(argv, &argc, "-s", "--sharp", 0.2); verbose = get_flag(argv, &argc, "-v", "--verbose"); kernel = get_flag(argv, &argc, "-k", "--kernel"); /* Only allowed one mode flag. */ mode = get_flag(argv, &argc, "--set-size", 0) ? M_SET_SIZE : get_flag(argv, &argc, "--max-size", 0) ? M_MAX_SIZE : get_flag(argv, &argc, "--min-size", 0) ? M_MIN_SIZE : get_flag(argv, &argc, "--set-area", 0) ? M_SET_AREA : get_flag(argv, &argc, "--max-area", 0) ? M_MAX_AREA : get_flag(argv, &argc, "--min-area", 0) ? M_MIN_AREA : get_flag(argv, &argc, "--crop", 0) ? M_CROP : M_SET_SIZE; /* Each filter type takes different arguments. */ if (get_filter(argv, &argc, "--flat", 0, 0, 0)) { filter = F_FLAT; extra = 1.0; } else if (get_filter(argv, &argc, "--linear", 0, 0, 0)) { filter = F_LINEAR; extra = 1.0; } else if (get_filter(argv, &argc, "--hermite", 0, 0, 0)) { filter = F_HERMITE; extra = 1.0; } else if (get_filter(argv, &argc, "--catrom", 1, 1.0, 0.0)) { filter = F_CATROM; extra = 2.0; } else if (get_filter(argv, &argc, "--mitchell", 0, 0.0, 0.0)) { filter = F_KEYS; extra = 2.0; arg1 = 1.0 / 3.0; arg2 = 1.0 / 3.0; } else if (get_filter(argv, &argc, "--keys", 2, 1.0/3.0, 1.0/3.0)) { filter = F_KEYS; extra = 2.0; } else if (get_filter(argv, &argc, "--lanczos", 1, 3.0, 0.0)) { filter = F_LANCZOS; extra = arg1; } else { filter = F_LANCZOS; arg1 = 3.0; extra = arg1; } /* Get files last because they complain if there are any flags left. */ file1 = get_file(argv, &argc); file2 = get_file(argv, &argc); if (argc > 1) bad_usage("unexpected argument: %s", argv[1]); /* Create and initialize decompress object. */ dinfo.err = jpeg_std_error(&jerr); jpeg_create_decompress(&dinfo); if ((fh1 = fopen(file1, "rb")) == NULL) { fprintf(stderr, "can't open %s for reading\n", file1); exit(1); } jpeg_stdio_src(&dinfo, fh1); /* Get dimensions and format of input image. */ jpeg_read_header(&dinfo, TRUE); jpeg_start_decompress(&dinfo); w1 = dinfo.output_width; h1 = dinfo.output_height; z1 = dinfo.output_components; /* Choose output size. */ if (mode == M_SET_SIZE) { /* leave as is */ sx = (double)w2 / w1; sy = (double)h2 / h1; ox = oy = 0.0; } else if (mode == M_MAX_SIZE) { if (w1 > w2 && h1 * w2 / w1 < h2) { sx = sy = (double)w2 / w1; h2 = sy * h1 + 0.5; } else if (h1 > h2) { sx = sy = (double)h2 / h1; w2 = sx * w1 + 0.5; } else { sx = sy = 1.0; w2 = w1; h2 = h1; } ox = oy = 0.0; } else if (mode == M_MIN_SIZE) { if (w1 < w2 && h1 * w2 / w1 > h2) { sx = sy = (double)w2 / w1; h2 = sy * h1 + 0.5; } else if (h1 < h2) { sx = sy = (double)h2 / h1; w2 = sx * w1 + 0.5; } else { sx = sy = 1.0; w2 = w1; h2 = h1; } ox = oy = 0.0; } else if (mode == M_SET_AREA) { sx = sy = sqrt(((double)w2) * h2 / w1 / h1); w2 = sx * w1 + 0.5; h2 = sy * h1 + 0.5; ox = oy = 0.0; } else if (mode == M_MAX_AREA) { if (w1 * h1 > w2 * h2) { sx = sy = sqrt(((double)w2) * h2 / w1 / h1); w2 = sx * w1 + 0.5; h2 = sy * h1 + 0.5; } else { sx = sy = 1.0; w2 = w1; h2 = h1; } ox = oy = 0.0; } else if (mode == M_MIN_AREA) { if (w1 * h1 < w2 * h2) { sx = sy = sqrt(((double)w2) * h2 / w1 / h1); w2 = sx * w1 + 0.5; h2 = sy * h1 + 0.5; } else { sx = sy = 1.0; w2 = w1; h2 = h1; } ox = oy = 0.0; } else if (mode == M_CROP) { sx = (double)w2 / w1; sy = (double)h2 / h1; sx = sy = sx > sy ? sx : sy; ox = ((double)w1 - (double)w2 / sx) * 0.5; oy = ((double)h1 - (double)h2 / sy) * 0.5; } else { fprintf(stderr, "invalid mode: %d!", mode); exit(1); } if (verbose) { fprintf(stderr, "input: %dx%d (%d) %s\n", w1, h1, z1, file1); fprintf(stderr, "output: %dx%d (%d) %s\n", w2, h2, z1, file2); if (sx > 1.0 && sy > 1.0) fprintf(stderr, "enlarge: %.2f %.2f\n", sx*1.0, sy*1.0); else fprintf(stderr, "reduce: %.2f %.2f\n", 1.0/sx, 1.0/sy); fprintf(stderr, "origin: %.2f %.2f\n", ox, oy); fprintf(stderr, "quality: %d\n", quality); fprintf(stderr, "radius: %f\n", radius); fprintf(stderr, "sharp: %f\n", sharp); if (filter == F_FLAT) fprintf(stderr, "filter: flat\n"); if (filter == F_LINEAR) fprintf(stderr, "filter: bilinear\n"); if (filter == F_HERMITE) fprintf(stderr, "filter: hermite\n"); if (filter == F_CATROM) fprintf(stderr, "filter: Catmull-Rom (M=%f)\n", arg1); if (filter == F_KEYS) fprintf(stderr, "filter: Keys-family (B=%f, C=%f)\n", arg1, arg2); if (filter == F_LANCZOS) fprintf(stderr, "filter: Lanczos (N=%f)\n", arg1); } /* Calculate size of convolution kernel. */ ax = sx < 1 ? radius / sx : radius; ay = sy < 1 ? radius / sy : radius; xo = (int)(ax * extra + 0.5); yo = (int)(ay * extra + 0.5); w3 = xo + xo + 1; h3 = yo + yo + 1; /* Pre-calculate coefficients for Keys-family filters. */ if (filter == F_CATROM) { filter = F_KEYS; c1 = 2.0 - arg1; c2 = -3.0 + arg1; c3 = 0.0; c4 = 1.0; c5 = -arg1; c6 = 2.0 * arg1; c7 = -arg1; c8 = 0.0; } else if (filter == F_KEYS) { c1 = ( 12.0 + -9.0 * arg1 + -6.0 * arg2) / 6.0; c2 = (-18.0 + 12.0 * arg1 + 6.0 * arg2) / 6.0; c3 = ( 0.0 + 0.0 * arg1 + 0.0 * arg2) / 6.0; c4 = ( 6.0 + -2.0 * arg1 + 0.0 * arg2) / 6.0; c5 = ( 0.0 + -1.0 * arg1 + -6.0 * arg2) / 6.0; c6 = ( 0.0 + 3.0 * arg1 + 12.0 * arg2) / 6.0; c7 = ( 0.0 + -3.0 * arg1 + -6.0 * arg2) / 6.0; c8 = ( 0.0 + 1.0 * arg1 + 0.0 * arg2) / 6.0; } if (verbose) { fprintf(stderr, "w1-h1: %d %d\n", w1, h1); fprintf(stderr, "xo-yo: %d %d\n", xo, yo); fprintf(stderr, "w3-h3: %d %d\n", w3, h3); fprintf(stderr, "ax-ay: %8.5f %8.5f\n", ax, ay); fprintf(stderr, "c1-4: %8.5f %8.5f %8.5f %8.5f\n", c1, c2, c3, c4); fprintf(stderr, "c5-8: %8.5f %8.5f %8.5f %8.5f\n", c5, c6, c7, c8); } /* Debug convolution kernel. */ if (kernel) { f = -1; for (xf=0; xf<10.0; xf+=0.1) { s = calc_factor(xf); fprintf(stderr, "%5.2f %7.4f\n", xf, s); if (s == 0.0 && f == 0.0) break; f = s; } exit(0); } /* Allocate buffers. */ len = w2 * (z1 + 1); data = (float*)malloc(h3 * len * sizeof(float)); ptrs = (float**)malloc(h3 * sizeof(float*)); line = (JSAMPLE*)malloc((w1 > w2 ? w1 : w2) * z1 * sizeof(JSAMPLE)); fx = (float*)malloc(w2 * w3 * sizeof(float)); fy = (float*)malloc(h2 * h3 * sizeof(float)); accum = (float*)malloc(z1 * sizeof(float)); /* Cache horizontal and vertical components of kernel. */ for (x2=0, ptr3=fx; x2<w2; x2++) { xf = ((float)x2) / sx + ox; for (i=0, x=(int)xf-xo; i<w3; i++, x++) { *ptr3++ = calc_factor(fabs(xf-x) / ax); } } for (y2=0, ptr3=fy; y2<h2; y2++) { yf = ((float)y2) / sy + oy; for (i=0, y=(int)yf-yo; i<h3; i++, y++) { *ptr3++ = calc_factor(fabs(yf-y) / ay); } } /* Create and initialize compress object. */ cinfo.err = jpeg_std_error(&jerr); jpeg_create_compress(&cinfo); if ((fh2 = fopen(file2, "wb")) == NULL) { fprintf(stderr, "can't open %s for writing\n", file2); exit(1); } jpeg_stdio_dest(&cinfo, fh2); cinfo.image_width = w2; cinfo.image_height = h2; cinfo.input_components = z1; switch (z1) { case 1: cinfo.in_color_space = JCS_GRAYSCALE; break; case 3: cinfo.in_color_space = JCS_RGB; break; case 4: cinfo.in_color_space = JCS_CMYK; break; default: fprintf(stderr, "Not sure what colorspace to make output for input file with %d components.\n", z1); exit(1); } jpeg_set_defaults(&cinfo); jpeg_set_quality(&cinfo, quality, TRUE); jpeg_start_compress(&cinfo, TRUE); /* Loop through output rows. */ n1 = 0; /* (num lines in buffer) */ yc = -1; /* (last line loaded) */ for (y2=0; y2<h2; y2++) { yf = ((float)y2) / sy + oy; /* Make sure we have the 'yo' rows above and below this row. */ y = (int)yf - yo; if (y - y1 >= h3) n1 = 0; ptr1 = n1 ? ptrs[y - y1] : data; if (n1) n1 -= y - y1; for (i=0; i<h3; i++, y++) { /* Move already-loaded lines into place until run out. */ ptrs[i] = ptr1; ptr1 += len; if (ptr1 >= data + len * h3) ptr1 = data; /* Need to load this line into next available slot. */ /* It's okay to leave junk in lines outside input image. */ if (n1-- <= 0 && y >= 0 && y < h1) { /* Read lines until get the one we want. */ for (; yc<y; yc++) { if (!jpeg_read_scanlines(&dinfo, &line, 1)) { fprintf(stderr, "JPEG image corrupted at line %d.\n", yc); exit(1); } } /* Do horizontal part of convolution now. Stores a partial /* result for each output column for this input row. */ /* ------------------------- start switch 1 on z1 ------------------------- */ switch (z1) { case 1: for (x2=0, ptr2=ptrs[i], ptr3=fx; x2<w2; x2++) { xf = ((float)x2) / sx + ox; r = s = 0; for (j=0, x=(int)xf-xo; j<w3; j++, x++) { f = *ptr3++; if (x >= 0 && x < w1 && fabs(f) > 1e-8) { ptr4 = line + x; r += f * *ptr4++; s += f; } } if (fabs(s) > 1e-3) { *ptr2++ = r; *ptr2++ = s; } else { fprintf(stderr, "x factor near zero -- shouldn't happen!\n"); ptr4 = line + (int)xf; *ptr2++ = *ptr4++; *ptr2++ = 1.0; } } break; case 3: for (x2=0, ptr2=ptrs[i], ptr3=fx; x2<w2; x2++) { xf = ((float)x2) / sx + ox; r = g = b = s = 0; for (j=0, x=(int)xf-xo; j<w3; j++, x++) { f = *ptr3++; if (x >= 0 && x < w1 && fabs(f) > 1e-8) { ptr4 = line + x + x + x; r += f * *ptr4++; g += f * *ptr4++; b += f * *ptr4++; s += f; } } if (fabs(s) > 1e-3) { *ptr2++ = r; *ptr2++ = g; *ptr2++ = b; *ptr2++ = s; } else { fprintf(stderr, "x factor near zero -- shouldn't happen!\n"); ptr4 = line + (int)xf * 3; *ptr2++ = *ptr4++; *ptr2++ = *ptr4++; *ptr2++ = *ptr4++; *ptr2++ = 1.0; } } break; default: for (x2=0, ptr2=ptrs[i], ptr3=fx; x2<w2; x2++) { xf = ((float)x2) / sx + ox; for (s=k=0; k<z1; k++) accum[k] = 0; for (j=0, x=(int)xf-xo; j<w3; j++, x++) { f = *ptr3++; if (x >= 0 && x < w1 && fabs(f) > 1e-8) { ptr4 = line + x * z1; for (k=0; k<z1; k++) accum[k] += f * *ptr4++; s += f; } } if (fabs(s) > 1e-3) { for (k=0; k<z1; k++) *ptr2++ = accum[k]; *ptr2++ = s; } else { fprintf(stderr, "x factor near zero -- shouldn't happen!\n"); ptr4 = line + (int)xf * z1; for (k=0; k<z1; k++) *ptr2++ = *ptr4++; *ptr2++ = 1.0; } } } /* ------------------------- end switch 1 on z1 ------------------------- */ } /* printf("i=%d y2=%d yc=%d y1=%d n1=%d ptrs[i]=%d\n", i, y2, yc, y1, n1, (ptrs[i]-data)/len); */ } /* Now have h3 lines in buffer, starting at y - yo. */ y1 = (int)yf - yo; n1 = h3; /* Do vertical part of convolution now. Finish off calculation for /* each output column in this output row by iterating over partial /* results for each corresponding input row we calculated above. */ /* ------------------------- start switch 2 on z1 ------------------------- */ switch (z1) { case 1: for (x2=0, ptr4=line; x2<w2; x2++) { xf = ((float)x2) / sx + ox; r = s = 0; ptr3 = fy + y2 * h3; for (i=0, y=(int)yf-yo; i<h3; i++, y++) { f = *ptr3++; if (y >= 0 && y < h1 && fabs(f) > 1e-8) { ptr1 = ptrs[i] + x2 + x2; r += f * *ptr1++; s += f * *ptr1++; } /* printf("x2=%d y2=%d i=%d f=%f s=%f (y=%d ptr1=%d)\n", x2, y2, i, f, s, y, (ptr1-data)/len); */ } if (fabs(s) > 1e-3) { *ptr4++ = (c = r / s) > 255 ? 255 : c < 0 ? 0 : c; } else { fprintf(stderr, "y factor near zero -- shouldn't happen!\n"); ptr1 = ptrs[h3/2] + ((int)xf) * 4; *ptr4++ = *ptr1++; } } break; case 3: for (x2=0, ptr4=line; x2<w2; x2++) { xf = ((float)x2) / sx + ox; r = g = b = s = 0; ptr3 = fy + y2 * h3; for (i=0, y=(int)yf-yo; i<h3; i++, y++) { f = *ptr3++; if (y >= 0 && y < h1 && fabs(f) > 1e-8) { ptr1 = ptrs[i] + x2 * 4; r += f * *ptr1++; g += f * *ptr1++; b += f * *ptr1++; s += f * *ptr1++; } /* printf("x2=%d y2=%d i=%d f=%f s=%f (y=%d ptr1=%d)\n", x2, y2, i, f, s, y, (ptr1-data)/len); */ } if (fabs(s) > 1e-3) { *ptr4++ = (c = r / s) > 255 ? 255 : c < 0 ? 0 : c; *ptr4++ = (c = g / s) > 255 ? 255 : c < 0 ? 0 : c; *ptr4++ = (c = b / s) > 255 ? 255 : c < 0 ? 0 : c; } else { fprintf(stderr, "y factor near zero -- shouldn't happen!\n"); ptr1 = ptrs[h3/2] + ((int)xf) * 4; *ptr4++ = *ptr1++; *ptr4++ = *ptr1++; *ptr4++ = *ptr1++; } } break; default: for (x2=0, ptr4=line; x2<w2; x2++) { xf = ((float)x2) / sx + ox; for (s=k=0; k<z1; k++) accum[k] = 0; ptr3 = fy + y2 * h3; for (i=0, y=(int)yf-yo; i<h3; i++, y++) { f = *ptr3++; if (y >= 0 && y < h1 && fabs(f) > 1e-8) { ptr1 = ptrs[i] + x2 * (z1 + 1); for (k=0; k<z1; k++) accum[k] += f * *ptr1++; s += f * *ptr1++; } /* printf("x2=%d y2=%d i=%d f=%f s=%f (y=%d ptr1=%d)\n", x2, y2, i, f, s, y, (ptr1-data)/len); */ } if (fabs(s) > 1e-3) { for (k=0; k<z1; k++) *ptr4++ = (c = accum[k] / s) > 255 ? 255 : c < 0 ? 0 : c; } else { fprintf(stderr, "y factor near zero -- shouldn't happen!\n"); ptr1 = ptrs[h3/2] + ((int)xf) * 4; for (k=0; k<z1; k++) *ptr4++ = *ptr1++; } } } /* ------------------------- end switch 2 on z1 ------------------------- */ /* Write this output line. */ jpeg_write_scanlines(&cinfo, &line, 1); } /* Finish off compression. */ jpeg_finish_compress(&cinfo); /* Clean up. */ jpeg_destroy_decompress(&dinfo); jpeg_destroy_compress(&cinfo); free(data); free(line); free(ptrs); free(fx); free(accum); exit(0); }
int compress_yuyv_to_jpeg (struct vdIn *vd, FILE * file, int quality) { struct jpeg_compress_struct cinfo; struct jpeg_error_mgr jerr; JSAMPROW row_pointer[1]; unsigned char *line_buffer, *yuyv; int z; fprintf (stderr, "Compressing YUYV frame to JPEG image.\n"); line_buffer = calloc (vd->width * 3, 1); yuyv = vd->framebuffer; cinfo.err = jpeg_std_error (&jerr); jpeg_create_compress (&cinfo); jpeg_stdio_dest (&cinfo, file); cinfo.image_width = vd->width; cinfo.image_height = vd->height; cinfo.input_components = 3; cinfo.in_color_space = JCS_RGB; jpeg_set_defaults (&cinfo); jpeg_set_quality (&cinfo, quality, TRUE); jpeg_start_compress (&cinfo, TRUE); z = 0; while (cinfo.next_scanline < cinfo.image_height) { int x; unsigned char *ptr = line_buffer; for (x = 0; x < vd->width; x++) { int r, g, b; int y, u, v; if (!z) y = yuyv[0] << 8; else y = yuyv[2] << 8; u = yuyv[1] - 128; v = yuyv[3] - 128; r = (y + (359 * v)) >> 8; g = (y - (88 * u) - (183 * v)) >> 8; b = (y + (454 * u)) >> 8; *(ptr++) = (r > 255) ? 255 : ((r < 0) ? 0 : r); *(ptr++) = (g > 255) ? 255 : ((g < 0) ? 0 : g); *(ptr++) = (b > 255) ? 255 : ((b < 0) ? 0 : b); if (z++) { z = 0; yuyv += 4; } } row_pointer[0] = line_buffer; jpeg_write_scanlines (&cinfo, row_pointer, 1); } jpeg_finish_compress (&cinfo); jpeg_destroy_compress (&cinfo); free (line_buffer); return (0); }
/* * EncodeBlock */ static block_t *EncodeBlock(encoder_t *p_enc, picture_t *p_pic) { encoder_sys_t *p_sys = p_enc->p_sys; block_t *p_block = block_Alloc(p_sys->i_blocksize); if (p_block == NULL) { return NULL; } JSAMPIMAGE p_row_pointers = NULL; /* libjpeg longjmp's there in case of error */ if (setjmp(p_sys->setjmp_buffer)) { goto error; } jpeg_create_compress(&p_sys->p_jpeg); jpeg_mem_dest(&p_sys->p_jpeg, &p_block->p_buffer, &p_block->i_buffer); p_sys->p_jpeg.image_width = p_enc->fmt_in.video.i_visible_width; p_sys->p_jpeg.image_height = p_enc->fmt_in.video.i_visible_height; p_sys->p_jpeg.input_components = 3; p_sys->p_jpeg.in_color_space = JCS_YCbCr; jpeg_set_defaults(&p_sys->p_jpeg); jpeg_set_colorspace(&p_sys->p_jpeg, JCS_YCbCr); p_sys->p_jpeg.raw_data_in = TRUE; p_sys->p_jpeg.do_fancy_downsampling = FALSE; jpeg_set_quality(&p_sys->p_jpeg, p_sys->i_quality, TRUE); jpeg_start_compress(&p_sys->p_jpeg, TRUE); /* Encode picture */ p_row_pointers = malloc(sizeof(JSAMPARRAY) * p_pic->i_planes); if (p_row_pointers == NULL) { goto error; } for (int i = 0; i < p_pic->i_planes; i++) { p_row_pointers[i] = malloc(sizeof(JSAMPROW) * p_sys->p_jpeg.comp_info[i].v_samp_factor * DCTSIZE); } while (p_sys->p_jpeg.next_scanline < p_sys->p_jpeg.image_height) { for (int i = 0; i < p_pic->i_planes; i++) { int i_offset = p_sys->p_jpeg.next_scanline * p_sys->p_jpeg.comp_info[i].v_samp_factor / p_sys->p_jpeg.max_v_samp_factor; for (int j = 0; j < p_sys->p_jpeg.comp_info[i].v_samp_factor * DCTSIZE; j++) { p_row_pointers[i][j] = p_pic->p[i].p_pixels + p_pic->p[i].i_pitch * (i_offset + j); } } jpeg_write_raw_data(&p_sys->p_jpeg, p_row_pointers, p_sys->p_jpeg.max_v_samp_factor * DCTSIZE); } jpeg_finish_compress(&p_sys->p_jpeg); jpeg_destroy_compress(&p_sys->p_jpeg); for (int i = 0; i < p_pic->i_planes; i++) { free(p_row_pointers[i]); } free(p_row_pointers); return p_block; error: jpeg_destroy_compress(&p_sys->p_jpeg); if (p_row_pointers != NULL) { for (int i = 0; i < p_pic->i_planes; i++) { free(p_row_pointers[i]); } } free(p_row_pointers); block_Release(p_block); return NULL; }
/**************************************************************************** DESCRIPTION: Save a portion of a device context to JPEG on disk. HEADER: mgraph.h PARAMETERS: dc - Device context to save JPEGName - Name of bitmap file to save left - Left coordinate of bitmap to save top - Top coordinate of bitmap to save right - Right coordinate of bitmap to save bottom - Bottom coordinate of bitmap to save quality - Quality factor for compression (1-100) RETURNS: True on success, false on error. REMARKS: This function saves a portion of a device context as a JPEG format bitmap file to disk. If this function fails for some reason, it will return false and you can get the error code from the MGL_result function. Note that the source rectangle for the bitmap to be saved is not clipped to the current clipping rectangle for the device context, but it is mapped to the current viewport. If you specify dimensions that are larger than the current device context, you will get garbage in the bitmap file as a result. Note that MGL currently only supports saving bitmap data to JPEG files from 8 bits per pixel device contexts. SEE ALSO: MGL_LoadJPEG,MGL_loadJPEGIntoDC ****************************************************************************/ ibool MGLAPI MGL_saveJPEGFromDC( MGLDC *dc, const char *JPEGName, int left, int top, int right, int bottom, int quality) { FILE *f; jpeg_compress cinfo; /* Main JPEG compressor object */ my_error_mgr jerr; /* Error handling object */ palette_t pal[256]; MGLDC *memDC; uchar *p; /* Attempt to open the file for writing */ if ((f = __MGL_fopen(JPEGName,"wb")) == NULL) return false; /* Allocate a temporary buffer in the correct format for compression */ if ((memDC = MGL_createMemoryDC(right-left,1,24,&_MGL_pixelFormats[pfBGR24])) == NULL) { fclose(f); return false; } /* Set palette for 24-bit memory DC the same as input DC */ MGL_getPalette(dc,pal,256,0); MGL_setPalette(memDC,pal,256,0); MGL_realizePalette(memDC,256,0,false); /* We set up the normal JPEG error routines, then override error_exit */ if ((cinfo.err = jpeg_std_error(&jerr.pub)) == NULL) MGL_fatalError("Unable to load JPEG library!"); jerr.pub.error_exit = my_error_exit; 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 output file, and * return. */ fclose(f); MGL_destroyDC(memDC); jpeg_destroy_compress(&cinfo); return false; } /* Initialize the JPEG decompression object and read header */ jpeg_create_compress(&cinfo); jpeg_stdio_dest(&cinfo, f); /* Set parameters for compression. Input data is always 24-bit RGB */ cinfo.image_width = right-left; cinfo.image_height = bottom-top; cinfo.input_components = 3; cinfo.in_color_space = JCS_RGB; jpeg_set_defaults(&cinfo); jpeg_set_quality(&cinfo, quality, true); /* Loop around passing one scanline at a time to the compressor */ jpeg_start_compress(&cinfo, true); p = memDC->surface; while (cinfo.next_scanline < cinfo.image_height) { /* jpeg_write_scanlines expects an array of pointers to scanlines. * Here the array is only one element long, but you could pass * more than one scanline at a time if that's more convenient. */ MGL_bitBltCoord(memDC,dc, left,top+cinfo.next_scanline, right,top+cinfo.next_scanline+1, 0,0,MGL_REPLACE_MODE); jpeg_write_scanlines(&cinfo, &p, 1); } /* Finish compression and clean up */ jpeg_finish_compress(&cinfo); fclose(f); jpeg_destroy_compress(&cinfo); MGL_destroyDC(memDC); return true; }
static void _JpegEncode(const CFX_DIBSource* pSource, uint8_t*& dest_buf, FX_STRSIZE& dest_size, int quality, const uint8_t* icc_buf, FX_DWORD icc_length) { struct jpeg_error_mgr jerr; jerr.error_exit = _error_do_nothing; jerr.emit_message = _error_do_nothing1; jerr.output_message = _error_do_nothing; jerr.format_message = _error_do_nothing2; jerr.reset_error_mgr = _error_do_nothing; struct jpeg_compress_struct cinfo; memset(&cinfo, 0, sizeof(cinfo)); cinfo.err = &jerr; jpeg_create_compress(&cinfo); int Bpp = pSource->GetBPP() / 8; FX_DWORD nComponents = Bpp >= 3 ? (pSource->IsCmykImage() ? 4 : 3) : 1; FX_DWORD pitch = pSource->GetPitch(); FX_DWORD width = pdfium::base::checked_cast<FX_DWORD>(pSource->GetWidth()); FX_DWORD height = pdfium::base::checked_cast<FX_DWORD>(pSource->GetHeight()); FX_SAFE_DWORD safe_buf_len = width; safe_buf_len *= height; safe_buf_len *= nComponents; safe_buf_len += 1024; if (icc_length) { safe_buf_len += 255 * 18; safe_buf_len += icc_length; } FX_DWORD dest_buf_length = 0; if (!safe_buf_len.IsValid()) { dest_buf = nullptr; } else { dest_buf_length = safe_buf_len.ValueOrDie(); dest_buf = FX_TryAlloc(uint8_t, dest_buf_length); const int MIN_TRY_BUF_LEN = 1024; while (!dest_buf && dest_buf_length > MIN_TRY_BUF_LEN) { dest_buf_length >>= 1; dest_buf = FX_TryAlloc(uint8_t, dest_buf_length); } } if (!dest_buf) { FX_OutOfMemoryTerminate(); } struct jpeg_destination_mgr dest; dest.init_destination = _dest_do_nothing; dest.term_destination = _dest_do_nothing; dest.empty_output_buffer = _dest_empty; dest.next_output_byte = dest_buf; dest.free_in_buffer = dest_buf_length; cinfo.dest = &dest; cinfo.image_width = width; cinfo.image_height = height; cinfo.input_components = nComponents; if (nComponents == 1) { cinfo.in_color_space = JCS_GRAYSCALE; } else if (nComponents == 3) { cinfo.in_color_space = JCS_RGB; } else { cinfo.in_color_space = JCS_CMYK; } uint8_t* line_buf = NULL; if (nComponents > 1) { line_buf = FX_Alloc2D(uint8_t, width, nComponents); } jpeg_set_defaults(&cinfo); if (quality != 75) { jpeg_set_quality(&cinfo, quality, TRUE); } jpeg_start_compress(&cinfo, TRUE); _JpegEmbedIccProfile(&cinfo, icc_buf, icc_length); JSAMPROW row_pointer[1]; JDIMENSION row; while (cinfo.next_scanline < cinfo.image_height) { const uint8_t* src_scan = pSource->GetScanline(cinfo.next_scanline); if (nComponents > 1) { uint8_t* dest_scan = line_buf; if (nComponents == 3) { for (int i = 0; i < width; i++) { dest_scan[0] = src_scan[2]; dest_scan[1] = src_scan[1]; dest_scan[2] = src_scan[0]; dest_scan += 3; src_scan += Bpp; } } else { for (int i = 0; i < pitch; i++) { *dest_scan++ = ~*src_scan++; } } row_pointer[0] = line_buf; } else { row_pointer[0] = (uint8_t*)src_scan; } row = cinfo.next_scanline; jpeg_write_scanlines(&cinfo, row_pointer, 1); if (cinfo.next_scanline == row) { dest_buf = FX_Realloc(uint8_t, dest_buf, dest_buf_length + JPEG_BLOCK_SIZE); dest.next_output_byte = dest_buf + dest_buf_length - dest.free_in_buffer; dest_buf_length += JPEG_BLOCK_SIZE; dest.free_in_buffer += JPEG_BLOCK_SIZE; } } jpeg_finish_compress(&cinfo); jpeg_destroy_compress(&cinfo); FX_Free(line_buf); dest_size = dest_buf_length - (FX_STRSIZE)dest.free_in_buffer; }
int compress_yuyv_to_jpeg (const char *basename, int quality, uint16_t width, uint16_t height, void *data) { struct jpeg_compress_struct cinfo; struct jpeg_error_mgr jerr; JSAMPROW row_pointer[1]; unsigned char *line_buffer, *yuyv; int z; struct timeval start, end; char outname[1024]; sprintf(outname, "%s.jpg", basename); gettimeofday(&start, NULL); FILE *file = fopen (outname, "wb"); if (!file) { perror ("Error opening output file"); return -1; } line_buffer = calloc (width * 3, 1); yuyv = data; cinfo.err = jpeg_std_error (&jerr); jpeg_create_compress (&cinfo); jpeg_stdio_dest (&cinfo, file); cinfo.image_width = width; cinfo.image_height = height; cinfo.input_components = 3; cinfo.in_color_space = JCS_RGB; jpeg_set_defaults (&cinfo); jpeg_set_quality (&cinfo, quality, TRUE); jpeg_start_compress (&cinfo, TRUE); z = 0; while (cinfo.next_scanline < cinfo.image_height) { int x; unsigned char *ptr = line_buffer; for (x = 0; x < width; x++) { int r, g, b; int y = 0, u = 0, v = 0; // Atmel uses this one if (!z) y = yuyv[1] << 8; else y = yuyv[3] << 8; u = yuyv[2] - 128; v = yuyv[0] - 128; r = (y + (359 * v)) >> 8; g = (y - (88 * u) - (183 * v)) >> 8; b = (y + (454 * u)) >> 8; #define CAP(x) ((x) < 0 ? 0 : ((x) > 255 ? 255 : (x)) ) *(ptr++) = (r > 255) ? 255 : ((r < 0) ? 0 : r); *(ptr++) = (g > 255) ? 255 : ((g < 0) ? 0 : g); *(ptr++) = (b > 255) ? 255 : ((b < 0) ? 0 : b); if (z++) { z = 0; yuyv += 4; } } row_pointer[0] = line_buffer; jpeg_write_scanlines (&cinfo, row_pointer, 1); } jpeg_finish_compress (&cinfo); jpeg_destroy_compress (&cinfo); free (line_buffer); fclose(file); gettimeofday(&end, NULL); end.tv_sec -= start.tv_sec; end.tv_usec -= start.tv_usec; if (end.tv_usec < 0) { end.tv_usec += 1000000; end.tv_sec -= 1; } printf("JPEG Time: %ld.%06ld\n", end.tv_sec, end.tv_usec); return (0); }
void jpeg_write(char *jpegFilename, unsigned char* yuv, int width, int height) { struct jpeg_compress_struct cinfo; struct jpeg_error_mgr jerr; unsigned char *img = (unsigned char *)malloc(width*height*3*sizeof(char)); JSAMPROW row_pointer[1]; FILE *outfile = fopen( jpegFilename, "wb" ); /* Open file for saving output */ if (!outfile) { printf("Can't open file!\n"); } /* Create jpeg data */ cinfo.err = jpeg_std_error( &jerr ); jpeg_create_compress(&cinfo); jpeg_stdio_dest(&cinfo, outfile); /* Set image parameters */ cinfo.image_width = width; cinfo.image_height = height; cinfo.input_components = 3; cinfo.in_color_space = JCS_YCbCr; /* Set jpeg compression parameters to default */ jpeg_set_defaults(&cinfo); jpeg_set_quality(&cinfo, 90, TRUE); /* Start compression */ jpeg_start_compress(&cinfo, TRUE); /* Feed in data. YUV422 is converted to YUV444 */ row_pointer[0] = img; while (cinfo.next_scanline < cinfo.image_height) { unsigned i, j; unsigned offset = cinfo.next_scanline * cinfo.image_width * 2; for (i = 0, j = 0; i < cinfo.image_width*2; i += 4, j += 6) { img[j + 0] = yuv[offset + i + 0]; // Y img[j + 1] = yuv[offset + i + 1]; // U img[j + 2] = yuv[offset + i + 3]; // V img[j + 3] = yuv[offset + i + 2]; // Y img[j + 4] = yuv[offset + i + 1]; // U img[j + 5] = yuv[offset + i + 3]; // V } jpeg_write_scanlines(&cinfo, row_pointer, 1); } /* Finish compression */ jpeg_finish_compress(&cinfo); /* Destroy jpeg data */ jpeg_destroy_compress(&cinfo); /* Close output file */ fclose(outfile); munmap(img, width*height*3*sizeof(char)); return; }
/* write_JPEG_memory: store JPEG compressed image into memory. */ static bool writeJPEGFile(io::IWriteFile* file, IImage* image, u32 quality) { void (*format)(const void*, s32, void*) = 0; switch( image->getColorFormat () ) { case ECF_R8G8B8: format = CColorConverter::convert_R8G8B8toR8G8B8; break; case ECF_A8R8G8B8: format = CColorConverter::convert_A8R8G8B8toR8G8B8; break; case ECF_A1R5G5B5: format = CColorConverter::convert_A1R5G5B5toB8G8R8; break; case ECF_R5G6B5: format = CColorConverter::convert_R5G6B5toR8G8B8; break; #ifndef _DEBUG default: break; #endif } // couldn't find a color converter if ( 0 == format ) return false; const core::dimension2du dim = image->getDimension(); struct jpeg_compress_struct cinfo; struct jpeg_error_mgr jerr; cinfo.err = jpeg_std_error(&jerr); jpeg_create_compress(&cinfo); jpeg_file_dest(&cinfo, file); cinfo.image_width = dim.Width; cinfo.image_height = dim.Height; cinfo.input_components = 3; cinfo.in_color_space = JCS_RGB; jpeg_set_defaults(&cinfo); if ( 0 == quality ) quality = 75; jpeg_set_quality(&cinfo, quality, TRUE); jpeg_start_compress(&cinfo, TRUE); u8 * dest = new u8[dim.Width*3]; if (dest) { const u32 pitch = image->getPitch(); JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */ row_pointer[0] = dest; u8* src = (u8*)image->lock(); while (cinfo.next_scanline < cinfo.image_height) { // convert next line format( src, dim.Width, dest ); src += pitch; jpeg_write_scanlines(&cinfo, row_pointer, 1); } image->unlock(); delete [] dest; /* Step 6: Finish compression */ jpeg_finish_compress(&cinfo); } /* Step 7: Destroy */ jpeg_destroy_compress(&cinfo); return (dest != 0); }
int main(int argc, char *argv[]) { long quality; const char *metric; const char *size; char *x; int luma_width; int luma_height; int chroma_width; int chroma_height; int frame_width; int frame_height; const char *yuv_path; const char *jpg_path; FILE *yuv_fd; size_t yuv_size; unsigned char *yuv_buffer; JSAMPLE *image_buffer; struct jpeg_compress_struct cinfo; struct jpeg_error_mgr jerr; FILE *jpg_fd; JSAMPROW yrow_pointer[16]; JSAMPROW cbrow_pointer[8]; JSAMPROW crrow_pointer[8]; JSAMPROW *plane_pointer[3]; int y; if (argc != 6) { fprintf(stderr, "Required arguments:\n"); fprintf(stderr, "1. JPEG quality value, 0-100\n"); fprintf(stderr, "2. Metric to tune for: psnr, hvspsnr, ssim, or msssim\n"); fprintf(stderr, "3. Image size (e.g. '512x512')\n"); fprintf(stderr, "4. Path to YUV input file\n"); fprintf(stderr, "5. Path to JPG output file\n"); return 1; } errno = 0; quality = strtol(argv[1], NULL, 10); if (errno != 0 || quality < 0 || quality > 100) { fprintf(stderr, "Invalid JPEG quality value!\n"); return 1; } metric = argv[2]; size = argv[3]; x = strchr(size, 'x'); if (!x && x != size && x != (x + strlen(x) - 1)) { fprintf(stderr, "Invalid image size input!\n"); return 1; } luma_width = (int)strtol(size, NULL, 10); if (errno != 0) { fprintf(stderr, "Invalid image size input!\n"); return 1; } luma_height = (int)strtol(x + 1, NULL, 10); if (errno != 0) { fprintf(stderr, "Invalid image size input!\n"); return 1; } if (luma_width <= 0 || luma_height <= 0) { fprintf(stderr, "Invalid image size input!\n"); return 1; } chroma_width = (luma_width + 1) >> 1; chroma_height = (luma_height + 1) >> 1; /* Will check these for validity when opening via 'fopen'. */ yuv_path = argv[4]; jpg_path = argv[5]; yuv_fd = fopen(yuv_path, "r"); if (!yuv_fd) { fprintf(stderr, "Invalid path to YUV file!\n"); return 1; } fseek(yuv_fd, 0, SEEK_END); yuv_size = ftell(yuv_fd); fseek(yuv_fd, 0, SEEK_SET); /* Check that the file size matches 4:2:0 yuv. */ if (yuv_size != (size_t)luma_width*luma_height + 2*chroma_width*chroma_height) { fprintf(stderr, "Unexpected input format!\n"); return 1; } yuv_buffer = malloc(yuv_size); if (fread(yuv_buffer, yuv_size, 1, yuv_fd) != 1) { fprintf(stderr, "Error reading yuv file\n"); }; fclose(yuv_fd); frame_width = (luma_width + (16 - 1)) & ~(16 - 1); frame_height = (luma_height + (16 - 1)) & ~(16 - 1); image_buffer = malloc(frame_width*frame_height + 2*(frame_width/2)*(frame_height/2)); extend_edge(image_buffer, frame_width, frame_height, yuv_buffer, luma_width, luma_height, chroma_width, chroma_height); free(yuv_buffer); cinfo.err = jpeg_std_error(&jerr); jpeg_create_compress(&cinfo); jpg_fd = fopen(jpg_path, "wb"); if (!jpg_fd) { fprintf(stderr, "Invalid path to JPEG file!\n"); return 1; } jpeg_stdio_dest(&cinfo, jpg_fd); cinfo.use_moz_defaults = TRUE; cinfo.image_width = luma_width; cinfo.image_height = luma_height; cinfo.input_components = 3; cinfo.in_color_space = JCS_YCbCr; jpeg_set_defaults(&cinfo); cinfo.raw_data_in = TRUE; cinfo.comp_info[0].h_samp_factor = 2; cinfo.comp_info[0].v_samp_factor = 2; cinfo.comp_info[0].dc_tbl_no = 0; cinfo.comp_info[0].ac_tbl_no = 0; cinfo.comp_info[0].quant_tbl_no = 0; cinfo.comp_info[1].h_samp_factor = 1; cinfo.comp_info[1].v_samp_factor = 1; cinfo.comp_info[1].dc_tbl_no = 1; cinfo.comp_info[1].ac_tbl_no = 1; cinfo.comp_info[1].quant_tbl_no = 1; cinfo.comp_info[2].h_samp_factor = 1; cinfo.comp_info[2].v_samp_factor = 1; cinfo.comp_info[2].dc_tbl_no = 1; cinfo.comp_info[2].ac_tbl_no = 1; cinfo.comp_info[2].quant_tbl_no = 1; if (strcmp("psnr", metric) == 0) { cinfo.use_flat_quant_tbl = TRUE; cinfo.lambda_log_scale1 = 9.0; cinfo.lambda_log_scale2 = 0.0; cinfo.use_lambda_weight_tbl = FALSE; } else if (strcmp("ssim", metric) == 0) { cinfo.use_flat_quant_tbl = TRUE; cinfo.lambda_log_scale1 = 12.0; cinfo.lambda_log_scale2 = 13.5; cinfo.use_lambda_weight_tbl = FALSE; } else if (strcmp("msssim", metric) == 0) { cinfo.use_flat_quant_tbl = TRUE; cinfo.lambda_log_scale1 = 10.5; cinfo.lambda_log_scale2 = 13.0; cinfo.use_lambda_weight_tbl = TRUE; } else if (strcmp("hvspsnr", metric) == 0) { cinfo.use_flat_quant_tbl = FALSE; cinfo.lambda_log_scale1 = 16.0; cinfo.lambda_log_scale2 = 15.5; cinfo.use_lambda_weight_tbl = TRUE; } else { fprintf(stderr, "Bad metric choice!\n"); return 1; } jpeg_set_quality(&cinfo, quality, TRUE); cinfo.optimize_coding = TRUE; jpeg_start_compress(&cinfo, TRUE); plane_pointer[0] = yrow_pointer; plane_pointer[1] = cbrow_pointer; plane_pointer[2] = crrow_pointer; while (cinfo.next_scanline < cinfo.image_height) { int scanline; scanline = cinfo.next_scanline; for (y = 0; y < 16; y++) { yrow_pointer[y] = &image_buffer[frame_width*(scanline + y)]; } for (y = 0; y < 8; y++) { cbrow_pointer[y] = &image_buffer[frame_width*frame_height + (frame_width/2)*((scanline/2) + y)]; crrow_pointer[y] = &image_buffer[frame_width*frame_height + (frame_width/2)*(frame_height/2) + (frame_width/2)*((scanline/2) + y)]; } jpeg_write_raw_data(&cinfo, plane_pointer, 16); } jpeg_finish_compress(&cinfo); jpeg_destroy_compress(&cinfo); free(image_buffer); fclose(jpg_fd); return 0; }
bool CCImage::_saveImageToJPG(const char * pszFilePath) { bool bRet = false; do { CC_BREAK_IF(NULL == pszFilePath); struct jpeg_compress_struct cinfo; struct jpeg_error_mgr jerr; FILE * outfile; /* target file */ JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */ int row_stride; /* physical row width in image buffer */ FILE_STANDARD_INFO fileStandardInfo = { 0 }; HANDLE hFile; std::wstring path = CCUtf8ToUnicode(pszFilePath); CREATEFILE2_EXTENDED_PARAMETERS extendedParams = {0}; extendedParams.dwSize = sizeof(CREATEFILE2_EXTENDED_PARAMETERS); extendedParams.dwFileAttributes = FILE_ATTRIBUTE_NORMAL; extendedParams.dwFileFlags = FILE_FLAG_SEQUENTIAL_SCAN; extendedParams.dwSecurityQosFlags = SECURITY_ANONYMOUS; extendedParams.lpSecurityAttributes = nullptr; extendedParams.hTemplateFile = nullptr; // read the file from hardware hFile = ::CreateFile2(path.c_str(), GENERIC_WRITE, 0, CREATE_ALWAYS, &extendedParams); if (INVALID_HANDLE_VALUE == hFile) { break; } int CrtFileHandle; /* convert OS file handle to CRT file pointer */ if ((CrtFileHandle=_open_osfhandle ((long)hFile,_O_RDONLY))==-1){ //printf( "_open_osfhandle Failed "); break; } /* Change handle access to stream access. */ if( (outfile = _fdopen( CrtFileHandle, "wb")) == NULL ) { //printf( "_fdopen Failed "); break; } cinfo.err = jpeg_std_error(&jerr); /* Now we can initialize the JPEG compression object. */ jpeg_create_compress(&cinfo); jpeg_stdio_dest(&cinfo, outfile); cinfo.image_width = m_nWidth; /* image width and height, in pixels */ cinfo.image_height = m_nHeight; cinfo.input_components = 3; /* # of color components per pixel */ cinfo.in_color_space = JCS_RGB; /* colorspace of input image */ jpeg_set_defaults(&cinfo); jpeg_start_compress(&cinfo, TRUE); row_stride = m_nWidth * 3; /* JSAMPLEs per row in image_buffer */ if (m_bHasAlpha) { unsigned char *pTempData = new unsigned char[m_nWidth * m_nHeight * 3]; if (NULL == pTempData) { jpeg_finish_compress(&cinfo); jpeg_destroy_compress(&cinfo); fclose(outfile); break; } for (int i = 0; i < m_nHeight; ++i) { for (int j = 0; j < m_nWidth; ++j) { pTempData[(i * m_nWidth + j) * 3] = m_pData[(i * m_nWidth + j) * 4]; pTempData[(i * m_nWidth + j) * 3 + 1] = m_pData[(i * m_nWidth + j) * 4 + 1]; pTempData[(i * m_nWidth + j) * 3 + 2] = m_pData[(i * m_nWidth + j) * 4 + 2]; } } while (cinfo.next_scanline < cinfo.image_height) { row_pointer[0] = & pTempData[cinfo.next_scanline * row_stride]; (void) jpeg_write_scanlines(&cinfo, row_pointer, 1); } CC_SAFE_DELETE_ARRAY(pTempData); } else { while (cinfo.next_scanline < cinfo.image_height) { row_pointer[0] = & m_pData[cinfo.next_scanline * row_stride]; (void) jpeg_write_scanlines(&cinfo, row_pointer, 1); } } jpeg_finish_compress(&cinfo); fclose(outfile); jpeg_destroy_compress(&cinfo); bRet = true; } while (0); return bRet; }
/* * Borrowed with very minor modifications from JPEG6 sample code. Error handling * remains as default (i.e. exit on errors). */ void write_JPEG_file (char * filename, int quality, int width, int height) { /* This struct contains the JPEG compression parameters and pointers to * working space (which is allocated as needed by the JPEG library). * It is possible to have several such structures, representing multiple * compression/decompression processes, in existence at once. We refer * to any one struct (and its associated working data) as a "JPEG object". */ struct jpeg_compress_struct cinfo; /* This struct represents a JPEG error handler. It is declared separately * because applications often want to supply a specialized error handler * (see the second half of this file for an example). But here we just * take the easy way out and use the standard error handler, which will * print a message on stderr and call exit() if compression fails. * Note that this struct must live as long as the main JPEG parameter * struct, to avoid dangling-pointer problems. */ struct jpeg_error_mgr jerr; /* More stuff */ FILE * outfile; /* target file */ JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */ int row_stride; /* physical row width in image buffer */ /* Step 1: allocate and initialize JPEG compression object */ /* We have to set up the error handler first, in case the initialization * step fails. (Unlikely, but it could happen if you are out of memory.) * This routine fills in the contents of struct jerr, and returns jerr's * address which we place into the link field in cinfo. */ cinfo.err = jpeg_std_error(&jerr); /* Now we can initialize the JPEG compression object. */ jpeg_create_compress(&cinfo); /* Step 2: specify data destination (eg, a file) */ /* Note: steps 2 and 3 can be done in either order. */ /* Here we use the library-supplied code to send compressed data to a * stdio stream. You can also write your own code to do something else. * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that * requires it in order to write binary files. */ if (strcmp(filename, "-") == 0) { outfile = stdout; } else { if ((outfile = fopen(filename, "wb")) == NULL) { fprintf(stderr, "can't open %s\n", filename); exit(1); } } jpeg_stdio_dest(&cinfo, outfile); /* Step 3: set parameters for compression */ /* First we supply a description of the input image. * Four fields of the cinfo struct must be filled in: */ cinfo.image_width = width; /* image width and height, in pixels */ cinfo.image_height = height; cinfo.input_components = RAW_BYTES_PER_PIXEL; /* # of color components per pixel */ cinfo.in_color_space = JCS_RGB; /* colorspace of input image */ /* Now use the library's routine to set default compression parameters. * (You must set at least cinfo.in_color_space before calling this, * since the defaults depend on the source color space.) */ jpeg_set_defaults(&cinfo); /* Now you can set any non-default parameters you wish to. * Here we just illustrate the use of quality (quantization table) scaling: */ jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */); /* VNCSNAPSHOT: Set file colourspace to RGB. * If it is not set to RGB, colour distortions occur. */ jpeg_set_colorspace(&cinfo, JCS_RGB); /* Step 4: Start compressor */ /* TRUE ensures that we will write a complete interchange-JPEG file. * Pass TRUE unless you are very sure of what you're doing. */ jpeg_start_compress(&cinfo, TRUE); /* Step 5: while (scan lines remain to be written) */ /* jpeg_write_scanlines(...); */ /* Here we use the library's state variable cinfo.next_scanline as the * loop counter, so that we don't have to keep track ourselves. * To keep things simple, we pass one scanline per call; you can pass * more if you wish, though. */ row_stride = width * 3; /* JSAMPLEs per row in image_buffer */ while (cinfo.next_scanline < cinfo.image_height) { /* jpeg_write_scanlines expects an array of pointers to scanlines. * Here the array is only one element long, but you could pass * more than one scanline at a time if that's more convenient. */ row_pointer[0] = & rawBuffer[cinfo.next_scanline * row_stride]; (void) jpeg_write_scanlines(&cinfo, row_pointer, 1); } /* Step 6: Finish compression */ jpeg_finish_compress(&cinfo); /* After finish_compress, we can close the output file. */ if (strcmp(filename, "-") != 0) { fclose(outfile); } /* Step 7: release JPEG compression object */ /* This is an important step since it will release a good deal of memory. */ jpeg_destroy_compress(&cinfo); /* And we're done! */ }
void GImage::encodeJPEG( BinaryOutput& out) const { if (m_channels != 3) { // Convert to three channel GImage tmp = *this; tmp.convertToRGB(); tmp.encodeJPEG(out); return; } debugAssert(m_channels == 3); out.setEndian(G3D_LITTLE_ENDIAN); // Allocate and initialize a compression object jpeg_compress_struct cinfo; jpeg_error_mgr jerr; cinfo.err = jpeg_std_error(&jerr); jpeg_create_compress(&cinfo); // Specify the destination for the compressed data. // (Overestimate the size) int buffer_size = m_width * m_height * 3 + 200; JOCTET* compressed_data = (JOCTET*)System::malloc(buffer_size); jpeg_memory_dest(&cinfo, compressed_data, buffer_size); cinfo.image_width = m_width; cinfo.image_height = m_height; // # of color components per pixel cinfo.input_components = 3; // colorspace of input image cinfo.in_color_space = JCS_RGB; cinfo.input_gamma = 1.0; // Set parameters for compression, including image size & colorspace jpeg_set_defaults(&cinfo); jpeg_set_quality(&cinfo, jpegQuality, false); cinfo.smoothing_factor = 0; cinfo.optimize_coding = TRUE; // cinfo.dct_method = JDCT_FLOAT; cinfo.dct_method = JDCT_ISLOW; cinfo.jpeg_color_space = JCS_YCbCr; // Initialize the compressor jpeg_start_compress(&cinfo, TRUE); // Iterate over all scanlines from top to bottom // pointer to a single row JSAMPROW row_pointer[1]; // JSAMPLEs per row in image_buffer int row_stride = cinfo.image_width * 3; while (cinfo.next_scanline < cinfo.image_height) { row_pointer[0] = &(m_byte[cinfo.next_scanline * row_stride]); jpeg_write_scanlines(&cinfo, row_pointer, 1); } // Shut down the compressor jpeg_finish_compress(&cinfo); // Figure out how big the result was. int outLength = ((mem_dest_ptr)cinfo.dest)->count; // Release the JPEG compression object jpeg_destroy_compress(&cinfo); // Copy into an appropriately sized output buffer. out.writeBytes(compressed_data, outLength); // Free the conservative buffer. System::free(compressed_data); compressed_data = NULL; }
int main (int argc, char **argv) { struct jpeg_compress_struct cinfo; struct jpeg_error_mgr jerr; #ifdef PROGRESS_REPORT struct cdjpeg_progress_mgr progress; #endif int file_index; cjpeg_source_ptr src_mgr; FILE * input_file; FILE * output_file; JDIMENSION num_scanlines; /* On Mac, fetch a command line. */ #ifdef USE_CCOMMAND argc = ccommand(&argv); #endif progname = argv[0]; if (progname == NULL || progname[0] == 0) progname = "cjpeg"; /* in case C library doesn't provide it */ /* Initialize the JPEG compression object with default error handling. */ cinfo.err = jpeg_std_error(&jerr); jpeg_create_compress(&cinfo); /* Add some application-specific error messages (from cderror.h) */ jerr.addon_message_table = cdjpeg_message_table; jerr.first_addon_message = JMSG_FIRSTADDONCODE; jerr.last_addon_message = JMSG_LASTADDONCODE; /* Now safe to enable signal catcher. */ #ifdef NEED_SIGNAL_CATCHER enable_signal_catcher((j_common_ptr) &cinfo); #endif /* Initialize JPEG parameters. * Much of this may be overridden later. * In particular, we don't yet know the input file's color space, * but we need to provide some value for jpeg_set_defaults() to work. */ cinfo.in_color_space = JCS_RGB; /* arbitrary guess */ jpeg_set_defaults(&cinfo); /* Scan command line to find file names. * It is convenient to use just one switch-parsing routine, but the switch * values read here are ignored; we will rescan the switches after opening * the input file. */ file_index = parse_switches(&cinfo, argc, argv, 0, FALSE); #ifdef TWO_FILE_COMMANDLINE /* Must have either -outfile switch or explicit output file name */ if (outfilename == NULL) { if (file_index != argc-2) { fprintf(stderr, "%s: must name one input and one output file\n", progname); usage(); } outfilename = argv[file_index+1]; } else { if (file_index != argc-1) { fprintf(stderr, "%s: must name one input and one output file\n", progname); usage(); } } #else /* Unix style: expect zero or one file name */ if (file_index < argc-1) { fprintf(stderr, "%s: only one input file\n", progname); usage(); } #endif /* TWO_FILE_COMMANDLINE */ /* Open the input file. */ if (file_index < argc) { if ((input_file = fopen(argv[file_index], READ_BINARY)) == NULL) { fprintf(stderr, "%s: can't open %s\n", progname, argv[file_index]); exit(EXIT_FAILURE); } } else { /* default input file is stdin */ input_file = read_stdin(); } /* Open the output file. */ if (outfilename != NULL) { if ((output_file = fopen(outfilename, WRITE_BINARY)) == NULL) { fprintf(stderr, "%s: can't open %s\n", progname, outfilename); exit(EXIT_FAILURE); } } else { /* default output file is stdout */ output_file = write_stdout(); } #ifdef PROGRESS_REPORT start_progress_monitor((j_common_ptr) &cinfo, &progress); #endif /* Figure out the input file format, and set up to read it. */ src_mgr = select_file_type(&cinfo, input_file); src_mgr->input_file = input_file; /* Read the input file header to obtain file size & colorspace. */ (*src_mgr->start_input) (&cinfo, src_mgr); /* Now that we know input colorspace, fix colorspace-dependent defaults */ jpeg_default_colorspace(&cinfo); /* Adjust default compression parameters by re-parsing the options */ file_index = parse_switches(&cinfo, argc, argv, 0, TRUE); /* Specify data destination for compression */ jpeg_stdio_dest(&cinfo, output_file); /* Start compressor */ jpeg_start_compress(&cinfo, TRUE); /* Process data */ while (cinfo.next_scanline < cinfo.image_height) { num_scanlines = (*src_mgr->get_pixel_rows) (&cinfo, src_mgr); (void) jpeg_write_scanlines(&cinfo, src_mgr->buffer, num_scanlines); } /* Finish compression and release memory */ (*src_mgr->finish_input) (&cinfo, src_mgr); jpeg_finish_compress(&cinfo); jpeg_destroy_compress(&cinfo); /* Close files, if we opened them */ if (input_file != stdin) fclose(input_file); if (output_file != stdout) fclose(output_file); #ifdef PROGRESS_REPORT end_progress_monitor((j_common_ptr) &cinfo); #endif /* All done. */ exit(jerr.num_warnings ? EXIT_WARNING : EXIT_SUCCESS); return 0; /* suppress no-return-value warnings */ }
// Access point for applications wishing to use the jpeg library directly in // conjunction with DevIL. // // The caller must set up the desired parameters by e.g. calling // jpeg_set_defaults and overriding the parameters the caller wishes // to change, such as quality, before calling this function. The caller // is also responsible for calling jpeg_finish_compress in case the // caller still needs to compressor for something. // ILboolean ILAPIENTRY ilSaveFromJpegStruct(ILvoid *_JpegInfo) { #ifndef IL_NO_JPG #ifndef IL_USE_IJL void (*errorHandler)(j_common_ptr); JSAMPROW row_pointer[1]; ILimage *TempImage; ILubyte *TempData; j_compress_ptr JpegInfo = (j_compress_ptr)_JpegInfo; if (iCurImage == NULL) { ilSetError(IL_ILLEGAL_OPERATION); return IL_FALSE; } //added on 2003-08-31 as explained in sf bug 596793 jpgErrorOccured = IL_FALSE; errorHandler = JpegInfo->err->error_exit; JpegInfo->err->error_exit = ExitErrorHandle; if ((iCurImage->Format != IL_RGB && iCurImage->Format != IL_LUMINANCE) || iCurImage->Bpc != 1) { TempImage = iConvertImage(iCurImage, IL_RGB, IL_UNSIGNED_BYTE); if (TempImage == NULL) { return IL_FALSE; } } else { TempImage = iCurImage; } if (TempImage->Origin == IL_ORIGIN_LOWER_LEFT) { TempData = iGetFlipped(TempImage); if (TempData == NULL) { if (TempImage != iCurImage) ilCloseImage(TempImage); return IL_FALSE; } } else { TempData = TempImage->Data; } JpegInfo->image_width = TempImage->Width; // image width and height, in pixels JpegInfo->image_height = TempImage->Height; JpegInfo->input_components = TempImage->Bpp; // # of color components per pixel jpeg_start_compress(JpegInfo, IL_TRUE); //row_stride = image_width * 3; // JSAMPLEs per row in image_buffer while (JpegInfo->next_scanline < JpegInfo->image_height) { // jpeg_write_scanlines expects an array of pointers to scanlines. // Here the array is only one element long, but you could pass // more than one scanline at a time if that's more convenient. row_pointer[0] = &TempData[JpegInfo->next_scanline * TempImage->Bps]; (ILvoid) jpeg_write_scanlines(JpegInfo, row_pointer, 1); } if (TempImage->Origin == IL_ORIGIN_LOWER_LEFT) ifree(TempData); if (TempImage != iCurImage) ilCloseImage(TempImage); return (!jpgErrorOccured); #endif #endif return IL_FALSE; }
JPG_BOOL JpegFile::RGBToJpegFile(JPG_CString fileName, unsigned char *dataBuf, JPG_UINT widthPix, JPG_UINT height, JPG_BOOL color, int quality) { if (dataBuf==NULL) return FALSE; if (widthPix==0) return FALSE; if (height==0) return FALSE; unsigned char * tmp; if (!color) { tmp = (unsigned char*)new unsigned char[widthPix*height]; if (tmp==NULL) { fprintf(stderr, "Memory error\n"); return FALSE; } JPG_UINT row,col; for (row=0;row<height;row++) { for (col=0;col<widthPix;col++) { unsigned char *pRed, *pGrn, *pBlu; pRed = dataBuf + row * widthPix * 3 + col * 3; pGrn = dataBuf + row * widthPix * 3 + col * 3 + 1; pBlu = dataBuf + row * widthPix * 3 + col * 3 + 2; // luminance int lum = (int)(.299 * (double)(*pRed) + .587 * (double)(*pGrn) + .114 * (double)(*pBlu)); unsigned char *pGray; pGray = tmp + row * widthPix + col; *pGray = (unsigned char)lum; } } } struct jpeg_compress_struct cinfo; /* More stuff */ FILE * outfile=NULL; /* target file */ //int row_stride; /* physical row widthPix in image buffer */ struct my_error_mgr jerr; /* Step 1: allocate and initialize JPEG compression object */ 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. */ jpeg_destroy_compress(&cinfo); if (outfile!=NULL) fclose(outfile); if (!color) { delete [] tmp; } return FALSE; } /* Now we can initialize the JPEG compression object. */ jpeg_create_compress(&cinfo); /* Step 2: specify data destination (eg, a file) */ /* Note: steps 2 and 3 can be done in either order. */ if ((outfile = fopen(fileName, "wb")) == NULL) { fprintf(stderr, "JpegFile :\nCan't open %s\n", fileName); return FALSE; } jpeg_stdio_dest(&cinfo, outfile); /* Step 3: set parameters for compression */ /* First we supply a description of the input image. * Four fields of the cinfo struct must be filled in: */ cinfo.image_width = widthPix; /* image widthPix and height, in pixels */ cinfo.image_height = height; if (color) { cinfo.input_components = 3; /* # of color components per pixel */ cinfo.in_color_space = JCS_RGB; /* colorspace of input image */ } else { cinfo.input_components = 1; /* # of color components per pixel */ cinfo.in_color_space = JCS_GRAYSCALE; /* colorspace of input image */ } /* Now use the library's routine to set default compression parameters. * (You must set at least cinfo.in_color_space before calling this, * since the defaults depend on the source color space.) */ jpeg_set_defaults(&cinfo); /* Now you can set any non-default parameters you wish to. * Here we just illustrate the use of quality (quantization table) scaling: */ jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */); /* Step 4: Start compressor */ /* TRUE ensures that we will write a complete interchange-JPEG file. * Pass TRUE unless you are very sure of what you're doing. */ jpeg_start_compress(&cinfo, TRUE); /* Step 5: while (scan lines remain to be written) */ /* jpeg_write_scanlines(...); */ /* Here we use the library's state variable cinfo.next_scanline as the * loop counter, so that we don't have to keep track ourselves. * To keep things simple, we pass one scanline per call; you can pass * more if you wish, though. */ //row_stride = widthPix * 3; /* JSAMPLEs per row in image_buffer */ while (cinfo.next_scanline < cinfo.image_height) { /* jpeg_write_scanlines expects an array of pointers to scanlines. * Here the array is only one element long, but you could pass * more than one scanline at a time if that's more convenient. */ unsigned char *outRow; if (color) { outRow = dataBuf + (cinfo.next_scanline * widthPix * 3); } else { outRow = tmp + (cinfo.next_scanline * widthPix); } (void) jpeg_write_scanlines(&cinfo, &outRow, 1); } /* Step 6: Finish compression */ jpeg_finish_compress(&cinfo); /* After finish_compress, we can close the output file. */ fclose(outfile); /* Step 7: release JPEG compression object */ /* This is an important step since it will release a good deal of memory. */ jpeg_destroy_compress(&cinfo); if (!color) delete [] tmp; /* And we're done! */ return TRUE; }
static bool image_jpeg_save (fs_file_t *f, const image_t *im) { struct jpeg_compress_struct cs; struct jpeg_error_mgr em; if (unlikely(IMAGE_DATA_FORMAT_BGRA != im->format)) { fs_print_error(f, "only BGRA format is supported for JPEG saving %c"); return false; } cs.err = jpeg_std_error(&em); cs.err->error_exit = jpeg_error_exit; cs.err->emit_message = jpeg_emit_message; if (unlikely(0 != setjmp(jpeg_jmpbuf))) { return false; } jpeg_CreateCompress(&cs, JPEG_LIB_VERSION, sizeof(cs)); if (unlikely(0 != setjmp(jpeg_jmpbuf))) { goto error; } jpeg_dest(&cs, f); cs.image_width = im->width; cs.image_height = im->height; cs.input_components = 3; cs.in_color_space = jpeg_bgr ? jpeg_bgr : JCS_RGB; jpeg_set_defaults(&cs); jpeg_set_quality(&cs, 100, TRUE); // 1x1 subsampling cs.comp_info[0].v_samp_factor = 1; cs.comp_info[0].h_samp_factor = 1; jpeg_start_compress(&cs, TRUE); uint8_t *data = mem_alloc(image_mem_pool, im->width * 3); for (int r = 0, in = 0; r < im->height; r++) { JSAMPROW scanlines[1] = { (void *)data }; for (int i = 0; i < im->width * 3; i += 3, in += 4) { if (jpeg_bgr) { data[i + 0] = im->data[in + 0]; data[i + 1] = im->data[in + 1]; data[i + 2] = im->data[in + 2]; } else { data[i + 0] = im->data[in + 2]; data[i + 1] = im->data[in + 1]; data[i + 2] = im->data[in + 0]; } } jpeg_write_scanlines(&cs, scanlines, 1); } jpeg_finish_compress(&cs); jpeg_destroy_compress(&cs); mem_free(data); return true; error: jpeg_destroy_compress(&cs); return false; }
static void write_rgb_JPEG_file (char * filename, int quality, int width, int height) { struct jpeg_compress_struct cinfo; struct jpeg_error_mgr jerr; /* More stuff */ FILE * outfile; /* target file */ JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */ int row_stride; /* physical row width in image buffer */ /* Step 1: allocate and initialize JPEG compression object */ cinfo.err = jpeg_std_error(&jerr); /* Now we can initialize the JPEG compression object. */ jpeg_create_compress(&cinfo); /* Step 2: specify data destination (eg, a file) */ /* Note: steps 2 and 3 can be done in either order. */ if ((outfile = fopen(filename, "wb")) == NULL) { tc_log_error(MOD_NAME, "can't open %s", filename); } jpeg_stdio_dest(&cinfo, outfile); /* Step 3: set parameters for compression */ /* First we supply a description of the input image. * Four fields of the cinfo struct must be filled in: */ cinfo.image_width = width; /* image width and height, in pixels */ cinfo.image_height = height; cinfo.input_components = 3; /* # of color components per pixel */ cinfo.in_color_space = JCS_RGB; /* colorspace of input image */ jpeg_set_defaults(&cinfo); /* Now you can set any non-default parameters you wish to. * Here we just illustrate the use of quality (quantization table) scaling: */ jpeg_set_quality(&cinfo, quality, TRUE); /* limit to baseline-JPEG values */ /* Step 4: Start compressor */ /* TRUE ensures that we will write a complete interchange-JPEG file. * Pass TRUE unless you are very sure of what you're doing. */ jpeg_start_compress(&cinfo, TRUE); /* Step 5: while (scan lines remain to be written) */ /* jpeg_write_scanlines(...); */ row_stride = cinfo.image_width * 3; /* JSAMPLEs per row in image_buffer */ while (cinfo.next_scanline < cinfo.image_height) { row_pointer[0] = & image_buffer[cinfo.next_scanline * row_stride]; (void) jpeg_write_scanlines(&cinfo, row_pointer, 1); } /* Step 6: Finish compression */ jpeg_finish_compress(&cinfo); /* After finish_compress, we can close the output file. */ fclose(outfile); /* Step 7: release JPEG compression object */ /* This is an important step since it will release a good deal of memory. */ jpeg_destroy_compress(&cinfo); }
int V4L2Camera::saveYUYVtoJPEG (unsigned char *inputBuffer, int width, int height, FILE *file, int quality) { struct jpeg_compress_struct cinfo; struct jpeg_error_mgr jerr; JSAMPROW row_pointer[1]; unsigned char *line_buffer, *yuyv; int z; int fileSize; line_buffer = (unsigned char *) calloc (width * 3, 1); yuyv = inputBuffer; cinfo.err = jpeg_std_error (&jerr); jpeg_create_compress (&cinfo); jpeg_stdio_dest (&cinfo, file); ALOGI("JPEG PICTURE WIDTH AND HEIGHT: %dx%d", width, height); cinfo.image_width = width; cinfo.image_height = height; cinfo.input_components = 3; cinfo.in_color_space = JCS_RGB; jpeg_set_defaults (&cinfo); jpeg_set_quality (&cinfo, quality, TRUE); jpeg_start_compress (&cinfo, TRUE); z = 0; while (cinfo.next_scanline < cinfo.image_height) { int x; unsigned char *ptr = line_buffer; for (x = 0; x < width; x++) { int r, g, b; int y, u, v; if (!z) y = yuyv[0] << 8; else y = yuyv[2] << 8; u = yuyv[1] - 128; v = yuyv[3] - 128; r = (y + (359 * v)) >> 8; g = (y - (88 * u) - (183 * v)) >> 8; b = (y + (454 * u)) >> 8; *(ptr++) = (r > 255) ? 255 : ((r < 0) ? 0 : r); *(ptr++) = (g > 255) ? 255 : ((g < 0) ? 0 : g); *(ptr++) = (b > 255) ? 255 : ((b < 0) ? 0 : b); if (z++) { z = 0; yuyv += 4; } } row_pointer[0] = line_buffer; jpeg_write_scanlines (&cinfo, row_pointer, 1); } jpeg_finish_compress (&cinfo); fileSize = ftell(file); jpeg_destroy_compress (&cinfo); free (line_buffer); return fileSize; }
// native YUV jpeg encoder code based on encode_JPEG of the quicktime4linux lib // static void write_yuv_JPEG_file(char *filename, int quality, unsigned char **input, int _width, int _height) { int i, j, k; int width = _width; int height = _height; unsigned char *base[3]; struct jpeg_compress_struct encinfo; struct jpeg_error_mgr jerr; FILE * outfile; /* target file */ jpeg_create_compress(&encinfo); encinfo.err = jpeg_std_error(&jerr); if ((outfile = fopen(filename, "wb")) == NULL) { tc_log_error(MOD_NAME, "can't open %s", filename); } jpeg_stdio_dest(&encinfo, outfile); encinfo.image_width = width; encinfo.image_height = height; encinfo.input_components = 3; jpeg_set_defaults(&encinfo); encinfo.dct_method = JDCT_FASTEST; jpeg_set_quality(&encinfo, quality, TRUE); encinfo.raw_data_in = TRUE; encinfo.in_color_space = JCS_YCbCr; encinfo.comp_info[0].h_samp_factor = 2; encinfo.comp_info[0].v_samp_factor = 2; encinfo.comp_info[1].h_samp_factor = 1; encinfo.comp_info[1].v_samp_factor = 1; encinfo.comp_info[2].h_samp_factor = 1; encinfo.comp_info[2].v_samp_factor = 1; jpeg_start_compress(&encinfo, TRUE); base[0] = input[0]; base[1] = input[1]; base[2] = input[2]; for (i = 0; i < height; i += 2*DCTSIZE) { for (j=0, k=0; j<2*DCTSIZE;j+=2, k++) { line[0][j] = base[0]; base[0] += width; line[0][j+1] = base[0]; base[0] += width; line[1][k] = base[1]; base[1] += width/2; line[2][k] = base[2]; base[2] += width/2; } jpeg_write_raw_data(&encinfo, line, 2*DCTSIZE); } jpeg_finish_compress(&encinfo); fclose(outfile); jpeg_destroy_compress(&encinfo); }
int write_image (dt_imageio_jpeg_t *jpg, const char *filename, const uint8_t *in, void *exif, int exif_len, int imgid) { struct dt_imageio_jpeg_error_mgr jerr; jpg->cinfo.err = jpeg_std_error(&jerr.pub); jerr.pub.error_exit = dt_imageio_jpeg_error_exit; if (setjmp(jerr.setjmp_buffer)) { jpeg_destroy_compress(&(jpg->cinfo)); return 1; } jpeg_create_compress(&(jpg->cinfo)); FILE *f = fopen(filename, "wb"); if(!f) return 1; jpeg_stdio_dest(&(jpg->cinfo), f); jpg->cinfo.image_width = jpg->width; jpg->cinfo.image_height = jpg->height; jpg->cinfo.input_components = 3; jpg->cinfo.in_color_space = JCS_RGB; jpeg_set_defaults(&(jpg->cinfo)); jpeg_set_quality(&(jpg->cinfo), jpg->quality, TRUE); if(jpg->quality > 90) jpg->cinfo.comp_info[0].v_samp_factor = 1; if(jpg->quality > 92) jpg->cinfo.comp_info[0].h_samp_factor = 1; if(jpg->quality > 95) jpg->cinfo.dct_method = JDCT_FLOAT; if(jpg->quality < 50) jpg->cinfo.dct_method = JDCT_IFAST; if(jpg->quality < 80) jpg->cinfo.smoothing_factor = 20; if(jpg->quality < 60) jpg->cinfo.smoothing_factor = 40; if(jpg->quality < 40) jpg->cinfo.smoothing_factor = 60; jpg->cinfo.optimize_coding = 1; jpeg_start_compress(&(jpg->cinfo), TRUE); if(imgid > 0) { cmsHPROFILE out_profile = dt_colorspaces_create_output_profile(imgid); uint32_t len = 0; cmsSaveProfileToMem(out_profile, 0, &len); if (len > 0) { unsigned char buf[len]; cmsSaveProfileToMem(out_profile, buf, &len); write_icc_profile(&(jpg->cinfo), buf, len); } dt_colorspaces_cleanup_profile(out_profile); } if(exif && exif_len > 0 && exif_len < 65534) jpeg_write_marker(&(jpg->cinfo), JPEG_APP0+1, exif, exif_len); uint8_t row[3*jpg->width]; const uint8_t *buf; while(jpg->cinfo.next_scanline < jpg->cinfo.image_height) { JSAMPROW tmp[1]; buf = in + jpg->cinfo.next_scanline * jpg->cinfo.image_width * 4; for(int i=0; i<jpg->width; i++) for(int k=0; k<3; k++) row[3*i+k] = buf[4*i+k]; tmp[0] = row; jpeg_write_scanlines(&(jpg->cinfo), tmp, 1); } jpeg_finish_compress (&(jpg->cinfo)); jpeg_destroy_compress(&(jpg->cinfo)); fclose(f); return 0; }
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; }