2016-06-29 11 views
8

Ho un'immagine che è stata caricata dal rullino fotografico o da qualsiasi altra fonte, di solito locale.Come accedere ai dati dei pixel dell'immagine in modalità nativa reattiva

Come accedere alla relativa mappa dei dati dei pixel per eseguire alcuni calcoli o misurazioni?

+1

Hai mai trovato una soluzione a questo? – James

+1

Penso che si possa disegnare l'immagine su una tela, quindi usare 'getImageData()' per ottenere la mappa dei dati: https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/getImageData. Sebbene, non è una soluzione basata su React. –

risposta

9

C'è un modo per ottenere queste informazioni usando i moduli nativi, ma al momento ho solo l'implementazione per Android. Testato su RN 0.42.3. Prima di tutto, dovrai creare un modulo nativo nella tua app. Supponendo che l'applicazione viene inizializzata con il nome SampleApp, creare una nuova directory nel Reagire progetto Native android/app/src/main/java/com/sampleapp/bitmap con due file in essa contenuti:

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

    } 

} 

Come si può vedere nel secondo file c'è un metodo getPixels, che sarà disponibile da JS come a parte del modulo nativo Bitmap. Accetta un percorso per un file immagine, converte l'immagine in un tipo Bitmap interno, che consente di leggere i pixel dell'immagine. Tutti i pixel dell'immagine vengono letti uno ad uno e salvati in serie di pixel in una forma di stringhe esadecimali (poiché React Native non consente di passare valori esadecimali attraverso il bridge). Queste stringhe esagonali hanno 8 caratteri, 2 caratteri per il canale ARGB: i primi due caratteri sono un valore esadecimale per canale alfa, il secondo due - per il rosso, il terzo due - per il verde e gli ultimi due - per il canale blu. Ad esempio, il valore ffffffff - è un colore bianco e ff0000ff - è un colore blu. Per comodità, la larghezza, l'altezza e la presenza dell'immagine del canale alfa vengono restituite insieme a una serie di pixel. Metodo restituisce una promessa con un oggetto:

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

modulo nativo deve anche essere registrato in app, modificare android/app/src/main/java/com/sampleapp/MainApplication.java e aggiungere nuovo modulo in là:

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

Come usare da 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); 
    }); 

Devo dire che funziona piuttosto lentamente, molto probabilmente a causa del trasferimento di un enorme array attraverso il bridge.

+1

Grazie per la tua risposta! Sembra che i moduli nativi siano la strada da percorrere. A proposito, la [API Android] (https://developer.android.com/reference/android/graphics/Color.html) afferma che i colori sono codificati nell'ordine ARGB, non RGBA. Hai detto che "valori esadecimali" non sono supportati. Gli array di numeri interi * in realtà * non sono supportati? Non che sia importante, qualsiasi elaborazione delle immagini dovrebbe probabilmente essere eseguita sul lato nativo comunque. – cubrr

+1

@cubrr, hai ragione, non ho prestato abbastanza attenzione ad esso. I colori sono davvero ARGB. Riguardo all'esagono: ho provato a passare il valore del colore che viene restituito direttamente dalla chiamata 'bitmap.getPixel (x, y)' attraverso il bridge, ma i valori int ottenuti non erano molto istruttivi per me, questi sono un mucchio di valori negativi. Dopo aver eseguito 'pixel.toString (16)' in JS è migliorato. Ad esempio: '(-4153434) .toString (16) =" -3f605a "'. Immagino che spetti a te decidere quale formato preferisci. –

+0

Ah, giusto, Java non ha numeri non firmati, quindi ovviamente potrebbero essere negativi.Ciò che potrebbe funzionare è passare attraverso i long: 'long color = bitmap.getPixel (x, y) & 0xFFFFFFFFL' – cubrr

Problemi correlati