How to fix this error? Xcode 7.2 - xcode

Hi, I’m trying to resize a uipasteboard but I keep getting this error. Is there a way to fix this it?
This is the code I’m using:
- (NSImage *)imageResize:(NSImage*)anImage newSize:(NSSize)newSize {
NSImage *sourceImage = anImage;
[sourceImage setScalesWhenResized:YES];
// Report an error if the source isn't a valid image
if (![sourceImage isValid]){
NSLog(#"Invalid Image");
} else {
NSImage *smallImage = [[NSImage alloc] initWithSize: newSize];
[smallImage lockFocus];
[sourceImage setSize: newSize];
[[NSGraphicsContext currentContext] setImageInterpolation:NSImageInterpolationHigh];
[sourceImage drawAtPoint:NSZeroPoint fromRect:CGRectMake(0, 0, newSize.width, newSize.height) operation:NSCompositeCopy fraction:1.0];
[smallImage unlockFocus];
return smallImage;
}
return nil;
}

Related

Is it possible to re-size a image in a uipasteboard xcode 7.2 Objective C?

I’m currently using this code bellow in Xcode 7.2, which takes the image and pastes it in imessages etc. But it’s too large (in dimensions). Is it possible to make this image smaller?
UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
NSData *imgData = UIImagePNGRepresentation(image);
[pasteboard setData:imgData forPasteboardType:[UIPasteboardTypeListImage objectAtIndex:0]];
Not whilst it's in the pasteboard. BUT, if you're worried about it being the wrong size when you paste it somewhere, FEAR NOT, Apple have been kind to us and have built quite a lot of the presentation "resizing" into things for us.
What you need to do if you really HAVE to resize the image is:
1) Be lazy and use code which you can resume... i.e. I found this on here I believe:
- (NSImage *)imageResize:(NSImage*)anImage newSize:(NSSize)newSize {
NSImage *sourceImage = anImage;
[sourceImage setScalesWhenResized:YES];
// Report an error if the source isn't a valid image
if (![sourceImage isValid]){
NSLog(#"Invalid Image");
} else {
NSImage *smallImage = [[NSImage alloc] initWithSize: newSize];
[smallImage lockFocus];
[sourceImage setSize: newSize];
[[NSGraphicsContext currentContext] setImageInterpolation:NSImageInterpolationHigh];
[sourceImage drawAtPoint:NSZeroPoint fromRect:CGRectMake(0, 0, newSize.width, newSize.height) operation:NSCompositeCopy fraction:1.0];
[smallImage unlockFocus];
return smallImage;
}
return nil;
}
then in the bit of code which you've given us:
*pasteboard = [UIPasteboard generalPasteboard];
NSImage *myShinyResizedImage = [self imageResize: oldImage newSize: CGSizeMake(100.0, 100.0)];
NSData *imgData = UIImagePNGRepresentation(myShinyResizedImage);
[pasteboard setData:imgData forPasteboardType:[UIPasteboardTypeListImage objectAtIndex:0]];
And it's been resized before if goes off to get pasted elsewhere.

How To Save PNG file From NSImage (retina issues) The Right Way?

I am trying to save each image in an array as a .PNG file (also as the right size, without scaling up because of retina mac dpi issues) and can't seem to find a solution. NONE of the solutions at How to save PNG file from NSImage (retina issues) seem to be working for me. I've tried each one and each of them would still save a 72x72 file as 144x144 in retina .etc.
More specifically I am looking for an NSImage category (yes, I am working in the Mac environment)
I am trying to have the user Choose a directory to save them in and execute the saving of the images from array like this:
- (IBAction)saveImages:(id)sender {
// Prepare Images that are checked and put them in an array
[self prepareImages];
if ([preparedImages count] == 0) {
NSLog(#"We have no preparedImages to save!");
NSAlert *alert = [[NSAlert alloc] init];
[alert setAlertStyle:NSInformationalAlertStyle];
[alert setMessageText:NSLocalizedString(#"Error", #"Save Images Error Text")];
[alert setInformativeText:NSLocalizedString(#"You have not selected any images to create.", #"Save Images Error Informative Text")];
[alert beginSheetModalForWindow:self.window
modalDelegate:self
didEndSelector:#selector(testDatabaseConnectionDidEnd:returnCode:
contextInfo:)
contextInfo:nil];
return;
} else {
NSLog(#"We have prepared %lu images.", (unsigned long)[preparedImages count]);
}
// Save Dialog
// Create a File Open Dialog class.
//NSOpenPanel* openDlg = [NSOpenPanel openPanel];
NSSavePanel *panel = [NSSavePanel savePanel];
// Set array of file types
NSArray *fileTypesArray;
fileTypesArray = [NSArray arrayWithObjects:#"jpg", #"gif", #"png", nil];
// Enable options in the dialog.
//[openDlg setCanChooseFiles:YES];
//[openDlg setAllowedFileTypes:fileTypesArray];
//[openDlg setAllowsMultipleSelection:TRUE];
[panel setNameFieldStringValue:#"Images.png"];
[panel setDirectoryURL:directoryPath];
// Display the dialog box. If the OK pressed,
// process the files.
[panel beginWithCompletionHandler:^(NSInteger result) {
if (result == NSFileHandlingPanelOKButton) {
NSLog(#"OK Button!");
// create a file manager and grab the save panel's returned URL
NSFileManager *manager = [NSFileManager defaultManager];
directoryPath = [panel URL];
[[self directoryLabel] setStringValue:[NSString stringWithFormat:#"%#", directoryPath]];
// then copy a previous file to the new location
// copy item at URL was self.myURL
// copy images that are created from array to this path
for (NSImage *image in preparedImages) {
#warning Fix Copy Item At URL to copy image from preparedImages array to save each one
NSString *imageName = image.name;
NSString *imagePath = [[directoryPath absoluteString] stringByAppendingPathComponent:imageName];
//[manager copyItemAtURL:nil toURL:directoryPath error:nil];
NSLog(#"Trying to write IMAGE: %# to URL: %#", imageName, imagePath);
//[image writePNGToURL:[NSURL URLWithString:imagePath] outputSizeInPixels:image.size error:nil];
[self saveImage:image atPath:imagePath];
}
//[manager copyItemAtURL:nil toURL:directoryPath error:nil];
}
}];
[preparedImages removeAllObjects];
return;
}
one user attempted to answer his by using this NSImage category but it does not produce any file or PNG for me.
#interface NSImage (SSWPNGAdditions)
- (BOOL)writePNGToURL:(NSURL*)URL outputSizeInPixels:(NSSize)outputSizePx error:(NSError*__autoreleasing*)error;
#end
#implementation NSImage (SSWPNGAdditions)
- (BOOL)writePNGToURL:(NSURL*)URL outputSizeInPixels:(NSSize)outputSizePx error:(NSError*__autoreleasing*)error
{
BOOL result = YES;
NSImage* scalingImage = [NSImage imageWithSize:[self size] flipped:[self isFlipped] drawingHandler:^BOOL(NSRect dstRect) {
[self drawAtPoint:NSMakePoint(0.0, 0.0) fromRect:dstRect operation:NSCompositeSourceOver fraction:1.0];
return YES;
}];
NSRect proposedRect = NSMakeRect(0.0, 0.0, outputSizePx.width, outputSizePx.height);
CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
CGContextRef cgContext = CGBitmapContextCreate(NULL, proposedRect.size.width, proposedRect.size.height, 8, 4*proposedRect.size.width, colorSpace, kCGImageAlphaPremultipliedLast);
CGColorSpaceRelease(colorSpace);
NSGraphicsContext* context = [NSGraphicsContext graphicsContextWithGraphicsPort:cgContext flipped:NO];
CGContextRelease(cgContext);
CGImageRef cgImage = [scalingImage CGImageForProposedRect:&proposedRect context:context hints:nil];
CGImageDestinationRef destination = CGImageDestinationCreateWithURL((__bridge CFURLRef)(URL), kUTTypePNG, 1, NULL);
CGImageDestinationAddImage(destination, cgImage, nil);
if(!CGImageDestinationFinalize(destination))
{
NSDictionary* details = #{NSLocalizedDescriptionKey:#"Error writing PNG image"};
[details setValue:#"ran out of money" forKey:NSLocalizedDescriptionKey];
*error = [NSError errorWithDomain:#"SSWPNGAdditionsErrorDomain" code:10 userInfo:details];
result = NO;
}
CFRelease(destination);
return result;
}
#end
I had trouble with the answer provided in original thread too. Further reading landed me on a post by Erica Sadun related to debugging code for retina displays without a retina display. She creates a bitmap of the desired size, then replaces the current drawing context (display based/retina influenced) with the generic one associated with the new bitmap. She then renders the original image into the bitmap (using the generic graphics context).
I took her code and made a quick category on NSImage which seems to do the job for me. After calling
NSBitmapImageRep *myRep = [myImage unscaledBitmapImageRep];
you should have a bitmap of the proper (original) dimensions, regardless of the type of physical display you started with. From this point, you can call representationUsingType:properties on the unscaled bitmap to get whatever format you are looking to write out.
Here is my category (header omitted). Note - you may need to expose the colorspace portion of the bitmap initializer. This is the value that works for my particular case.
-(NSBitmapImageRep *)unscaledBitmapImageRep {
NSBitmapImageRep *rep = [[NSBitmapImageRep alloc]
initWithBitmapDataPlanes:NULL
pixelsWide:self.size.width
pixelsHigh:self.size.height
bitsPerSample:8
samplesPerPixel:4
hasAlpha:YES
isPlanar:NO
colorSpaceName:NSDeviceRGBColorSpace
bytesPerRow:0
bitsPerPixel:0];
rep.size = self.size;
[NSGraphicsContext saveGraphicsState];
[NSGraphicsContext setCurrentContext:
[NSGraphicsContext graphicsContextWithBitmapImageRep:rep]];
[self drawAtPoint:NSMakePoint(0, 0)
fromRect:NSZeroRect
operation:NSCompositeSourceOver
fraction:1.0];
[NSGraphicsContext restoreGraphicsState];
return rep;
}
Thank tad & SnowPaddler.
For anyone who is not familiar with Cocoa and using Swift 4, you can view Swift 2 & Swift 3 version from edit history:
import Cocoa
func unscaledBitmapImageRep(forImage image: NSImage) -> NSBitmapImageRep {
guard let rep = NSBitmapImageRep(
bitmapDataPlanes: nil,
pixelsWide: Int(image.size.width),
pixelsHigh: Int(image.size.height),
bitsPerSample: 8,
samplesPerPixel: 4,
hasAlpha: true,
isPlanar: false,
colorSpaceName: .deviceRGB,
bytesPerRow: 0,
bitsPerPixel: 0
) else {
preconditionFailure()
}
NSGraphicsContext.saveGraphicsState()
NSGraphicsContext.current = NSGraphicsContext(bitmapImageRep: rep)
image.draw(at: .zero, from: .zero, operation: .sourceOver, fraction: 1.0)
NSGraphicsContext.restoreGraphicsState()
return rep
}
func writeImage(
image: NSImage,
usingType type: NSBitmapImageRep.FileType,
withSizeInPixels size: NSSize?,
to url: URL) throws {
if let size = size {
image.size = size
}
let rep = unscaledBitmapImageRep(forImage: image)
guard let data = rep.representation(using: type, properties: [.compressionFactor: 1.0]) else {
preconditionFailure()
}
try data.write(to: url)
}
Tad - thank you very much for this code - I agonised over this for days! It helped me write a file from a NSImage whilst keeping the resolution to 72DPI despite the retina display installed on my Mac. For the benefit of others that want to save a NSImage to a file with a specific pixel size and type (PNG, JPG etc) with a resolution of 72 DPI, here is the code that worked for me. I found that you need to set the size of your image before calling unscaledBitmapImageRep for this to work.
-(void)saveImage:(NSImage *)image
AsImageType:(NSBitmapImageFileType)imageType
forSize:(NSSize)targetSize
atPath:(NSString *)path
{
image.size = targetSize;
NSBitmapImageRep * rep = [image unscaledBitmapImageRep:targetSize];
// Write the target image out to a file
NSDictionary *imageProps = [NSDictionary dictionaryWithObject:[NSNumber numberWithFloat:1.0] forKey:NSImageCompressionFactor];
NSData *targetData = [rep representationUsingType:imageType properties:imageProps];
[targetData writeToFile:path atomically: NO];
return;
}
I have also included the source code for the category header and .m file below.
The NSImage+Scaling.h file:
#import <Cocoa/Cocoa.h>
#import <QuartzCore/QuartzCore.h>
#interface NSImage (Scaling)
-(NSBitmapImageRep *)unscaledBitmapImageRep;
#end
And the NSImage+Scaling.m file:
#import "NSImage+Scaling.h"
#pragma mark - NSImage_Scaling
#implementation NSImage (Scaling)
-(NSBitmapImageRep *)unscaledBitmapImageRep
{
NSBitmapImageRep *rep = [[NSBitmapImageRep alloc]
initWithBitmapDataPlanes:NULL
pixelsWide:self.size.width
pixelsHigh:self.size.height
bitsPerSample:8
samplesPerPixel:4
hasAlpha:YES
isPlanar:NO
colorSpaceName:NSDeviceRGBColorSpace
bytesPerRow:0
bitsPerPixel:0];
[NSGraphicsContext saveGraphicsState];
[NSGraphicsContext setCurrentContext:
[NSGraphicsContext graphicsContextWithBitmapImageRep:rep]];
[self drawAtPoint:NSMakePoint(0, 0)
fromRect:NSZeroRect
operation:NSCompositeSourceOver
fraction:1.0];
[NSGraphicsContext restoreGraphicsState];
return rep;
}
#end
I had the same difficulties with saving an NSImage object to a PNG or JPG file, and I finally understood why...
Firstly, the code excerpt shown above works well:
import Cocoa
func unscaledBitmapImageRep(forImage image: NSImage) -> NSBitmapImageRep {
guard let rep = NSBitmapImageRep(
bitmapDataPlanes: nil,
pixelsWide: Int(image.size.width),
pixelsHigh: Int(image.size.height),
bitsPerSample: 8,
samplesPerPixel: 4,
hasAlpha: true,
isPlanar: false,
colorSpaceName: .deviceRGB,
bytesPerRow: 0,
bitsPerPixel: 0
) else {
preconditionFailure()
}
NSGraphicsContext.saveGraphicsState()
NSGraphicsContext.current = NSGraphicsContext(bitmapImageRep: rep)
image.draw(at: .zero, from: .zero, operation: .sourceOver, fraction: 1.0)
NSGraphicsContext.restoreGraphicsState()
return rep
}
func writeImage(
image: NSImage,
usingType type: NSBitmapImageRep.FileType,
withSizeInPixels size: NSSize?,
to url: URL) throws {
if let size = size {
image.size = size
}
let rep = unscaledBitmapImageRep(forImage: image)
guard let data = rep.representation(using: type, properties:[.compressionFactor: 1.0]) else {
preconditionFailure()
}
try data.write(to: url)
}
...However, since I am working with a Mac App that is Sandboxed, which as you know is a requirement for Apple App Store distribution, I noticed that I had to choose my destination directory with care as I was testing my preliminary code.
If I used a file URL by way of:
let fileManager = FileManager.default
let documentsURL = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first!
let documentPath = documentsURL.path
let filePath = documentsURL.appendingPathComponent("TestImage.png")
filePath = file:///Users/Andrew/Library/Containers/Objects-and-Such.ColourSpace/Data/Documents/TestImage.png
...which works for sandboxed Apps, file saving won't work if I had chosen a directory such as Desktop:
filePath = file:///Users/Andrew/Library/Containers/Objects-and-Such.ColourSpace/Data/Desktop/TestImage.png
I hope this helps.

Merging 2 images in Cocoa on Retina Macs

I'm trying to merge two images to a background image. This works fine on non-Retina Macs.
The resulting image has the size of my original background image. But on a MacBook Pro Retina the resulting image is doubled. I read that one should use imageWithSize for solving that issue cause since 10.8 / Retina support images aren't measured in pixels anymore; as we know it's points.
I've no clue how I should change my code to solve this.
What i have so far:
NSSize size = background.size ;
GLsizei width = (GLsizei)size.width;
GLsizei height = (GLsizei)size.height;
NSBitmapImageRep* imgRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL pixelsWide:width pixelsHigh:height bitsPerSample:8 samplesPerPixel:3 hasAlpha:NO isPlanar:NO colorSpaceName:NSDeviceRGBColorSpace bytesPerRow:width*3 bitsPerPixel:0];
#ifdef __MAC_10_8
NSImage* backgroundWrapper = [NSImage imageWithSize:size flipped:YES drawingHandler:^(NSRect dstRect){ return [imgRep drawInRect:dstRect]; }];
NSPoint backgroundPoint;
backgroundPoint.x = 0;
backgroundPoint.y = 0;
[backgroundWrapper lockFocusFlipped:YES];
[background drawAtPoint:backgroundPoint fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0];
[firstImage firstImage fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0];
[backgroundWrapper unlockFocus];
NSBitmapImageRep *bmpImageRep = [[NSBitmapImageRep alloc]initWithData:[backgroundWrapper TIFFRepresentation]];
[backgroundWrapper addRepresentation:bmpImageRep];
#else
[background lockFocusFlipped:YES];
[firstImage drawAtPoint:firstImagePoint fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0];
[background unlockFocus];
NSBitmapImageRep *bmpImageRep = [[NSBitmapImageRep alloc]initWithData:[background TIFFRepresentation]];
[background addRepresentation:bmpImageRep];
#endif
NSData *data = [bmpImageRep representationUsingType: NSPNGFileType properties: nil];
How can I get this to work on a Retina display?
edit
I also tried this:
- (NSImage )drawImage:(NSImage)background with:(NSImage*)firstImage {
return [NSImage imageWithSize:NSMakeSize(3200, 2000) flipped:NO drawingHandler:^BOOL(NSRect dstRect) {
NSPoint backgroundPoint; backgroundPoint.x = 0;
backgroundPoint.y = 0;
[background drawAtPoint:backgroundPoint fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0];
[firstImage drawAtPoint:backgroundPoint fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0];
return true;
}];
}
But the resulting image is 6400x4000px

Is it possible to print IKImageBrowserView In Cocoa programmatically?

I want to take print of IKImageBrowserView with (content) images. I tried the following code
if (code == NSOKButton) {
NSPrintInfo *printInfo;
NSPrintInfo *sharedInfo;
NSPrintOperation *printOp;
NSMutableDictionary *printInfoDict;
NSMutableDictionary *sharedDict;
sharedInfo = [NSPrintInfo sharedPrintInfo];
sharedDict = [sharedInfo dictionary];
printInfoDict = [NSMutableDictionary dictionaryWithDictionary: sharedDict];
[printInfoDict setObject:NSPrintSaveJob
forKey:NSPrintJobDisposition];
[printInfoDict setObject:[sheet filename] forKey:NSPrintSavePath];
printInfo = [[NSPrintInfo alloc] initWithDictionary:printInfoDict];
[printInfo setHorizontalPagination: NSAutoPagination];
[printInfo setVerticalPagination: NSAutoPagination];
[printInfo setVerticallyCentered:NO];
printOp = [NSPrintOperation printOperationWithView:imageBrowser
printInfo:printInfo];
[printOp setShowsProgressPanel:NO];
[printOp runOperation];
}
because IKImageBrowserView is Inherits from NSView but print preview is showing null image. Please help me to over come this problem. Thanks in advance.....
/*
1) allocate a c buffer at the size of the visible rect of the image
browser
*/
NSRect vRect = [imageBrowser visibleRect];
NSSize size = vRect.size;
NSLog(#"Size W = %f and H = %f", size.width, size.height);
void *buffer = malloc(size.width * size.height * 4);
//2) read the pixels using openGL
[imageBrowser lockFocus];
glReadPixels(0,
0,
size.width,
size.height,
GL_RGBA,
GL_UNSIGNED_BYTE,
buffer);
[imageBrowser unlockFocus];
//3) create a bitmap with those pixels
unsigned char *planes[2];
planes[0] = (unsigned char *) (buffer);
NSBitmapImageRep *imageRep = [[NSBitmapImageRep alloc]
initWithBitmapDataPlanes:planes pixelsWide:size.width
pixelsHigh:size.height bitsPerSample:8 samplesPerPixel:4 hasAlpha:YES
isPlanar:NO colorSpaceName:NSDeviceRGBColorSpace bitmapFormat:0
bytesPerRow:size.width*4 bitsPerPixel:32];
/*
4) create a temporary image with this bitmap and set it flipped
(because openGL and the AppKit don't have the same pixels coordinate
system)
*/
NSImage *img = [[NSImage alloc] initWithSize:size];
[img addRepresentation:imageRep];
[img setFlipped:YES];
[imageRep release];
/*
5) draw this temporary image into another image so that we get an
image without any reference to our "buffer" buffer so that we can
release it after that
*/
NSImage *finalImage = [[NSImage alloc] initWithSize:size];
[finalImage lockFocus];
[img drawAtPoint:NSZeroPoint
fromRect:NSMakeRect(0,0,size.width,size.height)
operation:NSCompositeCopy fraction:1.0];
[finalImage unlockFocus];
//[NSString stringWithFormat:#"/tmp/%#.tiff", marker]
NSData *imageData = [finalImage TIFFRepresentation];
NSString *writeToFileName = [NSString stringWithFormat:#"/Users/Desktop/%#.png", [NSDate date]];
[imageData writeToFile:writeToFileName atomically:NO];
//6) release intermediate objects
[img release];
free(buffer);
After this I send imageData for print, which works great for me.

NSImage transparency

I'm trying to set a custom drag icon for use in an NSTableView. Everything seems to work but I've run into a problem due to my inexperience with Quartz.
- (NSImage *)dragImageForRowsWithIndexes:(NSIndexSet *)dragRows tableColumns:(NSArray *)tableColumns event:(NSEvent *)dragEvent offset:(NSPointPointer)dragImageOffset
{
NSImage *dragImage = [NSImage imageNamed:#"icon.png"];
NSString *count = [NSString stringWithFormat:#"%d", [dragRows count]];
[dragImage lockFocus];
[dragImage compositeToPoint:NSZeroPoint fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:0.5];
[count drawAtPoint:NSZeroPoint withAttributes:nil];
[dragImage unlockFocus];
return dragImage;
}
Essentially what I'm looking to do is render my icon.png file with 50% opacity along with an NSString which shows the number of rows currently being dragged. The issue I'm seeing is that my NSString renders with a low opacity, but not my icon.
The issue is that you’re drawing your icon on top of itself. What you probably want is something like this:
- (NSImage *)dragImageForRowsWithIndexes:(NSIndexSet *)dragRows tableColumns:(NSArray *)tableColumns event:(NSEvent *)dragEvent offset:(NSPointPointer)dragImageOffset
{
NSImage *icon = [NSImage imageNamed:#"icon.png"];
NSString *count = [NSString stringWithFormat:#"%lu", [dragRows count]];
NSImage *dragImage = [[[NSImage alloc] initWithSize:[icon size]] autorelease];
[dragImage lockFocus];
[icon drawAtPoint:NSZeroPoint fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:0.5];
[count drawAtPoint:NSZeroPoint withAttributes:nil];
[dragImage unlockFocus];
return dragImage;
}

Resources