I am creating a image processing app so first using android platform apis to process the bitmap ad then sending it to flutter. I am using below code to convert bitmap to byte[]
Bitmap bitmap = BitmapFactory.decodeFile(uri.getPath());
ByteBuffer allocate = ByteBuffer.allocate(bitmap.getByteCount());
bitmap.copyPixelsToBuffer(allocate);
byte[] array = allocate.array();
and then sending it to flutter using Method Channel as Uint8List but when i read it as Image.memory() . It is giving me error as
Failed decoding image. Data is either invalid, or it is encoded using an unsupported format. Below is code of My Main Activity
package com.rahul.flutterappdomain;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.util.Log;
import com.asksira.bsimagepicker.BSImagePicker;
import com.asksira.bsimagepicker.Utils;
import java.nio.ByteBuffer;
import io.flutter.app.FlutterFragmentActivity;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugins.GeneratedPluginRegistrant;
public class ActivityMain extends FlutterFragmentActivity implements BSImagePicker.OnSingleImageSelectedListener{
private static final String TAG = "DomainFilterFlutterApp";
private static final String CHANNEL = "com.rummy.io/filter";
MethodChannel methodChannel;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
GeneratedPluginRegistrant.registerWith(this);
methodChannel = new MethodChannel(getFlutterView(), CHANNEL);
methodChannel.setMethodCallHandler(new MethodChannel.MethodCallHandler() {
@Override
public void onMethodCall(MethodCall methodCall, MethodChannel.Result result) {
if (methodCall.method.equals("openImagePicker")) {
showImagePickerDialog();
result.success(null);
}
}
});
}
private void showImagePickerDialog() {
String providerAuthority = "com.rahul.ffd.fileprovider";
BSImagePicker singleSelectionPicker = new BSImagePicker.Builder(providerAuthority)
.setSpanCount(4)
.setGridSpacing(Utils.dp2px(4))
.setPeekHeight(Utils.dp2px(360))
.build();
singleSelectionPicker.show(getSupportFragmentManager(), "picker");
}
@Override
public void onSingleImageSelected(Uri uri) {
Bitmap bitmap = BitmapFactory.decodeFile(uri.getPath());
ByteBuffer allocate = ByteBuffer.allocate(bitmap.getByteCount());
bitmap.copyPixelsToBuffer(allocate);
byte[] array = allocate.array();
methodChannel.invokeMethod("setImage", array);
Log.d(TAG, "onSingleImageSelected: ------------");
}
}
and code of my dart file
import 'dart:async';
import 'dart:io';
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'colors.dart';
//import 'package:image_picker/image_picker.dart';
void main(){runApp(MyApp());}
class MyApp extends StatefulWidget {
static const platform = const MethodChannel('com.rummy.io/filter');
String _image;
Uint8List _image_data ;
Future<Null> getImage() async {
platform.invokeMethod("openImagePicker");
}
@override
State<StatefulWidget> createState() {
var myAppState = MyAppState();
platform.setMethodCallHandler((MethodCall call) {
switch (call.method) {
case 'setImage':
print('setState');
myAppState.makeState(call.arguments);
print('setState');
}
});
return myAppState;
}
}
class MyAppState extends State<MyApp> {
void makeState( Uint8List imgData) {
setState(() {
widget._image_data = imgData;
});
}
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: _mAppTheme,
home: Scaffold(
appBar: AppBar(
actions: <Widget>[
IconButton(
onPressed: () {},
icon: Icon(Icons.save),
)
],
),
body: _mBody(widget._image_data),
floatingActionButton: FloatingActionButton(
onPressed: () {
widget.getImage();
},
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.elliptical(12.0, 13.0))),
child: Icon(Icons.image),
),
),
);
}
double _discreteValue = 0.0;
double _discreteValue2 = 0.0;
Widget _mBody(Uint8List imgData) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: Card(
// shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20.0)),
child: imgData == null
? Image.asset(
'images/beauty.jpg',
fit: BoxFit.contain,
)
: /*Image.file(
File(img),
fit: BoxFit.contain,)*/
Image.memory(imgData),
),
),
new Slider(
value: _discreteValue,
min: 0.0,
max: 200.0,
divisions: 10,
activeColor: Colors.greenAccent,
label: '${_discreteValue.round()}',
onChanged: (double value) {
setState(() {
_discreteValue = value;
});}),
new Slider(
value: _discreteValue2,
min: 0.0,
max: 200.0,
divisions: 10,
activeColor: Colors.greenAccent,
label: '${_discreteValue2.round()}',
onChanged: (double value) {
setState(() {
_discreteValue2 = value;
});}),
],
),
);
}
/* Future getImage() async {
var image = await ImagePicker.pickImage(source: ImageSource.gallery);
setState(() {
_image = image;
});
}*/
}
final ThemeData _mAppTheme = _buildAppTheme();
ThemeData _buildAppTheme() {
final ThemeData base = ThemeData.light();
return base.copyWith(
accentColor: kShrineBrown900,
primaryColor: kShrinePink100,
buttonColor: kShrinePink100,
scaffoldBackgroundColor: kShrineBackgroundWhite,
cardColor: kShrineBackgroundWhite,
textSelectionColor: kShrinePink100,
errorColor: kShrineErrorRed,
);
}
Displaying. To easiest way to display an image is to getting the bitmap with header and then passing it to the widget Image. memory : // .. Uint8List headedBitmap = bitmap.
RaisedButton( onPressed: () async { List<int> imageBytes = await sampleImage. readAsBytes(); base64Image = base64Encode(imageBytes); print(base64Image);},), SizedBox(height: 30,), Image.
I had the same error message. The problem is that you decode bitmap image in a wrong way, in your Java code. Here's the solution that will work
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
byte[] byteArray = stream.toByteArray();
bitmap.recycle();
// And return byteArray through your MethodChannel
You can't pass a raw bitmap to Image.memory
because it doesn't contain enough information, notably width and height. The Image constructors need a recognized file format: JPEG, PNG, GIF, Animated GIF, WebP, Animated WebP, BMP, and WBMP.
If the file that you are opening here:
Bitmap bitmap = BitmapFactory.decodeFile(uri.getPath());
is in one of the formats above, then don't decode it into an Android bitmap, but rather read it verbatim into a byte array, send that over the channel and use that as the input for the Image constructor. (Or, if you can, simply pass the file path back to Dart and use dart:io
and, if necessary path_provider, to read the file.)
If you really need to pass a raw bitmap to Image then the simplest thing is to prepend a Windows Bitmap (BMP) header. There's an example here for an unusual raw bitmap format. Yours wouldn't even need the indexed color map as you almost certainly already have ARGB pixels (test this by checking that bitmap size in bytes = 4 * width * height).
More detail to @Ihor Klimov answer
I convert the bitmap in java from fingerprint device by:
ByteArrayOutputStream stream = new ByteArrayOutputStream();
fingerBitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
byte[] byteArray = stream.toByteArray();
fingerBitmap.recycle();
then in Flutter Dart I just use
Uint8List fingerImages;
void mapFingerImage(dynamic imageBytes) {
setState(() {
fingerImages = imageBytes;
});
}
Image.memory(fingerImages,
width: 100,
height: 100,
fit: BoxFit.contain,)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With