ToastUI图片编辑器loadImageFromURL不起作用

时间:2019-01-11 23:38:31

标签: javascript toast-ui-image-editor

请注意,这是一个自我回答的问题。

此问题与ToastUI图像编辑器v3.3.0有关,但也可能适用于较新的版本。

使用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')

编辑器将不会加载图像。该函数既不抛出也不返回任何指示失败的信息,并且您不会收到任何错误消息。它返回一个承诺,该承诺将按照文档中的说明进行解决。

它只能通过在初始配置中指定图像来加载图像,之后便无法更改:

// 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
});

看来loadImageFromURL功能已损坏,根据其他用户,loadImageFromFile也有同样的问题。

有关此问题的问题已在GitHub上提出,但基本上已被忽略。到现在已经一个月了,不幸的是它还没有修复。

所以问题是在存在此问题的情况下如何欺骗图像编辑器工作。

这里有个小提琴表明它不起作用:https://fiddle.sencha.com/#view/editor&fiddle/2org

2 个答案:

答案 0 :(得分:4)

TL; DR:
这是一个有效的小提琴:https://fiddle.sencha.com/#view/editor&fiddle/2p0o


长版:

有四个问题:

  • 您需要加载初始图像,否则无法使用编辑控件。
  • 您需要等到图像编辑器对象准备就绪后才能调用loadImageFromURL,否则可能会出现错误或无提示的故障
  • 加载图像后,您需要告知图像编辑器新的尺寸,否则图像将被隐藏或错误地设置尺寸。
  • 如果加载外部图像,则外部服务器必须设置Access-Control-Allow-Origin标头并明确允许您的域访问它,否则图像编辑器将无法访问它。

第一个问题可以通过加载如下空白图像来解决:

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
});

第二个问题可以通过使用未记录的功能等待图像编辑器退出其锁定状态来解决。您可以在运行时像这样修补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));
    };
})();

第三个问题可以解决,方法是将loadImageFromURL返回的promise解析为一个对象,并将新的和旧的width / height属性传递给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);
})

第四个问题可能会造成混淆。让我解释。在网站上,您可以使用<img>标签包含几乎所有想要的外部图像,但是如果您要使用JavaScript访问外部图像,提供该图像的服务器必须明确允许您使用{ {1}}标头。 例如,在Amazon S3上,服务器默认情况下不允许这样做。您必须手动设置服务器以允许您或任何域访问它。参见here。 如果您使用的是其他服务器,则可以像Wikipedia在this image上所做的那样,将access-control-allow-origin设置为access-control-allow-origin。然后,您(和图像编辑器)可以从任何域的JavaScript访问该图像。

答案 1 :(得分:0)

对于那些使用Rails的人来说,当谈到@Forivin提出的第四个问题时,这就是我为使其正常工作所做的。

问题是,当Toast调用存储在S3上的图像时,Chrome上会出现CORS错误,但是firefox很好。关于此的文章很多,从本质上讲,我发现最好的方法是在代码中使用代理。我仍然可以将CORS来源指向我的主机,并且由于呼叫是通过代理通过主机发出的,因此S3和Chrome很高兴。我的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>

在您的rails项目中执行以下操作:

在您的Gemfile中添加机架式代理宝石

gem 'rack-proxy'

创建一个代理文件。 s3路径经过URI编码,并附加到路由末尾。该路由仅用于代理,因此可以是任何路由,因为它将被重新路由到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

添加到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"
my_controller.rb中的

Controller方法。此处呈现的内容无关紧要,因为它将被代理重定向。由于代理服务器仍然会发生变化,因此我们可能无法摆脱任何方法。

  def dummy_path
    render plain: ""
  end

最后在我的Vue代码中,我首先通过填充空白的空白图片来调用Toast编辑器。然后,在安装组件时,我加载s3图像并覆盖现有图像并调整画布大小。我发现在装入s3图像之前需要稍微延迟一下。 s3图像是我在道具中传递的带预签名的网址。

<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>