テスト用社印作成ツール作成メモ

帳票作成ツールで、テスト用の社印データが欲しくなり、ChatGPT に作ってもらった。

# 概要

こんな感じで、文字入力した名前で、png データを作成します。
縦横、文字の大きさ・フォント等の調整機能で適当な文字から生成できます。
htmlファイルをブラウザーで表示するだけで、動作します。
ちょっとしたツールは、すぐにどこに置いたか忘れてしまうので、メモしておきます。
※BASE64化機能追加

![2025-02-26_11h53_01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/6f7a8602-c355-4e7b-a24d-8b5bedcc1296.png)


# テスト用社印の作成例

- 楕円

![company-seal (4).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/e3bb37cb-629e-41e6-8020-04b4637b27a5.png)

- 角丸

![company-seal (5).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/63b4eb47-a843-4776-a676-b98c442ac4e9.png)

![company-seal (6).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/1cca3aed-06d7-4ae6-adf2-94b26cf3b8cc.png)

![company-seal (7).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/3174d793-b4bf-45af-a284-5c175f1acc20.png)

![company-seal (8).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/43402d21-dcd0-441c-b401-8d56e68164ef.png)


# ツールのコード

```.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>社印 HTML & PNG 変換</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js"></script>
    <style>
        @import url('https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@400;700&family=Yuji+Syuku&family=Kosugi+Maru&display=swap');

        body {
            font-family: Arial, sans-serif;
            display: flex;
            flex-direction: column;
            align-items: center;
            gap: 10px;
            margin: 20px;
        }
        .controls {
            display: grid;
            grid-template-columns: 1fr 2fr;
            gap: 8px;
            width: 350px;
            align-items: center;
        }
        label {
            font-size: 16px;
            text-align: left;
        }
        input, select {
            width: 100%;
            padding: 5px;
            font-size: 16px;
            border: 1px solid #ccc;
        }
        .preview-container {
            border: 1px solid #ccc;
            padding: 10px;
            margin-top: 10px;
        }
        /* 社印のデザイン */
        .seal {
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: center;
            border: 5px solid red;
            color: red;
            font-weight: bold;
            text-align: center;
            background: transparent;
            padding: 10px;
        }
        .seal span {
            display: block;
            word-break: break-word;
        }
        .base64-output {
            word-break: break-all;
            font-size: 12px;
            max-width: 90%;
            overflow-wrap: break-word;
            background: #f8f8f8;
            padding: 10px;
            border: 1px solid #ddd;
            cursor: pointer;
            user-select: all;
        }
    </style>
</head>
<body>

    <h2>社印設定</h2>
    
    <div class="controls">
        <label for="companyName">会社名</label>
        <input type="text" id="companyName" placeholder="会社名を入力" oninput="updateSeal()">

        <label for="widthInput">横幅 (px)</label>
        <input type="number" id="widthInput" value="250" oninput="updateSeal()"> 

        <label for="heightInput">縦幅 (px)</label>
        <input type="number" id="heightInput" value="150" oninput="updateSeal()"> 

        <label for="borderWidthInput">枠の厚さ (px)</label>
        <input type="number" id="borderWidthInput" value="5" oninput="updateSeal()"> 

        <label for="fontSizeInput">文字サイズ (px)</label>
        <input type="number" id="fontSizeInput" value="34" oninput="updateSeal()"> 

        <label for="paddingInput">余白 (px)</label>
        <input type="number" id="paddingInput" value="10" oninput="updateSeal()"> 

        <label for="fontFamilyInput">フォント</label>
        <select id="fontFamilyInput" onchange="updateSeal()">
            <option value="'Noto Sans JP', sans-serif">Noto Sans JP</option>
            <option value="'Yuji Syuku', serif">Yuji Syuku</option>
            <option value="'Kosugi Maru', sans-serif">Kosugi Maru</option>
            <option value="'MS Gothic', sans-serif">MSゴシック</option>
            <option value="Arial, sans-serif">Arial</option>
        </select>

        <label for="shapeInput">形状</label>
        <select id="shapeInput" onchange="updateSeal()">
            <option value="square">角丸四角</option>
            <option value="ellipse">楕円</option>
        </select>

        <label for="bgColorInput">背景透過</label>
        <select id="bgColorInput" onchange="updateSeal()">
            <option value="transparent" selected>透過</option>
            <option value="white">白</option>
        </select>
    </div>

    <h3>プレビュー</h3>
    <div class="preview-container">
        <div id="seal" class="seal"></div>
    </div>

    <button onclick="convertToPng()">PNG に変換してダウンロード</button>

    <h3>Base64 形式（クリックでコピー）</h3>
    <div id="base64Output" class="base64-output" onclick="copyBase64()">ここにBase64データが表示されます</div>

    <script>
        function updateSeal() {
            const companyName = document.getElementById("companyName").value.trim();
            const seal = document.getElementById("seal");
            const width = document.getElementById("widthInput").value;
            const height = document.getElementById("heightInput").value;
            const borderWidth = document.getElementById("borderWidthInput").value;
            let fontSize = document.getElementById("fontSizeInput").value;
            const padding = document.getElementById("paddingInput").value;
            const fontFamily = document.getElementById("fontFamilyInput").value;
            const shape = document.getElementById("shapeInput").value;
            const bgColor = document.getElementById("bgColorInput").value;

            // Seal スタイル更新
            seal.style.width = width + "px";
            seal.style.height = height + "px";
            seal.style.borderWidth = borderWidth + "px";
            seal.style.padding = padding + "px";
            seal.style.backgroundColor = bgColor;
            seal.style.fontFamily = fontFamily;
            seal.style.borderRadius = shape === "square" ? (borderWidth * 4) + "px" : "50%";

            seal.innerHTML = "";
            if (companyName === "") return;

            let lines = companyName.split(/\s+/).slice(0, 5);
            const autoFontSize = Math.min(fontSize, (height - padding * 2) / lines.length * 0.8);

            lines.forEach(text => {
                let span = document.createElement("span");
                span.style.fontSize = autoFontSize + "px";
                span.textContent = text;
                seal.appendChild(span);
            });

            convertToBase64();
        }

        function convertToPng() {
            convertToBase64(true);
        }

        function convertToBase64(download = false) {
            const sealElement = document.getElementById("seal");
            const isTransparent = document.getElementById("bgColorInput").value === "transparent";

            html2canvas(sealElement, { backgroundColor: isTransparent ? null : "white" }).then(canvas => {
                const pngUrl = canvas.toDataURL("image/png");
                document.getElementById("base64Output").textContent = pngUrl;

                if (download) {
                    const downloadLink = document.createElement("a");
                    downloadLink.href = pngUrl;
                    downloadLink.download = "company-seal.png";
                    document.body.appendChild(downloadLink);
                    downloadLink.click();
                    document.body.removeChild(downloadLink);
                }
            });
        }

        function copyBase64() {
            navigator.clipboard.writeText(document.getElementById("base64Output").textContent);
            alert("Base64がクリップボードにコピーされました！");
        }

        updateSeal();
    </script>

</body>
</html>
```