From d2d798d0f11abcbf141db69869e76e8d123ec1eb Mon Sep 17 00:00:00 2001 From: Kirill Volinsky Date: Sat, 13 Dec 2014 20:28:24 +0000 Subject: FreeImage updated to 3.16 git-svn-id: http://svn.miranda-ng.org/main/trunk@11379 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- .../AdvaImg/src/FreeImageToolkit/Background.cpp | 8 +- .../AdvaImg/src/FreeImageToolkit/JPEGTransform.cpp | 1029 ++++++++++++-------- plugins/AdvaImg/src/FreeImageToolkit/Rescale.cpp | 338 +++---- plugins/AdvaImg/src/FreeImageToolkit/Resize.cpp | 142 +-- plugins/AdvaImg/src/FreeImageToolkit/Resize.h | 21 +- 5 files changed, 879 insertions(+), 659 deletions(-) (limited to 'plugins/AdvaImg/src/FreeImageToolkit') diff --git a/plugins/AdvaImg/src/FreeImageToolkit/Background.cpp b/plugins/AdvaImg/src/FreeImageToolkit/Background.cpp index fc18667b21..08cdd4473b 100644 --- a/plugins/AdvaImg/src/FreeImageToolkit/Background.cpp +++ b/plugins/AdvaImg/src/FreeImageToolkit/Background.cpp @@ -251,7 +251,7 @@ FillBackgroundBitmap(FIBITMAP *dib, const RGBQUAD *color, int options) { // release, just assume to have an unicolor background and fill // all with an 'alpha-blended' color. if (color->rgbReserved < 255) { - + // If we will draw on an unicolor background, it's // faster to draw opaque with an alpha blended color. // So, first get the color from the first pixel in the @@ -259,7 +259,7 @@ FillBackgroundBitmap(FIBITMAP *dib, const RGBQUAD *color, int options) { RGBQUAD bgcolor; if (bpp == 8) { bgcolor = FreeImage_GetPalette(dib)[*src_bits]; - } else { + } else { bgcolor.rgbBlue = src_bits[FI_RGBA_BLUE]; bgcolor.rgbGreen = src_bits[FI_RGBA_GREEN]; bgcolor.rgbRed = src_bits[FI_RGBA_RED]; @@ -269,14 +269,14 @@ FillBackgroundBitmap(FIBITMAP *dib, const RGBQUAD *color, int options) { color_intl = &blend; } } - + int index = (bpp <= 8) ? GetPaletteIndex(dib, color_intl, options, &color_type) : 0; if (index == -1) { // No palette index found for a palletized // image. This should never happen... return FALSE; } - + // first, build the first scanline (line 0) switch (bpp) { case 1: { diff --git a/plugins/AdvaImg/src/FreeImageToolkit/JPEGTransform.cpp b/plugins/AdvaImg/src/FreeImageToolkit/JPEGTransform.cpp index 5822f748a6..132fef7e85 100644 --- a/plugins/AdvaImg/src/FreeImageToolkit/JPEGTransform.cpp +++ b/plugins/AdvaImg/src/FreeImageToolkit/JPEGTransform.cpp @@ -1,410 +1,623 @@ -// ========================================================== -// JPEG lossless transformations -// -// Design and implementation by -// - Petr Pytelka (pyta@lightcomp.com) -// - Hervé Drolon (drolon@infonie.fr) -// -// This file is part of FreeImage 3 -// -// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY -// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES -// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE -// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED -// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT -// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY -// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL -// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER -// THIS DISCLAIMER. -// -// Use at your own risk! -// ========================================================== - -extern "C" { -#define XMD_H -#undef FAR -#include - -#include "../LibJPEG/jinclude.h" -#include "../LibJPEG/jpeglib.h" -#include "../LibJPEG/jerror.h" -#include "../LibJPEG/transupp.h" -} - -#include "FreeImage.h" -#include "Utilities.h" - +// ========================================================== +// JPEG lossless transformations +// +// Design and implementation by +// - Petr Pytelka (pyta@lightcomp.com) +// - HervĂ© Drolon (drolon@infonie.fr) +// - Mihail Naydenov (mnaydenov@users.sourceforge.net) +// +// This file is part of FreeImage 3 +// +// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY +// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES +// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE +// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED +// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT +// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY +// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL +// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER +// THIS DISCLAIMER. +// +// Use at your own risk! +// ========================================================== + +extern "C" { +#define XMD_H +#undef FAR +#include + +#include "../LibJPEG/jinclude.h" +#include "../LibJPEG/jpeglib.h" +#include "../LibJPEG/jerror.h" +#include "../LibJPEG/transupp.h" +} + +#include "FreeImage.h" +#include "Utilities.h" +#include "FreeImageIO.h" + // ---------------------------------------------------------- -// IO filename handling +// Source manager & Destination manager setup +// (see PluginJPEG.cpp) // ---------------------------------------------------------- - -typedef struct tagFilenameIO { - const char *src_file; - const char *dst_file; - const wchar_t *wsrc_file; - const wchar_t *wdst_file; -} FilenameIO; - -// ---------------------------------------------------------- -// Error handling -// ---------------------------------------------------------- - -/** - Receives control for a fatal error. Information sufficient to - generate the error message has been stored in cinfo->err; call - output_message to display it. Control must NOT return to the caller; - generally this routine will exit() or longjmp() somewhere. -*/ -METHODDEF(void) -ls_jpeg_error_exit (j_common_ptr cinfo) { - // always display the message - (*cinfo->err->output_message)(cinfo); - - // allow JPEG with a premature end of file - if((cinfo)->err->msg_parm.i[0] != 13) { - - // let the memory manager delete any temp files before we die - jpeg_destroy(cinfo); - - throw FIF_JPEG; - } -} - -/** - Actual output of any JPEG message. Note that this method does not know - how to generate a message, only where to send it. -*/ -METHODDEF(void) -ls_jpeg_output_message (j_common_ptr cinfo) { - char buffer[JMSG_LENGTH_MAX]; - - // create the message - (*cinfo->err->format_message)(cinfo, buffer); - // send it to user's message proc - FreeImage_OutputMessageProc(FIF_JPEG, buffer); -} - -// ---------------------------------------------------------- -// Main program -// ---------------------------------------------------------- - -static BOOL -LosslessTransform(const FilenameIO *filenameIO, FREE_IMAGE_JPEG_OPERATION operation, const char *crop, BOOL perfect) { - // We assume all-in-memory processing and can therefore use only a - // single file pointer for sequential input and output operation - FILE *fp = NULL; - - // check for UNICODE filenames - previous structure filling was done before - bool bUseUnicode = filenameIO && filenameIO->wsrc_file && filenameIO->wdst_file; - - // Set up the jpeglib structures - jpeg_decompress_struct srcinfo; - jpeg_compress_struct dstinfo; - jpeg_error_mgr jsrcerr, jdsterr; - jvirt_barray_ptr *src_coef_arrays = NULL; - jvirt_barray_ptr *dst_coef_arrays = NULL; - // Support for copying optional markers from source to destination file - JCOPY_OPTION copyoption; - // Image transformation options - jpeg_transform_info transfoptions; - - // Initialize structures - memset(&srcinfo, 0, sizeof(srcinfo)); - memset(&jsrcerr, 0, sizeof(jsrcerr)); - memset(&jdsterr, 0, sizeof(jdsterr)); - memset(&dstinfo, 0, sizeof(dstinfo)); - memset(&transfoptions, 0, sizeof(transfoptions)); - - // Copy all extra markers from source file - copyoption = JCOPYOPT_ALL; - - // Set up default JPEG parameters - transfoptions.force_grayscale = FALSE; - transfoptions.crop = FALSE; - - // Select the transform option - switch(operation) { - case FIJPEG_OP_FLIP_H: // horizontal flip - transfoptions.transform = JXFORM_FLIP_H; - break; - case FIJPEG_OP_FLIP_V: // vertical flip - transfoptions.transform = JXFORM_FLIP_V; - break; - case FIJPEG_OP_TRANSPOSE: // transpose across UL-to-LR axis - transfoptions.transform = JXFORM_TRANSPOSE; - break; - case FIJPEG_OP_TRANSVERSE: // transpose across UR-to-LL axis - transfoptions.transform = JXFORM_TRANSVERSE; - break; - case FIJPEG_OP_ROTATE_90: // 90-degree clockwise rotation - transfoptions.transform = JXFORM_ROT_90; - break; - case FIJPEG_OP_ROTATE_180: // 180-degree rotation - transfoptions.transform = JXFORM_ROT_180; - break; - case FIJPEG_OP_ROTATE_270: // 270-degree clockwise (or 90 ccw) - transfoptions.transform = JXFORM_ROT_270; - break; - default: - case FIJPEG_OP_NONE: // no transformation - transfoptions.transform = JXFORM_NONE; - break; - } - // (perfect == TRUE) ==> fail if there is non-transformable edge blocks - transfoptions.perfect = (perfect == TRUE) ? TRUE : FALSE; - // Drop non-transformable edge blocks: trim off any partial edge MCUs that the transform can't handle. - transfoptions.trim = TRUE; - - try { - - // Initialize the JPEG decompression object with default error handling - srcinfo.err = jpeg_std_error(&jsrcerr); - srcinfo.err->error_exit = ls_jpeg_error_exit; - srcinfo.err->output_message = ls_jpeg_output_message; - jpeg_create_decompress(&srcinfo); - - // Initialize the JPEG compression object with default error handling - dstinfo.err = jpeg_std_error(&jdsterr); - dstinfo.err->error_exit = ls_jpeg_error_exit; - dstinfo.err->output_message = ls_jpeg_output_message; - jpeg_create_compress(&dstinfo); - - // crop option - if(crop != NULL) { - if(!jtransform_parse_crop_spec(&transfoptions, crop)) { - FreeImage_OutputMessageProc(FIF_JPEG, "Bogus crop argument %s", crop); - throw(1); - } - } - - // Open the input file - if(bUseUnicode) { -#ifdef _WIN32 - if((fp = _wfopen(filenameIO->wsrc_file, L"rb")) == NULL) { - FreeImage_OutputMessageProc(FIF_JPEG, "Cannot open input file for reading"); - } -#else - fp = NULL; -#endif // _WIN32 - } else { - if((fp = fopen(filenameIO->src_file, "rb")) == NULL) { - FreeImage_OutputMessageProc(FIF_JPEG, "Cannot open %s for reading", filenameIO->src_file); - } - } - if(fp == NULL) { - jpeg_destroy_compress(&dstinfo); - jpeg_destroy_decompress(&srcinfo); - return FALSE; - } - - // Specify data source for decompression - jpeg_stdio_src(&srcinfo, fp); - - // Enable saving of extra markers that we want to copy - jcopy_markers_setup(&srcinfo, copyoption); - - // Read the file header - jpeg_read_header(&srcinfo, TRUE); - - // Any space needed by a transform option must be requested before - // jpeg_read_coefficients so that memory allocation will be done right - - // Prepare transformation workspace - // Fails right away if perfect flag is TRUE and transformation is not perfect - if( !jtransform_request_workspace(&srcinfo, &transfoptions) ) { - FreeImage_OutputMessageProc(FIF_JPEG, "Transformation is not perfect"); - throw(1); - } - - // Read source file as DCT coefficients - src_coef_arrays = jpeg_read_coefficients(&srcinfo); - - // Initialize destination compression parameters from source values - jpeg_copy_critical_parameters(&srcinfo, &dstinfo); - - // Adjust destination parameters if required by transform options; - // also find out which set of coefficient arrays will hold the output - dst_coef_arrays = jtransform_adjust_parameters(&srcinfo, &dstinfo, src_coef_arrays, &transfoptions); - - // Close the input file. - // Note: we assume that jpeg_read_coefficients consumed all input - // until JPEG_REACHED_EOI, and that jpeg_finish_decompress will - // only consume more while (! cinfo->inputctl->eoi_reached). - // We cannot call jpeg_finish_decompress here since we still need the - // virtual arrays allocated from the source object for processing. - fclose(fp); - - // Open the output file - if(bUseUnicode) { -#ifdef _WIN32 - if((fp = _wfopen(filenameIO->wdst_file, L"wb")) == NULL) { - FreeImage_OutputMessageProc(FIF_JPEG, "Cannot open output file for writing"); - } -#else - fp = NULL; -#endif // _WIN32 - } else { - if((fp = fopen(filenameIO->dst_file, "wb")) == NULL) { - FreeImage_OutputMessageProc(FIF_JPEG, "Cannot open %s for writing", filenameIO->dst_file); - } - } - if(fp == NULL) { - throw(1); - } - - // Specify data destination for compression - jpeg_stdio_dest(&dstinfo, fp); - - // Start compressor (note no image data is actually written here) - jpeg_write_coefficients(&dstinfo, dst_coef_arrays); - - // Copy to the output file any extra markers that we want to preserve - jcopy_markers_execute(&srcinfo, &dstinfo, copyoption); - - // Execute image transformation, if any - jtransform_execute_transformation(&srcinfo, &dstinfo, src_coef_arrays, &transfoptions); - - // Finish compression and release memory - jpeg_finish_compress(&dstinfo); - jpeg_destroy_compress(&dstinfo); - jpeg_finish_decompress(&srcinfo); - jpeg_destroy_decompress(&srcinfo); - - // Close output file and return - fclose(fp); - } - catch(...) { - if(fp) fclose(fp); - jpeg_destroy_compress(&dstinfo); - jpeg_destroy_decompress(&srcinfo); - return FALSE; - } - - return TRUE; -} - -// ---------------------------------------------------------- -// FreeImage interface -// ---------------------------------------------------------- - -BOOL DLL_CALLCONV -FreeImage_JPEGTransform(const char *src_file, const char *dst_file, FREE_IMAGE_JPEG_OPERATION operation, BOOL perfect) { - try { - // check the src file format - if(FreeImage_GetFileType(src_file) != FIF_JPEG) { - throw FI_MSG_ERROR_MAGIC_NUMBER; - } - - // setup IO - FilenameIO filenameIO; - memset(&filenameIO, 0, sizeof(FilenameIO)); - filenameIO.src_file = src_file; - filenameIO.dst_file = dst_file; - - // perform the transformation - return LosslessTransform(&filenameIO, operation, NULL, perfect); - - } catch(const char *text) { - FreeImage_OutputMessageProc(FIF_JPEG, text); - return FALSE; - } -} - -BOOL DLL_CALLCONV -FreeImage_JPEGCrop(const char *src_file, const char *dst_file, int left, int top, int right, int bottom) { - char crop[64]; - - try { - // check the src file format - if(FreeImage_GetFileType(src_file) != FIF_JPEG) { - throw FI_MSG_ERROR_MAGIC_NUMBER; - } - - // normalize the rectangle - if(right < left) { - INPLACESWAP(left, right); - } - if(bottom < top) { - INPLACESWAP(top, bottom); - } - - // build the crop option - sprintf(crop, "%dx%d+%d+%d", right - left, bottom - top, left, top); - - // setup IO - FilenameIO filenameIO; - memset(&filenameIO, 0, sizeof(FilenameIO)); - filenameIO.src_file = src_file; - filenameIO.dst_file = dst_file; - - // perform the transformation - return LosslessTransform(&filenameIO, FIJPEG_OP_NONE, crop, FALSE); - - } catch(const char *text) { - FreeImage_OutputMessageProc(FIF_JPEG, text); - return FALSE; - } -} - -BOOL DLL_CALLCONV -FreeImage_JPEGTransformU(const wchar_t *src_file, const wchar_t *dst_file, FREE_IMAGE_JPEG_OPERATION operation, BOOL perfect) { -#ifdef _WIN32 - try { - // check the src file format - if(FreeImage_GetFileTypeU(src_file) != FIF_JPEG) { - throw FI_MSG_ERROR_MAGIC_NUMBER; - } - - // setup IO - FilenameIO filenameIO; - memset(&filenameIO, 0, sizeof(FilenameIO)); - filenameIO.wsrc_file = src_file; - filenameIO.wdst_file = dst_file; - - // perform the transformation - return LosslessTransform(&filenameIO, operation, NULL, perfect); - - } catch(const char *text) { - FreeImage_OutputMessageProc(FIF_JPEG, text); - } -#endif /// _WIN32 - return FALSE; -} - -BOOL DLL_CALLCONV -FreeImage_JPEGCropU(const wchar_t *src_file, const wchar_t *dst_file, int left, int top, int right, int bottom) { -#ifdef _WIN32 - char crop[64]; - - try { - // check the src file format - if(FreeImage_GetFileTypeU(src_file) != FIF_JPEG) { - throw FI_MSG_ERROR_MAGIC_NUMBER; - } - - // normalize the rectangle - if(right < left) { - INPLACESWAP(left, right); - } - if(bottom < top) { - INPLACESWAP(top, bottom); - } - - // build the crop option - sprintf(crop, "%dx%d+%d+%d", right - left, bottom - top, left, top); - - // setup IO - FilenameIO filenameIO; - memset(&filenameIO, 0, sizeof(FilenameIO)); - filenameIO.wsrc_file = src_file; - filenameIO.wdst_file = dst_file; - - // perform the transformation - return LosslessTransform(&filenameIO, FIJPEG_OP_NONE, crop, FALSE); - - } catch(const char *text) { - FreeImage_OutputMessageProc(FIF_JPEG, text); - } -#endif // _WIN32 - return FALSE; -} + +void jpeg_freeimage_src(j_decompress_ptr cinfo, fi_handle infile, FreeImageIO *io); +void jpeg_freeimage_dst(j_compress_ptr cinfo, fi_handle outfile, FreeImageIO *io); + +// ---------------------------------------------------------- +// Error handling +// (see also PluginJPEG.cpp) +// ---------------------------------------------------------- + +/** + Receives control for a fatal error. Information sufficient to + generate the error message has been stored in cinfo->err; call + output_message to display it. Control must NOT return to the caller; + generally this routine will exit() or longjmp() somewhere. +*/ +METHODDEF(void) +ls_jpeg_error_exit (j_common_ptr cinfo) { + // always display the message + (*cinfo->err->output_message)(cinfo); + + // allow JPEG with a premature end of file + if((cinfo)->err->msg_parm.i[0] != 13) { + + // let the memory manager delete any temp files before we die + jpeg_destroy(cinfo); + + throw FIF_JPEG; + } +} + +/** + Actual output of any JPEG message. Note that this method does not know + how to generate a message, only where to send it. +*/ +METHODDEF(void) +ls_jpeg_output_message (j_common_ptr cinfo) { + char buffer[JMSG_LENGTH_MAX]; + + // create the message + (*cinfo->err->format_message)(cinfo, buffer); + // send it to user's message proc + FreeImage_OutputMessageProc(FIF_JPEG, buffer); +} + +// ---------------------------------------------------------- +// Main program +// ---------------------------------------------------------- + +/** +Build a crop string. + +@param crop Output crop string +@param left Specifies the left position of the cropped rectangle +@param top Specifies the top position of the cropped rectangle +@param right Specifies the right position of the cropped rectangle +@param bottom Specifies the bottom position of the cropped rectangle +@param width Image width +@param height Image height +@return Returns TRUE if successful, returns FALSE otherwise +*/ +static BOOL +getCropString(char* crop, int* left, int* top, int* right, int* bottom, int width, int height) { + if(!left || !top || !right || !bottom) { + return FALSE; + } + + *left = CLAMP(*left, 0, width); + *top = CLAMP(*top, 0, height); + + // negative/zero right and bottom count from the edges inwards + + if(*right <= 0) { + *right = width + *right; + } + if(*bottom <= 0) { + *bottom = height + *bottom; + } + + *right = CLAMP(*right, 0, width); + *bottom = CLAMP(*bottom, 0, height); + + // test for empty rect + + if(((*left - *right) == 0) || ((*top - *bottom) == 0)) { + return FALSE; + } + + // normalize the rectangle + + if(*right < *left) { + INPLACESWAP(*left, *right); + } + if(*bottom < *top) { + INPLACESWAP(*top, *bottom); + } + + // test for "noop" rect + + if(*left == 0 && *right == width && *top == 0 && *bottom == height) { + return FALSE; + } + + // build the crop option + sprintf(crop, "%dx%d+%d+%d", *right - *left, *bottom - *top, *left, *top); + + return TRUE; +} + +static BOOL +JPEGTransformFromHandle(FreeImageIO* src_io, fi_handle src_handle, FreeImageIO* dst_io, fi_handle dst_handle, FREE_IMAGE_JPEG_OPERATION operation, int* left, int* top, int* right, int* bottom, BOOL perfect) { + const BOOL onlyReturnCropRect = (dst_io == NULL) || (dst_handle == NULL); + const long stream_start = onlyReturnCropRect ? 0 : dst_io->tell_proc(dst_handle); + BOOL swappedDim = FALSE; + BOOL trimH = FALSE; + BOOL trimV = FALSE; + + // Set up the jpeglib structures + jpeg_decompress_struct srcinfo; + jpeg_compress_struct dstinfo; + jpeg_error_mgr jsrcerr, jdsterr; + jvirt_barray_ptr *src_coef_arrays = NULL; + jvirt_barray_ptr *dst_coef_arrays = NULL; + // Support for copying optional markers from source to destination file + JCOPY_OPTION copyoption; + // Image transformation options + jpeg_transform_info transfoptions; + + // Initialize structures + memset(&srcinfo, 0, sizeof(srcinfo)); + memset(&jsrcerr, 0, sizeof(jsrcerr)); + memset(&jdsterr, 0, sizeof(jdsterr)); + memset(&dstinfo, 0, sizeof(dstinfo)); + memset(&transfoptions, 0, sizeof(transfoptions)); + + // Copy all extra markers from source file + copyoption = JCOPYOPT_ALL; + + // Set up default JPEG parameters + transfoptions.force_grayscale = FALSE; + transfoptions.crop = FALSE; + + // Select the transform option + switch(operation) { + case FIJPEG_OP_FLIP_H: // horizontal flip + transfoptions.transform = JXFORM_FLIP_H; + trimH = TRUE; + break; + case FIJPEG_OP_FLIP_V: // vertical flip + transfoptions.transform = JXFORM_FLIP_V; + trimV = TRUE; + break; + case FIJPEG_OP_TRANSPOSE: // transpose across UL-to-LR axis + transfoptions.transform = JXFORM_TRANSPOSE; + swappedDim = TRUE; + break; + case FIJPEG_OP_TRANSVERSE: // transpose across UR-to-LL axis + transfoptions.transform = JXFORM_TRANSVERSE; + trimH = TRUE; + trimV = TRUE; + swappedDim = TRUE; + break; + case FIJPEG_OP_ROTATE_90: // 90-degree clockwise rotation + transfoptions.transform = JXFORM_ROT_90; + trimH = TRUE; + swappedDim = TRUE; + break; + case FIJPEG_OP_ROTATE_180: // 180-degree rotation + trimH = TRUE; + trimV = TRUE; + transfoptions.transform = JXFORM_ROT_180; + break; + case FIJPEG_OP_ROTATE_270: // 270-degree clockwise (or 90 ccw) + transfoptions.transform = JXFORM_ROT_270; + trimV = TRUE; + swappedDim = TRUE; + break; + default: + case FIJPEG_OP_NONE: // no transformation + transfoptions.transform = JXFORM_NONE; + break; + } + // (perfect == TRUE) ==> fail if there is non-transformable edge blocks + transfoptions.perfect = (perfect == TRUE) ? TRUE : FALSE; + // Drop non-transformable edge blocks: trim off any partial edge MCUs that the transform can't handle. + transfoptions.trim = TRUE; + + try { + + // Initialize the JPEG decompression object with default error handling + srcinfo.err = jpeg_std_error(&jsrcerr); + srcinfo.err->error_exit = ls_jpeg_error_exit; + srcinfo.err->output_message = ls_jpeg_output_message; + jpeg_create_decompress(&srcinfo); + + // Initialize the JPEG compression object with default error handling + dstinfo.err = jpeg_std_error(&jdsterr); + dstinfo.err->error_exit = ls_jpeg_error_exit; + dstinfo.err->output_message = ls_jpeg_output_message; + jpeg_create_compress(&dstinfo); + + // Specify data source for decompression + jpeg_freeimage_src(&srcinfo, src_handle, src_io); + + // Enable saving of extra markers that we want to copy + jcopy_markers_setup(&srcinfo, copyoption); + + // Read the file header + jpeg_read_header(&srcinfo, TRUE); + + // crop option + char crop[64]; + const BOOL hasCrop = getCropString(crop, left, top, right, bottom, swappedDim ? srcinfo.image_height : srcinfo.image_width, swappedDim ? srcinfo.image_width : srcinfo.image_height); + + if(hasCrop) { + if(!jtransform_parse_crop_spec(&transfoptions, crop)) { + FreeImage_OutputMessageProc(FIF_JPEG, "Bogus crop argument %s", crop); + throw(1); + } + } + + // Any space needed by a transform option must be requested before + // jpeg_read_coefficients so that memory allocation will be done right + + // Prepare transformation workspace + // Fails right away if perfect flag is TRUE and transformation is not perfect + if( !jtransform_request_workspace(&srcinfo, &transfoptions) ) { + FreeImage_OutputMessageProc(FIF_JPEG, "Transformation is not perfect"); + throw(1); + } + + if(left || top) { + // compute left and top offsets, it's a bit tricky, taking into account both + // transform, which might have trimed the image, + // and crop itself, which is adjusted to lie on a iMCU boundary + + const int fullWidth = swappedDim ? srcinfo.image_height : srcinfo.image_width; + const int fullHeight = swappedDim ? srcinfo.image_width : srcinfo.image_height; + + int transformedFullWidth = fullWidth; + int transformedFullHeight = fullHeight; + + if(trimH && transformedFullWidth/transfoptions.iMCU_sample_width > 0) { + transformedFullWidth = (transformedFullWidth/transfoptions.iMCU_sample_width) * transfoptions.iMCU_sample_width; + } + if(trimV && transformedFullHeight/transfoptions.iMCU_sample_height > 0) { + transformedFullHeight = (transformedFullHeight/transfoptions.iMCU_sample_height) * transfoptions.iMCU_sample_height; + } + + const int trimmedWidth = fullWidth - transformedFullWidth; + const int trimmedHeight = fullHeight - transformedFullHeight; + + if(left) { + *left = trimmedWidth + transfoptions.x_crop_offset * transfoptions.iMCU_sample_width; + } + if(top) { + *top = trimmedHeight + transfoptions.y_crop_offset * transfoptions.iMCU_sample_height; + } + } + + if(right) { + *right = (left ? *left : 0) + transfoptions.output_width; + } + if(bottom) { + *bottom = (top ? *top : 0) + transfoptions.output_height; + } + + // if only the crop rect is requested, we are done + + if(onlyReturnCropRect) { + jpeg_destroy_compress(&dstinfo); + jpeg_destroy_decompress(&srcinfo); + return TRUE; + } + + // Read source file as DCT coefficients + src_coef_arrays = jpeg_read_coefficients(&srcinfo); + + // Initialize destination compression parameters from source values + jpeg_copy_critical_parameters(&srcinfo, &dstinfo); + + // Adjust destination parameters if required by transform options; + // also find out which set of coefficient arrays will hold the output + dst_coef_arrays = jtransform_adjust_parameters(&srcinfo, &dstinfo, src_coef_arrays, &transfoptions); + + // Note: we assume that jpeg_read_coefficients consumed all input + // until JPEG_REACHED_EOI, and that jpeg_finish_decompress will + // only consume more while (! cinfo->inputctl->eoi_reached). + // We cannot call jpeg_finish_decompress here since we still need the + // virtual arrays allocated from the source object for processing. + + if(src_handle == dst_handle) { + dst_io->seek_proc(dst_handle, stream_start, SEEK_SET); + } + + // Specify data destination for compression + jpeg_freeimage_dst(&dstinfo, dst_handle, dst_io); + + // Start compressor (note no image data is actually written here) + jpeg_write_coefficients(&dstinfo, dst_coef_arrays); + + // Copy to the output file any extra markers that we want to preserve + jcopy_markers_execute(&srcinfo, &dstinfo, copyoption); + + // Execute image transformation, if any + jtransform_execute_transformation(&srcinfo, &dstinfo, src_coef_arrays, &transfoptions); + + // Finish compression and release memory + jpeg_finish_compress(&dstinfo); + jpeg_destroy_compress(&dstinfo); + jpeg_finish_decompress(&srcinfo); + jpeg_destroy_decompress(&srcinfo); + + } + catch(...) { + jpeg_destroy_compress(&dstinfo); + jpeg_destroy_decompress(&srcinfo); + return FALSE; + } + + return TRUE; +} + +// ---------------------------------------------------------- +// FreeImage interface +// ---------------------------------------------------------- + +BOOL DLL_CALLCONV +FreeImage_JPEGTransformFromHandle(FreeImageIO* src_io, fi_handle src_handle, FreeImageIO* dst_io, fi_handle dst_handle, FREE_IMAGE_JPEG_OPERATION operation, int* left, int* top, int* right, int* bottom, BOOL perfect) { + return JPEGTransformFromHandle(src_io, src_handle, dst_io, dst_handle, operation, left, top, right, bottom, perfect); +} + +static void +closeStdIO(fi_handle src_handle, fi_handle dst_handle) { + if(src_handle) { + fclose((FILE*)src_handle); + } + if(dst_handle) { + fclose((FILE*)dst_handle); + } +} + +static BOOL +openStdIO(const char* src_file, const char* dst_file, FreeImageIO* dst_io, fi_handle* src_handle, fi_handle* dst_handle) { + *src_handle = NULL; + *dst_handle = NULL; + + FreeImageIO io; + SetDefaultIO (&io); + + const BOOL isSameFile = (dst_file && (strcmp(src_file, dst_file) == 0)) ? TRUE : FALSE; + + FILE* srcp = NULL; + FILE* dstp = NULL; + + if(isSameFile) { + srcp = fopen(src_file, "r+b"); + dstp = srcp; + } + else { + srcp = fopen(src_file, "rb"); + if(dst_file) { + dstp = fopen(dst_file, "wb"); + } + } + + if(!srcp || (dst_file && !dstp)) { + if(!srcp) { + FreeImage_OutputMessageProc(FIF_JPEG, "Cannot open \"%s\" for reading", src_file); + } else { + FreeImage_OutputMessageProc(FIF_JPEG, "Cannot open \"%s\" for writing", dst_file); + } + closeStdIO(srcp, dstp); + return FALSE; + } + + if(FreeImage_GetFileTypeFromHandle(&io, srcp) != FIF_JPEG) { + FreeImage_OutputMessageProc(FIF_JPEG, " Source file \"%s\" is not jpeg", src_file); + closeStdIO(srcp, dstp); + return FALSE; + } + + *dst_io = io; + *src_handle = srcp; + *dst_handle = dstp; + + return TRUE; +} + +static BOOL +openStdIOU(const wchar_t* src_file, const wchar_t* dst_file, FreeImageIO* dst_io, fi_handle* src_handle, fi_handle* dst_handle) { +#ifdef _WIN32 + + *src_handle = NULL; + *dst_handle = NULL; + + FreeImageIO io; + SetDefaultIO (&io); + + const BOOL isSameFile = (dst_file && (wcscmp(src_file, dst_file) == 0)) ? TRUE : FALSE; + + FILE* srcp = NULL; + FILE* dstp = NULL; + + if(isSameFile) { + srcp = _wfopen(src_file, L"r+b"); + dstp = srcp; + } else { + srcp = _wfopen(src_file, L"rb"); + if(dst_file) { + dstp = _wfopen(dst_file, L"wb"); + } + } + + if(!srcp || (dst_file && !dstp)) { + if(!srcp) { + FreeImage_OutputMessageProc(FIF_JPEG, "Cannot open source file for reading"); + } else { + FreeImage_OutputMessageProc(FIF_JPEG, "Cannot open destination file for writing"); + } + closeStdIO(srcp, dstp); + return FALSE; + } + + if(FreeImage_GetFileTypeFromHandle(&io, srcp) != FIF_JPEG) { + FreeImage_OutputMessageProc(FIF_JPEG, " Source file is not jpeg"); + closeStdIO(srcp, dstp); + return FALSE; + } + + *dst_io = io; + *src_handle = srcp; + *dst_handle = dstp; + + return TRUE; + +#else + return FALSE; +#endif // _WIN32 +} + +BOOL DLL_CALLCONV +FreeImage_JPEGTransform(const char *src_file, const char *dst_file, FREE_IMAGE_JPEG_OPERATION operation, BOOL perfect) { + FreeImageIO io; + fi_handle src; + fi_handle dst; + + if(!openStdIO(src_file, dst_file, &io, &src, &dst)) { + return FALSE; + } + + BOOL ret = JPEGTransformFromHandle(&io, src, &io, dst, operation, NULL, NULL, NULL, NULL, perfect); + + closeStdIO(src, dst); + + return ret; +} + +BOOL DLL_CALLCONV +FreeImage_JPEGCrop(const char *src_file, const char *dst_file, int left, int top, int right, int bottom) { + FreeImageIO io; + fi_handle src; + fi_handle dst; + + if(!openStdIO(src_file, dst_file, &io, &src, &dst)) { + return FALSE; + } + + BOOL ret = FreeImage_JPEGTransformFromHandle(&io, src, &io, dst, FIJPEG_OP_NONE, &left, &top, &right, &bottom, FALSE); + + closeStdIO(src, dst); + + return ret; +} + +BOOL DLL_CALLCONV +FreeImage_JPEGTransformU(const wchar_t *src_file, const wchar_t *dst_file, FREE_IMAGE_JPEG_OPERATION operation, BOOL perfect) { + FreeImageIO io; + fi_handle src; + fi_handle dst; + + if(!openStdIOU(src_file, dst_file, &io, &src, &dst)) { + return FALSE; + } + + BOOL ret = JPEGTransformFromHandle(&io, src, &io, dst, operation, NULL, NULL, NULL, NULL, perfect); + + closeStdIO(src, dst); + + return ret; +} + +BOOL DLL_CALLCONV +FreeImage_JPEGCropU(const wchar_t *src_file, const wchar_t *dst_file, int left, int top, int right, int bottom) { + FreeImageIO io; + fi_handle src; + fi_handle dst; + + if(!openStdIOU(src_file, dst_file, &io, &src, &dst)) { + return FALSE; + } + + BOOL ret = FreeImage_JPEGTransformFromHandle(&io, src, &io, dst, FIJPEG_OP_NONE, &left, &top, &right, &bottom, FALSE); + + closeStdIO(src, dst); + + return ret; +} + +BOOL DLL_CALLCONV +FreeImage_JPEGTransformCombined(const char *src_file, const char *dst_file, FREE_IMAGE_JPEG_OPERATION operation, int* left, int* top, int* right, int* bottom, BOOL perfect) { + FreeImageIO io; + fi_handle src; + fi_handle dst; + + if(!openStdIO(src_file, dst_file, &io, &src, &dst)) { + return FALSE; + } + + BOOL ret = FreeImage_JPEGTransformFromHandle(&io, src, &io, dst, operation, left, top, right, bottom, perfect); + + closeStdIO(src, dst); + + return ret; +} + +BOOL DLL_CALLCONV +FreeImage_JPEGTransformCombinedU(const wchar_t *src_file, const wchar_t *dst_file, FREE_IMAGE_JPEG_OPERATION operation, int* left, int* top, int* right, int* bottom, BOOL perfect) { + FreeImageIO io; + fi_handle src; + fi_handle dst; + + if(!openStdIOU(src_file, dst_file, &io, &src, &dst)) { + return FALSE; + } + + BOOL ret = FreeImage_JPEGTransformFromHandle(&io, src, &io, dst, operation, left, top, right, bottom, perfect); + + closeStdIO(src, dst); + + return ret; +} + +// -------------------------------------------------------------------------- + +static BOOL +getMemIO(FIMEMORY* src_stream, FIMEMORY* dst_stream, FreeImageIO* dst_io, fi_handle* src_handle, fi_handle* dst_handle) { + *src_handle = NULL; + *dst_handle = NULL; + + FreeImageIO io; + SetMemoryIO (&io); + + if(dst_stream) { + FIMEMORYHEADER *mem_header = (FIMEMORYHEADER*)(dst_stream->data); + if(mem_header->delete_me != TRUE) { + // do not save in a user buffer + FreeImage_OutputMessageProc(FIF_JPEG, "Destination memory buffer is read only"); + return FALSE; + } + } + + *dst_io = io; + *src_handle = src_stream; + *dst_handle = dst_stream; + + return TRUE; +} + +BOOL DLL_CALLCONV +FreeImage_JPEGTransformCombinedFromMemory(FIMEMORY* src_stream, FIMEMORY* dst_stream, FREE_IMAGE_JPEG_OPERATION operation, int* left, int* top, int* right, int* bottom, BOOL perfect) { + FreeImageIO io; + fi_handle src; + fi_handle dst; + + if(!getMemIO(src_stream, dst_stream, &io, &src, &dst)) { + return FALSE; + } + + return FreeImage_JPEGTransformFromHandle(&io, src, &io, dst, operation, left, top, right, bottom, perfect); +} + diff --git a/plugins/AdvaImg/src/FreeImageToolkit/Rescale.cpp b/plugins/AdvaImg/src/FreeImageToolkit/Rescale.cpp index ffe667e7d4..0c8bbc2787 100644 --- a/plugins/AdvaImg/src/FreeImageToolkit/Rescale.cpp +++ b/plugins/AdvaImg/src/FreeImageToolkit/Rescale.cpp @@ -1,169 +1,169 @@ -// ========================================================== -// Upsampling / downsampling routine -// -// Design and implementation by -// - Hervé Drolon (drolon@infonie.fr) -// - Carsten Klein (cklein05@users.sourceforge.net) -// -// This file is part of FreeImage 3 -// -// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY -// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES -// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE -// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED -// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT -// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY -// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL -// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER -// THIS DISCLAIMER. -// -// Use at your own risk! -// ========================================================== - -#include "Resize.h" - -FIBITMAP * DLL_CALLCONV -FreeImage_Rescale(FIBITMAP *src, int dst_width, int dst_height, FREE_IMAGE_FILTER filter) { - FIBITMAP *dst = NULL; - - if (!FreeImage_HasPixels(src) || (dst_width <= 0) || (dst_height <= 0) || (FreeImage_GetWidth(src) <= 0) || (FreeImage_GetHeight(src) <= 0)) { - return NULL; - } - - // select the filter - CGenericFilter *pFilter = NULL; - switch (filter) { - case FILTER_BOX: - pFilter = new(std::nothrow) CBoxFilter(); - break; - case FILTER_BICUBIC: - pFilter = new(std::nothrow) CBicubicFilter(); - break; - case FILTER_BILINEAR: - pFilter = new(std::nothrow) CBilinearFilter(); - break; - case FILTER_BSPLINE: - pFilter = new(std::nothrow) CBSplineFilter(); - break; - case FILTER_CATMULLROM: - pFilter = new(std::nothrow) CCatmullRomFilter(); - break; - case FILTER_LANCZOS3: - pFilter = new(std::nothrow) CLanczos3Filter(); - break; - } - - if (!pFilter) { - return NULL; - } - - CResizeEngine Engine(pFilter); - - dst = Engine.scale(src, dst_width, dst_height, 0, 0, - FreeImage_GetWidth(src), FreeImage_GetHeight(src)); - - delete pFilter; - - // copy metadata from src to dst - FreeImage_CloneMetadata(dst, src); - - return dst; -} - -FIBITMAP * DLL_CALLCONV -FreeImage_MakeThumbnail(FIBITMAP *dib, int max_pixel_size, BOOL convert) { - FIBITMAP *thumbnail = NULL; - int new_width, new_height; - - if(!FreeImage_HasPixels(dib) || (max_pixel_size <= 0)) return NULL; - - int width = FreeImage_GetWidth(dib); - int height = FreeImage_GetHeight(dib); - - if(max_pixel_size == 0) max_pixel_size = 1; - - if((width < max_pixel_size) && (height < max_pixel_size)) { - // image is smaller than the requested thumbnail - return FreeImage_Clone(dib); - } - - if(width > height) { - new_width = max_pixel_size; - // change image height with the same ratio - double ratio = ((double)new_width / (double)width); - new_height = (int)(height * ratio + 0.5); - if(new_height == 0) new_height = 1; - } else { - new_height = max_pixel_size; - // change image width with the same ratio - double ratio = ((double)new_height / (double)height); - new_width = (int)(width * ratio + 0.5); - if(new_width == 0) new_width = 1; - } - - const FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib); - - // perform downsampling using a bilinear interpolation - - switch(image_type) { - case FIT_BITMAP: - case FIT_UINT16: - case FIT_RGB16: - case FIT_RGBA16: - case FIT_FLOAT: - case FIT_RGBF: - case FIT_RGBAF: - { - FREE_IMAGE_FILTER filter = FILTER_BILINEAR; - thumbnail = FreeImage_Rescale(dib, new_width, new_height, filter); - } - break; - - case FIT_INT16: - case FIT_UINT32: - case FIT_INT32: - case FIT_DOUBLE: - case FIT_COMPLEX: - default: - // cannot rescale this kind of image - thumbnail = NULL; - break; - } - - if((thumbnail != NULL) && (image_type != FIT_BITMAP) && convert) { - // convert to a standard bitmap - FIBITMAP *bitmap = NULL; - switch(image_type) { - case FIT_UINT16: - bitmap = FreeImage_ConvertTo8Bits(thumbnail); - break; - case FIT_RGB16: - bitmap = FreeImage_ConvertTo24Bits(thumbnail); - break; - case FIT_RGBA16: - bitmap = FreeImage_ConvertTo32Bits(thumbnail); - break; - case FIT_FLOAT: - bitmap = FreeImage_ConvertToStandardType(thumbnail, TRUE); - break; - case FIT_RGBF: - bitmap = FreeImage_ToneMapping(thumbnail, FITMO_DRAGO03); - break; - case FIT_RGBAF: - // no way to keep the transparency yet ... - FIBITMAP *rgbf = FreeImage_ConvertToRGBF(thumbnail); - bitmap = FreeImage_ToneMapping(rgbf, FITMO_DRAGO03); - FreeImage_Unload(rgbf); - break; - } - if(bitmap != NULL) { - FreeImage_Unload(thumbnail); - thumbnail = bitmap; - } - } - - // copy metadata from src to dst - FreeImage_CloneMetadata(thumbnail, dib); - - return thumbnail; -} +// ========================================================== +// Upsampling / downsampling routine +// +// Design and implementation by +// - Hervé Drolon (drolon@infonie.fr) +// - Carsten Klein (cklein05@users.sourceforge.net) +// +// This file is part of FreeImage 3 +// +// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY +// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES +// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE +// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED +// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT +// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY +// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL +// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER +// THIS DISCLAIMER. +// +// Use at your own risk! +// ========================================================== + +#include "Resize.h" + +FIBITMAP * DLL_CALLCONV +FreeImage_Rescale(FIBITMAP *src, int dst_width, int dst_height, FREE_IMAGE_FILTER filter) { + FIBITMAP *dst = NULL; + + if (!FreeImage_HasPixels(src) || (dst_width <= 0) || (dst_height <= 0) || (FreeImage_GetWidth(src) <= 0) || (FreeImage_GetHeight(src) <= 0)) { + return NULL; + } + + // select the filter + CGenericFilter *pFilter = NULL; + switch (filter) { + case FILTER_BOX: + pFilter = new(std::nothrow) CBoxFilter(); + break; + case FILTER_BICUBIC: + pFilter = new(std::nothrow) CBicubicFilter(); + break; + case FILTER_BILINEAR: + pFilter = new(std::nothrow) CBilinearFilter(); + break; + case FILTER_BSPLINE: + pFilter = new(std::nothrow) CBSplineFilter(); + break; + case FILTER_CATMULLROM: + pFilter = new(std::nothrow) CCatmullRomFilter(); + break; + case FILTER_LANCZOS3: + pFilter = new(std::nothrow) CLanczos3Filter(); + break; + } + + if (!pFilter) { + return NULL; + } + + CResizeEngine Engine(pFilter); + + dst = Engine.scale(src, dst_width, dst_height, 0, 0, + FreeImage_GetWidth(src), FreeImage_GetHeight(src)); + + delete pFilter; + + // copy metadata from src to dst + FreeImage_CloneMetadata(dst, src); + + return dst; +} + +FIBITMAP * DLL_CALLCONV +FreeImage_MakeThumbnail(FIBITMAP *dib, int max_pixel_size, BOOL convert) { + FIBITMAP *thumbnail = NULL; + int new_width, new_height; + + if(!FreeImage_HasPixels(dib) || (max_pixel_size <= 0)) return NULL; + + int width = FreeImage_GetWidth(dib); + int height = FreeImage_GetHeight(dib); + + if(max_pixel_size == 0) max_pixel_size = 1; + + if((width < max_pixel_size) && (height < max_pixel_size)) { + // image is smaller than the requested thumbnail + return FreeImage_Clone(dib); + } + + if(width > height) { + new_width = max_pixel_size; + // change image height with the same ratio + double ratio = ((double)new_width / (double)width); + new_height = (int)(height * ratio + 0.5); + if(new_height == 0) new_height = 1; + } else { + new_height = max_pixel_size; + // change image width with the same ratio + double ratio = ((double)new_height / (double)height); + new_width = (int)(width * ratio + 0.5); + if(new_width == 0) new_width = 1; + } + + const FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib); + + // perform downsampling using a bilinear interpolation + + switch(image_type) { + case FIT_BITMAP: + case FIT_UINT16: + case FIT_RGB16: + case FIT_RGBA16: + case FIT_FLOAT: + case FIT_RGBF: + case FIT_RGBAF: + { + FREE_IMAGE_FILTER filter = FILTER_BILINEAR; + thumbnail = FreeImage_Rescale(dib, new_width, new_height, filter); + } + break; + + case FIT_INT16: + case FIT_UINT32: + case FIT_INT32: + case FIT_DOUBLE: + case FIT_COMPLEX: + default: + // cannot rescale this kind of image + thumbnail = NULL; + break; + } + + if((thumbnail != NULL) && (image_type != FIT_BITMAP) && convert) { + // convert to a standard bitmap + FIBITMAP *bitmap = NULL; + switch(image_type) { + case FIT_UINT16: + bitmap = FreeImage_ConvertTo8Bits(thumbnail); + break; + case FIT_RGB16: + bitmap = FreeImage_ConvertTo24Bits(thumbnail); + break; + case FIT_RGBA16: + bitmap = FreeImage_ConvertTo32Bits(thumbnail); + break; + case FIT_FLOAT: + bitmap = FreeImage_ConvertToStandardType(thumbnail, TRUE); + break; + case FIT_RGBF: + bitmap = FreeImage_ToneMapping(thumbnail, FITMO_DRAGO03); + break; + case FIT_RGBAF: + // no way to keep the transparency yet ... + FIBITMAP *rgbf = FreeImage_ConvertToRGBF(thumbnail); + bitmap = FreeImage_ToneMapping(rgbf, FITMO_DRAGO03); + FreeImage_Unload(rgbf); + break; + } + if(bitmap != NULL) { + FreeImage_Unload(thumbnail); + thumbnail = bitmap; + } + } + + // copy metadata from src to dst + FreeImage_CloneMetadata(thumbnail, dib); + + return thumbnail; +} diff --git a/plugins/AdvaImg/src/FreeImageToolkit/Resize.cpp b/plugins/AdvaImg/src/FreeImageToolkit/Resize.cpp index f342bb794e..283a91e830 100644 --- a/plugins/AdvaImg/src/FreeImageToolkit/Resize.cpp +++ b/plugins/AdvaImg/src/FreeImageToolkit/Resize.cpp @@ -139,9 +139,8 @@ GetRGBAPalette(FIBITMAP *dib, RGBQUAD * const buffer) { // -------------------------------------------------------------------------- CWeightsTable::CWeightsTable(CGenericFilter *pFilter, unsigned uDstSize, unsigned uSrcSize) { - unsigned u; double dWidth; - double dFScale = 1.0; + double dFScale; const double dFilterWidth = pFilter->GetWidth(); // scale factor @@ -153,69 +152,70 @@ CWeightsTable::CWeightsTable(CGenericFilter *pFilter, unsigned uDstSize, unsigne dFScale = dScale; } else { // magnification - dWidth= dFilterWidth; + dWidth = dFilterWidth; + dFScale = 1.0; } // allocate a new line contributions structure // // window size is the number of sampled pixels m_WindowSize = 2 * (int)ceil(dWidth) + 1; + // length of dst line (no. of rows / cols) m_LineLength = uDstSize; + // allocate list of contributions m_WeightTable = (Contribution*)malloc(m_LineLength * sizeof(Contribution)); - for(u = 0 ; u < m_LineLength ; u++) { + for(unsigned u = 0; u < m_LineLength; u++) { // allocate contributions for every pixel m_WeightTable[u].Weights = (double*)malloc(m_WindowSize * sizeof(double)); } // offset for discrete to continuous coordinate conversion - const double dOffset = (0.5 / dScale) - 0.5; + const double dOffset = (0.5 / dScale); - for(u = 0; u < m_LineLength; u++) { + for(unsigned u = 0; u < m_LineLength; u++) { // scan through line of contributions - const double dCenter = (double)u / dScale + dOffset; // reverse mapping - // find the significant edge points that affect the pixel - int iLeft = MAX (0, (int)floor (dCenter - dWidth)); - int iRight = MIN ((int)ceil (dCenter + dWidth), int(uSrcSize) - 1); - // cut edge points to fit in filter window in case of spill-off - if((iRight - iLeft + 1) > int(m_WindowSize)) { - if(iLeft < (int(uSrcSize) - 1 / 2)) { - iLeft++; - } else { - iRight--; - } - } + // inverse mapping (discrete dst 'u' to continous src 'dCenter') + const double dCenter = (double)u / dScale + dOffset; + + // find the significant edge points that affect the pixel + const int iLeft = MAX(0, (int)(dCenter - dWidth + 0.5)); + const int iRight = MIN((int)(dCenter + dWidth + 0.5), int(uSrcSize)); m_WeightTable[u].Left = iLeft; m_WeightTable[u].Right = iRight; - int iSrc = 0; - double dTotalWeight = 0; // zero sum of weights - for(iSrc = iLeft; iSrc <= iRight; iSrc++) { + double dTotalWeight = 0; // sum of weights (initialized to zero) + for(int iSrc = iLeft; iSrc < iRight; iSrc++) { // calculate weights - const double weight = dFScale * pFilter->Filter(dFScale * (dCenter - (double)iSrc)); + const double weight = dFScale * pFilter->Filter(dFScale * ((double)iSrc + 0.5 - dCenter)); + // assert((iSrc-iLeft) < m_WindowSize); m_WeightTable[u].Weights[iSrc-iLeft] = weight; dTotalWeight += weight; } if((dTotalWeight > 0) && (dTotalWeight != 1)) { // normalize weight of neighbouring points - for(iSrc = iLeft; iSrc <= iRight; iSrc++) { + for(int iSrc = iLeft; iSrc < iRight; iSrc++) { // normalize point m_WeightTable[u].Weights[iSrc-iLeft] /= dTotalWeight; } - // simplify the filter, discarding null weights at the right - iSrc = iRight - iLeft; - while(m_WeightTable[u].Weights[iSrc] == 0) { + } + + // simplify the filter, discarding null weights at the right + { + int iTrailing = iRight - iLeft - 1; + while(m_WeightTable[u].Weights[iTrailing] == 0) { m_WeightTable[u].Right--; - iSrc--; + iTrailing--; if(m_WeightTable[u].Right == m_WeightTable[u].Left) { break; } } - + } - } + + } // next dst pixel } CWeightsTable::~CWeightsTable() { @@ -253,6 +253,12 @@ FIBITMAP* CResizeEngine::scale(FIBITMAP *src, unsigned dst_width, unsigned dst_h // greyscale images require an 8-bit destination image // (or a 32-bit image if the image is transparent) dst_bpp = FreeImage_IsTransparent(src) ? 32 : 8; + if (dst_bpp == 32) { + // additionally, for transparent images we always need a + // palette including transparency information (an RGBA palette) + // so, set color_type accordingly. + color_type = FIC_PALETTE; + } } else if (src_bpp == 16 && image_type == FIT_BITMAP) { // 16-bit 555 and 565 RGB images require a high-color destination image // (fixed to 24 bits, since 16-bit RGBs don't support transparency in FreeImage) @@ -303,7 +309,7 @@ FIBITMAP* CResizeEngine::scale(FIBITMAP *src, unsigned dst_width, unsigned dst_h // provide the source image's palette to the rescaler for // FIC_PALETTE type images (this includes palletized greyscale - // images with an unordered palette) + // images with an unordered palette as well as transparent images) if (color_type == FIC_PALETTE) { if (dst_bpp == 32) { // a 32 bit destination image signals transparency, so @@ -522,7 +528,7 @@ void CResizeEngine::horizontalFilter(FIBITMAP *const src, unsigned height, unsig const unsigned iRight = weightsTable.getRightBoundary(x); // retrieve right boundary double value = 0; - for (unsigned i = iLeft; i <= iRight; i++) { + for (unsigned i = iLeft; i < iRight; i++) { // scan between boundaries // accumulate weighted effect of each neighboring pixel const unsigned pixel = (src_bits[i >> 3] & (0x80 >> (i & 0x07))) != 0; @@ -546,7 +552,7 @@ void CResizeEngine::horizontalFilter(FIBITMAP *const src, unsigned height, unsig const unsigned iRight = weightsTable.getRightBoundary(x); // retrieve right boundary double value = 0; - for (unsigned i = iLeft; i <= iRight; i++) { + for (unsigned i = iLeft; i < iRight; i++) { // scan between boundaries // accumulate weighted effect of each neighboring pixel const unsigned pixel = (src_bits[i >> 3] & (0x80 >> (i & 0x07))) != 0; @@ -579,7 +585,7 @@ void CResizeEngine::horizontalFilter(FIBITMAP *const src, unsigned height, unsig const unsigned iRight = weightsTable.getRightBoundary(x); // retrieve right boundary double r = 0, g = 0, b = 0; - for (unsigned i = iLeft; i <= iRight; i++) { + for (unsigned i = iLeft; i < iRight; i++) { // scan between boundaries // accumulate weighted effect of each neighboring pixel const double weight = weightsTable.getWeight(x, i - iLeft); @@ -617,7 +623,7 @@ void CResizeEngine::horizontalFilter(FIBITMAP *const src, unsigned height, unsig const unsigned iRight = weightsTable.getRightBoundary(x); // retrieve right boundary double r = 0, g = 0, b = 0, a = 0; - for (unsigned i = iLeft; i <= iRight; i++) { + for (unsigned i = iLeft; i < iRight; i++) { // scan between boundaries // accumulate weighted effect of each neighboring pixel const double weight = weightsTable.getWeight(x, i - iLeft); @@ -663,7 +669,7 @@ void CResizeEngine::horizontalFilter(FIBITMAP *const src, unsigned height, unsig const unsigned iRight = weightsTable.getRightBoundary(x); // retrieve right boundary double value = 0; - for (unsigned i = iLeft; i <= iRight; i++) { + for (unsigned i = iLeft; i < iRight; i++) { // scan between boundaries // accumulate weighted effect of each neighboring pixel const unsigned pixel = i & 0x01 ? src_bits[i >> 1] & 0x0F : src_bits[i >> 1] >> 4; @@ -695,7 +701,7 @@ void CResizeEngine::horizontalFilter(FIBITMAP *const src, unsigned height, unsig const unsigned iRight = weightsTable.getRightBoundary(x); // retrieve right boundary double r = 0, g = 0, b = 0; - for (unsigned i = iLeft; i <= iRight; i++) { + for (unsigned i = iLeft; i < iRight; i++) { // scan between boundaries // accumulate weighted effect of each neighboring pixel const double weight = weightsTable.getWeight(x, i - iLeft); @@ -733,7 +739,7 @@ void CResizeEngine::horizontalFilter(FIBITMAP *const src, unsigned height, unsig const unsigned iRight = weightsTable.getRightBoundary(x); // retrieve right boundary double r = 0, g = 0, b = 0, a = 0; - for (unsigned i = iLeft; i <= iRight; i++) { + for (unsigned i = iLeft; i < iRight; i++) { // scan between boundaries // accumulate weighted effect of each neighboring pixel const double weight = weightsTable.getWeight(x, i - iLeft); @@ -781,7 +787,7 @@ void CResizeEngine::horizontalFilter(FIBITMAP *const src, unsigned height, unsig double value = 0; // for(i = iLeft to iRight) - for (unsigned i = 0; i <= iLimit; i++) { + for (unsigned i = 0; i < iLimit; i++) { // scan between boundaries // accumulate weighted effect of each neighboring pixel value += (weightsTable.getWeight(x, i) @@ -807,7 +813,7 @@ void CResizeEngine::horizontalFilter(FIBITMAP *const src, unsigned height, unsig double value = 0; // for(i = iLeft to iRight) - for (unsigned i = 0; i <= iLimit; i++) { + for (unsigned i = 0; i < iLimit; i++) { // scan between boundaries // accumulate weighted effect of each neighboring pixel value += (weightsTable.getWeight(x, i) * (double)pixel[i]); @@ -838,7 +844,7 @@ void CResizeEngine::horizontalFilter(FIBITMAP *const src, unsigned height, unsig double r = 0, g = 0, b = 0; // for(i = iLeft to iRight) - for (unsigned i = 0; i <= iLimit; i++) { + for (unsigned i = 0; i < iLimit; i++) { // scan between boundaries // accumulate weighted effect of each neighboring pixel const double weight = weightsTable.getWeight(x, i); @@ -875,7 +881,7 @@ void CResizeEngine::horizontalFilter(FIBITMAP *const src, unsigned height, unsig double r = 0, g = 0, b = 0, a = 0; // for(i = iLeft to iRight) - for (unsigned i = 0; i <= iLimit; i++) { + for (unsigned i = 0; i < iLimit; i++) { // scan between boundaries // accumulate weighted effect of each neighboring pixel const double weight = weightsTable.getWeight(x, i); @@ -919,7 +925,7 @@ void CResizeEngine::horizontalFilter(FIBITMAP *const src, unsigned height, unsig double r = 0, g = 0, b = 0; // for(i = iLeft to iRight) - for (unsigned i = 0; i <= iLimit; i++) { + for (unsigned i = 0; i < iLimit; i++) { // scan between boundaries // accumulate weighted effect of each neighboring pixel const double weight = weightsTable.getWeight(x, i); @@ -951,7 +957,7 @@ void CResizeEngine::horizontalFilter(FIBITMAP *const src, unsigned height, unsig double r = 0, g = 0, b = 0; // for(i = iLeft to iRight) - for (unsigned i = 0; i <= iLimit; i++) { + for (unsigned i = 0; i < iLimit; i++) { // scan between boundaries // accumulate weighted effect of each neighboring pixel const double weight = weightsTable.getWeight(x, i); @@ -989,7 +995,7 @@ void CResizeEngine::horizontalFilter(FIBITMAP *const src, unsigned height, unsig double r = 0, g = 0, b = 0; // for(i = iLeft to iRight) - for (unsigned i = 0; i <= iLimit; i++) { + for (unsigned i = 0; i < iLimit; i++) { // scan between boundaries // accumulate weighted effect of each neighboring pixel const double weight = weightsTable.getWeight(x, i); @@ -1026,7 +1032,7 @@ void CResizeEngine::horizontalFilter(FIBITMAP *const src, unsigned height, unsig double r = 0, g = 0, b = 0, a = 0; // for(i = iLeft to iRight) - for (unsigned i = 0; i <= iLimit; i++) { + for (unsigned i = 0; i < iLimit; i++) { // scan between boundaries // accumulate weighted effect of each neighboring pixel const double weight = weightsTable.getWeight(x, i); @@ -1069,7 +1075,7 @@ void CResizeEngine::horizontalFilter(FIBITMAP *const src, unsigned height, unsig double value = 0; // for(i = iLeft to iRight) - for (unsigned i = 0; i <= iLimit; i++) { + for (unsigned i = 0; i < iLimit; i++) { // scan between boundaries // accumulate weighted effect of each neighboring pixel const double weight = weightsTable.getWeight(x, i); @@ -1103,7 +1109,7 @@ void CResizeEngine::horizontalFilter(FIBITMAP *const src, unsigned height, unsig double r = 0, g = 0, b = 0; // for(i = iLeft to iRight) - for (unsigned i = 0; i <= iLimit; i++) { + for (unsigned i = 0; i < iLimit; i++) { // scan between boundaries // accumulate weighted effect of each neighboring pixel const double weight = weightsTable.getWeight(x, i); @@ -1141,7 +1147,7 @@ void CResizeEngine::horizontalFilter(FIBITMAP *const src, unsigned height, unsig double r = 0, g = 0, b = 0, a = 0; // for(i = iLeft to iRight) - for (unsigned i = 0; i <= iLimit; i++) { + for (unsigned i = 0; i < iLimit; i++) { // scan between boundaries // accumulate weighted effect of each neighboring pixel const double weight = weightsTable.getWeight(x, i); @@ -1181,7 +1187,7 @@ void CResizeEngine::horizontalFilter(FIBITMAP *const src, unsigned height, unsig const unsigned iRight = weightsTable.getRightBoundary(x); // retrieve right boundary double value[4] = {0, 0, 0, 0}; // 4 = 128 bpp max - for(unsigned i = iLeft; i <= iRight; i++) { + for(unsigned i = iLeft; i < iRight; i++) { // scan between boundaries // accumulate weighted effect of each neighboring pixel const double weight = weightsTable.getWeight(x, i-iLeft); @@ -1246,7 +1252,7 @@ void CResizeEngine::verticalFilter(FIBITMAP *const src, unsigned width, unsigned const BYTE *src_bits = src_base + iLeft * src_pitch + index; double value = 0; - for (unsigned i = 0; i <= iLimit; i++) { + for (unsigned i = 0; i < iLimit; i++) { // scan between boundaries // accumulate weighted effect of each neighboring pixel const unsigned pixel = (*src_bits & mask) != 0; @@ -1277,7 +1283,7 @@ void CResizeEngine::verticalFilter(FIBITMAP *const src, unsigned width, unsigned const BYTE *src_bits = src_base + iLeft * src_pitch + index; double value = 0; - for (unsigned i = 0; i <= iLimit; i++) { + for (unsigned i = 0; i < iLimit; i++) { // scan between boundaries // accumulate weighted effect of each neighboring pixel value += (weightsTable.getWeight(y, i) @@ -1313,7 +1319,7 @@ void CResizeEngine::verticalFilter(FIBITMAP *const src, unsigned width, unsigned const BYTE *src_bits = src_base + iLeft * src_pitch + index; double r = 0, g = 0, b = 0; - for (unsigned i = 0; i <= iLimit; i++) { + for (unsigned i = 0; i < iLimit; i++) { // scan between boundaries // accumulate weighted effect of each neighboring pixel const double weight = weightsTable.getWeight(y, i); @@ -1353,7 +1359,7 @@ void CResizeEngine::verticalFilter(FIBITMAP *const src, unsigned width, unsigned const BYTE *src_bits = src_base + iLeft * src_pitch + index; double r = 0, g = 0, b = 0, a = 0; - for (unsigned i = 0; i <= iLimit; i++) { + for (unsigned i = 0; i < iLimit; i++) { // scan between boundaries // accumulate weighted effect of each neighboring pixel const double weight = weightsTable.getWeight(y, i); @@ -1403,7 +1409,7 @@ void CResizeEngine::verticalFilter(FIBITMAP *const src, unsigned width, unsigned const BYTE *src_bits = src_base + iLeft * src_pitch + index; double value = 0; - for (unsigned i = 0; i <= iLimit; i++) { + for (unsigned i = 0; i < iLimit; i++) { // scan between boundaries // accumulate weighted effect of each neighboring pixel const unsigned pixel = x & 0x01 ? *src_bits & 0x0F : *src_bits >> 4; @@ -1437,7 +1443,7 @@ void CResizeEngine::verticalFilter(FIBITMAP *const src, unsigned width, unsigned const BYTE *src_bits = src_base + iLeft * src_pitch + index; double r = 0, g = 0, b = 0; - for (unsigned i = 0; i <= iLimit; i++) { + for (unsigned i = 0; i < iLimit; i++) { // scan between boundaries // accumulate weighted effect of each neighboring pixel const double weight = weightsTable.getWeight(y, i); @@ -1476,7 +1482,7 @@ void CResizeEngine::verticalFilter(FIBITMAP *const src, unsigned width, unsigned const BYTE *src_bits = src_base + iLeft * src_pitch + index; double r = 0, g = 0, b = 0, a = 0; - for (unsigned i = 0; i <= iLimit; i++) { + for (unsigned i = 0; i < iLimit; i++) { // scan between boundaries // accumulate weighted effect of each neighboring pixel const double weight = weightsTable.getWeight(y, i); @@ -1527,7 +1533,7 @@ void CResizeEngine::verticalFilter(FIBITMAP *const src, unsigned width, unsigned const BYTE *src_bits = src_base + iLeft * src_pitch + x; double value = 0; - for (unsigned i = 0; i <= iLimit; i++) { + for (unsigned i = 0; i < iLimit; i++) { // scan between boundaries // accumulate weighted effect of each neighboring pixel value += (weightsTable.getWeight(y, i) @@ -1554,7 +1560,7 @@ void CResizeEngine::verticalFilter(FIBITMAP *const src, unsigned width, unsigned const BYTE *src_bits = src_base + iLeft * src_pitch + x; double value = 0; - for (unsigned i = 0; i <= iLimit; i++) { + for (unsigned i = 0; i < iLimit; i++) { // scan between boundaries // accumulate weighted effect of each neighboring pixel value += (weightsTable.getWeight(y, i) @@ -1587,7 +1593,7 @@ void CResizeEngine::verticalFilter(FIBITMAP *const src, unsigned width, unsigned const BYTE *src_bits = src_base + iLeft * src_pitch + x; double r = 0, g = 0, b = 0; - for (unsigned i = 0; i <= iLimit; i++) { + for (unsigned i = 0; i < iLimit; i++) { // scan between boundaries // accumulate weighted effect of each neighboring pixel const double weight = weightsTable.getWeight(y, i); @@ -1624,7 +1630,7 @@ void CResizeEngine::verticalFilter(FIBITMAP *const src, unsigned width, unsigned const BYTE *src_bits = src_base + iLeft * src_pitch + x; double r = 0, g = 0, b = 0, a = 0; - for (unsigned i = 0; i <= iLimit; i++) { + for (unsigned i = 0; i < iLimit; i++) { // scan between boundaries // accumulate weighted effect of each neighboring pixel const double weight = weightsTable.getWeight(y, i); @@ -1671,7 +1677,7 @@ void CResizeEngine::verticalFilter(FIBITMAP *const src, unsigned width, unsigned const WORD *src_bits = src_base + iLeft * src_pitch + x; double r = 0, g = 0, b = 0; - for (unsigned i = 0; i <= iLimit; i++) { + for (unsigned i = 0; i < iLimit; i++) { // scan between boundaries // accumulate weighted effect of each neighboring pixel const double weight = weightsTable.getWeight(y, i); @@ -1702,7 +1708,7 @@ void CResizeEngine::verticalFilter(FIBITMAP *const src, unsigned width, unsigned const WORD *src_bits = src_base + iLeft * src_pitch + x; double r = 0, g = 0, b = 0; - for (unsigned i = 0; i <= iLimit; i++) { + for (unsigned i = 0; i < iLimit; i++) { // scan between boundaries // accumulate weighted effect of each neighboring pixel const double weight = weightsTable.getWeight(y, i); @@ -1743,7 +1749,7 @@ void CResizeEngine::verticalFilter(FIBITMAP *const src, unsigned width, unsigned const BYTE *src_bits = src_base + iLeft * src_pitch + index; double r = 0, g = 0, b = 0; - for (unsigned i = 0; i <= iLimit; i++) { + for (unsigned i = 0; i < iLimit; i++) { // scan between boundaries // accumulate weighted effect of each neighboring pixel const double weight = weightsTable.getWeight(y, i); @@ -1783,7 +1789,7 @@ void CResizeEngine::verticalFilter(FIBITMAP *const src, unsigned width, unsigned const BYTE *src_bits = src_base + iLeft * src_pitch + index; double r = 0, g = 0, b = 0, a = 0; - for (unsigned i = 0; i <= iLimit; i++) { + for (unsigned i = 0; i < iLimit; i++) { // scan between boundaries // accumulate weighted effect of each neighboring pixel const double weight = weightsTable.getWeight(y, i); @@ -1832,7 +1838,7 @@ void CResizeEngine::verticalFilter(FIBITMAP *const src, unsigned width, unsigned const WORD *src_bits = src_base + iLeft * src_pitch + index; double value = 0; - for (unsigned i = 0; i <= iLimit; i++) { + for (unsigned i = 0; i < iLimit; i++) { // scan between boundaries // accumulate weighted effect of each neighboring pixel const double weight = weightsTable.getWeight(y, i); @@ -1873,7 +1879,7 @@ void CResizeEngine::verticalFilter(FIBITMAP *const src, unsigned width, unsigned const WORD *src_bits = src_base + iLeft * src_pitch + index; double r = 0, g = 0, b = 0; - for (unsigned i = 0; i <= iLimit; i++) { + for (unsigned i = 0; i < iLimit; i++) { // scan between boundaries // accumulate weighted effect of each neighboring pixel const double weight = weightsTable.getWeight(y, i); @@ -1919,7 +1925,7 @@ void CResizeEngine::verticalFilter(FIBITMAP *const src, unsigned width, unsigned const WORD *src_bits = src_base + iLeft * src_pitch + index; double r = 0, g = 0, b = 0, a = 0; - for (unsigned i = 0; i <= iLimit; i++) { + for (unsigned i = 0; i < iLimit; i++) { // scan between boundaries // accumulate weighted effect of each neighboring pixel const double weight = weightsTable.getWeight(y, i); @@ -1969,7 +1975,7 @@ void CResizeEngine::verticalFilter(FIBITMAP *const src, unsigned width, unsigned const float *src_bits = src_base + iLeft * src_pitch + index; double value[4] = {0, 0, 0, 0}; // 4 = 128 bpp max - for (unsigned i = iLeft; i <= iRight; i++) { + for (unsigned i = iLeft; i < iRight; i++) { // scan between boundaries // accumulate weighted effect of each neighboring pixel const double weight = weightsTable.getWeight(y, i - iLeft); diff --git a/plugins/AdvaImg/src/FreeImageToolkit/Resize.h b/plugins/AdvaImg/src/FreeImageToolkit/Resize.h index 7fe1cdb112..ca382efa60 100644 --- a/plugins/AdvaImg/src/FreeImageToolkit/Resize.h +++ b/plugins/AdvaImg/src/FreeImageToolkit/Resize.h @@ -163,14 +163,15 @@ private: /** Performs horizontal image filtering - @param src - @param height - @param src_width + + @param src Source image + @param height Source / Destination image height + @param src_width Source image width @param src_offset_x @param src_offset_y @param src_pal - @param dst - @param dst_width + @param dst Destination image + @param dst_width Destination image width */ void horizontalFilter(FIBITMAP * const src, const unsigned height, const unsigned src_width, const unsigned src_offset_x, const unsigned src_offset_y, const RGBQUAD * const src_pal, @@ -178,14 +179,14 @@ private: /** Performs vertical image filtering - @param src - @param width - @param src_height + @param src Source image + @param width Source / Destination image width + @param src_height Source image height @param src_offset_x @param src_offset_y @param src_pal - @param dst - @param dst_height + @param dst Destination image + @param dst_height Destination image height */ void verticalFilter(FIBITMAP * const src, const unsigned width, const unsigned src_height, const unsigned src_offset_x, const unsigned src_offset_y, const RGBQUAD * const src_pal, -- cgit v1.2.3