Can someone point out a comprehensive example on Image processing using cocoa API? I am developing an application for the Mac, and not for the iphone device. I usually come across with UIImage manipulation which provides an intuitive set of methods to achieve task such as per pixel manipulation and saving into file at different format. In the case with Appkit, NSImage I really find it hard to manipulate per pixel data of the images and saving to different file formats such as PNG not just TIFF.
If you want to work with pixels, CGImage and CGImageSource and CGImageDestination are the way to go. Unlike AppKit's NSImage, which is designed generally in order to handle any kind of image, the CGImage classes are specifically designed for raster images.
You can retrieve a bitmap representation of your image object and modify its data
NSBitmapImageRep *rep = [[image representations] objectAtIndex: 0];
unsigned char *bmpData = [rep bitmapData];
To save modified representation in PNG format do the following:
NSData *data = [bits representationUsingType: NSPNGFileType properties: nil];
[data writeToFile: #"/path-to-your-file/image.png" atomically: NO];
Related
I have an NSImage instance and I'd like to identify the type of image it is (JPG, PNG, GIF, etc.).
Is the original format of the image preserved and possible to retrieve somehow?
EDIT:
Answers in other questions mention using CGImageSource. However, there does not seem to be a way of extracting the original data from the NSImage - only TIFFRepresentation, which will always return the TIFF image type via CGImageSource.
EDIT 2:
I think my suspicions may be true in that NSImage does not maintain the original format of the image. Everything is converted to bitmap representation. Therefore it is not possible to retrieve the original format without keeping track of it yourself. See similar answer from iOS equivalent: Detect whether an UIImage is PNG or JPEG?
Very weird behavior, but I have narrowed the problem down as far as I can go I think
I have a NSImage, let's call it inputImage. It is represented by a NSBitmapImageRep in a CGColorSpaceCreateDeviceGray, if that matters
I want to create a CGImageRef from it, but with inverted colors.
NSData *data = [inputImage TIFFRepresentation];
CGDataProviderRef provider = CGDataProviderCreateWithCFData((__bridge CFDataRef)data);
NSBitmapImageRep *maskedRep = (NSBitmapImageRep*)[inputImage representations][0];
CGFloat decode[] = {0.0, 1.0};
maskRef = CGImageMaskCreate(maskedRep.pixelsWide,
maskedRep.pixelsHigh,
8,
maskedRep.bitsPerPixel,
maskedRep.bytesPerRow,
provider,
decode,
false);
NSImage *testImage = [[NSImage alloc] initWithCGImage:maskRef size:NSMakeSize(1280,1185)]; //the size of the image, hard-coded for testing
NSLog(#"testimage: %#", testImage);
The problem is when I look at testImage, all of the pixels are slightly offset to the right from the original image.
inputImage:
testImage:
It's much easier to see if you save the pictures off, but you'll notice that everything in testImage is offset to the right by about 5 pixels or so. You'll see a white gap to the left of the black content in testImage
Somewhere in my 5 lines of code I am somehow moving my image over. Does anybody have any idea how this could be happening? I'm currently suspecting TIFFRepresentation
The data provider you pass to CGImageMaskCreate() is supposed to be raw pixels in the form specified by the other parameters, not an image file format. You shouldn't be passing TIFF data. Frankly, I'm surprised you got anything remotely resembling your original image, rather than noise/garbage. I'm guessing the TIFF data wasn't compressed, by sheer chance. You can actually see a bit of noise, which is the TIFF header interpreted as pixels, at the upper-left of your mask.
Probably, your best bet is to create a CGImage from your inputImage (or, depending on how inputImage was created, skip NSImage and create the CGImage directly from a file using the CGImageSource API or CGImageCreateWith{JPEG,PNG}DataProvider()). To get a CGImage from an NSImage, use -CGImageForProposedRect:context:hints:.
Then, get the data provider from that CGImage and create the mask CGImage from that, using the various properties (width, height, bpp, etc.) queried from the first CGImage using the various CGImageGet... functions.
How do you write out a 16x16 PNG file for a file type icon in Cocoa? I tried this before with code like the snippet below. The snippet worked on a PPC machine with Mac OS X 10.5, but no longer seems to work on Mac OS X 10.6: the PNG that's written out has size 512x512, rather than 16x16.
NSImage * icon = [[NSWorkspace sharedWorkspace] iconForFileType: NSFileTypeForHFSTypeCode(kGenericFolderIcon)];
[icon setSize: NSMakeSize(16.0,16.0)];
NSBitmapImageRep * bitmapRep = [NSBitmapImageRep imageRepWithData: [icon TIFFRepresentation]];
NSData * data = [bitmapRep representationUsingType: NSPNGFileType properties: nil];
[data writeToFile: #"/tmp/test.png" atomically: NO];
From what I understand from the documentation on NSImage and NSImageRep, the fact that the above code worked before was coincidence, as setSize: only sets the "drawing size" of the image which doesn't necessarily match the "physical size" of its representation(s).
So what is the correct way to get the 16x16 size PNG file? Also, icons on Mac OS X can include a specially-drawn version for the 16x16 size, which is not just a scaled-down version of the "big" icon; how do you make sure this special version is written out to the PNG file when one is available?
Nikolai is right, you should check to see if the image has a 16x16 representation first, but to simply resize an image to 16 x 16 you would do this:
NSImage * icon = [[NSWorkspace sharedWorkspace] iconForFileType: NSFileTypeForHFSTypeCode(kGenericFolderIcon)];
[icon setScalesWhenResized:YES]; //this makes NSImage create a new representation
[icon setSize: NSMakeSize(16.0,16.0)];
If you are sure that there's a 16x16 sized version of the icon present in the NSImage, you could look through the representations (-[NSImage representations]) and select the one you're interested in by looking at the size (-[NSImageRep pixelsWide] and pixelsHigh). You could then write the representation to disk.
A better way would be to create a 16x16 bitmap context, draw the image into that context and then save the contexts contents. This way also works if the original icon does not contain a 16x16 representation.
I have an NSImage from NSImage *myImage = [[NSBitmapImageRep alloc] initWithFocusedViewRect:[outputView bounds]]; and I need to save it to a file. I havent been able to find anything about saving NSImage in any format. Has anyone done this? Is it even possible?
Thanks
The way you say you're making an NSImage doesn't make sense. You show how to create an NSBitmapImageRep, not an NSImage.
Before you save it to a file, you convert to NSData. There is an NSImage method to convert to TIFF data, and there is an NSBitmapImageRep method to convert to data in several formats.
If you're creating a snapshot of an actual view (as opposed to an image that you've locked focus on), then an alternative to creating a bitmap image rep would be to ask the view for PDF data of the desired rectangle. This will be vector rather than raster (except where the view itself draws an image), which will scale more nicely to higher resolutions. You would then write that data to a file the same as you would any other data.
Having an NSBitmapImageRep (as JWWalker pointed out, that code doesn't create an NSImage instance), you can ask the image rep for a CGImage version of itself, and then create a CGImageDestination to write that image to a file. This may be more efficient than obtaining a data object (which will hold the raster data in memory) and provides more options.
I need to save the contents of a pixel editor application into a .png file but I am having trouble finding the best way to accomplish this. The pixel data is stored in a 32 bit RGBA buffer. Can anyone suggest any good tools I could use to accomplish this?
EDIT:
Unfortunately, CGImage and representationUsingType: are not supported by cocotron and I need to be able to target my app for PC release as well, can anyone suggest a third way of accomplishing this task?
NSBitmapImageRep should get you what you need. Load the data up into the NSBitmapImageRep
and then use representationUsingType:properties: to get it out as a PNG. A quick example:
NSBitmapImageRep *imageRep =
[[NSBitmapImageRep alloc] initWithBitmapDataPlanes:imageBuffer
pixelsWide:imageWidth
pixelsHigh:imageHeight
bitsPerSample:8
samplesPerPixel:4
hasAlpha:YES
isPlanar:NO
colorSpaceName:NSDeviceRGBColorSpace
bitmapFormat:NSAlphaFirstBitmapFormat
bytesPerRow:imageWidth * 4
bitsPerPixel:32];
NSData *pngData = [imageRep representationUsingType:NSPNGFileType
properties:propertyDictionary];
If you can't use these Cocoa methods, check out libpng.
Create a CGImage from the pixel data and feed it to a CGImageDestination.
Don't forget to finalize the destination before releasing it. That step is mandatory, and very easy to forget.