• Welcome to Jose's Read Only Forum 2023.
 

MeasureString

Started by Rick Kelly, May 03, 2013, 12:40:21 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Rick Kelly

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

Rick Kelly

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

José Roca

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.

Rick Kelly

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

Rick Kelly

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

José Roca

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.

Rick Kelly

#6
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

Rick Kelly

#7
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