点击UIWebView获取图片的URL的两种方法

I'm trying to get the url of an image tapped in a UIWebView using UILongPressGestureRecognizer.

I sort of have this working, but i'm not sure if the coordinates are off, or it's just not finding an img tag in the DOM as it doesn't always work.

I am using this code:

int displayWidth = [[self.webView stringByEvaluatingJavaScriptFromString:@"window.outerWidth"] intValue];
CGFloat scale = self.webView.frame.size.width / displayWidth;
CGPoint pt = [gesture locationInView:self.webView];
pt.x /= scale;
pt.y /= scale;
NSString *imgURL = [NSString stringWithFormat:@"document.elementFromPoint(%f, %f).parentElement.getElementsByTagName(\"img\")[0].src", pt.x, pt.y];
NSString *urlToSave = [self.webView stringByEvaluatingJavaScriptFromString:imgURL];

If I use a website that starts off zoomed right out and has images in a grid, and I zoom in then select an image, I get given the image at the top left corner of the page instead of the one clicked on. Not sure if it's a zoom issue, offset issue, or DOM issue?

EDIT ------------

For starters, the coordinates are definitely off! If I click a point on a webpage in the UIWebView I get these result: ScrollY: 0 Click pointY: 89 Y *= scale += scrollY = 86.8293

Now if I scroll the page up, so the point I clicked is in line with the top (approximately at y=0) I get these results: ScrollY: 144 Click pointY:1 Y *= scale += scrollY = 144.976

Now before the calculations, the scroll seems off. The point was 89, but when scrolled to that point the scroll reads 144. Why would that be?

I'm getting the scroll from window.pageYOffset

share improve this question
 
1  
I don't have the ability to test any iOS stuff over the weekend, but two guesses: 1) Perhaps locationInView returns co-ordinates relative to the UIWebView's frame, rather than it's content, meaning that e.g. a tap on the top-left of the UIWebView will give {0,0} regardless of whether you've scrolled or zoomed the page? 2) If all the images have a common parent, then document.elementFromPoint(%f, %f).parentElement.getElementsByTagName("img")[0]will obviously always return the first image, no matter which is tapped. –  Mark Amery  Aug 17 '13 at 20:16 
 
Thanks. I hadn't considered your second point about all images having a common parent. Would there be a way in this situation to get the image? Say for example, there is a <ul> list with many images. –  Darren  Aug 18 '13 at 21:47

3 Answers

up vote 6 down vote accepted
+50

Put this 2 javascript function in a file named JSTools.js

function getHTMLElementsAtPoint(x,y) {
var tags = "";
var e;
var offset = 0;
while ((tags.search(",(A|IMG),") < 0) && (offset < 20)) {
    tags = ",";
    e = document.elementFromPoint(x,y+offset);
    while (e) {
        if (e.tagName) {
            tags += e.tagName + ',';
        }
        e = e.parentNode;
    }
    if (tags.search(",(A|IMG),") < 0) {
        e = document.elementFromPoint(x,y-offset);
        while (e) {
            if (e.tagName) {
                tags += e.tagName + ',';
            }
            e = e.parentNode;
        }
    }

    offset++;
}
return tags;}

function getLinkSRCAtPoint(x,y) {
var tags = "";
var e = "";
var offset = 0;
while ((tags.length == 0) && (offset < 20)) {
    e = document.elementFromPoint(x,y+offset);
    while (e) {
        if (e.src) {
            tags += e.src;
            break;
        }
        e = e.parentNode;
    }
    if (tags.length == 0) {
        e = document.elementFromPoint(x,y-offset);
        while (e) {
            if (e.src) {
                tags += e.src;
                break;
            }
            e = e.parentNode;
        }
    }
    offset++;
}
return tags;}

Then in your controller

- (void)longPressRecognized:(UILongPressGestureRecognizer *)gestureRecognizer {
if (gestureRecognizer.state == UIGestureRecognizerStateBegan) {
    CGPoint point = [gestureRecognizer locationInView:webView];
    longpressTouchedPoint = point;
    // convert point from view to HTML coordinate system
    CGSize viewSize = [webView frame].size;
    CGSize windowSize = [webView windowSize];

    CGFloat f = windowSize.width / viewSize.width;
    if ([[[UIDevice currentDevice] systemVersion] doubleValue] >= 5.) {
        point.x = point.x * f;
        point.y = point.y * f;
    } else {
        // On iOS 4 and previous, document.elementFromPoint is not taking
        // offset into account, we have to handle it
        CGPoint offset = [webView scrollOffset];
        point.x = point.x * f + offset.x;
        point.y = point.y * f + offset.y;
    }

    // Load the JavaScript code from the Resources and inject it into the web page
    NSString *path = [[NSBundle mainBundle] pathForResource:@"JSTools" ofType:@"js"];
    NSString *jsCode = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
    [webView stringByEvaluatingJavaScriptFromString: jsCode];


    // call js functions
    NSString *tags = [webView stringByEvaluatingJavaScriptFromString:
                      [NSString stringWithFormat:@"getHTMLElementsAtPoint(%i,%i);",(NSInteger)point.x,(NSInteger)point.y]];
    NSString *tagsSRC = [webView stringByEvaluatingJavaScriptFromString:
                         [NSString stringWithFormat:@"getLinkSRCAtPoint(%i,%i);",(NSInteger)point.x,(NSInteger)point.y]];

    NSLog(@"src : %@",tags);
    NSLog(@"src : %@",tagsSRC);

    NSString *url = nil;
    if ([tags rangeOfString:@",IMG,"].location != NSNotFound) {
        url = tagsSRC;    // Here is the image url!
    }

Mixed from several source, credit to the web community!

EDIT

You also have to create a category on uiwebview with that two function :

- (CGSize)windowSize {
CGSize size;
size.width = [[self stringByEvaluatingJavaScriptFromString:@"window.innerWidth"] integerValue];
size.height = [[self stringByEvaluatingJavaScriptFromString:@"window.innerHeight"] integerValue];
return size;}

- (CGPoint)scrollOffset {
CGPoint pt;
pt.x = [[self stringByEvaluatingJavaScriptFromString:@"window.pageXOffset"] integerValue];
pt.y = [[self stringByEvaluatingJavaScriptFromString:@"window.pageYOffset"] integerValue];
return pt;}
share improve this answer
 
 
Thanks, although i'm getting 2 compile errors. No windowSize selector in webView and no scrollOffset selector in webView. Any ideas? –  Darren  Aug 22 '13 at 14:24
1  
edited sorry about that! –  Alban  Aug 22 '13 at 14:44
 
This works very well. Thank you. The main difference with this and the way I was doing it, is the way this gets the coordinates. –  Darren  Aug 22 '13 at 15:20
1  
you're welcome, actually js code wasn't the point –  Alban  Aug 23 '13 at 17:34
1  
no problem, it was my first answer on SO: even half a bounty is a good start in my opinion! –  Alban  Aug 26 '13 at 16:08

I've recently achieved a bit similar goal, but I didn't determine "touch" coordinates.

My answer can help if you have permissions to modify html/javascript source.

WHAT I DID:

On each image <img... html DOM element I put onClick javascript handler to change window.location

f.e

javascript function clickedImage(imageURL) {
    window.location = "customScheme://"+imageURL; // attached image url to be able to read it inside `UIWebView`
}

On UIWebView delegate's method ignore links like above, BUT, we are able to get image URL.

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{

  if ([[request.URL scheme] isEqualToString:@"customScheme"]) {
        //Fetching image URL
        NSLog(@"Clicked on image with URL %@", [request.URL host])
        ...
        // Always return NO not to allow `UIWebView` process such links
        return NO; 
    }
    ....
}

Sorry, if this approach doesn't fully fit your question, but I guess this is an option you can follow and dig deeply.

Small note: to use UILongPressGestureRecognizer you can simulate this behaviour by making javascript instead: Long Press in JavaScript?

share improve this answer
 
 
Thats a very interesting idea. Using Javascript to intercept and return the image URL. I would need to use long press as I want the user to be able to navigate around the web, so needs to click links. I wonder, what would happen in the case of an image that is also a link, would it be possible to grab the underlying image? –  Darren  Aug 21 '13 at 18:07
 
you shouldn't make image as a link (<a href=...), just trigger OnClick event to <img tag... should work and in OnClick function body changle windo.location. I'm not the best in javascript, but I think should be like this: <img src="path_to_image" OnClick="javascript:function() {window.location = \"myScheme://path_to_image\"}" /> –  Injectios  Aug 21 '13 at 18:23 
 
Ahh yes, but that's if it's my html? I want the user to browse any webpage and grab an image. I could possibly intercept the html while loading and change it, but many possiblities –  Darren  Aug 21 '13 at 18:36
 
yes, if user can browse anywhere, you should parse DOM elements and modify each <img tag, seems like not a good idea, not sure what is better –  Injectios  Aug 21 '13 at 19:16 
 
Please see my edit to question. The touch point is definitely off. –  Darren  Aug 21 '13 at 21:34

You can get element by following code

        <script type="text/javascript">

            (function($) {
             $.fn.longClick = function(callback, timeout) {
             var timer;
             timeout = timeout || 500;
             $(this).mousedown(function(e) {
                               timer = setTimeout(function() { callback(e.offsetX,e.offsetY); }, timeout);
                               return false;
                               });
             $(document).mouseup(function() {
                                 clearTimeout(timer);
                                 return false;
                                 });
             };

             })(jQuery);


            $(window).longClick(function(x,y)
            {
              var element = document.elementFromPoint(x, y);
              alert(nodeToString(element));
            },600);


            function nodeToString ( node ) {
                var tmpNode = document.createElement( "div" );
                tmpNode.appendChild( node.cloneNode( true ) );
                var str = tmpNode.innerHTML;
                tmpNode = node = null; // prevent memory leaks in IE
                return str;
            }
        </script>

This is just js code. mousedown and mouseup will not work for ios . You need to use other alternative event for ios webView.


链接地址

https://stackoverflow.com/questions/18239666/uiwebview-getting-image-url-with-elementfrompoint

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值