I am trying to render a number of related QgsRasterLayer objects that are related to eachother (they are slippy-type tiles). Ideally I would like one item in the legend that can have its position changed (i.e. move above or below other legend items) and add custom actions/properties dialog to, but have the actual rendering of the tiles be done by QgsRasterLayer.
My first approach was to attempt to subclass QgsPluginLayer and override the draw() method to call QgsRasterLayer.draw() for each of my loaded rasters. This does nothing, even if layers are added to the QgsMapLayerRegistry.
def draw(self, renderContext):
for rasterlayer in self.loadedlayers.values():
rasterlayer.draw(renderContext)
My second approach was to create a group in the legend that is somehow hidden. I can add the layer to the layer tree using
mygroup = QgsProject.instance().layerTreeRoot().addGroup("mygroup")
for rasterlayer in self.loadedlayers.values():
mygroup.addMapLayer(rasterlayer)
but it doesn't seem possible to hide this group from the user. From Showing only some layers in QGIS legend? it doesn't seem like there is an alternative. I feel as though there is an easy solution to this that I'm not seeing.
EDIT: I tried creating a QgsMapLayerRenderer object that renders the layer to an image using a QgsMapRenderer, and while this occasionally works, it often produces output that appears to have elements of the current screen in the output image (maybe having something to do with using a QgsMapRenderer() while one is already invoked on the current thread?). In my QgsPluginLayer I have:
def createMapRenderer(self, context):
return MultiRasterRenderer(self, context)
And my QgsMapLayerRenderer is this (includes some debugging output):
class MultiRasterRenderer(QgsMapLayerRenderer):
def __init__(self, layer, context):
QgsMapLayerRenderer.__init__(self, layer.id())
self.layer = layer
self.context = context
def render(self):
fout = open("/Users/dewey/Desktop/outputdump.txt", "w")
rendererContext = self.context
if len(self.layer.loadedlayers) > 0:
img = QImage(QSize(self.context.painter().device().width(),
self.context.painter().device().height()),
QImage.Format_ARGB32_Premultiplied)
painter = QPainter()
painter.begin(img)
painter.setRenderHint(QPainter.Antialiasing)
render = QgsMapRenderer()
render.setLayerSet([layer.id() for layer in self.layer.loadedlayers.values()])
render.setProjectionsEnabled(True)
render.setDestinationCrs(rendererContext.coordinateTransform().destCRS())
fout.write("Context extent: " + rendererContext.extent().toString() + "\n")
if render.setExtent(rendererContext.extent()):
render.setOutputSize(img.size(), img.logicalDpiX())
render.render(painter)
painter.end()
img.save("/Users/dewey/Desktop/output.jpg")
rendererContext.painter().drawImage(0, 0, img)
fout.write("Render extent: " + render.extent().toString() + "\n")
else:
fout.write("render.setExtent() returned false\n")
else:
fout.write("No tiles to load, skipping rendering")
fout.close()
return True