23 octubre 2007

Dibujando con la clase TCanvas (y III)

Vamos a terminar de ver lo más importante de las operaciones que se pueden realizar con el objeto Canvas.

DIBUJAR UN RECTANGULO SIN FONDO


El procedimiento FrameRect permite crear rectángulos sin fondo teniendo en cuenta el valor de la propiedad Brush:

procedure FrameRect( const Rect: TRect );

Veamos un ejemplo:

with Canvas do
begin
R.Left := 300;
R.Top := 250;
R.Right := 350;
R.Bottom := 300;
Brush.Color := clGreen;
FrameRect( R );
end;

Este sería el dibujo resultante:


COMO COPIAR IMAGENES DE UN BITMAP A OTRO

La manera más utilizada de copiar imágenes es mediante el método Draw:

procedure Draw( X, Y: Integer; Graphic: TGraphic );

Vamos a ver un ejemplo de como copiar la imagen de un objeto de la clase TImage a nuestro formulario utilizando el procedimiento Draw:

var
R: TRect;
begin
with Canvas do
begin
R.Left := 300;
R.Top := 250;
R.Right := 350;
R.Bottom := 300;
Brush.Color := clGreen;
FrameRect( R );
Draw( 100, 100, Imagen.Picture.Graphic );
end;
end;

Hemos supuesto que el objeto de la clase TImage se llama Imagen. Este sería el resultado:


La imagen copiada consta de cuatro iconos y un fondo de color blanco. Otra cosa que podemos hacer es modificar el tamaño de la imagen a copiar utilizando el procedimiento:

procedure StretchDraw( const Rect: TRect; Graphic: TGraphic );

El parámetro Rect determina las nuevas coordenadas así como en ancho y alto de la imagen a copiar. En el siguiente ejemplo voy a copiar la misma imagen pero voy a reducirla un tamaño de 100x100:

var
R: TRect;
begin
with Canvas do
begin
R.Left := 100;
R.Top := 100;
R.Right := 200;
R.Bottom := 200;
StretchDraw( R, Imagen.Picture.Graphic );
end;
end;

Quedaría de la siguiente manera:


También se pueden copiar imágenes utilizando el procedimiento:

procedure CopyRect( const Dest: TRect; Canvas: TCanvas; const Source: TRect );

cuyos parámetros son:

Dest: Coordenadas del rectángulo destino.
Canvas: Referencia al Canvas del origen a copiar.
Source: Coordenadas del rectángulo origen.

Para el ejemplo anterior voy a copiar la imagen en su tamaño original al formulario:

var
Origen, Destino: TRect;
begin
with Canvas do
begin
Origen.Left := 0;
Origen.Top := 0;
Origen.Right := Imagen.Picture.Width;
Origen.Bottom := Imagen.Picture.Height;
Destino.Left := 100;
Destino.Top := 100;
Destino.Right := 100 + Imagen.Width;
Destino.Bottom := 100 + Imagen.Height;
CopyRect( Destino, Imagen.Canvas, Origen );
end;
end;

Entonces, ¿que diferencia hay entre Draw o StretchDraw y CopyRect? La diferencia es que CopyRect sólo puede utilizarse cuando el objeto TImage ha cargado un bitmap (*.BMP) porque si es un JPG provoca una excepción. En cambio las funciones Draw o StretchDraw siempre funcionan independientemente del tipo de imagen que sea.

LOS MODOS DE COPIA DE UNA IMAGEN

En principio cuando se realiza la copia de una imagen a otra, la copia de los pixels es exacta. Pero si queremos modificar el modo de copiar entonces la clase TCanvas tiene de la propiedad CopyMode que establece que tipo de operación que se va a realizar. Estos son sus posibles valores:

cmBlackness: pinta la imagen destino de color negro, independientemente del origen.

cmDstInvert: Invierte los colores de la imagen según la imagen destino.

cmMergeCopy: mezcla la imagen origen y destino utilizando el operador binario AND.

cmMergePaint: mezcla la imagen origen y destino utilizando el operador binario OR.

cmNotSrcCopy: copia la imagen origen invertida a la imagen destino.

cmNotSrcErase: mezcla las imagenes origen y destino y después las invierte con el operador binario OR.

cmPatCopy: copia la imagen según el valor de la propiedad Brush.Style del Canvas.

cmPatInvert: copia la imagen invertida según el valor de la propiedad Brush.Style del Canvas.

cmPatPaint: combina las imágenes origen y destino utilizando la operación binaria OR para luego invertirlas.

cmSrcAnd: combina la imagen origen con la imagen destino utilizando el operador binario AND.

cmSrcCopy: realiza una copia exacta de la imagen origen a la imagen destino (por defecto).

cmSrcErase: invierte la imagen destino y copia el origen utilizando el operador binario AND.

cmSrcInvert: invierte las imágenes origen y destino utilizando el operador binario XOR.

cmSrcPaint: combina las imágenes destino y origen utilizando el operador binario AND.

cmWhiteness: pinta toda la imagen destino de color blanco ignorando la imagen origen.

Por ejemplo voy a crear un efecto fantasma con la imagen origen:

with Canvas do
begin
CopyMode := cmMergePaint;
Draw( 100, 100, Imagen.Picture.Graphic );
end;

El efecto sería el siguiente:


COMO ACCEDER A LOS PIXELS DE LA IMAGEN

Si no son suficientes las operaciones que podemos realizar en una imagen también podemos acceder directamente a los pixels de una imagen a traves de su propiedad Pixels:

property Pixels[ X, Y: Integer ]: TColor;

Esta propiedad nos sirve igualmente para leer y para escribir pixels en la imagen. El componente TColor es un tipo entero de 32 bits definido en la unidad Graphics del siguiente modo:

type
TColor = -$7FFFFFFF-1..$7FFFFFFF;

Dentro del mismo número entero están definidos los colores básicos RGB los
cuales son:

R = Red (Rojo)
G = Green (Verde)
B = Blue (Azul)

Combinando estos tres colores se puede crear cualquier otro color. Estos colores estan dentro del valor TColor del siguiento modo:

$00GGBBRR

Donde GG es el byte en hexadecimal que representa el color verde, BB es el color azul y RR es el color rojo. Aquí tenemos unos ejemplos de los números en hexadecimal:

Rojo := $000000FF;
Azul := $0000FF00;
Verde := $00FF0000;
Blanco := $00FFFFFF;
Negro := $00000000;

Para no complicarnos mucho la vida Delphi ya dispone de colores predeterminados tales como clRed (Rojo), clBlue (Azul), etc. Sabiendo esto imaginaos que deseo hacer un programa que convierta todos los colores blancos de la imagen en amarillo:

var
i, j: Integer;
begin
with Canvas do
for j := 0 to ClientHeight - 1 do
for i := 0 to ClientWidth - 1 do
if Pixels[i,j] = clWhite then
Pixels[i,j] := clYellow;
end;

Mediante un doble bucle recorro toda la imagen y compruebo si el pixel donde estoy es blanco para sustituirlo por el amarillo. Este sería el resultado:


Con este método se podemos realizar nuestros propios filtros o crear cualquier tipo de efecto.

Con esto finalizamos el apartado dedicado al objeto Canvas.

Pruebas realizadas en Delphi 7.

1 comentario:

rc dijo...

Gracias por el tutorial, es muy descriptivo y fácil de entender, me ha sido de mucha utilidad, continúe posteando este tipo de tutoriales que son de mucha utilidad. Hasta pronto.

Publicidad