#1 2016-12-24 19:55:26

Warpedone
Member
Registered: 2016-07-22
Posts: 3

Central European characters don't render properly

I'm using latest SynPdf code with Delphi7 on Windows10, Slovenian locale.

Preview (TGDIPages.ShowPreviewForm) is rendered correctly but the saved PDF opened in a PDF reader displays wrong characters. Acrobat Reader reports the fonts are embedded with ANSI encoding.

Can anyone help with what should I check, set, change?

Offline

#2 2017-05-15 07:25:44

Warpedone
Member
Registered: 2016-07-22
Posts: 3

Re: Central European characters don't render properly

I managed to pinpoint the cause .. my system is using code-page 1250, PDF gets rendered using
code-page 1252.

Problematic character is the one with code 200 (010C in cp1250 and 00C8 in cp1252) , it differs between both code-pages. Unfortunately this character is fairly frequently used in our language.

Is there a way to set proper code-page for PDF for it to render using cp1250? I couldn't find anything such in the code sad

Last edited by Warpedone (2017-05-15 07:36:51)

Offline

#3 2017-09-21 07:28:03

Gigo
Member
From: Split, Croatia
Registered: 2012-01-27
Posts: 16

Re: Central European characters don't render properly

Hi, I'm using same codepage (CP 1250 , Croatian locale)

1. Default TPdfDocument.Create should use correct codepage (ACP codepage in our case cp1250)
2. You can specify codepage in constructor i.e.  TPdfDocument.Create(false,1250);

try something like :

  FPDF := TPdfDocument.Create; //or TPdfDocument.Create(false,1250);
  try
    FPDF.EmbeddedTTF := true;
    //FPDF.EmbeddedWholeTTF := true;
    FPDF.DefaultPaperSize := psA4;
    with FPDF.AddPage do
      begin
        FPDF.Canvas.SetFont(StringToUTF8('Arial'),12, [] );

        PDF.Canvas.TextOut(100,100, #$8A#$D0#$C8#$C6#$8E);  // show characters ŠĐČĆŽ
      end

    FPDF.SaveToFile('Something.pdf')
  finally
    FreeAndNil(FPDF);
  end;

However, I've found some bugs that we need to fix and I thinks it's related to your problem.

-Text that we need to print goes trough TPdfCanvas.ShowText method
-Fonts are chosen via TPdfCanvas.SetFont methos

But in order to write AnsiString #$8A#$D0#$C8#$C6#$8E  (5 capital diacritics in our languages),
document uses 2 fonts : Unicode and WinAnsi (cp1252) not cp1250.
ShowText method tries to determine if any non-WinAnsi chars exist in text and sets font to
Unicode or WinAnsi font. Note that 2 chars from out text exists in WinAnsi cp1252 (#$8A and #$8E).
Those 2 letters are written using TPdfFontTrueType.WinAnsiFont, and #$D0#$C8#$C6 are written
using TPdfFontTrueType.UnicodeFont.

Problem arises when we have last ANSI character that is not in cp1252.
TPdfCanvas.ShowText switches to WinAnsi font but doesn't swith back to Unicode on next ShowText.

Furthermore TPdfCanvas.TextRect method calls TPdfCanvas.TextWidth method to calculate text position,
and fails at TPdfFontWinAnsi.GetAnsiCharWidth because fWinAnsiWidth = nil,
and TPdfCanvas.TextWidth method returns DefaultWidth * number of chars.

QuickFix would be :
  1. add one blank char after text if text does not need to be aligned right
  2. call TPdfCanvas.SetFont before each call to TPdfCanvas.ShowText
 
Of course, it won't help if you are using higher level components like TGDIPages / TRenderPages.


I've made 2 little changes to SynPDF that works for me but would need confirmation from AB :

procedure TPdfCanvas.ShowText(const text: PDFString; NextLine: boolean);
begin
  if (FContents<>nil) and (text<>'') then
    if (fDoc.FCharSet=ANSI_CHARSET) or IsAnsiCompatible(text) then begin
      if FPage.Font.Unicode and (FPage.FFont.FTrueTypeFontsIndex<>0) then
        SetPDFFont(TPdfFontTrueType(FPage.Font).WinAnsiFont,FPage.FontSize);
      FContents.Writer.Add('(').AddEscapeText(pointer(text),FPage.Font).Add(')').
        Add(SHOWTEXTCMD[NextLine])
    end else begin
      if not FPage.Font.Unicode and (FPage.FFont.FTrueTypeFontsIndex<>0) then     //
        if FPage.Font <> TPdfFontTrueType(FPage.Font).UnicodeFont then            // gigo
          SetPDFFont(TPdfFontTrueType(FPage.Font).UnicodeFont,FPage.FontSize);    //
      if FPage.FFont.FTrueTypeFontsIndex<>0 then
        // write TrueType text after conversion to unicode
        FContents.Writer.AddToUnicodeHexText(text,NextLine,self) else
        // this standard font should expect MBCS encoding
        FContents.Writer.Add('<').AddHex(text).Add('>').Add(SHOWTEXTCMD[NextLine]);
    end;
end;

override of TPdfFontWinAnsi.GetAnsiCharWidth :

function TPdfFontTrueType.GetAnsiCharWidth(const AText: PDFString; APos: integer): integer;   // gigo
var
  aWideChar: WideChar;
begin
  if Unicode then
    begin
      aWideChar := #32;
      CurrentAnsiConvert.AnsiBufferToUnicode(@aWideChar,@(AText[APos]),1,True);
      Result := GetWideCharWidth(aWideChar);
    end
  else
    Result := inherited GetAnsiCharWidth(AText,APos);
end;

Best regards.

Offline

Board footer

Powered by FluxBB