I am making an inventory of certain buildings in a city. In the object attributes, I'm - amongst other infos - linking to pictures of that building, so that in the layout, for each building, you have a map that shows the location of the building, a description of the building and some pictures of it.

There is a possibility to add up to five pictures, but not all buildings will have five (e.g. in some cases, we only have a picture with a general view of the building, in others we will also have pictures with details of certain parts of the construction). First I noticed, that big crosses are shown when a building doesn't have all five pictures, so I added a CASE WHEN ELSE, which makes sure that when there is a picture, the picture is shown, but when there isn't one, there is just nothing instead of a big cross:

  WHEN "Foto_2" > 0 THEN @project_home  + '/' +   "Foto_2"
  ELSE ' '

That works very well, but now, I noticed that portrait pictures are automatically turned and shown as landscape pictures. Is there a way to have an automatic check whether a picture is portrait or landscape and have it adapted accordingly? Because depending on the building, each picture could be landscape or portrait, it's unfortunately not so that for each building picture 1 is landscape, picture 2 is portrait etc.

I would need something like:

WHEN "Foto_2" < 0 THEN ' '
  WHEN bounds_width($area) > bounds_height($area)
  THEN @project_home  + '/' +   "Foto_2" landscape
  ELSE @project_home  + '/' +   "Foto_2" portrait

That doesn't work, but I don't know how to describe the landscape/portrait requirement, nor how to build multiple WHEN ELSE THEN-checks).

  • 1
    This seems like it might be a quirk of QGIS, so it might be solved by making a change that seems unrelated. Like, instead of supplying a blank string when the photo doesn't exist, use a placeholder image. – csk Dec 2 '19 at 17:49
  • 1
    Or you could add data-defined rotation based on the bounds_width($area) > bounds_height($area) comparison. In the image item properties, scroll down to the section called "rotation" (not "image rotation"). – csk Dec 2 '19 at 17:50
  • 1
    I just adapted the "rotation", with this: CASE WHEN bounds_width($area) > bounds_height($area) THEN 0 ELSE 90 END But somehow it now turns all pictures, even the landscape ones... (and it turns them so that an 90mmx60mm is now shown as an 60mmx90mm, whereas it should be 40mmx60mm, so that the height of each picture is the same. Sorry, forgot to mention that). – HaP Dec 2 '19 at 17:59
  • 1
    I took a second look at your bounds_width($area) > bounds_height($area) expression, and I don't think it actually has anything to do with the image width and height. bounds_width takes a geometry as its input. $area is not a geometry so it's not a valid input here. That expression is basically pointless, which means we're even further from a solution than I initially thought. – csk Dec 2 '19 at 18:05

As mentioned by @csk you can use your own function to get the image format. See code and images below how to use it:

from qgis.core import *
from qgis.gui import *
from scipy import misc
@qgsfunction(args='auto', group='Custom')
def image_format(imgsrc, feature, parent):
    Calculates if a image is portrait or landscape from the image source.
    image = misc.imread(imgsrc)
    if image.shape[0]>image.shape[1]:
        result = "portrait"
    elif image.shape[0]<image.shape[1]:
        result = "landscape"
        result = "quadratic"
    return result

enter image description here

enter image description here

  • Wow, thank you both of you! Glad I asked, because in no way would I ever have found this solution by myself (which the fact that I used the bounds_width and $area completely wrong proves even more...). I'm at home now, but will try the solution in the office tomorrow and will let you know if it worked! – HaP Dec 2 '19 at 21:07
  • I first tried the solution eurojam suggested, because it indeed seemed "a bit more work now, less in the future". However, when I input the code like this and then in the layout for each picture enter the following code (so as to have both the checking if the image is actually there as the checking of the format): CASE WHEN "Foto_2" > 0 THEN image_format(@project_home + '/' + "Foto_2") ELSE ' ' END it always shows a cross (meaning no picture is found). I even tried it, with just the image_format(@project_home + '/' + "Foto_2") but the result is the same. – HaP Dec 3 '19 at 9:17
  • it should be something like image_format(@project_home + '/' + 'Foto_2.jpg') - the function want to get a path to the image with filename. Is project_home + '/' + 'Foto_2' just a path to several photos? – eurojam Dec 3 '19 at 11:12
  • Yes, it's a path, because each building links to different pictures. Building A will have 001.jpg as Foto_1, 002.jpg as Foto_2 etc. Building B will have 006.jpg as Foto_1, 007.jpg as Foto_2 etc. Al these pictures are in the same folder, but I can't just link to one specific picture, because otherwise the atlas will just show that one picture instead of showing the specific ones for each building. All pictures are on a protected server, which is way we need to work with the @project_home/ – HaP Dec 3 '19 at 15:38
  • Not a protected server, sorry (wanted to edit, but was too late). All pictures are on a server with a path that is apparently too long for QGIS, because wenn we inserted the first picture via a normal path, it wouldn't take it. That's why we need to work with the @project_home/Foto_2 instead of D://folder/001.jpg. I tried just adding the .jpg, but then it says "Auswertungsfehler: Kann '@project_home + ' nicht in Fließkommazahl umwandeln". In English I guess that's "cannot convert to float number". – HaP Dec 3 '19 at 15:50

As far as I can tell there's no built-in function that can detect whether an image is portrait or landscape.

The best method I can come up with is to add another 5 fields to the attribute table, one for each photograph. Call then "portrait_1", "portrait_2", etc. For every single photo, manually enter 'yes' or 'y' or 1 if the photo has portrait orientation, and 'no' or 'n' or 0 if the photo has landscape orientation. Then use an expression like this to control the rotation:

if("portrait_2" = 1, 0, 90)

This method requires you to input a lot of new data into your attribute table. It's not a great solution, but it's the best one I can think of that doesn't require any coding.

A more efficient solution might be possible if you have some coding ability. It's possible to use pyqgis code to define a custom function. So perhaps you could write code to define a function that checks on the orientation of the photograph, and use that function to control the rotation. See the QGIS Manual section about defining a custom function for more information on setting up a custom function. See the PYQGIS Developer Cookbook for pyqgis coding info.

  • I also tried this one and although indeed laborious, it seemed to work for the first object I checked in the atlas. One problem was that the portrait picture was shown in a pretty random spot, but most of all: when I checked other buildings, some landscape pictures where all of a sudden also shown as portrait (but seemingly completely random, so not every picture_1 was landscape and every picture_2 portrait. I'm guessing the pictures themselves might have traits that define them as being portrait or landscape, without it actually being so. Could that be? – HaP Dec 3 '19 at 9:25
  • Sorry, I'm somehow very limited in the amount of characters I can write... Would still prefer a coding solution, since we only have 30 buildings in this test project (so a maximum of 150 pictures), but we have other projects with up to 500 buildings, which might mean 2500 pictures that we have to define as being portrait or landscape, which is a lot of work to do manually. – HaP Dec 3 '19 at 9:28

We found a solution for this problem: by taking away the "portrait/landscape"-property of the pictures (which can be done with certain photo-editors), QGIS was somehow able to recognise the orientation of the pictures without any problems and now shows landscape pictures as 90x60mm and portrait pictures as 40x60mm. Do not ask me how it works exactly, but it does, so no coding or other changes in QGIS itself necessary :)

Your Answer

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

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