mirror of
https://github.com/amyinspace/MagicSetEditor2.git
synced 2026-06-10 04:57:00 -04:00
ensure image script functions preserve metadata
This commit is contained in:
+2
-2
@@ -180,13 +180,13 @@ int Style::update(Context& ctx) {
|
||||
else if (automatic_side & AUTO_BOTTOM) bottom = top + height;
|
||||
else {int tb = int(top + bottom); top = (tb - height) / 2; bottom = (tb + height) / 2; }
|
||||
// adjust rotation point
|
||||
if (angle != 0 && (automatic_side & (AUTO_LEFT | AUTO_TOP))) {
|
||||
if (!almost_equal(angle, 0.0) && (automatic_side & (AUTO_LEFT | AUTO_TOP))) {
|
||||
double s = sin(deg_to_rad(angle)), c = cos(deg_to_rad(angle));
|
||||
if (automatic_side & AUTO_LEFT) { // attach right corner instead of left
|
||||
left = left + width * (1 - c);
|
||||
top = top + width * s;
|
||||
}
|
||||
if (automatic_side & AUTO_TOP) { // attach botom corner instead of top
|
||||
if (automatic_side & AUTO_TOP) { // attach bottom corner instead of top
|
||||
left = left - height * s;
|
||||
top = top + height * (1 - c);
|
||||
}
|
||||
|
||||
+34
-6
@@ -126,12 +126,40 @@ public:
|
||||
inline RealPoint getPos() const { return RealPoint(left, top); }
|
||||
inline RealSize getSize() const { return RealSize(width, height); }
|
||||
inline RealRect getExternalRect() const { return RealRect(left, top, width, height); }
|
||||
inline std::string getExternalRectString(double scale, Radians angle, int offset_x, int offset_y, int img_width, int img_height) { ///< update the style before calling this
|
||||
RealRect rect(left, top, width, height);
|
||||
int degrees = lround(rad_to_deg(this->angle));
|
||||
return transformAndEncodeRectInString(rect, degrees, scale, angle, offset_x, offset_y, img_width, img_height);
|
||||
}
|
||||
|
||||
inline RealRect getCanonicalExternalRect() const {
|
||||
if (almost_equal(angle, 90.0)) {
|
||||
if (automatic_side & Style::AutomaticSide::AUTO_LEFT) {
|
||||
if (automatic_side & Style::AutomaticSide::AUTO_TOP) return RealRect(left + width - height, top + height, height, width); //bottom right
|
||||
else return RealRect(left + width, top, height, width); //top right
|
||||
}
|
||||
else {
|
||||
if (automatic_side & Style::AutomaticSide::AUTO_TOP) return RealRect(left - height, top + height - width, height, width); //bottom left
|
||||
else return RealRect(left, top - width, height, width); //top left
|
||||
}
|
||||
}
|
||||
else if (almost_equal(angle, 270.0)) {
|
||||
if (automatic_side & Style::AutomaticSide::AUTO_LEFT) {
|
||||
if (automatic_side & Style::AutomaticSide::AUTO_TOP) return RealRect(left + width, top + height - width, height, width); //bottom right
|
||||
else return RealRect(left + width - height, top - width, height, width); //top right
|
||||
}
|
||||
else {
|
||||
if (automatic_side & Style::AutomaticSide::AUTO_TOP) return RealRect(left, top + height, height, width); //bottom left
|
||||
else return RealRect(left - height, top, height, width); //top left
|
||||
}
|
||||
}
|
||||
else if (almost_equal(angle, 180.0)) {
|
||||
if (automatic_side & Style::AutomaticSide::AUTO_LEFT) {
|
||||
if (automatic_side & Style::AutomaticSide::AUTO_TOP) return RealRect(left + width, top + height, width, height); //bottom right
|
||||
else return RealRect(left + width, top - height, width, height); //top right
|
||||
}
|
||||
else {
|
||||
if (automatic_side & Style::AutomaticSide::AUTO_TOP) return RealRect(left - width, top + height, width, height); //bottom left
|
||||
else return RealRect(left - width, top - height, width, height); //top left
|
||||
}
|
||||
}
|
||||
return getExternalRect();
|
||||
}
|
||||
|
||||
/// Does this style have a non-zero size (or is it scripted)?
|
||||
bool hasSize() const;
|
||||
|
||||
|
||||
@@ -39,6 +39,13 @@ public:
|
||||
inline ImageValue(const ImageFieldP& field) : Value(field) {}
|
||||
DECLARE_VALUE_TYPE(Image, LocalFileName);
|
||||
|
||||
inline Image getImage(const SetP& set) {
|
||||
auto imageInputStream = set->openIn(filename);
|
||||
Image img(*imageInputStream, wxBITMAP_TYPE_PNG);
|
||||
if (!img.IsOk()) throw ScriptError(_ERROR_2_("file not found", filename.toStringForKey(), set));
|
||||
return img;
|
||||
}
|
||||
|
||||
ValueType filename; ///< Filename of the image (in the current package), or ""
|
||||
Age last_update; ///< When was the image last changed?
|
||||
};
|
||||
@@ -55,11 +62,4 @@ public:
|
||||
Scriptable<bool> store_in_metadata; ///< Is the image stored in full in the metadata when exporting?
|
||||
|
||||
int update(Context&) override;
|
||||
|
||||
inline std::string getExternalImageString(const SetP& set, ImageValue* value) { ///< update the style before calling this
|
||||
auto imageInputStream = set->openIn(value->filename);
|
||||
Image img(*imageInputStream, wxBITMAP_TYPE_PNG);
|
||||
if (!img.IsOk()) throw ScriptError(_ERROR_2_("file not found", value->filename.toStringForKey(), set));
|
||||
return encodeImageInString(img);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -89,12 +89,18 @@ FileFormatP mtg_editor_file_format();
|
||||
// ----------------------------------------------------------------------------- : Other ways to export
|
||||
|
||||
/// Generate a wxImage of one or more cards
|
||||
Image export_image(const SetP& set, const CardP& card, const bool write_metadata = true, const double zoom = 1.0, const Radians angle_radians = 0.0, const double bleed_pixels = 0.0);
|
||||
Image export_image(const SetP& set, const vector<CardP>& cards, const int padding = 2, const double global_zoom = 1.0, const bool use_zoom_setting = true, const bool use_rotation_setting = true, const bool use_bleed_setting = false);
|
||||
Image export_image(const SetP& set, const CardP& card, bool write_metadata = true, double zoom = 1.0, Radians angle_radians = 0.0, double bleed_pixels = 0.0);
|
||||
Image export_image(const SetP& set, const vector<CardP>& cards, int padding = 2, double global_zoom = 1.0, bool use_zoom_setting = true, bool use_rotation_setting = true, bool use_bleed_setting = false);
|
||||
|
||||
/// Export the image of one or more cards to a given filename, using the app's zoom, rotation and bleed settings, and including metadata
|
||||
void export_image(const SetP& set, const CardP& card, const String& filename);
|
||||
void export_image(const SetP& set, const vector<CardP>& cards, const String& path, const String& filename_template, FilenameConflicts conflicts);
|
||||
|
||||
/// Write the metadata for a card
|
||||
// Assuming first the zoom is applied, then the rotation, then the offset.
|
||||
// This means that width and height need to be already scaled by a factor of zoom, but not already rotated
|
||||
// while offset_x and offset_y need to be already scaled and already rotated.
|
||||
String export_metadata(const SetP& set, const CardP& card, double zoom, Radians angle_radians, int width, int height, double offset_x, double offset_y);
|
||||
|
||||
/// Export a set to Magic Workstation format
|
||||
void export_mws(Window* parent, const SetP& set);
|
||||
|
||||
+57
-65
@@ -35,7 +35,7 @@ Rotation ZoomedUnrotatedDataViewer::getRotation() const {
|
||||
|
||||
// ----------------------------------------------------------------------------- : wxImage export
|
||||
|
||||
Image export_image(const SetP& set, const CardP& card, const bool write_metadata, const double zoom, const Radians angle_radians, const double bleed_pixels) {
|
||||
Image export_image(const SetP& set, const CardP& card, bool write_metadata, double zoom, Radians angle_radians, double bleed_pixels) {
|
||||
if (!set) throw Error(_("no set"));
|
||||
/// create and zoom
|
||||
ZoomedUnrotatedDataViewer viewer = ZoomedUnrotatedDataViewer(zoom);
|
||||
@@ -129,47 +129,24 @@ Image export_image(const SetP& set, const CardP& card, const bool write_metadata
|
||||
}
|
||||
|
||||
/// add metadata
|
||||
if (write_metadata) {
|
||||
String metadata = _("<mse-card-data>[");
|
||||
IndexMap<FieldP, ValueP>& card_data = card->data;
|
||||
boost::json::object cardv = mse_to_json(card, set.get());
|
||||
boost::json::object& cardv_data = cardv["data"].as_object();
|
||||
StyleSheetP stylesheet = set->stylesheetForP(card);
|
||||
if (!settings.stylesheetSettingsFor(*stylesheet).card_notes_export()) cardv["notes"] = "";
|
||||
// iterate over all image fields
|
||||
for(IndexMap<FieldP, ValueP>::iterator it = card_data.begin() ; it != card_data.end() ; ++it) {
|
||||
ImageValue* value = dynamic_cast<ImageValue*>(it->get());
|
||||
if (value && !value->filename.empty()) {
|
||||
FieldP field = (*it)->fieldP;
|
||||
ImageStyle* style = dynamic_cast<ImageStyle*>(stylesheet->card_style.at(field->index).get());
|
||||
if (style) {
|
||||
style->update(set->getContext(card));
|
||||
// store the entire image in the metadata
|
||||
if (style->store_in_metadata()) {
|
||||
std::string bytes = style->getExternalImageString(set, value);
|
||||
cardv_data[field->name.ToStdString()] = bytes;
|
||||
}
|
||||
// store only crop coordinates
|
||||
else {
|
||||
std::string rect = style->getExternalRectString(zoom, angle_radians, bleed_pixels, bleed_pixels, width, height);
|
||||
cardv_data[field->name.ToStdString()] = rect;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
metadata += json_ugly_print(cardv) + _("]</mse-card-data>");
|
||||
if (write_metadata) {
|
||||
bool rotated = is_rad90(angle_radians) || is_rad270(angle_radians); // we stored width and height after rotation, but export_metadata expects them before rotation
|
||||
String metadata = _("<mse-card-data>[")
|
||||
+ export_metadata(set, card, zoom, angle_radians, rotated ? height : width, rotated ? width : height, bleed_pixels, bleed_pixels)
|
||||
+ _("]</mse-card-data>");
|
||||
img.SetOption(wxIMAGE_OPTION_PNG_DESCRIPTION, metadata);
|
||||
}
|
||||
|
||||
return img;
|
||||
}
|
||||
|
||||
Image export_image( const SetP& set, const vector<CardP>& cards,
|
||||
const int padding,
|
||||
const double global_zoom,
|
||||
const bool use_zoom_setting,
|
||||
const bool use_rotation_setting,
|
||||
const bool use_bleed_setting) {
|
||||
Image export_image(const SetP& set,
|
||||
const vector<CardP>& cards,
|
||||
int padding,
|
||||
double global_zoom,
|
||||
bool use_zoom_setting,
|
||||
bool use_rotation_setting,
|
||||
bool use_bleed_setting) {
|
||||
if (!set) throw Error(_("no set"));
|
||||
if (cards.size() == 0) throw Error(_("no cards"));
|
||||
vector<Image> imgs;
|
||||
@@ -224,32 +201,8 @@ Image export_image( const SetP& set, const vector<CardP>& cards,
|
||||
for (int i = 0; i < cards.size(); ++i) {
|
||||
if (i > 0) metadata += _(",");
|
||||
CardP card = cards[i];
|
||||
IndexMap<FieldP, ValueP>& card_data = card->data;
|
||||
boost::json::object cardv = mse_to_json(card, set.get());
|
||||
boost::json::object& cardv_data = cardv["data"].as_object();
|
||||
StyleSheetP stylesheet = set->stylesheetForP(card);
|
||||
if (!settings.stylesheetSettingsFor(*stylesheet).card_notes_export()) cardv["notes"] = "";
|
||||
for(IndexMap<FieldP, ValueP>::iterator it = card_data.begin() ; it != card_data.end() ; ++it) {
|
||||
ImageValue* value = dynamic_cast<ImageValue*>(it->get());
|
||||
if (value && !value->filename.empty()) {
|
||||
FieldP field = (*it)->fieldP;
|
||||
ImageStyle* style = dynamic_cast<ImageStyle*>(stylesheet->card_style.at(field->index).get());
|
||||
if (style) {
|
||||
style->update(set->getContext(card));
|
||||
// store the entire image in the metadata
|
||||
if (style->store_in_metadata()) {
|
||||
std::string bytes = style->getExternalImageString(set, value);
|
||||
cardv_data[field->name.ToStdString()] = bytes;
|
||||
}
|
||||
// store only crop coordinates
|
||||
else {
|
||||
std::string rect = style->getExternalRectString(zooms[i], angles[i], bleeds[i] + offsets[i], bleeds[i], widths[i], heights[i]);
|
||||
cardv_data[field->name.ToStdString()] = rect;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
metadata += json_ugly_print(cardv);
|
||||
bool rotated = is_rad90(angles[i]) || is_rad270(angles[i]); // we stored width and height after rotation, but export_metadata expects them before rotation
|
||||
metadata += export_metadata(set, card, zooms[i], angles[i], rotated ? heights[i] : widths[i], rotated ? widths[i] : heights[i], bleeds[i] + offsets[i], bleeds[i]);
|
||||
}
|
||||
metadata += _("]</mse-card-data>");
|
||||
global_img.SetOption(wxIMAGE_OPTION_PNG_DESCRIPTION, metadata);
|
||||
@@ -265,8 +218,7 @@ void export_image(const SetP& set, const CardP& card, const String& filename) {
|
||||
img.SaveFile(filename);
|
||||
}
|
||||
|
||||
void export_image(const SetP& set, const vector<CardP>& cards,
|
||||
const String& path, const String& filename_template, FilenameConflicts conflicts)
|
||||
void export_image(const SetP& set, const vector<CardP>& cards, const String& path, const String& filename_template, FilenameConflicts conflicts)
|
||||
{
|
||||
wxBusyCursor busy;
|
||||
// Script
|
||||
@@ -289,4 +241,44 @@ void export_image(const SetP& set, const vector<CardP>& cards,
|
||||
used.insert(filename);
|
||||
export_image(set, card, filename);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String export_metadata(const SetP& set, const CardP& card, double zoom, Radians angle_radians, int width, int height, double offset_x, double offset_y)
|
||||
{
|
||||
IndexMap<FieldP, ValueP>& card_data = card->data;
|
||||
boost::json::object cardv = mse_to_json(card, set.get());
|
||||
boost::json::object& cardv_data = cardv["data"].as_object();
|
||||
StyleSheetP stylesheet = set->stylesheetForP(card);
|
||||
if (!settings.stylesheetSettingsFor(*stylesheet).card_notes_export()) cardv["notes"] = "";
|
||||
RealRect bounds_rect = RealRect(0, 0, width, height);
|
||||
int bounds_degrees = 0;
|
||||
RealRect::rotate(bounds_rect, bounds_degrees, width, height, lround(rad_to_deg(angle_radians)));
|
||||
RealRect::translate(bounds_rect, bounds_degrees, offset_x, offset_y);
|
||||
cardv.emplace("bounds", encodeRectInStdString(bounds_rect, bounds_degrees));
|
||||
// iterate over all image fields
|
||||
for (IndexMap<FieldP, ValueP>::iterator it = card_data.begin(); it != card_data.end(); ++it) {
|
||||
ImageValue* value = dynamic_cast<ImageValue*>(it->get());
|
||||
if (value && !value->filename.empty()) {
|
||||
FieldP field = (*it)->fieldP;
|
||||
ImageStyle* style = dynamic_cast<ImageStyle*>(stylesheet->card_style.at(field->index).get());
|
||||
if (style) {
|
||||
style->update(set->getContext(card));
|
||||
// store the entire image in the metadata
|
||||
if (style->store_in_metadata()) {
|
||||
Image img = value->getImage(set);
|
||||
cardv_data[field->name.ToStdString()] = encodeImageInString(img);
|
||||
}
|
||||
// store only crop coordinates
|
||||
else {
|
||||
RealRect rect = style->getCanonicalExternalRect();
|
||||
int degrees = lround(style->angle());
|
||||
RealRect::scale(rect, degrees, zoom, zoom);
|
||||
RealRect::rotate(rect, degrees, width, height, lround(rad_to_deg(angle_radians))); // width and height are already scaled
|
||||
RealRect::translate(rect, degrees, offset_x, offset_y); // offset_x and offset_y are already scaled and rotated
|
||||
cardv_data[field->name.ToStdString()] = encodeRectInStdString(rect, degrees);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return json_ugly_print(cardv);
|
||||
}
|
||||
|
||||
@@ -9,13 +9,15 @@
|
||||
// ----------------------------------------------------------------------------- : Includes
|
||||
|
||||
#include <util/prec.hpp>
|
||||
#include <util/real_point.hpp>
|
||||
#include <boost/json.hpp>
|
||||
#include <wx/filename.h>
|
||||
#include <fstream>
|
||||
|
||||
// ----------------------------------------------------------------------------- : Crop Rect Encoding
|
||||
|
||||
/// Encode a rect in a std::string
|
||||
inline static std::string encodeRectInStdString(wxRect rect, int degrees) {
|
||||
inline static std::string encodeRectInStdString(RealRect rect, int degrees) {
|
||||
return "<mse-crop-data>" + std::to_string((int)std::ceil (rect.x)) +
|
||||
";" + std::to_string((int)std::ceil (rect.y)) +
|
||||
";" + std::to_string((int)std::floor(rect.width)) +
|
||||
@@ -25,7 +27,7 @@ inline static std::string encodeRectInStdString(wxRect rect, int degrees) {
|
||||
}
|
||||
|
||||
/// Encode a rect in a wxString
|
||||
inline static String encodeRectInWxString(wxRect rect, int degrees) {
|
||||
inline static String encodeRectInWxString(RealRect rect, int degrees) {
|
||||
return _("<mse-crop-data>") + wxString::Format(wxT("%i"), (int)std::ceil (rect.x)) +
|
||||
_(";") + wxString::Format(wxT("%i"), (int)std::ceil (rect.y)) +
|
||||
_(";") + wxString::Format(wxT("%i"), (int)std::floor(rect.width)) +
|
||||
@@ -35,7 +37,7 @@ inline static String encodeRectInWxString(wxRect rect, int degrees) {
|
||||
}
|
||||
|
||||
/// Retreive a rect encoded in a string, return true if successful
|
||||
inline static bool decodeRectFromString(const String& rectString, wxRect& rect_out, int& degrees_out) {
|
||||
inline static bool decodeRectFromString(const String& rectString, RealRect& rect_out, int& degrees_out) {
|
||||
size_t start = rectString.find(_("<mse-crop-data>"));
|
||||
if (start == String::npos) return false;
|
||||
size_t end = rectString.find(_("</mse-crop-data>"), start + 15);
|
||||
@@ -73,44 +75,22 @@ inline static bool decodeRectFromString(const String& rectString, wxRect& rect_o
|
||||
|
||||
if(!string.ToInt(°rees_out)) return false;
|
||||
|
||||
rect_out = wxRect(x, y, width, height);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Apply a transformation to a rect, return true if successful
|
||||
inline static bool transformEncodedRect(wxRect& rect, int& degrees, double scale, Radians angle, int offset_x, int offset_y, int img_width, int img_height) {
|
||||
if (degrees != 0 && degrees != 90 && degrees != 180 && degrees != 270) return false;
|
||||
rect = wxRect(rect.x * scale, rect.y * scale, rect.width * scale, rect.height * scale);
|
||||
if (is_rad0(angle)) {
|
||||
} else if (is_rad180(angle)) {
|
||||
rect = wxRect(img_width - rect.x - rect.width, img_height - rect.y - rect.height, rect.width, rect.height);
|
||||
degrees += 180;
|
||||
} else if (is_rad90(angle)) {
|
||||
rect = wxRect(rect.y, img_height - rect.x - rect.width, rect.height, rect.width);
|
||||
degrees += 90;
|
||||
} else if (is_rad270(angle)) {
|
||||
rect = wxRect(img_width - rect.y - rect.height, rect.x, rect.height, rect.width);
|
||||
degrees += 270;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
rect = wxRect(rect.x + offset_x, rect.y + offset_y, rect.width, rect.height);
|
||||
if (degrees >= 360) degrees -= 360;
|
||||
rect_out = RealRect(x, y, width, height);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Retreive a rect encoded in a string, apply a transformation, then encode it back
|
||||
inline static String transformEncodedRect(const String& rectString, double scale, Radians angle, int offset_x, int offset_y, int img_width, int img_height) {
|
||||
wxRect rect;
|
||||
inline static String transformEncodedRect(const String& rectString, RectTransform transform, double param_x, double param_y, int mode) {
|
||||
RealRect rect(0,0,0,0);
|
||||
int degrees;
|
||||
if (!decodeRectFromString(rectString, rect, degrees)) return _("");
|
||||
if (!transformEncodedRect(rect, degrees, scale, angle, offset_x, offset_y, img_width, img_height)) return _("");
|
||||
transform(rect, degrees, param_x, param_y, mode);
|
||||
return encodeRectInWxString(rect, degrees);
|
||||
}
|
||||
|
||||
/// Retreive all rects encoded in a string, apply a transformation, then encode them back
|
||||
inline static String transformAllEncodedRects(const String& rectString, double scale, Radians angle, int offset_x, int offset_y, int img_width, int img_height) {
|
||||
wxRect rect;
|
||||
inline static String transformAllEncodedRects(const String& rectString, RectTransform transform, double param_x, double param_y, int mode = 0) {
|
||||
RealRect rect(0,0,0,0);
|
||||
int degrees;
|
||||
size_t start = rectString.find(_("<mse-crop-data>"));
|
||||
if (start == String::npos) return rectString;
|
||||
@@ -121,19 +101,13 @@ inline static String transformAllEncodedRects(const String& rectString, double s
|
||||
end = rectString.find(_("</mse-crop-data>"), start + 15);
|
||||
if (end == String::npos) return rectString;
|
||||
end += 16;
|
||||
result = result + transformEncodedRect(rectString.substr(start, end - start), scale, angle, offset_x, offset_y, img_width, img_height);
|
||||
result = result + transformEncodedRect(rectString.substr(start, end - start), transform, param_x, param_y, mode);
|
||||
start = rectString.find(_("<mse-crop-data>"), end);
|
||||
}
|
||||
result = result + rectString.substr(end);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Apply a transformation to a rect, then encode it in a string
|
||||
inline static std::string transformAndEncodeRectInString(wxRect rect, int degrees, double scale, Radians angle, int offset_x, int offset_y, int img_width, int img_height) {
|
||||
if (!transformEncodedRect(rect, degrees, scale, angle, offset_x, offset_y, img_width, img_height)) return "";
|
||||
return encodeRectInStdString(rect, degrees);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : File to UTF8 Encoding
|
||||
|
||||
/// Encode a file in a string
|
||||
@@ -227,3 +201,52 @@ inline static Image decodeImageFromString(const String& string) {
|
||||
wxRemoveFile(temppath.substr(0, temppath.size() - 4));
|
||||
return img;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : Metadata manipulation
|
||||
|
||||
inline static String metadata_merge(const Image& img1, const Image& img2, int offset_x1 = 0, int offset_y1 = 0, int offset_x2 = 0, int offset_y2 = 0)
|
||||
{
|
||||
if (img1.HasOption(wxIMAGE_OPTION_PNG_DESCRIPTION)) {
|
||||
String metadata1 = img1.GetOption(wxIMAGE_OPTION_PNG_DESCRIPTION);
|
||||
if (offset_x1 != 0 || offset_y1 != 0) metadata1 = transformAllEncodedRects(metadata1, RealRect::translate, offset_x1, offset_y1);
|
||||
if (img2.HasOption(wxIMAGE_OPTION_PNG_DESCRIPTION)) {
|
||||
String metadata2 = img2.GetOption(wxIMAGE_OPTION_PNG_DESCRIPTION);
|
||||
if (offset_x2 != 0 || offset_y2 != 0) metadata2 = transformAllEncodedRects(metadata2, RealRect::translate, offset_x2, offset_y2);
|
||||
size_t end1 = metadata1.find(_("</mse-card-data>"));
|
||||
size_t start2 = metadata2.find(_("<mse-card-data>"));
|
||||
if (end1 != String::npos && start2 != String::npos && end1 > 0 && start2 + 16 < metadata2.size()) {
|
||||
metadata1 = metadata1.substr(0, end1 - 1) + "," + metadata2.substr(start2 + 16);
|
||||
}
|
||||
}
|
||||
return metadata1;
|
||||
}
|
||||
else if (img2.HasOption(wxIMAGE_OPTION_PNG_DESCRIPTION)) {
|
||||
String metadata2 = img2.GetOption(wxIMAGE_OPTION_PNG_DESCRIPTION);
|
||||
if (offset_x2 != 0 || offset_y2 != 0) metadata2 = transformAllEncodedRects(metadata2, RealRect::translate, offset_x2, offset_y2);
|
||||
return metadata2;
|
||||
}
|
||||
return _("");
|
||||
}
|
||||
|
||||
inline static boost::json::array metadata_to_json(const String& metadata) {
|
||||
size_t start = metadata.find(_("<mse-card-data>"));
|
||||
if (start == String::npos) return boost::json::array();
|
||||
size_t end = metadata.find(_("</mse-card-data>"), start + 15);
|
||||
if (end == String::npos) return boost::json::array();
|
||||
String string = metadata.substr(start + 15, end - (start + 15));
|
||||
try {
|
||||
boost::system::error_code ec;
|
||||
boost::json::parse_options options;
|
||||
options.allow_invalid_utf8 = true;
|
||||
boost::json::value jv = boost::json::parse(string.ToStdString(), ec, {}, options);
|
||||
if(ec || !jv.is_array()) {
|
||||
queue_message(MESSAGE_ERROR, _ERROR_("json cant parse"));
|
||||
return boost::json::array();
|
||||
}
|
||||
return jv.as_array();
|
||||
}
|
||||
catch (...) {
|
||||
queue_message(MESSAGE_ERROR, _ERROR_("json cant parse"));
|
||||
return boost::json::array();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user