swift – 从CGImage获取像素格式

swift – 从CGImage获取像素格式,第1张

概述我理解位图布局和像素格式主题很好,但在使用通过NS Image加载的png / jpeg图像时遇到问题 – 我无法弄清楚我得到的是预期的行为还是错误. let nsImage:NSImage = NSImage(byReferencingURL: …)let cgImage:CGImage = nsImage.CGImageForProposedRect(nil, context: nil, h 我理解位图布局和像素格式主题很好,但在使用通过NS Image加载的png / jpeg图像时遇到问题 – 我无法弄清楚我得到的是预期的行为还是错误.
let nsImage:NSImage = NSImage(byReferencingURL: …)let cgImage:CGImage = nsImage.CGImageForProposedRect(nil,context: nil,hints: nil)!let bitmAPInfo:CGBitmAPInfo = CGImageGetBitmAPInfo(cgImage)Swift.print(bitmAPInfo.contains(CGBitmAPInfo.ByteOrderDefault)) // True

我的kCGBitmapByteOrder32Host是小端,这意味着像素格式也是小端 – 在这种情况下是BGRA.但是…… png格式是规范的大端,这就是字节实际排列在数据中的方式 – 与位图信息告诉我的方式相反.

有谁知道发生了什么事?当然,系统知道如何处理这个问题,因为pngs正确显示.是否有检测CGImage像素格式的防d方式? GitHub提供完整的demo project.

P. S.我正在通过CFDataGetBytePtr缓冲区将原始像素数据复制到另一个库缓冲区中,然后进行处理和保存.为此,我需要明确指定像素格式.我正在处理的实际图像(我检查过的任何png / jpeg文件)显示正确,例如:

但是相同图像的位图信息给出了不正确的字节序信息,导致位图被处理为BGRA像素格式而不是实际的RGBA,当我处理它时,结果如下所示:

生成的图像演示了红色和蓝色像素之间的颜色交换,如果明确指定RGBA像素格式,一切都很完美,但我需要将此检测自动化.

P. P. S.文档简要提到CGcolorSpace是定义像素格式/字节顺序的另一个重要变量,但我没有提到如何将它从那里拿出来.

几年后,在测试我的生产结果后,我可以很自信地分享它们,但希望有理论知识的人能在这里更好地解释一下吗?刷新记忆的好地方:

> Wikipedia: RGBA color space – Representation
> Apple Lists: Byte Order in CGBitmapContextCreate
> Apple Lists: kCGImageAlphaPremultiplied First/Last

基于此,您可以使用以下扩展:

public enum PixelFormat{    case abgr    case argb    case bgra    case rgba}extension CGBitmAPInfo{    public static var byteOrder16Host: CGBitmAPInfo {        return CFByteOrderGetCurrent() == Int(CFByteOrderlittleEndian.rawValue) ? .byteOrder16little : .byteOrder16Big    }    public static var byteOrder32Host: CGBitmAPInfo {        return CFByteOrderGetCurrent() == Int(CFByteOrderlittleEndian.rawValue) ? .byteOrder32little : .byteOrder32Big    }}extension CGBitmAPInfo{    public var pixelFormat: PixelFormat? {        // AlphaFirst – the Alpha channel is next to the red channel,argb and bgra are both Alpha first formats.        // AlphaLast – the Alpha channel is next to the blue channel,rgba and abgr are both Alpha last formats.        // littleEndian – blue comes before red,bgra and abgr are little endian formats.        // little endian ordered pixels are BGR (BGRX,XBGR,BGRA,ABGR,BGR).        // BigEndian – red comes before blue,argb and rgba are big endian formats.        // Big endian ordered pixels are RGB (XRGB,RGBX,ARGB,RGBA,RGB).        let AlphaInfo: CGImageAlphaInfo? = CGImageAlphaInfo(rawValue: self.rawValue & type(of: self).AlphaInfoMask.rawValue)        let AlphaFirst: Bool = AlphaInfo == .premultiplIEdFirst || AlphaInfo == .first || AlphaInfo == .noneskipFirst        let AlphaLast: Bool = AlphaInfo == .premultiplIEdLast || AlphaInfo == .last || AlphaInfo == .noneskipLast        let endianlittle: Bool = self.contains(.byteOrder32little)        // This is slippery… while byte order host returns little endian,default bytes are stored in big endian        // format. Here we just assume if no byte order is given,then simple RGB is used,aka big endian,though…        if AlphaFirst && endianlittle {            return .bgra        } else if AlphaFirst {            return .argb        } else if AlphaLast && endianlittle {            return .abgr        } else if AlphaLast {            return .rgba        } else {            return nil        }    }}

请注意,您应始终注意色彩空间 – 它会直接影响原始像素数据的存储方式. CGcolorSpace(名称:CGcolorSpace.sRGB)可能是最安全的 – 它以普通格式存储颜色,例如,如果处理红色RGB,它将被存储就像那样(255,0),而设备颜色空间将给出你喜欢(235,73,53).

要在实践中看到这一点,请将上方和下方放入游乐场.你需要两个带有Alpha和不带的单像素红色图像,this和this应该可以工作.

import AppKitimport CoreGraphicsextension CFData{    public var pixelComponents: [UInt8] {        let buffer: UnsafeMutablePointer<UInt8> = UnsafeMutablePointer.allocate(capacity: 4)        defer { buffer.deallocate(capacity: 4) }        CFDataGetBytes(self,CFRange(location: 0,length: CFDataGetLength(self)),buffer)        return Array(UnsafeBufferPointer(start: buffer,count: 4))    }}let color: NScolor = .redThread.sleep(forTimeInterval: 2)// Must flip coordinates to capture what we want…let screen: NSScreen = NSScreen.screens.first(where: { 
Will capture image with (285.7734375,294.5,1.0,1.0) frame.<CGcolorSpace 0x7fde4e9103e0> (kCGcolorSpaceICCBased; kCGcolorSpaceModelRGB; iMac) CGBitmAPInfo(rawValue: 8194) bgra [27,13,252,255]<CGcolorSpace 0x7fde4d703b20> (kCGcolorSpaceICCBased; kCGcolorSpaceModelRGB; color LCD) CGBitmAPInfo(rawValue: 3) rgba [235,53,255]<CGcolorSpace 0x7fde4e915dc0> (kCGcolorSpaceICCBased; kCGcolorSpaceModelRGB; color LCD) CGBitmAPInfo(rawValue: 5) rgba [235,255]<CGcolorSpace 0x7fde4d60d390> (kCGcolorSpaceICCBased; kCGcolorSpaceModelRGB; sRGB IEC61966-2.1) CGBitmAPInfo(rawValue: 2) argb [255,1,2,3]<CGcolorSpace 0x7fde4d60d390> (kCGcolorSpaceICCBased; kCGcolorSpaceModelRGB; sRGB IEC61966-2.1) CGBitmAPInfo(rawValue: 6) argb [255,3]<CGcolorSpace 0x7fde4d60d390> (kCGcolorSpaceICCBased; kCGcolorSpaceModelRGB; sRGB IEC61966-2.1) CGBitmAPInfo(rawValue: 1) rgba [1,3,255]<CGcolorSpace 0x7fde4d60d390> (kCGcolorSpaceICCBased; kCGcolorSpaceModelRGB; sRGB IEC61966-2.1) CGBitmAPInfo(rawValue: 5) rgba [1,255]
.frame.contains(NSEvent.mouseLocation) })!let rect: CGRect = CGRect(origin: CGPoint(x: NSEvent.mouseLocation.x - 10,y: screen.frame.height - NSEvent.mouseLocation.y),size: CGSize(wIDth: 1,height: 1))Swift.print("Will capture image with \(rect) frame.")let screenImage: CGImage = CGWindowListCreateImage(rect,[],kCGNullWindowID,[])!let urlimageWithAlpha: CGImage = NSImage(byReferencing: URL(fileURLWithPath: "/Users/ianbytchek/Downloads/red-pixel-with-Alpha.png")).cgImage(forProposedRect: nil,hints: nil)!let urlimageNoAlpha: CGImage = NSImage(byReferencing: URL(fileURLWithPath: "/Users/ianbytchek/Downloads/red-pixel-no-Alpha.png")).cgImage(forProposedRect: nil,hints: nil)!Swift.print(screenImage.colorSpace!,screenImage.bitmAPInfo,screenImage.bitmAPInfo.pixelFormat!,screenImage.dataProvIDer!.data!.pixelComponents)Swift.print(urlimageWithAlpha.colorSpace!,urlimageWithAlpha.bitmAPInfo,urlimageWithAlpha.bitmAPInfo.pixelFormat!,urlimageWithAlpha.dataProvIDer!.data!.pixelComponents)Swift.print(urlimageNoAlpha.colorSpace!,urlimageNoAlpha.bitmAPInfo,urlimageNoAlpha.bitmAPInfo.pixelFormat!,urlimageNoAlpha.dataProvIDer!.data!.pixelComponents)let formats: [CGBitmAPInfo.RawValue] = [ CGImageAlphaInfo.premultiplIEdFirst.rawValue,CGImageAlphaInfo.noneskipFirst.rawValue,CGImageAlphaInfo.premultiplIEdLast.rawValue,CGImageAlphaInfo.noneskipLast.rawValue,]for format in formats { // This "paints" and prints out components in the order they are stored in data. let context: CGContext = CGContext(data: nil,wIDth: 1,height: 1,bitsPerComponent: 8,bytesPerRow: 32,space: CGcolorSpace(name: CGcolorSpace.sRGB)!,bitmAPInfo: format)! let components: UnsafeBufferPointer<UInt8> = UnsafeBufferPointer(start: context.data!.assumingMemoryBound(to: UInt8.self),count: 4) context.setFillcolor(red: 1 / 0xFF,green: 2 / 0xFF,blue: 3 / 0xFF,Alpha: 1) context.fill(CGRect(x: 0,y: 0,height: 1)) Swift.print(context.colorSpace!,context.bitmAPInfo,context.bitmAPInfo.pixelFormat!,Array(components))}

这将输出以下内容.注意屏幕捕获的图像与磁盘加载的图像有何不同.

总结

以上是内存溢出为你收集整理的swift – 从CGImage获取像素格式全部内容,希望文章能够帮你解决swift – 从CGImage获取像素格式所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址:https://www.54852.com/web/1035049.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-05-24
下一篇2022-05-24

发表评论

登录后才能评论

评论列表(0条)

    保存