13
votes

I am creating a plist from my OSX app that contains some images. I am writing the image by :

[NSKeyedArchiver archivedDataWithRootObject:self.someImage]

Then I am using this plist file as a template for iOS app, but here I can't convert the file to UIImage and neither to NSImage(as this is only for OSX).

I am getting this error:

* Terminating app due to uncaught exception 'NSInvalidUnarchiveOperationException', reason: '* -[NSKeyedUnarchiver decodeObjectForKey:]: cannot decode object of class (NSImage)'

Please suggest me a way to perform the above.

4

4 Answers

24
votes

OS X:
Instead of using NSKeyedArchiver to convert an NSImage to NSData, use NSImage's TIFFRepresentation method:

NSData *imageData = [self.someImage TIFFRepresentation];
// save imageData to file

iOS:
Read the image data from the file, then convert it to a UIImage using UIImage's +imageWithData: convenience constructor:

NSData *imageData = ...; // load imageData from file
UIImage *image = [UIImage imageWithData: imageData];
5
votes

You need to create a NSBitmapImageRep and then save that, then read the NSData to UIImage with +[UIImage imageWithData:]:

First in OS X, save the data:

NSString *filepath;
NSBitmapImageRep *imageRep = [NSBitmapImageRep imageRepWithContentsOfFile:filepath];

NSData *data = [imageRep representationUsingType:NSPNGFileType properties:nil];
// Save the data

You could also use imageRepWithData: if you have NSData of the image already - the above will load it from a file (like you can also do with NSImage).

Then in iOS:

NSData *data; // Load from a file
UIImage *image = [UIImage imageWithData:data];

See here for the other allowed keys for the dictionary in representationUsingType:properties:.

0
votes

macOS

I found using TIFFRepresentation gave me tiny 15x15 images (I was trying to resize an SF Symbol (NSImage imageWithSystemSymbolName). Here's an alternative method to get an NSBitmapImageRep and its bytes based on this answer:

NSData* ImageToData(NSImage *image, int width, int height)
{
    // Build image rep with desired size.
    NSSize size = NSMakeSize(width, height);
    NSBitmapImageRep *rep = [[NSBitmapImageRep alloc]
        initWithBitmapDataPlanes:NULL
                      pixelsWide:size.width
                      pixelsHigh:size.height
                   bitsPerSample:8
                 samplesPerPixel:4
                        hasAlpha:YES
                        isPlanar:NO
                  colorSpaceName:NSCalibratedRGBColorSpace
                     bytesPerRow:0
                    bitsPerPixel:0];
    rep.size = size;

    [NSGraphicsContext saveGraphicsState];
    [NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithBitmapImageRep:rep]];
    [image drawInRect:NSMakeRect(0, 0, size.width, size.height) fromRect:NSZeroRect operation:NSCompositingOperationCopy fraction:1.0];
    [NSGraphicsContext restoreGraphicsState];

    if (rep == nil)
    {
        return nil;
    }
    // Passing nil gives a warning but seems to work okay.
    return [rep representationUsingType:NSBitmapImageFileTypePNG properties:nil];
}
-3
votes

You can convert an NSImage into NSData using the apple built-in API as follows:

UIImage *MyImage = [UIImage imageNamed:@"WhateverDir/MyImage.png"];
NSData *MyImageData = UIImagePNGRepresentation(MyImage);