-1

I use the following code to draw a text on an 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
    }

To prevent UI Freezing i do the long running operation in background thread

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)!);

                }

            }

        }
    }

When processing an Image of 391KB in size, the process takes too long to update the UI.How can i improve the performance.I just need to display the preview to the user,resizing image to a smaller size is also an option to improve the performance;But the same look should be achieved in full resolution image as well when processing later.

Update: Regarding Background threading

 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)

         }
techno
  • 6,100
  • 16
  • 86
  • 192
  • @vadian Can you please take a look at this – techno Apr 19 '20 at 14:51
  • Have you looked at `CATextLayer` ? – olha Apr 19 '20 at 18:00
  • @OlhaPavliuk Can `CATextLayer` be used to draw on NSImage? – techno Apr 19 '20 at 18:16
  • Probably not if you need to "export" that NSImage. But if you just need to display some text **above** the image, you can add CALayer and not to use any rendering code. – olha Apr 19 '20 at 18:30
  • @OlhaPavliuk I was wondering if the font size will match if the same font size is rendered on the exported image using the old code. – techno Apr 19 '20 at 18:32
  • Well, you could try with different font sizes, take the screenshots, and compare that screenshots. – olha Apr 19 '20 at 18:43
  • @OlhaPavliuk Can you please point me to some examples. – techno Apr 19 '20 at 18:52
  • @OlhaPavliuk Please take a look https://stackoverflow.com/questions/61309916/add-catextlayer-on-top-of-nsimageview – techno Apr 19 '20 at 18:57
  • @techo Could you describe your initial problem, e.g. why do you need to display the text in image, and provide some screenshot of what you have already? – olha Apr 19 '20 at 18:58
  • @OlhaPavliuk sorry for the late update.I just saw your message today.I need to draw text on an image based on user input in a textbox. – techno Apr 22 '20 at 05:04
  • One thing I notice right off the bat is that you're adding the image to `img_view`, which I assume is an `NSImageView`, in a background queue. This is incorrect; UI work such as this must be done on the main queue. You can build the image on a background queue, but you need to switch back to the main queue before you actually put it on an `NSView` subclass. – Charles Srstka Apr 22 '20 at 05:24
  • @CharlesSrstka Please see the update – techno Apr 22 '20 at 06:11
  • UIGraphicsBeginImageContextWithOptions and UIGraphicsGetImageFromCurrentImageContext can be used also... just put your textView over image as separate element, allowing user to move it, modify font etc.Merge them in final export. Take a look also on https://github.com/FarisAlbalawi/PhotoVideoEditor – ares777 Apr 28 '20 at 15:41

1 Answers1

2

There is no reason to recreate image with text in UI every time text has changed, it will always be heavy, because images can be huge, and most time-consuming here is coping image itself.

For solution separate UI and final image generation. Ie., just add regular label (flat NSTextField) over image (NSImageView) with set up parameters (location, constraints, font, style, etc.) in advance (in Storyboard, Xib, etc) and update only that UI TextField while editing. And only once, when export, render final text into final image - exporting is expected long operation for the user, so no concern, plus some progress can be shown.

Btw, layers also can be used, but it is not required.

Willeke
  • 14,578
  • 4
  • 19
  • 47
Asperi
  • 228,894
  • 20
  • 464
  • 690
  • The position of the text can be adjusted by the user.Plus the Font Size mismatch will occur in preview and final images.And image displayed in imageview will sometimes be scaled and there will be blank space left out.Lots of problems to solve. – techno Apr 23 '20 at 07:44