Author Topic: MeasureString  (Read 6877 times)

0 Members and 1 Guest are viewing this topic.

Offline Rick Kelly

  • Newbie
  • *
  • Posts: 18
  • User-Rate: +0/-1
MeasureString
« on: May 03, 2013, 12:40:21 PM »
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

Offline Rick Kelly

  • Newbie
  • *
  • Posts: 18
  • User-Rate: +0/-1
Re: MeasureString
« Reply #1 on: May 06, 2013, 09:02:13 AM »
I decided to give MeasureString a shot using this code:

Code: [Select]
#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

Offline José Roca

  • Administrator
  • Hero Member
  • *****
  • Posts: 2522
  • User-Rate: +209/-0
  • Gender: Male
Re: MeasureString
« Reply #2 on: May 06, 2013, 09:45:27 AM »
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".

Code: [Select]
#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.

Offline Rick Kelly

  • Newbie
  • *
  • Posts: 18
  • User-Rate: +0/-1
Re: MeasureString
« Reply #3 on: May 06, 2013, 10:57:11 AM »
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.

Code: [Select]

  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

Offline Rick Kelly

  • Newbie
  • *
  • Posts: 18
  • User-Rate: +0/-1
Re: MeasureString
« Reply #4 on: May 09, 2013, 11:53:32 AM »
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

Offline José Roca

  • Administrator
  • Hero Member
  • *****
  • Posts: 2522
  • User-Rate: +209/-0
  • Gender: Male
Re: MeasureString
« Reply #5 on: May 09, 2013, 12:44:44 PM »
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.

Offline Rick Kelly

  • Newbie
  • *
  • Posts: 18
  • User-Rate: +0/-1
Re: MeasureString
« Reply #6 on: May 10, 2013, 01:57:21 PM »
I'm not sure what extent really means so I looked around for another approach.

Code: [Select]
  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
« Last Edit: May 10, 2013, 05:55:11 PM by Rick Kelly »

Offline Rick Kelly

  • Newbie
  • *
  • Posts: 18
  • User-Rate: +0/-1
Re: MeasureString
« Reply #7 on: May 11, 2013, 07:19:55 AM »
Although not perfect, I think this is the best I'll be able to do for now.

Code: [Select]
   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
« Last Edit: May 11, 2013, 08:57:39 AM by Rick Kelly »