I'm trying to create a ThumbnailImage to Word document. I use a UIWebView to load the document and then transform it into an image. Png. I've watched a thousand times and the file path is correct, but the final image is blank. Someone can look at my code to see if there is something wrong?. Thank you very much in advance.
UIWebView *myWebView22 = [[UIWebView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
path44 = [caminoINICIAL stringByAppendingPathComponent:#"documentoInicial.doc"];
NSURL *fileURL22 = [[NSURL alloc] initFileURLWithPath:path44];
NSURLRequest *req22 = [NSURLRequest requestWithURL:fileURL22];
[myWebView22 setScalesPageToFit:YES];
[myWebView22 loadRequest:req22];
UIGraphicsBeginImageContext(myWebView22.bounds.size);
CGContextRef c = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(c, 0, 0);
[myWebView22.layer renderInContext:c];
UIImage* viewImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
pngPath = [caminoINICIAL stringByAppendingPathComponent:[NSString stringWithFormat:#"imagenFinal.png"]];
[UIImagePNGRepresentation(viewImage) writeToFile:pngPath atomically:YES];
I'm pretty sure that's a timing problem. UIWebView has is own threads and loads the document async, you need to wait until it's loaded before you use renderInContext.
Figuring out the time might be tricky, either with a fixed time or some deep-subview-inspection.
You might wanna use QuickLook instead of UIWebView to get a little bit more control about the rendering.
The problem is that you are firing the request then immediately capturing the image. loadRequest: is asynchronous. It sends the request, and returns immediately. It doesn't wait until the document has loaded before returning. So when you capture the image, the device is still busy loading the document.
You can provide a delegate to the web view that receives a message once the document has finished loading. Capture the image from within that delegate method.
Related
I need to load image from server(url) to UITableView. So i tired below code, but no use.
UIImageView *img=[[UIImageView alloc]init];
img.frame=fr;
img.image=[UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:countimg]]];
[cell.contentView addSubview:img];
Here countimg is NSMutableArray. countimg contains url of all images to load. But its not working, because its not a string variable. I don't know how to change NSMutuableArray to String.
Anyone help me.
You can get string urls from countimg array like this,
[countimg objectAtIndex:index];
Where index is an integer of range between >=0 && < [countimg count]
Now if you're using countimg array in UITableView delegate then, you've replace index variable with indexPath.row.
So for now your code would look like this,
UIImageView *img=[[UIImageView alloc]init];
img.frame=fr;
img.image=[UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:[countimg objectAtIndex:indexPath.row]]]]; //note this
[cell.contentView addSubview:img];
Update:
As #DavidAtkinson, suggestion, you should not use dataWithContentsOfURL method to load a NSURL to download a image. As its perform in main thread and will stuck the UI until download would not completes. Its better to load image in background.
Also, there's some asynchronous UIImageView's available, one which I am using is SDWebImage.
Use SDWebImage to load your image from server. here using this library you can put placeholder image in tableview cell's image view till the image loaded. You can even cache your image by just doing a single line code
[UIImageView setImageWithUrl:[pass your URL here] placeholderImage:[pass name of placeholder image] options:SDWebImageRefreshCached]
If you are trying to load your images from URL into a tableview,the SDWebImage code from Github does not specify how to do that.You have to create an object at index,then load the object for key name from the file you are parsing from.This will require you to change the SDWebImage code so that instead of parsing directly from a specific url,its parsing from
an object key name that contains an image url from your json or xml file.
Here is a sample code for loading an image from an object key in a json:
NSURL* url = [NSURL URLWithString:[dictionaryObject valueForKey:#"yourfile"]];
NSData *data = [NSData dataWithContentsOfURL:url];
dispatch_sync(dispatch_get_main_queue(), ^{
UIImageView *imgViewThumb=[[UIImageView alloc]initWithFrame:imgView.frame];
[imgViewThumb setImage:[UIImage imageWithData:data]];
[cell addSubview:imgViewThumb];
Currently, I'm working on the client for the website. I have tonne of images that I need to load to my TableView. Here is what I'm currectly doing:
NSDictionary *propertyItems = [self.items objectAtIndex:indexPath.row];
cell.fio.font = [UIFont boldSystemFontOfSize:17.0f];
if([propertyItems objectForKey:#"online"] == [NSNumber numberWithInt:1])
cell.fio.textColor = [UIColor colorWithRed:0.3 green:0.6 blue:0.3 alpha:1.0];
dispatch_queue_t downloadPhotosQueue = dispatch_queue_create("downloadPhotosQeue", NULL);
dispatch_async(downloadPhotosQueue, ^{
NSData *photosData = [NSData dataWithContentsOfURL:[NSURL URLWithString:[NSString stringWithFormat:#"http://www.example.com/%#", [propertyItems objectForKey:#"photo_trumb"]]]];
dispatch_async(dispatch_get_main_queue(), ^{
cell.pic.image = [UIImage imageWithData:photosData];
});
});
cell.fio.text = [propertyItems objectForKey:#"fio"];
I'm doing this in cellForRowAtIndexPath: method.
Everything is loading fast. But the problem is, when I'm scrolling my table down, and after again up, the images are reloading over and over again.
Question: Is there any way to easily cache my UIImages that I'm getting from the server? So if they are loaded once, they wouldn't reload over and over again, while I'm running the app. Maybe I'm doing something wrong?
Thanks in advance!
I strongly recommend AsyncImageView. I use it and it works like a charm. Just set the image url and it handles everything itself.
AsyncImageView *imageView = [[AsyncImageView alloc]init];
imageView.imageURL = [NSURL URLWithString:#"https://www.google.es/logos/classicplus.png"];
It caches the image in memory so it won't retrieve it from the server again. It will also release them when receiving a memory warning.
To load image from a website I use AFNetworking. It provides a class to load an image from an URL:
Start by adding #import "UIImageView+AFNetworking" to the top of a
controller or a view implementation file. This category adds methods
to UIImageView, like:
[imageView setImageWithURL:[NSURL URLWithString:#"…"]];
i recommend this library to accomplish what you want.
in cellForRowAtIndexPath:
[cell.imageView setImageWithURL:
[NSURL URLWithString:[NSString stringWithString:#"www.yourimagepath.path"]]
placeholderImage:[UIImage imageNamed:#"no_image.jpg"]];
the library will cache the image for you. you can also set the setHolder of the image, so it wont look like a blank image while the images are downloading.
The problem is here :
NSData *photosData = [NSData dataWithContentsOfURL:[NSURL URLWithString:[NSString stringWithFormat:#"http://www.example.com/%#", [propertyItems objectForKey:#"photo_trumb"]]]];
dataWithContentsOfURL
It launch a request to the Url everytime the function is called (everytime you scrolled).
You need to load all the picture before cellForRowAtIndexPath.
Like in ViewDidLoad.
You can just store them in an array and display your picture's array in cellForRowAtIndexPath.
If it's really fast to load like you say : jsut load picture Once in CellForRowAtIndexPath. Store them in a mutableArray. And check if the picture already exist .
I have a 400 pattern images at 400x300 bundled within my app. I would like to make some kind of factory method to take a portion of that image and load them into UIImageViews. I've had some success with using content mode and clipping to bounds, but when I load a ton of these into a view it can take upwards of 5 seconds for the view to load. Here is an example of my current method.
UIImageView *tinyImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed#"400x300testImage.png"];
[tinyImageView setFrame:CGRectMake(0, 0, 10, 200)];
[tinyImageView setContentMode:UIViewContentModeTopLeft];
[tinyImageView setClipsToBounds:YES];
[self.tinyImagesView addSubview:tinyImageView];
I've been reading the ImageIO class files and I think my answer is in there but I'm having a hard time putting together workable code. In another stackoverflow question I came across this code
CFDictionaryRef options = (__bridge CFDictionaryRef)[NSDictionary dictionaryWithObjectsAndKeys:
(id)kCFBooleanTrue, (id)kCGImageSourceCreateThumbnailWithTransform,
(id)kCFBooleanTrue, (id)kCGImageSourceCreateThumbnailFromImageIfAbsent,
(id)[NSNumber numberWithFloat:200.0f], (id)kCGImageSourceThumbnailMaxPixelSize,
nil];
CGImageRef imgRef = CGImageSourceCreateThumbnailAtIndex(imageSource, 0, options);
UIImage *scaled = [UIImage imageWithCGImage:imgRef];
CGImageRelease(imgRef);
CFRelease(imageSource);
return scaled;
This has a similar load time to loading the full images and clipping.
Is it possible to read in only a 10x200 strip of an image file and load that into a UIImageView that is as fast as creating that 10x200 png and loading that using imageNamed?
I'm pretty sure what you really want is a CATiledLayer, where you can point it at the set of images and have it automatically pull up what it needs.
You can just add a CATiledLayer to any UIView.
is it possible to convert the HTML page to image in cocoa?
Actually i have created the complete view in the HTML and now i want to convert the whole html preview to the image (any jpeg or png etc.).
I couldn't find any resource or sample on the web, which provides some sort of help on my above queries.It's highly appreciated if someone could share his wisdom on how I can achieve this.
Thanks in advance..
First off, I'd like to thank sergio... his answer got me started but I thought I'd share some of the code that I didn't find obvious that I had to write to make it work:
Here's how to make a thumbnail for a page without ever having it displayed:
// Your width and height can be whatever you like, but if you want this to render
// off screen, you need an x and y bigger than the superview's width and height
UIWebView* webView = [[UIWebView alloc] initWithFrame:CGRectMake(largerScreenDimension, largerScreenDimension, largerScreenDimension, largerScreenDimension)];
[self.view addSubview:webView]; // UIWebViews without an assigned superview don't load ever.
webView.delegate = self; // or whoever you have implement UIWebViewDelegate
webView.scalesToFit = YES; // This zooms the page appropriately to fill the entire thumbnail.
[webView loadRequest:[NSURLRequest requestWithURL:url]];
Then implement this in your delegate:
- (void)webViewDidFinishLoad:(UIWebView *)webView {
UIGraphicsBeginImageContext(webView.bounds.size);
[webView.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *webViewImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
NSData *thumbnailData = UIImagePNGRepresentation(webViewImage);
[webView removeFromSuperview];
}
Finally, to display this thumbnail you'll need something like:
thumbnailImageView.image = [UIImage imageWithData:thumbnailData];
As a bonus thing I'll mention, I wanted multiple thumbnails to be generated at once. I found using objc_setAssociatedObject() and objc_getAssociatedObject() to be very helpful with keeping track of which webView was loading which thumbnail. Going into detail on how that worked is beyond the scope of this question, though.
You can draw your view in an image context, like this:
UIWebView* view = ...
....
UIGraphicsBeginImageContext(view.bounds.size);
[view.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
NSData *imagedata = UIImagePNGRepresentation(viewimage);
NSString *encodedString = [imageData base64Encoding];
Another option would be using Quartz PDF engine to create a PDF.
I am loading an image in a UIImageView which I then add to a UIScrollView.
The image is a local image and is about 5000 pixels in height.
The problem is that when I add the UIImageView to the UIScrollView the thread is blocked.
It is obvious because when I do this I can not scroll the UIScrollView till the image is displayed.
Here's the example.
UIScrollView *myscrollview = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, 768, 1004)];
myscrollview.contentSize = CGSizeMake(7680, 1004);
myscrollview.pagingEnabled = TRUE;
[self.view addSubview:myscrollview];
NSString* str = [[NSBundle mainBundle] pathForResource:#"APPS.jpg" ofType:nil inDirectory:#""];
NSData *imageData = [NSData dataWithContentsOfFile:str];
UIImageView *singleImageView = [[UIImageView alloc] initWithImage:[UIImage imageWithData:imageData]];
//the line below is the blocking line
[scrollView addSubview:singleImageView];
It is the last line in the script that blocks the scroller. When I leave it out everything works perfect, except for the fact the image is not showing of course.
I seem to recall that using multithreading does not work on UIView operations so I guess that's out of the question ass well.
Thanks for your kind help.
If you're providing these large images, you should maybe check out CATiledLayer; there's a video of a good presentation on how to use this from WWDC 2010.
If these aren't your images, and you can't downsample them or break them into tiles, you can draw the image on a background thread. You may not draw to the screen graphics context on any main thread but the main thread, but that doesn't prevent you from drawing to a non-screen graphics context. On your background thread you can
create a drawing context with CGBitmapContextCreate
draw your image on it just as you would draw onto the screen in drawRect:
when you're done loading and drawing the image invoke your view's drawRect: method on the main thread using performSelectorOnMainThread:withObject:waitUntilDone:
In your view's drawRect: method, once you've fully drawn your image on the in-memory context, copy it to the screen using CGBitmapContextCreateImage and CGContextDrawImage.
This isn't trivial, you'll need to start your background thread at the right time, synchronize access to your images, etc. The CATiledLayer approach is almost certainly the better one if you can find a way to manipulate the images to make that work.
Why you want to load such huge image to memory at one time? split it into many small images and load/free it dynamically.
Try allocating the UIImageView without a UIImage, and add it as a sub-view to the UIScrollView.
Load the UIImage in a separate thread, and get the method running on the other thread to set the image property of the UIImageView when the image is loaded into memory. Also you'll probably encounter some memory problems as an image of this size loaded into a UIImage will probably be 30MB+
UIScrollView *myscrollview = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, 768, 1004)];
myscrollview.contentSize = CGSizeMake(7680, 1004);
myscrollview.pagingEnabled = TRUE;
[self.view addSubview:myscrollview];
NSString* str = [[NSBundle mainBundle] pathForResource:#"APPS.jpg" ofType:nil inDirectory:#""];
UIImageView *singleImageView = [[UIImageView alloc] init];
[scrollView addSubview:singleImageView];
//Then fire off a method on another thread to load the UIImage and set the image
//property of the UIImageView.
Just keep an eye on memory and beware of using convenience constructors with UIImage (or any object that could end up being huge)
Also where are you currently running this code?