166

I have a UIWebView in my app which I want to use to display an image which will link to another url.

I'm using

<img src="image.jpg" /> to load the image.

The problem is that the image doesn't load (ie. it can't be found) even though it's added as a resource in my project and is copied into the bundle.

I've tried using NSBundle to get the full path of the image and using that and it still doesn't show up in the web view.

Any ideas?

TheNeil
  • 3,321
  • 2
  • 27
  • 52
Jasarien
  • 58,279
  • 31
  • 157
  • 188
  • 8
    Why the down vote? :/ – Jasarien Mar 17 '10 at 11:29
  • 5
    It's not necessarily that they're evil. Maybe they had a legitimate reason? We'll probably never know. If only they'd have the courtesy to explain why they voted down in a comment... – Jasarien Mar 17 '10 at 17:30
  • 65
    It should be mandatory to write a comment on a vote down. – Robert Mar 11 '11 at 11:08
  • I'm no longer able to do this as of iPhone OS 3.0. :( [More info](http://stackoverflow.com/questions/478665/link-to-resources-inside-webview-iphone/1382396#1382396) (StackOverflow.com). – Joe D'Andrea Sep 05 '09 at 04:08
  • @Jasarien:I need same functionality. but I can't understand what should be passed in htmlString in [webView loadHTMLString:htmlString baseURL:baseURL] and how I put my image in html. – iPhone Aug 14 '15 at 18:30
  • you may refer to my answer on this post, hope it work for you [ http://stackoverflow.com/a/43011715/1316779 ](http://stackoverflow.com/a/43011715/1316779) – Amr Angry Mar 26 '17 at 09:38

13 Answers13

293

Using relative paths or file: paths to refer to images does not work with UIWebView. Instead you have to load the HTML into the view with the correct baseURL:

NSString *path = [[NSBundle mainBundle] bundlePath];
NSURL *baseURL = [NSURL fileURLWithPath:path];
[webView loadHTMLString:htmlString baseURL:baseURL];

You can then refer to your images like this:

<img src="myimage.png">

(from uiwebview revisited)

NANNAV
  • 4,875
  • 4
  • 32
  • 50
Adam Alexander
  • 15,132
  • 5
  • 42
  • 41
47

Use this:

[webView loadHTMLString:htmlString baseURL:[[NSBundle mainBundle] bundleURL]];
Somnath Muluk
  • 55,015
  • 38
  • 216
  • 226
Lithu T.V
  • 19,955
  • 12
  • 56
  • 101
  • 5
    But your answer is identical to the answer posted 3 years ago... Your answer offers nothing different, it didn't need to be posted because the accepted answer already covered what you posted. – Jasarien Jun 18 '12 at 13:58
  • 13
    It's a convenient one-line version of the accepted answer - no harm done by having it here. – MusiGenesis Jun 23 '12 at 13:18
  • 9
    @Jasarien that answer by Adam Alexander was the only solution until August 2009. But from Max OS X version 10.6 this new property `bundleURL` was added in NSBundle. No need to take bundlePath and convert to URL. So for people working in versions higher than 10.6 this gives a better solution. – rineez Jul 13 '12 at 18:18
  • seeing a lot of -ve activity in this post recently..And nobody noted why it is? – Lithu T.V Oct 25 '14 at 04:36
24

I just ran into this problem too. In my case, I was dealing with some images that were not localized and others that were--in multiple languages. A base URL didn't get the images inside localized folders for me. I solved this by doing the following:

// make sure you have the image name and extension (for demo purposes, I'm using "myImage" and "png" for the file "myImage.png", which may or may not be localized)
NSString *imageFileName = @"myImage";
NSString *imageFileExtension = @"png";

// load the path of the image in the main bundle (this gets the full local path to the image you need, including if it is localized and if you have a @2x version)
NSString *imagePath = [[NSBundle mainBundle] pathForResource:imageFileName ofType:imageFileExtension];

// generate the html tag for the image (don't forget to use file:// for local paths)
NSString *imgHTMLTag = [NSString stringWithFormat:@"<img src=\"file://%@\" />", imagePath];

Then, use imgHTMLTag in your UIWebView HTML code when you load the contents.

I hope this helps anyone who ran into the same problem.

Anton
  • 3,998
  • 25
  • 40
10

try use base64 image string.

NSData* data = UIImageJPEGRepresentation(image, 1.0f);

NSString *strEncoded = [data base64Encoding];   

<img src='data:image/png;base64,%@ '/>,strEncoded
Ping
  • 145
  • 2
  • 6
6

I had a simmilar problem, but all the suggestions didn't help.

However, the problem was the *.png itself. It had no alpha channel. Somehow Xcode ignores all png files without alpha channel during the deploy process.

  • What you did to get out of this? Did you found any solution? I am facing the same issue. UIWebView not showing images as it had No Alpha Channel. – spaleja Oct 28 '13 at 12:57
  • 1
    I used Gimp to add an alpha channel to my png files. See http://docs.gimp.org/en/gimp-layer-alpha-add.html –  Nov 04 '13 at 12:57
5

In Swift 3:

webView.loadHTMLString("<img src=\"myImg.jpg\">", baseURL: Bundle.main.bundleURL)

This worked for me even when the image was inside of a folder without any modifications.

MrAn3
  • 1,335
  • 17
  • 23
3

You can add folder (say WEB with sub folders css, img and js and file test.html) to your project by choosing Add Files to "MyProj" and selecting Create folder references. Now the following code will take care about all the referred images, css and javascript

NSString *filePath = [[NSBundle mainBundle] pathForResource:@"WEB/test.html" ofType:nil];
[webView  loadRequest:[NSURLRequest requestWithURL:[NSURL fileURLWithPath:filePath]]];
zeeawan
  • 6,667
  • 2
  • 50
  • 56
2

After having read a couple of chapters in the iOS 6 Programming Cookbok and started to learn objective-c and iOS programming, I would just like to add, that if one is going to load resources from a custom bundle and use that in a web view, it can be accomplished like this:

NSString *resourcesBundlePath = [[NSBundle mainBundle] pathForResource:@"Resources" ofType:@"bundle"];
NSBundle *resourcesBundle = [NSBundle bundleWithPath:resourcesBundlePath];
[self.outletWebView loadHTMLString:[html description] baseURL:[resourcesBundle bundleURL]];

Then, in your html you can refer to a resource using the "custom" bundle as your base path:

body {
    background-image:url('img/myBg.png');
}
Lasse Christiansen
  • 10,205
  • 7
  • 50
  • 79
2

Swift Version of Lithu T.V's answer:

webView.loadHTMLString(htmlString, baseURL: NSBundle.mainBundle().bundleURL)
Musa almatri
  • 5,596
  • 2
  • 34
  • 33
1

Swift version of Adam Alexanders Objective C answer:

let logoImageURL = NSURL(fileURLWithPath: "\(Bundle.main.bundlePath)/PDF_HeaderImage.png")
RJH
  • 358
  • 3
  • 12
0

If you use relative links to images then the images won't display as all folder structures are not preserved after the iOS app is compiled. What you can do is convert your local web folder into a bundle instead by adding the '.bundle' filename extension.

So if you local website is contained in a folder "www", this should be renamed to "www.bundle". This allows the image folders and directory structure to be preserved. Then load the 'index.html' file into the WebView as an HTML string with 'baseURL' (set to www.bundle path) to enable loading relative image links.

NSString *mainBundlePath = [[NSBundle mainBundle] resourcePath];
NSString *wwwBundlePath = [mainBundlePath stringByAppendingPathComponent:@"www.bundle"];
NSBundle *wwwBundle = [NSBundle bundleWithPath:wwwBundlePath];
if (wwwBundle != nil) {
    NSURL *baseURL = [NSURL fileURLWithPath:[wwwBundle bundlePath]];
    NSError *error = nil;
    NSString *page = [[NSBundle mainBundle] pathForResource:@"index.html" ofType:nil];
    NSString *pageSource = [NSString stringWithContentsOfFile:page encoding:NSUTF8StringEncoding error:&error];
    [self.webView loadHTMLString:pageSource baseURL:baseURL];
}
David Douglas
  • 10,377
  • 2
  • 55
  • 53
0

These answers did help me -- specifically the file:\\xxxxxxx.xxx, but I had to do a workaround to display the image.

In my case, I have an HTML file on my server which I download to the documents directory. I want to it to display with a local graphic in a UIWebView which I could not get to work. Here's what I did:

  1. Copy the file from the NSBundle to the local documents directory
  2. Reference the file in my HTML document as "file:\\filename.png"

So in startup copy the file to documents directory:

-(BOOL)copyBundleFilesToDocumentsDirectoryForFileName:(NSString *)fileNameToCopy OverwriteExisting:(BOOL)overwrite {
        //GET DOCUMENTS DIR
        //Search for standard documents using NSSearchPathForDirectoriesInDomains
        //First Param = Searching the documents directory
        //Second Param = Searching the Users directory and not the System
        //Expand any tildes and identify home directories.
        NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
        NSString *documentsDir = [paths objectAtIndex:0];

        //COPY FILE FROM NSBUNDLE File to Local Documents Dir
        NSString *writableFilePath = [documentsDir  stringByAppendingPathComponent:fileNameToCopy];

        NSFileManager *fileManager = [NSFileManager defaultManager];
        NSError *fileError;

        DDLogVerbose(@"File Copy From Bundle to Documents Dir would go to this path: %@", writableFilePath);

        if ([fileManager fileExistsAtPath:writableFilePath]) {
            DDLogVerbose(@"File %@ already exists in Documents Dir", fileNameToCopy);

            if (overwrite) {
                [fileManager removeItemAtPath:writableFilePath error:nil];
                DDLogVerbose(@"OLD File %@ was Deleted from  Documents Dir Successfully", fileNameToCopy);
            } else {
                return (NO);
            }
        }

        NSArray *fileNameParts = [fileNameToCopy componentsSeparatedByString:@"."];
        NSString *bundlePath = [[NSBundle mainBundle]pathForResource:[fileNameParts objectAtIndex:0] ofType:[fileNameParts objectAtIndex:1]];
        BOOL success = [fileManager copyItemAtPath:bundlePath toPath:writableFilePath error:&fileError];

        if (success) {
            DDLogVerbose(@"Copied %@ from Bundle to Documents Dir Successfully", fileNameToCopy);
        } else {
            DDLogError(@"File %@ could NOT be copied from bundle to Documents Dir due to error %@!!", fileNameToCopy, fileError);
        }

    return (success);
}
DoctorG
  • 1,168
  • 7
  • 11
-8

My complex solution (or tutorial) for rss-feed (get in RSSItems) works only on device:

#define CACHE_DIR       [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject]

for (RSSItem *item in _dataSource) {

    url = [NSURL URLWithString:[item link]];
    request = [NSMutableURLRequest requestWithURL:url];
    [request setHTTPMethod:@"GET"];

    [NSURLConnection sendAsynchronousRequest:request
                                       queue:queue
                           completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {

                               @autoreleasepool {

                                   if (!error) {

                                       NSString *html = [[NSString alloc] initWithData:data
                                                                              encoding:NSWindowsCP1251StringEncoding];

                                       {
                                           NSError *error = nil;

                                           HTMLParser *parser = [[HTMLParser alloc] initWithString:html error:&error];

                                           if (error) {
                                               NSLog(@"Error: %@", error);
                                               return;
                                           }

                                           HTMLNode *bodyNode = [parser body];

                                           NSArray *spanNodes = [bodyNode findChildTags:@"div"];

                                           for (HTMLNode *spanNode in spanNodes) {
                                               if ([[spanNode getAttributeNamed:@"class"] isEqualToString:@"page"]) {

                                                   NSString *absStr = [[response URL] absoluteString];
                                                   for (RSSItem *anItem in _dataSource)
                                                       if ([absStr isEqualToString:[anItem link]]){

                                                           NSArray *spanNodes = [bodyNode findChildTags:@"img"];
                                                           for (HTMLNode *spanNode in spanNodes){
                                                               NSString *imgUrl = [spanNode getAttributeNamed:@"src"];
                                                               if (imgUrl){
                                                                   [anItem setImage:imgUrl];
                                                                   break;
                                                               }
                                                           }

                                                           [anItem setHtml:[spanNode rawContents]];
                                                           [self subProcessRSSItem:anItem];
                                                       }
                                               }
                                           }

                                           [parser release];
                                       }

                                       if (error) {
                                           NSLog(@"Error: %@", error);
                                           return;
                                       }

                                       [[NSNotificationCenter defaultCenter] postNotificationName:notification_updateDatasource
                                                                                           object:self
                                                                                         userInfo:nil];

                                   }else
                                       NSLog(@"Error",[error userInfo]);
                               }
                           }];

and

- (void)subProcessRSSItem:(RSSItem*)item{

NSString *html = [item html];
if (html) {

    html = [html stringByReplacingOccurrencesOfString:@"<div class=\"clear\"></div>"
                                           withString:@""];

    html = [html stringByReplacingOccurrencesOfString:@"<p class=\"link\">"
                                           withString:@""];

    html = [html stringByReplacingOccurrencesOfString:@"<div class=\"page\">"
                                           withString:@""];

    html = [html stringByReplacingOccurrencesOfString:@"</div>"
                                           withString:@""];

    NSArray *array1 = [html componentsSeparatedByString:@"<a"];
    if ([array1 count]==2) {
        NSArray *array2 = [html componentsSeparatedByString:@"a>"];

        html = [[array1 objectAtIndex:0] stringByAppendingString:[array2 objectAtIndex:1]];
    }

    NSURL *url;
    NSString *fileName;
    NSString *filePath;
    BOOL success;
    if ([item image]) {

        url = [NSURL URLWithString:
                      [hostString stringByAppendingString:[item image]]];
        NSData *imageData = [NSData dataWithContentsOfURL:url];

        fileName = [[[url relativePath] componentsSeparatedByString:@"/"] lastObject];

        filePath = [NSString stringWithFormat:@"%@/%@",
                              CACHE_DIR,
                              fileName];

        //save image locally
        success = [[NSFileManager defaultManager] createFileAtPath:filePath
                                                               contents:imageData
                                                             attributes:nil];

        //replace links
        html = [html stringByReplacingOccurrencesOfString:[item image]
                                               withString:filePath];

        [item setImage:fileName];

        //Передадим обновление интерфейса, снабдив индексом обновляемой ячейки
        [[NSNotificationCenter defaultCenter] postNotificationName:notification_updateRow
                                                            object:self
                                                          userInfo:[NSDictionary dictionaryWithObject:@([_dataSource indexOfObject:item])
                                                                                               forKey:@"row"]];
    }

    //finalize html
    html = [NSString stringWithFormat:@"<html><body>%@</body></html>",html];

    fileName = [[[item link] componentsSeparatedByString:@"/"] lastObject];
    filePath = [NSString stringWithFormat:@"%@/%@",
                CACHE_DIR,
                fileName];
    success = [[NSFileManager defaultManager] createFileAtPath:filePath
                                                      contents:[html dataUsingEncoding:NSUTF8StringEncoding]
                                                    attributes:nil];

    [item setHtml:
     (success)?filePath:nil];//for direct download in other case
}

}

on View controller

- (void)viewDidAppear:(BOOL)animated{

RSSItem *item = [[DataSingleton sharedSingleton] selectedRSSItem];

NSString* htmlString = [NSString stringWithContentsOfFile:[item html]
                                                 encoding:NSUTF8StringEncoding error:nil];
NSURL *baseURL = [NSURL URLWithString:CACHE_DIR];

[_webView loadHTMLString:htmlString
                 baseURL:baseURL];

}

rss item class

#import <Foundation/Foundation.h>

@interface RSSItem : NSObject

@property(nonatomic,retain) NSString *title;
@property(nonatomic,retain) NSString *link;
@property(nonatomic,retain) NSString *guid;
@property(nonatomic,retain) NSString *category;
@property(nonatomic,retain) NSString *description;
@property(nonatomic,retain) NSString *pubDate;
@property(nonatomic,retain) NSString *html;
@property(nonatomic,retain) NSString *image;
@end

part of any html with image

<html><body>
<h2>blah-blahTC One Tab 7</h2>
<p>blah-blah НТС One.</p>
<p><img width="600" height="412" alt="" src="/Users/wins/Library/Application Support/iPhone Simulator/5.0/Applications/2EAD8889-6482-48D4-80A7-9CCFD567123B/Library/Caches/htc-one-tab-7-concept-1(1).jpg"><br><br>
blah-blah (Hasan Kaymak) blah-blah HTC One Tab 7, blah-blah HTC One. <br><br>
blah-blah
 microSD.<br><br>
blah-blah Wi-Fi to 4G LTE.</p>
</p>
</body></html>

image saved for name htc-one-tab-7-concept-1(1).jpg

WINSergey
  • 1,977
  • 27
  • 39