1

My issue is that i need have. I need to achieve this programmatically.

So for mac os x an application icon should have these sizes:

I have 10 images. Each one i placed a badge in the right corner, the placement and position of this badge does not scale. So i 10 different images.

How to make a ICNS out of this?

I thought to use sips, however sips only takes one file and it does all the scalings: http://cc.bingj.com/cache.aspx?q=mac+icns+sips+argument+list&d=5035141870911884&mkt=en-US&setlang=en-US&w=n3PZcWn6bEPxt4O96PPLd6nugtVq5jDz

Is there a way to make /usr/bin/sips take my 10 images and make a icns out of it? If sips cant do it is there any other way?

Cœur
  • 37,241
  • 25
  • 195
  • 267
Noitidart
  • 35,443
  • 37
  • 154
  • 323

1 Answers1

3

If you want to use iconutil, you can do that. At least on my 10.9.5 system, it's part of the base OS. It's not a special install, like developer tools. You can verify that using:

pkgutil --file-info /usr/bin/iconutil

Here, that outputs:

volume: /
path: /usr/bin/iconutil

pkgid: com.apple.pkg.BSD
pkg-version: 10.9.0.1.1.1306847324
install-time: 1402788942
uid: 0
gid: 0
mode: 755

The important part is the pkgid. It's part of the BSD package, which is part of the base OS.

That said, it's not hard to write a bit of code to do this.

You can use the CGDestination API. Create a destination using CGImageDestinationCreateWithURL(). For the type, pass kUTTypeAppleICNS.

Given that you want to add images from individual files, it's probably easiest to create a CGImageSource for each using CGImageSourceCreateWithURL(). Then, you can directly add an image from the source to the destination using CGImageDestinationAddImageFromSource(). Don't forget to CFRelease() each source after you've added its image to the destination.

Then, call CGImageDestinationFinalize() to have the destination write out the image to the URL. Then, CFRelease() the destination.

If each of the source images has the proper DPI set, this will be copied over intact to the destination. If the source images don't have the proper DPI set, you can override it by passing a dictionary of properties to CGImageDestinationAddImageFromSource(). Include the keys kCGImagePropertyDPIHeight and kCGImagePropertyDPIWidth, each with a corresponding value of a CFNumber object with the desired DPI. For a normal-resolution icon, use 72 DPI. For a high-resolution (@2x) icon, use 144 DPI.


Creating ICNS files can also be done using the old IconFamily API, but it's a bit hairy. Also, it doesn't support high-resolution icons.

First, you create a handle (pointer-to-pointer-to-resizable-buffer) for the icon family:

IconFamilyHandle iconFamily = (IconFamilyHandle)NewHandle(0);

Then, for each image size (16, 32, 128, 256, and 512), you create a handle for a raw bitmap of the image data. The bitmap should be 32 bits per pixel, 8 bits per component, ARGB non-premultiplied data with no padding.

int size = /* 16, 32, 128, 256, or 512 */;
Handle handle = NewHandle(size * size * 4);
// fill handle with image data; buffer pointer is *handle

Then, you add that handle to the icon family with a call like:

SetIconFamilyData(iconFamily, kIconServices16PixelDataARGB, handle);

For the other sizes, replace the "16" in kIconServices16PixelDataARGB with the appropriate value.

Then, you write the icon family handle's data out to file. A pointer to the data is obtained by simply dereferencing the handle (i.e. *iconFamily). Its size is obtained by calling GetHandleSize((Handle)iconFamily).

Dispose of any handles you created along the way by calling DisposeHandle().

Ken Thomases
  • 88,520
  • 7
  • 116
  • 154
  • 1
    Absolutely awesome!! Thank you Ken!! I'm going to try writing that CoreFoundation code. By any chance would you know if iconutil is available since which OSX? This topic here seems to show its missing on some Macs: [StackOverflow :: Where is the iconset command-line tool 'iconutil' located?](http://stackoverflow.com/questions/12281309/where-is-the-iconset-command-line-tool-iconutil-located) – Noitidart Jan 07 '15 at 01:00
  • 1
    Sorry, I don't know when `iconutil` was introduced. It is a good/important concern, though. How far back do you wish to deploy? I think that `CGImageDestination` only started supporting ICNS in 10.6, but it was buggy. So, you should only try to use it from 10.7 on. – Ken Thomases Jan 07 '15 at 01:02
  • Thanks for that important note on `CGImageDestination` I wouldn't have known that. I'm using this in an addon for Firefox 4+ which is supported on OSX >= 10.5. By any chance would you know of a workaround for `CGImageDestination` for 10.5? – Noitidart Jan 07 '15 at 01:12
  • 1
    `iconutil` was not available back in 10.5. I've got an old 10.6 partition and it's not even on that. Before `CGImageDestination` supported ICNS, there were a couple of options: 1) use the old, Carbon-era IconFamily API; or 2) combine the images into a TIFF file using `CGImageDestination` and then invoke `tiff2icns` on that. Unfortunately, the bug in `CGImageDestination`'s support for ICNS that is in 10.6.8 also affects `tiff2icns`. Those older OSes won't support high-resolution icons in ICNS files, anyway. There are also third-party, open-source libraries for the ICNS format, too. – Ken Thomases Jan 07 '15 at 01:33
  • Thanks Ken! It looks like before `10.6.8 v1.1` they didn't even support ICNS is that true? per this comment here: [How to manually create icns files using iconutil?](http://stackoverflow.com/questions/12306223/how-to-manually-create-icns-files-using-iconutil#comment16529950_12309734) So if i want to support 10.5 and 10.6 I should convert it to whatever they used back then huh? Do you know what was their icon file type back then? Thanks Ken I really appreciate your awesome help especially your digging into your old partition! – Noitidart Jan 07 '15 at 01:43
  • `icoutils` worked absolutely awesome!! here is my code for that: [GitHubGIST :: Noitidart / _ff-addon-snippet-NsiProcesIconutilIcns.js](https://gist.github.com/Noitidart/a8a83786d7a1efc78a80#comment-1367227) now to just figure out what icon file type they used in 10.5 and 10.6 any guidance you could give me would be sooo awesome! – Noitidart Jan 07 '15 at 01:49
  • 1
    ICNS was definitely used in 10.5 and 10.6. It goes back to classic Mac OS. – Ken Thomases Jan 07 '15 at 02:02
  • Oh dang, ok so ill still have to make an ICNS for 10.5 nd 10.6 but it just has to be done differently. I got it thanks Ill go by your comment on the combine images to tiff then use tiff2icns. Thanks! – Noitidart Jan 07 '15 at 02:25
  • 1
    But `tiff2icns`, like `CGImageDestination`, produces buggy ICNS files in 10.6.8. (That's because `tiff2icns` has used `CGImageDestination` under the hood ever since `CGImageDestination` started supporting ICNS.) – Ken Thomases Jan 07 '15 at 02:33
  • Ah thanks for the save. so the only way is to go to the IconFamily Carbon API. Could you please outline what to call from the api's like you did above please, I dont know C i just convert things to ctypes haha – Noitidart Jan 07 '15 at 02:36
  • 1
    I've updated my answer with the IconFamily API. Note that it doesn't support high-resolution icons. You might want to code both techniques and switch between them based on the version of the OS. Also, high-resolution icons (however they're created on versions of the OS where they're supported) won't be understood/displayed properly on earlier versions of the OS. I don't remember exactly where the support was added. You're going to have to do extensive testing. – Ken Thomases Jan 07 '15 at 03:08
  • I will definitely code for both thank you so much for such awesome help!! I really appreciate it! I will also definitely share my findings! Least I can do to return the favor a bit :) – Noitidart Jan 07 '15 at 03:21
  • Hi @Ken I was making progress on this and was curious is the 64 size not supported on the old API? I see for sizes we only have 16,32,128,256,and 512. – Noitidart Jun 16 '15 at 14:27