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

macOS中NSImage的textToImage方法返回结果不一致问题

问题:图片添加文字后缩放效果不稳定

我用以下NSImage扩展给图片叠加文字,调用时先生成带文字的图片,再缩小尺寸用于Widget(避免超过16MB限制),但有时候生成的图片效果异常——文字变得模糊错位,看起来像是缩放操作提前执行了一样。

正常效果与异常效果对比:
正常效果
异常效果

用于添加文字的NSImage扩展代码

extension NSImage {
     
     //https://stackoverflow.com/questions/54450429/macos-add-a-text-overlay-to-an-image-in-swift
     
     func textToImage(naam: String, slogan: String) -> NSImage {
          
         let targetImage = NSImage(size: self.size, flipped: false) { (dstRect: CGRect) -> Bool in

             let naamColor = NSColor.black

             let naamFont = NSFont(name: "Montserrat-SemiBold", size: 110)!
                          
             let paragraph = NSMutableParagraphStyle()
             paragraph.alignment = .center
             
             let naamFontAttributes = [NSAttributedString.Key.font: naamFont, .paragraphStyle: paragraph, NSAttributedString.Key.foregroundColor: naamColor] as [NSAttributedString.Key : Any]

             let naamString = NSAttributedString(string: naam, attributes: naamFontAttributes)

             self.draw(in: CGRect(x: 0, y: 0, width: self.size.width, height: self.size.height))

             let rectNaam = CGRect(x: 25, y: -25, width: self.size.width-25, height: self.size.height)
             
             naamString.draw(in: rectNaam)

             return true
                
         }
                
         return targetImage
          
     }
     
}

调用代码

let image = loadImage(named: "eigenradiostation.png")
                
let imageWithText = image.textToImage(naam: radiostationGeselecteerd[0], slogan: radiostationGeselecteerd[1])

//downsample zodat widget niet > 16 MB komt
imageWithText.size = CGSize(width: 100, height: 100)

let imageData = imageWithText.tiffRepresentation!
                                    
recentAfgespeeldeRadiostationsTegels.insert(imageData, at:0)

问题原因

问题出在NSImage的延迟绘制机制上:你创建targetImage时用了闭包绘制的方式,这个闭包并不会在调用textToImage时立即执行,而是要等到图片实际需要被渲染(比如调用tiffRepresentation获取数据)的时候才会触发。

而你先修改了imageWithText.size,这会导致闭包执行时,self.size(也就是原图片的尺寸)已经被改成了缩小后的100x100,文字会基于这个小尺寸绘制,最终生成的图片再被导出,就会出现文字模糊错位的异常效果。

解决方法

方法一:先导出图片数据再缩放

确保闭包在尺寸修改前执行完毕,再对导出的图片进行缩小:

let image = loadImage(named: "eigenradiostation.png")
let imageWithText = image.textToImage(naam: radiostationGeselecteerd[0], slogan: radiostationGeselecteerd[1])

// 先获取完整尺寸的图片数据,触发闭包绘制
guard let originalData = imageWithText.tiffRepresentation else { return }
// 从数据重新生成图片并缩小尺寸
if let downsampledImage = NSImage(data: originalData) {
    downsampledImage.size = CGSize(width: 100, height: 100)
    guard let downsampledData = downsampledImage.tiffRepresentation else { return }
    recentAfgespeeldeRadiostationsTegels.insert(downsampledData, at:0)
}

方法二:固定原图片尺寸,避免受后续修改影响

修改textToImage方法,提前保存原图片的尺寸,闭包内使用这个固定值绘制,不受后续size修改的影响:

extension NSImage {
    func textToImage(naam: String, slogan: String) -> NSImage {
        // 提前保存原图片的尺寸,避免后续修改干扰绘制
        let originalSize = self.size
        
        let targetImage = NSImage(size: originalSize, flipped: false) { (dstRect: CGRect) -> Bool in
            let naamColor = NSColor.black
            let naamFont = NSFont(name: "Montserrat-SemiBold", size: 110)!
            let paragraph = NSMutableParagraphStyle()
            paragraph.alignment = .center
            
            let naamFontAttributes = [
                NSAttributedString.Key.font: naamFont,
                .paragraphStyle: paragraph,
                NSAttributedString.Key.foregroundColor: naamColor
            ] as [NSAttributedString.Key : Any]

            let naamString = NSAttributedString(string: naam, attributes: naamFontAttributes)

            // 使用固定的原尺寸绘制原图
            self.draw(in: CGRect(origin: .zero, size: originalSize))
            // 基于原尺寸计算文字位置
            let rectNaam = CGRect(x: 25, y: -25, width: originalSize.width - 25, height: originalSize.height)
            naamString.draw(in: rectNaam)

            return true
        }
        return targetImage
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 06:44:55