Artículo original: Captcha Image Generator with GdiPlus-X
https://vfpimaging.blogspot.com/2012/03/captcha-image-generator-with-gdiplusx.html
Autor: Cesar Ch.
Traducido por: Ana María Bisbé York
Recientemente, estaba navegando por el Blog de Rick Stralh cuando encontré un escrito muy interesante, "A Captcha Image generator for FoxPro", en el cual el muestra cómo crear algunas imágenes "captcha".
Nota de la Traductora: CAPTCHA es el acrónimo de "Completely Automated Public Turing test to tell Computers and Humans Apart", y consiste en una verificación automatizada para determinar si el usuario que realiza la petición es humano o no.
Como ha dicho Rick Stralh en su escrito, "CAPTCHA muestra básicamente una imagen de verificación junto a un cuadro de texto que tiene que ser llenado para verificar la petición actual. No es un procedimiento infalible para la validación y tiene algunos problemas de accesibilidad; pero parece que es la solución más frecuente a este problema." La imagen generada contiene un texto aleatorio.
En este caso, Rick Stralh escogió crear una DLL en C++, y la llama desde VFP. Aquí mostraré cómo obtener los mismos resultados utilizando la nueva biblioteca GdiPlus-X.
El código que se muestra a continuación pudiera ser útil para otros propósitos también, porque se utilizaron algunas técnicas de dibujo muy interesantes.
Para obtener la cadena aleatoria, creé una función muy simple, que recibe como un parámetro de cantidad de caracteres que se crearán.
PROCEDURE CreateString(tnLength LOCAL lcText, lcChar, x, n lcText = "" FOR n = 1 TO tnLength x = INT(RAND() * 36) lcChar = IIF(x < 10, TRANSFORM(x), CHR(x + 55)) lcText = lcText + lcChar ENDFOR RETURN lcText ENDPROC
¡ A JUGAR !
IMPORTANTE:
Todos los ejemplos que se muestran emplean la nueva biblioteca GDIPlus-X, que está aun en versión ALPHA; pero es estable y fiable para hacer la mayoría de las tareas de GDI+. Descargue la última versión estable de Codeplex:
http://www.codeplex.com/Wiki/View.aspx?ProjectName=VFPX&title=GDIPlusX
EJEMPLO 1 - CREAR UN IMAGEN SENCILLA Y DIBUJE ALGÚN TEXTO
** Generador de imágenes Captcha ** Crea una imagen muy sencilla que contiene una cadena ** Se basa en el código de Rick Strahl expuesto en su weblog ** http://www.west-wind.com/wconnect/weblog/ShowEntry.blog?id=556 ** El siguiente ejemplo muestra como crear un sencillo Generador de imágenes Captcha LOCAL lcText AS Character lcText = CreateString(8) _SCREEN.AddProperty("System", NEWOBJECT("xfcSystem", ; LOCFILE("system.vcx","vcx"))) LOCAL loBmp AS xfcBitmap LOCAL loFont AS xfcFont LOCAL loSizeF AS xfcSizeF LOCAL loScreenGfx AS xfcGraphics LOCAL loGfx AS xfcGraphics WITH _SCREEN.System.Drawing loScreenGfx = .Graphics.FromHwnd(_Screen.HWnd) loFont = .Font.New("Tahoma",20) && Font Name, Size * Obtiene la altura y el ancho necesarios para la cadena loSizeF = loScreenGfx.MeasureString(lcText, loFont) * Crea un bitmap nuevo loBmp = .Bitmap.New(loSizeF.Width, loSizeF.Height) * Obtiene un objeto Graphics para dibujar loGfx = .Graphics.FromImage(loBmp) loGfx.Clear(.Color.White) * Dibuja toda la cadena loGfx.DrawString(lcText, loFont, .Brushes.Black, 0, 0) * Guarda la imagen en disco loBmp.Save("c:\captcha1.png", .Imaging.ImageFormat.Png) ENDWITH * Muestra la imagen en el explorador RUN /n explorer.exe c:\captcha1.png RETURN PROCEDURE CreateString(tnLength) LOCAL lcText, lcChar, x, n lcText = "" FOR n = 1 TO tnLength x = INT(RAND() * 36) lcChar = IIF(x < 10, TRANSFORM(x), CHR(x + 55)) lcText = lcText + lcChar ENDFOR RETURN lcText ENDPROC
El ejemplo de arriba crea la imagen más sencilla, que contiene una cadena aleatoria dentro. para obtener el tamaño necesario para crear el Bitmap, en el primer momento, he creado un objeto Graphics desde _Screen. Como se puede ver a continuación, este objeto tiene solamente una tarea: permitirnos llamar a la función MeasureString para obtener el tamaño necesario para nuestro bitmap.
loScreenGfx = .Graphics.FromHwnd(_Screen.HWnd) loFont = .Font.New("Tahoma",20) && FontName, FontSize * Obtiene la altura y el ancho necesarios para la cadena loSizeF = loScreenGfx.MeasureString(lcText, loFont) * Crea un bitmap nuevo loBmp = .Bitmap.New(loSizeF.Width, loSizeF.Height)
EJEMPLO 2 - CREA UNA IMAGEN SENCILLA Y DIBUJA UN TEXTO SOBRE UN FONDO TRAMADO.
** Generador de imágenes Captcha ** Crea una imagen muy sencilla que contiene una cadena con un fondo tramado ** Se basa en el código de Rick Strahl expuesto en su weblog ** http://www.west-wind.com/wconnect/weblog/ShowEntry.blog?id=556 ** El siguiente ejemplo muestra como crear un sencillo Generador de imágenes Captcha LOCAL lcText AS Character lcText = CreateString(8) _SCREEN.AddProperty("System", NEWOBJECT("xfcSystem", ; LOCFILE("system.vcx","vcx"))) LOCAL loBmp AS xfcBitmap LOCAL loFont AS xfcFont LOCAL loSizeF AS xfcSizeF LOCAL loScreenGfx AS xfcGraphics LOCAL loGfx AS xfcGraphics WITH _SCREEN.System.Drawing loScreenGfx = .Graphics.FromHwnd(_Screen.HWnd) loFont = .Font.New("Tahoma",20) && Font Name, Size * Obtiene la altura y el ancho necesarios para la cadena loSizeF = loScreenGfx.MeasureString(lcText, loFont) * Crea un bitmap nuevo loBmp = .Bitmap.New(loSizeF.Width, loSizeF.Height) * Obtiene un objeto Graphics para dibujar loGfx = .Graphics.FromImage(loBmp) loGfx.Clear(.Color.White) liRand = INT(RAND()*52) + 1 * Rellena el fondo del rectángulo con una brocha tramada de forma aleatoria loGfx.FillRectangle( ; .Drawing2D.HatchBrush.New(liRand, .Color.Black, .Color.White),; 0,0,loBmp.Width,loBmp.Height) * Dibuja toda la cadena loGfx.DrawString(lcText, loFont, .Brushes.Black, 0, 0) * Guarda la imagen en disco loBmp.Save("c:\captcha2.png", .Imaging.ImageFormat.Png) ENDWITH * Muestra la imagen en el explorador RUN /n explorer.exe c:\captcha2.png RETURN PROCEDURE CreateString(tnLength) LOCAL lcText, lcChar, x, n lcText = "" FOR n = 1 TO tnLength x = INT(RAND() * 36) lcChar = IIF(x < 10, TRANSFORM(x), CHR(x + 55)) lcText = lcText + lcChar ENDFOR RETURN lcText ENDPROC
Este es exactamente el mismo ejemplo que utilizamos antes; pero agregando un fondo tramado. GDI+ ofrece 52 plantillas diferentes para brochas con tramas. En este ejemplo, preferí utilizar uno aleatorio. Verifíquelo y seleccione el que le guste más:
* Rellena el fondo del rectángulo con una brocha tramada de forma aleatoria loGfx.FillRectangle( ; .Drawing2D.HatchBrush.New(liRand, .Color.Black, .Color.White),; 0,0,loBmp.Width,loBmp.Height)
EJEMPLO 3 - DIBUJAR ALGÚN TEXTO CON UN FONDO COLOREADO UTILIZANDO COLORES ALEATORIOS
** Generador de imágenes Captcha ** Crea una imagen muy sencilla que contiene una cadena ** Cada carácter en color aleatorio diferente con un color de fondo aleatorio ** Se basa en el código de Rick Strahl expuesto en su weblog ** http://www.west-wind.com/wconnect/weblog/ShowEntry.blog?id=556 ** El siguiente ejemplo muestra como crear un sencillo Generador de imágenes Captcha LOCAL lcText AS Character lcText = CreateString(8) _SCREEN.AddProperty("System", NEWOBJECT("xfcSystem", ; LOCFILE("system.vcx","vcx"))) LOCAL loBmp AS xfcBitmap LOCAL loFont AS xfcFont LOCAL loSizeF AS xfcSizeF LOCAL loScreenGfx AS xfcGraphics LOCAL loGfx AS xfcGraphics WITH _SCREEN.System.Drawing loScreenGfx = .Graphics.FromHwnd(_Screen.HWnd) loFont = .Font.New("Tahoma",20) && Font Name, Size * Obtiene la altura y el ancho necesarios para la cadena loSizeF = loScreenGfx.MeasureString(lcText, loFont) LOCAL lnWidth, lnHeight, lnCharWidth lnWidth = loSizeF.Width * 1.5 && Se estrecha al 50% para garantizar que quepan los caracteres rotados lnHeight = loSizeF.Height lnCharWidth = lnWidth / LEN(lcText) * Crea un bitmap nuevo loBmp = .Bitmap.New(lnWidth, lnHeight) * Obtiene un objeto Graphics para dibujar loGfx = .Graphics.FromImage(loBmp) loGfx.Clear(.Color.White) * Llena el fondo del rectángulo con una brocha sólida de color aleatorio * Necesitamos aquí un color pastel color, por lo que haremos que cada canal sea al menos 180 * Dibuja el rectángulo de fondo loGfx.FillRectangle( ; .SolidBrush.New(.Color.FromARGB(255, INT(RAND() * 76)+180, ; INT(RAND() * 76)+180, INT(RAND() * 76)+180)), ; 0,0,loBmp.Width,loBmp.Height) * Dibuja cada carácter en un color aleatorio diferente LOCAL n, lcChar LOCAL loBrush AS xfcSolidBrush FOR n = 0 TO LEN(lcText) lcChar = SUBSTR(lcText, n, 1) * Crea una brocha con un color aleatorio loBrush = .SolidBrush.New(.Color.FromRGB(INT(RAND() * 0xFFFFFF))) * Dibuja el carácter loGfx.DrawString(lcChar, loFont, loBrush, (n-1) * lnCharWidth, 0) ENDFOR * Guarda la imagen en disco loBmp.Save("c:\captcha3.png", .Imaging.ImageFormat.Png) ENDWITH * Muestra la imagen en el explorador RUN /n explorer.exe c:\captcha3.png RETURN PROCEDURE CreateString(tnLength) LOCAL lcText, lcChar, x, n lcText = "" FOR n = 1 TO tnLength x = INT(RAND() * 36) lcChar = IIF(x < 10, TRANSFORM(x), CHR(x + 55)) lcText = lcText + lcChar ENDFOR RETURN lcText ENDPROC
Esta vez decidí crear un fondo utilizando una brocha sólida con un valor aleatorio en BackColor. Quise asegurarme de obtener un color pastel, por que utilicé:
INT(RAND() * 76) + 180 para cada canal de color RGB. Esta forma, cada canal tendrá al menos el valor 180, asegurando que obtenga un color brillante.
También muy sencillo dibujar cada color en un color aleatorio. Solamente hice un lazo de la cadena y dibujé cada caracter en su posición proporcional. Este momento, deseo tener cualquier color aleatorio, por tanto podría ser cualquier valor entre 0 (RGB[0,0,0] - negro) y 0xFFFFFF (RGB[255,255,255] - blanco).
* Crea una brocha con un color aleatorio loBrush = .SolidBrush.New(.Color.FromRGB(INT(RAND() * 0xFFFFFF)))
EJEMPLO 4 - DIBUJAR ALGÚN TEXTO EN UN FONDO CON TRAMA COLOREADA UTILIZANDO COLORES ALEATORIOS CON ROTACIÓN DE CARACTERES.
** Generador de imágenes Captcha ** Crea una imagen muy sencilla que contiene una cadena ** Cada carácter en color aleatorio diferente y una ligera rotación ** Se basa en el código de Rick Strahl expuesto en su weblog ** http://www.west-wind.com/wconnect/weblog/ShowEntry.blog?id=556 ** El siguiente ejemplo muestra como crear un sencillo Generador de imágenes Captcha LOCAL lcText AS Character lcText = CreateString(8) _SCREEN.AddProperty("System", NEWOBJECT("xfcSystem", ; LOCFILE("system.vcx","vcx"))) LOCAL loBmp AS xfcBitmap LOCAL loFont AS xfcFont LOCAL loSizeF AS xfcSizeF LOCAL loScreenGfx AS xfcGraphics LOCAL loGfx AS xfcGraphics WITH _SCREEN.System.Drawing loScreenGfx = .Graphics.FromHwnd(_Screen.HWnd) loFont = .Font.New("Tahoma",20) && Font Name, Size * Obtiene la altura y el ancho necesarios para la cadena loSizeF = loScreenGfx.MeasureString(lcText, loFont) LOCAL lnWidth, lnHeight, lnCharWidth lnWidth = loSizeF.Width * 1.5 && Se estrecha al 50% para garantizar que quepan los caracteres rotados lnHeight = loSizeF.Height lnCharWidth = lnWidth / LEN(lcText) * Crea un bitmap nuevo loBmp = .Bitmap.New(lnWidth, lnHeight) * Obtiene un objeto Graphics para dibujar loGfx = .Graphics.FromImage(loBmp) loGfx.Clear(.Color.White) * Llena el fondo del rectángulo con una brocha sólida de colores pastel aleatorios loGfx.FillRectangle( ; .Drawing2D.HatchBrush.New(INT(RAND()*52), ; .Color.FromARGB(255, INT(RAND() * 76)+180, INT(RAND() * 76)+180, INT(RAND() * 76)+180), ; .Color.FromARGB(255, INT(RAND() * 76)+180, INT(RAND() * 76)+180, INT(RAND() * 76)+180)), ; 0,0,loBmp.Width,loBmp.Height) * Dibuja cada carácter en un color aleatorio diferente * y un ángulo aleatorio de rotación desde -40 a +40 grados LOCAL n, lcChar LOCAL loBrush AS xfcSolidBrush LOCAL loMatrix AS xfcMatrix FOR n = 0 TO LEN(lcText) lcChar = SUBSTR(lcText, n, 1) * Crea una brocha con un color aleatorio loBrush = .SolidBrush.New(.Color.FromRGB(INT(RAND() * 0xFFFFFF))) * Crea una matriz para aplicar la rotación de los caracteres loMatrix = _Screen.System.Drawing.Drawing2D.Matrix.New() * Calcula el ángulo aleatorio lnAngle = INT(RAND() * 80) - 40 * Rota al centro de cada posición de carácter loMatrix.RotateAt(lnAngle, ; .Point.New((n-1) * lnCharWidth + (lnCharWidth / 2), lnHeight / 2)) * Asocia la matriz al objeto Graphics loGfx.Transform = loMatrix * Dibuja el carácter loGfx.DrawString(lcChar, loFont, loBrush, (n-1) * lnCharWidth, 0) ENDFOR * Guarda la imagen en disco loBmp.Save("c:\captcha4.png", .Imaging.ImageFormat.Png) ENDWITH * Muestra la imagen en el explorador RUN /n explorer.exe c:\captcha4.png RETURN PROCEDURE CreateString(tnLength) LOCAL lcText, lcChar, x, n lcText = "" FOR n = 1 TO tnLength x = INT(RAND() * 36) lcChar = IIF(x < 10, TRANSFORM(x), CHR(x + 55)) lcText = lcText + lcChar ENDFOR RETURN lcText ENDPROC
Aquí hicimos lo mismo; pero utilizando una brocha con trama para el fondo, y aplicando una ligera rotación de cada carácter. La rotación de caracteres ya se ha discutido en un escrito anterior http://weblogs.foxite.com/vfpimaging/2012/03/16/draw-rotated-strings-with-gdiplusx en cualquier caso, he aquí una corta explicación:
"System.Drawing" brinda un método que permite dibujar cualquier objeto (forma, texto y otra imagen) utilizando rotación, de cualquier ángulo. Para esto necesitamos crear un objeto Matriz, y utilizamos el método "RotateAt", pasando el punto central del objeto que se rotará. En este caso, necesito pasar el centro de la cadena.
* Crea una matriz para aplicar la rotación de los caracteres loMatrix = .Drawing2D.Matrix.New() * Calcula el ángulo aleatorio lnAngle = INT(RAND() * 80) - 40 * Rota al centro de cada posición de carácter loMatrix.RotateAt(lnAngle, ; .Point.New((n-1) * lnCharWidth + (lnCharWidth / 2), lnHeight / 2)) * Asocia la matriz al objeto Graphics loGfx.Transform = loMatrix * Dibuja el carácter loGfx.DrawString(lcChar, loFont, loBrush, (n-1) * lnCharWidth, 0)
¿QUÉ MÁS?
Podemos hacer algunas otras cosas, tales como dibujar algunas líneas aleatorias en la imagen. Una forma podría ser simplemente agregando este sencillo código inmediatamente antes de guardar la imagen:
LOCAL x1, y1, x2, y2, lnColor FOR n = 1 TO 10 x1 = RAND() * lnWidth x2 = RAND() * lnWidth y1 = RAND() * lnHeight y2 = RAND() * lnHeight lnColor = RAND() * 0xFFFFFF loGfx.DrawLine(.Pen.New(.Color.FromRGB(lnColor),1),x1, y1, x2, y2) ENDFOR
A pesar de que se conoce que estos son únicamente algunos CAPTCHA decoradores, puede ser muy útil en determinadas situaciones. Mi objetivo en este escrito es simplemente mostrar algunas técnicas para crear buenos captchas. Hay mucho que mejorar. Usted puede utilizar fuentes irregulares aleatorias, otros fondos, aplicar algunas transformaciones a caracteres, como escalar, cortes, nublados, efectos halo. ¡ Todo esto con GDI+ !
En la próxima liberación de la biblioteca, espero enviar algunos ejemplos que creen efectos interesantes en textos, tales como, algunos que se muestran debajo pudieran también ser útiles.
Manténgase en contacto.
No hay comentarios. :
Publicar un comentario
Los comentarios son moderados, por lo que pueden demorar varias horas para su publicación.