Passport Photo Maker

by John Walker

I've never gotten along well with colour printers. Ever since the 1980s, I've tried to live a paperless life and, apart from reading books, more or less arrived at that happy state. I still find it easier to mark up documents in printed form, and I print disaster backup tape directories for offsite storage, but that's about it. I only have to change the toner cartridge in my laser printer about once every five years. Only on extremely rare occasions do I find the need to print colour images, and no matter what kind of colour printer I've tried, it seems like when I get around to using it, the ink's dried up, a nozzle is plugged, or the printer driver has broken due to operating system updates since I last used it. When you amortise the cost of the printer and supplies, the cost for the few pages I actually print is vastly more expensive than photographic prints from a custom lab.

Imagine how happy I was to come across this gizmo at the local mall. What a great idea! You just plug in a Kiosque à Photo Numérique digital camera memory card (it accepts five different kinds, standards being what they are in that domain), CD, or transfer images from a camera-equipped mobile phone or PDA via infrared or Bluetooth, and it displays all the JPEG images it finds, lets you choose which ones you wish to print, then spits out 10×15 centimetre photographic quality glossy prints in about 45 seconds (12 seconds for each additional copy of a given image). While most people simply make prints directly from snapshots taken with a digital camera, in fact, as I established by experiment, it will happily print any JPEG file (or more precisely JFIF or EXIF file, as JPEG is a compression algorithm, not a file format), whether or not it contains the EXIF header most digital cameras include. All you have to do is copy your JPEG file anywhere onto the memory card (you don't have to put in a specific folder), and the kiosk will find it and let you select it to be printed.

As it happened, I had an immediate application for this device. I'd just run out of passport photos, and needed one to renew my rail pass. Fortunately, before using up the last of the previous batch, I'd made a high resolution scan of the print in the hope I'd figure out some way to make more copies without having to go back and have another picture taken. Now that I had a way to make colour prints without owning a colour printer, I was in business—it was simply a matter of creating an image that printed the scanned photo at the correct size for a passport photo. Since I'm cheap, I also wanted to fit as many pictures as possible on the 10×15 cm prints, each of which costs CHF 1 (about € 0.65).

Rather than do a lot of one-off calculations for my specific scanned image and the properties of the kiosk printer, I decided to write a Sample passport photo general purpose passport photo maker which would work with digital photos and scans at any resolution and produce photos of any requested size on printers with arbitrary page size and resolution. The result is the passport_photo program, written in the Perl language, which uses the Netpbm image processing toolkit to assemble composite images which, when printed, produce multiple passport photos of the required size. To use the program, simply prepare a single photo with the required aspect (height to width) ratio, with the highest resolution possible, in JPEG, PNG, TIFF, or GIF format, and run passport_photo, specifying the printer's paper size, resolution (dots per millimetre or inch), and the size of the photos required. A ready-to-print JPEG file will be created. which you can send to a colour printer if you have one, or copy to a memory card or CD to print at the kiosk or camera store.

The passport_photo program is described, in manual page format (extracted from the “pod” language documentation embedded in the Perl program) below.

Downloading and Installation

The passport_photo utility may be downloaded from the following link:

passport_photo.tar.gz: Gzipped TAR archive (9 Kb)

Included in the archive are the Perl program and the manual page for the program extracted from the documentation embedded within it. You can use these files in the directory in which you extracted them or install them in your system's library directories to make them available to all users. You may wish to rename the Perl program as passport_photo so it can be run as a regular command line program; if you do so, make sure the location of Perl in the first line of the program corresponds to where Perl is installed on your system.

Manual Page



passport_photo [--black] [--copyright] [--grey/--gray] [--help] [--ifilter program] [--inputfile fname] [--ofilter program] [--outputfile fname] [--paperheight dim] [--paperwidth dim] [--photoheight dim] [--photowidth dim] [--resolution dots/unit] [--verbose] [--version] image_file


passport_photo takes an image file containing a single picture with suitable aspect (height to width) ratio and creates an image for a specified printer's paper size and resolution containing as many copies of the original image as will fit, with each scaled to a precise size on the paper. This permits economically creating passport and other identification photos which conform to the size requirements of those requesting them. The program can also be used to print multiple copies of other kinds of pictures on a page, for example, snaps of the family for all the in-laws and outlaws.

passport_photo is a Perl program which assembles images using components of the Netpbm image processing toolkit; you must have these utilities installed on your computer in order to use it. While these programs are usually associated with Unix (GNU/Linux, etc.) systems, passport_photo works fine on Windows systems with Cygwin ( and the requisite programs and libraries installed.

To obtain the highest quality results, start with a digital camera image or scan of a photographic print made with the highest reasonable resolution—when scanning a photo there's no point setting the resolution so high you can see film grain and paper fibres. The picture should be taken or cropped to “portrait mode” (greater height than width) with the same aspect ratio as that required for the individual photos. For example, if photos of the European standard of 45 millimetres high and 35 millimetres wide (aspect ratio 1.286) are being made, and your 5 megapixel digital camera produces images of 2592 by 1944 pixels (aspect ratio 1.333), you should take the photo in portrait mode filling the full 1944 pixel width, then crop the image with the face at the desired position to a height of 2500 pixels to match the aspect ratio of the printed photos. Nothing terrible will happen if the aspect ratios are slightly mismatched, but the image will be smaller due to the need to scale it to fit within the required size.


All options may be abbreviated to their shortest unambiguous prefix.

Use black borders between and around images instead of the default white. This is handy when you're using a printer which doesn't fill the entire page (“bleed”), and you wish to measure the actual print area so the individual photos will be scaled to the desired size. It's a poor idea to use this option in other circumstances, as it wastes ink.
Display copyright information.
--grey or --gray
Convert a colour image_file to grey scale. Use this option when grey scale (a.k.a. “black and white”) photos are required or preferable, for example when applying for a passport from a third world country most of whose bearers have such photos (one place you never want to stand out is at the immigration desk), or a visa for Zeta Reticuli, where such a complexion is de rigueur.
Display how to call information.
--ifilter program
Specify the Netpbm input filter (for example pngtopnm) used to convert the input file to PPM format. If the input file has an extension of .jpg, .jpeg, .png, .gif, .tif, .tiff, or .pxm, the input filter will be automatically “guessed” based on the file type if no --ifilter is specified. Note that you can pass command line options to the input filter by quoting the program argument and specifying them after the filter program name.
--inputfile fname
Specifies the name of the input file. This is entirely equivalent to specifying an image_file argument. In either case, a specification of “-” causes input to be read from standard input, in which case --ifilter must be specified.
--ofilter program
Specify the Netpbm output filter used to write the output file. The default is pnmtojpeg, and unless you really know what you're doing, you shouldn't change this as most services which print digital camera files don't understand file formats other than JPEG. Note that you can pass command line options to the output filter by quoting the program argument and specifying them after the filter program name.
--outputfile fname
Specify the name of the output file written by --ofilter. By default, output is written to standard output and may be redirected to a file or piped to another program.
--paperheight dim
The height of the image produced by the printer is set to the dimension dim, where “height” is taken to mean the longer of the dimensions of the image (hence “portrait mode”). Note that this specifies the size of the image produced by the printer, not the paper size. If the printer leaves a border around the image, you should print an image with the --black option and measure it to determine the actual printed image size. The dim argument is by default in millimetres. You may specify the dimension in other units by appending a suffix of “cm” for centimetres, “in” for inches, “pc” for picas, or “pt” for points. Dimension values may be decimal fractions, but are rounded to integral millimetres. These considerations apply to dim arguments of subsequent options. The default paper height is 150 millimetres (15 cm).
--paperwidth dim
The width of the image produced by the printer is set to dim, where “width” is the smaller of the dimensions of the image. The default paper width is 100 millimetres (10 cm).
--photoheight dim
Each individual photo will have height dim, the larger of the two image dimensions. The default photo height is 45 millimetres (4.5 cm).
--photowidth dim
Each individual photo will have width dim, the smaller of the two image dimensions. The default photo width is 35 millimetres (3.5 cm).
--resolution dots/unit
The image will be prepared with a resolution of dots/unit, where the dimension is interpreted as a number of dots per unit of length (millimetres if no unit is given). For example, “48/mm” (the default value) results in an image with a resolution of 48 dots per millimetre, which is approximately the same as “1200/in”, 1200 dots per inch.
Generate verbose output to indicate what's going on, including a transcript of all the Netpbm commands used to prepare the image.
Display version number.


Produce a 10 by 15 centimetre sheet containing six 35 by 45 millimetre passport photos from the image myshot.jpg, writing the ready-to-print 48 dot per millimetre resolution image to JPEG file myprint.jpg:

    perl myshot.jpg >myprint.jpg

Produce an 8 by 10 inch sheet at 1200 dots per inch resolution containing twenty 2 by 2 inch photos as required for United States visa applications.

    perl --paperheight 10in --paperwidth 8in
                           --photoheight 2in --photowidth 2in
                           --resolution 1200/in myshot.jpg >myvisa.jpg


Several intermediate temporary files are created in the current directory, which are assembled into the final image. These files are rather large (about 48 megabytes with the default settings), so make sure there's adequate space on the file system containing the current directory. If the program crashes or is killed before completing, the intermediate files won't be deleted. They all have names which can be deleted by a command such as “rm *_temp?.ppm” as long as you don't have any other files in the directory such a command would inadvertently delete.


Creating large sheets at high resolution takes lots of memory and substantial compute time. If you run passport_photo on a system with less RAM than the uncompressed image size, forcing paging to disc, it may take almost forever to generate an image.

One could add any number of fanciful length units to dimension and resolution arguments: parsecs, angstroms, chains, nautical miles, etc. On the other hand, one should have better things to do.

Yes, I've thought about calling this program ppmpassport or somesuch and submitting it as a Netpbm component. But somebody has to draw the line somewhere against accretion of special-purpose kludges into Netpbm, and here's where I draw it. If somebody does add this, they should remove the input file filtering mechanism and require the input be piped to standard input in PPM format.

Please report bugs to bugs at, indicating the version numbers of passport_photo, Perl, and Netpbm installed on your system.


John Walker (



This is passport_photo version 1.1, released on January 19th, 2020. The current version of this program is always posted at:


This program is in the public domain.

by John Walker
August, 2004