glfx.js を使用して画像を編集していますが、toDataURL()
関数を使用してその画像のデータを取得しようとすると、空白の画像(幅はと同じサイズ)が表示されます元の画像)。
奇妙なことに、Chromeではスクリプトが完全に機能します。
私が言及したいのは、画像がonloadイベントを使用してcanvas
にロードされるということです。
img.onload = function(){
try {
canvas = fx.canvas();
} catch (e) {
alert(e);
return;
}
// convert the image to a texture
texture = canvas.texture(img);
// draw and update canvas
canvas.draw(texture).update();
// replace the image with the canvas
img.parentNode.insertBefore(canvas, img);
img.parentNode.removeChild(img);
}
また、私の画像のパスは同じドメインにあります。
(Firefoxの)問題は、保存ボタンを押したときです。 Chromeは期待される結果を返しますが、Firefoxはこれを返します:
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA7YAAAIWCAYAAABjkRHCAAAHxklEQVR4nO3BMQEAAADCoPVPbQZ/oAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
... [ lots of A s ] ...
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAzwD6aAABkwvPRgAAAABJRU5ErkJggg==
この結果の原因は何ですか?また、どうすれば修正できますか?
ほとんどの場合、キャンバスに描画してからtoDataURL
を呼び出すまでの間に非同期イベントが発生します。デフォルトでは、キャンバスはすべてのコンポジットの後にクリアされます。次のようにpreserveDrawingBuffer: true
を使用してWebGLコンテキストを作成することにより、キャンバスがクリアされないようにします。
var gl = canvas.getContext("webgl", {preserveDrawingBuffer: true});
または、レンダリングに使用しているイベントを終了する前に、toDataURLが呼び出されていることを確認してください。たとえば、これを行う場合
function render() {
drawScene();
requestAnimationFrame(render);
}
render();
そしてどこかでこれを行う
someElement.addEventListener('click', function() {
var data = someCanvas.toDataURL();
}, false);
これらの2つのイベント、animation frame
とclick
は同期しておらず、それらを呼び出す間にキャンバスがクリアされる可能性があります。注:キャンバスはダブルバッファーであるためクリアされたようには見えませんが、バッファーtoDataURLおよびバッファーが参照していることに影響を与えるその他のコマンドはクリアされます。
解決策は、preserveDrawingBuffer
を使用するか、レンダリングと同じイベント内でtoDataURL
を呼び出すことです。例えば
var captureFrame = false;
function render() {
drawScene();
if (captureFrame) {
captureFrame = false;
var data = someCanvas.toDataURL();
...
}
requestAnimationFrame(render);
}
render();
someElement.addEventListener('click', function() {
captureFrame = true;
}, false);
デフォルトであるpreserveDrawingBuffer: false
のポイントは何ですか?特にモバイルでは、描画バッファを保持する必要がないため、大幅に高速化できます。別の見方をすると、ブラウザにはキャンバスのコピーが2つ必要です。あなたが描いているものとそれが表示しているもの。これらの2つのバッファを処理する方法は2つあります。 (A)ダブルバッファ。描画コマンドを発行したイベントの終了から推測されるレンダリングが完了したら、一方に描画し、もう一方を表示し、バッファを交換します(B)描画しているバッファの内容をコピーして、表示されているバッファを実行します。交換はコピーよりもはるかに高速です。したがって、スワッピングがデフォルトです。実際に何が起こるかはブラウザ次第です。唯一の要件は、preserveDrawingBuffer
がfalse
の場合、preserveDrawingBuffer
がtrue
次に、drawingbufferの内容が保持されるようにコピーする必要があります。
キャンバスにコンテキストがあると、常に同じコンテキストになることに注意してください。つまり、WebGLコンテキストを初期化するコードを変更したが、それでもpreserveDrawingBuffer: true
を設定したいとします。
少なくとも2つの方法があります。
後でコードが同じコンテキストになるためです。
<script>
document.querySelector('#somecanvasid').getContext(
'webgl', {preserveDrawingBuffer: true});
</script>
<script src="script/that/will/use/somecanvasid.js"></script>
そのキャンバスのコンテキストはすでに作成されているため、後続のスクリプトはすべて同じコンテキストを取得します。
getContext
<script>
HTMLCanvasElement.prototype.getContext = function(origFn) {
return function(type, attributes) {
if (type === 'webgl') {
attributes = Object.assign({}, attributes, {
preserveDrawingBuffer: true,
});
}
return origFn.call(this, type, attributes);
};
}(HTMLCanvasElement.prototype.getContext);
</script>
<script src="script/that/will/use/webgl.js"></script>
この場合、getContext
を拡張した後に作成されたwebglコンテキストでは、preserveDrawingBuffer
がtrueに設定されます。