【问题标题】:How can I extract the .jpg/.png components of an .hpi file?如何提取 .hpi 文件的 .jpg/.png 组件?
【发布时间】:2008-10-23 01:17:41
【问题描述】:

我偶然发现了我相当古老的照片对象磁盘,遗憾地发现该公司 (hemera) 不再为其提供支持。这给我留下了一大堆 .hpi 文件。幸运的是,我在提取文件的 jpg 和 png 组件时找到了this information

不幸的是,我无法让它工作。谁能弄清楚这段代码有什么问题?如果您不喜欢 Perl,我会很高兴使用 PHP 或 Python 解决方案。 :)

open(I, "$name") || die;
binmode(I);
$_ = <I>;
close(I);

my ($j, $p) = m|^.{32}(.*)(\211PNG.*)$|s;
open(J, ">$name.jpg") &&
    do { binmode(J); print J $j; close J; };
open(P, ">$name.png") &&
    do { binmode(P); print P $p; close P; };

我从 CD 上抓取的当前测试文件的 hexdump 在这里,如果它有帮助的话:

0000000 89 48 50 49 0d 0a 1a 0a 64 00 00 00 20 00 00 00
0000010 45 89 00 00 65 89 00 00 0a 21 00 00 00 d0 d0 00

【问题讨论】:

    标签: binaryfiles


    【解决方案1】:

    我在从 MS Word 文档中提取图像时遇到了类似的问题。这是我为此编写的程序。不过,它只提取 PNG:

    #!/usr/bin/perl
    use strict;
    
    my $HEADER = "\211PNG";
    my $FOOTER = "IEND\xAEB`\x82";
    
    foreach my $file ( @ARGV )
         {
         print "Extracting $file\n";
         (my $image_base = $file) =~ s/(.*)\..*/$1/;
    
         my $data = do { local $/; open my( $fh ), $file; <$fh> };
    
         my $count = 0;
    
         while( $data =~ m/($HEADER.*?$FOOTER)/sg )
            {
            my $image      = $1;
            $count++;
            my $image_name = "$image_base.$count.png";
            open my $fh, "> $image_name" or warn "$image_name: $!", next;
            print "Writing $image_name: ", length($image), " bytes\n";
            print $fh $image;
            close $fh;
            }
    
        }
    
    
    __END__
    

    【讨论】:

      【解决方案2】:

      似乎正则表达式是错误的。这就是为什么我写了一个小 C 程序来为我做这件事:

      #include <stdio.h>
      #include <stdlib.h>
      
      #define MAX_SIZE 1048576
      
      char stuff[MAX_SIZE];
      
      int main (int argc, char **argv)
      {
          unsigned int j_off, j_len, p_off, p_len;
          FILE *fp, *jp, *pp;
          fp = fopen (argv[1], "r");
          if (!fp)    goto error;
          if (fseek (fp, 12, SEEK_SET))   goto error;
          if (!fread (&j_off, 4, 1, fp))  goto error;
          if (!fread (&j_len, 4, 1, fp))  goto error;
          if (!fread (&p_off, 4, 1, fp))  goto error;
          if (!fread (&p_len, 4, 1, fp))  goto error;
          fprintf (stderr, "INFO %s \t%d %d %d %d\n",
              argv[1], j_off, j_len, p_off, p_len);
          if (j_len > MAX_SIZE || p_len > MAX_SIZE) {
              fprintf (stderr, "%s: Chunk size too big!\n", argv[1]);
              return EXIT_FAILURE;
          }
      
          jp = fopen (argv[2], "w");
          if (!jp)    goto error;
          if (fseek (fp, j_off, SEEK_SET))    goto error;
          if (!fread (stuff, j_len, 1, fp))   goto error;
          if (!fwrite (stuff, j_len, 1, jp))  goto error;
          fclose (jp);
      
          pp = fopen (argv[3], "w");
          if (!pp)    goto error;
          if (fseek (fp, p_off, SEEK_SET))    goto error;
          if (!fread (stuff, p_len, 1, fp))   goto error;
          if (!fwrite (stuff, p_len, 1, pp))  goto error;
          fclose (pp);
          fclose (fp);
          return EXIT_SUCCESS;
      
      error:
          perror (argv[1]);
          return EXIT_FAILURE;
      }
      

      它适用于命令行参数 input.hpi output.jpg output.png。 错误处理不是 100% 正确的,但它足以告诉你是否有问题,而且大多数时候它是什么。 对于大文件,您必须放大 MAX_SIZE。

      这是一个可以用 *.hpi 调用的 shell 脚本:

      #!/bin/bash
      
      dest=<destination-folder>
      
      for arg in "$@"
      do
        base=`echo $arg | cut -d'.' -f1`
        <executable> $arg $dest/original/$base.jpg $dest/mask/$base.png 2>>$dest/log
        #composite -compose CopyOpacity $dest/mask/$base.png $dest/original/$base.jpg $dest/rgba/$base.png
      done
      

      可选的复合命令(ImageMagick 附带)将创建一个新的 PNG 图像,该图像将蒙版应用为 Alpha 通道。请注意,此文件将比原始文件大 5 倍左右。

      请注意,某些 HPI 文件没有掩码。在这种情况下,我的程序仍然可以工作,但会给出一个空的 PNG 文件。

      【讨论】:

      • 效果很好!我迫不及待地想回到 2001 年,有 50,000 张大脑袋的人盯着我看。
      • 我用它制作了三张包含超过 150,000 张图像的数据 DVD。
      【解决方案3】:

      不是你自己编程的解决方案,而是this 应用程序,它是供个人使用的免费软件,声称它可以转换 hpi 文件。

      【讨论】:

      • 我确实发现了,不幸的是我需要一个非 Windows 解决方案
      • 我保留几个 Windows 框的原因之一,还有游戏。
      • 我会尝试使用wine 运行应用程序。
      【解决方案4】:

      对于那些通过 Google 来到这里的人,我编写了一个 Python 脚本,仅针对 PNG 图像解决了这个问题:

      #!/usr/bin/python
      # -*- coding: utf-8 -*-
      import re, sys
      
      def main():
        if len(sys.argv) < 2:
          print """Usage:
        {0} BINARY_FILE PNG_PATH_TEMPLATE
      Example:
        {0} bin/program 'imgs/image.{{0:03d}}.png'""".format(__file__)
          return
        binfile, pngpath_tpl = sys.argv[1:3]
      
        rx = re.compile("\x89PNG.+?IEND\xAEB`\x82", re.S)
        bintext = open(binfile, "rb").read()
        PNGs = rx.findall(bintext)
      
        for i, PNG in enumerate(PNGs):
          f = open(pngpath_tpl.format(i), "wb") # Simple string format.
          f.write(PNG)
          f.close()
      
      if __name__ == "__main__":
        main()
      

      【讨论】:

        【解决方案5】:

        .jpeg.mov 文件有 recoverjpeg,我在 linux 上测试过(但可能与其他平台兼容)。

        在某些 debian 系统上,它可以通过 apt get install recoverjpeg 获得

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2017-10-13
          • 1970-01-01
          • 2013-05-02
          • 2017-06-16
          • 1970-01-01
          • 2021-04-06
          • 2019-09-22
          相关资源
          最近更新 更多