diff options
author | Nico Weber <thakis@chromium.org> | 2023-02-18 20:23:04 -0500 |
---|---|---|
committer | Sam Atkins <atkinssj@gmail.com> | 2023-02-19 08:12:04 +0000 |
commit | 19e91e5211ea2394af85e694b4925d5976f671b2 (patch) | |
tree | e986f6725e374c0c455999ce79deee4446b60bbd /Userland | |
parent | 2504f2035c20e01f2cf6d75d6dc0b278a5f91671 (diff) | |
download | serenity-19e91e5211ea2394af85e694b4925d5976f671b2.zip |
LibGfx: Dedupe identical tag data objects when writing ICC data
With this, common v4 profiles, such as embedded into jpgs by iPhones
(when configured to write jpegs) or Pixel phones, are identical to
the input when reexported :^)
Diffstat (limited to 'Userland')
-rw-r--r-- | Userland/Libraries/LibGfx/ICC/BinaryWriter.cpp | 27 |
1 files changed, 16 insertions, 11 deletions
diff --git a/Userland/Libraries/LibGfx/ICC/BinaryWriter.cpp b/Userland/Libraries/LibGfx/ICC/BinaryWriter.cpp index 6af21719d5..df861cbdb5 100644 --- a/Userland/Libraries/LibGfx/ICC/BinaryWriter.cpp +++ b/Userland/Libraries/LibGfx/ICC/BinaryWriter.cpp @@ -238,21 +238,23 @@ static ErrorOr<ByteBuffer> encode_tag_data(TagData const& tag_data) return ByteBuffer {}; } -static ErrorOr<Vector<ByteBuffer>> encode_tag_datas(Profile const& profile) +static ErrorOr<Vector<ByteBuffer>> encode_tag_datas(Profile const& profile, HashMap<TagData*, size_t>& tag_data_map) { Vector<ByteBuffer> tag_data_bytes; + TRY(tag_data_bytes.try_ensure_capacity(profile.tag_count())); - // FIXME: If two tags refer to the same TagData object, write it just once to the output. - TRY(tag_data_bytes.try_resize(profile.tag_count())); - size_t i = 0; profile.for_each_tag([&](auto, auto tag_data) { + if (tag_data_map.contains(tag_data.ptr())) + return; + // FIXME: Come up with a way to allow TRY instead of MUST here. - tag_data_bytes[i++] = MUST(encode_tag_data(tag_data)); + tag_data_bytes.append(MUST(encode_tag_data(tag_data))); + MUST(tag_data_map.try_set(tag_data.ptr(), tag_data_bytes.size() - 1)); }); return tag_data_bytes; } -static ErrorOr<void> encode_tag_table(ByteBuffer& bytes, Profile const& profile, Vector<size_t> const& offsets, Vector<ByteBuffer> const& tag_data_bytes) +static ErrorOr<void> encode_tag_table(ByteBuffer& bytes, Profile const& profile, Vector<size_t> const& offsets, Vector<ByteBuffer> const& tag_data_bytes, HashMap<TagData*, size_t> const& tag_data_map) { VERIFY(bytes.size() >= sizeof(ICCHeader) + sizeof(u32) + profile.tag_count() * sizeof(TagTableEntry)); @@ -260,10 +262,12 @@ static ErrorOr<void> encode_tag_table(ByteBuffer& bytes, Profile const& profile, TagTableEntry* tag_table_entries = bit_cast<TagTableEntry*>(bytes.data() + sizeof(ICCHeader) + sizeof(u32)); int i = 0; - profile.for_each_tag([&](auto tag_signature, auto) { + profile.for_each_tag([&](auto tag_signature, auto tag_data) { tag_table_entries[i].tag_signature = tag_signature; - tag_table_entries[i].offset_to_beginning_of_tag_data_element = offsets[i]; - tag_table_entries[i].size_of_tag_data_element = tag_data_bytes[i].size(); + + auto index = tag_data_map.get(tag_data.ptr()).value(); + tag_table_entries[i].offset_to_beginning_of_tag_data_element = offsets[index]; + tag_table_entries[i].size_of_tag_data_element = tag_data_bytes[index].size(); ++i; }); @@ -324,7 +328,8 @@ ErrorOr<ByteBuffer> encode(Profile const& profile) // Valid profiles always have tags. Profile only represents valid profiles. VERIFY(profile.tag_count() > 0); - Vector<ByteBuffer> tag_data_bytes = TRY(encode_tag_datas(profile)); + HashMap<TagData*, size_t> tag_data_map; + Vector<ByteBuffer> tag_data_bytes = TRY(encode_tag_datas(profile, tag_data_map)); size_t tag_table_size = sizeof(u32) + profile.tag_count() * sizeof(TagTableEntry); size_t offset = sizeof(ICCHeader) + tag_table_size; @@ -344,7 +349,7 @@ ErrorOr<ByteBuffer> encode(Profile const& profile) for (size_t i = 0; i < tag_data_bytes.size(); ++i) memcpy(bytes.data() + offsets[i], tag_data_bytes[i].data(), tag_data_bytes[i].size()); - TRY(encode_tag_table(bytes, profile, offsets, tag_data_bytes)); + TRY(encode_tag_table(bytes, profile, offsets, tag_data_bytes, tag_data_map)); TRY(encode_header(bytes, profile)); return bytes; |