https://github.com/julianhille/muhammarajs
Muhammara a node module with c/cpp bindings to modify PDF with js for node or electron (based/replacement on/of galkhana/hummusjs)
https://github.com/julianhille/muhammarajs
c cpp electron node pdf
Last synced: 6 months ago
JSON representation
Muhammara a node module with c/cpp bindings to modify PDF with js for node or electron (based/replacement on/of galkhana/hummusjs)
- Host: GitHub
- URL: https://github.com/julianhille/muhammarajs
- Owner: julianhille
- License: other
- Created: 2020-05-04T23:06:35.000Z (over 5 years ago)
- Default Branch: develop
- Last Pushed: 2024-12-19T19:13:35.000Z (11 months ago)
- Last Synced: 2025-05-11T13:02:21.187Z (6 months ago)
- Topics: c, cpp, electron, node, pdf
- Language: C
- Homepage:
- Size: 32.8 MB
- Stars: 259
- Watchers: 9
- Forks: 48
- Open Issues: 34
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- Funding: .github/FUNDING.yml
- License: LICENSE
- Security: SECURITY.md
Awesome Lists containing this project
README
# Welcome to MuhammaraJS
[](https://www.npmjs.org/package/muhammara)
[](https://github.com/julianhille/MuhammaraJS/actions/workflows/build.yml)
Welcome to MuhammaraJS.
A Fast NodeJS Module for creating, parsing and manipulating PDF files and streams.
Original Project (CPP base version)
Project site is [here](http://www.pdfhummus.com).
If you are looking for a C++ library go [here](https://github.com/galkahana/PDF-Writer).
## Hummus JS is the base
This is a drop in replacement for hummusJS originally made by Galkahana.
He did an awesome job, but discontinued hummusjs.
The documentation for MuhammaraJS / HummusJS is still located at the
hummusJS github wiki: available [here](https://github.com/galkahana/HummusJS/wiki)
## muhammara-recipe (formerly known as hummus-recipe) as been added
Muhammara-recipe and hummus-recipe has been integrated, dependencies updated
and is now shipped along with muhammara itself.
It serves as a drop in replacement.
# Caution
## Breaking changes
### Version 2.x
will be incompatible with some older node and
electron versions because we needed to upgrade node-pre-gyp.
### Version 3.x
- Node < 11 and Electron < 11 removed the prebuilts
- Renamed typo exported value from eTokenSeprator to eTokenSeparator
This won't affect a lot of you but still.
### Version 4.x
- Node < 15 and electron < 15 pre-builts have been removed
- Ubuntu 18.04 has been removed from github actions and so it is unable to build on 18.04.
This means the glibc has been raised to 2.31 which might break pre-builts for you.
It is still possible to build for older glibc version.
### Version 5.x
- ~You may need to update your base linux distro where you use this as muhammara now needs GLIBCXX_3.4.31
Github removed ubuntu 18.04 runners and so we build on 20.04 now.~
~Ubuntu 20.04 comes with newer libstdc++6 and this brings newer glibc with it.~
This has been tackled by building inside of docker using a gcc bookworm build.
That means it lowers the needed glibc version to GLIBCXX_3.4.30 and so official node:20 docker should work again.
- Node <= 16 pre-builts have been removed
- Electron <= 23 pre-builts have been removed
- GCC 13 needed / std ++ 20 (only needed if you compile yourself)
# Installation
```
npm install muhammara
```
# Replace hummusJS with MuhammaraJS for hummus
Replace:
```
let hummus = require('hummus')
```
With:
```
let muhammara = require('muhammara')
```
# Replace hummus-recipe or muhammara-recipe with MuhammaraJS
Replace:
`const HummusRecipe = require('hummus-recipe');`
With:
```
const HummusRecipe = require('muhammara').Recipe;
```
# Documentation
## Muhammara
You can find samples and documentation [here](./docs/Home.md)
### Muhammara Recipe:
To generate the documentation you could clone this repo and execute:
`npm run recipe-jsdoc`
## Recipe
### Instructions
- [GetStarted](#getstarted)
- [Coordinate System](#coordinate-system)
- [Create a new PDF](#create-a-new-pdf)
- [Modify an existing PDF](#modify-an-existing-pdf)
- [PDF Pages/Info/Structure](#page-info)
- [Append PDF](#append-pdf)
- [Insert PDF](#insert-pdf)
- [Overlay PDF](#overlay-pdf)
- [Split PDF](#split-pdf)
- [Encryption](#encryption)
### GetStarted
```bash
const Recipe = require('muhammara').Recipe
```
### Coordinate System
In order to make things easier, I use `Left-Top` as center `[0,0]` instead of `Left-Bottom`.
You may write and edit the pdf like you write things on papers from the left top corner.
It is similar to the [Html Canvas](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/drawImage)
```javascript
pdfDoc
.text('start from here', 0, 0)
.text('next line', 0, 20)
.text('some other texts', 100, 100)
...
```
### Create a new PDF
```javascript
const Recipe = require("muhammara").Recipe;
const pdfDoc = new Recipe("new", "output.pdf", {
version: 1.6,
author: "John Doe",
title: "Hummus Recipe",
subject: "A brand new PDF",
});
pdfDoc.createPage("letter").endPage().endPDF();
```
```javascript
const Recipe = require("muhammara").Recipe;
const pdfDoc = new Recipe("new", "output.pdf");
pdfDoc
// 1st Page
.createPage("letter")
.circle("center", 100, 30, { stroke: "#3b7721", fill: "#eee000" })
.polygon(
[
[50, 250],
[100, 200],
[512, 200],
[562, 250],
[512, 300],
[100, 300],
[50, 250],
],
{
color: [153, 143, 32],
stroke: [0, 0, 140],
fill: [153, 143, 32],
lineWidth: 5,
},
)
.rectangle(240, 400, 50, 50, {
stroke: "#3b7721",
fill: "#eee000",
lineWidth: 6,
opacity: 0.3,
})
.moveTo(200, 600)
.lineTo("center", 650)
.lineTo(412, 600)
.text("Welcome to Hummus-Recipe", "center", 250, {
color: "#066099",
fontSize: 30,
bold: true,
font: "Helvatica",
align: "center center",
opacity: 0.8,
rotation: 180,
})
.text("some text box", 450, 400, {
color: "#066099",
fontSize: 20,
font: "Courier New",
strikeOut: true,
highlight: {
color: [255, 0, 0],
},
textBox: {
width: 150,
lineHeight: 16,
padding: [5, 15],
style: {
lineWidth: 1,
stroke: "#00ff00",
fill: "#ff0000",
dash: [20, 20],
opacity: 0.1,
},
},
})
.comment("Feel free to open issues to help us!", "center", 100)
.endPage()
// 2nd page
.createPage("A4", 90)
.circle(150, 150, 300)
.endPage()
// end and save
.endPDF(() => {
/* done! */
});
```
#### Create a new PDF as a Buffer
```javascript
const Recipe = require("muhammara").Recipe;
const pdfDoc = new Recipe(Buffer.from("new"), null, {
version: 1.6,
author: "John Doe",
title: "Hummus Recipe",
subject: "A brand new PDF",
});
const pdfBuffer = pdfDoc.createPage("letter").endPage().endPDF();
```
### Modify an existing PDF
```javascript
const Recipe = require("muhammara").Recipe;
const pdfDoc = new Recipe("input.pdf", "output.pdf");
pdfDoc
// edit 1st page
.editPage(1)
.text("Add some texts to an existing pdf file", 150, 300)
.rectangle(20, 20, 40, 100)
.comment("Add 1st comment annotation", 200, 300)
.image("/path/to/image.jpg", 20, 100, { width: 300, keepAspectRatio: true })
.endPage()
// edit 2nd page
.editPage(2)
.comment("Add 2nd comment annotation", 200, 100)
.endPage()
// end and save
.endPDF();
```
### Page Info
```javascript
const pdfDoc = new Recipe("input.pdf", "output.pdf");
console.log(pdfDoc.pageInfo(1));
```
#### Print the pdf structure
```javascript
const pdfDoc = new Recipe("input.pdf", "output.pdf");
recipe.structure("pdf-structure.txt").endPDF(done);
```
### Append PDF
```javascript
const Recipe = require("muhammara").Recipe;
const pdfDoc = new Recipe("input.pdf", "output.pdf");
const longPDF = "/longPDF.pdf";
pdfDoc
// just page 10
.appendPage(longPDF, 10)
// page 4 and page 6
.appendPage(longPDF, [4, 6])
// page 1-3 and 6-20
.appendPage(longPDF, [
[1, 3],
[6, 20],
])
// all pages
.appendPage(longPDF)
.endPDF();
```
### Insert PDF
```javascript
const Recipe = require("muhammara").Recipe;
const pdfDoc = new Recipe("input.pdf", "output.pdf");
pdfDoc
// insert page3 from longPDF to current page 2
.insertPage(2, "/longPDF.pdf", 3)
.endPDF();
```
### Overlay PDF
```javascript
const Recipe = require("muhammara").Recipe;
const pdfDoc = new Recipe("input.pdf", "output.pdf");
pdfDoc.overlay("/overlayPDF.pdf").endPDF();
```
### Split PDF
```javascript
const Recipe = require("muhammara").Recipe;
const pdfDoc = new Recipe("input.pdf");
const outputDir = path.join(__dirname, "output");
pdfDoc.split(outputDir, "prefix").endPDF();
```
### Encryption
```javascript
const Recipe = require("muhammara").Recipe;
const pdfDoc = new Recipe("input.pdf", "output.pdf");
pdfDoc
.encrypt({
userPassword: "123",
ownerPassword: "123",
userProtectionFlag: 4,
})
.endPDF();
```