Una clase para descargar del sitio de José Guillermo Ortiz Hernández, que permite incluir código EAN 128 en aplicaciones Visual FoxPro.
En el sitio Tortuga Productiva dedicado a Visual FoxPro, está publicado el siguiente artículo con código fuente incluido que permite incluir códigos de barra EAN 128 en aplicaciones Visual FoxPro.
-- El EAN 128, Uso e implementación en FoxPro --
http://www.tortugaproductiva.galeon.com/docs/ean128/index.html
31 de julio de 2007
23 de julio de 2007
Nueva versión de GradObjects
Artículo original: New version of GradObjects
http://weblogs.foxite.com/vfpimaging/archive/2007/06/28/4212.aspx
Autor: Cesar Ch.
Traducido por: Ana María Bisbé York
Acabo de subir una nueva versión de la clase GradObjects
Gracias a Nigel por informar de un error que ocurría cuando se utilizaban objetos OptionsGroups gráficos.
He aquí la versión actualizada.
http://www.geocities.com/macmarbr/gradobjects.zip
http://weblogs.foxite.com/files/vfpimaging/gradobjects/gradobjects.zip
Se puede obtener más información en el escrito original:
GRADIENT OBJECTS WITH GDI+
http://weblogs.foxite.com/vfpimaging/archive/2006/07/26/2076.aspx
http://weblogs.foxite.com/vfpimaging/archive/2007/06/28/4212.aspx
Autor: Cesar Ch.
Traducido por: Ana María Bisbé York
Acabo de subir una nueva versión de la clase GradObjects
Gracias a Nigel por informar de un error que ocurría cuando se utilizaban objetos OptionsGroups gráficos.
He aquí la versión actualizada.
http://www.geocities.com/macmarbr/gradobjects.zip
http://weblogs.foxite.com/files/vfpimaging/gradobjects/gradobjects.zip
Se puede obtener más información en el escrito original:
GRADIENT OBJECTS WITH GDI+
http://weblogs.foxite.com/vfpimaging/archive/2006/07/26/2076.aspx
20 de julio de 2007
Incruste imágenes a sus correos electrónicos con CDOSYS
Artículo original: Embed images to your emails with CDOSYS
http://weblogs.foxite.com/vfpimaging/archive/2007/07/03/4256.aspx
Autor: Cesar Ch.
Traducido por: Luis María Guayán
Basado en algunos excelentes ejemplos que encontré en la Web, especialmente los de Mike Gagnon, he creado mi propia clase para enviar correos electrónicos. Decidí usar CDOSYS (Microsoft Collaboration Data Objects for Windows 2000) porque esto viene con Win2000 / XP / Vista y 2003, y permite enviar mensajes de varios maneras, especialmente incrustando imágenes que son usadas en el contenido HTML del mensaje.
MAPI era mi primera opción, pero lamentablemente esto no permite incrustar imágenes, sólo son permitidos los adjuntos. La automatización de MS Outlook también funcionaría, pero no lo tengo.
Abajo está un simple código que genera una página HTML que contiene algunas imágenes que deben ser enviadas. Las imágenes son incrustadas al mensaje, ¡no como simples adjuntos!. Este permite que mostremos las imágenes en el sitio y con las características que deseamos.
Aparte de las características más comunes, esto también permite que incruste imágenes, agregue adjuntos, configure la prioridad, solicite confirmación de lectura y envíe HTML.
La propiedad "Body" de la clase acepta 3 diferentes tipos de parámetros: 1-un código de HTML, 2-una URL (CDOSYS incrustará la página entera en el mensaje) o 3-un archivo HTML que será incustado. Para esta última opción, mis pruebas fallaron cuándo usé espacios en el nombre de directorio y/o en el nombre del archivo, ¡entonces evite espacios en nombres del archivo!.
Las imágenes de abajo muestran algunas pantallas de ejemplo que generé y recibí, utilizando el código de abajo, abriendo con Outlook Express. Esto también fue probado con algunos correos Web, como por ejemplo Hotmail y los resultados son similares.
Guarde el código de abajo como un PRG, y no olvide cambiar la información en Rojo por la propia, y ejecútelo.
http://weblogs.foxite.com/vfpimaging/archive/2007/07/03/4256.aspx
Autor: Cesar Ch.
Traducido por: Luis María Guayán
Basado en algunos excelentes ejemplos que encontré en la Web, especialmente los de Mike Gagnon, he creado mi propia clase para enviar correos electrónicos. Decidí usar CDOSYS (Microsoft Collaboration Data Objects for Windows 2000) porque esto viene con Win2000 / XP / Vista y 2003, y permite enviar mensajes de varios maneras, especialmente incrustando imágenes que son usadas en el contenido HTML del mensaje.
MAPI era mi primera opción, pero lamentablemente esto no permite incrustar imágenes, sólo son permitidos los adjuntos. La automatización de MS Outlook también funcionaría, pero no lo tengo.
Abajo está un simple código que genera una página HTML que contiene algunas imágenes que deben ser enviadas. Las imágenes son incrustadas al mensaje, ¡no como simples adjuntos!. Este permite que mostremos las imágenes en el sitio y con las características que deseamos.
Aparte de las características más comunes, esto también permite que incruste imágenes, agregue adjuntos, configure la prioridad, solicite confirmación de lectura y envíe HTML.
La propiedad "Body" de la clase acepta 3 diferentes tipos de parámetros: 1-un código de HTML, 2-una URL (CDOSYS incrustará la página entera en el mensaje) o 3-un archivo HTML que será incustado. Para esta última opción, mis pruebas fallaron cuándo usé espacios en el nombre de directorio y/o en el nombre del archivo, ¡entonces evite espacios en nombres del archivo!.
Las imágenes de abajo muestran algunas pantallas de ejemplo que generé y recibí, utilizando el código de abajo, abriendo con Outlook Express. Esto también fue probado con algunos correos Web, como por ejemplo Hotmail y los resultados son similares.
Guarde el código de abajo como un PRG, y no olvide cambiar la información en Rojo por la propia, y ejecútelo.
19 de julio de 2007
Informe VFP a PowerPoint
He visto peticiones para pasar un informe de VFP a PowerPoint, aquí tengo un código para hacerlo.
*** Creamos un Objeto de PowerPoint oPPT=CREATEOBJECT('POWERPOINT.APPLICATION') PPTPRES=oPPT.PRESENTATIONS.ADD(1) PPTSLIDE1=PPTPRES.SLIDES.ADD(1,1) *** Creamos un Cuadro de Texto oTXT1=PptSlide1.Shapes.AddTextBox(1,5,220,700,25) WITH oTXT1 .Line.ForeColor.RGB=RGB(180,180,180) .LINE.VISIBLE=.T. .TEXTFRAME.TEXTRANGE.TEXT='ING. ERIK REYES LIMA' .TEXTFRAME.TEXTRANGE.FONT.SIZE=18 .TEXTFRAME.TEXTRANGE.FONT.BOLD=.T. .FILL.ForeColor.RGB = rgb(255,255,255) .FILL.VISIBLE=.T. .Shadow.ForeColor.RGB = RGB(180, 0, 119) .Shadow.VISIBLE=.T. ENDWITH *** CREAMOS UNA LINEA oLine1 = pptslide1.Shapes.AddLine(0,43,720,43) WITH oLine1.Line .ForeColor.RGB = rgb(180,0,119) .Weight = 2 ENDWITH *** CREAMOS UNA IMAGEN PptSlide1.Shapes.Addpicture('C:\FOTOS\MIFOTO.JPG',1,1,0,0,70,40) *** ACTIVAMOS EL POWERPOINT OPPT.VISIBLE = .T.[Sadex]
17 de julio de 2007
VFP9 a MySQL5 - Almacenamiento de Imágenes
Últimante he leído en los foros sobre gente que tiene problemas a la hora de guardar imágenes en una base de datos de MySQL.
Vamos a solucionar esto desglosando tres pequeños ejemplos de almacenamiento de imágenes en MySQL.
Vamos a tener que crear una pequeña tabla en nuestra base de datos MySQL con la siguiente estructura:
CODIGO, DESCRIPCION, FOTO (Atención al campo foto ya que será del tipo BLOB)
Crearemos la tabla desde nuestro querido VFP.
2. Archivar imagen en la tabla de MySQL.
Vamos a archivar una imagen en la tabla (albumfotos). La imagen estará ubicada en el directorio raiz C:\ y será el archivo de imagen FOTO001.JPG
Crearemos una variable en VFP del tipo BLOB que contendrá la imagen antes de su posterior grabación: (En este caso omitiremos las ordenes de conexión a la base de datos)
3. Extraer imagen de la tabla de MySQL.
Vamos a Extraer la misma imagen de la tabla de MySQL y ahora la guardaremos en el directorio fotos. (Obviamente en este caso también omitiremos las ordenes de conexión a la base de datos)
Antonio L. Montagut
www.ontarioxb.es
Vamos a solucionar esto desglosando tres pequeños ejemplos de almacenamiento de imágenes en MySQL.
- Crear una tabla en MySQL para almacenar las imágenes.
- Archivar una imágen en un campo de la tabla de nuestra base de datos.
- Proceder a su descarga posterior.
Vamos a tener que crear una pequeña tabla en nuestra base de datos MySQL con la siguiente estructura:
CODIGO, DESCRIPCION, FOTO (Atención al campo foto ya que será del tipo BLOB)
Crearemos la tabla desde nuestro querido VFP.
******************************************** * CREACION DE TABLA (albumfotos) ******************************************** LOCAL CSQL, NH, CCADENA CSQL="" NH=0 CCADENA="" CSQL= "DRIVER={MySQL ODBC 3.51 Driver};" + ; "SERVER=127.0.0.1;" + ; "PORT=3306;" + ; "UID=usuario;" + ; "PWD=pasword;" + ; "DATABASE=mybasededatos;" + ; "OPTIONS=2049;" NH=SQLSTRINGCONNECT(""+CSQL, .T.) IF NH > 0 SQLSETPROP(NH,'Asynchronous', .T.) SQLSETPROP(NH,'BatchMode', .T.) TEXT TO CSQL TEXTMERGE NOSHOW CREATE TABLE albumfotos ( codigo char(03) NOT NULL default '000', descripcion varchar(50) default '', foto longblob, PRIMARY KEY (codigo)) ENGINE=InnoDB ROW_FORMAT=DYNAMIC ENDTEXT SQLPREPARE(NH,""+CSQL) SQLEXEC(NH) WAIT WINDOW 'Tabla Creada' SQLDISCONNECT(NH) ENDIF RELEASE CSQL,NH,CCADENA *************************************************************
2. Archivar imagen en la tabla de MySQL.
Vamos a archivar una imagen en la tabla (albumfotos). La imagen estará ubicada en el directorio raiz C:\ y será el archivo de imagen FOTO001.JPG
Crearemos una variable en VFP del tipo BLOB que contendrá la imagen antes de su posterior grabación: (En este caso omitiremos las ordenes de conexión a la base de datos)
******************************************** * ARCHIVAR IMAGEN ******************************************** LOCAL BIMAGEN AS BLOB BIMAGEN=(0h) && Inicializamos la Variable BIMAGEN=FILETOSTR("C:\FOTO001.JPG") TEXT TO CSQL TEXTMERGE NOSHOW REPLACE INTO albumfotos SET CODIGO='001', DESCRIPCION='FOTO-001', FOTO=?BIMAGEN ENDTEXT SQLPREPARE(NH,""+CSQL) SQLEXEC(NH) WAIT WINDOW 'Imagen Grabada' RELEASE BIMAGEN *************************************************************
3. Extraer imagen de la tabla de MySQL.
Vamos a Extraer la misma imagen de la tabla de MySQL y ahora la guardaremos en el directorio fotos. (Obviamente en este caso también omitiremos las ordenes de conexión a la base de datos)
******************************************** * EXTRAER IMAGEN ******************************************** TEXT TO CSQL TEXTMERGE NOSHOW SELECT FOTO FROM albumfotos WHERE CODIGO='001' ENDTEXT SQLPREPARE(NH,""+CSQL,"TCURSOR") SQLEXEC(NH) SELECT TCURSOR IF RECCOUNT() > 0 STRTOFILE(TCURSOR.FOTO,"C:\FOTOS\FOTO001.JPG") ENDIF CLOSE TABLES ALL ********************************************Esto no solo sirve para almacenar imágenes solamente, También es posible almacenar documentos PDF, Word, lo que se nos ocurra. Yo por ejemplo lo utilizo para almacenar cada logo de empresa en mi base de datos, para posteriormente imprimirlo en la cabecera de las facturas e informes.
Antonio L. Montagut
www.ontarioxb.es
16 de julio de 2007
SQL Select - Bufferred Queries
Artículo original: SQL Select - Bufferred Queries
http://rickschummer.com/blog/2007/07/sql-select-bufferred-queries.html
Autor: Rick Schummer
Traducido por: Luis María Guayán - 16/07/2007
Utilicé hoy por primera vez, una nueva característica de VFP 9 en un escenario del mundo real: la nueva capacidad de consultar datos de un cursor con buffering, usando la nueva cláusula WITH (BUFFERING = .T.)
Sé que hay desarrolladores de VFP y administradores de bases de datos que dirán que usar esta sintaxis es absolutamente incorrecta porque los datos aun pueden ser revertidos, y así el resultado de la consulta no es reproducible. La información se podría utilizar incorrectamente para tomar decisiones de negocio y esto no es elegante, y no es un enfoque profesional. Estos individuos están absolutamente acertados, cuando necesitas tener control y equilibrio en la base de datos, integridad de los datos en la base de datos, e integridad en informes y análisis.
Por otra parte, yo tenía que usar esta nueva funcionalidad para comprobar la validez de los datos antes de que estos fueran grabados en la base de datos. Aquí está mi escenario:
Aquí está mi consulta para contar el número de la personas con registros duplicados:
Tengo otra idea donde esta nueva sintaxis ayudará al producto HackCX Professional. Espero agregar en la próxima versión un informe o resumen en pantalla, así se puedan ver todos los cambios almacenados en buffer que se realizaron en la biblioteca de clases que esta cambiando. Seguro que puedo hacer esto sin una sintaxis SQL Select, pero pienso que que escribir un simple SQL Select es más rápido y menos código que recorrer toda la tabla para determinar qué registros han cambiado.
¿Has utilizado esta nueva sintaxis? Si es así ¿Para qué?
http://rickschummer.com/blog/2007/07/sql-select-bufferred-queries.html
Autor: Rick Schummer
Traducido por: Luis María Guayán - 16/07/2007
Utilicé hoy por primera vez, una nueva característica de VFP 9 en un escenario del mundo real: la nueva capacidad de consultar datos de un cursor con buffering, usando la nueva cláusula WITH (BUFFERING = .T.)
Sé que hay desarrolladores de VFP y administradores de bases de datos que dirán que usar esta sintaxis es absolutamente incorrecta porque los datos aun pueden ser revertidos, y así el resultado de la consulta no es reproducible. La información se podría utilizar incorrectamente para tomar decisiones de negocio y esto no es elegante, y no es un enfoque profesional. Estos individuos están absolutamente acertados, cuando necesitas tener control y equilibrio en la base de datos, integridad de los datos en la base de datos, e integridad en informes y análisis.
Por otra parte, yo tenía que usar esta nueva funcionalidad para comprobar la validez de los datos antes de que estos fueran grabados en la base de datos. Aquí está mi escenario:
- Tengo datos para importar de una fuente exterior.
- Tengo datos para importar de una fuente interna, pero exportados de una aplicación diferente.
- Hay una gran posibilidad de datos duplicados en las dos fuentes de datos.
- Todos los datos se importan a cursores con buffering.
- Tengo que ejecutar la importación de los datos a través de tres tablas distintas, de una vez, o no. Dos de las tablas están relacionadas.
Aquí está mi consulta para contar el número de la personas con registros duplicados:
SELECT cLastName, cFirstName, COUNT(*) as nCount ; FROM people WITH (BUFFERING = .T.) ; JOIN registration WITH (BUFFERING = .T.) ; ON people.cPeople_PK = registration.cPeople_FK ; GROUP BY cLastName, cFirstName ; HAVING nCount > 1 ; INTO CURSOR curMultiYearRegistrationsAntes de la importación conté los registros de los datos de ejemplo para hacer mis comparaciones. Esta división y manejo de los datos almacenados en el buffer me ahorró muchos la molestia de quitar los datos importados cuando encontraba errores. Habría podido hacer volar la base de datos y restaurar una backup, pero ésa habría tomado más tiempo. Habría podido importar a otra área, pero con esto habría hecho dos veces el trabajo. Podía suspender el proceso de la importación y hacer algunas consultas específicas para verificar que todo está bien durante cada paso de la importación.
Tengo otra idea donde esta nueva sintaxis ayudará al producto HackCX Professional. Espero agregar en la próxima versión un informe o resumen en pantalla, así se puedan ver todos los cambios almacenados en buffer que se realizaron en la biblioteca de clases que esta cambiando. Seguro que puedo hacer esto sin una sintaxis SQL Select, pero pienso que que escribir un simple SQL Select es más rápido y menos código que recorrer toda la tabla para determinar qué registros han cambiado.
¿Has utilizado esta nueva sintaxis? Si es así ¿Para qué?
6 de julio de 2007
VFP 9 a MySQL5
Voy a Intentar en las próximas semanas escribir una serie de artículos sobre la utilización de VFP atacando bases de datos MySQL. Estos artículos reflejan en cierta manera la experiencia de mi trabajo diario con MySQL.
Función UUID()
El propósito de esta función es devolver un identificador único universal. Un UUID es un número de 128 bits representado por una cadena de cinco números hexadecimales en el formato:
Es de suponer pués que dos llamadas a UUID() generen dos valores diferentes, aunque esas llamadas se realizen en dos ordenadores separados físicamente y que no están conectados en red.
La utilidad de esta función está mas que clara. Nos permite obtener un identificador único por cada registro de una tabla, podemos utilizar esta cadena como clave primaria de la tabla, esto nos permitiria que en el caso de replicación de la base de datos, registros de la misma tabla pero en diferentes bases de datos no se sobreescribieran entre si. Cosa que si prodría pasar si utilizáramos como clave primaria campos autoincrementales.
Ya que al estar en bases de datos diferentes podría darse el caso de tener registros duplicados con el mismo identificador.
Vamos ha aplicar esta función con nuestro querido FOX:
www.ontarioxb.es
Función UUID()
El propósito de esta función es devolver un identificador único universal. Un UUID es un número de 128 bits representado por una cadena de cinco números hexadecimales en el formato:
aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee.Un UUID está diseñado para ser un único número globalmente en el espacio y el tiempo.
Es de suponer pués que dos llamadas a UUID() generen dos valores diferentes, aunque esas llamadas se realizen en dos ordenadores separados físicamente y que no están conectados en red.
La utilidad de esta función está mas que clara. Nos permite obtener un identificador único por cada registro de una tabla, podemos utilizar esta cadena como clave primaria de la tabla, esto nos permitiria que en el caso de replicación de la base de datos, registros de la misma tabla pero en diferentes bases de datos no se sobreescribieran entre si. Cosa que si prodría pasar si utilizáramos como clave primaria campos autoincrementales.
Ya que al estar en bases de datos diferentes podría darse el caso de tener registros duplicados con el mismo identificador.
Vamos ha aplicar esta función con nuestro querido FOX:
******************************************** * Ejemplo de uso función UUID ******************************************** LOCAL CSQL, NH, CCADENA CSQL = "" NH = 0 CCADENA = "" CSQL = "DRIVER={MySQL ODBC 3.51 Driver};" + ; "SERVER=127.0.0.1;" + ; "PORT=3306;" + ; "UID=usuario;" + ; "PWD=pasword;" + ; "DATABASE=mybasededatos;" + ; "OPTIONS=2049;" NH = SQLSTRINGCONNECT("" + CSQL, .T.) IF NH > 0 SQLSETPROP(NH,'Asynchronous', .F.) SQLSETPROP(NH,'BatchMode', .T.) CCADENA = PADR("",32,'0') SQLPREPARE(NH, "SELECT UUID()","CURSOR") SQLEXEC(NH) SELECT CURSOR IF RECCOUNT()>0 CCADENA = LEFT(FIELD(1),08)+ ; SUBSTR(FIELD(1),10,04)+ ; SUBSTR(FIELD(1),15,04)+ ; SUBSTR(FIELD(1),20,04)+ ; RIGHT(FIELD(1),12) ENDIF WAIT WINDOW CCADENA && Muestra la Cadena SELECT CURSOR USE ENDIF *************************************************************Antonio L. Montagut
www.ontarioxb.es
4 de julio de 2007
Diferentes formas de obtener las dimensiones de las imágenes (ancho y alto)
Artículo original: Different ways to get Image Dimensions (width and height)
http://weblogs.foxite.com/vfpimaging/archive/2007/05/28/3862.aspx
Autor: Cesar Ch.
Traducido por: Ana María Bisbé York
Una de las preguntas más comunes que he visto en los foros de VFP relacionadas con imágenes es "¿Cómo puedo obtener las dimensiones de un archivo de imagen?"
Afortunadamente, esto es muy fácil de obtener.
A continuación muestro varias técnicas que podemos utilizar, con una breve explicación. cada desarrollador puede escoger cuál de ellas es mejor para sus necesidades. Todas las técnicas son muy sencillas de utilizar. Para usuarios GDI+, lo muestro empleando 3 bibliotecas con las que ya he trabajado. Como bono, la última muestra cómo obtenerlo con GDI+ utilizando llamadas directas a API, para los que no quieren utilizar una clase envoltorio GDI+.
Todos los ejemplos a continuación son libres. Estoy seguro de que hay otras formas de hacerlo. Señalo solamente aquellas que conozco y he probado.
1.- Cargar la imagen en un objeto Image VFP
Esta técnica trabaja con cualquier versión VFP. Cuando asociamos un archivo a la propiedad PicturuFile de un objeto Image, va a guardar las dimensiones en las propiedades Width y Height.
2.- Utilizar la función LOADPICTURE()
El objeto devuelto por LOADPICTURE() es una instancia de la clase StdPicture. Los valores de altura y ancho son unidades HiMetric (1 HiMetric = 0.01 milímetro).
No estoy realmente seguro de cuál es la forma correcta para utilizar esta función para obtener las dimensiones de una imagen.
Lisa Slater Nicholls publicó hace mucho tiempo una función para obtener las dimensiones; pero a mí no me ha funcionado: http://www.spacefold.com/lisa/lisa_fx4.htm#loadpicture
En una discusión en Foxite, entre Eric den Doop y Boudewijn Lutgerik: http://www.foxite.com/archives/what-mysterious-calculation-is-behind-this-0000067503.htm, Boudewijn obtuvo las dimensiones utilizando un factor diferente.
En mi caso, escogí la técnica que encontré en http://www.xtremevbtalk.com/archive/index.php/t-13097.html
¡ Pero no confío en este proceder porque parece que depende de la resolución de la pantalla !
3.- Obtener la información de la cabecera del archivo imagen
Las dimensiones de la imagen se almacenan en sus binarios. El siguiente código utiliza FOPEN y FREAD para extraer esa información. Puede obtener las dimensiones para las imágenes tipo BMP, GIF y JPG.
4.- Utilizar GDIPlusX
GDI+ puede brindar esta información y muchas otras, fácilmente.
El ejemplo que muestro a continuación utiliza la biblioteca GdiPlusX de VFPX.
http://www.codeplex.com/VFPX/Wiki/View.aspx?title=GDIPlusX&referringTitle=Home
5.- Utilizar GPIMAGE2
El ejemplo que se muestra a continuación utiliza la biblioteca GpImage de Alexander Golovlev. En el siguiente enlace puede encontrar la versión más reciente para esta clase que contiene algunas funciones Graphics, que he agregado: http://cchalom.sites.uol.com.br/GPIMAGE
6.- Utilizar _GDIPLUS.VCX
El siguiente ejemplo utiliza la biblioteca de clases Foundations (FCC) _GdiPlus.vcx de Walter Nicholls, liberada con VFP9.
7.- Utilizar GDIPLUS con llamadas directas a API
Si no desea utilizar ninguna clase envoltorio GDI+, he aquí un código que obtiene las dimensiones de la imagen utilizando llamadas directas de API a gdiplus.dll. Asegúrese de tener gdiplus.dll en su sistema.
Gdiplus.dll está disponible gratis y se puede instalar con Win98 y superior. Si no tiene instalado WinXP or .NET runtime entonces debe bajar esta DLL desde http://www.microsoft.com/downloads/details.aspx?FamilyID=6a63ab9c-df12-4d41-933c-be590feaa05a&DisplayLang=en o directamente desde http://download.microsoft.com/download/platformsdk/redist/3097/W98NT42KMeXP/EN-US/gdiplus_dnld.exe
Puede obtener información valiosa sobre GDIPlus en el sitio oficial de Microsoft
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdicpp/GDIPlus/GDIPlusreference/flatgraphics.asp
Espero que esto ayude
¡ Que lo disfruten !
http://weblogs.foxite.com/vfpimaging/archive/2007/05/28/3862.aspx
Autor: Cesar Ch.
Traducido por: Ana María Bisbé York
Una de las preguntas más comunes que he visto en los foros de VFP relacionadas con imágenes es "¿Cómo puedo obtener las dimensiones de un archivo de imagen?"
Afortunadamente, esto es muy fácil de obtener.
A continuación muestro varias técnicas que podemos utilizar, con una breve explicación. cada desarrollador puede escoger cuál de ellas es mejor para sus necesidades. Todas las técnicas son muy sencillas de utilizar. Para usuarios GDI+, lo muestro empleando 3 bibliotecas con las que ya he trabajado. Como bono, la última muestra cómo obtenerlo con GDI+ utilizando llamadas directas a API, para los que no quieren utilizar una clase envoltorio GDI+.
Todos los ejemplos a continuación son libres. Estoy seguro de que hay otras formas de hacerlo. Señalo solamente aquellas que conozco y he probado.
1.- Cargar la imagen en un objeto Image VFP
Esta técnica trabaja con cualquier versión VFP. Cuando asociamos un archivo a la propiedad PicturuFile de un objeto Image, va a guardar las dimensiones en las propiedades Width y Height.
* Técnica 1 * Obtener las dimensiones del objeto Image LOCAL lcPictureFile lcPictureFile = GETPICT() LOCAL lnWidth, lnHeight LOCAL loVFPImg as Image loVFPImg = CREATEOBJECT("Image") loVFPImg.Picture = lcPictureFile lnWidth = loVFPImg.Width lnHeight = loVFPImg.Height loVFPImg = NULL MESSAGEBOX("Objeto Image VFP " + CHR(13) + ; "Dimensiones: " + TRANSFORM(lnWIdth) + " x " + TRANSFORM(lnHeight))
2.- Utilizar la función LOADPICTURE()
El objeto devuelto por LOADPICTURE() es una instancia de la clase StdPicture. Los valores de altura y ancho son unidades HiMetric (1 HiMetric = 0.01 milímetro).
No estoy realmente seguro de cuál es la forma correcta para utilizar esta función para obtener las dimensiones de una imagen.
Lisa Slater Nicholls publicó hace mucho tiempo una función para obtener las dimensiones; pero a mí no me ha funcionado: http://www.spacefold.com/lisa/lisa_fx4.htm#loadpicture
En una discusión en Foxite, entre Eric den Doop y Boudewijn Lutgerik: http://www.foxite.com/archives/what-mysterious-calculation-is-behind-this-0000067503.htm, Boudewijn obtuvo las dimensiones utilizando un factor diferente.
En mi caso, escogí la técnica que encontré en http://www.xtremevbtalk.com/archive/index.php/t-13097.html
¡ Pero no confío en este proceder porque parece que depende de la resolución de la pantalla !
* Técnica 2 * Obtener las dimensiones del objeto Imagen utilizando la función LOADPICT() * Código de Lisa Slater Nicholls * El objeto devuelto por LOADPIC() es una instancia de la clase StdPicture. * Los valores de altura y ancho son unidades HiMetric (1 HiMetric = 0.01 milímetro). * http://www.foxite.com/archives/what-mysterious-calculation-is-behind-this-0000067503.htm * http://www.xtremevbtalk.com/archive/index.php/t-13097.html LOCAL lcPictureFile lcPictureFile = GETPICT() LOCAL lnWidth, lnHeight LOCAL loLoadedPict loLoadedPict = LOADPICTURE(lcPictureFile) lnHeight = ROUND((loLoadedPict.Height / 26.45454545455),0) lnWidth = ROUND((loLoadedPict.Width / 26.45454545455),0) loLoadedPict = NULL MESSAGEBOX("Función VFP LOADPICTURE()" + CHR(13) + ; "Dimensiones: " + TRANSFORM(lnWidth) + " x " + TRANSFORM(lnHeight))
3.- Obtener la información de la cabecera del archivo imagen
Las dimensiones de la imagen se almacenan en sus binarios. El siguiente código utiliza FOPEN y FREAD para extraer esa información. Puede obtener las dimensiones para las imágenes tipo BMP, GIF y JPG.
* Técnica 3 * Obtener la información de la cabecera del archivo imagen * Los ejemplos se han adaptado a partir de las funciones de Thomas Gehrke en West-Wind Wiki: * http://www.west-wind.com/wiki/wc.dll?wc~JpgSizeFunction * http://www.west-wind.com/wiki/wc.dll?wc~GifSizeFunction LOCAL lcPictureFile lcPictureFile = GETPICT() LOCAL lnWidth, lnHeight, lcExt lcExt = LOWER(JUSTEXT(lcPictureFile)) DO CASE CASE lcExt = "bmp" LOCAL lnHandle, lcBytes lnHandle = FOPEN(lcPictureFile) IF m.lnHandle > -1 * Leer los primeros 27 bytes: lcBytes = FREAD( m.lnHandle, 27) = FCLOSE( m.lnHandle) lnWidth = CTOBIN(SUBSTR(lcBytes,19,4),"4RS") lnHeight = CTOBIN(SUBSTR(lcBytes,23,4),"4RS") ENDIF CASE lcExt = "gif" LOCAL lnHandle, lcBytes lnHandle = FOPEN(lcPictureFile) IF m.lnHandle > -1 * Leer los primeros 10 bytes: lcBytes = FREAD( m.lnHandle, 10) = FCLOSE( m.lnHandle) lnWidth = CTOBIN(SUBSTR( m.lcBytes, 7, 2),"2RS") lnHeight = CTOBIN(SUBSTR( m.lcBytes, 9, 2),"2RS") ENDIF CASE lcExt = "jpg" LOCAL lnHandle, lcBytes lnHandle = FOPEN(lcPictureFile) IF m.lnHandle > -1 LOCAL lnFileSize, lnCounter, lcBytes lnFileSize = FSEEK( m.lnHandle, 0, 2) lnCounter = 0 = FSEEK( m.lnHandle, 0, 0) FOR lnCounter = 1 TO m.lnFileSize - 2 lcBytes = FREAD( m.lnHandle, 3) IF m.lcBytes = CHR(0) + CHR(17) + CHR(8) OR ; m.lcBytes = CHR(0) + CHR(11) + CHR(8) * ¡Encontrar las marcas de bloque para las dimensiones! lcBytes = FREAD( m.lnHandle, 4) EXIT ELSE = FSEEK( m.lnHandle, -2, 1) ENDIF ENDFOR = FCLOSE( m.lnHandle) lnWidth = CTOBIN(SUBSTR( m.lcBytes, 3, 2),"2S") lnHeight = CTOBIN(SUBSTR( m.lcBytes, 1, 2),"2S") ENDIF ENDCASE MESSAGEBOX("Información desde la cabecera de imagen" + CHR(13) + ; "Dimensiones: " + TRANSFORM(lnWIdth) + " x " + TRANSFORM(lnHeight))
4.- Utilizar GDIPlusX
GDI+ puede brindar esta información y muchas otras, fácilmente.
El ejemplo que muestro a continuación utiliza la biblioteca GdiPlusX de VFPX.
http://www.codeplex.com/VFPX/Wiki/View.aspx?title=GDIPlusX&referringTitle=Home
* Técnica 4 * Obtener la información de la imagen utilizando GDI+, con GdiPlusX * http://www.codeplex.com/VFPX/Wiki/View.aspx?title=GDIPlusX&referringTitle=Home LOCAL lcPictureFile lcPictureFile = GETPICT() LOCAL lnWidth, lnHeight _SCREEN.AddProperty("System", NEWOBJECT("xfcSystem", LOCFILE("system.vcx","vcx"))) WITH _SCREEN.System.Drawing * Crear un Bitmap nuevo LOCAL loBmp as xfcBitmap loBmp = .Bitmap.FromFile(lcPictureFile) lnWidth = loBmp.Width lnHeight = loBmp.Height loBmp = NULL MESSAGEBOX("Biblioteca GDI+ - GdiPlusX" + CHR(13) + ; "Dimensiones: " + TRANSFORM(lnWIdth) + " x " + TRANSFORM(lnHeight)) ENDWITH
5.- Utilizar GPIMAGE2
El ejemplo que se muestra a continuación utiliza la biblioteca GpImage de Alexander Golovlev. En el siguiente enlace puede encontrar la versión más reciente para esta clase que contiene algunas funciones Graphics, que he agregado: http://cchalom.sites.uol.com.br/GPIMAGE
* Técnica 5 * Obtener la información de la imagen utilizando GDI+, con GpImage2 * http://cchalom.sites.uol.com.br/GPIMAGE LOCAL lcPictureFile lcPictureFile = GETPICT() LOCAL lnWidth, lnHeight IF Not "gpImage" $ SET("Procedure") SET PROCEDURE TO gpImage ADDITIVE ENDIF loGdip = CREATEOBJECT("gpInit") loBmp = CREATEOBJECT("gpImage") loBmp.Load(lcPictureFile) lnWidth = loBmp.ImageWidth lnHeight = loBmp.ImageHeight loBmp = NULL loGdip = NULL MESSAGEBOX("GDI+ library - GpImage2" + CHR(13) + ; "Dimensiones: " + TRANSFORM(lnWIdth) + " x " + TRANSFORM(lnHeight))
6.- Utilizar _GDIPLUS.VCX
El siguiente ejemplo utiliza la biblioteca de clases Foundations (FCC) _GdiPlus.vcx de Walter Nicholls, liberada con VFP9.
* Técnica 6 * Obtener la información de la imagen utilizando GDI+, con _GdiPlus.vcx, de Walter Nicholls LOCAL lcPictureFile lcPictureFile = GETPICT() LOCAL lnWidth, lnHeight LOCAL loBitmap as GpBitmap OF HOME() + "/FFC/_GdiPlus.vcx" loBitmap = NEWOBJECT("GpBitmap", HOME() + "/FFC/_GdiPlus.vcx") loBitmap.CreateFromFile(lcPictureFile) lnWidth = loBitmap.ImageWidth lnHeight = loBitmap.ImageHeight loBitmap = NULL MESSAGEBOX("Biblioteca GDI+ - FFC _GdiPlus.vcx" + CHR(13) + ; "Dimensiones: " + TRANSFORM(lnWIdth) + " x " + TRANSFORM(lnHeight))
7.- Utilizar GDIPLUS con llamadas directas a API
Si no desea utilizar ninguna clase envoltorio GDI+, he aquí un código que obtiene las dimensiones de la imagen utilizando llamadas directas de API a gdiplus.dll. Asegúrese de tener gdiplus.dll en su sistema.
Gdiplus.dll está disponible gratis y se puede instalar con Win98 y superior. Si no tiene instalado WinXP or .NET runtime entonces debe bajar esta DLL desde http://www.microsoft.com/downloads/details.aspx?FamilyID=6a63ab9c-df12-4d41-933c-be590feaa05a&DisplayLang=en o directamente desde http://download.microsoft.com/download/platformsdk/redist/3097/W98NT42KMeXP/EN-US/gdiplus_dnld.exe
Puede obtener información valiosa sobre GDIPlus en el sitio oficial de Microsoft
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdicpp/GDIPlus/GDIPlusreference/flatgraphics.asp
* Técnica 7 * Obtener información de la imagen utilizando GDI+, con lamadas directas de API LOCAL lcPictureFile lcPictureFile = GETPICT() * API Declarations for GDI+ DECLARE LONG GdiplusStartup IN GDIPLUS.DLL ; LONG @ token, STRING @ INPUT, LONG @ OUTPUT DECLARE LONG GdiplusShutdown IN GDIPLUS.DLL LONG token DECLARE INTEGER GdipLoadImageFromFile IN GDIPLUS.DLL ; STRING wFilename, INTEGER @ nImage DECLARE INTEGER GdipDisposeImage IN GDIPLUS.DLL INTEGER nImage DECLARE INTEGER GdipGetImageWidth IN GDIPLUS.DLL ; INTEGER nImage, INTEGER @ nWidth DECLARE INTEGER GdipGetImageHeight IN GDIPLUS.DLL ; INTEGER nImage, INTEGER @ nHeight * Inicializar GDI+. LOCAL gdiplusStartupInput, lhGdiPlusToken gdiplusStartupInput = CHR(1) + REPLICATE(CHR(0), 15) lhGdiPlusToken = 0 IF GdiplusStartup(@lhGdiPlusToken, @gdiplusStartupInput, 0) != 0 RETURN .F. ENDIF * Cargar el objeto Picture LOCAL lnPictHandle lnPictHandle = 0 = GdipLoadImageFromFile( STRCONV(lcPictureFile + CHR(0),5), @lnPictHandle) * Obtener las dimensiones de la imagen LOCAL lnWidth, lnHeight STORE 0 TO lnWidth, lnHeight = GdipGetImageWidth(lnPictHandle, @lnWidth) = GdipGetImageHeight(lnPictHandle, @lnHeight) * Limpiar el controlador principal GDI+ = GdiplusShutdown(lhGdiPlusToken) MESSAGEBOX("GDI+ con llamadas API" + CHR(13) + ; "Dimensiones: " + TRANSFORM(lnWidth) + " x " + TRANSFORM(lnHeight))
Espero que esto ayude
¡ Que lo disfruten !
2 de julio de 2007
Convertir imágenes a color monocromático con GdiPlusX
Artículo original: Convert Images to Monochrome with GdiPlus X
http://weblogs.foxite.com/vfpimaging/archive/2007/05/26/3857.aspx
Autor: Cesar Ch.
Traducido por: Ana María Bisbé York
Cada cierto tiempo, alguien pregunta sobre la creación de imágenes monocromáticas, que en la mayoría de los casos se utilizarán para enviar por Fax.
Desafortunadamente, GDI+ no brinda soporte para imágenes indexadas a 1 bpp (bipmaps monocromos)
Pero con la ayuda de Anatoliy Mogylevets y Mike Gagnon pude encontrar que la buena y vieja GDI (no GdiPlus) ofrece algunas funciones (CopyImage y LoadImage) para hacerlo en un flash. Entonces, estuvimos de acuerdo en añadir esta importante funcionalidad a la biblioteca como un método nuevo agregado a las clases Image y Bitmap: GetMonochrome().
Pasos para obtener la versión 1bpp monocromática de cualquier imagen utilizando las clases GDI+X
Todos los ejemplos siguientes utilizan la nueva biblioteca GdiPlus-X, que está en versión ALPHA; pero que es muy estable y fiable para hacer la mayoría de las tareas GDI+. Descargue la versión más actualizada desde Codeplex:
http://www.codeplex.com/Wiki/View.aspx?ProjectName=VFPX&title=GDIPlusX
Este es el código de ejemplo:
La primera imagen tiene buen aspecto, a que si?
Pero el logo VFPX no aparece en color monocromático. Esto ocurre porque el fondo naranja del texto es oscuro y GDI lo convierte en negro.
Pero utilizando un truco podemos arreglarlo, al convertir la imagen en escala de grises antes de convertirlo en monocromático. No está dentro del alcance de este corto artículo explicar cómo hacer esto, porque ya me dediqué a esto profundamente en dos artículos publicados en UTMAG Special effects on images with new GDIPlus-X classes - Part 1 y Special effects on images with new GDIPlus-X classes - Part 2.
Para convertir a escala de grises, podemos utilizar una matriz de color que va a convertir cada píxel en un promedio entre sus componentes rojo, azul y verde. Para escala de grises normalmente multiplicamos cada componente de color con 0.33 (1/3). Para obtener una imagen más brillante tenemos que multiplicar cada componente por un factor más alto.
Por tanto, he aquí los pasos para convertir a color monocromático:
Enlaces relacionados:
Artículos en UTMAG
http://weblogs.foxite.com/vfpimaging/archive/2007/05/26/3857.aspx
Autor: Cesar Ch.
Traducido por: Ana María Bisbé York
Cada cierto tiempo, alguien pregunta sobre la creación de imágenes monocromáticas, que en la mayoría de los casos se utilizarán para enviar por Fax.
Desafortunadamente, GDI+ no brinda soporte para imágenes indexadas a 1 bpp (bipmaps monocromos)
Pero con la ayuda de Anatoliy Mogylevets y Mike Gagnon pude encontrar que la buena y vieja GDI (no GdiPlus) ofrece algunas funciones (CopyImage y LoadImage) para hacerlo en un flash. Entonces, estuvimos de acuerdo en añadir esta importante funcionalidad a la biblioteca como un método nuevo agregado a las clases Image y Bitmap: GetMonochrome().
Pasos para obtener la versión 1bpp monocromática de cualquier imagen utilizando las clases GDI+X
- Cargar la imagen con GdiPlus
- Llamar a Image.GetMonochrome para obtener un objeto nuevo que contenga la imagen 1bpp.
- Guardar normalmente como Bmp.
Todos los ejemplos siguientes utilizan la nueva biblioteca GdiPlus-X, que está en versión ALPHA; pero que es muy estable y fiable para hacer la mayoría de las tareas GDI+. Descargue la versión más actualizada desde Codeplex:
http://www.codeplex.com/Wiki/View.aspx?ProjectName=VFPX&title=GDIPlusX
Este es el código de ejemplo:
_SCREEN.AddProperty("System", NEWOBJECT("xfcSystem", LOCFILE("system.vcx","vcx"))) WITH _SCREEN.System.Drawing * Crear un objeto Bitmap basado en un archivo BMP. LOCAL loOriginalBmp AS xfcBitmap loOriginalBmp = .Bitmap.New(GETPICT()) LOCAL loMonoChrBmp as xfcBitmap loMonoChrBmp = loOriginalBmp.GetMonochrome() * Guardar el Bmp monocromático que ha sido creado loMonoChrBmp.Save("c:\Monocromatico.bmp", .Imaging.ImageFormat.Bmp) ENDWITH RETURNY este es el resultado para dos imágenes:
La primera imagen tiene buen aspecto, a que si?
Pero el logo VFPX no aparece en color monocromático. Esto ocurre porque el fondo naranja del texto es oscuro y GDI lo convierte en negro.
Pero utilizando un truco podemos arreglarlo, al convertir la imagen en escala de grises antes de convertirlo en monocromático. No está dentro del alcance de este corto artículo explicar cómo hacer esto, porque ya me dediqué a esto profundamente en dos artículos publicados en UTMAG Special effects on images with new GDIPlus-X classes - Part 1 y Special effects on images with new GDIPlus-X classes - Part 2.
Para convertir a escala de grises, podemos utilizar una matriz de color que va a convertir cada píxel en un promedio entre sus componentes rojo, azul y verde. Para escala de grises normalmente multiplicamos cada componente de color con 0.33 (1/3). Para obtener una imagen más brillante tenemos que multiplicar cada componente por un factor más alto.
Por tanto, he aquí los pasos para convertir a color monocromático:
- Crear la imagen originar con GDI+
- Crear un Bitmap nuevo temporal del mismo tamaño que el original
- Crear un objeto ImageAttributes
- Aplicar una matriz de color con escala de grises a la imagen Attributes
- Dibujar la imagen original utilizando ImageAttributes
- Guardar la imagen
_SCREEN.AddProperty("System", NEWOBJECT("xfcSystem", LOCFILE("system.vcx","vcx"))) WITH _SCREEN.System.Drawing LOCAL lcImgFile lcImgFile = GETPICT() * Crea un objeto Bitmap basado en un archivo BMP. LOCAL loOriginalBmp AS xfcBitmap loOriginalBmp = .Bitmap.FromFile(lcImgFile) LOCAL loTempBmp as xfcBitmap loTempBmp = .Bitmap.New(loOriginalBmp.Width, loOriginalBmp.Height) LOCAL loGfx as xfcGraphics loGfx = .Graphics.FromImage(loTempBmp) LOCAL loAttr as xfcImageAttributes LOCAL loGreyScaleMatrix as xfcColorMatrix LOCAL loMonoChrBmp as xfcBitmap LOCAL loRectBounds as xfcRectangle loRectBounds = loOriginalBmp.GetBounds() FOR lnFactor = .10 TO 1 STEP .10 loGreyScaleMatrix = _Screen.System.Drawing.Imaging.ColorMatrix.New( ; lnFactor, lnFactor, lnFactor, 0.0, 0.0, ; lnFactor, lnFactor, lnFactor, 0.0, 0.0, ; lnFactor, lnFactor, lnFactor, 0.0, 0.0, ; 0.0 , 0.0 , 0.0 , 1.0, 0.0, ; 0.0 , 0.0 , 0.0 , 0.0, 1.0) loAttr = NULL loAttr = .Imaging.ImageAttributes.New() loAttr.SetColorMatrix(loGreyScaleMatrix) * Dibujar una imagen con las transformaciones en la matriz de colores loGfx.DrawImage(loOriginalBmp, loRectBounds, loRectBounds, 2, loAttr) loMonoChrBmp = loTempBmp.GetMonochrome() * Guarda el Bmp monocromático que ha sido creado loMonoChrBmp.Save("c:\" + JUSTSTEM(lcImgFile) + ; TRANSFORM(lnFactor * 100) + ".bmp", .Imaging.ImageFormat.Bmp) ENDFOR ENDWITH RETURNY esta vez podemos obtener mejores resultados, acorde con el factor deseado.
Imagen Original |
||||
Factor = 10 | Factor = 20 | Factor = 30 | Factor = 40 | Factor = 50 |
Factor = 60 | Factor = 70 | Factor = 80 | Factor = 90 | Factor = 100 |
Imagen Original |
||||
Factor = 10 | Factor = 20 | Factor = 30 | Factor = 40 | Factor = 50 |
Factor = 60 | Factor = 70 | Factor = 80 | Factor = 90 | Factor = 100 |
Enlaces relacionados:
Artículos en UTMAG
Suscribirse a:
Entradas
(
Atom
)