Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Gráficos (https://www.clubdelphi.com/foros/forumdisplay.php?f=8)
-   -   BMP/JPG a máxima velocidad (https://www.clubdelphi.com/foros/showthread.php?t=54125)

MaMu 10-03-2008 07:08:18

BMP/JPG a máxima velocidad
 
BMP/JPG a máxima velocidad

Existe alguna forma, digamos "al vuelo" para obtener el alto y el ancho de una imagen sea bmp y jpg?
Necesito algo que sea rapido y que no tome en cuenta el tamaño del archivo, ya pese 10kb como 10Mb, que solamente lea la resolucion.
Es que tengo que hacerlo con por lo menos 5000 imagenes, y realmente, ya con 100 me esta tardando horrores. Estuve usando las Vampyre Image Component, pero se me ralentiza todo. No se me ocurre como optimizar el proceso. Los path de las imagenes las cargo en un StringList, y luego cargo todo eso en una tabla (mySql), pero cuando quiero procesar la info de cada foto.... se hace demaciado lento el proceso, por lo que no me sirve.

Ideas bien locas serán vienvenidas.

Saludos.

seoane 10-03-2008 13:16:06

Para bmp puedes usar algo como esto:

http://www.clubdelphi.com/foros/show...07&postcount=4

Para jpg se podría hacer algo similar, tendría que repasar la estructura de un archivo Jpeg, pero creo que no habría problema.

MaMu 10-03-2008 17:17:36

Estuve probando con los BMP y la diferencia es rotundamente notable, se redujo el tiempo a pocos segundos. Ahora tendria que probar para los JPG, pero como seria la estructura, es decir, para hacer una funcion casi identica a:

Código Delphi [-]
GetBitmapInfo //como GetJPegInfo

Lo que temo, es que si convierto de JPG a BMP en la funcion, cada LoadFromFile del TJPEGImage haria todo mas lento, ya que dependeria del tamaño del JPG. Me gustaria poder hacer algo similar.

Saludos y muchas gracias seoane

seoane 10-03-2008 19:06:37

El código está un poco sucio pero quedaría mas o menos así:
Código Delphi [-]
type
  // No estan todos los elementos de la estructura
  TSOF = packed record
    Precision: Byte;
    Height: Word;
    Width: Word;
  end;
  PSOF = ^TSOF;

function GetJpegSize(Src: TStream; var Width: Integer; var Height: Integer): Boolean;
var
  Buffer: PByteArray;
  Size: Integer;
begin
  Result:= FALSE;
  GetMem(Buffer,Sizeof(TSOF));
  try
    while TRUE do
    begin
      FillChar(Buffer^,4,#0);
      if Src.Read(Buffer^,4) <> 4 then Break;
      Size:= ((Buffer[2] shl 8) + Buffer[3]) - 2;
      case Buffer[1] of
        $01,$D0..$D8:
          Src.Seek(-2,soFromCurrent);
        $C0: begin
            FillChar(Buffer^,Sizeof(TSOF),#0);
            if Src.Read(Buffer^,Sizeof(TSOF)) = Sizeof(TSOF) then
            begin
              Result:= TRUE;
              Width:= Swap(PSOF(Buffer).Width);
              Height:= Swap(PSOF(Buffer).Height);
            end;
            break;
          end;
        else
          Src.Seek(Size,soFromCurrent);
      end;
    end;
  finally
    FreeMem(Buffer);
  end;
end;

function GetJpegSizeFromFile(Filename: String; var Width: Integer;
  var Height: Integer): Boolean;
var
  Stream: TFileStream;
begin
  Result:= FALSE;
  Stream:= TFileStream.Create(Filename,fmOpenRead);
  try
    try
      Result:= GetJpegSize(Stream,Width,Height);
    except
    end;
  finally
    Stream.Free;
  end;
end;

// Un ejemplo de como usar la funcion
var
  x,y: Integer;
begin
  if GetJpegSizeFromFile('d:\1.jpg',x,y) then
    ShowMessage(Format('%d,%d',[x,y]));
end;

MaMu 10-03-2008 19:37:12

SOLUCIONADO

Resultados Vampyre Imaging Library Vs. D. Seoane
-----------------------------------------------------
Cantidad TOTAL de imágenes procesadas: 13047
Cantidad de BMP: 8756
Cantidad de JPG: 4290
-----------------------------------------------------
Tiempo de proceso V.I.L.: 6m-18s
Tiempo de proceso D.Seoane: 1m-04s
-----------------------------------------------------
DB: DS Memoria
-----------------------------------------------------
Procesador: Athlon 2.2 - 512Kb DDR
-----------------------------------------------------

Gracias seoane, sin palabras.

cHackAll 10-03-2008 21:56:54

No es por competir, pero la verdad que me daba mucha pena echar mi código al basurero;

Código Delphi [-]
function GetDimensions(lpFileName: PChar): TSize;
var hFile: Integer; Value, FileSize: Cardinal; Chunk: Word;
begin
 Result := TSize(Point(0, 0));
 hFile := _lopen(lpFileName, OF_READ);
 if hFile = -1 then Exit;
 _lread(hFile, @Value, 4);
 if Word(Value) = $4D42{BM} then
  begin
   _llseek(hFile, 18, FILE_BEGIN);
   _lread(hFile, @Result, SizeOf(Result));
  end
 else
  begin
   if Value = $E0FFD8FF{JPEG} then
    begin
     _lread(hFile, @Chunk, 2);
     _lread(hFile, @Value, 4);
     if Value = $4649464A{JFIF} then
      begin
       FileSize := GetFileSize(hFile, nil);
       Value := 4 + Swap(Chunk);
       while Value < FileSize do
        begin
         _llseek(hFile, Value, FILE_BEGIN);
         Inc(Value, 2); _lread(hFile, @Chunk, 2);
         if Lo(Chunk) <> $FF then Exit;
         if Hi(Chunk) = $C0 then
          begin
           _llseek(hFile, Value + 3, FILE_BEGIN);
           _lread(hFile, @Chunk, 2); Result.cy := Swap(Chunk);
           _lread(hFile, @Chunk, 2); Result.cx := Swap(Chunk);
           Break;
          end
         else
          begin
           _lread(hFile, @Chunk, 4);
           Inc(Value, Swap(Chunk));
          end;
        end;
      end;
    end;
  end;
 CloseHandle(hFile);
end;

Uso;

Código Delphi [-]
procedure TForm1.Button1Click(Sender: TObject);
var Size: TSize;
begin
 if OpenDialog1.Execute then
  begin
   Size := GetDimensions(PChar(OpenDialog1.FileName));
   ShowMessage(IntToStr(Size.cx) + 'x' + IntToStr(Size.cy));
  end;
end;

PD: Nadamas por curiosidad, cual es la velocidad de mi code?

Saludos

eduarcol 10-03-2008 22:14:25

Cita:

Empezado por cHackAll (Mensaje 272121)
***PD: Nadamas por curiosidad, cual es la velocidad de mi code?

Saludos


se abren las apuestas, quien da mas???
:D:D

MaMu 10-03-2008 22:17:14

SOLUCIONADO

Resultados Vampyre Imaging Library Vs. D. Seoane Vs. cHackAll
-----------------------------------------------------
Cantidad TOTAL de imágenes procesadas: 13047
Cantidad de BMP: 8756
Cantidad de JPG: 4290
-----------------------------------------------------
Tiempo de proceso V.I.L.: 6m-18s
Tiempo de proceso D.Seoane: 1m-04s
Tiempo de proceso cHackAll: 2m-27s
-----------------------------------------------------
DB: DS Memoria
-----------------------------------------------------
Procesador: Athlon 2.2 - 512Kb DDR
-----------------------------------------------------

Gracias seoane, cHackAll sin palabras.

dec 10-03-2008 22:25:51

Hola,

Sin querer quitar méritos a los compañeros (que no podría) me gustaría que pusieras el código que estabas usando cuando lo hacías con Vampyre Imaging. Me consta que la librería puede trabajar de varias formas, y, tal vez pudiera hacerse algo al respecto. Ahora mismo estoy echando un vistazo a su documentación, por cierto.

Concretando un poco, quisiera saber si haces uso de la "interfaz de alto nivel" o la "interfaz de bajo nivel", o las "clases VCL/CLX/LCL". Por poner un ejemplo, así sería el asunto usando la "interfaz de bajo nivel", según la documentación:

Código Delphi [-]
uses
  SysUtils, Classes, ImagingTypes, Imaging;
var
  Img: TImageData;
begin
  // call this before using any TImageData record
  InitImage(Img);
  // load tigers from file
  LoadImageFromFile('X:\images\tigers.jpg', Img);
  //write some image info
  WriteLn('Mighty tigers have resolution ', Img.Width, 'x', Img.Height,
  ' and occupy ', Img.Size, ' bytes of your memory.');
  // memory occupied by image is freed
  FreeImage(Img);
end.

Ojo, porque el "InitImage()" acaso no haga falta ejecutarlo en todo momento, para todas las imágenes. Lo mismo que el "FreeImage()". No sé. Tal vez esté un poco confundido. La idea de los compañeros (excelentemente implementada) creo que es correcta, es decir, no se carga toda la imagen, sino que se intenta obtener sólo la información necesaria, pero, tengo cierta esperanza de que la Vampyre Imaging pueda con algo similar, puesto que parece una estupenda "pieza de software". ;)

cHackAll 10-03-2008 22:27:13

Cita:

Empezado por mamu (Mensaje 272127)
Tiempo de proceso V.I.L.: 6m-18s
Tiempo de proceso D.Seoane: 1m-04s
Tiempo de proceso cHackAll: 2m-27s

mamu, cronometraste la comparacion de BMP + JPG en todos los casos?
en fin... habra que darle una oportunidad a los benditos Streams :o


Felicidades amigo seoane :D

Saludos

MaMu 10-03-2008 23:32:57

dec

Si, estoy usando a bajo nivel, y la forma que empleo es la siguiente:
Código Delphi [-]
 
var imagen:TImageData;
     x,y:integer;
begin
   ...
    LoadImageFromFile(lista[i],imagen);  //cargo la imagen
    if TestImage(imagen)                    //valida=True - archivo_corrupto=False           
       then begin
         x:=imagen.Width;
         y:=Img.Height;
       end;
   ...
end;

El tema del retraso pasa por la siguiente línea ya que tiene dependencia sobre el tamaño del archivo, y no encontré en la documentación otro método mas directo para las propiedades
Código Delphi [-]
LoadImageFromFile(lista[i],imagen);  //cargo la imagen

Con respecto a las funciones
Código Delphi [-]
InitImage(imagen);
FreeImage(imagen);

en este caso no son necesarias en todo momento, ya que no estoy utilizando ninguna de las funciones que se incluyen en las V.I.L. que dependen del TImageData en cuestión

cHackAll

Si, cronometré a las 3 funciones por igual proceso.

dec 10-03-2008 23:49:06

Hola,

Pues tal vez el "TestImage()"... pero, me parece que no. Quiero decir, queda más o menos claro que se carga la imagen completamente, al menos con las funciones de que hablamos. De este modo se puede conseguir mucha información acerca de la imagen, pero, lo que interesa en este caso es conseguir parte de esa información, y por tanto todo el tiempo que se invierta en lo demás será para nada.

MaMu 11-03-2008 00:00:38

Cita:

Empezado por dec (Mensaje 272165)
Hola,

Pues tal vez el "TestImage()"... pero, me parece que no. Quiero decir, queda más o menos claro que se carga la imagen completamente, al menos con las funciones de que hablamos. De este modo se puede conseguir mucha información acerca de la imagen, pero, lo que interesa en este caso es conseguir parte de esa información, y por tanto todo el tiempo que se invierta en lo demás será para nada.

Claro, pero el "TestImage()"... es muy util, sobre todo cuando los mal intencionados le cambian la extención a un EXE por BMP/JPG, lo que ahorra código, o cuando simplemente un archivo esta corrupto. De todas maneras, no la estoy usando actualmente para la carga, sino que la uso para la revisión de imágenes, donde informo archivos corruptos, etc.

Otra cosa, yo capture los ticks, haciendo un LoadFromFile a un TImage tradicional, y lo compare con el LoadImageFromFile(), ambos con una imagen de 3.5Mb, el tiempo es idéntico. Y ojo, pienso tambien que esta librería es espectacular, quizas o le estemos pifiando en algo o no me sirve por tratarse de ser muchas fotos (5000 prom).

seoane 11-03-2008 00:12:59

Cita:

Empezado por cHackAll (Mensaje 272121)
No es por competir

:D

Cita:

Empezado por cHackAll (Mensaje 272134)
en fin... habra que darle una oportunidad a los benditos Streams :o

Deberías darles esa oportunidad, al final usan las mismas APIs que tu.

cHackAll 11-03-2008 14:34:37

Cita:

Empezado por seoane (Mensaje 272174)
Cita:

Empezado por cHackAll (Mensaje 272121)
en fin... habra que darle una oportunidad a los benditos Streams :o

Deberías darles esa oportunidad, al final usan las mismas APIs que tu.

Pues no es cierto, yo he utilizado APIs compatibles con 16 bits :p

PD: creo que la comprobación de formato me ha costado la victoria :rolleyes:, sin embargo no olvidemos que el "concurso" de velocidades ha sido comprobado uno tras otro, y luego de que el NTFS ha echo un caché de gran parte de los datos y Sistema de archivos.

;)

Saludos


La franja horaria es GMT +2. Ahora son las 18:33:19.

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