Extract Uiimage from Nsattributed String

Extract UIImage from NSAttributed String

You have to enumerate the NSAttributedString looking for NSTextAttachments.

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



Leave a reply



Submit