Commit 6c93270d authored by Ian Hickson's avatar Ian Hickson Committed by GitHub

FileImage (#6853)

parent d3dc5d7c
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
// found in the LICENSE file. // found in the LICENSE file.
import 'dart:async'; import 'dart:async';
import 'dart:io' show File;
import 'dart:ui' show Size, Locale, hashValues; import 'dart:ui' show Size, Locale, hashValues;
import 'dart:ui' as ui show Image; import 'dart:ui' as ui show Image;
import 'dart:typed_data'; import 'dart:typed_data';
...@@ -370,6 +371,68 @@ class NetworkImage extends ImageProvider<NetworkImage> { ...@@ -370,6 +371,68 @@ class NetworkImage extends ImageProvider<NetworkImage> {
String toString() => '$runtimeType("$url", scale: $scale)'; String toString() => '$runtimeType("$url", scale: $scale)';
} }
/// Decodes the given [File] object as an image, associating it with the given
/// scale.
class FileImage extends ImageProvider<FileImage> {
/// Creates an object that decodes a [File] as an image.
///
/// The arguments must not be null.
const FileImage(this.file, { this.scale: 1.0 });
/// The file to decode into an image.
final File file;
/// The scale to place in the [ImageInfo] object of the image.
final double scale;
@override
Future<FileImage> obtainKey(ImageConfiguration configuration) {
return new SynchronousFuture<FileImage>(this);
}
@override
ImageStreamCompleter load(FileImage key) {
return new OneFrameImageStreamCompleter(
_loadAsync(key),
informationCollector: (StringBuffer information) {
information.writeln('Path: ${file?.path}');
}
);
}
Future<ImageInfo> _loadAsync(FileImage key) async {
assert(key == this);
Uint8List bytes = await file.readAsBytes();
if (bytes.lengthInBytes == 0)
return null;
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 FileImage typedOther = other;
return file?.path == file?.path
&& scale == typedOther.scale;
}
@override
int get hashCode => hashValues(file?.path, scale);
@override
String toString() => '$runtimeType("${file?.path}", scale: $scale)';
}
/// Fetches an image from an [AssetBundle], associating it with the given scale. /// Fetches an image from an [AssetBundle], associating it with the given scale.
/// ///
/// This implementation requires an explicit final [name] and [scale] on /// This implementation requires an explicit final [name] and [scale] on
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'dart:io' show Platform; import 'dart:io' show File, Platform;
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:meta/meta.dart'; import 'package:meta/meta.dart';
...@@ -14,7 +14,8 @@ import 'media_query.dart'; ...@@ -14,7 +14,8 @@ import 'media_query.dart';
export 'package:flutter/services.dart' show export 'package:flutter/services.dart' show
AssetImage, AssetImage,
ExactAssetImage, ExactAssetImage,
NetworkImage; NetworkImage,
FileImage;
/// Creates an [ImageConfiguration] based on the given [BuildContext] (and /// Creates an [ImageConfiguration] based on the given [BuildContext] (and
/// optionally size). /// optionally size).
...@@ -37,9 +38,10 @@ ImageConfiguration createLocalImageConfiguration(BuildContext context, { Size si ...@@ -37,9 +38,10 @@ ImageConfiguration createLocalImageConfiguration(BuildContext context, { Size si
/// specified: /// specified:
/// ///
/// * [new Image], for obtaining an image from an [ImageProvider]. /// * [new Image], for obtaining an image from an [ImageProvider].
/// * [new Image.network], for obtaining an image from a URL.
/// * [new Image.asset], for obtaining an image from an [AssetBundle] /// * [new Image.asset], for obtaining an image from an [AssetBundle]
/// using a key. /// using a key.
/// * [new Image.network], for obtaining an image from a URL.
/// * [new Image.file], for obtaining an image from a [File].
/// ///
/// To automatically perform pixel-density-aware asset resolution, specify the /// To automatically perform pixel-density-aware asset resolution, specify the
/// image using an [AssetImage] and make sure that a [MaterialApp], [WidgetsApp], /// image using an [AssetImage] and make sure that a [MaterialApp], [WidgetsApp],
...@@ -90,6 +92,26 @@ class Image extends StatefulWidget { ...@@ -90,6 +92,26 @@ class Image extends StatefulWidget {
}) : image = new NetworkImage(src, scale: scale), }) : image = new NetworkImage(src, scale: scale),
super(key: key); super(key: key);
/// Creates a widget that displays an [ImageStream] obtained from a [File].
///
/// The [file], [scale], and [repeat] arguments must not be null.
///
/// On Android, this may require the
/// `android.permission.READ_EXTERNAL_STORAGE` permission.
Image.file(File file, {
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 FileImage(file, scale: scale),
super(key: key);
/// Creates a widget that displays an [ImageStream] obtained from an asset /// Creates a widget that displays an [ImageStream] obtained from an asset
/// bundle. The key for the image is given by the `name` argument. /// bundle. The key for the image is given by the `name` argument.
/// ///
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment