summaryrefslogtreecommitdiff
path: root/Libraries
diff options
context:
space:
mode:
authorPaul Roukema <roukemap@gmail.com>2020-06-16 23:24:01 -0400
committerAndreas Kling <kling@serenityos.org>2020-06-21 17:41:52 +0200
commit82a75bcf5fc1cffb00e45f06723ef06ce42c8830 (patch)
treef68705e301b1eae1f6dd82b820394ab76a99f89e /Libraries
parentb1e3f728a1495d3c88f4deee8c6814403326196f (diff)
downloadserenity-82a75bcf5fc1cffb00e45f06723ef06ce42c8830.zip
LibGfx: Prefer the largest image in the file when loading an ICO
Since the current image handling APIs don't provide a way to handle a file which can contain multiple images, we just pick the largest one. This gives the best chance of a good looking result.
Diffstat (limited to 'Libraries')
-rw-r--r--Libraries/LibGfx/ICOLoader.cpp38
1 files changed, 29 insertions, 9 deletions
diff --git a/Libraries/LibGfx/ICOLoader.cpp b/Libraries/LibGfx/ICOLoader.cpp
index 3dd844d8fa..3026ce0f9d 100644
--- a/Libraries/LibGfx/ICOLoader.cpp
+++ b/Libraries/LibGfx/ICOLoader.cpp
@@ -113,6 +113,7 @@ struct ICOLoadingContext {
const u8* data { nullptr };
size_t data_size { 0 };
Vector<ImageDescriptor> images;
+ size_t largest_index;
};
RefPtr<Gfx::Bitmap> load_ico(const StringView& path)
@@ -164,6 +165,21 @@ static Optional<ImageDescriptor> decode_ico_direntry(BufferStream& stream)
return { desc };
}
+static size_t find_largest_image(const ICOLoadingContext& context)
+{
+ size_t max_area = 0;
+ size_t index = 0;
+ size_t largest_index = 0;
+ for(const auto& desc : context.images) {
+ if (desc.width * desc.height > max_area) {
+ max_area = desc.width * desc.height;
+ largest_index = index;
+ }
+ ++index;
+ }
+ return largest_index;
+}
+
static bool load_ico_directory(ICOLoadingContext& context)
{
auto buffer = ByteBuffer::wrap(context.data, context.data_size);
@@ -197,6 +213,7 @@ static bool load_ico_directory(ICOLoadingContext& context)
#endif
context.images.append(desc);
}
+ context.largest_index = find_largest_image(context);
context.state = ICOLoadingContext::State::DirectoryDecoded;
return true;
}
@@ -292,7 +309,7 @@ static bool load_ico_bmp(ICOLoadingContext& context, ImageDescriptor& desc)
return true;
}
-static bool load_ico_bitmap(ICOLoadingContext& context, size_t index)
+static bool load_ico_bitmap(ICOLoadingContext& context, Optional<size_t> index)
{
if (context.state < ICOLoadingContext::State::DirectoryDecoded) {
if (!load_ico_directory(context)) {
@@ -301,18 +318,21 @@ static bool load_ico_bitmap(ICOLoadingContext& context, size_t index)
}
context.state = ICOLoadingContext::State::DirectoryDecoded;
}
- if (index >= context.images.size()) {
+ size_t real_index = context.largest_index;
+ if (index.has_value())
+ real_index = index.value();
+ if (real_index >= context.images.size()) {
return false;
}
- ImageDescriptor& desc = context.images[index];
+ ImageDescriptor& desc = context.images[real_index];
PNGImageDecoderPlugin png_decoder(context.data + desc.offset, desc.size);
if (png_decoder.sniff()) {
desc.bitmap = png_decoder.bitmap();
if (!desc.bitmap) {
#ifdef ICO_DEBUG
- printf("load_ico_bitmap: failed to load PNG encoded image index: %lu\n", index);
+ printf("load_ico_bitmap: failed to load PNG encoded image index: %lu\n", real_index);
#endif
return false;
}
@@ -320,7 +340,7 @@ static bool load_ico_bitmap(ICOLoadingContext& context, size_t index)
} else {
if (!load_ico_bmp(context, desc)) {
#ifdef ICO_DEBUG
- printf("load_ico_bitmap: failed to load BMP encoded image index: %lu\n", index);
+ printf("load_ico_bitmap: failed to load BMP encoded image index: %lu\n", real_index);
#endif
return false;
}
@@ -351,7 +371,7 @@ IntSize ICOImageDecoderPlugin::size()
m_context->state = ICOLoadingContext::State::DirectoryDecoded;
}
- return { m_context->images[0].width, m_context->images[0].height };
+ return { m_context->images[m_context->largest_index].width, m_context->images[m_context->largest_index].height };
}
RefPtr<Gfx::Bitmap> ICOImageDecoderPlugin::bitmap()
@@ -361,7 +381,7 @@ RefPtr<Gfx::Bitmap> ICOImageDecoderPlugin::bitmap()
if (m_context->state < ICOLoadingContext::State::BitmapDecoded) {
// NOTE: This forces the chunk decoding to happen.
- bool success = load_ico_bitmap(*m_context, 0);
+ bool success = load_ico_bitmap(*m_context, {});
if (!success) {
m_context->state = ICOLoadingContext::State::Error;
return nullptr;
@@ -369,8 +389,8 @@ RefPtr<Gfx::Bitmap> ICOImageDecoderPlugin::bitmap()
m_context->state = ICOLoadingContext::State::BitmapDecoded;
}
- ASSERT(m_context->images[0].bitmap);
- return m_context->images[0].bitmap;
+ ASSERT(m_context->images[m_context->largest_index].bitmap);
+ return m_context->images[m_context->largest_index].bitmap;
}
void ICOImageDecoderPlugin::set_volatile()