简体   繁体   中英

Expo - reduce PDF filesize on iOS devices

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,
});

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"
  }
});

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.

  1. Use Expo Print API to get the pdf file in question, remember to set the base64 to true.
import * as Print from 'expo-print';

const pdf = Print.printToFileAsync({
    width: 612,    // <=== your width
    height: 612,   // <=== your height
    base64: true
});
  1. You can use this or this library to decode back the base64 file.
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!

If you have a requirement to take digital photos and add them to a PDF document and have a constraint on how big the PDF file size can be, before you start trying to make the page size smaller in order to shrink the size of the document....I'd strongly suggest you consider optimizing the created PDFs.

Not all PDF software is created equal and many creators birth documents that are bloated and can benefit greatly from being optimized.

Just a note that 1.9MB is a bit arbitrary especially when dealing with digital image(s), you may need to reconsider that requirement with your stakeholders depending on the quality and number of input images as well.

My company offers a tool called PDF Optimizer which can help.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM