diff --git a/src/data/field.hpp b/src/data/field.hpp
index 553a8559..d9f1927e 100644
--- a/src/data/field.hpp
+++ b/src/data/field.hpp
@@ -127,30 +127,10 @@ public:
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, double bleed, int img_width, int img_height, int img_offset) { ///< update the style before calling this
- double x = left * scale, y = top * scale;
- double w = width * scale, h = height * scale;
- RealRect rect(x, y, w, h);
- int degrees = 0;
- if (is_rad0(angle)) {
- } else if (is_rad180(angle)) {
- rect = RealRect(img_width - x - w, img_height - y - h, w, h);
- degrees = 180;
- } else if (is_rad90(angle)) {
- rect = RealRect(y, img_height - x - w, h, w);
- degrees = 90;
- } else if (is_rad270(angle)) {
- rect = RealRect(img_width - y - h, x, h, w);
- degrees = 270;
- } else {
- return "";
- }
- return "" + std::to_string((int)std::ceil (rect.x + bleed + img_offset)) +
- "-" + std::to_string((int)std::ceil (rect.y + bleed)) +
- "-" + std::to_string((int)std::floor(rect.width)) +
- "-" + std::to_string((int)std::floor(rect.height)) +
- "-" + std::to_string(degrees) +
- "";
- }
+ RealRect rect(left, top, width, height);
+ int degrees = lround(rad_to_deg(this->angle));
+ return transformAndEncodeRectInString(rect, degrees, scale, angle, bleed, img_width, img_height, img_offset);
+ }
/// Does this style have a non-zero size (or is it scripted)?
bool hasSize() const;
diff --git a/src/data/field/image.hpp b/src/data/field/image.hpp
index 3b30cac2..c72b6e84 100644
--- a/src/data/field/image.hpp
+++ b/src/data/field/image.hpp
@@ -59,12 +59,7 @@ public:
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));
- String temppath = wxFileName::CreateTempFileName(_("mse")) + _(".png");
- img.SaveFile(temppath);
- std::string s = "" + fileToUTF8(temppath.ToStdString()) + "";
- wxRemoveFile(temppath);
- wxRemoveFile(temppath.substr(0, temppath.size() - 4));
- return s;
+ if (!img.IsOk()) throw ScriptError(_ERROR_2_("file not found", value->filename.toStringForKey(), set));
+ return encodeImageInString(img);
}
};
diff --git a/src/data/format/file_to_text.h b/src/data/format/file_to_text.h
deleted file mode 100644
index 87186ce6..00000000
--- a/src/data/format/file_to_text.h
+++ /dev/null
@@ -1,76 +0,0 @@
-//+----------------------------------------------------------------------------+
-//| Description: Magic Set Editor - Program to make card games |
-//| Copyright: (C) Twan van Laarhoven and the other MSE developers |
-//| License: GNU General Public License 2 or later (see file COPYING) |
-//+----------------------------------------------------------------------------+
-
-#pragma once
-
-// ----------------------------------------------------------------------------- : Includes
-
-#include
-#include
-
-// ----------------------------------------------------------------------------- : File to UTF8 Encoding
-
-inline std::string fileToUTF8(const std::string& filepath) {
- // File to char
- std::ifstream file(filepath, std::ios::binary);
- file.unsetf(std::ios::skipws);
- std::vector buffer = std::vector(std::istreambuf_iterator(file), std::istreambuf_iterator());
- int size = buffer.size();
- if (size < 2) {
- queue_message(MESSAGE_WARNING, _("File too small to encode"));
- return "";
- }
- // All bytes that have a highest bit of 0 are valid UTF8 characters, so:
- // Reset the highest bit of each byte, store these bits in additional bytes at the end
- const unsigned char highest_bit = 1 << 7;
- unsigned char added_byte = 0;
- for (int i = 0, b = 0 ; i < size ; ++i, ++b) {
- if (b == 7) { // Never set the highest bit of the added byte
- buffer.push_back(added_byte);
- b = 0;
- }
- unsigned char bit = 1 << b;
- if ((buffer[i] & highest_bit) != 0) { // The highest bit of the buffer is set
- buffer[i] &= ~highest_bit; // Reset the highest bit of the buffer
- added_byte |= bit; // Set the bit of the added byte
- } else {
- added_byte &= ~bit; // Reset the bit of the added byte
- }
- }
- buffer.push_back(added_byte);
- // Char to string
- return std::string(buffer.begin(), buffer.end());
-}
-
-inline bool UTF8ToFile(const std::string& filepath, std::string& string) {
- // String to char
- std::vector buffer(string.begin(), string.end());
- int size = buffer.size();
- if (size < 2) {
- queue_message(MESSAGE_WARNING, _("File too small to decode"));
- return false;
- }
- // Restore the highest bit of each byte
- size = (size * 7) / 8;
- const unsigned char highest_bit = 1 << 7;
- unsigned char added_byte = buffer[size];
- for (int i = 0, j = size, b = 0 ; i < size ; ++i, ++b) {
- if (b == 7) {
- ++j;
- added_byte = buffer[j];
- b = 0;
- }
- unsigned char bit = 1 << b;
- if ((added_byte & bit) != 0) { // The bit of the added byte is set
- buffer[i] |= highest_bit; // Set the highest bit of the buffer
- }
- }
- buffer.resize(size);
- // Char to file
- std::ofstream file(filepath, std::ios::out|std::ios::binary);
- std::copy(buffer.cbegin(), buffer.cend(), std::ostream_iterator(file));
- return true;
-}
diff --git a/src/data/format/image.cpp b/src/data/format/image.cpp
index 425a9b02..fbbc8903 100644
--- a/src/data/format/image.cpp
+++ b/src/data/format/image.cpp
@@ -10,7 +10,6 @@
#include
#include
#include
-#include
#include
#include
#include
diff --git a/src/data/format/image_encoding.hpp b/src/data/format/image_encoding.hpp
new file mode 100644
index 00000000..e6a6beac
--- /dev/null
+++ b/src/data/format/image_encoding.hpp
@@ -0,0 +1,227 @@
+//+----------------------------------------------------------------------------+
+//| Description: Magic Set Editor - Program to make card games |
+//| Copyright: (C) Twan van Laarhoven and the other MSE developers |
+//| License: GNU General Public License 2 or later (see file COPYING) |
+//+----------------------------------------------------------------------------+
+
+#pragma once
+
+// ----------------------------------------------------------------------------- : Includes
+
+#include
+#include
+#include
+
+// ----------------------------------------------------------------------------- : Crop Rect Encoding
+
+/// Encode a rect in a std::string
+inline static std::string encodeRectInStdString(wxRect rect, int degrees) {
+ return "" + std::to_string((int)std::ceil (rect.x)) +
+ ";" + std::to_string((int)std::ceil (rect.y)) +
+ ";" + std::to_string((int)std::floor(rect.width)) +
+ ";" + std::to_string((int)std::floor(rect.height)) +
+ ";" + std::to_string(degrees) +
+ "";
+}
+
+/// Encode a rect in a wxString
+inline static String encodeRectInWxString(wxRect rect, int degrees) {
+ return _("") + 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)) +
+ _(";") + wxString::Format(wxT("%i"), (int)std::floor(rect.height)) +
+ _(";") + wxString::Format(wxT("%i"), 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) {
+ size_t start = rectString.find(_(""));
+ if (start == String::npos) return false;
+ size_t end = rectString.find(_(""), start + 15);
+ if (end == String::npos) return false;
+ String string = rectString.substr(start + 15, end - (start + 15));
+ if (string.empty()) return false;
+
+ size_t divider = string.find(_(";"));
+ if (divider == String::npos) return false;
+ if (divider == 0) return false;
+ int x;
+ if(!string.substr(0, divider).ToInt(&x)) return false;
+ string = string.substr(divider + 1);
+
+ divider = string.find(_(";"));
+ if (divider == String::npos) return false;
+ if (divider == 0) return false;
+ int y;
+ if(!string.substr(0, divider).ToInt(&y)) return false;
+ string = string.substr(divider + 1);
+
+ divider = string.find(_(";"));
+ if (divider == String::npos) return false;
+ if (divider == 0) return false;
+ int width;
+ if(!string.substr(0, divider).ToInt(&width)) return false;
+ string = string.substr(divider + 1);
+
+ divider = string.find(_(";"));
+ if (divider == String::npos) return false;
+ if (divider == 0) return false;
+ int height;
+ if(!string.substr(0, divider).ToInt(&height)) return false;
+ string = string.substr(divider + 1);
+
+ 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, double bleed, int img_width, int img_height, int img_offset) {
+ 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 + bleed + img_offset, rect.y + bleed, rect.width, rect.height);
+ if (degrees >= 360) degrees -= 360;
+ 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, double bleed, int img_width, int img_height, int img_offset) { ///< update the style before calling this
+ wxRect rect;
+ int degrees;
+ if (!decodeRectFromString(rectString, rect, degrees)) return _("");
+ if (!transformEncodedRect(rect, degrees, scale, angle, bleed, img_width, img_height, img_offset)) return _("");
+ 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, double bleed, int img_width, int img_height, int img_offset) { ///< update the style before calling this
+ wxRect rect;
+ int degrees;
+ size_t start = rectString.find(_(""));
+ if (start == String::npos) return rectString;
+ size_t end = 0;
+ String result;
+ while (start != String::npos) {
+ result = result + rectString.substr(end, start - end);
+ end = rectString.find(_(""), start + 15);
+ result = result + transformEncodedRect(rectString.substr(start, end - start), scale, angle, bleed, img_width, img_height, img_offset);
+ start = rectString.find(_(""), 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, double bleed, int img_width, int img_height, int img_offset) {
+ if (!transformEncodedRect(rect, degrees, scale, angle, bleed, img_width, img_height, img_offset)) return "";
+ return encodeRectInStdString(rect, degrees);
+}
+
+// ----------------------------------------------------------------------------- : File to UTF8 Encoding
+
+/// Encode a file in a string
+inline static std::string fileToUTF8(const std::string& filepath) {
+ // File to char
+ std::ifstream file(filepath, std::ios::binary);
+ file.unsetf(std::ios::skipws);
+ std::vector buffer = std::vector(std::istreambuf_iterator(file), std::istreambuf_iterator());
+ int size = buffer.size();
+ if (size < 2) {
+ queue_message(MESSAGE_WARNING, _("File too small to encode"));
+ return "";
+ }
+ // All bytes that have a highest bit of 0 are valid UTF8 characters, so:
+ // Reset the highest bit of each byte, store these bits in additional bytes at the end
+ const unsigned char highest_bit = 1 << 7;
+ unsigned char added_byte = 0;
+ for (int i = 0, b = 0 ; i < size ; ++i, ++b) {
+ if (b == 7) { // Never set the highest bit of the added byte
+ buffer.push_back(added_byte);
+ b = 0;
+ }
+ unsigned char bit = 1 << b;
+ if ((buffer[i] & highest_bit) != 0) { // The highest bit of the buffer is set
+ buffer[i] &= ~highest_bit; // Reset the highest bit of the buffer
+ added_byte |= bit; // Set the bit of the added byte
+ } else {
+ added_byte &= ~bit; // Reset the bit of the added byte
+ }
+ }
+ buffer.push_back(added_byte);
+ // Char to string
+ return std::string(buffer.begin(), buffer.end());
+}
+
+/// Retreive a file encoded in a string, return true if successful
+inline static bool UTF8ToFile(const std::string& filepath, std::string& string) {
+ // String to char
+ std::vector buffer(string.begin(), string.end());
+ int size = buffer.size();
+ if (size < 2) {
+ queue_message(MESSAGE_WARNING, _("File too small to decode"));
+ return false;
+ }
+ // Restore the highest bit of each byte
+ size = (size * 7) / 8;
+ const unsigned char highest_bit = 1 << 7;
+ unsigned char added_byte = buffer[size];
+ for (int i = 0, j = size, b = 0 ; i < size ; ++i, ++b) {
+ if (b == 7) {
+ ++j;
+ added_byte = buffer[j];
+ b = 0;
+ }
+ unsigned char bit = 1 << b;
+ if ((added_byte & bit) != 0) { // The bit of the added byte is set
+ buffer[i] |= highest_bit; // Set the highest bit of the buffer
+ }
+ }
+ buffer.resize(size);
+ // Char to file
+ std::ofstream file(filepath, std::ios::out|std::ios::binary);
+ std::copy(buffer.cbegin(), buffer.cend(), std::ostream_iterator(file));
+ return true;
+}
+
+/// Encode an image in a string
+inline static std::string encodeImageInString(const Image& img) {
+ String temppath = wxFileName::CreateTempFileName(_("mse")) + _(".png");
+ img.SaveFile(temppath);
+ std::string s = "" + fileToUTF8(temppath.ToStdString()) + "";
+ wxRemoveFile(temppath);
+ wxRemoveFile(temppath.substr(0, temppath.size() - 4));
+ return s;
+}
+
+/// Retreive an image encoded in a string
+inline static Image decodeImageFromString(const String& string) {
+ Image img;
+ size_t first = string.find(_(""));
+ if (first == String::npos) return img;
+ size_t last = string.find(_(""), first + 16);
+ if (last == String::npos) return img;
+ std::string s = string.substr(first + 16, last - (first + 16)).ToStdString();
+ if (s.empty()) return img;
+
+ const std::string& temppath = (wxFileName::CreateTempFileName(_("mse")) + _(".png")).ToStdString();
+ UTF8ToFile(temppath, s);
+ img.LoadFile(temppath, wxBITMAP_TYPE_PNG);
+ wxRemoveFile(temppath);
+ wxRemoveFile(temppath.substr(0, temppath.size() - 4));
+ return img;
+}
diff --git a/src/gfx/rotate_image.cpp b/src/gfx/rotate_image.cpp
index 5f78a943..aa0dd10e 100644
--- a/src/gfx/rotate_image.cpp
+++ b/src/gfx/rotate_image.cpp
@@ -14,7 +14,7 @@
// Rotates an image
// 'Rotater' is a function object that knows how to 'rotate' a pixel coordinate
template
-Image rotate_image_impl(Image img) {
+Image rotate_image_impl(const Image& img) {
UInt width = img.GetWidth(), height = img.GetHeight();
// initialize the return image
Image ret;
diff --git a/src/util/io/package.hpp b/src/util/io/package.hpp
index 13a778a8..0a1e3591 100644
--- a/src/util/io/package.hpp
+++ b/src/util/io/package.hpp
@@ -13,7 +13,7 @@
#include
#include
#include
-#include
+#include
class Package;
class wxFileInputStream;
@@ -54,71 +54,14 @@ public:
inline String const& toStringForKey() const { return fn; }
- /// Retreive a rect from a filename
- inline static void getExternalRect(const String& filename, wxRect& rect_out, int& degrees_out) {
- size_t first = filename.find(_(""));
- if (first == String::npos) return;
- size_t last = filename.find(_(""), first + 15);
- if (last == String::npos) return;
- String string = filename.substr(first + 15, last - (first + 15));
- if (string.empty()) return;
-
- size_t divider = string.find(_("-"));
- if (divider == String::npos) return;
- if (divider == 0) return;
- int x;
- if(!string.substr(0, divider).ToInt(&x)) return;
- string = string.substr(divider + 1);
-
- divider = string.find(_("-"));
- if (divider == String::npos) return;
- if (divider == 0) return;
- int y;
- if(!string.substr(0, divider).ToInt(&y)) return;
- string = string.substr(divider + 1);
-
- divider = string.find(_("-"));
- if (divider == String::npos) return;
- if (divider == 0) return;
- int width;
- if(!string.substr(0, divider).ToInt(&width)) return;
- string = string.substr(divider + 1);
-
- divider = string.find(_("-"));
- if (divider == String::npos) return;
- if (divider == 0) return;
- int height;
- if(!string.substr(0, divider).ToInt(&height)) return;
- string = string.substr(divider + 1);
-
- if(!string.ToInt(°rees_out)) return;
-
- rect_out = wxRect(x, y, width, height);
- }
+ /// Retreive a rect from a filename
inline void getExternalRect(wxRect& rect_out, int& degrees_out) {
- getExternalRect(fn, rect_out, degrees_out);
- }
-
- /// Retreive an image from a filename
- inline static Image getExternalImage(const String& filename) {
- Image img;
- size_t first = filename.find(_(""));
- if (first == String::npos) return img;
- size_t last = filename.find(_(""), first + 16);
- if (last == String::npos) return img;
- std::string s = filename.substr(first + 16, last - (first + 16)).ToStdString();
- if (s.empty()) return img;
-
- const std::string& temppath = (wxFileName::CreateTempFileName(_("mse")) + _(".png")).ToStdString();
- UTF8ToFile(temppath, s);
- img.LoadFile(temppath, wxBITMAP_TYPE_PNG);
- wxRemoveFile(temppath);
- wxRemoveFile(temppath.substr(0, temppath.size() - 4));
- return img;
- }
- inline Image getExternalImage() {
- return getExternalImage(fn);
- }
+ decodeRectFromString(fn, rect_out, degrees_out);
+ }
+ /// Retreive an image from a filename
+ inline Image getExternalImage() {
+ return decodeImageFromString(fn);
+ }
private:
LocalFileName(const wxString& fn) : fn(fn) {}