How to save UIWebView content into photo library - objective-c

How to save UIWebView Content into photo Library
-(IBAction)save:(id)sender{
UIImage* image = nil;
UIGraphicsBeginImageContext(webView.frame.size);
{
image = UIGraphicsGetImageFromCurrentImageContext();
}
UIGraphicsEndImageContext();
if (image != nil) {
UIImageWriteToSavedPhotosAlbum(image,self, nil, nil);
}
}
This code is saving empty page.

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

Related

what's the different between "cached image" and "local image"?

I am beginner. I want to show images by urls on TableView, so I use AFNetworking+SDURLCache, just as below
// init URLCache
SDURLCache *URLCache = [[SDURLCache alloc] initWithMemoryCapacity:1024*1024*2 diskCapacity:1024*1024*20 diskPath:[SDURLCache defaultCachePath]];
[URLCache setIgnoreMemoryOnlyStoragePolicy:YES];
[SDURLCache setSharedURLCache:URLCache];
========================================================
// set cell
[cell.imageView setImageWithURL:[NSURL URLWithString:IMAGE_URL] placeholderImage:[UIImage imageNamed:#"placeholder.png"]];
[[SDURLCache sharedURLCache] cachedResponseForRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:IMAGE_URL]]];
Here, I use a image on all different cells. Everything works OK! When I run my project first time, displaying images on cells need long time because my web image very large. When I run my project second time, I found that TableView load images one by one immediately
? Why?why not load all images once immediately. I replaced the cached image to local image, TableView load images at a time. what's the different between "cached image" and "local" image? SDURLCache did't work?
I have no iOS experience, but I would presume a cached image is an image that is stored in the web client's cache so that it will load that resource faster, unless that resource has been modified and the cached version invalidated since it was put in the cache.
A local image, I would assume, is an image stored on the device itself. Obviously this will be faster than downloading it as storage on the iDevices is comprised of NAND flash chips and such, which far outstrip a domestic Internet connection.

Titanium Images Wrong Size

I have a Titanium app where I am using the same ImageView for alot of different images. I am changing the image in the image view by setting it's image property.
The problem is some of the images are not showing at their full size sometimes, it is kinda random, but sometimes they show full size sometimes not.
I have width and height set to "auto" on the image view.
Anyone come across this issue.
A potentially more reliable way would be too dynamically resize the image before handing it off to the ImageView by using Titanium.Blob.imageAsReized.
Try to integrate this in your code, first you have to load the image as a blob though.
// Get the blob of your image first, then call this method
imageView.image = imageBlob.imageAsResized(newWidth, newHeight);

Animating retina images

I'm trying to animate some images. The images are working well on non-retina iPads but their retina counterparts are slow and the animations will not cycle through at the specified rate. The code i'm using is below with the method called every 1/25th second. This method appears to perform better than UIViewAnimations.
if (counter < 285) {
NSString *file = [[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:#"Animation HD1.2 png sequence/file_HD1.2_%d", counter] ofType:#"png"];
#autoreleasepool {
UIImage *someImage = [UIImage imageWithContentsOfFile:file];
falling.image = someImage;
}
counter ++;
} else {
NSLog(#"Timer invalidated");
[timer invalidate];
timer = nil;
counter = 1;
}
}
I realise there are a lot of images but the performance is the same for animations with less frames. Like i said, the non-retina animations work well. Each image above is about 90KB. Am i doing something wrong or is this simply a limitation of the iPad? To be honest, i find it hard to believe that it couldn't handle something like this when it can handle the likes of complex 3D games so i imagine i'm doing something wrong. Any help would be appreciated.
EDIT 1:
From the answers below, I have edited my code but to no avail. Executing the code below results in the device crashing.
in viewDidLoad
NSString *fileName;
myArray = [[NSMutableArray alloc] init];
for(int i = 1; i < 285; i++) {
fileName = [NSString stringWithFormat:#"Animation HD1.2 png sequence/HD1.2_%d.png", i];
[myArray addObject:[UIImage imageNamed:fileName]];
NSLog(#"Loaded image: %d", i);
}
falling.userInteractionEnabled = NO;
falling.animationImages = humptyArray;
falling.animationDuration = 11.3;
falling.animationRepeatCount = 1;
falling.contentMode = UIViewContentModeCenter;
the animation method
-(void) triggerAnimation {
[falling startAnimating];
}
First of all, animation performance on the retina iPad is notoriously choppy. That said, there are a few things you could do to make sure your getting the best performance for your animation (in no particular order).
Preloading the images - As some others have mentioned, your animation speed suffers when you have to wait for the reading of your image before you draw it. If you use UIImageView's animation properties this preloading will be taken care of automatically.
Using the right image type - Despite the advantage in file size, using JPEGs instead of PNGs will slow your animation down significantly. PNGs are less compressed and are easier for the system to decompress. Also, Apple has significantly optimized the iOS system for reading and drawing PNG images.
Reducing Blending - If at all possible, try and remove any transparency from your animation images. Make sure there is no alpha channel in your images even if it seems completely opaque. You can verify by opening the image in Preview and opening the inspector. By reducing or removing these transparent pixels, you eliminate extra rendering passes the system has to do when displaying the image. This can make a significant difference.
Using a GPU backed animation - Your current method of using a timer to animate the image is not recommended for optimal performance. By not using UIViewAnimation or CAAnimation you are forcing the CPU to do most of the animation work. Many of the animation techniques of Core Animation and UIViewAnimation are optimized and backed by OpenGL which using the GPU to process images and animate. Graphics processing is what the GPU is made for and by utilizing it you will maximize your animation performance.
Avoiding pixel misalignment - Make sure your animation images are at the right size on screen when displaying them. If you are stretching your image while animating or using an incorrect frame, the system has to do more work to process each frame. Also, using whole numbers for any frame or point values will keep from anti-aliasing when the system tries to position an image on a fractional pixel.
Be wary of shadows and rounded corners - CALayer has lots of easy ways to create shadows and rounded corners, but if you are moving these layers in animations, often times the system will redraw the layer in each frame of the animation. This is the case when specifying a shadow using the shadowOffset property (using UILabel's shadow properties will not render every frame). Also, borders and using maskToBounds and clipToBounds will be more performance intensive rather than just using an image editor to crop the actual asset.
There are a few things to notice here:
If "falling" is UIImageView, make sure it's content mode says something like "center" and not some sort of scaling (make sure your images fit it, of course).
Other than that, as #FogleBird said, test if your device have enough memory to preload all images, if not, try to at least preload the data by creating NSData objects with the image files.
Your use of #autorelease pool is not very useful, you end up creating an auto release object that does a single thing - remove a reference to an already retained object - no memory gain, but performance loss.
If anything, you should have wrapped the file name formatter code, and considering this method is called by an NSTimer, it is already wrapped in an autorelease pool.
just wanted to point out - when you are creating the NSString with the image name - what is the "Animation HD1.2 png sequence/HD1.2_%d.png" ?
It looks likey you are trying to put a path there, try just the image name - eg. "HD1.2_%d.png".

Using UIImagePickerController to get image -- how to know whether to save PNG or JPEG?

I've got a UIImagePickerController letting the user pick an image out of the image library, and am getting its results via the didFinishPickingMediaWithInfo method.
I need to be able to save the resulting image to disk (in the app's documents folder), and reload it later.
The issue is that I can't tell whether to store it as a PNG or JPEG. I can't just always store it as a PNG, because for larger photos it's interminably slow (not to mention then I have to deal with storing the image orientation separately). I can't just always store it as a JPEG, because in some cases the images have transparency, which will get lost if I do that.
I've examined the UIImagePickerControllerMediaType key in the info dictionary returned by the image picker, and regardless of whether I've selected a PNG or JPEG, what gets returned is "image.public".
So...
Is there some way to know whether the user has chosen a PNG? Maybe some method of just checking if the image has any transparency or something?
Thanks.
OK, so I figured it out. This may not work for every scenario, but it's sufficient for me:
CGImageAlphaInfo imgAlpha = CGImageGetAlphaInfo(theImage.CGImage);
// Is this an image with transparency (i.e. do we need to save as PNG?)
if ((imgAlpha == kCGImageAlphaNone) || (imgAlpha == kCGImageAlphaNoneSkipFirst) || (imgAlpha == kCGImageAlphaNoneSkipLast)) {
// save as a JPEG
} else {
// save as a PNG
}
...of course you need to remember which type of image you saved, give it the appropriate file extension, and load the right one back in... but basically this takes care of it. Images with transparency will be saved as PNGs, everything else as JPEGs.
If anyone has any better methods, I'd love to hear them. Thanks!
in the dictionary the key UIImagePickerControllerReferenceURL will give you informations about the type
(gdb) po info
{
UIImagePickerControllerMediaType = "public.image";
UIImagePickerControllerOriginalImage = "<UIImage: 0x5cfd00>";
UIImagePickerControllerReferenceURL = "assets-library://asset/asset.JPG?id=EFC44C3C-9C82-4669-924B-A2B9DE6F1F45&ext=JPG";
}
In this case it is a jpg as shown by ext=JPG

Objective C, Download a photo from web and show as a full screen

Let's say I have a thumbnail image and I have an original image(about 1200 * 1600) on my server. What is the best way for users to see the full screen of the original image on iPhone?
I could send HTTP request to download the image but how can I show the image on the full screen? Also. If I download the full size image then is this bed for memory management?
Use a UIImageView in your UI, download the fullscreen image to disk, create a new image using UIImage's imageWithContentsOfFile:
+ (UIImage *)imageWithContentsOfFile:(NSString *)path
and eventually assign the image property of your UIImageView instance to this newly created image.
To download the fullscreen image, do not use synchronous methods like NSData's dataWithContentsOfURL or it will block your UI. Instead use the asynchronous methods of NSURLConnection.
See the Loading Data Asynchronously section of NSURLConnection Class Reference.
The full image seem to be appr. 12 times larger than the standard iPhone 320x480 screen. I think you can pre-render a down-scaled image to download for this and not feel about that.
Automator is a simple way to batch process this for you. See this vid.
http://www.youtube.com/watch?v=q7p081Ui9WY