0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Web上のボタンを押すと指定範囲を印刷自動化

Last updated at Posted at 2024-08-06

展示会での物理的な思い出

パラメータいじるだけでグラフィックを作成できる展示に物理的な思い出を持たせたい!!!!

クリエイティブコーディングやWeb上で作成したグラフィック、
それをポストカードやステッカーなどで持ち帰る体験を作りたいなと思い

ボタンを押しただけで自動で印刷まで出来上がる仕組みを構築しました
以下はその簡易実装例です

概要

本記事では、Webページ上のボタンをクリックすることで指定範囲をキャプチャし、その画像をサーバーに送信して自動で印刷する仕組みを実装する手順を紹介します。使用技術や環境構築、各コード例を含めて解説します。

使用技術

  • HTML2Canvas
  • Node.js v18.17.0 (Express, Multer)
  • ShellScript

簡単な流れ

  1. HTML2Canvasで指定範囲を保存
  2. 画像データをサーバに送る
  3. クライアントから送信されたデータを受け取る
  4. シェルスクリプトをリクエスト
  5. 印刷を実行

実装

環境構築

Node.js が入ってない方はこちらを参考にしてください。

今回使う、Express, Multer をインポート

ターミナル
npm install express multer

※ HTML2CanvasはCDNを使用

フロント実装

↓実際の画面
スクリーンショット 2024-08-06 19.39.20.png

index.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>印刷テスト</title>
    <style>
        #captureArea {
            width: 300px;
            height: 200px;
            border: 1px solid #000;
            background-color: #d7a7a7;
            text-align: center;
            line-height: 200px;
        }
    </style>
</head>
<body>
    <div id="captureArea">
        ここが印刷されます
    </div>
    <button id="saveButton">画像を保存&印刷</button>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js"></script>
    <script>
        document.getElementById('saveButton').addEventListener('click', () => {
            const captureArea = document.getElementById('captureArea');

            html2canvas(captureArea).then(canvas => {
                const dataURL = canvas.toDataURL('image/png');
                const blob = dataURLToBlob(dataURL);
                const formData = new FormData();
                formData.append('image', blob, 'capture.png');

                fetch('/save-and-print', {
                    method: 'POST',
                    body: formData
                }).then(response => {
                    if (response.ok) {
                        alert('保存&印刷DONE');
                    } else {
                        alert('error');
                    }
                });
            });
        });

        function dataURLToBlob(dataURL) {
            const parts = dataURL.split(';base64,');
            const contentType = parts[0].split(':')[1];
            const raw = window.atob(parts[1]);
            const rawLength = raw.length;
            const uInt8Array = new Uint8Array(rawLength);

            for (let i = 0; i < rawLength; ++i) {
                uInt8Array[i] = raw.charCodeAt(i);
            }

            return new Blob([uInt8Array], { type: contentType });
        }
    </script>
</body>
</html>
  • captureAreaのID部分をキャプチャー
  • formDateオブジェクトにキャプチャーした部分をimageというキーでblobデータとして追加
  • /save-and-printというエンドポイントに対して、POSTリクエストを送信

dataURLToBlob関数ではbase64エンコードされたデータURLをBlob形式に変換しています。
dataURLToBlobはパッケージ化されてたのでそちらを使っても問題ないです

Blobオブジェクトに変換すると、画像ファイルとして保存したり、サーバーにアップロードできます

サーバ実装

server.js
const express = require('express');
const multer = require('multer');
const { exec } = require('child_process');
const path = require('path');
const fs = require('fs');

const app = express();
const port = 3000;

const upload = multer({ dest: 'uploads/' });

app.use(express.static('public'));

app.post('/save-and-print', upload.single('image'), (req, res) => {
    const tempPath = req.file.path;
    const targetPath = path.join(__dirname, 'uploads/capture.png');

    fs.rename(tempPath, targetPath, err => {
        if (err) {
            console.error(`file_rename_error: ${err}`);
            return res.sendStatus(500);
        }

        exec(`./print_file.sh ${targetPath}`, (error, stdout, stderr) => {
            if (error) {
                console.error(`sh error: ${error}`);
                return res.sendStatus(500);
            }
            console.log(`stdout: ${stdout}`);
            console.log(`stderr: ${stderr}`);
            res.sendStatus(200);
        });
    });
});

app.listen(port, () => {
    console.log(`port:${port}起動`);
});
  • Express を使用してサーバーを設定し、publicフォルダ内の静的ファイルへのアクセスを可能に
  • Multer を使ってファイルをアップロード
  • フロントからのPOSTリクエストを受け取れるエンドポイント/save-and-printを設定
  • uploadsフォルダ内のcapture.pngへリネーム
  • 保存されたファイルをShellScript:print_file.shを実行

シェルスクリプト

print_file.sh
#!/bin/bash

file_to_print=$1

if [ -z "$file_to_print" ]; then
    echo "エラー: ファイル指定なし"
    exit 1
fi
if [ ! -f "$file_to_print" ]; then
    echo "エラー: ファイル存在なし"
    exit 1
fi

lpr -P XXXXXXX "$file_to_print"

echo "印刷DONE"
  • ファイルパスが 指定されてない or 存在しない 時のエラーハンドリング
  • XXXXXXXの部分でプリンターを指定
  • 指定されたファイルを特定のプリンターに送信

※ プリンターの調べ方は下記載せています

プリンターの調べ方

ターミナル
lpstat -s

赤線部分をXXXXXXXの部分に指定してあげればOK
スクリーンショット 2024-08-06 19.08.22.png

その他の機能

lprコマンドには色々指定できるので、サイズなど調整してみてください

スクリーンショット 2024-08-06 19.56.58.png

ファイル構成

スクリーンショット 2024-08-06 19.59.57.png

立ち上げ

ターミナル
node server.js

localhost:3000が立ち上がり、publicフォルダー内のindex.htmlを参照してくれます

終わりに

これで、ボタンによる自動印刷が可能になると思います!

つまみやGUIなどと組み合わせて、参加者が作った作品を形あるものに出力できたら思い出の一部になりますよね。是非、Webでのグラフィック展示を行う際は、物理的な形で持ち帰る体験を提供してみてはいかがでしょう

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?