private PdfFont GetFontFromResources(XFont xFont) { //TODO: Check that bold an italic are found through just their font names var defaultFormResources = Owner.AcroForm.Elements.GetDictionary(PdfAcroForm.Keys.DR); if (defaultFormResources != null && defaultFormResources.Elements.ContainsKey(PdfResources.Keys.Font)) { var fontList = defaultFormResources.Elements.GetDictionary(PdfResources.Keys.Font); var font = GetFontResourceItem(xFont.FamilyName, defaultFormResources); PdfItem value = font.Value; if (value is PdfReference) { value = ((PdfReference)value).Value; } PdfFont systemFont = new PdfFont(value as PdfDictionary); if (systemFont.FontEncoding == PdfFontEncoding.Unicode) { OpenTypeDescriptor ttDescriptor = (OpenTypeDescriptor)FontDescriptorCache.GetOrCreateDescriptorFor(xFont); systemFont.FontDescriptor = new PdfFontDescriptor(Owner, ttDescriptor); } return(systemFont); } return(null); }
/// <summary> /// Returns the line spacing, in design units, of the FontFamily object of the specified style. /// The line spacing is the vertical distance between the base lines of two consecutive lines of text. /// </summary> public int GetLineSpacing(XFontStyle style) { OpenTypeDescriptor descriptor = (OpenTypeDescriptor)FontDescriptorCache.GetOrCreateDescriptor(Name, style); int result = descriptor.LineSpacing; return(result); }
public PdfType0Font(PdfDocument document, XFont font, bool vertical) : base(document) { Elements.SetName(Keys.Type, "/Font"); Elements.SetName(Keys.Subtype, "/Type0"); Elements.SetName(Keys.Encoding, vertical ? "/Identity-V" : "/Identity-H"); OpenTypeDescriptor ttDescriptor = (OpenTypeDescriptor)FontDescriptorCache.GetOrCreateDescriptorFor(font); FontDescriptor = new PdfFontDescriptor(document, ttDescriptor); _fontOptions = font.PdfOptions; Debug.Assert(_fontOptions != null); _cmapInfo = new CMapInfo(ttDescriptor); _descendantFont = new PdfCIDFont(document, FontDescriptor, font); _descendantFont.CMapInfo = _cmapInfo; // Create ToUnicode map _toUnicode = new PdfToUnicodeMap(document, _cmapInfo); document.Internals.AddObject(_toUnicode); Elements.Add(Keys.ToUnicode, _toUnicode); BaseFont = font.GlyphTypeface.GetBaseName(); // CID fonts are always embedded BaseFont = PdfFont.CreateEmbeddedFontSubsetName(BaseFont); FontDescriptor.FontName = BaseFont; _descendantFont.BaseFont = BaseFont; PdfArray descendantFonts = new PdfArray(document); Owner._irefTable.Add(_descendantFont); descendantFonts.Elements.Add(_descendantFont.Reference); Elements[Keys.DescendantFonts] = descendantFonts; }
/// <summary> /// Returns the cell descent, in design units, of the XFontFamily object of the specified style. /// </summary> public int GetCellDescent(XFontStyle style) { OpenTypeDescriptor descriptor = (OpenTypeDescriptor)FontDescriptorCache.GetOrCreateDescriptor(Name, style); int result = descriptor.Descender; return(result); }
/// <summary> /// Initializes a new instance of PdfTrueTypeFont from an XFont. /// </summary> public PdfTrueTypeFont(PdfDocument document, XFont font) : base(document) { Elements.SetName(Keys.Type, "/Font"); Elements.SetName(Keys.Subtype, "/TrueType"); // TrueType with WinAnsiEncoding only. OpenTypeDescriptor ttDescriptor = (OpenTypeDescriptor)FontDescriptorCache.GetOrCreateDescriptorFor(font); FontDescriptor = new PdfFontDescriptor(document, ttDescriptor); _fontOptions = font.PdfOptions; Debug.Assert(_fontOptions != null); //cmapInfo = new CMapInfo(null/*ttDescriptor*/); _cmapInfo = new CMapInfo(ttDescriptor); BaseFont = font.GlyphTypeface.GetBaseName(); if (_fontOptions.FontEmbedding == PdfFontEmbedding.Always) { BaseFont = PdfFont.CreateEmbeddedFontSubsetName(BaseFont); } FontDescriptor.FontName = BaseFont; Debug.Assert(_fontOptions.FontEncoding == PdfFontEncoding.WinAnsi); if (!IsSymbolFont) { Encoding = "/WinAnsiEncoding"; } Owner._irefTable.Add(FontDescriptor); Elements[Keys.FontDescriptor] = FontDescriptor.Reference; FontEncoding = font.PdfOptions.FontEncoding; }
internal override void PrepareForSave() { base.PrepareForSave(); // Use GetGlyphIndices to create the widths array. OpenTypeDescriptor descriptor = (OpenTypeDescriptor)FontDescriptor._descriptor; StringBuilder w = new StringBuilder("["); if (_cmapInfo != null) { int[] glyphIndices = _cmapInfo.GetGlyphIndices(); int count = glyphIndices.Length; int[] glyphWidths = new int[count]; for (int idx = 0; idx < count; idx++) { glyphWidths[idx] = descriptor.GlyphIndexToPdfWidth(glyphIndices[idx]); } //TODO: optimize order of indices for (int idx = 0; idx < count; idx++) { w.AppendFormat("{0}[{1}]", glyphIndices[idx], glyphWidths[idx]); } w.Append("]"); _descendantFont.Elements.SetValue(PdfCIDFont.Keys.W, new PdfLiteral(w.ToString())); } _descendantFont.PrepareForSave(); _toUnicode.PrepareForSave(); }
/// <summary> /// Gets the FontDescriptor identified by the specified FontSelector. If no such objects /// exists, a new FontDescriptor is created and added to the stock. /// </summary> public FontDescriptor CreateDescriptor(XFontFamily family, XFontStyle style) { if (family == null) { throw new ArgumentNullException("family"); } FontSelector selector = new FontSelector(family, style); FontDescriptor descriptor; if (!table.TryGetValue(selector, out descriptor)) { lock (typeof(FontDescriptorStock)) { // may be created by other thread meanwhile if (!table.TryGetValue(selector, out descriptor)) { XFont font = new XFont(family.Name, 10, style); descriptor = new OpenTypeDescriptor(font); if (table.ContainsKey(selector)) { GetType(); } else { table.Add(selector, descriptor); } } } } return(descriptor); }
/// <summary> /// Measure string directly from font data. /// </summary> public static XSize MeasureString(string text, XFont font, XStringFormat stringFormat_notyetused) { XSize size = new XSize(); OpenTypeDescriptor descriptor = FontDescriptorCache.GetOrCreateDescriptorFor(font) as OpenTypeDescriptor; if (descriptor != null) { // Height is the sum of ascender and descender. size.Height = (descriptor.Ascender + descriptor.Descender) * font.Size / font.UnitsPerEm; Debug.Assert(descriptor.Ascender > 0); bool symbol = descriptor.FontFace.cmap.symbol; int length = text.Length; int width = 0; for (int idx = 0; idx < length; idx++) { char ch = text[idx]; // HACK: Unclear what to do here. if (ch < 32) { continue; } if (char.IsLowSurrogate(ch)) { continue; // Don't process high surrorgate. Low will process this char } if (symbol) { // Remap ch for symbol fonts. ch = (char)(ch | (descriptor.FontFace.os2.usFirstCharIndex & 0xFF00)); // @@@ refactor // Used | instead of + because of: http://pdfsharp.codeplex.com/workitem/15954 } uint glyphIndex; if (char.IsHighSurrogate(ch)) { glyphIndex = descriptor.CharCodeToGlyphIndex(ch, text[idx + 1]); } else { glyphIndex = descriptor.CharCodeToGlyphIndex(ch); } width += descriptor.GlyphIndexToWidth(glyphIndex); } // What? size.Width = width * font.Size * (font.Italic ? 1 : 1) / descriptor.UnitsPerEm; size.Width = width * font.Size / descriptor.UnitsPerEm; // Adjust bold simulation. if ((font.GlyphTypeface.StyleSimulations & XStyleSimulations.BoldSimulation) == XStyleSimulations.BoldSimulation) { // Add 2% of the em-size for each character. // Unsure how to deal with white space. Currently count as regular character. size.Width += length * font.Size * Const.BoldEmphasis; } } Debug.Assert(descriptor != null, "No OpenTypeDescriptor."); return(size); }
// HACK FlagsFromDescriptor(OpenTypeDescriptor descriptor) PdfFontDescriptorFlags FlagsFromDescriptor(OpenTypeDescriptor descriptor) { PdfFontDescriptorFlags flags = 0; _isSymbolFont = descriptor.FontFace.cmap.symbol; flags |= descriptor.FontFace.cmap.symbol ? PdfFontDescriptorFlags.Symbolic : PdfFontDescriptorFlags.Nonsymbolic; return(flags); }
public PdfType0Font(PdfDocument document, XFont font, bool vertical) : base(document) { Elements.SetName(Keys.Type, "/Font"); Elements.SetName(Keys.Subtype, "/Type0"); Elements.SetName(Keys.Encoding, vertical ? "/Identity-V" : "/Identity-H"); OpenTypeDescriptor ttDescriptor = (OpenTypeDescriptor)FontDescriptorStock.Global.CreateDescriptor(font); this.fontDescriptor = new PdfFontDescriptor(document, ttDescriptor); this.fontOptions = font.PdfOptions; Debug.Assert(this.fontOptions != null); this.cmapInfo = new CMapInfo(ttDescriptor); this.descendantFont = new PdfCIDFont(document, this.fontDescriptor, font); this.descendantFont.CMapInfo = this.cmapInfo; // Create ToUnicode map this.toUnicode = new PdfToUnicodeMap(document, this.cmapInfo); document.Internals.AddObject(toUnicode); Elements.Add(Keys.ToUnicode, toUnicode); //if (this.fontOptions.BaseFont != "") //{ // BaseFont = this.fontOptions.BaseFont; //} //else { BaseFont = font.Name.Replace(" ", ""); switch (font.Style & (XFontStyle.Bold | XFontStyle.Italic)) { case XFontStyle.Bold: this.BaseFont += ",Bold"; break; case XFontStyle.Italic: this.BaseFont += ",Italic"; break; case XFontStyle.Bold | XFontStyle.Italic: this.BaseFont += ",BoldItalic"; break; } } // CID fonts are always embedded BaseFont = PdfFont.CreateEmbeddedFontSubsetName(BaseFont); this.fontDescriptor.FontName = BaseFont; this.descendantFont.BaseFont = BaseFont; PdfArray descendantFonts = new PdfArray(document); Owner.irefTable.Add(descendantFont); descendantFonts.Elements.Add(descendantFont.Reference); Elements[Keys.DescendantFonts] = descendantFonts; }
/// <summary> /// Returns the cell descent, in design units, of the XFontFamily object of the specified style. /// </summary> public int GetCellDescent(XFontStyle style) { OpenTypeDescriptor descriptor = (OpenTypeDescriptor)FontDescriptorCache.GetOrCreateDescriptor(Name, style); int result = descriptor.Descender; #if DEBUG_ && GDI int gdiValue = _gdiFamily.GetCellDescent((FontStyle)style); Debug.Assert(gdiValue == result); #endif return(result); }
/// <summary> /// Gets the height, in font design units, of the em square for the specified style. /// </summary> public int GetEmHeight(XFontStyle style) { OpenTypeDescriptor descriptor = (OpenTypeDescriptor)FontDescriptorCache.GetOrCreateDescriptor(Name, style); int result = descriptor.UnitsPerEm; #if DEBUG_ int headValue = descriptor.FontFace.head.unitsPerEm; Debug.Assert(headValue == result); #endif return(result); }
public PdfType0Font(PdfDocument document, string idName, byte[] fontData, bool vertical) : base(document) { Elements.SetName(Keys.Type, "/Font"); Elements.SetName(Keys.Subtype, "/Type0"); Elements.SetName(Keys.Encoding, vertical ? "/Identity-V" : "/Identity-H"); OpenTypeDescriptor ttDescriptor = (OpenTypeDescriptor)FontDescriptorStock.Global.CreateDescriptor(idName, fontData); this.fontDescriptor = new PdfFontDescriptor(document, ttDescriptor); this.fontOptions = new XPdfFontOptions(PdfFontEncoding.Unicode, PdfFontEmbedding.Always); Debug.Assert(this.fontOptions != null); this.cmapInfo = new CMapInfo(ttDescriptor); this.descendantFont = new PdfCIDFont(document, this.fontDescriptor, fontData); this.descendantFont.CMapInfo = this.cmapInfo; // Create ToUnicode map this.toUnicode = new PdfToUnicodeMap(document, this.cmapInfo); document.Internals.AddObject(toUnicode); Elements.Add(Keys.ToUnicode, toUnicode); BaseFont = ttDescriptor.FontName.Replace(" ", ""); //switch (font.Style & (XFontStyle.Bold | XFontStyle.Italic)) //{ // case XFontStyle.Bold: // this.BaseFont += ",Bold"; // break; // case XFontStyle.Italic: // this.BaseFont += ",Italic"; // break; // case XFontStyle.Bold | XFontStyle.Italic: // this.BaseFont += ",BoldItalic"; // break; //} // CID fonts are always embedded if (!BaseFont.Contains("+")) // HACK in PdfType0Font { BaseFont = PdfFont.CreateEmbeddedFontSubsetName(BaseFont); } this.fontDescriptor.FontName = BaseFont; this.descendantFont.BaseFont = BaseFont; PdfArray descendantFonts = new PdfArray(document); Owner.irefTable.Add(descendantFont); descendantFonts.Elements.Add(descendantFont.Reference); Elements[Keys.DescendantFonts] = descendantFonts; }
/// <summary> /// Returns the line spacing, in design units, of the FontFamily object of the specified style. /// The line spacing is the vertical distance between the base lines of two consecutive lines of text. /// </summary> public int GetLineSpacing(XFontStyle style) { OpenTypeDescriptor descriptor = (OpenTypeDescriptor)FontDescriptorCache.GetOrCreateDescriptor(Name, style); int result = descriptor.LineSpacing; #if DEBUG_ && GDI int gdiValue = _gdiFamily.GetLineSpacing((FontStyle)style); Debug.Assert(gdiValue == result); #endif #if DEBUG_ && WPF && !SILVERLIGHT int wpfValue = (int)Math.Round(_wpfFamily.LineSpacing * GetEmHeight(style)); Debug.Assert(wpfValue == result); #endif return(result); }
/// <summary> /// Gets the height, in font design units, of the em square for the specified style. /// </summary> public int GetEmHeight(XFontStyle style) { OpenTypeDescriptor descriptor = (OpenTypeDescriptor)FontDescriptorCache.GetOrCreateDescriptor(Name, style); int result = descriptor.UnitsPerEm; //#if DEBUG_ && GDI //int gdiValue = _gdiFamily.GetEmHeight((FontStyle)style); //Debug.Assert(gdiValue == result); //#endif //#if DEBUG_ // int headValue = descriptor.FontFace.head.unitsPerEm; // Debug.Assert(headValue == result); //#endif return(result); }
public FontDescriptor CreateDescriptor(string idName, byte[] fontData) { FontSelector selector = new FontSelector(idName); FontDescriptor descriptor; if (!table.TryGetValue(selector, out descriptor)) { lock (typeof(FontDescriptorStock)) { // may be created by other thread meanwhile if (!table.TryGetValue(selector, out descriptor)) { descriptor = new OpenTypeDescriptor(idName, fontData); table.Add(selector, descriptor); } } } return(descriptor); }
public PDFType0Font(PDFDocument document, string idName, byte[] fontData, bool vertical) : base(document) { Elements.SetName(Keys.Type, "/Font"); Elements.SetName(Keys.Subtype, "/Type0"); Elements.SetName(Keys.Encoding, vertical ? "/Identity-V" : "/Identity-H"); OpenTypeDescriptor ttDescriptor = (OpenTypeDescriptor)FontDescriptorCache.GetOrCreateDescriptor(idName, fontData); FontDescriptor = new PDFFontDescriptor(document, ttDescriptor); FontOptions = new XPDFFontOptions(PDFFontEncoding.Unicode); Debug.Assert(FontOptions != null); _cmapInfo = new CMapInfo(ttDescriptor); DescendantFont = new PDFCIDFont(document, FontDescriptor, fontData) { CMapInfo = _cmapInfo }; // Create ToUnicode map _toUnicode = new PDFToUnicodeMap(document, _cmapInfo); document.Internals.AddObject(_toUnicode); Elements.Add(Keys.ToUnicode, _toUnicode); //BaseFont = ttDescriptor.FontName.Replace(" ", ""); BaseFont = ttDescriptor.FontName; // CID fonts are always embedded if (!BaseFont.Contains("+")) // HACK in PDFType0Font { BaseFont = CreateEmbeddedFontSubsetName(BaseFont); } FontDescriptor.FontName = BaseFont; DescendantFont.BaseFont = BaseFont; PDFArray descendantFonts = new PDFArray(document); Owner.IrefTable.Add(DescendantFont); descendantFonts.Elements.Add(DescendantFont.Reference); Elements[Keys.DescendantFonts] = descendantFonts; }
internal PdfFontDescriptor(PdfDocument document, OpenTypeDescriptor descriptor) : base(document) { _descriptor = descriptor; Elements.SetName(Keys.Type, "/FontDescriptor"); Elements.SetInteger(Keys.Ascent, _descriptor.DesignUnitsToPdf(_descriptor.Ascender)); Elements.SetInteger(Keys.CapHeight, _descriptor.DesignUnitsToPdf(_descriptor.CapHeight)); Elements.SetInteger(Keys.Descent, _descriptor.DesignUnitsToPdf(_descriptor.Descender)); Elements.SetInteger(Keys.Flags, (int)FlagsFromDescriptor(_descriptor)); Elements.SetRectangle(Keys.FontBBox, new PdfRectangle( _descriptor.DesignUnitsToPdf(_descriptor.XMin), _descriptor.DesignUnitsToPdf(_descriptor.YMin), _descriptor.DesignUnitsToPdf(_descriptor.XMax), _descriptor.DesignUnitsToPdf(_descriptor.YMax))); // not here, done in PdfFont later... //Elements.SetName(Keys.FontName, "abc"); //descriptor.FontName); Elements.SetReal(Keys.ItalicAngle, _descriptor.ItalicAngle); Elements.SetInteger(Keys.StemV, _descriptor.StemV); Elements.SetInteger(Keys.XHeight, _descriptor.DesignUnitsToPdf(_descriptor.XHeight)); }
///// <summary> ///// Gets the FontDescriptor identified by the specified FontSelector. If no such object ///// exists, a new FontDescriptor is created and added to the stock. ///// </summary> //public static FontDescriptor GetOrCreateDescriptor_DEL-ETE(string familyName, XFontStyle stlye, OpenTypeFontface fontface) //{ // //FontSelector1 selector = new FontSelector1(familyName, stlye); // string fontDescriptorKey = null; // FontDescriptor.ComputeKey(familyName, stlye); // try // { // Lock.EnterFontFactory(); // FontDescriptor descriptor; // if (!Singleton._cache.TryGetValue(fontDescriptorKey, out descriptor)) // { // descriptor = new OpenTypeDescriptor(fontDescriptorKey, familyName, stlye, fontface, null); // Singleton._cache.Add(fontDescriptorKey, descriptor); // } // return descriptor; // } // finally { Lock.ExitFontFactory(); } //} /// <summary> /// Gets the FontDescriptor identified by the specified XFont. If no such object /// exists, a new FontDescriptor is created and added to the cache. /// </summary> public static FontDescriptor GetOrCreateDescriptorFor(XFont font) { if (font == null) { throw new ArgumentNullException("font"); } //FontSelector1 selector = new FontSelector1(font); string fontDescriptorKey = FontDescriptor.ComputeKey(font); try { Lock.EnterFontFactory(); FontDescriptor descriptor; if (!Singleton._cache.TryGetValue(fontDescriptorKey, out descriptor)) { descriptor = new OpenTypeDescriptor(fontDescriptorKey, font); Singleton._cache.Add(fontDescriptorKey, descriptor); } return(descriptor); } finally { Lock.ExitFontFactory(); } }
// ...took a look at the source code of WPF. About 50 classes and several 10,000 lines of code // deal with that what colloquial is called 'fonts'. // So let's start simple. /// <summary> /// Simple measure string function. /// </summary> public static XSize MeasureString(string text, XFont font, XStringFormat stringFormat) { XSize size = new XSize(); OpenTypeDescriptor descriptor = FontDescriptorStock.Global.CreateDescriptor(font) as OpenTypeDescriptor; if (descriptor != null) { size.Height = (descriptor.Ascender + Math.Abs(descriptor.Descender)) * font.Size / font.unitsPerEm; Debug.Assert(descriptor.Ascender > 0); bool symbol = descriptor.fontData.cmap.symbol; int length = text.Length; int width = 0; for (int idx = 0; idx < length; idx++) { char ch = text[idx]; int glyphIndex = 0; if (symbol) { glyphIndex = ch + (descriptor.fontData.os2.usFirstCharIndex & 0xFF00); // @@@ glyphIndex = descriptor.CharCodeToGlyphIndex((char)glyphIndex); } else { glyphIndex = descriptor.CharCodeToGlyphIndex(ch); } //double width = descriptor.GlyphIndexToEmfWidth(glyphIndex, font.Size); //size.Width += width; width += descriptor.GlyphIndexToWidth(glyphIndex); } size.Width = width * font.Size * (font.Italic ? 1 : 1) / descriptor.UnitsPerEm; } Debug.Assert(descriptor != null, "No OpenTypeDescriptor."); return(size); }
///// <summary> ///// Gets the FontDescriptor identified by the specified FontSelector. If no such objects ///// exists, a new FontDescriptor is created and added to the stock. ///// </summary> //public FontDescriptor CreateDescriptor(FontSelector selector) //{ // if (selector == null) // throw new ArgumentNullException("selector"); // FontDescriptor descriptor = this.table[selector] as FontDescriptor; // if (descriptor == null) // { // descriptor = new TrueTypeDescriptor(selector); // this.table.Add(selector, descriptor); // } // return descriptor; //} /// <summary> /// Gets the FontDescriptor identified by the specified FontSelector. If no such objects /// exists, a new FontDescriptor is created and added to the stock. /// </summary> public FontDescriptor CreateDescriptor(XFont font) { if (font == null) { throw new ArgumentNullException("font"); } FontSelector selector = new FontSelector(font); FontDescriptor descriptor; if (!table.TryGetValue(selector, out descriptor)) { lock (typeof(FontDescriptorStock)) { // may be created by other thread meanwhile if (!table.TryGetValue(selector, out descriptor)) { descriptor = new OpenTypeDescriptor(font); table.Add(selector, descriptor); } } } return(descriptor); }
/// <summary> /// Initializes a new instance of PdfTrueTypeFont from an XFont. /// </summary> public PdfTrueTypeFont(PdfDocument document, XFont font) : base(document) { Elements.SetName(Keys.Type, "/Font"); Elements.SetName(Keys.Subtype, "/TrueType"); // TrueType with WinAnsiEncoding only OpenTypeDescriptor ttDescriptor = (OpenTypeDescriptor)FontDescriptorStock.Global.CreateDescriptor(font); this.fontDescriptor = new PdfFontDescriptor(document, ttDescriptor); this.fontOptions = font.PdfOptions; Debug.Assert(this.fontOptions != null); //this.cmapInfo = new CMapInfo(null/*ttDescriptor*/); this.cmapInfo = new CMapInfo(ttDescriptor); BaseFont = font.Name.Replace(" ", ""); switch (font.Style & (XFontStyle.Bold | XFontStyle.Italic)) { case XFontStyle.Bold: BaseFont += ",Bold"; break; case XFontStyle.Italic: BaseFont += ",Italic"; break; case XFontStyle.Bold | XFontStyle.Italic: BaseFont += ",BoldItalic"; break; } if (this.fontOptions.FontEmbedding == PdfFontEmbedding.Always) { BaseFont = PdfFont.CreateEmbeddedFontSubsetName(BaseFont); } this.fontDescriptor.FontName = BaseFont; Debug.Assert(this.fontOptions.FontEncoding == PdfFontEncoding.WinAnsi); if (!IsSymbolFont) { Encoding = "/WinAnsiEncoding"; } // { //#if true // throw new NotImplementedException("Specifying a font file is not yet supported."); //#else // // Testcode // FileStream stream = new FileStream("WAL____I.AFM", FileAccess.Read); // int length = stream.Length; // byte[] fontProgram = new byte[length]; // PdfDictionary fontStream = new PdfDictionary(this.Document); // this.Document.xrefTable.Add(fontStream); // this.fontDescriptor.Elements[PdfFontDescriptor.Keys.FontFile] = fontStream.XRef; // fontStream.Elements["/Length1"] = new PdfInteger(fontProgram.Length); // if (!this.Document.Options.NoCompression) // { // fontProgram = Filtering.FlateDecode.Encode(fontProgram); // fontStream.Elements["/Filter"] = new PdfName("/FlateDecode"); // } // fontStream.Elements["/Length"] = new PdfInteger(fontProgram.Length); // fontStream.CreateStream(fontProgram); //#endif // } Owner.irefTable.Add(this.fontDescriptor); Elements[Keys.FontDescriptor] = this.fontDescriptor.Reference; FontEncoding = font.PdfOptions.FontEncoding; FontEmbedding = font.PdfOptions.FontEmbedding; }
/// <summary> /// Writes a Glyphs to the content stream. /// </summary> private void WriteGlyphs(Glyphs glyphs) { WriteSaveState("begin Glyphs", glyphs.Name); // Transform also affects clipping and opacity mask bool transformed = glyphs.RenderTransform != null; if (transformed) { WriteRenderTransform(glyphs.RenderTransform); } bool clipped = glyphs.Clip != null; if (clipped) { WriteClip(glyphs.Clip); } if (glyphs.Opacity < 1) { MultiplyOpacity(glyphs.Opacity); } if (glyphs.OpacityMask != null) { WriteOpacityMask(glyphs.OpacityMask); } XMatrix textMatrix = new XMatrix(); textMatrix.TranslatePrepend(glyphs.OriginX, glyphs.OriginY); glyphs.OriginX = glyphs.OriginY = 0; // HACK: do not change model double emSize = glyphs.FontRenderingEmSize; textMatrix.ScalePrepend(glyphs.FontRenderingEmSize); glyphs.FontRenderingEmSize = 1; // HACK: do not change model bool boldSimulation = (glyphs.StyleSimulations & StyleSimulations.BoldSimulation) == StyleSimulations.BoldSimulation; // just a draft... if (boldSimulation) { boldSimulation = true; // draw black stroke if it is not a solid color brush XColor color = XColor.FromArgb(0, 0, 0); if (glyphs.Fill is SolidColorBrush) { SolidColorBrush brush = glyphs.Fill as SolidColorBrush; color = brush.Color; } WriteLiteral(String.Format(CultureInfo.InvariantCulture, "{0:0.###} {1:0.###} {2:0.###} RG\n", color.R / 255.0, color.G / 255.0, color.B / 255.0)); WriteLiteral("{0:0.###} w\n", emSize / 50); } if ((glyphs.StyleSimulations & StyleSimulations.ItalicSimulation) == StyleSimulations.ItalicSimulation) { textMatrix.SkewPrepend(-20, 0); } XForm xform = null; XImage ximage = null; RealizeFill(glyphs.Fill, ref xform, ref ximage); RealizeFont(glyphs); if (boldSimulation) { WriteLiteral("2 Tr\n", 1); } double x = glyphs.OriginX; double y = glyphs.OriginY; //switch (format.Alignment) //{ // case XStringAlignment.Near: // // nothing to do // break; // case XStringAlignment.Center: // x += (rect.Width - width) / 2; // break; // case XStringAlignment.Far: // x += rect.Width - width; // break; //} PdfFont realizedFont = this.graphicsState.realizedFont; Debug.Assert(realizedFont != null); realizedFont.AddChars(glyphs.UnicodeString); OpenTypeDescriptor descriptor = realizedFont.FontDescriptor._descriptor; //if (bold && !descriptor.IsBoldFace) //{ // // TODO: emulate bold by thicker outline //} //if (italic && !descriptor.IsBoldFace) //{ // // TODO: emulate italic by shearing transformation //} #if true string s2 = ""; string s = glyphs.UnicodeString; if (!String.IsNullOrEmpty(s)) { int length = s.Length; for (int idx = 0; idx < length; idx++) { char ch = s[idx]; int glyphID = 0; if (descriptor.FontFace.cmap.symbol) { glyphID = (int)ch + (descriptor.FontFace.os2.usFirstCharIndex & 0xFF00); glyphID = descriptor.CharCodeToGlyphIndex((char)glyphID); } else { glyphID = descriptor.CharCodeToGlyphIndex(ch); } s2 += (char)glyphID; } } s = s2; #endif byte[] bytes = PdfEncoders.RawUnicodeEncoding.GetBytes(s); bytes = PdfEncoders.FormatStringLiteral(bytes, true, false, true, null); string text = PdfEncoders.RawEncoding.GetString(bytes); if (glyphs.IsSideways) { textMatrix.RotateAtPrepend(-90, new XPoint(x, y)); XPoint pos = new XPoint(x, y); AdjustTextMatrix(ref pos); //WriteTextTransform(textMatrix); WriteLiteral("{0} Tj\n", text); } else { #if true //if (glyphs.BidiLevel % 2 == 1) // WriteLiteral("-1 Tc\n"); if (!textMatrix.IsIdentity) { WriteTextTransform(textMatrix); } WriteGlyphsInternal(glyphs, null); #else XPoint pos = new XPoint(x, y); AdjustTextMatrix(ref pos); WriteLiteral("{0:0.###} {1:0.###} Td {2} Tj\n", pos.x, pos.y, text); //PdfEncoders.ToStringLiteral(s, PdfStringEncoding.RawEncoding, null)); #endif } WriteRestoreState("end Glyphs", glyphs.Name); }
/// <summary> /// This is just a draft to see what to do in detail. /// </summary> private void WriteGlyphs_ClusterMapping(Glyphs glyphs) { string unicodeString = glyphs.UnicodeString; #if DEBUG_ if (!String.IsNullOrEmpty(unicodeString)) { if (unicodeString.StartsWith("abc")) { GetType(); } } #endif bool boldSimulation = (glyphs.StyleSimulations & StyleSimulations.BoldSimulation) == StyleSimulations.BoldSimulation; double boldSimulationFactor = 1; if (boldSimulation) { boldSimulationFactor = 1; } bool RightToLeft = glyphs.BidiLevel % 2 == 1; // TODOWPF: why is this a level?? what means "bidirectional nesting"? GlyphIndices indices = glyphs.Indices; if (indices == null) { indices = new GlyphIndices(); } int codeIdx = 0; int codeCount = String.IsNullOrEmpty(unicodeString) ? 0 : unicodeString.Length; int glyphCount = indices.Count; int glyphIdx = 0; bool stop = false; PdfFont realizedFont = this.graphicsState.realizedFont; OpenTypeDescriptor descriptor = realizedFont.FontDescriptor._descriptor; int glyphIndex; double x = glyphs.OriginX; double y = glyphs.OriginY; XPoint pos = new XPoint(x, y); // accumulation may lead to rounding error -> check it! double uOffset = 0; double vOffset = 0; StringBuilder outputText = new StringBuilder(); double accumulatedWidth = 0; int outputGlyphCount = 0; bool mustRender = false; bool hasOffset = false; do { GlyphIndices.GlyphMapping clusterMapping = new GlyphIndices.GlyphMapping(42); if (glyphIdx < glyphCount) { clusterMapping = indices[glyphIdx]; } for (int clusterGlyphIdx = 0; clusterGlyphIdx < clusterMapping.ClusterGlyphCount; clusterGlyphIdx++) { GlyphIndices.GlyphMapping mapping = new GlyphIndices.GlyphMapping(42); if (glyphIdx + clusterGlyphIdx < glyphCount) { mapping = indices[glyphIdx + clusterGlyphIdx]; } Debug.Assert(mustRender == false); // Determine whether to render accumulated glyphs if (outputGlyphCount > 0 && (hasOffset || mapping.HasAdvanceWidthOrOffset)) { outputText.Append('>'); WriteLiteral("{0:0.####} {1:0.####} Td {2}Tj\n", pos.X, pos.Y, outputText.ToString()); //double width = descriptor.GlyphIndexToPdfWidth(glyphIndex); //if (!PdfSharp.Internal.DoubleUtil.IsNaN(mapping.AdvanceWidth)) // width = mapping.AdvanceWidth * 10; //pos = new XPoint(accumulatedWidth + width / 1000 * glyphs.FontRenderingEmSize, 0); pos = new XPoint(accumulatedWidth, 0); // reset values accumulatedWidth = 0; outputGlyphCount = 0; outputText.Length = 0; mustRender = false; } mustRender = mapping.HasAdvanceWidth; //mustRender = true; // Adjust former uOffset if (uOffset != 0) { pos.X -= uOffset; uOffset = 0; mustRender = true; } // Adjust position by current former uOffset if (mapping.HasUOffset) { uOffset = mapping.UOffset * glyphs.FontRenderingEmSize / 100; pos.X += uOffset; mustRender = true; hasOffset = true; } // Adjust former vOffset if (vOffset != 0) { pos.Y += vOffset; vOffset = 0; mustRender = true; } // Adjust position by current former vOffset if (mapping.HasVOffset) { vOffset = mapping.VOffset * glyphs.FontRenderingEmSize / 100; pos.Y -= vOffset; mustRender = true; hasOffset = true; } // get index of current glyph if (mapping.HasGlyphIndex) { glyphIndex = mapping.GlyphIndex; } else { glyphIndex = descriptor.CharCodeToGlyphIndex(unicodeString[codeIdx]); } // add glyph index to the fonts 'used glyph table' realizedFont.AddGlyphIndices(new string((char)glyphIndex, 1)); #if true if (outputGlyphCount == 0) { outputText.Append('<'); } outputText.AppendFormat("{0:X2}{1:X2}", (byte)(glyphIndex >> 8), (byte)glyphIndex); #else byte[] bytes = new byte[2] { (byte)(glyphIndex >> 8), (byte)glyphIndex }; bytes = PdfEncoders.FormatStringLiteral(bytes, true, false, true, null); string output = PdfEncoders.RawEncoding.GetString(bytes); #endif // At the end of the glyph run we must always render if (!mustRender) { mustRender = codeIdx + clusterMapping.ClusterCodeUnitCount >= codeCount && // is it the last code unit cluster glyphIdx + clusterGlyphIdx + 1 >= glyphCount; // is it the last glyph index } //mustRender = true; if (mustRender) { outputText.Append('>'); WriteLiteral("{0:0.####} {1:0.####} Td {2}Tj\n", pos.X, pos.Y, outputText.ToString()); double width = descriptor.GlyphIndexToPdfWidth(glyphIndex); if (!PdfSharp.Internal.DoubleUtil.IsNaN(mapping.AdvanceWidth)) { width = mapping.AdvanceWidth * 10; } pos = new XPoint(accumulatedWidth + width * boldSimulationFactor / 1000 * glyphs.FontRenderingEmSize, 0); // reset values accumulatedWidth = 0; outputGlyphCount = 0; outputText.Length = 0; mustRender = false; } else // deferred rendering { // accumulate width Debug.Assert(DoubleUtil.IsNaN(mapping.AdvanceWidth)); double width = descriptor.GlyphIndexToPdfWidth(glyphIndex); width = width * boldSimulationFactor / 1000 * glyphs.FontRenderingEmSize; accumulatedWidth += width; outputGlyphCount++; } } codeIdx += clusterMapping.ClusterCodeUnitCount; glyphIdx += clusterMapping.ClusterGlyphCount; if (codeIdx >= codeCount && glyphIdx >= glyphCount) { stop = true; } }while (!stop); }
public CMapInfo(OpenTypeDescriptor descriptor) { Debug.Assert(descriptor != null); this.descriptor = descriptor; }
internal override void PrepareForSave() { base.PrepareForSave(); #if true // use GetGlyphIndices to create the widths array OpenTypeDescriptor descriptor = (OpenTypeDescriptor)this.fontDescriptor.descriptor; StringBuilder w = new StringBuilder("["); if (this.cmapInfo != null) { int[] glyphIndices = this.cmapInfo.GetGlyphIndices(); int count = glyphIndices.Length; int[] glyphWidths = new int[count]; for (int idx = 0; idx < count; idx++) { glyphWidths[idx] = descriptor.GlyphIndexToPdfWidth(glyphIndices[idx]); } //TODO: optimize order of indices for (int idx = 0; idx < count; idx++) { w.AppendFormat("{0}[{1}]", glyphIndices[idx], glyphWidths[idx]); } w.Append("]"); this.descendantFont.Elements.SetValue(PdfCIDFont.Keys.W, new PdfLiteral(w.ToString())); #else TrueTypeDescriptor descriptor = (TrueTypeDescriptor)this.fontDescriptor.descriptor; bool symbol = descriptor.fontData.cmap.symbol; StringBuilder w = new StringBuilder("["); if (this.cmapInfo != null) { char[] chars = this.cmapInfo.Chars; int count = chars.Length; // We don't care about char that share the same glyph int[] glyphIndices = new int[count]; int[] glyphWidths = new int[count]; for (int idx = 0; idx < count; idx++) { char ch = chars[idx]; int glyphIndex; if (symbol) { glyphIndex = (int)ch + (descriptor.fontData.os2.usFirstCharIndex & 0xFF00); glyphIndex = descriptor.CharCodeToGlyphIndex((char)glyphIndex); } else { glyphIndex = descriptor.CharCodeToGlyphIndex(ch); } descriptor.CharCodeToGlyphIndex(chars[idx]); glyphIndices[idx] = glyphIndex; glyphWidths[idx] = descriptor.GlyphIndexToPdfWidth(glyphIndex); } //TODO: optimize order of indices for (int idx = 0; idx < count; idx++) { w.AppendFormat("{0}[{1}]", glyphIndices[idx], glyphWidths[idx]); } w.Append("]"); this.descendantFont.Elements.SetValue(PdfCIDFont.Keys.W, new PdfLiteral(w.ToString())); #endif } this.descendantFont.PrepareForSave(); this.toUnicode.PrepareForSave(); }
/// <summary> /// Measure string directly from font data. /// </summary> public static XSize MeasureString(string text, XFont font, XStringFormat stringFormat) { XSize size = new XSize(); OpenTypeDescriptor descriptor = FontDescriptorCache.GetOrCreateDescriptorFor(font) as OpenTypeDescriptor; if (descriptor != null) { // Height is the sum of ascender and descender. var singleLineHeight = (descriptor.Ascender + descriptor.Descender) * font.Size / font.UnitsPerEm; var lineGapHeight = (descriptor.LineSpacing - descriptor.Ascender - descriptor.Descender) * font.Size / font.UnitsPerEm; Debug.Assert(descriptor.Ascender > 0); bool symbol = descriptor.FontFace.cmap.symbol; int length = text.Length; int adjustedLength = length; var height = singleLineHeight; int maxWidth = 0; int width = 0; for (int idx = 0; idx < length; idx++) { char ch = text[idx]; // Handle line feed ( \n) if (ch == 10) { adjustedLength--; if (idx < (length - 1)) { maxWidth = Math.Max(maxWidth, width); width = 0; height += lineGapHeight + singleLineHeight; } continue; } // HACK: Handle tabulator sign as space (\t) if (ch == 9) { ch = ' '; } // HACK: Unclear what to do here. if (ch < 32) { adjustedLength--; continue; } if (symbol) { // Remap ch for symbol fonts. ch = (char)(ch | (descriptor.FontFace.os2.usFirstCharIndex & 0xFF00)); // @@@ refactor // Used | instead of + because of: http://PdfSharpCore.codeplex.com/workitem/15954 } int glyphIndex = descriptor.CharCodeToGlyphIndex(ch); width += descriptor.GlyphIndexToWidth(glyphIndex); } maxWidth = Math.Max(maxWidth, width); // What? size.Width = maxWidth * font.Size * (font.Italic ? 1 : 1) / descriptor.UnitsPerEm; size.Width = maxWidth * font.Size / descriptor.UnitsPerEm; size.Height = height; // Adjust bold simulation. if ((font.GlyphTypeface.StyleSimulations & XStyleSimulations.BoldSimulation) == XStyleSimulations.BoldSimulation) { // Add 2% of the em-size for each character. // Unsure how to deal with white space. Currently count as regular character. size.Width += adjustedLength * font.Size * Const.BoldEmphasis; } } Debug.Assert(descriptor != null, "No OpenTypeDescriptor."); return(size); }