diff --git a/src/gfx/generated_image.cpp b/src/gfx/generated_image.cpp index fb53b56c..3d816ff0 100644 --- a/src/gfx/generated_image.cpp +++ b/src/gfx/generated_image.cpp @@ -34,7 +34,7 @@ Image conform_image(const Image& img, const GeneratedImage::Options& options) { int iw = image.GetWidth(), ih = image.GetHeight(); if ((iw == options.width && ih == options.height) || (options.width == 0 && options.height == 0)) { // zoom? - if (options.zoom != 1.0) { + if (!almost_equal(options.zoom, 1.0)) { image = resample(image, int(iw * options.zoom), int(ih * options.zoom)); } else { // already the right size @@ -73,7 +73,7 @@ Image conform_image(const Image& img, const GeneratedImage::Options& options) { options.width = image.GetWidth(); options.height = image.GetHeight(); // rotate? - if (options.angle != 0) { + if (!almost_equal(options.angle, 0)) { image = rotate_image(image, options.angle); } return image; diff --git a/src/render/value/choice.cpp b/src/render/value/choice.cpp index f863fbe9..641ee9a7 100644 --- a/src/render/value/choice.cpp +++ b/src/render/value/choice.cpp @@ -56,7 +56,7 @@ bool prepare_choice_viewer(RotatedDC& dc, ValueViewer& viewer, ChoiceStyle& styl img.generateCached(img_options, &style.mask, &combine, &bitmap, &image, &size); // store content properties double zoom = dc.getZoom(); - if (style.content_width != size.width / zoom || style.content_height != size.height / zoom) { + if (!almost_equal(style.content_width, size.width / zoom) || !almost_equal(style.content_height, size.height / zoom)) { style.content_width = size.width / zoom; style.content_height = size.height / zoom; return true; diff --git a/src/script/image.cpp b/src/script/image.cpp index 09b83392..2e7bd87a 100644 --- a/src/script/image.cpp +++ b/src/script/image.cpp @@ -104,42 +104,47 @@ void CachedScriptableImage::generateCached(const GeneratedImage::Options& option ImageCombine combine_i = value->combine(); if (combine_i != COMBINE_DEFAULT) *combine = combine_i; *size = cached_size; - // does the size match? - bool w_ok = cached_size.width == options.width, - h_ok = cached_size.height == options.height; + // do the options match? + Radians relative_rotation = options.angle + rad360 - cached_options_angle; + bool ok = almost_equal(cached_options_size.width, options.width) && + almost_equal(cached_options_size.height, options.height) && + almost_equal(cached_options_zoom, options.zoom) && + cached_options_preserve_aspect == options.preserve_aspect && + cached_options_saturate == options.saturate && + is_straight(relative_rotation); // we only need an {0,90,180,270} degree rotation compared to the cached one, this doesn't reduce image quality // image or bitmap? if (*combine <= COMBINE_NORMAL) { // bitmap - if (cached_b.Ok() && options.angle == cached_angle) { - if ((w_ok && h_ok) || (options.preserve_aspect == ASPECT_FIT && (w_ok || h_ok))) { // only one dimension has to fit when fitting - // cached, we are done - *bitmap = cached_b; - return; - } + if (cached_b.Ok() && ok && almost_equal(cached_options_angle, options.angle)) { + // cached, we are done + *bitmap = cached_b; + return; } } else { // image - Radians relative_rotation = options.angle + rad360 - cached_angle; - if (cached_i.Ok() && is_straight(relative_rotation)) { - // we need only an {0,90,180,270} degree rotation compared to the cached one, this doesn't reduce image quality - if ((w_ok && h_ok) || (options.preserve_aspect == ASPECT_FIT && (w_ok || h_ok))) { // only one dimension has to fit when fitting - if (options.angle != cached_angle) { - // rotate cached image - cached_i = rotate_image(cached_i, relative_rotation); - cached_angle = options.angle; - } - *image = cached_i; - return; + if (cached_i.Ok() && ok) { + if (!almost_equal(cached_options_angle, options.angle)) { + // rotate cached image + cached_i = rotate_image(cached_i, relative_rotation); + cached_options_angle = options.angle; } + *image = cached_i; + return; } - } + } + // store the options as they were asked for + cached_options_size = RealSize(options.width, options.height); + cached_options_zoom = options.zoom; + cached_options_preserve_aspect = options.preserve_aspect; + cached_options_saturate = options.saturate; + cached_options_angle = options.angle; // hack(part1): temporarily set angle to 0, do actual rotation after applying mask - Radians a = options.angle; const_cast(options).angle = 0; // generate cached_i = generate(options); assert(cached_i.Ok()); - const_cast(options).angle = cached_angle = a; + const_cast(options).angle = cached_options_angle; + // store the size as it actually is (may have been changed by conform_image() when we generated the image) *size = cached_size = RealSize(options.width, options.height); if (mask) { // apply mask @@ -149,7 +154,7 @@ void CachedScriptableImage::generateCached(const GeneratedImage::Options& option mask_opts.angle = 0; mask->get(mask_opts).setAlpha(cached_i); } - if (options.angle != 0) { + if (!almost_equal(options.angle, 0.0)) { // hack(part2) do the actual rotation now cached_i = rotate_image(cached_i, options.angle); } diff --git a/src/script/image.hpp b/src/script/image.hpp index 652c8945..184239c7 100644 --- a/src/script/image.hpp +++ b/src/script/image.hpp @@ -98,10 +98,15 @@ public: void clearCache(); private: - Image cached_i; ///< The cached image - Bitmap cached_b; ///< *or* the cached bitmap - RealSize cached_size; ///< The size of the image before rotating - Radians cached_angle; + Image cached_i; ///< The cached image + Bitmap cached_b; ///< *or* the cached bitmap + RealSize cached_size; ///< The size of the image before rotating, may be different than the options size + /// The options as they were last specified + RealSize cached_options_size = RealSize(-1.0,-1.0); + double cached_options_zoom; + Radians cached_options_angle; + PreserveAspect cached_options_preserve_aspect; + bool cached_options_saturate; }; // ----------------------------------------------------------------------------- : CachedScriptableMask