源代码网整理以下参考 《让Fastreport3.x支持中文PDF的输出》一文,确实可以支持中文。但是发现两个问题:
源代码网整理以下1、只能在Adobe Reader下打开,在Foxit Reader下空白。
源代码网整理以下2、用Adobe Acrobat或者Adobe Reader打开时提示rebuild,关闭时提示save
源代码网整理以下研究了一下Fastreport3.14和3.07的源代码,发现关于字体这部分重新调整了。在3.07下,每个type0的字体有三个obj表示,而在3.14下只用两个obj(把FontDescriptor放进实际字体中去了)。3.14中源代码中有个小bug,漏掉了实际字体obj的ref(原frxPDFfile.pas的985行和986行之间)。Foxit Reader应该是严格按照ref去找obj的,找不到obj,所以显示不出来。Adobe Reader应该不是按ref找的,能够正常显示汉字,但是它会重新ref,所以提示rebuild。
源代码网整理以下修改后的TfrxPDFFont.SaveToStream替换原来的即可。
源代码网整理以下镶入字体还不行。有时间再说。3.15的说明中有说增强了PDF导出的功能,期待中。
源代码网整理以下procedure TfrxPDFFont.SaveToStream(Stream: TStream);
var
s: string;
b: TBitmap;
pm: ^OUTLINETEXTMETRIC;
FontName: string;
i: Cardinal;
pfont: PChar;
FirstChar, LastChar: Integer;
MemStream: TMemoryStream;
MemStream1: TMemoryStream;
pwidths: PABC;
Charset: TFontCharSet;
源代码网整理以下 // support DBCS font name encoding
function EncodeFontName(AFontName: string): string;
var
s: string;
Index, Len: Integer;
begin
// Add Begin by ijia 2004.12.20
// 修正在简体系统下繁体字体名的问题
// 只提供 MingLiU, PMingLiU --> 细明体, 新细明体的修正
s:=UpperCase(AFontName);
if Copy(s, 1, 7)="MINGLIU" then
AFontName:="细明体";
源代码网整理以下 if Copy(s, 1, 8)="PMINGLIU" then
AFontName:="新细明体";
// Add end
s := "";
Len := Length(AFontName);
Index := 0;
while Index < Len do
begin
Index := Index 1;
if Byte(AFontName[Index]) > $7F then
s := s "#" IntToHex(Byte(AFontName[Index]), 2)
else
s := s AFontname[Index];
end;
Result := s;
end;
源代码网整理以下begin
inherited SaveToStream(Stream);
b := TBitmap.Create;
b.Canvas.Font.Assign(Font);
b.Canvas.Font.PixelsPerInch := 96;
b.Canvas.Font.Size := 750;
i := GetOutlineTextMetrics(b.Canvas.Handle, 0, nil);
GetMem(pm, i);
try
try
GetOutlineTextMetrics(b.Canvas.Handle, i, pm);
FirstChar := Ord(pm.otmTextMetrics.tmFirstChar);
LastChar := Ord(pm.otmTextMetrics.tmLastChar);
FontName := StringReplace(Font.Name, " ", "#20", [rfReplaceAll]);
s := "";
if fsBold in Font.Style then
s := s "Bold";
if fsItalic in Font.Style then
s := s "Italic";
if s <> "" then
FontName := FontName "," s;
源代码网整理以下 Charset := pm.otmTextMetrics.tmCharSet;
FontName := EncodeFontName(FontName);
源代码网整理以下 Parent.XRefAdd(Stream);
WriteLn(Stream, IntToStr(Index Parent.FStartFonts) " 0 obj");
WriteLn(Stream, "<<");
WriteLn(Stream, "/Type /Font");
WriteLn(Stream, "/Name /F" IntToStr(Index - 1));
WriteLn(Stream, "/BaseFont /" FontName);
源代码网整理以下 // Add by ijia 2004.12.20
//if Charset <> CHINESEBIG5_CHARSET then
if not (Charset in [CHINESEBIG5_CHARSET, GB2312_CHARSET]) then
WriteLn(Stream, "/Subtype /TrueType")
else
WriteLn(Stream, "/Subtype /Type0");
源代码网整理以下 case Charset of
SYMBOL_CHARSET, ANSI_CHARSET:
WriteLn(Stream, "/Encoding /WinAnsiEncoding");
源代码网整理以下 RUSSIAN_CHARSET: {1251}
begin
WriteLn(Stream, "/Encoding <</Type/Encoding /BaseEncoding /WinAnsiEncoding");
Write(Stream, "/Differences [129 /afii10052");
Write(Stream, "/quotesinglbase/afii10100/quotedblbase/ellipsis/dagger/daggerdbl/Euro/perthousand/afii10058/guilsinglleft/afii10059/afii10061/afii10060/afii10145/afii10099/quoteleft");
Write(Stream, "/quoteright/quotedblleft/quotedblright/bullet/endash/emdash/space/trademark/afii10106/guilsinglright/afii10107/afii10109/afii10108/afii10193/space/afii10062");
Write(Stream, "/afii10110/afii10057/currency/afii10050/brokenbar/section/afii10023/copyright/afii10053/guillemotleft/logicalnot/hyphen/registered/afii10056/degree/plusminus");
Write(Stream, "/afii10055/afii10103/afii10098/mu/paragraph/periodcentered/afii10071/afii61352/afii10101/guillemotright/afii10105/afii10054/afii10102/afii10104/afii10017/afii10018");
Write(Stream, "/afii10019/afii10020/afii10021/afii10022/afii10024/afii10025/afii10026/afii10027/afii10028/afii10029/afii10030/afii10031/afii10032/afii10033/afii10034/afii10035");
Write(Stream, "/afii10036/afii10037/afii10038/afii10039/afii10040/afii10041/afii10042/afii10043/afii10044/afii10045/afii10046/afii10047/afii10048/afii10049/afii10065/afii10066");
Write(Stream, "/afii10067/afii10068/afii10069/afii10070/afii10072/afii10073/afii10074/afii10075/afii10076/afii10077/afii10078/afii10079/afii10080/afii10081/afii10082/afii10083");
WriteLn(Stream, "/afii10084/afii10085/afii10086/afii10087/afii10088/afii10089/afii10090/afii10091/afii10092/afii10093/afii10094/afii10095/afii10096/afii10097/space]");
WriteLn(Stream, ">>");
end;
源代码网整理以下 EASTEUROPE_CHARSET: {1250}
begin
WriteLn(Stream, "/Encoding <</Type/Encoding /BaseEncoding /WinAnsiEncoding");
Write(Stream, "/Differences [128 /Euro 140 /Sacute /Tcaron /Zcaron /Zacute");
Write(Stream, " 156 /sacute /tcaron /zcaron /zacute 161 /caron /breve /Lslash");
Write(Stream, " 165 /Aogonek 170 /Scedilla 175 /Zdotaccent 178 /ogonek /lslash");
Write(Stream, " 185 /aogonek /scedilla 188 /Lcaron /hungarumlaut /lcaron /zdotaccent /Racute");
Write(Stream, " 195 /Abreve 197 /Lacute /Cacute 200 /Ccaron 202 /Eogonek 204 /Ecaron 207 /Dcaron /Dslash");
Write(Stream, " 209 /Nacute /Ncaron /Oacute 213 /Ohungarumlaut 216 /Rcaron /Uring 219 /Uhungarumlaut");
Write(Stream, " 222 /Tcedilla 224 /racute 227 /abreve 229 /lacute /cacute /ccedilla /ccaron");
Write(Stream, " 234 /eogonek 236 /ecaron 239 /dcaron /dmacron /nacute /ncaron 245 /ohungarumlaut");
Write(Stream, " 248 /rcaron /uring 251 /uhungarumlaut 254 /tcedilla /dotaccent]");
WriteLn(Stream, ">>");
end;
源代码网整理以下 GREEK_CHARSET: {1253}
begin
WriteLn(Stream, "/Encoding <</Type/Encoding /BaseEncoding /WinAnsiEncoding");
Write(Stream, "/Differences [ 128 /Euro 160 /quoteleft/quoteright 175 /afii00208");
Write(Stream, " 180 /tonos/dieresistonos/Alphatonos");
Write(Stream, " 184 /Epsilontonos/Etatonos/Iotatonos");
Write(Stream, " 188 /Omicrontonos 190 /Upsilontonos");
Write(Stream, "/Omegatonos/iotadieresistonos/Alpha/Beta/Gamma/Delta/Epsilon/Zeta");
Write(Stream, "/Eta/Theta/Iota/Kappa/Lambda/Mu/Nu/Xi/Omicron/Pi/Rho");
Write(Stream, " 211 /Sigma/Tau/Upsilon/Phi");
Write(Stream, "/Chi/Psi/Omega/Iotadieresis/Upsilondieresis/alphatonos/epsilontonos");
Write(Stream, "/etatonos/iotatonos/upsilondieresistonos/alpha/beta/gamma/delta/epsilon");
Write(Stream, "/zeta/eta/theta/iota/kappa/lambda/mu/nu/xi/omicron/pi/rho/sigma1/sigma");
Write(Stream, "/tau/upsilon/phi/chi/psi/omega/iotadieresis/upsilondieresis/omicrontonos");
Write(Stream, "/upsilontonos/omegatonos ]");
WriteLn(Stream, ">>");
end;
源代码网整理以下 TURKISH_CHARSET: {1254}
begin
WriteLn(Stream, "/Encoding <</Type/Encoding /BaseEncoding /WinAnsiEncoding");
Write(Stream, "/Differences [ 128 /Euro");
Write(Stream, " 130 /quotesinglbase/florin/quotedblbase/ellipsis/dagger");
Write(Stream, " /daggerdbl/circumflex/perthousand/Scaron/guilsinglleft/OE");
Write(Stream, " 145 /quoteleft/quoteright/quotedblleft/quotedblright");
Write(Stream, " /bullet/endash/emdash/tilde/trademark/scaron/guilsinglright/oe");
Write(Stream, " 159 /Ydieresis 208 /Gbreve 221 /Idotaccent/Scedilla");
Write(Stream, " 240 /gbreve 253 /dotlessi/scedilla]");
WriteLn(Stream, ">>");
end;
源代码网整理以下 HEBREW_CHARSET: {1255}
begin
WriteLn(Stream, "/Encoding <</Type/Encoding /BaseEncoding /WinAnsiEncoding");
Write(Stream, "/Differences [ 128 /Euro 130 /quotesinglbase/florin/quotedblbase/ellipsis");
Write(Stream, " /dagger/daggerdbl/circumflex/perthousand 139 /guilsinglleft");
Write(Stream, " 145 /quoteleft/quoteright/quotedblleft/quotedblright");
Write(Stream, " /bullet/endash/emdash/tilde/trademark 155 /perthousand");
Write(Stream, " 164 /afii57636 170 /multiply 186 /divide");
Write(Stream, " 192 /afii57799/afii57801/afii57800/afii57802/afii57793");
Write(Stream, " /afii57794/afii57795/afii57798/afii57797/afii57806");
Write(Stream, " 203 /afii57796/afii57807/afii57839/afii57645/afii57841/afii57842");
Write(Stream, " /afii57804/afii57803/afii57658/afii57716/afii57717/afii57718");
Write(Stream, " 224 /afii57664/afii57665/afii57666/afii57667/afii57668/afii57669");
Write(Stream, " /afii57670/afii57671/afii57672/afii57673/afii57674/afii57675");
Write(Stream, " /afii57676/afii57677/afii57678/afii57679/afii57680/afii57681");
Write(Stream, " /afii57682/afii57683/afii57684/afii57685/afii57686/afii57687");
Write(Stream, " /afii57688/afii57689/afii57690 253 /afii299/afii300]");
WriteLn(Stream, ">>");
end;
源代码网整理以下 ARABIC_CHARSET:
begin
WriteLn(Stream, "/Encoding <</Type/Encoding /BaseEncoding /WinAnsiEncoding");
Write(Stream, "/Differences [ 128 /Euro/afii57506/quotesinglbase/florin/quotedblbase");
Write(Stream, "/ellipsis/dagger/daggerdbl/circumflex/perthousand/afii57511");
Write(Stream, "/guilsinglleft/OE/afii57507/afii57508");
Write(Stream, " 144 /afii57509/quoteleft/quoteright/quotedblleft");
Write(Stream, "/quotedblright/bullet/endash/emdash");
Write(Stream, " 153 /trademark/afii57513/guilsinglright/oe/afii61664");
Write(Stream, "/afii301/afii57514 161 /afii57388");
Write(Stream, " 186 /afii57403 191 /afii57407");
Write(Stream, " 193 /afii57409/afii57410/afii57411/afii57412/afii57413");
Write(Stream, "/afii57414/afii57415/afii57416/afii57417/afii57418/afii57419");
Write(Stream, "/afii57420/afii57421/afii57422/afii57423/afii57424/afii57425");
Write(Stream, "/afii57426/afii57427/afii57428/afii57429/afii57430");
Write(Stream, " 216 /afii57431/afii57432/afii57433/afii57434/afii57440");
Write(Stream, "/afii57441/afii57442/afii57443/afii57444");
Write(Stream, " 227 /afii57445/afii57446/afii57470/afii57448/afii57449");
Write(Stream, "/afii57450 240 /afii57451/afii57452/afii57453/afii57454");
Write(Stream, "/afii57455/afii57456 248 /afii57457 250 /afii57458");
Write(Stream, " 253 /afii299/afii300/afii57519]");
WriteLn(Stream, ">>");
end;
源代码网整理以下 VIETNAMESE_CHARSET:
begin
WriteLn(Stream, "/Encoding <</Type/Encoding /BaseEncoding /WinAnsiEncoding");
Write(Stream, "/Differences [128 /Euro 142 /Zcaron 158 /zcaron]");
WriteLn(Stream, ">>");
end;
源代码网整理以下 CHINESEBIG5_CHARSET: {136}
begin
WriteLn(Stream, "/DescendantFonts [" IntToStr(Index 1 Parent.FStartFonts) " 0 R]");
WriteLn(Stream, "/Encoding /ETenms-B5-H");
WriteLn(Stream, ">>");
WriteLn(Stream, "endobj");
// Add by MagicDog
Parent.XRefAdd(Stream);
源代码网整理以下 WriteLn(Stream, IntToStr(Index 1 Parent.FStartFonts) " 0 obj");
WriteLn(Stream, "<<");
WriteLn(Stream, "/Type /Font");
WriteLn(Stream, "/Subtype");
WriteLn(Stream, "/CIDFontType2");
WriteLn(Stream, "/BaseFont /" EncodeFontName(FontName));
WriteLn(Stream, "/WinCharSet 136");
Write(Stream, "/FontDescriptor ");
WriteLn(Stream, "<<");
WriteLn(Stream, "/Type /FontDescriptor");
if Parent.FEmbedded then
WriteLn(Stream, "/FontFile2 " IntToStr(Index 2 Parent.FStartFonts) " 0 R");
WriteLn(Stream, "/FontName /" EncodeFontName(FontName));
WriteLn(Stream, "/Flags 7");
WriteLn(Stream, "/FontBBox [" IntToStr(pm^.otmrcFontBox.Left) " " IntToStr(pm^.otmrcFontBox.Bottom) " " IntToStr(pm^.otmrcFontBox.Right) " " IntToStr(pm^.otmrcFontBox.Top) " ]");
WriteLn(Stream, "/Style << /Panose <010502020300000000000000> >>");
WriteLn(Stream, "/Ascent " IntToStr(pm^.otmAscent));
WriteLn(Stream, "/Descent " IntToStr(pm^.otmDescent));
WriteLn(Stream, "/CapHeight " IntToStr(pm^.otmTextMetrics.tmHeight));
WriteLn(Stream, "/StemV " IntToStr(50 Round(sqr(pm^.otmTextMetrics.tmWeight / 65))));
WriteLn(Stream, "/ItalicAngle " IntToStr(pm^.otmItalicAngle));
WriteLn(Stream, ">>");
WriteLn(Stream, "/CIDSystemInfo");
WriteLn(Stream, "<<");
WriteLn(Stream, "/Registry(Adobe)");
WriteLn(Stream, "/Ordering(CNS1)");
WriteLn(Stream, "/Supplement 0");
WriteLn(Stream, ">>");
WriteLn(Stream, "/DW 1000");
WriteLn(Stream, "/W [1 95 500]");
WriteLn(Stream, ">>");
WriteLn(Stream, "endobj");
end;
源代码网整理以下 // Add begin by ijia 2004.12.20
GB2312_CHARSET: {134}
begin
WriteLn(Stream, "/DescendantFonts [" IntToStr(Index 1 Parent.FStartFonts) " 0 R]");
WriteLn(Stream, "/Encoding /GB-EUC-H");
WriteLn(Stream, ">>");
WriteLn(Stream, "endobj");
源代码网整理以下 // Add by MagicDog
Parent.XRefAdd(Stream);
WriteLn(Stream, IntToStr(Index 1 Parent.FStartFonts) " 0 obj");
WriteLn(Stream, "<<");
WriteLn(Stream, "/Type /Font");
WriteLn(Stream, "/Subtype");
WriteLn(Stream, "/CIDFontType2");
WriteLn(Stream, "/BaseFont /" EncodeFontName(FontName));
WriteLn(Stream, "/WinCharSet 134");
软件开发网 www.mscto.com
源代码网整理以下 Write(Stream, "/FontDescriptor ");
WriteLn(Stream, "<<");
WriteLn(Stream, "/Type /FontDescriptor");
if Parent.FEmbedded then
WriteLn(Stream, "/FontFile2 " IntToStr(Index 2 Parent.FStartFonts) " 0 R");
WriteLn(Stream, "/FontName /" EncodeFontName(FontName));
WriteLn(Stream, "/Flags 6");
WriteLn(Stream, "/FontBBox [" IntToStr(pm^.otmrcFontBox.Left) " " IntToStr(pm^.otmrcFontBox.Bottom) " " IntToStr(pm^.otmrcFontBox.Right) " " IntToStr(pm^.otmrcFontBox.Top) " ]");
WriteLn(Stream, "/Style << /Panose <010502020400000000000000> >>");
WriteLn(Stream, "/Ascent " IntToStr(pm^.otmAscent));
WriteLn(Stream, "/Descent " IntToStr(pm^.otmDescent));
WriteLn(Stream, "/CapHeight " IntToStr(pm^.otmTextMetrics.tmHeight));
WriteLn(Stream, "/StemV " IntToStr(50 Round(sqr(pm^.otmTextMetrics.tmWeight / 65))));
WriteLn(Stream, "/ItalicAngle " IntToStr(pm^.otmItalicAngle));
WriteLn(Stream, ">>");
WriteLn(Stream, "/CIDSystemInfo");
WriteLn(Stream, "<<");
WriteLn(Stream, "/Registry(Adobe)");
WriteLn(Stream, "/Ordering(GB1)");
WriteLn(Stream, "/Supplement 2");
WriteLn(Stream, ">>");
WriteLn(Stream, "/DW 1000");
WriteLn(Stream, "/W [ 1 95 500 814 939 500 7712 [ 500 ] 7716 [ 500 ] ]");
WriteLn(Stream, ">>");
WriteLn(Stream, "endobj");
end;
// Add end
源代码网整理以下 end;
源代码网整理以下 // Add by ijia 2004.12.20
//if Charset <> CHINESEBIG5_CHARSET then
if not (Charset in [CHINESEBIG5_CHARSET, GB2312_CHARSET]) then
begin
WriteLn(Stream, "/FontDescriptor " IntToStr(Index 1 Parent.FStartFonts) " 0 R");
WriteLn(Stream, "/FirstChar " IntToStr(FirstChar));
WriteLn(Stream, "/LastChar " IntToStr(LastChar));
GetMem(pwidths, SizeOf(ABCArray));
Write(Stream, "/Widths [");
GetCharABCWidths(b.Canvas.Handle, FirstChar, LastChar, pwidths^);
for i := 0 to (LastChar - FirstChar) do
Write(Stream, IntToStr(pwidths^[i].abcA Integer(pwidths^[i].abcB) pwidths^[i].abcC) " ");
WriteLn(Stream, "]");
FreeMem(pwidths);
WriteLn(Stream, ">>");
WriteLn(Stream, "endobj");
Parent.XRefAdd(Stream);
WriteLn(Stream, IntToStr(Index 1 Parent.FStartFonts) " 0 obj");
WriteLn(Stream, "<<");
WriteLn(Stream, "/Type /FontDescriptor");
WriteLn(Stream, "/FontName /" FontName);
WriteLn(Stream, "/Flags 32");
WriteLn(Stream, "/FontBBox [" IntToStr(pm^.otmrcFontBox.Left) " " IntToStr(pm^.otmrcFontBox.Bottom) " " IntToStr(pm^.otmrcFontBox.Right) " " IntToStr(pm^.otmrcFontBox.Top) " ]");
WriteLn(Stream, "/ItalicAngle " IntToStr(pm^.otmItalicAngle));
WriteLn(Stream, "/Ascent " IntToStr(pm^.otmAscent));
WriteLn(Stream, "/Descent " IntToStr(pm^.otmDescent));
WriteLn(Stream, "/Leading " IntToStr(pm^.otmTextMetrics.tmInternalLeading)); //NEW
WriteLn(Stream, "/CapHeight " IntToStr(pm^.otmTextMetrics.tmHeight));
WriteLn(Stream, "/XHeight " IntToStr(pm^.otmsXHeight)); //NEW
WriteLn(Stream, "/StemV " IntToStr(50 Round(sqr(pm^.otmTextMetrics.tmWeight / 65))));
WriteLn(Stream, "/AvgWidth " IntToStr(pm^.otmTextMetrics.tmAveCharWidth)); //NEW 软件开发网 www.mscto.com
WriteLn(Stream, "/MaxWidth " IntToStr(pm^.otmTextMetrics.tmMaxCharWidth)); //NEW
WriteLn(Stream, "/MissingWidth " IntToStr(pm^.otmTextMetrics.tmAveCharWidth)); //NEW
if Parent.FEmbedded then
WriteLn(Stream, "/FontFile2 " IntToStr(Index 2 Parent.FStartFonts) " 0 R");
源代码网整理以下 WriteLn(Stream, ">>");
WriteLn(Stream, "endobj");
end;
源代码网整理以下 if Parent.FEmbedded then
begin
Parent.XRefAdd(Stream);
WriteLn(Stream, IntToStr(Index 2 Parent.FStartFonts) " 0 obj");
i := GetFontData(b.Canvas.Handle, 0, 0, nil, 1);
GetMem(pfont, i);
i := GetFontData(b.Canvas.Handle, 0, 0, pfont, i);
MemStream := TMemoryStream.Create;
MemStream.Write(pfont^, i);
MemStream1 := TMemoryStream.Create;
frxDeflateStream(MemStream, MemStream1, gzMax);
WriteLn(Stream, "<< /Length " IntToStr(MemStream1.Size) " /Filter /FlateDecode /Length1 " IntToStr(MemStream.Size) " >>");
WriteLn(Stream, "stream");
Stream.CopyFrom(MemStream1, 0);
MemStream1.Free;
MemStream.Free;
FreeMem(pfont);
WriteLn(Stream, "");
WriteLn(Stream, "endstream");
WriteLn(Stream, "endobj");
end;
except
end;
finally
FreeMem(pm);
b.Free;
end;
end;
源代码网整理以下