Draw NSBitmapImageRep in NSImageView - cocoa

How can I draw a NSBitmapImageRep in a NSImageView?

NSImage *im = [[[NSImage alloc] init] autorelease];
[im addRepresentation:bitmapRep];
[imageView setImage:im];

Pretty easy:
NSImage *image = [[NSImage alloc] initWithCGImage:[bitmapRep CGImage] size:NSMakeSize(width,height)];
Then:
[imageView setImage:image];
Another possibility is by turning it into a TIFF ( - (NSData *)TIFFRepresentation ) and using that to create the NSImage object, but that could create quite some overhead.
Also keep in mind that the method of NSBitmapImageRep - (CGImageRef)CGImage is 10.5 or higher.
Edit:
For a cleaner solution look at #Ken's answer.

Related

NSImage and PDFImageRep caching still draws at only one resolution

I have an NSImage, initialized with PDF data, created like this:
NSData* data = [view dataWithPDFInsideRect:view.bounds];
slideImage = [[NSImage alloc] initWithData:data];
The slideImage is now the size of the view.
When I try to render the image in an NSImageView, it only draws sharp when the image view is exactly the original size of the image, even if you clear the cache or change the image size. I tried setting the cacheMode to NSImageCacheNever, which also didn't work. The only image rep in the image is the PDF one, and when I render it to a PDF file it shows that it's vector.
As a workaround, I create a NSBitmapImageRep with a different size, call drawInRect on the original image, and put the bitmap representation inside a new NSImage and render that, which works, but it feels like it's not optimal:
- (NSBitmapImageRep*)drawToBitmapOfWidth:(NSInteger)width
andHeight:(NSInteger)height
withScale:(CGFloat)scale
{
NSBitmapImageRep *bmpImageRep = [[NSBitmapImageRep alloc]
initWithBitmapDataPlanes:NULL
pixelsWide:width * scale
pixelsHigh:height * scale
bitsPerSample:8
samplesPerPixel:4
hasAlpha:YES
isPlanar:NO
colorSpaceName:NSCalibratedRGBColorSpace
bitmapFormat:NSAlphaFirstBitmapFormat
bytesPerRow:0
bitsPerPixel:0
];
bmpImageRep = [bmpImageRep bitmapImageRepByRetaggingWithColorSpace:
[NSColorSpace sRGBColorSpace]];
[bmpImageRep setSize:NSMakeSize(width, height)];
NSGraphicsContext *bitmapContext = [NSGraphicsContext graphicsContextWithBitmapImageRep:bmpImageRep];
[NSGraphicsContext saveGraphicsState];
[NSGraphicsContext setCurrentContext:bitmapContext];
[self drawInRect:NSMakeRect(0, 0, width, height) fromRect:NSZeroRect operation:NSCompositeCopy fraction:1];
[NSGraphicsContext restoreGraphicsState];
return bmpImageRep;
}
- (NSImage*)rasterizedImageForSize:(NSSize)size
{
NSImage* newImage = [[NSImage alloc] initWithSize:size];
NSBitmapImageRep* rep = [self drawToBitmapOfWidth:size.width andHeight:size.height withScale:1];
[newImage addRepresentation:rep];
return newImage;
}
How can I get the PDF to render nicely at any size without resorting to hacks like mine?
The point of NSImage is that you create it with the size (in points) that you want it to be. The backing representation can be vector based (e.g. PDF), and the NSImage is resolution independent (i.e. it supports different pixels per point), but the NSImage still has a fixed size (in points).
One one the points of an NSImage is that it will / can add a cache representation to speed up subsequent drawing.
If you need to draw a PDF to multiple sizes, and you want to use an NSImage, you're probably best of creating an NSImage for your given target size. If you want to, you can keep the NSPDFImageRef around -- I don't think it'll save you much.
We tried the following:
NSPDFImageRep* rep = self.representations.lastObject;
return [NSImage imageWithSize:size flipped:NO drawingHandler:^BOOL (NSRect dstRect)
{
[[NSGraphicsContext currentContext] setImageInterpolation:NSImageInterpolationHigh];
[rep drawInRect:dstRect fromRect:NSZeroRect operation:NSCompositeCopy fraction:1 respectFlipped:YES hints:#{
NSImageHintInterpolation: #(NSImageInterpolationHigh)
}];
return YES;
}];
And that does give you nice results when scaling up, but makes for blurry images
when scaling down.

UIImage scale and tile

Is it possible to show a UIImage in a UIImageView such that the image is both, scaled and tiled?
for example, it should be scaled at 2 times it's actual resolution, but tiled across the full size of the UIImageView.
Is this doable?
This should work :
UIImage *image = [UIImage imageNamed:#"tile"];
UIImage *newImage = [UIImage imageWithCGImage:[image CGImage] scale:0.5 orientation:image.imageOrientation];
[self.myImageView setBackgroundColor:[UIColor colorWithPatternImage:newImage]];

Trying to get color value of pixel

I'm trying to read the color value of a pixel in a tif image but I can't fihure out the correct way to do it. I'm using OSX and my approach is as follows:
NSImage *picture = [[NSImage alloc] initWithContentsOfFile:#"bais2.tif"]; //file is located in resoureces folder.
NSBitmapImageRep *imageRep = [[picture representations] objectAtIndex:0];
NSColor* color = [imageRep colorAtX:10 y:10];
NSLog(#"%f %f, %f", [color redComponent], [color blueComponent], [color greenComponent]);
The problem is that for some reason the logged values in NSLog always becomes 0.0000000....
I have also tried to use:
NSBitmapImageRep* imageRep = [[NSBitmapImageRep alloc] initWithData:[picture TIFFRepresentation]];
instead of [[picture representations] objectAtIndex:0] but the result is the same.
I get no error messages or warnings, but I think there is something wrong when i load the picture?
Please help me, what am i doing wrong? And is there a better way to read pixel color data?
Your error is here:
NSImage *picture = [[NSImage alloc] initWithContentsOfFile:#"bais2.tif"];
-------------------------------------------------------------------^^^^
You can use:
NSImage *picture= [NSImage imageNamed:#"bais2.tiff"];
Or :
NSImage *picture = [[NSImage alloc] initWithContentsOfFile:#"bais2.tiff"];
NSData *someNSData = [Image TIFFRepresentation];
NSBitmapImageRep *someNSBitmapImageRepData = [[NSBitmapImageRep alloc] initWithData:someNSData];
NSSize imageSizee = [someNSBitmapImageRepData size];
CGFloat y = imageSize.height - 100.0;
NSColor* color = [someNSBitmapImageRepData colorAtX:100.0 y:y];
NSLog(#"color = %#",color);
output : color = NSCalibratedRGBColorSpace 1 1 1 1

NSBitmapImageRep generated BMP can't be read on Windows

I have an NSBitmapImageRep that I am creating the following way:
+ (NSBitmapImageRep *)bitmapRepOfImage:(NSURL *)imageURL {
CIImage *anImage = [CIImage imageWithContentsOfURL:imageURL];
CGRect outputExtent = [anImage extent];
NSBitmapImageRep *theBitMapToBeSaved = [[NSBitmapImageRep alloc]
initWithBitmapDataPlanes:NULL pixelsWide:outputExtent.size.width
pixelsHigh:outputExtent.size.height bitsPerSample:8 samplesPerPixel:4
hasAlpha:YES isPlanar:NO colorSpaceName:NSDeviceRGBColorSpace
bytesPerRow:0 bitsPerPixel:0];
NSGraphicsContext *nsContext = [NSGraphicsContext graphicsContextWithBitmapImageRep:theBitMapToBeSaved];
[NSGraphicsContext saveGraphicsState];
[NSGraphicsContext setCurrentContext: nsContext];
CGPoint p = CGPointMake(0.0, 0.0);
[[nsContext CIContext] drawImage:anImage atPoint:p fromRect:outputExtent];
[NSGraphicsContext restoreGraphicsState];
return [[theBitMapToBeSaved retain] autorelease];
}
And being saved as BMP this way:
NSBitmapImageRep *original = [imageTools bitmapRepOfImage:fileURL];
NSData *converted = [original representationUsingType:NSBMPFileType properties:nil];
[converted writeToFile:filePath atomically:YES];
The thing here is that the BMP file can be read and manipulated correctly under Mac OSX, but under Windows, it just fails to load, just like in this screenshot:
screenshot http://dl.dropbox.com/u/1661304/Grab/74a6dadb770654213cdd9290f0131880.png
If the file is opened with MS Paint (yes, MS Paint can open it) and then resaved, though, it will work.
Would appreciate a hand here. :)
Thanks in advance.
I think the main reason your code is failing is that you are creating your NSBitmapImageRep with 0 bits per pixel. That means your image rep will have precisely zero information in it. You almost certainly want 32 bits per pixel.
However, your code is an unbelievably convoluted way to obtain an NSBitmapImageRep from an image file on disk. Why on earth are you using a CIImage? That is a Core Image object designed for use with Core Image filters and makes no sense here at all. You should be using an NSImage or CGImageRef.
Your method is also poorly named. It should instead be named something like +bitmapRepForImageFileAtURL: to better indicate what it is doing.
Also, this code makes no sense:
[[theBitMapToBeSaved retain] autorelease]
Calling retain and then autorelease does nothing, because all it does in increment the retain count and then decrement it again immediately.
You are responsible for releasing theBitMapToBeSaved because you created it using alloc. Since it is being returned, you should call autorelease on it. Your additional retain call just causes a leak for no reason.
Try this:
+ (NSBitmapImageRep*)bitmapRepForImageFileAtURL:(NSURL*)imageURL
{
NSImage* image = [[[NSImage alloc] initWithContentsOfURL:imageURL] autorelease];
return [NSBitmapImageRep imageRepWithData:[image TIFFRepresentation]];
}
+ (NSData*)BMPDataForImageFileAtURL:(NSURL*)imageURL
{
NSBitmapImageRep* bitmap = [self bitmapRepForImageFileAtURL:imageURL];
return [bitmap representationUsingType:NSBMPFileType properties:nil];
}
You really need to review the Cocoa Drawing Guide and the Memory Management Guidelines, because it appears that you are having trouble with some basic concepts.

image scaling performance in Quartz/Cocoa vs Qt4

I wrote a test application in Qt4 which uses QImage.scaled() or QPixmap.scaled() methods that turned to be very slow. Even a perspective transform is faster, while a scaling transform is the same slow.
[I tried to scale directly a QPainter but I do not master paintEvent() so I always get "painter not active" or paintEvent() is not called at all. So I do not know the painter scaling performaces.]
I ask here if the same issue is known for Quartz/Cocoa or instead their performances for similar tasks are better. I am particularly interested in native Quartz pdf rendering capability and subsequent image scaling.
NIRTimer *timer = [NIRTimer timer];
[timer start];
NSImage *image = [[NSImage alloc]initWithContentsOfFile:#"filename"];
NSImage *scaledImage = [[NSImage alloc]initWithSize:NSMakeSize(720, 480)];
[scaledImage lockFocus];
[image drawInRect:NSMakeRect(0, 0, 720, 480) fromRect:NSZeroRect operation:NSCompositeSourceAtop fraction:1];
[scaledImage unlockFocus];
[image release];
[scaledImage release];
NSLog(#"time: %ld", [timer microseconds]);
This is how to scale an image in Cocoa, and it takes 80000 microseconds (0.08 seconds).

Resources