responsive-loader icon indicating copy to clipboard operation
responsive-loader copied to clipboard

Resize and/or crop images?

Open gbouteiller opened this issue 5 years ago • 7 comments

Is it possible to use this loader to also resize/crop images? For instance, it could be great to use it to create thumbnails with different ratio, ... Thank you

gbouteiller avatar Jul 14 '18 11:07 gbouteiller

@gbouteiller – Yes, you can resize and crop images using sharp adapter.

Melzmr avatar Aug 25 '18 20:08 Melzmr

@Melzmr Can't figure out how to achieve that, can you share a snippet perhaps?

obennaci avatar Oct 04 '18 10:10 obennaci

@Melzmr I think @gbouteiller was looking for ways to specify crop parameters at the URI-level. eg if I have a responsive background image in a hero section, I want to the height to be fixed as I generate crops of different widths.

AndrewIngram avatar Jan 31 '19 15:01 AndrewIngram

So sharp has params for height and crop strategy, but responsive-loader only takes width at the moment.

I guess it's possible to supply our own adapter, copying this one: https://github.com/herrstucki/responsive-loader/blob/master/src/adapters/sharp.js

and then including all the args to sharp.resize there (width, height, crop)

One strategy would be to use the width param as an integer key:

require("./images/image.jpg?resize?width=1")

that specifies one of a variety of settings used in our own site:

options = [
   {width: 1200, height: 800, fit: "crop"},
   {width: 300, height: 400, fit: "cover"},
]

which then calls:

image.clone.resize(options[width])

a la http://sharp.dimens.io/en/stable/api-resize/#parameters

crucialfelix avatar Feb 12 '19 15:02 crucialfelix

See https://github.com/herrstucki/responsive-loader/issues/70#issuecomment-444900842

jstcki avatar Feb 12 '19 15:02 jstcki

Here is my "works today" solution. It's somewhat of a hack (using the width parameter as an index into some presets), but it will work until there is a better way to do this.

I'm using this with

  • https://github.com/cyrilwanner/next-optimized-images
  • herrsucki/responsive-loader
  • https://github.com/lovell/sharp so there are many pancakes stacked high and they will probably all fallover soon enough.
// ./lib/sharp-adapter.js
const sharp = require("sharp");

/**
 * Factory to make a sharp adapter function for use in response-loader.
 * Width is interpreted as an integer index into the presets list supplied to the factory function.
 *
 * Usage:
 *
 * next.config.js
 *
 * const resizeOptions = {
 *   1: {
 *     width: 1024,
 *     height: 682,
 *     fit: "cover"
 *   },
 *   2: {
 *     width: 496,
 *     height: 593,
 *     fit: "cover"
 *   }
 * };
 *
 * // make the adapter
 * adapter: require("./lib/sharp-adapter")(resizeOptions)
 *
 * // usage
 * const main = require(`./images/some-image.jpg?resize&sizes[]=1`);
 * const thumb = require(`./images/some-image.jpg?resize&sizes[]=2`);
 */
function adapterFactory(resizeOptions) {
  return imagePath => {
    const image = sharp(imagePath);

    return {
      metadata: () => image.metadata(),
      resize: ({ width, mime, options }) =>
        new Promise((resolve, reject) => {
          const resizeOpts = resizeOptions[width] || { width: width };
          // console.log(width, mime, options, resizeOpts);

          let resized = image.clone().resize(resizeOpts);

          if (options.background) {
            resized = resized.background(options.background).flatten();
          }

          if (mime === "image/jpeg") {
            resized = resized.jpeg({
              quality: options.quality
            });
          }

          resized.toBuffer((err, data, { height }) => {
            if (err) {
              reject(err);
            } else {
              resolve({
                data,
                width: resizeOpts.width,
                height: height
              });
            }
          });
        })
    };
  };
}

module.exports = adapterFactory;

crucialfelix avatar Feb 13 '19 11:02 crucialfelix

+1, I also need this! I want to pass the height / crop width/height via URL, like background: url('../images/background.jpg?height=1000.

strarsis avatar Apr 06 '19 19:04 strarsis