One place for hosting & domains

      Images

      How To Process Images in Node.js With Sharp


      The author selected the Diversity in Tech Fund to receive a donation as part of the Write for DOnations program.

      Introduction

      Digital image processing is a method of using a computer to analyze and manipulate images. The process involves reading an image, applying methods to alter or enhance the image, and then saving the processed image. It’s common for applications that handle user-uploaded content to process images. For example, if you’re writing a web application that allows users to upload images, users may upload unnecessary large images. This can negatively impact the application load speed, and also waste your server space. With image processing, your application can resize and compress all the user-uploaded images, which can significantly improve your application performance and save your server disk space.

      Node.js has an ecosystem of libraries you can use to process images, such as sharp, jimp, and gm module. This article will focus on the sharp module. sharp is a popular Node.js image processing library that supports various image file formats, such as JPEG, PNG, GIF, WebP, AVIF, SVG and TIFF.

      In this tutorial, you’ll use sharp to read an image and extract its metadata, resize, change an image format, and compress an image. You will then crop, grayscale, rotate, and blur an image. Finally, you will composite images, and add text on an image. By the end of this tutorial, you’ll have a good understanding of how to process images in Node.js.

      Prerequisites

      To complete this tutorial, you’ll need:

      Step 1 — Setting Up the Project Directory and Downloading Images

      Before you start writing your code, you need to create the directory that will contain the code and the images you’ll use in this article.

      Open your terminal and create the directory for the project using the mkdir command:

      Move into the newly created directory using the cd command:

      Create a package.json file using npm init command to keep track of the project dependencies:

      The -y option tells npm to create the default package.json file.

      Next, install sharp as a dependency:

      You will use the following three images in this tutorial:

      Digitalocean maskot sammy
      Underwater ocean scene
      sammy with a transparent background

      Next, download the images in your project directory using the curl command.

      Use the following command to download the first image. This will download the image as sammy.png:

      • curl -O https://xpresservers.com/wp-content/uploads/2021/09/How-To-Process-Images-in-Nodejs-With-Sharp.png

      Next, download the second image with the following command. This will download the image as underwater.png:

      • curl -O https://xpresservers.com/wp-content/uploads/2021/09/1631157332_451_How-To-Process-Images-in-Nodejs-With-Sharp.png

      Finally, download the third image using the following command. This will download the image as sammy-transparent.png:

      • curl -O https://xpresservers.com/wp-content/uploads/2021/09/1631157333_547_How-To-Process-Images-in-Nodejs-With-Sharp.png

      With the project directory and the dependencies set up, you’re now ready to start processing images.

      In this section, you’ll write code to read an image and extract its metadata. Image metadata is text embedded into an image, which includes information about the image such as its type, width, and height.

      To extract the metadata, you’ll first import the sharp module, create an instance of sharp, and pass the image path as an argument. After that, you’ll chain the metadata() method to the instance to extract the metadata and log it into the console.

      To do this, create and open readImage.js file in your preferred text editor. This tutorial uses a terminal text editor called nano:

      Next, require in sharp at the top of the file:

      process_images/readImage.js

      const sharp = require("sharp");
      

      sharp is a promise-based image processing module. When you create a sharp instance, it returns a promise. You can resolve the promise using the then method or use async/await, which has a cleaner syntax.

      To use async/await syntax, you’ll need to create an asynchronous function by placing the async keyword at the beginning of the function. This will allow you to use the await keyword inside the function to resolve the promise returned when you read an image.

      In your readImage.js file, define an asynchronous function, getMetadata(), to read the image, extract its metadata, and log it into the console:

      process_images/readImage.js

      const sharp = require("sharp");
      
      async function getMetadata() {
        const metadata = await sharp("sammy.png").metadata();
        console.log(metadata);
      }
      
      

      getMetadata() is an synchronous function given the async keyword you defined before the function label. This lets you use the await syntax within the function. The getMetadata() function will read an image and return an object with its metadata.

      Within the function body, you read the image by calling sharp() which takes the image path as an argument, here with sammy.png.

      Apart from taking an image path, sharp() can also read image data stored in a Buffer, Uint8Array, or Uint8ClampedArray provided the image is JPEG, PNG, GIF, WebP, AVIF, SVG or TIFF.

      Now, when you use sharp() to read the image, it creates a sharp instance. You then chain the metadata() method of the sharp module to the instance. The method returns an object containing the image metadata, which you store in the metadata variable and log its contents using console.log().

      Your program can now read an image and return its metadata. However, if the program throws an error during execution, it will crash. To get around this, you need to capture the errors when they occur.

      To do that, wrap the code within the getMetadata() function inside a try...catch block:

      process_images/readImage.js

      const sharp = require("sharp");
      
      async function getMetadata() {
        try {
          const metadata = await sharp("sammy.png").metadata();
          console.log(metadata);
        } catch (error) {
          console.log(`An error occurred during processing: ${error}`);
        }
      }
      

      Inside the try block, you read an image, extract and log its metadata. When an error occurs during this process, execution skips to the catch section and logs the error preventing the program from crashing.

      Finally, call the getMetadata() function by adding the highlighted line:

      process_images/readImage.js

      
      const sharp = require("sharp");
      
      async function getMetadata() {
        try {
          const metadata = await sharp("sammy.png").metadata();
          console.log(metadata);
        } catch (error) {
          console.log(`An error occurred during processing: ${error}`);
        }
      }
      
      getMetadata();
      

      Now, save and exit the file. Enter y to save the changes you made in the file, and confirm the file name by pressing ENTER or RETURN key.

      Run the file using the node command:

      You should see an output similar to this:

      Output

      { format: 'png', width: 750, height: 483, space: 'srgb', channels: 3, depth: 'uchar', density: 72, isProgressive: false, hasProfile: false, hasAlpha: false }

      Now that you’ve read an image and extracted its metadata, you’ll now resize an image, change its format, and compress it.

      Step 3 — Resizing, Changing Image Format, and Compressing Images

      Resizing is the process of altering an image dimension without cutting anything from it, which affects the image file size. In this section, you’ll resize an image, change its image type, and compress the image. Image compression is the process of reducing an image file size without losing quality.

      First, you’ll chain the resize() method from the sharp instance to resize the image, and save it in the project directory. Second, you’ll chain the format() method to the resized image to change its format from png to jpeg. Additionally, you will pass an option to the format() method to compress the image and save it to the directory.

      Create and open resizeImage.js file in your text editor:

      Add the following code to resize the image to 150px width and 97px height:

      process_images/resizeImage.js

      const sharp = require("sharp");
      
      async function resizeImage() {
        try {
          await sharp("sammy.png")
            .resize({
              width: 150,
              height: 97
            })
            .toFile("sammy-resized.png");
        } catch (error) {
          console.log(error);
        }
      }
      
      resizeImage();
      

      The resizeImage() function chains the sharp module’s resize() method to the sharp instance. The method takes an object as an argument. In the object, you set the image dimensions you want using the width and height property. Setting the width to 150 and the height to 97 will make the image 150px wide, and 97px tall.

      After resizing the image, you chain the sharp module’s toFile() method, which takes the image path as an argument. Passing sammy-resized.png as an argument will save the image file with that name in the working directory of your program.

      Now, save and exit the file. Run your program in the terminal:

      You will get no output, but you should see a new image file created with the name sammy-resized.png in the project directory.

      Open the image on your local machine. You should see an image of Sammy 150px wide and 97px tall:

      image resized to 150px width and 97px height

      Now that you can resize an image, next you’ll convert the resized image format from png to jpeg, compress the image, and save it in the working directory. To do that, you will use toFormat() method, which you’ll chain after the resize() method.

      Add the highlighted code to change the image format to jpeg and compress it:

      process_images/resizeImage.js

      const sharp = require("sharp");
      
      async function resizeImage() {
        try {
          await sharp("sammy.png")
            .resize({
              width: 150,
              height: 97
            })
            .toFormat("jpeg", { mozjpeg: true })
            .toFile("sammy-resized-compressed.jpeg");
        } catch (error) {
          console.log(error);
        }
      }
      
      resizeImage();
      

      Within the resizeImage() function, you use the toFormat() method of the sharp module to change the image format and compress it. The first argument of the toFormat() method is a string containing the image format you want to convert your image to. The second argument is an optional object containing output options that enhance and compress the image.

      To compress the image, you pass it a mozjpeg property that holds a boolean value. When you set it to true, sharp uses mozjpeg defaults to compress the image without sacrificing quality. The object can also take more options; see the sharp documentation for more details.

      Note: Regarding the toFormat() method’s second argument, each image format takes an object with different properties. For example, mozjpeg property is accepted only on JPEG images.

      However, other image formats have equivalents options such quality, compression, and lossless. Make sure to refer to the documentation to know what kind of options are acceptable for the image format you are compressing.

      Next, you pass the toFile() method a different filename to save the compressed image as sammy-resized-compressed.jpeg.

      Now, save and exit the file, then run your code with the following command:

      You will receive no output, but an image file sammy-resized-compressed.jpeg is saved in your project directory.

      Open the image on your local machine and you will see the following image:

      Sammy image resized and compressed

      With your image now compressed, check the file size to confirm your compression is successful. In your terminal, run the du command to check the file size for sammy.png:

      -h option produces human-readable output showing you the file size in kilobytes, megabytes and many more.

      After running the command, you should see an output similar to this:

      Output

      120K sammy.png

      The output shows that the original image is 120 kilobytes.

      Next, check the file size for sammy-resized.png:

      After running the command, you will see the following output:

      Output

      8.0K sammy-resized.png

      sammy-resized.png is 8 kilobytes down from 120 kilobytes. This shows that the resizing operation affects the file size.

      Now, check the file size for sammy-resized-compressed.jpeg:

      • du -h sammy-resized-compressed.jpeg

      After running the command, you will see the following output:

      Output

      4.0K sammy-resized-compressed.jpeg

      The sammy-resized-compressed.jpeg is now 4 kilobytes down from 8 kilobytes, saving you 4 kilobytes, showing that the compression worked.

      Now that you’ve resized an image, changed its format and compressed it, you will crop and grayscale the image.

      Step 4 — Cropping and Converting Images to Grayscale

      In this step, you will crop an image, and convert it to grayscale. Cropping is the process of removing unwanted areas from an image. You’ll use the extend() method to crop the sammy.png image. After that, you’ll chain the grayscale() method to the cropped image instance and convert it to grayscale.

      Create and open cropImage.js in your text editor:

      In your cropImage.js file, add the following code to crop the image:

      process_images/cropImage.js

      const sharp = require("sharp");
      
      async function cropImage() {
        try {
          await sharp("sammy.png")
            .extract({ width: 500, height: 330, left: 120, top: 70  })
            .toFile("sammy-cropped.png");
        } catch (error) {
          console.log(error);
        }
      }
      
      cropImage();
      

      The cropImage() function is an asynchronous function that reads an image and returns your image cropped. Within the try block, a sharp instance will read the image. Then, the sharp module’s extract() method chained to the instance takes an object with the following properties:

      • width: the width of the area you want to crop.
      • height: the height of the area you want to crop.
      • top: the vertical position of the area you want to crop.
      • left: the horizontal position of the area you want to crop.

      When you set the width to 500 and the height to 330, imagine that sharp creates a transparent box on top of the image you want to crop. Any part of the image that fits in the box will remain, and the rest will be cut:

      image showing the cropping area

      The top and left properties control the position of the box. When you set left to 120, the box is positioned 120px from the left edge of the image, and setting top to 70 positions the box 70px from the top edge of the image.

      The area of the image that fits within the box will be extracted out and saved into sammy-cropped.png as a separate image.

      Save and exit the file. Run the program in the terminal:

      The output won’t be shown but the image sammy-cropped.png will be saved in your project directory.

      Open the image on your local machine. You should see the image cropped:

      image cropped

      Now that you cropped an image, you will convert the image to grayscale. To do that, you’ll chain the grayscale method to the sharp instance. Add the highlighted code to convert the image to grayscale:

      process_images/cropImage.js

      const sharp = require("sharp");
      
      async function cropImage() {
        try {
          await sharp("sammy.png")
            .extract({ width: 500, height: 330, left: 120, top: 70 })
            .grayscale()
            .toFile("sammy-cropped-grayscale.png");
        } catch (error) {
          console.log(error);
        }
      }
      
      cropImage();
      

      The cropImage() function converts the cropped image to grayscale by chaining the sharp module’s grayscale() method to the sharp instance. It then saves the image in the project directory as sammy-cropped-grayscale.png.

      Press CTRL+X to save and exit the file.

      Run your code in the terminal:

      Open sammy-cropped-grayscale.png on your local machine. You should now see the image in grayscale:

      image cropped and grayscaled

      Now that you’ve cropped and extracted the image, you’ll work with rotating and blurring it.

      Step 5 — Rotating and Blurring Images

      In this step, you’ll rotate the sammy.png image at a 33 degrees angle. You’ll also apply a gaussian blur on the rotated image. A gaussian blur is a technique of blurring an image using the Gaussian function, which reduces the noise level and detail on an image.

      Create a rotateImage.js file in your text editor:

      In your rotateImage.js file, write the following code block to create a function that rotates sammy.png to an angle of 33 degrees:

      process_images/rotateImage.js

      const sharp = require("sharp");
      
      async function rotateImage() {
        try {
          await sharp("sammy.png")
            .rotate(33, { background: { r: 0, g: 0, b: 0, alpha: 0 } })
            .toFile("sammy-rotated.png");
        } catch (error) {
          console.log(error);
        }
      }
      
      rotateImage();
      

      The rotateImage() function is an asynchronous function that reads an image and will return the image rotated to an angle of 33 degrees. Within the function, the rotate() method of the sharp module takes two arguments. The first argument is the rotation angle of 33 degrees. By default, sharp makes the background of the rotated image black. To remove the black background, you pass an object as a second argument to make the background transparent.

      The object has a background property which holds an object defining the RGBA color model. RGBA stands for red, green, blue, and alpha.

      • r: controls the intensity of the red color. It accepts an integer value of 0 to 255. 0 means the color is not being used, and 255 is red at its highest.

      • g: controls the intensity of the green color. It accepts an integer value of 0-255. 0 means that the color green is not used, and 255 is green at its highest.

      • b: controls the intensity of blue. It also accepts an integer value between 0 and 255. 0 means that the blue color isn’t used, and 255 is blue at its highest.

      • alpha: controls the opacity of the color defined by r, g, and b properties. 0 or 0.0 makes the color transparent and 1 or 1.1 makes the color opaque.

      For the alpha property to work, you must make sure you define and set the values for r, g, and b. Setting the r, g, and b values to 0 creates a black color. To create a transparent background, you must define a color first, then you can set alpha to 0 to make it transparent.

      Now, save and exit the file. Run your script in the terminal:

      Check for the existence of sammy-rotated.png in your project directory. Open it on your local machine.

      You should see the image rotated to an angle of 33 degrees:

      image rotated 33 degrees

      Next, you’ll blur the rotated image. You’ll achieve that by chaining the blur() method to the sharp instance.

      Enter the highlighted code below to blur the image:

      process_images/rotateImage.js

      const sharp = require("sharp");
      
      async function rotateImage() {
        try {
          await sharp("sammy.png")
            .rotate(33, { background: { r: 0, g: 0, b: 0, alpha: 0 } })
            .blur(4)
            .toFile("sammy-rotated-blurred.png");
        } catch (error) {
          console.log(error);
        }
      }
      
      rotateImage();
      

      The rotateImage() function now reads the image, rotate it, and applies a gaussian blur to the image. It applies a gaussian blur to the image using the sharp module’s blur() method. The method accepts a single argument containing a sigma value between 0.3 and 1000. Passing it 4 will apply a gaussian blur with a sigma value of 4. After the image is blurred, you define a path to save the blurred image.

      Your script will now blur the rotated image with a sigma value of 4. Save and exit the file, then run the script in your terminal:

      After running the script, open sammy-rotated-blurred.png file on your local machine. You should now see the rotated image blurred:

      rotated image blurred

      Now that you’ve rotated and blurred an image, you’ll composite an image over another.

      Step 6 — Compositing Images Using composite()

      Image Composition is a process of combining two or more separate pictures to create a single image. This is done to create effects that borrow the best elements from the different photos. Another common use case is to watermark an image with a logo.

      In this section, you’ll composite sammy-transparent.png over the underwater.png. This will create an illusion of sammy swimming deep in the ocean. To composite the images, you’ll chain the composite() method to the sharp instance.

      Create and open the file compositeImage.js in your text editor:

      Now, create a function to composite the two images by adding the following code in the compositeImages.js file:

      process_images/compositeImages.js

      const sharp = require("sharp");
      
      async function compositeImages() {
        try {
          await sharp("underwater.png")
            .composite([
              {
                input: "sammy-transparent.png",
                top: 50,
                left: 50,
              },
            ])
            .toFile("sammy-underwater.png");
        } catch (error) {
          console.log(error);
        }
      }
      
      compositeImages()
      

      The compositeImages() function reads the underwater.png image first. Next, you chain the composite() method of the sharp module, which takes an array as an argument. The array contains a single object that reads the sammy-transparent.png image. The object has the following properties:

      • input: takes the path of the image you want to composite over the processed image. It also accepts a Buffer, Uint8Array, or Uint8ClampedArray as input.
      • top: controls the vertical position of the image you want to composite over. Setting top to 50 offsets the sammy-transparent.png image 50px from the top edge of the underwater.png image.
      • left: controls the horizontal position of the image you want to composite over another. Setting left to 50 offsets the sammy-transparent.png 50px from the left edge of the underwater.png image.

      The composite() method requires an image of similar size or smaller to the processed image.

      To visualize what the composite() method is doing, think of it like its creating a stack of images. The sammy-transparent.png image is placed on top of underwater.png image:

      a graphic showing an image stack

      The top and left values positions the sammy-transparent.png image relative to the underwater.png image.

      Save your script and exit the file. Run your script to create an image composition:

      node compositeImages.js
      

      Open sammy-underwater.png in your local machine. You should now see the sammy-transparent.png composited over the underwater.png image:

      an image composition

      You’ve now composited images using the composite() method. In the next step, you’ll use the composite() method to add text to an image.

      Step 7 — Adding Text on an Image

      In this step, you’ll write text on an image. At the time of writing, sharp doesn’t have a native way of adding text to an image. To add text, first, you’ll write code to draw text using Scalable Vector Graphics(SVG). Once you’ve created the SVG image, you’ll write code to composite the image with the sammy.png image using the composite method.

      SVG is an XML-based markup language for creating vector graphics for the web. You can draw text, or shapes such as circles, triangles, and as well as draw complex shapes such as illustrations, logos, etc. The complex shapes are created with a graphic tool like Inkscape which generates the SVG code. The SVG shapes can be rendered and scaled to any size without losing quality.

      Create and open the addTextOnImage.js file in your text editor.

      In your addTextOnImage.js file, add the following code to create an SVG container:

      process_images/addTextOnImage.js

      const sharp = require("sharp");
      
      async function addTextOnImage() {
        try {
          const width = 750;
          const height = 483;
          const text = "Sammy the Shark";
      
          const svgImage = `
          <svg width="${width}" height="${height}">
          </svg>
          `;
        } catch (error) {
          console.log(error);
        }
      }
      
      addTextOnImage();
      

      The addTextOnImage() function defines four variables: width, height, text, and svgImage. width holds the integer 750, and height holds the integer 483. text holds the string Sammy the Shark. This is the text that you’ll draw using SVG.

      The svgImage variable holds the svg element. The svg element has two attributes: width and height that interpolates the width and height variables you defined earlier. The svg element creates a transparent container according to the given width and height.

      You gave the svg element a width of 750 and height of 483 so that the SVG image will have the same size as sammy.png. This will help in making the text look centered on the sammy.png image.

      Next, you’ll draw the text graphics. Add the highlighted code to draw Sammy the Shark on the SVG container:

      process_images/addTextOnImage.js

      async function addTextOnImage() {
          ...
          const svg = `
          <svg width="${width}" height="${height}">
          <text x="50%" y="50%" text-anchor="middle" class="title">${text}</text>
          </svg>
          `;
        ....
      }
      

      The SVG text element has four attributes: x, y, text-anchor, and class. x and y define the position for the text you are drawing on the SVG container. The x attribute positions the text horizontally, and the y attribute positions the text vertically.

      Setting x to 50% draws the text in the middle of the container on the x-axis, and setting y to 50% positions the text in the middle on y-axis of the SVG image.

      The text-anchor aligns text horizontally. Setting text-anchor to middle will align the text on the center at the x coordinate you specified.

      class defines a class name on the text element. You’ll use the class name to apply CSS styles to the text element.

      ${text} interpolates the string Sammy the Shark stored in the text variable. This is the text that will be drawn on the SVG image.

      Next, add the highlighted code to style the text using CSS:

      process_images/addTextOnImage.js

          const svg = `
          <svg width="${width}" height="${height}">
            <style>
            .title { fill: #001; font-size: 70px; font-weight: bold;}
            </style>
            <text x="50%" y="50%" text-anchor="middle" class="title">${text}</text>
          </svg>
          `;
      

      In this code, fill changes the text color to black, font-size changes the font size, and font-weight changes the font weight.

      At this point, you have written the code necessary to draw the text Sammy the Shark with SVG. Next, you’ll save the SVG image as a png with sharp so that you can see how SVG is drawing the text. Once that is done, you’ll composite the SVG image with sammy.png.

      Add the highlighted code to save the SVG image as a png with sharp:

      process_images/addTextOnImage.js

          ....
          const svgImage = `
          <svg width="${width}" height="${height}">
          ...
          </svg>
          `;
          const svgBuffer = Buffer.from(svgImage);
          const image = await sharp(svgBuffer).toFile("svg-image.png");
        } catch (error) {
          console.log(error);
        }
      }
      
      addTextOnImage();
      

      Buffer.from() creates a Buffer object from the SVG image. A buffer is a temporary space in memory that stores binary data.

      After creating the buffer object, you create a sharp instance with the buffer object as input. In addition to an image path, sharp also accepts a buffer, Uint9Array, or Uint8ClampedArray.

      Finally, you save the SVG image in the project directory as svg-image.png.

      Here is the complete code:

      process_images/addTextOnImage.js

      const sharp = require("sharp");
      
      async function addTextOnImage() {
        try {
          const width = 750;
          const height = 483;
          const text = "Sammy the Shark";
      
          const svgImage = `
          <svg width="${width}" height="${height}">
            <style>
            .title { fill: #001; font-size: 70px; font-weight: bold;}
            </style>
            <text x="50%" y="50%" text-anchor="middle" class="title">${text}</text>
          </svg>
          `;
          const svgBuffer = Buffer.from(svgImage);
          const image = await sharp(svgBuffer).toFile("svg-image.png");
        } catch (error) {
          console.log(error);
        }
      }
      
      addTextOnImage()
      

      Save and exit the file, then run your script with the following command:

      node addTextOnImage.js
      

      Note: If you installed Node.js using Option 2 — Installing Node.js with Apt Using a NodeSource PPA or Option 3 — Installing Node Using the Node Version Manager and getting the error fontconfig error: cannot load default config file: no such file: (null), install fontconfig to generate the font configuration file.

      Update your server’s package index, and after that, use apt install to install fontconfig.

      • sudo apt update
      • sudo apt install fontconfig

      Open svg-image.png on your local machine. You should now see the text Sammy the Shark rendered with a transparent background:

      svg text rendered

      Now that you’ve confirmed the SVG code draws the text, you will composite the text graphics onto sammy.png.

      Add the following highlighted code to composite the SVG text graphics image onto the sammy.png image.

      process_images/addTextOnImage.js

      const sharp = require("sharp");
      
      async function addTextOnImage() {
        try {
          const width = 750;
          const height = 483;
          const text = "Sammy the Shark";
      
          const svgImage = `
          <svg width="${width}" height="${height}">
            <style>
            .title { fill: #001; font-size: 70px; font-weight: bold;}
            </style>
            <text x="50%" y="50%" text-anchor="middle" class="title">${text}</text>
          </svg>
          `;
          const svgBuffer = Buffer.from(svgImage);
          const image = await sharp("sammy.png")
            .composite([
              {
                input: svgBuffer,
                top: 0,
                left: 0,
              },
            ])
            .toFile("sammy-text-overlay.png");
        } catch (error) {
          console.log(error);
        }
      }
      
      addTextOnImage();
      

      The composite() method reads the SVG image from the svgBuffer variable, and positions it 0 pixels from the top, and 0 pixels from the left edge of the sammy.png. Next, you save the composited image as sammy-text-overlay.png.

      Save and close your file, then run your program using the following command:

      Open sammy-text-overlay.png on your local machine. You should see text added over the image:

      text added on image

      You have now used the composite() method to add text created with SVG on another image.

      Conclusion

      In this article, you learned how to use sharp methods to process images in Node.js. First, you created an instance to read an image and used the metadata() method to extract the image metadata. You then used the resize() method to resize an image. Afterwards, you used the format() method to change the image type, and compress the image. Next, you proceeded to use various sharp methods to crop, grayscale, rotate, and blur an image. Finally, you used the composite() method to composite an image, and add text on an image.

      For more insight into additional sharp methods, visit the sharp documentation. If you want to continue learning Node.js, see How To Code in Node.js series.



      Source link

      How To Handle Images with GraphQL and the Gatsby Image API


      The author selected /dev/color to receive a donation as part of the Write for DOnations program.

      Introduction

      Handling images plays a pivotal role in building websites, but also can be challenging to deal with. Unoptimized images slow down websites, and many images that might look appropriate on a desktop are hard to scale down to a mobile device. Visually manipulating an image can also be tedious and difficult to maintain.

      All of these problems in isolation are not a big issue. The main problem is when you have to keep track of all of these rules and image-scaling techniques. When it comes to Gatsby.js projects, this is where the Gatsby Image API comes in handy. By using GraphQL queries, you can use the Gatsby Image API to take care of image compression, make an image responsive, and even handle basic image styling.

      In this tutorial, you are going to compress, transform, and style images using the Gatsby Image API and GraphQL queries.

      Prerequisites

      Step 1 — Setting Up a New Gatsby Project

      In this first step, you are going to set up a new Gatsby project and familiarize yourself with the key image plugins that you’ll use throughout this tutorial. You will also download and set up an image to optimize throughout the tutorial.

      First, use the CLI tool to start a new project named gatsby-image-project:

      • gatsby new gatsby-image-project https://github.com/gatsbyjs/gatsby-starter-default

      This creates a new website from the starter template in the [gatsby-starter-default](https://github.com/gatsbyjs/gatsby-starter-default) GitHub repository from Gatsby.

      Once the project is created, move into the new project directory:

      Next, open up the index.js file in a text editor of your choice:

      Delete all of the code between the layout wrapper component so that your file is the same as the following:

      gatsby-image-project/src/pages/index.js

      import React from "react"
      import { Link } from "gatsby"
      
      import Layout from "../components/layout"
      import Image from "../components/image"
      import SEO from "../components/seo"
      
      const IndexPage = () => (
        <Layout>
        </Layout>
      )
      
      export default IndexPage
      

      Next, replace the deleted code with the following highlighted JSX, which adds some HTML elements to the website:

      gatsby-image-project/src/pages/index.js

      import React from "react"
      import { Link } from "gatsby"
      
      import Layout from "../components/layout"
      import Image from "../components/image"
      import SEO from "../components/seo"
      
      const IndexPage = () => (
          <Layout>
            <div className="layout">
              <Image className="left-image"/>
              <h2>Hello</h2>
              <p>Welcome to my humble site</p>
              <p>All of our shirts are on sale!</p>
              <button className="shop-button">Shop</button>
            </div>
          </Layout>
      )
      
      export default IndexPage
      

      The Gatsby Image API will provide your new test image to the Image element in a later step. With this, you now have HTML to experiment with.

      Later in the tutorial, you’ll revisit the index.js page. For now, save and exit the file.

      The next file to open is gatsby-config.js. In this file, you will find the plugins responsible for processing images.

      Open up the file with the following:

      Once you have opened the gatsby-config file, locate the gatsby-plugin-sharp, gatsby-transformer-sharp, and gatsby-source-filesystem plugins:

      gatsby-image-project/gatsby-config.js

      module.exports = {
        siteMetadata: {
          title: `Gatsby Default Starter`,
          description: `Kick off your next, great Gatsby project with this default starter. This barebones starter ships with the main Gatsby configuration files you might need.`,
          author: `@gatsbyjs`,
        },
        plugins: [
          `gatsby-plugin-react-helmet`,
          {
            resolve: `gatsby-source-filesystem`,
            options: {
              name: `images`,
              path: `${__dirname}/src/images`,
            },
          },
          `gatsby-transformer-sharp`,
          `gatsby-plugin-sharp`,
          {
            resolve: `gatsby-plugin-manifest`,
            options: {
              name: `gatsby-starter-default`,
              short_name: `starter`,
              start_url: `/`,
              background_color: `#663399`,
              theme_color: `#663399`,
              display: `minimal-ui`,
              icon: `src/images/gatsby-icon.png`, // This path is relative to the root of the site.
            },
          },
          // this (optional) plugin enables Progressive Web App + Offline functionality
          // To learn more, visit: https://gatsby.dev/offline
          // `gatsby-plugin-offline`,
        ],
      }
      

      These plugins are as follows:

      • gatsby-plugin-sharp: Sharp is an image optimization library that Gatsby uses to process images. The gatsby-plugin-sharp provides a bridge between Sharp and Gatsby.

      • gatsby-transformer-sharp: This plugin performs image transformations, such as resizing, compressing, and changing background color.

      • gatsby-source-filesystem: This plugin allows you to source data from your filesystem into your application. In this case, it enables GraphQL to query images.

      Now that you have an idea of which plugins are used to process images, close the file.

      Next, add an image to your application to optimize, edit, and style later. In this tutorial, you are going to download an image from the Unsplash stock image website. Navigate to this picture of clothes on Unsplash in a browser and download the angela-bailey-jlo7Bf4tUoY-unsplash.jpg image into the /images folder of your Gatsby project. The image must be located in the right directory in order to query the image with GraphQL and transform it using Gatsby’s Image API.

      Alternatively, you can download the image from the command line. First, move to the images directory:

      Next, execute the following command:

      • curl -sL https://images.unsplash.com/photo-1556905055-8f358a7a47b2 -o angela-bailey-jlo7Bf4tUoY-unsplash.jpg

      This will use curl to download the image and output the file as angela-bailey-jlo7Bf4tUoY-unsplash.jpg.

      In this section, you set up your Gatsby project to use Gatsby’s Image API. You explored the Gatsby configuration file to find gatsby-plugin-sharp, gatsby-transform-sharp, and gatsby-source-filesystem, which work together to optimize images. In the next step, you will test out querying and optimizing your image using GraphiQL, the GraphQL integrated development environment (IDE).

      Step 2 — Querying Images with GraphQL

      You are now going to query your new image using GraphQL. GraphQL is a query language for obtaining information from an API. It is also the data layer of Gatsby.

      First, return to the root of your Gatsby project, then start the development server:

      After your site finishes building, you will receive the following output:

      Output

      ... success open and validate gatsby-configs - 0.081s success load plugins - 4.537s success onPreInit - 0.070s success initialize cache - 0.034s success copy gatsby files - 0.320s success onPreBootstrap - 0.177s success createSchemaCustomization - 0.050s success Checking for changed pages - 0.003s success source and transform nodes - 0.264s success building schema - 0.599s info Total nodes: 35, SitePage nodes: 1 (use --verbose for breakdown) success createPages - 0.057s success Checking for changed pages - 0.005s success createPagesStatefully - 0.188s success update schema - 0.046s success write out redirect data - 0.006s success Build manifest and related icons - 0.456s success onPostBootstrap - 0.465s info bootstrap finished - 19.515s success onPreExtractQueries - 0.003s success extract queries from components - 0.932s success write out requires - 0.029s success run page queries - 0.039s - 1/1 25.97/s ⠀ You can now view gatsby-starter-default in the browser. ⠀ http://localhost:8000/ ⠀ View GraphiQL, an in-browser IDE, to explore your site's data and schema ⠀ http://localhost:8000/___graphql ⠀ Note that the development build is not optimized. To create a production build, use gatsby build ⠀ warn ESLintError: /your_filepath/gatsby-image-project/src/pages/index.js 2:10 warning 'Link' is defined but never used no-unused-vars 6:8 warning 'SEO' is defined but never used no-unused-vars ✖ 2 problems (0 errors, 2 warnings) success Building development bundle - 10.814s

      This output contains two links. The first link, https://localhost:8000/, is where you can find your local development site. The second link, http://localhost:8000/___graphql, is the location of GraphiQL. GraphiQL is an integrated development editor (IDE) that allows you to make queries in the browser. This is a useful tool that helps you experiment and make data queries before you add them to your codebase. GraphiQL only works when you are running the development server.

      With the help of GraphiQL, you can try out queries to retrieve your newly downloaded image. Open your browser and enter the GraphiQL URL http://localhost:8000/___graphql into the address bar. The browser will display the GraphiQL interface:

      Screenshot of the GraphQL IDE

      GraphiQL is split into three sections. To the far left is the Explorer, where you can find the fields that you are able to access via GraphQL. In the middle of the IDE is the sandbox where you make queries. Finally, to the far right you can find GraphQL’s documentation.

      Your first goal is to query the angela-bailey-jlo7Bf4tUoY-unsplash.jpg image. Since the image is located in the local filesystem, you choose file in the Explorer box. This will show a dropdown menu of subdirectories. You will search for the image file by relative path, so select on relativePath. relativePath reveals another set of subfolders. You will enter the exact path of the image, so choose the eq for “equals”. Inside the quotes enter the path of the image angela-bailey-jlo7Bf4tUoY-unsplash.jpg.

      GraphQL IDE showing the query to locate the image in the filesystem

      Now you are set to try out your first image manipulation. Your original image is 1920 by 1280 pixels. That is too big for your landing page, and it would help to make the image responsive. Normally, you would have to hard code the width into CSS and add media queries to make the image responsive. Gatsby’s Image API does all of that work for you, without you needing to write extra CSS.

      Select childImageSharp in the Explorer box, which transforms the image under the hood. Make sure to choose this from the top-level menu, not from under file. Choose fluid from the next dropdown. A fluid image stretches to fill its container. In the dropdown options for fluid, check maxWidth and enter the 750.

      The blue values just below the purple querying parameters are the different values you can return. Choose src and srcSet to return the location of the original and transformed image. Then click the play button to view the results:

      childImageSharp parameters

      After selecting the parameters, GraphiQL builds the following query:

      query MyQuery {
        file(relativePath: {eq: "angela-bailey-jlo7Bf4tUoY-unsplash.jpg"}) {
          childImageSharp {
            fluid(maxWidth: 750) {
              src
              srcSet
            }
          }
        }
      }
      

      In the box on the right of the GraphiQL interface, you will find the return values. This will show:

      • src: Location of the image after processing.

      • srcSet: Same image set to a different size. This feature comes in handy if you want your images to be responsive.

      You do not have to choose fluid in your query; you also have the option to choose fix. A fixed image creates responsive images 1x, 1.5x, and 2x pixel densities using the <picture> element. The following is an example of a fixed query:

      query MyQuery {
        file(relativePath: {eq: "angela-bailey-jlo7Bf4tUoY-unsplash.jpg"}) {
          childImageSharp {
            fixed(cropFocus: CENTER) {
              src
              srcSet
            }
          }
        }
      }
      

      This query will return the following:

      {
        "data": {
          "file": {
            "childImageSharp": {
              "fixed": {
                "src": "/static/8e3a47b77ddf6636755d7be661d7b019/0ad16/angela-bailey-jlo7Bf4tUoY-unsplash.jpg",
                "srcSet": "/static/8e3a47b77ddf6636755d7be661d7b019/0ad16/angela-bailey-jlo7Bf4tUoY-unsplash.jpg 1x,n/static/8e3a47b77ddf6636755d7be661d7b019/44157/angela-bailey-jlo7Bf4tUoY-unsplash.jpg 1.5x,n/static/8e3a47b77ddf6636755d7be661d7b019/7fddd/angela-bailey-jlo7Bf4tUoY-unsplash.jpg 2x"
              }
            }
          }
        },
        "extensions": {}
      }
      

      In this query you have a fixed version of the image, with the crop focus set to center. Your return value is the location of the image and a set of different image sizes (1x, 1.5x, 2x respectively).

      Now that you have tested out the GraphQL query using GraphiQL and the childImageSharp node, you will next add the queried image to a template and further optimize it using Gatsby’s Image API.

      Step 3 — Optimizing Your Image’s Performance for the Web

      In this section you are going to transfer your GraphQL image to the index.js page of your project and perform more image optimizations.

      From your terminal in the root of your Gatsby project, open the image component in your favorite text editor:

      • nano src/components/image.js

      Now, use the query that you tried out in the GraphiQL interface. Delete "gatsby-astronaut.png" and replace it with "angela-bailey-jlo7Bf4tUoY-unsplash.jpg". Also replace maxWidth: 300 with maxWidth: 750:

      gatsby-image-project/src/components/image.js

      import React from "react"
      import { useStaticQuery, graphql } from "gatsby"
      import Img from "gatsby-image"
      
      /*
       * This component is built using `gatsby-image` to automatically serve optimized
       * images with lazy loading and reduced file sizes. The image is loaded using a
       * `useStaticQuery`, which allows us to load the image from directly within this
       * component, rather than having to pass the image data down from pages.
       *
       * For more information, see the docs:
       * - `gatsby-image`: https://gatsby.dev/gatsby-image
       * - `useStaticQuery`: https://www.gatsbyjs.com/docs/use-static-query/
       */
      
      const Image = () => {
        const data = useStaticQuery(graphql`
          query {
            placeholderImage: file(relativePath: { eq: "angela-bailey-jlo7Bf4tUoY-unsplash.jpg" }) {
              childImageSharp {
                fluid(maxWidth: 750) {
                  ...GatsbyImageSharpFluid
                }
              }
            }
          }
        `)
      
        if (!data?.placeholderImage?.childImageSharp?.fluid) {
          return <div>Picture not found</div>
        }
      
        return <Img fluid={data.placeholderImage.childImageSharp.fluid} />
      }
      
      export default Image
      

      ...GatsbyImageSharpFluid is a GraphQL fragment. This syntax allows you to obtain all of the different return values for childImageSharp and fluid. You will use this as the return value instead of src and srcSet.

      GraphiQL explorer list of return values for `childImageSharp` and `fluid`

      In the image.js file, after the GraphQL query there is an if statement:

      gatsby-image-project/src/components/image.js

      ...
        if (!data?.placeholderImage?.childImageSharp?.fluid) {
          return <div>Picture not found</div>
        }
      
        return <Img fluid={data.placeholderImage.childImageSharp.fluid} />
      }
      
      export default Image
      

      placeholderimage is the alias that is given in the query and returned in <Img fluid={data.placeholderImage.childImageSharp.fluid} />. In GraphQL you are able to name your queries. In the conditional statement, if you don’t have an image, then the words Picture not found will appear on the landing page.

      Save and close this file.

      Once you build your Gatsby site, the image will be processed and optimized by the Gatsby Image API. This will decrease the size of the image file to decrease loading time for your site. To test this out, navigate to the images directory to find the original file size:

      Now list out the files with the following command:

      The -sh flag will show you the memory size of the files in a human-readable format. You will receive the following output:

      Output

      total 5.0M 4.8M angela-bailey-jlo7Bf4tUoY-unsplash.jpg 164K gatsby-astronaut.png 24K gatsby-icon.png

      Without any optimization, the image is 4.8M. Now you will look at how big the image is after you’ve used Gatsby’s Image API.

      Navigate to the root of your project and start the development server:

      Once the development server has started, place the local address into the browser. Once the site has loaded, right-click the image and select Inspect.

      Image with Inspect dropdown menu

      Now navigate to the Network tab of your browser’s developer tools. This tutorial will use Google Chrome DevTools:

      Local image size

      Your image went from 4.8 MB to 68.4 kB. That is significantly smaller than if you hadn’t used the Gatsby Image API.

      Note: If the HTTP status for the image request is 304, the image may be significantly smaller due to caching. To get a more reliable view of the image size, clear the cache and refresh the page.

      Keep developer tools open and head over to the Elements tab. Hover over the image. You will find the HTML element <picture>...</picture> and its child <source>...</source>:

      Rendered HTML of the Gatsby site

      In the source tag, you can find the srcSet attribute (the same one you queried for in GraphQL). You will also find that the different heights and widths of the image were automatically generated. These different images ensure that angela-bailey-jlo7Bf4tUoY-unsplash.jpg is fluid, without needing to change CSS.

      Note: While hovering over the image you might have noticed that the image is not keyboard-focusable, which could be an accessibility problem. If you want to learn more about accessibility, you can check out the Ally Project checklist.

      In this section you used the GraphQL Image query in your Gatsby template. You also optimized angela-bailey-jlo7Bf4tUoY-unsplash.jpg without having to write extra CSS.

      In the next section, you will visually transform the image by using childSharpImage.

      Step 4 — Styling Your Image with childSharpImage

      In this section, you will transform the look of angela-bailey-jlo7Bf4tUoY-unsplash.jpg with the help of childSharpImage. To test this, you will change your image to grayscale.

      Open image.js in a text editor:

      • nano src/components/image.js

      Go into your placeholderImage GraphQL query and inside of fluid set grayscale to true:

      gatsby-image-project/src/components/image.js

      import React from "react"
      import { useStaticQuery, graphql } from "gatsby"
      import Img from "gatsby-image"
      
      /*
       * This component is built using `gatsby-image` to automatically serve optimized
       * images with lazy loading and reduced file sizes. The image is loaded using a
       * `useStaticQuery`, which allows us to load the image from directly within this
       * component, rather than having to pass the image data down from pages.
       *
       * For more information, see the docs:
       * - `gatsby-image`: https://gatsby.dev/gatsby-image
       * - `useStaticQuery`: https://www.gatsbyjs.com/docs/use-static-query/
       */
      
      const Image = () => {
        const data = useStaticQuery(graphql`
          query {
            placeholderImage: file(relativePath: { eq: "angela-bailey-jlo7Bf4tUoY-unsplash.jpg" }) {
              childImageSharp {
                fluid(
                  maxWidth: 750
                  grayscale: true
                  ) {
                  ...GatsbyImageSharpFluid
                }
              }
            }
          }
        `)
      
        if (!data?.placeholderImage?.childImageSharp?.fluid) {
          return <div>Picture not found</div>
        }
      
        return <Img fluid={data.placeholderImage.childImageSharp.fluid} tabIndex='0' />
      }
      
      export default Image
      

      Save and close the file.

      Go back to your terminal and restart the server. You will find your image changed using childImageSharp, without writing and maintaining unnecessary CSS:

      Grayscale image

      Grayscale is just one of the many ways you can process your image using childImageSharp. Go to Gatsby’s documentation if you are curious about the other childImageSharp props.

      In this section you implemented grayscale by using childImageSharp. With this knowledge, you can perform many more image manipulations by leveraging the Gatsby Image API.

      Conclusion

      In this tutorial, you set your Gatsby project up to use the Gatsby Image API, query your Image using GraphQL, optimize your image’s performance, and style your image using childImageSharp. If you would like to learn more about Gatsby, check out the official Gatsby documentation.



      Source link

      How To Style Images With CSS



      Part of the Series:
      How To Build a Website With CSS

      This tutorial is part of a series on creating and customizing this website with CSS, a stylesheet language used to control the presentation of websites. You may follow the entire series to recreate the demonstration website and gain familiarity with CSS or use the methods described here for other CSS website projects.

      Before proceeding, we recommend that you have some knowledge of HTML, the standard markup language used to display documents in a web browser. If you don’t have familiarity with HTML, you can follow the first ten tutorials of our series How To Build a Website With HTML before starting this series.

      Introduction

      In this tutorial, you will learn how to style images with CSS to add a border, and change the shape, and size of the image. Using CSS to style images allows you to uniformly specify how images should appear across your website with only a few rulesets.

      Prerequisites

      To follow this tutorial, make sure you have set up the necessary files and folders as instructed in a previous tutorial in this series How To Set Up You CSS and HTML Practice Project.

      Adding Images To index.html

      First, you need to add an image to the images folder. You can download the image from the demonstration website or use any image in a JPEG/JPG or PNG format. This exercise will also work better if the dimensions of your image are around 150-200 pixels by 150-200 pixels.

      Note: To download the image of Sammy the Shark, visit this link and CTRL + Left Click (on Macs) or Right Click (on Windows) on the image and select “Save Image As” and save it as small-profile.jpeg to your images folder.

      Once you have selected an image, save it to your images folder as small-profile.jpeg. If you save it as a different file name, you’ll need to modify the image file path in the step below.

      Next, erase all the content in your index.html file (except for the first line of code: <link rel="stylesheet" href="https://www.digitalocean.com/community/tutorials/css/styles.css">) and add the following code snippet:

      index.html

      <img src="https://www.digitalocean.com/community/tutorials/images/small-profile.jpeg" alt="Sammy the Shark, DigitalOcean’s mascot"> 
      

      This code snippet uses the <img> tag to insert an image and gives the browser the location of the image file (images/small-profile.jpeg). Make sure the highlighted file path is correct if you have changed the file name of your image.

      Note:
      To copy the file path of your image using Visual Studio Code, hover over the icon of the image file in the left-hand panel, click CTRL + Left Click (on Macs) or Right Click (on Windows), and select “Copy Path.” For an illustration of the process, please see the gif below:

      Gif of how to copy an image file path

      Make sure to copy the relative or project file path of the image rather than the absolute or full file path of the image. The relative path refers to the file location relative to the current working directory (as opposed to the absolute path, which refers to the file location relative to the root directory.) While both paths will work in this instance, only the relative path would work if you decided to publish the website online. Since the end goal is to create a publishable website, you will start using relative paths now when adding <img> elements to the document.

      You have also added the alternative text Sammy the Shark, DigitalOcean’s mascot using the alt attribute. When creating websites, alternative text should be added to all images to support site accessibility for individuals who use screen readers. To read more about using alternative text with HTML, please visit the section on alternative text in our guide How To Add Images To Your Webpage Using HTML.

      Save your index.html file and reload it in your browser. (For instructions on loading an HTML file, please visit our tutorial step How To View An Offline HTML File In Your Browser). You should receive a blank page with your image displayed:

      Small profile image displayed in browser

      If your image doesn’t display, check your code for errors and confirm that you have the correct file path for the image.

      Adding Styles To Images

      Now that index.html displays an image of Sammy the Shark (or the image of your choice), you’ll add a CSS rule to style the image. In your styles.css file, erase everything (if you’ve been following along the tutorial series) and add the following ruleset at the bottom of the document:

      styles.css

      . . .
      img {
        border: 2px solid red;
        border-radius: 8px;
        width: 200px;
      }
      

      Save your styles.css file and reload your index.html file in your browser. You should now receive an image with new style properties:

      Webpage with styled small profile image

      In this CSS rule, you have specified values for three different properties of the HTML <img> element. Let’s pause to examine each of the different properties and values:

      • The border property allows you to add a border to your image and specify the size, style, and color of the border. Notice that you can add multiple values for this CSS property. In this rule, you have specified a solid, red border with a width of 2px.

      • The border-radius property defines the radius of an element’s corners, allowing you to round the edges of an element. In this rule, you have specified 8 pixels as the size of the radius. Try changing this number to see how it affects the display of the image.

      • The width property defines the width of the image. In this rule, you have specified the width to be 200 pixels wide. Note that if you leave the height undefined, the height of the image will automatically adjust to maintain the original proportions of the image. Try changing both the height and width at the same time to check what happens.

      Exploring How Style is Applied To All Images

      Note that if you add any additional images to your HTML document, they will also have the same styling. To study how this works, add a second image to your index.html file using the HTML <img> element. (You can copy and paste the first <img> element if you don’t have a second image handy):

      index.html

      <img src="https://www.digitalocean.com/community/tutorials/images/small-profile.jpeg" alt="Sammy the Shark, DigitalOcean’s mascot"> 
      <img src="https://www.digitalocean.com/community/tutorials/images/small-profile.jpeg" alt="Sammy the Shark, DigitalOcean’s mascot"> 
      

      Make sure to change the highlighted section with your image file path. Save your index.html file and load it in the browser. Your webpage should display two images styled with the same CSS ruleset for the <img> tag:

      Webpage displaying two images with the same style

      To continue exploring style possibilities for images, try changing the values in the CSS rule you just created in the styles.css file, saving the file, and reloading the index.html to check the results.

      Conclusion

      In this tutorial you explored how to style an image’s border size, color, appearance, height, width, and border radius. You will return to image styling when you begin building the demonstration website in the second half of this tutorial series.

      Now that you are familiar with how to apply a set of style rules to all <img> elements, you may be curious how to apply different style rules to individual or groups of <img> elements. In the next tutorial, you will create CSS classes, which allow developers to sort HTML elements into different classes for different CSS styling.



      Source link