Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to get image drawn in canvas (The operation is insecure) #143

Open
wojtekhorembala opened this issue Aug 7, 2019 · 23 comments
Open

Comments

@wojtekhorembala
Copy link

Hi i want little bit optimization my images and i use for this canvas,

Currently i have this code

const context = canvas.getContext('2d', { alpha: false });
 const image = new CanvasImage(canvas)

image.src = 'https://res.cloudinary.com/pozna/image/upload/v1564828195/fpztmajxhmphfpaechfa.jpg';
canvas.width = width;
canvas.height = 600;

image.addEventListener('load', () => {
context.drawImage(image, 0, 0, 500, 500).then(() => {
// here i want get image url or other data
 });
});

Can anyone help me? :)

@wojtekhorembala
Copy link
Author

When i make this gets error from screen

image.addEventListener('load', async () => {
context.drawImage(image, 0, 0, 500, 500);
const imageData = await canvas.toDataURL();
});

image

@wojtekhorembala wojtekhorembala changed the title How to get image drawn in canvas How to get image drawn in canvas (The operation is insecure) Aug 7, 2019
@aravikanti
Copy link

I am facing the same issue when I am upgrading react native to 0.59.8. and using react-native-webview 6.1.0

@PierreCapo
Copy link

Same issue here on react-native 0.59.10 and react-native-webview 5.8.2

@iddan
Copy link
Owner

iddan commented Sep 13, 2019

This is a general HTML Canvas issue. Check this discussion: https://stackoverflow.com/questions/25753754/canvas-todataurl-security-error-the-operation-is-insecure.
Closing as it is not relevant only for this project.

@iddan iddan closed this as completed Sep 13, 2019
@seblambla
Copy link

@PierreCapo Did you find a solution for this?

@PierreCapo
Copy link

Not at all, we reprioritized our business requirements 😬

@seblambla
Copy link

OK thanks anyway.
(I didn't notice you are working for BAM, we've been working with them a few years ago 👍)

However I think this issue should be re-opened as I'm facing this error with a local file.

@iddan iddan reopened this Oct 19, 2019
@asasugar
Copy link

How to fixed ?

@MoeMamdouh
Copy link

Any updates?

@eashish93
Copy link

eashish93 commented Jan 16, 2020

I found the solution. Add this.crossOrigin = 'anonymous' here: https://github.com/iddan/react-native-canvas/blob/master/src/Image.js#L23 and make sure the server from you're requesting images will have CORS enabled.
Unfortunately setting crossOrigin on initialized Image constructor doesn't work, so you need to modify the library.

@plus-
Copy link

plus- commented Feb 3, 2020

Can confirm solution above works fine.

@dudyn5ky1
Copy link

If anyone wants a working module with a fix for a current issue - feel free to use react-native-canvas-anonymous.

It it is a fork with just one change (this.crossOrigin = 'anonymous') from the suggestion above.

https://www.npmjs.com/package/react-native-canvas-anonymous

@iddan
Copy link
Owner

iddan commented Apr 5, 2020

PRs are welcome to fix it here as well.

@dudyn5ky1
Copy link

@iddan To be honest, I've discovered another problem with this.crossOrigin = 'anonymous'. It prevents image from being loaded, I'm not sure yet why.

@iddan
Copy link
Owner

iddan commented Apr 8, 2020

I guess because it is insecure to load images from an anonymous origin

@plus-
Copy link

plus- commented Apr 8, 2020

I've noticed it depends on the origin, it works on my S3 urls but not cloudfront for example.

@iddan
Copy link
Owner

iddan commented Apr 8, 2020

Maybe it has to do with CORS headers

@W-alex
Copy link

W-alex commented Apr 22, 2020

I still have another problem, when I use canvas.fillRect and change it to base64 with toDataURL, the question arises anyway

@t3chcrazy
Copy link

t3chcrazy commented Jan 15, 2021

Anyone found a concrete solution for this? Images from links like wikimedia are working with img.crossOrigin = "anonymous" but for firebase images which I have to work with, the images don't load at all

@jsun969
Copy link

jsun969 commented Oct 5, 2021

img.crossOrigin = "anonymous" may cause the image not to be displayed, so my solution is to convert the image to base64 first before adding it.

This does solve the problem but may reduce performance.

@telpat0298
Copy link

telpat0298 commented Jun 8, 2022

@eashish93 is this still working for you? I added this line to the library but i am getting the error
TypeError: undefined is not a function (near '...this.postMessage...')
and i can't find or figure out an other way to solve this problem.

@Harukisatoh
Copy link

For me, the issue was happening with a local file, which doesn't make sense as in my opinion, this security feature should only apply to cross-origin content. But I managed to find a workaround.

Before the workaround, I was trying to load the image directly passing the image URI to the image.src prop. The code was like that:

...
const { imageUri } = route.params // This is the image I'm loading. It's a local image, and it's in this format 'file://...'

function handleCanvas(canvas: Canvas | null) {
  if (!canvas) {
    return
  }

  canvas.width = Dimensions.get('screen').width
  canvas.height = Dimensions.get('screen').height

  const image = new CanvasImage(canvas)
  const context = canvas.getContext('2d')

  image.src = imageUri

  image.addEventListener('load', async () => {
    context.drawImage(image, 0, 0, canvas.width, canvas.height)
    const pixel = await context.getImageData(0, 0, 1, 1) // This line would throw the error
  })
}
...

To make it work I used expo-file-system to read the image and transform it to a base64 string, and then passed the base64 string to the image.src prop, like that:

...
const { imageUri } = route.params

async function handleCanvas(canvas: Canvas | null) {
  if (!canvas) {
    return
  }

  canvas.width = Dimensions.get('screen').width
  canvas.height = Dimensions.get('screen').height

  const image = new CanvasImage(canvas)
  const context = canvas.getContext('2d')

  const base64Image = await FileSystem.readAsStringAsync(imageUri, {
    encoding: FileSystem.EncodingType.Base64,
  })
  image.src = `data:image/png;base64,${base64Image}`

  image.addEventListener('load', async () => {
    context.drawImage(image, 0, 0, canvas.width, canvas.height)
    const pixel = await context.getImageData(0, 0, 1, 1) // No more errors here
  })
}
...

Of course, it has the performance downside, but it suits my needs. Also, my problem was with local images, but I think this solution could work for remote images as well (I'm not sure, I haven't tested). I think that a possible approach would be to download the remote image, and then make the same process as I did.

Hope this helps someone!

@esbenvb
Copy link

esbenvb commented Jul 31, 2023

I didn't have any luck with the crossOrigin setting, so I ended up using RNFS.downloadFile and then RNFS.readFile and made a base64 PNG data URL of the data.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests