Search code examples
cocoansattributedstring

How do you get the image data from NSAttributedString


I have an NSTextView. I paste an image into it and see it. When I get the NSTextAttachment for the NSAttributedString of the text view, it's file wrapper is nil. How do I get the image data that was pasted into the text view?

I'm using a category on NSAttributedString to get the text attachments. I would prefer not to write to disk if it's possible.

- (NSArray *)allAttachments
{
    NSError *error = NULL;
    NSMutableArray *theAttachments = [NSMutableArray array];
    NSRange theStringRange = NSMakeRange(0, [self length]);
    if (theStringRange.length > 0)
    {
        NSUInteger N = 0;
        do
        {
            NSRange theEffectiveRange;
            NSDictionary *theAttributes = [self attributesAtIndex:N longestEffectiveRange:&theEffectiveRange inRange:theStringRange];
            NSTextAttachment *theAttachment = [theAttributes objectForKey:NSAttachmentAttributeName];
            if (theAttachment != NULL){
                NSLog(@"filewrapper: %@", theAttachment.fileWrapper);
                [theAttachments addObject:theAttachment];
            }
            N = theEffectiveRange.location + theEffectiveRange.length;
        }
        while (N < theStringRange.length);
    }
    return(theAttachments);
}

Solution

    1. Enumerate the attachments. [NSTextStorage enumerateAttribute:...]
    2. Get the attachment's filewrapper.
    3. Write to a URL.

      [textStorage enumerateAttribute:NSAttachmentAttributeName
                              inRange:NSMakeRange(0, textStorage.length)
                              options:0
                           usingBlock:^(id value, NSRange range, BOOL *stop)
       {
           NSTextAttachment* attachment = (NSTextAttachment*)value;
           NSFileWrapper* attachmentWrapper = attachment.fileWrapper;
           [attachmentWrapper writeToURL:outputURL options:NSFileWrapperWritingAtomic originalContentsURL:nil error:nil];
           (*stop) = YES; // stop so we only write the first attachment
       }];
      

    This sample code will only write the first attachment to outputURL.