1
#region PDFsharp - A .NET library for processing PDF
4
// Stefan Lange (mailto:Stefan.Lange@pdfsharp.com)
6
// Copyright (c) 2005-2008 empira Software GmbH, Cologne (Germany)
8
// http://www.pdfsharp.com
9
// http://sourceforge.net/projects/pdfsharp
11
// Permission is hereby granted, free of charge, to any person obtaining a
12
// copy of this software and associated documentation files (the "Software"),
13
// to deal in the Software without restriction, including without limitation
14
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
15
// and/or sell copies of the Software, and to permit persons to whom the
16
// Software is furnished to do so, subject to the following conditions:
18
// The above copyright notice and this permission notice shall be included
19
// in all copies or substantial portions of the Software.
21
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27
// DEALINGS IN THE SOFTWARE.
31
using System.Diagnostics;
32
using System.Globalization;
33
using System.Runtime.InteropServices;
37
using System.Drawing.Drawing2D;
41
using System.Windows.Media;
43
using PdfSharp.Pdf.Internal;
44
using PdfSharp.Drawing;
46
namespace PdfSharp.Fonts.TrueType
49
/// The TrueType font desriptor.
51
internal sealed class TrueTypeDescriptor : FontDescriptor
54
public TrueTypeDescriptor(XFont font, XPdfFontOptions options, XPrivateFontCollection privateFontCollection)
58
this.fontData = new FontData(font, options);
59
this.fontName = font.Name;
70
// public TrueTypeDescriptor(XFont font, XPdfFontOptions options)
74
// this.fontData = new FontData(font, options);
75
// this.fontName = font.Name;
78
// catch (Exception ex)
85
//internal TrueTypeDescriptor(FontSelector selector)
87
// throw new NotImplementedException("TrueTypeDescriptor(FontSelector selector)");
90
internal TrueTypeDescriptor(XFont font,
91
XPrivateFontCollection privateFontCollection)
92
: this(font, font.PdfOptions, privateFontCollection)
95
internal TrueTypeDescriptor(string idName, byte[] fontData)
99
this.fontData = new FontData(fontData);
100
// Try to get real name form name table
101
if (idName.Contains("XPS-Font-") && this.fontData.name != null && this.fontData.name.Name.Length != 0)
103
string tag = String.Empty;
104
if (idName.IndexOf('+') == 6)
105
tag = idName.Substring(0, 6);
106
idName = tag + "+" + this.fontData.name.Name;
107
if (this.fontData.name.Style.Length != 0)
108
idName += "," + this.fontData.name.Style;
109
idName = idName.Replace(" ", "");
111
this.fontName = idName;
120
internal FontData fontData;
124
bool embeddingRestricted = this.fontData.os2.fsType == 0x0002;
126
//this.fontName = image.n
127
this.italicAngle = this.fontData.post.italicAngle;
129
this.xMin = this.fontData.head.xMin;
130
this.yMin = this.fontData.head.yMin;
131
this.xMax = this.fontData.head.xMax;
132
this.yMax = this.fontData.head.yMax;
134
this.underlinePosition = this.fontData.post.underlinePosition;
135
this.underlineThickness = this.fontData.post.underlineThickness;
136
this.strikeoutPosition = this.fontData.os2.yStrikeoutPosition;
137
this.strikeoutSize = this.fontData.os2.yStrikeoutSize;
139
// No documetation found how to get the set vertical stems width from the
141
// The following formula comes from PDFlib Lite source code. Acrobat 5.0 sets
142
// /StemV to 0 always. I think the value doesn't matter.
143
//float weight = (float)(this.image.os2.usWeightClass / 65.0f);
144
//this.stemV = (int)(50 + weight * weight); // MAGIC
147
// PDFlib states that some Apple fonts miss the OS/2 table.
148
Debug.Assert(fontData.os2 != null, "TrueType font has no OS/2 table.");
150
this.unitsPerEm = fontData.head.unitsPerEm;
152
// PDFlib takes sTypoAscender and sTypoDescender from OS/2 tabel, but GDI+ uses usWinAscent and usWinDescent
153
if (fontData.os2.sTypoAscender != 0)
154
this.ascender = fontData.os2.usWinAscent;
156
this.ascender = fontData.hhea.ascender;
157
Debug.Assert(this.ascender > 0, "PDFsharp internal: Ascender should be greater than 0.");
159
if (fontData.os2.sTypoDescender != 0)
161
this.descender = fontData.os2.usWinDescent;
162
Debug.Assert(this.descender > 0, "PDFsharp internal: Font with non positive ascender value found.");
164
Debug.WriteLine(String.Format(CultureInfo.InvariantCulture,
165
"os2.usWinDescent={0}, hhea.descender={1}, os2.sTypoDescender={2}", fontData.os2.usWinDescent, fontData.hhea.descender, fontData.os2.sTypoDescender));
167
// Force sign from hhea.descender
169
this.descender = Math.Abs(this.descender) * Math.Sign(fontData.hhea.descender);
172
this.descender = fontData.hhea.descender;
173
Debug.Assert(this.descender < 0, "PDFsharp internal: Ascender should be less than 0.");
175
this.leading = fontData.hhea.lineGap;
177
// sCapHeight and sxHeight are only valid if version >= 2
178
if (fontData.os2.version >= 2 && fontData.os2.sCapHeight != 0)
179
this.capHeight = fontData.os2.sCapHeight;
181
this.capHeight = fontData.hhea.ascender;
183
if (fontData.os2.version >= 2 && fontData.os2.sxHeight != 0)
184
this.xHeight = fontData.os2.sxHeight;
186
this.xHeight = (int)(0.66f * this.ascender);
188
//this.flags = this.image.
190
Encoding ansi = PdfEncoders.WinAnsiEncoding; // System.Text.Encoding.Default;
191
Encoding unicode = System.Text.Encoding.Unicode;
192
byte[] bytes = new byte[256];
194
bool symbol = this.fontData.cmap.symbol;
195
this.widths = new int[256];
196
for (int idx = 0; idx < 256; idx++)
198
bytes[idx] = (byte)idx;
199
// PDFlib handles some font flaws here...
200
// We wait for bug reports.
203
string s = ansi.GetString(bytes, idx, 1);
216
glyphIndex = idx + (this.fontData.os2.usFirstCharIndex & 0xFF00);
217
glyphIndex = CharCodeToGlyphIndex((char)glyphIndex);
221
//Debug.Assert(idx + (this.fontData.os2.usFirstCharIndex & 0xFF00) == idx);
222
//glyphIndex = CharCodeToGlyphIndex((char)idx);
223
glyphIndex = CharCodeToGlyphIndex(ch);
225
this.widths[idx] = GlyphIndexToPdfWidth(glyphIndex);
230
public override bool IsBoldFace
234
return base.IsBoldFace;
238
public override bool IsItalicFace
242
return base.IsItalicFace;
246
internal int DesignUnitsToPdf(double value)
248
return (int)Math.Round(value * 1000.0 / this.fontData.head.unitsPerEm);
252
/// Maps a unicode to the index of the corresponding glyph.
253
/// See OpenType spec "cmap - Character To Glyph Index Mapping Table / Format 4: Segment mapping to delta values"
254
/// for details about this a little bit strange looking algorythm.
256
public int CharCodeToGlyphIndex(char value)
260
CMap4 cmap = this.fontData.cmap.cmap4;
261
int segCount = cmap.segCountX2 / 2;
263
for (seg = 0; seg < segCount; seg++)
265
if (value <= cmap.endCount[seg])
268
Debug.Assert(seg < segCount);
270
if (value < cmap.startCount[seg])
273
if (cmap.idRangeOffs[seg] == 0)
274
return (value + cmap.idDelta[seg]) & 0xFFFF;
276
int idx = cmap.idRangeOffs[seg] / 2 + (value - cmap.startCount[seg]) - (segCount - seg);
277
Debug.Assert(idx >= 0 && idx < cmap.glyphCount);
279
if (cmap.glyphIdArray[idx] == 0)
282
return (cmap.glyphIdArray[idx] + cmap.idDelta[seg]) & 0xFFFF;
291
/// Converts the width of a glyph identified by its index to PDF design units.
293
public int GlyphIndexToPdfWidth(int glyphIndex)
297
int numberOfHMetrics = this.fontData.hhea.numberOfHMetrics;
298
int unitsPerEm = this.fontData.head.unitsPerEm;
300
// glyphIndex >= numberOfHMetrics means the font is mono-spaced and all glyphs have the same width
301
if (glyphIndex >= numberOfHMetrics)
302
glyphIndex = numberOfHMetrics - 1;
304
int width = this.fontData.hmtx.metrics[glyphIndex].advanceWidth;
306
// Sometimes the unitsPerEm is 1000, sometimes a power of 2.
307
if (unitsPerEm == 1000)
309
return width * 1000 / unitsPerEm;
317
public int PdfWidthFromCharCode(char ch)
319
int idx = CharCodeToGlyphIndex(ch);
320
int width = GlyphIndexToPdfWidth(idx);
325
public static void Test()
327
Font font = new Font("Times New Roman", 10);
328
FontData image = new FontData(font);
330
// Font font = new Font("Isabelle", 12);
331
// LOGFONT logFont = new LOGFONT();
332
// font.ToLogFont(logFont);
334
// IntPtr hfont = CreateFontIndirect(logFont);
335
//// IntPtr hfont2 = font.ToHfont();
336
//// System.Windows.Forms.MessageBox.Show(hfont2.ToString());
338
// Graphics gfx = Graphics.FromHwnd(IntPtr.Zero);
339
// IntPtr hdc = gfx.GetHdc();
340
// IntPtr oldFont = SelectObject(hdc, hfont);
341
// int size = GetFontData(hdc, 0, 0, null, 0);
343
// byte[] fontbits = new byte[size];
344
// int xx = GetFontData(hdc, 0, 0, fontbits, size);
345
// SelectObject(hdc, oldFont);
346
// DeleteObject(hfont);
347
// gfx.ReleaseHdc(hdc);
349
// FontData image = new FontData(fontbits);
b'\\ No newline at end of file'