ensure image script functions preserve metadata

This commit is contained in:
GenevensiS
2026-01-21 18:33:27 +01:00
parent c42068f918
commit 6b1c7488bf
18 changed files with 365 additions and 181 deletions
+9 -2
View File
@@ -7,6 +7,7 @@
// ----------------------------------------------------------------------------- : Includes
#include <util/prec.hpp>
#include <data/format/image_encoding.hpp>
#include <gfx/gfx.hpp>
#include <util/error.hpp>
@@ -70,7 +71,10 @@ void linear_blend(Image& img1, const Image& img2, double x1,double y1, double x2
alpha2 += 1;
}
}
}
}
//transfer metadata
img1.SetOption(wxIMAGE_OPTION_PNG_DESCRIPTION, metadata_merge(img1, img2));
}
// ----------------------------------------------------------------------------- : Mask Blend
@@ -101,7 +105,10 @@ void mask_blend(Image& img1, const Image& img2, const Image& mask) {
// use mask's red channel to blend alpha (all mask channels should be identical since it's grey scale)
alpha1[i] = (alpha1[i] * dataM[i * 3] + alpha2[i] * (255 - dataM[i * 3])) / 255;
}
}
}
//transfer metadata
img1.SetOption(wxIMAGE_OPTION_PNG_DESCRIPTION, metadata_merge(img1, img2));
}
// ----------------------------------------------------------------------------- : Alpha
+5 -1
View File
@@ -7,6 +7,7 @@
// ----------------------------------------------------------------------------- : Includes
#include <util/prec.hpp>
#include <data/format/image_encoding.hpp>
#include <gfx/gfx.hpp>
#include <util/reflect.hpp>
#include <algorithm>
@@ -575,7 +576,10 @@ void combine_image(Image& a, const Image& b, ImageCombine combine) {
DISPATCH(COMBINE_SMALLER_THAN_240);
DISPATCH(COMBINE_SMALLER_THAN_245);
DISPATCH(COMBINE_SMALLER_THAN_250);
}
}
//transfer metadata
a.SetOption(wxIMAGE_OPTION_PNG_DESCRIPTION, metadata_merge(a, b));
}
void draw_combine_image(DC& dc, UInt x, UInt y, const Image& img, ImageCombine combine) {
+48 -4
View File
@@ -13,6 +13,7 @@
#include <data/set.hpp>
#include <data/symbol.hpp>
#include <data/field/symbol.hpp>
#include <script/functions/json.hpp>
#include <render/symbol/filter.hpp>
#include <gui/util.hpp> // load_resource_image
#include <gui/web_request_window.hpp>
@@ -297,6 +298,11 @@ Image EnlargeImage::generate(const Options& opt) {
for (int y = 0 ; y < h ; ++y) {
memcpy(data2 + dw + (y+dh)*w2, data1 + y*w, w); // copy a line
}
}
// transfer metadata
if (img.HasOption(wxIMAGE_OPTION_PNG_DESCRIPTION)) {
String metadata = transformAllEncodedRects(img.GetOption(wxIMAGE_OPTION_PNG_DESCRIPTION), RealRect::translate, dw, dh);
larger.SetOption(wxIMAGE_OPTION_PNG_DESCRIPTION, metadata);
}
// done
return larger;
@@ -436,8 +442,8 @@ Image BleedEdgedImage::generate(const Options& opt) {
}
// transfer metadata
if (base_img.HasOption(wxIMAGE_OPTION_PNG_DESCRIPTION)) {
String desc = transformAllEncodedRects(base_img.GetOption(wxIMAGE_OPTION_PNG_DESCRIPTION), 1.0, 0.0, dw, dh, width, height);
img.SetOption(wxIMAGE_OPTION_PNG_DESCRIPTION, desc);
String metadata = transformAllEncodedRects(base_img.GetOption(wxIMAGE_OPTION_PNG_DESCRIPTION), RealRect::translate, dw, dh);
img.SetOption(wxIMAGE_OPTION_PNG_DESCRIPTION, metadata);
}
// done
return img;
@@ -481,9 +487,12 @@ Image InsertedImage::generate(const Options& opt) {
alpha += 1;
}
img.Paste(base_img, base_x, base_y, wxIMAGE_ALPHA_BLEND_COMPOSE);
img.Paste(inserted_img, inserted_x, inserted_y, wxIMAGE_ALPHA_BLEND_COMPOSE);
img.Paste(inserted_img, inserted_x, inserted_y, wxIMAGE_ALPHA_BLEND_COMPOSE);
// transfer metadata
img.SetOption(wxIMAGE_OPTION_PNG_DESCRIPTION, metadata_merge(base_img, inserted_img, base_x, base_y, inserted_x, inserted_y));
return img;
}
ImageCombine InsertedImage::combine() const {
return base_image->combine();
}
@@ -519,7 +528,29 @@ Image CropImage::generate(const Options& opt) {
alpha += 1;
}
Image base_img = image->generate(opt);
img.Paste(base_img, -(int)offset_x, -(int)offset_y, wxIMAGE_ALPHA_BLEND_OVER);
img.Paste(base_img, -(int)offset_x, -(int)offset_y, wxIMAGE_ALPHA_BLEND_COMPOSE);
// transfer metadata
if (base_img.HasOption(wxIMAGE_OPTION_PNG_DESCRIPTION)) {
String metadata = transformAllEncodedRects(base_img.GetOption(wxIMAGE_OPTION_PNG_DESCRIPTION), RealRect::translate, -offset_x, -offset_y);
// prune out of bounds cards
boost::json::array cardsv = metadata_to_json(metadata);
boost::json::array inbounds_cardsv;
for (int i = 0; i < cardsv.size(); i++) {
boost::json::object cardv = cardsv[i].as_object();
if (cardv.contains("bounds")) {
String bounds = String(cardv["bounds"].as_string().c_str());
RealRect rect(0.0, 0.0, 0.0, 0.0);
int degrees = 0;
if (decodeRectFromString(bounds, rect, degrees)) {
rect = rect.intersect(RealRect(0.0, 0.0, width, height));
if (rect.width <= 0.0 || rect.height <= 0.0 ) continue;
}
}
inbounds_cardsv.emplace_back(cardv);
}
metadata = "<mse-card-data>" + json_ugly_print(inbounds_cardsv) + "</mse-card-data>";
img.SetOption(wxIMAGE_OPTION_PNG_DESCRIPTION, metadata);
}
return img;
}
bool CropImage::operator == (const GeneratedImage& that) const {
@@ -730,6 +761,19 @@ bool ImageValueToImage::operator == (const GeneratedImage& that) const {
&& age == that2->age;
}
// ----------------------------------------------------------------------------- : SetMetadataImage
Image SetMetadataImage::generate(const Options& opt) {
Image img = image->generate(opt);
img.SetOption(wxIMAGE_OPTION_PNG_DESCRIPTION, metadata);
return img;
}
bool SetMetadataImage::operator == (const GeneratedImage& that) const {
const SetMetadataImage* that2 = dynamic_cast<const SetMetadataImage*>(&that);
return that2 && *image == *that2->image
&& metadata == that2->metadata;
}
// ----------------------------------------------------------------------------- : ImportedImage
ImportedImage::ImportedImage(Set* set, const String& filepath)
+14
View File
@@ -467,6 +467,20 @@ private:
Age age; ///< Age the image was last updated
};
// ----------------------------------------------------------------------------- : SetMetadataImage
/// Change the alpha channel of an image
class SetMetadataImage : public SimpleFilterImage {
public:
inline SetMetadataImage(const GeneratedImageP& image, const String& metadata)
: SimpleFilterImage(image), metadata(metadata)
{}
Image generate(const Options& opt) override;
bool operator == (const GeneratedImage& that) const override;
private:
String metadata;
};
// ----------------------------------------------------------------------------- : ExternalImage
/// Load an image from outside the data folder
+6
View File
@@ -7,6 +7,7 @@
// ----------------------------------------------------------------------------- : Includes
#include <util/prec.hpp>
#include <data/format/image_encoding.hpp>
#include <gfx/gfx.hpp>
#include <util/error.hpp>
#if defined(__WXMSW__) && wxUSE_WXDIB
@@ -403,6 +404,11 @@ Image make_stroke_image(Image& img, Color stroke_color, int stroke_radius, int b
for (int i = 0 ; i < blur_radius ; ++i) {
blur_image_alpha(s_img, 3);
}
// transfer metadata
if (img.HasOption(wxIMAGE_OPTION_PNG_DESCRIPTION)) {
String metadata = transformAllEncodedRects(img.GetOption(wxIMAGE_OPTION_PNG_DESCRIPTION), RealRect::translate, margin, margin);
s_img.SetOption(wxIMAGE_OPTION_PNG_DESCRIPTION, metadata);
}
return s_img;
}
+8
View File
@@ -8,6 +8,7 @@
#include <util/prec.hpp>
#include <gfx/gfx.hpp>
#include <data/format/image_encoding.hpp>
#include <util/error.hpp>
// ----------------------------------------------------------------------------- : Resample passes
@@ -152,6 +153,13 @@ void resample_and_clip(const Image& img_in, Image& img_out, wxRect rect) {
Image img_temp(img_out.GetWidth(), rect.height, false);
resample_pass(img_in, img_temp, offset_in, 0, rect.width, 1, img_temp.GetWidth(), 1, rect .GetHeight(), img_in.GetWidth(), img_temp.GetWidth());
resample_pass(img_temp, img_out, 0, 0, rect.height, img_temp.GetWidth(), img_out .GetHeight(), img_temp.GetWidth(), img_temp.GetWidth(), 1, 1);
}
// transfer metadata
if (img_in.HasOption(wxIMAGE_OPTION_PNG_DESCRIPTION)) {
double scale_x = (double)img_out.GetWidth() / img_in.GetWidth();
double scale_y = (double)img_out.GetHeight() / img_in.GetHeight();
String metadata = transformAllEncodedRects(img_in.GetOption(wxIMAGE_OPTION_PNG_DESCRIPTION), RealRect::scale, scale_x, scale_y);
img_out.SetOption(wxIMAGE_OPTION_PNG_DESCRIPTION, metadata);
}
}
+14 -7
View File
@@ -42,11 +42,8 @@ Image rotate_image_impl(const Image& img) {
}
// transfer metadata
if (img.HasOption(wxIMAGE_OPTION_PNG_DESCRIPTION)) {
if (!almost_equal(Rotater::angle(), rad180)) {
swap(width, height);
}
String desc = transformAllEncodedRects(img.GetOption(wxIMAGE_OPTION_PNG_DESCRIPTION), 1.0, Rotater::angle(), 0, 0, width, height);
ret.SetOption(wxIMAGE_OPTION_PNG_DESCRIPTION, desc);
String metadata = transformAllEncodedRects(img.GetOption(wxIMAGE_OPTION_PNG_DESCRIPTION), RealRect::rotate, width, height, lround(rad_to_deg(Rotater::angle())));
ret.SetOption(wxIMAGE_OPTION_PNG_DESCRIPTION, metadata);
}
// ret is rotated image
return ret;
@@ -102,8 +99,10 @@ Image rotate_image(const Image& image, Radians angle) {
if (is_rad180(a)) return rotate_image_impl<Rotate180deg>(image);
if (is_rad270(a)) return rotate_image_impl<Rotate270deg>(image);
else {
if (!image.HasAlpha()) const_cast<Image&>(image).InitAlpha();
return image.Rotate(angle, wxPoint(0,0));
if (!image.HasAlpha()) const_cast<Image&>(image).InitAlpha();
Image ret = image.Rotate(angle, wxPoint(0,0));
ret.SetOption(wxIMAGE_OPTION_PNG_DESCRIPTION, image.GetOption(wxIMAGE_OPTION_PNG_DESCRIPTION));
return ret;
}
}
@@ -132,6 +131,10 @@ Image flip_image_horizontal(Image const& img) {
if (img.HasAlpha()) {
out.InitAlpha();
do_flip(img.GetAlpha(), out.GetAlpha(), 1, w, h);
}
if (img.HasOption(wxIMAGE_OPTION_PNG_DESCRIPTION)) {
String metadata = transformAllEncodedRects(img.GetOption(wxIMAGE_OPTION_PNG_DESCRIPTION), RealRect::flip, w, h, 1);
out.SetOption(wxIMAGE_OPTION_PNG_DESCRIPTION, metadata);
}
return out;
}
@@ -143,6 +146,10 @@ Image flip_image_vertical(Image const& img) {
if (img.HasAlpha()) {
out.InitAlpha();
do_flip(img.GetAlpha(), out.GetAlpha(), 1 * w, h);
}
if (img.HasOption(wxIMAGE_OPTION_PNG_DESCRIPTION)) {
String metadata = transformAllEncodedRects(img.GetOption(wxIMAGE_OPTION_PNG_DESCRIPTION), RealRect::flip, w, h, 0);
out.SetOption(wxIMAGE_OPTION_PNG_DESCRIPTION, metadata);
}
return out;
}