从 Android 平台发送 Bitmap 到 Flutter

Gau*_*aan 10 android dart flutter

我正在创建一个图像处理应用程序,因此首先使用 android 平台 apis 来处理位图广告,然后将其发送到 flutter。我正在使用下面的代码将位图转换为字节 []

  Bitmap bitmap = BitmapFactory.decodeFile(uri.getPath());
        ByteBuffer allocate = ByteBuffer.allocate(bitmap.getByteCount());
        bitmap.copyPixelsToBuffer(allocate);
        byte[] array = allocate.array();
Run Code Online (Sandbox Code Playgroud)

然后使用 Method Channel 作为 Uint8List 将其发送到 flutter 但当我将其读取为 Image.memory() 时。它给了我错误

解码图像失败。数据无效,或使用不受支持的格式编码。以下是我的主要活动的代码

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: ------------");

    }
}
Run Code Online (Sandbox Code Playgroud)

和我的飞镖文件的代码

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,
  );
}
Run Code Online (Sandbox Code Playgroud)

Iho*_*mov 7

我有同样的错误消息。问题在于您在 Java 代码中以错误的方式解码位图图像。这是可行的解决方案

ByteArrayOutputStream stream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
byte[] byteArray = stream.toByteArray();
bitmap.recycle();

// And return byteArray through your MethodChannel
Run Code Online (Sandbox Code Playgroud)


Ric*_*eap 3

您无法传递原始位图,Image.memory因为它不包含足够的信息,特别是宽度和高度。图像构造函数需要可识别的文件格式:JPEG、PNG、GIF、动画 GIF、WebP、动画 WebP、BMP 和 WBMP。

如果您在此处打开的文件:

Bitmap bitmap = BitmapFactory.decodeFile(uri.getPath());
Run Code Online (Sandbox Code Playgroud)

是上述格式之一,那么不要将其解码为 Android 位图,而是将其逐字读取到字节数组中,通过通道发送并将其用作 Image 构造函数的输入。(或者,如果可以的话,只需将文件路径传递回 Dart 并使用dart:io,如果需要的话,使用 path_provider 来读取文件。)

如果您确实需要将原始位图传递给 Image,那么最简单的方法就是在前面添加 Windows 位图 (BMP) 标头。这里有一个不寻常的原始位图格式的示例。您甚至不需要索引颜色图,因为您几乎肯定已经有了 ARGB 像素(通过检查位图大小(以字节为单位 = 4 * 宽度 * 高度来测试这一点)。