改变 NSImage 的色彩空间

发布于 2024-09-09 09:50:58 字数 91 浏览 8 评论 0原文

有没有办法可以更改 NSimage 或 NSBitmapImageRep/CGimage 等的颜色空间。我对任何方式都持开放态度。最好采用 Photoshop 的方式。

Is there a way I can change the color space of an NSimage or NSBitmapImageRep/CGimage or the like. I am open to any way. Preferably the way photoshop does it.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

深海不蓝 2024-09-16 09:50:58

您在下面看到的代码的问题

CGImageRef CGImageCreateCopyWithColorSpace (
CGImageRef image,
CGColorSpaceRef colorspace
);

不起作用,因为 Quartz2D 不支持 CMYK 图像或灰度图像的 alpha,它仅受 RGB 图像支持。
您应该做的是创建 2 个图像,然后在 CMYK 颜色空间和带有 alpha 的图像的情况下合并。我搜索了很多关于这个主题的信息,终于找到了。可能这个问题的作者不再需要它,但其他人可能需要它。

  1. 创建新的NSBitmapImageRep

    let imageRep = NSBitmapImageRep(bitmapDataPlanes: nil,
                                          PixelWide: Int(round(imageSize.width)),
                                          PixelsHigh: Int(round(imageSize.height)),
                                       每个样本位数:8,
                                     每像素样本数:4,
                                            有阿尔法:假,
                                            是平面:假,
                                      颜色空间名称:NSDeviceCMYKColorSpace,
                                        位图格式:NSBitmapFormat(原始值:0),
                                         bytesPerRow: Int(round(imageSize.width) * CGFloat(4)),
                                        每像素位数:0)
    
  2. 您需要将图像绘制到新的位图中
    假设您有 colorSpace: NSColorSpace

    let context = NSGraphicsContext(bitmapImageRep: imageRep)
    NSGraphicsContext.saveGraphicsState()
    NSGraphicsContext.setCurrentContext(上下文)
    imageRep.setProperty(NSImageColorSyncProfileData, withValue: colorSpace.ICCProfileData)
    // 在这里画画
    NSGraphicsContext.restoreGraphicsState()
    
  3. 此后您将拥有一个 imageRep,它是具有正确颜色空间但没有 alpha(透明度)的图像。

  4. 您需要一个遮罩位图。获取面具很棘手。

    let imageRep = NSBitmapImageRep(bitmapDataPlanes: nil,
                                          PixelWide: Int(round(imageSize.width)),
                                          PixelsHigh: Int(round(imageSize.height)),
                                       每个样本位数:8,
                                     每像素样本数:1,
                                            有阿尔法:假,
                                            是平面:假,
                                      颜色空间名称:NSDeviceWhiteColorSpace,
                                        位图格式:NSBitmapFormat(原始值:0),
                                         bytesPerRow: Int(round(imageSize.width)),
                                        每像素位数:0)
    
  5. 将白色图像剪辑到具有透明度的图像

    if letgraphicsPort = NSGraphicsContext.currentContext()?.graphicsPort {
        让 context = unsafeBitCast(graphicsPort, CGContextRef.self)
        let imgRect = NSRect(origin: NSPoint.zero, size: image.extent.size)
        让 ciContext = CIContext()
        让cgImage = ciContext.createCGImage(image, fromRect: image.extent)
        CGContextClipToMask(上下文,imgRect,cgImage)
    }
    
  6. 将所有像素着色为白色,这将被剪辑到图像。

    let context = NSGraphicsContext(bitmapImageRep: imageRep)
    NSGraphicsContext.saveGraphicsState()
    NSGraphicsContext.setCurrentContext(上下文)
    imageRep.setProperty(NSImageColorSyncProfileData, withValue: colorSpace.ICCProfileData)
    NSColor.whiteColor().setFill()
    NSBezierPath.fillRect(NSRect(原点:NSPoint.zero,大小:imageSize))
    NSGraphicsContext.restoreGraphicsState()
    
  7. 在此步骤中,您将获得图像和蒙版。接下来我们需要将它们结合起来。我正在使用这个小算法(您需要验证蒙版和源图像具有相同的尺寸和相同的 colorSpaceModel):

    func createCMYKAImageRepByApplingAlphaMask(srcImageRep: NSBitmapImageRep, alphaMaskImageRep alphaMask: NSBitmapImageRep) -> NSBitmapImageRep? {
        if canApplyMaskRepOnImageRep(srcImageRep, maskRep: alphaMask) == false {
            返回零
        }
        让 alphaData = alphaMask.bitmapData
        让 srcData = srcImageRep.bitmapData
        如果让 imageWithAlphaMaskRep = createEmptyCMYKABitmapImageRep(alphaMask.size) {
            如果让 colorSpaceData = imageColorSpace?.ICCProfileData {
                 imageWithAlphaMaskRep.setProperty(NSImageColorSyncProfileData, withValue: colorSpaceData)
            }
            fillPixelsWithComponentsData(imageWithAlphaMaskRep,组件:{(pixelIdx:Int)->(UInt8,UInt8,UInt8,UInt8,UInt8)中
                让青色 = srcData[pixelIdx * 4 + 0]
                让洋红色 = srcData[pixelIdx * 4 + 1]
                让黄色 = srcData[pixelIdx * 4 + 2]
                让黑色 = srcData[pixelIdx * 4 + 3]
                让 alpha = alphaData[pixelIdx]
                返回(青色、洋红色、黄色、黑色、alpha)
            })
            返回 imageWithAlphaMaskRep
        }
        返回零
    }
    
    func createEmptyBitmapImageRep() ->; NSBitmapImageRep? {
        让 imageRep = NSBitmapImageRep(bitmapDataPlanes: nil,
                                              PixelWide: Int(round(imageSize.width)),
                                              PixelsHigh: Int(round(imageSize.height)),
                                           每个样本位数:8,
                                         每像素样本数:5,
                                                有阿尔法:正确,
                                                是平面:假,
                                          颜色空间名称:NSDeviceCMYKColorSpace,
                                            位图格式:NSBitmapFormat(原始值:0),
                                             bytesPerRow: Int(round(imageSize.width) * CGFloat(5)),
                                            每像素位数:0)
        返回图像代表
    }
    
    私有 func fillPixelsWithComponentsData(imgRep: NSBitmapImageRep,
    组件:(Int) -> (青色:UInt8,洋红色:UInt8,黄色:UInt8,黑色:UInt8,alpha:UInt8)){
        让 imageRawData = imgRep.bitmapData
        让 imageWidth = Int(imgRep.size.width)
        让 imageHeight = Int(imgRep.size.height)
        对于 0 ..< 中的 PixelIdx (图像宽度 * 图像高度){
            让(青色,洋红色,黄色,黑色,alpha)=组件(pixelIdx)
            让 fAlpha = Float(alpha) / 255
            imageRawData[pixelIdx * 5 + 0] = UInt8(Float(青色) * fAlpha)
            imageRawData[pixelIdx * 5 + 1] = UInt8(Float(洋红色) * fAlpha)
            imageRawData[pixelIdx * 5 + 2] = UInt8(Float(黄色) * fAlpha)
            imageRawData[pixelIdx * 5 + 3] = UInt8(Float(black) * fAlpha)
            imageRawData[pixelIdx * 5 + 4] = 阿尔法
        }
    }
    

The problem with the code you see below

CGImageRef CGImageCreateCopyWithColorSpace (
CGImageRef image,
CGColorSpaceRef colorspace
);

is not working because Quartz2D does not support alpha for CMYK images or gray images, it is supported only by RGB images.
What you should do is creating 2 images then combine then in case of a CMYK color space and image with alpha. I have searched a lot about this topic and finally found. May be author of this question doesn't need it anymore but someone else may need it.

  1. Create new NSBitmapImageRep

    let imageRep = NSBitmapImageRep(bitmapDataPlanes: nil,
                                          pixelsWide: Int(round(imageSize.width)),
                                          pixelsHigh: Int(round(imageSize.height)),
                                       bitsPerSample: 8,
                                     samplesPerPixel: 4,
                                            hasAlpha: false,
                                            isPlanar: false,
                                      colorSpaceName: NSDeviceCMYKColorSpace,
                                        bitmapFormat: NSBitmapFormat(rawValue: 0),
                                         bytesPerRow: Int(round(imageSize.width) * CGFloat(4)),
                                        bitsPerPixel: 0)
    
  2. You need to draw your image into the new bitmap
    lets say you have colorSpace: NSColorSpace

    let context = NSGraphicsContext(bitmapImageRep: imageRep)
    NSGraphicsContext.saveGraphicsState()
    NSGraphicsContext.setCurrentContext(context)
    imageRep.setProperty(NSImageColorSyncProfileData, withValue: colorSpace.ICCProfileData)
    // Do your drawing here
    NSGraphicsContext.restoreGraphicsState()
    
  3. After this you will have an imageRep that is the image with correct color space but no alpha (transparency).

  4. You need a mask bitmap. Obtaining mask is tricky.

    let imageRep = NSBitmapImageRep(bitmapDataPlanes: nil,
                                          pixelsWide: Int(round(imageSize.width)),
                                          pixelsHigh: Int(round(imageSize.height)),
                                       bitsPerSample: 8,
                                     samplesPerPixel: 1,
                                            hasAlpha: false,
                                            isPlanar: false,
                                      colorSpaceName: NSDeviceWhiteColorSpace,
                                        bitmapFormat: NSBitmapFormat(rawValue: 0),
                                         bytesPerRow: Int(round(imageSize.width)),
                                        bitsPerPixel: 0)
    
  5. Clip white image to your image with transparency

    if let graphicsPort = NSGraphicsContext.currentContext()?.graphicsPort {
        let context = unsafeBitCast(graphicsPort, CGContextRef.self)
        let imgRect = NSRect(origin: NSPoint.zero, size: image.extent.size)
        let ciContext = CIContext()
        let cgImage = ciContext.createCGImage(image, fromRect: image.extent)
        CGContextClipToMask(context, imgRect, cgImage)
    }
    
  6. Colorize all pixel in white color, this will be clipped to image.

    let context = NSGraphicsContext(bitmapImageRep: imageRep)
    NSGraphicsContext.saveGraphicsState()
    NSGraphicsContext.setCurrentContext(context)
    imageRep.setProperty(NSImageColorSyncProfileData, withValue: colorSpace.ICCProfileData)
    NSColor.whiteColor().setFill()
    NSBezierPath.fillRect(NSRect(origin: NSPoint.zero, size: imageSize))
    NSGraphicsContext.restoreGraphicsState()
    
  7. At this step you have a image and a mask. Next we need to combine them. I am using this little algorithm (you need to verify that mask and source image have same sizes and same colorSpaceModel):

    func createCMYKAImageRepByApplingAlphaMask(srcImageRep: NSBitmapImageRep, alphaMaskImageRep alphaMask: NSBitmapImageRep) -> NSBitmapImageRep? {
        if canApplyMaskRepOnImageRep(srcImageRep, maskRep: alphaMask) == false {
            return nil
        }
        let alphaData = alphaMask.bitmapData
        let srcData = srcImageRep.bitmapData
        if let imageWithAlphaMaskRep = createEmptyCMYKABitmapImageRep(alphaMask.size) {
            if let colorSpaceData = imageColorSpace?.ICCProfileData {
                 imageWithAlphaMaskRep.setProperty(NSImageColorSyncProfileData, withValue: colorSpaceData)
            }
            fillPixelsWithComponentsData(imageWithAlphaMaskRep, components: { (pixelIdx: Int) -> (UInt8, UInt8, UInt8, UInt8, UInt8) in
                let cyan = srcData[pixelIdx * 4 + 0]
                let magenta = srcData[pixelIdx * 4 + 1]
                let yellow = srcData[pixelIdx * 4 + 2]
                let black = srcData[pixelIdx * 4 + 3]
                let alpha = alphaData[pixelIdx]
                return (cyan, magenta, yellow, black, alpha)
            })
            return imageWithAlphaMaskRep
        }
        return nil
    }
    
    func createEmptyBitmapImageRep() -> NSBitmapImageRep? {
        let imageRep = NSBitmapImageRep(bitmapDataPlanes: nil,
                                              pixelsWide: Int(round(imageSize.width)),
                                              pixelsHigh: Int(round(imageSize.height)),
                                           bitsPerSample: 8,
                                         samplesPerPixel: 5,
                                                hasAlpha: true,
                                                isPlanar: false,
                                          colorSpaceName: NSDeviceCMYKColorSpace,
                                            bitmapFormat: NSBitmapFormat(rawValue: 0),
                                             bytesPerRow: Int(round(imageSize.width) * CGFloat(5)),
                                            bitsPerPixel: 0)
        return imageRep
    }
    
    private func fillPixelsWithComponentsData(imgRep: NSBitmapImageRep,
    components: (Int) -> (cyan:UInt8, magenta:UInt8, yellow:UInt8, black:UInt8, alpha:UInt8)) {
        let imageRawData = imgRep.bitmapData
        let imageWidth = Int(imgRep.size.width)
        let imageHeight = Int(imgRep.size.height)
        for pixelIdx in 0 ..< (imageWidth * imageHeight) {
            let (cyan, magenta, yellow, black, alpha) = components(pixelIdx)
            let fAlpha = Float(alpha) / 255
            imageRawData[pixelIdx * 5 + 0] = UInt8(Float(cyan) * fAlpha)
            imageRawData[pixelIdx * 5 + 1] = UInt8(Float(magenta) * fAlpha)
            imageRawData[pixelIdx * 5 + 2] = UInt8(Float(yellow) * fAlpha)
            imageRawData[pixelIdx * 5 + 3] = UInt8(Float(black) * fAlpha)
            imageRawData[pixelIdx * 5 + 4] = alpha
        }
    }
    
晨曦慕雪 2024-09-16 09:50:58
CGImageRef CGImageCreateCopyWithColorSpace (
   CGImageRef image,
   CGColorSpaceRef colorspace
);

要获取 CGColorSpaceRef,您可以执行以下操作

CGColorSpaceRef CGColorSpaceCreateDeviceRGB();

或参阅此页面了解如何创建其他色彩空间。

CGImageRef CGImageCreateCopyWithColorSpace (
   CGImageRef image,
   CGColorSpaceRef colorspace
);

To get a CGColorSpaceRef, you can do things like

CGColorSpaceRef CGColorSpaceCreateDeviceRGB();

OR see this page for how to create other color spaces.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文