无法读取 PNG 文件的 IHDR 块

2024-01-02

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. enter image description here

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

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
        })
    }()
}

正如所指出的MartinR https://stackoverflow.com/users/1187415/martin-rPNG 文件存在一个名为CgBI http://iphonedevwiki.net/index.php/CgBI_file_format.

普通 PNG 文件的结构是 PNG 签名后跟 IHDR 块。

下面是普通 PNG 文件的十六进制表示形式的字节示例( xx 是具有变量值的占位符字节):

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=======

具有 CgBI 扩展名的 PNG 文件具有这样的结构:PNG 签名后跟 CgBI 块,然后是 IHDR 块。

当我说扩展名时,请不要将其与“filename.png、filename.cgbi”混淆。它实际上是 PNG 文件结构方式的扩展。

下面是带有 CgBI 扩展名的 PNG 文件的十六进制表示的字节示例( xx 是具有变量值的占位符字节):

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=======

虽然 PNG 文件会在所有图像查看器上呈现,但扩展名 CgBI 可能会也可能不会在所有图像查看器上呈现,具体取决于它们为此类文件提供的支持。

MacOS 预览可以显示此类图像,iOS 上的 UIImageView 也可以显示我的示例图像集中的文件(带有 CgBI 扩展名的 PNG)。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

无法读取 PNG 文件的 IHDR 块 的相关文章

随机推荐

  • Modernizr 只是为了快速检查一下?

    我想检查运行我的页面的浏览器是否 能够处理 html 5 占位符 我知道我可以添加以下 javascript 检查 Modernizr input placeholder 但仅仅为了一次检查就值得导入一个库吗 Modernizr 如何为我做
  • 学习 php 的最佳资源视频 [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我最近在 SO 上发现了这篇文章 学习 javascript 的最佳资源 https stackoverflow com question
  • 如何在android中定义像这样的三角形布局?

    如何创建如图所示的布局 我想你可以使用android rotation 45 在图像上放置一个交叉的组件并产生这种效果
  • 瓷砖重叠有什么好处?

    刚开始玩 OpenSeadragon 顺便说一句 非常好 并创建自定义图块集 我想知道创建重叠图块的优点或缺点是什么 我尝试过使用 0 似乎没问题 但我想知道是否有任何清晰度或性能优势或图块重叠 我认为 DeepZoom 格式使用 4 为例
  • MediaCapture Windows 8 桌面应用程序 - 无法运行

    我正在尝试通过此 API 实现图像捕获 并且我需要通过桌面应用程序实现 问题是当我将图像保存到文件中时 使用CapturePhotoToStorageFileAsync 我得到一张暗图片 几乎是黑色 或者我得到零大小的文件 我的代码很简单
  • 如何使静态样式表在 django 中工作?

    通过正常运行此代码html它运行起来也很有风格 但每当我在 django 中运行它时 它都不会运行 只显示文本 views py def index request return render request index html main
  • 如何使用 Json.NET 在 C# 中向 JSON 添加根节点?

    我正在研究Visual Studio C 项目 我需要转换JSON to XML 我收到JSON以字符串格式 问题是 我需要有一个根节点JSON结构如果JSON没有 这样我就可以转换为XML与所需的格式 假设我有这个JSON id 1 na
  • 查找并替换Android studio

    有没有办法在整个项目中查找和替换单词的所有出现 不仅仅是使用重构 gt 重命名的单个类 并维护大小写 无论是在 android studio 中还是使用命令行脚本 例如 供应商必须转到商家 供应商 gt 商家 供应商 gt 商家 我的老板希
  • 使用 DataAnnotations 和 DataType 验证电子邮件模型

    我有以下型号 public class FormularModel Required public string Position get set Required DataType DataType EmailAddress public
  • JDBC-接口的实现

    在 JDBC 中 为了连接和执行 DB 中的语句 我们主要使用 Connection Statement 和 ResultSet 这些接口 但它们相应的对象稍后用于运行 createStatement executeQuery next 等
  • 使用 Node.js 将一行写入 .txt 文件

    我想使用 Node js 创建一个简单的日志系统 它将上一行之前的一行打印到 txt 文件中 但是 我不知道 Node js 的文件系统功能是如何工作的 有人可以解释一下吗 将数据插入文本文件的中间并不是一项简单的任务 如果可能 您应该将其
  • 现有文件中的组织不明确:{ .... }。必须指定 --org 命令行参数才能重新创建项目

    尝试在 Windows 上运行我现有的 flutter 应用程序时 出现以下异常 异常 未配置 Windows 桌面项目 请参阅https flutter dev desktop add desktop support to an exis
  • Google 脚本触发器未触发

    我正在努力让我的脚本在早上 6 点自动运行 左右 我设置了触发器来在 上午 6 点至 7 点 之间的 日定时器 上运行此脚本 时间驱动 我没有收到任何失败通知 设置为立即通过电子邮件发送给我 但脚本没有运行 当我手动运行它时 它的工作原理与
  • BaseTransientBottomBar 和相关错误以及如何解决

    首先 我尝试解决以下问题 步骤 1 我在 BaseActivity 和 BaseActivity 抽象类中放置了一个方法 以了解 Activity 何时停止以及视图 片段的根视图 何时被销毁 在两种情况下返回 true 但在事件之前返回 f
  • TypeScript 设置 HTMLCollectionOf、NodeCollection、google 自动完成表单的 css 样式

    如何为 HTMLCollectionOf 或 NodeCollection 设置 css 样式 let items document querySelectorAll pac item as NodeListOf
  • WampServer - mysqld.exe 无法启动,因为缺少 MSVCR120.dll

    我尝试在本地运行 wampserver 但 mysql 服务器未运行 当我尝试安装服务 它给我错误 我一整天都在寻找答案 并在这里和那里找到了一些答案 但任何解决方案对我都不起作用 我尝试在 Windows 7 家庭操作系统 vmware
  • 如何在一行上运行PowerShell?

    As per 这个答案 https stackoverflow com questions 22258668 how to condense powershell script to fit on a single line PowerSh
  • 我们可以增加Android手机麦克风的增益吗?

    我正在尝试增加 Android 手机麦克风的增益 以便它能够听到非常微小的声音 这可能吗 你能帮我解决这个问题吗 这个链接 http developer android com reference android media AudioMa
  • Flask 消息在重定向时闪烁失败

    我目前正在使用一个项目Flask http en wikipedia org wiki Flask 28programming 29 and 谷歌应用引擎 http en wikipedia org wiki Google App Engi
  • 无法读取 PNG 文件的 IHDR 块

    I have read PNG file specification and learnt that after the first 8 bytes of PNG signature we have the IHDR chunk This