2

I am creating a QGIS project with a view to being exportable to QField to work offline. I want to be able to take pictures in the field and store them directly into PostgreSQL as binary data. I have followed Michael Miller's Udemy course 'QField Quickstart', but he just show how to save them locally in the device. According to the tutorial, I have added a varchar field to my spatial table and then configured the attribute form editor to employ the attachment widget with relative paths. So far so good, I can take photos in the field and store them in a folder located in the same directory where the .qgs file containing the QField project is. To be able to store the images as binary data in my PostgreSQL database, I have concocted a workaround that I believe is on the right course but, for some reason isn't working, and why is what I am asking here.

I have added another field of bytea type, named img_blob, to the table and configured the attribute form in such a way that, when a new feature is created and a photo is taken for it, the field is filled with a default value, namely, the open image file. I have also tried to encode the content of the file and fill img_blob with a base64 string, instead of byte, but to no avail. When I sync the QField project with the QGIS one I get the field to be filled with a BLOB in PostGIS, but, unfortunately, when I decode it I find that it is empty.

This is a snip of the form for img_blob field:

enter image description here

You can see that a preview is visible that says BLOB.

This is a snip of the expression that sets the default value for img_blob field:

enter image description here

You can see that here no preview shows for the feature Octavi.

And this is the function saveBinaryData(img_path) that I have created to perform the operation of opening the photo file at the location passed as a parameter and returning it. The photo file path is retrieved from the field with the attachment widget that I use to take the pictures, the one that I have referred to earlier:

from qgis.core import *
from qgis.gui import *
import base64
import io

@qgsfunction(args="auto", group='Custom')
def saveBinaryData(image, feature, parent):

#filerelpath = "[% <img_path> %]"; 
filerelpath = image
if (filerelpath is not None and len(filerelpath) > 0):
    projectpath = qgis.core.QgsProject.instance().fileName(); 
    path = os.path.dirname(str(projectpath)) ;
    file = os.path.abspath(os.path.join(path, filerelpath)); 
else:
    msg = QMessageBox()
    msg.setText('No attachment');
    msg.show();
with open(file, "rb") as image_file:
    encoded_string = image_file.read()
return encoded_string

I have also tried this one:

from qgis.core import *
from qgis.gui import *
import base64
import io

@qgsfunction(args="auto", group='Custom')
def saveBinaryData(image, feature, parent):

#filerelpath = "[% <img_path> %]"; 
filerelpath = image
if (filerelpath is not None and len(filerelpath) > 0):
    projectpath = qgis.core.QgsProject.instance().fileName(); 
    path = os.path.dirname(str(projectpath)) ;
    file = os.path.abspath(os.path.join(path, filerelpath)); 
else:
    msg = QMessageBox()
    msg.setText('No attachment');
    msg.show();
with open(file, "rb") as image_file:
    encoded_string = base64.b64encode(image_file.read())
return encoded_string

Lastly, this is a modification of the previous code that I have tested out of QGIS which returns the binary data contained in a .jpg file:

with open("DCIM/img.jpg", "rb") as image_file:
encoded_string = image_file.read()
print(encoded_string)

What do you think is preventing this from working?

6
  • QField does not yet support python functions. Can you do this as a post-survey process from QGiS.
    – Oisin
    Nov 24 at 19:21
  • Thank you for your comment. Nevertheless, I differ from what you say about QField not supporting python functions yet. Are you really sure about that? The fact is that I have managed to get this to work in QField, and I believe it is a python function: 'to_int(array_to_string(overlay_nearest('revisiones', idArbol)))' This code inserts into a layer's attribute a default value taken out from the nearest feature in another layer ('revisiones'). I have tried it boyh in QGIS and in QField and it works the same.
    – Octavi89
    Nov 28 at 11:08
  • as far as I know, python expressions work, but not functions
    – Oisin
    Nov 28 at 11:11
  • I am pretty sure that both are supported. In the end, an expression resorts to functions to transform and return a value.
    – Octavi89
    Nov 28 at 17:59
  • Certainly there was no python script support in 2019. I have not seen that it has been added. I think you should check again.
    – Oisin
    Nov 28 at 19:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.