Отправка растрового изображения во Flutter с платформы Android

Я создаю приложение для обработки изображений, поэтому сначала использую API платформы Android для обработки растрового объявления, а затем отправляю его на флаттер. Я использую приведенный ниже код для преобразования растрового изображения в byte []

  Bitmap bitmap = BitmapFactory.decodeFile(uri.getPath());
        ByteBuffer allocate = ByteBuffer.allocate(bitmap.getByteCount());
        bitmap.copyPixelsToBuffer(allocate);
        byte[] array = allocate.array();

а затем отправив его во флаттер, используя канал метода как Uint8List но когда я читаю его как 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: ------------");

    }
}

и код моего файла дротика

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,
  );
}

вы отправляете изображение из приложения Google Фото?

user6327816 25.07.2018 12:16

нет, я использую пользовательский сборщик изображений BSImagePicker, но это не имеет значения, потому что я получаю uri изображения, а затем декодирую его с помощью BitmapFactory

Gaurav Maan 25.07.2018 12:20

Я думаю, что лучше поставить путь изображения между Flutter и Android.

Scott Wang 25.03.2019 11:48

вы пытались сохранить изображение в кеш и прочитать его во флаттере?

Alexufo 24.05.2021 17:34
9
4
6 109
3

Ответы 3

Вы не можете передать необработанное растровое изображение в Image.memory, потому что оно не содержит достаточно информации, особенно ширины и высоты. Конструкторам изображений требуется распознанный формат файла: JPEG, PNG, GIF, анимированный GIF, WebP, Animated WebP, BMP и WBMP.

Если файл, который вы открываете здесь:

Bitmap bitmap = BitmapFactory.decodeFile(uri.getPath());

находится в одном из вышеперечисленных форматов, тогда не декодируйте его в растровое изображение Android, а скорее прочтите его дословно в массив байтов, отправьте его по каналу и используйте в качестве входных данных для конструктора изображения. (Или, если вы можете, просто передайте путь к файлу обратно в Dart и используйте dart:io и, при необходимости, path_provider, чтобы прочитать файл.)

Если вам действительно нужно передать необработанное растровое изображение в Image, то проще всего добавить заголовок Windows Bitmap (BMP). Есть пример здесь для необычного необработанного формата растрового изображения. Вашему даже не понадобится индексированная цветовая карта, поскольку у вас почти наверняка уже есть пиксели ARGB (проверьте это, проверив, что размер растрового изображения в байтах = 4 * ширина * высота).

Например: не используйте метод decodeFile, а только обычный ввод-вывод файлов Java. Однако, как было предложено, вероятно, проще передать имя файла Dart и использовать dart:io для его чтения.

Richard Heap 14.12.2019 17:22

У меня было такое же сообщение об ошибке. Проблема в том, что вы неправильно декодируете растровое изображение в своем Java-коде. Вот решение, которое будет работать

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

// And return byteArray through your MethodChannel

Подробнее на ответ @Ihor Klimov

Я конвертирую растровое изображение в java с устройства отпечатков пальцев:

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

тогда во Flutter Dart я просто использую

Uint8List fingerImages;

  void mapFingerImage(dynamic imageBytes) {
    setState(() {
      fingerImages = imageBytes;
    });
  }
    Image.memory(fingerImages,
                  width: 100,
                  height: 100,
                   fit: BoxFit.contain,)

Другие вопросы по теме