You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS中NSAttributedString添加竖图保存后水平翻转的问题

iOS竖版图片添加到NSAttributedString后保存变为横版的解决方法

在iOS开发中,使用NSTextAttachment调整NSAttributedString内的图片大小时,遇到竖版图片保存后变为横版的问题——图片缩放功能正常,但添加到NSAttributedString后出现莫名水平翻转。

问题根源

  1. 原图片缩放方法使用UIGraphicsBeginImageContext,未处理图片的imageOrientation属性,导致图片方向信息丢失,绘制后方向异常。
  2. NSTextAttachment未设置正确的bounds,仅设置image无法保证图片的显示和存储尺寸与方向匹配。

修改后的代码实现

1. 修复UIImage缩放扩展(处理方向)

extension UIImage {
    func resizeImage(scale: CGFloat) -> UIImage {
        let newSize = CGSize(width: size.width * scale, height: size.height * scale)
        
        UIGraphicsBeginImageContextWithOptions(newSize, false, UIScreen.main.scale)
        defer { UIGraphicsEndImageContext() }
        
        let transform = transformForOrientation(newSize)
        draw(in: CGRect(origin: .zero, size: newSize).applying(transform))
        
        return UIGraphicsGetImageFromCurrentImageContext()!
    }
    
    private func transformForOrientation(_ newSize: CGSize) -> CGAffineTransform {
        var transform = CGAffineTransform.identity
        
        switch imageOrientation {
        case .down, .downMirrored:
            transform = transform.translatedBy(x: newSize.width, y: newSize.height)
            transform = transform.rotated(by: .pi)
        case .left, .leftMirrored:
            transform = transform.translatedBy(x: newSize.width, y: 0)
            transform = transform.rotated(by: .pi / 2)
        case .right, .rightMirrored:
            transform = transform.translatedBy(x: 0, y: newSize.height)
            transform = transform.rotated(by: -.pi / 2)
        case .up, .upMirrored:
            break
        @unknown default:
            break
        }
        
        switch imageOrientation {
        case .upMirrored, .downMirrored:
            transform = transform.translatedBy(x: newSize.width, y: 0)
            transform = transform.scaledBy(x: -1, y: 1)
        case .leftMirrored, .rightMirrored:
            transform = transform.translatedBy(x: newSize.height, y: 0)
            transform = transform.scaledBy(x: -1, y: 1)
        case .up, .down, .left, .right:
            break
        @unknown default:
            break
        }
        
        return transform
    }
}

2. 优化NSAttributedString扩展(设置Attachment Bounds)

extension NSAttributedString {
    func attributedStringWithResizedImages(with maxWidth: CGFloat) -> NSAttributedString {
        let text = NSMutableAttributedString(attributedString: self)
        text.enumerateAttribute(.attachment, in: NSRange(location: 0, length: text.length), options: []) { value, range, stop in
            guard let attachment = value as? NSTextAttachment else { return }
            
            guard let image = attachment.image(forBounds: attachment.bounds, textContainer: NSTextContainer(), characterIndex: range.location) else { return }
            
            guard image.size.width > maxWidth else { return }
            
            let scale = maxWidth / image.size.width
            let newImage = image.resizeImage(scale: scale)
            
            let newAttachment = NSTextAttachment()
            newAttachment.image = newImage
            // 设置正确的bounds,确保图片显示尺寸匹配
            newAttachment.bounds = CGRect(origin: .zero, size: newImage.size)
            
            text.addAttribute(.attachment, value: newAttachment, range: range)
        }
        return text
    }
}

3. 保存与读取逻辑(无需修改)

原保存和读取代码可继续使用,RTFD格式会正确存储设置好的attachment信息:

func saveAttributedTextToUserDefault(attributedText: NSAttributedString, key: String) {
    do {
        let data = try attributedText.data(from: NSRange(location: 0, length: attributedText.length), documentAttributes: [.documentType: NSAttributedString.DocumentType.rtfd])
        userDefault.set(data, forKeyPath: myNotes)
    } catch {
        print(error)
    }
}

func getAttributedTextFromUserDefault(key: String) -> NSAttributedString {
    if let dataValue = userDefault.data(forKey: myNotes) as? Data {
        do {
            let attributeText = try NSAttributedString(data: dataValue, documentAttributes: nil)
            return attributeText
        } catch {
            print("error: ", error)
        }
    }
    return NSAttributedString()
}

关键修复说明

  • 新增transformForOrientation方法,根据图片的原始方向计算绘制变换,确保缩放后图片方向与原图一致。
  • 使用UIGraphicsBeginImageContextWithOptions替代UIGraphicsBeginImageContext,支持Retina屏幕,避免图片模糊。
  • 为新创建的NSTextAttachment设置bounds,确保图片在AttributedString中的显示尺寸和存储信息准确。

内容的提问来源于stack exchange,提问作者Dian

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 06:40:42