// 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" #include "../../../api/fileAPI.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, const ReadableString &fromPath) { 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 String absolutePath = file_getTheoreticalAbsolutePath(string_after(text, colonIndex), fromPath); this->value = image_load_RgbaU8(absolutePath); } 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; }