I have an image view and it pulls url from the internet this is the url that I got from the RSS Feed -
its an image pulled from rss feed .xml here is code I use to get image.
- (void)viewDidLoad {
[super viewDidLoad];
NSURL *URL = [NSURL URLWithString:#"www.something.com/rss/hi.xml"];
NSData *data = [NSData dataWithContentsOfURL:URL];
// Assuming data is in UTF8.
NSString *string = [NSString stringWithUTF8String:[data bytes]];
NSString *webStringz = string;
NSString *mastaString;
mastaString = webStringz;
NSScanner *theScanner2;
NSString *imageURL2;
theScanner2 = [NSScanner scannerWithString: mastaString];
// find start of tag
[theScanner2 scanUpToString: #"<media:content url=\"" intoString: nil];
if ([theScanner2 isAtEnd] == NO) {
// find end of tag
[theScanner2 scanUpToString: #"\" " intoString: &imageURL2];
imageURL2 = [imageURL2 stringByReplacingOccurrencesOfString:#"<media:content url=\"" withString:#""];
imageURL2 = [imageURL2 stringByReplacingOccurrencesOfString:#"\n" withString:#""];
imageURL2 = [imageURL2 stringByReplacingOccurrencesOfString:#" " withString:#""];
//Download Image
NSURL * imageURL = [NSURL URLWithString:[imageURL2 stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
NSData *imageData = [NSData dataWithData:UIImagePNGRepresentation([UIImage imageWithData:[NSData dataWithContentsOfURL:imageURL]])];
UIImage * image = [UIImage imageWithData:imageData];
[imageView setImage:image];
NSLog(#"Image URL #1: %#", imageURL2);
mastaString = [mastaString stringByReplacingOccurrencesOfString:imageURL2 withString:#""];
if (imageView.image == nil) {
NSLog(#"IS NIL");
}
else if (image == nil) {
NSLog(#"IS NIL");
}
// Do any additional setup after loading the view.
}
}
In my NSLOG it says the image url and its valid.
It DOES NOT show the IS NIL
It DOES NOT show the IS NIL 2
But the ImageView is not showing the image? Why? Its all linked up and everything?
Thanks
It must be that you didn't create the image view when the first time you access the view of UIViewController. Note that self.view will trigger viewDidLoad method if it is nil, but then the imageView is nil. So you'b better create the imageView in viewDidLoad method.
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.
What I have
For my game I'm creating several animations using view.animationImages = imagesArray; [view startAnimating];
In my animation helper class I use this
- (UIImage *)loadRetinaImageIfAvailable:(NSString *)path
{
NSString *retinaPath = [[path stringByDeletingLastPathComponent] stringByAppendingPathComponent:[NSString stringWithFormat:#"%##2x.%#", [[path lastPathComponent] stringByDeletingPathExtension], [path pathExtension]]];
if ([UIScreen mainScreen].scale == 2.0 && [[NSFileManager defaultManager] fileExistsAtPath:retinaPath] == YES)
return [[UIImage alloc] initWithCGImage:[[UIImage imageWithData:[NSData dataWithContentsOfFile:retinaPath]] CGImage] scale:2.0 orientation:UIImageOrientationUp];
else
return [UIImage imageWithContentsOfFile:path];
}
- (NSMutableArray *)generateCachedImageArrayWithFilename:(NSString *)filename extension:(NSString *)extension andImageCount:(int)count
{
_imagesArray = [[NSMutableArray alloc] init];
_fileExtension = extension;
_imageName = filename;
_imageCount = count;
for (int i = 0; i < count; i++)
{
NSString *tempImageNames = [NSString stringWithFormat:#"%#%i", filename, i];
NSString *imagePath = [[NSBundle mainBundle] pathForResource:tempImageNames ofType:extension];
UIImage *frameImage = [self loadRetinaImageIfAvailable:imagePath];
UIGraphicsBeginImageContext(frameImage.size);
CGRect rect = CGRectMake(0, 0, frameImage.size.width, frameImage.size.height);
[frameImage drawInRect:rect];
UIImage *renderedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[_imagesArray addObject:renderedImage];
if (_isDoublingFrames)
{
[_imagesArray addObject:renderedImage];
}
else if (_isTriplingFrames)
{
[_imagesArray addObject:renderedImage];
[_imagesArray addObject:renderedImage];
}
NSLog(#"filename = %#", filename);
}
return _imagesArray;
}
Problem and facts
Without caching images I got retina versions of images byt my animations are not fluent
If I cache images this way, animations are ok, but uses non-retina versions of images
Please is there some other way to cache and get retina versions?
Are these images located in your application bundle? If so this logic is all unnecessary because the imageWithContentsOfFile: method will already detect and load the #2x image on a retina device.
Also, you'd be better off using the [UIImage imageNamed:] method instead because this automatically caches the image for re-use, and decompresses it immediately, avoiding the need for manually caching the images, or for that trickery with drawing it into an offscreen CGContext.
I'm new to cocoa and programming, sorry if this is something basic.
I'm using ARC. I have an NSImageView component, which is controlled by DropZone class. I drag & drop an image into it, but once I try to call in the scalling method I got, it tells me that the ": ImageIO: CGImageSourceCreateWithData data parameter is nil" I assume I'm doing something wrong, just don't know what yet.
Here's my method in DropZone.m
- (void)scaleIcons:(NSString *)outputPath{
NSImage *anImage;
NSSize imageSize;
NSString *finalPath;
anImage = [[NSImage alloc]init];
anImage = image;
imageSize = [anImage size];
imageSize.width = 512;
imageSize.height = 512;
[anImage setSize:imageSize];
finalPath = [outputPath stringByAppendingString:#"/icon_512x512.png"];
NSData *imageData = [anImage TIFFRepresentation];
NSBitmapImageRep *rep = [NSBitmapImageRep imageRepWithData:imageData];
NSData *dataToWrite = [rep representationUsingType:NSPNGFileType properties:nil];
[dataToWrite writeToFile:finalPath atomically:NO];
}
The DropZone.h
#interface DropZone : NSImageView <NSDraggingDestination>{
NSImage *image;
}
- (void)scaleIcons:(NSString *)outputPath;
#end
And here's how I call it it my AppDelegate.m
- (IBAction)createIconButtonClicked:(id)sender {
NSFileManager *filemgr;
NSString *tempDir;
filemgr = [NSFileManager defaultManager];
tempDir = [pathString stringByAppendingString:#"/icon.iconset"];
NSURL *newDir = [NSURL fileURLWithPath:tempDir];
[filemgr createDirectoryAtURL: newDir withIntermediateDirectories:YES attributes: nil error:nil];
DropZone *myZone = [[DropZone alloc] init];
[myZone scaleIcons:tempDir];
NSAlert *alert = [[NSAlert alloc] init];
[alert setMessageText:#"Done!"];
[alert runModal];
}
the image get's pulled from the pastebaord:
- (BOOL)performDragOperation:(id<NSDraggingInfo>)sender{
if ([NSImage canInitWithPasteboard:[sender draggingPasteboard]]) {
image = [[NSImage alloc]initWithPasteboard:[sender draggingPasteboard]];
[self setImage:image];
[self setImageAlignment: NSImageAlignCenter];
}
return YES;
}
For some reason my "image" gets lost. Could somebody help?
The problem is that you're creating a new instance of DropZone in your app delegate, but I'm assuming that you created the image view in IB and changed its class to DropZone. Is that correct? If so, you need to have an IBOutlet in the app delegate connected to the image view in IB, and have this:
[self.iv scaleIcons:tempDir];
where iv is my IBOutlet.
Without knowing where "image" comes from, I would say your problem is in these lines...
anImage = [[NSImage alloc]init];
anImage = image;
You should just grab the image from the imageView...
anImage = [myImageView image];
So, the code to copy part of my screen to the pasteboard works because it was successfully coping it to my photo album. But, I want to be able to paste the partial screenshot into a new SMS message. I know it will have to be done manually (long hold on message and Paste), but it either pasted nothing, or does not have the Paste option (as it's saving it as a String). The middle portion of the code is the part I'm struggling with. Any help would be great. I've changed the forPasteboardType to "image" but that does not work either.
//Capture part of Screen Shot
UIGraphicsBeginImageContext(self.view.bounds.size);
CGContextRef c = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(c, 0, 98); //
[self.view.layer renderInContext:c];
UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
//Send Screenshot to Pasteboard
UIPasteboard *pasteBoard = [UIPasteboard pasteboardWithName:UIPasteboardNameGeneral create:YES];
pasteBoard.persistent = YES;
NSData *data = UIImagePNGRepresentation(viewImage);
[pasteBoard setData:data forPasteboardType:(NSString *)kUTTypePNG];
/////// Open SMS
MFMessageComposeViewController *controller = [[[MFMessageComposeViewController alloc] init] autorelease];
if([MFMessageComposeViewController canSendText])
{
controller.body = #"Hello from me, paste image here -->";
controller.recipients = [NSArray arrayWithObjects:#"123456789", nil];
controller.messageComposeDelegate = self;
[self presentModalViewController:controller animated:YES];
}
////// End SMS
}
//Capture part of Screen Shot
UIGraphicsBeginImageContext(self.view.bounds.size);
CGContextRef c = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(c, 0, 98); //
[self.view.layer renderInContext:c];
UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
//Send Screenshot to Pasteboard
UIPasteboard *pasteBoard = [UIPasteboard pasteboardWithName:UIPasteboardNameGeneral create:YES];
pasteBoard.persistent = YES;
NSData *data = UIImagePNGRepresentation(viewImage);
[pasteBoard setData:data forPasteboardType:(NSString *)kUTTypePNG];
NSString *stringURL = #"sms:";
NSURL *url = [NSURL URLWithString:stringURL];
[[UIApplication sharedApplication] openURL:url];