diff --git a/src/data/field/symbol.cpp b/src/data/field/symbol.cpp index e627fdd6..c2ffe774 100644 --- a/src/data/field/symbol.cpp +++ b/src/data/field/symbol.cpp @@ -34,6 +34,12 @@ SymbolVariation::SymbolVariation() {} SymbolVariation::~SymbolVariation() {} +bool SymbolVariation::operator == (const SymbolVariation& that) const { + return name == that.name + && border_radius == that.border_radius + && *filter == *that.filter; +} + IMPLEMENT_REFLECTION_NO_SCRIPT(SymbolVariation) { REFLECT(name); REFLECT(border_radius); diff --git a/src/data/field/symbol.hpp b/src/data/field/symbol.hpp index 370e4dd2..4d37001e 100644 --- a/src/data/field/symbol.hpp +++ b/src/data/field/symbol.hpp @@ -54,6 +54,9 @@ class SymbolVariation : public IntrusivePtrBase { String name; ///< Name of this variation SymbolFilterP filter; ///< Filter to color the symbol double border_radius; ///< Border radius for the symbol + + bool operator == (const SymbolVariation&) const; + DECLARE_REFLECTION(); }; diff --git a/src/gfx/blend_image.cpp b/src/gfx/blend_image.cpp index 28c1dcc1..9c5e5a4d 100644 --- a/src/gfx/blend_image.cpp +++ b/src/gfx/blend_image.cpp @@ -86,3 +86,13 @@ void set_alpha(Image& img, const Image& img_alpha) { im[i] = (im[i] * al[i*3]) / 255; } } + +void set_alpha(Image& img, double alpha) { + if (!img.HasAlpha()) img.InitAlpha(); + Byte b_alpha = alpha * 255; + Byte *im = img.GetAlpha(); + UInt size = img.GetWidth() * img.GetHeight(); + for (UInt i = 0 ; i < size ; ++i) { + im[i] = (im[i] * b_alpha) / 255; + } +} diff --git a/src/gfx/generated_image.cpp b/src/gfx/generated_image.cpp index 9cdfcb45..62958d77 100644 --- a/src/gfx/generated_image.cpp +++ b/src/gfx/generated_image.cpp @@ -152,6 +152,20 @@ bool SetMaskImage::operator == (const GeneratedImage& that) const { && *mask == *that2->mask; } +Image SetAlphaImage::generate(const Options& opt) const { + Image img = image->generate(opt); + set_alpha(img, alpha); + return img; +} +ImageCombine SetAlphaImage::combine() const { + return image->combine(); +} +bool SetAlphaImage::operator == (const GeneratedImage& that) const { + const SetAlphaImage* that2 = dynamic_cast(&that); + return that2 && *image == *that2->image + && alpha == that2->alpha; +} + // ----------------------------------------------------------------------------- : SetCombineImage Image SetCombineImage::generate(const Options& opt) const { @@ -166,6 +180,146 @@ bool SetCombineImage::operator == (const GeneratedImage& that) const { && image_combine == that2->image_combine; } +// ----------------------------------------------------------------------------- : EnlargeImage + +Image EnlargeImage::generate(const Options& opt) const { + // generate 'sub' image + Options sub_opt + ( opt.width * (border_size < 0.5 ? 1 - 2 * border_size : 0) + , opt.height * (border_size < 0.5 ? 1 - 2 * border_size : 0) + , opt.package + , opt.local_package + , opt.preserve_aspect); + Image img = image->generate(sub_opt); + // size of generated image + int w = img.GetWidth(), h = img.GetHeight(); // original image size + int dw = w * border_size, dh = h * border_size; // delta + int w2 = w + dw + dw, h2 = h + dh + dh; // new image size + Image larger(w2,h2); + larger.InitAlpha(); + memset(larger.GetAlpha(),0,w2*h2); // blank + // copy to sub-part of larger image + Byte* data1 = img.GetData(), *data2 = larger.GetData(); + for (int y = 0 ; y < h ; ++y) { + memcpy(data2 + 3*(dw + (y+dh)*w2), data1 + 3*y*w, 3*w); // copy a line + } + if (img.HasAlpha()) { + data1 = img.GetAlpha(), data2 = larger.GetAlpha(); + for (int y = 0 ; y < h ; ++y) { + memcpy(data2 + dw + (y+dh)*w2, data1 + y*w, w); // copy a line + } + } + // done + return larger; +} +ImageCombine EnlargeImage::combine() const { + return image->combine(); +} +bool EnlargeImage::operator == (const GeneratedImage& that) const { + const EnlargeImage* that2 = dynamic_cast(&that); + return that2 && *image == *that2->image + && border_size == that2->border_size; +} + +// ----------------------------------------------------------------------------- : DropShadowImage + +/// Preform a gaussian blur, from the image in of w*h bytes to out +/** out is scaled some scaling, this is the return value */ +UInt gaussian_blur(Byte* in, UInt* out, int w, int h, double radius) { + // blur horizontally + UInt* blur_x = new UInt[w*h]; // scaled by total_x, so in [0..255*total_x] + memset(blur_x, 0, w*h*sizeof(UInt)); + UInt total_x = 0; + { + double sigma = radius * w; + double mult = (1 << 8) / (sqrt(2 * M_PI) * sigma); + double sigsqr2 = 1 / (2 * sigma * sigma); + int range = min(w, (int)(3*sigma)); + for (int d = -range ; d <= range ; ++d) { + UInt factor = (int)( mult * exp(-d * d * sigsqr2) ); + total_x += factor; + if (factor > 0) { + int x_start = max(0, -d), x_end = min(w, w-d); + for (int y = 0 ; y < h ; ++y) { + for (int x = x_start ; x < x_end ; ++x) { + blur_x[x + y*w] += in[x + d + y*w] * factor; + } + } + } + } + } + // blur vertically + memset(out, 0, w*h*sizeof(UInt)); + UInt total_y = 0; + { + double sigma = radius * h; + double mult = (1 << 8) / (sqrt(2 * M_PI) * sigma); + double sigsqr2 = 1 / (2 * sigma * sigma); + int range = min(h, (int)(3*sigma)); + for (int d = -range ; d <= range ; ++d) { + UInt factor = (UInt)( mult * exp(-d * d * sigsqr2) ); + total_y += factor; + if (factor > 0) { + int y_start = max(0, -d), y_end = min(h, h-d); + for (int y = y_start ; y < y_end ; ++y) { + for (int x = 0 ; x < w ; ++x) { + out[x + y*w] += blur_x[x + (d + y)*w] * factor; + } + } + } + } + } + delete[] blur_x; + return total_x * total_y; +} + +Image DropShadowImage::generate(const Options& opt) const { + // sub image + Image img = image->generate(opt); + if (!img.HasAlpha()) { + // no alpha, there is nothing we can do + return img; + } + int w = img.GetWidth(), h = img.GetHeight(); + Byte* alpha = img.GetAlpha(); + // blur + UInt* shadow = new UInt[w*h]; + UInt total = 255 * gaussian_blur(alpha, shadow, w, h, shadow_blur_radius); + // combine + Byte* data = img.GetData(); + int dw = w * offset_x, dh = h * offset_y; + int x_start = max(0, dw), y_start = max(0, dh); + int x_end = min(w, w+dw), y_end = min(h, h+dh); + int delta = dw + w * dh; + int sa = (int)(shadow_alpha * (1 << 16)); + for (int y = y_start ; y < y_end ; ++y) { + for (int x = x_start ; x < x_end ; ++x) { + int p = x + y * w; // pixel we are working on + int a = alpha[p]; + int shad = ((((255 - a)*sa)>>16) * shadow[p - delta]) / total; // amount of shadow to add + int factor = max(1, a + shad); // divide by this + data[3 * p ] = (a * data[3 * p ] + shad * shadow_color.Red() ) / factor; + data[3 * p + 1] = (a * data[3 * p + 1] + shad * shadow_color.Green()) / factor; + data[3 * p + 2] = (a * data[3 * p + 2] + shad * shadow_color.Blue() ) / factor; + alpha[p] = a + shad; + } + } + //memset(data,0,3*w*h); + // cleanup + delete[] shadow; + return img; +} +ImageCombine DropShadowImage::combine() const { + return image->combine(); +} +bool DropShadowImage::operator == (const GeneratedImage& that) const { + const DropShadowImage* that2 = dynamic_cast(&that); + return that2 && *image == *that2->image + && offset_x == that2->offset_x && offset_y == that2->offset_y + && shadow_alpha == that2->shadow_alpha && shadow_blur_radius == that2->shadow_blur_radius + && shadow_color == that2->shadow_color; +} + // ----------------------------------------------------------------------------- : PackagedImage Image PackagedImage::generate(const Options& opt) const { @@ -223,7 +377,9 @@ bool SymbolToImage::operator == (const GeneratedImage& that) const { const SymbolToImage* that2 = dynamic_cast(&that); return that2 && filename == that2->filename && age == that2->age - && variation == that2->variation; + && (variation == that2->variation || + *variation == *that2->variation // custom variation + ); } // ----------------------------------------------------------------------------- : ImageValueToImage diff --git a/src/gfx/generated_image.hpp b/src/gfx/generated_image.hpp index faa82257..7836d1e1 100644 --- a/src/gfx/generated_image.hpp +++ b/src/gfx/generated_image.hpp @@ -129,6 +129,20 @@ class SetMaskImage : public GeneratedImage { GeneratedImageP image, mask; }; +/// Change the alpha channel of an image +class SetAlphaImage : public GeneratedImage { + public: + inline SetAlphaImage(const GeneratedImageP& image, double alpha) + : image(image), alpha(alpha) + {} + virtual Image generate(const Options& opt) const; + virtual ImageCombine combine() const; + virtual bool operator == (const GeneratedImage& that) const; + private: + GeneratedImageP image; + double alpha; +}; + // ----------------------------------------------------------------------------- : SetCombineImage /// Change the combine mode @@ -145,6 +159,42 @@ class SetCombineImage : public GeneratedImage { ImageCombine image_combine; }; +// ----------------------------------------------------------------------------- : EnlargeImage + +/// Enlarge an image by adding a border around it +class EnlargeImage : public GeneratedImage { + public: + inline EnlargeImage(const GeneratedImageP& image, double border_size) + : image(image), border_size(abs(border_size)) + {} + virtual Image generate(const Options& opt) const; + virtual ImageCombine combine() const; + virtual bool operator == (const GeneratedImage& that) const; + private: + GeneratedImageP image; + double border_size; +}; + +// ----------------------------------------------------------------------------- : DropShadowImage + +/// Add a drop shadow to an image +class DropShadowImage : public GeneratedImage { + public: + inline DropShadowImage(const GeneratedImageP& image, double offset_x, double offset_y, double shadow_alpha, double shadow_blur_radius, Color shadow_color) + : image(image), offset_x(offset_x), offset_y(offset_y) + , shadow_alpha(shadow_alpha), shadow_blur_radius(shadow_blur_radius), shadow_color(shadow_color) + {} + virtual Image generate(const Options& opt) const; + virtual ImageCombine combine() const; + virtual bool operator == (const GeneratedImage& that) const; + private: + GeneratedImageP image; + double offset_x, offset_y; + double shadow_alpha; + double shadow_blur_radius; + Color shadow_color; +}; + // ----------------------------------------------------------------------------- : PackagedImage /// Load an image from a file in a package diff --git a/src/gfx/gfx.hpp b/src/gfx/gfx.hpp index 1977c878..157a8018 100644 --- a/src/gfx/gfx.hpp +++ b/src/gfx/gfx.hpp @@ -123,6 +123,8 @@ void draw_combine_image(DC& dc, UInt x, UInt y, const Image& img, ImageCombine c /// Use the red channel of img_alpha as alpha channel for img void set_alpha(Image& img, const Image& img_alpha); +/// Set the transparency of img +void set_alpha(Image& img, double alpha); /// An alpha mask is an alpha channel that can be copied to another image /** It is created by treating black in the source image as transparent and white (red) as opaque diff --git a/src/render/symbol/filter.cpp b/src/render/symbol/filter.cpp index 25628eb6..1c065f4e 100644 --- a/src/render/symbol/filter.cpp +++ b/src/render/symbol/filter.cpp @@ -86,6 +86,12 @@ AColor SolidFillSymbolFilter::color(double x, double y, SymbolSet point) const { else return AColor(0,0,0,0); } +bool SolidFillSymbolFilter::operator == (const SymbolFilter& that) const { + const SolidFillSymbolFilter* that2 = dynamic_cast(&that); + return that2 && fill_color == that2->fill_color + && border_color == that2->border_color; +} + IMPLEMENT_REFLECTION(SolidFillSymbolFilter) { REFLECT_BASE(SymbolFilter); REFLECT(fill_color); @@ -101,6 +107,13 @@ AColor GradientSymbolFilter::color(double x, double y, SymbolSet point, const T* else return AColor(0,0,0,0); } +bool GradientSymbolFilter::equal(const GradientSymbolFilter& that) const { + return fill_color_1 == that.fill_color_1 + && fill_color_2 == that.fill_color_2 + && border_color_1 == that.border_color_1 + && border_color_2 == that.border_color_2; +} + IMPLEMENT_REFLECTION(GradientSymbolFilter) { REFLECT_BASE(SymbolFilter); REFLECT(fill_color_1); @@ -120,6 +133,14 @@ LinearGradientSymbolFilter::LinearGradientSymbolFilter() : center_x(0.5), center_y(0.5) , end_x(1), end_y(1) {} +LinearGradientSymbolFilter::LinearGradientSymbolFilter + ( const Color& fill_color_1, const Color& border_color_1 + , const Color& fill_color_2, const Color& border_color_2 + , double center_x, double center_y, double end_x, double end_y) + : GradientSymbolFilter(fill_color_1, border_color_1, fill_color_2, border_color_2) + , center_x(center_x), center_y(center_y) + , end_x(end_x), end_y(end_y) +{} AColor LinearGradientSymbolFilter::color(double x, double y, SymbolSet point) const { len = sqr(end_x - center_x) + sqr(end_y - center_y); @@ -132,6 +153,13 @@ double LinearGradientSymbolFilter::t(double x, double y) const { return min(1.,max(0.,t)); } +bool LinearGradientSymbolFilter::operator == (const SymbolFilter& that) const { + const LinearGradientSymbolFilter* that2 = dynamic_cast(&that); + return that2 && equal(*that2) + && center_x == that2->center_x && end_x == that2->end_x + && center_y == that2->center_y && end_y == that2->end_y; +} + IMPLEMENT_REFLECTION(LinearGradientSymbolFilter) { REFLECT_BASE(GradientSymbolFilter); REFLECT(center_x); REFLECT(center_y); @@ -149,3 +177,8 @@ AColor RadialGradientSymbolFilter::color(double x, double y, SymbolSet point) co double RadialGradientSymbolFilter::t(double x, double y) const { return sqrt( (sqr(x - 0.5) + sqr(y - 0.5)) * 2); } + +bool RadialGradientSymbolFilter::operator == (const SymbolFilter& that) const { + const RadialGradientSymbolFilter* that2 = dynamic_cast(&that); + return that2 && equal(*that2); +} diff --git a/src/render/symbol/filter.hpp b/src/render/symbol/filter.hpp index 1168fb1a..d0ba0fda 100644 --- a/src/render/symbol/filter.hpp +++ b/src/render/symbol/filter.hpp @@ -54,6 +54,8 @@ class SymbolFilter : public IntrusivePtrVirtualBase { virtual AColor color(double x, double y, SymbolSet point) const = 0; /// Name of this fill type virtual String fillType() const = 0; + /// Comparision + virtual bool operator == (const SymbolFilter& that) const = 0; DECLARE_REFLECTION_VIRTUAL(); }; @@ -66,8 +68,13 @@ intrusive_ptr read_new(Reader& reader); /// Symbol filter that returns solid colors class SolidFillSymbolFilter : public SymbolFilter { public: + inline SolidFillSymbolFilter() {} + inline SolidFillSymbolFilter(Color fill_color, Color border_color) + : fill_color(fill_color), border_color(border_color) + {} virtual AColor color(double x, double y, SymbolSet point) const; virtual String fillType() const; + virtual bool operator == (const SymbolFilter& that) const; private: Color fill_color, border_color; DECLARE_REFLECTION(); @@ -75,11 +82,18 @@ class SolidFillSymbolFilter : public SymbolFilter { /// Symbol filter that returns some gradient class GradientSymbolFilter : public SymbolFilter { + public: + inline GradientSymbolFilter() {} + inline GradientSymbolFilter(const Color& fill_color_1, const Color& border_color_1, const Color& fill_color_2, const Color& border_color_2) + : fill_color_1(fill_color_1), border_color_1(border_color_1) + , fill_color_2(fill_color_2), border_color_2(border_color_2) + {} protected: Color fill_color_1, border_color_1; Color fill_color_2, border_color_2; template AColor color(double x, double y, SymbolSet point, const T* t) const; + bool equal(const GradientSymbolFilter& that) const; DECLARE_REFLECTION(); }; @@ -88,9 +102,12 @@ class GradientSymbolFilter : public SymbolFilter { class LinearGradientSymbolFilter : public GradientSymbolFilter { public: LinearGradientSymbolFilter(); + LinearGradientSymbolFilter(const Color& fill_color_1, const Color& border_color_1, const Color& fill_color_2, const Color& border_color_2 + ,double center_x, double center_y, double end_x, double end_y); virtual AColor color(double x, double y, SymbolSet point) const; virtual String fillType() const; + virtual bool operator == (const SymbolFilter& that) const; /// return time on the gradient, used by GradientSymbolFilter::color inline double t(double x, double y) const; @@ -105,8 +122,14 @@ class LinearGradientSymbolFilter : public GradientSymbolFilter { /// Symbol filter that returns a radial gradient class RadialGradientSymbolFilter : public GradientSymbolFilter { public: + inline RadialGradientSymbolFilter() {} + inline RadialGradientSymbolFilter(const Color& fill_color_1, const Color& border_color_1, const Color& fill_color_2, const Color& border_color_2) + : GradientSymbolFilter(fill_color_1, border_color_1, fill_color_2, border_color_2) + {} + virtual AColor color(double x, double y, SymbolSet point) const; virtual String fillType() const; + virtual bool operator == (const SymbolFilter& that) const; /// return time on the gradient, used by GradientSymbolFilter::color inline double t(double x, double y) const; diff --git a/src/render/symbol/viewer.cpp b/src/render/symbol/viewer.cpp index d2fe343b..e784b7d9 100644 --- a/src/render/symbol/viewer.cpp +++ b/src/render/symbol/viewer.cpp @@ -180,7 +180,7 @@ void SymbolViewer::drawSymbolPart(const SymbolPart& part, DC* border, DC* interi segment_subdivide(*part.getPoint((int)i), *part.getPoint((int)i+1), rotation, points); } // draw border - if (border) { + if (border && border_radius > 0) { // white/black or, if directB white/green border->SetBrush(Color(borderCol, (directB && borderCol == 0 ? 128 : borderCol), borderCol)); border->SetPen(wxPen(*wxWHITE, (int) rotation.trS(border_radius))); diff --git a/src/script/functions/image.cpp b/src/script/functions/image.cpp index 6739ae66..ae02b1ba 100644 --- a/src/script/functions/image.cpp +++ b/src/script/functions/image.cpp @@ -16,6 +16,7 @@ #include #include #include +#include DECLARE_TYPEOF_COLLECTION(SymbolVariationP); @@ -61,6 +62,12 @@ SCRIPT_FUNCTION(set_mask) { return new_intrusive2(image, mask); } +SCRIPT_FUNCTION(set_alpha) { + SCRIPT_PARAM(GeneratedImageP, input); + SCRIPT_PARAM(double, alpha); + return new_intrusive2(input, alpha); +} + SCRIPT_FUNCTION(set_combine) { SCRIPT_PARAM(String, combine); SCRIPT_PARAM(GeneratedImageP, input); @@ -71,24 +78,72 @@ SCRIPT_FUNCTION(set_combine) { return new_intrusive2(input, image_combine); } +SCRIPT_FUNCTION(enlarge) { + SCRIPT_PARAM(GeneratedImageP, input); + SCRIPT_PARAM_N(double, _("border size"), border_size); + return new_intrusive2(input, border_size); +} + +SCRIPT_FUNCTION(drop_shadow) { + SCRIPT_PARAM(GeneratedImageP, input); + SCRIPT_OPTIONAL_PARAM_N_(double, _("offset x"), offset_x); + SCRIPT_OPTIONAL_PARAM_N_(double, _("offset y"), offset_y); + SCRIPT_OPTIONAL_PARAM_N_(double, _("alpha"), alpha); + SCRIPT_OPTIONAL_PARAM_N_(double, _("blur radius"), blur_radius); + SCRIPT_OPTIONAL_PARAM_N_(Color, _("color"), color); + return new_intrusive6(input, offset_x, offset_y, alpha, blur_radius, color); +} + SCRIPT_FUNCTION(symbol_variation) { // find symbol SCRIPT_PARAM(ValueP, symbol); SymbolValueP value = dynamic_pointer_cast(symbol); - SCRIPT_PARAM(String, variation); - // find style - SCRIPT_PARAM(Set*, set); - SCRIPT_OPTIONAL_PARAM_(CardP, card); - SymbolStyleP style = dynamic_pointer_cast(set->stylesheetForP(card)->styleFor(value->fieldP)); - if (!style) throw InternalError(_("Symbol value has a style of the wrong type")); - // find variation - FOR_EACH(v, style->variations) { - if (v->name == variation) { - // found it - return new_intrusive3(value->filename, value->last_update, v); + SCRIPT_OPTIONAL_PARAM(String, variation) { + // find style + SCRIPT_PARAM(Set*, set); + SCRIPT_OPTIONAL_PARAM_(CardP, card); + SymbolStyleP style = dynamic_pointer_cast(set->stylesheetForP(card)->styleFor(value->fieldP)); + if (!style) throw InternalError(_("Symbol value has a style of the wrong type")); + // find variation + FOR_EACH(v, style->variations) { + if (v->name == variation) { + // found it + return new_intrusive3(value->filename, value->last_update, v); + } } + throw ScriptError(_("Variation of symbol not found ('") + variation + _("')")); + } else { + // custom variation + SCRIPT_PARAM_N(double, _("border radius"), border_radius); + SCRIPT_OPTIONAL_PARAM_N_(String, _("fill type"), fill_type); + SymbolVariationP var(new SymbolVariation); + var->border_radius = border_radius; + if (fill_type == _("solid") || fill_type.empty()) { + SCRIPT_PARAM_N(Color, _("fill color"), fill_color); + SCRIPT_PARAM_N(Color, _("border color"), border_color); + var->filter = new_intrusive2(fill_color, border_color); + } else if (fill_type == _("linear gradient")) { + SCRIPT_PARAM_N(Color, _("fill color 1"), fill_color_1); + SCRIPT_PARAM_N(Color, _("border color 1"), border_color_1); + SCRIPT_PARAM_N(Color, _("fill color 2"), fill_color_2); + SCRIPT_PARAM_N(Color, _("border color 2"), border_color_2); + SCRIPT_PARAM_N(double, _("center x"), center_x); + SCRIPT_PARAM_N(double, _("center y"), center_y); + SCRIPT_PARAM_N(double, _("end x"), end_x); + SCRIPT_PARAM_N(double, _("end y"), end_y); + var->filter = new_intrusive8(fill_color_1, border_color_1, fill_color_2, border_color_2 + ,center_x, center_y, end_x, end_y); + } else if (fill_type == _("radial gradient")) { + SCRIPT_PARAM_N(Color, _("fill color 1"), fill_color_1); + SCRIPT_PARAM_N(Color, _("border color 1"), border_color_1); + SCRIPT_PARAM_N(Color, _("fill color 2"), fill_color_2); + SCRIPT_PARAM_N(Color, _("border color 2"), border_color_2); + var->filter = new_intrusive4(fill_color_1, border_color_1, fill_color_2, border_color_2); + } else { + throw ScriptError(_("Unknown fill type for symbol_variation: ") + fill_type); + } + return new_intrusive3(value->filename, value->last_update, var); } - throw ScriptError(_("Variation of symbol not found ('") + variation + _("')")); } SCRIPT_FUNCTION(built_in_image) { @@ -103,7 +158,10 @@ void init_script_image_functions(Context& ctx) { ctx.setVariable(_("masked blend"), script_masked_blend); ctx.setVariable(_("combine blend"), script_combine_blend); ctx.setVariable(_("set mask"), script_set_mask); + ctx.setVariable(_("set alpha"), script_set_alpha); ctx.setVariable(_("set combine"), script_set_combine); + ctx.setVariable(_("enlarge"), script_enlarge); + ctx.setVariable(_("drop shadow"), script_drop_shadow); ctx.setVariable(_("symbol variation"), script_symbol_variation); ctx.setVariable(_("built in image"), script_built_in_image); } diff --git a/src/script/image.cpp b/src/script/image.cpp index a7ee45d1..c436f656 100644 --- a/src/script/image.cpp +++ b/src/script/image.cpp @@ -42,7 +42,10 @@ GeneratedImageP image_from_script(const ScriptValueP& value) { // ----------------------------------------------------------------------------- : ScriptableImage Image ScriptableImage::generate(const GeneratedImage::Options& options, bool cache) const { - if (cached.Ok() && cached.GetWidth() == options.width && cached.GetHeight() == options.height) { + if (cached.Ok() && (cached.GetWidth() == options.width && cached.GetHeight() == options.height + || (options.preserve_aspect == ASPECT_FIT && // only one dimension has to fit + (cached.GetWidth() == options.width || cached.GetHeight() == options.height) + ))) { // cached, so we are done return cached; } diff --git a/src/script/to_value.hpp b/src/script/to_value.hpp index 6c06d5d0..c5ada01b 100644 --- a/src/script/to_value.hpp +++ b/src/script/to_value.hpp @@ -274,6 +274,7 @@ template <> inline String from_script (const ScriptValueP& va template <> inline int from_script (const ScriptValueP& value) { return *value; } template <> inline double from_script (const ScriptValueP& value) { return *value; } template <> inline bool from_script (const ScriptValueP& value) { return *value; } +template <> inline Color from_script (const ScriptValueP& value) { return *value; } // ----------------------------------------------------------------------------- : EOF #endif