Fish | 4 mins read

July 23, 2023

Resizing images and uploading to GCP Storage

A simple script to upload images that are blog-friendly

I am currently using GCS for the images in my blog, and I usually never resized images before uploading them to the bucket. I always thought that everything would be handled for me once I upload images to the bucket, thinking that there was already a built-in CDN on top of GCS.

This resulted in a couple of my blog posts loading large images that take quite some time to fully load.

I’ll manually set up Google CDN for my blog, but apart from that, I’ll make it a habit to resize my images down to a maximum of 1,200 pixels, either width or height, preserving the aspect ratio.

Resizing the image

I did some research on a couple of ways to resize images (aside: I created a tool for resizing images a few years back, but that was during the time I was using Linux as my daily driver), and found out that MacOS already had one built-in called as sips, with the usage as:

sips -Z 1200 $file -o $output

# example
sips -Z 1200 ~/Pictures/a-huge-image.jpeg -o ~/Pictures/blog/a-huge-image.jpeg

It just works without much fanfare, so I’ll stick to this for a while until I find a reason not to. An alternative that I’d like to explore sometime in the future is pngquant, which optimizes the image somehow.

Uploading to GCS

I use gcloud command to upload files to my google cloud storage bucket with the following command:

gcloud storage cp ~/Pictures/blog/$file gs://$bucket

It’s pretty straightforward too.

Packaging it all up

But to take it a step further, saving me extra keypresses moving forward, I decided to wrap these all up in a fish function. The idea would be:

flowchart LR A(Resize image) --> B(Upload to GCP) B --> C(Copy link to clipboard)

Creating fish functions was straightforward as I’ve done a couple already before. What was new was figuring out how to:

  • get the named arguments/flags
  • verify if the variable exists
  • use a fallback value if the variable is empty

To get values passed in flags, we could use argparse. I only wanted to support two flags: output and input.

argparse 'i/image'= 'o/output'= -- $argv

To access those flags, we use a predefined $_flag_ local variable, prefixed with the flag name.

echo $_flag_i # for the i/image flag
echo $_flag_o # for the o/output flag

Now, what I wanted is that the input should be required, while the output would be optional, falling back to the input value if it does not exist. Unfortunately, I haven’t yet figured out how to define default values for these flags, so I ended up using if statements:

if test -z $_flag_i
  echo "Missing -i, please specify which image to share"
  return 1
end

# set output default value as the -o flag value
set -l output $_flag_o

# if output (which uses -o flag value) is empty, then we use -i flag's value
if test -z "$output"
  set output $_flag_i
end

Next, I use the two commands I shared earlier: resize -> upload:

# resize image and save to ~/Pictures/blog/
sips -Z 1200 $_flag_i -o ~/Pictures/blog/$output

# we upload to gcp
gcloud storage cp ~/Pictures/blog/$output gs://$bucket

Lastly, we copy it to the clipboard:

echo "https://storage.googleapis.com/$bucket/$output" | pbcopy

The link is now in your clipboard and ready to be pasted to the blog post.

Final code

function shareimg
  argparse 'i/image'= 'o/output'= -- $argv

  if test -z $_flag_i
    echo "Missing -i, please specify which image to share"
    return 1
  end

  set -l output $_flag_o

  if test -z "$output"
    set output $_flag_i
  end

  # resize image and save to ~/Pictures/blog/
  sips -Z 1200 $_flag_i -o ~/Pictures/blog/$output

  # we upload to gcp
  gcloud storage cp ~/Pictures/blog/$output gs://$bucket

  # copy to clipboard
  echo "https://storage.googleapis.com/$bucket/$output" | pbcopy
end

Here’s some demonstration of it’s actual usage:

Aaand, this is the image that I uploaded using the script :)

Here’s the resized sample image I uploaded

No fancy copyright. Just creative commons | There's some vanity tracking going on, sorry | RSS.