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.
Hai mai trovato una soluzione a questo? – James
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. –