Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Gráficos (https://www.clubdelphi.com/foros/forumdisplay.php?f=8)
-   -   Como cambiar la resolucion (DPI) a un TBitmap (https://www.clubdelphi.com/foros/showthread.php?t=42148)

JCarlosas 05-04-2007 00:22:41

Como cambiar la resolucion (DPI) a un TBitmap
 
Hola saludos a todos.
Actualmente estoy desarrollando una aplicacion que trabaja con graficos vectoriales y en una de las opciones debo salvar mi grafico en .jpg o .bmp.
Ya eso lo tengo conseguido, pero ahora necesito poder cambiar la resolucion de la imagen y cuando creo el TBitmap, me lo crea con 96 DPI como valor implicito y no encuentro manera de cambiarle dicho valor para 300 DPI por ejemplo.
Estoy usando un TBitmap y sobre el dibujo todo el grafico y luego lo salvo.

Muchas gracias y agreadecido de antemano por el tiempo dedicado.
Saludos.
JCarlos

seoane 05-04-2007 02:11:13

Yo tampoco encuentro la manera de cambiársela desde el objeto TBitmap, pero podemos hacerlo directamente sobre el archivo. La resolución se guarda en la cabecera del bitmap, así que no tenemos mas que cambiar esos valores en la cabecera.

Algo así:
Código Delphi [-]
procedure SaveToFileDPI(Bitmap: TBitmap; Filename: String; Rx, Ry: Double);
var
  Stream: TMemoryStream;
  InfoHeader: BITMAPINFOHEADER;
begin
  Bitmap.SaveToFile(Filename);
  with TFileStream.Create(Filename,fmOpenReadWrite) do
  try
    Seek(Sizeof(BITMAPFILEHEADER),soFromBeginning);
    Read(InfoHeader,Sizeof(InfoHeader));
    InfoHeader.biXPelsPerMeter:= Trunc((Rx * 10000) / 254);
    InfoHeader.biYPelsPerMeter:= Trunc((Ry * 10000) / 254);
    Seek(Sizeof(BITMAPFILEHEADER),soFromBeginning);
    Write(InfoHeader,Sizeof(InfoHeader));
  finally
    Free;
  end;
end;

// Por ejemplo si bitmap es un objeto del tipo TBitmap
SaveToFileDPI(Bitmap,'c:\1.bmp',300,300);

JCarlosas 05-04-2007 23:12:31

Lo que estoy realmente salvando es un .jpg.
Mi rutina en esencia es algo asi.

Código Delphi [-]
        
var
         MiBitMap : TBitMap;    
        Begin
           
          MiBitMap := TBitMap.Create;         
          MiBitMap.SetSize(Ancho, Alto);
          
          //AQui dibujo lo que deseo en el bitmap y luego lo salvo como .jpg.
          MyJPEG := TJPEGImage.Create;
          try
           MyJPEG.Assign(MiBitMap);
           MyJPEG.CompressionQuality  := 100;
           MyJPEG.SaveToFile(FileName);
          finally
           MyJPEG.Free;
          end;
       end;

Y deseo cuando salve el archivo que ya tenga la resolucion incluida.
Quisiera no tener que hacer una salva intermedia a bmp, cambiar la resolucion y luego volver a salvarlo como .jpg y luego borrar el bmp.

Muchas gracias por la ayuda, intentare esa via sino encuentro otra.
Saludos a todos.
JCarlos

seoane 06-04-2007 01:24:19

Primero dices:
Cita:

debo salvar mi grafico en .jpg o .bmp.
Y luego dices:
Cita:

Lo que estoy realmente salvando es un .jpg.
Muchas veces pienso que si la gente explicara lo que realmente quiere ahorraríamos mucho tiempo ;)

De todas formas podemos hacer para el jpg lo mismo que hicimos para el bmp, es decir, modificar la parte del fichero donde se guardan esos valores. en el caso del jpeg esta información se guarda en el segmento AP0, así que añadimos un nuevo segmento AP0 con la información que queremos y borramos la información anterior.

El código nos quedaría mas o menos así:
Código Delphi [-]
uses jpeg;

procedure AjustarDPI(Origen, Destino: TStream; Rx,Ry: Word);
var
  AP0: array[1..18] of byte;
  Buffer: array[0..$FFFF] of Char;
  Header: array[1..4] of byte;
  Size: Integer;
begin
  Origen.Seek(0,soFromBeginning);
  Origen.ReadBuffer(Header,2);
  if (Header[1] <> $FF) or (Header[2] <> $D8) then
    raise Exception.Create('Identificador incorrecto');
  Destino.WriteBuffer(Header,2);
  FillChar(AP0,Sizeof(AP0),#0);
  AP0[1]:= $FF;
  AP0[2]:= $E0;
  AP0[4]:= Sizeof(AP0) - 2;
  AP0[5]:= Byte('J');AP0[6]:= Byte('F');AP0[7]:= Byte('I');AP0[8]:= Byte('F');
  AP0[10]:= 1; AP0[11]:= 2;
  AP0[12]:= 1;
  AP0[13]:= Rx shr 8; AP0[14]:= Rx and $FF;
  AP0[15]:= Ry shr 8; AP0[16]:= Ry and $FF;
  Destino.WriteBuffer(AP0,Sizeof(AP0));
  repeat
    Origen.ReadBuffer(Header,4);
    Size:= ((Header[3] shl 8) + Header[4]) - 2;
    case Header[2] of
      $FE, $E0..$EF: Origen.Seek(Size,soFromCurrent);
      $01,$D0..$D9: begin
                      Destino.WriteBuffer(Header,2);
                      Origen.Seek(-2,soFromCurrent)
                    end
      else
      begin
        Origen.ReadBuffer(Buffer,Size);
        Destino.WriteBuffer(Header,4);
        Destino.WriteBuffer(Buffer,Size);
      end;
    end;
  until Header[2] = $DA;
  Destino.CopyFrom(Origen,Origen.Size - Origen.Position);
end;

procedure SaveToFileDPI(Imagen: TJpegImage; Filename: String; Rx, Ry: Word);
var
  Temp: TMemoryStream;
  Stream: TFileStream;
begin
  Temp:= TMemoryStream.Create;
  try
    Imagen.SaveToStream(Temp);
    Stream:= TFileStream.Create(Filename, fmCreate);
    try
      AjustarDPI(Temp,Stream,Rx,Ry);
    finally
      Stream.Free;
    end;
  finally
    Temp.Free;
  end;
end;

Para usarlo solo tienes que sustituir esta linea:
Código Delphi [-]
MyJPEG.SaveToFile(FileName);

Por esta otra:
Código Delphi [-]
SaveToFileDPI(MyJPEG,FileName,300,300);

JCarlosas 09-04-2007 15:48:59

OK.
Muchisimas gracias.
Eso es lo que andaba buscando.
Saludos.
JCarlos

JCarlosas 09-04-2007 18:19:10

Ya probe el ejemplo y trabaja a la perfeccion.

Por cierto quizas no me exprese bien en lo que deseaba hacer.
Realmente cuando dije:

Cita:

Empezado por JCarlosas
debo salvar mi grafico en .jpg o .bmp.

Me referia a que a peticion del usuario era en un formato u otro.

Saludos a todos
y muy agradecido, me ha sido de gran ayuda los ejemplos

jcarlos.matrix 25-04-2007 03:50:31

No entiendo
 
Aplique el jemplo tal cual como esta. y no me cambia. cargo una imagen de 929 kb y y en el archivo resultando da = 929 kb

seoane 25-04-2007 12:59:48

Cita:

Empezado por jcarlos.matrix
Aplique el jemplo tal cual como esta. y no me cambia. cargo una imagen de 929 kb y y en el archivo resultando da = 929 kb

:confused: ¿Y cual debía ser el resultado? Ten en cuenta que solo cambias la resolución.

Una imagen de 100x100 píxeles con 72 ppp, ocupa exactamente lo mismo que una de 100x100 píxeles con 300 ppp, ya que sigue teniendo los mismos píxeles y en pantalla no apreciaras ningún cambio. El parámetro de la resolución solo sirve a la hora de imprimir la imagen para determinar la densidad de puntos con la que se debe imprimir. Es decir una imagen con el mismo tamaño de píxeles, pero con mayor resolución, se vera mas pequeña al imprimir, ya que se imprimirán mas puntos (píxeles) en el mismo espacio.

JCarlosas 25-04-2007 16:23:13

Hola.
Es exactamente como dice Seoane.
Si lo que quieres es reducir el tamaño del archivo que contien a la imagen modifica la linea que dice.

MyJPEG.CompressionQuality := 100;
en el ejemplo.

Código Delphi [-]
var
         MiBitMap : TBitMap;    
        Begin
           
          MiBitMap := TBitMap.Create;         
          MiBitMap.SetSize(Ancho, Alto);
          
          //AQui dibujo lo que deseo en el bitmap y luego lo salvo como .jpg.
          MyJPEG := TJPEGImage.Create;
          try
           MyJPEG.Assign(MiBitMap);
           MyJPEG.CompressionQuality  := 100;
           MyJPEG.SaveToFile(FileName);
          finally
           MyJPEG.Free;
          end;
       end;

Un numero menor de 100 te dara una mayor compresion del archivo que la contiene, pero la imagen tendra una menor calidad.
Con ese valor es neceario jugar hasta obtener una calidad aceptable y un tamaño de archivo requerido.
Cabe aclarar que no todas los ficheros de imagenes se reducen al mismo tamaño independientemente que las dimensiones de la imagen (Ancho por alto de la imagen en pixel) sean identicas. Depende en gran medida el contenido de la imagen como tal.
Bueno chao.
Saludos a todos.


La franja horaria es GMT +2. Ahora son las 05:58:00.

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