I'm not sure that this answers the OP's question, but I found this after searching for how to pad a geotiff with gdal. I am writing this answer because I tried the method of @ProudGIS and I was getting strange behavior. The output tif or vrt using -projwin was 8 pixels off in the y-direction and 12 pixels off in the x-direction after padding. All the metadata was correct for the padded tiff (i.e. origin, resolution, and nrows/ncols). I couldn't figure out the problem, so I wrote some code that pads a numpy array and writes it to a new tiff/vrt.
import numpy as np
import gdal
import os
def pad_geotiff(pathtopad, npad, outpath=0, padval=0):
"""
Pads a geotiff image by adding npad pixels to each edge.
"""
base, folder, file, ext = gh.parse_path(pathtopad)
if outpath == 0:
outpath = os.path.join(base,folder,file) + '_pad' + ext
topad = gdal.Open(pathtopad)
gt = topad.GetGeoTransform()
colortable = topad.GetRasterBand(1).GetColorTable()
data_type = topad.GetRasterBand(1).DataType
Itopad = topad.ReadAsArray()
ulx = gt[0] - gt[1] * npad
uly = gt[3] - gt[5] * npad
# lrx = gt[0] + gt[1] * (topad.RasterXSize + npad)
# lry = gt[3] + gt[5] * (topad.RasterYSize + npad)
# Make new geotransform
gt_new = (ulx, gt[1], gt[2], uly, gt[4], gt[5])
# Make padded raster (pad with zeros)
raster = np.pad(Itopad, npad, mode='constant', constant_values=padval)
write_tile(raster, gt_new, topad, outpath, dtype=data_type, color_table=colortable)
return outpath
def write_tile(raster, gt, data_obj, outputpath, dtype=gdal.GDT_UInt16, options=0, color_table=0, nbands=1, nodata=False):
width = np.shape(raster)[1]
height = np.shape(raster)[0]
# Prepare destination file
driver = gdal.GetDriverByName("GTiff")
if options != 0:
dest = driver.Create(outputpath, width, height, nbands, dtype, options)
else:
dest = driver.Create(outputpath, width, height, nbands, dtype)
# Write output raster
if color_table != 0:
dest.GetRasterBand(1).SetColorTable(color_table)
dest.GetRasterBand(1).WriteArray(raster)
if nodata is not False:
dest.GetRasterBand(1).SetNoDataValue(nodata)
# Set transform and projection
dest.SetGeoTransform(gt)
wkt = data_obj.GetProjection()
srs = osr.SpatialReference()
srs.ImportFromWkt(wkt)
dest.SetProjection(srs.ExportToWkt())
# Close output raster dataset
dest = None
def parse_path(path):
"""
Parses a file or folderpath into: base, folder (where folder is the
outermost subdirectory), filename, and extention. Filename and extension
are empty if a directory is passed.
"""
if path[0] != os.sep:
path = os.sep + path
filename = ''
extension = ''
split_for_ext = path.split('.')
if len(split_for_ext) > 1:
extension = '.' + split_for_ext[-1]
else:
extension = ''
# Remove trailOing '/'
path = os.path.normpath(split_for_ext[0])
if len(extension) > 0:
filename = path.split(os.sep)[-1]
path = os.path.join(*path.split(os.sep)[:-1])
path = list(filter(None,path.split(os.sep)))
folder = path[-1]
base = os.sep + os.path.join(*path[:-1])
return base, folder, filename, extension
I think all the options are self-explanatory. Provide the path to pad_geotiff and a pad width (npad). Optionally provide output filepath (outpath) and the value to use to pad (padval). It will write a padded geotiff and return the path of this geotiff (outpath).
You can pass in custom creation options to write_tile if you want to save with compression, set blocksize, etc. For example:
options = ['COMPRESS=PACKBITS',
# 'NUM_THREADS=ALL_CPUS',
'PREDICTOR=2',
'BLOCKXSIZE=256',
'BLOCKYSIZE=256',
'TILED=YES']
NODATA
, but also where the tile bounds exceeded the original raster. I probably should have mentioned the TMS tiling constraint in the original question. :/-te
, set target extent, and-hidenodata
, "...Useful when you want to control the background color of the dataset. By using along with the -addalpha option, you can prepare a dataset which doesn't report nodata value but is transparent in areas with no data."gdalwarp
is not an efficient approach here and takes a long time. I just need to pad as in a raster array ops. I'm testing this with Sentinel-2 10m global data. Any further thoughts here? thanksgdalbuildvrt
approach.