ブラウザでSVGイメージを変換する


SVGScalable Vector Graphics ) 我々がウェブサイトで使う通常のイメージフォーマットの上で、若干の利点を持ちます.まず、CSSを使ってスタイルを整えることができます.いくつかのアプリケーションでは、同等の高品質pngまたはjpegよりもfilesizeでも小さくすることができます.また、アニメーション化することができます.最後に、それが名前で言うように、彼らはスケーラブルです.これは、写真や他の高詳細画像はSVGには適していないが、ピクセルや他のShenanigansなしで拡大または縮小することができます.

SVG ( top )とPNG ( bottom )画像を50 (左)と100 (右)ピクセルで表示します.
しかしながら、私は最近SVGの有用性の限界に気づいた.

問題


私は一緒に入れているGame of Life 私の実験の1つとしてボードを一緒に、私はそれに少しテクスチャで何かを使用していた固体黒の正方形に置き換えたかった.

別のサイズで、右側に新しい“テクスチャ”タイルで左に古い黒いタイルを比較する.
ゲームは<canvas> を指定します.Canvas API , そして、セルを描画するための元のコードは、このプロジェクトを見てGitHub ):
drawCell(x, y, state) {
    let context = this.$refs.canvas.getContext('2d');

    switch (state) {
        case DEAD:
            context.fillStyle = 'white';
            break;

        case ALIVE:
            context.fillStyle = 'black';
            break;
    }

    // fill the grid square but leave the grid outline
    context.fillRect(
        (x * this.cellSize) + 1,
        (y * this.cellSize) + 1,
        this.cellSize - 2,
        this.cellSize - 2
    );
}

クローン画像


最初のパスとして、私はこの方法をこの短いほうで置き換えました.
drawCell(x, y, state) {
    let context = this.$refs.canvas.getContext('2d');

    context.drawImage(this.images[state], (x * this.cellSize), (y * this.cellSize), this.cellSize, this.cellSize);
}
drawImage(Image, x, y, height, width) PNG、JPEG、SVGを含む以前に読み込まれた画像データを受け付けます.
残念ながら、ユーザーによってセルサイズを制御することができるので、私が使用したどんなPNGイメージもリサイズ画像から来る通常の問題にさらされるでしょう.
私はコンポーネントのmounted つの画像をプリロードする方法
async mounted() {
    this.images = {
        'alive': await loadImage("./img/alive.svg"),
        'dead': await loadImage("./img/dead.svg"),
    }

    this.initialiseMap();
}
loadImage 画像を非同期的に読み込むことができる単純な関数であり、コンポーネントがレンダリングしようとする前に、画像が利用できるようにします.
function loadImage(url, height, width) {
    return new Promise((resolve, reject) => {
        let image = new Image();

        image.onload = () => {
            resolve(image);
        }
        image.onerror = reject;

        image.src = url;
    });
}

停止する


残念なことに、この実装は、全体の描画サイクルを大幅に挽くことを引き起こし、各世代を再描画するために数十秒を取っていた.これは、かなりの大規模な板でさえ、古い充填された正方形の方法が稲妻の速さであると考えて、かなり後退しました.
私はSVGSをプリロードすることによって最悪のパフォーマンスの問題をかわすことを望んでいた-しかし、それは、各セルのためのサイズ変更と描画はまだかなり高価な操作だったようです.
私は、平らな黒いタイルを運命づけられましたか?もう1つ試してみた.

SVGへのSVG変換


覚えてdrawImage 任意の読み込みイメージデータを受け入れることができますか?このデータはファイルから直接来る必要はありません.別の画像データを抽出することが可能ですcanvas 他の画像を使用することができる要素と使用drawImage .
更新しましたloadImage 機能
function loadImageAsPNG(url, height, width) {
    return new Promise((resolve, reject) => {
        let sourceImage = new Image();

        sourceImage.onload = () => {
            let png = new Image();
            let cnv = document.createElement('canvas'); // doesn't actually create an element until it's appended to a parent, 
                                                        // so will be discarded once this function has done it's job
            cnv.height = height;
            cnv.width = width;

            let ctx = cnv.getContext('2d');

            ctx.drawImage(sourceImage, 0, 0, height, width);
            png.src = cnv.toDataURL(); // defaults to image/png
            resolve(png);
        }
        image.onerror = reject;

        image.src = url;
    });
}
The toDataURL(type, encoderOptions) メソッドはMIME型の文字列(image/png、image/jpegなど)を受け取り、別のソースとして使用できるbase 64エンコードされたイメージデータを返しますImage . 要求されたMIMEタイプをサポートしていない場合、または1つを提供しない場合は、PNGを返します.番目のパラメータは、JPEGのような“損失”型の画質を制御するために使用されます.これは0と1の間の数をとります.
最後にtoDataURL また、より新しいWebTypeを出力することができます-しかし、Chromeでのみ(それは他のブラウザーでPNGにデフォルトであるのでOKです).

最後の思考


これは理想的ではない- drawimageはまだ高価な機能であり、大きなボードはまだかなり遅いので、私は他の最適化を検索する必要があります.
しかし、1つのイメージタイプからブラウザの他の(サポートされている)型に変換する必要がある場合は、キャンバスAPIとそのtoDataURL メソッド.The toDataURL ユーザーから描画されたキャンバスから画像データを取得するために使用することもできます.