PDA

Ver la Versión Completa : Recuperar imagenes jpeg


seoane
06-05-2007, 22:58:33
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 :D

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 (http://www.clubdelphi.com/foros/showthread.php?t=34186) :p

Una vez que tenemos la imagen solo tenemos que hacer algo como esto:

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:

JpegRecover imagen.jpg C:\%d.jpg


Bueno, creo que ya solté bastante rollo. Aquí va el código (es una aplicación de consola):

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 .... :p es broma, eso además de ilegal, estaría muy feo.

seoane
17-05-2007, 22:36:33
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)

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 :

dump if=\\.\F: > imagen.bin


Para crear una imagen del primer disco duro:

dump if=\\.\PhisicalDrive0 > imagen.bin


Para restaurar una imagen en un disco:

dump if=imagen.bin of=\\.\F:

Casimiro Notevi
18-05-2007, 01:53:27
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 :)

seoane
18-05-2007, 02:30:29
Gracias Casimiro, yo ya pensaba que me estaban ignorando :p :D

egostar
18-05-2007, 02:56:01
Gracias Casimiro, yo ya pensaba que me estaban ignorando :p :D

Vamos amigo seoane, que solo ver el código se queda uno pasmado y sin poder decir ni articular palabra alguna.:confused::D:cool::rolleyes:

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

Salud OS.

dec
18-05-2007, 02:58:54
Hola,


Gracias Casimiro, yo ya pensaba que me estaban ignorando :p :D


No; eso no, hombre. :)

jachguate
18-05-2007, 03:13:40
Gracias Casimiro, yo ya pensaba que me estaban ignorando :p :D

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" :eek: :D:D:D

Hasta luego.

;)

seoane
18-05-2007, 03:22:16
Bueno, sigo con el tema. Ahora que se que alguien lo lee :p :D

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.

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)) + ' <file> <format>');
except
On E: Exception do
// Si algo sale mal, escribimos la descripcion del error
Writeln('Error: ' + E.Message);
end;
end.


Por ejemplo:

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.

seoane
18-05-2007, 03:29:51
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"


:D 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 .... :p :D Y no se porque, yo no hago esas cosas :rolleyes:

seoane
31-05-2007, 22:10:21
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:

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:

Fisgon C:\ %d.jpg


A fisgonear :p

Caral
01-06-2007, 00:44:50
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 :eek:, total asombro.
Maestro eres genial.
Saludos

seoane
01-06-2007, 01:04:04
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.

Delphius
01-06-2007, 16:48:36
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:o.

Las únicas palabras que te puedo articular:
¡Sos un Maestro!

Lepe
01-06-2007, 17:04:58
Yo añadiría una coma, para que se entienda bien:

¡Sos un fisgon, Maestro! :D :D

Saludos

seoane
01-06-2007, 17:18:05
No soy muy fisgón :o , lo que pasa es que me aburro mucho :p :D

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 :p , eso que conste !!!

Delphius
01-06-2007, 18:12:54
¡Sos un fisgon, Maestro! :D :D
:D:D:D:D
No pude evitar reirme...

lo que pasa es que me aburro mucho:p :D

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,

seoane
01-06-2007, 18:20:28
¿Y porqué no aprovechas el enorme potencial que tienes sobre Delphi para sacarte unos euros extras?

Eso no depende solo de mi :(

Saiyan
01-06-2007, 19:43:42
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 ($$$$$)

seoane
07-10-2007, 01:51:35
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:

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