tui.image-editor icon indicating copy to clipboard operation
tui.image-editor copied to clipboard

Can't consistently see images loaded via `loadImageFromURL`

Open humblecoder opened this issue 5 years ago • 46 comments

Version

3.2.0

Development Environment

MacOS 10.12.6 Chrome Version 69.0.3497.100 (Official Build) (64-bit)

Current Behavior Using loadImageFromURL doesn't consistently display image. Occasionally there is a CORS error, despite the resource being fully configured for CORS. And sometimes it will load fine. It's fairly random. I am using the same test images for all tests. I can, with 100% certainty load the same images to <img> tags as well as to a raw fabric.js instance.

Are there any updated (perhaps undocumented) steps to take after loading an image via loadImageFromURL? Is a canvas refresh/resize required? Must I perform some step in the Promise after the fact? I'm hoping I'm simply missing something, but this is a fairly frustrating occurrence.

UPDATE: So, apparently, (in Chrome) when the dev tools are open it works. When the dev tools are closed, it fails. Video of issue in action.

When the tools are closed I receive Access-Control-Allow-Origin error. This, despite the fact that the resources are publicly accessible and currently configured to allow all '*'. You can see in the video the same resources being "previewed" in the grid via <img> tags. However, when attempting to open a modal and simply call loadImageFromURL it fails. I've tried nextTick and a host of other "hacks", but nothing seems to matter other than dev tools being opened or closed.

FYI, I'm console.loging nearly everything. Occasionally I receive an executing command state is locked error from the editor instance as well. No idea what that means.

humblecoder avatar Oct 05 '18 18:10 humblecoder

I am also having this issue as well! Particularly when loading the image editor from a browser on iPad.

emyl3 avatar Oct 18 '18 20:10 emyl3

Version

3.2.0

Development Environment

MacOS 10.12.6 Chrome Version 69.0.3497.100 (Official Build) (64-bit)

Current Behavior Using loadImageFromURL doesn't consistently display image. Occasionally there is a CORS error, despite the resource being fully configured for CORS. And sometimes it will load fine. It's fairly random. I am using the same test images for all tests. I can, with 100% certainty load the same images to <img> tags as well as to a raw fabric.js instance.

Are there any updated (perhaps undocumented) steps to take after loading an image via loadImageFromURL? Is a canvas refresh/resize required? Must I perform some step in the Promise after the fact? I'm hoping I'm simply missing something, but this is a fairly frustrating occurrence.

UPDATE: So, apparently, (in Chrome) when the dev tools are open it works. When the dev tools are closed, it fails. Video of issue in action.

When the tools are closed I receive Access-Control-Allow-Origin error. This, despite the fact that the resources are publicly accessible and currently configured to allow all '*'. You can see in the video the same resources being "previewed" in the grid via <img> tags. However, when attempting to open a modal and simply call loadImageFromURL it fails. I've tried nextTick and a host of other "hacks", but nothing seems to matter other than dev tools being opened or closed.

FYI, I'm console.loging nearly everything. Occasionally I receive an executing command state is locked error from the editor instance as well. No idea what that means.

Have You already solved that problem? If yes - how?

VitaliyOnRule avatar Nov 15 '18 16:11 VitaliyOnRule

@VitaliyOnRule I have not solved the problem. Although it does for some random reason seem to occur far less often.

humblecoder avatar Nov 16 '18 06:11 humblecoder

@humblecoder and @VitaliyOnRule I had the same issue of the images not loading consistently. I think it may have been some caching issue for me. It was an amazon s3 url.

When I loaded the image I added the following cache busting query param to the image url string + '?t=' + new Date().getTime().

This answer was from here: https://stackoverflow.com/questions/1077041/refresh-image-with-a-new-one-at-the-same-url/22429796#22429796

emyl3 avatar Dec 05 '18 22:12 emyl3

@emyl3 and @VitaliyOnRule I actually ended up using my server as a "proxy" and loading the image from base64 😞. Appreciate the input though.

humblecoder avatar Dec 05 '18 22:12 humblecoder

@humblecoder and @VitaliyOnRule I had the same issue of the images not loading consistently. I think it may have been some caching issue for me. It was an amazon s3 url.

When I loaded the image I added the following cache busting query param to the image url string + '?t=' + new Date().getTime().

This answer was from here: https://stackoverflow.com/questions/1077041/refresh-image-with-a-new-one-at-the-same-url/22429796#22429796

It is not a simple issue. But the only one way to solve it for 100% -is to write a proxy server or throw image via route of your server. Because some of remote s3 buckets and cloudflare/cloudfront mediators have origin white lists on their configurations and it is blocking access to the image from the javascript anyway. So to make it working for 100% - just get images via your backend

VitaliyOnRule avatar Dec 06 '18 08:12 VitaliyOnRule

Using v3.2.2, the editor never loads images located in Amazon S3. I have the CORS Configuration setup with: <ExposeHeader>Access-Control-Allow-Origin</ExposeHeader>

I always receive error: Access to image at 'https://xxx.s3.amazonaws.com/assets/custom/000364/images/web/flowers-2.jpg' from origin 'https://www.yyy.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

Here's an interesting thread I found about it: https://stackoverflow.com/questions/54155431/toastui-image-editor-loadimagefromurl-doesnt-work

bpautsch avatar Oct 01 '19 16:10 bpautsch

@jinwoo-kim-nhn any fixes for the problem ?

Aarbel avatar Oct 23 '20 14:10 Aarbel

Any updates? I'm experiencing the same issue with an AWS S3 image that's publicly available. Example: https://3stepsolutions.s3.amazonaws.com/assets/custom/000364/images/web/jet-ski.jpg

TUI-JS-Error

bpautsch avatar Feb 10 '21 21:02 bpautsch

May be this problem solved for AWS S3 bucket. you can try this. Link : https://zyst.io/how-to-fix-aws-s3-chrome-and-safari-cors-on-images

cseriyad avatar Mar 25 '21 04:03 cseriyad

I have all public CORS settings in S3 and randomly getting this error, any updates? What I noticed in failed requests, there is no HTTP Request Method like GET/HEAD when it fails, no idea if Chrome DevTools doesn't show it, or it is possible to send request without method, probably not ... AWS s3 requires to have a method specified (I have GET/HEAD), maybe here is a problem?

maccup avatar Apr 02 '21 13:04 maccup

I have all public CORS settings in S3 and randomly getting this error, any updates? What I noticed in failed requests, there is no HTTP Request Method like GET/HEAD when it fails, no idea if Chrome DevTools doesn't show it, or it is possible to send request without method, probably not ... AWS s3 requires to have a method specified (I have GET/HEAD), maybe here is a problem?

Same here. There is nothing blocking the download of these images. I'm using this tool in the Froala editor and they have no problem downloading and displaying images. Not working with AWS S3 is a big problem. We're hiding this tool for now.

bpautsch avatar Apr 02 '21 13:04 bpautsch

Only getting this issue with Toast. Renders the entire editor unusuable. Will seek out another tool.

Fawesum avatar Apr 20 '21 14:04 Fawesum

Agree, I temporarily disabled the editor tool since we don't know how to solve this right now. Any ideas?

maccup avatar Apr 20 '21 19:04 maccup

I was having the same issue with Amazon S3 urls, which after setting up the bucket CORS, it was still not working.

Looks like a cache issue, so I just fixed it by adding a random parameter at the end of the url:

s3_url+'&t='+Math.random()

It seems to work well now.

pythobot avatar Jun 04 '21 21:06 pythobot

@arnaldoanez I'm sorry for the late reply. Thank you for suggesting a good way.

lja1018 avatar Jun 16 '21 02:06 lja1018

Hello,

Any updates on this?

I use pre-signed urls, so setting a random query like suggested above won't work; since aws check the url to validate it's signature.

What other options do we have? (besides switching to a different image editor)

omar-dulaimi avatar Jul 13 '21 08:07 omar-dulaimi

It only works if you disable cache in chrome dev tools. Users don't open devtools, so that can't be a solution.

omar-dulaimi avatar Jul 13 '21 08:07 omar-dulaimi

On Firefox it works okay. Chrome however, it does not.

omar-dulaimi avatar Jul 13 '21 09:07 omar-dulaimi

@omar-dulaimi if you can you can create proxy route on your back-end which will return the image by the required route for example "https://my-app.com/image-proxy?url=https://aws-image" Or it also can be not aws issue but cloudflare. Cloudflare also as mediator could have access control origin blockers

VitaliyOnRule avatar Jul 13 '21 09:07 VitaliyOnRule

@VitaliyOnRule I'm not sure I understand what would the proxy do in this scenario, is it going to behave like a cdn?

I currently get the pre-signed urls through the backend, just load them on the frontend in the editor.

Also, I don't use cloudflare. But we do have nginx config on our elastic beanstalk.

omar-dulaimi avatar Jul 13 '21 10:07 omar-dulaimi

@omar-dulaimi with proxy you will request image from your server firstly - and will get the image hosted on aws. And you will exclude access-control-allow-origin error and will get the image for 100% because image will be requested not from the browser. And then your server will respond on browser request with fetched image.

  1. request from chrome to you back-end - https://my-app.com/image-proxy?url=https://aws-image"
  2. request from backend to aws - https://aws-image
  3. getting image from aws and responding to chrome request with fetched image

VitaliyOnRule avatar Jul 13 '21 10:07 VitaliyOnRule

after digging into this and playing a bit with the source code. I found that this line here is causing the CROS issue. Providing a way to override it would solve the issue. I am working on an external patch fix if it all went well I will post it here. This is a temp fix thought I think definitely a way to override the image option is the optimal solution

UPDATE patch file

diff --git a/node_modules/tui-image-editor/.DS_Store b/node_modules/tui-image-editor/.DS_Store
new file mode 100644
index 0000000..3e391de
Binary files /dev/null and b/node_modules/tui-image-editor/.DS_Store differ
diff --git a/node_modules/tui-image-editor/dist/tui-image-editor.js b/node_modules/tui-image-editor/dist/tui-image-editor.js
index 5b1f7e5..e7587ba 100644
--- a/node_modules/tui-image-editor/dist/tui-image-editor.js
+++ b/node_modules/tui-image-editor/dist/tui-image-editor.js
@@ -7231,7 +7231,7 @@ function _inherits(subClass, superClass) { if (typeof superClass !== "function"
 
 var imageOption = {
   padding: 0,
-  crossOrigin: 'Anonymous'
+  // crossOrigin: 'Anonymous'
 };
 
 /**

Ilaiwi avatar Sep 28 '21 11:09 Ilaiwi

After debugging with Burp Suite, I think I identified the problem and found a solution. No patch should be needed.

What's the quick solution ? Add the attribute crossorigin="anonymous" in the <img> tag that displays the image before opening it in the editor. ie: <img src="targetUri" crossorigin="anonymous" />

Explain the issue and solution The main issue is related to caching and how the browser sends the Origin header.

First you have to know that by default the browser does not send the Origin header when you load an image with the <img> tag that does not have the crossorigin="anonymous" attribute. More info

What's happening is that the browser tries to load the image from the <img> tag before the image editor is opened, and the puts it into its cache.

So when you open the editor, it tries to load the image a second time, and you actually get a cached response of the first request that was made without the Origin header. Without this header, that cached response does not contain all the allow-control-* headers necessary to pass the CORS check, that's why you get the error.

You can check this, by opening Chrome's inspector with "disable cache" checked. It should work. The previous posts that suggested to include a parameter ?t=<random_number> had the effect to bypass the browser cache, but this solution is not possible when using pre-signed urls.

So adding crossorigin="anonymous" in the img tag should solve the problem.

KrYpTeD974 avatar Sep 29 '21 11:09 KrYpTeD974

@KrYpTeD974 's solution doesn't work for me :(

DanielePalombo avatar Oct 25 '21 22:10 DanielePalombo

@DanielePalombo Could you elaborate more ? I'm pretty sure this issue can be solved with the crossorigin="anonymous" tag. But maybe there are some subtleties to adapt in your code.

KrYpTeD974 avatar Oct 26 '21 10:10 KrYpTeD974

It doesn't work because my server makes a redirect to the source image on s3. I had to set the s3 cors configuration with my domain.

DanielePalombo avatar Oct 27 '21 05:10 DanielePalombo

@KrYpTeD974 Could you provide an example ? In React project, my code is const ref = React.useRef(null); const instance = new ImageEditor(ref.current, {}) //... return (<div ref={ref}/> I don't know how to add the attribute crossorigin="anonymous" in the tag. thx

GuanJdoJ avatar Dec 24 '21 03:12 GuanJdoJ

Hi. Any update on this?

sergeyukhanov avatar Apr 14 '22 10:04 sergeyukhanov

@sergeyukhanov It has not been fixed yet. I'm sorry.

lja1018 avatar Apr 20 '22 01:04 lja1018

For those using Froala and who have access to the source code for the plugin (I can't remember if the plugin source code is open or not still) just add this line somewhere in the launch function after current_image_src is obtained:

if(current_image_src.indexOf('base64') === -1) {
  current_image_src = current_image_src + (current_image_src.indexOf('?') === -1 ? '?' : '&') + `timestamp=${new Date().getTime()}`
}

Won't work for signed URL's as people have mentioned, but works otherwise.

brendon avatar May 05 '22 10:05 brendon

We had the same issue with signed S3 URL. We found a workaround and preloaded the url in an Image object in the compenent implementing the editor.

const tempImage = new Image()
tempImage.crossOrigin = "Anonymous"
tempImage.src = JSON.parse(this.value).backgroundImage.src

elcatania avatar May 13 '22 08:05 elcatania

@elcatania, did you find it worked well with Chrome?

brendon avatar May 15 '22 21:05 brendon

@brendon Yes it does

elcatania avatar May 18 '22 06:05 elcatania

Thanks @elcatania, Is it the case that you've not previously had an image in the page with that same src? Otherwise I would have expected Chrome to have cached the response that didn't contain the CORS information.

brendon avatar May 18 '22 08:05 brendon

@brendon The issue was exactly as described previously. The image was being loaded and the cached request threw an CORS error. But the manually reloading of the image somehow fixed the issue. We still dont really know how and why it works.

elcatania avatar May 18 '22 08:05 elcatania

Yea that's pretty strange :) Glad it works though :D

brendon avatar May 18 '22 09:05 brendon