Delphi и TextWidth / TextHeight в PDF с текстом в юникоде - PullRequest
1 голос
/ 14 апреля 2010

Я новичок в Юникоде, поэтому я надеюсь, что кто-нибудь может мне помочь. Я хочу написать Unicode в PDF, теперь мне нужны ширина и высота текста Unicode для форматирования текста. Для AnsiString у меня есть эти функции в классе PDF:

function PDFClass.TextWidth(Text: AnsiString): Single;
var
  i: integer;
  ch: AnsiChar;
  tmpWidth: Single;
  chv: Integer;
begin
  Result := 0;
  for I := 1 to Length(Text) do
  begin
    ch := Text[i];
    chv := CurrentFontObj.GetCharWidth(Text, I);
    tmpWidth := chv * CurrentFontObj.Size / 1000;
    if FHorizontalScaling <> 100 then
      tmpWidth := tmpWidth * FHorizontalScaling / 100;
    if tmpWidth > 0 then
      tmpWidth := tmpWidth + FCharSpace
    else
      tmpWidth := 0;
    if (ch = ' ') and (FWordSpace > 0) and (i <> Length(Text)) then
      tmpWidth := tmpWidth + FWordSpace;
    Result := Result + tmpWidth;
  end;
  Result := (Result / DocScale);
end;


function PDFClass.TextHeight(Text: AnsiString): Real;
begin
  Result := CurrentFontObj.Size * CurrentFontObj.Ascent / 1000;
end;

Кто-нибудь может мне помочь с этой функцией для текста Unicode? Я использую этот компонент в C ++ Builder 2009 с UnicodeString.

CurrentFontObj из класса PDFFontObj

  PDFFontObj = class(TObject)
  private
    Name: AnsiString;
    Size: Single;
    ArrIndex: Integer;
    Saved: boolean;
    OldName: AnsiString;
    Ascent: Integer;
    FActive: boolean;
    IsUsed: boolean;
    UniLen: Integer;
    FontLen: Integer;
    IsUnicode: boolean;
    IsVertical: boolean;
    OrdinalName: AnsiString;
    IsStandard: boolean;
    FontStyle: TFontStyles;
    FontCharset: TFontCharset;
    IsMonospaced: boolean;
    OutTextM: OUTLINETEXTMETRIC;
    ABCArray: array[0..255] of ABC;
    Symbols: array of CDescript;
    UnicodeTable: array of IndexedChar;
    SymbolTable: array[32..255] of boolean;
    function GetCharWidth(AText: AnsiString; APos: integer): integer;
    function GetCodeByID(ID: Word): Word;
    procedure CopyFontFetures(InFnt: PDFFontObj);
    procedure GetFontFeatures;
    procedure ParseFontName;
    procedure ClearTables;
  end;

function PDFFontObj.GetCharWidth(AText: AnsiString; APos: integer): integer;
var
  ChCode: Byte;
begin
  ChCode := Ord(AText[APos]);
  if not IsMonospaced then
    Result := ABCArray[ChCode].abcA + Integer(ABCArray[ChCode].abcB) + ABCArray[ChCode].abcC
  else
    Result := ABCArray[0].abcA + Integer(ABCArray[0].abcB) + ABCArray[0].abcC;
end;

1 Ответ

0 голосов
/ 15 апреля 2010

В комментарии вы пишете

Я хотел бы написать 3 текста подряд, каждый из которых имеет свой цвет. Для этого мне нужна ширина пикселя каждого текста. Для AnsiString это:

int width = PDF->CurrentPage->TextWidth(ansi_text);

но мне нужна ширина текста Unicode, например:

int width = PDF->CurrentPage->TextWidthUnicode(unicode_text_with_chinese_signs);

Краткий ответ:
Если у вас есть код, который правильно работает со строками Ansi, он должен корректно работать с Unicode без изменений.

Более длинный ответ:
Метод PDFClass.TextWidth() перебирает все символы в строке, вызывает функцию текущего объекта шрифта, чтобы получить ширину одного символа, применяет масштабирование и добавляет дополнительный пробел между символами и словами. Это более или менее то, что вы можете прочитать в главе 9 спецификации PDF 1.7 .

Код, который вы разместили, является неполным, но я подозреваю, что он уже не работает правильно для строк Ansi. Существуют кодировки Ansi, которые могут использовать несколько символов для кодирования одного видимого символа, многобайтовых кодировок CJK. Цикл по одиночным байтам в строке Ansi и суммирование возвращенных значений ширины там не будет работать правильно. Код может как-то объяснить это, но ваш фрагмент не показывает это.

В коде также могут быть проблемы с разными однобайтовыми кодировками Ansi, но по фрагментам, которые вы выложили, трудно сказать. Если вы возьмете программу Ansi, которая использует символы не ASCII (например, «ä» или «á»), и запустите ее, например, на русской версии Windows, будут ли созданные PDF-файлы содержать кириллические символы? Если нет, то код не помещает необходимую информацию о кодировке в PDF. Если так, то это не будет работать и для строк Unicode. Обратитесь к спецификации PDF для получения дополнительной информации о проблемах кодирования.

Обратите внимание, что код может работать не для всех пользователей, даже когда он компилируется:

  • Вам понадобится шрифт, который содержит все необходимые глифы (китайский в вашем примере). Если этого не произойдет, вместо этого будет отображен запасной глиф. Если система не имеет точно такой же шрифт, то вместо этого может использоваться аналогичный, но другой шрифт, который может иметь разную ширину для некоторых или всех глифов, и в этом случае вычисленная ширина будет неправильной. По этой причине лучше всего встраивать шрифт TrueType (лучше даже только используемые глифы шрифта) в документ PDF. Шрифт TTF может быть или не быть встраиваемым, и вы не имеете права встраивать его и распространять документ.

  • Некоторые языки размещают глифы справа налево или даже укладывают их вертикально.

  • Некоторые языки будут использовать другие кодовые точки для разделения слов, код в вопросе распознает только пробелы в качестве разделителей слов. Это снова приведет к тому, что вычисления приведут к другим результатам, если FWordSpace не равно 0.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...