add image class serialization
This commit is contained in:
@@ -4,6 +4,7 @@
|
|||||||
#include "asset.h"
|
#include "asset.h"
|
||||||
|
|
||||||
#include <stb/stb_image.h>
|
#include <stb/stb_image.h>
|
||||||
|
#include <stb/stb_image_write.h>
|
||||||
|
|
||||||
bool Image::load(std::string filename)
|
bool Image::load(std::string filename)
|
||||||
{
|
{
|
||||||
@@ -15,6 +16,16 @@ bool Image::load(std::string filename)
|
|||||||
file.close();
|
file.close();
|
||||||
return false;
|
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);
|
stbi_set_flip_vertically_on_load(false);
|
||||||
uint8_t* buffer = stbi_load_from_memory(file.m_data, file.m_len, &width, &height, nullptr, 4);
|
uint8_t* buffer = stbi_load_from_memory(file.m_data, file.m_len, &width, &height, nullptr, 4);
|
||||||
file.close();
|
file.close();
|
||||||
@@ -36,6 +47,16 @@ bool Image::load_file(std::string filename)
|
|||||||
return false;
|
return false;
|
||||||
comp = 4;
|
comp = 4;
|
||||||
m_data = std::unique_ptr<uint8_t[]>(buffer);
|
m_data = std::unique_ptr<uint8_t[]>(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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,6 +107,9 @@ Image Image::resize(int w, int h) const
|
|||||||
{
|
{
|
||||||
Image ret;
|
Image ret;
|
||||||
ret.create(w, h);
|
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 temp = (glm::u8vec4*)ret.data();
|
||||||
auto pixels = (glm::u8vec4*)data();
|
auto pixels = (glm::u8vec4*)data();
|
||||||
float x_ratio = ((float)(width - 1)) / w;
|
float x_ratio = ((float)(width - 1)) / w;
|
||||||
@@ -122,6 +146,9 @@ Image Image::resize_power2() const
|
|||||||
{
|
{
|
||||||
Image i;
|
Image i;
|
||||||
i.create(width, height);
|
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());
|
std::copy(m_data.get(), m_data.get() + width * height * comp, i.m_data.get());
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
@@ -134,6 +161,9 @@ Image Image::resize_squared(const glm::u8vec4& bg) const
|
|||||||
if (width == height)
|
if (width == height)
|
||||||
{
|
{
|
||||||
ret.create(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());
|
std::copy(m_data.get(), m_data.get() + width * height * comp, ret.m_data.get());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -152,6 +182,9 @@ Image Image::resize_squared(const glm::u8vec4& bg) const
|
|||||||
pad_y = (size - height) / 2;
|
pad_y = (size - height) / 2;
|
||||||
}
|
}
|
||||||
ret.create(size, size);
|
ret.create(size, size);
|
||||||
|
ret.file_base = file_base;
|
||||||
|
ret.file_name = file_name;
|
||||||
|
ret.file_ext = file_ext;
|
||||||
auto ptr_src = reinterpret_cast<glm::u8vec4*>(m_data.get());
|
auto ptr_src = reinterpret_cast<glm::u8vec4*>(m_data.get());
|
||||||
auto ptr_dst = reinterpret_cast<glm::u8vec4*>(ret.m_data.get());
|
auto ptr_dst = reinterpret_cast<glm::u8vec4*>(ret.m_data.get());
|
||||||
std::fill_n(ptr_dst, size * size, bg);
|
std::fill_n(ptr_dst, size * size, bg);
|
||||||
@@ -160,3 +193,44 @@ Image Image::resize_squared(const glm::u8vec4& bg) const
|
|||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Image::read(BinaryStreamReader& r)
|
||||||
|
{
|
||||||
|
Serializer::Descriptor d;
|
||||||
|
if (d.class_id != "image_png")
|
||||||
|
return false;
|
||||||
|
r >> d;
|
||||||
|
d.value<Serializer::Integer>("width", width);
|
||||||
|
d.value<Serializer::Integer>("height", height);
|
||||||
|
d.value<Serializer::Integer>("comp", comp);
|
||||||
|
file_base = wstr2str(d.value<Serializer::String>("file_base"));
|
||||||
|
file_name = wstr2str(d.value<Serializer::String>("file_name"));
|
||||||
|
file_ext = wstr2str(d.value<Serializer::String>("file_ext"));
|
||||||
|
auto img_raw = d.get<Serializer::RawData>("data");
|
||||||
|
int png_width, png_height, png_comp;
|
||||||
|
m_data = std::unique_ptr<uint8_t[]>(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<Serializer::Integer>(width);
|
||||||
|
d.props["height"] = std::make_shared<Serializer::Integer>(height);
|
||||||
|
d.props["comp"] = std::make_shared<Serializer::Integer>(comp);
|
||||||
|
d.props["file_base"] = std::make_shared<Serializer::String>(file_base);
|
||||||
|
d.props["file_name"] = std::make_shared<Serializer::String>(file_name);
|
||||||
|
d.props["file_ext"] = std::make_shared<Serializer::String>(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<Serializer::Descriptor*>(context);
|
||||||
|
d.props["data"] = std::make_shared<Serializer::RawData>(std::vector<uint8_t>((uint8_t*)data, (uint8_t*)data + size));
|
||||||
|
}, &d, width, height, comp, m_data.get(), 0);
|
||||||
|
|
||||||
|
w << d;
|
||||||
|
}
|
||||||
|
|||||||
19
src/image.h
19
src/image.h
@@ -1,12 +1,25 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
#include "serializer.h"
|
||||||
|
|
||||||
class Image
|
class Image : public Serializer::Type
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
std::unique_ptr<uint8_t[]> m_data;
|
std::unique_ptr<uint8_t[]> m_data;
|
||||||
|
std::string file_name;
|
||||||
|
std::string file_base;
|
||||||
|
std::string file_ext;
|
||||||
int width = 0;
|
int width = 0;
|
||||||
int height = 0;
|
int height = 0;
|
||||||
int comp = 4;
|
int comp = 4;
|
||||||
|
Image() = default;
|
||||||
|
Image(const Serializer::VMArray::ImageData& d)
|
||||||
|
{
|
||||||
|
m_data = std::make_unique<uint8_t[]>(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(std::string filename);
|
||||||
bool load_file(std::string filename);
|
bool load_file(std::string filename);
|
||||||
const uint8_t* data() const { return m_data.get(); }
|
const uint8_t* data() const { return m_data.get(); }
|
||||||
@@ -18,6 +31,7 @@ public:
|
|||||||
width = w;
|
width = w;
|
||||||
height = h;
|
height = h;
|
||||||
comp = 4;
|
comp = 4;
|
||||||
|
file_base = file_name = file_ext = "";
|
||||||
m_data = data ? std::unique_ptr<uint8_t[]>(data) : std::make_unique<uint8_t[]>(size());
|
m_data = data ? std::unique_ptr<uint8_t[]>(data) : std::make_unique<uint8_t[]>(size());
|
||||||
}
|
}
|
||||||
void copy_from(const uint8_t* data)
|
void copy_from(const uint8_t* data)
|
||||||
@@ -29,6 +43,7 @@ public:
|
|||||||
width = 0;
|
width = 0;
|
||||||
height = 0;
|
height = 0;
|
||||||
comp = 0;
|
comp = 0;
|
||||||
|
file_base = file_name = file_ext = "";
|
||||||
m_data.reset();
|
m_data.reset();
|
||||||
}
|
}
|
||||||
void flip();
|
void flip();
|
||||||
@@ -38,4 +53,6 @@ public:
|
|||||||
Image resize(int w, int h) const;
|
Image resize(int w, int h) const;
|
||||||
Image resize_power2() const;
|
Image resize_power2() const;
|
||||||
Image resize_squared(const glm::u8vec4& bg) const;
|
Image resize_squared(const glm::u8vec4& bg) const;
|
||||||
|
bool read(BinaryStreamReader& r) override;
|
||||||
|
void write(BinaryStreamWriter& w) const override;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "binary_stream.h"
|
#include "binary_stream.h"
|
||||||
#include "image.h"
|
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "log.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<Integer>("width", data.width);
|
||||||
|
d.value<Integer>("height", data.height);
|
||||||
|
d.value<Integer>("comp", data.comp);
|
||||||
|
data.file_base = wstr2str(d.value<Serializer::String>("file_base"));
|
||||||
|
data.file_name = wstr2str(d.value<Serializer::String>("file_name"));
|
||||||
|
data.file_ext = wstr2str(d.value<Serializer::String>("file_ext"));
|
||||||
|
auto img_raw = d.get<RawData>("data");
|
||||||
|
int png_width, png_height, png_comp;
|
||||||
|
data.m_data = std::unique_ptr<uint8_t[]>(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<Integer>(data.width);
|
||||||
|
d.props["height"] = std::make_shared<Integer>(data.height);
|
||||||
|
d.props["comp"] = std::make_shared<Integer>(data.comp);
|
||||||
|
d.props["file_base"] = std::make_shared<Serializer::String>(data.file_base);
|
||||||
|
d.props["file_name"] = std::make_shared<Serializer::String>(data.file_name);
|
||||||
|
d.props["file_ext"] = std::make_shared<Serializer::String>(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<Descriptor*>(context);
|
||||||
|
d.props["data"] = std::make_shared<RawData>(std::vector<uint8_t>((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 VMArray : public Type
|
||||||
{
|
{
|
||||||
|
struct ImageData
|
||||||
|
{
|
||||||
|
std::unique_ptr<uint8_t[]> data;
|
||||||
|
size_t size = 0;
|
||||||
|
int width = 0;
|
||||||
|
int height = 0;
|
||||||
|
int comp = 0;
|
||||||
|
};
|
||||||
uint32_t version; // = 3
|
uint32_t version; // = 3
|
||||||
Rectangle rect;
|
Rectangle rect;
|
||||||
std::vector<Channel> channels;
|
std::vector<Channel> channels;
|
||||||
VMArray() = default;
|
VMArray() = default;
|
||||||
VMArray(uint32_t version, const Rectangle& rect) : version(version), rect(rect) { }
|
VMArray(uint32_t version, const Rectangle& rect) : version(version), rect(rect) { }
|
||||||
std::shared_ptr<Image> image(bool grayscale, bool invert) const
|
ImageData image(bool grayscale, bool invert) const
|
||||||
{
|
{
|
||||||
int nc = (int)channels.size();
|
int nc = (int)channels.size();
|
||||||
auto pixels = (channels[0].depth >> 3) * rect.area();
|
auto pixels = (channels[0].depth >> 3) * rect.area();
|
||||||
if (nc == 1 || nc >= 3)
|
if (nc == 1 || nc >= 3)
|
||||||
{
|
{
|
||||||
auto img = std::make_shared<Image>();
|
ImageData img;
|
||||||
img->comp = 4;
|
img.comp = 4;
|
||||||
img->width = rect.width();
|
img.width = rect.width();
|
||||||
img->height = rect.height();
|
img.height = rect.height();
|
||||||
img->m_data = std::make_unique<uint8_t[]>(pixels * 4);
|
img.data = std::make_unique<uint8_t[]>(pixels * 4);
|
||||||
auto out = reinterpret_cast<glm::u8vec4*>(img->m_data.get());
|
auto out = reinterpret_cast<glm::u8vec4*>(img.data.get());
|
||||||
if (grayscale)
|
if (grayscale)
|
||||||
{
|
{
|
||||||
auto const& raw = channels[0].data;
|
auto const& raw = channels[0].data;
|
||||||
@@ -690,7 +745,7 @@ public:
|
|||||||
{
|
{
|
||||||
LOG("Error image with %ld channels\n", channels.size());
|
LOG("Error image with %ld channels\n", channels.size());
|
||||||
}
|
}
|
||||||
return nullptr;
|
return {};
|
||||||
}
|
}
|
||||||
virtual bool read(BinaryStreamReader& r) override
|
virtual bool read(BinaryStreamReader& r) override
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user