So, I've got more time than brains. Anyways, I've made decent progress on a PDF creation class. One thing holding me back is a reliable way to determine the size of a string when it is rendered by a PDF reader. I'm only using the 14 default fonts after deciding I could live with that and it's a big time sink for me to figure out how to embed fonts.
Is MeasureString the way to go? Given the pixels size and the current screen dpi, I think I could convert that to the 72 point PDF space. Is it possible when not embedding any fonts and just trying a font family search or something like that?
PB 10, and Jose's headers of course.
Rick
I decided to give MeasureString a shot using this code:
#INCLUDE "cWindow.inc"
#INCLUDE "cgdiplus.inc"
LOCAL objGDI AS IGdiPlus
LOCAL objFont AS IGdipFont
LOCAL objGraphics AS IGdipGraphics
LOCAL objStringFormat AS IGdipStringFormat
LOCAL strLayout AS Rect
LOCAL strBounding AS RectF
LOCAL swzMeasureString AS WSTRINGZ * 1000
LOCAL swzFont AS WSTRINGZ * 32
LOCAL nLinesFilled AS LONG
objGDI = CLASS "CGdiPlus"
objFont = CLASS "CGdipFont"
objGraphics = CLASS "CGdipGraphics"
objStringFormat = CLASS "CGdipStringFormat"
objStringFormat = objGDI.StringFormat(0,0)
MSGBOX "StringFormat"
swzFont = "Courier"
objFont = objGDI.Font(swzFont,12,%FontStyleRegular,%UnitPoint)
MSGBOX "Font"
swzMeasureString = "How long am I?"
MSGBOX FORMAT$(objGraphics.MeasureString(swzMeasureString,objFont,strLayout,objStringFormat,strBounding,0,nLinesFilled))
MSGBOX FORMAT$(strBounding.Width,"9999.99")
objFont = NOTHING
objGraphics = NOTHING
objStringFormat = NOTHING
objGDI = NOTHING
The program dies and I never see the MSGBOX "Font" message. What am I doing wrong?
Rick
To begin with, you are not initializing GDI+ properly
use
objGDI =NewGdiPlus
or
objGDI = CLASS "CGdiPlus"
objGDI.Init(1)
Also don't create the objects with "CLASS".
#COMPILE EXE
#DIM ALL
#INCLUDE "cWindow.inc"
#INCLUDE "cgdiplus.inc"
FUNCTION PBMAIN () AS LONG
LOCAL objGDI AS IGdiPlus
LOCAL objFont AS IGdipFont
LOCAL objGraphics AS IGdipGraphics
LOCAL objStringFormat AS IGdipStringFormat
LOCAL strLayout AS Rect
LOCAL strBounding AS RectF
LOCAL swzMeasureString AS WSTRINGZ * 1000
LOCAL swzFont AS WSTRINGZ * 32
LOCAL nLinesFilled AS LONG
objGDI = CLASS "CGdiPlus"
objGDI.Init(1)
objStringFormat = objGDI.StringFormat(0,0)
MSGBOX "StringFormat"
swzFont = "Courier"
objFont = objGDI.Font("Courier", 12, %FontStyleRegular, %UnitPoint)
MSGBOX "Font"
END FUNCTION
To create a Graphics object, you need a device context.
See example #16 of this thread:
http://www.powerbasic.com/support/pbforums/showthread.php?t=50035&highlight=NewGdiPlus&page=4
that deals with MeasureString.
Thank you for your reply. I'm all new to this object paradigm. I used your information and reworked my code below that yielded a size of 92.39256.
LOCAL objGDI AS IGdiPlus
LOCAL objFont AS IGdipFont
LOCAL objGraphics AS IGdipGraphics
LOCAL strLayout AS RectF
LOCAL strBounding AS RectF
LOCAL swzMeasureString AS WSTRINGZ * 1000
LOCAL hDC AS DWORD
objGDI = CLASS "CGdiPlus"
objGDI.Init(1)
hDC = GetDC(0)
objGraphics = objGDI.GraphicsFromHDC(hdc)
objFont = objGDI.Font("Courier", 12, %FontStyleRegular, %UnitPoint)
swzMeasureString = "How long am I?"
strLayout = objGDI.RectF(0, 0, 100, 50)
objGraphics.MeasureString4(swzMeasureString,objFont,strLayout,strBounding)
MSGBOX FORMAT$(strBounding.Width)
ReleaseDC(0,hDC)
objFont = NOTHING
objGraphics = NOTHING
objGDI = NOTHING
Rick
Jose:
How did you arrive at determining the values to use in strLayout = objGDI.RectF(0, 0, 100, 50)? I can get wildly different values by playing around with varying the 100 and 50. Is there a metric calculation available for determining the optimum bounding rectangle size?
Rick
This method is not suitable for what you apparently want to do. The MeasureString method measures the extent of the string in the specified font and layout rectangle.
I'm not sure what extent really means so I looked around for another approach.
LOCAL objGDI AS IGdiPlus
LOCAL objFont AS IGdipFont
LOCAL hFont AS DWORD
LOCAL swzFont AS WSTRINGZ * 32
LOCAL hDC AS DWORD
LOCAL szMeasureString AS STRINGZ * 1000
LOCAL SizeStruct AS SIZE
objGDI = CLASS "CGdiPlus"
objGDI.Init(1)
hDC = CreateCompatibleDC(%NULL)
swzFont = sFontClass
objFont = objGDI.Font(swzFont,nFontSize,nFontStyle,%UnitPoint)
hFont = objFont.Ptr()
MSGBOX FORMAT$(SelectObject(hDC,hFont))
szMeasureString = sString
GetTextExtentPoint32A (hDC,szMeasureString,LEN(szMeasureString),SizeStruct)
objFont = NOTHING
objGDI = NOTHING
DeleteDC(hDC)
MSGBOX FORMAT$(SizeStruct.cX)
This didn't work either. I always get the same result without regard to the font size I use. DrawString gave the same results. I did notice that the SelectObject always returned 0 though.
Rick
Although not perfect, I think this is the best I'll be able to do for now.
METHOD PDFMeasureString(BYREF sString AS STRING, _
BYVAL sFontClass AS STRING, _
BYVAL nFontSize AS LONG, _
BYVAL nFontStyle AS LONG) AS DOUBLE
LOCAL hFont AS DWORD
LOCAL hDC AS DWORD
LOCAL oldhDC AS DWORD
LOCAL szMeasureString AS STRINGZ * 1000
LOCAL SizeStruct AS SIZE
LOCAL lFontA AS LOGFONTA
lFontA.lfFaceName = sFontClass
lFontA.lfOutPrecision = %OUT_TT_ONLY_PRECIS
lFontA.lfWeight = IIF(nFontStyle AND %FontStyleBold = %FontStyleBold,%FW_BOLD,%FW_NORMAL)
lFontA.lfHeight = nFontSize
lFontA.lfItalic = IIF(nFontStyle AND %FontStyleItalic = %FontStyleItalic,1,0)
hDC = CreateCompatibleDC(%NULL)
hFont = CreateFontIndirectA(lFontA)
oldhDC = SelectObject(hDC,hFont)
szMeasureString = sString
GetTextExtentPoint32A(hDC,szMeasureString,LEN(szMeasureString),SizeStruct)
DeleteObject(hFont)
DeleteDC(oldhDC)
DeleteDC(hDC)
METHOD = SizeStruct.cX
END METHOD
The string 'How long am I?' TIMES Bold, 24 point returns 140 as the size
Rick