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: Relative image transforms for PPI based responsive images. #5774

Closed
RickKukiela opened this issue Mar 9, 2020 · 5 comments
Closed

Comments

@RickKukiela
Copy link

@RickKukiela RickKukiela commented Mar 9, 2020

Description

Lets say I have a place holder for a product or blog post image that is 300x300. That's "CSS Pixels" not "real pixels". So I want to have some css generated that would include the proper image based on devices pixel ratio. Lets say for this example the highest ratio I'm supporting is 3x, so I would want to create my base transform for 3x, so 300x3 X 300x3 = 900x900. Great so I do that. Now in my code I would like to be able to call the transformation like like this: image.getUrl('Transform', '3x') or image.getUrl('Transform', '2x') or image.getUrl('Transform', '1.5x') for each pixel density media query i'm matching for.

I should have to tell my base transform that its set to a max of 3x so when I request a 3x it just sends the 900x900, however when I request a 2x, it should know that it needs to divide each dimension by the max provided (3) to get 300x300, then multiply each dimension by the the requested ratio (2) to get 600x600.

I guess theoretically I can just manually set up transforms for each pixel ratio but that seems much more cumbersome than just requesting a variation based on pixel density and having the system create it for me on the fly.

Steps to reproduce

Additional info

  • Craft version:
  • PHP version:
  • Database driver & version:
  • Plugins & versions:
@brandonkelly brandonkelly added this to the 3.5 milestone Mar 10, 2020
brandonkelly added a commit that referenced this issue Mar 10, 2020
@brandonkelly

This comment has been minimized.

Copy link
Member

@brandonkelly brandonkelly commented Mar 10, 2020

I’ll do you one better! Just added a new getSrcset() asset method, for Craft 3.5, which takes an array of srcset sizes (100w, 2x, etc.), and returns a srcset attribute value with the transform URLs combined with the given srcset sizes.

{% do asset.setTransform({ width: 300, height: 300 }) %}
{{ tag('img', {
    src: asset.url,
    width: asset.width,
    height: asset.height,
    srcset: asset.getSrcset(['1x', '1.5x', '2x', '3x']),
    alt: asset.title,
}) }}

The getImg() method also now accepts a sizes argument, so you’d get the same output as the above code by doing:

{{ asset.getImg({ width: 300, height: 300 }, ['1x', '1.5x', '2x', '3x']) }}
@rynpsc

This comment has been minimized.

Copy link
Contributor

@rynpsc rynpsc commented Mar 10, 2020

@brandonkelly Very nice, going to be a real time saver.

How would eager loading play into this? We currently have a custom module to handle srcset that returns a load of transform urls but the number of db queries ballons once we start having ~ 6 sizes per image. We've never figured out how to eager load as we don't have the actual transform object in the tempate, just the srcset string.

@RickKukiela

This comment has been minimized.

Copy link
Author

@RickKukiela RickKukiela commented Mar 10, 2020

Nice!

@brandonkelly

This comment has been minimized.

Copy link
Member

@brandonkelly brandonkelly commented Mar 10, 2020

@rynpsc Good question. Previously you would have had to manually specify each of the resulting transforms. Going with the previous example (300x300 @ 1x, 1.5x, 2x, and 3x), that would look like this:

{% set assets = entry.myAssetsField
    .withTransforms([
        {width: 300, height: 300},
        {width: 450, height: 450},
        {width: 600, height: 600},
        {width: 900, height: 900},
    ])
    .all() %}

I just pushed a new commit (7d97863 ) that brings srcset-style sizes to the withTransforms param though, so that can now be simplified to:

{% set assets = entry.myAssetsField
    .withTransforms([{width: 300, height: 300}, '1.5x', '2x', '3x'])
    .all() %}

Note that you still must start with a normal transform definition; otherwise the param will have no idea what to anchor the width/height on for “1.5x”, etc.

Putting it all together, here’s a way you can keep your template DRY:

{% set baseTransform = {width: 300, height: 300} %}
{% set srcsetSizes = ['1.5x', '2x', '3x'] %}

{% set assets = entry.myAssetsField
    .withTransforms([baseTransform]|merge(srcsetSizes))
    .all() %}

{% for asset in assets %}
    {{ asset.getImg(baseTransform, srcsetSizes) }}
{% endfor %}
@jsunsawyer

This comment has been minimized.

Copy link

@jsunsawyer jsunsawyer commented Mar 10, 2020

@brandonkelly This is rad. We usually lower the quality on high res (retina) images for performance reasons. This way you get higher quality images without much of an increase in file size. I wonder if it might make sense to be able to pass in quality settings for each srcset option.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
4 participants
You can’t perform that action at this time.