Check out the previous in the series:
Once you’ve done that, then let’s begin.
In this our sixth and penultimate tutorial I will show you how to present a UIImagePickerController in which a user can select an image of their choice and then add the users selected image into the document.
Let’s get right to it, in our ‘checkSelection’ method add the following code:
UIBarButtonItem *insertPhoto = [[UIBarButtonItem alloc] initWithTitle:@"Photo+" style:UIBarButtonItemStyleBordered target:self action:@selector(insertPhoto:)];
[items addObject:insertPhoto];
Okay now that’s done let’s head straight forward and implement the ‘insertPhoto:’ method:
- (void)insertPhoto:(id)sender {
UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
imagePicker.delegate = self;
UIPopoverController *popover = [[UIPopoverController alloc] initWithContentViewController:imagePicker];
[popover presentPopoverFromBarButtonItem:(UIBarButtonItem *)sender permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
imagePickerPopover = popover;
[imagePicker release];
}
What we’ve done here is created a image picker, set up some of its properties but most importantly its delegate. We then create a popover with the image picker as its content view, present it, assign it to a property for later use and release what we have to.
Seeing as though we haven’t yet added that property, just switch to the header file and add the following code in the appropriate place:
UIPopoverController *imagePickerPopover;
Now what we must do is implement one of the UIImagePickerController’s delegate methods to be notified when an image is selected. Let’s implement said method as well as adding a static variable:
static int i = 0;
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
// Obtain the path to save to
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *imagePath = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"photo%i.png", i]];
// Extract image from the picker and save it
NSString *mediaType = [info objectForKey:UIImagePickerControllerMediaType];
if ([mediaType isEqualToString:@"public.image"]){
UIImage *image = [info objectForKey:UIImagePickerControllerOriginalImage];
NSData *data = UIImagePNGRepresentation(image);
[data writeToFile:imagePath atomically:YES];
}
[webView stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"document.execCommand('insertImage', false, '%@')", imagePath]];
[imagePickerPopover dismissPopoverAnimated:YES];
i++;
}
Unfortunately what we want to do isn’t as easy as you might have thought, we can’t just take a UIImage and tell it to insert it, we have to save this image first before, so that we have a path to it which we can pass to the ‘execCommand’ function in the javascript.
The first block of the code is simply finding the documents directory and creating a path for where we can place the image. After this we get the image and write it to the path we created and finally we execute the command via javascript passing it our path to the image.
You may have also noticed that we use a static int ‘i’ which we use to change the photo path every time we insert a photo. We have to do this because if we don’t change the name and just overwrite the existing file then when we add the image to the web view then it just assumes it’s the same as the other image so adds the same image due to caching.
And that’s it, all done! You’ll have to test this on a device if you want to see it working as the simulator has no photos in it’s library but it should work like a charm.
Coming up next time!
I hope you’re looking forward to our next and last tutorial which will include subclassing UIGestureRecognizer, dealing with and using blocks but most importantly expanding our knowledge of javascript. What are we doing I hear you ask, adding drag and drop to our images of course!
Next in the series:







awesome series. keep on goin!
cool!
Great tutorial. Willing for the last episode.
Regarding the image, the code isn’t working. The image does not appear on the WebView. Everything else is working perfectly.
I think that the problem is the path that is point to the image, instead of http:// … is pointing to /Volumes/…
Congratulations and best regards, Cassio
@Cassio The path to the image should be a file path and not a http:// link as the image is saved to the documents directory. Here’s a video of it working fine for me after following the exact instructions in the tutorial: http://idzr.org/apzb
Found the problem: the size of the image (???).
Waiting for the next episode.
Congrats again….
This keeps getting more better. Can not wait for next article. Sorry it will be last. Thanks.
Also, do you know where I can find sample code to save and load these text files? I found some file code, but thought I would ask you.
@zahmed Could you give me more information? What do you mean by ‘save and load these text files’?
Sorry for not being clear Josh. I want to be able to read text/html files into the UIWebView and to save them. I saw somewhere how to do this, but now I can’t find it. I don’t think it was too hard to do.
Any ideas would be appreciated. Thanks
Hallo Josh,
The new stuff must be real hard since haven’t heard from you for a long time.
I did researching on how to save the UIWebView file that we are editing. I found this:
@"document.body.innerHTML"];
After is doing this, then just need to save in a file.
I hope this is helping some one.
Thanks again for such a great tutorial.
@zahmed Sorry for not getting back to you, I have been busy recently.
Glad you have figured it out yourself, I’m sure it has helped someone in a similar situation!
Hey Josh,
Really looking forward to the last installment – is there hope?
This tutorial is awesome – have you done any others? I want to read them.
Thanks!
@zahmed The last instalment is coming. Hopefully this coming week.
Hello,
thanks for your tutorial.
i have a question to ask.
if i want to load photo from camera.
because lost cursor location so insertImage will not work.
is there any way to keep or get cursor location?
thank you!
@ccko The cursor location should not be lost when you attempt to insert an image. As long as you have the cursor positioned somewhere in the text before you attempt to insert an image it should work fine. If this was not what you were talking about could you please clarify.
@Josh,
Thanks for you reply.
my web view has multiple div with contentediable = true.
so, choose a editable area and take the pic from camera (change to camera view) and back to webview .
the cursor will lost.
Finally, i insert a fake node before change to camera view.
when back to webview, call javascript to do replace node. works fine.
but is there any way to keep javascript range in objective-c?
@ccko Doing it like that with javascript is probably best as if you had to do it objective-c you would not just have to keep the javascript range but also which div was being edited and then attempt to communicate this information back to the document via javascript.
The way you have done it definitely sounds the best and most simple way.
Also, thanks for telling us how you did it because I wouldn’t be surprised if other people run into the same issue.
@ccko How do you add a fake node? Can this be done in objective-c, or does it have to be done in Javascript? In Javascript might be a problem since you can’t do undo/redo on this?
@z ,
I add a fake node also call javascript.
you can keep fake node id and img id in objective-c.
maybe undo/redo can achieve rely on these ids.
I have tried to implement this tutorial on a iPhone device, but the image does not appear on the WebView.
can anybody help me ?
@Alag Does it work in the simulator? Are you adding a photo using the photo picker or is it already in the HTML?
@ Josh Garnham no doesn’t work in the simulator.
I’m adding the photo using the photo picker.
you have any idea why it does not work ?
@Alag Hmm, odd. Are these images particularly large in dimensions or size as there have been issues with large images not being added to the UIWebView.
Have the same problems with inserting image, can’t find a solution..
Your project works fine, but the same code in my project won’t insert image.. I see just icon
@Nasty Have you got the same javascript code in your index.html file? If you are still having issues I might be able to help better if you sent me a sample project of your own demonstrating the issue.
Im having the same trouble. The image is not loading. Did anyone figure this out?
In case anyone missed this, you need to include both the UIImagePickerControllerDelegate and the UINavigationControllerDelegate in the .h file to get the warnings on delegate assignment to go away.
I should also comment that you can do images on the simulator. Go to Safari, do a search for “Apple images” in Google and show one of the images. Select and hold on the image until the menu appears and then choose “Save”. Finally, go back to your app and use the picker to select the image.
@alag, @Nasty, @Nidhi I’m guessing here but the problem on iPhone is likely one of timing. On the iOhine, I believe, the photo picker is in a modal dialog, which means the keyboard closes when the picker shows and then doesn’t show again until the modal view is dismissed and you return to the webView. Thus, you have to wait to insert the image into the view until viewDidAppear.
@Elia would you please Give any idea to solve the issue what@alag, @Nasty, @Nidhi ..are Discussing above.
Hmm, I have the same problem on iPhone. Working hard on a solution. Tried what Elia suggested above but the code still won’t display anything in the UIWebView when run from viewDidAppear. Granted, I have my UIWebView inside my view, not as the actual view itself. Hmm… will post an update if I can fix this.
the insertImage doesn’t work on iphone because the cursor and keyboard are gone after the modal imagepicker is dismissed; if you call the [webView ..insertImage...] after the cursor/keyboard is back (e.g. using UIKeyboardDidShowNotification) you will see the image.
Thanks,Josh For this tutorial…
It works fine for web view but is there any way to generate a RTF file with embedded images, which can subsequently be mailed across from the application itself.
@Deepak Unfortunately there’s no easy way to do it as there is no method which allows you to convert the HTML directly to RTF. You may have to handles this yourself going through each HTML entity and building up the RTF file bundle. It may be easier to convert it to an attributed string first and then use attributes from that to build a RTF file however either there’s no easy way to go about it.