Club Delphi  
    FTP   CCD     Buscar   Trucos   Trabajo   Foros

Retroceder   Foros Club Delphi > Principal > Gráficos
Registrarse FAQ Miembros Calendario Guía de estilo Temas de Hoy

Respuesta
 
Herramientas Buscar en Tema Desplegado
  #1  
Antiguo 06-05-2007
Avatar de seoane
[seoane] seoane is offline
Miembro Premium
 
Registrado: feb 2004
Ubicación: A Coruña, España
Posts: 3.717
Poder: 24
seoane Va por buen camino
Recuperar imagenes jpeg

El proyecto de esta tarde ha sido crear un programa para recuperar imágenes jpeg borradas. El proceso es sencillo, se va examinado byte a byte el fichero que contiene una imagen del disco, buscando una secuencia característica ($FFD8FF), esta secuencia se encuentra al comienzo de todos los archivos Jpeg.

Si encontramos esa secuencia es muy posible que lo que venga a continuación sea una imagen jpeg. Además vamos a suponer que el archivo se ha guardado en cluster contiguos, algo también muy probable, aunque si el disco estaba muy fragmentado esta suposición puede ser equivocada y en ese caso no podremos recuperar el archivo (con este método).

Bueno, vamos a ponernos en lo mejor, y suponemos que lo que viene a continuación de la secuencia es la imagen. Entonces el programa va copiando cada uno de los segmentos que forman la imagen jpg hasta encontrar la marca que indica el final del fichero. Si hay suerte recuperaremos la imagen

Hasta aquí supongo que el proceso se entiende bien, examinamos un fichero en busca de imágenes y las extraemos. La cuestión ahora es como obtener ese fichero. Ese fichero puede ser "cualquier cosa" en la que sepamos que hay una imagen, la imagen de un disco o incluso una archivo jpeg con un thumbnail dentro (en ese caso el programa extraerá la imagen en miniatura).

Asi que, si lo que queremos es examinar un disco (una memoria usb por ejemplo) primero tenemos que crear una imagen, eso lo podemos hacer con muchos programas (incluso creo que hay algún código para eso en el foro), yo recomiendo por ejemplo este programa

Una vez que tenemos la imagen solo tenemos que hacer algo como esto:
Código:
  JpegRecover imagen.bin C:\%d.jpg
El comando anterior buscara imágenes en el archivo imagen.bin y las guardara en C:\ con los nombres 0.jpg, 1.jpg, 2.jpg, ...

Y si lo que queremos es extraer la imagen en miniatura de un archivo jpg:
Código:
  JpegRecover imagen.jpg C:\%d.jpg
Bueno, creo que ya solté bastante rollo. Aquí va el código (es una aplicación de consola):
Código Delphi [-]
program JpegRecover;

{$APPTYPE CONSOLE}

uses
  SysUtils, Classes;

procedure Recover(Origen: TStream; FormatStr: String; var Index: Integer);
var
  Destino: TMemoryStream;
  Buffer: array[0..$FFFF] of Byte;
  Header: array[1..4] of Byte;
  Size: Integer;
begin
  Destino:= TMemoryStream.Create;
  try
    // Escribimos los 2 primeros bytes del archivo
    Header[1]:= $FF;  Header[2]:= $D8;
    Destino.WriteBuffer(Header,2);
    Origen.Seek(-1,soFromCurrent);
    // En este bucle vamos copiando segmento a segmento
    while TRUE do
    begin
      Origen.ReadBuffer(Header,4);
      Size:= ((Header[3] shl 8) + Header[4]) - 2;
      case Header[2] of
        $01,$D0..$D8: begin
                        // Estos segmentos solo miden dos bytes,
                        // asi que escribimos 2 bytes y
                        Destino.WriteBuffer(Header,2);
                        // retrocedemos otros dos hacia atras.
                        Origen.Seek(-2,soFromCurrent);
                      end;
        $D9: begin
               // Este indica que llegamos al final del archivo jpeg
               Destino.WriteBuffer(Header,2);
               // Guardamos el archivo usando la plantilla
               Destino.SaveToFile(Format(FormatStr,[Index]));
               Writeln('Recuperada: ' + Format(FormatStr,[Index]));
               // Incrementamos el indice
               inc(Index);
               // Salimos del procedure
               Exit;
             end;
        $DA: begin
               // Este segmento no tiene tamaño
               Destino.WriteBuffer(Header,2);
               Origen.Seek(-2,soFromCurrent);
               // Buscamos el final byte a byte
               while TRUE do
               begin
                 Origen.ReadBuffer(Buffer,1);
                 // Posible comienzo de otro segmento
                 if Buffer[0] = $FF then
                 begin
                   Origen.ReadBuffer(Buffer,1);
                   // $FF00 = Secuencia de escape
                   // $FFD0 .. $FFD7 = Se deben de ignorar
                   if (Buffer[0] <> 0) and not (Buffer[0] in [$D0..$D7]) then
                   begin
                     // Si encontramos el comienzo de otro segmento,
                     // retrocedemos dos bytes, y volvemos al bucle principal
                     Origen.Seek(-2,soFromCurrent);
                     break;
                   end else
                   begin
                     // Si no es el comienzo de otro segmento, escribimos
                     // y continuamos
                     Header[1]:= $FF;
                     Header[2]:= Buffer[0];
                     Destino.WriteBuffer(Header,2);
                   end;  
                 end else
                   Destino.WriteBuffer(Buffer,1);
               end;
             end
        else
        begin
          // Cualquier otro segmento lo copiamos directamente
          Origen.ReadBuffer(Buffer,Size);
          Destino.WriteBuffer(Header,4);
          Destino.WriteBuffer(Buffer,Size);
        end;
      end;
    end;
  finally
    Destino.Free;
  end;
end;

procedure Scanfile(Stream: TStream; FormatStr: String; Index: Integer);
var
  B: Byte;
  Leidos: Integer;
  Posicion: int64;
begin
  // Vamos leyendo byte a byte el archivo
  Leidos:= Stream.Read(B,1);
  while Leidos = 1 do
    if B = $FF then
    begin
      Leidos:= Stream.Read(B,1);
      if Leidos = 1 then
        if B = $D8 then
        begin
          Leidos:= Stream.Read(B,1);
          if Leidos = 1 then
            if B = $FF then
            begin
              // Hasta encontrar la combinacion $FFD8FF
              Writeln('Encontrada una posible imagen.');
              // Guardamos la posicion
              Posicion:= Stream.Position;
              try
                // Intentamos recuperar la imagen
                Recover(Stream,FormatStr,Index);
              except
                // Si se produce un error lo mostramos, pero no salimos del bucle
                On E: Exception do
                   Writeln('Error: ' + E.Message);
              end;
              // Volvemos a la posicion en la que estabamos
              Stream.Position:= Posicion;
            end;
        end;
    end else
      Leidos:= Stream.Read(B,1);
end;

var
  Stream: TFileStream;

begin
  // Al menos necesitamos 2 parametros para trabajar
  if ParamCount >= 2 then
  try
    // El segundo parametro esla plantilla para guardar la imagenes
    // recuperadas, asi que comprobamos que su formato es correcto.
    Format(ParamStr(2),[0]);
    // Abrimos el archivo
    Stream:= TFileStream.Create(Paramstr(1),fmOpenRead);
    try
      Writeln('Explorando el archivo: ' + ParamStr(1));
      // El nombre de las imagenes recuperadas es la combinacion de la plantilla
      // y un indice que se va incrementando. Si no lo pasamos en la liena
      // de comandos el indice es cero.
      if ParamCount = 3 then
        Scanfile(Stream,ParamStr(2),StrToInt(ParamStr(3)))
      else
        Scanfile(Stream,ParamStr(2),0);
    finally
      Stream.Free;
    end;
  except
    // Si se produce un error, lo mostramos
    On E: Exception do
      Writeln('Error: ' + E.Message);
  end;
end.

PD: El siguiente proyecto sera crear un programa que cree de forma automática y oculta una imagen de todos los discos usb que se inserten en el ordenador, mas tarde le pasamos el recover a las imágenes y .... es broma, eso además de ilegal, estaría muy feo.
Responder Con Cita
  #2  
Antiguo 17-05-2007
Avatar de seoane
[seoane] seoane is offline
Miembro Premium
 
Registrado: feb 2004
Ubicación: A Coruña, España
Posts: 3.717
Poder: 24
seoane Va por buen camino
Veo que no levanto mucho interés este tema. Quizá sea por necesitar de otro programa para leer sector a sector el disco que se quiere explorar en busca de imágenes jpg. También es verdad que daba como alternativa un programa hecho en C y que también publique por aquí hace tiempo.

El caso es que, como estamos en el ClubDelphi, quizá sea mas interesante si el código para extraer la información del disco esta escrito en delphi y no en C. Pues no hay problema, aquí va un poco de código:

(Es una aplicación de consola)
Código Delphi [-]
program dump;

{$APPTYPE CONSOLE}

uses Windows, SysUtils, Classes;

const
  BufferSize = 32*1024*1024;  // 32 Mb

procedure WriteMsg(Msg: string);
var
  StdError: THandle;
begin
  StdError:= GetStdHandle(STD_ERROR_HANDLE);
  if (StdError <> STD_ERROR_HANDLE) and (StdError <> 0) then
  begin
    FileWrite(StdError,PChar(Msg + #13#10)^,Length(Msg) + 2);
  end;
end;

procedure WriteError(Msg: String);
var
  ErrorCode: Cardinal;
begin
  ErrorCode:= GetLastError;
  if ErrorCode <> 0 then
    Msg:= Msg + ': ' + SysErrorMessage(GetLastError);
  WriteMsg(Msg);
end;

procedure Loop(Input,Output: THandle);
var
  Buffer: Pointer;
  BytesRead: Cardinal;
  BytesWritten: Cardinal;
begin
  GetMem(Buffer,BufferSize);
  try
    while TRUE do
    begin
      if not ReadFile(Input,Buffer^,BufferSize,BytesRead,nil) then
       if GetLastError <> ERROR_BROKEN_PIPE then
       begin
         WriteError('ReadFile()');
         break;
       end;
      if BytesRead = 0 then
        break;
      if not WriteFile(Output,Buffer^,BytesRead,BytesWritten,nil) then
      begin
        WriteError('WriteFile()');
        break;
      end;
    end;
  finally
    FreeMem(Buffer);
  end;
end;

var
  i: integer;
  Input, Output: THandle;
  InputStr, OutputStr: String;
begin
  with TStringList.Create do
  try
    for i:= 1 to ParamCount do
      Add(LowerCase(ParamStr(i)));
    InputStr:= Values['if'];
    OutputStr:= Values['of']; 
    if (OutputStr <> '') then
      Output:= CreateFile(PChar(OutputStr),GENERIC_WRITE,FILE_SHARE_READ,nil,
        OPEN_EXISTING,FILE_FLAG_SEQUENTIAL_SCAN,0)
    else
      Output:= GetStdHandle(STD_OUTPUT_HANDLE);
    if (Output <> STD_ERROR_HANDLE) and (Output <> 0) then
    begin
        if (InputStr <> '') then
          Input:= CreateFile(PChar(InputStr),GENERIC_READ,
            FILE_SHARE_READ,nil,OPEN_EXISTING,FILE_FLAG_SEQUENTIAL_SCAN,0)
        else
          Input:= GetStdHandle(STD_INPUT_HANDLE);
        if (Output <> STD_ERROR_HANDLE) and (Output <> 0) then
        begin
          Loop(Input,Output);
        end else
          WriteError('');
    end else
      WriteError('');
  finally
    Free;
  end;
end.

Para usarlo, por ejemplo para crear una imagen del disco F :
Código:
dump if=\\.\F: > imagen.bin
Para crear una imagen del primer disco duro:
Código:
dump if=\\.\PhisicalDrive0 > imagen.bin
Para restaurar una imagen en un disco:
Código:
dump if=imagen.bin of=\\.\F:
Responder Con Cita
  #3  
Antiguo 18-05-2007
Avatar de Casimiro Notevi
Casimiro Notevi Casimiro Notevi is offline
Moderador
 
Registrado: sep 2004
Ubicación: En algún lugar.
Posts: 32.039
Poder: 10
Casimiro Notevi Tiene un aura espectacularCasimiro Notevi Tiene un aura espectacular
je, je... seoane, no es que no levante interés tu estupendo programa... lo que ocurre es que no muchos tenemos jpeg para recuperar en estos momentos

Personalmente, me gusta ver tu código, es bastante parecido a como escribo yo, es muy claro, no necesita comentarios y siempre me hace recordar al lenguaje C, mi querido lenguaje C
Responder Con Cita
  #4  
Antiguo 18-05-2007
Avatar de seoane
[seoane] seoane is offline
Miembro Premium
 
Registrado: feb 2004
Ubicación: A Coruña, España
Posts: 3.717
Poder: 24
seoane Va por buen camino
Gracias Casimiro, yo ya pensaba que me estaban ignorando
Responder Con Cita
  #5  
Antiguo 18-05-2007
[egostar] egostar is offline
Registrado
 
Registrado: feb 2006
Posts: 6.556
Poder: 25
egostar Va camino a la fama
Cita:
Empezado por seoane
Gracias Casimiro, yo ya pensaba que me estaban ignorando
Vamos amigo seoane, que solo ver el código se queda uno pasmado y sin poder decir ni articular palabra alguna.

A título personal, no se como manipular ese código, rebasa mi entendimiento.

Salud OS.
__________________
"La forma de empezar es dejar de hablar y empezar a hacerlo." - Walt Disney
Responder Con Cita
  #6  
Antiguo 18-05-2007
Avatar de dec
dec dec is offline
Moderador
 
Registrado: dic 2004
Ubicación: Alcobendas, Madrid, España
Posts: 13.107
Poder: 34
dec Tiene un aura espectaculardec Tiene un aura espectacular
Hola,

Cita:
Empezado por Seoane
Gracias Casimiro, yo ya pensaba que me estaban ignorando
No; eso no, hombre.
__________________
David Esperalta
www.decsoftutils.com
Responder Con Cita
  #7  
Antiguo 18-05-2007
Avatar de jachguate
jachguate jachguate is offline
Miembro
 
Registrado: may 2003
Ubicación: Guatemala
Posts: 6.254
Poder: 27
jachguate Va por buen camino
Cita:
Empezado por seoane
Gracias Casimiro, yo ya pensaba que me estaban ignorando
no.. claro que no... lo que pasa es que quedó pendiente aún subir la aplicación que detecta cuando se inserta el USB y realiza el proceso de imágen "en background"

Hasta luego.

__________________
Juan Antonio Castillo Hernández (jachguate)
Guía de Estilo | Etiqueta CODE | Búsca antes de preguntar | blog de jachguate
Responder Con Cita
  #8  
Antiguo 18-05-2007
Avatar de seoane
[seoane] seoane is offline
Miembro Premium
 
Registrado: feb 2004
Ubicación: A Coruña, España
Posts: 3.717
Poder: 24
seoane Va por buen camino
Bueno, sigo con el tema. Ahora que se que alguien lo lee

Vamos a sacrificar un poco de rapidez a cambio de ganar sencillez, y evitar además tener que guardar una imagen del disco. Ahora leemos directamente la información del disco y la analizamos, todo en memoria.
Código Delphi [-]
program recover;

{$APPTYPE CONSOLE}

uses Windows, SysUtils, Classes;

const
  // Aquí hacemos una estimación del tamaño del cluster.
  // Siempre tendrá que ser un múltiplo de 512 (1024, 4096, ...)
  // Cuanto mayor sea el valor que utilicemos, mas rápido sera el análisis. 
  // Pero si es demasiado grande, el análisis puede fallar. 
  // Así que por ahora lo dejamos en el valor mas pequeño posible.
  ClusterSize = 512; 

procedure Intento(Origen: TStream; FormatStr: String; var Index: Integer);
var
  Destino: TMemoryStream;
  Buffer: array[0..$FFFF] of Byte;
  Header: array[1..4] of Byte;
  Size: Integer;
begin
  Destino:= TMemoryStream.Create;
  try
    // Escribimos los 2 primeros bytes del archivo
    Header[1]:= $FF;  Header[2]:= $D8;
    Destino.WriteBuffer(Header,2);
    // En este bucle vamos copiando segmento a segmento
    while TRUE do
    begin
      Origen.ReadBuffer(Header,4);
      Size:= ((Header[3] shl 8) + Header[4]) - 2;
      case Header[2] of
        $01,$D0..$D8: begin
                        // Estos segmentos solo miden dos bytes,
                        // asi que escribimos 2 bytes y
                        Destino.WriteBuffer(Header,2);
                        // retrocedemos otros dos hacia atras.
                        Origen.Seek(-2,soFromCurrent);
                      end;
        $D9: begin
               // Este indica que llegamos al final del archivo jpeg
               Destino.WriteBuffer(Header,2);
               // Guardamos el archivo usando la plantilla
               Destino.SaveToFile(Format(FormatStr,[Index]));
               Writeln('Recuperada: ' + Format(FormatStr,[Index]));
               // Incrementamos el indice
               inc(Index);
               // Salimos del procedure
               Exit;
             end;
        $DA: begin
               // Este segmento no tiene tamaño
               Destino.WriteBuffer(Header,2);
               Origen.Seek(-2,soFromCurrent);
               // Buscamos el final byte a byte
               while TRUE do
               begin
                 Origen.ReadBuffer(Buffer,1);
                 // Posible comienzo de otro segmento
                 if Buffer[0] = $FF then
                 begin
                   Origen.ReadBuffer(Buffer,1);
                   // $FF00 = Secuencia de escape
                   // $FFD0 .. $FFD7 = Se deben de ignorar
                   if (Buffer[0] <> 0) and not (Buffer[0] in [$D0..$D7]) then
                   begin
                     // Si encontramos el comienzo de otro segmento,
                     // retrocedemos dos bytes, y volvemos al bucle principal
                     Origen.Seek(-2,soFromCurrent);
                     break;
                   end else
                   begin
                     // Si no es el comienzo de otro segmento, escribimos
                     // y continuamos
                     Header[1]:= $FF;
                     Header[2]:= Buffer[0];
                     Destino.WriteBuffer(Header,2);
                   end;  
                 end else
                   Destino.WriteBuffer(Buffer,1);
               end;
             end
        else
        begin
          // Cualquier otro segmento lo copiamos directamente
          Origen.ReadBuffer(Buffer,Size);
          Destino.WriteBuffer(Header,4);
          Destino.WriteBuffer(Buffer,Size);
        end;
      end;
    end;
  finally
    Destino.Free;
  end;
end;

procedure Scan(Stream: TStream; FormatStr: String);
var
  Buffer: PChar;
  Indice: Integer;
  Leidos: Integer;
  MemStream: TMemoryStream;
  Posicion: int64;
begin
  Indice:= 0;
  GetMem(Buffer,ClusterSize);
  try
    Leidos:= Stream.Read(Buffer^,ClusterSize);
    while Leidos > 0 do
    begin
      // Buscamos la secuencia que indica el comienzo de un archivo jpeg
      if CompareMem(Buffer,PChar(#$FF#$D8#$FF),3) then
      begin
        Posicion:= Stream.Position;
        try
          // Cargamos en un stream 8 Megas para su analisis
          MemStream:= TMemoryStream.Create;
          try
            MemStream.Write(Buffer[2],Leidos - 2);
            // Si creemos que hay imagenes de mas de 8 megas, cambiaremos este valor
            MemStream.CopyFrom(Stream,8*1024*1024);
            MemStream.Position:= 0;
            Writeln('Encontrada una posible imagen.');
            Intento(MemStream,FormatStr,Indice);
          finally
            MemStream.Free;
          end;
        except
          // Si se produce un error lo mostramos, pero no salimos del bucle
          On E: Exception do
             Writeln('Error: ' + E.Message);
        end;
        Stream.Position:= Posicion + ClusterSize;
      end;
      Leidos:= Stream.Read(Buffer^,ClusterSize);
    end;
  finally
    FreeMem(Buffer);
  end;
end;

var
  Stream: TFileStream;
  Marca: TDateTime;
begin
  try
    // Necesitamos 2 parametros
    if ParamCount = 2 then
    begin
      // Comprobamos que se pueden crear archivos en la ruta indicada
      TFileStream.Create(Format(ParamStr(2),[0]),fmCreate).Free;
      // Borramos el archivo de prueba
      DeleteFile(Format(ParamStr(2),[0]));
      Stream:= TFileStream.Create(ParamStr(1),fmOpenRead or fmShareDenyNone);
      try
        // Si llegamos hasta aqui podemos leer y escribir
        Marca:= Now;
        Scan(Stream,ParamStr(2));
        Writeln('Tiempo transcurrido: ' + TimeToStr(Now-Marca));
      finally
        Stream.Free;
      end;
    end else
      // Si no nos pasan dos parametros, imprimimos una pequeña ayuda
      Writeln('Help: ' + ExtractFilename(ParamStr(0)) + '  ');
  except
    On E: Exception do
      // Si algo sale mal, escribimos la descripcion del error
      Writeln('Error: ' + E.Message);
  end;
end.

Por ejemplo:
Código:
recover \\.\F: c:\temp\%d.jpg
Tarda un poco en realizar el análisis de todo el disco, por ejemplo, para un disco de Usb de 128 Megas tarda unos 5 Minutos. Aunque puede que sea menos si el dispositivo es rápido, y ajustamos mejor el tamaño del cluster.
Responder Con Cita
  #9  
Antiguo 18-05-2007
Avatar de seoane
[seoane] seoane is offline
Miembro Premium
 
Registrado: feb 2004
Ubicación: A Coruña, España
Posts: 3.717
Poder: 24
seoane Va por buen camino
Cita:
Empezado por jachguate
lo que pasa es que quedó pendiente aún subir la aplicación que detecta cuando se inserta el USB y realiza el proceso de imágen "en background"
Caramba, nos metemos en terreno peligroso. Pues nada, si tienes interés lo modificamos un poquito (sobre todo para que la luz no parpadee mucho), le añadimos el código de roman para detectar la inserción, y listo.

A mi no creo que me sirva de mucho, mis amigos, que ya me conocen, no me dejan sus discos y cuando los insertan en mi ordenador lo hacen con recelo. Uno ya me advirtió que como la luz parpadee demasiado se va a mosquear .... Y no se porque, yo no hago esas cosas
Responder Con Cita
  #10  
Antiguo 31-05-2007
Avatar de seoane
[seoane] seoane is offline
Miembro Premium
 
Registrado: feb 2004
Ubicación: A Coruña, España
Posts: 3.717
Poder: 24
seoane Va por buen camino
Pues yo sigo aquí, de fisgón, aquí les dejo un programa que busca los archivos "thumb.db" (al parecer en Vista se llaman thumbcache_xxxx.db) creados por el explorer cuando vemos una carpeta con imágenes utilizando las "Vistas en miniatura". Lo "divertido" es que tiene el mal habito de no borrar las miniaturas almacenadas en la cache cuando se borra la imagen original, así que podemos encontrarnos con alguna sorpresa.

Es una aplicación de consola:
Código Delphi [-]
program Fisgon;

{$APPTYPE CONSOLE}

uses
  SysUtils,
  Classes;

procedure Recover(Origen: TStream; FormatStr: String; var Index: Integer);
var
  Destino: TMemoryStream;
  Buffer: array[0..$FFFF] of Byte;
  Header: array[1..4] of Byte;
  Size: Integer;
begin
  Destino:= TMemoryStream.Create;
  try
    // Escribimos los 2 primeros bytes del archivo
    Header[1]:= $FF;  Header[2]:= $D8;
    Destino.WriteBuffer(Header,2);
    Origen.Seek(-1,soFromCurrent);
    // En este bucle vamos copiando segmento a segmento
    while TRUE do
    begin
      Origen.ReadBuffer(Header,4);
      Size:= ((Header[3] shl 8) + Header[4]) - 2;
      case Header[2] of
        $01,$D0..$D8: begin
                        // Estos segmentos solo miden dos bytes,
                        // asi que escribimos 2 bytes y
                        Destino.WriteBuffer(Header,2);
                        // retrocedemos otros dos hacia atras.
                        Origen.Seek(-2,soFromCurrent);
                      end;
        $D9: begin
               // Este indica que llegamos al final del archivo jpeg
               Destino.WriteBuffer(Header,2);
               // Guardamos el archivo usando la plantilla
               Destino.SaveToFile(Format(FormatStr,[Index]));
               Writeln('Recuperada: ' + Format(FormatStr,[Index]));
               // Incrementamos el indice
               inc(Index);
               // Salimos del procedure
               Exit;
             end;
        $DA: begin
               // Este segmento no tiene tamaño
               Destino.WriteBuffer(Header,2);
               Origen.Seek(-2,soFromCurrent);
               // Buscamos el final byte a byte
               while TRUE do
               begin
                 Origen.ReadBuffer(Buffer,1);
                 // Posible comienzo de otro segmento
                 if Buffer[0] = $FF then
                 begin
                   Origen.ReadBuffer(Buffer,1);
                   // $FF00 = Secuencia de escape
                   // $FFD0 .. $FFD7 = Se deben de ignorar
                   if (Buffer[0] <> 0) and not (Buffer[0] in [$D0..$D7]) then
                   begin
                     // Si encontramos el comienzo de otro segmento,
                     // retrocedemos dos bytes, y volvemos al bucle principal
                     Origen.Seek(-2,soFromCurrent);
                     break;
                   end else
                   begin
                     // Si no es el comienzo de otro segmento, escribimos
                     // y continuamos
                     Header[1]:= $FF;
                     Header[2]:= Buffer[0];
                     Destino.WriteBuffer(Header,2);
                   end;  
                 end else
                   Destino.WriteBuffer(Buffer,1);
               end;
             end
        else
        begin
          // Cualquier otro segmento lo copiamos directamente
          Origen.ReadBuffer(Buffer,Size);
          Destino.WriteBuffer(Header,4);
          Destino.WriteBuffer(Buffer,Size);
        end;
      end;
    end;
  finally
    Destino.Free;
  end;
end;

procedure Scanfile(Stream: TStream; FormatStr: String; var Index: Integer);
var
  B: Byte;
  Leidos: Integer;
  Posicion: int64;
begin
  // Vamos leyendo byte a byte el archivo
  Leidos:= Stream.Read(B,1);
  while Leidos = 1 do
    if B = $FF then
    begin
      Leidos:= Stream.Read(B,1);
      if Leidos = 1 then
        if B = $D8 then
        begin
          Leidos:= Stream.Read(B,1);
          if Leidos = 1 then
            if B = $FF then
            begin
              // Hasta encontrar la combinacion $FFD8FF
              Writeln('Encontrada una posible imagen.');
              // Guardamos la posicion
              Posicion:= Stream.Position;
              try
                // Intentamos recuperar la imagen
                Recover(Stream,FormatStr,Index);
              except
                // Si se produce un error lo mostramos, pero no salimos del bucle
                On E: Exception do
                   Writeln('Error: ' + E.Message);
              end;
              // Volvemos a la posicion en la que estabamos
              Stream.Position:= Posicion;
            end;
        end;
    end else
      Leidos:= Stream.Read(B,1);
end;

procedure Buscar(Path: string; var Index: Integer);
var
  SR: TSearchRec;
  Stream: TFileStream;
begin
  if Path = '' then exit;
  if copy(Path, Length(Path), 1) <> '\' then Path := Path + '\';
  if FindFirst(Path + '*', faDirectory, SR) = 0 then
  repeat
    if (SR.Name <> '.') and (SR.Name <> '..') then
      Buscar(Path + SR.Name, Index);
  until FindNext(SR) <> 0;
  FindClose(SR);
  if FindFirst(Path + 'thumb*.db',faAnyfile, SR) = 0 then
  repeat
    Stream:= TFileStream.Create(Path + SR.Name,fmOpenRead);
    try
      Writeln('Explorando el archivo: ' + Path + SR.Name);
      Scanfile(Stream,ParamStr(2),Index);
    finally
      Stream.Free;
    end;
  until FindNext(SR) <> 0;
  FindClose(SR);
end;

var
  i: Integer;
begin
  if ParamCount = 2 then
  try
    // Comprobamos que se pueden crear archivos en la ruta indicada
    TFileStream.Create(Format(ParamStr(2),[0]),fmCreate).Free;
    // Borramos el archivo de prueba
    DeleteFile(Format(ParamStr(2),[0]));
    // Buscamos en la ruta indicada
    i:= 0;
    Buscar(ParamStr(1),i);
  except
    // Si se produce un error, lo mostramos
    On E: Exception do
      Writeln('Error: ' + E.Message);
  end;
end.

Por ejemplo:
Código:
Fisgon C:\ %d.jpg
A fisgonear
Responder Con Cita
  #11  
Antiguo 01-06-2007
Avatar de Caral
[Caral] Caral is offline
Miembro Premium
 
Registrado: ago 2006
Posts: 7.659
Poder: 25
Caral Va por buen camino
Hola
Lo vengo viendo desde que empezaste este hilo, debería haber un contador de visitas silenciosas, ya ni se cuantas veces he entrado en este, pero siempre me quedo igual, es demasiado para mi.
Lo unico que puedo poner aqui es , total asombro.
Maestro eres genial.
Saludos
Responder Con Cita
  #12  
Antiguo 01-06-2007
Avatar de seoane
[seoane] seoane is offline
Miembro Premium
 
Registrado: feb 2004
Ubicación: A Coruña, España
Posts: 3.717
Poder: 24
seoane Va por buen camino
Gracias Caral, pero en realidad no es muy complicado, solo hay que conocer el formato de los archivos jpeg. La verdad es que no tiene mucha utilidad "real", pero demuestra perfectamente lo difícil que es mantener los secretos ocultos cuando hablamos de ordenadores.
Responder Con Cita
  #13  
Antiguo 01-06-2007
Avatar de Delphius
[Delphius] Delphius is offline
Miembro Premium
 
Registrado: jul 2004
Ubicación: Salta, Argentina
Posts: 5.582
Poder: 25
Delphius Va camino a la fama
No se que palabras decirte, no he probado el código aún, y es algo que escapa a lo que mi pobre cerebro logra entender....

Leí el hilo hace tiempo, cuando tu recién lo habías iniciado. Preferí no meter mi nariz en el asunto porque todavía me suena a una dimensión desconocida.
No es tu código, sino que mi conocimiento del tema sobre la estructura del jpg no es muy alentador.

Las únicas palabras que te puedo articular:
¡Sos un Maestro!
__________________
Delphius
[Guia de estilo][Buscar]
Responder Con Cita
  #14  
Antiguo 01-06-2007
Avatar de Lepe
[Lepe] Lepe is offline
Miembro Premium
 
Registrado: may 2003
Posts: 7.424
Poder: 28
Lepe Va por buen camino
Yo añadiría una coma, para que se entienda bien:

¡Sos un fisgon, Maestro!

Saludos
__________________
Si usted entendió mi comentario, contácteme y gustosamente,
se lo volveré a explicar hasta que no lo entienda, Gracias.
Responder Con Cita
  #15  
Antiguo 01-06-2007
Avatar de seoane
[seoane] seoane is offline
Miembro Premium
 
Registrado: feb 2004
Ubicación: A Coruña, España
Posts: 3.717
Poder: 24
seoane Va por buen camino
No soy muy fisgón , lo que pasa es que me aburro mucho

PD: Si en vez de buscar "thumbs*.db", le decimos que busque imágenes jpeg, por ejemplo con "*.jpg", lo que obtendremos serán las imágenes originales, y además, las imágenes en miniatura que almacenan algunos programas dentro de los archivos y que a veces dan sorpresas. Pero sigo sin ser un fisgón , eso que conste !!!
Responder Con Cita
  #16  
Antiguo 01-06-2007
Avatar de Delphius
[Delphius] Delphius is offline
Miembro Premium
 
Registrado: jul 2004
Ubicación: Salta, Argentina
Posts: 5.582
Poder: 25
Delphius Va camino a la fama
Cita:
Empezado por Lepe
¡Sos un fisgon, Maestro!

No pude evitar reirme...

Cita:
Empezado por seoane
lo que pasa es que me aburro mucho
Creo que muchos coinciderán en lo que te digo:
¿Y porqué no aprovechas el enorme potencial que tienes sobre Delphi para sacarte unos euros extras?
Para mantenerte ocupado...

Saludos,
__________________
Delphius
[Guia de estilo][Buscar]
Responder Con Cita
  #17  
Antiguo 01-06-2007
Avatar de seoane
[seoane] seoane is offline
Miembro Premium
 
Registrado: feb 2004
Ubicación: A Coruña, España
Posts: 3.717
Poder: 24
seoane Va por buen camino
Cita:
Empezado por Delphius
¿Y porqué no aprovechas el enorme potencial que tienes sobre Delphi para sacarte unos euros extras?
Eso no depende solo de mi
Responder Con Cita
  #18  
Antiguo 01-06-2007
Saiyan Saiyan is offline
Miembro
 
Registrado: abr 2007
Posts: 47
Poder: 0
Saiyan Va por buen camino
Cita:
Vamos amigo seoane, que solo ver el código se queda uno pasmado y sin poder decir ni articular palabra alguna.
tan cierto como el sol q sale...

y apoyo eso de que publiques en mas lugares tus desarrollos, que seguramente gente te necesita ($$$$$)
Responder Con Cita
  #19  
Antiguo 07-10-2007
Avatar de seoane
[seoane] seoane is offline
Miembro Premium
 
Registrado: feb 2004
Ubicación: A Coruña, España
Posts: 3.717
Poder: 24
seoane Va por buen camino
Aquí podéis encontrar la ultima versión. Compila en Delphi y Freepascal, funciona en windows y en linux, recupera imágenes en discos y archivos, etc ...

http://delphi.jmrds.com/?q=node/42

Algunos ejemplos de uso:
Código:
recover --if=\\.\F: --bs=4096 --fs=%d.jpg
recover --if=/dev/sda --bs=4096 --fs=%d.jpg
recover --if=thumb.db --fs=%d.jpg --id=100
Responder Con Cita
Respuesta



Normas de Publicación
no Puedes crear nuevos temas
no Puedes responder a temas
no Puedes adjuntar archivos
no Puedes editar tus mensajes

El código vB está habilitado
Las caritas están habilitado
Código [IMG] está habilitado
Código HTML está deshabilitado
Saltar a Foro

Temas Similares
Tema Autor Foro Respuestas Último mensaje
Incluir imagenes JPEG en paradox 7 rsantosr Gráficos 3 06-12-2005 01:12:25
cabecera de imagenes jpeg samantha jones Gráficos 1 19-08-2004 03:35:29
Problemas alguardar imagenes jpeg y gif en un campo blob Flycket Firebird e Interbase 3 20-02-2004 09:29:02
TMysql imagenes jpeg xobius Conexión con bases de datos 0 11-02-2004 16:21:16
Visualizar Imagenes Jpeg Legolas Gráficos 1 17-11-2003 21:14:23


La franja horaria es GMT +2. Ahora son las 16:05:47.


Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi
Copyright 1996-2007 Club Delphi