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 Manager
and select your QGIS Cloud database - Select Menue
Table -> Create Table
- name the new layer
images
- 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
images
and open the section fields - Open “Attributes Form”
- Select: Provide ui-file
- To get the custom UI select the path to
attribute.ui
in “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
encodeimage.py
- 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.
tool_button = dialog.findChild( QToolButton, "tool_button" )
When the ToolButton is clicked run the method get_file_name()
tool_button.clicked.connect(get_file_name)
Set the imageField Widget invisible for a nicer GUI. It is not nesseccary to see the data
image_field.setVisible(False)
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
image_field.setPlainText(encoded_image)
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 QGIS Cloud 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
images
and jump to theDisplay
section. - 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.
Prevent the 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
Stay well
Dr. Horst Düster (@moazagotl)