Compare commits

..

22 Commits

Author SHA1 Message Date
f3ea075b72 2.0.17 2022-01-06 13:10:12 +01:00
af725a7f78 fix(core): update 2022-01-06 13:10:12 +01:00
016e0db797 2.0.16 2022-01-05 23:55:38 +01:00
4cf8b2e1f8 fix(core): update 2022-01-05 23:55:37 +01:00
67b0aa9d47 2.0.15 2022-01-05 17:20:28 +01:00
567c6eafea fix(core): update 2022-01-05 17:20:28 +01:00
ff890fb2af 2.0.14 2022-01-05 16:32:48 +01:00
a512fd64b5 fix(core): update 2022-01-05 16:32:47 +01:00
377318a62a 2.0.13 2022-01-05 14:19:40 +01:00
671c871304 fix(core): update 2022-01-05 14:19:39 +01:00
e0cc6b5655 2.0.12 2022-01-05 14:17:43 +01:00
e74b44b49c fix(core): update 2022-01-05 14:17:43 +01:00
d6f0d88d4a 2.0.11 2021-10-14 16:04:58 +02:00
9674e5b8dc fix(core): update 2021-10-14 16:04:58 +02:00
ea4cf777a9 2.0.10 2021-10-14 10:59:45 +02:00
8a308fa9e3 fix(core): update 2021-10-14 10:59:45 +02:00
56fa53b701 2.0.9 2021-04-29 15:19:15 +00:00
2a4ddd4e41 fix(core): update 2021-04-29 15:19:14 +00:00
3d8a63fddd 2.0.8 2021-04-29 09:32:13 +00:00
9d9b1d0399 fix(core): update 2021-04-29 09:32:12 +00:00
739d60d410 2.0.7 2021-04-14 11:35:06 +00:00
9003034d0d fix(core): update 2021-04-14 11:35:05 +00:00
8 changed files with 19430 additions and 4554 deletions

23831
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
{ {
"name": "@pushrocks/smartpdf", "name": "@pushrocks/smartpdf",
"version": "2.0.6", "version": "2.0.17",
"private": false, "private": false,
"description": "create pdfs on the fly", "description": "create pdfs on the fly",
"main": "dist_ts/index.js", "main": "dist_ts/index.js",
@ -12,22 +12,24 @@
"build": "(tsbuild --web)" "build": "(tsbuild --web)"
}, },
"devDependencies": { "devDependencies": {
"@gitzone/tsbuild": "^2.1.25", "@gitzone/tsbuild": "^2.1.28",
"@gitzone/tsrun": "^1.2.12", "@gitzone/tsrun": "^1.2.18",
"@gitzone/tstest": "^1.0.52", "@gitzone/tstest": "^1.0.60",
"@pushrocks/tapbundle": "^3.2.14", "@pushrocks/tapbundle": "^3.2.15",
"@types/node": "^14.14.37", "@types/node": "^17.0.8",
"tslint": "^6.1.3", "tslint": "^6.1.3",
"tslint-config-prettier": "^1.18.0" "tslint-config-prettier": "^1.18.0"
}, },
"dependencies": { "dependencies": {
"@pushrocks/smartfile": "^8.0.9", "@pushrocks/smartfile": "^9.0.5",
"@pushrocks/smartnetwork": "^2.0.4", "@pushrocks/smartnetwork": "^2.0.10",
"@pushrocks/smartpromise": "^3.1.3", "@pushrocks/smartpromise": "^3.1.6",
"@pushrocks/smartpuppeteer": "^1.0.21", "@pushrocks/smartpuppeteer": "^1.0.36",
"@pushrocks/smartunique": "^3.0.3", "@pushrocks/smartunique": "^3.0.3",
"@types/express": "^4.17.11", "@types/express": "^4.17.13",
"express": "^4.17.1" "express": "^4.17.2",
"pdf-merger-js": "^3.2.1",
"pdf2json": "^2.0.0"
}, },
"files": [ "files": [
"ts/**/*", "ts/**/*",

View File

@ -29,7 +29,6 @@ Platform support | [![Supports Windows 10](https://badgen.net/badge/supports%20W
We are always happy for code contributions. If you are not the code contributing type that is ok. Still, maintaining Open Source repositories takes considerable time and thought. If you like the quality of what we do and our modules are useful to you we would appreciate a little monthly contribution: You can [contribute one time](https://lossless.link/contribute-onetime) or [contribute monthly](https://lossless.link/contribute). :) We are always happy for code contributions. If you are not the code contributing type that is ok. Still, maintaining Open Source repositories takes considerable time and thought. If you like the quality of what we do and our modules are useful to you we would appreciate a little monthly contribution: You can [contribute one time](https://lossless.link/contribute-onetime) or [contribute monthly](https://lossless.link/contribute). :)
## Contribution ## Contribution
We are always happy for code contributions. If you are not the code contributing type that is ok. Still, maintaining Open Source repositories takes considerable time and thought. If you like the quality of what we do and our modules are useful to you we would appreciate a little monthly contribution: You can [contribute one time](https://lossless.link/contribute-onetime) or [contribute monthly](https://lossless.link/contribute). :) We are always happy for code contributions. If you are not the code contributing type that is ok. Still, maintaining Open Source repositories takes considerable time and thought. If you like the quality of what we do and our modules are useful to you we would appreciate a little monthly contribution: You can [contribute one time](https://lossless.link/contribute-onetime) or [contribute monthly](https://lossless.link/contribute). :)

View File

@ -13,7 +13,11 @@ tap.test('should start the instance', async () => {
}); });
tap.test('should create a pdf from html string', async () => { tap.test('should create a pdf from html string', async () => {
await testSmartPdf.getPdfResultForHtmlString('hi'); await testSmartPdf.getA4PdfResultForHtmlString('hi');
});
tap.test('should create a pdf from html string', async () => {
await testSmartPdf.getA4PdfResultForHtmlString('hi');
}); });
tap.test('should create a pdf from website as A4', async () => { tap.test('should create a pdf from website as A4', async () => {
@ -25,18 +29,28 @@ tap.test('should create a pdf from website as single page PDF', async () => {
}); });
tap.test('should create a valid PDFResult', async () => { tap.test('should create a valid PDFResult', async () => {
const pdfResult = await testSmartPdf.getFullWebsiteAsSinglePdf( const writePDfToDisk = async (urlArg: string, fileName: string) => {
'https://maintainedby.lossless.com' const pdfResult = await testSmartPdf.getFullWebsiteAsSinglePdf(urlArg);
); expect(pdfResult.buffer).to.be.instanceOf(Buffer);
expect(pdfResult.buffer).to.be.instanceOf(Buffer); const fs = await import('fs');
const fs = await import('fs');
if (!fs.existsSync('.nogit/')) { if (!fs.existsSync('.nogit/')) {
fs.mkdirSync('.nogit/'); fs.mkdirSync('.nogit/');
} }
fs.writeFileSync('.nogit/sample.pdf', pdfResult.buffer); fs.writeFileSync(`.nogit/${fileName}`, pdfResult.buffer);
};
await writePDfToDisk('https://maintainedby.lossless.com/', '1.pdf')
await writePDfToDisk('https://rendertron.lossless.one/render/https://lossless.com', '2.pdf')
}); });
tap.test('should combine pdfs', async () => {
const fs = await import('fs');
const buffer1 = fs.readFileSync('.nogit/1.pdf');
const buffer2 = fs.readFileSync('.nogit/2.pdf');
fs.writeFileSync(`.nogit/combined.pdf`, await testSmartPdf.mergePdfBuffers([buffer1, buffer2]));
})
tap.test('should be able to close properly', async () => { tap.test('should be able to close properly', async () => {
await testSmartPdf.stop(); await testSmartPdf.stop();
}); });

View File

@ -1,5 +1,8 @@
export interface IPdfResult { export interface IPdfResult {
name: string; name: string;
id: string; id: string;
metadata: {
textExtraction: string;
};
buffer: Buffer; buffer: Buffer;
} }

View File

@ -1,8 +1,11 @@
import * as plugins from './smartpdf.plugins'; import * as plugins from './smartpdf.plugins';
export class PdfCandidate { export class PdfCandidate {
pdfId = plugins.smartunique.shortId(); public htmlString: string;
doneDeferred = plugins.smartpromise.defer(); public pdfId = plugins.smartunique.shortId();
public doneDeferred = plugins.smartpromise.defer();
constructor(public htmlString) {} constructor(htmlStringArg: string) {
this.htmlString = htmlStringArg;
}
} }

View File

@ -3,7 +3,7 @@ import * as paths from './smartpdf.paths';
import { Server } from 'http'; import { Server } from 'http';
import { PdfCandidate } from './smartpdf.classes.pdfcandidate'; import { PdfCandidate } from './smartpdf.classes.pdfcandidate';
declare const document; declare const document: any;
import * as interfaces from './interfaces'; import * as interfaces from './interfaces';
@ -19,7 +19,7 @@ export class SmartPdf {
this._readyDeferred = new plugins.smartpromise.Deferred(); this._readyDeferred = new plugins.smartpromise.Deferred();
} }
async start(headlessBrowserArg?) { async start(headlessBrowserArg?: plugins.smartpuppeteer.puppeteer.Browser) {
// lets set the external browser in case one is provided // lets set the external browser in case one is provided
this.headlessBrowser = headlessBrowserArg; this.headlessBrowser = headlessBrowserArg;
// setup puppeteer // setup puppeteer
@ -63,11 +63,15 @@ export class SmartPdf {
/** /**
* returns a pdf for a given html string; * returns a pdf for a given html string;
*/ */
async getPdfResultForHtmlString(htmlStringArg: string): Promise<interfaces.IPdfResult> { async getA4PdfResultForHtmlString(htmlStringArg: string): Promise<interfaces.IPdfResult> {
await this._readyDeferred.promise; await this._readyDeferred.promise;
const pdfCandidate = new PdfCandidate(htmlStringArg); const pdfCandidate = new PdfCandidate(htmlStringArg);
this._candidates[pdfCandidate.pdfId] = pdfCandidate; this._candidates[pdfCandidate.pdfId] = pdfCandidate;
const page = await this.headlessBrowser.newPage(); const page = await this.headlessBrowser.newPage();
await page.setViewport({
width: 794,
height: 1122,
});
const response = await page.goto(`http://localhost:3210/${pdfCandidate.pdfId}`, { const response = await page.goto(`http://localhost:3210/${pdfCandidate.pdfId}`, {
waitUntil: 'networkidle2', waitUntil: 'networkidle2',
}); });
@ -80,10 +84,10 @@ export class SmartPdf {
} }
const pdfBuffer = await page.pdf({ const pdfBuffer = await page.pdf({
format: 'A4', width: 794,
height: 1122,
printBackground: true, printBackground: true,
displayHeaderFooter: false, displayHeaderFooter: false,
preferCSSPageSize: true,
}); });
await page.close(); await page.close();
delete this._candidates[pdfCandidate.pdfId]; delete this._candidates[pdfCandidate.pdfId];
@ -92,12 +96,19 @@ export class SmartPdf {
return { return {
id: pdfCandidate.pdfId, id: pdfCandidate.pdfId,
name: `${pdfCandidate.pdfId}.js`, name: `${pdfCandidate.pdfId}.js`,
metadata: {
textExtraction: await this.extractTextFromPdfBuffer(pdfBuffer),
},
buffer: pdfBuffer, buffer: pdfBuffer,
}; };
} }
async getPdfResultForWebsite(websiteUrl: string): Promise<interfaces.IPdfResult> { async getPdfResultForWebsite(websiteUrl: string): Promise<interfaces.IPdfResult> {
const page = await this.headlessBrowser.newPage(); const page = await this.headlessBrowser.newPage();
await page.setViewport({
width: 1980,
height: 1200,
});
await page.emulateMediaType('screen'); await page.emulateMediaType('screen');
const response = await page.goto(websiteUrl, { waitUntil: 'networkidle2' }); const response = await page.goto(websiteUrl, { waitUntil: 'networkidle2' });
const pdfId = plugins.smartunique.shortId(); const pdfId = plugins.smartunique.shortId();
@ -108,45 +119,79 @@ export class SmartPdf {
}; };
}); });
const pdfBuffer = await page.pdf({ const pdfBuffer = await page.pdf({
format: 'A4', height: documentHeight,
height: documentWidth,
width: documentWidth, width: documentWidth,
printBackground: true, printBackground: true,
displayHeaderFooter: false, displayHeaderFooter: false,
preferCSSPageSize: true,
}); });
await page.close(); await page.close();
return { return {
id: pdfId, id: pdfId,
name: `${pdfId}.js`, name: `${pdfId}.js`,
metadata: {
textExtraction: await this.extractTextFromPdfBuffer(pdfBuffer),
},
buffer: pdfBuffer, buffer: pdfBuffer,
}; };
} }
async getFullWebsiteAsSinglePdf(websiteUrl: string) { async getFullWebsiteAsSinglePdf(websiteUrl: string): Promise<interfaces.IPdfResult> {
const page = await this.headlessBrowser.newPage(); const page = await this.headlessBrowser.newPage();
await page.setViewport({
width: 1920,
height: 1200,
});
page.emulateMediaType('screen'); page.emulateMediaType('screen');
const response = await page.goto(websiteUrl, { waitUntil: 'networkidle2' }); const response = await page.goto(websiteUrl, { waitUntil: 'networkidle2' });
const pdfId = plugins.smartunique.shortId(); const pdfId = plugins.smartunique.shortId();
const { documentHeight, documentWidth } = await page.evaluate(() => { const { documentHeight, documentWidth } = await page.evaluate(() => {
return { return {
documentHeight: document.height, documentHeight: document.body.scrollHeight,
documentWidth: document.width, documentWidth: document.body.clientWidth,
}; };
}); });
const pdfBuffer = await page.pdf({ const pdfBuffer = await page.pdf({
format: 'A4', height: documentHeight,
height: documentWidth, width: 1920,
width: documentWidth,
printBackground: true, printBackground: true,
displayHeaderFooter: false, displayHeaderFooter: false,
preferCSSPageSize: true, scale: 1
}); });
await page.close(); await page.close();
return { return {
id: pdfId, id: pdfId,
name: `${pdfId}.js`, name: `${pdfId}.js`,
metadata: {
textExtraction: await this.extractTextFromPdfBuffer(pdfBuffer),
},
buffer: pdfBuffer, buffer: pdfBuffer,
}; };
} }
public async mergePdfBuffers(pdfBuffers: Buffer[]): Promise<Buffer> {
const merger = new plugins.pdfMerger();
for (const buffer of pdfBuffers) {
merger.add(buffer);
}
return merger.saveAsBuffer();
}
public async extractTextFromPdfBuffer(pdfBufferArg: Buffer): Promise<string> {
const deferred = plugins.smartpromise.defer<string>();
const pdfParser: any = new plugins.pdf2json();
pdfParser.on('pdfParser_dataReady', (pdfData: any) => {
let finalText = ''
for (const page of pdfData.Pages) {
for(const text of page.Texts) {
for (const letter of text.R) {
finalText = finalText + letter.T;
}
};
}
deferred.resolve(finalText);
});
pdfParser.parseBuffer(pdfBufferArg);
return deferred.promise;
}
} }

View File

@ -14,6 +14,9 @@ import * as smartunique from '@pushrocks/smartunique';
export { smartfile, smartpromise, smartpuppeteer, smartunique, smartnetwork }; export { smartfile, smartpromise, smartpuppeteer, smartunique, smartnetwork };
// thirdparty // thirdparty
import pdfMerger from 'pdf-merger-js';
// @ts-ignore
import pdf2json from 'pdf2json';
import express from 'express'; import express from 'express';
export { express }; export { pdfMerger, pdf2json, express };