Show Menu

Looking for an iOS Developer?

Submit your 30 day Job Listing for FREE

This tutorial is part of a series:

Rich Text Editing : A Simple Start (Part 1)

Rich Text Editing : Validation (Part 2)

Rich Text Editing : Highlighting and UIMenuController (Part 3)

Rich Text Editing : Fonts (Part 4)

Rich Text Editing : Undo and Redo (Part 5)

Rich Text Editing : Inserting Images (Part 6)

Rich Text Editing : Draggable Images (Part 7)

Bonus: Rich Text Editing: Sample Project

iOS 5 Rich Text Editing

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!

iOS 5 Rich Text Editing

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:

having issues?

We have a Questions and Answer section where you can ask your iOS Development questions to thousands of iOS Developers.

Ask Question

FREE Download!

Get your FREE Swift 2 Cheat Sheet and quick reference guide PDF download when you sign up to SwiftMonthly


Sharing is caring

If you enjoyed this tutorial, please help us and others by sharing using one of the social media buttons below.


Written by:

Josh is an indie Mac and iOS Developer with 2 years of experience behind him. You may know him as the developer of Spark for Mac as well as 4Score and 2Code for iOS. He is also a huge Apple lover, a Star Trek fan and active users on both Stack Overflow and Twitter

Comments

There are currently: 40 Responses to “Rich Text Editing : Inserting Images (Part 6)”. Leave your comment!

Unable to insert image using this code. I did everything as shown in the tutorial.


Hey thanks for the tutorial, but unable to insert the image can you help me.

Thanks



// Set the selection to the caret range, so we can then add the image
var selection = window.getSelection();
var range = document.createRange();
selection.removeAllRanges();
selection.addRange(startInsertRange);
// Re-insert the image
document.execCommand('insertImage', false, imageSrc);

I have this code, and that after I add an image ,and then add the second , the sencode image is before the first image. should I change the selection then add the second Image ,and how can i change?


    @samhuang After the last line where you add the first image, you will need to adjust the startInsertRange by 1 then set it as the sole range in the selection (e.g. remove all ranges in the selection and add it again). Once you’ve done that add the second image.


No image appears when I try to insert.
Can someone post working code? I’m confused about whether the insertImage syntax is wrong, or if the problem is the modal photo picker.
Will


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.


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.


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.


@Elia would you please Give any idea to solve the issue what@alag, @Nasty, @Nidhi ..are Discussing above.


@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.


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.


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.


Im having the same trouble. The image is not loading. Did anyone figure this out?


@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.


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


@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.


@ 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 Does it work in the simulator? Are you adding a photo using the photo picker or is it already in the HTML?


I have tried to implement this tutorial on a iPhone device, but the image does not appear on the WebView.

can anybody help me ?


@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.


@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?


@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. :)


@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 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.


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!


@zahmed The last instalment is coming. Hopefully this coming week.


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 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!


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:


NSString *webViewContenst = [myWebView stringByEvaluatingJavaScriptFromString:
@"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.


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


@zahmed Could you give me more information? What do you mean by ‘save and load these text files’?


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.


Found the problem: the size of the image (???).
Waiting for the next episode.
Congrats again….


@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


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



awesome series. keep on goin!


Leave a Reply

Would you like to sign up to the mailing list by our sister site: SwiftMonthly?