ToastUI Image Editor loadImageFromURL doesn't work
请注意,这是一个自我回答的问题。
此问题与ToastUI图像编辑器v3.3.0有关,但也可能适用于较新的版本。
使用此官方示例加载图像时:
1 2 3 4 5 6 7 8 | // 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') |
编辑器将不会加载图像。该函数既不抛出也不返回任何指示失败的信息,并且您不会收到任何错误消息。它返回一个诺言,该诺言按照文档中的说明进行解析。
它仅通过在初始配置中指定图像来加载图像,此后您将无法更改它:
1 2 3 4 5 6 7 8 9 10 11 | // 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函数已损坏,并且根据其他用户,
与此相关的问题已在GitHub上提出,但基本上已被忽略。到现在已经一个月了,不幸的是它还没有修复。
因此,问题是在存在此问题的情况下如何欺骗图像编辑器使其工作。
这是一个显示不起作用的小提琴:https://fiddle.sencha.com/#view/editor&fiddle/2org
TL; DR:
这是一个有效的小提琴:https://fiddle.sencha.com/#view/editor&fiddle/2p0o
长版:
有四个问题:
- 您需要加载初始图像,否则无法使用编辑控件。
-
您需要等到图像编辑器对象准备就绪后才能调用
loadImageFromURL ,否则可能会出现错误或无提示故障 - 加载图像后,您需要告知图像编辑器新的尺寸,否则图像将被隐藏或尺寸错误。
-
如果加载外部图像,则外部服务器必须设置
Access-Control-Allow-Origin 标头并明确允许您的域访问它,否则图像编辑器将无法访问它。
可以通过加载如下空白图像来解决第一个问题:
1 2 3 4 5 6 7 8 9 10 11 12 | 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 }); |
第二个问题可以通过使用未记录的功能等待图像编辑器退出其锁定状态来解决。您可以像这样在运行时修补
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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)); }; })(); |
第三个问题可以通过采用
1 2 3 4 5 6 7 | 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); }) |
第四个问题可能有点令人困惑。让我解释。在网站上,您可以使用
例如,在Amazon S3上,服务器默认情况下不允许这样做。您必须手动设置服务器以允许您或任何域访问它。看这里。
如果您使用的是其他服务器,则可以例如将
对于那些正在使用Rails的人,当涉及到@Forivin提出的第四个问题时,这就是我为使其正常工作所做的。
问题是,当Toast调用存储在S3上的图像时,Chrome上会出现CORS错误,但是firefox很好。关于此的文章很多,从本质上讲,我发现最好的方法是在代码中使用代理。我仍然可以将CORS来源指向我的主机,并且由于呼叫是通过代理通过主机发出的,因此S3和Chrome很高兴。我的S3 CORS配置看起来像这样(允许子域):
1 2 3 4 5 6 7 8 9 10 11 12 | <?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项目中执行以下操作:
在
1 | gem 'rack-proxy' |
创建一个代理文件。 s3路径经过URI编码,并附加到路由末尾。该路由仅用于代理,因此可以是任何路由,因为它将被重新路由到s3。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | 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 |
添加到
1 2 3 4 5 6 7 | require"./app/proxy/s3_proxy" class Application < Rails::Application ... config.middleware.use S3Proxy end |
1 | get"/my/dummy/path/:s3_url", to:"my_controller#dummy_path" |
1 2 3 | def dummy_path render plain:"" end |
最后在我的Vue代码中,我首先通过填充空白的空白图片来调用Toast编辑器。然后,在安装组件时,我加载s3图像并覆盖现有图像并调整画布大小。我发现在装入s3图像之前需要稍微延迟一下。 s3图像是我在道具中传递的带预签名的URL。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | <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 |