SVG を高画質の PNG に変換する方法 - JavaScript を使用して

Web 開発において、**SVG** を**高画質**の**PNG** 形式に変換したい場合があります。

例えば、以下の記事で紹介しているツールを作成する際に、Web ページ上では SVG を小さく表示しますが、ダウンロード時には高画質な PNG 画像として提供したい場合です。

https://qiita.com/shikuno_dev/items/367fffe2ef52c903a6ae


本記事では、JavaScript と Canvas API を使用して SVG 画像を高画質の PNG 画像に変換する方法を紹介します。SVG の基本要素を説明した上で、実装の手順を解説します。

# SVGの基本要素
SVG要素には、いくつかの重要な属性があります。ここでは、`width`、`height`、および `viewBox` について説明します。

## width と height
width と height 属性は、SVG 要素の幅と高さを指定します。これらの値はピクセル単位で指定され、表示される領域のサイズを決定します。

```xml
<svg 
    width="400" 
    height="300" 
    xmlns="http://www.w3.org/2000/svg" 
    viewBox="0 0 800 600"
></svg>
```
上記の例では、SVG要素の幅が 400 ピクセル、高さが 300 ピクセルに設定されています。

## viewBox
**viewBox 属性**は、SVG の**内部座標系**を指定します。
viewBox は SVG の内部に仮想的なキャンバスを設定し、その中で描画する要素（例えば、`<rect>` や `<circle>` など）の位置とサイズを制御するものです。



viewBox は4つの値を持ちます。
```xml
<svg viewBox="min-x min-y width height">
```
- `min-x` と `min-y`：仮想キャンバスの左上の座標
- `width` と `height`：仮想キャンバスの幅と高さ


```xml
<svg viewBox="0 0 200 200" width="100" height="100" xmlns="http://www.w3.org/2000/svg">
    <circle cx="100" cy="100" r="80" fill="green" />
</svg>
```
この例では、`viewBox="0 0 200 200"` と設定されています。この仮想キャンバスは、**実際の表示サイズ（`100x100 ピクセル`）にかかわらず**、SVG の内部では `200x200` の領域として扱われます。



## SVG を高画質で PNG に変換する手順
`200x200 ピクセル`の SVG を例に説明します。
```html
<svg id="mySVG" width="200" height="200" xmlns="http://www.w3.org/2000/svg">
    <circle cx="100" cy="100" r="80" fill="green" viewBox="0 0 200 200" />
</svg>
```
SVG はベクタ形式の画像であるため、拡大しても画質が劣化しません。しかし、PNG はラスタ形式の画像であるため、`200x200 ピクセル`のままでは、拡大すると画質が劣化してしまいます。

そのため、高画質な PNG を生成するには、元の SVG を大きなサイズで描画し、その後 PNG に変換する必要があります。

### 0. 準備
まずは、`<svg>` 要素と `<button>` 要素、`<script>` 要素を index.html ファイルに記述します。
```html:index.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>SVG to PNG Converter</title>
</head>
<body>

    <svg id="mySVG" width="200" height="200" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200">
        <circle cx="100" cy="100" r="80" fill="green" />
        <text x="100" y="100" text-anchor="middle" dominant-baseline="middle" fill="white" font-size="45" font-weight="bold">あ</text>
    </svg>
    
    <button id="downloadPNG">Download PNG</button>
    
    <script>
    </script>
    
</body>
</html>
```
以下のコードは、`<script>` 要素内に記述します。

### 1. SVGの取得と設定

`<button>` 要素にクリックイベント時の動作を追加します。

HTML の SVG 要素を取得し、文字列に変換します。この文字列データを後で画像に変換します。

```javascript
document.getElementById('downloadPNG').addEventListener('click', () => {
    const svgElement = document.getElementById('mySVG');
    const svgData = new XMLSerializer().serializeToString(svgElement);
 });
```

### 2. Canvas に描画

次に、`Canvas` 要素を作成し、ダウンロード時のサイズを設定します（この例では `1000x1000 ピクセル`）。

```javascript
document.getElementById('downloadPNG').addEventListener('click', () => {
    // ...
    
    // Canvas要素を作成
    const canvas = document.createElement('canvas');
    const context = canvas.getContext('2d');

    // 高解像度設定
    const width = 1000; // ダウンロード時の幅
    const height = 1000; // ダウンロード時の高さ
    canvas.width = width;
    canvas.height = height;
 });
```

### 3. Canvas から PNG 画像を生成
次に、Image オブジェクトを作成し、SVG データを base64 エンコードして `src` 属性に設定します。

画像がロードされたら、`context.drawImage` を使って `Canvas` に描画します。

`canvas.toDataURL('image/png')` でダウンロードリンクを作成し、それをクリックすることで PNG 画像をダウンロードします。（ダウンロードリンクはページ上に表示されません。）

```javascript
document.getElementById('downloadPNG').addEventListener('click', () => {
    // ...
    
    // SVGデータを元に画像を作成
    const img = new Image();
    
    // img.src = 'data:image/svg+xml;base64,' + btoa(svgData); // SVGデータに非ASCII文字が含まれている場合、適切にエンコードされない
    img.src = 'data:image/svg+xml;charset=utf-8;base64,' + btoa(unescape(encodeURIComponent(svgData))); 

    img.onload = function () {
        // Canvasに描画
        context.drawImage(img, 0, 0, width, height);

        // PNGデータURLを取得
        const pngDataUrl = canvas.toDataURL('image/png');

        // ダウンロードリンクを作成してクリック
        const downloadLink = document.createElement('a');
        downloadLink.href = pngDataUrl;
        downloadLink.download = 'image.png';
        downloadLink.click();
    };
});
```




## まとめ

以上の手順で、JavaScript を使用して SVG を高画質の PNG に変換することができます。この方法を使用すれば、Web アプリケーションで高品質な画像を簡単に生成できます。