Создание документов Pdf в NativeScript - пока непростая задача. Мало существующих тем по генерации PDF,

Решение

По сути, любая библиотека JavaScript, основанная на спецификации CommonJS, будет работать из коробки с NativeScript, но для библиотек, которые имеют зависимости DOM или любые другие зависимости API браузера, мы должны провести дополнительную работу, чтобы они могли работать в NativeScript.

Я использовал упомянутые ниже замечательные библиотеки JavaScript для создания PDF-документов в веб-проектах и ​​попытался интегрироваться с NativeScript, а затем заставил его работать, не касаясь библиотек DOM и других методов / API на основе зависимостей,

Вот результат pdf в виртуальных устройствах iOS и Android,

Позвольте волшебству начаться ...

Буфер обмена NativeScript

Плагин NativeScript для копирования и вставки данных из буфера обмена устройства и в него. Нам потребовалась оболочка буфера обмена, чтобы скопировать сгенерированные данные PDF в кодировке base64 и позволить пользователям протестировать их в браузерах устройства (Safari, Chrome ...).

npm i nativescript-clipboard

Интеграция библиотеки PDFMake

Печать PDF на стороне клиента / сервера на чистом JavaScript.

Github repo - https://github.com/bpampuch/pdfmake
Documentation - https://pdfmake.github.io/docs/getting-started/
Playground - http://pdfmake.org/playground.html

Установить pdfmake

npm i pdfmake

Начните использовать pdfmake

import * as pdfMake from 'pdfmake/build/pdfmake.js';

Используйте любое семейство и стили шрифтов, и вы должны указать в качестве параметров стили шрифта Italic, Medium, MediumItalic и Regular.

getFonts(): void { 
  this.fr.readJSON('/app/core/fonts.json').then( res => { 
    this.fonts = res["fonts"];
}, err => { 
    console.log('Error reading json: ' + JSON.stringify(err)); }); 
}

В моем случае у меня есть файлы шрифтов в кодировке base64 в файле JSON и я получаю шрифты в ловушке жизненного цикла ngOnInit.

ngOnInit(): void {        
   this.getFonts();    
}
//Example
this.fonts = { 
  "Roboto-Italic.": base64string,
  "Roboto-Medium.": base64string,
  "Roboto-MediumItalic.": base64string,
  "Roboto-Regular.": base64string
}

Давайте создадим объект определения документа с необходимым содержимым и предоставим шрифты в качестве параметра, а затем сгенерируем PDF-файл. Попробуйте использовать метод getBase64(), чтобы получить PDF-файл в формате base64.



После того, как PDF-файл был создан как данные base64, скопируйте его в буфер обмена и вставьте в браузеры устройства, чтобы увидеть волшебство.

generatePdfmake(): void {
 var docDefinition = {
  content: ['First PDF with NativeScript using pdfMake!'
  ]
 };
 pdfMake.createPdf(docDefinition, '', '',this.fonts)
  .getDataUrl((dataUrl) => {
   dialogs.alert({
    title: "PDFMake - Base64",
    message: dataUrl,
    okButtonText: "Copy to Clipboard"
   }).then(() => {
    clipboard.setText(dataUrl)
   });
 });
}

Интеграция библиотеки jsPDF

Библиотека для создания PDF-файлов на клиентском JavaScript.

Github repo - https://github.com/MrRio/jsPDF
Documentation - https://rawgit.com/MrRio/jsPDF/master/docs/
Playground - https://parall.ax/products/jspdf

Проверьте этот POC с помощью jsPDF от @ jdnichollsc



Установить jspdf

npm i jspdf

Определения типов установки для jsPDF

npm i @types/jspdf

Установить base64

npm i base-64

Начать использовать jspdf

//Add global variables for NaveScript
global['window'] = {
 'document': {
 'createElementNS': () => { return {} }
}
};
global['document'] = {
 'createElement': (str) => { return {} }
};
global['navigator'] = {};
//Imports
var base64 = require('base-64');
import * as jsPDF from 'jspdf';
global['btoa'] = (str) => {
 return base64.encode(str);
};
global['atob'] = (bytes) => {
 return base64.decode(bytes);
};
global['u8'] = {};

Давайте создадим объект документа для jsPDF, добавим необходимые определения и приступим к созданию вашего первого документа. Попробуйте создать PDF-файл как данные base64, передав ‘datauristring’ в качестве параметра методу doc. output ().

generateJspdf(): void {
  let doc = new jsPDF();
  doc.setFontSize(26);
  doc.text(40, 40, "First PDF with NativeScript using jsPDF!");
  let dataUrl = doc.output('datauristring');
if(dataUrl) {
    dialogs.alert({
    title: "jsPDF - Base64",
    message: dataUrl,
    okButtonText: "Copy to Clipboard"
  }).then(() => {
    clipboard.setText(dataUrl)
  });
  }
}

После того, как PDF-файл был создан как данные base64, скопируйте его в буфер обмена и вставьте в браузеры устройства, чтобы увидеть магию jsPDF в NativeScript.

Скачать pdf на Android

Хотите загрузить сгенерированные данные в формате PDF в формате base64? Ну вот,

  • Объявите базовый путь к каталогу загрузок Android.
  • Создайте подпапку в папке загрузок с помощью модуля файловой системы.
  • Получите только данные содержимого из pdf dataUrl с помощью метода slice.
  • Создайте во вложенной папке файл с именем certificate.pdf.
  • Расшифруйте данные base64 и запишите двоичные данные в файл, используя метод writeSync().
import { File, Folder, path } from "tns-core-modules/file-system";
declare var android: any;
public basePath = android.os.Environment
.getExternalStoragePublicDirectory(android.os.Environment.DIRECTORY_DOWNLOADS).toString();
savePdf(dataUrl) {
let encodedData = dataUrl.toString().slice(28);
let folder = Folder.fromPath(path.join(this.basePath, "NSPdf     Files"));
let tofile: File = folder.getFile('certificate.pdf');
if(tofile){
let data = android.util.Base64.decode(encodedData,  android.util.Base64.DEFAULT);
tofile.writeSync(data, err => {
     console.log("err :", err);
   });
   console.log("pdf file writed");
 }
}

Давайте посмотрим на окончательный вид компонента и файлы кода программной части,

home.component.ts

import { Component, OnInit } from "@angular/core";
import { Page } from "tns-core-modules/ui/page/page";
var dialogs = require("tns-core-modules/ui/dialogs");
import { formatDate } from '@angular/common';
import { action } from "tns-core-modules/ui/dialogs";
import * as pdfMake from 'pdfmake/build/pdfmake.js';
var clipboard = require("nativescript-clipboard");
import { FileReaderService } from "../core/fileReader.service";
global['window'] = {
'document': {
'createElementNS': () => { return {} }
}
};
global['document'] = {
'createElement': (str) => { return {} }
};
global['navigator'] = {};
var base64 = require('base-64');
import * as jsPDF from 'jspdf';
global['btoa'] = (str) => {
return base64.encode(str);
};
global['atob'] = (bytes) => {
return base64.decode(bytes);
};
global['utf8'] = {};
@Component({
selector: "Home",
moduleId: module.id,
templateUrl: "./home.component.html"
})
export class HomeComponent implements OnInit {
fonts;
images;
date;
name;
coursename;
pdfclient;
constructor(
private page: Page,
private fr: FileReaderService
) {}
ngOnInit(): void {
this.page.actionBarHidden = true;
this.date = formatDate(new Date(), 'fullDate', 'en').split(",");
this.date = this.date[1] + "," + this.date[2];
this.getDatas();
}
getDatas(): void {
this.fr.readJSON('/app/core/data.json').then(
res => {
this.fonts = res["fonts"];
this.images = res['images'];
},
err => {
console.log('Error reading json: ' + JSON.stringify(err));
})
}
selectCourse(): void {
let options = {
title: "Pick the course",
message: "",
cancelButtonText: "Cancel",
actions: ["NativeScript with Angular Pro", "NativeScript Core Pro", "NativeScript Vue and VueX"]
};
action(options).then((result) => {
if (result != 'Cancel') {
this.coursename = result;
}
});
}
selectPdfClient(): void {
let options = {
title: "Pick the pdf library",
message: "",
cancelButtonText: "Cancel",
actions: ["pdfMake", "jsPDF"]
};
action(options).then((result) => {
if (result != 'Cancel') {
this.pdfclient = result;
}
});
}
generateCert(): void {
if (this.pdfclient == 'pdfMake') {
this.generatepdfMake();
}
else {
this.generatejsPDF();
}
}
clearFields(): void {
this.name = '';
this.coursename = '';
this.pdfclient = '';
}
generatepdfMake(): void {
let that = this;
var docDefinition = {
pageOrientation: 'landscape',
content: [
{ text: 'Certificate', fontSize: '25', italics: true, alignment: 'center' },
{ text: 'of', fontSize: '25', italics: true, alignment: 'center' },
{ text: '\nTRAINING COMPLETION', fontSize: '30', alignment: 'center' },
{ text: '\n\nThis certifies that', fontSize: '18', alignment: 'center' },
{ text: '\n' + this.name, fontSize: '30', alignment: 'center' },
{ text: '\nhas successfully completed the training in', fontSize: '18', alignment: 'center' },
{ text: '\n' + this.coursename, fontSize: '30', alignment: 'center' },
{ text: '\nOn ' + this.date + '\n\n', fontSize: '18', alignment: 'center' },
{
columns: [{
width: 150,
text: ''
},
{
image: this.images['nscripting'],
width: 100
},
{},
{
image: this.images['nslogojpeg'],
width: 80
}]
},
{
"canvas": [{
"type": "line",
"x1": 400,
"y1": 0,
"x2": 0,
"y2": 0,
"lineWidth": 0.5,
"lineColor": "#000000"
}]
}
],
background: function () {
return { image: that.images['watermark'], width: 300, opacity: 0.2, absolutePosition: { x: 260, y: 150 } }\
}
}
pdfMake.createPdf(docDefinition, '', '', this.fonts).getDataUrl((dataUrl) => {
dialogs.alert({
title: "PDFMake - Base64",
message: dataUrl,
okButtonText: "Copy to Clipboard"
}).then(() => {
clipboard.setText(dataUrl);
this.clearFields();
});
});
}
generatejsPDF(): void {
var doc = new jsPDF({
orientation: 'landscape',
})
doc.setFontSize(40)
doc.setFontType("italic")
doc.text(120, 25, 'Certificate')
doc.text(145, 40, 'of')
doc.setFontSize(40)
doc.setFontType("normal")
doc.text(70, 60, 'TRAINING COMPLETION')
doc.setFontSize(25)
doc.text(110, 100, 'This certifies that')
doc.setFontSize(40)
doc.setFontType("bold")
doc.text(105, 120, this.name)
doc.setFontSize(25)
doc.setFontType("normal")
doc.text(65, 135, 'has successfully completed the training in')
doc.setFontSize(40)
doc.setFontType("bold")
doc.text(50, 160, this.coursename)
doc.setFontSize(25)
doc.setFontType("normal")
doc.text(110, 175, 'On ' + this.date)
doc.setFontSize(22)
doc.setTextColor(29, 161, 242)
doc.text(75, 190, 'NativeScripting')
doc.setLineWidth(1)
doc.line(20, 195, 180, 195)
doc.setFontSize(14)
doc.setTextColor(122, 133, 159)
doc.text(45, 205, '<Comprehensive NativeScript Courses>')
doc.addImage(this.images['nslogojpeg'], 'JPEG', 240, 160, 40, 40)
let dataUrl = doc.output('datauristring');
if (dataUrl) {
dialogs.alert({
title: "jsPDF - Base64",
message: dataUrl,
okButtonText: "Copy to Clipboard"
}).then(() => {
clipboard.setText(dataUrl);
this.clearFields();
});
}
}
//To download resulted pdf on Android
import { File, Folder, path } from "tns-core-modules/file-system";
declare var android: any;
public basePath = android.os.Environment
.getExternalStoragePublicDirectory(android.os.Environment.DIRECTORY_DOWNLOADS).toString();
savePdf(dataUrl) {
let encodedData = dataUrl.toString().slice(28);
let folder = Folder.fromPath(path.join(this.basePath, "NSPdf     Files"));
let tofile: File = folder.getFile('certificate.pdf');
if(tofile){
let data = android.util.Base64.decode(encodedData,  android.util.Base64.DEFAULT);
tofile.writeSync(data, err => {
     console.log("err :", err);
   });
   console.log("pdf file writed");
 }
}
}

home.component.html

<ScrollView class="page">
<StackLayout>
<Label class="m-10 h1" text="NativeScript PDF" marginTop="20" color="#3A53FF" fontWeight="bold"></Label>
<StackLayout class="home-menu">
<Label text="Name"></Label>
<TextField hint="Enter student name" [(ngModel)]="name" autocapitalizationType="allCharacters" returnKeyType="done"></TextField>
</StackLayout>
<StackLayout class="home-menu">
<Label text="Course Name"></Label>
<TextField hint="Select course name" [(ngModel)]="coursename" editable="false" textWrap="true" (tap)="selectCourse()">
</TextField>
</StackLayout>
<StackLayout class="home-menu">
<Label text="Choose pdf client"></Label>
<TextField hint="Select pdf library" [(ngModel)]="pdfclient" editable="false" (tap)="selectPdfClient()">
</TextField>
</StackLayout>
<Label class="m-10 h1" text="Generate Certificate" marginTop="30" class="gen-cert" (tap)="generateCert()"></Label>
</StackLayout>
</ScrollView>

Заключение:

Я могу подтвердить, что библиотеки pdfMake и jsPDF отлично работают с ограниченными необходимыми функциями на платформах NativeScript iOS и Android. Для вашего удобства я создал проект на площадке NativeScript Playground. Удачи вам в следующем поколении PDF-файлов на NativeScript!

Ваше здоровье! Удачи в NativeScripting!