FUNCTION MakeImageFromUnicode(tcFileName, tcUnicode, tcFontName, tnImgSize, tnForeColor, tnBackColor)
*!* tcUnicode allows up to 2 characters, that will be drawn one over the other
*!* Par1: Main Unicode
*!* Par2: Socondary Unicode
*!* Par3: Mode, where 0=Center, 1=TopLeft, 2=TopRight, 3=BottLeft, 4=BottRight
*!* Par4: Size of the 2nd character
LOCAL lnChars, lnFactor, lnFontHeight, lnFontSize, lnHeight, lnLines, lnNewFontSize, lnWidth
LOCAL lqUnicode
LOCAL lcUnicode1, lcUnicode2, lnMode, lnSize2
IF EMPTY(m.tcFileName) OR EMPTY(m.tcUnicode) OR EMPTY(m.tcFontName) OR EMPTY(m.tnImgSize)
RETURN
ENDIF
m.lnFontSize = 48
m.lnWidth = m.tnImgSize
m.lnHeight = m.tnImgSize
* Create a font object using the text object's settings.
LOCAL loFont0 AS GpFont OF HOME() + "FFC/_GdiPlus.vcx"
m.loFont0 = NEWOBJECT('gpFont', HOME() + 'FFC/_GdiPlus.vcx')
m.loFont0.Create(m.tcFontName, m.lnFontSize, 0, 3) && 0 = Font Style
LOCAL loGfx0 AS GpGraphics OF HOME() + "FFC/_GdiPlus.vcx"
m.loGfx0 = NEWOBJECT('gpGraphics', home() + 'FFC\_GdiPlus.vcx')
m.loGfx0.CreateFromHWnd(_screen.HWnd)
m.lnChars = 0
m.lnLines = 0
LOCAL loSize AS gpSize OF HOME() + "FFC/_GdiPlus.vcx"
m.loSize = m.loGfx0.MeasureStringA("A", m.loFont0, , , @m.lnChars, @m.lnLines)
* lnFontWidth = loSize.W
m.lnFontHeight = m.loSize.H
m.lnFactor = m.lnFontHeight / m.tnImgSize
m.lnNewFontSize = INT(m.lnFontSize / m.lnFactor)
* Create a font object using the text object's settings.
LOCAL loFont AS GpFont OF HOME() + "FFC/_GdiPlus.vcx"
m.loFont = NEWOBJECT('gpFont', HOME() + 'FFC/_GdiPlus.vcx')
m.loFont.Create(m.tcFontName, m.lnNewFontSize, 0, 3) && 0 = Font Style
LOCAL loBMP AS GpBitmap OF HOME() + "FFC/_GdiPlus.vcx"
m.loBMP = NEWOBJECT("gpBitmap", HOME() + "FFC/_GdiPlus.vcx")
#DEFINE GdiPlus_PixelFormat_32BPPARGB 0x0026200a
m.loBMP.Create(m.lnHeight, m.lnHeight, GdiPlus_PixelFormat_32BPPARGB)
LOCAL loGfx AS GpGraphics OF HOME() + "FFC/_GdiPlus.vcx"
m.loGfx = NEWOBJECT('gpGraphics', HOME() + 'FFC/_GdiPlus.vcx')
m.loGfx.CreateFromImage(m.loBMP)
* Setting the Backcolor
LOCAL loBackColor AS GpColor OF HOME() + "FFC/_GdiPlus.vcx"
IF EMPTY(m.tnBackColor)
m.loBackColor = 0xFFFFFFFF && White background
ELSE
m.loBackColor = NEWOBJECT("gpColor", HOME() + 'FFC/_GdiPlus.vcx')
m.loBackColor.FoxRGB = m.tnBackColor
ENDIF
m.loGfx.CLEAR(m.loBackColor) && Background
* Create a rectangle
LOCAL loRect AS GpRectangle OF HOME() + "FFC/_GdiPlus.vcx"
m.loRect = NEWOBJECT("GPRectangle", HOME() + 'FFC/_GdiPlus.vcx', "", 0, 0, m.lnWidth, m.lnHeight)
m.loRect.y = m.loRect.y + 1
* Setting the Forecolor
LOCAL loColor AS GpColor OF HOME() + "FFC/_GdiPlus.vcx"
IF EMPTY(m.tnForeColor)
m.tnForeColor = 0 && Black
ENDIF
m.loColor = NEWOBJECT("gpColor", HOME() + 'FFC/_GdiPlus.vcx')
m.loColor.FoxRGB = m.tnForeColor
LOCAL loBrush AS GpSolidBrush OF HOME() + "FFC/_GdiPlus.vcx"
m.loBrush = NEWOBJECT("gpSolidBrush", HOME() + 'FFC/_GdiPlus.vcx', "", m.loColor)
* The character need to be drawn at the center of the image object
* Get a basic string format object
* StringAlignment enumeration
* Applies to GpStringFormat::Alignment, GpStringFormat::LineAlignment
#DEFINE GDIPLUS_STRINGALIGNMENT_Near 0 && in Left-To-Right locale, this is Left
#DEFINE GDIPLUS_STRINGALIGNMENT_Center 1
#DEFINE GDIPLUS_STRINGALIGNMENT_Far 2 && in Left-To-Right locale, this is Right
LOCAL loStringFormat AS gpStringFormat OF HOME() + "FFC/_GdiPlus.vcx"
m.loStringFormat = NEWOBJECT("GpStringFormat", HOME() + "FFC/_GdiPlus.vcx")
m.loStringFormat.Create()
m.loStringFormat.Alignment = GDIPLUS_STRINGALIGNMENT_Center
m.loStringFormat.LineAlignment = GDIPLUS_STRINGALIGNMENT_Center
* Prepare the Unicode
m.lcUnicode1 = GETWORDNUM(m.tcUnicode, 1, ",")
m.lqUnicode = LEFT(BINTOC(EVALUATE("0x" + m.lcUnicode1), "4RS"), 2)
* Draw the string
m.loGfx.DrawStringW(m.lqUnicode, m.loFont, m.loRect, m.loStringFormat, m.loBrush)
m.lcUnicode2 = GETWORDNUM(m.tcUnicode, 2, ",")
IF NOT EMPTY(m.lcUnicode2)
m.lqUnicode = LEFT(BINTOC(EVALUATE("0x" + m.lcUnicode2), "4RS"), 2)
m.lnMode = VAL(GETWORDNUM(m.tcUnicode, 3, ","))
m.lnSize2 = VAL(GETWORDNUM(m.tcUnicode, 4, ","))
m.lnSize2 = EVL(m.lnSize2, 100)
lnNewFontSize = CEILING(m.lnNewFontSize * (lnSize2/100))
m.loFont.Create(m.tcFontName, m.lnNewFontSize, 0, 3) && 0 = Font Style
m.loStringFormat.Alignment = GDIPLUS_STRINGALIGNMENT_Center
m.loStringFormat.LineAlignment = GDIPLUS_STRINGALIGNMENT_Center
m.loRect.w = INT(m.lnWidth * (m.lnSize2 / 100))
m.loRect.H = INT(m.lnHeight * (m.lnSize2 / 100))
DO CASE
CASE m.lnMode = 0 && No transformation, the 2nd image will be drawn over the original
m.loRect.x = INT((m.lnWidth - m.loRect.w) / 2)
m.loRect.Y = INT((m.lnHeight - m.loRect.H) / 2)
CASE m.lnMode = 1 && Top-Left
m.loRect.x = 0
m.loRect.Y = 0
CASE m.lnMode = 2 && Top-Right
m.loRect.x = m.lnWidth - m.loRect.w
m.loRect.Y = 0
CASE m.lnMode = 3 && Bottom-Left
m.loRect.x = 0
m.loRect.Y = m.lnHeight - m.loRect.H
CASE m.lnMode = 4 && Bottom-Right
m.loRect.x = m.lnWidth - m.loRect.w
m.loRect.Y = m.lnHeight - m.loRect.H
OTHERWISE
ENDCASE
m.loRect.y = m.loRect.y + 1
m.loGfx.DrawStringW(m.lqUnicode, m.loFont, m.loRect, m.loStringFormat, m.loBrush)
ENDIF
* Save as image
m.loBMP.SaveToFile(m.tcFileName, "image/bmp")
RETURN
ENDFUNC
The function also allows you to create new icons by merging two, in this case, the Printer and the Settings icon at the bottom right:
CUSTOMIZE YOUR ICONS
lcFile = "Print.bmp"
lcUnicode = "e749,e713,4,25"
lcFont = "SEGOE MDL2 ASSETS"
lnSize = 32 && Pixels
lnForeColor = RGB(0, 0, 128) && Dark Blue
lnBackColor = RGB(255, 255, 128) && Yellow
=MakeImageFromUnicode(m.lcFile, lcUnicode, lcFont, lnSize, lnForeColor, lnBackColor)
EXTRACTING ALL ICONS FROM A FONT
The above function can be adapted in order to extract all characters of a given font, using a loop.
Fonts usually have some codes that are not being used, so in the code below I used a simple trick to detect the empty font dimensions, and every time the same conditions are met in the loop, the unicode will be discarded.
Just run the code below to extract all icons from any given font, at the desired image size and colors. Adjust the initial variables to fit your needs!
* Setup the initial 5 variables
LOCAL lcFontName, lnImgSize, lnForeColor, lnBackColor, lcImageType
m.lcFontName = "SEGOE MDL2 ASSETS"
m.lnImgSize = 64 && The desired bmp size in pixels
m.lnForeColor = RGB(0, 0, 0) && the ForeColor
m.lnBackColor = RGB(255, 255, 255) && the BackColor
m.lcImageType = "bmp" && available: bmp, jpg, gif, tif, png
* Let's start
LOCAL lcEmptyUnicode, lcFileName, lcHex, lcUnicode, lnChars, lnEmptyH, lnEmptyW, lnFactor
LOCAL lnFontHeight, lnFontSize, lnFontWidth, lnHeight, lnLines, lnNewFontSize, lnWidth, loSizeReal, n
m.lnFontSize = 48
m.lnWidth = m.lnImgSize
m.lnHeight = m.lnImgSize
m.lcImageType = LOWER(EVL(m.lcImageType, "bmp"))
* Create a rectangle
LOCAL loRect AS GpRectangle OF HOME() + "FFC/_GdiPlus.vcx"
m.loRect = NEWOBJECT("GPRectangle", HOME() + 'FFC/_GdiPlus.vcx', "", 0, 0, m.lnWidth, m.lnHeight)
m.loRect.y = m.loRect.y + 1
* The character need to be drawn at the center of the image object
* Get a basic string format object
* StringAlignment enumeration
* Applies to GpStringFormat::Alignment, GpStringFormat::LineAlignment
#DEFINE GDIPLUS_STRINGALIGNMENT_Near 0 && in Left-To-Right locale, this is Left
#DEFINE GDIPLUS_STRINGALIGNMENT_Center 1
#DEFINE GDIPLUS_STRINGALIGNMENT_Far 2 && in Left-To-Right locale, this is Right
LOCAL loStringFormat AS gpStringFormat OF HOME() + "FFC/_GdiPlus.vcx"
m.loStringFormat = NEWOBJECT("GpStringFormat", HOME() + "FFC/_GdiPlus.vcx")
m.loStringFormat.Create()
m.loStringFormat.Alignment = GDIPLUS_STRINGALIGNMENT_Center
m.loStringFormat.LineAlignment = GDIPLUS_STRINGALIGNMENT_Center
* Create a font object using the text object's settings.
LOCAL loFont0 AS GpFont OF HOME() + "FFC/_GdiPlus.vcx"
m.loFont0 = NEWOBJECT('gpFont', HOME() + 'FFC/_GdiPlus.vcx')
m.loFont0.Create(m.lcFontName, m.lnFontSize, 0, 3) && 0 = Font Style
LOCAL loGfx0 AS GpGraphics OF HOME() + "FFC/_GdiPlus.vcx"
m.loGfx0 = NEWOBJECT('gpGraphics', home() + 'FFC\_GdiPlus.vcx')
m.loGfx0.CreateFromHWnd(_screen.HWnd)
LOCAL loSize AS gpSize OF HOME() + "FFC/_GdiPlus.vcx"
m.lnChars = 0
m.lnLines = 0
m.loSize = m.loGfx0.MeasureStringA("A", m.loFont0, , , @m.lnChars, @m.lnLines)
m.lnFontWidth = m.loSize.W
m.lnFontHeight = m.loSize.H
m.lnFactor = m.lnFontHeight / m.lnImgSize
m.lnNewFontSize = INT(m.lnFontSize / m.lnFactor)
* Create a font object using the text object's settings.
LOCAL loFont AS GpFont OF HOME() + "FFC/_GdiPlus.vcx"
m.loFont = NEWOBJECT('gpFont', HOME() + 'FFC/_GdiPlus.vcx')
m.loFont.Create(m.lcFontName, m.lnNewFontSize, 0, 3) && 0 = Font Style
* Get the measure of the empty character, that will be used to avoid saving it several times
m.lcEmptyUnicode = CHR(0) + CHR(0)
LOCAL loSizeEmpty AS gpSize OF HOME() + "FFC/_GdiPlus.vcx"
m.loSizeEmpty = m.loGfx0.MeasureStringW(m.lcEmptyUnicode, m.loFont, m.loRect, m.loStringFormat, @m.lnChars, @m.lnLines)
m.lnEmptyW = m.loSizeEmpty.W
m.lnEmptyH = m.loSizeEmpty.H
LOCAL loBMP AS GpBitmap OF HOME() + "FFC/_GdiPlus.vcx"
m.loBMP = NEWOBJECT("gpBitmap", HOME() + "FFC/_GdiPlus.vcx")
#DEFINE GdiPlus_PixelFormat_32BPPARGB 0x0026200a
m.loBMP.Create(m.lnHeight, m.lnHeight, GdiPlus_PixelFormat_32BPPARGB)
LOCAL loGfx AS GpGraphics OF HOME() + "FFC/_GdiPlus.vcx"
m.loGfx = NEWOBJECT('gpGraphics', HOME() + 'FFC/_GdiPlus.vcx')
m.loGfx.CreateFromImage(m.loBMP)
* Setting the Backcolor
LOCAL loBackColor AS GpColor OF HOME() + "FFC/_GdiPlus.vcx"
IF EMPTY(m.lnBackColor)
m.loBackColor = 0xFFFFFFFF && White background
ELSE
m.loBackColor = NEWOBJECT("gpColor", HOME() + 'FFC/_GdiPlus.vcx')
m.loBackColor.FoxRGB = m.lnBackColor
ENDIF
* Setting the Forecolor
LOCAL loColor AS GpColor OF HOME() + "FFC/_GdiPlus.vcx"
IF EMPTY(m.lnForeColor)
m.lnForeColor = 0 && Black
ENDIF
m.loColor = NEWOBJECT("gpColor", HOME() + 'FFC/_GdiPlus.vcx')
m.loColor.FoxRGB = m.lnForeColor
LOCAL loBrush AS GpSolidBrush OF HOME() + "FFC/_GdiPlus.vcx"
m.loBrush = NEWOBJECT("gpSolidBrush", HOME() + 'FFC/_GdiPlus.vcx', "", m.loColor)
FOR m.n = 0xe001 TO 0xf8b3 && the last available found in charmap
m.lcHex = TRANSFORM(m.n, "@0")
m.lcHex = STRTRAN(m.lcHex, "0x0000", "")
m.lcFileName = FORCEEXT(m.lcHex, m.lcImageType)
* Prepare the Unicode
m.lcUnicode = LEFT(BINTOC(EVALUATE("0x" + m.lcHex), "4RS"), 2)
m.loSizeReal = m.loGfx0.MeasureStringW(m.lcUnicode, m.loFont, m.loRect, m.loStringFormat, @m.lnChars, @m.lnLines)
m.loGfx.CLEAR(m.loBackColor) && Background
* Draw the string
m.loGfx.DrawStringW(m.lcUnicode, m.loFont, m.loRect, m.loStringFormat, m.loBrush)
* Save as image
m.loBMP.SaveToFile(m.lcFileName, "image/" + m.lcImageType)
ENDFOR
* Clear GDI+ objects
m.loRect = NULL
m.loStringFormat = NULL
m.loColor = NULL
m.loBackColor = NULL
m.loBrush = NULL
m.loSize = NULL
m.loSizeEmpty = NULL
m.loGfx0 = NULL
m.loGfx = NULL
m.loBMP = NULL
m.loFont0 = NULL
m.loFont = NULL
RETURN
IMPORTANT
Don't forget that all fonts have a license. That means that you need to check first if you are allowed to distribute the images generated. Make sure to read the EULA, and see what you can or cannot do with them, ok?
SEE ALSO
Unicode button icons in Visual FoxPro
Unicode Controls in Visual FoxPro - A new faster and efficient aproachUnicode Button Icons in Visual FoxPro