Add Image.memory for making images from typed data (#8877)
Fixes #7503 Fixes #8870
This commit is contained in:
parent
9056ded298
commit
e836a84e30
@ -424,7 +424,7 @@ class FileImage extends ImageProvider<FileImage> {
|
||||
if (other.runtimeType != runtimeType)
|
||||
return false;
|
||||
final FileImage typedOther = other;
|
||||
return file?.path == file?.path
|
||||
return file?.path == typedOther.file?.path
|
||||
&& scale == typedOther.scale;
|
||||
}
|
||||
|
||||
@ -435,6 +435,58 @@ class FileImage extends ImageProvider<FileImage> {
|
||||
String toString() => '$runtimeType("${file?.path}", scale: $scale)';
|
||||
}
|
||||
|
||||
/// Decodes the given [Uint8List] buffer as an image, associating it with the
|
||||
/// given scale.
|
||||
class MemoryImage extends ImageProvider<MemoryImage> {
|
||||
/// Creates an object that decodes a [Uint8List] buffer as an image.
|
||||
///
|
||||
/// The arguments must not be null.
|
||||
const MemoryImage(this.bytes, { this.scale: 1.0 });
|
||||
|
||||
/// The bytes to decode into an image.
|
||||
final Uint8List bytes;
|
||||
|
||||
/// The scale to place in the [ImageInfo] object of the image.
|
||||
final double scale;
|
||||
|
||||
@override
|
||||
Future<MemoryImage> obtainKey(ImageConfiguration configuration) {
|
||||
return new SynchronousFuture<MemoryImage>(this);
|
||||
}
|
||||
|
||||
@override
|
||||
ImageStreamCompleter load(MemoryImage key) {
|
||||
return new OneFrameImageStreamCompleter(_loadAsync(key));
|
||||
}
|
||||
|
||||
Future<ImageInfo> _loadAsync(MemoryImage key) async {
|
||||
assert(key == this);
|
||||
|
||||
final ui.Image image = await decodeImageFromList(bytes);
|
||||
if (image == null)
|
||||
return null;
|
||||
|
||||
return new ImageInfo(
|
||||
image: image,
|
||||
scale: key.scale,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(dynamic other) {
|
||||
if (other.runtimeType != runtimeType)
|
||||
return false;
|
||||
final MemoryImage typedOther = other;
|
||||
return bytes == typedOther.bytes
|
||||
&& scale == typedOther.scale;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => hashValues(bytes.hashCode, scale);
|
||||
|
||||
@override
|
||||
String toString() => '$runtimeType(${bytes.runtimeType}#${bytes.hashCode}, scale: $scale)';
|
||||
}
|
||||
/// Fetches an image from an [AssetBundle], associating it with the given scale.
|
||||
///
|
||||
/// This implementation requires an explicit final [name] and [scale] on
|
||||
|
@ -3,6 +3,7 @@
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:io' show File, Platform;
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
@ -14,6 +15,7 @@ import 'media_query.dart';
|
||||
export 'package:flutter/services.dart' show
|
||||
AssetImage,
|
||||
ExactAssetImage,
|
||||
MemoryImage,
|
||||
NetworkImage,
|
||||
FileImage;
|
||||
|
||||
@ -42,6 +44,7 @@ ImageConfiguration createLocalImageConfiguration(BuildContext context, { Size si
|
||||
/// using a key.
|
||||
/// * [new Image.network], for obtaining an image from a URL.
|
||||
/// * [new Image.file], for obtaining an image from a [File].
|
||||
/// * [new Image.memory], for obtaining an image from a [Uint8List].
|
||||
///
|
||||
/// To automatically perform pixel-density-aware asset resolution, specify the
|
||||
/// image using an [AssetImage] and make sure that a [MaterialApp], [WidgetsApp],
|
||||
@ -141,6 +144,23 @@ class Image extends StatefulWidget {
|
||||
: new AssetImage(name, bundle: bundle),
|
||||
super(key: key);
|
||||
|
||||
/// Creates a widget that displays an [ImageStream] obtained from a [Uint8List].
|
||||
///
|
||||
/// The [bytes], [scale], and [repeat] arguments must not be null.
|
||||
Image.memory(Uint8List bytes, {
|
||||
Key key,
|
||||
double scale: 1.0,
|
||||
this.width,
|
||||
this.height,
|
||||
this.color,
|
||||
this.fit,
|
||||
this.alignment,
|
||||
this.repeat: ImageRepeat.noRepeat,
|
||||
this.centerSlice,
|
||||
this.gaplessPlayback: false
|
||||
}) : image = new MemoryImage(bytes, scale: scale),
|
||||
super(key: key);
|
||||
|
||||
/// The image to display.
|
||||
final ImageProvider image;
|
||||
|
||||
|
11
packages/flutter/test/services/image_data.dart
Normal file
11
packages/flutter/test/services/image_data.dart
Normal file
@ -0,0 +1,11 @@
|
||||
// Copyright 2016 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
const List<int> kTransparentImage = const <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,
|
||||
0x00, 0x00, 0x00, 0x1F, 0x15, 0xC4, 0x89, 0x00, 0x00, 0x00, 0x0A, 0x49, 0x44,
|
||||
0x41, 0x54, 0x78, 0x9C, 0x63, 0x00, 0x01, 0x00, 0x00, 0x05, 0x00, 0x01, 0x0D,
|
||||
0x0A, 0x2D, 0xB4, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE,
|
||||
];
|
@ -8,17 +8,11 @@ import 'dart:ui' as ui;
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
const List<int> transparentImage = const <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,
|
||||
0x00, 0x00, 0x00, 0x1F, 0x15, 0xC4, 0x89, 0x00, 0x00, 0x00, 0x0A, 0x49, 0x44,
|
||||
0x41, 0x54, 0x78, 0x9C, 0x63, 0x00, 0x01, 0x00, 0x00, 0x05, 0x00, 0x01, 0x0D,
|
||||
0x0A, 0x2D, 0xB4, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE,
|
||||
];
|
||||
import 'image_data.dart';
|
||||
|
||||
void main() {
|
||||
test('Image decoder control test', () async {
|
||||
final ui.Image image = await decodeImageFromList(new Uint8List.fromList(transparentImage));
|
||||
final ui.Image image = await decodeImageFromList(new Uint8List.fromList(kTransparentImage));
|
||||
expect(image, isNotNull);
|
||||
expect(image.width, 1);
|
||||
expect(image.height, 1);
|
||||
|
@ -3,6 +3,7 @@
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:typed_data';
|
||||
import 'dart:ui' as ui show Image;
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
@ -11,6 +12,8 @@ import 'package:flutter/services.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
import '../services/image_data.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets('Verify Image resets its RenderImage when changing providers', (WidgetTester tester) async {
|
||||
final GlobalKey key = new GlobalKey();
|
||||
@ -299,6 +302,9 @@ void main() {
|
||||
expect(image.toString(), matches(new RegExp(r'_ImageState#[0-9]+\(_StateLifecycle.defunct; not mounted; stream: ImageStream\(OneFrameImageStreamCompleter; \[100×100\] @ 1\.0x; 0 listeners\); pixels: \[100×100\] @ 1\.0x\)')));
|
||||
});
|
||||
|
||||
testWidgets('Image.memory control test', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(new Image.memory(new Uint8List.fromList(kTransparentImage)));
|
||||
});
|
||||
}
|
||||
|
||||
class TestImageProvider extends ImageProvider<TestImageProvider> {
|
||||
|
Loading…
x
Reference in New Issue
Block a user