Problema con el tamaño de las imágenes en un informe

Tengo un informe para imprimir un presupuesto, y, en cada uno de las líneas de los conceptos, carga su correspondiente imagen. Hasta ahí, todo correcto y funciona a la perfección.

El problema viene con el tamaño de las imágenes que el usuario sube a la aplicación (base de datos) para que se muestren en el informe de presupuesto. Como esas imágenes son de ventanas, estas pueden ser más grandes o más chicas, y esa proporción debería respetarla en el informe.

He probado con los tipos de tamaño. A saber, zoom, extender y recortar. Este último queda descartado porque no muestra la imagen entera. Los otros dos sacan la imagen exactamente igual.

Os pongo un ejemplo con una captura de un presupuesto:

Como veis, la última imagen (139x117, supongo que píxeles -he cogido el valor del explorador de archivos de W10-), debería ver más chica que la primera (227x355).

No sé si he conseguido explicarme.

¿Hay alguna manera de solucionarlo, aunque sea mediante programación? Si es con esta última opción, ¿podrías decirme algún ejemplo en el que basarme?

Respuesta
2

El problema, en mi opinión, no es tanto el tamaño de la imagen que cargas en el cuadro como entender qué hace cada opción del "modo de cambiar el tamaño" y el propio tamaño del control imagen. Veráas, segun indica el propio Microsoft (https://docs.microsoft.com/es-es/office/vba/api/Access.Image.SizeMode):

Recortar(Valor predeterminado):Muestra el objeto con su tamaño real. Si el objeto es mayor que el control, su imagen se recorta por la parte derecha y la parte inferior según los bordes del control.

Extender: Cambia el tamaño del objeto para rellenar el control. Este valor puede distorsionar las proporciones del objeto.

Zoom: Muestra todo el contenido del objeto después de cambiar su tamaño para que llene el alto o el ancho del gráfico o del marco de objeto sin distorsionar las proporciones del objeto. Este valor puede dejar espacio extra si se cambia el tamaño del control.

Con una imagen se aprecia mejor. El control imagen es un cuadro de 5 cm de ancho por 4 cm de alto:

Verás que la imagen de 100x90, si la pongo en recortar (abajo a la izquierda), se ve a tamaño real, y queda "espacio" desde la imagen a los bordes. Si la pongo como Zoom (arriba izquierda) se redimensiona manteniendo las proporciones originales) para ocupar el máximo del control imagen, pero aún queda espacio en algún borde, aunque no se aprecie porque el fondo de la imagen también es blanco (en la otra se ve más claro). Si la pongo como Extender, se redimensiona sin mantener las proporciones para ocupar todo el control imagen, lo que hace que la imagen se estire a lo ancho y quede como "achatada".

En la imagen grande (1920x1080), en Zoom, se redimensiona para encajar en el control imagen, pero queda hueco por arriba y abajo. Si la pongo como Extender, se alarga arriba y abajo para ocupar todo el control, lo que hace que se distorsione. En recortar, se muestra a tamaño real, y lógicamente solo se ve un pequeño trozo de la imagen.

Si quieres que las imágenes se vean en distintos tamaños, tu mejor opción es usar Zoom, y además redimensionar los controles de imagen en función del tamaño, o usar Recortar si sabes seguro que las imágenes no van a exceder las dimensiones del control imagen (aquí podrías controlar en la carga de la imagen que no exceda de unas dimensiones concretas) .

Para saber las dimensiones de una imagen lo puedes hacer con LoadFile(), tal que así:

Dim miImagen As Object
Dim Ancho As Long, Alto As Long
Set miImagen = LoadPicture(RutaCompletaImagen)
Ancho = Round(miImagen.Width / 26.4583) 'Sacamos el ancho en píxeles
Alto = Round(miImagen.Height / 26.4583) 'Sacamos el alto en píxeles
MsgBox "Ancho:" & Ancho & " - Alto:" & Alto

En este código solo debes cambiar "RutaCompletaImagen" por la ruta completa al archivo imagen, con su extensión), que supongo que no estarán incrustados en el control imagen, sino "vinculados", y la ruta al archivo la tienes almacenada en algún campo o al menos es conocida.

Sabiendo sacar las dimensiones de la imagen, no deberías tener problema en redimensionar el control de imagen, o limitar la carga de imágenes grandes. Ten en cuenta que las imágenes se miden en pixels, en las propiedades del control de imagen las dimensiones van en centímetros, y en VBA las dimensiones se miden en twips

Hola. Muchas gracias por la magnífica explicación. Dos preguntas:

  1. ¿De dónde sacas el valor 26.4583?
  2. ¿Qué unidad toma miImagen.Height? ¿Twips?

Un saludo.

Así lo he resuelto:

Private Sub Detalle_Format(Cancel As Integer, FormatCount As Integer)
Dim rst As DAO.Recordset
Dim miImagen As Object
Set rst = CurrentDb.OpenRecordset("SELECT Imagen FROM TPresupuestosSubtabla WHERE CodigoPresupuesto = '" & Me.CodigoPresupuesto & "'")
If rst.RecordCount = 0 Then Exit Sub
rst.MoveFirst
Do Until rst.EOF
    With rst
     .Edit
      Set miImagen = LoadPicture(Ruta & "\" & Me.Imagen1)
      Me.ImgImagen.Width = (miImagen.Width * 15) / 26.4583
      Me.ImgImagen.Height = (miImagen.Height * 15) / 26.4583
     .Update
     .MoveNext
     contador = contador + 1
    End With
Loop
rst.Close
Set rst = Nothing
End Sub

Una última cosa. Estoy viendo que, con el código que he pegado antes con el que dije que lo había resuelto, me da problemas con las imágenes en png. ¿Es normal?

Te respondo

¿De dónde sacas el valor 26.4583?

Sinceramente, no lo recuerdo, el código está copiado de un ejemplo que escribí hace varios años (un álbum fotográfico en access). Debe ser la conversión cm - pixels

¿Qué unidad toma miImagen. Height? ¿Twips?

Si no recuerdo mal, centímetros

¿Qué problema te da? En teoría debería funcionar con cualquier tipo de imagen, pero no sé si el LoadPicture tiene alguna limitación de tipo de archivo para cargar...

Y dos últimas preguntas:

  1. Me da error "imagen no válida".
  2. ¿Cómo hago para limitar el tamaño de las imágenes subidas? Estoy buscando por internet pero no encuentro nada. Tengo el siguiente código:
Public Function buscaruta(Optional Presupuesto As Boolean) As String
    Dim fDialog As Office.FileDialog
    Dim puntoCorte As Integer
    Set fDialog = Application.FileDialog(msoFileDialogFilePicker)
    With fDialog
        .AllowMultiSelect = False
        .ButtonName = "Seleccionar"
        .Title = Titulo
        If Dir(Ruta, vbDirectory) = "" Then
            .InitialFileName = Ruta
        Else
            .InitialFileName = Ruta
        End If
        .InitialView = msoFileDialogViewDetails
        .Filters.Clear
        If Presupuesto = True Then
            .Filters.Add "Imagenes", "*.jpg; *.jpeg"
        Else
            .Filters.Add "Imagenes", "*.jpg; *.jpeg ; *.png; *.bmp; *.ico"
        End If
        If .Show = True Then
            If InStr(1, .SelectedItems(1), ".jpeg") Then
                buscaruta = Replace(.SelectedItems(1), ".jpeg", ".jpg")
            Else
                buscaruta = .SelectedItems(1)
            End If
        Else
            MsgBox "Has cancelado la selección de una imagen.", vbInformation, NombreBD
        End If
    End With
    puntoCorte = InStrRev(buscaruta, "\")
    buscaruta = Right(buscaruta, Len(buscaruta) - puntoCorte)
    'Compruebo si el Fichero se ha elegido del directorio de Imágenes por defecto o de otro Directorio
    On Error Resume Next
    Dim vArchivo As String
    vArchivo = buscaruta
    If vArchivo = Ruta & "\" & buscaruta Then
        'No hacemos nada. La Imágen ya estaba en el Directorio adecuado
    Else
        'Copiamos el Fichero elegido en la Carpeta de las Imagenes por defecto >> RutaImagenes
        Dim fso As Scripting.FileSystemObject
        Dim Archivo As Scripting.File
        'Establezco el Objeto
        Set fso = CreateObject("Scripting.FileSystemObject")
        Set Archivo = fso.GetFile(vArchivo)
         'Ahora copio la Imagen a la Carpeta de Imágenes por defecto de la Aplicación
        Archivo.Copy (Ruta & "\" & buscaruta)
    End If
End Function

He encontrado esta información relativa a los png:

https://www.vbforums.com/showthread.php?555084-picture-BOX-LOAD-PNG-PROB 

Por lo visto, VBA no los soporta.

LoadPicture no soporta los png, efectivamente, así que ahí nada puedes hacer...

Para limitar el tamaño yo pensaba en esto (solo te doy la idea, que no es difícil de implementar):

1º/ El usuario elige una imagen (con FileDialog, por lo que veo)

2º/ Una vez elegida, antes de guardarla o lo que hagas con ella,, y si no es png, sacas el ancho y alto en pixels (con el código que te pasé)

3º/ Comparas esos valores con los valores máximos que tu establezcas

4º/ Si son iguales o menores, pues haces lo que venías haciendo con la imagen. Si son mayores, avisas de que excede el límite de ancho/alto de la imagen y cancelas y no guardas la imagen ni haces nada con ella.

Vale, vale. Yo pensaba que existía algún parámetro o algo, por eso te he pasado el código.

Yo estaba pensando en hacer otra cosa. Que el usuario pueda subir la imagen que quiera, pero que, al cargarla en el informe, compare con los valores máximos y mínimos. Si excede, no hace nada, pero si no excede, lo pone en tamaño real con el código que tú me pasaste. De esta manera, el usuario no tiene que quebrarse la cabeza redimensionando imágenes.

Muchas gracias.

Bueno, pues ya está resuelto. Al final el código, que lo dejo por aquí por si a alguien le pudiera servir, es este:

Dim rst As DAO.Recordset
Dim miImagen As Object
    Set rst = CurrentDb.OpenRecordset("SELECT Imagen FROM TPresupuestosSubtabla WHERE CodigoPresupuesto = '" & Me.CodigoPresupuesto & "'")
    If rst.RecordCount = 0 Then Exit Sub
    rst.MoveFirst
    Do Until rst.EOF
        With rst
            .Edit
            If Not IsNull(Me.Imagen1) Then
                Set miImagen = LoadPicture(Ruta & "\" & Me.Imagen1)
                Select Case Round(miImagen.Width / 264583)
                    Case Is < 151
                        Select Case Round(miImagen.Height / 26.4583)
                            Case Is < 189
                                Me.ImgImagen.Width = (miImagen.Width * 15) / 26.4583
                                Me.ImgImagen.Height = (miImagen.Height * 15) / 26.4583
                        End Select
                End Select
            End If
            .Update
            .MoveNext
        End With
    Loop
    rst.Close
    Set rst = Nothing

De esta manera, el usuario no tiene que andar con el paint cambiando o ajustando el tamaño de la imagen. Ahí le establecido yo el ancho y el alto que tiene la imagen en el informe (151x189 en píxeles).

La única putada es que no puedo aplicarle el Application.Echo porque me da muchos parpadeos el formulario al abrir el informe. Pero también es cierto que con el presupuesto que estoy probando, que tiene 8 imágenes, es normal que vaya más lento. Con presupuestos con menos imágenes irá más rápido, supongo.

Muchas gracias por tu inestimable ayuda.

Un saludo.

Acabo de encontrar esto, que dicen soluciona el tema del LoadPicture con png... por si aún te interesa:

https://www.vbforums.com/showthread.php?783321-VBA-LoadPictureGDI-is-displaying-a-black-background-for-PNG-image

1 respuesta más de otro experto

Respuesta
2

Te digo una posible forma para que la explores. El problema radica en ¿cómo sabe el sistema que tamaño debe coger? Al no saber como suben la imagen, sus dimensiones, etc, puedes crear una tabla, más o menos, con unas dimensiones estándar y asignarle un tamaño, en centímetros, como por ejemplo en la tabla

Y en el informe, en el evento Al dar formato de la sección Detalle poner

 Private Sub Detalle_Format(Cancel As Integer, FormatCount As Integer)
Me.ImagenFoto.Height = Tamaño * 567
End Sub

Así cuando abres el informe

No sé si era eso a lo que referías.

Añade tu respuesta

Haz clic para o

Más respuestas relacionadas