Print PDFs with Python?

59549
9
Jump to solution
09-17-2012 01:02 PM
by Anonymous User
Not applicable
People often come into my office requesting maps of their property.  I have a script that will open up a command prompt window then allow the non-GIS users in my office to enter a Parcel ID number in the command window. Once user input has been accepted, the script will automatically select that parcel, zoom to it, then export it to PDF.  I would like to add a print function to automatically print the PDF of the map.  I know that I can use the PrintMap function to print straight from ArcMap, however, this does not come out very clear.  I am wondering if anyone knows of a way to use python to print a PDF?
Tags (2)
0 Kudos
1 Solution

Accepted Solutions
Luke_Pinner
MVP Regular Contributor
You can use the Adobe Reader command line print option. If you leave the printer name blank, reader will print to the default printer.
AcroRd32 /N /T PdfFile [PrinterName [ PrinterDriver [ PrinterPort ] ] ]


Python example:
import subprocess  printer='MyPrinter' pdffile=r'C:\Some Dir\some pdf.pdf' acroread=r'C:\Program Files (x86)\Adobe\Reader 9.0\Reader\AcroRd32.exe'  #'"%s"'is to wrap double quotes around paths # as subprocess will use list2cmdline internally if we pass it a list #which escapes double quotes and Adobe Reader doesn't like that cmd='"%s" /N /T "%s" "%s"'%(acroread,pdffile,printer)  proc = subprocess.Popen(cmd,stdout=subprocess.PIPE,stderr=subprocess.PIPE) stdout,stderr=proc.communicate() exit_code=proc.wait()

View solution in original post

9 Replies
Luke_Pinner
MVP Regular Contributor
You can use the Adobe Reader command line print option. If you leave the printer name blank, reader will print to the default printer.
AcroRd32 /N /T PdfFile [PrinterName [ PrinterDriver [ PrinterPort ] ] ]


Python example:
import subprocess  printer='MyPrinter' pdffile=r'C:\Some Dir\some pdf.pdf' acroread=r'C:\Program Files (x86)\Adobe\Reader 9.0\Reader\AcroRd32.exe'  #'"%s"'is to wrap double quotes around paths # as subprocess will use list2cmdline internally if we pass it a list #which escapes double quotes and Adobe Reader doesn't like that cmd='"%s" /N /T "%s" "%s"'%(acroread,pdffile,printer)  proc = subprocess.Popen(cmd,stdout=subprocess.PIPE,stderr=subprocess.PIPE) stdout,stderr=proc.communicate() exit_code=proc.wait()
KenCarrier
Deactivated User

Luke,

Your example certainly helped me in getting started. The hard part for me was hard coding the path for adobe as it is not that flexible and would require each machine to be at the same level of Adobe Reader. This led me to look for a more dynamic way of handling this so I thought I would share my findings if anyone should come across your post. I still had problems with ArcMap locking when the pdf was open and had to manually kill the adobe process in task manager to free up ArcMap so I issued a simple command to kill the process after 5 seconds allowing adobe reader to open the document, and send the pdf to the print spool. In our case we were automating a report using an *.rlf file and exporting it to a pdf, we needed a way to print both a map and the report which is what the below was doing. Thank you for your contribution and sharing your code!

import _winreg as winreg

import time, arcpy, os, subprocess

# This is where you would specify the path to your pdf

pdf = 'Place the path to your pdf here.pdf'

# Dynamically get path to AcroRD32.exe

AcroRD32Path = winreg.QueryValue(winreg.HKEY_CLASSES_ROOT,'Software\\Adobe\\Acrobat\Exe')

acroread = AcroRD32Path

#print('variable acroread is : {0}'.format(acroread))

# The last set of double quotes leaves the printer blank, basically defaulting to the default printer for the system.

cmd= '{0} /N /T "{1}" ""'.format(acroread,pdf)

# See what the command line will look like before execution

print(cmd)

# Open command line in a different process other than ArcMap

proc = subprocess.Popen(cmd)

# 2 lines below would not close adobe reader and locked ArcMap.

#stdout,stderr=proc.communicate()

#exit_code=proc.wait()

# Needed to put a sleep in here so the command line had time to open the pdf and spool the job to the printer.

time.sleep(5)

# Kill AcroRD32.exe from Task Manager

os.system("TASKKILL /F /IM AcroRD32.exe")

by Anonymous User
Not applicable

That is pretty cool, Ken!  In the past I have just used glob, which should also find AcroRd32.exe no matter what the version:

acroread = glob.glob(r"C:\Program Files (x86)\Adobe\Reader*\Reader\AcroRd32.exe")[0]

I like yours better though.  I was also having issues with adobe reader remaining open after PDF was printed so thanks for sharing termination part!

0 Kudos
by Anonymous User
Not applicable
You are the smartest man alive!!! Thank you soo much, worked like a charm!

Here is the code in case anyone is interested in doing something similar:

# This script allows a user to input a parcel ID number
# This will automatically save the map to PDF so it can be printed
# Written by Caleb Mackey  9/17/2012
# Print PDF section courtesy of Luke Pinner 9/18/2012

import arcpy, os, sys, traceback
import subprocess
arcpy.env.overwriteOutput = True

def userinput():
    mxd = arcpy.mapping.MapDocument("G:\\Map_Documents\\Walkin_requests\\Customer_map.mxd")
    df = arcpy.mapping.ListDataFrames(mxd, "Main")[0]
    parcels = arcpy.mapping.ListLayers(mxd, "Parcels GIS Acres", df)[0]
    pdfpath = 'C:\\Documents and Settings\\gis\\Desktop\\PRINT_MAPS\\'
    txtfile = pdfpath + 'Parcelmap_ERROR.txt'
    acroread = r'C:\Program Files\Adobe\Reader 10.0\Reader\AcroRd32.exe'
    try:
        print "Enter Parcel Number WITHOUT dashes and hit ENTER"
        parcelid = raw_input()
        parcel_num = str(parcelid)

        print 'selecting parcel...'
        query = "SOL_PID ='%s'" % parcel_num
        arcpy.SelectLayerByAttribute_management(parcels, "NEW_SELECTION", query)
        result = arcpy.GetCount_management(parcels)
        if str(result) == '0':
            print 'Invalid SQL statement, check parcel ID'
            print 'Please verify the Parcel ID and try again'
            return userinput();
        
        elif str(result) > 0:
            df.zoomToSelectedFeatures()
            df.extent = parcels.getSelectedExtent(True)
            df.scale *= 1.65
            arcpy.RefreshActiveView()

            print 'Exporting to pdf...'
            pdf = pdfpath + str(parcel_num) + '.pdf'
            pdfname = str(parcel_num) + '.pdf'
            if arcpy.Exists(pdf):
                arcpy.Delete_management(pdf)
            arcpy.mapping.ExportToPDF(mxd,pdfpath + str(parcel_num) + '.pdf')

            del mxd
            print 'PDF Exported, to view open ' + str(pdfname) + ' in the "PRINT MAPS" folder.'
            print 'Sending document to default printer'

            #### Print PDF Code thanks to Luke Pinner #####
            # '"%s"'is to wrap double quotes around paths
            # as subprocess will use list2cmdline internally if we pass it a list
            # which escapes double quotes and Adobe Reader doesn't like that
            cmd='"%s" /N /T "%s"' %(acroread,pdf)

            proc = subprocess.Popen(cmd,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
            stdout,stderr=proc.communicate()
            exit_code=proc.wait()
            print 'Successful'
                    
    except:
           print arcpy.GetMessages(2)
try:
    userinput()
        
except:
    # Get the traceback object
    tb = sys.exc_info()[2]
    tbinfo = traceback.format_tb(tb)[0]

    # Concatenate information together concerning the error into a message string
    pymsg = "PYTHON ERRORS:\nTraceback info:\n" + tbinfo + "\nError Info:\n" + str(sys.exc_info()[1])
    msgs = "ArcPy ERRORS:\n" + arcpy.GetMessages(2) + "\n"

    # Return python error messages for use in script tool or Python Window
    arcpy.AddError(pymsg)
    arcpy.AddError(msgs)

    # Print Python error messages for use in Python / Python Window
    print pymsg + "\n"
    print msgs

    # Print Log file
    txtFile = open(txtfile, "w")
    txtFile.write(pymsg)
    txtFile.write(msgs)
    txtFile.write(query)

    txtFile.close()
DavidBrett
Occasional Contributor
Thanks for sharing this!!

Is there a way to specify printer options using this method?
Specifically, set color or black and white, paper size, scaling, print quality, etc.?
0 Kudos
by Anonymous User
Not applicable
Thanks for sharing this!!

Is there a way to specify printer options using this method?
Specifically, set color or black and white, paper size, scaling, print quality, etc.?


The method that Luke provided is just passing some command parameters through the python subprocess module.  I am not aware of any ways to pass print settings through the command prompt.  There may be a way. 

I would recommend looking at the python CUPS module, aka [url=https://pypi.python.org/pypi/pycups]pycups[/url].  This module seems to give you control to connecting to printers as well as setting up printing properties.
0 Kudos
Luke_Pinner
MVP Regular Contributor
I would recommend looking at the python CUPS module, aka pycups.


CUPS is Linux/UNIX only.

I don't know if there's a(n easy) way to control the print output on Windows.
0 Kudos
DavidBrett
Occasional Contributor
I ended up using win32api and win32print and setting my default printer preferences.  There is a way to expose all the printer defaults, but I haven't figured out how to set them yet.

import osfrom os import path
from os import listdir
from os.path import isfile, join
import win32api
import win32print


mypath = r"\\<your path goes here>"

#list all the files in a folder
files = [ f for f in listdir(mypath) if isfile(join(mypath,f)) ]


for file in files:
    file = mypath + "\\" + file
    if "11x17" in file and "County" in file: 
        win32api.ShellExecute (
          0,
          "print",
          file,
          #
          # If this is None, the default printer will
          # be used anyway.
          #
          '/d:"%s"' % win32print.GetDefaultPrinter (),
          ".",
          0
        )
    
del files
del mypath



this will show all the properties for all your connected printers:


#Lists properties and capabilities for all the printers installed on a computer.
import win32com.client
strComputer = "."
objWMIService = win32com.client.Dispatch("WbemScripting.SWbemLocator")
objSWbemServices = objWMIService.ConnectServer(strComputer,"root\cimv2")
colItems = objSWbemServices.ExecQuery("Select * from Win32_PrinterConfiguration")
for objItem in colItems:
    print "Bits Per Pel: ", objItem.BitsPerPel
    print "Caption: ", objItem.Caption
    print "Collate: ", objItem.Collate
    print "Color: ", objItem.Color
    print "Copies: ", objItem.Copies
    print "Description: ", objItem.Description
    print "Device Name: ", objItem.DeviceName
    print "Display Flags: ", objItem.DisplayFlags
    print "Display Frequency: ", objItem.DisplayFrequency
    print "Dither Type: ", objItem.DitherType
    print "Driver Version: ", objItem.DriverVersion
    print "Duplex: ", objItem.Duplex
    print "Form Name: ", objItem.FormName
    print "Horizontal Resolution: ", objItem.HorizontalResolution
    print "ICM Intent: ", objItem.ICMIntent
    print "ICM Method: ", objItem.ICMMethod
    print "Log Pixels: ", objItem.LogPixels
    print "Media Type: ", objItem.MediaType
    print "Name: ", objItem.Name
    print "Orientation: ", objItem.Orientation
    print "Paper Length: ", objItem.PaperLength
    print "Paper Size: ", objItem.PaperSize
    print "Paper Width: ", objItem.PaperWidth
    print "Pels Height: ", objItem.PelsHeight
    print "Pels Width: ", objItem.PelsWidth
    print "Print Quality: ", objItem.PrintQuality
    print "Scale: ", objItem.Scale
    print "Setting ID: ", objItem.SettingID
    print "Specification Version: ", objItem.SpecificationVersion
    print "TT Option: ", objItem.TTOption
    print "Vertical Resolution: ", objItem.VerticalResolution
    print "X Resolution: ", objItem.XResolution
    print "Y Resolution: ", objItem.YResolution
    print "---------------------------------------------------"

Source: http://win32com.goermezer.de/content/view/145/189/


0 Kudos
CesarMediavilla
Emerging Contributor

I got it . Thank you very much for your help. Translation courtesy of Google .

From Spain

0 Kudos