0

I'm generating an image from QgsComposer composition through QgsLayoutExporter.exportToImage() method that allows saving the image to disk.

I wonder if there is any way to get image binary data into a variable?

I need to send this image later to a server to process, so I don't need a physical file at all. One way would be saving the file in /tmp and then deleting, but it requires unnecessary interaction with HDD and looks ugly.

I tried to find another solution using eg. generating an image from mapCanvas, but similarly, they provide only saving data to a file.

I'm using QGIS API ( 3.3.0-Master)

2 Answers 2

1

There's QgsLayoutExporter.renderPageToImage. This returns a QImsge object. Depending on your requirements, the QImage API can be used to transform the image into the required format.

1
  • Thanks for response. I tried getting QImage as you suggested, but I think I cannot export it to valid bytes variable. I tried my_qimage.bits() but couldn't read it into Reportlab's Image object (what I do through BytesIO(my_bytes_data)). Is it the right way to convert to bytes? I need it so I can send data over sockets.
    – adamczi
    Commented Aug 10, 2018 at 18:16
1

To generate buffer object with image, I ended up with a snippet like this on QGIS side:

# Open pre-prepared QGIS .qpt Composer file which consists of map image only
composition_path = 'path to qpt file'
with open(composition_path, 'rt') as f:
    content = f.read()

doc = QDomDocument()
doc.setContent(content)
c = QgsLayout(QgsProject().instance())
c.loadFromTemplate(doc, QgsReadWriteContext())

# Get the map item from Composer and set it's extent
map_item = getLayoutItemById(c, 'map', QgsLayoutItemMap)
map_item.zoomToExtent(memory.extent())
map_item.refresh()

# Export PNG to a buffer of QBuffer type
exporter = QgsLayoutExporter(c)
buffer = QBuffer()
buffer.open(QIODevice.ReadWrite)        
image = exporter.renderPageToImage(0)
image.save(buffer, 'PNG')
buffer.seek(0)

# Send payload like this to the server
payload = {
    ...,
    'map_image':base64.encodebytes(buffer.data()).decode('utf-8'),
    ...
}

This was not included in question, but if anyone wonders what can you do with the object, on the server side I would load it into PIL image like this:

image_data = payload.get('map_image')
map_image = BytesIO()
PilImage.open( 
    BytesIO(image_data.decode('base64_codec')) 
).save(map_image, format='PNG')
map_image.seek(0)
# now do whatever with the PIL object, like create a PDF where map is an element

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.