mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Merge 4b638dc6c46212ff3efffc1d746e72dd62502d9a into 06df71c51446e96939c6a615b7c34ce9123806ba
This commit is contained in:
commit
ef9dc100f5
@ -8498,6 +8498,34 @@ base class _NativePicture extends NativeFieldWrapperClass1 implements Picture {
|
||||
if (width <= 0 || height <= 0) {
|
||||
throw Exception('Invalid image dimensions.');
|
||||
}
|
||||
// Check for dimensions that commonly exceed GPU texture limits.
|
||||
// Many Android devices have max texture sizes between 2048-4096 pixels.
|
||||
// While some modern GPUs support up to 8192 or 16384, we warn for
|
||||
// dimensions above 4096 as they may fail on mid-range and older devices.
|
||||
const int warningSizeThreshold = 4096;
|
||||
const int hardLimitThreshold = 8192;
|
||||
|
||||
if (width > hardLimitThreshold || height > hardLimitThreshold) {
|
||||
throw Exception(
|
||||
'Image dimensions ($width x $height) exceed the maximum supported size '
|
||||
'of $hardLimitThreshold pixels. The image cannot be rasterized.\n'
|
||||
'Consider:\n'
|
||||
' - Reducing the SVG/Picture dimensions\n'
|
||||
' - Splitting into smaller segments\n'
|
||||
' - Using a raster image format (PNG/JPEG) instead'
|
||||
);
|
||||
}
|
||||
|
||||
if (width > warningSizeThreshold || height > warningSizeThreshold) {
|
||||
// Print warning but allow the operation to proceed
|
||||
// ignore: avoid_print
|
||||
print(
|
||||
'Warning: Picture.toImage dimensions ($width x $height) exceed $warningSizeThreshold pixels.\n'
|
||||
'This may fail on devices with limited GPU capabilities (particularly older Android devices).\n'
|
||||
'If rendering fails, consider reducing dimensions or splitting into smaller images.'
|
||||
);
|
||||
}
|
||||
|
||||
return _futurize(
|
||||
(_Callback<Image?> callback) => _toImage(width, height, (_Image? image) {
|
||||
if (image == null) {
|
||||
@ -8523,6 +8551,34 @@ base class _NativePicture extends NativeFieldWrapperClass1 implements Picture {
|
||||
throw Exception('Invalid image dimensions.');
|
||||
}
|
||||
|
||||
// Check for dimensions that commonly exceed GPU texture limits.
|
||||
// Many Android devices have max texture sizes between 2048-4096 pixels.
|
||||
// While some modern GPUs support up to 8192 or 16384, we warn for
|
||||
// dimensions above 4096 as they may fail on mid-range and older devices.
|
||||
const int warningSizeThreshold = 4096;
|
||||
const int hardLimitThreshold = 8192;
|
||||
|
||||
if (width > hardLimitThreshold || height > hardLimitThreshold) {
|
||||
throw Exception(
|
||||
'Image dimensions ($width x $height) exceed the maximum supported size '
|
||||
'of $hardLimitThreshold pixels. The image cannot be rasterized.\n'
|
||||
'Consider:\n'
|
||||
' - Reducing the SVG/Picture dimensions\n'
|
||||
' - Splitting into smaller segments\n'
|
||||
' - Using a raster image format (PNG/JPEG) instead'
|
||||
);
|
||||
}
|
||||
|
||||
if (width > warningSizeThreshold || height > warningSizeThreshold) {
|
||||
// Print warning but allow the operation to proceed
|
||||
// ignore: avoid_print
|
||||
print(
|
||||
'Warning: Picture.toImageSync dimensions ($width x $height) exceed $warningSizeThreshold pixels.\n'
|
||||
'This may fail on devices with limited GPU capabilities (particularly older Android devices).\n'
|
||||
'If rendering fails, consider reducing dimensions or splitting into smaller images.'
|
||||
);
|
||||
}
|
||||
|
||||
final image = _Image._();
|
||||
_toImageSync(width, height, targetFormat.index, image);
|
||||
return Image._(image, image.width, image.height);
|
||||
|
||||
@ -172,6 +172,17 @@ Dart_Handle Picture::DoRasterizeToImage(const sk_sp<DisplayList>& display_list,
|
||||
return tonic::ToDart("Image dimensions for scene were invalid.");
|
||||
}
|
||||
|
||||
// Warn about dimensions that may exceed common GPU texture limits.
|
||||
// This provides a better error message than a silent failure or crash.
|
||||
constexpr uint32_t kWarningSizeThreshold = 4096;
|
||||
if (width > kWarningSizeThreshold || height > kWarningSizeThreshold) {
|
||||
FML_LOG(WARNING) << "Picture.toImage dimensions (" << width << " x "
|
||||
<< height << ") exceed " << kWarningSizeThreshold
|
||||
<< " pixels. This may fail on devices with limited GPU "
|
||||
<< "capabilities. Consider reducing dimensions or "
|
||||
<< "splitting into smaller images.";
|
||||
}
|
||||
|
||||
auto* dart_state = UIDartState::Current();
|
||||
auto image_callback = std::make_unique<tonic::DartPersistentValue>(
|
||||
dart_state, raw_image_callback);
|
||||
|
||||
@ -58,6 +58,80 @@ void main() {
|
||||
|
||||
Picture.onDispose = null;
|
||||
});
|
||||
|
||||
test('toImage throws for dimensions exceeding hard limit', () async {
|
||||
final picture = _createPicture();
|
||||
|
||||
// Test exceeding hard limit (8192 pixels)
|
||||
expect(
|
||||
() => picture.toImage(8193, 100),
|
||||
throwsA(isA<Exception>().having(
|
||||
(e) => e.toString(),
|
||||
'message',
|
||||
contains('exceed the maximum supported size'),
|
||||
)),
|
||||
);
|
||||
|
||||
expect(
|
||||
() => picture.toImage(100, 8193),
|
||||
throwsA(isA<Exception>().having(
|
||||
(e) => e.toString(),
|
||||
'message',
|
||||
contains('exceed the maximum supported size'),
|
||||
)),
|
||||
);
|
||||
|
||||
picture.dispose();
|
||||
});
|
||||
|
||||
test('toImageSync throws for dimensions exceeding hard limit', () async {
|
||||
final picture = _createPicture();
|
||||
|
||||
// Test exceeding hard limit (8192 pixels)
|
||||
expect(
|
||||
() => picture.toImageSync(8193, 100),
|
||||
throwsA(isA<Exception>().having(
|
||||
(e) => e.toString(),
|
||||
'message',
|
||||
contains('exceed the maximum supported size'),
|
||||
)),
|
||||
);
|
||||
|
||||
expect(
|
||||
() => picture.toImageSync(100, 8193),
|
||||
throwsA(isA<Exception>().having(
|
||||
(e) => e.toString(),
|
||||
'message',
|
||||
contains('exceed the maximum supported size'),
|
||||
)),
|
||||
);
|
||||
|
||||
picture.dispose();
|
||||
});
|
||||
|
||||
test('toImage succeeds for normal dimensions', () async {
|
||||
final picture = _createPicture();
|
||||
|
||||
// Should not throw for normal dimensions
|
||||
final image = await picture.toImage(100, 100);
|
||||
expect(image.width, 100);
|
||||
expect(image.height, 100);
|
||||
|
||||
image.dispose();
|
||||
picture.dispose();
|
||||
});
|
||||
|
||||
test('toImageSync succeeds for normal dimensions', () async {
|
||||
final picture = _createPicture();
|
||||
|
||||
// Should not throw for normal dimensions
|
||||
final image = picture.toImageSync(100, 100);
|
||||
expect(image.width, 100);
|
||||
expect(image.height, 100);
|
||||
|
||||
image.dispose();
|
||||
picture.dispose();
|
||||
});
|
||||
}
|
||||
|
||||
Picture _createPicture() {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user