如何提取.hpi文件的.jpg / .png组件?

时间:2008-10-23 01:17:41

标签: binaryfiles

我偶然发现了相当古老的照片对象磁盘,遗憾地发现公司(hemera)不再提供支持了。这给我留下了一大堆.hpi文件。幸运的是,我发现了this information提取文件的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

5 个答案:

答案 0 :(得分: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__

答案 1 :(得分:4)

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

#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。

这是一个shell脚本,您可以使用* .hpi调用:

#!/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文件。

答案 2 :(得分:2)

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

答案 3 :(得分:2)

对于谷歌来这里的人,我写了一个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()

答案 4 :(得分:0)

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

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

获取