Reputation: 1999
I'm currently creating an A4 PDF within my Expo-App, using the "expo-print" API (printtofileasync). The PDF includes images (photos taken from the device) and some text. I've set the PDF size to 595 width, 842 height (A4 dimensions). Unfortunately the size of the PDF is too large for my requirements (1,9MB with only 1 image).
I was able to reduce the PDF size on Android by decreasing the image size, but that does not work on iOS. I have the suspicion that on iOS Expo is simply "making screenshots" of the page, therefore changing the image size has no effect. I've already tried to decrease the whole PDF size to A5, but that's not a solution, because the PDFs needs to be printed afterwards on A4.
Any help would be appreciated!
Update: currently this my code:
const { uri, base64 } = await Print.printToFileAsync({
width: 595,
height: 842,
html: 'data...',
base64: true,
});
Share.share({
url: 'data:application/pdf;base64,' + base64,
});
Upvotes: 7
Views: 2333
Reputation: 196
I have the same problem, I change my pdf creator because html creates variable size pdf and it depends on the resolution device, I use pdf-lib it works in javascript, you can create or modify pdf, I write small example in Expo , I plan to create a library to do Additional, you can fill PDF NOTE: it similar to react-native-pdf-lib but working in only enviroment javascript
My App.tsx example:
import React from "react";
import { StyleSheet, View, Text, Button } from "react-native";
import { Asset } from "expo-asset";
import * as Print from "expo-print";
import { degrees, PDFDocument, rgb, StandardFonts } from "pdf-lib";
export default function App({ context }: any) {
return (
<View style={styles.container}>
<Button
title="Generate PDF"
onPress={async () => {
const req = new XMLHttpRequest();
/* const templateUri = Asset.fromModule(
require("./assets/template.pdf")
);
console.log(templateUri); */
const url = 'https://pdf-lib.js.org/assets/with_update_sections.pdf' // templateUri.uri
req.open("GET", url, true);
req.responseType = "blob";
/* req.onprogress = e => (t.progress = e.loaded); */
req.onload = () => {
const blob = req.response;
var reader = new FileReader();
reader.readAsDataURL(blob);
reader.onloadend = async function() {
const base64data = reader.result as string; // template pdf in base64
const pdfDoc = await PDFDocument.load(base64data);
const helveticaFont = await pdfDoc.embedFont(
StandardFonts.Helvetica
);
const pages = pdfDoc.getPages();
const firstPage = pages[0];
const { width, height } = firstPage.getSize();
console.log(width, height);
firstPage.drawText('This text was added with JavaScript!', {
x: 5,
y: height / 2 + 300,
size: 50,
font: helveticaFont,
color: rgb(0.95, 0.1, 0.1),
rotate: degrees(-45),
});
const pdfDataUri = await pdfDoc.saveAsBase64({ dataUri: true });
Print.printAsync({ uri: pdfDataUri });
};
};
req.onerror = console.error;
req.send();
}}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
alignItems: "center",
justifyContent: "center"
}
});
Upvotes: 2
Reputation: 932
You can try using the base64
string and decoding it back to the pdf file. i think it should be of smaller size, Follow along.
import * as Print from 'expo-print';
const pdf = Print.printToFileAsync({
width: 612, // <=== your width
height: 612, // <=== your height
base64: true
});
import * as Print from 'expo-print';
import base64 from 'base64'; // or import base64 from 'react-native-base64'
const pdf = Print.printToFileAsync({
width: 612, // <=== your width
height: 612, // <=== your height
base64: true
});
const pdfDecoded = base64(pdf);
The pdfDecoded
will hold your new pdf file and it should be of smaller size, you can either send it to your server or display it.
I have not tested this just my 2 cents.
Hope this Helps!
Upvotes: 0