Get image width and height before loading it completely in iPhone - iphone

I am loading an image in my UITableViewCell using
[NSData dataWithContentsOfURL:imageUrl]
For setting custom height for my tableview cell , i need the actual size of the image that am loading.
Can we get the width and height of an image before loading it completely ? Thanks in advance.

Try the Image I/O interface as done below. This will allow you to get the image size without having to load the entire file:
#import <ImageIO/ImageIO.h>
NSMutableString *imageURL = [NSMutableString stringWithFormat:#"http://www.myimageurl.com/image.png"];
CGImageSourceRef source = CGImageSourceCreateWithURL((CFURLRef)[NSURL URLWithString:imageURL], NULL);
NSDictionary* imageHeader = (__bridge NSDictionary*) CGImageSourceCopyPropertiesAtIndex(source, 0, NULL);
NSLog(#"Image header %#",imageHeader);
NSLog(#"PixelHeight %#",[imageHeader objectForKey:#"PixelHeight"]);

you can do it like this:
NSData *imageData = [NSData dataWithContentsOfURL:imageUrl];
UIImage *image = [UIImage imageWithData:imageData];
NSLog(#"image height: %f",image.size.height);
NSLog(#"image width: %f",image.size.width);

Take a look at this Question How do I extract the width and height of a PNG from looking at the header in objective c which shares how is it possible to parse image Meta-data.
I have a created OpenSource project Ottran that extracts the image size and type of a remote image by downloading as little as possible, which supports PNG, JPEG , BMP and GIF formats.

NSData is an "opaque" data, so you cannot do much with it before converting it to something more "useful" (e.g., creating an UIImage by means of it -initWithData: method). At that moment you could enquiry the image size, but it would be late for you.
The only approach I see, if you really need knowing the image size before the image is fully downloaded, is implementing a minimal server-side API so that you can ask for the image size before trying to download it.
Anyway, why do you need to know the image size before it is actually downloaded? Could you not set the row height at the moment when it has been downloaded (i.e., from your request delegate method)?

dataWithContentsOfURL is synchronous it will block your UI until its download complete, so please use header content to get resolution, Below is Swift 3.0 code
if let imageSource = CGImageSourceCreateWithURL(url! as CFURL, nil) {
if let imageProperties = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, nil) as Dictionary? {
let pixelWidth = imageProperties[kCGImagePropertyPixelWidth] as! Int
let pixelHeight = imageProperties[kCGImagePropertyPixelHeight] as! Int
print("the image width is: \(pixelWidth)")
print("the image height is: \(pixelHeight)")
}
}

Related

Loaded image in UIImage is pixelated on retina

I parsed the data from a web which also contains jpg image. The problem is that the image looks blurry/pixelated on retina display. Any solution for this? Thanks.
NSData *data = [NSData dataWithContentsOfURL:linkUrl];
UIImage *img = [[UIImage alloc] initWithData:data];
// detailViewController.faces.contentScaleFactor=[UIScreen mainScreen].scale;//Attampt to solve the problem
detailViewController.faces.image=img;
After initializing your image with the data, create a new one from it with the correct scale like this:
img = [UIImage imageWithCGImage:img.CGImage scale:[UIScreen mainScreen].scale orientation:img.imageOrientation];
...but note that the image will now appear half the size on retina displays unless you scale it up, for example by stretching it in an image view.

how to compress image in iphone?

I m taking images from photo library.I have large images of 4-5 mb but i want to compress those images.As i need to store those images in local memory of iphone.for using less memory or for getting less memory warning i need to compress those images.
I don't know how to compress images and videos.So i want to know hot to compress images?
UIImage *image = [info objectForKey:#"UIImagePickerControllerOriginalImage"];
NSData* data = UIImageJPEGRepresentation(image,1.0);
NSLog(#"found an image");
NSString *path = [destinationPath stringByAppendingPathComponent:[NSString stringWithFormat:#"%#.jpeg", name]];
[data writeToFile:path atomically:YES];
This is the code for saving my image. I dont want to store the whole image as its too big. So, I want to compress it to a much smaller size as I'll need to attach multiple images.
Thanks for the reply.
You can choose a lower quality for JPEG encoding
NSData* data = UIImageJPEGRepresentation(image, 0.8);
Something like 0.8 shouldn't be too noticeable, and should really improve file sizes.
On top of this, look into resizing the image before making the JPEG representation, using a method like this:
+ (UIImage *)imageWithImage:(UIImage *)image scaledToSize:(CGSize)newSize {
UIGraphicsBeginImageContext(newSize);
[image drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
Source: The simplest way to resize an UIImage?
UIImageJPEGRepresentation(UIImage,Quality);
1.0 means maximum Quality and 0 means minimum quality.
SO change the quality parameter in below line to reduce file size of the image
NSData* data = UIImageJPEGRepresentation(image,1.0);
NSData *UIImageJPEGRepresentation(UIImage *image, CGFloat compressionQuality);
OR
NSData *image_Data=UIImageJPEGRepresentation(image_Name,compressionQuality);
return image as JPEG. May return nil if image has no CGImageRef or invalid bitmap format. compressionQuality is 0(most) & 1(least).

Adding thumbnail size images to tableview

I have a tableview, and i am loading images to it. I have images which are ranging from 150kb - 2MB. Since this is too much for a tableview to handle (it takes long time to load, and makes the scrolling slow), i thought of using ImageIO framework to create thumbnail images of images.
I found a code that does this, but i can't undestand it.
1.) Can someone please explain me the code
2.) My problem is that, I have a tableview and i need to load thumbnail images to it. So how can i use the following code and display it on my tableview. Can someone show me some sample code or a tutorial that does this ?
heres the code ;
-(void)buildGallery
{
for (NSUInteger i = 0; i < kMaxPictures; i++)
{
NSInteger imgTag = i + 1;
NYXPictureView* v = [[NYXPictureView alloc] initWithFrame:(CGRect){.origin.x = x, .origin.y = y, .size = _thumbSize}];
NSString* imgPath = [[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:#"%d", imgTag] ofType:#"jpg"];
CGImageSourceRef src = CGImageSourceCreateWithURL((CFURLRef)[NSURL fileURLWithPath:imgPath], NULL);
CFDictionaryRef options = (CFDictionaryRef)[[NSDictionary alloc] initWithObjectsAndKeys:(id)kCFBooleanTrue, (id)kCGImageSourceCreateThumbnailWithTransform, (id)kCFBooleanTrue, (id)kCGImageSourceCreateThumbnailFromImageIfAbsent, (id)[NSNumber numberWithDouble:_maxSize], (id)kCGImageSourceThumbnailMaxPixelSize, nil];
CGImageRef thumbnail = CGImageSourceCreateThumbnailAtIndex(src, 0, options); // Create scaled image
CFRelease(options);
CFRelease(src);
UIImage* img = [[UIImage alloc] initWithCGImage:thumbnail];
[v setImage:img];
[img release];
CGImageRelease(thumbnail);
}
}
Basically the problem you have is due to the fact that when you scale down an image, the number of bytes stored in memory doesnt change when you scale it down. The hardware still has to read your 2mb image, and then render it to a smaller scale. What you need to do is to either change the size of your image (use photoshop or other) or the way im suggesting is to compress your image, and then scale it down. The image will look rough at normal size, but will look ok when you scale it down to a thumbview.
To generate an NSData version of your image encoded as a PNG.
NSData *PNGFile = UIImagePNGRepresentation(myImage);
Or a JPEG, with a quality value set
NSData *JPEGFile = UIImageJPEGRepresentation(myImage, 0.9f);
Both of these will give you an image smaller than you currently have, which will be easier to render in the tableView.
In order to get better performance you're going to have to load the image in a background thread, and after it's in memory add the UIImage to the image view on the main thread. There are a couple ways to go about doing this, but the simplest is going to be using GCD's block based methods.
Resizing the image is definitely still important for memory considerations, but get the asynchronous image loading part down first.

How do I map and store images using Core Data and RestKit?

Using images with Core Data isn't a problem. There are a lot of examples out there on how to do that like: How should I store UIImages within my Core Data database?
I want to know how to use RestKit to download images and map them correctly to Core Data. There is a RestKit example on how to upload an image but not downloading and retrieving.
Right now my entities just have an attribute with the url to the image but I want to be able to access the images offline. I was thinking of doing some simple mapping like download an image and rename it to the id of the object it belongs to but before I recreate this wheel I was wondering if someone else knows the most 'correct' way to achieve this.
I use JsonKit and ASIHTTPRequest, but the same principle applies - I use base64 encoding to store the image data as a string. It's a platform and language agnostic approach that fits well with the JSON standard.
Cocoa with Love's Matt Gallagher wrote a very clean category on NSData for base64 encoding and decoding here.
I ended up just requesting the object with the image url and after receiving the object I grab the image for the url set it to the my object's image property. Simple
NSURL *imageURL;
UIImage *selectedImage;
for (Employee *employee in _employees){
imageURL = [NSURL URLWithString:employee.imageURL];
selectedImage = [UIImage imageWithData:[NSData dataWithContentsOfURL:imageURL]];
// Delete any existing image.
NSManagedObject *oldImage = employee.image;
if (oldImage != nil) {
[employee.managedObjectContext deleteObject:oldImage];
}
// Create an image object for the new image.
NSManagedObject *image = [NSEntityDescription insertNewObjectForEntityForName:#"Image" inManagedObjectContext:employee.managedObjectContext];
employee.image = image;
// Set the image for the image managed object.
[image setValue:selectedImage forKey:#"image"];
// Create a thumbnail version of the image for the recipe object.
CGSize size = selectedImage.size;
CGFloat ratio = 0;
if (size.width > size.height) {
ratio = 100.0 / size.width;
} else {
ratio = 100.0 / size.height;
}
CGRect rect = CGRectMake(0.0, 0.0, ratio * size.width, ratio * size.height);
UIGraphicsBeginImageContext(rect.size);
[selectedImage drawInRect:rect];
employee.thumbnailImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
}

Converting UIImage image representation

I am getting an UIImage from UIGraphicsGetImageFromCurrentImageContext, but they are very heavyweight memory wise.
UIGraphicsBeginImageContext([self bounds].size);
// CGContext procedures
_cacheImage = UIGraphicsGetImageFromCurrentImageContext();
the size of the image is almost as the size of the iPad screen, (a little smaller), and when I do something like this:
NSData *data = UIImagePNGRepresentation(_cacheImage)
NSLog(#"%i", data.lenght);
It gives me like 700,000 in lenght. I'm guessing its a .7MB file?
Anyway if there is some way to reduce the image size, please let me know.
If you wish to reduce quality, try using
NSData * UIImageJPEGRepresentation (
UIImage *image,
CGFloat compressionQuality
);
Pass compressionQuality == 0.0 for maximum quality or compressionQuality == 1.0 for maximum compression.