Using multi-resolution TIFF files with WebKit on Mac for Retina support

I’m working on Retina support for our Mac application Trickster. Most of the things are pretty standard – either creating PDF images instead of PNGs or creating two PNGs for regular and @2x image.

During the build process the latest Xcode will take the two PNGs and create one multi-image TIFF file which is inserted into the built application’s Resource folder.

Trickster uses WebKit to display its Help screens. Two are just text but one is an image.

Previously I only loaded the image directly, without HTML with:

[[NSBundle mainBundle] URLForImageResource:@"Trickster Help"];

To support Retina version of the image, I created the @2x version, added it to the bundle and went to look how to use the media queries and other CSS tricks to display the double-resolution image on Retina display. I had to build an HTML file and load it into WebKit instead of the PNG:

[[NSBundle mainBundle] URLForResource:@"Trickster Help" withExtension:@"html"];

I built the HTML:

<!DOCTYPE html>
<html>
<head>
    <style type="text/css" media="screen">
    body { margin:0 }

    div#help {
        width: 740px;
        height: 562px;
        background-image: url(Trickster%20Help.png);
        background-size: 740px 562px;       
    }

    @media screen and (-webkit-min-device-pixel-ratio: 1.5), screen and (min-device-pixel-ratio: 1.5) {
      div#help {
        background-image: url(Trickster%20Help@2x.png);  
      }
    }

    </style>
</head>
<body>
    <div id="help"></div>
</body>
</html>

It worked great when I checked it in the standalone Safari. Safari even dynamically substituted the image used based on where the window was when I dragged it.

The problem was in the built application. The PNGs are converted to TIFF, by default, and the HTML can’t find them so it doesn’t display anything.

I thought “OK, I’ll just change the CSS to point to TIFF image”. Then I thought – but I only have one TIFF, what do I put in the media query?

The solution was unexpectedly simple: point background-image URL to the TIFF file and don’t use the media query at all. WebKit handles the double-resolution TIFFs automatically and selects the Retina version when the window is on the Retina screen and regular one, when on regular screens. Yes, it even does that dynamically when dragging Trickster’s help window.

Here’s the final HTML:

<!DOCTYPE html>
<html>
<head>
    <style type="text/css" media="screen">
    div#help {
        width: 740px;
        height: 562px;
        background-image: url(Trickster%20Help.tiff);
        background-size: 740px 562px;       
    }
    body {
        margin: 0;
    }

    </style>
</head>
<body>
    <div id="help"></div>
</body>
</html>

To sum it up — using WebKit with Retina images inside your Mac application becomes very easy. It just works if you point your HTML to multi-resolution TIFF files instead of PNGs. And Xcode generates these TIFF files by automatically. Easy win!

It’s probably not an appropriate solution for general Web use as I don’t think that other browser will support multi-resolution TIFFs. It also requires visitors to download large TIFFs even if they don’t use them (and let’s not forget – most people don’t have Retina displays).

I wonder if a similar solution works on iOS. I haven’t tried. Would love to hear result, if you try it.

You can get in touch with me on Twitter at @apparentsoft.