One place for hosting & domains

      Images

      How to Use Buildah to Build OCI Container Images


      Buildah is an open source containerization tool capable of creating images from scratch, Dockerfiles, or Containerfiles. It also follows the Open Container Initiative (OCI) specifications, making Buildah images both versatile and open.

      Learn how to install and start using Buildah in this tutorial. Below, find steps for creating containers and rendering those containers to images.

      Before You Begin

      1. Familiarize yourself with our
        Getting Started with Linode guide, and complete the steps for setting your Linode’s hostname and timezone.

      2. This guide uses sudo wherever possible. Complete the sections of our
        How to Secure Your Server guide to create a standard user account, harden SSH access, and remove unnecessary network services.

      3. Update your system.

        • AlmaLinux, CentOS Stream, Fedora, or Rocky Linux:

          sudo dnf upgrade
          
        • Ubuntu:

          sudo apt update && sudo apt upgrade
          

      Note

      This guide is written for a non-root user. Commands that require elevated privileges are prefixed with sudo. If you’re not familiar with the sudo command, see the
      Users and Groups guide.

      What Is Buildah?

      Buildah is an open source tool for building container images that are compliant with the OCI.

      The OCI seeks to create an open standard for containerization. To that end, it defines specifications for container runtimes and images. Another goal of the OCI is to help secure and streamline operating system virtualization.

      Buildah provides powerful tools to create and maintain OCI-compliant images. You may be familiar with Dockerfiles, one of the most common formats for container images. Buildah fully supports them, and can create images directly from them.

      But Buildah can also craft container images from scratch. Buildah allows you to use the command line to build up the container from a complete blank slate, giving it only the contents you need. Buildah can then render and export an OCI container image from your work.

      Buildah vs Docker

      Overall, Buildah is similar in functionality to Docker. So what sets it apart? Why use Buildah instead of Docker?

      One of Buildah’s primary advantages is it avoids the security risks of the Docker daemon. The Docker daemon runs on a socket with root-level access, and this has the potential to introduce security risks. Buildah avoids this risk by running without a daemon, allowing containers to be truly rootless.

      With Buildah, the user also has the ability to create container images from scratch. Buildah can mount an empty container and let the user add only what they need. This feature can be extraordinarily useful when you need a lightweight image.

      Buildah also gives the user precise control of images, and specifically image layers. For those wanting more capabilities in their containerization tools, Buildah tends to offer what they need.

      However, Buildah is not as useful when it comes to running and deploying container images. It can run them, but lacks some of the features to be found in other tools. Instead, Buildah puts the vast majority of its emphasis on creating containers and building container images.

      For that reason, users often build their OCI images in Buildah and run them using Podman, a tool for running and managing containers. You can learn more about Podman in our guide
      Podman vs Docker: Comparing the Two Containerization Tools.

      How to Install Buildah

      1. Install Buildah using your distribution’s package manager.

        • AlmaLinux, CentOS Stream (8 or later), Fedora, or Rocky Linux:

          sudo dnf install buildah
          
        • Ubuntu (20.10 or later):

          sudo apt install buildah
          
      2. Verify your installation by checking the installed Buildah version using the command below:

        buildah -v
        

        Your output may vary from what is shown here, but you are just looking to see that Buildah installed successfully:

        buildah version 1.26.1 (image-spec 1.0.2-dev, runtime-spec 1.0.2-dev)

      Configuring Buildah for Rootless Usage

      By default, Buildah commands are executed with root privileges, prefaced with the sudo command. However, one of the most appealing features of Buildah is its ability to run containers in rootless mode. This lets limited users work securely with Buildah.

      While Docker also allows you to run commands as a limited user, the Docker daemon still runs as root. This is a potential security issue with Docker, one that may allow limited users to execute privileged commands through the daemon.

      Buildah’s rootless mode solves this because it runs containers completely in a non-root environment, without a root daemon. Find the steps needed to set up your Buildah instance for rootless usage below.

      1. Install the slirp4netns and fuse-overlayfs tools to support your rootless Buildah operations.

        • AlmaLinux, CentOS Stream, Fedora, or Rocky Linux:

          sudo dnf install slirp4netns fuse-overlayfs
          
        • Ubuntu:

          sudo apt install slirp4netns fuse-overlayfs
          
      2. Add subuids and subgids ranges for your limited user. This example does so for the user example_user. It gives that user a sub-UID and sub-GID of 100000, each with a range of 65535 IDs:

        sudo usermod --add-subuids 100000-165535 --add-subgids 100000-165535 example_user
        

      How to Use Buildah

      Buildah is primarily used for creating container images. Like Docker, Buildah can construct containers from Dockerfiles, but Buildah stands out for also allowing you to craft images from scratch.

      The next two sections show you how to build container images using each of these methods.

      Creating an Image from a Dockerfile

      Dockerfiles provide an approachable way to create containers with Buildah, especially for users already familiar with Docker or Dockerfiles.

      Buildah is fully capable of interpreting Dockerfile script, making it straightforward to build your Docker container images with Buildah.

      This guide uses an example Dockerfile provided in one of the official Buildah tutorials. This Dockerfile results in a container with the latest version of Fedora and the Apache HTTP server (httpd). It also “exposes” the HTTP server via port 80.

      1. Create a new file named Dockerfile in your user’s home directory:

        nano Dockerfile
        
      2. Fill it with the following contents:

        File: Dockerfile
         1
         2
         3
         4
         5
         6
         7
         8
         9
        10
        11
        12
        13
        
        # Base on the most recently released Fedora
        FROM fedora:latest
        MAINTAINER ipbabble email buildahboy@redhat.com # not a real email
        
        # Install updates and httpd
        RUN echo "Updating all fedora packages"; dnf -y update; dnf -y clean all
        RUN echo "Installing httpd"; dnf -y install httpd && dnf -y clean all
        
        # Expose the default httpd port 80
        EXPOSE 80
        
        # Run the httpd
        CMD ["/usr/sbin/httpd", "-DFOREGROUND"]
      3. Press CTRL+X to exit, Y to save, and Enter to quit nano.

        Assuming you are still in the directory where this Dockerfile is located (your user’s home directory), you can immediately build the container’s image.

      4. This example names the new image fedora-http-server:

        buildah build -t fedora-http-server
        

        The output should look like the following:

        STEP 1/6: FROM fedora:latest
        Resolved "fedora" as an alias (/etc/containers/registries.conf.d/000-shortnames.conf)
        Trying to pull registry.fedoraproject.org/fedora:latest...
        Getting image source signatures
        Copying blob 75f075168a24 done
        Copying config 3a66698e60 done
        Writing manifest to image destination
        Storing signatures
        STEP 2/6: MAINTAINER ipbabble email buildahboy@redhat.com # not a real email
        STEP 3/6: RUN echo "Updating all fedora packages"; dnf -y update; dnf -y clean all
        [...]

        Now you can now run the image with Podman, a tool for working with containers which is often used as a compliment to Buildah.

      5. First, install Podman:

        • AlmaLinux, CentOS Stream, Fedora, or Rocky Linux:

          sudo dnf install podman
          
        • Ubuntu:

          sudo apt install podman
          
      6. In the command below, the -p option “publishes” a given port, here routing the container’s port 80 to the local machine’s port 8080. The --rm option automatically removes the container when it has finished running, a fitting solution for a quick test like this.

        podman run -p 8080:80 --rm fedora-http-server
        
      7. Now you can open another Terminal session on the machine where the image is running, and use a cURL command to verify the default page is being served on port 8080:

        curl localhost:8080
        

        You should see the raw HTML of the Fedora HTTP Server test page as output:

        <!doctype html>
        <html>
          <head>
            <meta charset='utf-8'>
            <meta name='viewport' content='width=device-width, initial-scale=1'>
            <title>Test Page for the HTTP Server on Fedora</title>
            <style type="text/css">
              /*<![CDATA[*/
        
              html {
                height: 100%;
                width: 100%;
              }
                body {
        [...]
      8. When done, stop the container, but first, determine your container’s ID or name:

        podman ps
        

        You should see an out put like this:

        CONTAINER ID  IMAGE                                COMMAND               CREATED        STATUS            PORTS                 NAMES
        daadb647b880  localhost/fedora-http-server:latest  /usr/sbin/httpd -...  8 seconds ago  Up 8 seconds ago  0.0.0.0:8080->80/tcp  suspicious_goodall
      9. Now stop the container. Replace container-name-or-id with your container name or ID:

        podman stop container-name-or-id
        

        Since we set this example container to automatically remove when done with the --rm flag, stopping it also removes it.

      10. You can now logout, close the second Terminal session, and return to the original Terminal:

        exit
        

      Learn more about Podman in our guide
      How to Install Podman for Running Containers.

      You can also learn more about crafting Dockerfiles in our guide
      How to Use a Dockerfile to Build a Docker Image. This guide also includes links to further tutorials with more in-depth coverage of Dockerfiles.

      Creating an Image from Scratch

      As noted above, Buildah stands out for its ability to create container images from scratch. This section walks you through an example of how you can do just that.

      Note

      Buildah’s commands for working with containers can involve a few keywords, so often these commands are executed using environment variables. So, for instance, to create a new container with Fedora, you may see something like:

      fedoracontainer=$(buildah from fedora)
      

      Learn more about how environment variables work in our guide
      How to Use and Set Environment Variables.

      The example container that follows starts with an empty container. It then adds Bash and some other core utilities to that container to demonstrate how you can add programs to create a minimal container image.

      Note

      This section assumes you want to run Buildah in rootless mode, being its major draw versus Docker. Unfortunately, the Ubuntu package manager, APT, presents issues with installing packages onto a non-root container. So the instructions that follow are for RHEL-derived distributions such as AlmaLinux, CentOS Stream, Fedora, and Rocky Linux.

      If you want to run Buildah under Ubuntu in regular root mode, simply preface each buildah command that follows with sudo.

      For rootless operation, you need to execute the unshare command first. This command puts you in a shell within the user namespace. The next several steps presume your are in the user namespace shell until noted, otherwise the buildah mount command below will fail.

      1. Enter the user namespace shell:

        buildah unshare
        
      2. Create a blank container using Buildah’s scratch base:

        scratchcontainer=$(buildah from scratch)
        
      3. Mount the container as a virtual file system:

        scratchmnt=$(buildah mount $scratchcontainer)
        
      4. Install Bash and coreutils to the empty container.

        • AlmaLinux, CentOS Stream, Fedora, or Rocky Linux:

          Replace the value 36 below with the version of your RHEL-derived distribution:

          dnf install --installroot $scratchmnt --releasever 36 bash coreutils --setopt install_weak_deps=false
          
        • Debian or Ubuntu:

          Replace the value bullseye below with the codename of your Debian-based distribution:

          sudo apt install debootstrap
          sudo debootstrap bullseye $scratchmnt
          
      5. You can now test Bash on the container. The following command puts you in a Bash shell within the container:

        buildah run $scratchcontainer bash
        
      6. You can then exit the Bash shell using:

        exit
        
      7. You can now safely operate the container from outside of the user namespace shell initiated with unshare:

        exit
        

        From here on out, we replace $scratchcontainer with the container’s name, which should be working-container. However, if you have more than one container, the container’s name may differ. You can verify the container name via the buildah containers command.

      8. Now let’s recreate the test script file. From your user’s home directory, create the script-files folder and the example-script.sh file in the script-files folder:

        mkdir script-files
        nano script-files/example-script.sh
        

        Give it the following contents:

        File: script-files/example-script.sh
        1
        2
        
        #!/bin/bash
        echo "This is an example script."

        When done, press CTRL+X to exit, Y to save, and Enter to quit.

      9. The command below copies that file to the container’s /usr/bin directory:

        buildah copy working-container ~/script-files/example-script.sh /usr/bin
        
      10. Verify the file’s delivery by running the ls command on the container for the /usr/bin directory:

        buildah run working-container ls /usr/bin
        

        Your example-script.sh file should be among the listed files:

        [...]
        example-script.sh
        [...]
      11. For a working example of how to execute scripts on a Buildah container, give this file executable permissions:

        buildah run working-container chmod +x /usr/bin/example-script.sh
        
      12. You can now run the script via the run command:

        buildah run working-container /usr/bin/example-script.sh
        

        Your output should be identical to the following:

        This is an example script.
      13. Once you are satisfied with the container, you can commit the change to an image:

        buildah commit working-container bash-core-image
        

        Your output should look something like this:

        Getting image source signatures
        Copying blob a0282af9505e done
        Copying config 9ea7958840 done
        Writing manifest to image destination
        Storing signatures
        9ea79588405b48ff7b0572438a81a888c2eb25d95e6526b75b1020108ac11c10
      14. You can now unmount and remove the container:

        buildah unmount working-container
        buildah rm working-container
        

      Managing Images and Containers

      Buildah is oriented towards creating container images, but it does have a few features for reviewing available containers and images. Here’s a brief list of the associated commands for these features.

      • To see a list of images built with your Buildah instance, run the following command:

        buildah images
        

        If you followed along for the sections above on creating Buildah images, you may have an image listing like this:

        REPOSITORY                  TAG      IMAGE ID       CREATED              SIZE
        localhost/fedora-http-server        latest   c313b363840d   8 minutes ago    314 MB
        localhost/bash-core-image           latest   9ea79588405b   20 minutes ago   108 MB
        registry.fedoraproject.org/fedora   latest   3a66698e6040   2 months ago     169 MB
      • To list containers currently running under Buildah, use the following command:

        buildah containers
        

        Should you use this command while the container is still running from the section above on building an image from scratch, you may get an output like:

        CONTAINER ID  BUILDER  IMAGE ID     IMAGE NAME                       CONTAINER NAME
        68a1cc02025d     *                  scratch                          working-container
      • You can get the details of a particular image using a command like the following one, replacing 9ea79588405b with your image’s ID. You can get your image’s ID when the image is built or from the buildah images command show above:

        buildah inspect 9ea79588405b
        

        The image details actually consist of the JSON document that fully represents the image’s contents. All container images are just that: JSON documents with the instructions for building their corresponding containers.

        Here is an example of the first portion of a container image JSON resulting from the section above on creating an image from scratch:

        {
            "Type": "buildah 0.0.1",
            "FromImage": "localhost/bash-core-image:latest",
            "FromImageID": "9ea79588405b48ff7b0572438a81a888c2eb25d95e6526b75b1020108ac11c10",
            "FromImageDigest": "sha256:beee0e0603e62647addab15341f1a52361a9684934d8d6ecbe1571fabd083dca",
            "Config": "{\"created\":\"2022-07-20T17:34:55.16639723Z\",\"architecture\":\"amd64\",\"os\":\"linux\",\"config\":{\"Labels\":{\"io.buildah.version\":\"1.26.1\"}},\"rootfs\":{\"type\":\"layers\",\"diff_ids\":[\"sha256:a0282af9505ed0545c7fb82e1408e1b130cad13a9c3393870c7c4a0d5cf06a62\"]},\"history\":[{\"created\":\"2022-07-20T17:34:55.72288433Z\",\"created_by\":\"/bin/sh\"}]}",
            "Manifest": "{\"schemaVersion\":2,\"mediaType\":\"application/vnd.oci.image.manifest.v1+json\",\"config\":{\"mediaType\":\"application/vnd.oci.image.config.v1+json\",\"digest\":\"sha256:9ea79588405b48ff7b0572438a81a888c2eb25d95e6526b75b1020108ac11c10\",\"size\":324},\"layers\":[{\"mediaType\":\"application/vnd.oci.image.layer.v1.tar\",\"digest\":\"sha256:a0282af9505ed0545c7fb82e1408e1b130cad13a9c3393870c7c4a0d5cf06a62\",\"size\":108421632}],\"annotations\":{\"org.opencontainers.image.base.digest\":\"\",\"org.opencontainers.image.base.name\":\"\"}}",
            "Container": "",
            "ContainerID": "",
            "MountPoint": "",
            "ProcessLabel": "",
            "MountLabel": "",
            "ImageAnnotations": {
                "org.opencontainers.image.base.digest": "",
                "org.opencontainers.image.base.name": ""
            },
        [...]

      Conclusion

      Buildah gives you a simple yet robust tool for crafting container images. It’s more than just an alternative to Docker. Buildah is a containerization tool for securely creating open containers and container images. With this tutorial, you have everything you need to get started building your own images and using Buildah to the utmost.

      More Information

      You may wish to consult the following resources for additional information
      on this topic. While these are provided in the hope that they will be
      useful, please note that we cannot vouch for the accuracy or timeliness of
      externally hosted materials.



      Source link

      3 Easy Ways to Optimize Images for Web


      Visual content can help make your site more engaging and enhance the user experience. However, poorly optimized images can wreak havoc on your website’s performance and even harm your Search Engine Optimization (SEO) rankings.

      Optimizing images for web can help you improve your page load times and cut down on file bloat. This task may sound a little tedious, but with the right tools, you can simplify the process and boost your site’s performance in no time.

      In this article, we’ll talk about the importance of image optimization and its impact on your website. Then, we’ll suggest three easy methods for optimizing photos. Let’s dive in!

      The Importance of Image Optimization

      Image optimization is the process of reducing image file sizes to minimize load times. It typically involves compressing images while preserving their quality.

      Search engines take several factors into consideration when ranking the quality of a website. This includes a site’s Core Web Vitals score.

      Core Web Vitals is a set of metrics that are used by Google to measure a site’s performance. One of the most important metrics is the Largest Contentful Paint (LCP):

      Core Web Vitals LCP report

      LCP measures the time it takes for the largest element on the page to load. This element is usually a hero image.

      Large image files can lead to a poor LCP score. They can also result in high bounce rates, which can have a negative impact on your conversions. Therefore, optimizing images is one of the most effective ways to improve your site’s performance and boost your SEO.

       

      Different Image File Types

      If you use images on your website, it’s important to familiarize yourself with the different file types and when to use them. There are three main types of image formats:

      • JPEG: This file type helps you reduce the image size while retaining decent image quality, and it’s best suited for simple designs and lower-quality images.
      • PNG: PNG images tend to have better quality than JPEGs, and should ideally be used for photographs that contain a lot of detail.
      • GIF: This format uses a low number of colors, so it’s ideal for plain graphics like logos and icons.

      There are other image formats you might use, including vector graphics. This type of image file can be resized without losing its quality. The downside is that vector graphics are not as widely supported as other image types.

      Get Content Delivered Straight to Your Inbox

      Subscribe to our blog and receive great content just like this delivered straight to your inbox.

      3 Easy Ways to Optimize Images for the Web

      Fortunately, image optimization doesn’t require technical knowledge. There are a number of tools and best practices that can help you resize, compress, and convert images to the optimal conditions for the web. Let’s take a close look at a few different methods.

      1. Resize and Crop Images with a Photo Editing Tool

      Original images may be much larger than needed for the web. One of the easiest steps you can take to optimize images is to resize or crop them. You can do this with photo editing software like Adobe Photoshop.

      For example, you might take a screenshot to show how something works, but only need to show a small part of the screen. You can crop out all of the unnecessary areas from the screenshot using the default photo editor on your Operating System (OS). This will help you reduce the file size of the image while enabling your audience to focus on what is important.

      If you use Windows, you can easily crop and resize images in Microsoft Photos. To get started, open your image in the Photos app, then click on the first icon in the top menu:

      edit image

      You can then use the drag handles to crop your image:

      cropping images for web

      If you want to resize the image, click on the three-dot icon in the main menu and select Resize:

      resize website image

      This will launch a window where you can select a different file size, or set your own custom dimensions:

       

      resize image

      If you click on Define custom dimensions, you can change the width and height of the image. You can also control its quality from the available slider. For instance, if you want to compress your image to reduce its size, you can set the quality to 50%:

      resize images

      You can then click on Save resized copy. We recommend that you choose a different name for the resized image to avoid overriding the original one.

      2. Use an Online Compression Tool

      Another way to resize photos is to use an online compression tool. This can help you to significantly reduce the image file size without any noticeable changes in quality.

      Some optimization tools enable you to compress images in bulk. This can help you save a lot of time.

      Let’s look at two powerful image compression tools that you can use.

      TinyPNG

      TinyPNG

      TinyPNG is a user-friendly web app that enables you to compress up to 20 images at a time. It is free to use and supports WebP, JPEG, and PNG file types.

      With TinyPNG, you can reduce file sizes while retaining image quality. The result is optimized images that take up less server space and load faster.

      To optimize an image with TinyPNG, simply upload your image files into the box at the top of the page and wait for the compression process to complete:

      TinyPNG

      You can then review the results and download your optimized images. For raw images, you can expect reductions in the range of 40%-70%.

      Kraken.io

      Kraken.io Image Optimization tool

       

      Kraken.io is another online image optimizer that you can use. Like TinyPNG, it’s free (with a premium option) and lets you compress images in bulk. However, it offers more compression options than TinyPNG:

      Kraken.io optimize images for web

      For example, you can choose from three optimization modes, including lossy and lossless. With lossy compression, you can make your image file significantly smaller by removing large amounts of data from your image.

      Meanwhile, lossless compression reduces your file size without removing any data from the image. Therefore, this method is ideal for high-quality images.

      Kraken.io gives you more control over how your images are compressed. You can choose to prioritize image quality over file size or vice versa.

      To optimize an image with Kraken.io, simply upload the images you want to compress, select an optimization method, and choose a download option. For instance, you can download each file individually, download multiple files together in a .zip file or to Dropbox, or share them straight to Facebook and Twitter:

      download optimized images via Kraken.io

      The free version of Kraken.io gives you a lot of options. The major downside is that you are limited to uploading 1MB files. Kraken.io PRO lifts this limitation and adds more settings.

      3. Install a WordPress Image Optimization Plugins

      If you have a WordPress site, there are several image optimization plugins that you can use. These are designed to help you compress WordPress images and make your site load faster.

      Additionally, these plugins enable you to optimize your image right from your WordPress dashboard. Some of them will automatically compress any images that you upload to your site.

      Let’s look at some popular image optimization plugins for WordPress sites.

      Smush

      Smush plugin for image optimization

      Smush is a popular WordPress image optimizer with over a million active installations and a five-star rating. It helps you improve your page load times by compressing and resizing your images.

      For example, the Bulk Smush feature detects images on your site that can be optimized and enables you to compress them in bulk:

      Bulk Smush optimize images for web

      You can also activate lazy loading to make your web pages load even faster:

      lazy load images

      Typically, your media files are loaded all at once, resulting in slower page speeds. With lazy loading, your images will load as users scroll down this page. This can make your content load faster.

      If you upgrade to Smush Pro, you’ll get access to more features, including the option to automatically serve images in Next-Gen WebP format. Plans start at $7.50 per month.

      ShortPixel Image Optimizer

      ShortPixel

      ShortPixel automatically shrinks image file sizes to help boost your site’s performance. However, it converts PNG images to JPEGs. While this can help you achieve faster load times, it may also reduce the quality of your content.

      With ShortPixel, you can choose from different compressions methods, including lossy and lossless:

      ShortPixel image compression settings

      You can also compress your thumbnails and create a backup of your original images. For more options, you can upgrade to the premium version, which starts at $3.99 per month.

      Jetpack

      Jetpack for WordPress

      While Jetpack isn’t an image optimization plugin, its Site Accelerator feature includes an option for optimizing images and hosting them on a Content Delivery Network (CDN). A CDN is a network of servers designed to serve content from the device that’s closest to the user’s geographic location, thus improving page load times.

      You can find these image optimization options under the plugin’s Performance & speed settings:

      Enable Site Accelerator settings in Jetpack

      These features are available for free with Jetpack Boost. The plugin comes with other tools that help you enhance your site’s performance.

      Speed Up Your Site with Optimized Images

      Poorly optimized images can have a negative impact on your site’s performance. Fortunately,  you can speed up your site and improve SEO rankings simply by resizing and compressing your images.

      To recap, here are three easy ways to optimize images for the web:

      1. Resize and crop images using a program like Adobe Photoshop or Microsoft Photos.
      2. Use an online compression tool like TinyPNG or Kraken.io.
      3. Install a WordPress optimization plugin like Smush Pro, Short Pixel, or Jetpack Boost.

      You can also improve the performance of your site by choosing a powerful hosting plan. Our DreamPress managed WordPress hosting offers a fast and reliable service with 24/7 support. Check out our plans today!

      You Dream It, We Code It

      Tap into 20+ years of coding expertise when you opt for our Web Development service. Just let us know what you want for your site — we take it from there.

      woman of color on laptop



      Source link

      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/webpc-passthru.php?src=https://xpresservers.com/wp-content/uploads/2021/09/How-To-Process-Images-in-Nodejs-With-Sharp.png&nocache=1

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

      • curl -O https://xpresservers.com/wp-content/webpc-passthru.php?src=https://xpresservers.com/wp-content/uploads/2021/09/1631157332_451_How-To-Process-Images-in-Nodejs-With-Sharp.png&nocache=1

      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/webpc-passthru.php?src=https://xpresservers.com/wp-content/uploads/2021/09/1631157333_547_How-To-Process-Images-in-Nodejs-With-Sharp.png&nocache=1

      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