【问题标题】:Drawing Text on NSImage is Slow - How to improve performance?在 NSImage 上绘制文本很慢 - 如何提高性能?
【发布时间】:2020-08-02 00:02:33
【问题描述】:

我使用以下代码在 NSImage 上绘制文本

func drawText(image :NSImage) ->NSImage
    {

        let text = textdata
        let font = NSFont(name:String(combo_font.stringValue), size: 50)
        let imageRect = CGRect(x: 0, y: 0, width: image.size.width, height: image.size.height)

        let fontAttributes = [NSAttributedStringKey.font: font]

        let fontsize = (text as NSString).size(withAttributes: fontAttributes)

        let textRect = CGRect(x: (image.size.width/2-fontsize.width/2), y: image.size.height/2, width: fontsize.width, height: fontsize.height)



        let textStyle = NSMutableParagraphStyle.default.mutableCopy() as! NSMutableParagraphStyle
        let textFontAttributes = [
            NSAttributedStringKey.font: font,
            NSAttributedStringKey.foregroundColor: NSColor.white,
            NSAttributedStringKey.paragraphStyle: textStyle
        ]
        let im:NSImage = NSImage(size: image.size)
        let rep:NSBitmapImageRep = NSBitmapImageRep(bitmapDataPlanes: nil, pixelsWide: Int(image.size.width), pixelsHigh: Int(image.size.height), bitsPerSample: 8, samplesPerPixel: 4, hasAlpha: true, isPlanar: false, colorSpaceName: NSColorSpaceName.calibratedRGB, bytesPerRow: 0, bitsPerPixel: 0)!
        im.addRepresentation(rep)
        im.lockFocus()
        image.draw(in: imageRect)
        text.draw(in: textRect, withAttributes: textFontAttributes)
        im.unlockFocus()
        return im
    }

为了防止 UI 冻结,我在后台线程中执行长时间运行的操作

override func controlTextDidChange(_ obj: Notification) {
        if(obj.object is  NSTextField)
        {
            let textdata=obj.object as! NSTextField
            if(txtfield.identifier?.rawValue=="txt_field")
            {


                self.textdata=self.txtbox.stringValue
                DispatchQueue.global().async {
                self.img_view.image=self.drawText(image: NSImage(byReferencingFile: self.selectedfilename)!);

                }

            }

        }
    }

处理 391KB 大小的图像时,更新 UI 的过程需要很长时间。如何提高性能。我只需要向用户显示预览,将图像调整为更小的尺寸也是一种选择以提高性能;但在以后处理时,全分辨率图像也应达到相同的外观。

更新: 关于后台线程

 let group = DispatchGroup()
          group.enter()
          self.progress_preview.isHidden=false
          self.progress_preview.startAnimation(self)

          DispatchQueue.global(qos: .background).async {

            self.text = self.txt_text.stringValue 
            self.globaimage  = self.drawText(image: NSImage(byReferencingFile: self.selectedfilename)!);
             group.leave()
         }

         // does not wait. But the code in notify() gets run
         // after enter() and leave() calls are balanced

          group.notify(queue: .main) {
          self.img_view.image=self.globaimage
          self.progress_preview.isHidden=true
          self.progress_preview.stopAnimation(self)

         }

【问题讨论】:

  • @vadian 你能看看这个
  • 你看过CATextLayer吗?
  • @OlhaPavliuk CATextLayer 可以用来在 NSImage 上绘图吗?
  • 如果您需要“导出”该 NSImage,则可能不需要。但是如果你只需要在图像上方显示一些文本,你可以添加CALayer而不使用任何渲染代码。
  • @OlhaPavliuk 我想知道如果使用旧代码在导出的图像上呈现相同的字体大小,字体大小是否会匹配。

标签: swift macos xcode-storyboard nsimage


【解决方案1】:

没有理由在每次文本更改时都在 UI 中重新创建带有文本的图像,它总是很重,因为图像可能很大,而这里最耗时的是处理图像本身。

对于解决方案单独的 UI 和最终图像生成。即,只需在图像 (NSImageView) 上添加常规标签 (flat NSTextField) 并提前(在 Storyboard、Xib 等中)设置参数(位置、约束、字体、样式等)并仅更新编辑时的 UI 文本字段。并且只有一次,在导出时,将最终文本渲染为最终图像 - 导出对用户来说是预期的长时间操作,所以不用担心,而且可以显示一些进度。

顺便说一句,层也可以使用,但不是必需的。

【讨论】:

  • 文字的位置可以由用户调整。加上预览和最终图像会出现字体大小不匹配的情况。并且在imageview中显示的图像有时会被缩放,并且会留下空白.很多问题要解决。
猜你喜欢
  • 1970-01-01
  • 2012-12-02
  • 2018-04-02
  • 2012-11-30
  • 1970-01-01
  • 2012-05-01
  • 2011-05-14
  • 1970-01-01
  • 2020-08-20
相关资源
最近更新 更多