En este escrito tenemos la clave sobre cómo colocar marcas de agua u otras etiquetas rotadas en informes VFP 9.0. Cesar Chalom combina el empleo de GDI+ con los beneficios que aporta el nuevo motor de informes en VFP 9.0. Muy sencillo y muy práctico, ¡Gracias Cesar!
Dibujar imágenes rotadas con GDI+
Artículo original: DRAW ROTATED STRINGS WITH GDIPLUS-X
http://weblogs.foxite.com/cesarchalom/archive/2006/08/30/2388.aspx
Autor: Cesar Chalom (http://weblogs.foxite.com/cesarchalom)
Traducido por: Ana María Bisbé York (amby@telefonica.net)
Para: PortalFox (http://www.portalfox.com)
GDI+ ofrece muchas formas para dibujar objetos rotados, como imágenes, cadenas y formas. Básicamente, necesitamos hacer una transformación en traslación de la localización del texto, y luego una transformación en rotación hasta el ángulo necesario, y luego, escribir el texto como si estuviéramos escribiendo normalmente.
Esta es la definición encontrada en MSDN: "La operación de rotación consiste en multiplicación matriz a matriz cuyos elementos se derivan del parámetro del ángulo. Este método aplica la rotación como anexo a la transformación de la matriz."

IMPORTANTE
Todos los ejemplos a continuación utilizan la nueva biblioteca GDIPlus-X, que se encuentra aun en versión ALPHA; pero en realidad es estable y es segura para hacer la mayoría de las tareas de GDI+. Descargue la versión más recientemente librada desde Codeplex:
http://www.codeplex.com/Wiki/View.aspx?ProjectName=VFPX&title=GDIPlusX
* Inicializa la biblioteca GdiPlus-X
_SCREEN.ADDPROPERTY("System", NEWOBJECT("xfcSystem", LOCFILE("system.vcx","vcx")))
WITH _SCREEN.SYSTEM.Drawing
* Crea un nuevo Bitmap vacío
LOCAL loBmp as xfcBitmap
loBmp = .Bitmap.New(180,180)
* Crea un objeto Graphics asociado al bitmap
LOCAL loGfx as xfcGraphics
loGfx = .Graphics.FromImage(loBmp)
* Limpia el fondo de la imagen con color azul claro
loGfx.Clear(.Color.FromRgb(230,230,255))
* Crea una broch sólida -SolidBrush de color rojo
LOCAL loBrush AS xfcBrush
loBrush = .SolidBrush.New(.COLOR.FromRgb(255,0,0))
* La instrucción anterior pudo haber sido también
* loBrush = .SolidBrush.New(.COLOR.FromARgb(255,255,0,0))
* loBrush = .SolidBrush.New(.COLOR.Red)
* Crea un rectángulo - objeto Rectangle en el que va a dibujar el texto rotado
LOCAL loRect AS xfcRectangle
loRect = .Rectangle.New(0, 0, loBmp.Width, loBmp.Height)
* Crea un objeto string básico, luego configura sus propiedades
LOCAL loStringFormat AS xfcStringFormat
loStringFormat = .StringFormat.New()
loStringFormat.ALIGNMENT = .StringAlignment.CENTER
loStringFormat.LineAlignment = .StringAlignment.CENTER
* Crea un objeto fuente - Font
LOCAL loFont AS xfcFont
loFont = .FONT.New("Verdana",16, .FontStyle.Bold, .GraphicsUnit.POINT)
* Después de crear todos los objetos necesarios, podemos aplicar la rotación
* y dibujar el texto
* Traslada y rota
loGfx.TranslateTransform(loBmp.Width /2, loBmp.Height /2)
loGfx.RotateTransform(-45) && angle of 45 degrees
loGfx.TranslateTransform(-loBmp.Width /2, -loBmp.Height /2)
* Finalmente, dibuja la cadena
loGfx.DrawString("Rotated Text" + CHR(13) + CHR(10) + "GDIPlus-X is COOL !!!", ;
loFont, loBrush, loRect, loStringFormat)
* Reinicia la rotación
loGfx.ResetTransform()
* Guarda la imagen en un archivo
loBmp.Save("c:\rotated.png", .Imaging.ImageFormat.Png)
ENDWITH
* Muestra la imagen creada
RUN /N explorer.exe c:\rotated.png
HORA DE JUGAR
Para el ejemplo anterior, usé un truco para rotar el texto al centro de la imagen, y no en el ángulo izquierdo, como es el comportamiento predeterminado. Ahora, es su turno de hacer algunas pruebas. Intente omitiendo las dos líneas que llaman Graphics.TranslateTransform, cambia el ángulo, cambie el ángulo, utilizando ángulos positivos y negativos, etc
* Traslación y rotación
loGfx.TranslateTransform(loBmp.Width /2, loBmp.Height /2)
loGfx.RotateTransform(-45) && angle of 45 degrees
loGfx.TranslateTransform(-loBmp.Width /2, -loBmp.Height /2)
En la carpeta "Samples" de la última versión de la biblioteca GDIPlus-X hay otro buen ejemplo, "Rotation.scx", en el cual se utilizó otra técnica de traslación. Todo el código está en el método "BeforeDraw" del objeto ImageCanVas.
¡DIBUJE CADENAS ROTADAS EN UN INFORME!

La origen real para este escrito, fue una pregunta hecha en FoxBrasil por mi amigo Emerson Santon Reed, cuando preguntó sobre crear una marca de agua de un gran texto rotado en 45 grados en un informe.
Entonces, mi parte fue adaptar el código GDI+ mostrado antes en la clase ReportListener y el Informe que el proporcionó.
Ejecute el código que aparece a continuación para ver un texto rotado centrado 45 grados en un informe.
* Crea un informe de ejemplo
LOCAL i
CREATE CURSOR dummy (fld1 c(20), fld2 c(15))
FOR i=1 TO 100
INSERT INTO dummy VALUES ("ReportListener con GdiPlus-X", "Visite CodePlex")
ENDFOR
SELECT dummy
CREATE REPORT _testreport FROM dummy
* Inicializa GdiPlus-X
_SCREEN.ADDPROPERTY("System", NEWOBJECT("xfcSystem", LOCFILE("system.vcx","vcx")))
* Carga la clase Listener
LOCAL loreportlistener
loreportlistener = CREATEOBJECT("MyReportListener")
loreportlistener.LISTENERTYPE = 1
* Llama al informe empleando nuestro listener
REPORT FORM _testreport OBJECT loreportlistener
USE IN dummy
RETURN
DEFINE CLASS myreportlistener AS _reportlistener OF ;
ADDBS(HOME()) + "FFC\" + "_ReportListener.VCX"
newpage = .T.
ogdigraphics = NULL
FUNCTION BEFOREREPORT
DODEFAULT()
This.ogdigraphics = _SCREEN.SYSTEM.drawing.graphics.new()
ENDFUNC
FUNCTION BEFOREBAND(nbandobjcode, nfrxrecno)
#DEFINE frx_objcod_pageheader 1
IF nbandobjcode==frx_objcod_pageheader
This.newpage = .T.
IF NOT This.issuccessor
This.sharedgdiplusgraphics = This.GDIPLUSGRAPHICS
ENDIF
This.ogdigraphics.handle = This.sharedgdiplusgraphics
ENDIF
DODEFAULT(nbandobjcode, nfrxrecno)
ENDFUNC
PROCEDURE RENDER(nfrxrecno,;
nleft,ntop,nwidth,nheight,;
nobjectcontinuationtype, ;
ccontentstoberendered, gdiplusimage)
WITH _SCREEN.SYSTEM.drawing
IF This.newpage
* Crea un objeto SolidBrush de color gris
LOCAL lobrush AS xfcbrush
lobrush = .solidbrush.new(.COLOR.fromrgb(210,128,128))
* Crea un objeto Rectangle en el que va a ser dibujado el texto rotado
LOCAL lorect AS xfcrectangle
lorect = .rectangle.new(0, 0, This.sharedpagewidth,;
This.sharedpageheight)
* Crea un objeto string básico, luego configura sus propiedades
LOCAL lostringformat AS xfcstringformat
lostringformat = .stringformat.new()
lostringformat.ALIGNMENT = .stringalignment.CENTER
lostringformat.linealignment = .stringalignment.CENTER
* Crea un objeto fuente - Font
LOCAL lofont AS xfcfont
lofont = .FONT.new("Verdana",48, 0, .graphicsunit.POINT)
* Traslada y rota
This.ogdigraphics.translatetransform(This.sharedpagewidth/2,;
This.sharedpageheight/2)
This.ogdigraphics.rotatetransform(-45)
This.ogdigraphics.translatetransform(-This.sharedpagewidth/2,;
-This.sharedpageheight/2)
This.ogdigraphics.drawstring("Rotated Text" +CHR(13)+CHR(10)+;
"GDIPlus-X is COOL !!!", ;
lofont, lobrush, lorect, lostringformat)
* Reinicia la rotación
This.ogdigraphics.resettransform()
This.newpage = .F.
ENDIF
ENDWITH
DODEFAULT(nfrxrecno,;
nleft,ntop,nwidth,nheight,;
nobjectcontinuationtype, ;
ccontentstoberendered, gdiplusimage)
ENDPROC
ENDDEFINE
Actualización 06-08-31
Para asegurarnos de que la marca de agua no será sobreescrita por controles
opacos, el código a continuación muestra lo mismo que antes; pero este caso
dibuja la marca de agua justo después de que la banda Pie ha sido totalmente
generada. El color utilizado para este caso fue también cambiado de opaco a
semitransparente, utilizando Alpha de 128 (0 = totalmente transparente, 255 =
opaco). Entonces, he aquí la nueva clase ReportListener para solucionar
este problema:
DEFINE CLASS myreportlistener AS _reportlistener OF ;
ADDBS(HOME()) + "FFC\" + "_ReportListener.VCX"
ogdigraphics = NULL
FUNCTION BEFOREREPORT
DODEFAULT()
This.ogdigraphics = _SCREEN.SYSTEM.drawing.graphics.new()
ENDFUNC
FUNCTION AFTERBAND(nbandobjcode, nfrxrecno)
*-- Valores de las columnas de FRX OBJCODE
#DEFINE FRX_OBJCOD_TITLE 0
#DEFINE FRX_OBJCOD_PAGEHEADER 1
#DEFINE FRX_OBJCOD_COLHEADER 2
#DEFINE FRX_OBJCOD_GROUPHEADER 3
#DEFINE FRX_OBJCOD_DETAIL 4
#DEFINE FRX_OBJCOD_GROUPFOOTER 5
#DEFINE FRX_OBJCOD_COLFOOTER 6
#DEFINE FRX_OBJCOD_PAGEFOOTER 7
#DEFINE FRX_OBJCOD_SUMMARY 8
#DEFINE FRX_OBJCOD_DETAILHEADER 9
#DEFINE FRX_OBJCOD_DETAILFOOTER 10
IF nbandobjcode==frx_objcod_pagefooter
IF NOT This.issuccessor
This.sharedgdiplusgraphics = This.GDIPLUSGRAPHICS
ENDIF
This.ogdigraphics.handle = This.sharedgdiplusgraphics
WITH _SCREEN.SYSTEM.drawing
* Crea un objeto SolidBrush de color rojo semi transparente
LOCAL lobrush AS xfcbrush
lobrush = .solidbrush.new(.COLOR.fromArgb(128,255,128,128))
* Crea un objeto Rectangle en el que va a ser dibujado el texto rotado
LOCAL lorect AS xfcrectangle
lorect = .rectangle.new(0, 0, This.sharedpagewidth,;
This.sharedpageheight)
* Crea un objeto string básico, luego configura sus propiedades
LOCAL lostringformat AS xfcstringformat
lostringformat = .stringformat.new()
lostringformat.ALIGNMENT = .stringalignment.CENTER
lostringformat.linealignment = .stringalignment.CENTER
* Crea un objeto fuente - Font
LOCAL lofont AS xfcfont
lofont = .FONT.new("Verdana",48, 0, .graphicsunit.POINT)
* Traslada y rota
This.ogdigraphics.translatetransform(This.sharedpagewidth/2,;
This.sharedpageheight/2)
This.ogdigraphics.rotatetransform(-45)
This.ogdigraphics.translatetransform(-This.sharedpagewidth/2,;
-This.sharedpageheight/2)
This.ogdigraphics.drawstring("Rotated Text" +CHR(13)+CHR(10)+;
"GDIPlus-X is COOL !!!", ;
lofont, lobrush, lorect, lostringformat)
* Reinicia la rotación
This.ogdigraphics.resettransform()
ENDWITH
ENDIF
DODEFAULT(nBandObjCode, nFRXRecNo)
ENDFUNC
ENDDEFINE
ENLACES RELACIONADOS
Artículo de Bill Wagner: http://www.ftponline.com/vsm/2002_10/online/csharp_bwagner_10_31_02
Página GdiPlusX en CodePlex: http://www.codeplex.com/Wiki/View.aspx?ProjectName=VFPX&title=GDIPlusX
|