@@ -2124,6 +2124,10 @@ Future<Codec> instantiateImageCodec(
2124
2124
/// The data can be for either static or animated images. The following image
2125
2125
/// formats are supported: {@macro dart.ui.imageFormats}
2126
2126
///
2127
+ /// The [buffer] will be disposed by this method once the codec has been created,
2128
+ /// so the caller must relinquish ownership of the [buffer] when they call this
2129
+ /// method.
2130
+ ///
2127
2131
/// The [targetWidth] and [targetHeight] arguments specify the size of the
2128
2132
/// output image, in image pixels. If they are not equal to the intrinsic
2129
2133
/// dimensions of the image, then the image will be scaled after being decoded.
@@ -2141,26 +2145,145 @@ Future<Codec> instantiateImageCodec(
2141
2145
///
2142
2146
/// The returned future can complete with an error if the image decoding has
2143
2147
/// failed.
2148
+ ///
2149
+ /// ## Compatibility note on the web
2150
+ ///
2151
+ /// When running Flutter on the web, only the CanvasKit renderer supports image
2152
+ /// resizing capabilities (not the HTML renderer). So if image resizing is
2153
+ /// critical to your use case, and you're deploying to the web, you should
2154
+ /// build using the CanvasKit renderer.
2144
2155
Future <Codec > instantiateImageCodecFromBuffer (
2145
2156
ImmutableBuffer buffer, {
2146
2157
int ? targetWidth,
2147
2158
int ? targetHeight,
2148
2159
bool allowUpscaling = true ,
2160
+ }) {
2161
+ return instantiateImageCodecWithSize (
2162
+ buffer,
2163
+ getTargetSize: (int intrinsicWidth, int intrinsicHeight) {
2164
+ if (! allowUpscaling) {
2165
+ if (targetWidth != null && targetWidth! > intrinsicWidth) {
2166
+ targetWidth = intrinsicWidth;
2167
+ }
2168
+ if (targetHeight != null && targetHeight! > intrinsicHeight) {
2169
+ targetHeight = intrinsicHeight;
2170
+ }
2171
+ }
2172
+ return TargetImageSize (width: targetWidth, height: targetHeight);
2173
+ },
2174
+ );
2175
+ }
2176
+
2177
+ /// Instantiates an image [Codec] .
2178
+ ///
2179
+ /// This method is a convenience wrapper around the [ImageDescriptor] API.
2180
+ ///
2181
+ /// The [buffer] parameter is the binary image data (e.g a PNG or GIF binary
2182
+ /// data). The data can be for either static or animated images. The following
2183
+ /// image formats are supported: {@macro dart.ui.imageFormats}
2184
+ ///
2185
+ /// The [buffer] will be disposed by this method once the codec has been
2186
+ /// created, so the caller must relinquish ownership of the [buffer] when they
2187
+ /// call this method.
2188
+ ///
2189
+ /// The [getTargetSize] parameter, when specified, will be invoked and passed
2190
+ /// the image's intrinsic size to determine the size to decode the image to.
2191
+ /// The width and the height of the size it returns must be positive values
2192
+ /// greater than or equal to 1, or null. It is valid to return a
2193
+ /// [TargetImageSize] that specifies only one of `width` and `height` with the
2194
+ /// other remaining null, in which case the omitted dimension will be scaled to
2195
+ /// maintain the aspect ratio of the original dimensions. When both are null or
2196
+ /// omitted, the image will be decoded at its native resolution (as will be the
2197
+ /// case if the [getTargetSize] parameter is omitted).
2198
+ ///
2199
+ /// Scaling the image to larger than its intrinsic size should usually be
2200
+ /// avoided, since it causes the image to use more memory than necessary.
2201
+ /// Instead, prefer scaling the [Canvas] transform.
2202
+ ///
2203
+ /// The returned future can complete with an error if the image decoding has
2204
+ /// failed.
2205
+ ///
2206
+ /// ## Compatibility note on the web
2207
+ ///
2208
+ /// When running Flutter on the web, only the CanvasKit renderer supports image
2209
+ /// resizing capabilities (not the HTML renderer). So if image resizing is
2210
+ /// critical to your use case, and you're deploying to the web, you should
2211
+ /// build using the CanvasKit renderer.
2212
+ Future <Codec > instantiateImageCodecWithSize (
2213
+ ImmutableBuffer buffer, {
2214
+ TargetImageSizeCallback ? getTargetSize,
2149
2215
}) async {
2216
+ getTargetSize ?? = _getDefaultImageSize;
2150
2217
final ImageDescriptor descriptor = await ImageDescriptor .encoded (buffer);
2151
- if (! allowUpscaling) {
2152
- if (targetWidth != null && targetWidth > descriptor.width) {
2153
- targetWidth = descriptor.width;
2154
- }
2155
- if (targetHeight != null && targetHeight > descriptor.height) {
2156
- targetHeight = descriptor.height;
2157
- }
2218
+ try {
2219
+ final TargetImageSize targetSize = getTargetSize (descriptor.width, descriptor.height);
2220
+ assert (targetSize.width == null || targetSize.width! > 0 );
2221
+ assert (targetSize.height == null || targetSize.height! > 0 );
2222
+ return descriptor.instantiateCodec (
2223
+ targetWidth: targetSize.width,
2224
+ targetHeight: targetSize.height,
2225
+ );
2226
+ } finally {
2227
+ buffer.dispose ();
2158
2228
}
2159
- buffer.dispose ();
2160
- return descriptor.instantiateCodec (
2161
- targetWidth: targetWidth,
2162
- targetHeight: targetHeight,
2163
- );
2229
+ }
2230
+
2231
+ TargetImageSize _getDefaultImageSize (int intrinsicWidth, int intrinsicHeight) {
2232
+ return const TargetImageSize ();
2233
+ }
2234
+
2235
+ /// Signature for a callback that determines the size to which an image should
2236
+ /// be decoded given its intrinsic size.
2237
+ ///
2238
+ /// See also:
2239
+ ///
2240
+ /// * [instantiateImageCodecWithSize] , which used this signature for its
2241
+ /// `getTargetSize` argument.
2242
+ typedef TargetImageSizeCallback = TargetImageSize Function (
2243
+ int intrinsicWidth,
2244
+ int intrinsicHeight,
2245
+ );
2246
+
2247
+ /// A specification of the size to which an image should be decoded.
2248
+ ///
2249
+ /// See also:
2250
+ ///
2251
+ /// * [TargetImageSizeCallback] , a callback that returns instances of this
2252
+ /// class when consulted by image decoding methods such as
2253
+ /// [instantiateImageCodecWithSize].
2254
+ class TargetImageSize {
2255
+ /// Creates a new instance of this class.
2256
+ ///
2257
+ /// The `width` and `height` may both be null, but if they're non-null, they
2258
+ /// must be positive.
2259
+ const TargetImageSize ({this .width, this .height})
2260
+ : assert (width == null || width > 0 ),
2261
+ assert (height == null || height > 0 );
2262
+
2263
+ /// The width into which to load the image.
2264
+ ///
2265
+ /// If this is non-null, the image will be decoded into the specified width.
2266
+ /// If this is null and [height] is also null, the image will be decoded into
2267
+ /// its intrinsic size. If this is null and [height] is non-null, the image
2268
+ /// will be decoded into a width that maintains its intrinsic aspect ratio
2269
+ /// while respecting the [height] value.
2270
+ ///
2271
+ /// If this value is non-null, it must be positive.
2272
+ final int ? width;
2273
+
2274
+ /// The height into which to load the image.
2275
+ ///
2276
+ /// If this is non-null, the image will be decoded into the specified height.
2277
+ /// If this is null and [width] is also null, the image will be decoded into
2278
+ /// its intrinsic size. If this is null and [width] is non-null, the image
2279
+ /// will be decoded into a height that maintains its intrinsic aspect ratio
2280
+ /// while respecting the [width] value.
2281
+ ///
2282
+ /// If this value is non-null, it must be positive.
2283
+ final int ? height;
2284
+
2285
+ @override
2286
+ String toString () => 'TargetImageSize($width x $height )' ;
2164
2287
}
2165
2288
2166
2289
/// Loads a single image frame from a byte array into an [Image] object.
0 commit comments