麻烦保存NSAttributedString,与图像,到一个RTF文件

我有一些输出是一个非常简单的RTF文件。 当我生成这个文件,用户可以通过电子邮件发送。 所有这一切正常。 文件看起来不错。 一旦我有NSAttributedString,我做了一个NSData块,并将其写入文件,如下所示:

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

这个文件可以通过电子邮件发送。 当我检查电子邮件都很好。

现在,我负责在文档的顶部添加一个UIImage。 太棒了,所以我创build了一个属性如下所示的string:

 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"]]; 

在这一点上,在Xcode中,我可以在imageAttrString上做一个QuickLook,它画得很好。

一旦build立了这个string,我正在这样做:

 [attrString appendAttributedString:imageAttrString]; 

然后再添加我最初生成的所有其他属性文本。

当我现在看文件时,没有图像。 debugging器中的QuickLook看起来不错,但在最终输出中没有图像。

在此先感谢您的帮助。

尽pipeRTF在Windows上支持embedded式图像,但显然它不在OS X上.RTF由Microsoft开发,他们在1.5版本中添加了embedded式图像( http://en.wikipedia.org/wiki/Rich_Text_Format#Version_changes )。 我认为,苹果采取了格式的早期版本,他们的解决scheme,在文件中的图像是RTFD。 以下是苹果公司有关RTF的文章:

富文本格式(RTF)是由Microsoft Corporationdevise的文本格式化语言。 您可以使用包含散布的RTF命令,组和转义序列的纯文本来表示字符,段落和文档格式属性。 RTF被广泛用作文档交换格式,以在应用程序和计算平台之间传输具有格式化信息的文档。 苹果已经用自定义命令扩展了RTF,本章将对其进行描述。

所以没有提到图像。 最后要certificateRTF不支持mac上的图像,下载这个RTF文件 – 它将在Windows写字板中显示照片,并不会显示在OS X TextEdit中。

所以Larme提到 – 在添加附件时,您应该selectRTFD文件types。 维基百科:

RTF格式目录(也称为RTFD(由于其扩展名为.rtfd)或带有附件的RTF格式)

虽然你将能够通过dataFromRange:documentAttributes:@{NSDocumentTypeDocumentAttribute: NSRTFDTextDocumentType} error:]获得包含文本和图像的NSData对象(根据其大小来判断),但是可能无法保存它可以成功打开。 至less – 我无法做到这一点。

这可能是因为实际上RTFD不是文件格式 – 它是一个包的格式。 要检查它,你可以使用你的Mac上的TextEdit来创build一个新的文档,添加图像和文本到它并保存为一个文件。 然后右键单击该文件,然后select“显示软件包内容”,您将注意到目录包含您的图像和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上的其他电子邮件应用程序中使用,因为它是知道如何显示.rtfd.zip的UIWebView。 以下是关于它的技术说明: https : //developer.apple.com/library/ios/qa/qa1630/_index.html#//apple_ref/doc/uid/DTS40008749

所以底线是 – 它可以做,但RTFD文件将是电子邮件的附件,而不是电子邮件内容本身。 如果您想将其作为电子邮件内容,您应该考虑将图像embedded到HTML中,并将邮件作为HTML发送。

正如Andris所说,Apple RTF的实现不支持embedded式图像。

RTFD不是一个真正的select,因为只有less数OS X应用程序可以打开RTFD文件。 例如MS Office不能。

在某些情况下创build带有embedded式图像的HTML文件可能会有所帮助,但是 – 例如 – 大多数电子邮件客户端不支持带有embedded式图像的HTML(Apple Mail,但Outlook不支持)。

幸运的是,有一个解决scheme来创buildembedded图像的真正的RTF文件!

由于RTF格式当然支持embedded式图像(只有Apples实现没有),NSAttributedStrings(NSTextAttachments)中的图像可以(手动)编码到RTFstream中。

以下类别可以完成所有需要的工作:

 /** 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