internal void Read() { try { int tableOffset = _fontData.Position; version = _fontData.ReadUShort(); numTables = _fontData.ReadUShort(); #if DEBUG_ if (_fontData.Name == "Cambria") { Debug - Break.Break(); } #endif bool success = false; for (int idx = 0; idx < numTables; idx++) { PlatformId platformId = (PlatformId)_fontData.ReadUShort(); int encodingId = _fontData.ReadUShort(); int offset = _fontData.ReadLong(); int currentPosition = _fontData.Position; // Just read Windows stuff. if (platformId == PlatformId.Win && ((WinEncodingId)encodingId == WinEncodingId.Symbol || (WinEncodingId)encodingId == WinEncodingId.Unicode)) { symbol = (WinEncodingId)encodingId == WinEncodingId.Symbol; _fontData.Position = tableOffset + offset; cmap4 = new CMap4(_fontData, (WinEncodingId)encodingId); _fontData.Position = currentPosition; // We have found what we are looking for, so break. success = true; break; } if (platformId == PlatformId.Apple && (AppleEncodingId)encodingId == AppleEncodingId.Unicode20BmpOnly) { symbol = false; _fontData.Position = tableOffset + offset; cmap4 = new CMap4(_fontData, WinEncodingId.Unicode); _fontData.Position = currentPosition; // We have found what we are looking for, so break. success = true; break; } } if (!success) { throw new InvalidOperationException("Font has no usable platform or encoding ID. It cannot be used with PDFsharp."); } } catch (Exception ex) { throw new InvalidOperationException(PSSR.ErrorReadingFontData, ex); } }
/// <summary> /// Create a WPF GlyphTypeface and retrieve font data from it. /// </summary> internal static XFontSource CreateFontSource(string familyName, FontResolvingOptions fontResolvingOptions, out WpfFontFamily wpfFontFamily, out WpfTypeface wpfTypeface, out WpfGlyphTypeface wpfGlyphTypeface, string typefaceKey) { if (string.IsNullOrEmpty(typefaceKey)) { typefaceKey = XGlyphTypeface.ComputeKey(familyName, fontResolvingOptions); } XFontStyle style = fontResolvingOptions.FontStyle; #if DEBUG if (StringComparer.OrdinalIgnoreCase.Compare(familyName, "Segoe UI Semilight") == 0 && (style & XFontStyle.BoldItalic) == XFontStyle.Italic) { familyName.GetType(); } #endif // Use WPF technique to create font data. wpfTypeface = XPrivateFontCollection.TryCreateTypeface(familyName, style, out wpfFontFamily); #if DEBUG__ if (wpfTypeface != null) { WpfGlyphTypeface glyphTypeface; ICollection <WpfTypeface> list = wpfFontFamily.GetTypefaces(); foreach (WpfTypeface tf in list) { if (!tf.TryGetGlyphTypeface(out glyphTypeface)) { Debug - Break.Break(); } } //if (!WpfTypeface.TryGetGlyphTypeface(out glyphTypeface)) // throw new InvalidOperationException(PSSR.CannotGetGlyphTypeface(familyName)); } #endif if (wpfFontFamily == null) { wpfFontFamily = new WpfFontFamily(familyName); } if (wpfTypeface == null) { wpfTypeface = FontHelper.CreateTypeface(wpfFontFamily, style); } // Let WPF choose the right glyph typeface. if (!wpfTypeface.TryGetGlyphTypeface(out wpfGlyphTypeface)) { throw new InvalidOperationException(PSSR.CannotGetGlyphTypeface(familyName)); } // Get or create the font source and cache it unter the specified typeface key. XFontSource fontSource = XFontSource.GetOrCreateFromWpf(typefaceKey, wpfGlyphTypeface); return(fontSource); }
/// <summary> /// When overridden in a derived class, encodes a set of characters from the specified character array into the specified byte array. /// </summary> /// <param name="chars">The character array containing the set of characters to encode.</param> /// <param name="charIndex">The index of the first character to encode.</param> /// <param name="charCount">The number of characters to encode.</param> /// <param name="bytes">The byte array to contain the resulting sequence of bytes.</param> /// <param name="byteIndex">The index at which to start writing the resulting sequence of bytes.</param> /// <returns> /// The actual number of bytes written into <paramref name="bytes"/>. /// </returns> public override int GetBytes(char[] chars, int charIndex, int charCount, byte[] bytes, int byteIndex) { for (int count = charCount; count > 0; charIndex++, byteIndex++, count--) { #if DEBUG_ if ((uint)chars[charIndex] > 255) { Debug - Break.Break(true); } #endif //Debug.Assert((uint)chars[charIndex] < 256, "Raw string contains invalid character with a value > 255."); bytes[byteIndex] = (byte)chars[charIndex]; //#warning Here is a HACK that must not be ignored! // HACK: // bytes[byteIndex] = (byte)chars[charIndex]; } return(charCount); }
/// <summary> /// Create a GDI+ font and use its handle to retrieve font data using native calls. /// </summary> internal static XFontSource CreateFontSource(string familyName, FontResolvingOptions fontResolvingOptions, out GdiFont font, string typefaceKey) { if (string.IsNullOrEmpty(typefaceKey)) { typefaceKey = XGlyphTypeface.ComputeKey(familyName, fontResolvingOptions); } #if true_ if (familyName == "Cambria") { Debug - Break.Break(); } #endif GdiFontStyle gdiStyle = (GdiFontStyle)(fontResolvingOptions.FontStyle & XFontStyle.BoldItalic); // Create a 10 point GDI+ font as an exemplar. XFontSource fontSource; font = FontHelper.CreateFont(familyName, 10, gdiStyle, out fontSource); if (fontSource != null) { Debug.Assert(font != null); // Case: Font was created by a GDI+ private font collection. #if true #if DEBUG XFontSource existingFontSource; Debug.Assert(FontFactory.TryGetFontSourceByTypefaceKey(typefaceKey, out existingFontSource) && ReferenceEquals(fontSource, existingFontSource)); #endif #else // Win32 API cannot get font data from fonts created by private font collection, // because this is handled internally in GDI+. // Therefore the font source was created when the private font is added to the private font collection. if (!FontFactory.TryGetFontSourceByTypefaceKey(typefaceKey, out fontSource)) { // Simplify styles. // (The code is written for clarity - do not rearrange for optimization) if (font.Bold && font.Italic) { if (FontFactory.TryGetFontSourceByTypefaceKey(XGlyphTypeface.ComputeKey(font.Name, true, false), out fontSource)) { // Use bold font. FontFactory.CacheExistingFontSourceWithNewTypefaceKey(typefaceKey, fontSource); } else if (FontFactory.TryGetFontSourceByTypefaceKey(XGlyphTypeface.ComputeKey(font.Name, false, true), out fontSource)) { // Use italic font. FontFactory.CacheExistingFontSourceWithNewTypefaceKey(typefaceKey, fontSource); } else if (FontFactory.TryGetFontSourceByTypefaceKey(XGlyphTypeface.ComputeKey(font.Name, false, false), out fontSource)) { // Use regular font. FontFactory.CacheExistingFontSourceWithNewTypefaceKey(typefaceKey, fontSource); } } else if (font.Bold || font.Italic) { // Use regular font. if (FontFactory.TryGetFontSourceByTypefaceKey(XGlyphTypeface.ComputeKey(font.Name, false, false), out fontSource)) { FontFactory.CacheExistingFontSourceWithNewTypefaceKey(typefaceKey, fontSource); } } else { if (FontFactory.TryGetFontSourceByTypefaceKey(XGlyphTypeface.ComputeKey(font.Name, false, false), out fontSource)) { // Should never come here... FontFactory.CacheExistingFontSourceWithNewTypefaceKey(typefaceKey, fontSource); } } } #endif } else { // Get or create the font source and cache it unter the specified typeface key. fontSource = XFontSource.GetOrCreateFromGdi(typefaceKey, font); } return(fontSource); }
/// <summary> /// Inserts pages of the specified document into this document. /// </summary> /// <param name="index">The index in this document where to insert the page .</param> /// <param name="document">The document to be inserted.</param> /// <param name="startIndex">The index of the first page to be inserted.</param> /// <param name="pageCount">The number of pages to be inserted.</param> public void InsertRange(int index, PdfDocument document, int startIndex, int pageCount) { if (document == null) { throw new ArgumentNullException("document"); } if (index < 0 || index > Count) { throw new ArgumentOutOfRangeException("index", "Argument 'index' out of range."); } int importDocumentPageCount = document.PageCount; if (startIndex < 0 || startIndex + pageCount > importDocumentPageCount) { throw new ArgumentOutOfRangeException("startIndex", "Argument 'startIndex' out of range."); } if (pageCount > importDocumentPageCount) { throw new ArgumentOutOfRangeException("pageCount", "Argument 'pageCount' out of range."); } PdfPage[] insertPages = new PdfPage[pageCount]; PdfPage[] importPages = new PdfPage[pageCount]; // 1st create all new pages. for (int idx = 0, insertIndex = index, importIndex = startIndex; importIndex < startIndex + pageCount; idx++, insertIndex++, importIndex++) { PdfPage importPage = document.Pages[importIndex]; PdfPage page = ImportExternalPage(importPage); insertPages[idx] = page; importPages[idx] = importPage; Owner._irefTable.Add(page); // Add page substitute to importedObjectTable. PdfImportedObjectTable importedObjectTable = Owner.FormTable.GetImportedObjectTable(importPage); importedObjectTable.Add(importPage.ObjectID, page.Reference); PagesArray.Elements.Insert(insertIndex, page.Reference); if (Owner.Settings.TrimMargins.AreSet) { page.TrimMargins = Owner.Settings.TrimMargins; } } Elements.SetInteger(Keys.Count, PagesArray.Elements.Count); // 2nd copy link annotations that are in the range of the imported pages. for (int idx = 0, importIndex = startIndex; importIndex < startIndex + pageCount; idx++, importIndex++) { PdfPage importPage = document.Pages[importIndex]; PdfPage page = insertPages[idx]; // Get annotations. PdfArray annots = importPage.Elements.GetArray(PdfPage.Keys.Annots); if (annots != null) { PdfAnnotations annotations = new PdfAnnotations(Owner); // Loop through annotations. int count = annots.Elements.Count; for (int idxAnnotation = 0; idxAnnotation < count; idxAnnotation++) { PdfDictionary annot = annots.Elements.GetDictionary(idxAnnotation); if (annot != null) { string subtype = annot.Elements.GetString(PdfAnnotation.Keys.Subtype); if (subtype == "/Link") { bool addAnnotation = false; PdfLinkAnnotation newAnnotation = new PdfLinkAnnotation(Owner); PdfName[] importAnnotationKeyNames = annot.Elements.KeyNames; foreach (PdfName pdfItem in importAnnotationKeyNames) { PdfItem impItem; switch (pdfItem.Value) { case "/BS": newAnnotation.Elements.Add("/BS", new PdfLiteral("<</W 0>>")); break; case "/F": // /F 4 impItem = annot.Elements.GetValue("/F"); Debug.Assert(impItem is PdfInteger); newAnnotation.Elements.Add("/F", impItem.Clone()); break; case "/Rect": // /Rect [68.6 681.08 145.71 702.53] impItem = annot.Elements.GetValue("/Rect"); Debug.Assert(impItem is PdfArray); newAnnotation.Elements.Add("/Rect", impItem.Clone()); break; case "/StructParent": // /StructParent 3 impItem = annot.Elements.GetValue("/StructParent"); Debug.Assert(impItem is PdfInteger); newAnnotation.Elements.Add("/StructParent", impItem.Clone()); break; case "/Subtype": // Already set. break; case "/Dest": // /Dest [30 0 R /XYZ 68 771 0] impItem = annot.Elements.GetValue("/Dest"); impItem = impItem.Clone(); // Is value an array with 5 elements where the first one is an iref? PdfArray destArray = impItem as PdfArray; if (destArray != null && destArray.Elements.Count == 5) { PdfReference iref = destArray.Elements[0] as PdfReference; if (iref != null) { iref = RemapReference(insertPages, importPages, iref); if (iref != null) { destArray.Elements[0] = iref; newAnnotation.Elements.Add("/Dest", destArray); addAnnotation = true; } } } break; default: #if DEBUG_ Debug - Break.Break(true); #endif break; } } // Add newAnnotations only it points to an imported page. if (addAnnotation) { annotations.Add(newAnnotation); } } } } // At least one link annotation found? if (annotations.Count > 0) { //Owner._irefTable.Add(annotations); page.Elements.Add(PdfPage.Keys.Annots, annotations); } } } }
/// <summary> /// Reads all required tables from the font data. /// </summary> internal void Read() { // Determine font technology // ReSharper disable InconsistentNaming const uint OTTO = 0x4f54544f; // Adobe OpenType CFF data, tag: 'OTTO' const uint TTCF = 0x74746366; // TrueType Collection tag: 'ttcf' // ReSharper restore InconsistentNaming try { #if DEBUG_ if (Name == "Cambria") { Debug - Break.Break(); } #endif // Check if data is a TrueType collection font. uint startTag = ReadULong(); if (startTag == TTCF) { _fontTechnology = FontTechnology.TrueTypeCollection; throw new InvalidOperationException("TrueType collection fonts are not yet supported by PdfSharpCore."); } // Read offset table _offsetTable.Version = startTag; _offsetTable.TableCount = ReadUShort(); _offsetTable.SearchRange = ReadUShort(); _offsetTable.EntrySelector = ReadUShort(); _offsetTable.RangeShift = ReadUShort(); // Move to table dictionary at position 12 Debug.Assert(_pos == 12); //tableDictionary = (offsetTable.TableCount); if (_offsetTable.Version == OTTO) { _fontTechnology = FontTechnology.PostscriptOutlines; } else { _fontTechnology = FontTechnology.TrueTypeOutlines; } for (int idx = 0; idx < _offsetTable.TableCount; idx++) { TableDirectoryEntry entry = TableDirectoryEntry.ReadFrom(this); TableDictionary.Add(entry.Tag, entry); #if VERBOSE Debug.WriteLine(String.Format("Font table: {0}", entry.Tag)); #endif } // PDFlib checks this, but it is not part of the OpenType spec anymore if (TableDictionary.ContainsKey("bhed")) { throw new NotSupportedException("Bitmap fonts are not supported by PdfSharpCore."); } // Read required tables if (Seek(CMapTable.Tag) != -1) { cmap = new CMapTable(this); } if (Seek(ControlValueTable.Tag) != -1) { cvt = new ControlValueTable(this); } if (Seek(FontProgram.Tag) != -1) { fpgm = new FontProgram(this); } if (Seek(MaximumProfileTable.Tag) != -1) { maxp = new MaximumProfileTable(this); } if (Seek(NameTable.Tag) != -1) { name = new NameTable(this); } if (Seek(FontHeaderTable.Tag) != -1) { head = new FontHeaderTable(this); } if (Seek(HorizontalHeaderTable.Tag) != -1) { hhea = new HorizontalHeaderTable(this); } if (Seek(HorizontalMetricsTable.Tag) != -1) { hmtx = new HorizontalMetricsTable(this); } if (Seek(OS2Table.Tag) != -1) { os2 = new OS2Table(this); } if (Seek(PostScriptTable.Tag) != -1) { post = new PostScriptTable(this); } if (Seek(GlyphDataTable.Tag) != -1) { glyf = new GlyphDataTable(this); } if (Seek(IndexToLocationTable.Tag) != -1) { loca = new IndexToLocationTable(this); } if (Seek(GlyphSubstitutionTable.Tag) != -1) { gsub = new GlyphSubstitutionTable(this); } if (Seek(ControlValueProgram.Tag) != -1) { prep = new ControlValueProgram(this); } } catch (Exception) { GetType(); throw; } }