简体   繁体   English

ToastUI 图像编辑器 loadImageFromURL 不起作用

[英]ToastUI Image Editor loadImageFromURL doesn't work

Please note this is a self-answered question.请注意这是一个自我回答的问题。

This question is about the ToastUI Image Editor v3.3.0, but it may also apply to newer versions.这个问题是关于 ToastUI 图像编辑器 v3.3.0,但它也可能适用于较新的版本。

When you load an image using this official example :当您使用此官方示例加载图像时:

// Create image editor
var imageEditor = new tui.component.ImageEditor('#my-image-editor canvas', {
    cssMaxWidth: 1000, // Component default value: 1000
    cssMaxHeight: 800  // Component default value: 800
});

// Load image
imageEditor.loadImageFromURL('img/sampleImage.jpg', 'My sample image')

The editor will not load the image.编辑器不会加载图像。 The function neither throws, nor returns anything indicating a failure and you don't get any error messages. function 既不抛出也不返回任何指示失败的信息,您也不会收到任何错误消息。 It returns a promise that resolves as specified in the documentation.它返回一个 promise,按照文档中指定的方式解析。

It only loads an image by specifying it in the initial config and you can't change it afterwards:它仅通过在初始配置中指定图像来加载图像,之后您无法更改它:

// Create image editor
var imageEditor = new tui.component.ImageEditor('#my-image-editor canvas', {
     includeUI: {
         loadImage: {
             path: 'img/sampleImage.jpg',
             name: 'My sample image'
         },
     },
    cssMaxWidth: 1000, // Component default value: 1000
    cssMaxHeight: 800  // Component default value: 800
});

It appears that the loadImageFromURL function is broken and according to other users loadImageFromFile has the same problem. loadImageFromURL function 似乎已损坏,根据其他用户的说法, loadImageFromFile也有同样的问题。

Issues about this have been raised on GitHub, but have basically been ignored. GitHub上有提过这方面的问题,但基本上都被忽略了。 It's been a month now and unfortunately it still hasn't been fixed.现在已经一个月了,不幸的是它仍然没有修复。

So the question is how can the image editor be tricked into working while this issue exists.所以问题是当这个问题存在时,图像编辑器如何被欺骗工作。

Here is a fiddle showing that it doesn't work: https://fiddle.sencha.com/#view/editor&fiddle/2org这是一个表明它不起作用的小提琴: https://fiddle.sencha.com/#view/editor&fiddle/2org

TL;DR:特尔;博士:
Here is a working fiddle: https://fiddle.sencha.com/#view/editor&fiddle/2p0o这是一个工作小提琴: https : //fiddle.sencha.com/#view/editor&fiddle/2p0o


Long version:长版:

There are four problems:有四个问题:

  • You need to load an initial image, otherwise you can't use the editing controls.您需要加载初始图像,否则无法使用编辑控件。
  • You need to wait until the image editor object is ready before calling loadImageFromURL , otherwise you may get an error or a silent failure在调用loadImageFromURL之前需要等待图像编辑器对象准备好,否则可能会出现错误或静默失败
  • When the image is loaded you need to tell the image editor the new size, otherwise the image will be hidden or sized incorrectly.加载图像时,您需要告诉图像编辑器新的大小,否则图像将被隐藏或大小不正确。
  • If you load an external image, the external server has to set the Access-Control-Allow-Origin header and explicitly allow your domain to access it, otherwise the image editor can not access it.如果加载外部图像,外部服务器必须设置Access-Control-Allow-Origin标头并明确允许您的域访问它,否则图像编辑器无法访问它。

This first problem can be solved by loading a blank image like this:第一个问题可以通过像这样加载一个空白图像来解决:

var imageEditor = new tui.ImageEditor('#tui-image-editor-container', {
    includeUI: {
        loadImage: {
            path: 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7',
            name: 'Blank'
        },
        theme: whiteTheme,
        menuBarPosition: 'bottom'
    },
    cssMaxWidth: 700,
    cssMaxHeight: 700
});

The second problem can be solved by waiting for the image editor to get out of its lock state using undocumented functionality.第二个问题可以通过使用未记录的功能等待图像编辑器摆脱其锁定状态来解决。 You can patch your loadImageFromURL during runtime like this:您可以在运行时修补您的loadImageFromURL ,如下所示:

imageEditor.loadImageFromURL = (function() {
    var cached_function = imageEditor.loadImageFromURL;
    function waitUntilImageEditorIsUnlocked(imageEditor) {
        return new Promise((resolve,reject)=>{
            const interval = setInterval(()=>{
                if (!imageEditor._invoker._isLocked) {
                    clearInterval(interval);
                    resolve();
                }
            }, 100);
        })
    }
    return function() {
        return waitUntilImageEditorIsUnlocked(imageEditor).then(()=>cached_function.apply(this, arguments));
    };
})();

The third problem can be resolved by taking the object that the promise returned by loadImageFromURL resolves with and passing the new and old width/height properties to the ui.resizeEditor function like this:第三个问题可以通过使用loadImageFromURL返回的loadImageFromURL解析的对象并将新的和旧的宽度/高度属性传递给ui.resizeEditor函数来解决,如下所示:

imageEditor.loadImageFromURL("https://upload.wikimedia.org/wikipedia/en/thumb/8/80/Wikipedia-logo-v2.svg/526px-Wikipedia-logo-v2.svg.png", "SampleImage").then(result=>{
    imageEditor.ui.resizeEditor({
        imageSize: {oldWidth: result.oldWidth, oldHeight: result.oldHeight, newWidth: result.newWidth, newHeight: result.newHeight},
    });
}).catch(err=>{
    console.error("Something went wrong:", err);
})

The fourth problem can be a bit confusing.第四个问题可能有点令人困惑。 Let me explain.让我解释。 On websites you can include pretty much any external image you want in using an <img> tag, but if you want to access an external image using JavaScript, the server providing the image has to explicitly allow you to do that using the access-control-allow-origin header.在网站上,您可以使用<img>标签包含几乎任何您想要的外部图像,但是如果您想使用 JavaScript 访问外部图像,则提供图像的服务器必须明确允许您使用access-control-allow-origin来执行此access-control-allow-origin标头。 On Amazon S3 for instance, the servers don't allow this by default.例如,在 Amazon S3 上,服务器默认不允许这样做。 You have to manually set the server to allow your or any domain to access it.您必须手动设置服务器以允许您或任何域访问它。 See here .这里 If you are using a different server, you could for example set the access-control-allow-origin to * like wikipedia has done on this image .如果您使用不同的服务器,您可以例如将access-control-allow-origin*就像 wikipedia 在此图像上所做的那样。 Then you (and the image editor) could access that image from the JavaScript of any domain.然后您(和图像编辑器)可以从任何域的 JavaScript 访问该图像。

For those who are using Rails, when it came to the fourth problem stated by @Forivin, this is what I did to get it working.对于那些使用 Rails 的人来说,当谈到@Forivin 所说的第四个问题时,我就是这样做的。

The issue is when Toast would call the image stored on S3 I would get a CORS error on Chrome, but firefox was fine.问题是当 Toast 调用存储在 S3 上的图像时,我会在 Chrome 上收到 CORS 错误,但 firefox 很好。 There are lots of articles on this, essentially I found the best way is to use a proxy in my code.有很多关于这方面的文章,基本上我发现最好的方法是在我的代码中使用代理。 I can still have my CORS origin pointing to my host, and since the call is coming from my host via proxy, S3 and Chrome are happy.我仍然可以让我的 CORS 源指向我的主机,并且由于呼叫是通过代理来自我的主机,S3 和 Chrome 很高兴。 My S3 CORS config looks like this (allows subdomains):我的 S3 CORS 配置如下所示(允许子域):

<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
    <AllowedOrigin>http://*.mycompany.com</AllowedOrigin>
    <AllowedMethod>POST</AllowedMethod>
    <AllowedMethod>GET</AllowedMethod>
    <AllowedMethod>PUT</AllowedMethod>
    <AllowedMethod>DELETE</AllowedMethod>
    <AllowedMethod>HEAD</AllowedMethod>
    <AllowedHeader>*</AllowedHeader>
</CORSRule>
</CORSConfiguration>

In your rails project do this:在您的 rails 项目中执行以下操作:

Add rack-proxy gem in your GemfileGemfile添加机架代理 gem

gem 'rack-proxy'

Create a proxy file.创建代理文件。 The s3 path is URI encoded and appended to end of route. s3 路径是 URI 编码的并附加到路由的末尾。 The route is just used for proxy so it can be anything, as it will be rerouted to s3.该路由仅用于代理,因此它可以是任何东西,因为它将被重新路由到 s3。

app/proxy/s3_proxy.rb

class S3Proxy < Rack::Proxy

  def perform_request(env)
    if env['REQUEST_PATH'] =~ %r{^/my/dummy/path}
      s3_path = CGI.unescape(env['REQUEST_PATH'][15..-1])

      uri = URI.parse(s3_path)
      env['HTTP_HOST'] = uri.host
      env['SERVER_PORT'] = uri.port
      env['REQUEST_PATH'] = s3_path
      env['REQUEST_URI'] = s3_path
      env['PATH_INFO'] = s3_path
      env['rack.url_scheme'] = 'https'

      super(env)
    else
      @app.call(env)
    end
  end

end

Add to application.rb file:添加到application.rb文件:

require "./app/proxy/s3_proxy"

class Application < Rails::Application
  ...

  config.middleware.use S3Proxy
end

routes.rb

get "/my/dummy/path/:s3_url", to: "my_controller#dummy_path"

Controller method in my_controller.rb . my_controller.rb控制器方法。 Doesnt matter what gets rendered here as it will be redirected by proxy.在这里呈现的内容无关紧要,因为它将被代理重定向。 We could probably get away with no method since proxy will change anyway.我们可能没有任何方法可以逃脱,因为无论如何代理都会改变。

  def dummy_path
    render plain: ""
  end

And finally in my Vue code, I call Toast editor by first populating with a blank white image.最后在我的 Vue 代码中,我首先填充一个空白的白色图像来调用 Toast 编辑器。 Then when the component is mounted, I load the s3 image and overwrite the existing image and resize the canvas.然后在安装组件时,我加载 s3 图像并覆盖现有图像并调整画布大小。 I found I needed a slight delay when it is mounted before reading s3 image.我发现在读取 s3 图像之前安装它时需要稍微延迟。 The s3 image is a presigned url that I pass in props. s3 图像是我在 props 中传递的预先签名的 url。

<template lang="pug">
.v-image-editor-tool
  tui-image-editor(:include-ui='useDefaultUI' :options="editorOptions" ref="tuiImageEditor")
</template>

<script lang="coffee">
import { ImageEditor } from '@toast-ui/vue-image-editor'
import 'tui-image-editor/dist/tui-image-editor.min.css'

export default app =
  props: ['imageUrl']
  data: ->
    useDefaultUI: true
    editorOptions:
      cssMaxWidth: 700
      cssMaxHeight: 700
      usageStatistics: false
      includeUI:
        loadImage:
          path: 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7'
          name: 'Blank'
        menuBarPosition: 'bottom'

  mounted: ->
    fn = => this.$refs.tuiImageEditor.invoke('loadImageFromURL', @imageUrl, 'Image').then (result) =>
      this.$refs.tuiImageEditor.invoke('ui.resizeEditor', { imageSize: { newWidth: result.newWidth, newHeight: result.newHeight }})
    setTimeout(fn, 600)

  components:
    'tui-image-editor': ImageEditor
</script>

Add this attribute to the image tag you want to edit before opening it:在打开之前将此属性添加到要编辑的图像标签中:

crossorigin="anonymous"

As explained here: https://github.com/nhn/tui.image-editor/issues/68#issuecomment-930106372如此处所述: https://github.com/nhn/tui.image-editor/issues/68#issuecomment-930106372

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM