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

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

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

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

HTML5

HTML5 (Hyper Text Markup Language、バージョン 5)は、マークアップ言語であるHTMLの第5版です。

JavaScript

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

WebGL

WebGL(ウェブジーエル)は、ウェブブラウザで 3次元コンピュータグラフィックスを表示させるための標準仕様です。

Chrome extension

Chrome拡張機能

Q&A

解決済

4回答

5117閲覧

webGLのreadPixelをcanvas2dに用いられるImageDataに変換したい

ke9000

総合スコア8

canvas

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

HTML5

HTML5 (Hyper Text Markup Language、バージョン 5)は、マークアップ言語であるHTMLの第5版です。

JavaScript

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

WebGL

WebGL(ウェブジーエル)は、ウェブブラウザで 3次元コンピュータグラフィックスを表示させるための標準仕様です。

Chrome extension

Chrome拡張機能

0グッド

0クリップ

投稿2018/05/04 15:09

編集2018/05/05 16:15

前提・実現したいこと

webGLのgetPixelでcanvas全体の色情報を取得したものをcanvas2dに用いられるImageDataに変換し,
webGLで表示されている部分のcanvasをキャプチャしたい.

###考えた手法
webGLのgl.readPixelsがRGBA, Uint8Arrayで出力でき、それがcanvasのgetImageDataにおけるImageData.dataと同じであることがわかった。 (下記参考にしたサイトを参照)
そこでwebGLからgl.readPixelsを用いてUnit8Arrayの配列でcavas全体の色情報を取得する。
その後、その配列情報をImageData.dataとして変数に格納し、別に用意したcanvasにputImageで表示させようとした。
そしてputImageされたCanvasをtoDataURL()でpng化させようとした。

###制約事項
・元のcanvasはid, class なし / WebGL(PixiJS)で描画されている
・取得した画像を表示するclone_canvasはcanvas2dで描画する

該当のソースコード

javascript

1//元のcanvasの色情報取得 2var orig_canvas = document.getElementsByTagName("canvas")[0]; 3var gl = canvas.getContext("webgl"); 4 5var Uint8Array = new Uint8Array( canvas.width * canvas.height * 4); 6gl.readPixels(0, 0, canvas.width, canvas.height, gl.RGBA, gl.UNSIGNED_BYTE, Uint8Array); 7 8//cloneのcanvas生成 9var create_clone = document.createElement("canvas"); 10create_clone.id = "clone_canvas"; 11create_clone.width = orig_canvas.width; 12create_clone.height = orig_canvas.height; 13 14//cloneのElement 15var clone_canvas = document.getElementById("clone_canvas"); 16var context_clone = clone_canvas.getContext("2d"); 17 18//ImageDataの作成とputImage 19var img_data = { 20 data : Uint8Array, 21 height: orig_canvas.height, 22 width: orig_canvas.width 23}; 24 25context_clone.putImageData(img_data, 0, 0); 26 27//toDataURLによる画像化 28var canvas_img = clone_canvas.toDataURL();

発生している問題・エラーメッセージ

TypeError: Failed to execute 'putImageData' on 'CanvasRenderingContext2D': parameter 1 is not of type 'ImageData'.

Uint8Arrayで生成された配列データがcanvas2dのものと型がちがっていると推測しました。

試したこと

canvas2dのRefernceには Uint8ClampedArray とあったのでそれに書き換えましたが結果は変わりませんでした・・・

###参考にしたサイト
https://developer.mozilla.org/ja/docs/Web/API/WebGLRenderingContext/readPixels
https://developer.mozilla.org/en-US/docs/Web/API/ImageData
https://wgld.org/d/webgl/w086.html

補足情報(FW/ツールのバージョンなど)

chorme : 66.0.3359.139
上記のスクリプトはcontextscriptとして特定のcanvasで動作しているゲームのサイトのみで読み込まれています


くだらないミス、根本的な認識の間違えの可能性もあります。その場合は大変申し訳ありません。
何か気が付いた事がありましたら教えていただけると幸いです。
よろしくお願いします。

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

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

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

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

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

guest

回答4

0

js

1canvas.getContext('weggl', {preserveDrawingBuffer: true});

と、オプションでpreserveDrawingBufferを有効にする必要があるようです。

ヘタレなのでサンプルではThree.jsを使ってます。
サンプル

投稿2018/05/05 08:30

turbgraphics200

総合スコア4267

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

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

0

pixi.jsのCanvasをキャプチャしたいだけなら、下記のような取り方もあります。

var canvas = pixi.renderer.extract.canvas(pixi.stage); var ctx = canvas.getContext('2d'); // 指定したピクセルの位置の色を取得 var pixel = ctx.getImageData(500, 500, 1, 1); // そのままクローンすることもできます document.body.appendChild(canvas);

自分の使用している PixiJS 4.6.2 では、上記で画像が取得できました。
情報参照元です
https://github.com/pixijs/pixi.js/issues/3880

以上、何かの参考になれば幸いです。

投稿2018/05/04 18:51

adrs2002

総合スコア203

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

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

ke9000

2018/05/05 03:21

回答ありがとうございます。 ここで投稿したスクリプトはGoogle Chrome Extention の Content Scriptで特定のPixiJSで作成されたwebGLで動いているサイトでのみ読み込ませており、こちらが対象のPixiJSを操作できないものなのです・・・ 回答していただいたのに大変申し訳ありません。
guest

0

こんばんは。

実際には試さず書いていますので、もしうまくいかなかったら申し訳ありません……

まず、最終的な目的が「WebGL の描画結果の画像化」である場合、WebGL のコンテキストを生成している Canvas 単体でも toDataURL による画像化はできたような気がします。

具体的には、WebGL のコンテキストを初期化する際に次のようにオプションを指定します。

javascript

1let canvas = document.getElementById('webgl-canvas'); 2let gl = canvas.getContext('webgl', { 3 preserveDrawingBuffer: true 4});

WebGL コンテキストの初期化時のオプションについては、仕様の「5.2 WebGLContextAttributes」のところに記載があります。

https://www.khronos.org/registry/webgl/specs/latest/1.0/

昔、一度試したときはこれで普通にうまくいきました。
参考になるといいのですが……

投稿2018/05/04 15:50

doxas

総合スコア112

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

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

ke9000

2018/05/04 16:06

回答ありがとうございます。 既にご回答いただいたことも一度やっております・・・ 投稿の追記としてこの投稿に至るまでにあったことを書きます: ・読み取るwebGLは私が作成したものではなく他の方が作成したもの ・そのwebGLはPixiJSで動いている(説明として適切な表現ではないかもしれませんが・・・) ・canvasを直接 toDataURLしたが真っ黒な画像が出てくる ・ご回答いただいたオプションを付加しても真っ黒な画像がでてくる ・なので仕方がなくcanvasを複製して取得することを思いつく ・この投稿に至る という形です・・・ 自分自身でも他サイトの英語での情報を探しながら解決策を模索しているところです。 わざわざご回答していただいたのに結果にならず大変申し訳ないです・・・
doxas

2018/05/04 16:14

うおお……そうだったのですね…… それは失礼しました。 これも、もしかすると役に立たない知識になってしまうかもしれませんが、そもそも `readPixels` の結果は、ちゃんとそれらしいデータが取れてるんでしょうか? であれば、あとはちゃんとループ回すなり、適切にデータ紐付けてやるなりすればうまくいくような気がします。 ImageData は、グローバルに定義されているオブジェクトです。なので例えばおもむろに以下のように…… ``` let imgData = new ImageData(512, 512); ``` とかってやると、普通にオブジェクトのインスタンスが作られます。 このオブジェクトは当たり前ですが `ImageData` のインスタンスなので `data` などのメンバを持っています。型は、ご質問の本文にあるように `UintClampedArray` ですね。 でもこの手の型付配列であっても、通常の Array と同じようにループを回してデータを逐次セットしたり、あるいはもしかしたら代入してもいけるかもしれませんので、試してみてはいかがでしょうか。 もしうまくいかなかったら……すいません!
ke9000

2018/05/05 03:17

①今更気が付いたのですがreadPixelsの結果が {0,0,0,255,0,0,0,255,....}の繰り返しになっていました・・・・ こうなるとすべてALPHAになっているという認識でよろしいのでしょうか・・・? それならばまた取得方法を考えます・・・(WebRTCを使う・・・?) ②ご回答いただいた `let imgData`ですがここにreadPixelsで取得したデータを代入(自分の元のコードとご回答いただいたものから:imgData.data = Uint8Array)すると代入したにも関わらずすべての配列の値が0になるという問題が起きてしまいました。こちらも何か認識ミス、もしかfor loopでないといけいないのかもしれません・・・ お手数をおかけしてしまい本当に申し訳ないです・・・何か思い当たることがありましたら教えていただけると幸いです・・・
doxas

2018/05/05 07:01 編集

Oh... うまくいかないですか……困りましたね…… 実装を見てないので、推測で書きます。 readPixels で黒が返ってくるということは、そもそも別のコンテキストで readPixels している、もしくはコンテキストは同じでも、WebGL の描画結果がフレームバッファに書き込まれていないタイミングで readPixels しているかのいずれかだと思います。 adrs2002 さんの書かれている回答の方法で、なんかうまくいきそうな気もするので、試してみてはいかがでしょうか。と思ったら、既に試した後だったのか。 なんか別のアプローチを考えたほうがいいかもしれませんね。 拡張で動いてるものだったら、やり方はありそうな気がしますが、私はそのへんあまり詳しくないです……
guest

0

自己解決

adrs2002さんの回答にコメントした通りchrome拡張でこのscriptを動作させようとしていました。
この点記載しなかったことをお詫びします。

また、doxasさんの投稿の最中に取得方法を考えchromeAPIを洗いざらいしらべたところ
chrome.tabs.captureVisibleTab(Document)というAPIがありました。
最終的にこちらで実装することにしました。(数分で実装でき今までのは・・・となってます・・・)

質問ジャンルと解決したジャンルが違う投稿になってしまったことお詫びします。
また今回回答してくださった doxasさん, adrs2002さん,turbgraphics200さん 大変申し訳ありませんでした。
また、本当にありがとうございました。

投稿2018/05/05 16:13

ke9000

総合スコア8

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問