Optimizing JPEG images – save 20% in file size

Optimizing your image file size is one of the low hanging fruits when it comes to page speed optimization for your website.

My current workflow for JPEGs looks something like this:

  • ‘Save for Web’ in Photoshop with 60% quality
  • Run through ImageOptim to reduce file size

Yesterday, Marc Thiele asked on Twitter:

In the unfolding discussion some folks stated that they use both JPEGmini and ImageOptim when it comes to JPEGs and that this would reduce the file size even more. Fortunately I had to add pictures to 50 new products today. Every product has three pictures from different angles, so this sums it up to 150 images in various sizes, 900 images in total, all JPEG.
So I gave it a try and here are the results (I bought JPEGmini for this test as 20 images on the lite version might not be enough to get reliable results, still, your mileage may vary).

‘Save for Web’

With just using ‘Save for Web’ the images had a total size of 84MB. Quite heavy.


Running these through ImageOptim saved nearly 10% and lowered the total size to 75.7MB.


Using the ‘Save for Web’ images again (not touched by ImageOptim yet) results in 74.2MB.

ImageOptim after JPEGmini

Now adding another run of ImageOptim to the images already optimized by JPEGmini lowers the total size to 66.9MB. Thats more than 20% in file size saved without compromising image quality.

As far as I can tell it is not necessary to run the tools multiple times. At least in ImageOptim it is obvious that the latest version does this by itself. And I wasn’t able to spot any major changes on a second and third run with JPEGmini.

To give you the ability to compare the results, below are two images. The left one is the image just saved from Photoshop, the right one is the image after the whole optimization process.
photographer_ps photographer_optimized

Kundenservice? Not here. Not now.

Ich bin umgezogen. Irgendwann im Mai. Im Rahmen der Einrichtung der neuen Wohnung habe ich es geschafft, mir meine sämtlichen Plastikkarten zu bricken. Also von Kreditkarte über Packstation, Krankenkasse bis hin zu Payback. Topfmagnet vs. Karte ist halt keine so gut Idee. Wurde mir auch klar, als der Magnet sich von meinem Kleingeld magisch angezogen fühlte.

Also konnte ich direkt zwei Fliegen mit einer Klappe schlagen: Adressänderung und neue Karten anfordern. Bei der Bank habe ich angerufen. Da ging auch alles glatt. DHL und DAK habe ich eine E-Mail geschrieben. Wobei das nicht wirklich richtig ist. Ich habe das Kontaktformular benutzt, das auf deren Homepages angeboten wird. Bei beiden ist das jetzt 3,5 Wochen her. Seitdem ist nichts geschehen. Keine Bestätigung der Adressänderung, keine neuen Karten. Der Griff zum Telefonhörer also unvermeidlich.

Bei DHL wusste man nichts von einer Mail. „Das Kontaktformular geht über verschiedene Kanäle” war da die Aussage. Was auch immer das heißen mag. Vielleicht, dass man es sich betriebsintern so lange weiterleitet bis sich das Problem von selbst erledigt hat. Ich weiß es nicht. Eine neue Karte würde aber zwei Wochen dauern. Das ich schon mehr als drei Wochen warten würde, weil DHL die internen Prozesse nicht im Griff hat, wollte man nicht gelten lassen. Immerhin war die neue Adresse schon hinterlegt. Das liegt aber daran, dass man die bei DHL selbst ändern kann.

Mehr als drei Wochen keine Reaktion und dann zwei Wochen Wartezeit für ein neues Plastikkärtchen. Geht nicht schlimmer? Klar geht das schlimmer. Nächster Anruf DAK:
Da die DAK-Karte keinen Magnetstreifen besitzt hatte ich denen ins Kontaktformular geschrieben, dass sie mir doch bitte mitteilen sollen, ob es der Karte schadet wenn man sie mit einem Magnet in Kontakt bringt. Genau das war meine Einstiegsfrage ins Gespräch:

Das kann ich Ihnen leider auch nicht sagen.
Dann bringen Sie das doch bitte mal in Erfahrung.
Waren Sie in der Zwischenzeit beim Arzt und sie hat nicht funktioniert?
Nein, ich dachte ihr seit in der Lage, innerhalb von drei Wochen eine E-Mail zu beantworten.
Äh, da kann ich jetzt nichts zu sagen. Ich schick Ihnen eine neue zu.
Klären Sie doch erstmal, ob das wirklich nötig ist!
Das kann ich nicht.
Es wird doch irgend jemand bei Ihnen im Haus geben, der diese Frage beantworten kann.
Äh… Moment.
(Geht also doch. Man will nur nicht. Man hört Rascheln im Hintergrund, keine Warteschleifenmusik. Sehr professionell.)
Ja, es schadet der Karte. Ich schick Ihnen also eine neue zu. Wie heißen Sie denn.
(Die genaue Schreibweise war nicht zu ermitteln)
Slovig. Siegfried, Ludwig, Otto, Vogel, Ida, Gustav.
Mit einfachem T?
Mit doppelt-T und H.
In Berlin?
Nein. Ich glaube, es ist einfacher, ich gebe Ihnen meine Versichertennummer.
Ja, das ist eine gute Idee.

Es gibt keinen Matthias Slovig mit genau dieser Schreibweise in Berlin. Die Supportmitarbeiterin hat es also tatsächlich geschafft, einen aus sechs Buchstaben bestehenden buchstabierten Nachnamen falsch ins Formular einzutragen. Warum sie nicht von sich aus nach der Versichertennummer gefragt hat wird ein ewiges Rätsel bleiben.

In Mainz also.
(Zumindest das fehlerfreie Eintippen eines Buchstabens und einer neunstelligen Nummer hat funktioniert.)
Ich schick die Karte dann raus.
Welche Adresse haben Sie denn hinterlegt?
Am Schinnergraben 102.
Verdammt noch mal! Ihr habt es also in diesen drei Wochen nicht mal geschafft, meine neue Adresse in Euer System zu übernehmen! Das kann es doch echt nicht sein!

Ich bin seit Geburt bei der DAK. Derzeit zahle ich monatlich einen hohen dreistelligen Betrag, damit ich zweimal jährlich meine Zahnreinigung selber zahlen darf *. Ich habe mich trotzdem nie mit dem Gedanken getragen, die Krankenkasse zu wechseln. Bis heute. Wenn das der Anspruch der DAK ist, den sie an ihren Kundendienst stellen (unfähige Hotline-Mitarbeiter, niemand, der E-Mails bearbeitet), dann muss ich mich ernsthaft fragen, ob das noch immer die Krankenkasse ist, bei der ich versichert sein möchte.
Sollte man jetzt auch noch ein neues Bild brauchen, weil man das alte verschlampt hat, werde ich das so lange ausfechten bis man mir eine Karte ohne Bild schickt, das ist sicher.

* Mir ist durchaus klar wie so ein Solidarsystem funktioniert. Kommentare diesbezüglich kann man sich also sparen. Danke.

xt:Commerce performance issues due to getAlsoPurchased()

Modern shopsystems, and for the sake of this post I’m counting the dated xt:Commerce 3 as ‘modern’, are full of features. Features you most likely never use. We, for instance, don’t use Tell-a-friend (as it’s not compatible with german law) or wishlists (as we never saw a need for it).

However, chances are good that those unused features turn out to be a bottleneck when it comes to performance. Especially when they are coded by someone who has heard the word ‘MySQL’ for the first time (i.e. those guys who wrote xt:Commerce 3).

At X-Skating we recently faced the problem that the front page loaded pretty good, the page for a single product however had almost one second till time to first byte (the .700 in the screenshot is better than most other tests we ran).
Read more

Free these mobile contracts, Deutsche Telekom

To give you some context this starts last friday. I attended border:none, a conference for web professionals that took place in Nuremberg. My parents only live an hour north and so I took the opportunity and swung by their place. Also my brother is among the best german model railroaders, his work is known all over Europe and, thanks to his website, worldwide. His club ran their yearly exhibition on that same weekend and as I hadn’t seen it in action before I went there to have a look at his new South Africa layout. Of course I took some pictures and back at my parents uploaded them to my dropbox. Well, at least I tried.

My parents have DSL6000, that means 6016 kbit/s down and 576 kbit/s up. However, as the line is too long, they only can use a fraction of this. It took ages to upload only one picture. I put my phone in the pocket and went upstairs to see my other brother. There is no WIFI reception upstairs and when I unlocked my phone in the attic the upload was incredible fast. I was stunned. What happend? Due to the lack of a WIFI connection my iPhone 5S ‘dropped’ to LTE, which is available in the area. LTE, however, gives me something similar to DSL16000 and all 40 images and two videos got uploaded in less than 10 minutes. You would like to cancel the DSL6000 contract now, put a SIM into your router and use LTE from there on. There is, however, one problem and it has a name: The carriers.

The contracts offered by Deutsche Telekom (and all other carriers in Germany) don’t have a real flatrate, you get your bandwith limited when you hit a ridiculously low amount of data transfered. Remove this, Deutsche Telekom, or at least lift it up to something useful, 50GB or 100GB would do for the beginning. Free these mobile contracts! It’s your chance! And your obligation. Make Germany fast!

International Tracking Links

I’m currently building a new ERP for our company. To make life easier for our customer service they have direct links from within any order to the parcel tracking. We ship most of our items with DHL Germany. Other than with DHL Express the parcel will not be delivered with DHL in the destination country but with the local company instead. DHL provides us with a match code/UPU once the parcel reaches the destination country.

I already built a lot of icons for this but I wanted to improve this even more for our customer service. So where available I tracked down the URL for the Track&Trace in the destination countries – if available the direct link to the result page without any need for our people to put in the match code into another form and submit it.

I’d like to share this list, maybe it’s helpful to anybody else. If you have suggestions, improvements or want to add missing companies, just drop me a line.

This project on Github

Read more

The Tripadvisor desaster

If your business model builds on user generated content – hell, don’t fuck with the users! Yes, I’m looking at you, TripAdvisor!

While researching hotels I not only rely on the HRS ratings but also look the hotel up on TripAdvisor for even more reviews. As this works pretty well I decided to give something back to the community by rating the hotels we stayed.

Signup is easy as you can use your Facebook login. Reviewing is also quite easy, however, your review goes to a pending queue, more commonly known as a black whole and this is where the fun begins. It stays there for some time. The FAQ says 24 to 48 hours, however mine are in the queue for more than 72 hours each. This is quite anoying, as they pile up while you write new reviews and don’t even know if they are helpful for the community, as nobody can read them. On the first review I thought this might be because I’m new to the platform but also with more reviews written nothing speeds up.

But here is what really sucks: Some of my reviews got deleted while pending. No word about why TripAdvisor trashed them, not even an email and there have been reviews for hotels that have only one review to date. And none of them was rude or anything like this, just honest reviews.

I wrote TripAdvisor about this five days ago but haven’t heard back yet. The contact form is also pretty hard to find and the issue ‘My review got deleted’ is not even an option to select.
So all of you who rely on user generated content: If I spend my time to improve your site, let me know what’s going on! Learn from the TripAdvisor desaster!

VX ConnectBot – ConnectBot on steroids

Most of the time ranting about something brings up better solutions. I was quite disappointed with ConnectBot as an alternative to Prompt and mentioned this in my first android review. @DarthMowl replied on Twitter and suggested VX ConnectBot.

Well, we are back in Canada and it’s raining again so I got some time to write about VX ConnectBot. It addresses most of the issues I criticized.

  • You can import keys. Just store the key on the device and import it with VX ConnectBot.
  • Bookmarks can be renamed, that however also works with ConnectBot, I just didn’t try a tap-and-hold on the bookmark before.
  • Terminal size can be changed by pinch gestures.

The problem with the arrow keys remains. However, there’s an app for that (sic!), Full Keyboard. Or any other keyboard extension on Android. However, I found none I’m comfortable with so I will stick with the default keyboard for the time being.

There are some more features that set VX ConnectBot apart from ConnectBot, what I love most is the ability to assign keystrokes to hardware buttons. So ‘Volume up’ now works as tab key and ‘Volume down’ as control key. With no more hardware buttons on the Nexus 4 that’s it for this device, but you can assign more buttons on other devices.

The HRS touch interface and why it sucks

I like to be ahead of the game. Not only as a softball umpire but also on my vacation trips. The two guys I’m with on vacation picked hotels on a try-and-error basis in the first days. But just stopping at the first hotel that comes in sight neither gives you the best prices nor the best hotels, so I jumped in and took over the hotel management.

I book everything through HRS. This is not because they have the greatest platform on earth but they have a lot of hotels around the world. But speaking of the platform, hell it sucks. Especially the touch interface. It starts with this modal overlay that tell’s you that they are gathering the search results. Have you ever seen something similar on Google? No? That’s because it’s completely unnecessary and bloats the interface. And I built a hotel reservation system on my own a few years ago, I know what I’m talking about!

Location awareness? Not with HRS. We stayed one night in London. London, Ontario to be exact. While Google offered me the canadian London as a first choice in the Maps app HRS always offered London, England first. It’s so easy to get this right based on IP or location! And yes, HRS is allowed to use my location.

Browsing through the results is slow as hell. Because every time you select a hotel you get this fancy overlay. And every time you go back to the result list, you get it again.

Currency conversion: I have no idea what they are smoking. In the result list it is converted correctly, 103 Canadian Dollar equals more or less 75 Euro. In the detail view on the offer tab however, this becomes 149 Euro, but still 103 Canadian Dollar.

Error handling: What a mess! Filling forms on a mobile device is a pain in the ass by default. But it get’s worse with the error handling HRS implemented. Got a typo on your 16 digit credit card number? No problem, a model overlay will let you know and you can correct it. For your convenience HRS deletes both the whole number and the name on the card. Once fixed you get an error 5000, ‘Person invalid’. This time, you can’t correct it. You are thrown back to a blanked out search form. HRS yells in your face: „Don’t make any typos, stupid! So start over completely again till you learned your lesson”.
Because you are already annoyed you skip the second person on a double room as the fields are marked optional anyway. Well, obviously this is no longer true but the backend guy forgot to tell the frontend guy. You might already know what happens: Model overlay that says to fill in a first name for the second person. After fixing this (and typing your credit card number once again as HRS blanked the field for your convenience) you get: Error 5000. Welcome back home, baby! I was that close to calling the hotel and book by phone, but it worked on the third try. Once again when you are dominant in your market you get lazy, as HRS does.
The good thing is: I can tell my credit card number from memory now and impress front desk clerks all over the world with this useless trick.

Going Android

My day-to-day phone still is an iPhone 4S, netlocked thanks to Deutsche Telekom. So I was in need for another phone for my recent trip to the US and Canada. From my collection auf test devices I picked the Nexus 4 with the latest Android OS. We are now on the road for more than a week and, while cruising around Lake Superior on the Trans-Canada Highway, it’s time to write a short review.


Before leaving I ordered an AT&T SIM and a voucher from travelSIMple which I activated while still in Germany. I went off the plane in Chicago and had data instant on. That’s really great. What’s not so great is the size of the phone. It’s both taller and wider than my iPhone and that sucks. There are tasks on Android where you have to reach the upper left corner on the phone and I always have to change the position of the phone in my hand or I use my other hand.

It happens all the time to me that I hit the wrong button when I want to unlock the phone. When you draw the phone from your pocket you can’t tell where is up and down as there is no real home button. And putting the unlock button on the side doesn’t make that in any way easier.

What I miss most is to scroll up all the way by a simple press on the title bar. But I guess, there’s an app for that, as I also had to install an app to prevent the display from rotating. You’re kiddin’ me, right?

What also works on a good-luck-basis is locking the phone, especially when you use the standard slide unlock. I happend more than once that my phone was unlocked and doing weired things while sitting in my pocket. I switched to a pin code and it never happend again. Still ridiculous.

What’s really great is the spell correction. It happens to me quite often on the iPhone that I select a correction on error. You have to delete everything then. On Android when this happens and you hit backspace it reverts to the word it corrected from. I love this as I love the abbility to pick from three different suggestions. However, sometimes hitting space does exactly nothing and you come up with concatenated words that shouldn’t. I think this is related to the spell correction but I wasn’t able to figure this out yet


I have a very limited set of apps on the phone, only those I really need while on vacation.


This includes K9 Mail for my regular email. This is a great app, supports multiple accounts, colors for the accounts and is a full-fledged IMAP client. Missing a swipe-to-delete gesture in list view, however.

I use the GMail client that ships with the phone and this one is so much worse than the current iPhone client. Makes me wonder what Googles primary platform really is. You can’t batch delete mail by tapping a checkbox in list view, you can only archive on swipe but not delete and assigning labels drives my crazy every time as it is an unnecessary multi-step process.


The built in Maps app is, compared to the GMail app, so much better. I use it for navigaton, it has a real small data usage footprint and good directions. I’m somewhat confused with the multiple search input fields that return different result views and I haven’t figured out yet how to start a navigation from my current location once I delete the current location entry.
Quite funny is the voice on navigation. The phone is set to German as it’s primary language and the navigation tries to pronounce all street names in German. There’s room for improvement…


I love the Foursquare widget on the home screen. I check in quite more often than I do on my iPhone. Otherwise this app is not much different from the iPhone app.


I’m a hardcore user of Panic’s Prompt on the iPhone. I did a lot of research and finally installed ConnectBot. Well, it’s not yet competitve but as far as I can tell it’s the best you can get.

  • There is now way to import keys, you have to generate a key on the device and then introduce the public key to your server. This means some work when you have more than two servers (as I do). And even then connection with keys isn’t the default, so connection takes some time as password based has to fail first.
  • You can’t rename bookmarks. I have quite a few connections to the same server with numeric usernames. You just can’t tell them apart when you can’t give the bookmark a name. I had to set up subdomains to do so.
  • You can’t read anything on the prompt by default. You have to reset the terminal to a given size. And you have to do this every time. Pinch gestures don’t work.
  • No arrow keys. If you want to do execute the same command again you have to type !! every time.



As mentioned above I got an AT&T SIM from travelSIMple before leaving. The internet coverage is quite amazing, even in not so densly populated areas, buying extra data is easy, tethering works out of the box and like a charme. In brief, im quite happy with AT&T.


On the other hand, Rogers sucks. Big time. I go with the claim ‘Where I am is internet’ so I couldn’t risk to be without while in Canada, even if it’s only for four days (things somewhat change when you are self employed). I got a Rogers SIM, also from travelSIMple, but you can’t activate it from abroad.
This is because you need either a canadian credit card (which I don’t have) or a voucher. Unfortunately you can’t buy vouchers before, because they are only valid for 30 days and expire afterwards without any refund. This is ridiculous and I’m happy to live in Germany where those things won’t happen. Next problem: These vouchers are pretty hard to get. I tried right after the border where you can get fishing and hunting permits, but no Rogers vouchers. I tried on a truck stop to no avail. Finally, I got lucky at a Walmart.
Nontheless, network coverage by Rogers is pretty good. I had no activated SIM around the north shore of Lake Superior, so AT&T dropped to Rogers roaming. I had coverage almost on the whole Trans-Canada Highway 17, however, as I was on roaming and not interested in getting bankrupt, I can’t tell if and who good data coverage would have been.

Query Doctrine/Translatable for translated strings

I’m currently working on a new backend for all our onlineshops that will help us to streamline our workflow so we can get our lovely nutcrackers and cuckoo clocks to the customers even faster than ever before (it’s all about speed, no matter if in the browser or in the warehouse).

As I’m not doing that much backend development these days I gave both Zend Framework and Symfony a try. I went with Symfony (and Rock Hammer, but that’s a story for another day). So far this works out quite well. Symfonys documentation is great, everything (well, almost everything) works as expected and you save a lot of time because you can concentrate on your business logic and don’t have to think about the underlying things as database connections etc.

However, there is one thing with Doctrine and Translatable that took me almost two hours today to figure out.

I have a database table with countrienames in German, english names are stored with the help of Translatable in the default table ext_translations. What I tried to achieve was to get the ID of a country. The only information I got was the name in english:

$oCountry = $oEM->getRepository('W3LShopBundle:Country')->findOneByName($aOrder['countries_name']);

returns no hits. I searched the whole web for a solution as the documentation is not very helpful here. I came with up some solutions that set hints on the query, all of them returning exactly zero rows. I tried to write native SQL, however Doctrine messus up with the backslashes needed for object class. In the end, you get zero results with Doctrine while the same statement works fine in phpMyAdmin (you could work with a like statement on the object class field, but that’s a real performance hog).

Finally, I figured out that you need to set multiple hints.

$oQB = $this->getContainer()->get('doctrine')->getManager()->createQueryBuilder();
$oQuery = $oQB->select('c')->from('W3LShopBundle:Country', 'c')->where('c.name = :name')->getQuery()->setParameter('name', $sCountry);
$oQuery->setHint(\Doctrine\ORM\Query::HINT_CUSTOM_OUTPUT_WALKER, 'Gedmo\\Translatable\\Query\\TreeWalker\\TranslationWalker');
$oQuery->setHint(\Gedmo\Translatable\TranslatableListener::HINT_TRANSLATABLE_LOCALE, 'en_US');
$aCustomerCountry = $oQuery->getResult();

This finally returns results. Maybe this is helpful for anybody else.