How to make an art website load at lightning speed using Cloudinary and Python
I collaborated with Ciaboga Studio to work with them on their new website. Ciaboga is an art studio and their website is packed with high quality images. The first issue I encountered was slow loading times and the second is that they wanted their images watermarked.
The website is hosted on Squarespace with more than 100 high-quality images (usually 15Mb per image), and apparently, when you upload an image, they don’t optimize it. I wanted to find a solution that can scale and work on all the website images.
I wanted to try Cloudinary service for a while now, and now I got a real chance to work with it. I signed up and did a few trials on their dashboard, and I realized they have what I need, and it can be faster than manipulating images by myself.

After playing with the Media Library, I moved into Transformations, which is the core of Cloudinary service, with the Transformations I was able to create a ‘template’ of particular transformation I want to make to my images.
I can use the full URL like this:
http://res.cloudinary.com/ciabogastudio/image/upload/if_ar_gt_1:1/c_scale,w_1024/c_scale,h_1024/if_else/q_86/if_end/c_scale,co_rgb:000000,g_south_east,l_logo-ciaboga,w_100,x_10,y_10/sample.jpg
Or, the named transformation:
http://res.cloudinary.com/ciabogastudio/image/upload/t_ciaboga_transformation_black/sample.jpg
You will immediately see your transformation results.
Transformations are necessary, especially for my use case where I wanted to change more than 100 pictures at the same time. To do so, I downloaded Cloudinary Python SDK and started coding (Using Python 3)
Using Cloudinary SDK is simple as downloading the pip package, configure your Cloudinary credentials, and upload an image:
$ pip install cloudinaryimport cloudinary
# Initiate cloudinary sdk
cloudinary.config(
cloud_name='sample_user',
api_key='111122223333444'
api_secret='abcDEFgHij_KLMNopqrStuvWxYz'
)
# Upload an image
cloudinary.uploader.upload("my_picture.jpg")
With the help of Yakir, from Cloudinary support team, I was able to create a custom transformation for my exact needs, easily and seamlessly.
The transformation did the following:
- If the image is landscape, it scales the width to 1024 pixels
- If the image is portrait, it scales the height to 1024 pixels
- Lower jpeg quality to 86%
- Add an overlay image, Ciaboga studio logo, as a watermark on the lower right corner and ajust the size
I used Python’s os.walk to iterate through all of the website images I had locally on my computer and apply the transformation to them:
for root, subdirs, files in os.walk(input_directory):
for f in files:
if f.lower().endswith('.jpg') or f.lower().endswith('.png'):
image_path = os.path.join(root, f)
cloudinary.uploader.upload(image_path, named_transformation=['resize_and_watermark'])All the images were soon available and ready to use from Cloudinary dashboard.
I encountered two problems at this stage
- The watermark on some of the images was not visible because it was black and the bottom corner was dark
- Squarespace won’t let me use image urls, and I had to upload the images directly to their service

Dealing with the colors of the corners was a little bit complicated. I used Pillow library for Python to analyze the image.
def get_main_color(image_path):
img = Image.open(image_path)
width = img.size[0]
height = img.size[1]
# Crop the south east corner of the image
img_cropped = img.crop(
(
width - 200,
height - 150,
width,
height
)
)
colors = img_cropped.getcolors(1024000)
max_occurence, most_present = 0, 0
for c in colors:
if c[0] > max_occurence:
(max_occurence, most_present) = c
return most_presentThis function returned the most significant color, which in the above picture was (13, 8, 4) — Close to (0, 0, 0), which means black. It’s easy to it’s closer to black with the eyes, but I needed an easier way to do this with code. I converted the RGB colors to grayscale by computing the luminance with the following formula:
Y = 0.2126*R + 0.7152*G + 0.0722*BOr in Python:
def get_watermark_color(image_path):
main_color = get_main_color(image_path)
Y = 0.2126 * main_color[0] + 0.7152 * main_color[1] + 0.0722 * main_color[2]
return 'white' if Y < 128 else 'black'# Notice that this code returns 'white' if the corner is black and returns 'black' if the corner is white, because the name of the function is: get_watermark_color
Again, using Cloudinary support team, I was able to create two different transformations, one with the original black logo, and one that changed the logo to white (With the same black logo image). I changed the code above to something like this:
for f in files:
if f.lower().endswith('.jpg') or f.lower().endswith('.png'):
image_path = os.path.join(root, f)
watermark_color = get_watermark_color(image_path)
cloudinary_upload = None
if watermark_color is 'black':
cloudinary_upload = cloudinary.uploader.upload(image_path, transformation=[black_watermark_transformation], use_filename=True, unique_filename=False) elif watermark_color is 'white':
cloudinary_upload = cloudinary.uploader.upload(image_path, transformation=[black_watermark_transformation], use_filename=True, unique_filename=False)
Dealing with Squarespace upload limitation was a bit easier, I had to download the image right after I upload it to Cloudinary. This made simple when using Cloudinary SDK because the upload function returns JSON as follows:
{
'public_id': '3wahoos',
'version': 1503588453,
'signature': '79cde65b42d279d432ff2bb0888f60ef43030c36',
'width': 1024,
'height': 768,
'format': 'jpg',
'resource_type': 'image',
'created_at': '2017-08-24T15:27:33Z',
'tags': [],
'bytes': 128085,
'type': 'upload',
'etag': 'e215c8853ded0687f47e3efde4395d73',
'url': 'http://res.cloudinary.com/username/image/upload/v1503588453/3wahoos.jpg',
'secure_url': 'https://res.cloudinary.com/username/image/upload/v1503588453/3wahoos.jpg',
'overwritten': True,
'original_filename': '3wahoos'
}I could easily grab the ‘url’ value and download the image using Python’s urllib.request.urlretrieve (Didn’t want to add more dependencies using requests). I would recommend using their CDN instead of downloading if possible
def download_transformed_image(output_folder, output_file, cloudinary_upload):
output_path = os.path.join(output_folder, output_file)
transformed_url = cloudinary_upload['url']
print('Downloaded image')The result


Summary
I added an external configuration file to the project and also added some command line options. You can find the project here:
Using Cloudinary SDK was incredibly easy and saved me a lot of time handling image scaling and overlaying. Cloudinary support team was there for me 100% of the time and helped me get the best out of their service.
Ciaboga studio website is now much faster and works great, you can visit it here: www.ciabogastudio.com and check out their beautiful art.
You are more than welcome to download my code, submit issues and let me know how it went for you!
Michelle Brener @ Ciaboga Studio
Yakir Perlin @ Cloudinary Support Team
