Hacker News new | past | comments | ask | show | jobs | submit login
IOS Image Tricks (dwellable.com)
90 points by gurgeous on July 27, 2012 | hide | past | favorite | 22 comments



I'm being a bit picky here, but IOS is an operating system that runs on Cisco networking equipment. "Images" is how one refers to the software that is loaded on the switch/router/etc. For example, I can buy an "layer 3 enhanced image" for a Cisco switches that will give me limited routing capabilities.

For that reason, one should be careful about the case of the letters when referring to IOS and iOS, as they can lead to confusion if not used appropriately.


The author correctly capitalizes "iOS" in the article. Hacker News automatically capitalizes the first letter of submission titles, though.


The rule would be improved if it only capitalized the first letter when the first word does not contain any capital letters.


Or it should stop trying to second guess users.


Given the audience here, I would imagine anyone writing about Cisco IOS would naturally write the title as "Cisco IOS Image Tricks", but as pointed out, hn would be better off not trying to secondguess and proper case titles.


Using 16-bit images won't save any memory, and may actually use more memory. The iOS graphics pipeline requires 32-bit images for rendering, so all other types of images are converted to a 32-bit texture.

If you are trying to optimize memory consumption, you need to measure memory consumption! You can't just change some code and assume your memory consumption has gone down.


I certainly was measuring memory consumption. Many of these images are offscreen in paging scroll views (per the blog post), or stuck in caches.


Like gurgeous, I also measure memory consumption almost to a fault. Even though it appear iOS loads jpgs directly into a 32bpp RGBA bitmap, you can after that trim down the size of the image resident in memory. It makes a significant difference in memory usage according to Instruments, but slows down the loading of an image from disk. Unfortunately, like noted elsewhere in this thread, it doesn't seem possible to load a jpg directly into a 16bpp in memory representation and skip the intermediate 32bpp format.


You could compress those images down to 4bpp or even 2bpp by encoding to PVRTC. Since they're photorealistic images you'll retain image quality despite being 8x or even 16x smaller, and the graphics chip supports the format natively so you don't need to decompress it.

I use it in games whenever a photorealistic image is required. Some more info:

http://www.uchidacoonga.com/2011/07/pvrtc-textures-and-cocos...

https://developer.apple.com/library/ios/#qa/qa2008/qa1611.ht...


I'm not familiar with PVRTC, unfortunately. Here's one of the better articles I could find:

http://www.kihongames.com/blog/labs/2011/04/labs-pvrtc-power...

Some highlights from the article:

- "Avoid using PVRTC when you have static images that are the focus of your content" - "images are 2-4x larger, but memory use is less" - "amazing memory improvement, but no real change in performance" - "textures must be power of two"

It probably doesn't fit my use case, but it's fascinating.


Right now you are using 32bpp images, and then falling back to 16bpp for slower devices. Because PNG uses zip-style compression, pictures of houses won't compress that well, so your size on disk and size in memory will be similar.

PVRTC allows you to save at 4bpp or 2bpp, so you'll get sizes 8x or even 16x SMALLER than a full color image, both on disk and while loaded into memory (loading images are a major source of lag on iPhone, so a smaller on-disk footprint is always welcome). You can even zip compress it for further on-disk savings, though YMMV.

The quality degradation is similar to what you'll get in JPEG, in that there will be some artifacting depending on the quality of the encoder and the source image (hard edges don't compress well, nor does text, but photorealistic images retain a lot of quality).

The power-of-2 restriction is the only real pain point of PVRTC. But if you're making sprite sheets, that's probably not going to be a big issue for you anyway. Once it's in memory it's just a texture like any other, and you can use it sprite sheet style like you're already doing, chopping up the contents any way you choose.

I suggest you try cropping one of your house images to a square sized power-of-2 as a quick test and convert it to PVRTC so you can see for yourself what the quality is like. It may yet be usable for your purposes, and the potential payoff is huge.


Actually here you go:

I took the first image from here: http://www.dwellable.com/h/8559/Cape-Cod/Upper-Cape-Cod/Falm...

Cropped it to 1024x1024 (you'd of course make a sprite sheet instead). Then shrank it to 512x512 just for demonstration purposes.

I then converted it using texturetool, also back-converting it to make a png with exactly the pixels produced in the PVRTC image:

    $ texturetool -e PVRTC --channel-weighting-perceptual --bits-per-pixel-2 -p converted2.png -o converted2.pvrtc original.png
    $ texturetool -e PVRTC --channel-weighting-perceptual --bits-per-pixel-4 -p converted4.png -o converted4.pvrtc original.png
The PVRTC images are significantly smaller, both on disk and in memory:

    $ ls -l original.png 
    -rw-r--r--  1 kstenerud  staff  571225 Jul 27 15:10 original.png
    $ ls -l converted*.pvrtc
    -rw-r--r--  1 kstenerud  staff   65536 Jul 27 15:12 converted2.pvrtc
    -rw-r--r--  1 kstenerud  staff  131072 Jul 27 15:12 converted4.pvrtc

Here's the quality:

Original image: http://i.imgur.com/flT7c.png

4bpp image (converted back to png): http://i.imgur.com/Itz4F.png

2bpp image (converted back to png): http://i.imgur.com/tzqlw.png


Ooh, cool! We're using JPGs, though. At quality 75:

   67K  flT7c.jpg
  558K  flT7c.png
Once those JPGs make it across the network and arrive on the device, we're stuck with plain old CGImages, right?


Yeah. When you load a JPEG image, it gets decoded to a 32bpp image in memory on the device. PVRTC images, on the other hand, stay the same size (2bpp or 4bpp) when loaded into memory. Plus they don't need to be decoded.

So this 512x512 image would take 64k of RAM using 2bpp pvrtc, 128k using 4bpp pvrtc, and a whopping 1MB using JPEG or PNG.


Another thing to look out for with PVRTC compression is that you tend to get compression artifacts along the edges of the texture. If you attempt to tile multiple texture to form a larger image, they will show up as very distracting lines.

It can be fixed by discarding the last few pixels of each edge.


Very interesting read, especially the image sprite part and how it improved cpu usage.

BTW:

  gIsLowCPU = [gModel matches:[NSRegularExpression re:@"^(iPhone1|iPod[12])"]];
this is gonna be fun when the iPhone 10 is released!


Ha! I really hope none of these techniques are in vogue for iPhone 10. Or iPod 10, for that matter.


That's what people said about 2 digit years :P


Unless the iPhone10 has a cheap CPU


I remember back in the day of 60 MHz PowerPC with 16 MB RAM, that I used software that would decode JPEG files in blocks, so you could look at high-res photos without holding the whole uncompressed image in RAM. In fact, I have an app like that for my Android phone for viewing a very high res bike route map I rendered out of a PDF.

Are there any libraries like that floating around that would work in this situation?


So, it sounds like 'spriting' in this context is a way of sending a stitched together larger image and then showing a portion of it in each uiimage. I work on Android, and I'm interested in the technique but just was looking for some validation before I go off doing research.


Here's a tip when you start working on android. There is a method in the bitmap factory class that can handle image scaling for you on device.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: