Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
e8fa87e3
Unverified
Commit
e8fa87e3
authored
Jun 23, 2020
by
Dan Field
Committed by
GitHub
Jun 23, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Make upscaling images opt-in (#59856)
* Make upscaling images opt-in
parent
65550d0f
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
98 additions
and
28 deletions
+98
-28
binding.dart
packages/flutter/lib/src/painting/binding.dart
+19
-8
image_provider.dart
packages/flutter/lib/src/painting/image_provider.dart
+23
-9
image_data.dart
packages/flutter/test/painting/image_data.dart
+15
-0
image_provider_and_image_cache_test.dart
...er/test/painting/image_provider_and_image_cache_test.dart
+2
-2
image_provider_network_image_test.dart
...tter/test/painting/image_provider_network_image_test.dart
+2
-2
image_provider_resize_image_test.dart
...utter/test/painting/image_provider_resize_image_test.dart
+31
-3
painting_utils.dart
packages/flutter/test/painting/painting_utils.dart
+1
-1
fade_in_image_test.dart
packages/flutter/test/widgets/fade_in_image_test.dart
+5
-3
No files found.
packages/flutter/lib/src/painting/binding.dart
View file @
e8fa87e3
...
...
@@ -71,26 +71,37 @@ mixin PaintingBinding on BindingBase, ServicesBinding {
@protected
ImageCache
createImageCache
()
=>
ImageCache
();
/// Calls through to [dart:ui]
with [decodedCacheRatioCap]
from [ImageCache].
/// Calls through to [dart:ui] from [ImageCache].
///
/// The
[cacheWidth] and [cacheHeight] parameters, when specified, indicate th
e
/// size to decode the image to.
/// The
`cacheWidth` and `cacheHeight` parameters, when specified, indicat
e
///
the
size to decode the image to.
///
/// Both [cacheWidth] and [cacheHeight] must be positive values greater than or
/// equal to 1 or null. It is valid to specify only one of [cacheWidth] and
/// [cacheHeight] with the other remaining null, in which case the omitted
/// dimension will decode to its original size. When both are null or omitted,
/// the image will be decoded at its native resolution.
/// Both `cacheWidth` and `cacheHeight` must be positive values greater than
/// or equal to 1, or null. It is valid to specify only one of `cacheWidth`
/// and `cacheHeight` with the other remaining null, in which case the omitted
/// dimension will be scaled to maintain the aspect ratio of the original
/// dimensions. When both are null or omitted, the image will be decoded at
/// its native resolution.
///
/// The `allowUpscaling` parameter determines whether the `cacheWidth` or
/// `cacheHeight` parameters are clamped to the intrinsic width and height of
/// the original image. By default, the dimensions are clamped to avoid
/// unnecessary memory usage for images. Callers that wish to display an image
/// above its native resolution should prefer scaling the canvas the image is
/// drawn into.
Future
<
ui
.
Codec
>
instantiateImageCodec
(
Uint8List
bytes
,
{
int
cacheWidth
,
int
cacheHeight
,
bool
allowUpscaling
=
false
,
})
{
assert
(
cacheWidth
==
null
||
cacheWidth
>
0
);
assert
(
cacheHeight
==
null
||
cacheHeight
>
0
);
assert
(
allowUpscaling
!=
null
);
return
ui
.
instantiateImageCodec
(
bytes
,
targetWidth:
cacheWidth
,
targetHeight:
cacheHeight
,
allowUpscaling:
allowUpscaling
,
);
}
...
...
packages/flutter/lib/src/painting/image_provider.dart
View file @
e8fa87e3
...
...
@@ -162,13 +162,15 @@ class ImageConfiguration {
/// Performs the decode process for use in [ImageProvider.load].
///
/// This callback allows decoupling of the `cacheWidth` and `cacheHeight`
/// parameters from implementations of [ImageProvider] that do not use them.
/// This callback allows decoupling of the `cacheWidth`, `cacheHeight`, and
/// `allowUpscaling` parameters from implementations of [ImageProvider] that do
/// not expose them.
///
/// See also:
///
/// * [ResizeImage], which uses this to override the `cacheWidth` and `cacheHeight` parameters.
typedef
DecoderCallback
=
Future
<
ui
.
Codec
>
Function
(
Uint8List
bytes
,
{
int
cacheWidth
,
int
cacheHeight
});
/// * [ResizeImage], which uses this to override the `cacheWidth`,
/// `cacheHeight`, and `allowUpscaling` parameters.
typedef
DecoderCallback
=
Future
<
ui
.
Codec
>
Function
(
Uint8List
bytes
,
{
int
cacheWidth
,
int
cacheHeight
,
bool
allowUpscaling
});
/// Identifies an image without committing to the precise final asset. This
/// allows a set of images to be identified and for the precise image to later
...
...
@@ -718,7 +720,9 @@ class ResizeImage extends ImageProvider<_SizeAwareCacheKey> {
this
.
imageProvider
,
{
this
.
width
,
this
.
height
,
})
:
assert
(
width
!=
null
||
height
!=
null
);
this
.
allowUpscaling
=
false
,
})
:
assert
(
width
!=
null
||
height
!=
null
),
assert
(
allowUpscaling
!=
null
);
/// The [ImageProvider] that this class wraps.
final
ImageProvider
imageProvider
;
...
...
@@ -729,6 +733,15 @@ class ResizeImage extends ImageProvider<_SizeAwareCacheKey> {
/// The height the image should decode to and cache.
final
int
height
;
/// Whether the [width] and [height] parameters should be clamped to the
/// intrinsic width and height of the image.
///
/// In general, it is better for memory usage to avoid scaling the image
/// beyond its intrinsic dimensions when decoding it. If there is a need to
/// scale an image larger, it is better to apply a scale to the canvas, or
/// to use an appropriate [Image.fit].
final
bool
allowUpscaling
;
/// Composes the `provider` in a [ResizeImage] only when `cacheWidth` and
/// `cacheHeight` are not both null.
///
...
...
@@ -743,12 +756,13 @@ class ResizeImage extends ImageProvider<_SizeAwareCacheKey> {
@override
ImageStreamCompleter
load
(
_SizeAwareCacheKey
key
,
DecoderCallback
decode
)
{
final
DecoderCallback
decodeResize
=
(
Uint8List
bytes
,
{
int
cacheWidth
,
int
cacheHeight
})
{
final
DecoderCallback
decodeResize
=
(
Uint8List
bytes
,
{
int
cacheWidth
,
int
cacheHeight
,
bool
allowUpscaling
})
{
assert
(
cacheWidth
==
null
&&
cacheHeight
==
null
,
'ResizeImage cannot be composed with another ImageProvider that applies cacheWidth or cacheHeight.'
cacheWidth
==
null
&&
cacheHeight
==
null
&&
allowUpscaling
==
null
,
'ResizeImage cannot be composed with another ImageProvider that applies '
'cacheWidth, cacheHeight, or allowUpscaling.'
);
return
decode
(
bytes
,
cacheWidth:
width
,
cacheHeight:
height
);
return
decode
(
bytes
,
cacheWidth:
width
,
cacheHeight:
height
,
allowUpscaling:
this
.
allowUpscaling
);
};
return
imageProvider
.
load
(
key
.
providerCacheKey
,
decodeResize
);
}
...
...
packages/flutter/test/painting/image_data.dart
View file @
e8fa87e3
...
...
@@ -4,6 +4,21 @@
// @dart = 2.8
/// A 50x50 blue square png.
const
List
<
int
>
kBlueSquare
=
<
int
>[
0x89
,
0x50
,
0x4e
,
0x47
,
0x0d
,
0x0a
,
0x1a
,
0x0a
,
0x00
,
0x00
,
0x00
,
0x0d
,
0x49
,
0x48
,
0x44
,
0x52
,
0x00
,
0x00
,
0x00
,
0x32
,
0x00
,
0x00
,
0x00
,
0x32
,
0x08
,
0x06
,
0x00
,
0x00
,
0x00
,
0x1e
,
0x3f
,
0x88
,
0xb1
,
0x00
,
0x00
,
0x00
,
0x48
,
0x49
,
0x44
,
0x41
,
0x54
,
0x78
,
0xda
,
0xed
,
0xcf
,
0x31
,
0x0d
,
0x00
,
0x30
,
0x08
,
0x00
,
0xb0
,
0x61
,
0x63
,
0x2f
,
0xfe
,
0x2d
,
0x61
,
0x05
,
0x34
,
0xf0
,
0x92
,
0xd6
,
0x41
,
0x23
,
0x7f
,
0xf5
,
0x3b
,
0x20
,
0x44
,
0x44
,
0x44
,
0x44
,
0x44
,
0x44
,
0x44
,
0x44
,
0x44
,
0x44
,
0x44
,
0x44
,
0x44
,
0x44
,
0x44
,
0x44
,
0x44
,
0x44
,
0x44
,
0x44
,
0x44
,
0x44
,
0x44
,
0x44
,
0x44
,
0x44
,
0x44
,
0x44
,
0x44
,
0x44
,
0x44
,
0x44
,
0x44
,
0x44
,
0x44
,
0x44
,
0x44
,
0x44
,
0x36
,
0x06
,
0x03
,
0x6e
,
0x69
,
0x47
,
0x12
,
0x8e
,
0xea
,
0xaa
,
0x00
,
0x00
,
0x00
,
0x00
,
0x49
,
0x45
,
0x4e
,
0x44
,
0xae
,
0x42
,
0x60
,
0x82
,
];
const
List
<
int
>
kTransparentImage
=
<
int
>[
0x89
,
0x50
,
0x4E
,
0x47
,
0x0D
,
0x0A
,
0x1A
,
0x0A
,
0x00
,
0x00
,
0x00
,
0x0D
,
0x49
,
0x48
,
0x44
,
0x52
,
0x00
,
0x00
,
0x00
,
0x01
,
0x00
,
0x00
,
0x00
,
0x01
,
0x08
,
0x06
,
...
...
packages/flutter/test/painting/image_provider_and_image_cache_test.dart
View file @
e8fa87e3
...
...
@@ -19,8 +19,8 @@ import 'mocks_for_image_cache.dart';
void
main
(
)
{
TestRenderingFlutterBinding
();
final
DecoderCallback
_basicDecoder
=
(
Uint8List
bytes
,
{
int
cacheWidth
,
int
cacheHeight
})
{
return
PaintingBinding
.
instance
.
instantiateImageCodec
(
bytes
,
cacheWidth:
cacheWidth
,
cacheHeight:
cacheHeight
);
final
DecoderCallback
_basicDecoder
=
(
Uint8List
bytes
,
{
int
cacheWidth
,
int
cacheHeight
,
bool
allowUpscaling
})
{
return
PaintingBinding
.
instance
.
instantiateImageCodec
(
bytes
,
cacheWidth:
cacheWidth
,
cacheHeight:
cacheHeight
,
allowUpscaling:
allowUpscaling
??
false
);
};
FlutterExceptionHandler
oldError
;
...
...
packages/flutter/test/painting/image_provider_network_image_test.dart
View file @
e8fa87e3
...
...
@@ -20,8 +20,8 @@ import 'image_data.dart';
void
main
(
)
{
TestRenderingFlutterBinding
();
final
DecoderCallback
_basicDecoder
=
(
Uint8List
bytes
,
{
int
cacheWidth
,
int
cacheHeight
})
{
return
PaintingBinding
.
instance
.
instantiateImageCodec
(
bytes
,
cacheWidth:
cacheWidth
,
cacheHeight:
cacheHeight
);
final
DecoderCallback
_basicDecoder
=
(
Uint8List
bytes
,
{
int
cacheWidth
,
int
cacheHeight
,
bool
allowUpscaling
})
{
return
PaintingBinding
.
instance
.
instantiateImageCodec
(
bytes
,
cacheWidth:
cacheWidth
,
cacheHeight:
cacheHeight
,
allowUpscaling:
allowUpscaling
);
};
_MockHttpClient
httpClient
;
...
...
packages/flutter/test/painting/image_provider_resize_image_test.dart
View file @
e8fa87e3
...
...
@@ -21,13 +21,40 @@ void main() {
PaintingBinding
.
instance
.
imageCache
.
clearLiveImages
();
});
test
(
'ResizeImage resizes to the correct dimensions'
,
()
async
{
test
(
'ResizeImage resizes to the correct dimensions
(up)
'
,
()
async
{
final
Uint8List
bytes
=
Uint8List
.
fromList
(
kTransparentImage
);
final
MemoryImage
imageProvider
=
MemoryImage
(
bytes
);
final
Size
rawImageSize
=
await
_resolveAndGetSize
(
imageProvider
);
expect
(
rawImageSize
,
const
Size
(
1
,
1
));
const
Size
resizeDims
=
Size
(
14
,
7
);
final
ResizeImage
resizedImage
=
ResizeImage
(
MemoryImage
(
bytes
),
width:
resizeDims
.
width
.
round
(),
height:
resizeDims
.
height
.
round
(),
allowUpscaling:
true
);
const
ImageConfiguration
resizeConfig
=
ImageConfiguration
(
size:
resizeDims
);
final
Size
resizedImageSize
=
await
_resolveAndGetSize
(
resizedImage
,
configuration:
resizeConfig
);
expect
(
resizedImageSize
,
resizeDims
);
},
skip:
isBrowser
);
// https://github.com/flutter/flutter/issues/56312
test
(
'ResizeImage resizes to the correct dimensions (down)'
,
()
async
{
final
Uint8List
bytes
=
Uint8List
.
fromList
(
kBlueSquare
);
final
MemoryImage
imageProvider
=
MemoryImage
(
bytes
);
final
Size
rawImageSize
=
await
_resolveAndGetSize
(
imageProvider
);
expect
(
rawImageSize
,
const
Size
(
50
,
50
));
const
Size
resizeDims
=
Size
(
25
,
25
);
final
ResizeImage
resizedImage
=
ResizeImage
(
MemoryImage
(
bytes
),
width:
resizeDims
.
width
.
round
(),
height:
resizeDims
.
height
.
round
(),
allowUpscaling:
true
);
const
ImageConfiguration
resizeConfig
=
ImageConfiguration
(
size:
resizeDims
);
final
Size
resizedImageSize
=
await
_resolveAndGetSize
(
resizedImage
,
configuration:
resizeConfig
);
expect
(
resizedImageSize
,
resizeDims
);
},
skip:
isBrowser
);
// https://github.com/flutter/flutter/issues/56312
test
(
'ResizeImage resizes to the correct dimensions - no upscaling'
,
()
async
{
final
Uint8List
bytes
=
Uint8List
.
fromList
(
kTransparentImage
);
final
MemoryImage
imageProvider
=
MemoryImage
(
bytes
);
final
Size
rawImageSize
=
await
_resolveAndGetSize
(
imageProvider
);
expect
(
rawImageSize
,
const
Size
(
1
,
1
));
const
Size
resizeDims
=
Size
(
1
,
1
);
final
ResizeImage
resizedImage
=
ResizeImage
(
MemoryImage
(
bytes
),
width:
resizeDims
.
width
.
round
(),
height:
resizeDims
.
height
.
round
());
const
ImageConfiguration
resizeConfig
=
ImageConfiguration
(
size:
resizeDims
);
final
Size
resizedImageSize
=
await
_resolveAndGetSize
(
resizedImage
,
configuration:
resizeConfig
);
...
...
@@ -73,10 +100,11 @@ void main() {
final
MemoryImage
memoryImage
=
MemoryImage
(
bytes
);
final
ResizeImage
resizeImage
=
ResizeImage
(
memoryImage
,
width:
123
,
height:
321
);
final
DecoderCallback
decode
=
(
Uint8List
bytes
,
{
int
cacheWidth
,
int
cacheHeight
})
{
final
DecoderCallback
decode
=
(
Uint8List
bytes
,
{
int
cacheWidth
,
int
cacheHeight
,
bool
allowUpscaling
})
{
expect
(
cacheWidth
,
123
);
expect
(
cacheHeight
,
321
);
return
PaintingBinding
.
instance
.
instantiateImageCodec
(
bytes
,
cacheWidth:
cacheWidth
,
cacheHeight:
cacheHeight
);
expect
(
allowUpscaling
,
false
);
return
PaintingBinding
.
instance
.
instantiateImageCodec
(
bytes
,
cacheWidth:
cacheWidth
,
cacheHeight:
cacheHeight
,
allowUpscaling:
allowUpscaling
);
};
resizeImage
.
load
(
await
resizeImage
.
obtainKey
(
ImageConfiguration
.
empty
),
decode
);
...
...
packages/flutter/test/painting/painting_utils.dart
View file @
e8fa87e3
...
...
@@ -17,7 +17,7 @@ class PaintingBindingSpy extends BindingBase with SchedulerBinding, ServicesBind
int
get
instantiateImageCodecCalledCount
=>
counter
;
@override
Future
<
ui
.
Codec
>
instantiateImageCodec
(
Uint8List
list
,
{
int
cacheWidth
,
int
cacheHeight
})
{
Future
<
ui
.
Codec
>
instantiateImageCodec
(
Uint8List
list
,
{
int
cacheWidth
,
int
cacheHeight
,
bool
allowUpscaling
=
false
})
{
counter
++;
return
ui
.
instantiateImageCodec
(
list
);
}
...
...
packages/flutter/test/widgets/fade_in_image_test.dart
View file @
e8fa87e3
...
...
@@ -323,11 +323,12 @@ Future<void> main() async {
);
bool
called
=
false
;
final
DecoderCallback
decode
=
(
Uint8List
bytes
,
{
int
cacheWidth
,
int
cacheHeight
})
{
final
DecoderCallback
decode
=
(
Uint8List
bytes
,
{
int
cacheWidth
,
int
cacheHeight
,
bool
allowUpscaling
})
{
expect
(
cacheWidth
,
20
);
expect
(
cacheHeight
,
30
);
expect
(
allowUpscaling
,
false
);
called
=
true
;
return
PaintingBinding
.
instance
.
instantiateImageCodec
(
bytes
,
cacheWidth:
cacheWidth
,
cacheHeight:
cacheHeight
);
return
PaintingBinding
.
instance
.
instantiateImageCodec
(
bytes
,
cacheWidth:
cacheWidth
,
cacheHeight:
cacheHeight
,
allowUpscaling:
allowUpscaling
);
};
final
ImageProvider
resizeImage
=
image
.
placeholder
;
expect
(
image
.
placeholder
,
isA
<
ResizeImage
>());
...
...
@@ -345,9 +346,10 @@ Future<void> main() async {
);
bool
called
=
false
;
final
DecoderCallback
decode
=
(
Uint8List
bytes
,
{
int
cacheWidth
,
int
cacheHeight
})
{
final
DecoderCallback
decode
=
(
Uint8List
bytes
,
{
int
cacheWidth
,
int
cacheHeight
,
bool
allowUpscaling
})
{
expect
(
cacheWidth
,
null
);
expect
(
cacheHeight
,
null
);
expect
(
allowUpscaling
,
null
);
called
=
true
;
return
PaintingBinding
.
instance
.
instantiateImageCodec
(
bytes
,
cacheWidth:
cacheWidth
,
cacheHeight:
cacheHeight
);
};
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment