我正在尝试在保存a的内容时优化存储空间NSTextView,即其NSTextStorage属性本身a NSAttributedString.
将其保存为Data,例如使用该rtfd(from:documentAttributes:)方法,并作为Codable结构的一部分,会产生非常大的字符串,比内容本身大得多,尤其是在将图像插入到内容中时NSTextView.例如,插入200K图像将生成5MB的JSON文件.
旁注:当Data对象直接编码而不是编码对象的属性时更糟糕,因为它是以小整数数组的形式编码而不是任意字符串.我不知道为什么,虽然我能够通过插入Data一个简单的包装结构来防止这种情况.
奇怪的是,使用ZIP压缩实际的JSON文件仍然会产生4MB的文件,只有20%的增益,因此我不清楚200K图像如何变成如此庞大,难以压缩的编码字符串.
我想弄清楚NSAttributedString使用Codable协议有效存储的正确方法是什么.非常感谢任何提示或建议.
我也想知道是否有一个有效的二进制编码选项Codable.
TL; DR:RTFD将图像编码为PNG,但您可以将其编码为JPG而不是节省空间.如果您有时间创建自定义格式,则自定义格式可能会更好更容易.
NSAttributedString 可以编码为HTML,rtf,rtfd,纯文本,各种Office/Word格式等.鉴于这些都是官方规格必须遵循的官方格式,所以没有太多可以做到的节省空间除了:
要么
在支持的格式中,RTFD确实听起来最适合您的用例,因为它包括对图像等附件的支持.请随意尝试其他包含的格式,其中的描述如下"其他格式".
将其保存为数据,例如使用rtfd(from:documentAttributes :)方法,并作为Codable结构的一部分,会产生一个非常大的字符串,比内容本身大得多,尤其是在将图像插入NSTextView时.例如,插入200K图像将生成5MB的JSON文件.
要了解此处发生的情况,请尝试以下代码:
do {
let rtfd = try someAttributedString.rtfdFileWrapper(from: NSRange(location: 0, length: someAttributedString.length), documentAttributes: [:])
rtfd?.write(to: URL(fileURLWithPath: "/Users/yourname/someFolder/RTFD.rtfd"), options: .atomic, originalContentsURL: nil)
} catch {
print("\(error)")
}
Run Code Online (Sandbox Code Playgroud)
当你打电话时rtfd(from:documentAttributes:),你会变得平坦Data.然后可以在某处对此平坦数据进行编码并将其读回NSAttributedString.但不要搞错:RTFD是一种包格式("D"代表目录).因此,通过调用rtfdFileWrapper(from:documentAttributes:)并将其写入URL带有rtfd扩展名的a,我们可以看到rtfd(from:documentAttributes:)复制的实际包格式,但是作为目录而不是原始数据.在Finder中,右键单击生成的文件,然后选择"显示包内容".
RTFD包中包含一个RTF文件,用于指定文本和属性,以及每个附件的副本.那么为什么你的榜样如此之大?在我的测试中,答案似乎是RTFD希望以PNG格式找到它的图像.在调用rtfdFileWrapper(from:documentAttributes:)或时rtfd(from:documentAttributes:),任何图像附件似乎都被写为PNG文件,这会占用更多空间.发生这种情况是因为你的图像在被包裹NSImage之前被包裹了NSTextAttachment.的NSImage是能够将图像数据写入列于其它格式,包括更大的格式,如PNG.
我假设您尝试的图像采用JPEG等压缩格式,并将NSAttributedString其作为PNG写入RTFD.
JPEG改为使用
假设你对图像被压缩并且没有像alpha通道这样的信息没问题,你应该能够用jpg图像创建一个RTFD文件.
例如,只需将生成的PNG图像替换为原始JPG图像,我就可以从超过12 MB(大图像)获得低至2.8 MB的RTFD文件.这最初对TextEdit不敏感,但我随后将图像的文件扩展名更改为.png(即使它仍然是JPG)并且它接受了它.
在代码中它甚至更简单.只需更改添加图像附件的方式,您就可以逃脱.
// Don't do this unless you want PNG
let image = NSImage(contentsOf: ...) // NSImage will write to a larger PNG file
let attachment = NSTextAttachment()
attachment.image = image
// Do this if you want smaller files
let image = try? Data(contentsOf: ...) // This will remain in raw JPG format
let attachment = NSTextAttachment(data: image, ofType: kUTTypeJPEG as String) // Explicitly specify JPG
Run Code Online (Sandbox Code Playgroud)
然后当你NSAttributedString用它创建一个新的NSTextAttachment并附加它时NSTextStorage,编写RTFD数据将显着变小.
当然,如果您依赖Cocoa UI/API来附加图像,则可能无法控制此过程.这可能会使过程变得更加困难,您可能需要通过交换图像来修改生成的数据.
由于没有控制附件添加过程并且需要平面数据,上面刚刚描述的方法可能是不方便的.在这种情况下,自定义格式可能会更好.
没有什么可以阻止你设计自己的格式(二进制,文本,包,等等),然后为它编写一个编码器.您可以指定特定的图像格式或支持多种图像格式.由你决定.除非你是一个奇特的文字处理器,否则你可能不需要像字体一样存储所有属性.
我也想知道Codable是否有一个有效的二进制编码选项.
首先,请注意,这NSAttributedString是一个Objective-C类(在Apple平台上使用时)并且符合NSSecureCoding而不是Codable.
请注意,您不能扩展NSAttributedString以符合Codable,因为只有通过保证初始化程序也包含在所有子类中才能满足init(from:)要求Decodable.由于这个类是非类的final,这意味着它只能被a满足required init.必需的初始化程序只能在原始声明中指定,而不能在扩展名中指定.
因此,如果要符合它Codable,则需要使用包装器对象.enumerateAttributes(in:options:using:)应该有助于获取需要编码的属性和原始字符,但您还需要确保注意图像.
对于二进制编码,Codable格式化是完全不可知的,因此您可以编写自己的对象,符合Coder您的要求,包括使用原始字节存储所有内容.
以下是其他支持格式的快速概述(按大小排序).在这些测试中,我使用"Hello World! There's so much to see!"了系统字体中的非常小的字符串.在每个格式描述(括号中)之后是存储该字符串的字节数.
NSAttributedString.(536字节)NSKeyedArchiver如果您只需要与Apple平台兼容并且不喜欢上述格式,那么在您使用时制作的二进制Plist是一个很好的选择.此格式也支持图像,但通常仍然大于上面(和RTFD).(648字节)最后,NSAttributedString随着Foundation继续适应Swift而不是Objective-C ,编码体验应该会变得更好.你可以想象一天NSAttributedString或某些类似的Swifty类型符合Codable开箱即用,然后可以与任何文件格式配对Coder.
| 归档时间: |
|
| 查看次数: |
268 次 |
| 最近记录: |