Skip to content

Commit 5917e9b

Browse files
committed
feat: align iOS and Android PDF rendering with consistent spacing and page breaks
- Changed Android CSS @page margins from px to pt units to match iOS PDF points - Fixed header/footer positioning to respect marginTop/marginBottom on both platforms - Updated page number positioning to footerHeight + fontSize + 5pt for consistent placement - Added page-break-inside: avoid to totals section to prevent splitting across pages - Removed global page-break-inside: avoid to allow table content to flow naturally - iOS: Added marginTop/marginBottom to CustomPrintPageRenderer for proper overlay positioning - Android: Updated mergePdfs to position header at pageHeight - marginTop - headerHeight - Android: Updated mergePdfs to position footer at marginBottom - Both platforms now produce identical PDF layout and spacing
1 parent 143fb87 commit 5917e9b

9 files changed

Lines changed: 1022 additions & 486 deletions

File tree

README.md

Lines changed: 154 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,175 @@
11
# react-native-nitro-html-pdf
22

3-
HTML to PDF
3+
High-quality HTML to PDF conversion for React Native with vector-based header/footer support.
44

5-
## Installation
5+
## Features
6+
7+
- ✅ Vector-based PDF generation (text remains selectable)
8+
- ✅ Custom headers and footers with vector quality
9+
- ✅ Automatic page numbering
10+
- ✅ Multiple page sizes (A4, A3, A5, Letter, Legal)
11+
- ✅ Custom margins
12+
- ✅ iOS and Android support
13+
- ✅ Built with [Nitro Modules](https://nitro.margelo.com/) for optimal performance
614

15+
## Installation
716

817
```sh
918
npm install react-native-nitro-html-pdf react-native-nitro-modules
19+
```
1020

1121
> `react-native-nitro-modules` is required as this library relies on [Nitro Modules](https://nitro.margelo.com/).
22+
23+
## Usage
24+
25+
### Basic Example
26+
27+
```typescript
28+
import { generatePdf } from 'react-native-nitro-html-pdf';
29+
30+
const result = await generatePdf({
31+
html: '<h1>Hello World</h1><p>This is a PDF document.</p>',
32+
fileName: 'document.pdf',
33+
pageSize: 'A4',
34+
});
35+
36+
console.log('PDF created at:', result.filePath);
1237
```
1338

39+
### With Header and Footer
40+
41+
```typescript
42+
const result = await generatePdf({
43+
html: '<h1>Invoice</h1><p>Invoice content...</p>',
44+
fileName: 'invoice.pdf',
45+
pageSize: 'A4',
46+
header: '<div style="text-align: center;"><h3>Company Name</h3></div>',
47+
footer: '<div style="text-align: center;"><p>Thank you!</p></div>',
48+
headerHeight: 100, // Required when using header
49+
footerHeight: 80, // Required when using footer
50+
showPageNumbers: true,
51+
pageNumberFormat: 'Page {page} of {total}',
52+
marginTop: 20,
53+
marginBottom: 20,
54+
});
55+
```
1456

15-
## Usage
57+
## API Reference
58+
59+
### `generatePdf(options: PdfOptions): Promise<PdfResult>`
60+
61+
#### PdfOptions
62+
63+
| Property | Type | Required | Default | Description |
64+
|----------|------|----------|---------|-------------|
65+
| `html` | `string` || - | HTML content to convert to PDF |
66+
| `fileName` | `string` || - | Output PDF file name (must end with .pdf) |
67+
| `pageSize` | `'A4' \| 'A3' \| 'A5' \| 'LETTER' \| 'LEGAL'` || `'A4'` | Page size |
68+
| `header` | `string` || - | HTML content for header |
69+
| `footer` | `string` || - | HTML content for footer |
70+
| `headerHeight` | `number` | ⚠️ | - | Header height in pixels (required if header is provided) |
71+
| `footerHeight` | `number` | ⚠️ | - | Footer height in pixels (required if footer is provided) |
72+
| `showPageNumbers` | `boolean` || `false` | Show page numbers in footer |
73+
| `pageNumberFormat` | `string` || `'Page {page} of {total}'` | Page number format |
74+
| `pageNumberFontSize` | `number` || `12` | Page number font size |
75+
| `marginTop` | `number` || `0` | Top margin in pixels |
76+
| `marginBottom` | `number` || `0` | Bottom margin in pixels |
77+
| `marginLeft` | `number` || `0` | Left margin in pixels |
78+
| `marginRight` | `number` || `0` | Right margin in pixels |
79+
| `directory` | `string` || Cache dir | Output directory path |
80+
81+
#### PdfResult
82+
83+
```typescript
84+
interface PdfResult {
85+
filePath: string; // Absolute path to generated PDF
86+
success: boolean; // Whether generation succeeded
87+
error?: string; // Error message if failed
88+
}
89+
```
90+
91+
## Important Notes
92+
93+
### Header and Footer Heights
1694

95+
**You must provide explicit `headerHeight` and `footerHeight` values when using headers or footers.** The library does not auto-calculate these values.
1796

18-
```js
19-
import { multiply } from 'react-native-nitro-html-pdf';
97+
```typescript
98+
// ❌ Wrong - will throw error
99+
await generatePdf({
100+
html: '...',
101+
fileName: 'doc.pdf',
102+
header: '<h3>Header</h3>', // Missing headerHeight!
103+
});
20104

21-
// ...
105+
// ✅ Correct
106+
await generatePdf({
107+
html: '...',
108+
fileName: 'doc.pdf',
109+
header: '<h3>Header</h3>',
110+
headerHeight: 100, // Explicit height
111+
});
112+
```
22113

23-
const result = multiply(3, 7);
114+
### Page Size Dimensions
115+
116+
- **A4**: 595 × 842 pts (210 × 297 mm)
117+
- **A3**: 842 × 1191 pts (297 × 420 mm)
118+
- **A5**: 420 × 595 pts (148 × 210 mm)
119+
- **Letter**: 612 × 792 pts (8.5 × 11 in)
120+
- **Legal**: 612 × 1008 pts (8.5 × 14 in)
121+
122+
### Margin Behavior
123+
124+
The library automatically adjusts content margins to prevent overlap:
125+
- Total top margin = `marginTop + headerHeight`
126+
- Total bottom margin = `marginBottom + footerHeight + (showPageNumbers ? 20 : 0)`
127+
128+
### Supported HTML/CSS
129+
130+
Both iOS and Android use native WebView rendering, supporting:
131+
- Standard HTML5 tags
132+
- CSS styling (inline, `<style>` tags)
133+
- Tables, lists, images
134+
- Custom fonts (with proper CSS `@font-face`)
135+
136+
## Error Handling
137+
138+
```typescript
139+
try {
140+
const result = await generatePdf(options);
141+
142+
if (result.success) {
143+
console.log('PDF created:', result.filePath);
144+
} else {
145+
console.error('PDF generation failed:', result.error);
146+
}
147+
} catch (error) {
148+
console.error('Unexpected error:', error);
149+
}
24150
```
25151

152+
## Common Errors
153+
154+
| Error | Cause | Solution |
155+
|-------|-------|----------|
156+
| `headerHeight must be provided` | Using header without height | Add `headerHeight` property |
157+
| `footerHeight must be provided` | Using footer without height | Add `footerHeight` property |
158+
| `Combined header, footer, and margins exceed page height` | Heights too large | Reduce header/footer/margin values |
159+
| `File name must end with .pdf` | Invalid file name | Ensure fileName ends with `.pdf` |
160+
| `HTML content cannot be empty` | Empty HTML | Provide valid HTML content |
161+
162+
## Platform Differences
163+
164+
### Android
165+
- Uses `PrintDocumentAdapter` for vector rendering
166+
- PDFs merged using PDFBox `LayerUtility`
167+
- Text remains selectable in output PDF
168+
169+
### iOS
170+
- Uses `UIPrintPageRenderer` for vector rendering
171+
- Native PDF context drawing
172+
- Text remains selectable in output PDF
26173

27174
## Contributing
28175

0 commit comments

Comments
 (0)