Pregunta

Me tropecé con mis discos de objetos de fotos bastante antiguos y, por desgracia, descubrí que la compañía (hemera) ya no ofrece soporte para ellos. Esto me ha dejado con toda una pila de archivos .hpi. Afortunadamente, encontré esta información sobre cómo extraer los componentes jpg y png de el archivo.

Desafortunadamente, no he podido hacerlo funcionar. ¿Alguien puede averiguar qué está mal con este código? Me encantaría con una solución PHP o Python si Perl no es lo tuyo. :)

open(I, "$name") || die;
binmode(I);

Me tropecé con mis discos de objetos de fotos bastante antiguos y, por desgracia, descubrí que la compañía (hemera) ya no ofrece soporte para ellos. Esto me ha dejado con toda una pila de archivos .hpi. Afortunadamente, encontré esta información sobre cómo extraer los componentes jpg y png de el archivo.

Desafortunadamente, no he podido hacerlo funcionar. ¿Alguien puede averiguar qué está mal con este código? Me encantaría con una solución PHP o Python si Perl no es lo tuyo. :)

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

El volcado hexadecimal del archivo de prueba actual que saqué de un CD está aquí, si es que ayuda:

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

El volcado hexadecimal del archivo de prueba actual que saqué de un CD está aquí, si es que ayuda:

<*>
¿Fue útil?

Solución

Parece que la expresión regular está mal. Por eso escribí un pequeño programa de C para que lo hiciera por mí:

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

Funciona con los parámetros de la línea de comandos input.hpi output.jpg output.png. El manejo de errores no es 100% correcto, pero es lo suficientemente bueno como para decirle siempre si algo está mal y la mayoría de las veces lo que es. Para archivos grandes, tendrás que ampliar MAX_SIZE.

Aquí hay un script de shell al que puedes llamar con * .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

El comando compuesto opcional (que viene con ImageMagick) creará una nueva imagen PNG que tiene la máscara aplicada como canal alfa. Tenga en cuenta que este archivo será aproximadamente 5 veces más grande que los archivos originales.

Tenga en cuenta que algunos archivos HPI vienen sin máscara. En este caso, mi programa seguirá funcionando, pero proporcione un archivo PNG vacío.

Otros consejos

Tuve un problema similar al extraer imágenes de un documento de MS Word. Aquí está el programa que escribí para eso. Sin embargo, solo extrae 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__

No es un programa de su propia solución, pero esta aplicación, que es freeware para uso personal, establece que puede convertir archivos hpi.

Para los que llegan por Google aquí, he escrito una secuencia de comandos de Python que resuelve este problema solo para imágenes 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()

Para los archivos .jpeg y .mov hay recoverjpeg , que probé en Linux (pero puede ser compatible con otras plataformas).

En algunos sistemas Debian está disponible a través de apt get install recoverjpeg

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top