Swift 无法读取PNG文件的IHDR块

Swift 无法读取PNG文件的IHDR块,swift,png,nsfilehandle,Swift,Png,Nsfilehandle,我阅读了PNG文件规范,了解到在PNG签名的前8个字节之后,我们有了IHDR块。此图像表示我们有长度为13(0x0000000D)字节的IHDR。 我已经用swift编写了一个代码来读取相同的png文件并打印字节,但这并没有给我一个长度等于png签名后块的前4个字节中13个字节的IHDR。控制台中的代码输出为 PNG Signature Bytes: 89 50 4E 47 0D 0A 1A 0A File offset: 8 IHDR length bytes: 00 00 00 04

我阅读了PNG文件规范,了解到在PNG签名的前8个字节之后,我们有了IHDR块。此图像表示我们有长度为13(0x0000000D)字节的IHDR。

我已经用swift编写了一个代码来读取相同的png文件并打印字节,但这并没有给我一个长度等于png签名后块的前4个字节中13个字节的IHDR。控制台中的代码输出为

PNG Signature Bytes: 89 50 4E 47 0D 0A 1A 0A 
File offset: 8
IHDR length bytes: 00 00 00 04 
File offset: 12
IHDR Chunktype bytes: 43 67 42 49 
File offset: 16
IHDR Data byte: 50 00 20 02 
File offset: 20
pngImageWidth: 1342185474
pngImageWidth: 20480
pngImageHeight: 8194
我是否遗漏了一些内容,或者我阅读的规范已经过时了?

前8个字节是实际PNG签名字节。IHDR字节是我无法获得预期长度和块类型的地方(IHDR的宽度、高度和其他字节对于不同的文件是可变的,但是长度和块类型应该与我的读取相同)

读取png文件的代码是直截了当的,如下所示:

enum PNGFileAnatomyConstants {
    static let pngSignatureLength = 8
    static let ihdrLength = 4
    static let chunkTypeLength = 4
    static let chunkCRCLength = 4
    static let imageWidthLength = 4
    static let imageHeigthLength = 4
}

func anatomyOfPNGFile() {
    let bundle = Bundle.main

    guard let pngFileUrl = bundle.url(forResource: "PNGFileSignature", withExtension: "png") else { fatalError() }

    do {
        // Signature start------------------------------------------------------------------------------------------

        let readFileHandle = try FileHandle(forReadingFrom: pngFileUrl)
        defer {
            readFileHandle.closeFile()
        }
        let pngSignatureData = readFileHandle.readData(ofLength: PNGFileAnatomyConstants.pngSignatureLength)
        let signatureString  = pngSignatureData.hexEncodedString(options: [Data.HexEncodingOptions.upperCase])
        if signatureString != "89 50 4E 47 0D 0A 1A 0A " {
            fatalError(" Not a png")
        }
        print("PNG Signature Bytes: \(signatureString)")
        print("File offset: \(readFileHandle.offsetInFile)")
        // Signature ebd------------------------------------------------------------------------------------------




        // IHDR Length start------------------------------------------------------------------------------------------
        let ihdrLengthDataBigEndian = readFileHandle.readData(ofLength: PNGFileAnatomyConstants.ihdrLength)

        let ihdrLength: UInt32
        if PlatformEndianess.isLittleEndian {
            ihdrLength = Data(ihdrLengthDataBigEndian.reversed()).withUnsafeBytes({ (unsafePointer: UnsafePointer<UInt32>) -> UInt32 in
                return unsafePointer.pointee
            })
        } else {
            ihdrLength = ihdrLengthDataBigEndian.withUnsafeBytes({ (unsafePointer: UnsafePointer<UInt32>) -> UInt32 in
                return unsafePointer.pointee
            })
        }

        let ihdrLengthDataBigEndianString = ihdrLengthDataBigEndian.hexEncodedString(options: [.upperCase])
        print("IHDR length bytes: \(ihdrLengthDataBigEndianString)")
        print("File offset: \(readFileHandle.offsetInFile)")
        // IHDR Length end------------------------------------------------------------------------------------------





        // IHDR chunk type start------------------------------------------------------------------------------------------
        let ihdrChunkTypeData = readFileHandle.readData(ofLength: PNGFileAnatomyConstants.chunkTypeLength)
        let ihdrChunkTypeDataString  = ihdrChunkTypeData.hexEncodedString(options: [Data.HexEncodingOptions.upperCase])
        print("IHDR Chunktype bytes: \(ihdrChunkTypeDataString)")
        print("File offset: \(readFileHandle.offsetInFile)")
        // IHDR chunk type end------------------------------------------------------------------------------------------



        // IHDR data byte start------------------------------------------------------------------------------------------
        let ihdrData = readFileHandle.readData(ofLength: Int(ihdrLength))
        let ihdrDataString = ihdrData.hexEncodedString(options: [.upperCase])
        print("IHDR Data byte: \(ihdrDataString)")
        print("File offset: \(readFileHandle.offsetInFile)")
        // IHDR data byte end------------------------------------------------------------------------------------------

        do {
            let pngImageWidth: UInt32
            if PlatformEndianess.isLittleEndian {
                pngImageWidth = Data(ihdrData.reversed()).withUnsafeBytes({ (unsafePointer: UnsafePointer<UInt32>) -> UInt32 in
                    return unsafePointer.pointee
                })
            } else {
                pngImageWidth = ihdrData.withUnsafeBytes({ (unsafePointer: UnsafePointer<UInt32>) -> UInt32 in
                    return unsafePointer.pointee
                })
            }

            print("pngImageWidth: \(pngImageWidth)")
        }

        do {
            let pngImageWidth: UInt16
            let widthData = Data(bytes: [ihdrData[0], ihdrData[1]])
            if PlatformEndianess.isLittleEndian {

                pngImageWidth = Data(widthData.reversed()).withUnsafeBytes({ (unsafePointer: UnsafePointer<UInt16>) -> UInt16 in
                    return unsafePointer.pointee
                })
            } else {
                pngImageWidth = widthData.withUnsafeBytes({ (unsafePointer: UnsafePointer<UInt16>) -> UInt16 in
                    return unsafePointer.pointee
                })
            }

            print("pngImageWidth: \(pngImageWidth)")//20480

            let pngImageHeight: UInt16
            let heightData = Data(bytes: [ihdrData[2], ihdrData[3]])
            if PlatformEndianess.isLittleEndian {

                pngImageHeight = Data(heightData.reversed()).withUnsafeBytes({ (unsafePointer: UnsafePointer<UInt16>) -> UInt16 in
                    return unsafePointer.pointee
                })
            } else {
                pngImageHeight = heightData.withUnsafeBytes({ (unsafePointer: UnsafePointer<UInt16>) -> UInt16 in
                    return unsafePointer.pointee
                })
            }

            print("pngImageHeight: \(pngImageHeight)")//20480
        }

    } catch {
        fatalError(error.localizedDescription)
    }
}

extension Data {
    struct HexEncodingOptions: OptionSet {
        let rawValue: Int
        static let upperCase = HexEncodingOptions(rawValue: 1 << 0)
    }

    func hexEncodedString(options: HexEncodingOptions = []) -> String {
        let hexDigits = Array((options.contains(.upperCase) ? "0123456789ABCDEF " : "0123456789abcdef ").utf16)
        var chars: [unichar] = []
        chars.reserveCapacity(3 * count)
        for byte in self {
            chars.append(hexDigits[Int(byte / 16)])
            chars.append(hexDigits[Int(byte % 16)])
            chars.append(hexDigits.last!)
        }
        return String(utf16CodeUnits: chars, count: chars.count)
    }
}

class PlatformEndianess {
    static var isLittleEndian: Bool = {
        var integer: UInt16 = 0x0001
        return withUnsafeBytes(of: &integer, { (rawBufferPointer) -> Bool in
            return rawBufferPointer.first == 0x01
        })
    }()
}
enum PNGFileAnatomyConstants{
静态let pngSignatureLength=8
静态let ihdrLength=4
静态let chunkTypeLength=4
静态let chunkCRCLength=4
静态let imageWidthLength=4
静态let图像高度长度=4
}
func anatomyOfPNGFile(){
设bundle=bundle.main
guard let pngFileUrl=bundle.url(用于资源:“PNGFileSignature”,扩展名为:“png”)else{fatalError()}
做{
//签名开始------------------------------------------------------------------------------------------
让readFileHandle=尝试FileHandle(forReadingFrom:pngFileUrl)
推迟{
readFileHandle.closeFile()文件
}
让pngSignatureData=readFileHandle.readData(长度:PNGFileAnatomyConstants.pngSignatureLength)
让signatureString=pngSignatureData.hexEncodedString(选项:[Data.HexEncodingOptions.upperCase])
如果签名限制!=“89 50 4E 47 0D 0A 1A 0A”{
fatalError(“非png”)
}
打印(“PNG签名字节:\(签名限制)”)
打印(“文件偏移量:\(readFileHandle.offsetInFile)”)
//特征ebd------------------------------------------------------------------------------------------
//IHDR长度起始------------------------------------------------------------------------------------------
设ihdrLengthDataBigEndian=readFileHandle.readData(长度:PNGFileAnatomyConstants.ihdrLength)
让ihdrLength:UInt32
if PlatformEndianess.isLittleEndian{
ihdrLength=Data(ihdrLengthDataBigEndian.reversed())。在
返回unsafePointer.pointee
})
}否则{
ihdrLength=ihdrLengthDataBigEndian.withUnsafeBytes({(unsafePointer:unsafePointer)->UInt32 in
返回unsafePointer.pointee
})
}
让ihdrLengthDataBigEndianString=ihdrLengthDataBigEndian.hexEncodedString(选项:[.upperCase])
打印(“IHDR长度字节:\(ihdrLengthDataBigEndianString)”)
打印(“文件偏移量:\(readFileHandle.offsetInFile)”)
//IHDR长度端------------------------------------------------------------------------------------------
//IHDR块类型开始------------------------------------------------------------------------------------------
让ihdrChunkTypeData=readFileHandle.readData(长度:PNGFileAnatomyConstants.chunkTypeLength)
让ihdrChunkTypeDataString=ihdrChunkTypeData.hexEncodedString(选项:[Data.HexEncodingOptions.upperCase])
打印(“IHDR Chunktype字节:\(ihdrChunkTypeDataString)”)
打印(“文件偏移量:\(readFileHandle.offsetInFile)”)
//IHDR块类型结束------------------------------------------------------------------------------------------
//IHDR数据字节开始------------------------------------------------------------------------------------------
设ihdrData=readFileHandle.readData(of长度:Int(ihdrLength))
让ihdrDataString=ihdrData.hexEncodedString(选项:[.upperCase])
打印(“IHDR数据字节:\(ihdrDataString)”)
打印(“文件偏移量:\(readFileHandle.offsetInFile)”)
//IHDR数据字节结束------------------------------------------------------------------------------------------
做{
让pngImageWidth:UInt32
if PlatformEndianess.isLittleEndian{
pngImageWidth=Data(ihdrData.reversed())。在中包含unsafebytes({(unsafePointer:unsafePointer)->UInt32
返回unsafePointer.pointee
})
}否则{
pngImageWidth=ihdrData.withUnsafeBytes({(unsafePointer:unsafePointer)->UInt32 in
返回unsafePointer.pointee
})
}
打印(“pngImageWidth:\(pngImageWidth)”)
}
做{
让pngImageWidth:UInt16
设widthData=Data(字节:[ihdrData[0],ihdrData[1]]
if PlatformEndianess.isLittleEndian{
pngImageWidth=Data(widthData.reversed())。在
返回unsafePointer.pointee
})
}否则{
pngImageWidth=widthData.withUnsafeBytes({(unsafePointer:unsafePointer)->UInt16 in
返回unsafePointer.pointee
})
}
打印(“pngImageWidth:\(pngImageWidth)”)/20480
让pngImageHeight:UInt16
设heightData=Data(字节:[ihdrData[2],ihdrData[3]]
if PlatformEndianess.isLittleEndian{
pngImageHeight=Data(heightData.reversed())。在
返回unsafePointer.pointee
})
}否则{
pngImageHeight=heightData.withUnsafeBytes({(unsafePointer:unsafePointer)->UInt16 in
重新
PNG Signature(8 bytes): 89 50 4E 47 0D 0A 1A 0A
=======Chunk start=======
IHDR Chunk:
    IHDR chunk length(4 bytes): 00 00 00 0D
    IHDR chunk type(Identifies chunk type to be IHDR): 49 48 44 52
    Image width in pixels(variable 4): xx xx xx xx
    Image height in pixels(variable 4): xx xx xx xx
    Flags in the chunk(variable 5 bytes): xx xx xx xx xx
    CRC checksum(variable 4 bytes): xx xx xx xx 
=======Chunk end=======
PNG Signature(8 bytes): 89 50 4E 47 0D 0A 1A 0A
=======Chunk start=======
CgBI Chunk:
    CgBI chunk length(4 bytes): 00 00 00 04
    CgBI chunk type(Identifies chunk type to be CgBI): 43 67 42 49
    CgBI info flags(4 bytes): xx xx xx xx
    CRC checksum(variable 4 bytes): xx xx xx xx 
=======Chunk end=======
=======Chunk start=======
IHDR Chunk:
    IHDR chunk length(4 bytes): 00 00 00 0D
    IHDR chunk type(Identifies chunk type to be IHDR): 49 48 44 52
    Image width in pixels(variable 4): xx xx xx xx
    Image height in pixels(variable 4): xx xx xx xx
    Flags in the chunk(variable 5 bytes): xx xx xx xx xx
    CRC checksum(variable 4 bytes): xx xx xx xx 
=======Chunk end=======