but i want dowload a video from URL and to rename the file of that video before saving it.i use UISaveVideoAtPathToSavedPhotosAlbum ?any help..what i have to do ?
NSData *imageData = [NSData dataWithContentsOfURL:[NSURL
URLWithString:#"www.xyz.com/image.mp4"]];
You would do something like this:
- (void) downloadVideo
NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:#"http://www.xyz.com/image.mp4"]];
NSString *tempPath = [NSString stringWithFormat:#"%#/%#", NSTemporaryDirectory(), temp.mp4];
[imageData writeToFile:tempPath atomically:NO];
UISaveVideoAtPathToSavedPhotosAlbum (# tempPath, self, #selector(video:didFinishSavingWithError: contextInfo:), nil);
);
- (void) video: (NSString *) videoPath
didFinishSavingWithError: (NSError *) error
contextInfo: (void *) contextInfo {
NSLog(#"Finished saving video with error: %#", error);
}
There are two things you need to take note of:
Make sure you specify the scheme of the URL. This isn't a browser, it is not going to attempt to autofill http and guess for you.
If this is on the main thread it will cause a synchronous stall while dataWithContentsOfURL: happens. If the main thread stalls for more than 20 seconds the phone will assume the app has gotten stuck in an infinite loop and kill it. So if this code is on the main thread you need to either move it onto a background thread or move to an asynchronous download using NSURLConnection.
I had the same problem, solved it changing the extension of the file being saved from .mpg to .mp4. apparently UISaveVideoAtPathToSavedPhotosAlbum expects a correct extension, though from the documentation it is not clear to me that this is a requirement:
http://developer.apple.com/library/ios/#DOCUMENTATION/UIKit/Reference/UIKitFunctionReference/Reference/reference.html
Related
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
iOS download and save image inside app
I want to download a file. I found this
[NSData dataWithContentsOfURL:[NSURL URLWithString:#"http://lasp.colorado.edu/home/wp-content/uploads/2011/03/suncombo1.jpg"]]
My questions are:
Where does the file saved?
By using threads, is it any possible to build a status bar for downloads?
Are there any way to change the memory(internal/external) to save the file?
Now I am using
NSData *dataImage = [NSData dataWithContentsOfURL:[NSURL URLWithString:#"http://lasp.colorado.edu/home/wp-content/uploads/2011/03/suncombo1.jpg"]];
downloadStatus.text =#"size: %zd", malloc_size(dataImage);
The result is always 32. Shouldn't that be the size of the actual image?
The file is not saved. It's loaded/retrieved and converted into an NSData object.
Yes. However, if you're doing this you should look at NSURLConnection and particularly the NSURLConnectionDataDelegate protocol. You'll need to asynchronously download the file and get the callbacks into the delegate to be able to update your status bar. Or you could use a 3rd party networking library to simplify the whole thing, but it's good to understand what's going on behind the scenes.
Yes. You can save the NSData object as a file when it's downloaded. If you were using Cocoa (not iOS) you could use NSURLDownload to download the file directly.
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setDownloadProgressDelegate:myProgressIndicator];
[request startSynchronous];
NSLog(#"Max: %f, Value: %f", [myProgressIndicator maxValue],[myProgressIndicator doubleValue]);
And you can also follow this link to make more underastanding :)
http://allseeing-i.com/ASIHTTPRequest/How-to-use
You can assign the downloaded data to a variable and show it in an UIImageView as follows.
NSData *dataImage = [NSData dataWithContentsOfURL:[NSURL URLWithString:#"http://lasp.colorado.edu/home/wp-content/uploads/2011/03/suncombo1.jpg"]];
self.imageViewYours.image = [UIImage imageWithData:dataImage];
Try This Code Worked for Me. The Image will save to your PhotoAlbum.
-(IBAction)save_Image:(id)sender
{
UIImageWriteToSavedPhotosAlbum([UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:[NSString stringWithFormat:#"Your URL"]]]], self, #selector(image:didFinishSavingWithError:contextInfo:), nil);
[self performSelectorOnMainThread:#selector(imageDownloaded) withObject:nil waitUntilDone:NO ];
}
- (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo
{
if (error != NULL)
{
// handle error
}
else
{
// handle ok status
}
}
- (void)imageDownloaded
{
// network animation off
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
// do whatever you need to do after
}
Since you're new to Obj-C, I'd first get familiar with NSURLConnection and NSURLConnectionDataDelegate (protocol). Once you feel comfortable that you know what's going on, you can easily switch to a networking library such as AFNetworking to simplify things.
Hello I would like to run a thread and check the current downloaded size of a file.
This is what I use
UIImage *image = [[UIImage alloc] initWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:#"http://lasp.colorado.edu/home/wp-content/uploads/2011/03/suncombo1.jpg"]]];
NSString *docDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *jpegFilePath = [NSString stringWithFormat:#"%#/test.jpeg",docDir];
NSData *data2 = [NSData dataWithData:UIImageJPEGRepresentation(image, 1.0f)];//1.0f = 100% quality
[data2 writeToFile:jpegFilePath atomically:YES];
downloadStatus.text =[NSString stringWithFormat:#"size: %zd", malloc_size(data2)];
[image release];
I have also tried to change malloc_size(data2) into image but again it is not the real result. I know this does not have thread and do not check during the download process but what am I supposed to use here to see the file size?
A couple of observations:
Your question presumed that your attempts to retrieve the size of the NSData were failing. They are not. The correct way to get the size of a NSData is via length.
Your confusion, though, stems from a faulty assumption that taking an externally generated JPEG on a roundtrip through UIImage and UIImageJPEGRepresentation would yield the identical NSData. This would have been extraordinarily unlikely. There are too many different JPG settings that could have changed (see the JPEG Wikipedia page). We certainly don't know what settings that original file used. I know that UIImage and/or UIImageJPEGRepresentation changed the color space of the file. I'd wager it's doing a lot of other things, too.
So your results are correct. The original file was 2.6mb and the resulting file was 4.5mb. If you change the compressionQuality from 1.0 to 0.99, the resulting file is only 1.4mb! But if you want the original file, just save it first (like I do below).
Consider the following code which downloads the image file, saves it, loads it into a UIImage, re-extracts it via UIImageJPEGRepresentation, and saves another copy of the image:
// let's make filenames where we'll store the files
NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *suncomboOrig = [documentsPath stringByAppendingPathExtension:#"suncombo1-orig.jpg"];
NSString *suncomboReprocessed = [documentsPath stringByAppendingPathExtension:#"suncombo1-reprocessed.jpg"];
// let's download the original suncombo1.jpg and save it in Documents and display the size
NSURL *url = [NSURL URLWithString:#"http://lasp.colorado.edu/home/wp-content/uploads/2011/03/suncombo1.jpg"];
NSData *data = [NSData dataWithContentsOfURL:url];
NSLog(#"original = %d", [data length]);
[data writeToFile:suncomboOrig atomically:NO];
// let's load that into a UIImage
UIImage *image = [UIImage imageWithData:data];
// let's extract data out of the image and write that to Documents, too, also logging the size of that
NSData *data2 = UIImageJPEGRepresentation(image, 1.0);
NSLog(#"reprocessed = %d", [data2 length]);
[data2 writeToFile:suncomboReprocessed atomically:NO];
What that does is it reports:
2012-12-13 22:30:39.576 imageapp[90647:c07] original = 2569128
2012-12-13 22:30:40.141 imageapp[90647:c07] reprocessed = 4382876
So the first file I saved (which I suspect is identical to what's on your server) was 2.5mb, and the file after doing a roundtrip to a UIImage and re-extracted via 4.3mb. If I look at the two files that the above code saved, I can confirm that these NSData sizes are correct.
My original answer was predicated on the presumption that the OP was either unable to retrieve the size of a NSData or that there was some subtle issue underlying the simple question (such as wanting to get the size before the download commenced). Anyway, I've expanded my answer above, but I'll keep my original answer for historical purposes:
Original Answer:
The NSData property length tells you how many bytes were downloaded. E.g. [data2 length].
If it's really big, you can use NSURLConnection to download it asynchronously, which, depending upon your web server, may provide total file size before the download commences in the method didReceiveResponse (with the expectedContentLength property in the NSHTTPURLResponse *response parameter).
The other nice thing about NSURLConnection downloading is that you don't have to load the entire file in memory as you're downloading it, but rather you can stream it directly to persistent storage, which is especially useful if you're downloading multiple large files at the same time. If you're downloading a reasonably sized file, using NSURLConnection to download is overkill, but it can be nice when downloading large files and you want a progress indicator (or want to get the file size before the download commences).
But if you just want to know how many bytes were downloaded to your NSData, use length.
You can just use the C FILE class to get the file size.
FILE * handle = fopen([jpegFilePath UTF8String], "r");
fseek(handle, EOF); // seek to end of file
int size = ftell(handle); // returns position in bytes
fclose();
Because you say "current" size and mention a thread, I'm guessing you're trying to determine the file size as it is received. In that case, you can get the thread for free from an NSURLConnection, and you can get the data size from the delegate methods as it's received...
Create an instance variable for the downloaded data:
#property (nonatomic, strong) NSMutableData *data;
Create and launch a connection:
NSURL *url = [NSURL URLWithString:#"http://lasp.colorado.edu/home/wp-content/uploads/2011/03/suncombo1.jpg"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
self.data = [NSMutableData data];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
Implement the required methods in NSURLConnectionDataDelegate. For your question, the special part is this:
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[self.data appendData:data];
NSUInteger bytesSoFar = [self.data length];
// you're on the app main thread here, so you can do something
// to the UI to indicate progress
downloadStatus.text = [NSString stringWithFormat#"size: %d", bytesSoFar];
}
A good doc on the rest of the protocol is here. When the connection is complete, you can create the image as you did with the dataWithContentsOfURL...
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
UIImage *image = [[UIImage alloc] initWithData:self.data];
downloadStatus.text = [NSString stringWithFormat#"size: %d", [self.data length]];
}
My app is downloading packages of images from a server. It's an array of direct links (20-50 files) from XML.
How do I make sure the whole set of images is fully downloaded?
How do I add a condition to cancel whole download (and remove all already downloaded files) if app was closed with iPhone button? (such methods are in AppDelegate while my whole download code is in some downloadviewcontroller.m)
Anything else I have to worry about while downloading several files? (5-10 MB in total)
The code I currently use isn't very safe in case of download interrupting or app closing. In background thread I'm calling this method for each file:
(BOOL) loadImageFromURL:(NSString *)url withName:(NSString *)filename toFolder:(NSString *)folder {
NSURL *link = [NSURL URLWithString:url];
NSFileManager *manager = [NSFileManager defaultManager];
NSString *filepath = [folder stringByAppendingPathComponent:filename];
if ([manager fileExistsAtPath:filepath]) {
return YES;
}
else
{
UIImage *image = [[UIImage imageWithData:[NSData dataWithContentsOfURL:link]] retain];
NSData *data = [NSData dataWithData:UIImageJPEGRepresentation(image, 1.0f)];
if ([data length] <= 0)
[image release];
return NO; // no data
else
{
[data writeToFile:filepath atomically:YES];
[image release];
return YES;
}
}
}
Use nsoperation to do so
check out blow link..
http://www.cimgf.com/2008/02/16/cocoa-tutorial-nsoperation-and-nsoperationqueue/
now on august 2012 try to search wwdc 2012 video no 211 to learn nsoperation.
u can use block to do so.
[aNsque addExecutionBlock:^{ ...code... }];
where aNsque is nsblockoperation.
Dont use the synchronous call dataWithContentsOfURL. Instead look at how to use the asynchronous method of NSURLConnection, – initWithRequest:delegate:
You can then cancel the request with [connection cancel]; Also you will not have to run it on another thread because it is already asynchronous.
As far as having multiple requests running, you probably have a few options. One idea would be to create an abject that starts the NSURLConnection and parses the response, then create an array of theses objects.
I'm creating some temporary files in the iPad simulator. To test my file creation, I create the file and then read it back. Here's some code to show this:
-(NSString *) writeToTempFile:(UIImage*) image{
NSString *path = [self createTemporaryFile];
NSLog(#"path: %#", path);
NSData *data = UIImageJPEGRepresentation(image, 1);
[data writeToFile:path atomically:YES];
free(data);
return path;
}
-(UIImage *) readTempFile:(NSString *) path{
NSData *data = [[NSData alloc] initWithContentsOfFile:path];
UIImage *image = [[UIImage alloc] initWithData:data];
return image;
}
I call these methods one after another, before a final function writes out the UIImage to the photo album.
UIImageWriteToSavedPhotosAlbum(image2, self, nil, nil);
The problem is, this always crashes my app on the third time it is executed. First and second time it successfully does all of this and stores to the album. Third time it crashes to Home. Any ideas?
NSData *data = UIImageJPEGRepresentation(image, 1);
[data writeToFile:path atomically:YES];
free(data);
The NSData returned from UIImageJPEGRepresentation is -autoreleased. There is no need to free() it. And it is wrong to free() any Objective-C objects — send a -release message instead.
Please read through the Memory Management Programming Guide.
I have an application, in which the user will select an image from a UIImagePickerView.
After selecting an image from it, I want to save it in my application.
How can this be achieved?
Thanks in advance for helping me.
Assuming you're using SDK 3.0, here is some code to save the image into your application's documents folder:
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
// Dismiss the picker
[[picker parentViewController] dismissModalViewControllerAnimated:YES];
// Get the image from the result
UIImage* image = [info valueForKey:#"UIImagePickerControllerOriginalImage"];
// Get the data for the image as a PNG
NSData* imageData = UIImagePNGRepresentation(image);
// Give a name to the file
NSString* imageName = "MyImage.png";
// Now, we have to find the documents directory so we can save it
// Note that you might want to save it elsewhere, like the cache directory,
// or something similar.
NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString* documentsDirectory = [paths objectAtIndex:0];
// Now we get the full path to the file
NSString* fullPathToFile = [documentsDirectory stringByAppendingPathComponent:imageName];
// and then we write it out
[imageData writeToFile:fullPathToFile atomically:NO];
return;
}
I would say something like this:
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)image editingInfo:(NSDictionary *)editingInfo {
self.resumePreviousSettingAfterEditing = true;
[self.topImageView setImage:image];
[cubeModel setImage:image forFace:[cubeModel.validFaces objectAtIndex:selectedRowInFacePicker]];
[self dismissImagePickerAnimated:true];
}
You register an event in your controller to handle the image selection. In that event handler, call a method somewhere, say in your model to set the new image. That function would look something like this:
(void)saveImage:(UIImage *)image withName:(NSString *)imageName {
// get the image path
NSString *filename = [self determineImagePath:imageName];
// make sure the file is removed if it exists
NSFileManager *fileManager = [NSFileManager defaultManager];
if([fileManager fileExistsAtPath:filename]) {
if(NO == [fileManager removeItemAtPath:filename error:NULL]) {
}
}
// Now, save the image to a file.
if(NO == [UIImagePNGRepresentation(image) writeToFile:filename atomically:YES]) {
[NSException raise:#"Image Save Failed" format:#"Unable to store image %s", filename];
}
}
When you want to load the image again, you would so something like:
- (UIImage *)loadImage:(NSString *)imageName {
NSString *filename = [self determineImagePath:imageName];
NSFileManager *fileManager = [NSFileManager defaultManager];
self.currentImage = nil;
if([fileManager fileExistsAtPath:filename]) {
NSData *imageData = [[NSData alloc] initWithContentsOfFile:filename];
UIImage *image = [UIImage imageWithData:imageData];
self.currentImage = image;
}
return self.currentImage;
}
And don't get me started on transforming which is way harder than it should be.
Enjoy,
Jacob
One thing you will need to address when saving images returned by UIImagePickerVIewController is that writing the data to disk will almost always be unacceptably slow. Your UI will hang while the writing is occurring. So, you should always execute these types of operations in an asynchronous queue. Even if the performance seems good enough for your application when testing, you should still do it an asynch queue -- you never know what other processes the device might have going on which might slow the save down once your app is in the hands of users.
Newer versions of iOS make saving photos asynchronously really, really easy using Grand Central Dispatch (GCD). The steps are:
Create an NSBlockOperation which saves the image
In the block operation's completion block, read the image from disk & display it (the only caveat here is that you must use the main queue to display the image: all UI operations must occur on the main thread).
Add the block operation to an operation queue and watch it go!
That's it. And here's the code:
// Grab the image
UIImage *image = [info objectForKey:UIImagePickerControllerEditedImage];
// Create a block operation with our saves
NSBlockOperation* saveOp = [NSBlockOperation blockOperationWithBlock: ^{
[UIImagePNGRepresentation(image) writeToFile:file atomically:YES];
}];
// Use the completion block to update our UI from the main queue
[saveOp setCompletionBlock:^{
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
UIImage *image = [UIImage imageWithContentsOfFile:file];
// TODO: Assign image to imageview
}];
}];
// Kick off the operation, sit back, and relax. Go answer some stackoverflow
// questions or something.
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperation:saveOp];
Once you are comfortable with this code pattern, you will find yourself using it a lot. It's incredibly useful when generating large datasets, long operations on load, etc. Essentially, any operation that makes your UI laggy in the least is a good candidate for this code. Just remember, you can't do anything to the UI while you aren't in the main queue and everything else is cake.