Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 17 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,12 @@
- **PDF** → Images (JPG)
- **PDF** → Text (TXT) - Extract text content from PDF files
- **PDF Info** → Display metadata (title, creator, page count, file size)
- Merge multiple PDFs

#### Coming Soon
- PowerPoint → PDF
- Excel → PDF
- HTML → PDF
- Merge multiple PDFs
- PDF compression
- PDF text extraction

Expand Down Expand Up @@ -158,6 +158,22 @@ filto extract input.pdf -o extracted.txt
```
filto extract input.pdf --page 1 --output page1.txt
```
---
### 5. Merge PDF Files
Merge multiple PDF files into a single PDF

**Basic usage:**
```
filto merge file1.pdf file2.pdf output.pdf
```

**Example with multiple files:**
```
filto merge doc1.pdf doc2.pdf doc3.pdf merged_output.pdf
```

> **Note:** You need to provide at least two PDF files to merge. The last argument will be used as the output file.

---
## Contributing

Expand Down
55 changes: 55 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"@oclif/plugin-plugins": "^5",
"asposepdfnodejs": "^25.10.0",
"image-to-pdf": "^3.0.2",
"pdf-lib": "^1.17.1",
"pdf-parse": "^2.4.5",
"rewiremock": "^3.14.6"
},
Expand Down
35 changes: 35 additions & 0 deletions src/commands/merge/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { Args, Command, Flags } from '@oclif/core'
import { MergePdfs } from '../../merge/index.js';
export default class Merge extends Command {
static override description = ' Merge multiple PDFs'

static override args = {
inputs: Args.string({ description: 'Input PDF files to merge', required: true, multiple: true }),
output: Args.string({ description: 'Output merged PDF file', required: true }),
}
static override strict = false;

public async run(): Promise<void> {
const { args } = await this.parse(Merge)
const { inputs } = args;

if (inputs.length < 2) {
this.error('Please provide at least two PDF files to merge.');
}

try {
const argv = process.argv;
const inputsArr = argv.slice(3, argv.length - 1);
const result = await MergePdfs(inputsArr, argv[argv.length - 1]);

if (result.success) {
this.log(result.message);
} else {
this.error(result.message);
}
} catch (error: any) {
this.error(`Unexpected error during merge: ${error.message}`);
}

}
}
42 changes: 42 additions & 0 deletions src/merge/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@

import { PDFDocument } from 'pdf-lib';
import fs from 'fs';
import ConversionResult from '../types/converstionResult.js';

export async function MergePdfs(inputPdf: string[], output: string = "merged.pdf"): Promise<ConversionResult> {
if (!fs.existsSync(inputPdf[0])) {
return {
success: false,
message: `Input file not found: ${inputPdf}`
};
}

try {
const pdfToMerge = inputPdf.map(filePath => fs.readFileSync(filePath));

const mergedPdf = await PDFDocument.create();
for (const pdfBytes of pdfToMerge) {
const pdf = await PDFDocument.load(pdfBytes);
const copiedPages = await mergedPdf.copyPages(pdf, pdf.getPageIndices());
copiedPages.forEach((page) => {
mergedPdf.addPage(page);
});
}

const buf = await mergedPdf.save();
fs.writeFileSync(output, buf);

return {
success: true,
message: `Successfully Merged PDFs: ${inputPdf.map(pdf => {
return pdf
})} into -> ${output}`
};
} catch (error: any) {
return {
success: false,
message: `Error during Merge: ${error.message}`,
error
};
}
}
Loading