14
9

More than 3 years have passed since last update.

NodejsでエクセルやPDFをテンプレートにして文字を挿入&ダウンロードする

Last updated at Posted at 2021-06-27

WebUIで表示する分にはいろいろUIライブラリーがあったりして綺麗にできデータ連係とかで完結すれば良いのですが、結局はエクセルに記入して提出とか、PDFに文字を記入して提出とかありますよね。出力までスマートに自動化したくて、挿入する方法をいくつか検討しました。

前提

Nodejsでの例になります。

  • Nodejs
  • FileSaver - 生成したblobをダウンロードするには一手間必要ですが、それをシンプルにします。おすすめです。

yarn add file-saverでインストールします。

PDF

いろいろやりましたが、labelmakeを使うのが簡単です。pdf-libがベースのようですが、テンプレートデザイン&コードジェネレータがあり、PDF上に位置指定が簡単にできます。

yarn add labelmake

準備

フォントダウンロード

日本語フォントファイルが無い場合はIPAフォントをダウンロードしておきます。

テンプレートの作成

位置をXYで細かく指定する従来の方法もつかえますが、差し込み位置を定義できるデザイン&コードジェネレーターがあるので、それを利用します。

スクリーンショット 2021-06-27 21.25.52.png

使い方は見れば解る簡単さです。BasePDFでテンプレート元のファイルを選択し、フィールド枠をドラッグで合わせ名称、フォントサイズ、色などを指定します。Alignmentやフォントサイズ、スペーシングが設定できるのでほぼキッチリあわせる事ができます。 「Get Code」で表示されるtemplate以下をコピペするのが便利かと思います。fontが指定されていないと日本語が入っているとエラーになるので注意が必要です。

サンプルコード

import { saveAs } from 'file-saver'
import labelmake from 'labelmake'

// ここではURLから読み込みます
const basePdf = await fetch('/base.pdf').then((res) =>
  res.arrayBuffer()
)
const IPAFont = await fetch('/ipaexg.ttf').then((res) => res.arrayBuffer())
const font = { IPAFont }

// テンプレートの差し込み位置情報
const template = {
  fontName: 'IPAFont',
  basePdf,
  schemas: [{
    field1: {
      ....
    }
  }]
}
// テンプレートに対応するデータ
const inputs = [{
  "field1": "hogehoge"
  ....
}]
const pdf = await labelmake({ template, inputs, font })
const blob = new Blob([pdf.buffer], { type: 'application/pdf' })

const output_filename = 'output.pdf'
saveAs(blob, output_filename)

Microsoft Excel

まだまだ、手元で修正できるエクセルで欲しいという要望もあります。いろいろ試行錯誤しましたが、xlsx-populate を使うのが便利でした。

yarn add xlsx-populate

サンプルコード

いろいろできますが、とりあえず指定のセルに文字を入れるだけならこんな感じでできます。

import { saveAs } from 'file-saver'
const XlsxPopulate = require('xlsx-populate')

// テンプレート読み込み
const baseXLSX = await fetch('/base.xlsx').then((res) =>
  res.arrayBuffer()
)
const wb = await XlsxPopulate.fromDataAsync(baseXLSX)
const ws = wb.sheet(0)

// セル操作
ws.cell('A1').value("ほげほげー")

// ダウンロード(SaveAsモジュール)
const wbout = await wb.outputAsync()
const blob = new Blob([wbout], { type: 'application/octet-stream' })

const output_filename = "output.xlsx"
saveAs(blob, output_filename)

むにゃむにゃ

ちょっとしたツールを作る事が多いのですが、結局最終出力は紙で!という感じになるのでうまくテンプレートファイルから生成する方法を試行錯誤していました。

今回labelmakeを発見して、使って見たらテンプレート出力に特化していて非常に良くできていたのでPDF出力まで簡単に実装する事ができました。感謝です。

参考

他のPDFライブラリーも比較したまとめがあります。PDFKitは使った事があり、結構大変だった思い出があります...。参考まで。

14
9
1

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
14
9