Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to access image pixel data in react-native

I have an Image that was loaded from camera roll or any other source, usually local one.

How can I access its pixel data map to perform some calculations or measurements?

like image 417
zamuka Avatar asked Jun 29 '16 11:06

zamuka


People also ask

How do I read an image in react-native?

Open App. js and add the following code: import { StatusBar } from "expo-status-bar"; import React from "react"; import { StyleSheet, Text, View, ImageBackground } from "react-native"; const staticImage = require("./src/assets/static-image. png"); export default function App() { return ( <View style={styles.

Can I use PX in react-native?

Also instead of pixels, React Native uses “units” that get converted into pixels, related pixels. We know that all our mobile devices have screens with different pixel density, even though we always work with relative pixels.


1 Answers

There is a way of getting this information using native modules, but I only have Android implementation at the moment. Tested on RN 0.42.3. First of all, you'll need to create a native module in your app. Assuming that application is initialized with the name SampleApp, create new directory in your React Native project android/app/src/main/java/com/sampleapp/bitmap with two files in it:

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

  }

}

As you can see in the second file there is a method getPixels, which will be available from JS as a part of Bitmap native module. It accepts a path to an image file, converts the image to an internal Bitmap type, which allows to read image pixels. All image pixels are read one by one and saved to array of pixels in a form of hex strings (because React Native does not allow to pass hex values through the bridge). These hex strings have 8 characters, 2 characters per ARGB channel: first two characters is a hex value for alpha channel, second two - for red, third two - for green and the last two - for blue channel. For example, the value ffffffff - is a white color and ff0000ff - is a blue color. For convenience, image width, height and presence of alpha channel are returned along with array of pixels. Method returns a promise with an object:

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

Native module also has to be registered in the app, modify android/app/src/main/java/com/sampleapp/MainApplication.java and add new module in there:

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

How to use from 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);
  });

I need to mention, that it performs pretty slow, most likely because of transfering a huge array through the bridge.

like image 93
Michael Radionov Avatar answered Oct 03 '22 02:10

Michael Radionov