Pdf-lib: Extract images from a pdf page

Created on 18 Mar 2019  路  11Comments  路  Source: Hopding/pdf-lib

Hi everyone !
I am trying to extract all images from a pdf page. I don't know if it is possible, but I would to do something like this website does.
I am currently manipulating the pdf as follows :
const pdfDoc = PDFDocumentFactory.load('pdf/path');
const pages = pdfDoc.getPages();
const existingPage = pages[0];
Thank you four your answers :)

Most helpful comment

Hello @totorelmatador! I've finally gotten some time to finish up my investigation into this.

First off, it is possible to extract all image types from a PDF using pdf-lib. The question is, how much code will you have to write on top of pdf-lib to do this. It turns out, you'll have to write a fair amount of code if you want to handle all possible images in any type of PDF file.

pdf.js is an open source PDF rendering engine maintained by Mozilla. It's all written in JavaScript. So, of course, this library must be able to extract and render all types of images. This makes it a very good reference to see how this might be done using pdf-lib.

In particular, it's PDFImage class is worth looking at. All of this logic would need to be ported over to use pdf-lib in order to handle all possible types of images. This is because the embedded image format outlined in the PDF specification is pretty long and complicated (as are many things in PDF files).


All of that being said, I created a script that extracts the more common image formats from PDF files. Here it is:

extract-images.zip

You just need to unzip the file and run yarn install (or npm install) and then run node index.js existing1.pdf or node index.js existing2.pdf. The script will extract as many embedded images as it can from the PDF into the images/ directory.

Again, this does not extract all possible types of images. Just the more common formats. It could certainly be improved by porting some code from pdf.js.


I did a bit of googling to see if pdf.js has an API to extract images from PDFs. It looks like this may be possible for certain types of images: https://github.com/mozilla/pdf.js/issues/7813 https://github.com/mozilla/pdf.js/issues/7043. But full support doesn't yet seem available.

I think that adding proper support for image extraction would be an interesting feature to implement in pdf-lib. I imagine it would be quite useful to many developers. However, unless somebody from the community decides to work on this, there are several other things I have to work on first. So it'll be awhile before this feature lands in pdf-lib.

All 11 comments

Hello @totorelmatador!

There are a couple of ways to go about this. Some more challenging than others. I wrote a Node script that "scans" an existing PDF and finds all the images it contains, and redraws them all on a new page:

redraw-images.zip

You just need to unzip the file and run yarn install (or npm install) and then run node index.js. The script will write the new PDF to modified.pdf. Here's what modified.pdf looks like:

modified.pdf

The script will also log some information about each image in the document, e.g.

Images in PDF:
Name: JfImage0001
  Width: 176
  Height: 157
  Bits Per Component: 1
  Data: Uint8Array(1778)
  Ref: 20 0 R
...
Name: JfImage0036
  Width: 556
  Height: 271
  Bits Per Component: 8
  Data: Uint8Array(461)
  Ref: 58 0 R

Let me know if this is what you're looking for, or if you have any questions!

Hello @Hopding !

Thank you so much for your answer ! This is exactly the kind of thing I was trying to do !
But I still have a question. My final objective is to save these images as separated files. I tried to do so with the following code (added to your file index.js) :

var i = 0;
imagesInDoc.forEach(image => {
  fs.writeFile("./images/out"+i+".png", image.data, 'base64', function(err) {
    console.log(err);
  });
  i+=1;
});

But it doesn't work well. Saved images can't be opened...
The funny thing is that the code works for some images. When I try on this document :

existing.pdf

Only one of the two images is saved and ready to be opened. I think that the cause is the transparency of the image, but I would like to know if it is possible to face this issue...

Thank you again for your time !

@totorelmatador Sorry for taking so long to respond to this. I've been swamped with work and school lately, so I haven't had a lot of time to devote to this. However, I've made some progress on creating an example script that shows how to do this (though there are some limitations). I'll try to post a more detailed response soon.

Thank you a lot for your time @Hopding !
I have observed something. When we add a png image in a pdf file, we use the following function:
[imgRef, imgDims] = pdfDoc.embedPNG(PNGimage)
The type of imgRef is PDFIndirectReference, the one of imgDims is PNGXObjectFactory, and PNGimage is an image buffer.
When we find all the image objects in the PDF we use the following code:

pdfDoc.index.index.forEach((pdfObject, ref) => {
  objectIdx += 1;

  if (!(pdfObject instanceof PDFRawStream)) return;

  const { lookupMaybe } = pdfDoc.index;
  const { dictionary: dict } = pdfObject;

  const subtype = lookupMaybe(dict.getMaybe('Subtype'));
  const width = lookupMaybe(dict.getMaybe('Width'));
  const height = lookupMaybe(dict.getMaybe('Height'));
  const name = lookupMaybe(dict.getMaybe('Name'));
  const bitsPerComponent = lookupMaybe(dict.getMaybe('BitsPerComponent'));

  if (subtype === PDFName.from('Image')) {
      imagesInDoc.push({
      ref,
      name: name ? name.key : `Object${objectIdx}`,
      width: width.number,
      height: height.number,
      bitsPerComponent: bitsPerComponent.number,
      data: pdfObject.content,
    });
  }
});

where every pdfObject is a PDFRawStream object and ref a PDFIndirectReference. It is possible to extract the image buffer associated to the couple pdfObject & ref ?

Hello @totorelmatador! I've finally gotten some time to finish up my investigation into this.

First off, it is possible to extract all image types from a PDF using pdf-lib. The question is, how much code will you have to write on top of pdf-lib to do this. It turns out, you'll have to write a fair amount of code if you want to handle all possible images in any type of PDF file.

pdf.js is an open source PDF rendering engine maintained by Mozilla. It's all written in JavaScript. So, of course, this library must be able to extract and render all types of images. This makes it a very good reference to see how this might be done using pdf-lib.

In particular, it's PDFImage class is worth looking at. All of this logic would need to be ported over to use pdf-lib in order to handle all possible types of images. This is because the embedded image format outlined in the PDF specification is pretty long and complicated (as are many things in PDF files).


All of that being said, I created a script that extracts the more common image formats from PDF files. Here it is:

extract-images.zip

You just need to unzip the file and run yarn install (or npm install) and then run node index.js existing1.pdf or node index.js existing2.pdf. The script will extract as many embedded images as it can from the PDF into the images/ directory.

Again, this does not extract all possible types of images. Just the more common formats. It could certainly be improved by porting some code from pdf.js.


I did a bit of googling to see if pdf.js has an API to extract images from PDFs. It looks like this may be possible for certain types of images: https://github.com/mozilla/pdf.js/issues/7813 https://github.com/mozilla/pdf.js/issues/7043. But full support doesn't yet seem available.

I think that adding proper support for image extraction would be an interesting feature to implement in pdf-lib. I imagine it would be quite useful to many developers. However, unless somebody from the community decides to work on this, there are several other things I have to work on first. So it'll be awhile before this feature lands in pdf-lib.

It does work perfectly, thank you a lot !

thanks a lot, this helps me 29/07/2019 :)

Thank you so much!
Exactly what I needed and worked perfectly.
Aces!

This does not work on scanned pdf. It results in an "unknown compression method error"

The pages are filter = JBIG2Decode

@Hopding thanks for taking the time to post such a useful reply and provide the script. I was wondering if there's an easy way to get the x/y position of the image as well as the width/height?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

fatso83 picture fatso83  路  3Comments

kevinswartz picture kevinswartz  路  5Comments

BoLaMN picture BoLaMN  路  5Comments

jboxxx picture jboxxx  路  4Comments

msvargas picture msvargas  路  6Comments