Flutter 創(chuàng)建多圖像的 PDF 文件

貓哥說

保持熱情去改變!

今天這篇文章是讓你在客戶端完成 PDF 的創(chuàng)建,這樣能減輕服務(wù)器的壓力。

這是很有必要的,服務(wù)器的 CPU 資源很寶貴。

Flutter 插件 https://pub.dev/packages/pdf

  • 功能有:
    • 載入圖片
    • 寫上文字
    • 加密、簽名文件
    • 也可以載入 pdf

老鐵記得 轉(zhuǎn)發(fā) ,貓哥會呈現(xiàn)更多 Flutter 好文~~~~

微信群 ducafecat

b 站 https://space.bilibili.com/404904528

原文

https://medium.com/flutterdevs/flutter-create-pdf-files-with-multiple-images-4458e813fe37

代碼

https://github.com/flutter-devs/flutter_pdf_create_view_demo

參考

正文

[圖片上傳失敗...(image-104616-1623982135598)]

在 Flutter 不同的功能使您的應(yīng)用程序豐富的有用性,并給簡單的客戶端做東西內(nèi)的應(yīng)用程序和改善客戶端的經(jīng)驗,是一個專家合作是另外必不可少的開發(fā)人員。

有很多軟件包可以用來在應(yīng)用程序中打開 pdf,有些比較復(fù)雜,有些并不難執(zhí)行,在這里我將闡明可能最容易使用的方法。

在這個博客中,我們將探索 Flutter ー創(chuàng)建多張圖片的 PDF 文件。我們將實(shí)施一個演示程序,以顯示如何 Flutter 創(chuàng)建一個 pdf 文件與多個圖像使用的三個要素包在您的 Flutter 應(yīng)用程序。

狀態(tài)管理

簡介:

PDF 很可能是用于交換業(yè)務(wù)信息的最著名的文檔格式,因為內(nèi)容不能像不同配置那樣有效地更改。這樣可以保護(hù)我們的信息不受未經(jīng)批準(zhǔn)的更改的影響。一旦你知道了策略,這通常是一個簡單的互動,我會告訴你在你的任務(wù)中制作 pdf 文檔的最好方法。

對于這個演示,需要三個基本的軟件包。

演示模塊:

[圖片上傳失敗...(image-fef52e-1623982135598)]

這個演示視頻顯示了如何在一個 Flutter 與多個圖像創(chuàng)建 pdf 文件。它顯示了 pdf 文件將如何使用這三個軟件包在您的 Flutter 應(yīng)用程序。它顯示當(dāng)用戶點(diǎn)擊一個創(chuàng)建按鈕,然后出現(xiàn) pdf,根據(jù)頁面有多個圖像。它會顯示在你的設(shè)備上。

實(shí)施方案:

  • 第一步: 添加依賴項

將依賴項添加到 pubspec ー yaml 文件。

dependencies:
  flutter:
    sdk: flutter
  cupertino_icons: ^1.0.2
  path_provider: ^2.0.1
  pdf: ^3.3.0
  syncfusion_flutter_pdfviewer: ^19.1.64-beta
  • 第二步: 添加 assets

將 assets 添加到 pubspec ー yaml 文件。

assets:
  - assets/images/
  • 第三步: 導(dǎo)入
import 'package:pdf/pdf.dart';
import 'package:path_provider/path_provider.dart';
import 'package:syncfusion_flutter_pdfviewer/pdfviewer.dart';
  • 第四步: 在應(yīng)用程序的根目錄中運(yùn)行 flutter 軟件包

如何實(shí)現(xiàn) dart 文件中的代碼:

你需要分別在你的代碼中實(shí)現(xiàn)它:

在 lib 文件夾中創(chuàng)建一個名為 pdf _ screen _ demo. dart 的新 dart 文件。

  • 首先,讓我們創(chuàng)建一個基本的 PDF 文件:

在文件中創(chuàng)建一個 StatefulWidget,名為 PdfScreenDemo。

String pdfFile = '';

一個基本的用戶界面,我們有一個凸起的按鈕,使我們的 PDF 文件和一個可見性小部件揭示 PDF 瀏覽器一旦 PDF 記錄。要查看 PDF 記錄,我們將使用 syncfusion/flutter/pdfviewer 包的 SfPdfViewer.file 小部件,在這個小部件中,我們將制作一個文檔,其方式與我們制作的 PDF 類似。

Column(
  mainAxisAlignment: MainAxisAlignment.center,
  children: [
      Visibility(
          visible: pdfFile.isNotEmpty,
          child: SfPdfViewer.file(File(pdfFile),
              canShowScrollHead: false, canShowScrollStatus:
           false),
        ),
    RaisedButton(
        color: Colors.tealAccent,
        onPressed: () {
        },
        child: Text('Create a Pdf File')),
  ],
),

PDF 包有它自己的小部件庫存,為了調(diào)用這些庫存,我們需要導(dǎo)入 PDF 小部件作為一個變量名為 pw。

import 'package:pdf/widgets.dart' as pw;

為了構(gòu)造一個 PDF 格式,我們將通過調(diào)用 pw < widgetnme > 來調(diào)用小部件。

為了保存一個 pdf 文件,我們應(yīng)該做一個。文件()。這個不常見的小部件將保存已生成 PDF 的數(shù)據(jù),因此我們在 _ PdfScreenDemoState 中生成一個變量如何。

var pdf = pw.Document();

Lest’s create createPdfFile() method:

在這個模型中,我們的想法是制作一個多頁的帶有 a4 設(shè)計的 PDF。因為我們要添加的圖片的數(shù)量,頁面的數(shù)量可能是多個的,按照這些順序,現(xiàn)在制作一個多頁面小部件是個好兆頭。

在 MultiPage 小部件的構(gòu)建方法內(nèi)部,將有一個帶有 Header 的 Column 和 Divider,用于將實(shí)質(zhì)內(nèi)容與 Header 分離。在接下來的幾個階段中,我們將在本欄內(nèi)的分隔符下添加實(shí)質(zhì)內(nèi)容。

createPdfFile() {
  pdf.addPage(pw.MultiPage(
      margin: pw.EdgeInsets.all(10),
      pageFormat: PdfPageFormat.a4,
      build: (pw.Context context) {
        return <pw.Widget>[
          pw.Column(
              crossAxisAlignment: pw.CrossAxisAlignment.center,
              mainAxisSize: pw.MainAxisSize.min,
              children: [
                pw.Text('Create a basic PDF',
                    textAlign: pw.TextAlign.center,
                    style: pw.TextStyle(fontSize: 26)),
                pw.Divider(),
              ]),
        ];
      }));
}

此后,我們應(yīng)該創(chuàng)建一個 savePdfFile ()方法。

它是一種異步方法,等待 IOS 或 Android 平臺的目錄。然后,該技術(shù)使用 ID 的名稱和目錄的 documentPath 創(chuàng)建一個記錄。你可以用任何你喜歡的方式來命名你的記錄,但是對于不同的 PDF 創(chuàng)建來說,更聰明的做法是為每個 PDF 文檔都起一個特殊的名字。

最后,該方法將 PDF 保存為文件。Path 和 value 被賦給 setState 策略中的 pdfFile 變量,以便稍后刷新 UI。

savePdfFile() async {
Directory documentDirectory = await getApplicationDocumentsDirectory();

String documentPath = documentDirectory.path;

String id = DateTime.now().toString();

File file = File("$documentPath/$id.pdf");

file.writeAsBytesSync(await pdf.save());
setState(() {
pdfFile = file.path;
pdf = pw.Document();
});
}

重要提示: 任命民主黨人是根本。在保存 pdf 文件之后,將 Document ()轉(zhuǎn)換為 pdf 變量。如果不這樣做,該 pdf 將嘗試使另一個最近制作的 pdf 文件,這將導(dǎo)致一個有缺陷的 pdf 文件被制作。

如果您需要保存您的 PDF 文件的字節(jié),您可以利用下方的方法。

List<int> pdfBytes;
pdfBytes = await file.readAsBytes();
pdfFile base64Encode(pdfBytes);

除此之外,使用異步 onPressed 方法:

為了保存記錄,我們需要首先等待 createPdfFile ()策略。

onPressed: () async {
  await createPdfFile();
  savePdfFile();
},

好了,現(xiàn)在一切都安排好了。你可以點(diǎn)擊“創(chuàng)建一個 PDF 文件”按鈕來查看你的第一個基本 PDF 文檔。當(dāng)我們運(yùn)行應(yīng)用程序時,我們應(yīng)該得到屏幕的輸出,就像下面的屏幕截圖一樣。

image
  • 讓我們用一個圖片創(chuàng)建一個 pdf 文件:

在 pdf 包中,你可以添加一個圖片。MemoryImage.因此,我們需要將圖片更改為內(nèi)存字節(jié)。

首先導(dǎo)入下面的軟件包。

import 'dart:typed_data';
import 'package:flutter/services.dart';

從那時起,將 createdffile 轉(zhuǎn)換為一個 async 方法,并添加這兩個變量。

final ByteData bytes = await rootBundle.load('assets/images/null_safety.png');
final Uint8List byteList = bytes.buffer.asUint8List();

第一個變量在資源圖片上更改為字節(jié),第二個變量在字節(jié)上更改為 Uint8List 字節(jié)列表。

然后,在這一點(diǎn)上添加一個 pw 圖像小部件在分隔符下面。

createPdfFile() async {
  final ByteData bytes =
      await rootBundle.load('assets/images/null_safety.png');
  final Uint8List byteList = bytes.buffer.asUint8List();
  pdf.addPage(pw.MultiPage(
      margin: pw.EdgeInsets.all(10),
      pageFormat: PdfPageFormat.a4,
      build: (pw.Context context) {
        return <pw.Widget>[
          pw.Column(
              crossAxisAlignment: pw.CrossAxisAlignment.center,
              mainAxisSize: pw.MainAxisSize.min,
              children: [
                pw.Text('Flutter Pdf File with Image',
                    textAlign: pw.TextAlign.center,
                    style: pw.TextStyle(fontSize: 26)),

                pw.Divider(),
              ]),
          pw.SizedBox(height: 70),
          pw.Image(
              pw.MemoryImage(
                byteList,
              ),
              height: 300,
              fit: pw.BoxFit.fitHeight),
        ];
      }));
}

MemoryImage 接受 byteList 作為位置競爭,將圖片傳送到 pdf 記錄中。現(xiàn)在重新啟動應(yīng)用程序,并嘗試制作另一個 PDF 文檔,以查看其中包含圖片的文件。當(dāng)我們運(yùn)行應(yīng)用程序時,我們應(yīng)該獲得屏幕輸出,就像下面的屏幕截圖一樣。

image
  • 讓我們創(chuàng)建一個有多個圖片的 pdf 文件:

在演示的最后一步,我們將制作一個 pdf 構(gòu)建技術(shù),它可以用給定的各種圖像生成一條記錄。首先,我們需要制定一個策略,將圖片轉(zhuǎn)換為 Uint8List 設(shè)計。

在狀態(tài)小部件中,創(chuàng)建一個空白列表,用于將圖片放入 Uint8list。

List<Uint8List> imagesUint8list = [];

然后,我們應(yīng)該重構(gòu) createdffile 方法,并集中于另一種獲取圖片字節(jié)的技術(shù)。

getImageBytes(String assetImage) async {
    final ByteData bytes = await rootBundle.load(assetImage);
    final Uint8List byteList = bytes.buffer.asUint8List();
    imagesUint8list.add(byteList);
  }

現(xiàn)在我們將制作一個類型為 pw 的列表。createPdfFile ()技術(shù)中的小部件,它生成具有圖像標(biāo)題和圖像本身的 Column。

final List<pw.Widget> pdfImages = imagesUint8list.map((image) {
      return pw.Padding(
          padding: pw.EdgeInsets.symmetric(vertical: 20, horizontal:    10),
          child: pw.Column(
              crossAxisAlignment: pw.CrossAxisAlignment.center,
              mainAxisSize: pw.MainAxisSize.max,
              children: [
                pw.Text(
                    'Image'
                            ' ' +
                        (imagesUint8list
                                    .indexWhere((element) => element
                                   == image) +
                                1)
                            .toString(),
                    style: pw.TextStyle(fontSize: 22)),
                pw.SizedBox(height: 10),
                pw.Image(
                    pw.MemoryImage(
                      image,
                    ),
                    height: 400,
                    fit: pw.BoxFit.fitHeight)
              ]));
    }).toList();

注意: 這是緊急給一個特定的最大大小的圖片小部件,否則一個圖片可能會溢出頁面設(shè)計促使一個失敗的 pdf 創(chuàng)建。

Createdffile 最初會創(chuàng)建一個 for 循環(huán),將多個圖片更改為 Uint8List。稍后,它將制作一個帶有頭部的圖片列表。最后,pdfImages 將作為子文件顯示在 pdf 的基本列中。

createPdfFile() async {
    for (String image in assetImages) await getImageBytes(image);
    final List<pw.Widget> images = imagesUint8list.map((image) {
      return pw.Padding(
          padding: pw.EdgeInsets.symmetric(vertical: 20, horizontal:  10),
          child: pw.Column(
              crossAxisAlignment: pw.CrossAxisAlignment.center,
              mainAxisSize: pw.MainAxisSize.max,
              children: [
                pw.Text(
                    'Image'
                            ' ' +
                        (imagesUint8list
                                   .indexWhere((element) => element
                             == image) +
                                1)
                            .toString(),
                    style: pw.TextStyle(fontSize: 22)),
                pw.SizedBox(height: 10),
                pw.Image(
                    pw.MemoryImage(
                      image,
                    ),
                    height: 400,
                    fit: pw.BoxFit.fitHeight)
              ]));
    }).toList();
    pdf.addPage(pw.MultiPage(
        margin: pw.EdgeInsets.all(10),
        pageFormat: PdfPageFormat.a4,
        build: (pw.Context context) {
          return <pw.Widget>[
            pw.Column(
                crossAxisAlignment: pw.CrossAxisAlignment.center,
                mainAxisSize: pw.MainAxisSize.min,
                children: [
                  pw.Text('Create a Simple PDF',
                      textAlign: pw.TextAlign.center,
                      style: pw.TextStyle(fontSize: 26)),
                  pw.Divider(),
                ]),
            pw.Column(
                crossAxisAlignment: pw.CrossAxisAlignment.center,
                mainAxisSize: pw.MainAxisSize.max,
                children: pdfImages),
          ];
        }));
  }

另一個步驟是用 SingleChildScrollView 和 Expanded 小部件包裝可見性小部件。

Expanded(
              child: SingleChildScrollView(
                child: Visibility(
                  visible: pdfFile.isNotEmpty,
                  child: SfPdfViewer.file(File(pdfFile),
                      canShowScrollHead: false, canShowScrollStatus: false),
                ),
              ),
            ),

現(xiàn)在如何我們按下按鈕最后一次機(jī)會,使 PDF 文件與多個圖片。當(dāng)我們運(yùn)行應(yīng)用程序時,我們應(yīng)該得到屏幕的輸出,就像下面的屏幕截圖一樣。

image

代碼:

import 'dart:io';
import 'dart:typed_data';
import 'package:flutter/services.dart';
import 'package:path_provider/path_provider.dart';
import 'package:pdf/pdf.dart';
import 'package:pdf/widgets.dart' as pw;
import 'package:flutter/material.dart';
import 'package:syncfusion_flutter_pdfviewer/pdfviewer.dart';

class PdfScreenDemo extends StatefulWidget {
  @override
  _PdfScreenDemoState createState() => _PdfScreenDemoState();
}

class _PdfScreenDemoState extends State<PdfScreenDemo> {
  String pdfFile = '';
  var pdf = pw.Document();

  static const List<String> assetImages = [
    'assets/images/null_safety.png',
    'assets/images/stream.png',
    'assets/images/error_handling.jpg'
  ];
  List<Uint8List> imagesUint8list = [];

  @override
  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: Scaffold(
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Expanded(
                child: SingleChildScrollView(
                  child: Visibility(
                    visible: pdfFile.isNotEmpty,
                    child: SfPdfViewer.file(File(pdfFile),
                        canShowScrollHead: false, canShowScrollStatus: false),
                  ),
                ),
              ),
              RaisedButton(
                  color: Colors.tealAccent,
                  onPressed: () async {
                    await createPdfFile();
                    savePdfFile();
                  },
                  child: Text('Create a Pdf File')),
            ],
          ),
        ),
      ),
    );
  }

  getImageBytes(String assetImage) async {
    final ByteData bytes = await rootBundle.load(assetImage);
    final Uint8List byteList = bytes.buffer.asUint8List();
    imagesUint8list.add(byteList);
    print(imagesUint8list.length);
  }

  createPdfFile() async {
    for (String image in assetImages) await getImageBytes(image);
    final List<pw.Widget> pdfImages = imagesUint8list.map((image) {
      return pw.Padding(
          padding: pw.EdgeInsets.symmetric(vertical: 50, horizontal: 10),
          child: pw.Column(
              crossAxisAlignment: pw.CrossAxisAlignment.center,
              mainAxisSize: pw.MainAxisSize.max,
              children: [
                pw.Text(
                    'Image'
                            ' ' +
                        (imagesUint8list
                                    .indexWhere((element) => element == image) +
                                1)
                            .toString(),
                    style: pw.TextStyle(fontSize: 22)),
                pw.SizedBox(height: 30),
                pw.Image(
                    pw.MemoryImage(
                      image,
                    ),
                    height: 300,
                    fit: pw.BoxFit.fitHeight)
              ]));
    }).toList();

    pdf.addPage(pw.MultiPage(
        margin: pw.EdgeInsets.all(10),
        pageFormat: PdfPageFormat.a4,
        build: (pw.Context context) {
          return <pw.Widget>[
            pw.Column(
                crossAxisAlignment: pw.CrossAxisAlignment.center,
                mainAxisSize: pw.MainAxisSize.min,
                children: [
                  pw.Text('Flutter Pdf File with Multiple Image',
                      textAlign: pw.TextAlign.center,
                      style: pw.TextStyle(fontSize: 26)),
                  pw.Divider(),
                ]),
            pw.Column(
                crossAxisAlignment: pw.CrossAxisAlignment.center,
                mainAxisSize: pw.MainAxisSize.max,
                children: pdfImages),
          ];
        }));
  }

  savePdfFile() async {
    Directory documentDirectory = await getApplicationDocumentsDirectory();

    String documentPath = documentDirectory.path;

    String id = DateTime.now().toString();

    File file = File("$documentPath/$id.pdf");

    file.writeAsBytesSync(await pdf.save());
    setState(() {
      pdfFile = file.path;
      pdf = pw.Document();
    });
  }
}

Conclusion

在這篇文章中,我解釋了創(chuàng)建 PDF 文件的基本結(jié)構(gòu)與多重圖像 Flutter; 您可以修改這個代碼根據(jù)您的選擇。這是一個小的介紹創(chuàng)建 PDF 文件與多圖像用戶交互從我這邊,它的工作使用 Flutter。

我希望這個博客將提供您在嘗試創(chuàng)建 PDF 文件與多個圖像在您的撲項目充分的信息。我們將向您展示介紹是什么?.制作一個演示程序為工作創(chuàng)建 PDF 文件與多個圖像和顯示當(dāng)用戶點(diǎn)擊一個創(chuàng)建按鈕,然后 PDF 發(fā)生,與多個圖像根據(jù)頁面使用所有三個軟件包在您的 Flutter 應(yīng)用程序。所以請嘗試一下。


? 貓哥

https://ducafecat.tech/

https://github.com/ducafecat

往期

開源

GetX Quick Start

https://github.com/ducafecat/getx_quick_start

新聞客戶端

https://github.com/ducafecat/flutter_learn_news

strapi 手冊譯文

https://getstrapi.cn

微信討論群 ducafecat

系列集合

譯文

https://ducafecat.tech/categories/%E8%AF%91%E6%96%87/

開源項目

https://ducafecat.tech/categories/%E5%BC%80%E6%BA%90/

Dart 編程語言基礎(chǔ)

https://space.bilibili.com/404904528/channel/detail?cid=111585

Flutter 零基礎(chǔ)入門

https://space.bilibili.com/404904528/channel/detail?cid=123470

Flutter 實(shí)戰(zhàn)從零開始 新聞客戶端

https://space.bilibili.com/404904528/channel/detail?cid=106755

Flutter 組件開發(fā)

https://space.bilibili.com/404904528/channel/detail?cid=144262

Flutter Bloc

https://space.bilibili.com/404904528/channel/detail?cid=177519

Flutter Getx4

https://space.bilibili.com/404904528/channel/detail?cid=177514

Docker Yapi

https://space.bilibili.com/404904528/channel/detail?cid=130578

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容