Skip to content

About

Focal points for images in Plone: detected on upload, set by editors in Volto, and crops around them in the aspect ratios of your templates.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

collective.focalpoint 🚀

Built with Cookieplone Black code style CI

Focal points for images: detected on upload, set by editors in Volto, and crops around them in the aspect ratios of your templates.

What it does

Templates show images in fixed aspect ratios: teasers at 16:9, a header square on phones, a listing at 3:2. With object-fit: cover the browser crops them around their center, so heads, buildings or the subject of a photo often fall off. This add-on keeps the subject in view.

  • Focal point detection. When an image is uploaded, its focal point is detected and stored on the image: a simple saliency estimate (detail, saturation, skin tones, a bias towards the center) with Pillow only. Where it is unsure, it stays near the center.
  • Focal point editor. In the sidebar of blocks with an image, editors click on what must stay in view, with previews of crops. It is saved on the image itself (REST service @focal-point), so it applies wherever the image is used. In Volto's image and teaser blocks (also in grids) out of the box; for other blocks, see below.
  • Crops around the focal point. image_scales (catalog metadata and REST api) gets the focal point and, per aspect ratio of the setting collective.focalpoint.crops, the largest crop around it with its own scales. Templates ask for the crop they show: smaller files, and the focal point in view.
  • object-position. Volto's Image component puts the focal point in object-position, for the cropping that object-fit: cover still does.

Requirements

  • Plone 6.1 or later, Volto 18 or later.
  • The focal_point option of plone.scale.scale.scaleImage, which is not released yet: until then, use the branch focal-point (Plone 6.2+) or 4.x-focal-point (Plone 6.1) of plone.scale, see backend/mx.ini.
  • Recommended: plone/plone.namedfile#238, so that images always have a scale as large as the original, and the original (often a much larger file) does not have to be in the srcset.

Usage

Install

Add collective.focalpoint to the backend, install it in the add-ons control panel, and add @plone-collective/volto-focal-point to the add-ons of the frontend. Installing detects the focal points of the existing images and updates image_scales in the catalog; that takes a while on a site with many images.

Crops

The registry record collective.focalpoint.crops lists the crops, one per line: an aspect ratio, then the widths of its scales.

16:9 400 800 1200 1600
4:3 400 800 1200
1:1 400 800 1200

Set it to the aspect ratios your templates use, for example in the registry.xml of your policy package. After a change, run collective.focalpoint.setuphandlers.maintenance.update_image_scales() (for example in an upgrade step) so that listings get the new crops.

In templates

Volto's Image component gets a prop crop:

<Image item={item} crop="16:9" sizes="(min-width: 1600px) 660px, 45vw" />

It uses the scales of that crop when the image has one, and the image itself otherwise. For art direction, imageSources(item, imageField, crop) gives the src, srcSet, width, height and objectPosition of an image or of a crop, for example for a <source> of a <picture> with the square crop on phones.

The setting config.settings.focalPoint.originalInSrcset decides when the original goes in the srcset: "auto" (default, only when no scale is as large as the original) or "never".

The editor in your own blocks

Wrap the schema enhancer of the block with withFocalPoint, with a function that gives the item with the image from the block data:

import { withFocalPoint, teaserImageItem } from '@plone-collective/volto-focal-point';

config.blocks.blocksConfig.myBlock.schemaEnhancer = withFocalPoint(
  config.blocks.blocksConfig.myBlock.schemaEnhancer,
  (data) => data.image, // an object browser value
  'default', // the fieldset
);

Do the same when your project replaces the schemaEnhancer of the teaser or image block, as that replaces the one of this add-on. In a sidebar of your own, render <FocalPointEditor item={item} />.

Limits

  • The detection is a heuristic: it misses small subjects in front of busy backgrounds, like cyclists in front of brick façades. Editors can correct it.
  • Pages show a new focal point after they are reloaded: the scales of a crop are cached per focal point.

Quick Start 🏁

Prerequisites ✅

Installation 🔧

  1. Clone this repository, then change your working directory.

    git clone git@github.com:collective/collective-focalpoint.git
    cd collective-focalpoint
  2. Install this code base.

    make install

Fire Up the Servers 🔥

  1. Create a new Plone site on your first run.

    make backend-create-site
  2. Start the backend at http://localhost:8080/.

    make backend-start
  3. In a new shell session, start the frontend at http://localhost:3000/.

    make frontend-start

Voila! Your Plone site should be live and kicking! 🎉

Local Stack Deployment 📦

Deploy a local Docker Compose environment that includes the following.

Run the following commands in a shell session.

make stack-create-site
make stack-start

And... you're all set! Your Plone site is up and running locally! 🚀

Project structure 🏗️

This monorepo consists of the following distinct sections:

  • backend: Houses the API and Plone installation, utilizing pip instead of buildout, and includes a policy package named collective.focalpoint.
  • frontend: Contains the React (Volto) package.
  • devops: Encompasses Docker stack, Ansible playbooks, and cache settings.
  • docs: Scaffold for writing documentation for your project.

Why this structure? 🤔

  • All necessary codebases to run the site are contained within the repository (excluding existing add-ons for Plone and React).
  • Specific GitHub Workflows are triggered based on changes in each codebase (refer to .github/workflows).
  • Simplifies the creation of Docker images for each codebase.
  • Demonstrates Plone installation/setup without buildout.

Code quality assurance 🧐

To check your code against quality standards, run the following shell command.

make check

Format the codebase

To format and rewrite the code base, ensuring it adheres to quality standards, run the following shell command.

make format
Section Tool Description Configuration
backend Ruff Python code formatting, imports sorting backend/pyproject.toml
backend zpretty XML and ZCML formatting --
frontend ESLint Fixes most common frontend issues frontend/.eslintrc.js
frontend prettier Format JS and Typescript code frontend/.prettierrc
frontend Stylelint Format Styles (css, less, sass) frontend/.stylelintrc

Formatters can also be run within the backend or frontend folders.

Linting the codebase

or lint:

make lint
Section Tool Description Configuration
backend Ruff Checks code formatting, imports sorting backend/pyproject.toml
backend Pyroma Checks Python package metadata --
backend check-python-versions Checks Python version information --
backend zpretty Checks XML and ZCML formatting --
frontend ESLint Checks JS / Typescript lint frontend/.eslintrc.js
frontend prettier Check JS / Typescript formatting frontend/.prettierrc
frontend Stylelint Check Styles (css, less, sass) formatting frontend/.stylelintrc

Linters can be run individually within the backend or frontend folders.

Internationalization 🌐

Generate translation files for Plone and Volto with ease:

make i18n

Credits and acknowledgements 🙏

Generated using Cookieplone (2.0.2) and cookieplone-templates (005674c) on 2026-11-11 18:58:54.235716. A special thanks to all contributors and supporters!

About

Focal points for images in Plone: detected on upload, set by editors in Volto, and crops around them in the aspect ratios of your templates.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages