Sharp Resizer: A CLI App For Resizing Images in Bulk
Tags: sharp, typescript, cli, node
Published: 2023-04-25 22:48:17


#Intro
In this article, we will be building a command line interface (CLI) application to assist in creating copies of an image to any number of specified sizes. This tool can be super useful and save you a lot of time, especially when building mobile apps that require different image sizes to display in different parts of the app.
<br>
You can download the code through GitHub here: https://github.com/evanryan210/sharp-resize
<br>

![Final result: A set of resized images in your folder ready to use!](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hx04x7n9hh8ehnkp68z5.png)
<br>

#Getting Started
For this CLI app we will need to install a few node packages. We will be using node package manager so make sure you have that installed at this point. If you do not have it installed you can download it here: https://nodejs.org/en/download. The commands to install the packages we will be using are listed below.

```
npm install sharp
npm install fs
npm install path
```

**Sharp**: A high-speed Node.js module that converts large images to varying dimensions.
**Fs**: A module that allows you to work with the file system on your computer.
**Path**: The Path module provides a way of working with directories and file paths.

In our project folder, lets make a json file and name it `resize.json`. This is where we will store our path to the image we want to resize, our path to the destination we want to save our resized images to, and an array of our desired sizes.

```
{
    "imagePath" : "[IMAGE PATH TO BE RESIZED]",
    "outputPath": "[DESTINATION FOLDER PATH TO STORE IMAGES]",
    "settings": {
        "ios": [20,29,40,40,58,60,60,76,80,87,120,120,152,167,180,1024],
        "android": [36,48,64,72,96,144,192,512]
    }
}
```
**Note**: You can add however many `'settings'` values you need. For this example, I did two since I wanted two sets of resized images in their own respective folder.
<br>

#Setting Up a Watcher
If you are not aware, since we are using Typescript we must compile our code before we run it in node. To avoid having to compile each time we make changes to our app, I prefer to run a watcher in the terminal to save some time. This watcher will look for changes in our file and compile instantly. The command to run the watcher is as follows:

```
tsc -w
```
And your terminal should display something like this:

```
[5:05:25 PM] Starting compilation in watch mode...

[5:05:27 PM] Found 0 errors. Watching for file changes.
```
_(P.S. Make sure not to accidentally close this terminal)_
<br>

#Index.ts
Now we will be working in the root `index.ts` file of the project. Lets start by defining a 'type', `PlatformData`, for our json object we just created.

```
type PlatformData = {
    imagePath: string,
    outputPath: string,
    settings: Record<string, number[]>
}
```
Now we are going to use the `fs` module we installed to get the data from our `resize.json` file using the `fs.readFileSync()` method.

```
const data = fs.readFileSync(path.join(`resize.json`), 'utf8');
const parsedData: PlatformData = JSON.parse(data);
const imgPath = parsedData.imagePath //"[IMAGE PATH]"
const folderPath = parsedData.outputPath //"[DESTINATION FOLDER PATH]"
```
We are then going to parse that data and store it in a variable, `parsedData`. Now we can use this parsed data and also create `imgPath` and `folderPath`.

Now lets make the actual function that is going to take the image size and platform as arguments, and give us a file from the resized image data at the specified path.

```
const resize = (imgSize: number, platform: string) =>{
    sharp(imgPath)
        .resize(imgSize)
        .toFile(`${folderPath}/${platform}/sample_${imgSize}.jpg`, function (err) {
        });
}
```
Now that our function to resize our image is done, lets make sure there is a directory to store our new set of resized images by checking if it exists using `fs.existsSync(folderPath)`. If it does not exist, we can use `fs.mkdirSync(folderPath)` to create a folder as shown below.

```
if (!fs.existsSync(folderPath)){
    fs.mkdirSync(folderPath)
}
```
Lastly, we need to do a `try...catch` that will use a `forEach() ` loop to iterate through the values in our array(s) and resize the image to each size being passed. After this stage you have a completed resizing app! 

```
try {
    const platforms = parsedData.settings
    Object.keys(platforms).forEach(platform => {
        if (!fs.existsSync(`${folderPath}/${platform}`)) {
            fs.mkdirSync(`${folderPath}/${platform}`)
            //Only if you want platform specific folders
        }
        const platformSizes = platforms[platform]
        platformSizes.forEach(size => {
            resize(size, platform)
        })
    })
    console.log(`Resizer has loaded images here: ${folderPath} `)
} catch (err) {
    console.error(err);
}
``` 
<br>
<br>
<br> 

#Usage
To use the app we just created, make sure the `resize.json` has the proper values for `imagePath `and `outputPath`, and simply run the following command in the terminal.

```
node index
```
<br>
I hoped you enjoyed this walkthrough! Best of luck in your coding endeavors :D

_Author,
Evan Ryan, OrangeSpark Solutions_