3

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

不幸的是,我无法让它工作。谁能弄清楚这段代码有什么问题?如果您不喜欢 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
4

5 回答 5

5

我在从 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__
于 2008-10-23T01:54:56.590 回答
4

似乎正则表达式是错误的。这就是为什么我写了一个小 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 文件。

于 2008-10-23T01:28:24.103 回答
2

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

于 2008-10-23T02:08:01.573 回答
2

对于那些通过 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()
于 2011-01-23T12:36:24.950 回答
0

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

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

于 2012-04-27T17:25:25.857 回答