WYSIWIG с Юникодом - PullRequest
       2

WYSIWIG с Юникодом

2 голосов
/ 17 августа 2010

Я написал программу для Windows на Delphi, которая очень точно размещает и переносит текст на экран и на принтер, используя GetCharWidth и Em-Square. Это хорошо работает с текстом ANSI, где вам нужно только получить и вычислить ширину 255 символов, но когда вы переходите на Unicode с 65535 символами, это слишком медленно. Проблема усугубляется созданием 2 массивов ширины, одного для нормального и одного для жирного.

 //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 ) ;`

Ответы [ 4 ]

8 голосов
/ 17 августа 2010

Вычисление ширины отдельных символов и их сложение в Юникоде не только очень медленно, но и неправильно и не будет работать правильно.Юникод объединяет символьные метки вместе, иногда сложным образом.

С Юникодом правильный способ сделать это - передать всю строку в функцию API Windows GetTextExtentExPoint вместе с ширинойline, и он определит, сколько символов поместится для вас в строке.

Здесь есть пример его использования .

2 голосов
/ 17 августа 2010

Я так понимаю, маловероятно использовать тысячи символов в типичном сеансе. Если это так, в первом раунде вычислите только первые 128 символов ширины и положите f.i. -1 всем остальным. Когда поиск выполнен, проверьте, если ширина равна -1, если это только тогда, вычислите ширину, высоту и т.д. для этого символа.

1 голос
/ 17 августа 2010

Помимо сомнений в отношении самого вопроса, вы можете значительно сократить обработку, я думаю, получив два массива nCharWidth с использованием отдельных массивов и объектов шрифтов и т. Д. И обработав их вместе, сократив два цикла 0..65535 до одного цикл. * * 1 001

Кроме того, вы можете исключить диапазон $ D800- $ DFFF из ваших циклов, поскольку они никогда не могут представлять символы сами по себе (будучи первыми из суррогатной пары, которую ваш код, по-видимому, не предназначен для обработки).

0 голосов
/ 17 августа 2010

Вы использовали профилировщик, чтобы увидеть, где может быть узкое место?
Одна из распространенных идей при использовании справочных таблиц, которые, по-видимому, слишком динамичны для динамического построения, состоит в том, чтобы создать их один раз и, например, сохранить как ресурс ...

...