Jose M. Rojo
GDI+
GDI+ es la tecnología contenida en .NET Frameworks con la que se pueden generar salidas gráficas, textuales y trabajo con mapas de bits e imágenes.
IMAGING
Es una parte del GDI+ nos permitirá mostrar y procesar imágenes. Los dos objetos mas importantes para trabajar con imágenes son la clase Image (que dispone de métodos para guardar y cargar imágenes desde disco) y la clase Bitmap (que hereda de Image y que permitirá acceder a pixels y a otras características de la imagen). Los dos objetos se encuentran en el espacio de nombres System.Drawing pero el subsistema de generación de imágenes necesita de otros objetos pertenecientes al espacio de nombres System.Drawing.Imaging.
Carga y almacenamiento de imágenes
Los métodos FromFile y FromStream de las clases Image y Bitmap permitirán cargar imágenes desde un archivo o desde un objeto Stream que se encuentre abierto (no necesariamente un archivo)
Para mostrar esa imagen tenemos múltiples alternativas, la primera que veremos será la utilización de un objeto Graphics. Esta clase nos permite relacionar la imagen con una superficie.
Para hacer esto podemos aprovechar para construir el objeto Graphics del método CreateGraphics que tenemos en casi todos los controles de .Net. Este método relaciona a nuestro objeto con el fondo de nuestro control.
Posteriormente utilizaremos el método DrawImage de Graphics para mostrar el Bitmap.
En el siguiente ejemplo se muestra como utilizar un control OpenFileDialog para cargar el nombre de la imagen, posteriormente esta se asigna a nuestro formulario, pasando así a ser su imagen de fondo
if (openFileDialog1.ShowDialog()==DialogResult.OK)
{
gr= this.CreateGraphics();
bmp=(Bitmap)Bitmap.FromFile(openFileDialog1.FileName);
gr.DrawImage(bmp,0,0);
}
GDI+ Permite cargar imágenes de los siguientes formatos BMP, GIF, JPEG, EXIF, PNG, TIFF.
Podremos guardar la imagen utilizando el método Save de la clase Image o Bitmap, este método acepta el nombre del archivo y un argumento que especifica el formato de destino. La lista de los formatos la podemos obtener de los elementos de ImageFormat
Mostrar imágenes
Como se vio antes el método DrawImage nos permite mostrar la imagen de un objeto Graphics, este método admite 30 sobrecargas, entre ellas podemos encontrar alternativas para mostrar la posición de destino
gr.Drawimage(bmp, 0,0);
Para especificar un área rectangular donde dibujar la imagen
gr.Drawimage(bmp, 0,0, New RectangleF(0,0,bmp.Width,bmp,Height),GraphicsUnit.Pixel);
Ampliar o reducir la imagen para que se adapte al rectángulo especificador
gr.Drawimage(bmp, New RectangleF(0,0,bmp.Width/2,bmp,Height/2));
Combinar los dos efectos, mostrar un trozo ampliado o reducido, para ello se utilizan dos rectángulos
//rectangulo origin, el que amplia o reduce
Rectangle origen=New RectangleF(0,0,bmp.Width*2,bmp,Height*2);
//rectangulo de destino, el que fija el area a representar
Rectangle destino=New RectangleF(0,0,bmp.Width/2,bmp,Height/3);
gr.Drawimage(bmp, destino, origen,GraphicsUnit.Pixel);
Girar, rotar e inclinar una imagen
El método DrawImage también puede aceptar como parámetros una matriz de tres elementos Point, estos puntos definen el paralelogramo que objeto Graphics utilizará como área de destino donde mostrar la imagen que está pintando. Estos tres puntos definen la colocación de la esquina superior izquierda, la superior derecha y la inferior izquierda.
Comprender la forma en que se deben suministrar estos tres puntos nos resulta inmediato, por ejemplo para la rotación requiere cálculos trigonométricos.
Cuando se está estrechando o estirando una imagen un mismo punto de la imagen de origen puede convertirse en varios puntos de la imagen de destino y viceversa. Para controlar esto el GDI+ debe determinar el color de píxel de destino interpolando los colores de más de un píxel. Para controlar como se lleva a cabo esta tarea de interpolación, de asigna un valor a la propiedad Graphics.InterpolationMode. Los modos disponibles son Low, High, Bilinear, Bicubic, NearestNeighbor, HighQualityBilinear y HighQualityBicubic.
Cuando no se necesite transformar nada podrá mejorar el rendimiento de DrawImage sin más que especificar explícitamente que el rectángulo de destino tiene el mismo tamaño que la imagen a mostrar.
Ejemplo de funciones para voltear, rotar y deformar basadas en puntos
private void reflejaimagen(Graphics gr, Bitmap bmp, int x, int y, bool reflejaX, bool reflejaY)
{
//Inicicamos los valores como si no fuese a haber transformacaion
int x0=x;
int y0=y;
int x1=x+bmp.Width;
int y1=y;
int x2=x;
int y2=y+bmp.Height;
if(reflejaX)
{
x0=x+bmp.Width;
x1=x;
x2=x0;
}
if (reflejaY)
{
y0=y+bmp.Height;
y1=y0;
y2=y;
}
//creacion de la matriz de puntos
Point []puntos={new Point(x0,y0),new Point(x1,y1),new Point(x2,y2)};
//dibujar imagen relejada
gr.DrawImage(bmp,puntos);
}
private void rotarimagen(Graphics gr, Bitmap bmp, int x, int y, double angulo)
{
angulo=angulo/(180/Math.PI);
//Encontrar la posicion de (x1,y1) y (x2,y2)
double x1=x+bmp.Width*Math.Cos(angulo);
double y1=y+bmp.Width*Math.Sin(angulo);
double x2=x-bmp.Height*Math.Sin(angulo);
double y2=y-bmp.Height*Math.Cos(angulo);
//creacion de la matriz de puntos
Point []puntos={new Point(Convert.ToInt32(x1),Convert.ToInt32(y1)),
new Point(Convert.ToInt32(x2),Convert.ToInt32(y2))};
//dibujar imagen girada
gr.DrawImage(bmp,puntos);
}
private void deformarimagen(Graphics gr, Bitmap bmp, int x, int y,int dx, int dy)
{
//Encontrar la posicion de (x1,y1) y (x2,y2)
int x1=x+bmp.Width;
int y1=y+dy;
int x2=x+dx;
int y2=y+bmp.Height;
//creacion de la matriz de puntos
Point []puntos={new Point(x1,y1),new Point(x2,y2)};
//dibujar imagen deformada
gr.DrawImage(bmp,puntos);
}
Muestra y trabajo con imágenes utilizando el control PictureBox
También podemos trabajar y visualizar imágenes utilizando el control PictureBox alojado en la barra de herramientas. Este control nos permite modificar la apariencia de una imagen de una forma mas fácil, laboras vistas en el GDI+ para rotar o voltear se convierten en simples llamadas a métodos.
Veamos algunos de los más interesantes.
Voltear imágenes
Para lograr un volteo vertical únicamente debemos usar
PictureBox1.Image.RotateFlip(RotateFlipType.RotateNoneFlipY);
PictureBox1.Refresh();
El refresco del cuadro se convierte en indispensable cuando modificamos su apariencia.
El volteo horizontal es tan simple como:
PictureBox1.Image.RotateFlip(RotateFlipType.RotateNoneFlipX);
PictureBox1.Refresh();
Rotar imagen
Una rotación de 90 grados a la derecha se puede conseguir así:
PictureBox1.Image.RotateFlip(RotateFlipType.Rotate90FlipNone);
PictureBox1.Width = PictureBox1.Height * PictureBox1.Image.Width / PictureBox1.Image.Height;
La primera sentencia realiza la rotación y la segunda simplemente nos ajusta el ancho de nuestro PictureBox para que entre nuestra imagen
Una rotación de 90 grados a la izquierda se realizará así:
PictureBox1.Image.RotateFlip(RotateFlipType.Rotate270FlipNone);
PictureBox1.Width = PictureBox1.Height * PictureBox1.Image.Width / PictureBox1.Image.Height;
Realizar ampliaciones y reducciones
Un efecto de zoom lo podemos conseguir así.
PictureBox1.Width = PictureBox1.Width * 2;
PictureBox1.Height = PictureBox1.Height * 2;
El efecto de reducción es así de simple:
PictureBox1.Width = PictureBox1.Width / 2;
PictureBox1.Height = PictureBox1.Height / 2;
Y para dejar la imagen a tamaño natural simplemente:
PictureBox1.Width = PictureBox1.Width;
PictureBox1.Height = PictureBox1.Height;
Jose M. Rojo