【Flutter】「PDFの作成」及び「プレビューと印刷」
概要
Flutterアプリ開発における「PDF作成」及び「プレビュー/印刷」の実装についての備忘録を記す📝
アプリにPDFの機能を付ければ
などなど、開発の幅が一気に広がるであろう。
また、PDF出力のみ有料オプションにしても良いだろう。
ちなみに、記事を書きながら思ったのが「note」記事のエクスポート機能だが『PDF』形式にも追加対応してくれたら良いかもねと思った。
PDF機能の実装
検証環境
※ 基本的なFlutter開発環境は整っている事を前提とします
プロジェクトを作成
●新規プロジェクトの作成
1.コマンドパレット(Command + Shift + P)を開き「flutter」と入力し、「Flutter: New Project」を選択。
2.一番上の「Application」を選択。
3.ワークスペースとなるディレクトリを選択(この中にプロジェクトが作成されます)
プロジェクト名は「note_flutter_pdf」とします(今回の記事では画像は省略)。
下準備
●ビルド対象
ビルド対象デバイスをWebにしておく。
(Android/iOSの動作確認は後でする)
・コマンドパレット(Command + Shift + P)を開き「flutter」と入力し、「Flutter: Select Device」を選択。
「Chrome」を選択。
パッケージの導入
以下、2つのパッケージを導入する
PDFを作成しても出力しなければ意味がないので、「pdf」と「printing」は基本、セットで導入します。
「pubspec.yaml」のdependencies:ブロックに追記します
ウィジェット/インポート
●ウィジェット
PDFのコンテンツには、標準ウィジェットは使えません。
そのため、pdf/widgets.dartにある「PDF用ウィジェット」を使って作成します。
●インポート
import 'package:flutter/material.dart';
import 'package:pdf/pdf.dart';
import 'package:pdf/widgets.dart' as pw;
import 'package:printing/printing.dart';
各パッケージのインポート。
pdf/widgets.dartですが、標準ウィジェットと名前が被ります。
衝突を避けるため、別名インポートします。
( PDFコンテンツ作成には、「pw.XXXX」のように、PDF用ウィジェットを使う)
PDF作成
PDFを作成していきましょう。
●Documentの生成
final pdf = pw.Document();
まずは、Documentインスタンスの生成をします。
●ページ作成
final page = pw.Page(
build: (pw.Context context) {
return pw.Center(
child: pw.Text("PDF Test"),
); // Center
}
);
次にページを作成します。
ページコンテンツは「PDF用ウィジェット」にて作成していきます。
とは言え、ほぼ標準ウィジェットと同じ感覚で使えます。
違いと言えば、先ほど別名インポートした「pw」を使う(pw.XXXX)ぐらいでしょうか。
●ページ追加
pdf.addPage(page);
ドキュメントにページを追加する
●関数化
PDF作成用の関数です。
Future makePdf() async {
final pdf = pw.Document();
final page = pw.Page(
build: (pw.Context context) {
return pw.Center(
child: pw.Text("PDF Test"),
); // Center
}
);
pdf.addPage(page);
return pdf;
}
単に関数にしただけです。
PDFの作成は「時間が掛かる処理」とされるため非同期にします。
プレビュー表示
●PdfPreviewウィジェット
作成したPDFをプレビュー表示させましょう。
PdfPreview(// プレビューの表示
build: (format) async {
final pdf = await makePdf();
// .save()で「Uint8List」形式の作成
return await pdf.save();
},),
);
PdfPreviewウィジェットでプレビューの表示が出来ます。
.save()メソッドで「Uint8List」形式にして返します。
●画面側
画面側の実装をしましょう。
void main() {
final body = Center( // ボディー
child: PdfPreview(// プレビューの表示
build: (format) async {
final pdf = await makePdf();
// .save()で「Uint8List」形式の作成
return await pdf.save();
},),
);
final sc = Scaffold(
body: body, // ボディー
);
final app = MaterialApp(home: sc);
runApp(app);
}
main関数はこんな感じになります。
全体のコード
main.dart(コピペで使えます)
import 'package:flutter/material.dart';
import 'package:pdf/pdf.dart';
import 'package:pdf/widgets.dart' as pw;
import 'package:printing/printing.dart';
void main() {
final body = Center( // ボディー
child: PdfPreview(// プレビューの表示
build: (format) async {
final pdf = await makePdf();
// .save()で「Uint8List」形式の作成
return await pdf.save();
},),
);
final sc = Scaffold(
body: body, // ボディー
);
final app = MaterialApp(home: sc);
runApp(app);
}
// PDF作成
Future makePdf() async {
final pdf = pw.Document();
final page = pw.Page(
build: (pw.Context context) {
return pw.Center(
child: pw.Text("PDF Test"),
); // Center
}
);
pdf.addPage(page);
return pdf;
}
とにかく短さを意識し「40行未満」で書きました。
おそらく世界最短レベル。
動作確認
では、動作確認をして見ましょう
一見、真っ白だが、テキストはど真ん中に表示しているので
下にスクロールすると「PDF Test」が出てくる。
プレビューワーの機能許可
アンダーバーに以下の機能選択が付加されてます
順々に試して行きましょう
1.「印刷」ボタンで印刷画面表示。この「保存」ボタンで保存が出来る。
2.「シェア」ボタンですが、Webの場合は押した瞬間にPDFがダウンロードされます。
3.「ページフォーマット」の選択。
A4かLetterの選択肢。
4.「向き(縦か横)」の切り替え
Webのためか、テキストがど真ん中に一行だけのためか、切り替えても余り変わらないような気もした
5.「デバッグ」機能の可否
こんな感じになる
●パラメーター調整
サジェストでPdfPreviewの引数を確認してみる。
まあ、これは一部ですがパラメーターの調整をしてみましょう。
印刷許可だけ残して見ると
「印刷」ボタンのみになる🖨
印刷許可も残さないようにすると
プレビューワーのみになる📄
それにしても、たったの40行のコードだけで、これだけの機能が実装できるとは ……
Flutterのパッケージ恐るべしですね。
ただ、このままでは日本語を使うと文字化けします。
次項にて「日本語フォントに対応」して見ましょう。
日本語フォントに対応する
フォントをダウンロードする
●日本語フォント対応
日本語フォント対応は、2つの方法がある。
本記事では「1」のアセットに設置する方法を説明する
(「2」に関しては技術書出版の予定)
●フォントファイルの種類
FlutterのPDF出力では「.ttfファイル」を使います。
●GoogleFonts公式
GoogleFonts公式(https://fonts.google.com)にアクセス
最初は、この「Noto Sans Japanese」が良さげに思ったのですが、FlutterのPDF出力で使うと何故か文字化けしてまう ……
●フォントのダウンロード
で、調べて見ると、Shippori Mincho(しっぽり明朝)が良さげなので、今回はこれを使います。
shippori で検索をかける
「Get Font」ボタン押下
「Download All」ボタン押下
すぐ左にある、このボタンからもダウンロード出来そう
ダウンロード完了したらディレクトリを開く
.zipファイルなので解凍する
太さの段階が一通りあるので
「Regular」を使いましょう。
注意点
アセットに設置する
●アセットに設置する
プロジェクト内にフォントファイルを置きます。
慣例的には
となるかと思います。
●アセットの定義
アセットに置いたフォントファイルを使うには「pubspec.yaml」にパスを定義する必要があります。
実装例
●フォントの取得 コード内では、rootBundleを使いフォントファイルを取得します。
( servicesパッケージのインポートが必要です )
import 'package:flutter/services.dart'; // これを追記
・rootBundleを使い、アセットにあるフォントを取得する例
final fontData = await rootBundle.load('assets/fonts/ShipporiMincho-Regular.ttf');
final font = pw.Font.ttf(fontData);
・使用例
final page2 = pw.Page(
pageTheme: pw.PageTheme( // ページのテーマ
pageFormat: PdfPageFormat.a4, // ついでにA4にして見る
theme: pw.ThemeData.withFont(base: font), // フォントを設定
),
build: (pw.Context context) {
return pw.Center(
child: pw.Text("テキスト"),
); // Center
}
);
全体のコード
main.dart(コピペで使えます)
import 'package:flutter/material.dart';
import 'package:pdf/pdf.dart';
import 'package:pdf/widgets.dart' as pw;
import 'package:printing/printing.dart';
import 'package:flutter/services.dart'; // rootBundleで使用
void main() {
final body = Center( // ボディー
child: PdfPreview(// プレビューの表示
build: (format) async {
final pdf = await makePdf();
// .save()で「Uint8List」形式の作成
return await pdf.save();
},),
);
final sc = Scaffold(
body: body, // ボディー
);
final app = MaterialApp(home: sc);
runApp(app);
}
// PDF作成
Future makePdf() async {
// フォントの読み込み
final fontData = await rootBundle.load('assets/fonts/ShipporiMincho-Regular.ttf');
final font = pw.Font.ttf(fontData);
final pdf = pw.Document();
final page = pw.Page(
build: (pw.Context context) {
return pw.Center(
child: pw.Text("PDF Test"),
); // Center
}
);
final page2 = pw.Page(
pageTheme: pw.PageTheme( // ページのテーマ
pageFormat: PdfPageFormat.a4, // ついでにA4にして見る
theme: pw.ThemeData.withFont(base: font), // フォントを設定
),
build: (pw.Context context) {
return pw.Center(
child: pw.Text("テキスト"),
); // Center
}
);
pdf.addPage(page);
pdf.addPage(page2);
return pdf;
}
●動作確認
動作確認しましょう。
まずは先ほどの1ページ目です
日本語を使っている2ページ目です。
文字化けせず表示されているのが分かります。
「Pixel Fold」での動作確認
Web以外でもテストして見ましょう。
●Android
Androidのエミュレーター(Pixel Fold)を使います
やはりM3のMacbookAirだとサクサク動いて快適ですね✨
1ページ目の真ん中
2ページ目の真ん中
「印刷」ボタン押下
いいですね〜🖨
左上のボタン押下で、表示されるメニュー
「シェア」ボタンも押しちゃうぞ💡
このように色々選べる
●iOS
iOSの方もテストしたいと所ですね。
先週辺りに「Xcode16」がリリースされたので、それをFlutterと連携させてテストする予定です。
「Xcode16」導入の記事にて記載します📝
Flutter技術書の執筆予定
なお、Flutterの技術書(電子書籍)を執筆する予定です。
など、さらに凝った内容を書くので、ご興味のある方は是非ご購読頂ければと思います。
早ければ、2024年10月半ばより着手。
2025年の年明け辺りに出版出来ればなと考えております。
著書
【辛島信芳の著書】
IT技術などに興味のある方は、是非ご覧になってください。
この記事が気に入ったらサポートをしてみませんか?