I am trying to attach an image rendered from UIGraphicsBeginImageContext. As a test, I am adding the image to the photo album as well. It all works perfectly on the simulator, but on the device the correct image get added to the photo album, but will not display in the email attachment correctly. I think it is because it is a big image, and it takes some time on an iPhone 3gs. Which means I have to check if it is done rendering image. Is there a way to to that? Here is my code:
UIGraphicsBeginImageContext(backGround.layer.frame.size);
[backGround.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil);
UIGraphicsEndImageContext();
MFMailComposeViewController *mailer = [[MFMailComposeViewController alloc] init];
mailer.mailComposeDelegate = self;
NSData *imgData = UIImagePNGRepresentation(image);
[mailer addAttachmentData:imgData mimeType:#"image/png" fileName:#"myfilename"];
I am wondering, maybe it is not completely finished with the image, and it still has corrupted data when I am making a PNG Representation of it. Can I somehow check if the UIImage is 'done' ?
Try implementing the completion method and check it. One example is,
UIImageWriteToSavedPhotosAlbum(image, self, #selector(image:didFinishSavingWithError:contextInfo:), NULL);
- (void)image:(UIImage *) image didFinishSavingWithError:(NSError *) error contextInfo: (void *) contextInfo {
NSLog(#"SAVE IMAGE COMPLETE");
if(error != nil) {
NSLog(#"ERROR SAVING:%#", [error localizedDescription]);
}
}
Based on the error message you can debug for the error message. Check UIImageWriteToSavedPhotosAlbum documentation for more details.
Related
i will like to pick an images from UIImagepicker, there are PNG and JPG format in camera roll.
and i need to convert it into NSData. However i need to know if this images is UIImageJPEGRepresentation or UIImagePNGRepresentation so i could convert it.
UIImage *orginalImage = [info objectForKey:UIImagePickerControllerOriginalImage];
[picker dismissViewControllerAnimated:YES completion:nil];
NSData *orgData = UIImagePNGRepresentation(orginalImage);
You shouldn't know or care what the internal representation of images in the camera roll is. The methods you mentioned UIImageJPEGRepresentation and UIImagePNGRepresentation return you representations of the camera roll image. It's up to you to pick which representation you want to use.
To summarize:
NSData * pngData = UIImagePNGRepresentation(originalImage);
Will return you the image representation in an NSData object, with the format PNG.
When the delegate method imagePickerController:didFinishPickingMediaWithInfo: for UIImagePickerController is called, you get the asset URL for the particular photo picked.
[info valueForKey:UIImagePickerControllerReferenceURL]
Now this URL can be used to access the asset in the ALAssetsLibrary. Then you would need a ALAssetRepresentation of that accessed asset. From this ALAssetRepresentation we can get the UTI for that image (http://developer.apple.com/library/ios/#DOCUMENTATION/FileManagement/Conceptual/understanding_utis/understand_utis_conc/understand_utis_conc.html)
Maybe the code would make it a bit clearer :
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
if (!(picker.sourceType == UIImagePickerControllerSourceTypeCamera)) {
NSLog(#"User picked image from photo library");
ALAssetsLibrary *library = [[[ALAssetsLibrary alloc] init] autorelease];
[library assetForURL:[info valueForKey:UIImagePickerControllerReferenceURL] resultBlock:^(ALAsset *asset) {
ALAssetRepresentation *repr = [asset defaultRepresentation];
if ([[repr UTI] isEqualToString:#"public.png"]) {
NSLog(#"This image is a PNG image in Photo Library");
} else if ([[repr UTI] isEqualToString:#"public.jpeg"]) {
NSLog(#"This image is a JPEG image in Photo Library");
}
} failureBlock:^(NSError *error) {
NSLog(#"Error getting asset! %#", error);
}];
}
}
As the UTI explains, this should be a sure shot answer to how the image is stored in the photo library.
in Swift 2.2
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
if (!(picker.sourceType == UIImagePickerControllerSourceType.Camera)) {
let assetPath = info[UIImagePickerControllerReferenceURL] as! NSURL
if assetPath.absoluteString.hasSuffix("JPG") {
} else {
}
In my app I am taking a picture and showing it in an image view.
Now I need the path of that image so I can upload it to a server.
How do I get that path? I try importing ALAsset framework but there is no framework called that my x code (4.2) iOS 5.0
NSData *data = UIImagePNGRepresentation(imagePic.image);
NSString *file = [NSTemporaryDirectory() stringByAppendingPathComponent:#"upload.jpg"];
[data writeToFile:file atomically:YES];
[[EPUploader alloc] initWithURL:[NSURL URLWithString:#"myWebSite"]
filePath:#"file"
delegate:self
doneSelector:#selector(onUploadDone:)
errorSelector:#selector(onUploadError:)];
This is what I am currently trying.
Also what would be a hard coded path to a photo in an iphone camera roll? "iphone/pictures/myPic" ?? so I can try the upload separate from finding the path.
Please and Thank you
EDIT:
- (void) imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
// Access the uncropped image from info dictionary
image2 = [info objectForKey:#"UIImagePickerControllerOriginalImage"];
// Save image
UIImageWriteToSavedPhotosAlbum(image2, self, #selector(image:didFinishSavingWithError:contextInfo:), nil);
imagePic.image = image2;
[picker release];
}
An image view has no path, it's in memory. You'll have to save the path you get when you return from taking the image. In the delegate method imagePickerController:didFinishPickingMediaWithInfo: you can get the NSURL in UIImagePickerControllerMediaURL which points to the image on disk:
NSURL *imageURL = [info valueForKey:UIImagePickerControllerMediaURL];
I'm trying to create a PhoneGap plugin which uses AFFoundation to capture photos and return the image as base64 encoded string. This all works fine but the exif data seems to be missing from the returned image. Tried a few variations and got some pointers from other questions asked here but it still doesn't seem to work correctly. The current code is
NSMutableString *stringToReturn = [NSMutableString stringWithString: #""];
NSLog(#"about to request a capture from: %#", stillImageOutput);
[stillImageOutput captureStillImageAsynchronouslyFromConnection:videoConnection completionHandler:^(CMSampleBufferRef imageBuffer, NSError *error)
{
if (imageBuffer != NULL)
{
CFDictionaryRef exifAttachments = CMGetAttachment(imageBuffer, kCGImagePropertyExifDictionary, NULL);
CFMutableDictionaryRef mutable;
if (exifAttachments)
{
//
// Set orientation
//
mutable = CFDictionaryCreateMutableCopy(NULL, 0, exifAttachments);
int orientation = (int)[UIDevice currentDevice].orientation;
CFDictionaryAddValue(mutable, kCGImagePropertyOrientation, CFNumberCreate(NULL, kCFNumberIntType, &orientation));
CMSetAttachments(imageBuffer, mutable, kCMAttachmentMode_ShouldPropagate);
NSLog(#"attachements: %#", mutable);
}
//
// Get the image
//
NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageBuffer];
[stringToReturn setString:[imageData base64EncodedString]];
//
// Call the success callback
//
[self performSelectorOnMainThread:#selector(doSuccessCallback:) withObject:[NSString stringWithString:stringToReturn] waitUntilDone:NO];
//
// Save it to the photo album
// It is done after we did the success callback to avoid accidental issues with
// the photo album stopping further processing
//
UIImage *image = [[UIImage alloc] initWithData:imageData];
UIImageWriteToSavedPhotosAlbum(image, self, #selector(image:didFinishSavingWithError:contextInfo:), nil);
}
}];
Can anyone shed some light please? I seem to be completely stuck here.
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.
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