cloudinary-community / netlify-plugin-cloudinary

Supercharge images on your Netlify site with Cloudinary!
https://netlify.cloudinary.dev/
MIT License
42 stars 18 forks source link

Generate responsive images #22

Open colbyfayock opened 2 years ago

colbyfayock commented 2 years ago

Cloudinary supports generating responsive images.

https://cloudinary.com/documentation/responsive_images#responsive_breakpoint_generator

cloudinary.uploader.v2.upload("sample.jpg", { responsive_breakpoints: { create_derived: true, bytes_step: 20000, min_width: 200, max_width: 1000, transformation: { crop: 'fill', aspect_ratio: '16:9', gravity: 'auto' } } }, function(error, result) { console.log(result); });

The sizes used should be configurable in the Netlify file-based configuration. Ideally we could also target configuration, for instance, using element selectors to use specific sizes for that specific element(s).

For example: All images get sizes="..." while .my-images get sizes="..."

More Info

colbyfayock commented 2 years ago

sounds great @Ambareen09!

When using the Cloudinary uploader, we're able to automatically generate responsive images that we can use to improve how images load

That code snippet in the original post is an example of that:

cloudinary.uploader.v2.upload("sample.jpg", {
  responsive_breakpoints: {
    create_derived: true,
    bytes_step: 20000,
    min_width: 200,
    max_width: 1000,
    transformation: {
      crop: 'fill',
      aspect_ratio: '16:9',
      gravity: 'auto'
    }
  }
})

In the response, the breakpoints would be included

here's another simpler example from the docs:

To upload an image from a remote url: https://www.example.com/sample.jpg and request Cloudinary to find the best breakpoints based on the following guidelines: a minimum width of 200 pixels, a maximum width of 1000 pixels, at least 20000 bytes file size difference between the breakpoints, while keeping the generated derived images:

cloudinary.v2.uploader
.upload("https://www.example.com/sample.jpg",
  { responsive_breakpoints: 
    { create_derived: true, 
      bytes_step: 20000, 
      min_width: 200, 
      max_width: 1000 }})
.then(result=>console.log(result));

Under https://cloudinary.com/documentation/image_upload_api_reference#upload_examples

Once we have these breakpoints, we can use them in the code such as:

<img
sizes="(max-width: 1400px) 100vw, 1400px"
srcset="
castle_c_scale,w_200.jpg 200w,
castle_c_scale,w_476.jpg 476w,
castle_c_scale,w_665.jpg 665w,
castle_c_scale,w_816.jpg 816w,
castle_c_scale,w_962.jpg 962w,
castle_c_scale,w_1094.jpg 1094w,
castle_c_scale,w_1215.jpg 1215w,
castle_c_scale,w_1294.jpg 1294w,
castle_c_scale,w_1381.jpg 1381w,
castle_c_scale,w_1400.jpg 1400w"
src="castle_c_scale,w_1400.jpg"
alt="">

we likely need to recognize inputs to turn this on and off. see my comment here for how to do this:

https://github.com/colbyfayock/netlify-plugin-cloudinary/issues/23#issuecomment-1264367515

in an example where someone has an image:

<img src="myimage.jpg" />

we would want the end result to be something along the lines of

<img src="myimage.jpg" sizes="..." srcset="https://res.cloudinary.com/.../myimage.jpg..." />
colbyfayock commented 2 years ago

i also encourage you to write a test for your work to help debug and to make sure it's working as expected

BajajAyush commented 2 years ago

Hi! Is it okay if I work on this issue? @Ambareen09 are you still working on it? Thank you!

colbyfayock commented 2 years ago

It's only been 4 days, we need to wait to hear back from them but if they're not going to work on it it's yours. I'll give them until Tuesday to respond.

colbyfayock commented 2 years ago

Thanks for letting us know

colbyfayock commented 2 years ago

hey @BajajAyush are you still working on this?

developer-diganta commented 2 years ago

Hey @colbyfayock if @BajajAyush is not working on this issue, I'd like to give it a try!

colbyfayock commented 2 years ago

@developer-diganta we'll give them until tomorrow to respond, but if they don't you can take it!

colbyfayock commented 2 years ago

@developer-diganta are you still interested in this? if so its yours

developer-diganta commented 2 years ago

Yes! Gonna start working on it!

developer-diganta commented 2 years ago

@colbyfayock I understood that once I get the image from the user, I use cloudinary.uploader.v2.upload to generate responsive breakpoints. Once I get the result, I have a url for example, in the documentation, I saw that eager key has urls for various sizes, I'll then use that in the srcset right? And these transformations should only be applied if the user wants it? The sample response on the site is:

{
  "asset_id": "b5e6d2b39ba3e0869d67141ba7dba6cf",
  "public_id": "eneivicys42bq5f2jpn2",
  "version": 1570979139,
  "version_id": "98f52566f43d8e516a486958a45c1eb9",
  "signature": "abcdefghijklmnopqrstuvwxyz12345",
  "width": 1000,
  "height": 672,
  "format": "jpg",
  "resource_type": "image",
  "created_at": "2017-08-11T12:24:32Z",
  "tags": [],
  "pages": 1,
  "bytes": 350749,
  "type": "upload",
  "etag": "5297bd123ad4ddad723483c176e35f6e",
  "placeholder": false,
  "url": "http://res.cloudinary.com/demo/image/upload/v1570979139/eneivicys42bq5f2jpn2.jpg",
  "secure_url": "https://res.cloudinary.com/demo/image/upload/v1570979139/eneivicys42bq5f2jpn2.jpg",
  "access_mode": "public",
  "original_filename": "sample",
  "eager": [
    { "transformation": "c_pad,h_300,w_400",
      "width": 400,
      "height": 300,
      "url": "http://res.cloudinary.com/demo/image/upload/c_pad,h_300,w_400/v1570979139/eneivicys42bq5f2jpn2.jpg",
      "secure_url": "https://res.cloudinary.com/demo/image/upload/c_pad,h_300,w_400/v1570979139/eneivicys42bq5f2jpn2.jpg" },
    { "transformation": "c_crop,g_north,h_200,w_260",
      "width": 260,
      "height": 200,
      "url": "http://res.cloudinary.com/demo/image/upload/c_crop,g_north,h_200,w_260/v1570979139/eneivicys42bq5f2jpn2.jpg",
      "secure_url": "https://res.cloudinary.com/demo/image/upload/c_crop,g_north,h_200,w_260/v1570979139/eneivicys42bq5f2jpn2.jpg" }]
}
colbyfayock commented 2 years ago

looks like you're on the right track. would be great if someone could define the sizes they would like to use in the netlify.toml configuration

developer-diganta commented 2 years ago

By sizes you mean the min and max widths?

colbyfayock commented 2 years ago

so a few different ways to configure it to the API:

cloudinary.v2.uploader
.upload("https://www.example.com/sample.jpg",
  { responsive_breakpoints: 
    { create_derived: true, 
      bytes_step: 20000, 
      min_width: 200, 
      max_width: 1000 }})

which generates a bunch of steps which may look like:

  [plugins.inputs]
  steps:
    minWidth: 200
    maxWidth: 1000
    createDerived: true
    bytesStep: 20000

Or defining the exact sizes:

cloudinary.v2.uploader
.upload("ftp://user1:mypass@ftp.example.com/sample.jpg", 
  { eager: [
    { width: 400, height: 300, crop: "pad" }, 
    { width: 260, height: 200, crop: "crop", gravity: "north"} ]}) 

which may look like:

  [plugins.inputs]
  sizes
  - width: 400
    height: 300
    crop: pad
  - width: 260
    height: 200
    crop: crop
    gravity: north
developer-diganta commented 2 years ago

Getting the idea now! Will start working on it and get back with the doubts😅

developer-diganta commented 2 years ago

@colbyfayock https://github.com/colbyfayock/netlify-plugin-cloudinary/blob/main/src/lib/cloudinary.js#L127 is this the uploadOptions where I should specify the breakpoints that is the uploadOptions should have the breakpoints?

colbyfayock commented 2 years ago

yup! that should be it

developer-diganta commented 2 years ago

@colbyfayock wanted to know if I have to give some default responsive breakpoint values or simply accept it as options from the user?

colbyfayock commented 2 years ago

given it's opt-in, i would expect that it requires someone to pass in values in order to work. it would be great to have a simple example in the docs though

developer-diganta commented 2 years ago

@colbyfayock could you please tell me how do I read the values from the toml file?

  sizes
  - width: 400
    height: 300
    crop: pad
  - width: 260
    height: 200
    crop: crop
    gravity: north

for this one suppose, how do I read it in the js file? since for uploadOptions, I have to format it in the way the example specifies?

colbyfayock commented 2 years ago

@colbyfayock see here for example: https://github.com/colbyfayock/netlify-plugin-cloudinary/blob/main/src/index.js#L25-L37

developer-diganta commented 2 years ago

Yup! I saw that. But since I have different values for sizes shall I get an array in return like sizes[0].width gives me 400? Sorry never worked with toml so this confusion!

colbyfayock commented 2 years ago

you can try logging the values and running a Netlify build

use the Netlify CLI to test locally https://docs.netlify.com/cli/get-started/

once installed run netlify deploy --build

developer-diganta commented 2 years ago

@colbyfayock Thank You for the help. I am able to read the values. But for deliveryType=upload, I am getting this error: image The error message is from this line Is there any value that I am missing?

colbyfayock commented 2 years ago

i can't tell from just that unfortunately, i would recommend adding some console logs

do you have your environment variables set up? you need to have the API key and API secret set for uploading, you can find the details on the README

developer-diganta commented 2 years ago

Yeah I did that. I have also made an uploadPreset. I am trying to find a solution. If I can't can I make a PR so that you can have a look?

colbyfayock commented 2 years ago

you can certainly create a PR! and we can work from there

console.logs didnt help? are you looking through all of the logs, not just the end where the error shows?

add logs before and after the getCloudinaryUrl, simple things like "before" and "after"

add logs inside of getCloudinaryUrl at different points

try to determine where it's failing

developer-diganta commented 2 years ago

Yup I tried. I saw that https://github.com/colbyfayock/netlify-plugin-cloudinary/blob/main/src/lib/cloudinary.js#L117 till this line it works. There's something happening after this. Trying to figure it out...

colbyfayock commented 2 years ago

try adding a try/catch around these:

    if ( canSignUpload ) {
      // We need an API Key and Secret to use signed uploading

      results = await cloudinary.uploader.upload(fullPath, {
        ...uploadOptions
      });
    } else {
      // If we want to avoid signing our uploads, we don't need our API Key and Secret,
      // however, we need to provide an uploadPreset

      results = await cloudinary.uploader.unsigned_upload(fullPath, uploadPreset, {
        ...uploadOptions
      });
    }

such as:

try {
  results = await cloudinary.uploader.upload(fullPath, {
        ...uploadOptions
      });
} catch(e) {
  console.log(`Failed to upload to Cloudinary: ${e.message}`);
  throw e;
}
developer-diganta commented 2 years ago

Thank You! Trying it!

colbyfayock commented 2 years ago

@developer-diganta you still working on thnis?

developer-diganta commented 2 years ago

Yeah! Sorry fell sick in between... Will put up a PR soon...

colbyfayock commented 2 years ago

np. hope all is well!

developer-diganta commented 2 years ago

Yup!

developer-diganta commented 1 year ago

Hey @colbyfayock! I have exams till 12th after that I can continue. In the meantime if someone else wants to work on it, then you assign them. Else I'll continue and try to resolve this asap after 12th...

colbyfayock commented 1 year ago

all good, thanks for the update. good luck with exams!

colbyfayock commented 1 year ago

hey @developer-diganta thanks for your help here. @matiasfha is going to create a branch from your Pull Request, update it to latest, and wrap this up for us. excited to see this feature get merged in!