[engine] Decode animation frames with alpha after an opaque first frame (#193113) Fixes https://github.com/flutter/flutter/issues/85831 While working on webp encoder for `image` package i noticed that flutter does not render some animated webp and gifs with following exception: ``` ======== Exception caught by image resource service ================================================ The following _Exception was thrown resolving an image frame: Exception: Could not getPixels for frame 1 When the exception was thrown, this was the stack: Path: \\Mac\Downloads\gif\200w.webp ==================================================================================================== ``` <details> <summary>Code sample and visual demo with the files used, since the issue has no screenshots and author did not provide his code sample:</summary> <img width="1491" height="819" alt="image" src="https://github.com/user-attachments/assets/04e7dc17-bc7f-453f-ba28-5621d47c3f23" /> ```dart import 'dart:io'; import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Material App', home: Scaffold( appBar: AppBar(title: Text('Material App Bar')), body: Center(child: Column(children: <Widget>[ Image.file(File(r'\\Mac\Downloads\gif\200w.gif'), height: 100,), Image.file(File(r'\\Mac\Downloads\gif\200w.webp'), height: 100,), Image.file(File(r'\\Mac\Downloads\gif\giphy.gif'), height: 100,), Image.file(File(r'\\Mac\Downloads\gif\giphy.webp'), height: 100,), Image.file(File(r'\\Mac\Downloads\gif\opaque_first_frame_bug.gif'), height: 100,), ])), ), ); } } ``` <details> <summary>Webp and gif Images used for this sample:</summary> <img width="200" height="356" alt="200w" src="https://github.com/user-attachments/assets/abcbdd6e-d4d0-4e23-b88d-04c0e3d4a79e" /> <img width="56" height="100" alt="200w" src="https://github.com/user-attachments/assets/8df4d356-1297-4aad-af85-a2b4bd23b606" /> <img width="480" height="480" alt="giphy" src="https://github.com/user-attachments/assets/13b6952e-1bf9-49ec-b58f-52c5caf6fa04" /> <img width="100" height="100" alt="giphy" src="https://github.com/user-attachments/assets/4d3bb3dc-0f8c-4384-9b1d-86e3a4474206" /> <img width="200" height="200" alt="opaque_first_frame_bug" src="https://github.com/user-attachments/assets/5e41e321-04f4-4ad5-a9cd-90c0164e4c6a" /> </details> </details> It appears that this is an old issue in how Flutter uses Skia, because for animated WebP and GIF, Skia's SkCodec::getInfo() reports the alpha type of the first frame only, and its documentation doesn't mention that (or at least i did not find it). Flutter allocates every frame's bitmap from that info without checking getFrameInfo(i).fAlphaType, so Skia rejects any later frame with alpha after an opaque first frame with kInvalidConversion. Tested on an engine built from master (e619960004d, Windows x64 release) with an app that decodes every frame through `ui.instantiateImageCodec`: | file | without the change | with the change | |---|---|---| | WebP, 59 frames, frames 46 and 53 have alpha | frames 46, 53 fail | all decode | | 3 WebP files, 15 frames each, frames 1-14 have alpha (lossy and lossless) | frames 1-14 fail | all decode | | GIF, opaque frame 0, frame 1 with transparency, disposal to background | frame 1 fails | all decode | | the same WebP frames with one alpha pixel in frame 0, and a GIF with disposal none | all decode | all decode | Fix: when `SkCodec::getInfo()` reports `kOpaque_SkAlphaType` for an animation, `BuiltinSkiaCodecImageGenerator` now reports `kPremul_SkAlphaType` if any later frame reports a non-opaque `SkCodec::FrameInfo::fAlphaType`. Animations whose later frames all report `kOpaque_SkAlphaType` stay opaque. APNG is decoded by APNGImageGenerator, which this change doesn't touch. The new tests in `testing/dart/codec_test.dart` use a 140-byte WebP and a 70-byte GIF fixture. I ran `codec_test.dart` with `flutter_tester` from a `host_debug_unopt_x64` build (Windows x64) with the Skia and Impeller Vulkan backends, single and multithreaded: all 16 tests pass. Without the change the two new tests fail with `Could not getPixels for frame 1`. The Impeller OpenGL ES tests were not tested locally. <details> <summary>Screenshot after the fix, both with impeller enabled and disabled:</summary> <img width="1329" height="760" alt="image" src="https://github.com/user-attachments/assets/a01da7d8-3c40-49a1-a312-4941d23128a2" /> </details> ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [AI contribution guidelines] and understand my responsibilities, or I am not using AI tools. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I signed the [CLA]. - [x] I listed at least one issue that this PR fixes in the description above. - [ ] I updated/added relevant in-code documentation (doc comments with `///`). - [ ] If this PR introduces a new feature or capability, I created and linked a website documentation issue or PR in [flutter/website] (or verified none is needed). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [ ] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [ ] All existing and new tests are passing. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [AI contribution guidelines]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#ai-contribution-guidelines [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/website]: https://github.com/flutter/website [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
Flutter is Google's SDK for crafting beautiful, fast user experiences for mobile, web, and desktop from a single codebase. Flutter works with existing code, is used by developers and organizations around the world, and is free and open source.
For release and other announcements, join the flutter-announce mailing list. Our documentation also tracks breaking changes across releases.
The Flutter tool may occasionally download resources from Google servers. By downloading or using the Flutter SDK, you agree to the Google Terms of Service: https://policies.google.com/terms
For example, when installed from GitHub (as opposed to from a prepackaged archive), the Flutter tool will download the Dart SDK from Google servers immediately when first run, as it is used to execute the flutter tool itself. This will also occur when Flutter is upgraded (e.g. by running the flutter upgrade command).
We think Flutter will help you create beautiful, fast apps, with a productive, extensible and open development model, whether you're targeting iOS or Android, web, Windows, macOS, Linux or embedding it as the UI toolkit for a platform of your choice.
We want to enable designers to deliver their full creative vision without being forced to water it down due to limitations of the underlying framework. Flutter‘s layered architecture gives you control over every pixel on the screen and its powerful compositing capabilities let you overlay and animate graphics, video, text, and controls without limitation. Flutter includes a full set of widgets that deliver pixel-perfect experiences whether you’re building for iOS (Cupertino) or other platforms (Material), along with support for customizing or creating entirely new visual components.
Flutter is fast. It's powered by hardware-accelerated 2D graphics libraries like Skia (which underpins Chrome and Android) and Impeller. We architected Flutter to support glitch-free, jank-free graphics at the native speed of your device.
Flutter code is powered by the world-class Dart programming language, which enables compilation to 32-bit and 64-bit ARM machine code for iOS and Android, JavaScript and WebAssembly for the web, as well as Intel x64 and ARM for desktop devices.
Flutter offers stateful hot reload, allowing you to make changes to your code and see the results instantly without restarting your app or losing its state.
Flutter works with any development tool (or none at all), and also includes editor plug-ins for both Visual Studio Code and IntelliJ / Android Studio. Flutter provides tens of thousands of packages to speed your development, regardless of your target platform. And accessing other native code is easy, with support for both FFI (on Android, on iOS, on macOS, on Linux, and on Windows) as well as platform-specific APIs.
Flutter is a fully open-source project, and we welcome contributions. Information on how to get started can be found in our contributor guide.