Convert multi-page PDF file to TIFF


#
# @date 18/08/2015
# @author Cindy Williams
#
# Converts a range of pages from a pdf to separate tiff
# files using the PDF to TIFF tool added at ArcGIS 10.3.
# For very basic conversion, with minimal error handling.
#
# For use as a standalone script.
#
import arcpy
import os
def convertPDFtoTIFF(in_pdf, out_folder, out_tiff, start_page=1, end_page=1):
if start_page > end_page:
print("The start page number cannot exceed the end page number.")
else:
for i in range(start_page, end_page + 1):
out_tiff_name = os.path.join(out_folder, out_tiff + str(i) + ".tif)
arcpy.conversion.PDFtoTIFF(in_pdf, out_tiff_name, pdf_page_number=i)
print("Processed page " + str(i))
pdf_in = r"C:\Some\Arb\Folder\test.pdf"
tif_folder = r"C:\Some\Arb\Folder\tiffs"
convertPDFtoTIFF(pdf_in,tif_folder, "Page_", 2,9)
print("Script complete.")

A new tool was added to ArcGIS 10.3 to convert a page in a PDF to TIFF. This is especially useful for the asset management work I do, as I often get pdf drawings or maps which need to be georeferenced. I created a function to wrap around the ArcGIS one to enable the conversion of more than one page in the pdf at a time.

By default, the function will only convert the first page. Specifying a start and/or end page will override the defaults. Link to the code is here.

Reformat all layer names in an ArcMap document

*Before I get into today’s script, I’ve noticed that the embedded gists do not appear on mobile devices when accessing the feed for this blog via Feedly or some other RSS reader. The post needs to be opened in a web browser to view the code. I’ll also be including a link to it at the end of the post.

When I create feature classes for asset management data manually instead of automatically, I always make sure to name them consistently. However, I rarely change the feature class alias manually. This means that when I need to pull all the layers into a map to create a kml, I need to rename each layer.

Which is why I turn to Python instead.


#
# @date 14/08/2015
# @author Cindy Williams
#
# Quickly formats the names of all the layers in a map
# document. In this example, the part of the name before
# the first full stop is removed, underscores are replaced
# spaces, a regex is used to insert spaces before capitals
# and the string is converted to proper case.
#
# For use in the Python window in ArcMap.
#
import arcpy
import re
mxd = arcpy.mapping.MapDocument("CURRENT")
lyrs = arcpy.mapping.ListLayers(mxd)
for lyr in lyrs:
new_name_replaced = lyr.name.split(".")[1].replace("_", " ")
new_name_spaced = re.sub(r"(\w)([A-Z])", r"\1 \2", new_name_replaced)
lyr.name = new_name_spaced.title()
arcpy.RefreshTOC()

Of course, the way the name gets split will change depending on the current format of the names. In this instance, the part of the name that I needed occurred after the first full stop, and contained underscores which needed to be replaced by spaces. I then used a regular expression to insert spaces between InitialCaps words.

Link to the code is here.

Create random points in a polygon

I needed to create random points inside polygons for some testing I needed to do. Since I only had a Standard Licence available (and therefore no access to the Create Random Points tool that I used to POST random points as ESRI JSON to a REST endpoint), I decided it was as good a time as any to write a tool in Python.


#
# @date 06/08/2015
# @author Cindy Williams
#
# Creates random points in each polygon feature
# without the need for an Advanced licence to run
# the Create Random Points tool.
#
# For use in the Python window in ArcCatalog.
#
import arcpy
import random
arcpy.env.workspace = r"C:\Some\Arb\Folder\work.gdb"
ftr_polys = "ftr_poly"
ftr_points = "ftr_points"
fields = ["SHAPE@", "Name"]
cursor_ins = arcpy.da.InsertCursor(ftr_points, fields)
with arcpy.da.SearchCursor(ftr_polys, fields) as cursor:
for row in cursor:
num_points = random.randint(1, 11)
poly_ext = [row[0].extent.XMin,
row[0].extent.XMax,
row[0].extent.YMin,
row[0].extent.YMax]
for n in xrange(num_points):
x = random.uniform(poly_ext[0], poly_ext[1])
y = random.uniform(poly_ext[2], poly_ext[3])
randpoint = [arcpy.PointGeometry(arcpy.Point(x, y)), row[1]]
cursor_ins.insertRow(randpoint)
del cursor_ins

After creating an InsertCursor on the point feature class, I iterate over the polygon feature class using a SearchCursor. In Line 25, a random number is chosen between 1 and 10 to determine the number of points that will be created for that feature. The extent of the current feature is stored in Line 26.

The actual points are created in Lines 30 – 34. For each point, a random floating point number within the polygon’s extent is chosen as the x and y coordinates. A point feature is created using the coordinates to build the geometry, as well as the name of the polygon feature. The point feature is then inserted into the point feature class.

Segment line at chainage points using a table

I have a table containing a description field and an integer field which has values along the line. I need to split each line according to the values in the table.


#
# @date 04/08/2015
# @author Cindy Williams
#
# Creates segments along a selected line feature
# by splitting it according to a table of measures
# and saving it in a new feature class.
#
# For use as a standalone script.
#
import arcpy
arcpy.env.workspace = r"C:\Some\Arb\Folder\work.gdb"
selected_feature = "Line1"
selected_field = "Name"
qry = """ "{0}" = '{1}' """.format(selected_field, selected_feature)
# Get the selected geometry
line_geom = arcpy.da.SearchCursor("ftr_lines", "SHAPE@", qry).next()[0]
fields_fc = ["SHAPE@", "Description"]
cursor_ins = arcpy.da.InsertCursor("ftr_segments", fields_fc)
fields_tbl = ["Measure", "Description"]
start = 1 # Placeholder for previous row value
with arcpy.da.SearchCursor("tbl_measures", fields_tbl, qry) as cursor_sea:
for row in cursor_sea:
if start == 1:
start = 0
print("Handled first row")
else:
end = row[0]
segment_geom = line_geom.segmentAlongLine(start, end)
segment = [segment_geom, row[1]]
cursor_ins.insertRow(segment)
start = row[0]
del cursor_ins

segmentAlongLine requires a start and end value for where the line needs to be cut. The end value is the current row’s measure value, while the start value is the previous row’s end value. After trying to move the cursor back and forth, I decided the best way to achieve this would be to simply store the row’s value in the start variable.

The script inserts the segments into an existing line feature class.