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

Feature Request: twig filter to resize & fit - no cropping #1332

Closed
tomasvanrijsse opened this issue Feb 23, 2017 · 10 comments
Closed

Feature Request: twig filter to resize & fit - no cropping #1332

tomasvanrijsse opened this issue Feb 23, 2017 · 10 comments
Labels
enhancement needs-info Need more info on this issue in order to properly investigate

Comments

@tomasvanrijsse
Copy link

I'd like to resize my images without cropping them, just making them fit.
We got used to declaring image sizes in twig but seem to lack this feature.

For example like this:

<img src="{{ product.thumbnail|resize(1000,500,'fit') }}" />

although that might be a bit confusing to as an alternative:

<img src="{{ product.thumbnail|fit(1000,500) }}" />
@jarednova
Copy link
Member

jarednova commented Feb 23, 2017

Hi @tomasvanrijsse thanks for this idea. Just to make sure you're aware, there's a filter called letterbox that might accomplish what you're looking for:

<img src="{{ production.thumbnail | letterbox(1000, 500, '#000000') }}">

This transforms an image like...

colbert

into...

colbert-letterbox

With fit, what is the expected output for this source image fit with <img src="{{ product.thumbnail|fit(1000,500) }}" /> ?

@jarednova jarednova added enhancement needs-info Need more info on this issue in order to properly investigate labels Feb 23, 2017
@tomasvanrijsse
Copy link
Author

The expected output for images smaller then the requested limitations would be the original dimensions. That would make sense in the grammatical sense because the original image fits the given dimensions.

And the website I'm currently developing has images with black backgrounds and images with white backgrounds. The result would look appropriate if only I would know what background color to apply.

@danburzo
Copy link
Contributor

danburzo commented Feb 25, 2017

If I understand correctly, I think Timber needs in the first place a way to proportionally resize images so that they fit a certain width and height.

There are a couple of things that are currently missing from the docs, but looking at the code it seems they might be possible already:

  • The docs mention you can resize an image proportionally to a specific width by omitting the height attribute in the resize filter. You may be able to resize proportionally to a specific height if you call resize(0, height) (I haven't tested yet). (Reference)

  • There seems to be a third parameter that controls the crop mode, with the allowed values: 'default', 'center', 'top', 'bottom', 'left', 'right', 'top-center', 'bottom-center'. In addition, you can send false as the crop argument (but again I haven't tested). (Reference)

Assuming the things above hold true, you might already be able to resize an image proportionally to a certain width / height. What's left from your use-case is to not upscale smaller images, and I think this can be easily implemented through a new Twig filter that looks at the dimensions of the image and conditionally calls the resize filter if needed (i.e. the original size is larger than the target size).

Note: These are all based on my limited experience with Timber, so your mileage may vary.

@tomasvanrijsse
Copy link
Author

tomasvanrijsse commented Feb 25, 2017

I tried false as the third parameter.

<img src="{{ product.thumbnail|resize(1000,500,'false') }}" />

All images where changed to exactly match these dimensions by ignoring the original aspect ratio.
Smaller images are stretched and bigger images squished.
I need to be sure images fit within both boundaries so I can't omit the width or the height.

@danburzo
Copy link
Contributor

danburzo commented Feb 26, 2017

Yes, you're right, resize(w,h,false) will resize the image to w x h ignoring the image's proportions.

I could see resize getting another option for the crop mode -- let's call it fit -- that works like this:

  • when setting either width or height to zero, it can behave like default (scale proportionally to fit the non-zero dimension)
  • when setting both with and height to non-zero, it will scale it proportionally to fit the dimensions

But this still leaves out your use-case for the enlarge smaller behavior, so to not overload the resize filter with too many options, maybe it would be better served with a separate fit filter, and three modes: 'enlarge-only', 'shrink-only', 'default' (does both).

@danburzo
Copy link
Contributor

danburzo commented Feb 26, 2017

Here's how you could do it with the current API:

// functions.php

class MySite extends TimberSite {
  function __construct() {
    ...
    add_filter( 'get_twig', array( $this, 'add_to_twig' ) );
    ...
  }

function add_to_twig( $twig ) {
		/* this is where you can add your own functions to twig */
		$twig->addFilter('fit', new Twig_SimpleFilter('fit', array($this, 'fit_image')));
		return $twig;
	}

	function fit_image($src, $w, $h = 0) {
		// Instantiate TimberImage from $src so we have access to dimensions
		$img = new TimberImage($src);

		// If the image is smaller on both width and height, return original
		if ($img->width() <= $w && $img->height() <= $h) {
			return $src;
		}

		// Compute aspect ratio of target box
		$aspect = $w / $h;

		// Call proportional resize on width or height, depending on how the image's
		// aspect ratio compares to the target box aspect ratio
		if ($img->aspect() > $aspect) {
			return Timber\ImageHelper::resize($src, $w);
		} else {
			return Timber\ImageHelper::resize($src, 0, $h);
		}
	}
}

Note: Now, this is a very naive implementation (division by zero is not handled yet) provided just as an example, but it works.

@idflood
Copy link

idflood commented Feb 7, 2019

Hitting the same issue, I would propose an alternative implementation. Since the third parameter is already here to define a crop I think it should also allow a FALSE value.

This way we keep the syntax "compatible" with the wordpress add_image_size() function.

Taking the example given in the issue summary this would give us:

<img src="{{ product.thumbnail|resize(1000,500,false) }}" />

ps: a nice feature would be also to allow the same array syntax to define the crop position as the add_image_size function, would make the transition from wordpress even easier.

@idflood
Copy link

idflood commented Feb 8, 2019

One small benefit if implemented this way is that it is automatically compatible with timmy without having to change anything to it.

'test' => [
  'resize' => [420, 420, FALSE]
]

@wiesys
Copy link

wiesys commented Dec 2, 2019

Here's a little workaround. It's not ideal, but works fine, if you don't want to add a custom filter to Timber.

{% set img = post.thumbnail %}
<img src="{{ img.height > img.width ? img.src|resize(0, 720) : img.src|resize(720) }}">

@Levdbas
Copy link
Member

Levdbas commented May 26, 2023

I think the workarounds provided will do for now. As we want to keep Timber core minimal we are going to close this for now. If you want to make a PR for the 2.x branch, please feel free to do so. :)

@Levdbas Levdbas closed this as not planned Won't fix, can't repro, duplicate, stale May 26, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement needs-info Need more info on this issue in order to properly investigate
Projects
None yet
Development

No branches or pull requests

6 participants