diff --git a/.gitignore b/.gitignore index 6285d17..3ff0689 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ node_modules package-lock.json -/build \ No newline at end of file +/build +test_files \ No newline at end of file diff --git a/README.md b/README.md index 156d469..ad92975 100644 --- a/README.md +++ b/README.md @@ -44,6 +44,7 @@ - [Possible values in image to pdf options](#possible-values-in-image-to-pdf-options) - [Merge the converted images with single object](#merge-the-converted-images-with-single-object) - [Get buffer of the resultant image inserted pdf](#get-buffer-of-the-resultant-image-inserted-pdf) + - [Rules for specifying the range array](#rules-for-specifying-range) ## Description @@ -100,11 +101,9 @@ import { PdfSplitter } from 'pdf-ops'; const splitter = new PdfSplitter(); // Split the desired pdf into desired parts - await splitter.splitWithRange('test_files/pdf2.pdf', [ - [0, 1], - [1, 3], - [3, 6], - ]); + // Reverse selection will separate each page within the selection + // read the rules for specifying range + await splitter.splitWithRange('test_files/pdf2.pdf', [1, [2, 3], [4, 6], ['end', 3]]); // Save the folder carrying all the pdfs // The first parameter is the path of the directory in which it will get stored @@ -134,8 +133,8 @@ import { PdfSplitter } from 'pdf-ops'; // Splitting pdf1 into two pdfs await splitter.splitWithRange('test_files/pdf1.pdf', [ - [0, 3], - [3, 6], + [1, 3], + [4, 6], ]); // Splitting pdf2 into single paged pdfs @@ -146,11 +145,7 @@ import { PdfSplitter } from 'pdf-ops'; await splitter.save('./test_files', 'split1'); // Splitting pdf4 into 3 parts and putting it into same object - await splitter.splitWithRange('test_files/pdf4.pdf', [ - [0, 2], - [2, 4], - [4, 6], - ]); + await splitter.split('test_files/pdf4.pdf'); // Saving the pdfs in the folder named split2 await splitter.save('./test_files', 'split2'); @@ -159,14 +154,7 @@ import { PdfSplitter } from 'pdf-ops'; await splitter.clearDoc(); // Splitting pdf3 in reverse order - await splitter.splitWithRange('test_files/pdf3.pdf', [ - [5, 6], - [4, 5], - [3, 4], - [2, 3], - [1, 2], - [0, 1], - ]); + await splitter.splitWithRange('test_files/pdf3.pdf', [['end', 'start']]); // Saving the pdfs in the folder named split3 await splitter.save('./test_files', 'split3'); @@ -183,9 +171,9 @@ import { PdfMerger, PdfSplitter } from 'pdf-ops'; (async () => { const splitter = new PdfSplitter(); - await splitter.splitWithRange('test_files/pdf1.pdf', [[0, 3]]); + await splitter.splitWithRange('test_files/pdf1.pdf', [[1, 3]]); await splitter.split('test_files/pdf2.pdf'); - await splitter.splitWithRange('test_files/pdf1.pdf', [[3, 6]]); + await splitter.splitWithRange('test_files/pdf1.pdf', [[4, 6]]); // To merge the pdfs in the splitter // Make an object of PdfMerger @@ -213,9 +201,9 @@ import { PdfSplitter } from 'pdf-ops'; const splitter = new PdfSplitter(); // Split the desired pdfs - await splitter.splitWithRange('test_files/pdf1.pdf', [[0, 3]]); + await splitter.splitWithRange('test_files/pdf1.pdf', [[1, 3]]); await splitter.split('test_files/pdf2.pdf'); - await splitter.splitWithRange('test_files/pdf1.pdf', [[3, 6]]); + await splitter.splitWithRange('test_files/pdf1.pdf', [[4, 6]]); // Get pdf buffer const bufferList = await splitter.getPdfBuffer(); @@ -255,27 +243,23 @@ import { PdfMerger } from 'pdf-ops'; const merger = new PdfMerger(); // Specify the filepath with the range - // The range works just like array indexing - // [start, end] start page is included and end page is excluded + // read the rules to specify range await merger.mergeWithRange([ { filepath: 'test_files/pdf4.pdf', - range: [ - [0, 1], - [5, 6], - ], + range: [1, 5], }, { filepath: 'test_files/pdf1.pdf', - range: [[0, 2]], + range: [1, 2], }, { filepath: 'test_files/pdf2.pdf', - range: [[2, 4]], + range: [3, 4], }, { filepath: 'test_files/pdf3.pdf', - range: [[4, 6]], + range: [5, 6], }, ]); @@ -286,6 +270,8 @@ import { PdfMerger } from 'pdf-ops'; In this example [pdf1](/example-files/pdf1.pdf), [pdf2](/example-files/pdf2.pdf), [pdf3](/example-files/pdf3.pdf), and [pdf4](/example-files/pdf4.pdf) will generate [mergedWithRange.pdf](/example-files/mergedWithRange.pdf) +[rules to specify range](#rules-for-specifying-range) + #### **Merge multiple PDFs multiple times with a single object** - You can keep on adding more and more pdfs in the same object and save whenever you want. @@ -307,11 +293,11 @@ import { PdfMerger } from 'pdf-ops'; await merger.mergeWithRange([ { filepath: 'test_files/pdf1.pdf', - range: [[0, 2]], + range: [1, 2], }, { filepath: 'test_files/pdf2.pdf', - range: [[4, 6]], + range: [5, 6], }, ]); @@ -325,7 +311,7 @@ import { PdfMerger } from 'pdf-ops'; await merger.mergeWithRange([ { filepath: 'test_files/pdf3.pdf', - range: [[1, 4]], + range: [[2, 4]], }, ]); @@ -339,31 +325,19 @@ import { PdfMerger } from 'pdf-ops'; await merger.mergeWithRange([ { filepath: 'test_files/pdf1.pdf', - range: [ - [0, 1], - [5, 6], - ], + range: [1, 6], }, { filepath: 'test_files/pdf2.pdf', - range: [ - [0, 1], - [5, 6], - ], + range: [1, 6], }, { filepath: 'test_files/pdf3.pdf', - range: [ - [0, 1], - [5, 6], - ], + range: [1, 6], }, { filepath: 'test_files/pdf4.pdf', - range: [ - [0, 1], - [5, 6], - ], + range: [1, 6], }, ]); // saving it as merge3.pdf @@ -386,8 +360,8 @@ import { PdfMerger } from 'pdf-ops'; // Merge the desired pdfs await merger.mergeWithRange([ - { filepath: 'test_files/pdf1.pdf', range: [[0, 2]] }, - { filepath: 'test_files/pdf2.pdf', range: [[4, 6]] }, + { filepath: 'test_files/pdf1.pdf', range: [1, 2] }, + { filepath: 'test_files/pdf2.pdf', range: [5, 6] }, ]); await merger.merge(['test_files/pdf4.pdf']); @@ -436,30 +410,19 @@ import { PdfRotator } from 'pdf-ops'; { // give the filepath inside the file field file: 'test_files/pdf1.pdf', - // range is a list of range of pages - // the range is specified as [start, end] - // start page is included and end page is excluded - range: [ - [0, 2], - [4, 6], - ], + // range is a list to specify the pages of the pdf (read the rules for specifying this list) + range: [1, 2, 5, 6], // degree should be a multiple of 90 degree: 90, }, { file: 'test_files/pdf2.pdf', - range: [ - [0, 1], - [4, 5], - ], + range: [1, 5], degree: -90, }, { file: 'test_files/pdf3.pdf', - range: [ - [4, 6], - [0, 2], - ], + range: [5, 6, 1, 2], degree: 180, }, ]); @@ -495,7 +458,7 @@ import { PdfRotator } from 'pdf-ops'; await rotator.rotateWithRange([ { file: 'test_files/pdf3.pdf', - range: [[1, 5]], + range: [[2, 5]], degree: 180, }, ]); @@ -507,10 +470,7 @@ import { PdfRotator } from 'pdf-ops'; await rotator.rotateWithRange([ { file: 'test_files/pdf2.pdf', - range: [ - [0, 1], - [5, 6], - ], + range: [1, 6], degree: -90, }, ]); @@ -547,7 +507,7 @@ import { PdfRotator } from 'pdf-ops'; await rotator.rotateWithRange([ { file: 'test_files/pdf3.pdf', - range: [[1, 5]], + range: [[2, 5]], degree: 180, }, ]); @@ -684,7 +644,7 @@ import { PdfResizer } from 'pdf-ops'; await resizer.resizeWithRange([ { file: 'test_files/pdf1.pdf', - range: [[2, 5]], + range: [[3, 5]], // refer to the resize options for possible allowed values options: { size: 'Letter', @@ -693,7 +653,7 @@ import { PdfResizer } from 'pdf-ops'; }, { file: 'test_files/pdf4.pdf', - range: [[1, 3]], + range: [[2, 3]], options: { size: 'A5', mode: 'crop', @@ -736,10 +696,7 @@ import { PdfResizer } from 'pdf-ops'; await resizer.resizeWithRange([ { file: 'test_files/pdf4.pdf', - range: [ - [0, 2], - [4, 5], - ], + range: [1, 2, 5], options: { size: 'A5' }, }, ]); @@ -764,7 +721,7 @@ import { PdfResizer } from 'pdf-ops'; await resizer.resizeWithRange([ { file: 'test_files/pdf2.pdf', - range: [[1, 3]], + range: [2, 3], }, ]); @@ -789,7 +746,7 @@ import { PdfResizer } from 'pdf-ops'; await resizer.resizeWithRange([ { file: 'test_files/pdf4.pdf', - range: [[0, 2]], + range: [1, 2], options: { size: 'A5' }, }, ]); @@ -835,18 +792,18 @@ import { PdfMarginManipulator } from 'pdf-ops'; await marginManipulator.addMarginWithRange([ { file: 'test_files/pdf1.pdf', - range: [[0, 2]], + range: [1, 2], // [top, right, bottom, left] margin: [10, 10, 10, 10], }, { file: 'test_files/pdf2.pdf', - range: [[2, 4]], + range: [3, 4], margin: [20, 20, 20, 20], }, { file: 'test_files/pdf3.pdf', - range: [[4, 6]], + range: [5, 6], margin: [30, 30, 30, 30], }, ]); @@ -883,7 +840,7 @@ import { PdfMarginManipulator } from 'pdf-ops'; await marginManipulator.addMarginWithRange([ { file: 'test_files/pdf2.pdf', - range: [[1, 4]], + range: [[2, 4]], margin: [10, 0, 10, 10], }, ]); @@ -904,10 +861,7 @@ import { PdfMarginManipulator } from 'pdf-ops'; await marginManipulator.addMarginWithRange([ { file: 'test_files/pdf4.pdf', - range: [ - [0, 1], - [4, 6], - ], + range: [1, 5, 6], margin: [10, 10, 10, 0], }, ]); @@ -933,7 +887,7 @@ import { PdfMarginManipulator } from 'pdf-ops'; await marginManipulator.addMarginWithRange([ { file: 'test_files/pdf2.pdf', - range: [[1, 4]], + range: [[2, 4]], margin: [10, 0, 10, 10], }, ]); @@ -1013,15 +967,12 @@ import { PdfToImageConverter } from 'pdf-ops'; await converter.renderToImageWithRange([ { file: 'test_files/pdf2.pdf', - range: [ - [0, 2], - [5, 6], - ], + range: [1, 2, 6], options: { size: 'A4' }, }, { file: 'test_files/pdf3.pdf', - range: [[2, 4]], + range: [3, 4], }, ]); @@ -1055,10 +1006,7 @@ import { PdfToImageConverter } from 'pdf-ops'; await converter.renderToImageWithRange([ { file: 'test_files/pdf2.pdf', - range: [ - [1, 2], - [4, 6], - ], + range: [2, 5, 6], }, ]); @@ -1075,7 +1023,7 @@ import { PdfToImageConverter } from 'pdf-ops'; await converter.clearDoc(); // render some pages of pdf4 - await converter.renderToImageWithRange([{ file: 'test_files/pdf4.pdf', range: [[1, 5]] }]); + await converter.renderToImageWithRange([{ file: 'test_files/pdf4.pdf', range: [[2, 5]] }]); // save inside images3 folder await converter.save('./test_files', 'images3'); @@ -1098,10 +1046,7 @@ import { PdfToImageConverter } from 'pdf-ops'; await converter.renderToImageWithRange([ { file: 'test_files/pdf2.pdf', - range: [ - [1, 2], - [4, 6], - ], + range: [2, 5, 6], }, ]); @@ -1228,9 +1173,28 @@ import { ImageToPdfConverter } from 'pdf-ops'; }, ); - // save the resultant mergeed pdf to desired locations const buffer = await converter.getPdfBuffer(); console.log(buffer); })(); ``` + +### Rules for specifying range + +- Single Page Selection: To select a single page, specify the page number as an integer. For example: [1] selects page 1. + +- Multiple Page Selection: To select multiple non-consecutive pages, list the page numbers as separate integers within square brackets. For example: [1, 2, 3] selects pages 1, 2, and 3. + +- Page Range Selection: To select a range of consecutive pages, specify the starting and ending page numbers as a two-element array within square brackets. For example: [5, 10] selects pages 5 to 10, inclusive. + +- Mixed Page Selection: To select a combination of single pages, page ranges, and the start or end of the PDF, provide them as separate elements in the array. For example: [1, 2, 3, [6, 10], [7, "end"]] selects pages 1, 2, 3, 6 to 10, page 7 to the end of the PDF. + + - To select from a specific page to the end of the PDF, use the string "end" as the second element in the array. For example: [7, "end"] selects page 7 to the end of the PDF. + + - To select from the start of the PDF to a specific page, use the string "start" as the first element in the array. For example: ["start", 3] selects from the start of the PDF to page 3. + +- Reverse Page Selection: To select pages in reverse order, specify the page numbers in reverse order within a two-element array. + + - To select a range of pages in reverse order, provide the ending page number as the first element and the starting page number as the second element in the array. For example: [10, 6] selects pages 10 to 6 in reverse order. + + - To select from a specific page to the beginning of the PDF in reverse, use the "start" keyword as the second element and the page number as the first element in the array. For example: [4, "start"] selects page 4 to the beginning of the PDF in reverse order. diff --git a/package.json b/package.json index 1bb677a..84fcecc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pdf-ops", - "version": "1.5.2", + "version": "1.6.0", "description": "Do multile pdf operations with one package", "main": "build/index.js", "scripts": { diff --git a/src/ImageToPdfConverter.ts b/src/ImageToPdfConverter.ts deleted file mode 100644 index 765d971..0000000 --- a/src/ImageToPdfConverter.ts +++ /dev/null @@ -1,103 +0,0 @@ -import { PDFDocument } from 'pdf-lib'; -import fs from 'fs'; -import { extendPdf } from './pdf-micro-tools/extendPdf'; -import { imageToPdf } from './pdf-micro-tools/imageToPdf'; -import { createOptions } from './types'; -import { resizePdf } from './pdf-micro-tools/resizePdf'; -import { marginPdf } from './pdf-micro-tools/marginPdf'; - -export default class ImageToPdfConverter { - private pdfDoc: PDFDocument | undefined; - - constructor() { - this.clearDoc(); - } - - // To clear and reinitialize the pdfDoc - async clearDoc() { - this.pdfDoc = await PDFDocument.create(); - } - - // getter for pdfDoc - getDoc() { - return this.pdfDoc; - } - - // This ensure that pdfDoc is not undefined - private async ensureDoc() { - if (!this.pdfDoc) { - await this.clearDoc(); - } - } - - // To read the pdf file from the file system and convert it to a PDFDocument object - private async readDoc(file: string): Promise { - try { - const fileBuffer = await fs.promises.readFile(file); - return fileBuffer; - } catch (err) { - throw new Error(`Error reading file ${file}: ${err}`); - } - } - - // To create pdf from the given array of objects - async createPdf(files: string[] | Uint8Array[], options?: createOptions) { - try { - options = { - size: 'do-not-change', - orientation: 'portrait', - mode: 'shrink-to-fit', - position: 'center', - opacity: 1, - margin: [0, 0, 0, 0], - ...options, - }; - - const imgs: Uint8Array[] = []; - for (const file of files) { - if (typeof file === 'string') { - imgs.push(await this.readDoc(file)); - } else { - imgs.push(file); - } - } - - let pdf = await imageToPdf(imgs); - pdf = await resizePdf(pdf, options); - if (options.margin) { - pdf = await marginPdf(pdf, options.margin); - } - - await this.ensureDoc(); - if (this.pdfDoc) { - this.pdfDoc = await extendPdf(this.pdfDoc, [pdf]); - } - } catch (err) { - throw new Error(`Error converting to Pdf: ${err}`); - } - } - - // To export the generated file as a pdf into the file system - async save(filepath: string) { - if (this.pdfDoc) { - try { - const pdfBuffer = await this.pdfDoc.save(); - await fs.promises.writeFile(filepath, pdfBuffer); - } catch (err) { - throw new Error(`Error saving PDF to ${filepath}: ${err}`); - } - } - } - - // To return a buffer of the resultant pdf file - async getPdfBuffer() { - if (this.pdfDoc) { - try { - const pdfBuffer = await this.pdfDoc.save(); - return pdfBuffer; - } catch (err) { - throw new Error(`Error generating Buffer: ${err}`); - } - } - } -} diff --git a/src/PdfManipulator.ts b/src/PdfManipulator.ts new file mode 100644 index 0000000..c2c1000 --- /dev/null +++ b/src/PdfManipulator.ts @@ -0,0 +1,103 @@ +import { PDFDocument } from 'pdf-lib'; +import fs from 'fs'; +import { range } from './types'; + +export default class PdfManipulator { + protected pdfDoc: PDFDocument | undefined; + + constructor() { + this.clearDoc(); + } + + // To clear and reinitialize the pdfDoc + async clearDoc() { + this.pdfDoc = await PDFDocument.create(); + } + + // getter for pdfDoc + getDoc() { + return this.pdfDoc; + } + + // This ensure that pdfDoc is not undefined + protected async ensureDoc() { + if (!this.pdfDoc) { + await this.clearDoc(); + } + } + + protected processOrder(order: range, pageCount: number) { + const finalOrder: [number, number][] = []; + for (const pageRange of order) { + // if a range is provided + if (typeof pageRange === 'object') { + // change the end and start to 0 or n + if (pageRange[0] === 'end') { + pageRange[0] = pageCount; + } else if (pageRange[0] === 'start') { + pageRange[0] = 1; + } + if (pageRange[1] === 'end') { + pageRange[1] = pageCount; + } else if (pageRange[1] === 'start') { + pageRange[1] = 1; + } + + // if the range of order is in reverse reverese the pages + if (pageRange[0] > pageRange[1]) { + for (let i = pageRange[0]; i >= pageRange[1]; i--) { + finalOrder.push([i - 1, i]); + } + } + // if the range of the page is in correct order + else if (pageRange[0] < pageRange[1]) { + finalOrder.push([pageRange[0] - 1, pageRange[1]]); + } + // if the first and last of the order are same then consider it as a single digit + else { + finalOrder.push([pageRange[0], pageRange[0] + 1]); + } + } + // if a single number is provided + else if (typeof pageRange === 'number') { + finalOrder.push([pageRange - 1, pageRange]); + } + } + return finalOrder; + } + + // To read the pdf file from the file system and convert it to a PDFDocument object + protected async readDoc(filepath: string): Promise { + try { + const fileBuffer = await fs.promises.readFile(filepath); + const file = await PDFDocument.load(fileBuffer); + return file; + } catch (err) { + throw new Error(`Error reading file ${filepath}: ${err}`); + } + } + + // To export the generated file as a pdf into the file system + async save(filepath: string) { + if (this.pdfDoc) { + try { + const pdfBuffer = await this.pdfDoc.save(); + await fs.promises.writeFile(filepath, pdfBuffer); + } catch (err) { + throw new Error(`Error saving PDF to ${filepath}: ${err}`); + } + } + } + + // To return a buffer of the resultant pdf file + async getPdfBuffer() { + if (this.pdfDoc) { + try { + const pdfBuffer = await this.pdfDoc.save(); + return pdfBuffer; + } catch (err) { + throw new Error(`Error generating Buffer: ${err}`); + } + } + } +} diff --git a/src/PdfMarginManipulator.ts b/src/PdfMarginManipulator.ts deleted file mode 100644 index 8dc20f1..0000000 --- a/src/PdfMarginManipulator.ts +++ /dev/null @@ -1,114 +0,0 @@ -import fs from 'fs'; -import { PDFDocument } from 'pdf-lib'; -import { extendPdf } from './pdf-micro-tools/extendPdf'; -import { marginPdf } from './pdf-micro-tools/marginPdf'; -import { splitPdf } from './pdf-micro-tools/splitPdf'; - -export default class PdfMarginManipulator { - private pdfDoc: PDFDocument | undefined; - - constructor() { - this.clearDoc(); - } - - // To clear and reinitialize the pdfDoc - async clearDoc() { - this.pdfDoc = await PDFDocument.create(); - } - - // getter for pdfDoc - getDoc() { - return this.pdfDoc; - } - - // This ensure that pdfDoc is not undefined - private async ensureDoc() { - if (!this.pdfDoc) { - await this.clearDoc(); - } - } - - // To read the pdf file from the file system and convert it to a PDFDocument object - private async readDoc(filepath: string): Promise { - try { - const fileBuffer = await fs.promises.readFile(filepath); - const file = await PDFDocument.load(fileBuffer); - return file; - } catch (err) { - throw new Error(`Error reading file ${filepath}: ${err}`); - } - } - - // To add margin to the pdf - async addMargin(file: string | PDFDocument, margin: [number, number, number, number]) { - let pdf; - if (typeof file === 'string') { - pdf = await this.readDoc(file); - } else { - pdf = file; - } - - pdf = await marginPdf(pdf, margin); - - await this.ensureDoc(); - if (this.pdfDoc) { - try { - this.pdfDoc = await extendPdf(this.pdfDoc, [pdf]); - } catch (err) { - throw new Error(`Error mergin PDFs: ${err}`); - } - } - } - - // To add the margin to the pdf with specified range - async addMarginWithRange( - orderList: { - file: string | PDFDocument; - range: [number, number][]; - margin: [number, number, number, number]; - }[], - ) { - try { - for (const part of orderList) { - let pdf; - if (typeof part.file === 'string') { - pdf = await this.readDoc(part.file); - } else { - pdf = part.file; - } - - const splitted = await splitPdf(pdf, part.range); - - for (const doc of splitted) { - await this.addMargin(doc, part.margin); - } - } - } catch (err) { - throw new Error(`Error adding margin to the PDF: ${err}`); - } - } - - // To export the generated file as a pdf into the file system - async save(filepath: string) { - if (this.pdfDoc) { - try { - const pdfBuffer = await this.pdfDoc.save(); - await fs.promises.writeFile(filepath, pdfBuffer); - } catch (err) { - throw new Error(`Error saving PDF to ${filepath}: ${err}`); - } - } - } - - // To return a buffer of the resultant pdf file - async getPdfBuffer() { - if (this.pdfDoc) { - try { - const pdfBuffer = await this.pdfDoc.save(); - return pdfBuffer; - } catch (err) { - throw new Error(`Error generating Buffer: ${err}`); - } - } - } -} diff --git a/src/PdfMerger.ts b/src/PdfMerger.ts deleted file mode 100644 index 405f3da..0000000 --- a/src/PdfMerger.ts +++ /dev/null @@ -1,105 +0,0 @@ -import fs from 'fs'; -import { PDFDocument } from 'pdf-lib'; -import { extendPdf } from './pdf-micro-tools/extendPdf'; -import { splitPdf } from './pdf-micro-tools/splitPdf'; - -export default class PdfMerger { - private pdfDoc: PDFDocument | undefined; - - constructor() { - this.clearDoc(); - } - - // To clear and reinitialize the pdfDoc - async clearDoc() { - this.pdfDoc = await PDFDocument.create(); - } - - // getter for pdfDoc - getDoc() { - return this.pdfDoc; - } - - // This ensure that pdfDoc is not undefined - private async ensureDoc() { - if (!this.pdfDoc) { - await this.clearDoc(); - } - } - - // To read the pdf file from the file system and convert it to a PDFDocument object - private async readDoc(filepath: string): Promise { - try { - const fileBuffer = await fs.promises.readFile(filepath); - const file = await PDFDocument.load(fileBuffer); - return file; - } catch (err) { - throw new Error(`Error reading file ${filepath}: ${err}`); - } - } - - // To merge all the pages of all the pdfs into a single pdf - async merge(files: string[] | PDFDocument[]) { - const pdfFileList: PDFDocument[] = []; - for (const file of files) { - if (typeof file === 'string') { - pdfFileList.push(await this.readDoc(file)); - } else { - pdfFileList.push(file); - } - } - await this.ensureDoc(); - if (this.pdfDoc) { - try { - this.pdfDoc = await extendPdf(this.pdfDoc, pdfFileList); - } catch (err) { - throw new Error(`Error merging PDFs: ${err}`); - } - } - } - - // to merge the pdfs with range specified for the pages of the Pdf into one pdf - async mergeWithRange(orderList: { filepath: string; range: [number, number][] }[]) { - const toBeMerged: PDFDocument[] = []; - for (const part of orderList) { - try { - const pdf = await this.readDoc(part.filepath); - const trimmed = await splitPdf(pdf, part.range); - toBeMerged.push(...trimmed); - } catch (err) { - throw new Error(`Error splitting pdf ${part.filepath}: ${err}`); - } - } - if (this.pdfDoc) { - try { - this.pdfDoc = await extendPdf(this.pdfDoc, toBeMerged); - } catch (err) { - throw new Error(`Error mergin splitted PDFs: ${err}`); - } - } - } - - // To export the generated file as a pdf into the file system - async save(filepath: string) { - if (this.pdfDoc) { - try { - const pdfBuffer = await this.pdfDoc.save(); - await fs.promises.writeFile(filepath, pdfBuffer); - } catch (err) { - throw new Error(`Error saving PDF to ${filepath}: ${err}`); - } - } - } - - // To return a buffer of the resultant pdf file - async getPdfBuffer() { - if (this.pdfDoc) { - try { - const pdfBuffer = await this.pdfDoc.save(); - return pdfBuffer; - } catch (err) { - throw new Error(`Error generating Buffer: ${err}`); - } - } - } -} diff --git a/src/PdfResizer.ts b/src/PdfResizer.ts deleted file mode 100644 index 453dab5..0000000 --- a/src/PdfResizer.ts +++ /dev/null @@ -1,115 +0,0 @@ -import { PDFDocument } from 'pdf-lib'; -import fs from 'fs'; -import { extendPdf } from './pdf-micro-tools/extendPdf'; -import { splitPdf } from './pdf-micro-tools/splitPdf'; -import { resizePdf } from './pdf-micro-tools/resizePdf'; -import { resizeOptions } from './types'; - -export default class PdfResizer { - private pdfDoc: PDFDocument | undefined; - - constructor() { - this.clearDoc(); - } - - // To clear and reinitialize the pdfDoc - async clearDoc() { - this.pdfDoc = await PDFDocument.create(); - } - - // This ensure that pdfDoc is not undefined - private async ensureDoc() { - if (!this.pdfDoc) { - await this.clearDoc(); - } - } - - // Getter for the pdfDocs array - getDocs() { - return this.pdfDoc; - } - - // To read the pdf file from the file system and convert it to a PDFDocument object - private async readDoc(filepath: string): Promise { - try { - const fileBuffer = await fs.promises.readFile(filepath); - const file = await PDFDocument.load(fileBuffer); - return file; - } catch (err) { - throw new Error(`Error reading file ${filepath}: ${err}`); - } - } - - // to resize all the pages of the Given pdf - async resize(file: string | PDFDocument, options?: resizeOptions) { - try { - let pdf; - if (typeof file === 'string') { - pdf = await this.readDoc(file); - } else { - pdf = file; - } - - await this.ensureDoc(); - if (!this.pdfDoc) return; - - pdf = await resizePdf(pdf, options); - - this.pdfDoc = await extendPdf(this.pdfDoc, [pdf]); - } catch (err) { - throw new Error(`Error resizing the pdf: ${err}`); - } - } - - // Resize the pdf using a range specified by the user - async resizeWithRange( - orderList: { - file: string | PDFDocument; - range: [number, number][]; - options?: resizeOptions; - }[], - ) { - try { - for (const part of orderList) { - let pdf; - if (typeof part.file === 'string') { - pdf = await this.readDoc(part.file); - } else { - pdf = part.file; - } - - const splitted = await splitPdf(pdf, part.range); - - for (const doc of splitted) { - await this.resize(doc, part.options); - } - } - } catch (err) { - throw new Error(`Error resizing the pdf: ${err}`); - } - } - - // To export the generated file as a pdf into the file system - async save(filepath: string) { - if (this.pdfDoc) { - try { - const pdfBuffer = await this.pdfDoc.save(); - await fs.promises.writeFile(filepath, pdfBuffer); - } catch (err) { - throw new Error(`Error saving PDF to ${filepath}: ${err}`); - } - } - } - - // To return a buffer of the resultant pdf file - async getPdfBuffer() { - if (this.pdfDoc) { - try { - const pdfBuffer = await this.pdfDoc.save(); - return pdfBuffer; - } catch (err) { - throw new Error(`Error generating Buffer: ${err}`); - } - } - } -} diff --git a/src/PdfRotator.ts b/src/PdfRotator.ts deleted file mode 100644 index 1986370..0000000 --- a/src/PdfRotator.ts +++ /dev/null @@ -1,100 +0,0 @@ -import { PDFDocument, degrees } from 'pdf-lib'; -import fs from 'fs'; -import { extendPdf } from './pdf-micro-tools/extendPdf'; -import { splitPdf } from './pdf-micro-tools/splitPdf'; -import { rotatePdf } from './pdf-micro-tools/rotatePdf'; - -export default class PdfRotator { - private pdfDoc: PDFDocument | undefined; - - constructor() { - this.clearDoc(); - } - - // To clear and reinitialize the pdfDoc - async clearDoc() { - this.pdfDoc = await PDFDocument.create(); - } - - // getter for pdfDoc - getDoc() { - return this.pdfDoc; - } - - // This ensure that pdfDoc is not undefined - private async ensureDoc() { - if (!this.pdfDoc) { - await this.clearDoc(); - } - } - - // To read the pdf file from the file system and convert it to a PDFDocument object - private async readDoc(filepath: string): Promise { - try { - const fileBuffer = await fs.promises.readFile(filepath); - const file = await PDFDocument.load(fileBuffer); - return file; - } catch (err) { - throw new Error(`Error reading file ${filepath}: ${err}`); - } - } - - // To rotate the pdf(all pages) - async rotate(file: string | PDFDocument, degree: number) { - let pdf; - if (typeof file === 'string') { - pdf = await this.readDoc(file); - } else { - pdf = file; - } - - pdf = await rotatePdf(pdf, degree); - - await this.ensureDoc(); - if (this.pdfDoc) { - this.pdfDoc = await extendPdf(this.pdfDoc, [pdf]); - } - } - - // To rotate the pdf with the specified range and angle - async rotateWithRange(orderList: { file: string | PDFDocument; range: [number, number][]; degree: number }[]) { - for (const part of orderList) { - let pdf; - if (typeof part.file === 'string') { - pdf = await this.readDoc(part.file); - } else { - pdf = part.file; - } - - const splitted = await splitPdf(pdf, part.range); - - for (const doc of splitted) { - await this.rotate(doc, part.degree); - } - } - } - - // To export the generated file as a pdf into the file system - async save(filepath: string) { - if (this.pdfDoc) { - try { - const pdfBuffer = await this.pdfDoc.save(); - await fs.promises.writeFile(filepath, pdfBuffer); - } catch (err) { - throw new Error(`Error saving PDF to ${filepath}: ${err}`); - } - } - } - - // To return a buffer of the resultant pdf file - async getPdfBuffer() { - if (this.pdfDoc) { - try { - const pdfBuffer = await this.pdfDoc.save(); - return pdfBuffer; - } catch (err) { - throw new Error(`Error generating Buffer: ${err}`); - } - } - } -} diff --git a/src/index.ts b/src/index.ts index bcdc613..892d6b1 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,10 +1,10 @@ -import PdfMerger from './PdfMerger'; -import PdfSplitter from './PdfSplitter'; -import PdfRotator from './PdfRotator'; -import PdfResizer from './PdfResizer'; -import PdfToImageConverter from './PdfToImageConverter'; -import PdfMarginManipulator from './PdfMarginManipulator'; -import ImageToPdfConverter from './ImageToPdfConverter'; +import PdfMerger from './utils/PdfMerger'; +import PdfSplitter from './utils/PdfSplitter'; +import PdfRotator from './utils/PdfRotator'; +import PdfResizer from './utils/PdfResizer'; +import PdfToImageConverter from './utils/PdfToImageConverter'; +import PdfMarginManipulator from './utils/PdfMarginManipulator'; +import ImageToPdfConverter from './utils/ImageToPdfConverter'; export { PdfMerger, diff --git a/src/types.ts b/src/types.ts index 77d24ac..c0bbd3d 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,3 +1,5 @@ +export type range = (number | [number | 'start' | 'end', number | 'start' | 'end'])[]; + export type resizeOptions = { size?: | [number, number] diff --git a/src/utils/ImageToPdfConverter.ts b/src/utils/ImageToPdfConverter.ts new file mode 100644 index 0000000..9943972 --- /dev/null +++ b/src/utils/ImageToPdfConverter.ts @@ -0,0 +1,57 @@ +import fs from 'fs'; +import { extendPdf } from '../pdf-micro-tools/extendPdf'; +import { imageToPdf } from '../pdf-micro-tools/imageToPdf'; +import { createOptions } from '../types'; +import { resizePdf } from '../pdf-micro-tools/resizePdf'; +import { marginPdf } from '../pdf-micro-tools/marginPdf'; +import PdfManipulator from '../PdfManipulator'; + +export default class ImageToPdfConverter extends PdfManipulator { + // To read the pdf file from the file system and convert it to a PDFDocument object + // @ts-ignore + private async readDoc(file: string): Promise { + try { + const fileBuffer = await fs.promises.readFile(file); + return fileBuffer; + } catch (err) { + throw new Error(`Error reading file ${file}: ${err}`); + } + } + + // To create pdf from the given array of objects + async createPdf(files: string[] | Uint8Array[], options?: createOptions) { + try { + options = { + size: 'do-not-change', + orientation: 'portrait', + mode: 'shrink-to-fit', + position: 'center', + opacity: 1, + margin: [0, 0, 0, 0], + ...options, + }; + + const imgs: Uint8Array[] = []; + for (const file of files) { + if (typeof file === 'string') { + imgs.push(await this.readDoc(file)); + } else { + imgs.push(file); + } + } + + let pdf = await imageToPdf(imgs); + pdf = await resizePdf(pdf, options); + if (options.margin) { + pdf = await marginPdf(pdf, options.margin); + } + + await this.ensureDoc(); + if (this.pdfDoc) { + this.pdfDoc = await extendPdf(this.pdfDoc, [pdf]); + } + } catch (err) { + throw new Error(`Error converting to Pdf: ${err}`); + } + } +} diff --git a/src/utils/PdfMarginManipulator.ts b/src/utils/PdfMarginManipulator.ts new file mode 100644 index 0000000..99a4cfc --- /dev/null +++ b/src/utils/PdfMarginManipulator.ts @@ -0,0 +1,58 @@ +import { PDFDocument } from 'pdf-lib'; +import { extendPdf } from '../pdf-micro-tools/extendPdf'; +import { marginPdf } from '../pdf-micro-tools/marginPdf'; +import { splitPdf } from '../pdf-micro-tools/splitPdf'; +import PdfManipulator from '../PdfManipulator'; +import { range } from '../types'; + +export default class PdfMarginManipulator extends PdfManipulator { + // To add margin to the pdf + async addMargin(file: string | PDFDocument, margin: [number, number, number, number]) { + let pdf; + if (typeof file === 'string') { + pdf = await this.readDoc(file); + } else { + pdf = file; + } + + pdf = await marginPdf(pdf, margin); + + await this.ensureDoc(); + if (this.pdfDoc) { + try { + this.pdfDoc = await extendPdf(this.pdfDoc, [pdf]); + } catch (err) { + throw new Error(`Error mergin PDFs: ${err}`); + } + } + } + + // To add the margin to the pdf with specified range + async addMarginWithRange( + orderList: { + file: string | PDFDocument; + range: range; + margin: [number, number, number, number]; + }[], + ) { + try { + for (const part of orderList) { + let pdf; + if (typeof part.file === 'string') { + pdf = await this.readDoc(part.file); + } else { + pdf = part.file; + } + + const r = this.processOrder(part.range, pdf.getPageCount()); + const splitted = await splitPdf(pdf, r); + + for (const doc of splitted) { + await this.addMargin(doc, part.margin); + } + } + } catch (err) { + throw new Error(`Error adding margin to the PDF: ${err}`); + } + } +} diff --git a/src/utils/PdfMerger.ts b/src/utils/PdfMerger.ts new file mode 100644 index 0000000..01e3d96 --- /dev/null +++ b/src/utils/PdfMerger.ts @@ -0,0 +1,49 @@ +import { PDFDocument } from 'pdf-lib'; +import { extendPdf } from '../pdf-micro-tools/extendPdf'; +import { splitPdf } from '../pdf-micro-tools/splitPdf'; +import PdfManipulator from '../PdfManipulator'; +import { range } from '../types'; + +export default class PdfMerger extends PdfManipulator { + // To merge all the pages of all the pdfs into a single pdf + async merge(files: string[] | PDFDocument[]) { + const pdfFileList: PDFDocument[] = []; + for (const file of files) { + if (typeof file === 'string') { + pdfFileList.push(await this.readDoc(file)); + } else { + pdfFileList.push(file); + } + } + await this.ensureDoc(); + if (this.pdfDoc) { + try { + this.pdfDoc = await extendPdf(this.pdfDoc, pdfFileList); + } catch (err) { + throw new Error(`Error merging PDFs: ${err}`); + } + } + } + + // to merge the pdfs with range specified for the pages of the Pdf into one pdf + async mergeWithRange(orderList: { filepath: string; range: range }[]) { + const toBeMerged: PDFDocument[] = []; + for (const part of orderList) { + try { + const pdf = await this.readDoc(part.filepath); + const r = this.processOrder(part.range, pdf.getPageCount()); + const trimmed = await splitPdf(pdf, r); + toBeMerged.push(...trimmed); + } catch (err) { + throw new Error(`Error splitting pdf ${part.filepath}: ${err}`); + } + } + if (this.pdfDoc) { + try { + this.pdfDoc = await extendPdf(this.pdfDoc, toBeMerged); + } catch (err) { + throw new Error(`Error mergin splitted PDFs: ${err}`); + } + } + } +} diff --git a/src/utils/PdfResizer.ts b/src/utils/PdfResizer.ts new file mode 100644 index 0000000..15c305c --- /dev/null +++ b/src/utils/PdfResizer.ts @@ -0,0 +1,58 @@ +import { PDFDocument } from 'pdf-lib'; +import { extendPdf } from '../pdf-micro-tools/extendPdf'; +import { splitPdf } from '../pdf-micro-tools/splitPdf'; +import { resizePdf } from '../pdf-micro-tools/resizePdf'; +import { range, resizeOptions } from '../types'; +import PdfManipulator from '../PdfManipulator'; + +export default class PdfResizer extends PdfManipulator { + // to resize all the pages of the Given pdf + async resize(file: string | PDFDocument, options?: resizeOptions) { + try { + let pdf; + if (typeof file === 'string') { + pdf = await this.readDoc(file); + } else { + pdf = file; + } + + await this.ensureDoc(); + if (!this.pdfDoc) return; + + pdf = await resizePdf(pdf, options); + + this.pdfDoc = await extendPdf(this.pdfDoc, [pdf]); + } catch (err) { + throw new Error(`Error resizing the pdf: ${err}`); + } + } + + // Resize the pdf using a range specified by the user + async resizeWithRange( + orderList: { + file: string | PDFDocument; + range: range; + options?: resizeOptions; + }[], + ) { + try { + for (const part of orderList) { + let pdf; + if (typeof part.file === 'string') { + pdf = await this.readDoc(part.file); + } else { + pdf = part.file; + } + + const r = this.processOrder(part.range, pdf.getPageCount()); + const splitted = await splitPdf(pdf, r); + + for (const doc of splitted) { + await this.resize(doc, part.options); + } + } + } catch (err) { + throw new Error(`Error resizing the pdf: ${err}`); + } + } +} diff --git a/src/utils/PdfRotator.ts b/src/utils/PdfRotator.ts new file mode 100644 index 0000000..51e6a0c --- /dev/null +++ b/src/utils/PdfRotator.ts @@ -0,0 +1,44 @@ +import { PDFDocument } from 'pdf-lib'; +import { extendPdf } from '../pdf-micro-tools/extendPdf'; +import { splitPdf } from '../pdf-micro-tools/splitPdf'; +import { rotatePdf } from '../pdf-micro-tools/rotatePdf'; +import PdfManipulator from '../PdfManipulator'; +import { range } from '../types'; + +export default class PdfRotator extends PdfManipulator { + // To rotate the pdf(all pages) + async rotate(file: string | PDFDocument, degree: number) { + let pdf; + if (typeof file === 'string') { + pdf = await this.readDoc(file); + } else { + pdf = file; + } + + pdf = await rotatePdf(pdf, degree); + + await this.ensureDoc(); + if (this.pdfDoc) { + this.pdfDoc = await extendPdf(this.pdfDoc, [pdf]); + } + } + + // To rotate the pdf with the specified range and angle + async rotateWithRange(orderList: { file: string | PDFDocument; range: range; degree: number }[]) { + for (const part of orderList) { + let pdf; + if (typeof part.file === 'string') { + pdf = await this.readDoc(part.file); + } else { + pdf = part.file; + } + + const r = this.processOrder(part.range, pdf.getPageCount()); + const splitted = await splitPdf(pdf, r); + + for (const doc of splitted) { + await this.rotate(doc, part.degree); + } + } + } +} diff --git a/src/PdfSplitter.ts b/src/utils/PdfSplitter.ts similarity index 68% rename from src/PdfSplitter.ts rename to src/utils/PdfSplitter.ts index 631222c..62cf834 100644 --- a/src/PdfSplitter.ts +++ b/src/utils/PdfSplitter.ts @@ -1,11 +1,14 @@ import fs from 'fs'; import { PDFDocument } from 'pdf-lib'; -import { splitPdf } from './pdf-micro-tools/splitPdf'; +import { splitPdf } from '../pdf-micro-tools/splitPdf'; +import PdfManipulator from '../PdfManipulator'; +import { range } from '../types'; -export default class PdfSplitter { +export default class PdfSplitter extends PdfManipulator { private pdfDocs: PDFDocument[]; constructor() { + super(); this.pdfDocs = []; } @@ -14,17 +17,6 @@ export default class PdfSplitter { this.pdfDocs = []; } - // To read the document from the file system and convert it into a PDFDocument object - private async readDoc(filepath: string): Promise { - try { - const fileBuffer = await fs.promises.readFile(filepath); - const file = await PDFDocument.load(fileBuffer); - return file; - } catch (err) { - throw new Error(`Error reading file ${filepath}: ${err}`); - } - } - // Getter for the pdfDocs array getDocs() { return this.pdfDocs; @@ -46,10 +38,11 @@ export default class PdfSplitter { } // To split the pdf from the file system based on the given range - async splitWithRange(filepath: string, range: [number, number][]) { + async splitWithRange(filepath: string, ranges: range) { try { const pdf = await this.readDoc(filepath); - const splitted = await splitPdf(pdf, range); + const r = this.processOrder(ranges, pdf.getPageCount()); + const splitted = await splitPdf(pdf, r); this.pdfDocs.push(...splitted); } catch (err) { throw new Error(`Error splitting ${filepath}: ${err}`); @@ -57,23 +50,24 @@ export default class PdfSplitter { } // To save the resultant pdf in the file system - async save(dirpath: string, dirname: string) { + // @ts-ignore + async save(dirpath: string, dirname: string, basename: string = 'split') { try { if (!(fs.existsSync(`${dirpath}/${dirname}`) && fs.lstatSync(`${dirpath}/${dirname}`).isDirectory())) { await fs.promises.mkdir(`${dirpath}/${dirname}`); } - for (const [index, pdf] of this.pdfDocs.entries()) { const buffer = await pdf.save(); - await fs.promises.writeFile(`${dirpath}/${dirname}/split${index + 1}.pdf`, buffer); + await fs.promises.writeFile(`${dirpath}/${dirname}/${basename}${index + 1}.pdf`, buffer); } } catch (err) { throw new Error(`Error saving files to directory ${dirpath}/${dirname}: ${err}`); } } - // To return the buffer of the resultant pdf - async getPdfBuffer() { + // To return the buffer of the resultant pdfBuffer + // @ts-ignore + async getPdfBuffer(): Promise { try { const bufferArr = []; for (const pdf of this.pdfDocs) { diff --git a/src/PdfToImageConverter.ts b/src/utils/PdfToImageConverter.ts similarity index 75% rename from src/PdfToImageConverter.ts rename to src/utils/PdfToImageConverter.ts index 0790524..08f9aac 100644 --- a/src/PdfToImageConverter.ts +++ b/src/utils/PdfToImageConverter.ts @@ -1,14 +1,17 @@ import fs from 'fs'; import { PDFDocument } from 'pdf-lib'; -import { pdfToImage } from './pdf-micro-tools/pdfToImage'; -import { splitPdf } from './pdf-micro-tools/splitPdf'; -import { resizePdf } from './pdf-micro-tools/resizePdf'; -import { resizeOptions } from './types'; +import { pdfToImage } from '../pdf-micro-tools/pdfToImage'; +import { splitPdf } from '../pdf-micro-tools/splitPdf'; +import { resizePdf } from '../pdf-micro-tools/resizePdf'; +import { range, resizeOptions } from '../types'; import sharp from 'sharp'; +import PdfManipulator from '../PdfManipulator'; -export default class PdfToImageConverter { +export default class PdfToImageConverter extends PdfManipulator { private imgDocs: Uint8Array[] = []; + constructor() { + super(); this.clearDoc(); } @@ -22,17 +25,6 @@ export default class PdfToImageConverter { return this.imgDocs; } - // To read the pdf file from the file system and convert it to a PDFDocument object - private async readDoc(filepath: string): Promise { - try { - const fileBuffer = await fs.promises.readFile(filepath); - const file = await PDFDocument.load(fileBuffer); - return file; - } catch (err) { - throw new Error(`Error reading file ${filepath}: ${err}`); - } - } - // to render all the pages of the Given pdf to image async renderToImage(file: string | PDFDocument, options?: resizeOptions) { try { @@ -62,7 +54,7 @@ export default class PdfToImageConverter { async renderToImageWithRange( orderList: { file: string | PDFDocument; - range: [number, number][]; + range: range; options?: resizeOptions; }[], ) { @@ -75,7 +67,8 @@ export default class PdfToImageConverter { pdf = part.file; } - const splitted = await splitPdf(pdf, part.range); + const r = this.processOrder(part.range, pdf.getPageCount()); + const splitted = await splitPdf(pdf, r); for (const doc of splitted) { await this.renderToImage(doc, part.options); @@ -87,7 +80,8 @@ export default class PdfToImageConverter { } // To save the resultant pdf in the file system - async save(dirpath: string, dirname: string, exportType: 'png' | 'jpg' = 'png') { + // @ts-ignore + async save(dirpath: string, dirname: string, exportType: 'png' | 'jpg' = 'png', basename: string = 'img') { try { if (!(fs.existsSync(`${dirpath}/${dirname}`) && fs.lstatSync(`${dirpath}/${dirname}`).isDirectory())) { await fs.promises.mkdir(`${dirpath}/${dirname}`); @@ -95,7 +89,7 @@ export default class PdfToImageConverter { for (const [index, img] of this.imgDocs.entries()) { if (exportType === 'png') - await fs.promises.writeFile(`${dirpath}/${dirname}/img${index + 1}.${exportType}`, img); + await fs.promises.writeFile(`${dirpath}/${dirname}/${basename}${index + 1}.${exportType}`, img); else await fs.promises.writeFile( `${dirpath}/${dirname}/img${index + 1}.${exportType}`,