mirror of
https://github.com/RGBCube/serenity
synced 2025-05-14 08:54:58 +00:00
LibGfx+Fallout: Make ImageDecoder return ErrorOr
...from try_create_for_raw_bytes(). If a plugin returns `true` from sniff but then fails when calling its `create()` method, we now no longer swallow that error. Allows `image` (and other places in the system) to print a more actionable error if early image headers are invalid. (We now no longer try to find another plugin that can also handle the image.) Fixes a regression from #20063 / #19893 -- before then, we didn't do fallible work this early.
This commit is contained in:
parent
be5e7a360f
commit
2e2cae26c6
12 changed files with 22 additions and 22 deletions
|
@ -403,7 +403,7 @@ ErrorOr<void> PropertiesWindow::create_font_tab(GUI::TabWidget& tab_widget, Nonn
|
||||||
|
|
||||||
ErrorOr<void> PropertiesWindow::create_image_tab(GUI::TabWidget& tab_widget, NonnullOwnPtr<Core::MappedFile> mapped_file, StringView mime_type)
|
ErrorOr<void> PropertiesWindow::create_image_tab(GUI::TabWidget& tab_widget, NonnullOwnPtr<Core::MappedFile> mapped_file, StringView mime_type)
|
||||||
{
|
{
|
||||||
auto image_decoder = Gfx::ImageDecoder::try_create_for_raw_bytes(mapped_file->bytes(), mime_type);
|
auto image_decoder = TRY(Gfx::ImageDecoder::try_create_for_raw_bytes(mapped_file->bytes(), mime_type));
|
||||||
if (!image_decoder)
|
if (!image_decoder)
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
|
|
|
@ -224,7 +224,7 @@ ErrorOr<void> ViewWidget::try_open_file(String const& path, Core::File& file)
|
||||||
Vector<Animation::Frame> frames;
|
Vector<Animation::Frame> frames;
|
||||||
// Note: Doing this check only requires reading the header of images
|
// Note: Doing this check only requires reading the header of images
|
||||||
// (so if the image is not vector graphics it can be still be decoded OOP).
|
// (so if the image is not vector graphics it can be still be decoded OOP).
|
||||||
if (auto decoder = Gfx::ImageDecoder::try_create_for_raw_bytes(file_data); decoder && decoder->natural_frame_format() == Gfx::NaturalFrameFormat::Vector) {
|
if (auto decoder = TRY(Gfx::ImageDecoder::try_create_for_raw_bytes(file_data)); decoder && decoder->natural_frame_format() == Gfx::NaturalFrameFormat::Vector) {
|
||||||
// Use in-process decoding for vector graphics.
|
// Use in-process decoding for vector graphics.
|
||||||
is_animated = decoder->is_animated();
|
is_animated = decoder->is_animated();
|
||||||
loop_count = decoder->loop_count();
|
loop_count = decoder->loop_count();
|
||||||
|
|
|
@ -341,11 +341,12 @@ void MapWidget::process_tile_queue()
|
||||||
m_first_image_loaded = true;
|
m_first_image_loaded = true;
|
||||||
|
|
||||||
// Decode loaded PNG image data
|
// Decode loaded PNG image data
|
||||||
auto decoder = Gfx::ImageDecoder::try_create_for_raw_bytes(payload, "image/png");
|
auto decoder_or_err = Gfx::ImageDecoder::try_create_for_raw_bytes(payload, "image/png");
|
||||||
if (!decoder || (decoder->frame_count() == 0)) {
|
if (decoder_or_err.is_error() || !decoder_or_err.value() || (decoder_or_err.value()->frame_count() == 0)) {
|
||||||
dbgln("Maps: Can't decode image: {}", url);
|
dbgln("Maps: Can't decode image: {}", url);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
auto decoder = decoder_or_err.release_value();
|
||||||
m_tiles.set(tile_key, decoder->frame(0).release_value_but_fixme_should_propagate_errors().image);
|
m_tiles.set(tile_key, decoder->frame(0).release_value_but_fixme_should_propagate_errors().image);
|
||||||
|
|
||||||
// FIXME: only update the part of the screen that this tile covers
|
// FIXME: only update the part of the screen that this tile covers
|
||||||
|
|
|
@ -79,7 +79,7 @@ void ImageWidget::load_from_file(StringView path)
|
||||||
|
|
||||||
auto& mapped_file = *file_or_error.value();
|
auto& mapped_file = *file_or_error.value();
|
||||||
auto mime_type = Core::guess_mime_type_based_on_filename(path);
|
auto mime_type = Core::guess_mime_type_based_on_filename(path);
|
||||||
m_image_decoder = Gfx::ImageDecoder::try_create_for_raw_bytes(mapped_file.bytes(), mime_type);
|
m_image_decoder = MUST(Gfx::ImageDecoder::try_create_for_raw_bytes(mapped_file.bytes(), mime_type));
|
||||||
VERIFY(m_image_decoder);
|
VERIFY(m_image_decoder);
|
||||||
|
|
||||||
auto frame = m_image_decoder->frame(0).release_value_but_fixme_should_propagate_errors();
|
auto frame = m_image_decoder->frame(0).release_value_but_fixme_should_propagate_errors();
|
||||||
|
|
|
@ -147,7 +147,7 @@ ErrorOr<NonnullRefPtr<Bitmap>> Bitmap::load_from_file(NonnullOwnPtr<Core::File>
|
||||||
|
|
||||||
ErrorOr<NonnullRefPtr<Bitmap>> Bitmap::load_from_bytes(ReadonlyBytes bytes, Optional<IntSize> ideal_size, Optional<ByteString> mine_type)
|
ErrorOr<NonnullRefPtr<Bitmap>> Bitmap::load_from_bytes(ReadonlyBytes bytes, Optional<IntSize> ideal_size, Optional<ByteString> mine_type)
|
||||||
{
|
{
|
||||||
if (auto decoder = ImageDecoder::try_create_for_raw_bytes(bytes, mine_type)) {
|
if (auto decoder = TRY(ImageDecoder::try_create_for_raw_bytes(bytes, mine_type))) {
|
||||||
auto frame = TRY(decoder->frame(0, ideal_size));
|
auto frame = TRY(decoder->frame(0, ideal_size));
|
||||||
if (auto& bitmap = frame.image)
|
if (auto& bitmap = frame.image)
|
||||||
return bitmap.release_nonnull();
|
return bitmap.release_nonnull();
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
|
|
||||||
namespace Gfx {
|
namespace Gfx {
|
||||||
|
|
||||||
static OwnPtr<ImageDecoderPlugin> probe_and_sniff_for_appropriate_plugin(ReadonlyBytes bytes)
|
static ErrorOr<OwnPtr<ImageDecoderPlugin>> probe_and_sniff_for_appropriate_plugin(ReadonlyBytes bytes)
|
||||||
{
|
{
|
||||||
struct ImagePluginInitializer {
|
struct ImagePluginInitializer {
|
||||||
bool (*sniff)(ReadonlyBytes) = nullptr;
|
bool (*sniff)(ReadonlyBytes) = nullptr;
|
||||||
|
@ -56,11 +56,9 @@ static OwnPtr<ImageDecoderPlugin> probe_and_sniff_for_appropriate_plugin(Readonl
|
||||||
auto sniff_result = plugin.sniff(bytes);
|
auto sniff_result = plugin.sniff(bytes);
|
||||||
if (!sniff_result)
|
if (!sniff_result)
|
||||||
continue;
|
continue;
|
||||||
auto plugin_decoder = plugin.create(bytes);
|
return TRY(plugin.create(bytes));
|
||||||
if (!plugin_decoder.is_error())
|
|
||||||
return plugin_decoder.release_value();
|
|
||||||
}
|
}
|
||||||
return {};
|
return OwnPtr<ImageDecoderPlugin> {};
|
||||||
}
|
}
|
||||||
|
|
||||||
static OwnPtr<ImageDecoderPlugin> probe_and_sniff_for_appropriate_plugin_with_known_mime_type(StringView mime_type, ReadonlyBytes bytes)
|
static OwnPtr<ImageDecoderPlugin> probe_and_sniff_for_appropriate_plugin_with_known_mime_type(StringView mime_type, ReadonlyBytes bytes)
|
||||||
|
@ -88,9 +86,9 @@ static OwnPtr<ImageDecoderPlugin> probe_and_sniff_for_appropriate_plugin_with_kn
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
RefPtr<ImageDecoder> ImageDecoder::try_create_for_raw_bytes(ReadonlyBytes bytes, Optional<ByteString> mime_type)
|
ErrorOr<RefPtr<ImageDecoder>> ImageDecoder::try_create_for_raw_bytes(ReadonlyBytes bytes, Optional<ByteString> mime_type)
|
||||||
{
|
{
|
||||||
if (OwnPtr<ImageDecoderPlugin> plugin = probe_and_sniff_for_appropriate_plugin(bytes); plugin)
|
if (auto plugin = TRY(probe_and_sniff_for_appropriate_plugin(bytes)); plugin)
|
||||||
return adopt_ref_if_nonnull(new (nothrow) ImageDecoder(plugin.release_nonnull()));
|
return adopt_ref_if_nonnull(new (nothrow) ImageDecoder(plugin.release_nonnull()));
|
||||||
|
|
||||||
if (mime_type.has_value()) {
|
if (mime_type.has_value()) {
|
||||||
|
@ -98,7 +96,7 @@ RefPtr<ImageDecoder> ImageDecoder::try_create_for_raw_bytes(ReadonlyBytes bytes,
|
||||||
return adopt_ref_if_nonnull(new (nothrow) ImageDecoder(plugin.release_nonnull()));
|
return adopt_ref_if_nonnull(new (nothrow) ImageDecoder(plugin.release_nonnull()));
|
||||||
}
|
}
|
||||||
|
|
||||||
return {};
|
return RefPtr<ImageDecoder> {};
|
||||||
}
|
}
|
||||||
|
|
||||||
ImageDecoder::ImageDecoder(NonnullOwnPtr<ImageDecoderPlugin> plugin)
|
ImageDecoder::ImageDecoder(NonnullOwnPtr<ImageDecoderPlugin> plugin)
|
||||||
|
|
|
@ -98,7 +98,7 @@ protected:
|
||||||
|
|
||||||
class ImageDecoder : public RefCounted<ImageDecoder> {
|
class ImageDecoder : public RefCounted<ImageDecoder> {
|
||||||
public:
|
public:
|
||||||
static RefPtr<ImageDecoder> try_create_for_raw_bytes(ReadonlyBytes, Optional<ByteString> mime_type = {});
|
static ErrorOr<RefPtr<ImageDecoder>> try_create_for_raw_bytes(ReadonlyBytes, Optional<ByteString> mime_type = {});
|
||||||
~ImageDecoder() = default;
|
~ImageDecoder() = default;
|
||||||
|
|
||||||
IntSize size() const { return m_plugin->size(); }
|
IntSize size() const { return m_plugin->size(); }
|
||||||
|
|
|
@ -43,11 +43,12 @@ static void decode_image_to_details(Core::AnonymousBuffer const& encoded_buffer,
|
||||||
VERIFY(bitmaps.size() == 0);
|
VERIFY(bitmaps.size() == 0);
|
||||||
VERIFY(durations.size() == 0);
|
VERIFY(durations.size() == 0);
|
||||||
|
|
||||||
auto decoder = Gfx::ImageDecoder::try_create_for_raw_bytes(ReadonlyBytes { encoded_buffer.data<u8>(), encoded_buffer.size() }, known_mime_type);
|
auto decoder_or_err = Gfx::ImageDecoder::try_create_for_raw_bytes(ReadonlyBytes { encoded_buffer.data<u8>(), encoded_buffer.size() }, known_mime_type);
|
||||||
if (!decoder) {
|
if (decoder_or_err.is_error() || !decoder_or_err.value()) {
|
||||||
dbgln_if(IMAGE_DECODER_DEBUG, "Could not find suitable image decoder plugin for data");
|
dbgln_if(IMAGE_DECODER_DEBUG, "Could not find suitable image decoder plugin for data");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
auto decoder = decoder_or_err.release_value();
|
||||||
|
|
||||||
if (!decoder->frame_count()) {
|
if (!decoder->frame_count()) {
|
||||||
dbgln_if(IMAGE_DECODER_DEBUG, "Could not decode image from encoded data");
|
dbgln_if(IMAGE_DECODER_DEBUG, "Could not decode image from encoded data");
|
||||||
|
|
|
@ -256,7 +256,7 @@ ErrorOr<void> SpiceAgent::did_receive_clipboard_message(ClipboardMessage& messag
|
||||||
auto mime_type = TRY(clipboard_data_type_to_mime_type(message.data_type()));
|
auto mime_type = TRY(clipboard_data_type_to_mime_type(message.data_type()));
|
||||||
|
|
||||||
// FIXME: It should be trivial to make `try_create_for_raw_bytes` take a `StringView` instead of a direct `ByteString`.
|
// FIXME: It should be trivial to make `try_create_for_raw_bytes` take a `StringView` instead of a direct `ByteString`.
|
||||||
auto decoder = Gfx::ImageDecoder::try_create_for_raw_bytes(message.contents(), mime_type.to_byte_string());
|
auto decoder = TRY(Gfx::ImageDecoder::try_create_for_raw_bytes(message.contents(), mime_type.to_byte_string()));
|
||||||
if (!decoder || (decoder->frame_count() == 0)) {
|
if (!decoder || (decoder->frame_count() == 0)) {
|
||||||
return Error::from_string_literal("Failed to find a suitable decoder for a pasted image!");
|
return Error::from_string_literal("Failed to find a suitable decoder for a pasted image!");
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,7 @@ static ErrorOr<Optional<String>> image_details(StringView description, StringVie
|
||||||
{
|
{
|
||||||
auto mapped_file = TRY(Core::MappedFile::map(path));
|
auto mapped_file = TRY(Core::MappedFile::map(path));
|
||||||
auto mime_type = Core::guess_mime_type_based_on_filename(path);
|
auto mime_type = Core::guess_mime_type_based_on_filename(path);
|
||||||
auto image_decoder = Gfx::ImageDecoder::try_create_for_raw_bytes(mapped_file->bytes(), mime_type);
|
auto image_decoder = TRY(Gfx::ImageDecoder::try_create_for_raw_bytes(mapped_file->bytes(), mime_type));
|
||||||
if (!image_decoder)
|
if (!image_decoder)
|
||||||
return OptionalNone {};
|
return OptionalNone {};
|
||||||
|
|
||||||
|
|
|
@ -276,7 +276,7 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
||||||
}
|
}
|
||||||
auto file = TRY(Core::MappedFile::map(path));
|
auto file = TRY(Core::MappedFile::map(path));
|
||||||
|
|
||||||
auto decoder = Gfx::ImageDecoder::try_create_for_raw_bytes(file->bytes());
|
auto decoder = TRY(Gfx::ImageDecoder::try_create_for_raw_bytes(file->bytes()));
|
||||||
if (decoder) {
|
if (decoder) {
|
||||||
if (auto embedded_icc_bytes = TRY(decoder->icc_data()); embedded_icc_bytes.has_value()) {
|
if (auto embedded_icc_bytes = TRY(decoder->icc_data()); embedded_icc_bytes.has_value()) {
|
||||||
icc_bytes = *embedded_icc_bytes;
|
icc_bytes = *embedded_icc_bytes;
|
||||||
|
|
|
@ -227,9 +227,9 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
||||||
Options options = TRY(parse_options(arguments));
|
Options options = TRY(parse_options(arguments));
|
||||||
|
|
||||||
auto file = TRY(Core::MappedFile::map(options.in_path));
|
auto file = TRY(Core::MappedFile::map(options.in_path));
|
||||||
auto decoder = Gfx::ImageDecoder::try_create_for_raw_bytes(file->bytes());
|
auto decoder = TRY(Gfx::ImageDecoder::try_create_for_raw_bytes(file->bytes()));
|
||||||
if (!decoder)
|
if (!decoder)
|
||||||
return Error::from_string_view("Failed to decode input file"sv);
|
return Error::from_string_view("Could not find decoder for input file"sv);
|
||||||
|
|
||||||
LoadedImage image = TRY(load_image(*decoder, options.frame_index));
|
LoadedImage image = TRY(load_image(*decoder, options.frame_index));
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue