【问题标题】:Detect if PNG file is corrupted in Objective C检测PNG文件是否在Objective C中损坏
【发布时间】:2012-05-11 13:18:27
【问题描述】:

我正在使用 NSURLRequest 下载 jpg 和 png。这工作正常,但有时文件已损坏。 我见过Catching error: Corrupt JPEG data: premature end of data segment 并且可以为jpgs 工作。 有谁知道对pngs做同样的事情的方法?即以编程方式检查png数据是否有效...

【问题讨论】:

    标签: objective-c png nsurlrequest corrupt


    【解决方案1】:

    PNG 格式有几个内置检查。每个“块”都有一个 CRC32 检查,但要检查您是否需要阅读完整文件。

    更基本的检查(当然不是万无一失的)是读取文件的开头和结尾。

    前 8 个字节应始终为以下(十进制)值 { 137, 80, 78, 71, 13, 10, 26, 10 } (ref)。特别是,第二到第四个字节对应于 ASCII 字符串“PNG”。

    十六进制:

    89 50 4e 47 0d 0a 1a 0a
    .. P  N  G  ...........
    

    您还可以检查文件的最后 12 个字节(IEND 块)。中间 4 个字节应对应 ASCII 字符串“IEND”。更具体地说,最后 12 个字节应该是(以十六进制表示):

    00 00 00 00 49 45 4e 44 ae 42 60 82
    ........... I  E  N  D  ...........
    

    (严格来说,PNG 文件以这 12 个字节结尾并不是必须的,IEND 块本身发出 PNG 流结束的信号,因此文件原则上可以有额外的尾随字节,这些字节会被PNG 阅读器。实际上,这是极不可能的)。

    【讨论】:

      【解决方案2】:

      就像Catching error: Corrupt JPEG data: premature end of data segment 一样,这里是 PNG 的代码 sn-p:

      - (BOOL)dataIsValidPNG:(NSData *)data
      {
          if (!data || data.length < 12)
          {
              return NO;
          }
      
          NSInteger totalBytes = data.length;
          const char *bytes = (const char *)[data bytes];
      
          return (bytes[0] == (char)0x89 && // PNG
                  bytes[1] == (char)0x50 &&
                  bytes[2] == (char)0x4e &&
                  bytes[3] == (char)0x47 &&
                  bytes[4] == (char)0x0d &&
                  bytes[5] == (char)0x0a &&
                  bytes[6] == (char)0x1a &&
                  bytes[7] == (char)0x0a &&
      
                  bytes[totalBytes - 12] == (char)0x00 && // IEND
                  bytes[totalBytes - 11] == (char)0x00 &&
                  bytes[totalBytes - 10] == (char)0x00 &&
                  bytes[totalBytes - 9] == (char)0x00 &&
                  bytes[totalBytes - 8] == (char)0x49 &&
                  bytes[totalBytes - 7] == (char)0x45 &&
                  bytes[totalBytes - 6] == (char)0x4e &&
                  bytes[totalBytes - 5] == (char)0x44 &&
                  bytes[totalBytes - 4] == (char)0xae &&
                  bytes[totalBytes - 3] == (char)0x42 &&
                  bytes[totalBytes - 2] == (char)0x60 &&
                  bytes[totalBytes - 1] == (char)0x82);
      }
      

      【讨论】:

        【解决方案3】:

        更好的 dataIsValidPNG 版本:

        BOOL dataIsValidPNG(NSData *data) {
        
            if (!data) {
                return NO;
            }
        
            const NSInteger totalBytes = data.length;
            const char *bytes = (const char *)[data bytes];
            const char start[] = { '\x89',  'P',  'N',  'G', '\r', '\n', '\x1a', '\n' };
            const char end[]   = {   '\0', '\0', '\0', '\0',  'I',  'E',    'N',  'D', '\xAE', 'B', '`', '\x82' };
        
            if (totalBytes < (sizeof(start) + sizeof(end))) {
                return NO;
            }
        
            return (memcmp(bytes, start, sizeof(start)) == 0) &&
                   (memcmp(bytes + (totalBytes - sizeof(end)), end, sizeof(end)) == 0);
        }
        

        【讨论】:

          猜你喜欢
          • 2010-12-29
          • 2012-04-13
          • 2011-01-23
          • 1970-01-01
          • 1970-01-01
          • 2012-08-31
          • 1970-01-01
          • 2017-10-26
          • 2013-07-06
          相关资源
          最近更新 更多