In Flutter integration testing, how can we handle ImagePicker? as well as other platform related plugins?
Finally, I got a solution for this question.
this is the code in app.dart:
prepare an image file in assets, for example: images/sample.png.
import 'dart:io';
import 'dart:typed_data';
import 'package:path_provider/path_provider.dart';
import 'package:image_picker_test/main.dart' as app;
import 'package:flutter_driver/driver_extension.dart';
import 'package:flutter/services.dart';
void main() {
// This line enables the extension.
enableFlutterDriverExtension();
const MethodChannel channel =
MethodChannel('plugins.flutter.io/image_picker');
channel.setMockMethodCallHandler((MethodCall methodCall) async {
ByteData data = await rootBundle.load('images/sample.png');
Uint8List bytes = data.buffer.asUint8List();
Directory tempDir = await getTemporaryDirectory();
File file = await File('${tempDir.path}/tmp.tmp', ).writeAsBytes(bytes);
print(file.path);
return file.path;
});
app.main();
}
Frank Yan's solution works fine. Basically he is using MethodChannel as an interceptor of request to ImagePicker
MethodChannel('plugins.flutter.io/image_picker')
In this part he defines which plugin has to be mocked
channel.setMockMethodCallHandler((MethodCall methodCall) async {
ByteData data = await rootBundle.load('images/sample.png');
Uint8List bytes = data.buffer.asUint8List();
Directory tempDir = await getTemporaryDirectory();
File file = await File('${tempDir.path}/tmp.tmp', ).writeAsBytes(bytes);
print(file.path);
return file.path;
});
This function defines what has to be returned from request to image picker plugin. So your program will do these actions each time when user uses image picker. Right here it will just return the image from 'images/sample.png'. In my case I had to put image into assets/image.png in my project root. Anyway you can mock any plugin like that. I had to also mock cropper plugin which is called after image picker ends it's job.
**Note: **mocking is not the best way to go with e2e or as they are called in flutter integration tests. I used it just because there is no workaround (I couldn't find it) at the moment and I am blocked with step of picture upload in my scenario. So be careful with using such approach.
You don't need to call this function anywhere in test. Your app will run with mocked plugin that we define in MethodChannel constuctor MethodChannel('');
Related
Trying to write to a local file in Android.
Tried import {fileSystemModule} from "#nativescript/core"; but get error 'fileSystemModule' was not found in '#nativescript/core'.
Have also tried import {fileSystemModule} from "#nativescript/core/file-system" but it doesn't exist. I'm using plain Javascript.
Nativescript 8.0.2
The import paths are updated in the recent versions of NativeScript. You can access these directly now without having to go through fileSystemModule. See code below:
import { knownFolders, File, Folder } from '#nativescript/core';
To write to a local file using the latest NativeScript would look like this:
writeToFile(): void {
const folder = knownFolders.documents().getFolder(FOLDER_NAME);
const file = folder.getFile(FILE_NAME.txt);
file.writeText(SOME_STRING_TO_WRITE_TO_FILE);
}
To write to an accessible location in Android, you can use the following:
writeToFile(): void {
const folderPath = path.join(android.os.Environment.getExternalStorageDirectory().getAbsolutePath().toString())
const folder = Folder.fromPath(folderPath);
const file = folder.getFile(FILE_NAME.txt);
file.writeText(SOME_STRING_TO_WRITE_TO_FILE);
}
I have a video file in my assets folder (like mp4). I want to read that video file as an image stream, like an image stream in the camera package https://pub.dev/documentation/camera/latest/camera/CameraController/startImageStream.html
I want to pass the image to Tflite model.
Something like that:
controller = loadVideo('assets/example.mp4'); // how to do that?!
controller.startImageStream((CameraImage img) {
Tflite.runPoseNetOnFrame(
bytesList: img.planes.map((plane) {
return plane.bytes;
}).toList(),
imageHeight: img.height,
imageWidth: img.width,
numResults: 1,
threshold: 0.1,
).then((recognitions) {
// ...
}
}
I tried to search in the image_picker and video_player packages, but did not find anything.
What I did is to split the images and save them as files and then send it to the tf model. It's not fast (because you make file and then read it) but it is working, tested on android and it should work on IOS :)
I made a PR in the package flutter_export_video_frame, now it have a function in the name of exportImagesFromFile. It is Returning a Stream of images from video file as Stream<File>.
To get the video file from the asset folder I use the following function:
import 'dart:async';
import 'dart:io';
import 'package:path_provider/path_provider.dart';
import 'package:flutter/services.dart' show rootBundle;
import 'package:path/path.dart';
Future<File> getImageFileFromAssets(String path) async {
final byteData = await rootBundle.load('assets/$path');
final fileName = basename(path);
final file = new File('${(await getTemporaryDirectory()).path}/$fileName');
await file.writeAsBytes(byteData.buffer
.asUint8List(byteData.offsetInBytes, byteData.lengthInBytes));
return file;
}
And then to move it to the posenet/model, there is a function that gets File as input:
var results = await Tflite.runPoseNetOnImage(
path: path,
numResults: 1,
);
One possible improvement to this method is to make it works only on the RAM (after you read the video, of course)
Yes, sure you can do that in one of the following ways:
Use the export_video_frame plugin
Use video_thumbnail plugin
You can specify an exact frame by the time parameter.
I am trying to save the image from assets to internal storage. But, I could not load the image from assets to file. Here is what I have done:
onTap: () async {
final String documentPath = (await getApplicationDocumentsDirectory()).path;
String imgPath = (galleryItems[currentIndex].assetName).substring(7);
File image = await getImageFileFromAssets(imgPath);
print(image.path);
}
I used substring(7) to eliminate assets/ as, my assetName comes as assets/images/foo.jpg.
Future<File> getImageFileFromAssets(String path) async {
final byteData = await rootBundle.load('assets/$path');
final file =
await File('${(await getApplicationDocumentsDirectory()).path}/$path')
.create(recursive: true);
await file.writeAsBytes(byteData.buffer
.asUint8List(byteData.offsetInBytes, byteData.lengthInBytes));
return file;
}
After I get image, I don't know how to proceed forward to create a directory with my name in internal storage. And, copy file there.
*Note:- I have editted the post, as some basic mistakes were pointed out.
Update
Here is what I came up with. And it saves image in the /storage/emulated/0/Android/data/com.example.my_project/files/Pics/foo.jpg path.
File image = await getImageFileFromAssets(imgPath);
final extDir = await getExternalStorageDirectory();
// Path of file
final myImagePath = '${extDir.path}/Pics';
// Create directory inside where file will be saved
await new Directory(myImagePath).create();
// File copied to ext directory.
File newImage =
await image.copy("$myImagePath/${basename(imgPath)}");
print(newImage.path);
Here are some links that really helped me:
Flutter How to save Image file to new folder in gallery?
How to Save Image File in Flutter ? File selected using Image_picker plugin
How to convert asset image to File?
Special thanks to #David for the help. Please see comments to understand full scene if you are here to solve your similar problem.
So, I am accepting the answer from #David.
You are trying to create a file object in a path that doesn't exist. You're using your asset path, the path relative to the root of your Flutter project. However, this path doesn't exist in the device's documents folder, so the file can't be created there. The file also doesn't exist in the assets folder because you're prepending the documents path.
To fix your issue, you should pass assetName to rootBundle.load(), without the documents path and open the File() somewhere like $documentPath/foo.jpg
Edit:
To create the file you still have to call File.create, so you need to run:
final file = await File('$documentPath/images/foo.jpg').create(recursive: true);
For future reference, this is just to update the solution of #Biplove which really helped me a lot as a newbie...
Future<File> getImageFileFromAssets(String unique, String filename) async {
ByteData byteData = await rootBundle.load(assets/filename));
// this creates the file image
File file = await File('$imagesAppDirectory/$filename').create(recursive: true);
// copies data byte by byte
await file.writeAsBytes(byteData.buffer.asUint8List(byteData.offsetInBytes, byteData.lengthInBytes));
return file;
}
Thanks.
I am trying to use the image_picker plugin. I can get the image as file using this plugin. I need to convert this image to bytes and send to a api. So I tried to use dart:convert to convert the image to byte string. Now when I decode I am getting a Uint8List type. How to convert this to a file and display in a Image.file(). I couldn’t proceed from here. Can someone help me with this.
consider i am getting this decodedBytes i am getting from a api response, how can i convert them to display in a Image widget
This is the code I tried so far.
var image = await ImagePicker.pickImage(source: ImageSource.camera);
setState(() {
imageURI = image;
final bytes = image.readAsBytesSync();
String img64 = base64Encode(bytes);
print(bytes);
print(img64);
final decodedBytes = base64Decode(img64);
print(decodedBytes);
//consider i am getting this decodedBytes i am getting from a api response, how can i convert them to display in a Image widget
});
I am getting this error using writeAsBytesSync(),
Unhandled Exception: FileSystemException: Cannot open file, path = 'decodedimg.png'
You get this error, because you can't write to any arbitrary location in an application sandbox. You can use path_provider to look up a temporary directory.
But in your case, just use the image object, pickImage already returns a File object, so just use Image.file(image)
If you want to decode a base64 into a temporary directory you can use:
import 'package:path_provider/path_provider.dart';
import 'package:path/path.dart' as path;
Future<File> writeImageTemp(String base64Image, String imageName) async {
final dir = await getTemporaryDirectory();
await dir.create(recursive: true);
final tempFile = File(path.join(dir.path, imageName));
await tempFile.writeAsBytes(base64.decode(base64Image));
return tempFile;
}
with pubspec.yaml:
dependencies:
path: ^1.6.0
path_provider: ^1.6.7
I am building an application, currently facing a problem I want to return an images which is stored in my server. I want to return image to React client, then it would be rendered in my component. But I can't figure out how to return the image itself. As far as I understand, I need to return image as JSON? But can't figure out how to do it in Nest.js framework.
First you should have a service, to serve static files. You can achieve this with Nest.JS. For example, if your images are placed in a public folder, placed in the root of your project, simply you can serve it, by adding the following line to your main.ts file:
import { join } from 'path';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.use('/public', express.static(join(__dirname, '..', 'public'))); // <-
await app.listen(3000);
}
Then for example you have cat.png placed in the public folder, and you want to send this in your response, you can send something like this:
{
image: `${baseUrl}/public/cat.png`
}
For example for your local server, baseURL will be http://localhost:3000.
You can take a look at this article for more detailed explanations.