-
-
Notifications
You must be signed in to change notification settings - Fork 208
Description
PLIP (Plone Improvement Proposal)
Responsible Persons
Proposer: Jens W. Klein (@jensens)
Seconder:
Abstract
Extend plone.allowed_sizes text format to support an optional scaling mode per named scale.
Current format: name width:height
Proposed format: name width:height[:mode]
Where mode is scale (default, can be omitted) or crop (fill exact dimensions, cut off overflow).
This enables configuring cropped scales through the Image Handling Settings control panel — something currently impossible with named scales.
Motivation
ImageScaling.scale() accepts a mode parameter — but when a named scale is used (e.g. @@images/image/preview), the mode is always hardcoded to "scale":
https://github.com/plone/plone.namedfile/blob/master/plone/namedfile/scaling.py#L598
width, height = available[scale]getAllowedSizes() returns {name: (width, height)} — no mode.
There is no way to configure a named scale with crop behavior through the control panel or registry. The only option is explicit Python API calls with width/height/mode parameters.
Real-world use case: image galleries, teasers, and card layouts need exact square crops (400×400 crop, not 400×400 fit-within). Currently impossible without custom code.
Naming confusion
The existing mode names contain and cover are documented as aligned with CSS background-size but actually have swapped semantics compared to CSS:
- Plone's
containcrops. CSScontaindoes not crop. - Plone's
coverdoes not crop. CSScovercrops.
The proposed crop term avoids this confusion entirely. It means what it says: fill exact dimensions, cut off the rest.
Assumptions
plone.allowed_sizesis a free-text lines field — the format can be extended without schema changes.- Only two modes matter in practice:
scale(fit within box) andcrop(fill exact dimensions).containandcoverexist but their naming is confusing (see above). - Backward compatible: lines without
:modesuffix keep working as before (defaultscale).
Proposal & Implementation
1. Text format
preview 400:400:crop ← crop to exact 400×400
large 800:600 ← scale (default, no suffix needed)
thumb 128:128:scale ← explicit scale (same as no suffix)
2. Changes in plone.namedfile
utils/__init__.py — extend regex, return 3-tuple:
# current
pattern = re.compile(r"^(.*)\s+(\d+)\s*:\s*(\d+)$")
# proposed
pattern = re.compile(r"^(.*)\s+(\d+)\s*:\s*(\d+)(?:\s*:\s*(\w+))?$")getAllowedSizes() returns {name: (width, height, mode)} where mode defaults to "scale".
scaling.py — unpack mode from available sizes:
# current (line 598)
width, height = available[scale]
# proposed
width, height, mode = available[scale]3. Mode mapping
| Text format | Internal mode= |
Behavior |
|---|---|---|
(default / scale) |
"scale" |
Fit within box, preserve aspect ratio |
crop |
"contain" |
Fill exact dimensions, crop overflow |
cover and contain accepted as aliases for backward compat.
4. Callers to update
plone/namedfile/scaling.py:598— unpack 3-tuple, use modeplone/app/vocabularies/images.py:19—for scale, (width, height) in ...→ add mode
Deliverables
plone.namedfile— format parsing,getAllowedSizes(),scale()mode passthroughplone.app.vocabularies— adapt tuple unpackingplone.restapi— adapt scale info handling (backward compatible with older Plone versions):split_scale_info()inimaging.pyparses the mode from rawplone.allowed_sizestext lines directly (does not depend ongetAllowedSizes()), defaults to"scale"when absent — works on any Plone versionget_scales()passes mode toimages_view.scale()get_actual_scale()accounts for crop dimensions@siteendpoint already exposes rawplone.allowed_sizesstrings (no change needed)
documentation— updatedocs/classic-ui/images.md:- Document the extended format
name width:height[:mode] - Add
cropto the scaling modes reference - Clarify the
contain/covernaming vs CSS conventions
- Document the extended format
- Volto — no changes required (only uses
download,width,heightfrom scale objects; unknown fields are ignored) - No control panel UI changes needed (textarea already accepts free text)
- No migration needed (old format still valid)
Risks
Low. Backward compatible — existing name width:height lines work unchanged.
Only breakage risk: third-party code calling getAllowedSizes() and destructuring as 2-tuple. Unlikely outside core.
Participants
Metadata
Metadata
Assignees
Labels
Type
Projects
Status
Status