Extract URL of Image From String - ios

I am trying to extract the URL for an image from a string of text. It may be from different websites, and could be any form of image (jpg, png, gif, etc.). What would be a good way to scan the string, find any matching picture extension, and get the graphic from it?
The string may be something like this:
Hello, I hope you like my picture located at http://www.website.com/picture1.png. However, if you don't, I know you'll like this one http://www.website2.org/picture2.jpg.Please refer all comments to http://www.website5.com/
I want to be able to scan the string for ONLY URLs of image files, and make a new string of whatever the first image URL is. So in this string, I could create a new string that only has http://www.website.com/picture1.png

I got from The Link Objective-C - Finding a URL within a string
No need to use RegexKitLite for this, since iOS 4 Apple provide NSDataDetector (a subclass of NSRegularExpression).
You can use it simply like this (source is your string) :
NSDataDetector* detector = [NSDataDetector dataDetectorWithTypes:NSTextCheckingTypeLink error:nil];
NSArray* matches = [detector matchesInString:source options:0 range:NSMakeRange(0, [source length])];

Use below code after later finish with #Anup Kumar
for (NSTextCheckingResult *match in matches) {
NSRange matchRange = [match range];
if ([match resultType] == NSTextCheckingTypeLink) {
NSURL *url = [match URL];
} else if ([match resultType] == NSTextCheckingTypePhoneNumber) {
NSString *phoneNumber = [match phoneNumber];
}
}

Well, to get the extension you can use the NSString method pathExtension, this will result in a string with just the extension, so you will know if it is jpg, gif, png, etc.
NSString* path = #"http://location.com/pictures/image.jpg";
NSString* extension = [path pathExtension];
For your graphic you can use the UIImage imageWithData method, and pass it the output from NSData dataWithContentsOfUrl method, using these methods together will allow you to create a UIImage which you can then display in a UIImageView.
UIImage* image = [UIImage imageWithData:[NSData dataWithContentsOfURL:path]];
Hopefully that is helpful.

Related

base 64 encoding objective-c

I am trying to convert copied images on the iOS pasteboard from a string to an image. 90% of the time this works under the scheme i have with URL's. However 1/10 times the image is not a url but is of what seems to be a base 64 encoding. The string looks like this.
data:image/jpeg;base64,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
Now I use the following code to recognize its base64 based off a post I found.
- (BOOL)isBase64Data :(NSString *)input{
input=[[input componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] componentsJoinedByString:#""];
if ([input length] % 4 == 0) {
static NSCharacterSet *invertedBase64CharacterSet = nil;
if (invertedBase64CharacterSet == nil) {
invertedBase64CharacterSet = [[NSCharacterSet characterSetWithCharactersInString:#"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="]invertedSet];
}
return [input rangeOfCharacterFromSet:invertedBase64CharacterSet options:NSLiteralSearch].location == NSNotFound;
}
return NO;
}
However it always returns false. Does this string I show need some trimming in some way? I find the length of the string to be 8391 therefore modulo 4==0 is never invoked.
/9j/4AAQSkZJ is a typical beginning of JPEG data, converted to hex as FFD8FFE00010+JFIF. If you want to convert it to an image, you need to point the converter to the point AFTER the data:image/jpeg;base64, text.
I think you can do something like this:
NSData *base64 = [yourData subdataWithRange:NSMakeRange(24, yourData.length-24)];
NSData *imgData = [[NSData alloc] initWithBase64EncodedData:base64 options:0];
UIImage *img = [UIImage imageWithData:imgData];
I might be wrong with the exact implementation but this is the general idea...

How to reduce length of links OR set a fixed length for links detected in TTTAttributedLabel

The links pasted by users are very long and contain "http://" etc and hence I want to restrict the length of links and show only the main website name or a bit more than that.
Example:
Link pasted by user:
http://www.androidpolice.com/2015/08/16/an-alleged-leak-of-lgs-nexus-5-2015-bullhead-pops-up-on-google/
Link I want to display in the label: www.androidpolice.com/2015/08/...
Is there any way to do it?
I searched and found something called attributedTruncationToken but I didn't understand much and I think it's related to truncation at the end of line.
I don't use TTTAttributeLabel but this answer is for all the future question seekers that are struggling to create a URL shortener without 3rd party API's.
Simply use a NSMutableAttributedString and pass into a UIDataDetectorTypeLink capable object:
Let's say your user inputs a link or passes a string entirely:
I am a user. I want to enter this URL to share to all other awesome users of Apple products, and only Apple products :). Check out my link here http://www.androidpolice.com/2015/08/16/an-alleged-leak-of-lgs-nexus-5-2015-bullhead-pops-up-on-google/
We can easily extract the text using commonly frequented methods:
NSString *userInput = #"I am a user. I want to enter this URL to share to all other awesome users of Apple products, and only Apple products :). Check out my link here http://www.androidpolice.com/2015/08/16/an-alleged-leak-of-lgs-nexus-5-2015-bullhead-pops-up-on-google/"
// get the range of the substring (url) starting with #"http://"
NSRange httpRange = [userInput rangeOfString:#"http://" options:NSCaseInsensitiveSearch];
if (httpRange.location == NSNotFound) {
NSLog(#"URL not found");
} else {
//Get the new string from the range we just found
NSString *urlString = [userInput substringFromIndex:httpRange.location];
//create the new url
NSURL *newURL = [NSURL URLWithString:urlString];
//cut off the last components of the string
NSString *shortenedName = [urlString stringByDeletingLastPathComponent];
//new output
NSLog(#"%#", [NSString stringWithFormat:#"\n original user input : \n %# \n original URL name : \n %# \n shortenedName : \n %#", userInput, urlString, shortenedName]);
//We have everything we need so all we have remaining to do is create the attributes and pass into a UITextView.
self.someTextView.attributedText = [self createHyperLinkForURL:newURL withName:shortenedName];
}
Where [self createHyperLinkForURL:newURL withName:shortenedName];
-(NSMutableAttributedString *)createHyperLinkForURL:(NSURL *)url withName:(NSString *)hyperLinkText {
NSMutableAttributedString *string = [[NSMutableAttributedString alloc] initWithString:hyperLinkText];
[string beginEditing];
[string addAttribute:NSLinkAttributeName
value:url
range:NSMakeRange(0, string.length)];
[string endEditing];
return string;
}

Is it possible to detect links within an NSString that have spaces in them with NSDataDetector?

First off, I have no control over the text I am getting. Just wanted to put that out there so you know that I can't change the links.
The text I am trying to find links in using NSDataDetector contains the following:
<h1>My main item</h1>
<img src="http://www.blah.com/My First Image Here.jpg">
<h2>Some extra data</h2>
The detection code I am using is this, but it will not find this link:
NSDataDetector *linkDetector = [NSDataDetector dataDetectorWithTypes:NSTextCheckingTypeLink error:nil];
NSArray *matches = [linkDetector matchesInString:myHTML options:0 range:NSMakeRange(0, [myHTML length])];
for (NSTextCheckingResult *match in matches)
{
if ([match resultType] == NSTextCheckingTypeLink)
{
NSURL *url = [match URL];
// does some stuff
}
}
Is this a bug with Apple's link detection here, where it can't detect links with spaces, or am I doing something wrong?
Does anyone have a more reliable way to detect links regardless of whether they have spaces or special characters or whatever in them?
I just got this response from Apple for a bug I filed on this:
We believe this issue has been addressed in the latest iOS 9 beta.
This is a pre-release iOS 9 update.
Please refer to the release notes for complete installation
instructions.
Please test with this release. If you still have issues, please
provide any relevant logs or information that could help us
investigate.
iOS 9 https://developer.apple.com/ios/download/
I will test and let you all know if this is fixed with iOS 9.
You could split the strings into pieces using the spaces so that you have an array of strings with no spaces. Then you could feed each of those strings into your data detector.
// assume str = <img src="http://www.blah.com/My First Image Here.jpg">
NSArray *components = [str componentsSeparatedByString:#" "];
for (NSString *strWithNoSpace in components) {
// feed strings into data detector
}
Another alternative is to look specifically for that HTML tag. This is a less generic solution, though.
// assume that those 3 HTML strings are in a string array called strArray
for (NSString *htmlLine in strArray) {
if ([[htmlLine substringWithRange:NSMakeRange(0, 8)] isEqualToString:#"<img src"]) {
// Get the url from the img src tag
NSString *urlString = [htmlLine substringWithRange:NSMakeRange(10, htmlLine.length - 12)];
}
}
I've found a very hacky way to solve my issue. If someone comes up with a better solution that can be applied to all URLs, please do so.
Because I only care about URLs ending in .jpg that have this problem, I was able to come up with a narrow way to track this down.
Essentially, I break out the string into components based off of them beginning with "http:// into an array. Then I loop through that array doing another break out looking for .jpg">. The count of the inner array will only be > 1 when the .jpg"> string is found. I then keep both the string I find, and the string I fix with %20 replacements, and use them to do a final string replacement on the original string.
It's not perfect and probably inefficient, but it gets the job done for what I need.
- (NSString *)replaceSpacesInJpegURLs:(NSString *)htmlString
{
NSString *newString = htmlString;
NSArray *array = [htmlString componentsSeparatedByString:#"\"http://"];
for (NSString *str in array)
{
NSArray *array2 = [str componentsSeparatedByString:#".jpg\""];
if ([array2 count] > 1)
{
NSString *stringToFix = [array2 objectAtIndex:0];
NSString *fixedString = [stringToFix stringByReplacingOccurrencesOfString:#" " withString:#"%20"];
newString = [newString stringByReplacingOccurrencesOfString:stringToFix withString:fixedString];
}
}
return newString;
}
You can use NSRegularExpression to fix all URLs by using a simple regex to detect the links and then just encode the spaces (if you need more complex encoding you can look into CFURLCreateStringByAddingPercentEscapes and there are plenty of examples out there). The only thing that might take you some time if you haven't worked with NSRegularExpression before is how to iterate the results and do the replacing, the following code should do the trick:
NSError *error = NULL;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:#"src=\".*\"" options:NSRegularExpressionCaseInsensitive error:&error];
if (!error)
{
NSInteger offset = 0;
NSArray *matches = [regex matchesInString:myHTML options:0 range:NSMakeRange(0, [myHTML length])];
for (NSTextCheckingResult *result in matches)
{
NSRange resultRange = [result range];
resultRange.location += offset;
NSString *match = [regex replacementStringForResult:result inString:myHTML offset:offset template:#"$0"];
NSString *replacement = [match stringByReplacingOccurrencesOfString:#" " withString:#"%20"];
myHTML = [myHTML stringByReplacingCharactersInRange:resultRange withString:replacement];
offset += ([replacement length] - resultRange.length);
}
}
Try this regex pattern: #"<img[^>]+src=(\"|')([^\"']+)(\"|')[^>]*>" with ignore case ... Match index=2 for source url.
regex demo in javascript: (Try for any help)
Demo
Give this snippet a try (I got the regexp from your first commentator user3584460) :
NSError *error = NULL;
NSString *myHTML = #"<http><h1>My main item</h1><img src=\"http://www.blah.com/My First Image Here.jpg\"><h2>Some extra data</h2><img src=\"http://www.bloh.com/My Second Image Here.jpg\"><h3>Some extra data</h3><img src=\"http://www.bluh.com/My Third-Image Here.jpg\"></http>";
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:#"src=[\"'](.+?)[\"'].*?>" options:NSRegularExpressionCaseInsensitive error:&error];
NSArray *arrayOfAllMatches = [regex matchesInString:myHTML options:0 range:NSMakeRange(0, [myHTML length])];
NSTextCheckingResult *match = [regex firstMatchInString:myHTML options:0 range:NSMakeRange(0, myHTML.length)];
for (NSTextCheckingResult *match in arrayOfAllMatches) {
NSRange range = [match rangeAtIndex:1];
NSString* substringForMatch = [myHTML substringWithRange:range];
NSLog(#"Extracted URL : %#",substringForMatch);
}
In my log, I have :
Extracted URL : http://www.blah.com/My First Image Here.jpg
Extracted URL : http://www.bloh.com/My Second Image Here.jpg
Extracted URL : http://www.bluh.com/My Third-Image Here.jpg
You should not use NSDataDetector with HTML. It is intended for parsing normal text (entered by an user), not computer-generated data (in fact, it has many heuristics to actually make sure it does not detect computer-generated things which are probably not relevant to the user).
If your string is HTML, then you should use an HTML parsing library. There are a number of open-source kits to help you do that. Then just grab the href attributes of your anchors, or run NSDataDetector on the text nodes to find things not marked up without polluting the string with tags.
URLs really shouldn't contain spaces. I'd remove all spaces from the string before doing anything URL-related with it, something like the following
// Custom function which cleans up strings ready to be used for URLs
func cleanStringForURL(string: NSString) -> NSString {
var temp = string
var clean = string.stringByReplacingOccurrencesOfString(" ", withString: "")
return clean
}

How to convert formatted content of NSTextView to string

I need transfer content of NSTextView from Mac app to iOS app. I'm using XML as transfered file format.
So I need to save content of NSTextView (text, fonts, colors atd.) as a string. Is there any way how to do that?
One way to do this is to archive the NSAttributedString value. Outline sample code typed directly into answer:
NSTextView *myTextView;
NSString *myFilename;
...
[NSKeyedarchiver archiveRootObject:myTextStorage.textStorage
toFile:myFilename];
To read it back:
myTextView.textStorage.attributedString = [NSKeyedUnarchiver unarchiveObjectWithFile:myFilename];
That's all that is needed to create and read back a file. There are matching methods which create an NSData rather than a file, and you can convert an NSData into an NSString or just insert one into an NSDictionary and serialise that as a plist (XML), etc.
Your best bet is probably to store the text as RFTD and load it as such in the other text view via an NSAttributedString.
// Load
NSFileWrapper* filewrapper = [[NSFileWrapper alloc] initWithPath: path];
NSTextAttachment *attachment = [[NSTextAttachment alloc] initWithFileWrapper: filewrapper];
NSAttributedString* origFile = [NSAttributedString attributedStringWithAttachment: attachment];
// Save
NSData *data = [origFile RTFDFromRange: NSMakeRange(0, [origFile length]) documentAttributes: nil];
[[NSFileManager defaultManager] createFileAtPath: path contents: data attributes:nil];

MWFeedParser - RSS with images

I have problem, I'm using MWFeedParser Rss reader in my iOS aplication and it works well, but I need to fetch the images from my feed. Can you help me please?
Here is url of that MWFeedParser project: GitHub
I have used this in my cellForRowAtIndexPath function so that it searches for images as the cell is displayed
MWFeedItem *item = itemsToDisplay[indexPath.row];
if (item) {
NSString *htmlContent = item.content;
NSString *imgSrc;
// find match for image
NSRange rangeOfString = NSMakeRange(0, [htmlContent length]);
NSRegularExpression* regex = [NSRegularExpression regularExpressionWithPattern:#"(<img.*?src=\")(.*?)(\".*?>)" options:0 error:nil];
if ([htmlContent length] > 0) {
NSTextCheckingResult *match = [regex firstMatchInString:htmlContent options:0 range:rangeOfString];
if (match != NULL ) {
NSString *imgUrl = [htmlContent substringWithRange:[match rangeAtIndex:2]];
NSLog(#"url: %#", imgUrl);
//NSLog(#"match %#", match);
if ([[imgUrl lowercaseString] rangeOfString:#"feedburner"].location == NSNotFound) {
imgSrc = imgUrl;
}
}
}
}
Note I am also ignoring the image if it has 'feedburner' in the url to avoid feedburner type icons.
I am also using AFNetwork's class when I show the image later
if (imgSrc != nil && [imgSrc length] != 0 ) {
[myimage setImageWithURL:[NSURL URLWithString:imgSrc] placeholderImage:[UIImage imageNamed:IMAGETABLENEWS]];
} else {
NSLog(#"noimage");
cell.imageView.image = [UIImage imageNamed:IMAGETABLENEWS];
//[myimage setImage:[UIImage imageNamed:IMAGETABLENEWS]];
}
I have left in my commented NSLog parts so you can uncomment and check if you want
Make sure you have an IMAGETABLENEWS constant for the placeholder or get rid of that part as you need.
This is only a very simple check of images in the html text and is not comprehensive. It served my purpose and may help you get your logic right for doing something more detailed.
In case your MWFeedItem has an image embedded in it's enclosure-tag, you might want to consider to do the following:
MWFeedItem has a property called enclosures. It's an array containing one or more dictionaries.
This dictionaries are generated in
- (BOOL)createEnclosureFromAttributes:(NSDictionary *)attributes andAddToItem:(MWFeedItem *)currentItem (MWFeedParser.M).
These dictionaries have three keys (if available): url, type & length.
That first one is probably the one you're looking for. I managed to get it like this:
Feed Example
<item>
<title>Item title</title>
<link>http://www.yourdomain.com</link>
<description>Item description</description>
<pubDate>Mon, 01 Jan 2016 12:00:00 +0000</pubDate>
<enclosure url="http://www.yourdomain.com/image.jpg" length="0" type="image/jpeg"></enclosure>
<category>Algemeen</category>
</item>
Please notice the image link inside <enclosure></enclosure>
YourViewController.m
- (void)feedParser:(MWFeedParser *)parser didParseFeedItem:(MWFeedItem *)item {
NSArray *EnclosureArray = item.enclosures;
NSDictionary *ImageDict = [EnclosureArray objectAtIndex:0]; // 0 Should be replaced with the index of your image dictionary.
NSString *ImageLink = [ImageDict objectForKey:#"url"];
// Returns: http://www.yourdomain.com/image.jpg
}

Resources