展示会での物理的な思い出
パラメータいじるだけでグラフィックを作成できる展示に物理的な思い出を持たせたい!!!!
クリエイティブコーディングやWeb上で作成したグラフィック、
それをポストカードやステッカーなどで持ち帰る体験を作りたいなと思い
ボタンを押しただけで自動で印刷まで出来上がる仕組みを構築しました
以下はその簡易実装例です
概要
本記事では、Webページ上のボタンをクリックすることで指定範囲をキャプチャし、その画像をサーバーに送信して自動で印刷する仕組みを実装する手順を紹介します。使用技術や環境構築、各コード例を含めて解説します。
使用技術
- HTML2Canvas
- Node.js v18.17.0 (Express, Multer)
- ShellScript
簡単な流れ
- HTML2Canvasで指定範囲を保存
- 画像データをサーバに送る
- クライアントから送信されたデータを受け取る
- シェルスクリプトをリクエスト
- 印刷を実行
実装
環境構築
Node.js
が入ってない方はこちらを参考にしてください。
今回使う、Express
, Multer
をインポート
npm install express multer
※ HTML2CanvasはCDNを使用
フロント実装
<!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オブジェクトに変換すると、画像ファイルとして保存したり、サーバーにアップロードできます
サーバ実装
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
を実行
シェルスクリプト
#!/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
その他の機能
lpr
コマンドには色々指定できるので、サイズなど調整してみてください
ファイル構成
立ち上げ
node server.js
localhost:3000
が立ち上がり、publicフォルダー内のindex.html
を参照してくれます
終わりに
これで、ボタンによる自動印刷が可能になると思います!
つまみやGUIなどと組み合わせて、参加者が作った作品を形あるものに出力できたら思い出の一部になりますよね。是非、Webでのグラフィック展示を行う際は、物理的な形で持ち帰る体験を提供してみてはいかがでしょう