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

Add ability to crop images #31

Closed
johnridesabike opened this issue Nov 23, 2020 · 14 comments
Closed

Add ability to crop images #31

johnridesabike opened this issue Nov 23, 2020 · 14 comments
Labels
enhancement New feature or request needs-votes A feature request on the backlog that needs upvotes or downvotes. Remove this label when resolved.

Comments

@johnridesabike
Copy link

johnridesabike commented Nov 23, 2020

I just started using this plugin, and this is the main feature I’m missing the most.

Its use case is when you need your images to conform to specific aspect ratios, such as square thumbnails.

(Sure, you can accomplish this with CSS too, but I’d prefer cropping the images during the build process.)

Since the widths option is already an array, perhaps there could be a single aspectRatio option too? e.g. [1, 1] or [16, 9].

Bonus points if you could also pass all of the sharp resize options too, e.g. position: "center" https://sharp.pixelplumbing.com/api-resize

@reubenlillie
Copy link

@johnridesabike, I don’t have a solution per se, just a thought that I’m currently working through as I familiarize myself with this plugin too. I’ve got an dev site that I’m experimenting with passing URLs from Cloudinary as the src argument to Image(src) using this plugin. Again, I don’t know if it meets your use case, but I think there’s some value in keeping this plugin as a slim build-time tool. Then, if you want more sophisticated image transformations, you could use a remote service (and, in that sense, the remote caching features come in really handy) or another package that’s designed for those tasks.

@zachleat zachleat added the enhancement New feature or request label Jan 2, 2021
@anghelos
Copy link

anghelos commented Mar 6, 2021

I'd also love the ability to crop just some of the given widths, to change the aspect ratio for mobile, for example.

@szegheo
Copy link

szegheo commented Nov 28, 2021

@zachleat can we ask priority for this? E.g. think just a full screen hero background image optimization for mobiles, usually 800x1200, when we don't know the dimensions of the user selected picture (by some headless cms) but we need to resize it to be exactly 1200px height.

I'm working on a tiny Webpack image loader based on eleventy-img (to reduce dependencies in my 11ty sites) which can be used in CSS like some.jpg?format=webp&height=1200 but currently only width can be used. FYI currently I'm using webpack-image-resize-loader (link) which is also using Sharp and can handle heights, but now it's an extra unnecessary dependency with a different version of Sharp. eleventy-img could be used for this task so nicely...

Thank you!

@zeroby0
Copy link
Contributor

zeroby0 commented Nov 28, 2021

I wonder if we can use sharpOptions: {} to pass arguments to Sharp and define a shortcode that does cropping and aspect ratio

@szegheo
Copy link

szegheo commented Nov 28, 2021

It seems to me that the sharpOptions of eleventy-img is for the Sharp constructor, and the resize parameters cannot be set there (fix me if I'm wrong).

However looking at the code of eleventy-img where it does the resizing (L437) sharpInstance.resize(resizeOptions) the resize options - what we would need to alter - are fixed.

Maybe a new option and a little modification something like this could work?:

let userSharpResizeOptions = this.options.sharpResizeOptions || {};

sharpInstance.resize({
  resizeOptions,
  ...userSharpResizeOptions
});

...then we would be able to use all the magic of https://sharp.pixelplumbing.com/api-resize#parameters
(but it's just a sudden idea)

@zeroby0
Copy link
Contributor

zeroby0 commented Nov 29, 2021

Good eye! They are constructor options, I didn't notice that 😆

The name sharpResizeOptions feels right to me too. But the codebase's way to do || {} seems to be via Object.assign
So maybe Object.assign({}, resizeOptions, this.options.sharpResizeOptions)? (I don't know how object.assign works, just writing this in hope some one will make a PR)

If someone does make a PR, please include the name in keysToKeep too

@szegheo
Copy link

szegheo commented Nov 29, 2021

This was once started in May 2020, the PR is still open but abandoned. Even sharpResizeOptions was recommended before in the last post. I don't know why this thing is still hanging 😞

@sprabowo are you still interested in 11ty? (seems to me he has switched to Astro)

@architchandra
Copy link

Please consider this. Cropping images at build time seems so much better than just using CSS methods from a performance perspective.

@zeroby0
Copy link
Contributor

zeroby0 commented Nov 29, 2021

The code has changed a lot since then, so I wouldn't really expect it to get merged. If there is no PR by Jan 1st, I'll draft one. Although I wouldn't expect it to be merged and shipped any time soon from that.

If you need the feature soon, I strongly recommend forking the repo and implementing sharpResizeOptions yourself. Then after you've tested it, consider contributing the improvements back with a PR :)

@szegheo
Copy link

szegheo commented Nov 29, 2021

Sure, I'm thinking of that, but also I'm absolutely certain that @zachleat could do this thing ways better than I could. I'm just a plain 11ty user and to be honest I would give my half hand for the JS skills that Zach has 😄 . Also as I read somewhere before, he said that issues with more likes will get more priority.

So if you are reading this, please press the like icon on the first post 👍 if you need this feature.

@zachleat zachleat added the needs-votes A feature request on the backlog that needs upvotes or downvotes. Remove this label when resolved. label Feb 23, 2022
@zachleat
Copy link
Member

I believe this is the top feature request right now but it’s still going into the queue. Thanks folks!

This repository is now using lodash style issue management for enhancements. This means enhancement issues will now be closed instead of leaving them open.

View the enhancement backlog here. Don’t forget to upvote the top comment with 👍!

@mortendk
Copy link

mortendk commented Mar 28, 2023

hmmm wonder if this kinda dies or somebody have a good idea to crop images ?
custom sharp instead or

@jeromecoupe
Copy link

@mortendk I tend to use an external NPM script running in parallel to generate resized images. On bigger projects, I generally use external images services.

@HerodoteVDR
Copy link

HerodoteVDR commented Dec 3, 2023

@mortendk I figured sharp could be a good workaround, here is the Shortcode I added to get responsive picture generation in templating.
(I'm an absolute 11ty noob so it might be really dirty coding but it worked out for me)

const Image = require("@11ty/eleventy-img");
const Sharp = require('sharp');

module.exports = function(eleventyConfig) {
	eleventyConfig.addShortcode("myImage", async function(src, alt, smallSize, midSize, bigSize) {
		try {
			console.log(`myImage shortcode called with src:`, src);

			const resizedImageBuffer = await Promise.all([
				resizeImage(src, smallSize[0], smallSize[1], "cover"),
				resizeImage(src, midSize[0], midSize[1], "cover"),
				resizeImage(src, bigSize[0], bigSize[1], "cover"),
			]);

			const metadata = await Promise.all(
				resizedImageBuffer.map(async buffer => {
					return await Image(buffer, {
						formats: ["webp"],
						outputDir: "./dist/assets/img/output",
						urlPath: "/assets/img/output/",
					});
				})
			);

			console.log("Generated image metadata:", metadata);

			let imageAttributes = {
				alt,
				loading: "lazy",
				decoding: "async",
				class: "o-fluidimage"
			};

			const imageHTML = 
				`<picture> 
					<source media="(min-width: 1050px)" srcset="${metadata[2].webp[0].url}">
					<source media="(min-width: 750px)" srcset="${metadata[1].webp[0].url}">
					<img
						class="${ imageAttributes.class }" 
						alt="${ imageAttributes.alt }" 
						loading="${ imageAttributes.loading }
						decoding="${ imageAttributes.decoding }" 
						src="${ metadata[0].webp[0].url }"
					/>
				</picture>`;

			console.log(`Generated image HTML:`, imageHTML);

			return imageHTML;
		} 
		catch (error) {
			console.error(`Error in myImage shortcode:`, error);
			return "";
		}
	});
}

async function resizeImage(src, width, height, mode) {
    return await Sharp(src)
        .resize({ width: width, height: height, fit: mode })
        .toBuffer();
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request needs-votes A feature request on the backlog that needs upvotes or downvotes. Remove this label when resolved.
Projects
None yet
Development

No branches or pull requests

10 participants