Skip to content

Robust optimization and delivery on hosted images

Reusability is at the heart of web development, using hosted images across multiple applications and websites. The need to transform, optimize, and deliver a version of that image with each application may arise.

This post discusses applying robust transformations and optimizations on hosted images in a Next.js website. Cloudinary, which we will employ, provides a feature to manage this and a suite of image enhancements and optimizations.

Images used in this project

This post is completed in a CodeSandbox. Fork it to get started quickly.

Check out the source code on Github.

  • Node for installing dependencies
  • Knowledge of Next.js
  • A text/code editor

We create a Next.js application using the following command:

npx create-next-app image-optimizations && cd image-optimizations

Next, we install the Cloudinary packages using yarn.

yarn add @cloudinary/url-gen @cloudinary/react

# or 

npm i @cloudinary/url-gen @cloudinary/react
  • @cloudinary/url-gen: Includes particular components and directives for easy embedding of assets in our app
  • @cloudinary/react: used to render images on our site

Next, let’s install the classnames package, a JavaScript utility for conditionally joining classNames together in writing the CSS modules for styling.

yarn add classnames

# or 

npm i classnames

Finally, we start a local development server with the command.

yarn dev

# or 

npm run dev

We will use the fetch-url feature of Cloudinary to deliver the hosted image.

Before adding transformations to any component in our project, we create a file in the component directory that renders the transformed image.

In the component/Marathoner.js file we create, we include the following code to display an image using the fetch URL, prefixed to the URL of the image.

component/Marathoner.js

    import { Cloudinary } from "@cloudinary/url-gen";
    import { AdvancedImage } from "@cloudinary/react";
    
    import styles from "../styles/Home.module.css";
    
    export default function Marathoner() {
      const cld = new Cloudinary({
        cloud: {
          cloudName: "demo"
        }
      });
      const myImage = cld
        .image("https://reefit.netlify.app/img/eloho.jpg")
        .setDeliveryType("fetch");
    
      return (
        <div>
          <AdvancedImage
            className={styles.img}
            cldImg={myImage}
          />
        </div>
      );
    }
Code language: JavaScript (javascript)

lagos marathoner

The above snippet creates and configures a new Cloudinary instance using a public identifier, cloudName. You can get this from your Cloudinary dashboard after you create an account.

Using the Cloudinary instance created, we defined a new image pointing to a publicly hosted photo, and we set the delivery type to fetch. Lastly, we rendered the transformed image using the AdvancedImage component.

We create a file called Home.module.css in the styles folder having the following content.

styles/Home.module.css

    @import url("https://fonts.googleapis.com/css?family=Poppins:200,300,400,500,600,700,800,900&display=swap");
    
    .main {
      font-family: "Poppins", sans-serif;
    }
    .align {
      text-align: center;
    }
    .img {
      max-width: 100%;
      display: block;
    }
    .container {
      max-width: 75rem;
      padding-inline: 2em;
      margin: auto;
      width: 85%;
    }
    .space {
      margin-bottom: 2em;
    }
Code language: CSS (css)

After delivering the image, we want to add transformations to it. Using @cloudinary/url-gen, we can import specific Cloudinary transformation actions and qualifiers. These are then used to build a complete image URL with transformations.

Alternatively, we could apply on-the-fly transformations to the image by modifying the resulting image URL.

Still in the component/Marathoner.js, include the following code to transform the image.

component/Marathoner.js

    import { Cloudinary } from "@cloudinary/url-gen";
    import { AdvancedImage } from "@cloudinary/react";
    import { Transformation } from "@cloudinary/url-gen";
    
    // import required actions and qualifiers
    import { thumbnail, scale } from "@cloudinary/url-gen/actions/resize";
    import { byRadius } from "@cloudinary/url-gen/actions/roundCorners";
    import { grayscale } from "@cloudinary/url-gen/actions/effect";
    import { source } from "@cloudinary/url-gen/actions/overlay";
    import { FocusOn } from "@cloudinary/url-gen/qualifiers/focusOn";
    import { Position } from "@cloudinary/url-gen/qualifiers/position";
    import { focusOn } from "@cloudinary/url-gen/qualifiers/gravity";
    import { compass } from "@cloudinary/url-gen/qualifiers/gravity";
    import { image } from "@cloudinary/url-gen/qualifiers/source";
    
    import styles from "../styles/Home.module.css";

    // javascript utility for classnames
    import cls from "classnames";
    export default function Marathoner() {
      const cld = new Cloudinary({
        cloud: {
          cloudName: "demo"
        }
      });
      const myImage = cld
        .image("https://reefit.netlify.app/img/eloho.jpg")
        .setDeliveryType("fetch");
    
      myImage
        .resize(thumbnail().width(250).height(250).gravity(focusOn(FocusOn.face()))) 
        .roundCorners(byRadius(20))
        .effect(grayscale())
        .overlay(
          source(
            image("cloudinary_icon_blue").transformation(
              new Transformation().resize(scale(50))
            )
          ).position(
            new Position().gravity(compass("south_west")).offsetX(10).offsetY(5)
          )
        );
      return (
        <div>
          <AdvancedImage
            className={cls(styles.img, styles.space)}
            cldImg={myImage}
          />
        </div>
      );
    }
Code language: JavaScript (javascript)

flying man

The code above applies the following transformations:

  • The image is cropped to a 250 x 250 thumbnail using face-detection gravity to determine the crop’s location automatically
  • Round the corners of the image with a radius of 20px
  • Applied to the image is the grayscale effect
  • Applied to the image is the Cloudinary logo on the southwest corner of the photo and scaled-down to 50px width of the original size with an offset from the edge of the picture in the X and Y direction

Like the image transformation steps, we’ll add a transformation effect to an image, along with format and quality optimizations.

Next, we create a new file called Athlete.js in the component directory with the following content:

component/Athlete.js

    import { Cloudinary } from "@cloudinary/url-gen";
    import { AdvancedImage } from "@cloudinary/react";

    // import required actions
    import { vectorize } from "@cloudinary/url-gen/actions/effect";
    import styles from "../styles/Home.module.css";
    export default function Athlete() {
      const cld = new Cloudinary({
        cloud: {
          cloudName: "demo"
        }
      });
      const athlete = cld
        .image("https://images.pexels.com/photos/6354732/pexels-photo-6354732.jpeg")
        .setDeliveryType("fetch");
    
      athlete.effect(vectorize()).format("auto").quality("auto");
      return (
        <div>
          <AdvancedImage className={styles.img} cldImg={athlete} />
        </div>
      );
    }
Code language: JavaScript (javascript)

The resulting image should look like this:

flying man

This post discussed modifying and reusing images hosted publicly on the internet by applying Cloudinary transformation and optimization parameters.

Back to top

Featured Post