iddan / react-native-canvas

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

PutImageData draws only part of the image #158

Open felixkhulis opened 4 years ago

felixkhulis commented 4 years ago

hi, when i use getImageData manipulate pixels and then putImageData the result that is that a smaller version of the image is drawn even though i want to the entire canvas.

you can reproduce this in your example file where the purple rectangle is not covered completely by a black one. example code:

handleImageData(canvas) { canvas.width = 100; canvas.height = 100;

const context = canvas.getContext('2d');
context.fillStyle = 'purple';
context.fillRect(0, 0, 100, 100);

context.getImageData(0, 0, 100, 100).then(imageData => {
  const data = Object.values(imageData.data);
  const length = Object.keys(data).length;
  for (let i = 0; i < length; i += 4) {
    data[i] = 0;
    data[i + 1] = 0;
    data[i + 2] = 0;
  }
  const imgData = new ImageData(canvas, data, 100, 100);
  context.putImageData(imgData, 0, 0);
});

}

to my understanding this should cover the original purple rectangle with a black one since you change all the pixels to black. Note: that this code works as expected on web. actual result expected result

felixkhulis commented 4 years ago

first image is actual result which doesn't cover the entire purple rectangle second image is the correct behaviour and expected result of the above code

jorgem0 commented 4 years ago

I am having the same issue as well. Was this ever resolved? image

jorgem0 commented 4 years ago

After looking at this closer, it seems that getImageData is only getting 1/9th of the data (the top left corner). This issue was resolved by multiplying the canvas.width and canvas.height by 3.

context.getImageData(0, 0, 3*canvas.width, 3*canvas.height).then(async imageData => {...

const imgData = await new ImageData(canvas, data, Math.ceil(3*canvas.width), Math.ceil(3*canvas.height));

image

iddan commented 4 years ago

I'm guessing the bug has to do with the code for fixing the resolution of the canvas to match the resolution factor of the device. PRs are welcome

FarazzShaikh commented 4 years ago

+1

jorgem0 commented 4 years ago

However, when I try it on the Android simulator, it does not capture the full image. The fix above was on iPhone 11 Pro Max (it also works on the iPad simulator) but when I switch over to Pixel 3 XL, I get the image below. However, it works fine on Pixel 3. Any ideas on how to make it work for all devices? Would I need to know the resolution of the canvas to the resolution factor of the device?

image

jorgem0 commented 4 years ago

Edit-Edit: Okay, seemed to have figured it out. Just used PixelRatio.get() instead. It just so happens that for iPhones the PixelRatio is 3 which is why the original comment of x3 was working. https://reactnative.dev/docs/pixelratio

context.getImageData(0, 0, Math.ceil(PixelRatio.get() * canvas.width), Math.ceil(PixelRatio.get() * canvas.height)).then(async imageData => {...

const imgData = await new ImageData(canvas, data, Math.ceil(PixelRatio.get() * canvas.width), Math.ceil(PixelRatio.get() * canvas.height))

image