Take the 2-minute tour ×
Super User is a question and answer site for computer enthusiasts and power users. It's 100% free, no registration required.

Does there exist a commandline tool for Linux which allows me to extract all /Subtype /Image raster image objects from a PDF, allows me to process them using another 3rd party tool and then is able to reinsert them into the original PDF?

The Debian package poppler-utils brings the tool pdfimages which allows me to extract all images from a PDF but I can't easily re-insert them into the PDF after I changed them.

I wrote simple parsers for PDF before so my current take on this problem would be to

  1. run pdfclean (from the mupdf package) on the PDF to decompress all streams and thus make parsing easier
  2. parse the pdf with a simple parser (surely this will not be able to parse most PDF but as long as it works for my PDF I'm happy) and extract all images as bitmaps with the object id in their name
  3. do some foo on the images using a 3rd party program
  4. parse the original pdf again but this time replace the images inside with the modified ones, adapting the /Length and /Filter as necessary
  5. run pdfclean again to correct all offsets in the xref table

But maybe a tool which allows all this and is not limited to the capabilties of a simple parser written by me already exists?

If you say such a tool does not exist, then it is also okay to tell me a library which allows to extract and later replace images.

share|improve this question
add comment

2 Answers

up vote 1 down vote accepted

It seems this is not (yet) possible to do in the commandline but I found an easy way to script it in python using the pdfrw python module like this:

#!/usr/bin/env python
import sys
import os
import zlib
import Image
import StringIO

from pdfrw import PdfReader, PdfDict, PdfArray, PdfName, PdfWriter

def process_image(image):
    if image["/Filter"] == PdfName("FlateDecode"):
        pass
    elif image["/Filter"] == PdfName("DCTDecode"):
        im = Image.open(StringIO.StringIO(image.stream))
        outf = StringIO.StringIO()
        im.save(outf, "JPEG", quality=45)
        image.stream = outf.getvalue()
        outf.close()

def find_images(obj, visited=set()):
    if not isinstance(obj, (PdfDict, PdfArray)):
        return
    myid = id(obj)
    if myid in visited:
        return
    visited.add(myid)

    if isinstance(obj, PdfDict):
        if obj.Type == PdfName.XObject and obj.Subtype == PdfName.Image:
            process_image(obj)
        obj = obj.itervalues()

    for item in obj:
        find_images(item, visited)

if __name__ == '__main__':
    inpfn,outfn = sys.argv[1:]
    reader = PdfReader(inpfn)
    find_images(reader)
    PdfWriter().addpages(reader.pages).write(outfn)

You can potentially implement whatever you want in the process_images function and even complicated things like calling external programs to modify the current image can easily be done. In this example we just use PIL to reencode jpeg images with a quality of 45.

share|improve this answer
add comment

you can try to use inkscape in command line

inkscape -S # show all the object inside  the document
inkscape --select=YouImage --verb=YourTransformation 
inkscape --verb-list #to obtain all the possibilities

Or you can extract image, modify them with anything you want (imagemagick?) then replace them in your document with inkscape.

Regards

share|improve this answer
    
Yes, I can freely edit PDFs and replace images in them using inkscape and many other free and non-free tools. But they all only allow me to manually select and modify images not to automatically batch process all pages and all images inside. –  josch Jul 3 '13 at 15:41
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.