NSImage在我绘制文本时调整大小

时间:2017-10-18 06:33:30

标签: swift xcode macos swift3

我有以下代码在NSImage上绘制文本。 但是当我将图像保存到磁盘时,生成的图像会调整为较小的图像。

我做错了什么?请建议

func drawText(image :NSImage) ->NSImage
{
    let text = "Sample Text"
    let font = NSFont.boldSystemFont(ofSize: 18)
    let imageRect = CGRect(x: 0, y: 0, width: image.size.width, height: image.size.height)

    let textRect = CGRect(x: 5, y: 5, width: image.size.width - 5, height: image.size.height - 5)
    let textStyle = NSMutableParagraphStyle.default().mutableCopy() as! NSMutableParagraphStyle
    let textFontAttributes = [
        NSFontAttributeName: font,
        NSForegroundColorAttributeName: NSColor.white,
        NSParagraphStyleAttributeName: 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: NSCalibratedRGBColorSpace, bytesPerRow: 0, bitsPerPixel: 0)!

    im.addRepresentation(rep)

    im.lockFocus()

    image.draw(in: imageRect)
    text.draw(in: textRect, withAttributes: textFontAttributes)

    im.unlockFocus()

    return im
}

2 个答案:

答案 0 :(得分:1)

这是一种使用临时NSView绘制图像和文本并将结果缓存到新图像(代码为Swift 4)的不同方法。你不需要处理像素的好处

class ImageView : NSView  {

    var image : NSImage
    var text : String

    init(image: NSImage, text: String)
    {
        self.image = image
        self.text = text
        super.init(frame: NSRect(origin: NSZeroPoint, size: image.size))
    }

    required init?(coder decoder: NSCoder) { fatalError() }

    override func draw(_ dirtyRect: NSRect) {
        let font = NSFont.boldSystemFont(ofSize: 18)
        let textRect = CGRect(x: 5, y: 5, width: image.size.width - 5, height: image.size.height - 5)
        image.draw(in: dirtyRect)
        text.draw(in: textRect, withAttributes: [.font: font, .foregroundColor: NSColor.white])
    }

    var outputImage : NSImage  {
        let imageRep = bitmapImageRepForCachingDisplay(in: frame)!
        cacheDisplay(in: frame, to:imageRep)
        let tiffData = imageRep.tiffRepresentation!
        return NSImage(data : tiffData)!
    }
}

要使用它,请初始化视图

let image = ... // get some image
let view = ImageView(image: image, text: "Sample Text")

并获取新图片

let imageWithText = view.outputImage

注意:

根本不使用段落样式,但如果要创建可变段落样式,只需编写

let textStyle = NSMutableParagraphStyle()

答案 1 :(得分:0)

混合像素与点? 根据您的屏幕,2x或3x图像较小2倍或3倍?

这是更详细的信息(向下滚动到"在像素和点之间转换") http://blog.fluidui.com/designing-for-mobile-101-pixels-points-and-resolutions/

但请记住:

  

当您在具有视网膜屏幕的系统上锁定焦点时,NSImage可识别分辨率并使用HiDPI图形上下文。   传递给NSBitmapImageRep初始值设定项的图像尺寸以点(不是像素)为单位。因此,150.0点宽的图像在@ 2x上下文中使用300个水平像素。

来源: How to save PNG file from NSImage (retina issues)

以下简单的应用程序适合我。享受;)

import Cocoa

class ViewController: NSViewController {

    func save(image:NSImage, imageURL:String, format:String) -> Bool
    {
        let bMImg = NSBitmapImageRep(data: (image.tiffRepresentation)!)
        switch format {
        case ".png":
            let filepath = URL(fileURLWithPath: imageURL+".png")
            let dataToSave = bMImg?.representation(using: NSBitmapImageRep.FileType.png, properties: [NSBitmapImageRep.PropertyKey.compressionFactor : 1])
            do
            {
                try  dataToSave?.write(to: filepath)
                return true

            } catch {
                return false
            }
        default:
            return false
        }
    }

    func draw(text:String, image:NSImage) -> NSImage
    {
        let font = NSFont.boldSystemFont(ofSize: 18)
        let imageRect = CGRect(x: 0, y: 0, width: image.size.width, height: image.size.height)

        let textRect = CGRect(x: 5, y: 5, width: image.size.width - 5, height: image.size.height - 5)
        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
    }

    @IBAction func action(_ sender: NSButton) {
        let dialog = NSOpenPanel();

        dialog.title                   = "Choose a image...";
        dialog.showsResizeIndicator    = true;
        dialog.showsHiddenFiles        = false;
        dialog.canChooseDirectories    = true;
        dialog.canCreateDirectories    = true;
        dialog.allowsMultipleSelection = false;
        dialog.allowedFileTypes        = ["png", "jpg"];

        if (dialog.runModal() == NSApplication.ModalResponse.OK) {
            guard let url = dialog.url,
                let imageCIImage = CIImage(contentsOf: url) else {
                    return
            }
            let rep: NSCIImageRep = NSCIImageRep(ciImage: imageCIImage)
            let nsImage = NSImage(size: rep.size)
            nsImage.addRepresentation(rep)

            let imageWithText = draw(text:"ABC", image: nsImage)

            if (save(image: imageWithText, imageURL: "imageWithText", format: ".png")) {
                print("Success")
            } else {
                print("ERROR:Failed to save image")
            }
        } else {
            // User clicked on "Cancel"
            return
        }
    }
}