Almacena imágenes

259 views
Skip to first unread message

Bibiana Cacciaguerra

unread,
Jan 24, 2023, 2:38:38 PM1/24/23
to Comunidad de Visual Foxpro en Español
Buenas tardes.
Cuando un sistema trabaja con gran cantidad de imágenes ¿es aconsejable guardarlas en tablas (en este caso utilizo base Mysql) o es suficiente almacenarlas en una carpeta directamente?
¿Qué ventaja o desventaja tiene para Uds una y otra forma y cuál aconsejan?
En mi opinión, es más sencillo ponerlas en una carpeta pero reconozco que están accesibles para ser vistas y borradas incluso de forma accidental.
Sin embargo, quiero escuchar otras opiniones.

Desde ya, muchas gracias.

Saludos, Bibiana

Francisco Lorente

unread,
Jan 24, 2023, 2:54:15 PM1/24/23
to Comunidad de Visual Foxpro en Español
Hola Bibiana.

Para cantidades grandes de imágenes o archivos, lo mejor es tenerlos en carpetas (puede ser una carpeta de red, para que todos los usuarios tengan acceso a ella) y en la base de datos solo almacenar la ruta de la misma.
Con esto el flujo de tránsito de datos con tu base de datos se hace más ágil (si los archivos son muy pesados la consulta puede ralentizarse).

Saludos.
Francisco Lorente.
Murcia. España.

roberto martinez andrade

unread,
Jan 24, 2023, 3:34:53 PM1/24/23
to publice...@googlegroups.com
Hice algo parecido pero con archivos PDF y utilice la opción de almacenar la ruta en una tabla de la BD y acceder al archivo que lo almaceno en una carpeta. Ha funcionado bastante bien, incluso accediendo por red wifi a la ruta especificada.

Como bien dice Bibiana podría haber inconveniente en que borren archivos en forma accidental pero eso podría controlarse por los permisos sobre los archivos (se me ocurrió recién, no lo he probado). 

Como actualmente estoy haciendo otros módulos de administración documental voy a probar eso de los permisos y lo comento.

Sl2s
Roberto
Coyhaique - Chile

--
Blog de la Comunidad Visual FoxPro en Español: http://comunidadvfp.blogspot.com
---
Has recibido este mensaje porque estás suscrito al grupo "Comunidad de Visual Foxpro en Español" de Grupos de Google.
Para cancelar la suscripción a este grupo y dejar de recibir sus mensajes, envía un correo electrónico a publicesvfoxp...@googlegroups.com.
Para ver esta conversación en el sitio web, visita https://groups.google.com/d/msgid/publicesvfoxpro/23c83613-45c7-4eb9-9f97-88863185bca6n%40googlegroups.com.

Esteban Herrero

unread,
Jan 24, 2023, 3:35:05 PM1/24/23
to publice...@googlegroups.com

Yo trabajo con Firebird y en mis clientes normalmente tengo 2 DB, una es la DB principal donde estan todos los datos de trabajo y la otra DB es p guardar los PDF de toda factura/ND/NC q se haga, todas se guardan ahi en una tabla q tiene un campo BloB y el acceso es super rápido...

No se si es a esto q te referías...

Saludos

--
Blog de la Comunidad Visual FoxPro en Español: http://comunidadvfp.blogspot.com
---
Has recibido este mensaje porque estás suscrito al grupo "Comunidad de Visual Foxpro en Español" de Grupos de Google.
Para cancelar la suscripción a este grupo y dejar de recibir sus mensajes, envía un correo electrónico a publicesvfoxp...@googlegroups.com.

Alfonso Ramirez Diaz

unread,
Jan 24, 2023, 3:39:35 PM1/24/23
to Comunidad de Visual Foxpro en Español
Buenas tardes

Personalmente recomiendo guardar las imagenes o archivos dentro de la misma database sobretodo si ya usas mysql porque esto te permite hacer mas movible tu sistema, si lo guardas en carpetas te será mas difícil hacer una solución web por ejemplo, en cambio guardando en la database puedes usar php por ejemplo para recuperarlo vía web o cualquier otro lenguaje.

También cuando respaldes mysql se respaldaran las imagenes y documentos también.

Irwin Rodriguez

unread,
Jan 24, 2023, 3:59:49 PM1/24/23
to publice...@googlegroups.com
Puedes tener una tabla aparte dedicada solo al almacenamiento de imágenes codificadas en base64 y crearte una rutina que dé de alta tu imagen y te devuelva un identificador único como un GUID y en la tabla principal solo guardas la referencia de la imagen (GUID).

Aquí te dejo un ejemplo que he creado al vuelo así que solo úsalo de referencia porque no va a funcionar ya que asume una conexión activa a un servidor remoto y dos tablas tblClientes y tblImagenes

* Ejemplo: El siguiente código registra una imagen (su identificador) en la tabla tblClientes.

LOCAL lcImagen, lcImagenGuid

lcImagen = GETPIC()

IF EMPTY(lcImagen)
    RETURN
ENDIF

lcImagenGuid = registrarImagen(lcImagen)
IF EMPTY(lcImagenGuid)
    RETURN
ENDIF

* Aquí ya es posible registrar los datos del cliente
LOCAL lcQuery
* Este es el query que inserta la imagen
TEXT TO lcQuery NOSHOW PRETEXT 7 TEXTMERGE
    INSERT INTO tblClientes (CODIGO, NOMBRE, FOTO)
        VALUES('CL001', 'PEDRO PEREZ', '<<lcImageGuid>>')
ENDTEXT

IF SQLEXEC(gnHandle, lcQuery) < 0
    AERROR(laSqlError)
    MESSAGEBOX("Error en el registro del cliente: " + laSqlError[2], 16)
    RETURN ""
ENDIF

* y con este código recuperas la imagen
recuperarImagen(lcImageGuid, "c:\MiSistema\Imagenes\imagen.jpg")

RETURN

* Registra una imagen en la tabla [tblImagenes]
* Devuelve GUID
FUNCTION registrarImagen(tcRutaImagen)
    LOCAL lcQuery, loScript, lcGuid, lcBase64Image

    IF !FILE(tcRutaImagen)
        MESSAGEBOX("El nombre o la ruta de la imagen no existen.", 16)
        RETURN ""
    ENDIF

    * Esto almacena la imagen con una codificación básica (base64)
    lcBase64Image = STRCONV(FILETOSTR(tcRutaImagen), 13)

    * Esto genera un GUID de 36 caracteres.
    loScript = CREATEOBJECT("scriptlet.typelib")
    lcGuid = loScript.substr(loGuid.GUID, 2, 36)

    * Este es el query que inserta la imagen
    TEXT TO lcQuery NOSHOW PRETEXT 7 TEXTMERGE
        INSERT INTO tblImagenes (GUID, IMAGEN, FECHA)
            VALUES('<<lcGuid>>', <<lcBase64Image>>, '<<DATETIME()>>')
    ENDTEXT

    IF SQLEXEC(gnHandle, lcQuery) < 0
        AERROR(laSqlError)
        MESSAGEBOX("Error en el registro de imagen: " + laSqlError[2], 16)
        RETURN ""
    ENDIF

    RETURN lcGuid
ENDFUNC

* Registra una imagen en la tabla [tblImagenes]
* Devuelve GUID
FUNCTION recuperarImagen(tcImageGuid, tcOutput)
    LOCAL lcSelect
   
    TEXT TO lcSelect NOSHOW PRETEXT 7 TEXTMERGE
        SELECT IMAGEN FROM tblImagenes WHERE GUID = '<<tcImageGuid>>'
    ENDTEXT

    IF SQLEXEC(gnHandle, lcSelect, "curImagen") < 0
        AERROR(laSqlError)
        MESSAGEBOX("Error en la recuperación de la imagen: " + laSqlError[2], 16)
        RETURN .F.
    ENDIF

    * Decodificamos la imagen y la guardamos en la ruta especificada.

    =STRTOFILE(STRCONV(curImagen.imagen, 14), tcOutput)

    RETURN FILE(tcOutput)
ENDFUNC


--
Blog de la Comunidad Visual FoxPro en Español: http://comunidadvfp.blogspot.com
---
Has recibido este mensaje porque estás suscrito al grupo "Comunidad de Visual Foxpro en Español" de Grupos de Google.
Para cancelar la suscripción a este grupo y dejar de recibir sus mensajes, envía un correo electrónico a publicesvfoxp...@googlegroups.com.

Bibiana Cacciaguerra

unread,
Jan 24, 2023, 4:42:29 PM1/24/23
to Comunidad de Visual Foxpro en Español
Muchas gracias. Muy útiles vuestros aportes. ¿Codificar en Base64 no aumenta el tamaño de los archivos? 

Alfonso Ramirez Diaz

unread,
Jan 24, 2023, 4:49:22 PM1/24/23
to Comunidad de Visual Foxpro en Español
Si aumenta un poco pero te asegura compatibilidad con diversos lenguajes y seguridad al grabar la información porque a veces con los caracteres raros queda mal almacenada la información.

Cristian Novoa

unread,
Jan 24, 2023, 5:25:55 PM1/24/23
to Comunidad de Visual Foxpro en Español
Tengo en una tabla 20937 imágenes de productos. Pesan alrededor de 100KB, pues gracias a VFPX las convierto en 800x600 jpg 75%.

No he tenido problema alguno, por lo tanto, en lo que a mi respecta es mejor guardarlas en la BD.

*------------------------------------------------------------------------------------------------------
* Debido al problema con win7, no se pudo asignar el blob a la propiedad pictureval
* Por lo tanto, se usa la propiedad Picture.
PROCEDURE muestra_imagen_blob(toImagen, tbImagen, tlBorraArchTemp)

IF ISNULL(tbImagen)
    toImagen.Picture = ""
    RETURN
ENDIF


lcArch = archazar("jpg")
   
STRTOFILE(tbImagen, lcArch)

toImagen.Picture = lcArch

toImagen.MousePointer = 1    && evita que quede el "reloj de arena", gatillado por toImagen.Picture = lcArch


*-- 27/06/2020 ID ERROR 109822 "File is in use." en la línea "DELETE FILE (lcArch)"
*-- No supe que pasa. Al investigar, descarté que ocurría en productos con varias imágenes.
*-- Entonces, la "solución" pasó por usar TRY/CATCH
IF tlBorraArchTemp
    TRY
        DELETE FILE (lcArch)    && Ojo que dió error aqui "El archivo ya está en uso" id error 1903
    CATCH
    ENDTRY
ENDIF

RETURN

*------------------------------------------------------------------------------------------------------
FUNCTION lee_imagen

PARAMETERS tcCodigoParametro

LOCAL lbImagen, lnAreaAnterior
lnAreaAnterior = SELECT()


IF ! ejecuta_bd("select valor from tbl_parametro_imagen where rut_empresa = ?goEntorno.crut_empresa and codigo_parametro=?tcCodigoParametro", "cImagen")
    RETURN ""
ENDIF

*lcImagen = CAST(cImagen.valor as blob)
lbImagen = cImagen.valor
CierraAlias("cImagen")



SELECT (lnAreaAnterior)

RETURN lbImagen

*------------------------------------------------------------------------------------------------------
PROCEDURE graba_imagen

PARAMETERS tcCodigoParametro, tcArchivo

LOCAL lcArchivoDestino

PRIVATE pbImagen



*--------------
lcArchivoDestino = cambia_formato_imagen(tcArchivo)
IF EMPTY(lcArchivoDestino)
    RETURN .F.
ENDIF


*--------------
pbImagen = cast(filetostr(lcArchivoDestino) as blob)
*vimagen= "0x"+STRCONV(vimagentemp,15)    && mejor FILETOSTR()

borra_arch(lcArchivoDestino)

*-- la extension por ahora es solo JPG
RETURN ejecuta_bd("update tbl_parametro_imagen set valor = ?pbImagen, extension='JPG' where rut_empresa = ?goEntorno.crut_empresa and codigo_parametro=?tcCodigoParametro")

*------------------------------------------------------------------------------------------------------
*- imagen bmp sin formatear
PROCEDURE graba_imagen_bmp

PARAMETERS tcCodigoParametro, tcArchivo

LOCAL lcArchivoDestino


PRIVATE pbImagen

pbImagen = cast(filetostr(tcArchivo) as blob)

*-- la extension por ahora es solo JPG
RETURN ejecuta_bd("update tbl_parametro_imagen set valor = ?pbImagen, extension='BMP' where rut_empresa = ?goEntorno.crut_empresa and codigo_parametro=?tcCodigoParametro")

*------------------------------------------------------------------------------------------------------
PROCEDURE trae_imagen_a_disco

PARAMETERS tcCodigoParametro

LOCAL lcArchivo, lnAreaAnterior
lnAreaAnterior = SELECT()


IF ! ejecuta_bd("select extension, valor from tbl_parametro_imagen where rut_empresa = ?goEntorno.crut_empresa and codigo_parametro=?tcCodigoParametro", "cImagen")
    RETURN ""
ENDIF

IF ! ISNULL(cImagen.valor)
    lcArchivo = LOWER(FULLPATH(".\temp\"+tcCodigoParametro+"."+cImagen.extension))
    STRTOFILE(cImagen.valor, lcArchivo)
ELSE
    lcArchivo = LOWER(FULLPATH(".\temp\imagen_por_defecto.jpg"))
    COPY FILE imagen_por_defecto.jpg TO (lcArchivo)
ENDIF

CierraAlias("cImagen")



SELECT (lnAreaAnterior)

RETURN lcArchivo

******************************************************************************
FUNCTION archazar(ext) && retorna un nombre de archivo al azar (arch.temporal)

RETURN gcDirTemp + SYS(2015) + "." + ext

*------------------------------------------------------------------------------------------------------
PROCEDURE borra_arch(tcArchivo)

IF FILE(tcArchivo)
    DELETE FILE (tcArchivo)
ENDIF

RETURN

*--------------------------------------------------
* Para cambiar solo el formato de una imagen
* Por ahora para JPG
*--------------------------------------------------
FUNCTION cambia_formato_imagen(tcImagenOrigen)

LOCAL lcImagenDestino
lcImagenDestino = archazar("jpg")
 
LOCAL loImage AS GpImage OF "libs/_gdiplus.vcx"
loImage = NEWOBJECT("GpImage", "libs/_gdiplus.vcx")
loImage.CreateFromFile(tcImagenOrigen)

*- forma poco ortodoxa de validar un error
IF ISNULL(loImage.ImageHeight)
    RETURN ""
ENDIF


loImage.SaveToFile(lcImagenDestino, "image/jpeg")

*!*    loImage.SaveToFile(lcDestination + ".bmp","image/bmp")
*!*    loImage.SaveToFile(lcDestination + ".tif","image/tiff")
*!*    loImage.SaveToFile(lcDestination + ".gif","image/gif")
*!*    loImage.SaveToFile(lcDestination + ".png","image/png")

*!* JPEGs allow to choose the quality of the image
*!*    loImage.SaveToFile(lcImagenDestino, "image/jpeg", "quality=85")    && decia quality=70 (lei que recomiendan 75-85)

RETURN lcImagenDestino


*------------------------------------------------------------------------------------------------------
* Cambia la resolucion de la imagen a 800x600 y el formato a jpg calidad 75.
* El resultado lo envia a temp en un archivo al azar.
* Retorna el nombre del archivo imagen resultante.
* En caso de error retorna la cadena vacia.
FUNCTION cambia_resol_y_formato_imagen(tcImagenOrigen)

#DEFINE GDIPLUS_PIXELFORMAT_1bppIndexed      0x00030101
#DEFINE GDIPLUS_PIXELFORMAT_4bppIndexed      0x00030402
#DEFINE GDIPLUS_PIXELFORMAT_8bppIndexed      0x00030803
#DEFINE GDIPLUS_PIXELFORMAT_16bppGrayScale   0x00101004
#DEFINE GDIPLUS_PIXELFORMAT_16bppRGB555      0x00021005
#DEFINE GDIPLUS_PIXELFORMAT_16bppRGB565      0x00021006
#DEFINE GDIPLUS_PIXELFORMAT_16bppARGB1555    0x00061007
#DEFINE GDIPLUS_PIXELFORMAT_24bppRGB         0x00021808
#DEFINE GDIPLUS_PIXELFORMAT_32bppRGB         0x00022009
#DEFINE GDIPLUS_PIXELFORMAT_32bppARGB        0x0026200A
#DEFINE GDIPLUS_PIXELFORMAT_32bppPARGB       0x000E200B
#DEFINE GDIPLUS_PIXELFORMAT_48bppRGB         0x0010300C
#DEFINE GDIPLUS_PIXELFORMAT_64bppPARGB       0x001C400E

*lcSource = GETPICT("jpg;gif;bmp")
*lcDestination = ADDBS(JUSTPATH(lcSource))+ "Resized_" +;
*   JUSTSTEM(lcSource)+".jpg"


LOCAL lcImagenDestino
lcImagenDestino = archazar("jpg")

LOCAL loImage AS GpImage OF "libs/_gdiplus.vcx"

loImage = NEWOBJECT("GpImage", "libs/_gdiplus.vcx")
loImage.CreateFromFile(tcImagenOrigen)

*- forma poco ortodoxa de validar un error
IF ISNULL(loImage.ImageHeight)
    RETURN ""
ENDIF
 
LOCAL loBitmap AS GpBitmap OF "libs/_gdiplus.vcx"
loBitmap = NEWOBJECT("GpBitmap", "libs/_gdiplus.vcx")

LOCAL loGraphics as GpGraphics OF "libs/_gdiplus.vcx"
loGraphics = NEWOBJECT('GpGraphics', "libs/_gdiplus.vcx")
 
*** Now we create a new image with
*** Create Method - Creates a bitmap object.
*** Syntax: ? THIS.Create(tnWidth, tnHeight[, tnPixelFormat])
***
*** tnPixelFormat, optional, one of GDIPLUS_PIXELFORMAT_* constants,
*** defaults to GDIPLUS_PIXELFORMAT_32bppARGB.
 
LOCAL lnNewWidth, lnNewHeight
*lnNewWidth = 800  && Put here the desired Width (decia 640)
*lnNewHeight = 600 && Put here the desired Height (decia 480)

********** determina dimensiones proporcionalmente
LOCAL nAlto_Original, nAncho_Original
nAlto_Original = loImage.ImageHeight
nAncho_Original= loImage.ImageWidth
IF nAlto_Original > nAncho_Original
    lnNewHeight = 600
    lnNewWidth = 600 / nAlto_Original * nAncho_Original
ELSE
    lnNewWidth = 800
    lnNewHeight = 800 / nAncho_Original * nAlto_Original
ENDIF
**********


loBitmap.Create(lnNewWidth, lnNewHeight, GDIPLUS_PIXELFORMAT_32bppPARGB)
*** The other constants are in the beginning of this code
 
loGraphics.CreateFromImage(loBitmap)
loGraphics.DrawImageScaled(loImage, 0, 0, lnNewWidth, lnNewHeight)

*loBitmap.SaveToFile(lcDestination, "image/bmp")    && con esta linea solo cambiaba el tamaño de la imagen
loBitmap.SaveToFile(lcImagenDestino, "image/jpeg", "quality=75")


RETURN lcImagenDestino

******************************************************************************
FUNCTION archazar(ext) && retorna un nombre de archivo al azar (arch.temporal)

RETURN gcDirTemp + SYS(2015) + "." + ext

Hernán Medina

unread,
Jan 30, 2023, 11:20:13 AM1/30/23
to publice...@googlegroups.com
Hola, en relación al tema de almacenar imágenes, alguno de los exponentes puede indicar por favor cómo se crea una librería .dll que sólo contengan un Identificador único y la imágen ?  Hace mucho tiempo use una versión de Visual studio 6 para crear archivos .dll Ahora he revisado las versiones actuales y no consigo crearlas. Tienen alguna idea de algún programa que pueda usar para crear los archivos .dll. Esta también es una opción para almacenar imágenes, en mi caso las use para una aplicación multi-idioma, es decir, cada archivo.dll contienen las imágenes en el idioma seleccionado, así cambiando incluso ciertas ventanas en el idioma que se deseaba. Pero ahora no consigo un programa para crear  dichas dll.   Gracias por su aporte...

Reply all
Reply to author
Forward
0 new messages