質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
canvas

HTML5の<canvas>要素用のタグです。CanvasはHTML5から導入された、二次元の図形描写が可能な要素です。

Heroku

HerokuはHeroku社が開発と運営を行っているPaaSの名称です。RubyやNode.js、Python、そしてJVMベース(Java、Scala、Clojureなど)の複数のプログラミング言語をサポートしている。

Node.js

Node.jsとはGoogleのV8 JavaScriptエンジンを使用しているサーバーサイドのイベント駆動型プログラムです。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Q&A

解決済

1回答

1369閲覧

Node.jsでcanvasを画像化したい

mi_ho

総合スコア34

canvas

HTML5の<canvas>要素用のタグです。CanvasはHTML5から導入された、二次元の図形描写が可能な要素です。

Heroku

HerokuはHeroku社が開発と運営を行っているPaaSの名称です。RubyやNode.js、Python、そしてJVMベース(Java、Scala、Clojureなど)の複数のプログラミング言語をサポートしている。

Node.js

Node.jsとはGoogleのV8 JavaScriptエンジンを使用しているサーバーサイドのイベント駆動型プログラムです。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

0グッド

0クリップ

投稿2021/05/24 20:09

編集2021/05/24 23:19

前提・実現したいこと

heroku+Node.jsでWebアプリを作成しています.
フロント(html)の<canvas>を,サーバーサイド(Node.js)側で,toDataURL()で画像化したいです.

当初は,サーバーサイドのNode.jsではなく,レンダリングをするJavaScript(htmlから呼び出し)内でtoDataURL()処理をしようとしていたのですが,canvasにCross Originの画像が描画されている部分があるため,CORSエラーによりtoDataURL()が実行できませんでした(この方と同じエラーです).
CORSエラーを回避するために,サーバーサイドで処理しようとしています.

ソースコード

html

1<canvas id="canvas"></canvas> 2<input type="button" value="get_image" id="get_image"> 3 4<script> 5var socketio = io(); 6$(function(){ 7 $('#get_image').on('click', function() { //NodeへcanvasのDOMを送信 8 var canvas = document.getElementById("canvas"); 9 socketio.emit("get_image", canvas); 10 }); 11}); 12</script>

Node

1const io = require('socket.io')(http); 2io.on('connection',function(socket){ 3 socket.on('get_image',function(msg){ //canvasのDOMを受信 4 get_image(msg); 5 }); 6}); 7function get_image(dom){ //canvasをデータURIに変換 8 var canvas = dom.toDataURL("image/png"); 9 console.log(canvas); 10}

発生しているエラー

var canvas = dom.toDataURL("image/png"); ^ TypeError: dom.toDataURL is not a function

このエラーについて,どのような原因が考えられるでしょうか?
ご教授お願いいたします.

追記

詳しい内容を捕捉します. 2021/5/25 8:15

画像は,gyazoという画像共有サービスのURLから呼び出しています.
呼び出しているURLは,https://i.gyazo.com/???.png のようなものです.

vis.jsを利用してcanvasに描画したネットワーク図のノードに,gyazoの画像を設定しています.
このような感じです↓(画像はvis.js公式ドキュメントより引用)
イメージ説明

しかし,このcanvasをtoDataURL()をすると,

Uncaught DOMException: Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported.

というエラーがでています.

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hoshi-takanori

2021/05/24 21:23

「canvasのDOMを送信」なんてことはできないと思いますが…。 とりあえず CORS エラーを回避するには、問題の画像を Node.js で proxy すれば良いのでは。
mi_ho

2021/05/24 21:45

「canvasのDOMを送信」はできないんですね.ありがとうございます! 画像はgyazoという画像共有サービスのURLから呼び出していて,canvasへの描画はできています. しかし,toDataURL()をすると, Uncaught DOMException: Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported. というエラーがでるという状況です. 「問題の画像を Node.js で proxy 」とは,gyazoのURLをNodeに送信して,なにか処理をするということでしょうか?
hoshi-takanori

2021/05/24 22:23

heroku のアプリが example.com だとして、それ以外のサイトから取ってきた画像を canvas に表示するとそうなるようですが、例えば https://example.com/get_image?url=https://i.gyazo.com/???.png というリクエストがあったら node.js で https://i.gyazo.com/???.png を取得してそのまま返すようにすれば、ブラウザから見たら同じサイトから撮ってきた画像に見えるってことです。(gyazo の規約的にやっていいかどうかは知りませんが…。)
mi_ho

2021/05/24 23:21

hoshi-takanoriさん,詳しく書いていただきありがとうございます! 質問文に捕捉を追記しました. canvasに描画しているgyazoのURLは,https://i.gyazo.com/???.png です. 詳しく書くと,vis.jsを利用してcanvasに描画したネットワーク図のノードに,gyazoの画像を設定しています(質問文に画像を追記しています). URLはhttps://i.gyazo.com/???.pngなので,CORSは問題ないかと思っていたのですが,なぜかtoDataURL()のみできない状況です….
guest

回答1

0

ベストアンサー

こんな感じでいかがでしょうか。canvas1 は外部の画像に直接アクセスしてるのでエラーになりますが、canvas2 は node.js サーバー経由で画像にアクセスするので、toDataURL が成功するはず。

node.js サーバー (expressnode-fetch が必要です。)

js

1const express = require('express'); 2const fetch = require('node-fetch'); 3 4const app = express(); 5app.use(express.urlencoded({ extended: true })); 6 7app.get("/", (req, res) => { 8 res.sendFile('index.html', { root: __dirname }); 9}); 10 11app.get("/get_image", async (req, res, next) => { 12 try { 13 const r = await fetch(req.query.url); 14 const buffer = await r.buffer(); 15 res.set('Content-Type', r.headers.get('content-type')); 16 res.status(r.status).send(buffer); 17 } catch (err) { 18 next(err); 19 } 20}); 21 22app.listen(3000);

index.html

html

1<canvas id="canvas1"></canvas> 2<button onClick="convert('canvas1')">Convert 1</button> 3 4<canvas id="canvas2"></canvas> 5<button onClick="convert('canvas2')">Convert 2</button> 6 7<script> 8window.onload = () => { 9 const url = 'https://i.gyazo.com/???.png'; // 実際の画像 URL を指定してください。 10 load_image('canvas1', url); 11 load_image('canvas2', '/get_image?url=' + url); 12}; 13 14function load_image(id, url) { 15 const canvas = document.getElementById(id); 16 const ctx = canvas.getContext('2d'); 17 const img = new Image(); 18 img.onload = () => { 19 ctx.drawImage(img, 0, 0); 20 }; 21 img.src = url; 22} 23 24function convert(id) { 25 const canvas = document.getElementById(id); 26 console.log(canvas.toDataURL()); 27} 28</script>

投稿2021/05/26 06:03

編集2021/05/26 06:08
hoshi-takanori

総合スコア7893

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

mi_ho

2021/05/27 09:21

hoshi-takanoriさん,ご回答ありがとうございます! この方法で試したところ,画像化できました! 勉強になりました!ベストアンサーつけさせていただきます!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問