Extract UIImage from NSAttributed String
You have to enumerate the NSAttributedString
looking for NSTextAttachment
s.
NSMutableArray *imagesArray = [[NSMutableArray alloc] init];
[attributedString enumerateAttribute:NSAttachmentAttributeName
inRange:NSMakeRange(0, [attributedString length])
options:0
usingBlock:^(id value, NSRange range, BOOL *stop)
{
if ([value isKindOfClass:[NSTextAttachment class]])
{
NSTextAttachment *attachment = (NSTextAttachment *)value;
UIImage *image = nil;
if ([attachment image])
image = [attachment image];
else
image = [attachment imageForBounds:[attachment bounds]
textContainer:nil
characterIndex:range.location];
if (image)
[imagesArray addObject:image];
}
}];
As you can see, there is the test if ([attachment image])
. That's because it seems that if you created the NSTextAttachment
to put with NSAttachmentAttributeName
it will exist and your image will be there. But if you use for example an image from the web and convert it as a NSTextAttachment
from a HTML code, then [attachment image]
will be nil and you won't be able to get the image.
You can see using breakpoints with this snippet (with setting real image URL and an real image name from bundle.
NSString *htmlString = @"http://anImageURL\">Blahttp://anOtherImageURL\"> Test retest";
NSError *error;
NSAttributedString *attributedStringFromHTML = [[NSAttributedString alloc] initWithData:[htmlString dataUsingEncoding:NSUTF8StringEncoding]
options:@{NSDocumentTypeDocumentAttribute:NSHTMLTextDocumentType,
NSCharacterEncodingDocumentAttribute:@(NSUTF8StringEncoding)}
documentAttributes:nil
error:&error];
NSTextAttachment *textAttachment = [[NSTextAttachment alloc] init];
[textAttachment setImage:[UIImage imageNamed:@"anImageNameFromYourBundle"]];
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithAttributedString:attributedStringFromHTML];
[attributedString appendAttributedString:[NSAttributedString attributedStringWithAttachment:textAttachment]];
How to get Custom Text Equivalent of NSAttributedString containing UIImage?
Got the solution myself.
We need to do the following :-
1. To retrieve the contents, we need to add a method (richText) to UITextView(customCategory) say UITextView(RichText) (text is already there so I recommend richText)in order to retrieve the desired text values.
2. Save the custom text into the NSTextAttachment. This was done by subclassing NSTextAttachment (into customNSTextAttatchment) and adding an @property id custom.
Now, after creation of customNSTextAttachment(similarly as the code in my question), we can assign our desired NSString into custom.
To retrieve, we do the following:
@implementation UITextView(RichText)
-(NSString*)richText
{
__block NSString *str=self.attributedText.string; //Trivial String representation
__block NSMutableString *final=[NSMutableString new]; //To store customized text
[self.attributedText enumerateAttributesInRange:NSMakeRange(0, self.attributedText.length) options:0 usingBlock:
^(NSDictionary *attributes, NSRange range, BOOL *stop) {
//enumerate through the attributes
NSString *v;
NSObject* x=[attributes valueForKey:@"NSAttachment"];
if(x) //YES= This is an attachment
{
v=x.custom; // Get Custom value (i.e. the previously stored NSString).
if(v==nil) v=@"";
}
else v=[str substringWithRange:range]; //NO=This is a text block.
[final appendString:v]; //Append the value
}];
return final;
}
Inverse UIImage from NSAttributedString
Use NSBackgroundColorAttributeName
to set background for green and NSForegroundColorAttributeName
the text to white.
The docs include:
NSString *const NSForegroundColorAttributeName;
NSString *const NSBackgroundColorAttributeName;
at https://developer.apple.com/library/ios/documentation/UIKit/Reference/NSAttributedString_UIKit_Additions/Reference/Reference.html#//apple_ref/doc/uid/TP40011688
How to retrieve photo from UITextView after adding it using NSAttributedString?
Retrieving images are explained here.
Your new issue is that if two image are consecutive and the same.
So instead of:
if (image)
[imagesArray addObject:image];
You need to to other checks, this will do for two images, but you can't know if they are consecutive or not.
if (image)
{
if ([imagesArray lastObject] != image)
[imagesArray addObject:image];
}
So you need to keep references of the NSRange
too.
if (image)
{
if ([imagesArray count] > 0)
{
NSDictionary *lastFound = [imagesArray lastObject];
NSRange lastRange = [lastFound[@"range"] rangeValue];
UIImage *lastImage = lastFound[@"image"];
if (lastImage == image && lastRange.location+lastRange.length == range.location)
{ //Two images same & consecutive}
else
{
[imagesArray addObject:@{@"image":image, @"range":[NSValue valueWithRange:range]}];
}
}
else
{
[imagesArray addObject:@{@"image":image, @"range":[NSValue valueWithRange:range]}];
}
}
Retrieving only images:
NSArray *onlyImages = [imagesArray valueForKey:@"image"];
Note: I didn't check if this code compile, but you should get the whole idea.
My range calculation may be wrong (some +1/-1 missing, but nothing difficult to verify with test), and what if there is space between two same consecutive images? You may want to get the String between (NSString *stringBetween = [[attributedString string] substringWithRange:NSMakeRange(lastRange.location+lastRange.length, range.location-lastRange.location+lastRange.length)]
, and check for spaces, ponctuation characters (there are a lot of way to do it).
Additional note:
In your case, just comparing image != newImage
may be enough, but if you use web images, or even two images with different name in your bundle but that are identical, that's another issue to know if they are the same. There are a few questions on SO about comparing two images, but that should take some time/ressources.
How to pull NSImage from NSTextAttachment in NSTextView?
Since the NSImage
was created with an NSTextAttachmentCell
, it must be retrieved from the attachment cell. The key is to cast the cell as NSCell
and then grab the image
property. So, replacing the section of code from the original
if z != nil {
let cell = z!.attachmentCell as? NSCell
if cell != nil {
let image = cell?.image
}
}
Related Topics
What Is the Height of Iphone's Onscreen Keyboard
How to Recognize Which Pin Was Tapped
Xcode 8 - Ib Designables - Failed to Render and Update Auto Layout Status, the Agent Crashed
App Rejected Because of "Missing Push Notification Entitlement"
Uitableview - Change Section Header Color
Getting User Location Every N Minutes After App Goes to Background
Nsurlsession: How to Increase Time Out for Url Requests
How to Change Device Volume on iOS - Not Music Volume
Volunteermatch API Objective C
Comparing Nsdates Without Time Component
How to Capitalize Each Word in a String Using Swift iOS
How to Draw a Line Programmatically from a View Controller
Custom Mkannotation Callout Bubble with Button
iPhone Sdk Cgaffinetransform Getting the Angle of Rotation of an Object