Animated GIF is not a good video format.
Actually it even isn’t a proper video format because it lacks random access and audio support. Nonetheless animated GIFs experienced a rennaisance in recent years.
My theory is, that the format’s success doesn’t stem from the features it has, but from the ones it lacks:
- No random access: Defaults to autoplay – No playback interaction needed
- No sound: Guarantees silence – Always “Safe for Work”
- No support for 32bit colors: Moderate file sizes and a characteristic look
Given those constraints, GIFs are a great way to communicate simple concepts or interactions.
Want to showcase an animation or an application feature? Instead of a static screenshot with paragraphs of text, a 3 second GIF works equally well and also draws more attention.
In my daily life as software developer, I often need a quick way to capture graphical bugs. Those clips can be easily shared with colleagues or included with bug reports.
Sometimes it’s also simpler to attach a GIF to customer support requests instead of explaining how a certain feature works.
To cover my own needs, I wrote a small macOS application that allows me to record the screen and export the result as animated GIF. The app uses a custom recording codec and also covers the rest of the GIF creation workflow like crop, trim and file size optimization.
When I started to implement the Animated GIF feature for Claquette, I began with a naïve approach.
Armed with several years of experience in writing Objective-C and some knowledge about video APIs on the Mac, I wrote a small prototype.
That first version just read a video file frame by frame and sent the resulting frames to ImageIO. ImageIO is a system framework that supports reading and writing several file formats.
It also comes with a basic Animated GIF encoder and so I decided to skip any third party libraries and just use the built-in mechanisms of macOS.
I was able to come up with a working prototype in a single afternoon. The program was just a simple command line utility, but it was able to turn an arbitrary video file into an animated GIF.
There was just one problem… Or actually there were several of them: Due to the inner workings of ImageIO, the program used vast amounts of memory. Also, the encoding took very long and the files it created were huge. On top of all that, the resulting GIFs looked horrible.
So while it only took me one Sunday afternoon to create a working prototype, it took me several months to fix the above issues. Especially the large file size and the bad visual appearance of the resulting GIFs required a lot of research.
Getting the most out of a 30 year old file format
The original GIF specification (GIF87a) was written in 1987 – almost 30 years ago. Animation features were added in GIF89a, which is still the most recent version of the format.
So how is it possible that a file format designed for low resolution screens and 256 colors is still in use today?
It turns out that the GIF specification contains some sections that open room for exploitation. Additionally, the visual nature of GIFs allows for optimizations to trick human color perception.
The format is simple and has the following basic structure:
- Logical Screen Descriptor
- Global Color Table
- Graphic Control Extension (Frame #1)
– Disposal Method
– Local Color Table
– Image Descriptor
– Image Data
- Graphic Control Extensions (Frame #2)
- Graphic Control Extension (Frame #3)
- … (1 GCE for each animation frame)
Header and Trailer are basically just magic numbers that mark the start and the end of the file. The Logical Screen Descriptor contains some general image information like width, height and background color. The Global Color Table is a simple list of colors that may contain a maximum of 256 entries.
Main image information is stored in one or more Graphic Control Extension blocks.
Color Table Generation
The color table sections of the format specification are a good starting point to optimize the visual quality of an animated GIF.
Both palettes are restricted by the format’s infamous 256 color limit. When reducing an image that uses 32bit (16.777.216 colors, 256 alpha values) to 8bit (255 colors, 1 alpha bit) it becomes really important which colors you leave out. The process of reducing large palettes to small ones is called Color Quantization. Choosing a good quantization algorithm is crucial when aiming for visually similar images with a reduced palette.
Naïve quantization implementations are based on occurrence, where seldom used colors are left out in the final image. More elaborate algorithms use techniques like dimensional clustering or tree partitioning.
When developing for Apple devices there are several libraries that provide color quantization functionality. macOS and iOS even have basic color quantization algorithms built-in. Apple’s implementation is part of the ImageIO framework’s CGImageDestination API.
The following sample images were created using different quantization techniques. They illustrate the quality impact of the used algorithm on the final image.
The first image shows the output of CGImageDestination. The resulting colors are noticeably off. Apple’s encoder also messes up the transparency color in the GIF palette, which leads to holes in some areas of the image (e.g. the titlebar).
The open source library FFmpeg also includes a color quantizer. FFmpeg produces way better results than CGImageDestination. The colors are more vibrant and the transparency color is set correctly.
The color quantization library used by Claquette also outputs a good choice of colors. Additionally the app performs color matching to avoid color shifts and to guarantee correct gamma values.
Frame Difference Calculation
Another important factor during GIF generation is efficient frame difference calculation.
The disposal mode in the Graphic Control Extension allows an encoder to specify how the context is set up before the next frame gets rendered.
GIF89a defines 4 disposal modes:
- Unspecified: Replaces the existing canvas with the full contents of the current frame.
- Do not Dispose: Leaves the existing canvas as-is and composites the current (sub)frame over it.
- Restore to Background: Sets a defined background color and draws the current frame. Areas outside of the subsection in the Image Descriptor shine through.
- Restore to Previous: Fully restores the canvas to the last frame that did not specify a disposal method.
The Image Descriptor section can be used to define a sub-image which does not provide pixel data for a full frame. Instead it contains coordinates and pixel data for a subsection of the full image.
By using frame differences and sub-images with a proper disposal mode, redundant image data can be avoided. Depending on the nature of the input video, this can greatly reduce the file size of the final GIF.
Modern video codecs like H.264 use techniques like macro blocks and motion compensation. Those methods introduce small errors that propagate from frame to frame. Propagated errors show up as noise when calculating frame diffs and eventually lead to unnecessary large files.
Claquette uses a custom lossless codec, that only stores regions that actually changed. This guarantees exact frame diffs.
The following images show the difference between frame #1 and frame #2 of a screen recording. The only effective change between those frames is a change in the mouse cursor location. An exact diff should therefore only contain an offsetted cursor image.
The above diff image was created between 2 frames of an H.264 encoded movie. The visible noise is a result of intra-frame encoding errors.
The second image was created by Claquette’s image diff algorithm. It only contains the mouse cursor – The only image element that actually changed between frame #1 and #2.
After implementing technical details like encoding and optimization, there were still some features missing. Claquette needed an editing UI to handle the whole GIF creation workflow.
As I wanted to keep the app lightweight and simple to use, I decided to add only a small set of editing capabilities: Trim and Crop.
Claquette uses AVFoundation, and therefore I was able to use the AVPlayer class, which comes with a built-in trim tool.
Crop functionality was a bit harder to implement. AVFoundation doesn’t provide any UI component to display crop handles so I had to implement my own.
Besides the standard drag & move interface, my implementation also provides some unique features. It offers alignment guides with haptic feedback and the possibility to enter crop coordinates.
You can see the final implementation of the crop utility in the animated GIF below:
To launch the animated GIF feature, I prepared a press kit and wrote mails to review sites that mostly cover Mac software.
Additionally I submitted the app to Product Hunt and informed Apple’s App Store Marketing team.
I can really recommend to launch on Product Hunt: Claquette received over 400 upvotes and finished in the top 3 on launch day. The site also hosts a friendly community, that makes extensive use of the Q&A section below each hunted product.
I was also lucky to get some mentions from high profile Twitter users and good App Store reviews.
Two weeks after launch, Apple suddenly moved Claquette into the “New and Noteworthy” feature section on the Mac App Store front page. Of course this also lead to a noticeable spike in the sales charts.
Overall I was very pleased with the release and the reception of Claquette 1.5.
Thomas Zoechling is an independent software developer living in Vienna, Austria.
Besides working on his own products, he is also doing contract work. Currently he is helping IdeasOnCanvas to develop the excellent mind mapping software MindNode (macOS, iOS).
From January 21st to January 28th, Apple ran a promotion on its App Stores: Get Productive.
I was lucky enough to be asked to participate on the Mac App Store with Yoink, my app that improves and simplifies drag and drop on the Mac.
I thought I’d share my experience with this promotion and some of the stuff that went on behind the scenes.
It started at the beginning of January, when I received an eMail from a very nice person at Apple, asking if I was interested in putting Yoink on sale for a promotion to happen later in January. I didn’t think too much before responding that I would love to participate – after all, when Apple asks you to participate in a promo, you participate in that promo, there’s no question about it.
It’s not the first time the app partook in a promotion.
In February 2013, Yoink was part of a three-weeks-long productivity promotion on the Mac App Store called “Get Stuff Done” (Yoink was part of the third week – “Utilize”):
Yoink in the Mac App Store’s 2013 Promotion “Get Stuff Done – Utilize” (image credit: macrumors.com)
Thankfully, Yoink did pretty well in that promotion and I think that may have helped in making Apple consider it for this promotion, too.
In case you’re wondering, I don’t have any access or connections to the powers-that-be of the Mac App Store.
However, I do contact them (very rarely, mind you) through iTunes Connect ahead of time if I have a substantial update coming out with information about what’s new and what technologies are used in the update. I do not recommend contacting them about every update you put out – that can only be bad for you, I’m sure.
Pushing my luck, or: Trying to get ScreenFloat included
I realize I should be counting my lucky stars getting one app featured in this promotion.
The thing is, I really believe that another app of mine – ScreenFloat, which takes screenshots and puts them in front of all windows so they’re always visible as a reference to whatever you’re working on – would have been a good fit for the theme of “Get Productive”.
In my mail to Apple, I mentioned ScreenFloat, described it in one sentence and asked if it would be considered.
They did, but the app apparently didn’t make the cut. Since that was what I was expecting anyway, no harm was done and as far as I can tell, they didn’t find it too pushy. Quite the contrary; they seemed very thankful for the suggestion.
I did not receive information about why it was not included, but I have a guess:
I think perhaps the reason they decided not to include ScreenFloat in the sale was its lack of localization – ScreenFloat is localized in English and German, whereas Yoink is available in English, German, Japanese, Simplified Chinese, Korean, Portuguese (Brazil and Europe), French and Italian. Or maybe that it hasn’t received an update in a while (although I am working on version 2.0 these days).
Holding Back an Update
As you’re probably aware, when you release an update on the App Store, its current reviews vanish, the star-rating is averaged over all versions and the new version has 0 (zero) stars.
I was about ready to release an update for Yoink when Apple contacted me, and I knew I had to postpone releasing that update, since if I released it, no stars would be shown next to the app, and I think it does make a difference – it looks much more enticing with stars than without:
Yoink listing without stars on the Mac App Store
Yoink listing with stars on the Mac App Store
I generally dislike withholding an update to my apps (as I regularly fix bugs and I don’t like knowing that a version with bugs that I have already fixed internally is still out there for users to use), but in this case, I had to make an exception.
It came as a blessing in disguise anyhow since it gave me some extra time to test the soon-to-be-released update and make sure the new Force Touch integration was working as expected.
The Effects of the Promotion
I am more than happy with the results of the promotion. Then again, there’s bound to be a big impact on sales when Apple puts your app (along with other developer’s) in front of (potentially) all Mac App Store users.
Apple calls users to action beautifully (see the first image of this post) – a nice banner with icons of popular apps along with the tag line “limited-time prices”. I know that gets me pushing the Purchase button.
Impact on Sales
As expected, I noticed a significant jump in sales during the promotion.
I’m uncomfortable sharing numbers (something I need to overcome, other developers have shared their numbers and it’s always been helpful), but here’s the curve before, during and after the sale from iTunes Connect:
Yoink’s sales graph before, during and after the promotion
Mac App Store Ranking
When the promotion began, Yoink was not in the Top 100 of the Top Paid category in the US at the time.
On January 21st, the app started rising, went to the 43rd place, and on January 22 had its best spot at position 13. It hovered around that spot until the end of the promotion a week later.
It rose to the Top Paid Top 10 in several countries, including China, Japan, Germany and Austria.
I did not see a significant increase in the number of reviews – however, the ones I did receive during the campaign were written in China – something I attribute to the fact that, with a recent update of Yoink, I localized it into Simplified Chinese. I haven’t gotten many reviews of Yoink in that country before, so that’s a safe bet.
Surprisingly, requests for support (by mail, twitter or facebook) didn’t come in in the amounts I was expecting and I think that’s a good indication that Yoink is working reasonably well.
Not getting support requests can mean two things: No one purchases it or the software is working more or less without major problems.
Regarding the amount of copies sold, I take not seeing a big bump in support requests as a good thing.
As I mentioned on twitter, I gave Promoted Tweets a try. I put €200,- (around $215) into it and I think it’s safe to say that it’s the most expensive way for me yet of reaching people. On the other hand, the targeting is first-class.
Promoted Tweet views (highest: around 14.500 views)
I hand-picked 100 twitter accounts that I thought were relevant to the Mac community (developers, app-accounts, bloggers, journalists), chose interests that I thought were relevant to Yoink and let it fly.
I reached 55.813 people, resulting in 4.142 “engagements”, a conversion rate of 7.4%.
For $215, I can get banner ads on websites that yield 170.000 views and up, but the engagement rate there is much lower.
What is an “engagement”, exactly? It’s a click on the tweet, a click on your profile, a click on the image, a click on the link, a “like” or a retweet. So the engagement rate of 7.4% itself is more or less meaningless.
According to Twitter, I received 35 direct clicks on the link. Thirty-five. That’s an engagement rate of 0.06%. Pretty expensive advertising indeed.
Promoted Tweet – Engagements
The funniest thing is that some of the people “liking” the tweet ended up blocking me as “spam”. One reply of the two I received was this image:
I ended up on a couple of lists with the specific purpose of blocking me, since I had an ad on twitter. Granted, those were most likely Twitter users who weren’t ever inclined to purchase my software and there are no hurt feelings, I just found it funny.
Seems some users on twitter don’t realise there’s advertisement and figured I spammed them somehow.
The Link for the Sponsored Tweet
In the beginning, I ran a tweet with a link directed to Yoink on the Mac App Store, which later on I discovered was a bad idea.
Most of the users I targeted with this tweet use Twitter on their iOS device and when you open a Mac App Store link on iOS, you receive this:
Yoink in the iOS App Store
When you click on “Learn more about this App”, it does take you to the app’s website, but that’s another tap most users are not willing to do.
I changed the link to take them directly to Yoink’s website and only lost about 4.000 views. My bad. (I filed a radar to improve the “Mac Apps page in the iOS App Store” here).
I didn’t like linking directly to my app. I’d rather have linked to the sale, the promotion page where all apps are shown. As far as I can tell, however, that is not possible as of yet (I filed a radar for it, too). It is definitely something that could be improved for future promotions.
Maybe the sponsored tweet may have raised the awareness of Yoink among some users, but I don’t think it was worth it. Perhaps an even more targeted audience would have helped.
Being featured by Apple seriously helps you in getting new customers for your app and I’ll do it again any time they invite me.
Sponsored tweets? Quite expensive for little to no effect (in my case – mind you, it was my first sponsored tweet and I might not have targeted it right. Next time, I might go for a sponsorship of a popular blog instead).
If you enjoyed this blog post, perhaps you’d like to join the Eternal Storms Software Newsletter where I write you once a month at most about what’s going on with my apps and on my blog :) Thank you.