2016-06-29 3 views
8

У меня есть изображение, загруженное из рулона камеры или любого другого источника, обычно локального.Как получить данные пикселя изображения в ответном нативном

Как я могу получить доступ к своей карте данных пикселей для выполнения некоторых расчетов или измерений?

+1

Вы когда-нибудь находили решение этого вопроса? – James

+1

Я думаю, вы могли бы нарисовать изображение на холсте, а затем использовать 'getImageData()' для получения карты данных: https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/getImageData. Хотя это не решение на основе React. –

ответ

9

Существует способ получения этой информации с использованием собственных модулей, но на данный момент у меня есть только реализация Android. Протестировано по RN 0.42.3. Прежде всего, вам нужно создать собственный модуль в своем приложении. Если предположить, что приложение инициализируется с именем SampleApp, создать новый каталог в вашем React Native проект android/app/src/main/java/com/sampleapp/bitmap с двумя файлами в нем:

Android/приложение/SRC/главная/Java/COM/SampleApp/растровый/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/приложение/SRC/главная/Java/COM/SampleApp/растровый/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, который будет доступен JS как часть встроенного модуля Bitmap. Он принимает путь к файлу изображения, преобразует изображение во внутренний тип Bitmap, что позволяет считывать пиксели изображения. Все пиксели изображений считываются один за другим и сохраняются в массиве пикселей в форме шестнадцатеричных строк (поскольку React Native не позволяет передавать шестнадцатеричные значения через мост). Эти шестнадцатеричные строки имеют 8 символов, 2 символа на канал ARGB: первые два символа - это шестнадцатеричное значение для альфа-канала, второе - для красного, третье - для зеленого, а последние два - для синего канала. Например, значение ffffffff - это белый цвет и ff0000ff - это синий цвет. Для удобства, ширина изображения, высота и наличие альфа-канала возвращаются вместе с массивом пикселей. Метод возвращает обещание с объектом:

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

Native модуль также должен быть зарегистрирован в приложении, изменять 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); 
    }); 

Я должен упомянуть, что он работает довольно медленно, скорее всего, из-за передачи огромного массива через мост.

+1

Спасибо за ваш ответ! Похоже, что родные модули - это путь. Кстати, в [Android API] (https://developer.android.com/reference/android/graphics/Color.html) упоминается, что цвета закодированы в заказе ARGB, а не RGBA. Вы упомянули, что «шестнадцатеричные значения» не поддерживаются. Являются ли целые массивы * действительно * не поддерживаемыми? Не то чтобы это важно, любая обработка изображений, вероятно, должна быть выполнена на родной стороне в любом случае. – cubrr

+1

@cubrr, вы правы, я не обращал на это достаточного внимания. Цвета действительно ARGB. Что касается hex: я попытался передать значение цвета, которое возвращается непосредственно из вызова 'bitmap.getPixel (x, y)' через мост, но значения int, которые я получил, были не очень информативными для меня, это куча отрицательный ints. После выполнения 'pixel.toString (16)' в JS в порядке улучшилось. Например: '(-4153434) .toString (16) =" -3f605a "'. Думаю, вам решать, какой формат вы предпочитаете. –

+0

А, правильно, Java не имеет неподписанных чисел, поэтому, конечно, они могут быть отрицательными.То, что может работать, проходит через longs: 'long color = bitmap.getPixel (x, y) & 0xFFFFFFFFL' – cubrr

Смежные вопросы