diff --git a/src/abr.cpp b/src/abr.cpp index 37c40bd..e09d608 100644 --- a/src/abr.cpp +++ b/src/abr.cpp @@ -1,40 +1,6 @@ #include "pch.h" #include "abr.h" -//std::map> ABR::m_parser_table; -//{ -// { "VlLs", std::bind(&ABR::parse_vlls, this) }, -// { "TEXT", std::bind(&ABR::parse_text, this) }, -// { "Objc", std::bind(&ABR::parse_objc, this) }, -// { "UntF", std::bind(&ABR::parse_untf, this) }, -// { "bool", std::bind(&ABR::parse_bool, this) }, -// { "long", std::bind(&ABR::parse_long, this) }, -// { "doub", std::bind(&ABR::parse_doub, this) }, -// { "enum", std::bind(&ABR::parse_enum, this) }, -// //{ "Dmtr", &ABR::parse_prop }, -// //{ "Hrdn", &ABR::parse_prop }, -// //{ "Angl", &ABR::parse_prop }, -// //{ "Rndn", &ABR::parse_prop }, -// //{ "Spcn", &ABR::parse_prop }, -// //{ "Intr", &ABR::parse_prop }, -// //{ "flipX", &ABR::parse_prop }, -// //{ "flipY", &ABR::parse_prop }, -// //{ "useTipDynamics", &ABR::parse_prop }, -// //{ "useScatter", &ABR::parse_prop }, -// //{ "dualBrush", &ABR::parse_prop }, -// //{ "useDualBrush", &ABR::parse_prop }, -// //{ "brushGroup", &ABR::parse_prop }, -// //{ "useBrushGroup", &ABR::parse_prop }, -// //{ "useTexture", &ABR::parse_prop }, -// //{ "usePaintDynamics", &ABR::parse_prop }, -// //{ "useColorDynamics", &ABR::parse_prop }, -// //{ "Wtdg", &ABR::parse_prop }, -// //{ "Nose", &ABR::parse_prop }, -// //{ "Rpt ", &ABR::parse_prop }, -// //{ "useBrushSize", &ABR::parse_prop }, -// //{ "useBrushPose", &ABR::parse_prop }, -//}; - bool ABR::section_desc() { auto sz = align4(ru32()); @@ -59,8 +25,83 @@ bool ABR::section_samp() bool ABR::section_patt() { - auto sz = align4(ru32()); - skip(sz); + auto sz = ru32(); + auto sz_aligned = align4(sz); + + auto start = pos(); + auto end = start + sz; + while (pos() < end) + { + auto length = ru32(); // length of this pattern + auto version = ru32(); // = 1 + // Bitmap = 0; Grayscale = 1; Indexed = 2; RGB = 3; + // CMYK = 4; Multichannel = 7; Duotone = 8; Lab = 9 + auto image_mode = ru32(); + if (!(image_mode == 1 || image_mode == 3)) + { + skip(length - 8); + snap(); + continue; + } + auto point = rpoint(); + auto name = rwstring(); + auto uid = rpascal(); + + // Index color table (256 * 3 RGB values): + // only present when image mode is indexed color + // read(...); + // no worries indexed is skipped anyway + + // Virtual Memory Array List + { + auto version = ru32(); // = 3 + auto length = ru32(); + auto rect = rrect(); + auto channels = ru32(); + // The following is a virtual memory array, + // repeated for the number of channels + // + one for a user mask + one for a sheet mask. + channels += 2; // user and sheet mask + std::vector out(rect.area()); + bool valid = false; + for (int ch = 0; ch < channels; ch++) + { + auto array_written = ru32(); // skip if 0 + if (array_written == 0) + continue; + auto length = ru32(); // skip if 0, length is from the next field to the end + if (length == 0) + continue; + auto depth = ru32(); // Pixel depth: 1, 8, 16 or 32 + auto rect = rrect(); + auto depth2 = ru16(); // again? + auto compression = ru8(); // 1 = zip + if (compression != 0 || depth != 8) + { + skip(length - 23); + continue; + } + int data_size = (depth >> 3) * rect.area(); + auto raw = rraw(data_size); + if (image_mode == 3) + { + for (int i = 0; i < data_size; i++) + out[i][ch] = raw[i]; + } + else + { + for (int i = 0; i < data_size; i++) + out[i] = glm::u8vec3(raw[i]); + } + valid = true; + } + if (valid) + stbi_write_png(fmt::format("{}.png", uid).c_str(), rect.width(), rect.height(), 3, out.data(), 0); + snap(); + } + } + + //skip(sz); return true; } @@ -160,6 +201,13 @@ std::shared_ptr ABR::parse_enum() return ret; } +std::shared_ptr ABR::parse_tdta() +{ + auto ret = std::make_shared(); + ret->data = rraw(); + return ret; +} + ABR::ABR() { m_parser_table = std::map> @@ -172,28 +220,7 @@ ABR::ABR() { "long", std::bind(&ABR::parse_long, this) }, { "doub", std::bind(&ABR::parse_doub, this) }, { "enum", std::bind(&ABR::parse_enum, this) }, - //{ "Dmtr", &ABR::parse_prop }, - //{ "Hrdn", &ABR::parse_prop }, - //{ "Angl", &ABR::parse_prop }, - //{ "Rndn", &ABR::parse_prop }, - //{ "Spcn", &ABR::parse_prop }, - //{ "Intr", &ABR::parse_prop }, - //{ "flipX", &ABR::parse_prop }, - //{ "flipY", &ABR::parse_prop }, - //{ "useTipDynamics", &ABR::parse_prop }, - //{ "useScatter", &ABR::parse_prop }, - //{ "dualBrush", &ABR::parse_prop }, - //{ "useDualBrush", &ABR::parse_prop }, - //{ "brushGroup", &ABR::parse_prop }, - //{ "useBrushGroup", &ABR::parse_prop }, - //{ "useTexture", &ABR::parse_prop }, - //{ "usePaintDynamics", &ABR::parse_prop }, - //{ "useColorDynamics", &ABR::parse_prop }, - //{ "Wtdg", &ABR::parse_prop }, - //{ "Nose", &ABR::parse_prop }, - //{ "Rpt ", &ABR::parse_prop }, - //{ "useBrushSize", &ABR::parse_prop }, - //{ "useBrushPose", &ABR::parse_prop }, + { "tdta", std::bind(&ABR::parse_tdta, this) }, }; } @@ -215,6 +242,10 @@ bool ABR::open(const std::string& path) { section_desc(); } + else if (t == "patt") + { + section_patt(); + } else { printf("skip section %s\n", t.c_str()); diff --git a/src/abr.h b/src/abr.h index fb1f603..55ba274 100644 --- a/src/abr.h +++ b/src/abr.h @@ -33,7 +33,10 @@ public: m_byte_order = byte_order; m_swap = byte_order == ByteOrder::Host ? false : byte_order != sys_order(); } + size_t pos() { return std::distance(m_ptr, m_cur); } void skip(size_t bytes) { m_cur += bytes; } + // snap to the next 4-alignment + void snap() { if ((size_t)m_cur % 4 != 0) m_cur += 4 - (size_t)m_cur % 4; } bool eof() { return std::distance(m_ptr, m_cur) >= m_size; } bool has_data(size_t sz) { return std::distance(m_ptr, m_cur + sz) < m_size; } uint8_t ru8() { return read(); } @@ -65,6 +68,23 @@ public: std::swap(ptr[i * 2], ptr[i * 2 + 1]); return std::wstring((wchar_t*)ptr, len); } + std::string rpascal() + { + auto len = ru8(); + return rstring(len); + } + std::vector rraw() + { + auto size = ru32(); + return rraw(size); + } + std::vector rraw(size_t bytes) + { + std::vector ret(bytes); + std::copy_n(m_cur, bytes, ret.data()); + skip(bytes); + return ret; + } protected: template inline T align4(T x) { return ((x - T{1}) & (~(T{3}))) + T{4}; } template T read() @@ -161,10 +181,9 @@ class ABR : public BinaryStream Type::Vec items; virtual std::string str(int indent, const std::string& prefix) const override { - //return std::string(indent, '-') + prefix + fmt::format("list: {} items", items.size()); - auto ret = std::string(indent, '-') + fmt::format("list: {} props:\n", items.size()); + auto ret = std::string(indent, '-') + fmt::format("list: {} props:", items.size()); for (int i = 0; i < items.size(); i++) - ret += items[i]->str(indent + 1, fmt::format("{}) ", i) + "\n"); + ret += "\n" + items[i]->str(indent + 1, fmt::format("{}) ", i)); return ret; } }; @@ -213,6 +232,12 @@ class ABR : public BinaryStream { return std::string(indent, '-') + prefix + fmt::format("bool: {}", value); } }; struct Alias : public Type { }; + struct RawData : public Type + { + std::vector data; + virtual std::string str(int indent, const std::string& prefix) const override + { return std::string(indent, '-') + prefix + fmt::format("raw: {} bytes", data.size()); } + }; struct Descriptor : public Type { std::wstring name; @@ -220,24 +245,60 @@ class ABR : public BinaryStream Type::Map props; virtual std::string str(int indent, const std::string& prefix) const override { - auto ret = std::string(indent, '-') + fmt::format("objc: {} props:", props.size()); + auto ret = std::string(indent, '-') + + fmt::format("objc {} ({}): {} props:", wstr2str(name), class_id, props.size()); for (const auto& p : props) ret += "\n" + p.second->str(indent + 1, fmt::format("'{}' ", p.first)); return ret; } }; + struct Rectangle : public Type + { + uint32_t top; + uint32_t left; + uint32_t bottom; + uint32_t right; + uint32_t area() const { return (right - left) * (bottom - top); } + uint32_t width() const { return right - left; } + uint32_t height() const { return bottom - top; } + virtual std::string str(int indent, const std::string& prefix) const override + { return std::string(indent, '-') + prefix + fmt::format("rect: [{}, {}, {}, {}]", top, left, bottom, right); } + }; + struct Point : public Type + { + uint32_t x; + uint32_t y; + virtual std::string str(int indent, const std::string& prefix) const override + { return std::string(indent, '-') + prefix + fmt::format("point: [{}, {}]", x, y); } + }; public: ABR(); bool open(const std::string& path); private: - inline std::string rkey_or_string() + std::string rkey_or_string() { auto len = ru32(); if (len == 0) len = 4; return rstring(len); } + Rectangle rrect() + { + Rectangle ret; + ret.top = ru32(); + ret.left = ru32(); + ret.bottom = ru32(); + ret.right = ru32(); + return ret; + } + Point rpoint() + { + Point ret; + ret.x = ru16(); + ret.y = ru16(); + return ret; + } bool section_desc(); bool section_samp(); bool section_patt(); @@ -249,7 +310,7 @@ private: std::shared_ptr parse_long(); std::shared_ptr parse_doub(); std::shared_ptr parse_enum(); - //Type::Ref parse_prop(); + std::shared_ptr parse_tdta(); Type::Ref call(std::string t) { if (m_parser_table.find(t) != m_parser_table.end())