Ir a la sección de .NET Utilidades .NET 2.0
 

gsImageThumb

Crear thumbnails (miniaturas) de las imágenes indicadas

 

Publicado el 20/Mar/2007
Actualizado el 20/Mar/2007
Autor: Guillermo 'guille' Som

Utilidad para crear thumbnails (imágenes en miniatura) de las imágenes indicadas.


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
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#

 


Código para Visual Basic.NET (VB.NET)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 &amp; 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

 


Código para C Sharp (C#)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 &amp; 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
 


Código de ejemplo (comprimido):

 

Fichero con el código de ejemplo: gsImageThumb.zip - 68.3 KB

El ZIP incluye tanto el código fuente como el ejecutable, tanto para Visual Basic 2005 como para C# 2005

(MD5 checksum: 2E7AD5B5A45B73F896EA55E4089363EF)

 


Ir al índice principal de el Guille

Valid XHTML 1.0 Transitional ¡CSS Válido!