In 2015 we have already published a blog on this topic, which has met with great response. In the meantime a lot has changed in the QGIS world and with QGIS3 the 2015 manual can no longer be adopted 1:1. So I decided to write a new, revised blog article on this topic.
A lot of people are using QGIS Cloud as a service with ready to use QGIS webclient. It’s very easy to publish data and share maps in this way. Publishing of georeferenced images can be done with QGIS Cloud in a few steps as well. But the main problems are:
- how to upload the binary images into the cloud database?
- how to manage them?
- how to display the results?
QGIS and QGIS Cloud are offering all tools for this task.
Create a new postgis layer with QGIS:
As the first step we need to create a point layer with some mandatory columns. The prerequisite for this step is the existence of a QGIS Cloud database. If you don’t have a QGIS Cloud database yet, create one in the QGIS Cloud plugin.
- Open the
QGIS DB Managerand select your QGIS Cloud database
- Select Menue
Table -> Create Table
- name the new layer
- Create in minimum four columns:
- id bigserial
- geom (point)
- name text
- image text
Create a new dialog with QtDesigner which looks like in the image below.
For adding and managing the images a customized input GUI is needed.
add two QLineEdit Widgets and name them with the corret objectName
add two QTextEdit Widgets and name them with the corret objectName
add a QToolButton Widget with the corret objectName
or download the file attribute.ui
- Open the layer properties of layer
imagesand open the section fields
- Open “Attributes Form”
- Select: Provide ui-file
- To get the custom UI select the path to
attribute.uiin “Edit UI” and open the gui.
- Click OK
Create a Python init function for handling the image data.
When you add a new feature to the layer
images, the dialog opens but the tool button is not working. To get it working we need some Python code.
The idea behind that is to run some functionality to convert the binary image to text based base64 encoding. Let’s Python doing that job for us. QGIS offers the ability to define an init function when a custom dialog is opened. This offers a wide range of options.
- create a new text file and call it
- add the following Python code (or download the Python script encodeimage.py):
Import all nesseccary Modules and Classes from PyQt5 and QGIS
from PyQt5.QtWidgets import QTextEdit, QToolButton, QFileDialog, QLineEdit, QLabel import base64
This is the main function which will be connected with the QGIS layer dialog
def form_open( dialog, layer, featureid ): global name_field global image_field global image_preview global tool_button global file_name
Find all UI widgets and link them with the layer
name_field = dialog.findChild( QLineEdit, "name" ) file_name = dialog.findChild( QLineEdit, "filename" ) image_field = dialog.findChild( QTextEdit, "image" ) image_preview = dialog.findChild( QTextEdit, "imagePreview" )
Find the QToolButton Object to connect the conversion function.
toolButton = dialog.findChild( QToolButton, "tool_button" )
When the ToolButton is clicked run the method get_file_name()
Set the imageField Widget invisible for a nicer GUI. It is not nesseccary to see the data
Make the image preview visible with the HTML image tag
image_preview.setText('<img width="300" src="data:image/jpg;base64,%s"/>' % (image_field.toPlainText()))
Open FileDialog and convert the binary image to base64
def get_file_name(): file_path, filter = QFileDialog.getOpenFileName(None, 'Open Image File', '', '(Images *.jpg *.JPG)') if len(file_path) > 0: file_name.setText(file_path) encoded_image = ''
Read the image file and proceed the encoding
encoded_image = base64.b64encode(open(file_path, 'rb').read()).decode('utf-8')
Set the appropriate fields for storing in the QGIS layer
Set HTML img tag around the base64 image
image_preview.setText('<img width="300" src="data:image/jpg;base64, %s"/>' % (str(encoded_image)))
If you have finished editing, save this file.
Open “Attributes Form” again and click on the small Python icon at the top of the form. Then the “Python init Code Configuration” dialog opens. As source of the Python init function select ‘Load from External File’. Then select the location of the file ‘encodeimage.py’. Finally, enter the name of the initialization function. In our case the function is called ‘form_open’. Finish the configuration with OK.
Alternatively to loading the initialization function from a file, you can also enter the program code directly in the dialog. Then the program code is only connected to this project. However, if you want to pass on the code or maintain the code, it is better to maintain the code in a separate file.
Now you are able to add images and photos to your spatialite database table. But be careful because the main disadvantage of this approach is the size of the image. The conversion of a 5Mb image produces a huge base64 string. As the result it will be very wise to reduce the size of the images you want to add to the layer. If you like, you can add a check of image size to the Python module or an automatically resize of images.
A nice tool of the QGIS map canvas is the option to add maptips to a layer. When maptips are activated the images should be visible when the mouse moves over a feature of the layer
images in the map.
Create a maptip with image as content
- open the layer properties of the layer
imagesand jump to the
- add the HTML code to the Text field as you can see in the figure below:
- close the dialog with OK
- activate the maptip tool in QGIS and move over a feature of the layer
images. The name and the image are popped up.
<table> <tr><td><b>[% "name" %]</b></td></tr> <tr><td><img width="400" src="data:image/jpg;base64,[% "image" %]"/></td></tr> </table>
Some additional settings
The image is saved in the
images field. But this is only the base64 string. To prevent this from being displayed on an Identify in QGIS or in the QGIS Cloud Web Client we have to make some settings.
images field from appearing in QGIS during an identify
To prevent a particular field from appearing in QGIS we need to reopen the layer settings of the
images layer. There, select the
Attributes Form section and check the
image in the
Fields section. The options appear on the right side of the dialog. Under
Widget Type switch to
Hidden. Now the
image field no longer appears anywhere in QGIS.
Create a new virtual field with the HTML tag
Switch to the
Fields section in the layer settings. Click on the field calculator icon and create a new virtual field of type Text (string).
As expression write:
'<img width="400" src="data:image/jpg;base64,' || "image" || ' "/>'
Share your images with QGIS Cloud
What’s about to share the pictures and the geolocation of the pictures with others over the web. For this task QGIS Cloud is the right choice. QGIS Cloud is your personal spatial data infrastructure and offers OGC Web Services and ready preconfigured Web GIS clients.
save the project.
open the QGIS Cloud plugin (If you don’t have the QGIS Cloud plugin installed, than install it from the official QGIS Plugin Repository)
log in your QGIS Cloud account. (If you don’t have a QGIS Cloud account, sign up a new account).
upload the local data to your QGIS Cloud database (if you don’t have a QGIS Cloud database, create one from the QGIS Cloud plugin).
publish the project via QGIS Cloud plugin.
open the map in QGIS Cloud Web Client
here you are, it works
Dr. Horst Düster (@moazagotl)