Problem saving NSAttributedString, with image, to RTF file

I have output, which is a very simple RTF file. When I create this document, the user can send it by email. All of this works great. The document looks good. When I have an NSAttributedString, I make an NSData block and write it to a file, for example:

NSData* rtfData = [attrString dataFromRange:NSMakeRange(0, [attrString length]) documentAttributes:@{NSDocumentTypeDocumentAttribute: NSRTFTextDocumentType} error:&error];

This file can be emailed. When I check the letter, everything is fine.

Now I am tasked with adding UIImage at the top of the document. Great, so I create an attribute string as follows:

NSTextAttachment *attachment = [[NSTextAttachment alloc] init];

UIImage* image = [UIImage imageNamed:@"logo"];
attachment.image = image;
attachment.bounds = CGRectMake(0.0f, 0.0f, image.size.width, image.size.height);

NSMutableAttributedString *imageAttrString = [[NSAttributedString attributedStringWithAttachment:attachment] mutableCopy];

// sets the paragraph styling of the text attachment

NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init] ;

[paragraphStyle setAlignment:NSTextAlignmentCenter];            // centers image horizontally

[paragraphStyle setParagraphSpacing:10.0f];   // adds some padding between the image and the following section

[imageAttrString addAttribute:NSParagraphStyleAttributeName value:paragraphStyle range:NSMakeRange(0, [imageAttrString length])];
[imageAttrString appendAttributedString:[[NSAttributedString alloc] initWithString:@"\n\n"]];

At this point, in Xcode, I can make QuickLook on imageAttrString and it draws fine.

Once this line is built, I do this:

[attrString appendAttributedString:imageAttrString];

And then adding to the rest of the attribute that I originally created.

, . QuickLook , .

.

+4
2

RTF Windows, -, OS X. RTF Microsoft, 1.5 (http://en.wikipedia.org/wiki/Rich_Text_Format#Version_changes). , Apple , RTFD. Apple RTF:

Rich Text Format (RTF) - , Microsoft. , , RTF, escape-. RTF . Apple RTF , .

, . , , RTF Mac, RTF - Windows WordPad OS X TextEdit.

Larme - RTFD . :

Rich Text Format, RTFD (- .rtfd) Rich Text Format

NSData, , ( ), dataFromRange:documentAttributes:@{NSDocumentTypeDocumentAttribute: NSRTFDTextDocumentType} error:] , , , . , .

, , , RTFD - . , TextEdit Mac , . " ", , , RTF.

:

NSFileWrapper *fileWrapper = [imageAttrString fileWrapperFromRange:NSMakeRange(0, [imageAttrString length]) documentAttributes:@{NSDocumentTypeDocumentAttribute: NSRTFDTextDocumentType} error:&error];
[fileWrapper writeToURL:yourFileURL options:NSFileWrapperWritingAtomic originalContentsURL:nil error:&error];

, -, NSFileWrapper , RTFD, NSData , .

- ? RTFD , , , , .rtfd.zip. , , , . , Gmail , , iOS, UIWebView , .rtfd.zip. : https://developer.apple.com/library/ios/qa/qa1630/_index.html#//apple_ref/doc/uid/DTS40008749

, - , RTFD , . , , , , HTML HTML.

+4

, Apple RTF .

RTFD , OS X RTFD . , MS Office .

HTML , , , HTML (Apple Mail , Outlook ).

, , RTF !

RTF, , ( ), NSAttributedStrings (NSTextAttachments) () RTF.

:

/**
 NSAttributedString (MMRTFWithImages)

 */
@interface NSAttributedString (MMRTFWithImages)

- (NSString *)encodeRTFWithImages;

@end

/**
 NSAttributedString (MMRTFWithImages)

 */
@implementation NSAttributedString (MMRTFWithImages)

/*
 encodeRTFWithImages

 */
- (NSString *)encodeRTFWithImages {

    NSMutableAttributedString*  stringToEncode = [[NSMutableAttributedString alloc] initWithAttributedString:self];
    NSRange                     strRange = NSMakeRange(0, stringToEncode.length);

    //
    // Prepare the attributed string by removing the text attachments (images) and replacing them by
    // references to the images dictionary
    NSMutableDictionary*        attachmentDictionary = [NSMutableDictionary dictionary];
    while (strRange.length) {
        // Get the next text attachment
        NSRange effectiveRange;
        NSTextAttachment* textAttachment = [stringToEncode attribute:NSAttachmentAttributeName
                                                             atIndex:strRange.location
                                                      effectiveRange:&effectiveRange];

        strRange = NSMakeRange(NSMaxRange(effectiveRange), NSMaxRange(strRange) - NSMaxRange(effectiveRange));

        if (textAttachment) {
            // Text attachment found -> store image to image dictionary and remove the attachment
            NSFileWrapper*  fileWrapper = [textAttachment fileWrapper];

            UIImage*    image = [[UIImage alloc] initWithData:[fileWrapper regularFileContents]];
            // Kepp image size
            UIImage*    scaledImage = [self imageFromImage:image
                                               withSize:textAttachment.bounds.size];
            NSString*   imageKey = [NSString stringWithFormat:@"_MM_Encoded_Image#%zi_", [scaledImage hash]];
            [attachmentDictionary setObject:scaledImage
                                     forKey:imageKey];

            [stringToEncode removeAttribute:NSAttachmentAttributeName
                                      range:effectiveRange];
            [stringToEncode replaceCharactersInRange:effectiveRange
                                          withString:imageKey];
            strRange.length += [imageKey length] - 1;
        } // if
    } // while

    //
    // Create the RTF stream; without images but including our references
    NSData*             rtfData = [stringToEncode dataFromRange:NSMakeRange(0, stringToEncode.length)
                                    documentAttributes:@{
                                                         NSDocumentTypeDocumentAttribute:   NSRTFTextDocumentType
                                                         }
                                                 error:NULL];
    NSMutableString*    rtfString = [[NSMutableString alloc] initWithData:rtfData
                                                              encoding:NSASCIIStringEncoding];

    //
    // Replace the image references with hex encoded image data
    for (id key in attachmentDictionary) {
        NSRange     keyRange = [rtfString rangeOfString:(NSString*)key];
        if (NSNotFound != keyRange.location) {
            // Reference found -> replace with hex coded image data
            UIImage*    image = [attachmentDictionary objectForKey:key];
            NSData*     pngData = UIImagePNGRepresentation(image);

            NSString*   hexCodedString = [self hexadecimalRepresentation:pngData];
            NSString*   encodedImage = [NSString stringWithFormat:@"{\\*\\shppict {\\pict \\pngblip %@}}", hexCodedString];

            [rtfString replaceCharactersInRange:keyRange withString:encodedImage];
        }
    }
    return rtfString;
}

/*
 imageFromImage:withSize:

 Scales the input image to pSize
 */
- (UIImage *)imageFromImage:(UIImage *)pImage
                   withSize:(CGSize)pSize {

    UIGraphicsBeginImageContextWithOptions(pSize, NO, 0.0);
    [pImage drawInRect:CGRectMake(0, 0, pSize.width, pSize.height)];

    UIImage*    resultImage = UIGraphicsGetImageFromCurrentImageContext();

    UIGraphicsEndImageContext();

    return resultImage;
}

/*
 hexadecimalRepresentation:

 Returns a hex codes string for all bytes in a NSData object
 */
- (NSString *) hexadecimalRepresentation:(NSData *)pData {

    static const char*  hexDigits = "0123456789ABCDEF";

    NSString*   result = nil;

    size_t      length = pData.length;
    if (length) {

        NSMutableData*  tempData = [NSMutableData dataWithLength:(length << 1)];    // double length
        if (tempData) {
            const unsigned char*    src = [pData bytes];
            unsigned char*          dst = [tempData mutableBytes];

            if ((src) &&
                (dst)) {
                // encode nibbles
                while (length--) {
                    *dst++ = hexDigits[(*src >> 4) & 0x0F];
                    *dst++ = hexDigits[(*src++ & 0x0F)];
                } // while

                result = [[NSString alloc] initWithData:tempData
                                               encoding:NSASCIIStringEncoding];
            } // if
        } // if
    } // if
    return result;
}

@end

: http://www.cocoadev.com/RTFOrWordDocsWithImages

+3

Source: https://habr.com/ru/post/1538615/


All Articles