diff --git a/src/image.cpp b/src/image.cpp index affd75a..28ec5b0 100644 --- a/src/image.cpp +++ b/src/image.cpp @@ -4,6 +4,7 @@ #include "asset.h" #include +#include bool Image::load(std::string filename) { @@ -15,6 +16,16 @@ bool Image::load(std::string filename) file.close(); return false; } + + std::string name, base, ext; + std::regex r(R"((.*)[\\/]([^\\/]+)\.(\w+)$)"); + std::smatch m; + if (!std::regex_search(filename, m, r)) + return false; + file_base = m[1].str(); + file_name = m[2].str(); + file_ext = m[3].str(); + stbi_set_flip_vertically_on_load(false); uint8_t* buffer = stbi_load_from_memory(file.m_data, file.m_len, &width, &height, nullptr, 4); file.close(); @@ -36,6 +47,16 @@ bool Image::load_file(std::string filename) return false; comp = 4; m_data = std::unique_ptr(buffer); + + std::string name, base, ext; + std::regex r(R"((.*)[\\/]([^\\/]+)\.(\w+)$)"); + std::smatch m; + if (!std::regex_search(filename, m, r)) + return false; + file_base = m[1].str(); + file_name = m[2].str(); + file_ext = m[3].str(); + return true; } @@ -86,6 +107,9 @@ Image Image::resize(int w, int h) const { Image ret; ret.create(w, h); + ret.file_base = file_base; + ret.file_name = file_name; + ret.file_ext = file_ext; auto temp = (glm::u8vec4*)ret.data(); auto pixels = (glm::u8vec4*)data(); float x_ratio = ((float)(width - 1)) / w; @@ -122,6 +146,9 @@ Image Image::resize_power2() const { Image i; i.create(width, height); + i.file_base = file_base; + i.file_name = file_name; + i.file_ext = file_ext; std::copy(m_data.get(), m_data.get() + width * height * comp, i.m_data.get()); return i; } @@ -134,6 +161,9 @@ Image Image::resize_squared(const glm::u8vec4& bg) const if (width == height) { ret.create(width, height); + ret.file_base = file_base; + ret.file_name = file_name; + ret.file_ext = file_ext; std::copy(m_data.get(), m_data.get() + width * height * comp, ret.m_data.get()); } else @@ -152,6 +182,9 @@ Image Image::resize_squared(const glm::u8vec4& bg) const pad_y = (size - height) / 2; } ret.create(size, size); + ret.file_base = file_base; + ret.file_name = file_name; + ret.file_ext = file_ext; auto ptr_src = reinterpret_cast(m_data.get()); auto ptr_dst = reinterpret_cast(ret.m_data.get()); std::fill_n(ptr_dst, size * size, bg); @@ -160,3 +193,44 @@ Image Image::resize_squared(const glm::u8vec4& bg) const } return ret; } + +bool Image::read(BinaryStreamReader& r) +{ + Serializer::Descriptor d; + if (d.class_id != "image_png") + return false; + r >> d; + d.value("width", width); + d.value("height", height); + d.value("comp", comp); + file_base = wstr2str(d.value("file_base")); + file_name = wstr2str(d.value("file_name")); + file_ext = wstr2str(d.value("file_ext")); + auto img_raw = d.get("data"); + int png_width, png_height, png_comp; + m_data = std::unique_ptr(stbi_load_from_memory( + img_raw->data.data(), img_raw->data.size(), &png_width, &png_height, &png_comp, 4)); + return true; +} + +void Image::write(BinaryStreamWriter& w) const +{ + Serializer::Descriptor d; + d.class_id = "image_png"; + d.name = L"Image class"; + + d.props["width"] = std::make_shared(width); + d.props["height"] = std::make_shared(height); + d.props["comp"] = std::make_shared(comp); + d.props["file_base"] = std::make_shared(file_base); + d.props["file_name"] = std::make_shared(file_name); + d.props["file_ext"] = std::make_shared(file_ext); + + // really ugly way to compress the png and store it with a lambda + stbi_write_png_to_func([](void* context, void* data, int size) { + Serializer::Descriptor& d = *static_cast(context); + d.props["data"] = std::make_shared(std::vector((uint8_t*)data, (uint8_t*)data + size)); + }, &d, width, height, comp, m_data.get(), 0); + + w << d; +} diff --git a/src/image.h b/src/image.h index fe536d2..03d4b7d 100644 --- a/src/image.h +++ b/src/image.h @@ -1,12 +1,25 @@ #pragma once +#include "serializer.h" -class Image +class Image : public Serializer::Type { public: std::unique_ptr m_data; + std::string file_name; + std::string file_base; + std::string file_ext; int width = 0; int height = 0; int comp = 4; + Image() = default; + Image(const Serializer::VMArray::ImageData& d) + { + m_data = std::make_unique(d.size); + std::copy_n(d.data.get(), d.size, m_data.get()); + width = d.width; + height = d.height; + comp = d.comp; + } bool load(std::string filename); bool load_file(std::string filename); const uint8_t* data() const { return m_data.get(); } @@ -18,6 +31,7 @@ public: width = w; height = h; comp = 4; + file_base = file_name = file_ext = ""; m_data = data ? std::unique_ptr(data) : std::make_unique(size()); } void copy_from(const uint8_t* data) @@ -29,6 +43,7 @@ public: width = 0; height = 0; comp = 0; + file_base = file_name = file_ext = ""; m_data.reset(); } void flip(); @@ -38,4 +53,6 @@ public: Image resize(int w, int h) const; Image resize_power2() const; Image resize_squared(const glm::u8vec4& bg) const; + bool read(BinaryStreamReader& r) override; + void write(BinaryStreamWriter& w) const override; }; diff --git a/src/serializer.h b/src/serializer.h index d1a2415..fb5e15a 100644 --- a/src/serializer.h +++ b/src/serializer.h @@ -1,6 +1,5 @@ #pragma once #include "binary_stream.h" -#include "image.h" #include "util.h" #include "log.h" @@ -631,25 +630,81 @@ public: { } }; +/* + struct ImagePNG : public Type + { + using native_type = Image; + Image data; + + bool read(BinaryStreamReader& r) override + { + Descriptor d; + if (d.class_id != "image_png") + return false; + r >> d; + d.value("width", data.width); + d.value("height", data.height); + d.value("comp", data.comp); + data.file_base = wstr2str(d.value("file_base")); + data.file_name = wstr2str(d.value("file_name")); + data.file_ext = wstr2str(d.value("file_ext")); + auto img_raw = d.get("data"); + int png_width, png_height, png_comp; + data.m_data = std::unique_ptr(stbi_load_from_memory( + img_raw->data.data(), img_raw->data.size(), &png_width, &png_height, &png_comp, 4)); + return true; + } + + void write(BinaryStreamWriter& w) const override + { + Descriptor d; + d.class_id = "image_png"; + d.name = L"Image class"; + + d.props["width"] = std::make_shared(data.width); + d.props["height"] = std::make_shared(data.height); + d.props["comp"] = std::make_shared(data.comp); + d.props["file_base"] = std::make_shared(data.file_base); + d.props["file_name"] = std::make_shared(data.file_name); + d.props["file_ext"] = std::make_shared(data.file_ext); + + // really ugly way to compress the png and store it with a lambda + stbi_write_png_to_func([](void* context, void* data, int size) { + Descriptor& d = *static_cast(context); + d.props["data"] = std::make_shared(std::vector((uint8_t*)data, (uint8_t*)data + size)); + }, &d, data.width, data.height, data.comp, data.m_data.get(), 0); + + w << d; + } + }; +*/ struct VMArray : public Type { + struct ImageData + { + std::unique_ptr data; + size_t size = 0; + int width = 0; + int height = 0; + int comp = 0; + }; uint32_t version; // = 3 Rectangle rect; std::vector channels; VMArray() = default; VMArray(uint32_t version, const Rectangle& rect) : version(version), rect(rect) { } - std::shared_ptr image(bool grayscale, bool invert) const + ImageData image(bool grayscale, bool invert) const { int nc = (int)channels.size(); auto pixels = (channels[0].depth >> 3) * rect.area(); if (nc == 1 || nc >= 3) { - auto img = std::make_shared(); - img->comp = 4; - img->width = rect.width(); - img->height = rect.height(); - img->m_data = std::make_unique(pixels * 4); - auto out = reinterpret_cast(img->m_data.get()); + ImageData img; + img.comp = 4; + img.width = rect.width(); + img.height = rect.height(); + img.data = std::make_unique(pixels * 4); + auto out = reinterpret_cast(img.data.get()); if (grayscale) { auto const& raw = channels[0].data; @@ -690,7 +745,7 @@ public: { LOG("Error image with %ld channels\n", channels.size()); } - return nullptr; + return {}; } virtual bool read(BinaryStreamReader& r) override {