Introducción:
Esta utilidad te permitirá crear imágenes en miniatura a
partir de imágenes normales.
Para usarla, solo tienes que seleccionar las imágenes que
quieras "miniaturizar" y del resto se encarga el programa.
Esa selección de las imágenes a convertir en miniatura la
puedes hacer de dos formas:
1- Seleccionando las imágenes de forma individual.
2- Seleccionando un directorio que contenga imágenes, ya que el programa se
encargará de añadir las imágenes que haya a la lista de imágenes a
miniaturizar. En este caso, en realidad no se procesan todos los tipos de
imágenes, ya que el programa solo comprueba las extensiones .JPG, .GIF y
.PNG, pero si quieres cambiar el código para que soporte otros tipos, es
fácil de modificar... no me preguntes porqué solo he puesto esos tres
tipos... que no sabría darte una respuesta satisfactoria... je, je.
Como puedes ver en la captura de la utilidad en ejecución
(figura 1), tienes la posibilidad de indicar el tamaño en porcentaje o bien
en tamaño fijo. En este último caso, si la imagen es vertical, se usará el
tamaño menor como ancho y el mayor como alto.
Figura 1. La utilidad de crear thumbnails en ejecución
Cuando seleccionas las fotos a miniaturizar, el proceso
de conversión en miniatura se puede hacer de forma automatizada o bien
manual (una a una). En el primer caso, (el que seguramente siempre usarás),
tendrás que seleccionar la opción Automático.
Al pulsar en el botón Procesar es cuando empieza el espectáculo, y si
no has marcado la opción Automático, tendrás que ir pulsando en el
botón Guardar imagen para miniaturizar cada imagen.
Independientemente de que miniaturices o no las imágenes,
al hacer doble clic en una de las imágenes de la lista, podrás ver esa
imagen en el control que hay a la derecha de la lista (ver la figura 1).
El código que crea los thumbnails (las miniaturas)
Bueno, ya sabes que es lo que hace esta utilidad, así que
ahora te mostraré el código que permite la creación de esas miniaturas.
La verdad es que me ha dado un poco de "quebradero" de
cabeza, aunque, como suele ocurrir, por no buscar bien en las opciones que
el propio .NET Framework pone a nuestra disposición.
Aunque la verdad es que ese quebradero de cabeza también ha sido porque yo
"suponía" que algunas cosas debían hacerse de otra forma... y no... el .NET
dice que no... y eso es lo que hay... además de que en algunos de los
ejemplos de la ayuda, pues... en fin... que te voy a comentar de algunos de
los ejemplos de la ayuda... si todos estuvieran bien y fueran lo
suficientemente claros, pues no habría sitios como el mío... je, je...
aunque... a decir verdad es que lo mismo esos ejemplos están hechos para la
gente "menos torpe" que yo... que también puede ser.
La cosa es que primero pensé en cargar una imagen en un
PictureBox creado por código y a partir de esa imagen guardarla más
pequeña... pero el que se cambie el tamaño del control no implica que se
cambie el tamaño original.
Después opté por usar el método GetThumbnailImage,
pero me pareció mucho "rollo" eso de tener que usar un delegado, y en
realidad aunque casi era lo que quería hacer... yo me empeñaba en cambiar
"manualmente" el tamaño de la imagen, así que estuve mirando el método
DrawImage de la clase Graphics, pero el problema de ese método es
que está muy bien para otras cosas, pero no para lo que yo quería, así que,
al final me decidí por GetThumbnailImage, ya que ese método permite
indicar el tamaño de la imagen, aunque si la imagen procesada ya incorpora
una miniatura, se usará esa miniatura.
El método GetThumbnailImage se usa indicando el
tamaño de la miniatura, además de un parámetro que es un delegado y otro que
no se usa y siempre debe ser IntPtr.Zero.
El delegado, es una función que devuelve verdadero o falso según se deba o
no generar la miniatura.
En mi caso, ese delegado lo he definido de esta forma:
' Para usar como delegado del método GetThumbnailImage
' (devolver siempre False ya que True significa que se cancela)
Private Function getThumbnailImageAbort() As Boolean
Return False
End Function
Como puedes comprobar, siempre devuelve False, es decir,
nunca cancela.
El método GetThumbnailImage devuelve un objeto de
tipo Image, y como ese método está definido en la clase Image,
uso el que proporciona la imagen del control PictureBox en el que se
va mostrando cada imagen a procesar (en mi código un control llamado pic).
Este es el código que genera la miniatura:
' Crear un thumbnail con el método GetThumbnailImage
' Esto usará el thumbnail que tenga la imagen
' o creará uno si no la tiene.
img = pic.Image.GetThumbnailImage(imgWidth, imgHeight, _
AddressOf getThumbnailImageAbort, IntPtr.Zero)
En C#, gracias a los métodos anónimos, el código anterior
lo podemos simplificar, sin necesidad de crear un método independiente. El
código sería el siguiente:
// Usando el delegado directamente:
img = pic.Image.GetThumbnailImage(imgWidth, imgHeight,
delegate { return false; }, IntPtr.Zero);
El tamaño de la miniatura será el indicado manualmente o
bien por porcentaje.
En este caso, si se ha indicado que se use un porcentaje, lo calculo y
asigno los valores correspondientes a las dos variables usadas (imgWidth e
imgHeight).
En caso de que el tamaño se indique de forma manual, se
tendrá en cuenta si la imagen original está en vertical, en cuyo caso
utilizo los valores del ancho para el alto y el del alto para el ancho, ya
que si el tamaño de la miniatura es 200x150, al ser vertical debería ser de
150x200 (aunque en el caso de que la miniatura ya exista no se si esto
tendrá algún efecto o lo único que servirá es para distorsionar más la
imagen... pero mi lógica me decía que lo hiciera de esta formas, así
que...).
Este es el código para calcular el tamaño de la
miniatura:
Dim imgWidth As Integer
Dim imgHeight As Integer
If Me.optPorcentaje.Checked Then
' Usar el tamaño indicado por el porcentaje
Dim porciento As Integer = CInt(Me.txtPorcentaje.Value)
imgWidth = CInt(pic.Image.Width * (porciento / 100))
imgHeight = CInt(pic.Image.Height * (porciento / 100))
Else
' Si la imagen original está en vertical,
' cambiar los valores
If pic.Image.Height > pic.Image.Width Then
imgHeight = CInt(Me.txtWidth.Text)
imgWidth = CInt(Me.txtHeight.Text)
Else
imgWidth = CInt(Me.txtWidth.Text)
imgHeight = CInt(Me.txtHeight.Text)
End If
End If
Una vez que hemos calculado el tamaño y posteriormente
generado el thumbnail, solo queda guardar la imagen. Esto lo hago
averiguando la extensión (tipo de fichero) original, ya que si no se indica
el tipo de imagen, el método Save de la clase Image lo guarda
como PNG aunque la extensión sea diferente.
Este es el código que comprueba la extensión original y llama al método
Save:
' Guardar la nueva imagen
' (si no se indica el formato, se guardará como PNG)
'img.Save(ficNue)
' Usar el mismo tipo que la original (20/Mar/07)
Select Case Path.GetExtension(ficNue).ToLower()
Case ".jpg", ".jpeg"
img.Save(ficNue, Imaging.ImageFormat.Jpeg)
Case ".gif"
img.Save(ficNue, Imaging.ImageFormat.Gif)
Case ".png"
img.Save(ficNue, Imaging.ImageFormat.Png)
Case ".bmp"
img.Save(ficNue, Imaging.ImageFormat.Bmp)
Case ".tif"
img.Save(ficNue, Imaging.ImageFormat.Tiff)
Case Else
img.Save(ficNue)
End Select
Un objeto My para C# (o casi)
Esta utilidad usa valores de configuración, que en Visual
Basic 2005 se usa por medio de My.Settings, y en C# como no existe el objeto
My, pues me he creado una clase para que me resulte más fácil hacer la
conversión de Visual Basic a C#. El código de esa clase es muy simple, ya
que lo único que hace falta es tener una propiedad de solo lectura que
devuelva un objeto del tipo apropiado, es decir, del tipo
Properties.Settings que el propio C# define al añadir propiedades al
proyecto:
static class My
public static Properties.Settings Settings
{
get
{
return Properties.Settings.Default;
}
}
}
Y esto es casi todo... el resto del código lo puedes ver
más abajo. Sí, sí, también está el código de C#,
que aunque yo prefiera usar el Visual Basic no me olvido de los que os gusta
escribir puntos y comas, je, je... (un día de estos
cualquiera se va a enfadar y...)
Espero que te sea de utilidad.
Nos vemos.
Guillermo
Abajo del todo tienes el ZIP con el código fuente para la versión
2005 de Visual Basic y Visual C#
El
código para Visual Basic
|
'------------------------------------------------------------------------------
' Convertir las imágenes seleccionadas en pequeñas (Thumbnail) (19/Mar/07)
'
' ©Guillermo 'guille' Som, 2007
'------------------------------------------------------------------------------
Option Strict On
Imports vb = Microsoft.VisualBasic
Imports System
Imports System.Windows.Forms
Imports System.Drawing
Imports System.IO
Public Class fImageThumb
' Las variables usadas a nivel del formulario
Private procesarAuto As Boolean
Private errores As Integer
Private ficNue As String
Private ficOri As String
Private nActual As Integer
'
'--------------------------------------------------------------------------
' Los métodos que no son de eventos
' se ve que no me gusta usar #Region...
'--------------------------------------------------------------------------
'
Private Function ficPeq(ByVal ficOri As String) As String
' Genera el nombre del fichero pequeño.
Dim p As String = Path.GetDirectoryName(ficOri)
If p.EndsWith(Path.DirectorySeparatorChar) = False Then
p = p & Path.DirectorySeparatorChar
End If
p = p & Path.GetFileNameWithoutExtension(ficOri) & "_peq" & _
Path.GetExtension(ficOri)
Return p
End Function
' Para usar como delegado del método GetThumbnailImage
' (devolver siempre False ya que True significa que se cancela)
Private Function getThumbnailImageAbort() As Boolean
Return False
End Function
' Guardar el thumbnail
' Este método se llamará tanto desde el botón guardar
' como desde el evento Loadcomplete del control Picture
Private Sub guardarImagen()
btnGuardarImagen.Enabled = False
btnGuardarImagen.Refresh()
progressConv.Value = nActual + 1
'
' Si existe el destino, eliminarlo
If System.IO.File.Exists(ficNue) Then
' Si da error, seguir con el siguiente
Try
System.IO.File.Delete(ficNue)
Catch ex As Exception
errores += 1
End Try
End If
' Guardar la imagen usando uno de los formatos soportados
Try
Dim img As Image
Dim imgWidth As Integer
Dim imgHeight As Integer
If Me.optPorcentaje.Checked Then
' Usar el tamaño indicado por el porcentaje
Dim porciento As Integer = CInt(Me.txtPorcentaje.Value)
imgWidth = CInt(pic.Image.Width * (porciento / 100))
imgHeight = CInt(pic.Image.Height * (porciento / 100))
Else
' Si la imagen original está en vertical,
' cambiar los valores
If pic.Image.Height > pic.Image.Width Then
imgHeight = CInt(Me.txtWidth.Text)
imgWidth = CInt(Me.txtHeight.Text)
Else
imgWidth = CInt(Me.txtWidth.Text)
imgHeight = CInt(Me.txtHeight.Text)
End If
End If
' Crear un thumbnail con el método GetThumbnailImage
' Esto usará el thumbnail que tenga la imagen
' o creará uno si no la tiene.
img = pic.Image.GetThumbnailImage(imgWidth, imgHeight, _
AddressOf getThumbnailImageAbort, IntPtr.Zero)
'
' Guardar la nueva imagen
' (si no se indica el formato, se guardará como PNG)
'img.Save(ficNue)
' Usar el mismo tipo que la original (20/Mar/07)
Select Case Path.GetExtension(ficNue).ToLower()
Case ".jpg", ".jpeg"
img.Save(ficNue, Imaging.ImageFormat.Jpeg)
Case ".gif"
img.Save(ficNue, Imaging.ImageFormat.Gif)
Case ".png"
img.Save(ficNue, Imaging.ImageFormat.Png)
Case ".bmp"
img.Save(ficNue, Imaging.ImageFormat.Bmp)
Case ".tif"
img.Save(ficNue, Imaging.ImageFormat.Tiff)
Case Else
img.Save(ficNue)
End Select
'
Catch ex As Exception
errores += 1
'MessageBox.Show(ex.Message)
End Try
'
' Marcarlo para saber que está convertido
lvImagenes.Items(nActual).Checked = True
Dim sb As New System.Text.StringBuilder
If nActual = 0 Then
sb.Append("Procesada 1 imagen")
Else
sb.AppendFormat("Procesadas {0} imágenes", nActual + 1)
End If
If errores > 0 Then
If errores = 1 Then
sb.Append(" con 1 error.")
Else
sb.AppendFormat(" con {0} errores.", errores)
End If
Else
sb.Append(".")
End If
LabelStatus.Text = sb.ToString()
statusStrip1.Refresh()
'
' Incrementar el número del fichero procesado
incrementarActual()
'
End Sub
Private Sub incrementarActual()
' Incrementar el número del fichero procesado
nActual += 1
' y comprobar si ya los hemos procesado todos.
If nActual >= lvImagenes.Items.Count Then
btnGuardarImagen.Enabled = False
lvImagenes.Enabled = True
progressConv.Visible = False
lvImagenes.CheckBoxes = False
mnuSeleccionarImagenes.Enabled = True
btnExaminar.Enabled = True
Me.btnExaminarDir.Enabled = True
Me.mnuSeleccionarDir.Enabled = True
'
procesarAuto = False
Else
' Preparar la imagen para el siguiente fichero
ficOri = lvImagenes.Items(nActual).Text
' Comprobar que no sea nulo y que exista (19/Mar/07)
If String.IsNullOrEmpty(ficOri) Then
incrementarActual()
Exit Sub
Else
If File.Exists(ficOri) = False Then
incrementarActual()
Exit Sub
End If
End If
ficNue = ficPeq(ficOri)
LabelFic.Text = System.IO.Path.GetFileName(ficNue)
LabelFic.Refresh()
If procesarAuto Then
pic.LoadAsync(ficOri)
Else
pic.ImageLocation = ficOri
End If
'
' Por si hay muchos elementos, para que se muestre el actual.
lvImagenes.TopItem = lvImagenes.Items(nActual)
'
If procesarAuto = False Then
btnGuardarImagen.Enabled = True
LabelStatus.Text = "Pulsa en 'Guardar imagen' para procesar el fichero."
Else
LabelStatus.Text = "Guardando " & Path.GetFileName(ficNue) & "..."
End If
statusStrip1.Refresh()
End If
End Sub
'
'--------------------------------------------------------------------------
' Los métodos de evento de los controles del formulario
'--------------------------------------------------------------------------
'
Private Sub btnExaminar_Click(ByVal sender As Object, ByVal e As EventArgs) _
Handles btnExaminar.Click, mnuSeleccionarImagenes.Click
Dim oFD As New OpenFileDialog
With oFD
.AddExtension = True
.Multiselect = True
.Title = "Selecciona uno o más ficheros a convertir"
.Filter = "Imágenes soportadas|*.jpg;*.jpeg;*.png;*.gif;*.tif;*.bmp;*.ico|" & _
"Imagen JPG - JPEG|*.jpg|PNG - Portable Network Graphics|*.png|" & _
"GIF - Graphics Interchange Format|*.gif|Todos (*.*)|*.*"
If .ShowDialog = Windows.Forms.DialogResult.OK Then
For Each s As String In .FileNames
lvImagenes.Items.Add(s)
Next
End If
btnProcesar.Enabled = (Me.lvImagenes.Items.Count > 0)
End With
End Sub
Private Sub btnExaminarDir_Click(ByVal sender As Object, ByVal e As EventArgs) _
Handles btnExaminarDir.Click, mnuSeleccionarDir.Click
' Seleccionar todas las imágenes del directorio indicado
' NO se tienen en cuenta las que contengan _peq. en el nombre.
Dim fb As New FolderBrowserDialog
With fb
If String.IsNullOrEmpty(My.Settings.UltimoDir) = False Then
.SelectedPath = My.Settings.UltimoDir
End If
.RootFolder = Environment.SpecialFolder.Desktop
.Description = "Selecciona el directorio con las imágenes " & _
"(solo se procesará los tipos .jpg, .png y .gif)"
If .ShowDialog = Windows.Forms.DialogResult.OK Then
' Seleccionar los ficheros del directorio indicado
Dim p As String = .SelectedPath
My.Settings.UltimoDir = .SelectedPath
Dim i As Integer = 0
Me.LabelStatus.Text = "Obteniendo las imágenes de " & _
Path.GetDirectoryName(p) & "..."
Me.statusStrip1.Refresh()
For Each s As String In Directory.GetFiles(p)
Dim ext As String = Path.GetExtension(s).ToLower()
If ".jpg .gif .png".IndexOf(ext) > -1 Then
' No añadir las que contengan _peq.
If s.IndexOf("_peq.") = -1 Then
i += 1
Me.lvImagenes.Items.Add(s)
End If
End If
Next
If i = 1 Then
Me.LabelStatus.Text = "Se ha añadido 1 imagen."
ElseIf i = 0 Then
Me.LabelStatus.Text = "No había imágenes de los formatos soportados."
Else
Me.LabelStatus.Text = "Se han añadido " & i & " imágenes."
End If
Me.statusStrip1.Refresh()
btnProcesar.Enabled = (Me.lvImagenes.Items.Count > 0)
End If
End With
End Sub
Private Sub btnGuardarImagen_Click(ByVal sender As Object, ByVal e As EventArgs) _
Handles btnGuardarImagen.Click
guardarImagen()
End Sub
Private Sub btnProcesar_Click(ByVal sender As Object, ByVal e As EventArgs) _
Handles btnProcesar.Click
' Comprobar si los valores del tamaño son correctos
Dim bCorrecto As Boolean = True
If Me.optPorcentaje.Checked = False Then
If vb.IsNumeric(Me.txtWidth.Text) = False _
OrElse vb.IsNumeric(Me.txtHeight.Text) = False Then
bCorrecto = False
Else
Dim imgWidth As Integer = CInt(Me.txtWidth.Text)
Dim imgHeight As Integer = CInt(Me.txtHeight.Text)
If imgWidth < 50 OrElse imgHeight < 50 Then
bCorrecto = False
End If
End If
End If
If bCorrecto = False Then
MessageBox.Show( _
"Debes indicar unos valores correctos para el tamaño," & vb.vbCrLf & _
"en tamaño fijo, el mínimo es de 50x50 y en porcentaje es de " & _
Me.txtPorcentaje.Minimum & " a " & Me.txtPorcentaje.Maximum, _
"Procesar", _
MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
Exit Sub
End If
'
nActual = 0
errores = 0
btnGuardarImagen.Enabled = False
'
If lvImagenes.Items.Count < 1 Then
progressConv.Visible = False
LabelStatus.Text = " No hay nada que procesar."
statusStrip1.Refresh()
MessageBox.Show( _
"Debes seleccionar alguna imagen para crear el thumbnail.", _
"Procesar", _
MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
Exit Sub
Else
mnuSeleccionarImagenes.Enabled = False
btnExaminar.Enabled = False
Me.btnExaminarDir.Enabled = False
Me.mnuSeleccionarDir.Enabled = False
'
progressConv.Maximum = lvImagenes.Items.Count
progressConv.Minimum = 0
progressConv.Step = 1
progressConv.Value = 0
progressConv.Visible = True
ficOri = lvImagenes.Items(nActual).Text
ficNue = ficPeq(ficOri)
LabelFic.Text = System.IO.Path.GetFileName(ficNue)
LabelFic.Refresh()
'
procesarAuto = chkAutomatico.Checked
'
If procesarAuto Then
pic.WaitOnLoad = False
pic.LoadAsync(ficOri)
Else
pic.WaitOnLoad = True
pic.ImageLocation = ficOri
End If
lvImagenes.Enabled = False
lvImagenes.CheckBoxes = True
End If
If procesarAuto = False Then
btnGuardarImagen.Enabled = True
LabelStatus.Text = "Pulsa en 'Guardar imagen' para procesar el fichero."
Else
LabelStatus.Text = "Las imágenes se irán guardando automáticamente..."
End If
statusStrip1.Refresh()
End Sub
Private Sub fImageThumb_FormClosing(ByVal sender As Object, ByVal e As FormClosingEventArgs) _
Handles Me.FormClosing
' El restoreBounds solo si lo hemos minimizado o cambiado de tamaño
If Me.WindowState = FormWindowState.Normal Then
My.Settings.CambiarLeft = Me.Left
My.Settings.CambiarTop = Me.Top
My.Settings.CambiarHeight = Me.Height
My.Settings.CambiarWidth = Me.Width
Else
My.Settings.CambiarLeft = Me.RestoreBounds.Left
My.Settings.CambiarTop = Me.RestoreBounds.Top
My.Settings.CambiarHeight = Me.RestoreBounds.Height
My.Settings.CambiarWidth = Me.RestoreBounds.Width
End If
'
My.Settings.PorcentajeUsar = Me.optPorcentaje.Checked
My.Settings.Porcentaje = CInt(Me.txtPorcentaje.Value)
My.Settings.tamHeight = CInt(Me.txtHeight.Text)
My.Settings.tamWidth = CInt(Me.txtWidth.Text)
My.Settings.CambiarAuto = Me.chkAutomatico.Checked
'
My.Settings.Save()
End Sub
Private Sub fImageThumb_Load(ByVal sender As Object, ByVal e As EventArgs) _
Handles MyBase.Load
Me.Location = New Point(0, 0)
If My.Settings.CambiarLeft > -1 Then
Me.Left = My.Settings.CambiarLeft
End If
If My.Settings.CambiarTop > -1 Then
Me.Top = My.Settings.CambiarTop
End If
If My.Settings.CambiarHeight > -1 Then
Me.Height = My.Settings.CambiarHeight
End If
If My.Settings.CambiarWidth > -1 Then
Me.Width = My.Settings.CambiarWidth
End If
'
Me.optPorcentaje.Checked = My.Settings.PorcentajeUsar
Me.optFijo.Checked = Not Me.optPorcentaje.Checked
Me.txtPorcentaje.Value = My.Settings.Porcentaje
Me.txtHeight.Text = My.Settings.tamHeight.ToString
Me.txtWidth.Text = My.Settings.tamWidth.ToString
Me.chkAutomatico.Checked = My.Settings.CambiarAuto
'
btnGuardarImagen.Enabled = False
btnProcesar.Enabled = False
lvImagenes.CheckBoxes = False
LabelFic.Text = ""
LableNumFics.Text = ""
progressConv.Visible = False
LableNumFics.BorderSides = ToolStripStatusLabelBorderSides.Right
End Sub
Private Sub fImageThumb_Resize(ByVal sender As Object, ByVal e As EventArgs) _
Handles MyBase.Resize, lvImagenes.Resize
If Me.WindowState <> FormWindowState.Minimized Then
' Ajustar el ancho de la columna del ListView al tamaño del control.
lvImagenes.Columns(0).Width = lvImagenes.ClientRectangle.Width
End If
End Sub
Private Sub lvImagenes_DoubleClick(ByVal sender As Object, ByVal e As EventArgs) _
Handles lvImagenes.DoubleClick
' Mostrar la imagen seleccionada (22/Ene/07)
If lvImagenes.SelectedItems.Count > 0 Then
LabelFic.Text = Path.GetFileName(lvImagenes.SelectedItems(0).Text)
pic.Load(lvImagenes.SelectedItems(0).Text)
End If
End Sub
Private Sub lvImagenes_DragDrop(ByVal sender As Object, ByVal e As DragEventArgs) _
Handles lvImagenes.DragDrop, MyBase.DragDrop
' Drag & Drop, comprobar con DataFormat
If e.Data.GetDataPresent(DataFormats.FileDrop) Then
Dim fics() As String = CType(e.Data.GetData(DataFormats.FileDrop, True), String())
For Each s As String In fics
lvImagenes.Items.Add(s)
Next
btnProcesar.Enabled = True
End If
End Sub
'
''' <summary>
''' Permitir indicar los ficheros a convertir usando drag & drop.
''' </summary>
''' <param name="sender"></param>
''' <param name="e"></param>
''' <remarks>Los ficheros soltados se agregarán a la lista.</remarks>
Private Sub lvImagenes_DragEnter(ByVal sender As Object, ByVal e As DragEventArgs) _
Handles lvImagenes.DragEnter, MyBase.DragEnter
' Comprobar el formato con DataFormat
If e.Data.GetDataPresent(DataFormats.FileDrop) Then
e.Effect = DragDropEffects.Copy
End If
End Sub
Private Sub lvImagenes_KeyUp(ByVal sender As Object, ByVal e As KeyEventArgs) _
Handles lvImagenes.KeyUp
' Eliminar los elementos seleccionados del ListView
Try
If e.KeyCode = Keys.Delete Then
If lvImagenes.SelectedIndices.Count > 0 Then
For i As Integer = lvImagenes.SelectedIndices.Count - 1 To 0 Step -1
lvImagenes.Items.RemoveAt(lvImagenes.SelectedIndices.Item(i))
Next
' Botón procesar se habilitará solo si hay ficheros que convertir
btnProcesar.Enabled = (lvImagenes.Items.Count > 0)
End If
End If
Catch 'ex As Exception
End Try
End Sub
Private Sub pic_LoadCompleted(ByVal sender As Object, _
ByVal e As System.ComponentModel.AsyncCompletedEventArgs) _
Handles pic.LoadCompleted
' Se produce cuando la imagen se ha cargado completamente
' Hay que asignar un valor True a WaitOnLoad
If procesarAuto Then
guardarImagen()
End If
End Sub
Private Sub mnuCerrar_Click(ByVal sender As Object, ByVal e As EventArgs) _
Handles mnuCerrar.Click
Me.Close()
End Sub
Private Sub mnuMaximizar_Click(ByVal sender As Object, ByVal e As EventArgs) _
Handles mnuMaximizar.Click
If Me.WindowState = FormWindowState.Maximized Then
Me.WindowState = FormWindowState.Normal
Me.mnuMaximizar.Text = "Maximizar"
Else
Me.WindowState = FormWindowState.Maximized
Me.mnuMaximizar.Text = "Restaurar"
End If
End Sub
Private Sub mnuMinimizar_Click(ByVal sender As Object, ByVal e As EventArgs) _
Handles mnuMinimizar.Click
Me.WindowState = FormWindowState.Minimized
End Sub
Private Sub optPorcentaje_CheckedChanged(ByVal sender As Object, ByVal e As EventArgs) _
Handles optPorcentaje.CheckedChanged
If Me.optPorcentaje.Checked Then
Me.txtPorcentaje.Enabled = True
Me.txtHeight.Enabled = False
Me.txtWidth.Enabled = False
Else
Me.txtPorcentaje.Enabled = False
Me.txtHeight.Enabled = True
Me.txtWidth.Enabled = True
End If
End Sub
Private Sub mnuBorrarTodas_Click(ByVal sender As Object, ByVal e As EventArgs) _
Handles mnuBorrarTodas.Click
Me.lvImagenes.Items.Clear()
Me.btnProcesar.Enabled = False
End Sub
End Class
|
El código para
Visual C#
|
//-----------------------------------------------------------------------------
// Convertir las imágenes seleccionadas en pequeñas (Thumbnail) (20/Mar/07)
//
// ©Guillermo 'guille' Som, 2007
//-----------------------------------------------------------------------------
using System;
using System.Windows.Forms;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
namespace gsImageThumb_cs
{
public partial class fImageThumb : Form
{
public fImageThumb()
{
InitializeComponent();
}
// Las variables usadas a nivel del formulario
private bool procesarAuto;
private int errores;
private string ficNue;
private string ficOri;
private int nActual;
//
//--------------------------------------------------------------------------
// Los métodos que no son de eventos
// se ve que no me gusta usar #Region...
//--------------------------------------------------------------------------
//
private string ficPeq(string ficOri)
{
// Genera el nombre del fichero pequeño.
string p = Path.GetDirectoryName(ficOri);
if (p.EndsWith(Path.DirectorySeparatorChar.ToString()) == false)
{
p = p + Path.DirectorySeparatorChar;
}
p = p + Path.GetFileNameWithoutExtension(ficOri) + "_peq" +
Path.GetExtension(ficOri);
return p;
}
// Para usar como delegado del método GetThumbnailImage
// (devolver siempre False ya que True significa que se cancela)
private bool getThumbnailImageAbort()
{
return false;
}
// Guardar el thumbnail
// Este método se llamará tanto desde el botón guardar
// como desde el evento Loadcomplete del control Picture
private void guardarImagen()
{
btnGuardarImagen.Enabled = false;
btnGuardarImagen.Refresh();
progressConv.Value = nActual + 1;
//
// Si existe el destino, eliminarlo
if (File.Exists(ficNue))
{
// Si da error, seguir con el siguiente
try
{
File.Delete(ficNue);
}
catch (Exception ex)
{
errores += 1;
}
}
// Guardar la imagen usando uno de los formatos soportados
try
{
Image img;
int imgWidth;
int imgHeight;
if (this.optPorcentaje.Checked)
{
// Usar el tamaño indicado por el porcentaje
int porciento = Convert.ToInt32(this.txtPorcentaje.Value);
imgWidth = Convert.ToInt32(pic.Image.Width * (porciento / 100.0));
imgHeight = Convert.ToInt32(pic.Image.Height * (porciento / 100.0));
}
else
{
// Si la imagen original está en vertical,
// cambiar los valores
if (pic.Image.Height > pic.Image.Width)
{
imgHeight = Convert.ToInt32(this.txtWidth.Text);
imgWidth = Convert.ToInt32(this.txtHeight.Text);
}
else
{
imgWidth = Convert.ToInt32(this.txtWidth.Text);
imgHeight = Convert.ToInt32(this.txtHeight.Text);
}
}
// Crear un thumbnail con el método GetThumbnailImage
// Esto usará el thumbnail que tenga la imagen
// o creará uno si no la tiene.
img = pic.Image.GetThumbnailImage(imgWidth, imgHeight,
getThumbnailImageAbort, IntPtr.Zero);
//// Usando el delegado directamente:
//img = pic.Image.GetThumbnailImage(imgWidth, imgHeight,
// delegate { return false; }, IntPtr.Zero);
//
// Guardar la nueva imagen
// (si no se indica el formato, se guardará como PNG)
//img.Save(ficNue)
// Usar el mismo tipo que la original (20/Mar/07)
switch (Path.GetExtension(ficNue).ToLower())
{
case ".jpg":
case ".jpeg":
img.Save(ficNue, ImageFormat.Jpeg);
break;
case ".gif":
img.Save(ficNue, ImageFormat.Gif);
break;
case ".png":
img.Save(ficNue, ImageFormat.Png);
break;
case ".bmp":
img.Save(ficNue, ImageFormat.Bmp);
break;
case ".tif":
img.Save(ficNue, ImageFormat.Tiff);
break;
default:
img.Save(ficNue);
break;
}
//
}
catch (Exception ex)
{
errores += 1;
}
//
// Marcarlo para saber que está convertido
lvImagenes.Items[nActual].Checked = true;
System.Text.StringBuilder sb = new System.Text.StringBuilder();
if (nActual == 0)
{
sb.Append("Procesada 1 imagen");
}
else
{
sb.AppendFormat("Procesadas {0} imágenes", nActual + 1);
}
if (errores > 0)
{
if (errores == 1)
{
sb.Append(" con 1 error.");
}
else
{
sb.AppendFormat(" con {0} errores.", errores);
}
}
else
{
sb.Append(".");
}
LabelStatus.Text = sb.ToString();
statusStrip1.Refresh();
//
// Incrementar el número del fichero procesado
incrementarActual();
//
}
private void incrementarActual()
{
// Incrementar el número del fichero procesado
nActual += 1;
// y comprobar si ya los hemos procesado todos.
if (nActual >= lvImagenes.Items.Count)
{
btnGuardarImagen.Enabled = false;
lvImagenes.Enabled = true;
progressConv.Visible = false;
lvImagenes.CheckBoxes = false;
mnuSeleccionarImagenes.Enabled = true;
btnExaminar.Enabled = true;
this.btnExaminarDir.Enabled = true;
this.mnuSeleccionarDir.Enabled = true;
//
procesarAuto = false;
}
else
{
// Preparar la imagen para el siguiente fichero
ficOri = lvImagenes.Items[nActual].Text;
// Comprobar que no sea nulo y que exista (19/Mar/07)
if (String.IsNullOrEmpty(ficOri))
{
incrementarActual();
return;
}
else
{
if (File.Exists(ficOri) == false)
{
incrementarActual();
return;
}
}
ficNue = ficPeq(ficOri);
LabelFic.Text = Path.GetFileName(ficNue);
LabelFic.Refresh();
if (procesarAuto)
{
pic.LoadAsync(ficOri);
}
else
{
pic.ImageLocation = ficOri;
}
//
// Por si hay muchos elementos, para que se muestre el actual.
lvImagenes.TopItem = lvImagenes.Items[nActual];
//
if (procesarAuto == false)
{
btnGuardarImagen.Enabled = true;
LabelStatus.Text = "Pulsa en 'Guardar imagen' para procesar el fichero.";
}
else
{
LabelStatus.Text = "Guardando " + Path.GetFileName(ficNue) + "...";
}
statusStrip1.Refresh();
}
}
//
//--------------------------------------------------------------------------
// Los métodos de evento de los controles del formulario
//--------------------------------------------------------------------------
//
private void btnExaminar_Click(object sender, EventArgs e)
{
OpenFileDialog oFD = new OpenFileDialog();
oFD.AddExtension = true;
oFD.Multiselect = true;
oFD.Title = "Selecciona uno o más ficheros a convertir";
oFD.Filter = "Imágenes soportadas|*.jpg;*.jpeg;*.png;*.gif;*.tif;*.bmp;*.ico" +
"|Imagen JPG - JPEG|*.jpg|PNG - Portable Network Graphics|*.png|" +
"GIF - Graphics Interchange Format|*.gif|Todos (*.*)|*.*";
if (oFD.ShowDialog() == DialogResult.OK)
{
foreach (string s in oFD.FileNames)
{
lvImagenes.Items.Add(s);
}
}
btnProcesar.Enabled = (this.lvImagenes.Items.Count > 0);
}
private void btnExaminarDir_Click(object sender, EventArgs e)
{
// Seleccionar todas las imágenes del directorio indicado
// NO se tienen en cuenta las que contengan _peq. en el nombre.
FolderBrowserDialog fb = new FolderBrowserDialog();
if (String.IsNullOrEmpty(My.Settings.UltimoDir) == false)
{
fb.SelectedPath = My.Settings.UltimoDir;
}
fb.RootFolder = Environment.SpecialFolder.Desktop;
fb.Description = "Selecciona el directorio con las imágenes " +
"(solo se procesará los tipos .jpg, .png y .gif)";
if (fb.ShowDialog() == DialogResult.OK)
{
// Seleccionar los ficheros del directorio indicado
string p = fb.SelectedPath;
My.Settings.UltimoDir = fb.SelectedPath;
int i = 0;
this.LabelStatus.Text = "Obteniendo las imágenes de " +
Path.GetDirectoryName(p) + "...";
this.statusStrip1.Refresh();
foreach (string s in Directory.GetFiles(p))
{
string ext = Path.GetExtension(s).ToLower();
if (".jpg .gif .png".IndexOf(ext) > -1)
{
// No añadir las que contengan _peq.
if (s.IndexOf("_peq.") == -1)
{
i += 1;
this.lvImagenes.Items.Add(s);
}
}
}
if (i == 1)
{
this.LabelStatus.Text = "Se ha añadido 1 imagen.";
}
else if (i == 0)
{
this.LabelStatus.Text = "No había imágenes de los formatos soportados.";
}
else
{
this.LabelStatus.Text = "Se han añadido " + i + " imágenes.";
}
this.statusStrip1.Refresh();
btnProcesar.Enabled = (this.lvImagenes.Items.Count > 0);
}
}
private void btnGuardarImagen_Click(object sender, EventArgs e)
{
guardarImagen();
}
private void btnProcesar_Click(object sender, EventArgs e)
{
// Comprobar si los valores del tamaño son correctos
bool bCorrecto = true;
if (this.optPorcentaje.Checked == false)
{
try
{
int imgWidth = Convert.ToInt32(this.txtWidth.Text);
int imgHeight = Convert.ToInt32(this.txtHeight.Text);
if (imgWidth < 50 || imgHeight < 50)
{
bCorrecto = false;
}
}
catch
{
bCorrecto = false;
}
}
if (bCorrecto == false)
{
MessageBox.Show("Debes indicar unos valores correctos para el tamaño,\n" +
"en tamaño fijo, el mínimo es de 50x50 y en porcentaje es de " +
this.txtPorcentaje.Minimum + " a " + this.txtPorcentaje.Maximum,
"Procesar", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
return;
}
//
nActual = 0;
errores = 0;
btnGuardarImagen.Enabled = false;
//
if (lvImagenes.Items.Count < 1)
{
progressConv.Visible = false;
LabelStatus.Text = " No hay nada que procesar.";
statusStrip1.Refresh();
MessageBox.Show("Debes seleccionar alguna imagen para crear el thumbnail.",
"Procesar",
MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
return;
}
else
{
mnuSeleccionarImagenes.Enabled = false;
btnExaminar.Enabled = false;
this.btnExaminarDir.Enabled = false;
this.mnuSeleccionarDir.Enabled = false;
//
progressConv.Maximum = lvImagenes.Items.Count;
progressConv.Minimum = 0;
progressConv.Step = 1;
progressConv.Value = 0;
progressConv.Visible = true;
ficOri = lvImagenes.Items[nActual].Text;
ficNue = ficPeq(ficOri);
LabelFic.Text = System.IO.Path.GetFileName(ficNue);
LabelFic.Refresh();
//
procesarAuto = chkAutomatico.Checked;
//
if (procesarAuto)
{
pic.WaitOnLoad = false;
pic.LoadAsync(ficOri);
}
else
{
pic.WaitOnLoad = true;
pic.ImageLocation = ficOri;
}
lvImagenes.Enabled = false;
lvImagenes.CheckBoxes = true;
}
if (procesarAuto == false)
{
btnGuardarImagen.Enabled = true;
LabelStatus.Text = "Pulsa en 'Guardar imagen' para procesar el fichero.";
}
else
{
LabelStatus.Text = "Las imágenes se irán guardando automáticamente...";
}
statusStrip1.Refresh();
}
private void fImageThumb_FormClosing(object sender, FormClosingEventArgs e)
{
// El restoreBounds solo si lo hemos minimizado o cambiado de tamaño
if (this.WindowState == FormWindowState.Normal)
{
My.Settings.CambiarLeft = this.Left;
My.Settings.CambiarTop = this.Top;
My.Settings.CambiarHeight = this.Height;
My.Settings.CambiarWidth = this.Width;
}
else
{
My.Settings.CambiarLeft = this.RestoreBounds.Left;
My.Settings.CambiarTop = this.RestoreBounds.Top;
My.Settings.CambiarHeight = this.RestoreBounds.Height;
My.Settings.CambiarWidth = this.RestoreBounds.Width;
}
//
My.Settings.PorcentajeUsar = this.optPorcentaje.Checked;
My.Settings.Porcentaje = Convert.ToInt32(this.txtPorcentaje.Value);
My.Settings.tamHeight = Convert.ToInt32(this.txtHeight.Text);
My.Settings.tamWidth = Convert.ToInt32(this.txtWidth.Text);
My.Settings.CambiarAuto = this.chkAutomatico.Checked;
//
My.Settings.Save();
}
private void fImageThumb_Load(object sender, EventArgs e)
{
this.Location = new Point(0, 0);
if (My.Settings.CambiarLeft > -1)
{
this.Left = My.Settings.CambiarLeft;
}
if (My.Settings.CambiarTop > -1)
{
this.Top = My.Settings.CambiarTop;
}
if (My.Settings.CambiarHeight > -1)
{
this.Height = My.Settings.CambiarHeight;
}
if (My.Settings.CambiarWidth > -1)
{
this.Width = My.Settings.CambiarWidth;
}
//
this.optPorcentaje.Checked = My.Settings.PorcentajeUsar;
this.optFijo.Checked = !this.optPorcentaje.Checked;
this.txtPorcentaje.Value = My.Settings.Porcentaje;
this.txtHeight.Text = My.Settings.tamHeight.ToString();
this.txtWidth.Text = My.Settings.tamWidth.ToString();
this.chkAutomatico.Checked = My.Settings.CambiarAuto;
//
btnGuardarImagen.Enabled = false;
btnProcesar.Enabled = false;
lvImagenes.CheckBoxes = false;
LabelFic.Text = "";
LableNumFics.Text = "";
progressConv.Visible = false;
LableNumFics.BorderSides = ToolStripStatusLabelBorderSides.Right;
}
private void fImageThumb_Resize(object sender, EventArgs e)
{
if (this.WindowState != FormWindowState.Minimized)
{
// Ajustar el ancho de la columna del ListView al tamaño del control.
lvImagenes.Columns[0].Width = lvImagenes.ClientRectangle.Width;
}
}
private void lvImagenes_DoubleClick(object sender, EventArgs e)
{
// Mostrar la imagen seleccionada (22/Ene/07)
if (lvImagenes.SelectedItems.Count > 0)
{
LabelFic.Text = Path.GetFileName(lvImagenes.SelectedItems[0].Text);
pic.Load(lvImagenes.SelectedItems[0].Text);
}
}
private void lvImagenes_DragDrop(object sender, DragEventArgs e)
{
// Drag & Drop, comprobar con DataFormat
if (e.Data.GetDataPresent(DataFormats.FileDrop))
{
string[] fics = ((String[])e.Data.GetData(DataFormats.FileDrop, true));
foreach (string s in fics)
{
lvImagenes.Items.Add(s);
}
btnProcesar.Enabled = true;
}
}
//
/// <summary>
/// Permitir indicar los ficheros a convertir usando drag & drop.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
/// <remarks>Los ficheros soltados se agregarán a la lista.</remarks>
private void lvImagenes_DragEnter(object sender, DragEventArgs e)
{
// Comprobar el formato con DataFormat
if (e.Data.GetDataPresent(DataFormats.FileDrop))
{
e.Effect = DragDropEffects.Copy;
}
}
private void lvImagenes_KeyUp(object sender, KeyEventArgs e)
{
// Eliminar los elementos seleccionados del ListView
try
{
if (e.KeyCode == Keys.Delete)
{
if (lvImagenes.SelectedIndices.Count > 0)
{
for (int i = lvImagenes.SelectedIndices.Count - 1; i >= 0; i--)
{
lvImagenes.Items.RemoveAt(lvImagenes.SelectedIndices[i]);
}
// Botón procesar se habilitará solo si hay ficheros que convertir
btnProcesar.Enabled = (lvImagenes.Items.Count > 0);
}
}
}
catch
{ //ex As Exception
}
}
private void pic_LoadCompleted(object sender,
System.ComponentModel.AsyncCompletedEventArgs e)
{
// Se produce cuando la imagen se ha cargado completamente
// Hay que asignar un valor True a WaitOnLoad
if (procesarAuto)
{
guardarImagen();
}
}
private void mnuCerrar_Click(object sender, EventArgs e)
{
this.Close();
}
private void mnuMaximizar_Click(object sender, EventArgs e)
{
if (this.WindowState == FormWindowState.Maximized)
{
this.WindowState = FormWindowState.Normal;
this.mnuMaximizar.Text = "Maximizar";
}
else
{
this.WindowState = FormWindowState.Maximized;
this.mnuMaximizar.Text = "Restaurar";
}
}
private void mnuMinimizar_Click(object sender, EventArgs e)
{
this.WindowState = FormWindowState.Minimized;
}
private void optPorcentaje_CheckedChanged(object sender, EventArgs e)
{
if (this.optPorcentaje.Checked)
{
this.txtPorcentaje.Enabled = true;
this.txtHeight.Enabled = false;
this.txtWidth.Enabled = false;
}
else
{
this.txtPorcentaje.Enabled = false;
this.txtHeight.Enabled = true;
this.txtWidth.Enabled = true;
}
}
private void mnuBorrarTodas_Click(object sender, EventArgs e)
{
this.lvImagenes.Items.Clear();
this.btnProcesar.Enabled = false;
}
}
// Una clase para simular (en parte) el objeto My de Visual Basic 2005
static class My
{
public static Properties.Settings Settings
{
get
{
return Properties.Settings.Default;
}
}
}
|
Espacios de nombres usados en el código de este artículo:
System.Windows.Forms
System.Drawing
System.Drawing.Imaging
System.IO
|