title: Not able to read IHDR chunk of a PNG file
body: <p>I have read PNG file specification and learnt that after the first 8 bytes of PNG signature, we have the IHDR chunk. This image states that we have IHDR with length of 13(0x0000000D) bytes. 
  <a href="https://i.stack.imgur.com/hcIIO.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/hcIIO.png" alt="enter image description here"></a></p>
  
  <p>I have written a code in swift to read the same png file and print the bytes which does not give me an IHDR with length equal to 13 bytes from the first 4 bytes of the chunk after the PNG signature. The output of the code in console is </p>
  
  <pre><code>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
  </code></pre>
  
  <p><strong>Have I missed something here or the specification that I read was outdated?</strong></p>
  
  <p>The first 8 bytes are infact PNG signature bytes. The IHDR bytes is where I dont get the expected length and chunk types(width, heigth and other bytes of the IHDR are variable for different files, but length and chunk types should be same as per my reading).</p>
  
  <p>The code for reading the png file is straight forward and is as below:</p>
  
  <pre><code>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&lt;UInt32&gt;) -&gt; UInt32 in
                  return unsafePointer.pointee
              })
          } else {
              ihdrLength = ihdrLengthDataBigEndian.withUnsafeBytes({ (unsafePointer: UnsafePointer&lt;UInt32&gt;) -&gt; 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&lt;UInt32&gt;) -&gt; UInt32 in
                      return unsafePointer.pointee
                  })
              } else {
                  pngImageWidth = ihdrData.withUnsafeBytes({ (unsafePointer: UnsafePointer&lt;UInt32&gt;) -&gt; 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&lt;UInt16&gt;) -&gt; UInt16 in
                      return unsafePointer.pointee
                  })
              } else {
                  pngImageWidth = widthData.withUnsafeBytes({ (unsafePointer: UnsafePointer&lt;UInt16&gt;) -&gt; 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&lt;UInt16&gt;) -&gt; UInt16 in
                      return unsafePointer.pointee
                  })
              } else {
                  pngImageHeight = heightData.withUnsafeBytes({ (unsafePointer: UnsafePointer&lt;UInt16&gt;) -&gt; 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 &lt;&lt; 0)
      }
  
      func hexEncodedString(options: HexEncodingOptions = []) -&gt; 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: &amp;integer, { (rawBufferPointer) -&gt; Bool in
              return rawBufferPointer.first == 0x01
          })
      }()
  }
  </code></pre>