I'm trying to create an ICNS (including a 1024x1024 image) programmatically. Currently I'm creating an NSImage
, then I create CGImageRef
objects with the appropriate resolution, finally I'm adding them to an icon by using CGImageDestinationAddImage()
. Peter Hosey has helped me create '@2x' images already, but the sizes of the images don't wanna be set.
This is the code (still a bit messy, sourcefile
represents the path to the image):
NSSize sizes[10];
sizes[0] = NSMakeSize(1024,1024);
sizes[1] = NSMakeSize(512,512);
sizes[2] = NSMakeSize(512,512);
sizes[3] = NSMakeSize(256,256);
sizes[4] = NSMakeSize(256,256);
sizes[5] = NSMakeSize(128,128);
sizes[6] = NSMakeSize(64,64);
sizes[7] = NSMakeSize(32,32);
sizes[8] = NSMakeSize(32,32);
sizes[9] = NSMakeSize(16,16);
int count = 0;
for (int i=0 ; i<10 ; i++) {
if ([[NSUserDefaults standardUserDefaults] boolForKey:[NSString stringWithFormat:@"Size%i",i+1]]) count++;
}
NSURL *fileURL = [NSURL fileURLWithPath:aPath];
// Create icns
CGImageDestinationRef dr = CGImageDestinationCreateWithURL((CFURLRef)fileURL, kUTTypeAppleICNS , count, NULL);
NSImage *img = [[NSImage alloc] initWithContentsOfFile:sourcefile];
for (int i=0 ; i<10 ; i++) {
if ([[NSUserDefaults standardUserDefaults] boolForKey:[NSString stringWithFormat:@"Size%i",i+1]]) {
// Create dictionary
BOOL is2X = true;
if (i == 1 || i == 3 || i == 5 || i == 7 || i == 9) is2X = false;
int dpi = 144, size = (int)(sizes[i].width/2);
if (!is2X) {dpi = 72;size = sizes[i].width;}
[img setSize:NSMakeSize(size,size)];
for (NSImageRep *rep in [img representations])[rep setSize:NSMakeSize(size,size)];
const void *keys[2] = {kCGImagePropertyDPIWidth, kCGImagePropertyDPIHeight};
const void *values[2] = {CFNumberCreate(0, kCFNumberSInt32Type, &dpi), CFNumberCreate(0, kCFNumberSInt32Type, &dpi)};
CFDictionaryRef imgprops = CFDictionaryCreate(NULL, keys, values, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
// Add image
NSRect prect = NSMakeRect(0,0,size,size);
CGImageRef i1 = [img CGImageForProposedRect:&prect context:nil hints:nil];
CGImageDestinationAddImage(dr, i1, imgprops);
}
}
CGImageDestinationFinalize(dr);
CFRelease(dr);
size
is the width or height that the current image should be. dpi
is 144 if we're making an '@2x' image, otherwise it's 72. These values have been checked with NSLog
.
The images in the resulting ICNS file are all the same size as the input image. If the size of the input image is 1024x1024, ImageIO complains:
ImageIO: _CGImagePluginWriteICNS unsupported image size (1024 x 1024) - scaling factor: 1
The above error is displayed every time the dpi is 72 and the size is 1024x1024.
I need to know how to set the size of the CGImage that is to be added to the ICNS file.
EDIT: I logged the images:
2012-12-31 12:48:51.281 Eicon[912:680f] |NSImage 0x101b4caf0 Size={512, 512} Reps=(
"NSBitmapImageRep 0x10380b900 Size={512, 512} ColorSpace=(not yet loaded) BPS=8 BPP=(not yet loaded) Pixels=1024x1024 Alpha=YES
Planar=NO Format=(not yet loaded) CurrentBacking=nil (faulting) CGImageSource=0x10380ae70"
)|
2012-12-31 12:48:52.058 Eicon[912:680f] |NSImage 0x101b4caf0 Size={512, 512} Reps=(
"NSBitmapImageRep 0x10380b900 Size={512, 512} ColorSpace=Generic RGB colorspace BPS=8 BPP=32 Pixels=1024x1024 Alpha=YES Planar=NO
Format=2 CurrentBacking=|CGImageRef: 0x101c14630| CGImageSource=0x10380ae70"
)|
2012-12-31 12:48:52.111 Eicon[912:680f] |NSImage 0x101b4caf0 Size={256, 256} Reps=(
"NSBitmapImageRep 0x10380b900 Size={256, 256} ColorSpace=Generic RGB colorspace BPS=8 BPP=32 Pixels=1024x1024 Alpha=YES Planar=NO
Format=2 CurrentBacking=|CGImageRef: 0x101c14630| CGImageSource=0x10380ae70"
)|
2012-12-31 12:48:52.238 Eicon[912:680f] |NSImage 0x101b4caf0 Size={256, 256} Reps=(
"NSBitmapImageRep 0x10380b900 Size={256, 256} ColorSpace=Generic RGB colorspace BPS=8 BPP=32 Pixels=1024x1024 Alpha=YES Planar=NO
Format=2 CurrentBacking=|CGImageRef: 0x101c14630| CGImageSource=0x10380ae70"
)|
2012-12-31 12:48:52.309 Eicon[912:680f] |NSImage 0x101b4caf0 Size={128, 128} Reps=(
"NSBitmapImageRep 0x10380b900 Size={128, 128} ColorSpace=Generic RGB colorspace BPS=8 BPP=32 Pixels=1024x1024 Alpha=YES Planar=NO
Format=2 CurrentBacking=|CGImageRef: 0x101c14630| CGImageSource=0x10380ae70"
)|
2012-12-31 12:48:52.409 Eicon[912:680f] |NSImage 0x101b4caf0 Size={128, 128} Reps=(
"NSBitmapImageRep 0x10380b900 Size={128, 128} ColorSpace=Generic RGB colorspace BPS=8 BPP=32 Pixels=1024x1024 Alpha=YES Planar=NO
Format=2 CurrentBacking=|CGImageRef: 0x101c14630| CGImageSource=0x10380ae70"
)|
2012-12-31 12:48:52.534 Eicon[912:680f] |NSImage 0x101b4caf0 Size={32, 32} Reps=(
"NSBitmapImageRep 0x10380b900 Size={32, 32} ColorSpace=Generic RGB colorspace BPS=8 BPP=32 Pixels=1024x1024 Alpha=YES Planar=NO Format=2
CurrentBacking=|CGImageRef: 0x101c14630| CGImageSource=0x10380ae70"
)|
2012-12-31 12:48:52.616 Eicon[912:680f] |NSImage 0x101b4caf0 Size={32, 32} Reps=(
"NSBitmapImageRep 0x10380b900 Size={32, 32} ColorSpace=Generic RGB colorspace BPS=8 BPP=32 Pixels=1024x1024 Alpha=YES Planar=NO Format=2
CurrentBacking=|CGImageRef: 0x101c14630| CGImageSource=0x10380ae70"
)|
2012-12-31 12:48:52.729 Eicon[912:680f] |NSImage 0x101b4caf0 Size={16, 16} Reps=(
"NSBitmapImageRep 0x10380b900 Size={16, 16} ColorSpace=Generic RGB colorspace BPS=8 BPP=32 Pixels=1024x1024 Alpha=YES Planar=NO Format=2
CurrentBacking=|CGImageRef: 0x101c14630| CGImageSource=0x10380ae70"
)|
2012-12-31 12:48:52.864 Eicon[912:680f] |NSImage 0x101b4caf0 Size={16, 16} Reps=(
"NSBitmapImageRep 0x10380b900 Size={16, 16} ColorSpace=Generic RGB colorspace BPS=8 BPP=32 Pixels=1024x1024 Alpha=YES Planar=NO Format=2
CurrentBacking=|CGImageRef: 0x101c14630| CGImageSource=0x10380ae70"
)|
aFile
) in all of the different representations? Anything that draws an IconFamily will automatically scale the nearest available element, so you could just add the image once in its natural size (if it's a valid element size) or the next smaller valid element size. – Peter HoseyNSImage
, then add it repeatedly, changing its size while doing so? – Fatso