Introducción:
Pues eso, siguiendo con el mismo tema que en
la primera parte, en esta ocasión te muestro cómo trocear una imagen en
los trozos que indiques durante la ejecución del programa, de esa forma,
puedes indicar cuantas columnas y cuantas filas quieres usar, y también le
he puesto para que se adapte al tamaño de la ventana, de forma que se vea
más grande si así lo quieres. Además de poner una una opción para que se
pueda ver automáticamente el nuevo tamaño sin necesidad de volver a pulsar
en el botón trocear.
Esta es la captura de la aplicación en tiempo de ejecución:
Figura 1. La aplicación en tiempo de ejecución
Como puedes comprobar, puedes usar la imagen que quieras, y si te gusta
la que incluye el programa, que es la que está en la captura de la primera
parte, simplemente borra el contenido de la caja de textos con la imagen a
trocear y al pulsar la tecla Intro se mostrará nuevamente la imagen
original.
No me voy a enrollar en esta ocasión ya que en el otro artículo
prácticamente te lo expliqué todo paso a paso. Solo decirte que utilizo
valores de configuración del usuario para almacenar las columnas, el fichero
y esas cosillas, ni que decir tiene que no me he complicado la vida y en
esta ocasión he usado cosas que solo tiene la versión 2005 de los dos
lenguajes, aunque si quitas la parte de configuración, el código te valdrá
lo mismo para Visual Studio 2003.
Nota:
Si quieres usar el código mostrado en este artículo en Visual Studio 2003
debes quitar todo lo que hace referencia a My.Settings y My.Resouces en
Visual Basic y Properties.Settings y Properties.Resources en C#.
Sí, ya se que este es diferente y que seguramente necesitaría que te lo
"desglosara", pero... mejor que mires los comentarios y así vas habituándote
a entender el código... ;-)))
Sí, ya se que no es una excusa, pero... je, je... ¿a que lo parecía?
Pues eso... ahí abajo tienes el código de Visual Basic
y el de C#, para que te entretengas... y si no quieres
entretenerte, también te pongo un fichero .rar para que
te bajes los proyectos para Visual Basic 2005 y Visual C# 2005, es decir,
que los puedes usar con las versiones Express de Visual Studio 2005 o con
las versiones "normales".
Para un próximo artículo, (si no se te olvida, que
ya nos vamos conociendo) le añadiré un botón para poder guardar las
imágenes generadas... pero mientras tanto, puedes ir probándolo por tu
cuenta. Como pista te diré que el objeto Image tiene una propiedad
que te facilitará la tarea.
¡Que lo trocees dinámicamente bien!
Nos vemos.
Guillermo
P.S.
El código incluido en el ZIP tiene algunas cosillas que
no muestro aquí, por ejemplo, una barra de progreso (aunque no consigo que
llegue al 100%, je, je) y también un Timer para que le de tiempo al
formulario a mostrarse, ya que si has indicado muchos trozos tardará en
mostrarse, porque al iniciarse, primero trocea la imagen. Ese mismo
temporizador lo uso para poner a cero la barra de progreso.
El código para Visual Basic .NET
(casi cualquier versión)
|
'------------------------------------------------------------------------------
' Trocear una imagen (17/Ene/07)
' Las imágenes de destino pueden cambiar de tamaño
'
' ©Guillermo 'guille' Som, 2007
'------------------------------------------------------------------------------
Option Strict On
Imports Microsoft.VisualBasic
Imports vb = Microsoft.VisualBasic
Imports System
Imports System.Windows.Forms
Imports System.Drawing
Public Class fTamañoDinamico
Private ficImagen As String
' El número de dimensiones, por ejemplo 3x3 = 9 trozos
Private nColumnas As Integer = 3
Private nFilas As Integer = 3
' Para que no se produzca el evento Resize mientras se inicia
Private iniciando As Boolean = True
' Constante con el número máximo de filas y columnas
Private Const maxTrozos As Integer = 50
Private Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs) _
Handles MyBase.Load
' Asignar los valores de la configuración
ficImagen = My.Settings.Fichero
nColumnas = My.Settings.Columnas
nFilas = My.Settings.Filas
Me.txtColumnas.Text = nColumnas.ToString
Me.txtFilas.Text = nFilas.ToString
Me.chkAjustarAuto.Checked = My.Settings.AjustarAuto
Me.txtImagen.Text = ficImagen
' Si no existe la imagen, dejamos la mía
If System.IO.File.Exists(ficImagen) Then
Me.picMain.Image = Image.FromFile(ficImagen)
Else
Me.picMain.Image = My.Resources.Guille28sep06_1003_240x308
End If
' Mostrar los trozos
trocearImagen(nColumnas, nFilas)
iniciando = False
End Sub
Private Sub btnExaminar_Click(ByVal sender As Object, ByVal e As EventArgs) _
Handles btnExaminar.Click
Dim oFD As New OpenFileDialog
oFD.Title = "Seleccionar imagen"
oFD.Filter = "Imágenes|*.jpg;*.gif;*.png;*.bmp|Todos (*.*)|*.*"
oFD.FileName = Me.txtImagen.Text
If oFD.ShowDialog = Windows.Forms.DialogResult.OK Then
Me.txtImagen.Text = oFD.FileName
Me.picMain.Image = Image.FromFile(Me.txtImagen.Text)
My.Settings.Fichero = Me.txtImagen.Text
End If
End Sub
Private Sub chkAjustarAuto_CheckedChanged(ByVal sender As Object, ByVal e As EventArgs) _
Handles chkAjustarAuto.CheckedChanged
My.Settings.AjustarAuto = chkAjustarAuto.Checked
End Sub
Private Sub txtImagen_KeyPress(ByVal sender As Object, ByVal e As KeyPressEventArgs) _
Handles txtImagen.KeyPress
If e.KeyChar = ChrW(13) Then
ficImagen = Me.txtImagen.Text
My.Settings.Fichero = ""
If String.IsNullOrEmpty(ficImagen) Then
Me.picMain.Image = My.Resources.Guille28sep06_1003_240x308
End If
End If
End Sub
Private Sub btnTrocear_Click(ByVal sender As System.Object, ByVal e As EventArgs) _
Handles btnTrocear.Click
' Trocear una imagen en trozos más pequeños
' Asignar el tamño según las columnas y filas indicadas
' Comprobar que son datos correctos
Dim novalido As Boolean = False
If vb.IsNumeric(txtColumnas.Text) = False Then
novalido = True
Else
nColumnas = CInt(txtColumnas.Text)
If nColumnas < 1 OrElse nColumnas > maxTrozos Then
novalido = True
End If
End If
If novalido Then
MessageBox.Show("Debes indicar un número de 1 a " & maxTrozos & " en las columnas")
txtColumnas.Focus()
Exit Sub
End If
If vb.IsNumeric(txtFilas.Text) = False Then
novalido = True
Else
nFilas = CInt(txtFilas.Text)
If nFilas < 1 OrElse nFilas > maxTrozos Then
novalido = True
End If
End If
If novalido Then
MessageBox.Show("Debes indicar un número de 1 a " & maxTrozos & " en las filas")
txtFilas.Focus()
Exit Sub
End If
' Guardar los valores en la configuración
My.Settings.Columnas = nColumnas
My.Settings.Filas = nFilas
trocearImagen(nColumnas, nFilas)
End Sub
Private Sub gbImagenes_Resize(ByVal sender As Object, ByVal e As EventArgs) _
Handles gbImagenes.Resize
If iniciando Then Exit Sub
' El número de filas y de columnas será
' el usado la última vez al pulsar en trocear
If Me.chkAjustarAuto.Checked Then
trocearImagen(nColumnas, nFilas)
End If
End Sub
Private Sub trocearImagen(ByVal columnas As Integer, ByVal filas As Integer)
' Separación entre la imagen y el borde del contenedor
Const sepX As Integer = 6
Const sepY As Integer = 16
' La separación entre cada trozo
Const sep As Integer = 2
' El tamaño de cada imagen será:
' Ancho del groupBox \ columnas - columnas
' Alto del groupBox \ filas - filas
' Al usar columnas y filas, se separa más de la cuenta o menos de lo deseado
' Pero dejando 2 para el ancho y (filas\2) para el alto parece que está bien
Dim tamW As Integer = (Me.gbImagenes.ClientSize.Width - sepX) \ columnas - 2
Dim tamH As Integer = (Me.gbImagenes.ClientSize.Height - sepY) \ filas - 2
' El tamaño proporcional del ancho y alto
' correspondientes a los trozos a usar
Dim tamTrozoW As Integer = Me.picMain.Image.Width \ columnas
Dim tamTrozoH As Integer = Me.picMain.Image.Height \ filas
' El rectángulo de cada nuevo trozo
Dim rectDest As New Rectangle(0, 0, tamW, tamH)
' Estas variables se usan en el bucle
Dim bmpDest As Bitmap
Dim g As Graphics
Dim rectOri As Rectangle
'
' Array con el número de pictures necesarias
'Dim trozos(0 To (columnas * filas - 1)) As PictureBox
Dim trozos(columnas * filas - 1) As PictureBox
' Eliminamos las imágenes que tuviera el groupBox
Me.gbImagenes.Controls.Clear()
' Para contar cada columna y fila
Dim c, f As Integer
' La posición X e Y en la imagen original
Dim pX, pY As Integer
For i As Integer = 0 To trozos.Length - 1
' El trozo de la imagen original
rectOri = New Rectangle(pX, pY, tamTrozoW, tamTrozoH)
' La imagen de destino
bmpDest = New Bitmap(tamW, tamH)
g = Graphics.FromImage(bmpDest)
' Obtenemos un trozo de la imagen original
' y lo dibujamos en la imagen de destino
g.DrawImage(Me.picMain.Image, rectDest, rectOri, GraphicsUnit.Pixel)
'
' Asignamos la nueva imagen al picture correspondiente
' creamos el picture y lo asignamos al groupBox
trozos(i) = New PictureBox
Me.gbImagenes.Controls.Add(trozos(i))
' Asignamos el tamaño
trozos(i).Size = New Size(tamW, tamH)
' Posicionamos el picture
trozos(i).Location = New Point(tamW * c + (sep * c) + sepX, _
tamH * f + (sep * f) + sepY)
' Asignar la imagen creada
trozos(i).Image = bmpDest
'
' Calculamos la posición del próximo trozo
c += 1
pX += tamTrozoW
' Cuando hayamos recorrido las columnas,
' pasamos a la siguiente fila
If c >= columnas Then
c = 0
f += 1
pX = 0
pY += tamTrozoH
End If
Next
End Sub
End Class
|
El código para C#
(casi cualquier versión)
|
//-----------------------------------------------------------------------------
// Trocear una imagen (17/Ene/07)
// Las imágenes de destino pueden cambiar de tamaño
//
// ©Guillermo 'guille' Som, 2007
//-----------------------------------------------------------------------------
using System;
using System.Windows.Forms;
using System.Drawing;
namespace trocearImagen_cs
{
public partial class fTamañoDinamico : Form
{
public fTamañoDinamico()
{
InitializeComponent();
}
private string ficImagen;
// El número de dimensiones, por ejemplo 3x3 = 9 trozos
private int nColumnas = 3;
private int nFilas = 3;
// Para que no se produzca el evento Resize mientras se inicia
private bool iniciando = true;
// Constante con el número máximo de filas y columnas
const int maxTrozos = 50;
Properties.Settings mySettings = new trocearImagen_cs.Properties.Settings();
private void fTamañoDinamico_Load(object sender, EventArgs e)
{
// Asignar los valores de la configuración
ficImagen = mySettings.Fichero;
nColumnas = mySettings.Columnas;
nFilas = mySettings.Filas;
this.txtColumnas.Text = nColumnas.ToString();
this.txtFilas.Text = nFilas.ToString();
this.chkAjustarAuto.Checked = mySettings.AjustarAuto;
this.txtImagen.Text = ficImagen;
// Si no existe la imagen, dejamos la mía
if (System.IO.File.Exists(ficImagen))
{
this.picMain.Image = Image.FromFile(ficImagen);
}
else
{
this.picMain.Image = Properties.Resources.Guille28sep06_1003_240x308;
}
// Mostrar los trozos
trocearImagen(nColumnas, nFilas);
iniciando = false;
}
private void fTamañoDinamico_FormClosing(object sender, FormClosingEventArgs e)
{
// C# no guarda automáticamente los cambios
mySettings.Save();
}
private void btnExaminar_Click(object sender, EventArgs e)
{
OpenFileDialog oFD = new OpenFileDialog();
oFD.Title = "Seleccionar imagen";
oFD.Filter = "Imágenes|*.jpg;*.gif;*.png;*.bmp|Todos (*.*)|*.*";
oFD.FileName = this.txtImagen.Text;
if (oFD.ShowDialog() == DialogResult.OK)
{
this.txtImagen.Text = oFD.FileName;
this.picMain.Image = Image.FromFile(this.txtImagen.Text);
mySettings.Fichero = this.txtImagen.Text;
}
}
private void chkAjustarAuto_CheckedChanged(object sender, EventArgs e)
{
mySettings.AjustarAuto = chkAjustarAuto.Checked;
}
private void txtImagen_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == (char)13)
{
ficImagen = this.txtImagen.Text;
mySettings.Fichero = "";
if (String.IsNullOrEmpty(ficImagen))
{
this.picMain.Image = Properties.Resources.Guille28sep06_1003_240x308;
}
}
}
private void btnTrocear_Click(System.Object sender, EventArgs e)
{
// Trocear una imagen en trozos más pequeños
// Asignar el tamño según las columnas y filas indicadas
// Comprobar que son datos correctos
bool novalido = false;
try
{
nColumnas = Convert.ToInt32(txtColumnas.Text);
if (nColumnas < 1 || nColumnas > maxTrozos)
{
novalido = true;
}
}
catch
{
novalido = true;
}
if (novalido)
{
MessageBox.Show("Debes indicar un número entero de 1 a " +
maxTrozos + " en las columnas");
txtColumnas.Focus();
return;
}
try
{
nFilas = Convert.ToInt32(txtFilas.Text);
if (nFilas < 1 || nFilas > maxTrozos)
{
novalido = true;
}
}
catch
{
novalido = true;
}
if (novalido)
{
MessageBox.Show("Debes indicar un número entero de 1 a " +
maxTrozos + " en las filas");
txtFilas.Focus();
return;
}
// Guardar los valores en la configuración
mySettings.Columnas = nColumnas;
mySettings.Filas = nFilas;
trocearImagen(nColumnas, nFilas);
}
private void gbImagenes_Resize(object sender, EventArgs e)
{
if (iniciando) return;
// El número de filas y de columnas será
// el usado la última vez al pulsar en trocear
if (this.chkAjustarAuto.Checked)
{
trocearImagen(nColumnas, nFilas);
}
}
private void trocearImagen(int columnas, int filas)
{
// Separación entre la imagen y el borde del contenedor
const int sepX = 6;
const int sepY = 16;
// La separación entre cada trozo
const int sep = 2;
// El tamaño de cada imagen será:
// Ancho del groupBox \ columnas - columnas
// Alto del groupBox \ filas - filas
// Al usar columnas y filas, se separa más de la cuenta o menos de lo deseado
// Pero dejando 2 para el ancho y (filas\2) para el alto parece que está bien
int tamW = (this.gbImagenes.ClientSize.Width - sepX) / columnas - 2;
int tamH = (this.gbImagenes.ClientSize.Height - sepY) / filas - 2;
// El tamaño proporcional del ancho y alto
// correspondientes a los trozos a usar
int tamTrozoW = this.picMain.Image.Width / columnas;
int tamTrozoH = this.picMain.Image.Height / filas;
// El rectángulo de cada nuevo trozo
Rectangle rectDest = new Rectangle(0, 0, tamW, tamH);
// Estas variables se usan en el bucle
Bitmap bmpDest;
Graphics g;
Rectangle rectOri;
//
// Array con el número de pictures necesarias
PictureBox[] trozos = new PictureBox[columnas * filas];
// Eliminamos las imágenes que tuviera el groupBox
this.gbImagenes.Controls.Clear();
// Para contar cada columna y fila
int c = 0, f = 0;
// La posición X e Y en la imagen original
int pX = 0, pY = 0;
for (int i = 0; i < trozos.Length; i++)
{
// El trozo de la imagen original
rectOri = new Rectangle(pX, pY, tamTrozoW, tamTrozoH);
// La imagen de destino
bmpDest = new Bitmap(tamW, tamH);
g = Graphics.FromImage(bmpDest);
// Obtenemos un trozo de la imagen original
// y lo dibujamos en la imagen de destino
g.DrawImage(this.picMain.Image, rectDest, rectOri, GraphicsUnit.Pixel);
//
// Asignamos la nueva imagen al picture correspondiente
// creamos el picture y lo asignamos al groupBox
trozos[i] = new PictureBox();
this.gbImagenes.Controls.Add(trozos[i]);
// Asignamos el tamaño
trozos[i].Size = new Size(tamW, tamH);
// Posicionamos el picture
trozos[i].Location = new Point(tamW * c + (sep * c) + sepX,
tamH * f + (sep * f) + sepY);
// Asignar la imagen creada
trozos[i].Image = bmpDest;
//
// Calculamos la posición del próximo trozo
c += 1;
pX += tamTrozoW;
// Cuando hayamos recorrido las columnas,
// pasamos a la siguiente fila
if (c >= columnas)
{
c = 0;
f += 1;
pX = 0;
pY += tamTrozoH;
}
}
}
}
}
|
Espacios de nombres usados en el código de este artículo:
System.Windows.Forms
System.Drawing
Compatibilidad:
Este código funciona con cualquier versión de .NET salvo por lo indicado
de las configuraciones, particularmente en Visual Basic.
Windows Vista ready! ;-)))
|