Pergunta

me deparei com a minha foto, em vez antiga objetos discos, e, infelizmente, descobri a empresa (hemera) não fornece suporte para mais. este deixou-me com toda uma pilha de arquivos .hpi. Felizmente, eu encontrei este informações sobre como extrair o JPG e PNG componentes do o arquivo.

Infelizmente, eu não tenho sido capaz de fazê-lo funcionar. Alguém pode descobrir o que está errado com este código? Eu ficaria feliz com um PHP ou solução Python se Perl não é sua coisa. :)

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; };

O hexdump do arquivo de teste atual eu roubado de um CD está aqui, se isso ajuda em tudo:

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
Foi útil?

Solução

Parece que o regexp está errado. É por isso que eu escrevi um pequeno programa C para fazer isso por mim:

#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;
}

Ele funciona com os parâmetros de linha de comando input.hpi output.jpg output.png. O tratamento de erros não é 100% correto, mas é bom o suficiente para sempre dizer-lhe se errado de alguma coisa, e na maioria das vezes o que é. Para arquivos grandes, você terá que ampliar MAX_SIZE.

Aqui está um script shell que você pode chamar com * .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

O comando composto opcional (vem com ImageMagick) vai criar uma nova imagem PNG que tem a máscara aplicada como alfa canal. Note que este arquivo será de cerca de 5 vezes maiores do que os arquivos originais.

Note que alguns arquivos HPI vêm sem máscara. Neste caso, o meu programa de trabalho ainda, mas dar um arquivo PNG vazia.

Outras dicas

Eu tive um problema semelhante extrair imagens de um documento do MS Word. Aqui está o programa que eu escrevi para isso. Ele só extrai PNGs, no entanto:

#!/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__

Nem uma solução programa-seu-próprio, mas esta aplicação , que é freeware para uso pessoal, estados que pode converter arquivos de HPI.

Para aqueles que chegam pelo Google aqui, eu escrevi um script Python que resolve este problema para imagens PNG apenas:

#!/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()

Para arquivos .jpeg e .mov recoverjpeg , que eu testei no Linux (mas pode ser compatível com outras plataformas).

Em alguns sistemas debian está disponível através apt get install recoverjpeg

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top