【问题标题】:How to access image pixel data in react-native如何在 react-native 中访问图像像素数据
【发布时间】:2016-06-29 11:27:40
【问题描述】:

我有一张从相机胶卷或任何其他来源(通常是本地来源)加载的图像。

如何访问其像素数据图以执行一些计算或测量?

【问题讨论】:

  • 你找到解决方案了吗?
  • 我认为您可以将图像绘制到画布上,然后使用getImageData() 获取数据映射:developer.mozilla.org/en-US/docs/Web/API/…。虽然,它不是基于 React 的解决方案。

标签: javascript react-native


【解决方案1】:

有一种使用本机模块获取此信息的方法,但我目前只有 Android 实现。在 RN 0.42.3 上测试。首先,您需要在您的应用程序中创建一个原生模块。假设应用程序使用名称 SampleApp 进行初始化,请在您的 React Native 项目 android/app/src/main/java/com/sampleapp/bitmap 中创建新目录,其中包含两个文件:

android/app/src/main/java/com/sampleapp/bitmap/BitmapReactPackage.java

package com.sampleapp;

import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.JavaScriptModule;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class BitmapReactPackage implements ReactPackage {

  @Override
  public List<Class<? extends JavaScriptModule>> createJSModules() {
    return Collections.emptyList();
  }

  @Override
  public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
    return Collections.emptyList();
  }

  @Override
  public List<NativeModule> createNativeModules(
                              ReactApplicationContext reactContext) {
    List<NativeModule> modules = new ArrayList<>();

    modules.add(new BitmapModule(reactContext));

    return modules;
  }

}

android/app/src/main/java/com/sampleapp/bitmap/BitmapModule.java

package com.sampleapp;

import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.WritableNativeArray;
import com.facebook.react.bridge.WritableNativeMap;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;

import java.io.IOException;

public class BitmapModule extends ReactContextBaseJavaModule {

  public BitmapModule(ReactApplicationContext reactContext) {
    super(reactContext);
  }

  @Override
  public String getName() {
    return "Bitmap";
  }

  @ReactMethod
  public void getPixels(String filePath, final Promise promise) {
    try {
      WritableNativeMap result = new WritableNativeMap();
      WritableNativeArray pixels = new WritableNativeArray();

      Bitmap bitmap = BitmapFactory.decodeFile(filePath);
      if (bitmap == null) {
        promise.reject("Failed to decode. Path is incorrect or image is corrupted");
        return;
      }

      int width = bitmap.getWidth();
      int height = bitmap.getHeight();

      boolean hasAlpha = bitmap.hasAlpha();

      for (int x = 0; x < width; x++) {
        for (int y = 0; y < height; y++) {
          int color = bitmap.getPixel(x, y);
          String hex = Integer.toHexString(color);
          pixels.pushString(hex);
        }
      }

      result.putInt("width", width);
      result.putInt("height", height);
      result.putBoolean("hasAlpha", hasAlpha);
      result.putArray("pixels", pixels);

      promise.resolve(result);

    } catch (Exception e) {
      promise.reject(e);
    }

  }

}

正如您在第二个文件中看到的那样,有一个方法getPixels,它将作为Bitmap 原生模块的一部分从JS 中获得。它接受图像文件的路径,将图像转换为内部位图类型,允许读取图像像素。所有图像像素都被逐个读取并以十六进制字符串的形式保存到像素数组中(因为 React Native 不允许通过桥传递十六进制值)。这些十六进制字符串有 8 个字符,每个 ARGB 通道有 2 个字符:前两个字符是 alpha 通道的十六进制值,后两个 - 红色,第三个 - 绿色,最后两个 - 蓝色通道。例如,值ffffffff - 是白色,ff0000ff - 是蓝色。为方便起见,图像宽度、高度和 alpha 通道的存在与像素数组一起返回。方法返回一个带有对象的承诺:

{
  width: 1200,
  height: 800,
  hasAlpha: false,
  pixels: ['ffffffff', 'ff00ffff', 'ffff00ff', ...]
}

原生模块也必须在应用中注册,修改android/app/src/main/java/com/sampleapp/MainApplication.java并在其中添加新模块:

@Override
protected List<ReactPackage> getPackages() {
  return Arrays.<ReactPackage>asList(
      new MainReactPackage(),
      new BitmapReactPackage() // <---
  );
}

如何从 JS 中使用:

import { NativeModules } from 'react-native';

const imagePath = '/storage/emulated/0/Pictures/blob.png';

NativeModules.Bitmap.getPixels(imagePath)
  .then((image) => {
    console.log(image.width);
    console.log(image.height);
    console.log(image.hasAlpha);


    for (let x = 0; x < image.width; x++) {
      for (let y = 0; y < image.height; y++) {
        const offset = image.width * y + x;
        const pixel = image.pixels[offset];
      }
    }
  })
  .catch((err) => {
    console.error(err);
  });

我需要提一下,它的执行速度很慢,很可能是因为通过桥传输了一个巨大的数组。

【讨论】:

  • 感谢您的回答!看起来本机模块是要走的路。顺便说一句,Android API 提到颜色是按 ARGB 顺序编码的,而不是 RGBA。您提到不支持“十六进制值”。整数数组真的不支持吗?没关系,任何图像处理都应该在本机端完成。
  • @cubrr,你是对的,我没有引起足够的重视。颜色确实是 ARGB。关于十六进制:我试图通过桥传递直接从调用bitmap.getPixel(x, y) 返回的颜色值,但是我得到的 int 值对我来说不是很有信息,这些是一堆负整数。在 JS 中执行 pixel.toString(16) 后变得更好。例如:(-4153434).toString(16) = "-3f605a"。我想由您决定您喜欢哪种格式。
  • 啊,对,Java 没有无符号数,所以它们当然可能是负数。可能有效的是通过长期:long color = bitmap.getPixel(x, y) &amp; 0xFFFFFFFFL
【解决方案2】:

谢谢迈克尔。 今天似乎更容易了

import { RNCamera } from 'react-native-camera';

<RNCamera ref={ref => {this.camera = ref;}} style={styles.preview}></RNCamera>

//Set the options for the camera
const options = {
    base64: true
};
// Get the base64 version of the image
const data = await this.camera.takePictureAsync(options)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-30
    • 2020-07-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-21
    • 2019-08-27
    相关资源
    最近更新 更多