πΎ Archived View for republic.circumlunar.space βΊ users βΊ johngodlee βΊ posts βΊ 2019-07-05-img-convertβ¦ captured on 2021-12-04 at 18:04:22. Gemini links have been rewritten to link to archived content
-=-=-=-=-=-=-
DATE: 2019-07-05
AUTHOR: John L. Godlee
I wanted my webpages to load faster, and I was somewhat inspired by this website[1] which runs entirely on a solar powered raspberry pi. They needed to minimize the amount of data transfer to keep energy usage down. I was also inspired a bit by this blog post[2] on their image dithering procedure which converts images to black and white while preserving the essence of what the image is trying to portray. Unfortunately they do their image conversion in Adobe Photoshop, which I didn't want to use. Instead I decided to see if I could replicate their conversion process and achieve highly compressed dithered images using ImageMagick[3], which could be written into a reproducible script that I could run on a set of images. I also wanted to see if there was a better method of compressing the images.
1: https://solar.lowtechmagazine.com/2018/09/how-to-build-a-lowtech-website/
2: http://gauthierroussilhe.com/en/posts/convert-low-tech
3: https://imagemagick.org/index.php
ImageMagick runs on the command line and the command I use is convert which is designed to take an image, alter it in a multitude of ways, then save to a new file. mogrify is better for overwriting the same image.
I have an example image here[4] which is currently 6.8 MB.
4: /img_full/spot_autumn/bike.png
y first pass at the image is simply to reduce the -quality of the image, which takes a percentage value that pertains to the compression level.
convert bike.jpg -quality 90% output_1.jpg
This produces an image of 3.3 MB.
Here is a plot of the file size as the -quality percentage is reduced. and a table of file sizes. Note that 100% compression on the original image actually made the original image of 6.8 MB larger, to 7.8 MB.
Plot of comperession percentage and image size
βββββββββββββββββββββ¬βββββββββββββββ β Compression (%) β Size (MB) β βββββββββββββββββββββͺβββββββββββββββ‘ β 100 β 7.799 β βββββββββββββββββββββΌβββββββββββββββ€ β 95 β 4.479 β βββββββββββββββββββββΌβββββββββββββββ€ β 90 β 3.229 β βββββββββββββββββββββΌβββββββββββββββ€ β 85 β 2.600 β βββββββββββββββββββββΌβββββββββββββββ€ β 80 β 2.240 β βββββββββββββββββββββΌβββββββββββββββ€ β 75 β 1.973 β βββββββββββββββββββββΌβββββββββββββββ€ β 70 β 1.808 β βββββββββββββββββββββΌβββββββββββββββ€ β 65 β 1.658 β βββββββββββββββββββββΌβββββββββββββββ€ β 60 β 1.531 β βββββββββββββββββββββΌβββββββββββββββ€ β 55 β 1.434 β βββββββββββββββββββββΌβββββββββββββββ€ β 50 β 1.349 β βββββββββββββββββββββΌβββββββββββββββ€ β 45 β 1.268 β βββββββββββββββββββββΌβββββββββββββββ€ β 40 β 1.172 β βββββββββββββββββββββΌβββββββββββββββ€ β 35 β 1.086 β βββββββββββββββββββββΌβββββββββββββββ€ β 30 β 0.979 β βββββββββββββββββββββΌβββββββββββββββ€ β 25 β 0.868 β βββββββββββββββββββββΌβββββββββββββββ€ β 20 β 0.742 β βββββββββββββββββββββΌβββββββββββββββ€ β 15 β 0.600 β βββββββββββββββββββββΌβββββββββββββββ€ β 10 β 0.437 β βββββββββββββββββββββΌβββββββββββββββ€ β 5 β 0.239 β βββββββββββββββββββββΌβββββββββββββββ€ β ----------------- β ------------ β βββββββββββββββββββββ΄βββββββββββββββ
It's interesting that even at 5% -quality, the image is still not bad to look at.
For the next part I'll take an arbitrary -quality value of 50%, meaning the base image is 1.349 MB.
Converting the image to grayscale makes the file slightly smaller, but not much
convert bike.jpg -quality 50% -colorspace gray output_21.jpg
The original image was 1,414,879 bytes (1.349 MB) and the grayscale image is 1,325,856 (1.264 MB), a difference of 89,023 bytes, or 87 KB.
I also experimented with other options for reducing the colors, but none of these made any positive difference. -posterize 4 = 1.781 MB, -quantize gray = 1.349 MB.
Next I want to dither the image to hopefully save even more file size. I'll use the grayscale image I generated earlier, which is 1.264 MB. There are multiple options for dithering so here is a comparison.
convert bike.jpg -quality 50% -colorspace gray -dither floyd-steinberg output_25.jpg
Both methods produced files of exactly the same size as the grascale image so I think I'm doing something wrong. I think I should apply some sort of dithering color reduction flag as well. Here are examples with different color reduction methods:
convert bike.jpg -quality 50% -colorspace gray -dither floyd-steinberg -monochrome output_26.jpg convert bike.jpg -quality 50% -colorspace gray -dither floyd-steinberg -posterize 10 output_27.jpg
The -monochrome option produced a file of 2.812 MB and the -posterize 10 option produced a file of 1.428 MB.
Posterize is an interesting one to play with. Here is a comparison of -posterize with different numbers of colours:
βββββββββββββββ¬ββββββββββββββββββββββ β Size (MB) β Number of colours β βββββββββββββββͺββββββββββββββββββββββ‘ β 1.428 β 10 β βββββββββββββββΌββββββββββββββββββββββ€ β 1.459 β 9 β βββββββββββββββΌββββββββββββββββββββββ€ β 1.487 β 8 β βββββββββββββββΌββββββββββββββββββββββ€ β 1.532 β 7 β βββββββββββββββΌββββββββββββββββββββββ€ β 1.578 β 6 β βββββββββββββββΌββββββββββββββββββββββ€ β 1.631 β 5 β βββββββββββββββΌββββββββββββββββββββββ€ β 1.674 β 4 β βββββββββββββββΌββββββββββββββββββββββ€ β 1.793 β 3 β βββββββββββββββΌββββββββββββββββββββββ€ β 1.437 β 2 β βββββββββββββββΌββββββββββββββββββββββ€ β 0.068 β 1 β βββββββββββββββΌββββββββββββββββββββββ€ β ----------- β ------------------- β βββββββββββββββ΄ββββββββββββββββββββββ
Weirdly, the file size actually increases as the number of colours decreases, up until the number of colours is two.
There are also predefined dithering threshold maps that can be used with -ordered-dither:
convert bike.jpg -quality 50% -colorspace gray -ordered-dither c7x7w output_43.jpg
Here is a comparison of these methods:
Plot of ordered dither method and output size
ββββββββββββ¬ββββββββββββββββββββββββββββββ¬ββββββββββββββ β Code β Description β Size (MB) β ββββββββββββͺββββββββββββββββββββββββββββββͺββββββββββββββ‘ β checks β Checkerboard 2x1 (dither) β 2.678 β ββββββββββββΌββββββββββββββββββββββββββββββΌββββββββββββββ€ β o2x2 β Ordered 2x2 (dispersed) β 3.702 β ββββββββββββΌββββββββββββββββββββββββββββββΌββββββββββββββ€ β o3x3 β Ordered 3x3 (dispersed) β 4.445 β ββββββββββββΌββββββββββββββββββββββββββββββΌββββββββββββββ€ β o4x4 β Ordered 4x4 (dispersed) β 4.557 β ββββββββββββΌββββββββββββββββββββββββββββββΌββββββββββββββ€ β o8x8 β Ordered 8x8 (dispersed) β 4.675 β ββββββββββββΌββββββββββββββββββββββββββββββΌββββββββββββββ€ β h6x6a β Halftone 6x6 (angled) β 4.824 β ββββββββββββΌββββββββββββββββββββββββββββββΌββββββββββββββ€ β h8x8a β Halftone 8x8 (angled) β 1.264 β ββββββββββββΌββββββββββββββββββββββββββββββΌββββββββββββββ€ β h6x6o β Halftone 6x6 (orthogonal) β 4.877 β ββββββββββββΌββββββββββββββββββββββββββββββΌββββββββββββββ€ β h8x8o β Halftone 8x8 (orthogonal) β 4.831 β ββββββββββββΌββββββββββββββββββββββββββββββΌββββββββββββββ€ β c5x5b β Circles 5x5 (black) β 4.879 β ββββββββββββΌββββββββββββββββββββββββββββββΌββββββββββββββ€ β c5x5w β Circles 5x5 (white) β 4.879 β ββββββββββββΌββββββββββββββββββββββββββββββΌββββββββββββββ€ β c6x6b β Circles 6x6 (black) β 4.831 β ββββββββββββΌββββββββββββββββββββββββββββββΌββββββββββββββ€ β c6x6w β Circles 6x6 (white) β 4.823 β ββββββββββββΌββββββββββββββββββββββββββββββΌββββββββββββββ€ β c7x7b β Circles 7x7 (black) β 4.915 β ββββββββββββΌββββββββββββββββββββββββββββββΌββββββββββββββ€ β c7x7w β Circles 7x7 (white) β 4.899 β ββββββββββββΌββββββββββββββββββββββββββββββΌββββββββββββββ€ β -------- β --------------------------- β ----------- β ββββββββββββ΄ββββββββββββββββββββββββββββββ΄ββββββββββββββ
So the h8x8a method produced the smallest file size of 1.264 MB, but this is only as small as the undithered grayscale image!
So from my little test so far it seems that the best way of compressing images is to use a grayscale undithered image an adjust the -quality of the image to my liking.
Here are a few other options to reduce file size I came across. Here is a comparison using the undithered grayscale image.
Removing EXIF data, which I would probably want to do regardless of the file size, just for privacy reasons:
convert bike.jpg -quality 50% -colorspace gray -strip output_54.jpg
This reduces the file size from 1.264 MB to 1.242 MB, a difference of 23.2 KB.
Adding some Gaussian blur to reduce the detail level:
convert bike.jpg -quality 50% -colorspace gray -strip -gaussian-blur 0.05 output_54.jpg
This reduces the stripped grayscale image from 1.242 MB to 1.031 MB, a difference of 215 KB.
Here is a comparison of images converted with different levels of gaussian blur.
One thing I did find was that the computation time increased with the radius of the blur.
Plot of gaussian blur and output size
ββββββββββ¬ββββββββββββββ β Blur β Size (MB) β ββββββββββͺββββββββββββββ‘ β 0.050 β 1.031 β ββββββββββΌββββββββββββββ€ β 0.100 β 1.031 β ββββββββββΌββββββββββββββ€ β 0.200 β 1.031 β ββββββββββΌββββββββββββββ€ β 0.300 β 1.031 β ββββββββββΌββββββββββββββ€ β 0.400 β 1.031 β ββββββββββΌββββββββββββββ€ β 0.500 β 1.031 β ββββββββββΌββββββββββββββ€ β 0.600 β 1.031 β ββββββββββΌββββββββββββββ€ β 0.700 β 1.031 β ββββββββββΌββββββββββββββ€ β 0.800 β 1.031 β ββββββββββΌββββββββββββββ€ β 0.900 β 1.031 β ββββοΏ½οΏ½οΏ½βββββΌββββββββββββββ€ β 1 β 1.031 β ββββββββββΌββββββββββββββ€ β 2 β 0.947 β ββββββββββΌββββββββββββββ€ β 3 β 0.938 β ββββββββββΌββββββββββββββ€ β 4 β 0.937 β ββββββββββΌββββββββββββββ€ β 5 β 0.937 β ββββββββββΌββββββββββββββ€ β 10 β 0.937 β ββββββββββΌββββββββββββββ€ β 20 β 0.937 β ββββββββββΌββββββββββββββ€ β 30 β 0.937 β ββββββββββΌββββββββββββββ€ β 40 β 0.937 β ββββββββββΌββββββββββββββ€ β 50 β 0.937 β ββββββββββΌββββββββββββββ€ β ------ β ----------- β ββββββββββ΄ββββββββββββββ
So, finally, the optimal way of compressing my JPEG images seems to be:
convert bike.jpg -quality 20% -colorspace gray -strip -gaussian-blur 3.5 output.jpg
This leads to an image of 538 KB. It looks good, except when zooming in, then it gets a bit hairy, this is where dithering might become useful if I can find a way of dithering while maintaining the small size of the image.
Another thing I learned from reading the comments on this website[5] was that JPEG is the most appropriate format for reducing image file size as it is lossy, unlike PNG, so I can convert all my PNG images to JPEG using:
5: https://solar.lowtechmagazine.com/2018/09/how-to-build-a-lowtech-website/
convert test.png -background white -flatten output.jpg
-background white -flatten is needed to allow the JPEG to properly display the transparent areas of the JPG as white background.
I have a folder on my website with images sorted into directories based on what blog post they refer to. I wrote this shell script to prepare the images to be put onto the website:
#!/bin/bash shopt -s nullglob # For each image for i in img_full/*/*.{jpg,JPG,jpeg,png,PNG}; do # If the directory in the compressed images directory doesn't exist, create it new_dir=$(dirname ${i} | sed "s/img_full/img/g") if [ ! -d $new_dir ]; then mkdir -p $new_dir; fi echo $dir # Create new file path for output new_path=$(echo "${i}" | sed "s/img_full/img/g") echo $new_path # Convert image files if [ ! -f $new_path ]; then convert $i -quality 20% -colorspace gray -strip -background white -flatten -gaussian-blur 3.5 $new_path fi done # Maintain full size 404 image cp img_full/404/404.png img/404/404.png