|
@@ -0,0 +1,117 @@
|
|
|
|
|
+// zlib open source license
|
|
|
|
|
+//
|
|
|
|
|
+// Copyright (c) 2021 David Forsgren Piuva
|
|
|
|
|
+//
|
|
|
|
|
+// This software is provided 'as-is', without any express or implied
|
|
|
|
|
+// warranty. In no event will the authors be held liable for any damages
|
|
|
|
|
+// arising from the use of this software.
|
|
|
|
|
+//
|
|
|
|
|
+// Permission is granted to anyone to use this software for any purpose,
|
|
|
|
|
+// including commercial applications, and to alter it and redistribute it
|
|
|
|
|
+// freely, subject to the following restrictions:
|
|
|
|
|
+//
|
|
|
|
|
+// 1. The origin of this software must not be misrepresented; you must not
|
|
|
|
|
+// claim that you wrote the original software. If you use this software
|
|
|
|
|
+// in a product, an acknowledgment in the product documentation would be
|
|
|
|
|
+// appreciated but is not required.
|
|
|
|
|
+//
|
|
|
|
|
+// 2. Altered source versions must be plainly marked as such, and must not be
|
|
|
|
|
+// misrepresented as being the original software.
|
|
|
|
|
+//
|
|
|
|
|
+// 3. This notice may not be removed or altered from any source
|
|
|
|
|
+// distribution.
|
|
|
|
|
+
|
|
|
|
|
+#include "PersistentImage.h"
|
|
|
|
|
+
|
|
|
|
|
+using namespace dsr;
|
|
|
|
|
+
|
|
|
|
|
+PERSISTENT_DEFINITION(PersistentImage)
|
|
|
|
|
+
|
|
|
|
|
+static uint8_t readHexaDecimal(const ReadableString &text, int &readFrom) {
|
|
|
|
|
+ uint8_t result = 0u;
|
|
|
|
|
+ for (int i = 0; i < 2; i++) {
|
|
|
|
|
+ result = result << 4;
|
|
|
|
|
+ DsrChar c = text[readFrom];
|
|
|
|
|
+ if (U'0' <= c && c <= U'9') {
|
|
|
|
|
+ result = result | (c - U'0');
|
|
|
|
|
+ } else if (U'a' <= c && c <= U'f') {
|
|
|
|
|
+ result = result | (c - U'a' + 10);
|
|
|
|
|
+ } else if (U'A' <= c && c <= U'F') {
|
|
|
|
|
+ result = result | (c - U'A' + 10);
|
|
|
|
|
+ }
|
|
|
|
|
+ readFrom++;
|
|
|
|
|
+ }
|
|
|
|
|
+ return result;
|
|
|
|
|
+}
|
|
|
|
|
+bool PersistentImage::assignValue(const ReadableString &text) {
|
|
|
|
|
+ if (string_caseInsensitiveMatch(text, U"NONE")) {
|
|
|
|
|
+ // Set the handle to null
|
|
|
|
|
+ this->value = OrderedImageRgbaU8();
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // Create an image from the text
|
|
|
|
|
+ int colonIndex = string_findFirst(text, U':');
|
|
|
|
|
+ if (colonIndex == -1) {
|
|
|
|
|
+ printText("Missing colon when creating PersistentImage from text!\n");
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+ ReadableString leftSide = string_before(text, colonIndex);
|
|
|
|
|
+ if (string_caseInsensitiveMatch(leftSide, U"FILE")) {
|
|
|
|
|
+ // Read image from the file path
|
|
|
|
|
+ this->value = image_load_RgbaU8(string_after(text, colonIndex));
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // Read dimensions and a sequence of pixels as hexadecimals
|
|
|
|
|
+ int xIndex = string_findFirst(text, U'x');
|
|
|
|
|
+ if (xIndex == -1 || xIndex > colonIndex) {
|
|
|
|
|
+ printText("Missing x when parsing embedded PersistentImage from text!\n");
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+ int width = string_toInteger(string_before(leftSide, xIndex));
|
|
|
|
|
+ int height = string_toInteger(string_after(leftSide, xIndex));
|
|
|
|
|
+ if (width <= 0 || height <= 0) {
|
|
|
|
|
+ // No pixels found
|
|
|
|
|
+ this->value = OrderedImageRgbaU8();
|
|
|
|
|
+ } else {
|
|
|
|
|
+ this->value = image_create_RgbaU8(width, height);
|
|
|
|
|
+ int readIndex = colonIndex + 1;
|
|
|
|
|
+ for (int y = 0; y < height; y++) {
|
|
|
|
|
+ for (int x = 0; x < width; x++) {
|
|
|
|
|
+ int red = readHexaDecimal(text, readIndex);
|
|
|
|
|
+ int green = readHexaDecimal(text, readIndex);
|
|
|
|
|
+ int blue = readHexaDecimal(text, readIndex);
|
|
|
|
|
+ int alpha = readHexaDecimal(text, readIndex);
|
|
|
|
|
+ image_writePixel(this->value, x, y, ColorRgbaI32(red, green, blue, alpha));
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ return true;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static const String hexadecimals = U"0123456789ABCDEF";
|
|
|
|
|
+static void writeHexaDecimal(String &out, uint8_t value) {
|
|
|
|
|
+ string_appendChar(out, hexadecimals[(value & 0b11110000) >> 4]);
|
|
|
|
|
+ string_appendChar(out, hexadecimals[value & 0b00001111]);
|
|
|
|
|
+}
|
|
|
|
|
+String& PersistentImage::toStreamIndented(String &out, const ReadableString &indentation) const {
|
|
|
|
|
+ string_append(out, indentation);
|
|
|
|
|
+ if (string_length(this->path)) {
|
|
|
|
|
+ string_append(out, "File:", this->path);
|
|
|
|
|
+ } else if (image_exists(this->value)) {
|
|
|
|
|
+ int width = image_getWidth(this->value);
|
|
|
|
|
+ int height = image_getHeight(this->value);
|
|
|
|
|
+ string_append(out, width, U"x", height, U":");
|
|
|
|
|
+ for (int y = 0; y < height; y++) {
|
|
|
|
|
+ for (int x = 0; x < width; x++) {
|
|
|
|
|
+ ColorRgbaI32 color = image_readPixel_clamp(this->value, x, y);
|
|
|
|
|
+ writeHexaDecimal(out, color.red);
|
|
|
|
|
+ writeHexaDecimal(out, color.green);
|
|
|
|
|
+ writeHexaDecimal(out, color.blue);
|
|
|
|
|
+ writeHexaDecimal(out, color.alpha);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ string_append(out, U"None");
|
|
|
|
|
+ }
|
|
|
|
|
+ return out;
|
|
|
|
|
+}
|