/// <summary> /// Initializes a new instance of the <see cref="FontData"/> class. /// </summary> public FontData(XFont font, XPdfFontOptions options) { #if GDI && !WPF CreateGdiFontImage(font, options, font.privateFontCollection); #endif #if WPF && !GDI CreateWpfFontData(font, options); #endif #if WPF && GDI System.Drawing.Font gdiFont = font.RealizeGdiFont(); if (font.font != null) CreateGdiFontImage(font, options, font.privateFontCollection); else if (font.typeface != null) CreateWpfFontData(font, options); #endif if (this.data == null) throw new InvalidOperationException("Cannot allocate font image."); Read(); }
// ----- MeasureString ------------------------------------------------------------------------ /// <summary> /// Measures the specified string when drawn with the specified font. /// </summary> public XSize MeasureString(string text, XFont font, XStringFormat stringFormat) { // TODO: Here comes a lot of code in the future: kerning etc... if (text == null) throw new ArgumentNullException("text"); if (font == null) throw new ArgumentNullException("font"); if (stringFormat == null) throw new ArgumentNullException("stringFormat"); #if GDI && !WPF return XSize.FromSizeF(this.gfx.MeasureString(text, font.RealizeGdiFont(), new PointF(0, 0), stringFormat.RealizeGdiStringFormat())); #endif #if WPF && !GDI #if !SILVERLIGHT //FormattedText formattedText = new FormattedText(text, new CultureInfo("en-us"), // FlowDirection.LeftToRight, font.typeface, font.Size, System.Windows.Media.Brushes.Black); FormattedText formattedText = FontHelper.CreateFormattedText(text, font.typeface, font.Size, System.Windows.Media.Brushes.Black); return new XSize(formattedText.WidthIncludingTrailingWhitespace, formattedText.Height); #else return dc.MeasureString(this, text, font, stringFormat); #endif #endif #if WPF && GDI if (this.targetContext == XGraphicTargetContext.GDI) { XSize gdiSize = XSize.FromSizeF(this.gfx.MeasureString(text, font.RealizeGdiFont(), new PointF(0, 0), stringFormat.RealizeGdiStringFormat())); #if DEBUG Debug.WriteLine(gdiSize); #endif return gdiSize; } if (this.targetContext == XGraphicTargetContext.WPF) { //double h = font.Height; //FormattedText formattedText = new FormattedText(text, new CultureInfo("en-us"), // FlowDirection.LeftToRight, font.typeface, font.Size, System.Windows.Media.Brushes.Black); FormattedText formattedText = FontHelper.CreateFormattedText(text, font.typeface, font.Size, System.Windows.Media.Brushes.Black); XSize wpfSize = new XSize(formattedText.WidthIncludingTrailingWhitespace, formattedText.Height); #if DEBUG Debug.WriteLine(wpfSize); #endif return wpfSize; } Debug.Assert(false); return XSize.Empty; #endif }
/// <summary> /// Draws the specified text string. /// </summary> public void DrawString(string text, XFont font, XBrush brush, XRect layoutRectangle, XStringFormat format) { if (text == null) throw new ArgumentNullException("text"); if (font == null) throw new ArgumentNullException("font"); if (brush == null) throw new ArgumentNullException("brush"); if (format != null && format.LineAlignment == XLineAlignment.BaseLine && layoutRectangle.Height != 0) throw new InvalidOperationException("DrawString: With XLineAlignment.BaseLine the height of the layout rectangle must be 0."); if (text.Length == 0) return; if (format == null) format = XStringFormats.Default; if (this.drawGraphics) { #if GDI if (this.targetContext == XGraphicTargetContext.GDI) { RectangleF rect = layoutRectangle.ToRectangleF(); if (format.LineAlignment == XLineAlignment.BaseLine) { double lineSpace = font.GetHeight(this); int cellSpace = font.FontFamily.GetLineSpacing(font.Style); int cellAscent = font.FontFamily.GetCellAscent(font.Style); int cellDescent = font.FontFamily.GetCellDescent(font.Style); double cyAscent = lineSpace * cellAscent / cellSpace; cyAscent = lineSpace * font.cellAscent / font.cellSpace; rect.Offset(0, (float)-cyAscent); } this.gfx.DrawString(text, font.RealizeGdiFont(), brush.RealizeGdiBrush(), rect, format != null ? format.RealizeGdiStringFormat() : null); } #endif #if WPF if (this.targetContext == XGraphicTargetContext.WPF) { #if !SILVERLIGHT double x = layoutRectangle.X; double y = layoutRectangle.Y; double lineSpace = font.GetHeight(this); double cyAscent = lineSpace * font.cellAscent / font.cellSpace; double cyDescent = lineSpace * font.cellDescent / font.cellSpace; bool bold = (font.Style & XFontStyle.Bold) != 0; bool italic = (font.Style & XFontStyle.Italic) != 0; bool strikeout = (font.Style & XFontStyle.Strikeout) != 0; bool underline = (font.Style & XFontStyle.Underline) != 0; //FormattedText formattedText = new FormattedText(text, new CultureInfo("en-us"), // WPFHACK // FlowDirection.LeftToRight, font.typeface, font.Size, brush.RealizeWpfBrush()); FormattedText formattedText = FontHelper.CreateFormattedText(text, font.typeface, font.Size, brush.RealizeWpfBrush()); //formattedText.SetTextDecorations(TextDecorations.OverLine); switch (format.Alignment) { case XStringAlignment.Near: // nothing to do, this is the default //formattedText.TextAlignment = TextAlignment.Left; break; case XStringAlignment.Center: x += layoutRectangle.Width / 2; formattedText.TextAlignment = TextAlignment.Center; break; case XStringAlignment.Far: x += layoutRectangle.Width; formattedText.TextAlignment = TextAlignment.Right; break; } if (PageDirection == XPageDirection.Downwards) { switch (format.LineAlignment) { case XLineAlignment.Near: //y += cyAscent; break; case XLineAlignment.Center: // TODO use CapHeight. PDFlib also uses 3/4 of ascent y += -formattedText.Baseline + (cyAscent * 1 / 3) + layoutRectangle.Height / 2; //y += -formattedText.Baseline + (font.Size * font.Metrics.CapHeight / font.unitsPerEm / 2) + layoutRectangle.Height / 2; break; case XLineAlignment.Far: y += -formattedText.Baseline - cyDescent + layoutRectangle.Height; break; case XLineAlignment.BaseLine: y -= formattedText.Baseline; break; } } else { // TODOWPF: make unit test switch (format.LineAlignment) { case XLineAlignment.Near: //y += cyDescent; break; case XLineAlignment.Center: // TODO use CapHeight. PDFlib also uses 3/4 of ascent //y += -(cyAscent * 3 / 4) / 2 + rect.Height / 2; break; case XLineAlignment.Far: //y += -cyAscent + rect.Height; break; case XLineAlignment.BaseLine: // nothing to do break; } } //if (bold && !descriptor.IsBoldFace) //{ // // TODO: emulate bold by thicker outline //} //if (italic && !descriptor.IsBoldFace) //{ // // TODO: emulate italic by shearing transformation //} if (underline) { formattedText.SetTextDecorations(TextDecorations.Underline); //double underlinePosition = lineSpace * realizedFont.FontDescriptor.descriptor.UnderlinePosition / font.cellSpace; //double underlineThickness = lineSpace * realizedFont.FontDescriptor.descriptor.UnderlineThickness / font.cellSpace; //DrawRectangle(null, brush, x, y - underlinePosition, width, underlineThickness); } if (strikeout) { formattedText.SetTextDecorations(TextDecorations.Strikethrough); //double strikeoutPosition = lineSpace * realizedFont.FontDescriptor.descriptor.StrikeoutPosition / font.cellSpace; //double strikeoutSize = lineSpace * realizedFont.FontDescriptor.descriptor.StrikeoutSize / font.cellSpace; //DrawRectangle(null, brush, x, y - strikeoutPosition - strikeoutSize, width, strikeoutSize); } //this.dc.DrawText(formattedText, layoutRectangle.Location.ToPoint()); this.dc.DrawText(formattedText, new System.Windows.Point(x, y)); #else dc.DrawString(this, text, font, brush, layoutRectangle, format); #endif } #endif } if (this.renderer != null) this.renderer.DrawString(text, font, brush, layoutRectangle, format); }
// ----- MeasureString ------------------------------------------------------------------------ /// <summary> /// Measures the specified string when drawn with the specified font. /// </summary> public XSize MeasureString(string text, XFont font, XStringFormat stringFormat) { // TODO: Here comes a lot of code in the future: kerning etc... if (text == null) throw new ArgumentNullException("text"); if (font == null) throw new ArgumentNullException("font"); if (stringFormat == null) throw new ArgumentNullException("stringFormat"); return XSize.FromSizeF(this.gfx.MeasureString(text, font.RealizeGdiFont(), new PointF(0, 0), stringFormat.RealizeGdiStringFormat())); }
/// <summary> /// Draws the specified text string. /// </summary> public void DrawString(string s, XFont font, XBrush brush, XRect layoutRectangle, XStringFormat format) { if (s == null) throw new ArgumentNullException("s"); if (font == null) throw new ArgumentNullException("font"); if (brush == null) throw new ArgumentNullException("brush"); if (format.LineAlignment == XLineAlignment.BaseLine && layoutRectangle.Height != 0) throw new InvalidOperationException("DrawString: With XLineAlignment.BaseLine the height of the layout rectangle must be 0."); if (s.Length == 0) return; if (format == null) format = XStringFormat.Default; if (this.drawGraphics) { RectangleF rect = layoutRectangle.ToRectangleF(); if (format.LineAlignment == XLineAlignment.BaseLine) { // TODO optimze double lineSpace = font.GetHeight(this); int cellSpace = font.FontFamily.GetLineSpacing(font.Style); int cellAscent = font.FontFamily.GetCellAscent(font.Style); int cellDescent = font.FontFamily.GetCellDescent(font.Style); double cyAscent = lineSpace * cellAscent / cellSpace; cyAscent = lineSpace * font.cellAscent / font.cellSpace; rect.Offset(0, (float)-cyAscent); } this.gfx.DrawString(s, font.RealizeGdiFont(), brush.RealizeGdiBrush(), rect, format != null ? format.RealizeGdiStringFormat() : null); } if (this.renderer != null) this.renderer.DrawString(s, font, brush, layoutRectangle, format); }
//internal TrueTypeDescriptor(FontSelector selector) //{ // throw new NotImplementedException("TrueTypeDescriptor(FontSelector selector)"); //} internal TrueTypeDescriptor(XFont font) : this(font.RealizeGdiFont(), font.PdfOptions) { }
/// <summary> /// Create the font image using GDI+ functionality. /// </summary> void CreateGdiFontImage(XFont font, XPdfFontOptions options, XPrivateFontCollection privateFontCollection) { System.Drawing.Font gdiFont = font.RealizeGdiFont(); NativeMethods.LOGFONT logFont; #if DEBUG_ logFont = new NativeMethods.LOGFONT(); gdiFont.ToLogFont(logFont); Debug.WriteLine("FontData: " + logFont.lfFaceName); #endif this.data = null; if (privateFontCollection != null) { //XPrivateFont privateFont = privateFontCollection.FindFont(logFont.lfFaceName, logFont.lfWeight >= 700, logFont.lfItalic > 0); XPrivateFont privateFont = privateFontCollection.FindFont(font.Name, font.Bold, font.Italic); if (privateFont != null) { int size = privateFont.GetFontData(ref this.data, 0); if (size > 0) { this.data = new byte[size]; privateFont.GetFontData(ref this.data, size); } } } if (this.data == null) { int error; IntPtr hfont = gdiFont.ToHfont(); IntPtr hdc = NativeMethods.GetDC(IntPtr.Zero); error = Marshal.GetLastWin32Error(); IntPtr oldFont = NativeMethods.SelectObject(hdc, hfont); error = Marshal.GetLastWin32Error(); // size is exactly the size of the font file. int size = NativeMethods.GetFontData(hdc, 0, 0, null, 0); error = Marshal.GetLastWin32Error(); if (size > 0) { this.data = new byte[size]; int effectiveSize = NativeMethods.GetFontData(hdc, 0, 0, this.data, this.data.Length); Debug.Assert(size == effectiveSize); NativeMethods.SelectObject(hdc, oldFont); NativeMethods.ReleaseDC(IntPtr.Zero, hdc); error.GetType(); } else { // Sometimes size is -1 (GDI_ERROR), but I cannot determine why. It happens only with the font 'Symbol'. // The issue occurs the first time in early 2005, when I start writing PDFsharp. I could not fix it and after // some code refactoring the problem disappears. // There was never a report from anyone about this issue. // Now I get it again (while debugging QBX 2006). Maybe it is a problem with my PC at my home office. // As a work-around I create a new font handle with a different height value. This works. Maybe the // font file gets locked somewhere. Very very strange. // IF SOMEONE ELSE COMES HERE PLEASE LET ME KNOW! // Clean up old handles NativeMethods.SelectObject(hdc, oldFont); NativeMethods.ReleaseDC(IntPtr.Zero, hdc); // Try again with new font handle logFont = new NativeMethods.LOGFONT(); gdiFont.ToLogFont(logFont); logFont.lfHeight += 1; // force new handle IntPtr hfont2 = NativeMethods.CreateFontIndirect(logFont); hdc = NativeMethods.GetDC(IntPtr.Zero); error = Marshal.GetLastWin32Error(); oldFont = NativeMethods.SelectObject(hdc, hfont2); error = Marshal.GetLastWin32Error(); // size is exactly the size of the font file. size = NativeMethods.GetFontData(hdc, 0, 0, null, 0); error = Marshal.GetLastWin32Error(); if (size > 0) { this.data = new byte[size]; int effectiveSize = NativeMethods.GetFontData(hdc, 0, 0, this.data, this.data.Length); Debug.Assert(size == effectiveSize); } NativeMethods.SelectObject(hdc, oldFont); NativeMethods.ReleaseDC(IntPtr.Zero, hdc); NativeMethods.DeleteObject(hfont2); error.GetType(); } } if (this.data == null) throw new InvalidOperationException("Internal error. Font data could not retrieved."); }
/// <summary> /// Create the font image using GDI+ functionality. /// </summary> void CreateGdiFontImage(XFont font, XPdfFontOptions options/*, XPrivateFontCollection privateFontCollection*/) { System.Drawing.Font gdiFont = font.RealizeGdiFont(); #if DEBUG_ logFont = new NativeMethods.LOGFONT(); gdiFont.ToLogFont(logFont); Debug.WriteLine("FontData: " + logFont.lfFaceName); #endif this.data = null; // PFC //if (privateFontCollection != null) //{ // //XPrivateFont privateFont = privateFontCollection.FindFont(logFont.lfFaceName, logFont.lfWeight >= 700, logFont.lfItalic > 0); // XGlyphTypeface privateFont = privateFontCollection.FindFont(font.Name, font.Bold, font.Italic); // if (privateFont != null) // { // //////int size = privateFont.GetData(ref this.data); // //////if (size > 0) // //////{ // ////// this.data = new byte[size]; // ////// privateFont.GetData(ref this.data, size); // //////} // } //} if (this.data == null) { var assembly = FontDataConfig.ResourceAssembly; var name = string.Format("{0}.FontHacks.{1}{2}{3}.fontdat", assembly != null ? assembly.GetName().Name : string.Empty, font.Name, font.Bold ? ".Bold" : string.Empty, font.Italic ? ".Italic" : string.Empty); if (assembly != null && new List<string>(assembly.GetManifestResourceNames()).Contains(name)) { System.Diagnostics.Debug.WriteLine("*** Reading fontdata from Resource"); using (var s = assembly.GetManifestResourceStream(name)) { this.data = new byte[s.Length]; s.Read(this.data, 0, (int)s.Length); } } else { System.Diagnostics.Debug.WriteLine("*** Reading fontdata from GDI+"); int error; IntPtr hfont = gdiFont.ToHfont(); using(var dcBmp = new Bitmap(100, 100)) using (var dc = Graphics.FromImage(dcBmp)) { IntPtr hdc = dc.GetHdc(); error = Marshal.GetLastWin32Error(); IntPtr oldFont = NativeMethods.SelectObject(hdc, hfont); error = Marshal.GetLastWin32Error(); // size is exactly the size of the font file. int size = NativeMethods.GetFontData(hdc, 0, 0, null, 0); error = Marshal.GetLastWin32Error(); if (size > 0) { this.data = new byte[size]; int effectiveSize = NativeMethods.GetFontData(hdc, 0, 0, this.data, this.data.Length); Debug.Assert(size == effectiveSize); if (FontDataConfig.SaveFont) { FileExtensions.WriteFileBytes(this.data, string.Format("..\\..\\FontHacks\\{0}{1}{2}.fontdat", font.Name, font.Bold ? ".Bold" : string.Empty, font.Italic ? ".Italic" : string.Empty)); } NativeMethods.SelectObject(hdc, oldFont); NativeMethods.ReleaseDC(IntPtr.Zero, hdc); error.GetType(); } else { // Sometimes size is -1 (GDI_ERROR), but I cannot determine why. It happens only with the font 'Symbol'. // The issue occurs the first time in early 2005, when I start writing PDFsharp. I could not fix it and after // some code refactoring the problem disappears. // There was never a report from anyone about this issue. // Now I get it again (while debugging QBX 2006). Maybe it is a problem with my PC at my home office. // As a work-around I create a new font handle with a different height value. This works. Maybe the // font file gets locked somewhere. Very very strange. // IF SOMEONE ELSE COMES HERE PLEASE LET ME KNOW! // Clean up old handles NativeMethods.SelectObject(hdc, oldFont); NativeMethods.ReleaseDC(IntPtr.Zero, hdc); // Try again with new font handle var logFont = new NativeMethods.LOGFONT(); gdiFont.ToLogFont(logFont); logFont.lfHeight += 1; // force new handle IntPtr hfont2 = NativeMethods.CreateFontIndirect(logFont); hdc = NativeMethods.GetDC(IntPtr.Zero); error = Marshal.GetLastWin32Error(); oldFont = NativeMethods.SelectObject(hdc, hfont2); error = Marshal.GetLastWin32Error(); // size is exactly the size of the font file. size = NativeMethods.GetFontData(hdc, 0, 0, null, 0); error = Marshal.GetLastWin32Error(); if (size > 0) { this.data = new byte[size]; int effectiveSize = NativeMethods.GetFontData(hdc, 0, 0, this.data, this.data.Length); Debug.Assert(size == effectiveSize); } NativeMethods.SelectObject(hdc, oldFont); NativeMethods.ReleaseDC(IntPtr.Zero, hdc); NativeMethods.DeleteObject(hfont2); error.GetType(); } } } if (this.data == null) throw new InvalidOperationException("Internal error. Font data could not retrieved."); } }