I am trying to export a GeoTIFF using a script in the QGIS Python Console, but the exported GeoTIFF is missing most layers. The image being exported is part of a larger canvas, too big to export as a single file so I am slicing it into multiple images.
Notes:
- I am using a rectangular layer (layer_name) to set the bounds for the exported image
- I am printing out the visible layer names, to make sure they are present
- In every other respect the script works (image bounds, size, scale & DPI)
- I am using QGIS 3.26
Here is my code:
from qgis.core import (
QgsProject,
QgsMapSettings,
QgsCoordinateTransform,
QgsLayerTreeLayer,
)
from PyQt5.QtCore import QSize
from PyQt5.QtGui import QImage, QPainter
import os
def get_fully_visible_layers(node, visible_layers):
# Recursively collect visible layers (where layer and parent group is visible)
if isinstance(node, QgsLayerTreeLayer):
if node.isVisible():
# Check all parents for visibility
parent = node.parent()
while parent:
if not parent.isVisible():
return
parent = parent.parent()
visible_layers.append(node.layer())
else:
for child in node.children():
get_fully_visible_layers(child, visible_layers)
# -------- Config --------
layer_name = r"layer_name" # Name of the bounding rectangle layer
output_path = r"C:\Users\USERNAME\Desktop\Map\exported_map.tif" # Change path accordingly
dpi = 96
# -------- Get bounding layer --------
layer_list = QgsProject.instance().mapLayersByName(layer_name)
if not layer_list:
raise Exception(f"Layer '{layer_name}' not found.")
bbox_layer = layer_list[0]
# -------- Get the Extent --------
layer_extent = bbox_layer.extent()
# -------- CRS Transform (if required) --------
canvas = iface.mapCanvas()
project_crs = QgsProject.instance().crs()
layer_crs = bbox_layer.crs()
if layer_crs != project_crs:
xform = QgsCoordinateTransform(layer_crs, project_crs, QgsProject.instance())
extent = xform.transform(layer_extent)
else:
extent = layer_extent
# -------- Calculate image size based on current canvas scale --------
# Calculation of map_units_per_pixel for CRS is in meters (e.g. EPSG:3857)
scale = round(canvas.scale())
map_units_per_pixel = (scale * 0.0254) / dpi
# Compute image dimensions
image_width = int(extent.width() / map_units_per_pixel)
image_height = int(extent.height() / map_units_per_pixel)
# -------- Map settings --------
map_settings = QgsMapSettings()
# Collect all visible layers, even inside groups
layer_tree_root = QgsProject.instance().layerTreeRoot()
visible_layers = []
get_fully_visible_layers(layer_tree_root, visible_layers)
# Match order of visible_layers to layerTree.layerOrder()
draw_order = layer_tree_root.layerOrder()
visible_layers = [layer for layer in draw_order if layer in visible_layers]
# Print visible layers list
print("Rendering layers:")
for lyr in visible_layers:
print(f"- {lyr.name()}")
# Apply map settings
map_settings.setLayers(visible_layers)
map_settings.setExtent(extent)
map_settings.setOutputSize(QSize(image_width, image_height))
map_settings.setOutputDpi(dpi)
# -------- Render and save image --------
image = QImage(image_width, image_height, QImage.Format_ARGB32_Premultiplied)
image.fill(0)
painter = QPainter(image)
render = QgsMapRendererParallelJob(map_settings)
render.start()
render.waitForFinished()
render.renderedImage().save(output_path, "tif")
painter.end()
print(f"------------------------------")
print(f"Extent Layer - {layer_name}")
print(f"Map Scale - 1:{scale}")
print(f"Image Size - {image_width} x {image_height}")
print(f"DPI - {dpi}")
print(f"------------------------------")
print(f"GeoTIFF saved - {output_path}")
print(f"------------------------------")
What I would like to achieve, but automatically via a script, is exactly what is generated when you use the menu Project -> Import/Export -> Export Map to Image, and on that dialog by selecting Calculate from: [select a layer] to calculate the extent.
Is there anything in the script that may be preventing all layers from rendering? I note that doing it via the menu takes a little longer so clearly not all layers are rendering with the script. Does anyone have any success in exporting a GeoTIFF image with all layers showing?