Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WYSIWIG with Unicode

I've written a Windows program in Delphi that places and wraps text very precisely to both the screen and printer using GetCharWidth and Em-Square. This has worked well with ANSI text where you only need to retrieve and calculate the widths of 255 characters but when you go to Unicode with 65535 characters its too slow. The problem is made worse by having to create 2 arrays of width, one for normal and one for bold.

 //Setup a reference canvas for measuring purposes
  RefDC := CreateCompatibleDC ( FCanvas.Handle ) ;
  DPI := GetDeviceCaps ( RefDC , LOGPIXELSY ) ;

  //find EmSquare
  GetOutlineTextMetrics ( RefDC , sizeof(otm) , @otm[0] ) ;
  EmSq := otm[0].otmEmSquare ;

  //calc NORMAL char sizes
  GetObject ( FCanvas.Font.Handle , SizeOf ( lf ) , @lf ) ;

  lf.lfHeight := -EmSq ;
  lf.lfWidth  := 0 ;
  lf.lfWeight   := FW_NORMAL ;

  hf := CreateFontIndirect ( lf ) ;
  hold := SelectObject ( RefDC , hf ) ;

  GetCharWidth ( RefDC , 0 , $FFFF , nCharWidth ) ;
  for a := 0 to $FFFF do
    fCharWidth[a] := nCharWidth[a]* PixelSize / EmSq ;

  SelectObject ( RefDC , hold ) ;
  DeleteObject ( hf ) ;

  //calculate line height
  PixelSize := abs ( fCanvas.Font.Size * DPI / 72 ) ;
  GetOutlineTextMetrics ( RefDC , sizeof(otm) , @otm[0] ) ;
  LineHt := round ( ( otm[0].otmTextMetrics.tmHeight +
                      otm[0].otmTextMetrics.tmExternalLeading ) *
                      PixelSize / EmSq ) ;

  //calculate Bold char sizes
  lf.lfWeight := FW_BOLD ;
  hf := CreateFontIndirect ( lf ) ;
  hold := SelectObject ( RefDC , hf ) ;

  GetCharWidth ( RefDC , 0 , $FFFF , nCharWidth ) ;
  for a := 0 to $FFFF do
    fBoldWidth[a] := nCharWidth[a] * PixelSize / EmSq ;

  SelectObject ( RefDC , hold ) ;
  DeleteObject ( hf ) ;

  DeleteDC ( RefDC ) ;`
like image 771
Mitch Avatar asked Mar 12 '26 13:03

Mitch


1 Answers

Calculating individual character widths and adding them up in Unicode is not only very slow, but it's wrong and will not work correctly. Unicode combines character marks together, sometimes in complex ways.

With Unicode, the correct way to do it is to pass your whole string to the windows API function GetTextExtentExPoint along with the width of your line, and it will figure out how many characters will fit on the line for you.

There is an example of its use here.

like image 153
lkessler Avatar answered Mar 14 '26 04:03

lkessler