Thumbnail view of images - iphone

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

Related

Resizing UIImage and saving

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.

Memory consumption while loading a large image in uiimageview in

I am loading a UIImage of size 2480 × 3508 into UIImageView using UIViewContentModeScaleAspectFit. I am getting memory warning while loading this image. And after i loaded a few images of this size in this UIImageView the application crashes. Is there any method to solve this.
Solution to this problem consists of either loading scaled version of the image (*1) or you have option to display it in full resolution with help of CATiledLayer(*2).
[UIImage imageWithCGImage:scale:orientation:];
CATiledLayer example
Addendum: If your image source is Photo Library, ALASSet provides already scaled image to full screen and full resolution image. You can use combination of both with CATiledLayer. Full screen image is added to layer beneath the CATiledLayer to serve as placeholder while you're waiting for tiles in CATiledLayer to load.
Well, according to the documentation :
You should avoid creating UIImage objects that are greater than 1024 x 1024 in size.
Reduce your image then load it in your ImageView, there are plenty of libraries to do this, here is one :
https://github.com/Nyx0uf/NYXImagesUtilities
You can use this for scaling
The method is described simply in the following link:
How to scale a UIImageView proportionally?

Is it possible to know if an image is in the iPhone system cache?

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.

Image overlapping in photo viewer on three20 framework?

I just integrated the photo viewer from three20 framework. Its working fine but some time images are overlapping, that ia happening only for thumnail image while original image is perfectly loaded. Till the original image loaded , at that point of time images are overlapping.
Did any one face this problem and have any solution for that?
Thanks
If images are overlapping, you are not correctly setting their size when you are including them in the photo view controller. You have to (unfortunately) tell three20 the exact size so it knows how to display them in paging mode of the scrollview.
Make sure you are resizing your thumbnails similar sizes to his (somewhere around 100 pixels tall or wide, based on if it's in portrait or landscape)
[[[MockPhoto alloc]
initWithURL:#"http://farm4.static.flickr.com/3444/3223645618_13fe36887a_o.jpg"
smallURL:#"http://farm4.static.flickr.com/3444/3223645618_f5e2fa7fea_t.jpg"
size:CGSizeMake(320, 480) // see how he sets the size here for each and every photo? this is crucial
caption:#"These are the wood tiles that we had installed after the accident."] autorelease],
If you look at the thumbnail, it is 67pixels by 100pixels: http://farm4.static.flickr.com/3444/3223645618_f5e2fa7fea_t.jpg
If you look at the regular photo, it is 320pixels by 480pixels. : http://farm4.static.flickr.com/3444/3223645618_13fe36887a_o.jpg
These are two independent files, the three20 code does not create the thumbnail for you based on the larger photo. You must do this manually or subclass whatever container class he uses to do it for you.
Just by setting line 135 of TTPhotoView.m to
self.contentMode = UIViewContentModeScaleAspectFit
will help.

Rendering a UIWebView into an ImageContext

I am trying to capture the contents of a UIWebView including that which is not visible to the user. i.e. The whole web page even though the user is only looking at the top.
Looking around I found the best way to capture a UIView is to retrieve its layer and use renderInContext.
However, UIWebView seems to be using its own CALayer implementation which is behaving a lot more like CATiledLayer, although it is still claiming to be a standard CALayer. When I call renderInContext I only get one portion of the web page, up to 940px down, as opposed to the whole page.
Has anyone got any ideas on how to either: force the UIWebView to scroll down another 940px (obviously that is far from ideal) or tell whatever breed of CALayer it is backing the WebView to render all of its content when I ask it to.
Cheers
EDIT: I should add that currently change the frame of the webview to fit the size of the page retrieved through javascript.
I've released an app (Web2Pic) doing that, and please trust me that UIGraphicsBeginImageContext(webView.frame.size);
can do nothing except getting a small image from the visible area in our UIWebView ;-(
The right way is a bit complex but it just works:
1.Use JavaScript in our UIWebView to get these float values:
//Whole page size in HTML coordinate
document.body.scrollWidth
document.body.scrollHeight
//UIWebView visible size in HTML coordinate
window.innerWidth
window.innerHeight
2.Now we can 'cut' the whole page into dozens of UIWebView-sized small pieces. Then we can capture every small pieces individually and save them into our Cache. I implemented this by calculating page-offsets and use UIGraphicsBeginImageContext(webView.frame.size); to get a array of images. In addition, you should cache the image array into the file system, or the app will eventually crash!
3.When we finally got all the small pieces, we can start a full-resolution context: UIGraphicsBeginImageContext(CGSizeMake(document.body.scrollWidth,document.body.scrollHeight));
4.Render every small images into the big context based on the coordinates. And be careful to the corners, the last image in every line/row may not be a full image.
5.There is still one step left: saving the big image. Do not save it into the PhotoAlbum, because iOS will automatically cut down the resolution of images in the album. Instead, we can save it into the file system and enable the app's iTunes File Share support, or even write a simple in-app photo manager.
Hope these can help ;-)
Yichao Peak Ji
It looks to me like UIWebView renders on demand (witness the checkerboard as you scroll downwards rapidly on a large page), so there won't be anything in the part of the layer below what you can reach until the user scrolls down there. The layer won't be able to write out what it doesn't have, so I don't think you'll be able to capture the whole area.
As far as scrolling, there aren't any obvious exposed API methods that I can think of to move it down. The web view seems to host a UIScrollView or something similar, which you could try to access by traversing the view hierarchy and use its scrollRectToVisible:animated:, but that doesn't sound like a good long-term solution.
Just to answer one of my questions, you can scroll the view by using javascript.
So you use stringByEvaluatingJavaScriptFromString: with a javascript of window.scrollTo(0,%i);, where %i is where you want to scroll to. You can also use scrollY to retrieve the current scroll value.
Resizing the Webview is the way I solved it. If you want a bigger image with more detail, you just have to zoom in before calling this method. Beware that large dimensions could infulence the performance.
- (UIImage*) imageFromWebview:(UIWebView*) webview{
//store the original framesize to put it back after the snapshot
CGRect originalFrame = webview.frame;
//get the width and height of webpage using js (you might need to use another call, this doesn't work always)
int webViewHeight = [[webview stringByEvaluatingJavaScriptFromString:#"document.body.scrollHeight;"] integerValue];
int webViewWidth = [[webview stringByEvaluatingJavaScriptFromString:#"document.body.scrollWidth;"] integerValue];
//set the webview's frames to match the size of the page
[webview setFrame:CGRectMake(0, 0, webViewWidth, webViewHeight)];
//make the snapshot
UIGraphicsBeginImageContextWithOptions(webview.frame.size, false, 0.0);
[webview.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
//set the webview's frame to the original size
[webview setFrame:originalFrame];
//and VOILA :)
return image;
}
All UIViews have a size limit of 1024x1024, so you will probably have programmatically scroll, capture the page in chunks, and stitch them together somehow.
Set the height of webview equal to the contentsize of scrollview of webview.
-(UIImage *)captureImage:(UIWebView *)webvw
{
webvw.frame=CGRectMake(webvw.frame.origin.x, webvw.frame.origin.y, webvw.frame.size.width, webvw.scrollView.contentSize.height);
UIGraphicsBeginImageContextWithOptions(webvw.frame.size, NO, 0.0f);
[webvw.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *screenshot = UIGraphicsGetImageFromCurrentImageContext();
return screenshot;
}