I am trying to figure out how I can shrink and save a UIImage, read it back in later, and then convert back to the original size without losing quality. I have managed to do the resizing and saving, but the problem is that if I save it smaller, when I read it back in and expand it, the quality is very poor. Does anyone know how this can be done without losing image quality?
You can't downsize the image and then bring it back without losing quality. You can't make something out of nothing, once you lose the data you lose the data.
You will need to save two versions of the image, one large and one small. This is a very typical scenario when dealing with thumbnails.
Check out the following site which provides categories for resizing images as well as several other really cool stuff:
http://vocaro.com/trevor/blog/2009/10/12/resize-a-uiimage-the-right-way/
Although you cannot upsize a downsized image, you can display a downsized one while retaining a reference to the original image (which you can save):
UIImage *image = [UIImage imageNamed:#"myImage"];
[image drawInRect: destinationRect];
UIImage *thumbnail = UIGraphicsGetImageFromCurrentImageContext();
UIImageWriteToSavedPhotosAlbum(image,nil,nil,nil);
The destinationRect will be sized according to the dimensions of the downsized version.
Related
My app takes screenshot of entire web pages. When it saves to Photo Album, the image quality suffers a bit and text on still image is blurry and hard to read. I found this solution which promises to have a better quality when saving to Photo Album, but it still appears to not be perfectly acceptable. Is there a better way than this to save UIImage to Photo Album with very minimal quality loss? Thanks.
UIImage* img = [UIImage imageWithCGImage:screenshotImage.CGImage];
NSData* imdata = UIImagePNGRepresentation ( img );
UIImage* image = [UIImage imageWithData:imdata]; // wrap UIImage around PNG representation
UIImageWriteToSavedPhotosAlbum(image, self, #selector(image:didFinishSavingWithError:contextInfo:), nil);
In addition to looking at the image quality settings, you need to be aware of which image formats are best for storing different types of images.
I prefer JPG for real world images such as those taken with a camera. JPEG does a better job of retaining high image quality while achieving good compression.
If you are taking a screenshot where a lot of the parts of the image are the same color (like this web page or your programming editor), then I prefer to use PNG. PNG will save the image without creating a lot of the dirty artifacts that often appear in JPEG but will still achieve good compression ratio for these types of images.
The reasons for the above have to do with the compression algorithms each use (JPEG is FFT; PNG is DEFLATE). Try changing the image type as well as the quality settings and see if that makes a difference.
I am using following code to resize an image - it all works well and as expected...
Resize UIImage the right way
I use interpolation quality as kCGInterpolationLow and UIImageJPEGRepresentation(image,0.0) to get the NSData of that image.
The problem is that the image size is still a bit high in size at around 100kb.
My question is can I reduce it further?
The images originate from the iPhone Photo Album and are selected via a imagePickerController.
Many thanks,
I am trying to improve scrolling performance of a UITableView. I am loading the images using imageNamed: and dispatch_async, but scrolling is very good once the images have been loaded into the cells. I would like to fade in the images only if they are not in the system cache to reduce the jarring effect of the images "popping" into view.
Is there a way to know if an image is already in the system cache?
There is no documented way to look inside the UIImage to check such things.
I think the only way to know for sure that the image is available immediately, is to force the UIImage to be loaded. This can be done in the background, by creating the UIImage and accessing it's pixels, using CGImage functions. If you ensure that there is no rescaling needed (i.e. don't put a 3000x2000 image in a 30x20 space) then it should display without a glitch.
I want to show some images as a thumbnail in View controller but i dont know how to do this. Can anyone please give me some ideas or sample code if possible.
Are you asking how to create thumbnails from larger images, or about how to build a view controller which displays them nicely?
Building a view controller:
You could use TTPhotoViewController from the Three20 project (description), which acts similarly to the iPhone's built in camera roll to view images.
You can look at the Scrolling sample code from apple, referred to in this question about using it for thumbnails.
If you want to build one yourself, you might consider using a GridView from the moriarty library, either as a large grid in a UIScrollView, or on a more efficient row-by-row basis in a UITableView. There's a previous question on optimized image loading in a UIScrollView.
Creating thumbnails from larger images:
The code-easiest way to scale down an image is to simply display it in a UIImageView with a frame set to the smaller size that you want - it's scaled for you.
If you want to save a thumbnail, or care about memory usage, you can create a hard-scaled version. The sample code below is taken from this blog post, and can be added to UIImage as a category method:
- (UIImage*) imageScaledToSize: (CGSize) newSize {
UIGraphicsBeginImageContext(newSize);
[self drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
Finally, here's a previous question on masking out round corners on an image, similar to the app icons used on the home screen.
Added
Using an image's built-in thumbnail:
There's a nice function called CGImageSourceCreateThumbnailAtIndex that understands built-in thumbnails in certain image data formats. You can see some useful sample code for this under Creating a Thumbnail Image from an Image Source in the Image I/O Programming Guide from Apple.
There are multiple issues with thumbnails; perhaps you could clarify which ones you are most concerned about?
How to display a smaller version of an existing image
How to speed up paging by caching the thumbnails (instead of just dynamically shrinking the originals)
How to allow the user to page through the thumbnails
How to synchronize the thumbnails with the originals, in the event that your images are editable or the user can add to them
I'm using a whole bunch of CALayers, creating a tile-based image not unlike GoogleMaps (different versions of the same image with more/less detail).
The code I'm using to do this is:
UIImage* image = [self loadImage:obj.fileName zoomLevel:obj.zoomLevel];
[CATransaction setValue:(id)kCFBooleanTrue
forKey:kCATransactionDisableActions];
obj.layerToAddTo.contents = [image CGImage];
[CATransaction commit];
I don't really feel like loading the CGImage from file using CoreGraphics because I'm lazy. But I will if there's a big performance boost! LoadImage just mangles a string to get the right path for loading said image, and obj is a NSObject-struct that holds all the info I need for this thread.
Help?
There's not a big performance boost - if anything it's the other way around. By going throuh UIImage to load up your images, you'll get all the benefits of caching that it does for you and it'll be a very speedy critter to use with your various CALayers.
I just tried this and using pure CoreGraphics to load the image rather than using UIImage gave a noticeable speed improvement when loading many images in one go.
"I just tried this and using pure CoreGraphics to load the image rather than using UIImage gave a noticeable speed improvement when loading many images in one go."
How did you avoid using a UIImage? Or more precisely, how do you load an image file directly into CoreGraphics without going through a UIImage?
One reason why NOT to use UIImage -imageNamed: to load images is that they are stored in the internal cache and that cache is not cleared in low memory situation.
I don't have a definite answer but I'd guess that you'd see a slower load time when using UIImage than you'd see when using CGImage. With CGImage, you specify the image type (jpg or png) during creation, but with UIImage, the object type needs to be determined dynamically. Admittedly, this is probably as simple as looking at the first few bytes of the image file, but it might not be.
Once the image is actually in use, I wouldn't imagine that there'd be any difference at all between using the CGImage that internally represents a UIImage vs. using a CGImage you created yourself. I'd think they'd be exactly equivalent.