Ver Mensaje Individual
  #15  
Antiguo 23-05-2006
Avatar de seoane
[seoane] seoane is offline
Miembro Premium
 
Registrado: feb 2004
Ubicación: A Coruña, España
Posts: 3.717
Reputación: 24
seoane Va por buen camino
Lo de no comentar el codigo es una fea costumbre que tengo, pero estoy encantado de comentarlo si esta interesado. Para no volver a subir el proyecto voy a ir poniendo aqui varias de las funciones ya comentadas:


Estas funciones manejan el archivo JPEG una vez lo tenemos en un stream
Código Delphi [-]
// Esta funcion lee el comentario de un archivo JPEG.
// El archivo JPEG esta dividido en segmentos con el siguiente formato
// Identificador (2Bytes) + Longitud (2Bytes) + Contenido
// Asi que vamos leyendo segmento a segmento hasta encontrar el que nos interesa
function LeerCom(Stream: TStream): string;
var
  Buffer: array[0..$FFFF] of Char;
  Header: array[1..4] of byte;
  Size: Integer;
begin
  // Nos colocamos al principio del archivo
  Stream.Seek(0,soFromBeginning);
  // Leemos los 2 primeros Bytes
  Stream.ReadBuffer(Header,2);
  // Y comprobamos que son correctos  (todos los JPEG empiezan por FF D8)
  if (Header[1] <> $FF) or (Header[2] <> $D8) then
    // Si no es asi, provocamos un error
    raise Exception.Create('Identificador incorrecto');
  repeat
    // Leemos los 4 primeros bytes del segemento
    Stream.ReadBuffer(Header,4);
    // Usamos los 2 ultimos bytes para calcular el tamño del segmento
    // que es igual al tamaño del contenido + 2, asi que le restamos 2
    Size:= ((Header[3] shl 8) + Header[4]) - 2;
    // Todos los segmentos comienzan por FF asi que utilizamos el segundo
    // byte para identificarlos
    case Header[2] of
      // FE corresponde al segemnto con los comentarios
      $FE: begin
             FillChar(Buffer,Sizeof(Buffer),0);
             // Leemos el contenido del segemento
             Stream.ReadBuffer(Buffer,Size);
             // Y lo convertimos en un string
             Result:= String(PChar(@Buffer));
           end;
      // Estos segemntos son casos especiales, solo miden 2 bytes, asi que
      // restrocedemos el puntero 2 bytes hacia atras
      $01,$D0..$D9: Stream.Seek(-2,soFromCurrent) ;
      // Si no es ni un comentario ni un caso especial, adelantamos el puntero
      // hasta el siguiente segmento
      else Stream.Seek(Size,soFromCurrent);
    end;
  // Salimos del bucle si ya hemos leido el comentario o llegamos al ultimo
  // segmento, ya que a partir de aqui el archivo solo contiene informacion
  // correspondiente a la propia imagen.
  until (Result <> '') or (Header[2] = $DA);
end;

// Esta funcion inserta un comentario. Hay que tener en cuenta que si hay un
// comentario anterior no se elimina, asi que deberemos usar antes la
// funcion "Limpiar" para quitar los comentarios anteriores.
procedure InsertarCom(Origen, Destino: TStream; Comment: string);
var
  Buffer: array[0..$FFFF] of Char;
  Header: array[1..4] of byte;
  Size: Integer;
begin
  // No colocamos al principio del archivo
  Origen.Seek(0,soFromBeginning);
  // Leemos los 2 primeros bytes
  Origen.ReadBuffer(Header,2);
  // y comprobamos que son correctos
  if (Header[1] <> $FF) or (Header[2] <> $D8) then
    raise Exception.Create('Identificador incorrecto');
  // Escribimos los 2 primeros bytes
  Destino.WriteBuffer(Header,2);
  // Calculamos la longitud del segmento
  Size:= Length(Comment) + 2;
  Header[1]:= $FF;
  Header[2]:= $FE;
  Header[3]:= Size div 256;
  Header[4]:= Size mod 256;
  // Copiamos el comentario a un buffer
  StrCopy(@Buffer,PChar(Comment));
  // Escribimos la cabecera del segmento
  Destino.WriteBuffer(Header,4);
  // Escribimos el contenido del segmento
  Destino.WriteBuffer(Buffer,Length(Comment));
  // Copiamos el resto
  Destino.CopyFrom(Origen,Origen.Size - Origen.Position);
end;

// Esta funcion elimina los segmentos resrvados para comentarios y para
// aplicaciones, informacion que nos es necesaria para ver la imagen. Hay
// que tener cuidado porque algunas aplicaciones guardan informacion ahi, por
// ejemplo cuando fue tomada la foto o que camara se uso.
procedure Limpiar(Origen, Destino: TStream);
var
  Buffer: array[0..$FFFF] of Char;
  Header: array[1..4] of byte;
  Size: Integer;
begin
  // Nos colocamos al principio del archivo
  Origen.Seek(0,soFromBeginning);
  // Leemos los 2 primeros bytes
  Origen.ReadBuffer(Header,2);
  // Comprobamos que son correctos
  if (Header[1] <> $FF) or (Header[2] <> $D8) then
    raise Exception.Create('Identificador incorrecto');
  Destino.WriteBuffer(Header,2);
  // Leemos segemento a segmento
  repeat
    Origen.ReadBuffer(Header,4);
    Size:= ((Header[3] shl 8) + Header[4]) - 2;
    case Header[2] of
      // Si es un comentario o un segmento de aplicacion saltamos al siguiente
      $FE, $E0..$EF: Origen.Seek(Size,soFromCurrent);
      // Si es un caso especial retrocedemos 2 bytes
      $01,$D0..$D9: begin
                      Destino.WriteBuffer(Header,2);
                      Origen.Seek(-2,soFromCurrent)
                    end
      else
      // Si es un segmento normal lo copiamos
      begin
        Origen.ReadBuffer(Buffer,Size);
        Destino.WriteBuffer(Header,4);
        Destino.WriteBuffer(Buffer,Size);
      end;
    end;
  until Header[2] = $DA;
  // Copiamos el resto del archivo
  Destino.CopyFrom(Origen,Origen.Size - Origen.Position);
end;

Para mas informacion sobre el formato de archivo JPEG
http://www.wotsit.org/search.asp?page=5&s=graphics

PD: Al comentar la funcion de insertar comentario me di cuenta de que daba mas pasos de los necesarios, debido a una confusion que tenia con respecto al primer segmento. Esto demuestra que nunca esta mal repasar el codigo

Última edición por seoane fecha: 23-05-2006 a las 20:35:31.
Responder Con Cita