Skip to content

Image management & delivery

There are two main sources of images for the gallery site: Collection images and CMS images. In each case we need to differentiate between image files and image objects.

  1. Image files: The actual image files (comprising bitmap data and metadata), predominantly in JPEG format. These are stored in Azure Blob Storage.
  2. Image objects: The database representation of these images, consisting of links to the image files, as well as numerous attributes and methods defined by the model instance and inherited parent class.

1. Collection Images

Backend

  1. The Photography Department uploads hi-res master images to the iBase DAM system. Here they are were tagged with subject index terms (this stopped in ?2018) and IPTC metadata is added.
  2. The Image Loader Java application creates a 'four-pack' of JPEGs (sizes 7 through 10) for newly detected imagery and saves these in an INTERNET/ directory on the JavaNet server, in a format based on the artwork's acquisition number (acno): {acno_initial}/{acno_fragment}/{acno}_{size}.jpg. For example: T/T08/A08234_9.jpg
  3. After the CIS updates, the INTERNET/ directory is rsynced to a shared mountpoint in the WHAM stack (azT-p-web-respg:/apps/shared_files/art/images/work/)
  4. The Image Organiser Java application (running on azT-p-web-respg) checks the CIS image records' copyright status and sorts each file into the art/images/work or art/images.not-cleared/ folder, maintaining the directory structure outlined above. (NB: the Java Image Organiser will soon be replaced by a Python script, run as a management command in the Wagtail environment).
  5. Via a cron job on the old Drupal server (azT-p-app-drp01), the shared_files/art/ folder is rsynced to the /art Blob Container in the aztateprdewdgwgtailst1 Azure Storage account.
  6. Fastly routes requests to media.tate.org.uk to this Azure host, so images are finally hosted via URLs like: https://media.tate.org.uk/art/images/work/P/P06/P06286_10.jpg

Frontend

Until recently the Collection imagery was being rendered by the same picture_tag template tag as the CMS images, but since the Collection Pages Redesign, we are using a React frontend. The rendered HTML, however, is the same – currently dependent on the supplied four-pack:

<picture>
  <source type="image/jpeg"
    srcset="
      https://media.tate.org.uk/art/images/work/P/P06/P06286_7.jpg 94w,
      https://media.tate.org.uk/art/images/work/P/P06/P06286_8.jpg 188w,
      https://media.tate.org.uk/art/images/work/P/P06/P06286_9.jpg 537w,
      https://media.tate.org.uk/art/images/work/P/P06/P06286_10.jpg 1131w
      "     
    sizes="
      (max-width: 94px) 94px,
      (max-width: 188px) 188px,
      (max-width: 537px) 537px,
      1131px
    ">
  <img alt="" src="/static/images/placeholder/placeholder-4x3.gif">
</picture>

2. CMS Images

Backend / Frontend

Wagtail's CMS images are generated by client calls to the CustomImage model, which inherits from Wagtail's AbstractImage model. The get_rendition() method is extended in CustomImage to preserve the IPTC metadata in the original image and to check the Redis cache for prefetched renditions. (Note: something about this override and its changing of the Filter object to IPTCPreservingFilter caused universal cache key mis-matches which brought down the site in February '24 when attempting to upgrade from 5.0 to 5.2. Possibly due to 5.2 returning a dict of Rendition instances rather than a single instance?)

Responsive images are generated via the custom picture_tag template tag, which takes a tuple of 'sizes' attributes (as defined in the PICTURE_OPTIONS constant) and converts this to a list of rendition specs. This means when the template initially renders the following HTML, Wagtail will generate seven rendition sizes:

<picture>
  <source 
    srcset="
      https://media.tate.org.uk/cms/images/.width-340_0T4h5ZV.jpg 340w,
      https://media.tate.org.uk/cms/images/.width-420_ivMC2wE.jpg 420w,
      https://media.tate.org.uk/cms/images/.width-540_0T4h5ZV.jpg 540w,
      https://media.tate.org.uk/cms/images/.width-680_XxNaafu.jpg 680w,
      https://media.tate.org.uk/cms/images/.width-840_2X405ZV.jpg 840w,
      https://media.tate.org.uk/cms/images/.width-1200_9M055Zx.jpg 1200w,
      https://media.tate.org.uk/cms/images/.width-1440_0F4u7Z3.jpg 1440w
    "
    sizes="
      (max-width: 340px) 340px,
      (max-width: 479px) 420px,
      (max-width: 600px) 540px,
      (max-width: 840px) 680px,
      (max-width: 1023px) 840px,
      (max-width: 1420px) 1200px,
      1440px
    ">
  <img alt="" src="https://media.tate.org.uk/cms/images/.width-340_0T4h5ZV.jpg"
    loading="lazy" width="340" height="461" data-current-size="0-0">
</picture>

While this delivers improved granularity for various sized devices, it does put a load on the server, and can generate a huge number of image files. (There are currently 1,638,660 images in the Wagtail media directory!)