iddan / react-native-canvas

A Canvas component for React Native
MIT License
981 stars 172 forks source link

ImageData/getImageData/putImageData strange behaviour #309

Closed wil2106 closed 1 year ago

wil2106 commented 1 year ago

Hi,

This code should set all pixels of the picture black but only a small rectangle is set, what am I doing wrong ?

            context.drawImage(canvasImage, 0, 0);
            const imgData = await context.getImageData(
              0,
              0,
              canvasImage.width,
              canvasImage.height
            );

            const length = Object.keys(imgData.data).length;
            let data = Object.values(imgData.data);
            for (let i=0; i < length;i+=4){
              data[i] = 0;
              data[i+1] = 0;
              data[i+2] = 0;
              data[i+3] = 255;
            }

            const newImgData = new ImageData(canvasRef.current, data, canvasImage.height, canvasImage.width);
            context.putImageData(newImgData, 0, 0);

The result: image

bartproo commented 1 year ago

may I know how did u solve this?

tylerrrkd commented 1 year ago

may I know how did u solve this?

bdtren commented 2 months ago

There are 2 issues causing that and they both from await context.getImageData():

  1. It can only get max to rectangle of size canvasImage.width / 3 * canvasImage.height / 3
  2. And if the 4 canvasImage.width / 3 canvasImage.height / 3 > 196608 it will only return Uint8ClampedArray of 196608 items (maybe this issue is because of webview's postMessage limitation?)

Your issue might be because of the (2). So I think you can do a workaround by replacing:

const length = Object.keys(imgData.data).length;
let data = Object.values(imgData.data);
//...
const newImgData = new ImageData(canvasRef.current, data, canvasImage.height, canvasImage.width);

With:

const width = Math.floor(canvasImage.width - 1) * 3;
const height = Math.floor(canvasImage.height - 1) * 3
const length = 4 * width * height;
let data = Array.from({length}).map(_ => 0);
//...
const newImgData = new ImageData(canvasRef.current, data, width, height);