SVG NSTextAttachment 文本编码问题
SVG NSTextAttachment text encoding issue
为了能够将 SVG 图像用于从 HTML 创建的属性字符串,我这样做了
func createAttributedString(string: String) -> NSMutableAttributedString {
let data = string.dataUsingEncoding(NSUTF8StringEncoding)
let options = [NSDocumentTypeDocumentAttribute:NSHTMLTextDocumentType,
NSCharacterEncodingDocumentAttribute: NSUTF8StringEncoding]
let attributedString = (try! NSMutableAttributedString(
data: data!,
options: options as! [String : AnyObject],
documentAttributes: nil))
var svgImageAttributes: [NSTextAttachment] = []
var svgImageRanges: [NSRange] = []
attributedString.enumerateAttribute("NSAttachment", inRange: NSMakeRange(0, attributedString.length), options: []) { (attribute, range, stop) -> Void in
if let attribute = attribute as? NSTextAttachment, fileType = attribute.fileType where fileType == "public.svg-image"{
svgImageAttributes.append(attribute)
svgImageRanges.append(range)
}
}
let array = Array(zip(svgImageAttributes, svgImageRanges))
for i in array {
let (attachment, range) = i
if let imageData = attachment.fileWrapper?.serializedRepresentation {
var chapterTextAttachment:ChapterImageTextAttachment!
if let preferedImageWidth = self.preferedImageWidth{
chapterTextAttachment = ChapterImageTextAttachment(data: imageData, ofType: attachment.fileType, desiredWidth: preferedImageWidth)
} else {
chapterTextAttachment = ChapterImageTextAttachment(data: imageData, ofType: attachment.fileType)
}
let string = NSMutableAttributedString(string: attributedString.string.substringWithRange(attributedString.string.rangeFromNSRange(range)!), attributes: ["NSAttachment": chapterTextAttachment])
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.alignment = .Center
string.addAttribute(NSParagraphStyleAttributeName, value: paragraphStyle, range: range)
attributedString.replaceCharactersInRange(range, withAttributedString: string)
}
}
return attributedString
}
和ChapterImageTextAttachment
class ChapterImageTextAttachment: NSTextAttachment {
let width:CGFloat
var size: CGSize! {
set{
self.bounds = CGRectMake(0,0,newValue.width, newValue.height)
}
get{
return self.bounds.size
}
}
init(data contentData: NSData?, ofType uti: String?, desiredWidth:CGFloat = 320) {
self.width = desiredWidth
super.init(data: contentData, ofType: uti)
if let contentData = contentData {
let string = String(data: contentData, encoding: NSASCIIStringEncoding)!
let svgrender = SVGRenderer(string: self.fixSVGString(string))
let image = svgrender.asImageWithSize(CGSizeMake(self.width, 1000), andScale: UIScreen.mainScreen().scale)
self.image = image
self.size = image.size
}
}
override func attachmentBoundsForTextContainer(textContainer: NSTextContainer?, proposedLineFragment lineFrag: CGRect, glyphPosition position: CGPoint, characterIndex charIndex: Int) -> CGRect {
return CGRectInset(self.bounds, 0, 20)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func fixSVGString(string:String) -> String {
var result: String?
if string.hasPrefix("rtfd"){
let startIndex = string.rangeOfString("<?xml")?.startIndex
let stopIndex = string.rangeOfString("</svg>")?.endIndex
result = string.substringWithRange(startIndex! ..< stopIndex!)
} else {
result = string
}
return result!
}
}
它有效,但有一个缺陷:非 ASCII 字符被破坏。
最重要的是,HTML 和 SVG 都是 UTF-8 编码的,但是在附件中 class 我必须将 SVG 字符串实例化为 ASCII
let string = String(data: contentData, encoding: NSASCIIStringEncoding)!
否则为零
fixSVGString(_:)
删除了一些添加的富文本信息。
如何对 SVG 图像实施 UTF-8 编码?
如果返回的字符串为nil,则表示无法使用UTF-8编码进行转换。事实上,ASCII "worked" 可能只是意味着它按原样获取字节,因此任何非 ASCII 字符都是先前编码所具有的任何字节值,并且这些字符后来会被误解。
所以,很简单,您要转换的数据不是 UTF-8,也不是 ASCII。事实上,您正在寻找 "rtfd" 意味着包装数据可能是 RTF 格式,它将有自己的字符集。 RTF 规范可能有一个 \ansi 指令(我认为代码页 1252)、\mac(Mac OS 罗马)或 \pc(代码页 437)来指定字符集的内容。默认是\ansi。字符集有些混乱。
尝试使用 NSWindowsCP1252StringEncoding,而不是 NSASCIIStringEncoding。或者使用参数为 437 的 CFStringConvertWindowsCodepageToEncoding() 并查看生成的编码是否效果更好。
如果您一开始没有 NSTextAttachment,我会根据数据创建一个 NSAttributedString(使用 NSRTFDTextDocumentType 作为文档类型),然后看看您是否可以在其中找到 NSTextAttachment,并获取数据通过内容 属性.
这样
但是您确实有一个 NSTextAttachment...所以也许它就像获取 NSTextAttachment 的 "contents" 属性 而不是 fileWrapper 的 serializedRepresentation 一样简单。或者只是 return 一个 link?
为了能够将 SVG 图像用于从 HTML 创建的属性字符串,我这样做了
func createAttributedString(string: String) -> NSMutableAttributedString {
let data = string.dataUsingEncoding(NSUTF8StringEncoding)
let options = [NSDocumentTypeDocumentAttribute:NSHTMLTextDocumentType,
NSCharacterEncodingDocumentAttribute: NSUTF8StringEncoding]
let attributedString = (try! NSMutableAttributedString(
data: data!,
options: options as! [String : AnyObject],
documentAttributes: nil))
var svgImageAttributes: [NSTextAttachment] = []
var svgImageRanges: [NSRange] = []
attributedString.enumerateAttribute("NSAttachment", inRange: NSMakeRange(0, attributedString.length), options: []) { (attribute, range, stop) -> Void in
if let attribute = attribute as? NSTextAttachment, fileType = attribute.fileType where fileType == "public.svg-image"{
svgImageAttributes.append(attribute)
svgImageRanges.append(range)
}
}
let array = Array(zip(svgImageAttributes, svgImageRanges))
for i in array {
let (attachment, range) = i
if let imageData = attachment.fileWrapper?.serializedRepresentation {
var chapterTextAttachment:ChapterImageTextAttachment!
if let preferedImageWidth = self.preferedImageWidth{
chapterTextAttachment = ChapterImageTextAttachment(data: imageData, ofType: attachment.fileType, desiredWidth: preferedImageWidth)
} else {
chapterTextAttachment = ChapterImageTextAttachment(data: imageData, ofType: attachment.fileType)
}
let string = NSMutableAttributedString(string: attributedString.string.substringWithRange(attributedString.string.rangeFromNSRange(range)!), attributes: ["NSAttachment": chapterTextAttachment])
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.alignment = .Center
string.addAttribute(NSParagraphStyleAttributeName, value: paragraphStyle, range: range)
attributedString.replaceCharactersInRange(range, withAttributedString: string)
}
}
return attributedString
}
和ChapterImageTextAttachment
class ChapterImageTextAttachment: NSTextAttachment {
let width:CGFloat
var size: CGSize! {
set{
self.bounds = CGRectMake(0,0,newValue.width, newValue.height)
}
get{
return self.bounds.size
}
}
init(data contentData: NSData?, ofType uti: String?, desiredWidth:CGFloat = 320) {
self.width = desiredWidth
super.init(data: contentData, ofType: uti)
if let contentData = contentData {
let string = String(data: contentData, encoding: NSASCIIStringEncoding)!
let svgrender = SVGRenderer(string: self.fixSVGString(string))
let image = svgrender.asImageWithSize(CGSizeMake(self.width, 1000), andScale: UIScreen.mainScreen().scale)
self.image = image
self.size = image.size
}
}
override func attachmentBoundsForTextContainer(textContainer: NSTextContainer?, proposedLineFragment lineFrag: CGRect, glyphPosition position: CGPoint, characterIndex charIndex: Int) -> CGRect {
return CGRectInset(self.bounds, 0, 20)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func fixSVGString(string:String) -> String {
var result: String?
if string.hasPrefix("rtfd"){
let startIndex = string.rangeOfString("<?xml")?.startIndex
let stopIndex = string.rangeOfString("</svg>")?.endIndex
result = string.substringWithRange(startIndex! ..< stopIndex!)
} else {
result = string
}
return result!
}
}
它有效,但有一个缺陷:非 ASCII 字符被破坏。
最重要的是,HTML 和 SVG 都是 UTF-8 编码的,但是在附件中 class 我必须将 SVG 字符串实例化为 ASCII
let string = String(data: contentData, encoding: NSASCIIStringEncoding)!
否则为零
fixSVGString(_:)
删除了一些添加的富文本信息。
如何对 SVG 图像实施 UTF-8 编码?
如果返回的字符串为nil,则表示无法使用UTF-8编码进行转换。事实上,ASCII "worked" 可能只是意味着它按原样获取字节,因此任何非 ASCII 字符都是先前编码所具有的任何字节值,并且这些字符后来会被误解。
所以,很简单,您要转换的数据不是 UTF-8,也不是 ASCII。事实上,您正在寻找 "rtfd" 意味着包装数据可能是 RTF 格式,它将有自己的字符集。 RTF 规范可能有一个 \ansi 指令(我认为代码页 1252)、\mac(Mac OS 罗马)或 \pc(代码页 437)来指定字符集的内容。默认是\ansi。字符集有些混乱。
尝试使用 NSWindowsCP1252StringEncoding,而不是 NSASCIIStringEncoding。或者使用参数为 437 的 CFStringConvertWindowsCodepageToEncoding() 并查看生成的编码是否效果更好。
如果您一开始没有 NSTextAttachment,我会根据数据创建一个 NSAttributedString(使用 NSRTFDTextDocumentType 作为文档类型),然后看看您是否可以在其中找到 NSTextAttachment,并获取数据通过内容 属性.
这样但是您确实有一个 NSTextAttachment...所以也许它就像获取 NSTextAttachment 的 "contents" 属性 而不是 fileWrapper 的 serializedRepresentation 一样简单。或者只是 return 一个 link?