2009-03-01

Drawing Unicode texts with GdiPlusX

It's really very simple to draw Unicode texts with GdiPlusX:

We'll use the function "drawstringw", that is just an adapted version from the original xfcgraphics.drawstring function.

It accepts the same parameters and overloads from the original function - the sole difference is the first parameter that was introduced - the graphics object.

Another helper function - "hextounicode" was introduced. It converts a string containing hex values separated by a space into the unicode needed by gdiplus.dll to draw the string.

Just run the script and you'll obtain a result similar to the one below:





Prerequisites
Visual FoxPro 9 and the GdiPlusX library from VfpX  


DO LOCFILE("System.app")

LOCAL N, x, Y, lnColor
LOCAL loBmp AS xfcbitmap, loGfx AS xfcGraphics, loFont AS xfcFont
LOCAL loBrush AS xfcsolidBrush
LOCAL laWords(9,2)

* greek
laWords(1,1) = "greek"
laWords(1,2) = "03b5 03b9 03c1 03ae 03bd 03b7"

* korean
laWords(2,1) = "korean"
laWords(2,2) = "d3c9 d654"

* hebrew
laWords(3,1) = "hebrew"
laWords(3,2) = "05e9 05dc 05d5 05dd"

* bulgarian
laWords(4,1) = "bulgarian"
laWords(4,2) = "043c 0438 0440"

* arabic
laWords(5,1) = "arabic"
laWords(5,2) = "0633 0644 0627 0645"

* simplified chinese
laWords(6,1) = "chinese"
laWords(6,2) = "548c 5e73"

* thai
laWords(7,1) = "thai"
laWords(7,2) = "0e04 0e27 0e32 0e21 0e2a 0e07 0e1a"

* russian
laWords(8,1) = "russian"
laWords(8,2) = "043c 0438 0440"

* japanese
laWords(9,1) = "japanese"
laWords(9,2) = "5e73 548c"

WITH _SCREEN.SYSTEM.Drawing
 loFont = .Font.New("tahoma", 18)
 loBmp = .BITMAP.New(350,370)
 loGfx = .Graphics.fromImage(loBmp)
 loGfx.CLEAR(.COLOR.White)
 loGfx.DrawString("gdi+x Drawing Unicodes", loFont, .Brushes.black, 10,5)

 FOR N = 1 TO 9
  Y = N * 35
  x = 160

  lnColor = RGB(RAND() * 255, RAND() * 255, RAND() * 255)
  * create a solidBrush with randomic color
  loBrush = .solidBrush.New(.COLOR.fromrgb(lnColor))

  * Draw the language Name
  loGfx.DrawString(laWords(N,1), .Font.New("tahoma", 10), .Brushes.black, 65, Y + 5)

  * Draw the text in Unicodes
  =DrawStringw(loGfx, hextoUnicode(laWords(N,2)), loFont,;
   loBrush, x, Y)
 ENDFOR

 loBmp.SAVE("testUnicodes.png", .imaging.ImageFormat.png)
ENDWITH



FUNCTION DrawStringw(togfx, ;
  tcString, toFont AS xfcFont, toBrush AS xfcBrush, tnX, tnY ;
  , toFormat AS xfcStringFormat)
 *********** tcString, toFont AS xfcFont, toBrush AS xfcBrush, toPoint AS xfcPointf ;
 , toFormat AS xfcStringFormat
 *********** tcString, toFont AS xfcFont, toBrush AS xfcBrush, toRectangle AS xfcRectanglef ;
 , toFormat AS xfcStringFormat
 LOCAL lqlayoutRect
 LOCAL lnWidth, lnHeight, loPoint AS xfcPointf, loRect AS xfcRectanglef
 LOCAL lhFormat
 STORE 0 TO lnWidth, lnHeight
 STORE NULL TO loPoint, loRect
 m.lqlayoutRect = 0h00
 ** handle overload parameters

 DO CASE
  CASE VARTYPE(tnX) = "N"
  CASE VARTYPE(tnX) = "O" AND INLIST(tnX.baseName,"Point","Pointf")
   m.loPoint = m.tnX
   m.toFormat = m.tnY
   m.loPoint.getextent(@tnX, @tnY)
  CASE VARTYPE(tnX) = "O" AND INLIST(tnX.baseName,"Rectangle","Rectanglef")
   m.loRect = m.tnX
   m.toFormat = m.tnY
   m.loRect.getextent(@tnX, @tnY, @lnWidth, @lnHeight)
 ENDCASE

 ** optional parameter
 ** the c++ classes show this parameter as null if not specified
 IF VARTYPE(m.toFormat) = "O"
  m.lhFormat = m.toFormat.handle
 ELSE
  m.lhFormat = 0
 ENDIF
 m.lqlayoutRect = BINTOC(m.tnX,"F")+BINTOC(m.tnY,"F")+;
  BINTOC(m.lnWidth,"F")+BINTOC(m.lnHeight,"F")

 =xfcgdipDrawString(togfx.handle, m.tcString+0h00, LENC(tcString)/2, ;
  m.toFont.handle, @lqlayoutRect, m.lhFormat, m.toBrush.handle)
ENDFUNC


FUNCTION HexToUnicode(tcHex)
 LOCAL N, lcHex, lcUnicode
 lcUnicode = SPACE(0)   
 FOR N = 1 TO GETWORDCOUNT(tchex, SPACE(1))
  lcHex = EVALUATE("0x" + GETWORDNUM(tcHex, N, SPACE(1)))
  lcUnicode = lcUnicode + BINTOC(lcHex, "4RS")
 ENDFOR
 RETURN lcUnicode
ENDFUNC