Archive for Sites

Image Optimization Guide

On the forum I administer, I am forced to run a tight attachment policy. Disk space doesn’t grow on trees. Occasionally this leads to questions about the small attachment size limit of 50 KiB. This guide is intended to clarify that this is not nearly as tiny as you might think. Note that although I’ll mention commands without much explanation for the sake of brevity, you’re always recommended to further explore the possibilities offered by those commands with the --help flag as well as by running man the-command-here.

First you need to ask yourself what kind of file type is appropriate, if you have the choice. On screenshots, the main purpose of attachments on my forum, you’ll often encounter large areas of uniform background colors. PNG is therefore almost invariably the right choice. Crop out everything but what’s relevant. JPEG is appropriate for more dynamic pictures such as photographs. If you want to do a lot with photographs, you might want to consider an external hosting service. My wife likes SmugMug. Still, for thumbnails you might be able to do a fair bit more within a few hundred KiB than you might think. Finally, the vector graphics in SVG result in pictures that always look sharp. You’ll typically have drawn these in a program like Inkscape or Adobe Illustrator.

Table of Contents

  1. 1. Optimizing JPEG
  2. 2. Optimizing PNG
  3. 3. Optimizing SVG
  4. Addendum A: Scanned Documents
  5. Addendum B: Video

1. Optimizing JPEG

Often you’ll want to crop your file. Do not edit your JPEG followed by resaving it because this will result in reduced quality! You can crop losslessly with cropgui. On Windows you can use IrfanView.

If you don’t want to crop, and also potentially for some post-cropgui optimization, use jpegtran -copy none -progressive -optimize file.jpg > file-opt.jpg. Note that this will get rid of all metadata, which may be undesirable. If so, use jpegtran -copy all -progressive -optimize file.jpg > file-opt.jpg.

Of course if you want to scale down your JPEG there’s no point in mucking about with lossless cropping first. After scaling down, check how long your quality can go (also see a little helper script I wrote). In any case, you should avoid introducing any unnecessary compression steps with associated quality loss. Here are some results:

  • The original 11.jpg at 2.19 MB.
  • Losslessly cropped 11-crop.jpg at 1.11 MB.
  • Optimized with -copy all -progressive -optimize 11-crop-opt.jpg at 1.04 MB. -copy none would’ve saved an extra whopping 40-some KiB, which on this kind of filesize has little benefit, and besides, I quite like the metadata. For thumbnail-sized files the balance is likely to be different. For example, the 52.2 KiB SmugMug auto-generated thumbnail below can be insignificantly reduced to 51.1 KiB with --copy all, but to 48.2 KiB with --copy none. I think an 8% reduction is not too shabby, plus it brings the file size down to under the arbitrary 50 KiB limit on my forum.

2. Optimizing PNG

As I wrote in the introduction, for screenshots PNG is typically the right choice. If you want to use lossless PNG, use optipng -o7. In my experience it’s ever so slightly smaller than other solutions like pngcrush. But as long as you use a PNG optimizer it shouldn’t much matter which one you fancy. Also see this comparison.

If you don’t care about potentially losing some color accuracy, use pngquant instead. To top it off, if you really want to squeeze out your PNG, you can pass quality settings with --quality min-max, meaning you can pass --quality 30-50 or just --quality 10. Here are some quick results for the screenshot in the SVG section below, but be sure to check out the pngquant website for some impressive examples.

$ du -h --apparent-size inkscape-plain-svg.png
27K	inkscape-plain-svg.png

$ du -h --apparent-size inkscape-plain-svg-fs8\ default.png 
7.6K	inkscape-plain-svg-fs8 default.png

$ du -h --apparent-size inkscape-plain-svg-fs8\ quality\ 10.png 
4.3K	inkscape-plain-svg-fs8 quality 10.png

In this case there is no visual distinction between the original PNG and the default pngquant settings. The quality 10 result is almost imperceptibly worse unless you look closely, so I didn’t bother to include a sample.

3. Optimizing SVG

For using SVG on the web, I imagine I don’t have to tell you that in Inkscape, you should save your file as Plain SVG.

Save as Plain SVG in Inkscape.

What you may not know is that just like there are lossy PNGs, you can also create what amounts to lossy SVGs. There are some command-line tools to optimize SVGs, including (partially thanks to this SO answer):

  • Scour is probably the best command line tool for some quick optimization. You can just use the defaults like scour < in.svg > out.svg or scour -i in.svg -o out.svg. But I recommend you go further.
  • SVGO (SVG Optimizer)
  • SVG-optimiser (by Peter Collingridge)
  • SVG-editor (by Peter Collingridge

My personal preference for squeezing out every last byte goes toward the web-based version of the SVG-editor by Peter Collingridge. By running it in a browser with inferior SVG support such as Firefox, you’ll be sure that your optimized SVG still works properly afterward. The command line tools can only safely be used for basic optimizations, whereas the effects of going lossy (such as lowering precision) can only be fully appreciated graphically.

Addendum A: Scanned Documents

Scanned documents are a different item altogether. The best format for private use is DjVu, but for public sharing PDF is probably preferable. To achieve the best results, you should scan your documents in TIFF or PNG, followed by processing with unpaper or ScanTailor. If you’ve already got a PDF you’d like to improve, you can use pdfsandwich or my own readablepdf.

Addendum B: Video

I’m not aware of any lossless optimization for video compression such as offered by jpegtran, but you can often losslessly cut video. In the general purpose Avidemux, simply make sure both video and audio are set to copy. There is also a dedicated cross-platform app for lossless trimming of videos called, unsurprisingly, LosslessCut. If you do want to introduce loss for a smaller file size you can use the very same Avidemux with a different setting, ffmpeg, mpv, VLC, and so forth. You can get reasonable quality that’ll play many places with something like:

ffmpeg -i input-file.ext -c:v libx264 -crf 19 -preset slow -c:a libfaac -b:a 192k -ac 2 output-file.mp4

For the open WebM format, you can use along these lines:

ffmpeg -i input.mp4 -c:v libvpx -b:v 1M -c:a libvorbis output.webm

More examples on the ffmpeg wiki. Note that in many cases you should just copy the audio using -acodec copy, but of course that’s not always an option. Extra compression artifacts in audio detract significantly more from the experience than low-quality video.


Failing Automation is (Almost) Always Fun

Just so long as you don’t depend on it. In this case we’ve got Gmail’s automated translation feature, which I’ve probably only used once or twice in the past decade in order to see how it worked. Today it had the nice idea to suggest interference in English.

The original message. Must be French!
After translation. Yup, removing that one word really helped me understand this mysterious language.

There is in fact French text hiding in the conversation history. Funny thing though — there’s no suggestion to translate on any of the preceding or following messages that are actually in French. So it goes.

Comments (1)Tags:

SSH publickey denied?

I was suddenly having trouble connecting to GitHub, after pulling in an OpenSSH update to version 7. Chances are that means the problem is security-related, meaning it’s worthwhile to take the time to investigate the cause.

$ git pull
Permission denied (publickey).
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.

A little debugging showed the following:

$ ssh -vT
OpenSSH_7.1p2 Debian-2, OpenSSL 1.0.2f  28 Jan 2016
debug1: Reading configuration data /etc/ssh/ssh_config
debug1: /etc/ssh/ssh_config line 19: Applying options for *
debug1: Connecting to [] port 22.
debug1: Connection established.
debug1: Skipping ssh-dss key /home/frans/.ssh/id_dsa for not in PubkeyAcceptedKeyTypes
debug1: No more authentication methods to try.
Permission denied (publickey).

Of course I could quickly fix the problem by adding PubkeyAcceptedKeyTypes ssh-dss to ~/.ssh/config, but checking tells me that “OpenSSH 7.0 and greater similarly disables the ssh-dss (DSA) public key algorithm. It too is weak and we recommend against its use.” So, although I could obviously re-enable it easily, I guess I’ll have to generate a new key. I hope GitHub’s guide is accurate for generating something sufficiently secure, because I’m kind of ticked off that something I generated in 2013 is already considered “legacy.” I hope I’m to blame and not an earlier version of GitHub’s guide.

Incidentally, to change the passphrase one would use the -p option, e.g.:

ssh-keygen -f id_rsa -p


Adding a User Font Size Preference to Simple Machines

Users should be able to choose their default font size easily through their browser, and their choice should be respected. But because all browsers default to 16px and most people never change the default, many sites—including Wikipedia—set their font-size to about 80% of that value to end up at a font size of 12px or 13px. Thus users might be prevented from lowering their font size on a site that actually respects their preferences if they so desire.

Because I don’t believe that either joining the 80% crowd or specifying a size in pixels is generally the right answer, I decided to add a user preference that overrides the font-size on the HTML element. For this to work as intended, your stylesheet needs to be entirely in percentages, em, rem, or use equivalent keywords like small and large.

First, in Admin > Configuration > Core Features, enable Advanced Profile Fields. Then, you can add custom profile fields in Admin > Configuration > Features and Options > Profile Fields. I added one named “Font size” with an input mask of /^[0-9]{1,3}(\.[0-9]{1,2})?(em|pt|px|%)$/.

Assuming your theme is based on the default, start editing index.template.php. Then, under the linked stylesheets you can put the override:

	// Custom user font-size
	if ($context['user']['is_logged']) {
		global $user_profile;
		if (!empty($user_profile[$context['user']['id']]['options']['cust_fontsi'])) {
			echo '
	<style>', 'html {font-size: ', $user_profile[$context['user']['id']]['options']['cust_fontsi'], '}', '</style>';

To find out exactly what kind of useful values you can obtain from e.g. $context and $user_profile, you can use var_dump($user_profile).


Dealing With cPanel: Setting Up a 301 Redirect to Your Main Domain And Preventing .htaccess Hell

cPanel is surprisingly ill-suited for managing domains. Rather than treating each domain as a separate entity, you get one main domain and various so-called add-on domains. The most annoying aspect of this is that it always creates a subdomain when you add a new add-on domain. There should be no such thing as an add-on domain, just a bunch of domains. cPanel has some features that help you work around these defects, but I wasn’t too thrilled with those. It now seems to automatically redirect the www-subdomain to your no-www domain and you can easily set up subdomains to redirect through the interface, but it doesn’t satisfy me.

Setting Up a 301 Redirect

Instead of having to bother with a plethora of settings in cPanel itself, I came up with the following to stick at the top of .htaccess. A quick look around on the Internet brought up Fayaz Miraz’s blog, but while the solution suggestion was close, it misses one crucial aspect: it only redirects from the main page as far as I can tell. This is fixed easily by the addition of $1 (i.e. everything that was added after the main page).

<IfModule mod_rewrite.c>
RewriteEngine On

RewriteCond %{HTTP_HOST} !^fransdejonge\.com$
RewriteRule ^(.*)$$1 [R=301,L]


Simply put, it matches all possible routes of approach (whether through www or through a subdomain of another domain) and if it’s not, it will 301 redirect to The L means no further rewriting will occur after that rule. Mostly because it would just be inefficient, and partially because something else further down the line might mess things up.

Preventing .htaccess Hell

Another problem is that cPanel automatically creates a /public_html/addondomain directory. This is bad, because /public_html already contains a .htaccess file for the main domain. When accessing /public_html/addondomain, it would first parse the .htaccess file in /public_html before moving on and overriding it in /public_html/addondomain, and that’s assuming none of the rules in /public_html make anything go awry!

To prevent this kind of nightmare from occurring I took the simple precaution of creating a new directory /domains. This domain is contained in /domains/, for instance, and any other add-on or subdomains can reside in their own /domains/ directory to prevent any added load from needlessly parsing .htaccess files.

Comments (1)

Fun With Yahoo Pipes and Podcasts

I never really got into the whole podcast fad years ago. The available aggregators annoyed me, the available podcasts seemed generally uninteresting, and I didn’t have an MP3 player. Things change: I’ve had an MP3 player for a couple of years now. However, I only reevaluated my dislike for podcasts quite recently, when I discovered Wil Wheaton’s Memories of the Futurecast. I wanted a way to automate the process of getting it onto my MP3 player, and I found it: gPodder seems to do everything I want without getting in my way. Now I can do a quick sync with my MP3 player in the morning and I’ll have stuff to listen to while, among other things, going to and from the university.

All of that was about a month ago. I’ve only got a small selection of feeds in there so far, but since I’m still catching up on literally months of old material, that’s not an issue as of now. Aside from Wil Wheaton’s, my favorite podcast right now is Stuff You Should Know. But enough about that.

When I was younger, I usually listened to the radio news at 7 or 8 AM while eating breakfast. I have long since switched to doing some quick reading of my e-mails and feeds, but that’s not the ideal way to get a quick update on what’s currently going on. The radio news does a better job of that, but it just feels too much like a waste of time. Cue the podcast. I’ve known that Dutch public radio has had its broadcasts available as podcasts since 2005 or so. Selecting the podcast most relevant to me was easy: Radio Netherlands Worldwide, specifically the Nieuwslijn (news line) program. Of course there are competitors, such as BBC’s Global News and the German ARD Tagesschau, and I may have missed some other potentially interesting sources—which would presumably mostly mean American or Flemish—, but for now I’m sticking with this. Alas, there’s one small problem: there’s a news broadcast just about each two hours. This makes the new episodes available dialog look rather cluttered. I only want to listen to the news once a day.

New episodes available in gPodder

New episodes available in gPodder

That’s where Yahoo Pipes comes in. When I start it, it complains about Opera, but I haven’t been able to discern any difference in functionality between Opera and Firefox on the site. In only a couple of minutes, I have something that only gives me the 8 o’clock news.


If I wanted, I could easily add the BBC and ARD feeds and also strip them to just one item a day. What I can’t do, however, is output the de facto standard <itunes:image href="http://some-picture" /> with the feed. Nevertheless, I can manually link up a picture in gPodder so it doesn’t look strange in the feed display list.

For things more complicated than such simplistic mash-ups, Yahoo Pipe’s graphical programming interface quickly becomes lacking, which is strange considering that it seems to aspire to be more than just a simple mash-up tool. Nevertheless, it certainly makes life a little easier.

Comments (1)

Extend Opera was launched a few days ago. It’s a user initiative, aimed at bringing those aspects of Opera customization that Opera software has somewhat abandoned together.


Google in English

Google apparently thinks that it knows what I want better than I do. I have clearly specified “en-US” as my preferred language, “en” if that’s not available, and “nl” if that’s not available. I tried removing the “nl” in an attempt to get Google to speak English to me, but it won’t comply. I finally got annoyed enough to write this little script to fix it. It would be easy to adjust for other preferred languages.

Install Google in English user script.


SVG Favicons Are Not Supported Yet

I really want to do the following, but I’m still stuck with Microsoft’s icon format and PNG.

<link rel="shortcut icon" href="some-vector-image.svg" type="type="image/svg+xml">

I’m especially surprised that Google Chrome doesn’t support this. They do the whole web application thing; which utilizes the favicons of sites as application icons. SVG would be perfect to also offer a nice larger size icon. Another thing I didn’t know is that IE7 still doesn’t support PNGs as favicons.

Last, but not least, here is the favicon I created in the end: A favicon that depicts the face of a monkey..

Comments (2)

Scrolling on Google Maps

I don’t know when they added it, but it’s brilliant. Just scroll to zoom in and out.

Comments (2)

Older Entries »