TransWikia.com

Batch export rasters as rendered images

Geographic Information Systems Asked on August 28, 2020

I want to export a lot of raster layers as rendered images. After looking around, I got to this code:

myDir = 'e:/Data/'
layers = [layer for layer in QgsProject.instance().mapLayers().values()]
pipe = QgsRasterPipe()
for layer in layers:
   extent = layer.extent()
   width, height = layer.width(), layer.height()
   renderer = layer.renderer()
   provider=layer.dataProvider()
   crs = layer.crs().toWkt() 
   pipe.set(provider.clone())
   pipe.set(renderer.clone())
   file_writer = QgsRasterFileWriter(myDir + layer.name() + ".tif")
   file_writer.writeRaster(pipe,
                           width,
                           height,
                           extent,
                           layer.crs())

But when I run it, I get this error:

Traceback (most recent call last):
  File "C:PROGRA~1QGIS3~1.12appsPython37libcode.py", line 90, in runcode
    exec(code, self.locals)
  File "<input>", line 1, in <module>
  File "<string>", line 6, in <module>
AttributeError: 'QgsVectorLayer' object has no attribute 'width'

I’m using QGIS 3.12.2.
Any suggestions?

One Answer

To help you understand the cause of the error, in the block of code you are iterating through all the layers loaded in the current project. In each iteration, you are calling methods such as width() and height() on the object referenced in the layer identifier. The object stored in this reference changes dynamically on each iteration of the for loop. I am guessing you have at least one vector layer loaded in your project as well as raster layers. Since QgsVectorLayer objects do not have the width() or height() methods, when the for loop hits a vector layer the error you received is raised.

This can be avoided by adding a conditional to the list comprehension so that only QgsRasterLayer objects are collected. You could use something like:

if isinstance(layer, QgsRasterLayer)

However, this would also include WMS layers etc. which may not be what you want. I used:

if layer.dataProvider().name() == 'gdal'

The code below is working for me (tested in 3.14.15). I have made a few other small changes. Since 3.8 you should also pass a QgsCoordinateTransformContext() argument to the writeRaster() method.

See: https://qgis.org/api/classQgsRasterFileWriter.html#a16e7914edef28fd41db83f599224f560

Also, I recommend using os.path.join() for constructing file path strings.

import os

myDir = 'e:/Data'
project = QgsProject().instance()
layers = [layer for layer in QgsProject.instance().mapLayers().values()
            if layer.dataProvider().name() == 'gdal']
pipe = QgsRasterPipe()
for layer in layers:
    pipe.set(layer.dataProvider().clone())
    pipe.set(layer.renderer().clone())
    output_path = os.path.join(myDir, '{}.tif'.format(layer.name()))
    file_writer = QgsRasterFileWriter(output_path)
    file_writer.writeRaster(pipe,
                           layer.width(),
                           layer.height(),
                           layer.extent(),
                           layer.crs(),
                           project.transformContext())

Correct answer by Ben W on August 28, 2020

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP