Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fill image transform setting #12214

Merged
merged 42 commits into from
Feb 4, 2023

Conversation

brianjhanson
Copy link
Contributor

@brianjhanson brianjhanson commented Oct 27, 2022

Description

Adds an additional fill parameter to image transforms.

The value of fill must be either a hex value (3 or 6 digits) or the string transparent.

When the transform mode is set to fit and a fill color is provided, the fill color will be used to fill any empty pixels surrounding the image so the final image size is always equal to the transform sized passed in.

You can also use position in order to control where within the transform space the image should appear.

Within the UI there's a new "Fill empty pixels" checkbox that will show or hide the color field for the fill.

CleanShot.2022-10-27.at.14.01.57.mp4

Related issues

#8848

To-Do

  • Support for animated files (gif, webp)
  • Make sure non-raster images don't break

@linear
Copy link

linear bot commented Oct 27, 2022

DEV-239 `fill` image transform setting

fill should be checked whenever there are transforms where the resulting image is going to be smaller than the specified width and height.

  • When using mode=fit for any image with a different aspect ration than the target dimensions
  • When upscaleImages is false and the resulting image is smaller than either of the target dimensions

In these cases, if fill is specified, the resulting image should be set to the same width and height as the transform’s target dimensions, with any whitespace surrounding the image filled in based on whatever fit is set to.

Possible values could be:

  • a hex value (possibly supporting an alpha channel for transparent PNGs)
  • transparent (supported for transparent PNGs; fall back to #ffffff)

This will be useful for cases where you need something that looks like fit visually, but absolutely need the image to be a certain size (e.g. HTML email, where CSS support is limited).

@brianjhanson brianjhanson marked this pull request as ready for review October 27, 2022 21:46
@brianjhanson brianjhanson requested a review from a team as a code owner October 27, 2022 21:46
@brianjhanson brianjhanson changed the base branch from develop to 5.0 October 27, 2022 21:46
@brianjhanson brianjhanson changed the base branch from 5.0 to 4.4 October 27, 2022 21:47
Comment on lines 161 to 167
$useFill = $this->request->getBodyParam('useFill');
if ($useFill && $transform->mode === 'fit') {
$transform->fill = $transform->fill ? ColorValidator::normalizeColor($transform->fill) : 'transparent';
} else {
$transform->fill = null;
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not wild about this, but I couldn't think of a better way to allow users to specify if they wanted the current behavior (image is sized proportionately to fit within a window) or the new behavior (image is placed within an area specified by the transform).

In code, the fact that fill exists tells Craft which behavior to us, but in the UI a fill is always returned, and currently there's not a difference between no fill and a transparent one.

src/migrations/Install.php Show resolved Hide resolved
Adds an additional `fill` parameter to image transforms.

The value of `fill` must be a value that the `ColorValidator` class accepts as valid (right now that means either 3 or 6 digit hex

The fill is only applied when it is valid, the mode is set to `fit` and the upscale images setting is set to `false` OR when the ratio of the transform differs from the ratio of the image itself. In that scenario, blank pixels between the size of the source image and the specified transform will be filled with the color specified (using the image’s color space or palette).

Indexes in the `imagetransformindex` table will now have the fill appended to the end of the string.

Generated folders will also have the fill color appended (minus the `#` character).
When applying the fill and a position is provided it will be used to
place the image within the transform size specified
Allows image to be scaled down to fit a ratio not equal to its intrinsic ration, but still apply the fill.
@brianjhanson brianjhanson force-pushed the feature/dev-239-fill-image-transform-setting branch from b81d5f8 to 232b30a Compare November 23, 2022 19:52
abstract public function scaleToFit(?int $targetWidth, ?int $targetHeight, bool $scaleIfSmaller = true): self;
abstract public function scaleToFit(?int $targetWidth, ?int $targetHeight, bool $scaleIfSmaller = true, string $position = 'center-center'): self;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing @param for $position

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also if the fill stuff is exclusive to Raster, it feels weird to have $position defined here in the base class. Maybe Raster should just be defining its own scaleToFitAndFill() method that combines scaleToFit() and setFill()?

Comment on lines 237 to 243
public function scaleToFit(?int $targetWidth, ?int $targetHeight, bool $scaleIfSmaller = true): self
public function scaleToFit(?int $targetWidth, ?int $targetHeight, bool $scaleIfSmaller = true, array|string $position = 'center-center'): self
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$position has a different type declaration here than in the base class (array|string vs string).

@brandonkelly
Copy link
Member

brandonkelly commented Jan 30, 2023

@brianjhanson This doesn’t seem to be working for me.

I created a transform with the following settings:

  • Mode: Fit
  • Fill empty pixels:
  • Fill Color: #ff0000
  • Width: 300
  • Height: 200
  • Quality: Auto
  • Interlacing: None
  • Image Format: Auto

However when I output a 1200x394 image using this transform, the result is 300x99 without any red pixels. I would have expected it to end up as 300x200, with ~50 red pixels above and below the original image.

(upscaleImages is true.)

And separately, looks like there’s a bug when Fill Color is left blank: when you go back to the transform edit page, the input value is set to #transparent.

Copy link
Member

@brandonkelly brandonkelly left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As discussed,

  • Let’s introduce a new dedicated “Letterbox” transform mode for this, with “Fill Color” and “Gravity” settings. (Gravity should default to center-center.)
  • All transforms should get a new “Upscale” setting, and the upscaleImages config setting should be used by default.

@brianjhanson
Copy link
Contributor Author

Just pushed some code to address the first half of this and wanted to jot down some notes before I forget.

Positioning

I went with "Position" instead of "Gravity" because that felt more straightforward. In Cloudinary world, Gravity is how they refer to a focal point, but we have established language for that. We could keep it as "Focal Point" here, but given how it behaves, I think "position" is a better description (and aligns with how to determine it programmatically).

CleanShot 2023-02-02 at 14 29 52

I duplicated the field rather than just messing with it via JS because JS introduced some complications (translations, accessibility, etc.). It felt like just duplicating the field was better all around.

UI Update

CleanShot 2023-02-02 at 14 18 21

Focal Points

If an image has a focal point set, we will do our best to put that point into the center. Some screenshots of how this behaves are below.

Focal point
CleanShot 2023-02-02 at 14 22 17

Results in
CleanShot 2023-02-02 at 14 22 29

@brandonkelly brandonkelly merged commit bf93085 into 4.4 Feb 4, 2023
@brandonkelly brandonkelly deleted the feature/dev-239-fill-image-transform-setting branch February 4, 2023 01:48
brandonkelly added a commit that referenced this pull request Feb 4, 2023
This was referenced Feb 18, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants