- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I require to obtain individual character widths and character string lengths for applications such as microsoft word and autocad.
I am using the functions GetTextExtentPoint32 and getcharabcwidths to get this information. If I use fontheights of 12,18 and 24 points using Arial and Bookman old style (bookos), the ratio of the string lengths (arial/Bookos)is 1.06, 1.12 and 0.91 respectively. When I plotthe character strings with a Fortran windows application i indeed get the same ratios. However if i replicate the strings in microsoft word or microsoft paint or autocad the ratio is approx. 0.88 for all font point heights. Why is there a discrepancy ? and is there any method of obtainingcharacter widths forgeneral applications
Link Copied
13 Replies
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
It's difficult to tell offhand what is wrong, but I'd like to turn your attention to two finesses in font size handling:
1) Take a closer look at documentation of LOGFONT/lfHeight. When lfHeight is a positive value n, the returned font has "cell height" of n, while when lfHeight < 0, the returned font has "character height" of n. It's not clear from the text, but I think the latter is greater from the former for the size of descent. As far as I can tell, most applications use the latter (lfHeight < 0) to denote a "12pt font".
2) There might be a confusion over the default assumed screen resolution. LOGFONT documentation appears to say 72 dpi, but 96 dpi is also used; (Note: it also depends on Small/Large fonts settings on the system! don't blindly assume 72). GetDeviceCaps(LOGPIXELSY) should tell you the correct value, and that's the one that should be used when converting points to pixels.
Finally, you can use GetTextMetrics to get detailed information about the font.
1) Take a closer look at documentation of LOGFONT/lfHeight. When lfHeight is a positive value n, the returned font has "cell height" of n, while when lfHeight < 0, the returned font has "character height" of n. It's not clear from the text, but I think the latter is greater from the former for the size of descent. As far as I can tell, most applications use the latter (lfHeight < 0) to denote a "12pt font".
2) There might be a confusion over the default assumed screen resolution. LOGFONT documentation appears to say 72 dpi, but 96 dpi is also used; (Note: it also depends on Small/Large fonts settings on the system! don't blindly assume 72). GetDeviceCaps(LOGPIXELSY) should tell you the correct value, and that's the one that should be used when converting points to pixels.
Finally, you can use GetTextMetrics to get detailed information about the font.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
SUBROUTINE fontsizes (hdc,width,height)
USE ifwin
IMPLICIT NONE
INTEGER,INTENT(IN) :: hdc
INTEGER,INTENT(OUT) :: width,height
INTEGER :: lret
TYPE(T_TEXTMETRIC) :: tm
lret = GetTextMetrics (hdc,tm)
width = tm%tmAveCharWidth
height = tm%tmHeight
END SUBROUTINE fontsizes
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks for the replies - the screen resolution is 96
The problem I am encountering is that I want to use Digital Fortran as a tool to generate a table of character widths which i can then multiply by the font height to get the correct character string length for use in autocad or other applications such as word for windows . In these applications a character string at 24 point heght is twice as long as that for 12 point. In programs from Fortran windows this is not the case.
I use
hfont = CreateFont(nh, 0, 0, 0, 0, 0, 0, 0, &
DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, &
DEFAULT_QUALITY,INT(FIXED_PITCH) ,typeface)
DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, &
DEFAULT_QUALITY,INT(FIXED_PITCH) ,typeface)
to create the font substituting nh and typeface for the appropriate values
and use
ret=getcharabcwidthsfloat(hdc,1,ntv,ABC(1))
ret=getcharwidth32 (hdc,1,ntv,LOC(ABCD(1)))
ret=getcharwidth32 (hdc,1,ntv,LOC(ABCD(1)))
to get the character widths.
If you run the SAMPLES program cmndlg the problem I am having can be demonstrated. If you insert any string and specify a 12 point and a 24 point font and measure the string length instead of the 24 point string being twice that of the 12 point string it can be say 1.8 times or 2.2 times as long.
Further if you use the above expressions and generate a table for (length of character string ) / (point height), for point heights of say 1- 200 you get an erratic set of values
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
In these applications a character string at 24 point height is twice as long as that for 12 point.
This should NOT be the case. Character spacing varies with font size, and will be comparatively greater with smaller sizes.
Please see the attached picture. The fonts used are Arial 8,12,16, and 24 points respectively. They appear largely identical (I think Word uses different kerning to match the selected printer). One in the background is from Fortran application, with string lengths in pixels as indicated.
This is the code I used to create the Fortran output. Note, however, that it uses XFTGDI wrappers from my Xeffort library:
Does it shed some light?
This should NOT be the case. Character spacing varies with font size, and will be comparatively greater with smaller sizes.
Please see the attached picture. The fonts used are Arial 8,12,16, and 24 points respectively. They appear largely identical (I think Word uses different kerning to match the selected printer). One in the background is from Fortran application, with string lengths in pixels as indicated.
This is the code I used to create the Fortran output. Note, however, that it uses XFTGDI wrappers from my Xeffort library:
CHARACTER(*), PARAMETER:: sText = "ABCDEFGHIJKLMNOPQRSTUVWXYZ 1234567890"XSetScaling introduces logical coordinate system expressed in points (1/72 of an inch). XSetFont_W calls CreateFont with negative lfHeight, equal to 8*96 (screen dpi)/ 72(points per inch) = 11 pixels for 8-point font. XGetTextExtent calls GetTextExtentPoint32.
INTEGER, PARAMETER:: iSize(4) = (/8,12,16,24/)
INTEGER:: i, iX, iY
REAL:: xPos
LOGICAL:: bSt
bSt = XFillViewport(xDC, X_BRUSH(BS_SOLID, XCOLOR_WHITE, 0))
xPos = 0.
CALL XSetScaling(xDC, 0., 0., MM_POINTS)
DO i=1,4
bSt = XSetFont_W(xDC, "Arial", REAL(iSize(i)))
CALL XGetTextExtent(xDC, sText, iX, iY)
bSt = XTextOut_W(xDC, 0., REAL(xPos), XString(iX))
bSt = XTextOut_W(xDC, 70., REAL(xPos), sText)
xPos = xPos + 1.1*iSize(i)
END DO
Does it shed some light?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
...ah, yes, the picture :-).
Message Edited by JugoslavDujic on 02-21-2006 11:33 AM
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I tried using
ret=GetTextExtentPoint32(HDC,charx(1:nexten), nexten,LPSIZE)
to get the lengths of the strings and for arial got
point size length length/pointsize
8 169 21
12 219 18
16 303 19
24 496 21
compared to JugoslavDujic of
point size length length/pointsize
8 243 30
12 371 31
16 490 31
24 752 31
I acknowledge there will discrepancies due to rounding but the length/pointsize in the value I obtained is not acceptable.
I also tried the code supplied by JugoslavDujic, I had to modify to this beacuse i am running version 6.0
my code for the size 8 font is
ret = xfillviewport(xDC,X_BRUSH(BS_SOLID,XCOLOR_WHITE,0))
call XsetScaling(xdc,0.,0.,MM_POINTS)
call XsetScaling(xdc,0.,0.,MM_POINTS)
ret = XsetFont_W(xDC,"Arial",8.,0,0.,0,.false.,.false.,.false.)
call XgettextExtent(xdc,"ABCDEFGHIJKLMNOPQRSTUVWXYZ",ix8,iy8,.false.)
call XgettextExtent(xdc,"ABCDEFGHIJKLMNOPQRSTUVWXYZ",ix8,iy8,.false.)
write(95,*)'8.',ix8,iy8
The code compiled OK and ran but i got
8. -2147483648 -2147483648
in the Fort.95 file
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The lengths given in the previous thread are for the string
"ABCDEFGHIJKLMNOPQRSTUVWXYZ 1234567890" and not
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
My code will probably not be of use to you as-is; it was an excerpt from a larger application (and Xeffort won't compile on 6.0 anymore). The strange -2147483648 are probably the result that xDC was not initialized -- at least, you should set xDC%hDC to your hDC value and XSetViewport to (0,0,whatever,whatever). I can't repeat your (169, 219, 303, 496) results though. Here's the supposedly equivalent Win32 code (sorry, no time to test it at the moment):
You should pass the negative value to CreateFont. I don't see how you could possibly achieve different results provided normal fonts (iYSF = 96 dpi) :-).
iret = SetMapMode(hDC, MM_TEXT) !this is the default, just in caseFor (8, 12, 16, 24) pt Arial, you should get iPxSize of (11, 16, 21, 32) pixels respectively, and (at least approximately) my results for the total length (note that my exact string was:
iPtSize = 8
iXSF = GetDeviceCaps(xDC%hDC, LOGPIXELSX)
iYSF = GetDeviceCaps(xDC%hDC, LOGPIXELSY)
iPxSize = NINT(iPtSize * REAL(iYSF) / 72)
hFont = CreateFont(-iPxSize...)
hOldFont = SelectObject(hDC, hFont)
...
iret = GetTextExtentPoint32(...)
"ABCDEFGHIJKLMNOPQRSTUVWXYZ 1234567890"
You should pass the negative value to CreateFont. I don't see how you could possibly achieve different results provided normal fonts (iYSF = 96 dpi) :-).
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
P.S. I can repeat your results after all (at least, very close). It seems that you made two errors:
1) did not correctly calculate pixel size on the basis of point size, i.e. you did 8 * (96/72) which is still equal to 8 pixels. Best, use floating-point operations.
2) passed the positive value to CreateFont. This yields a font of smaller size than in Word and Paint (for whatever reasons).
1) did not correctly calculate pixel size on the basis of point size, i.e. you did 8 * (96/72) which is still equal to 8 pixels. Best, use floating-point operations.
2) passed the positive value to CreateFont. This yields a font of smaller size than in Word and Paint (for whatever reasons).
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Using the information in the previous two threads by JugoslavDujic
I get the string lengths of 246 375 496 761 which is near enough to 243 , 371, 490 and 752 -
many thanks
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
PS - to incorporate the Xeffort routines I lifted the source for XFTGDI.f90 and XFTTYPES.f90 and inserted them into my source code . I had to remove a couple of the functions within XFTGDI.f90 which gave compilation errors. After modification of the routines to match the version 6 , the code compiled ok
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Just releasied that I used a string length of 38 instead of 37 and accordinglymy figures in reply 11 should be less than I have posted. I think I have probably added an extra character which is about the average widtth of an arial character so my numbres will be 37 / 38 less so tallying with the other results - I can confirm this ion thurs 23rd feb
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
onfirm i now get the values of 243, 371,490 and 752 for the length of string

Reply
Topic Options
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page