//////////////////////////////////////////////////////////////////// // Character substitution // This program accepts character codes 32 to 126 and 160 to 255 // If the font supports characters above 255, you can map // this codes into the valid region. //////////////////////////////////////////////////////////////////// public void CharSubstitution ( Int32 OrigFrom, Int32 OrigTo, Int32 DestFrom ) { // font must be embedded if (!EmbeddedFont) { throw new ApplicationException("Character substitution is allowed only for embedded fonts"); } // create new character substitution array if (CharSubArray == null) { CharSubArray = new Int32[256]; for (Int32 CharCode = 0; CharCode < 256; CharCode++) { CharSubArray[CharCode] = CharCode; } } // character count Int32 Count = OrigTo - OrigFrom + 1; // get character width Double[] SubWidthArray = FontInfo.GetCharWidthApi(OrigFrom, OrigTo); // get array of glyph bounding box and width BoundingBox[] SubGlyphArray = FontInfo.GetGlyphMetricsApi(OrigFrom, OrigTo); // replace existing character width and bounding box for (Int32 Ptr = 0; Ptr < Count; Ptr++) { CharSubArray[DestFrom + Ptr] = OrigFrom + Ptr; CharWidthArray[DestFrom + Ptr] = SubWidthArray[Ptr]; GlyphArray[DestFrom + Ptr] = SubGlyphArray[Ptr]; } // exit return; }
//////////////////////////////////////////////////////////////////// // Constructor //////////////////////////////////////////////////////////////////// public PdfFont ( PdfDocument Document, // PDF document main object String FontFamilyName, // font family name FontStyle FontStyle, // font style (Regular, Bold, Italic or Bold | Italic Boolean EmbeddedFont // embed font in PDF document file ) : base(Document, false, "/Font") { // save embedded font flag this.EmbeddedFont = EmbeddedFont; // font style cannot be underline or strikeout if ((FontStyle & (FontStyle.Underline | FontStyle.Strikeout)) != 0) { throw new ApplicationException("Font resource cannot have underline or strikeout"); } // create resource code ResourceCode = Document.GenerateResourceNumber('F'); // get font family structure FontFamily = new FontFamily(FontFamilyName); // test font style availability if (!FontFamily.IsStyleAvailable(FontStyle)) { throw new ApplicationException("Font style not available for font family"); } // design height DesignHeight = FontFamily.GetEmHeight(FontStyle); // Ascent, descent and line spacing for a one point font PdfAscent = WindowsToPdf(FontFamily.GetCellAscent(FontStyle)); PdfDescent = WindowsToPdf(FontFamily.GetCellDescent(FontStyle)); // positive number PdfLineSpacing = WindowsToPdf(FontFamily.GetLineSpacing(FontStyle)); // create design font DesignFont = new Font(FontFamily, DesignHeight, FontStyle, GraphicsUnit.Pixel); // create windows sdk font info object FontInfo = new FontApi(DesignFont, DesignHeight); // get character width array CharWidthArray = FontInfo.GetCharWidthApi(0, 255); // get array of glyph bounding box and width GlyphArray = FontInfo.GetGlyphMetricsApi(0, 255); // reset active (used) characters to not used ActiveChar = new Boolean[256]; // get outline text metrics structure WinOutlineTextMetric OTM = FontInfo.GetOutlineTextMetricsApi(); // license if ((OTM.otmfsType & 2) != 0) { throw new ApplicationException("Font " + FontFamilyName + " is not licensed for embedding"); } // make sure we have true type font and not device font if ((OTM.otmTextMetric.tmPitchAndFamily & 0xe) != 6) { throw new ApplicationException("Font must be True Type and vector"); } // PDF font flags FontFlags = 0; if ((OTM.otmfsSelection & 1) != 0) { FontFlags |= PdfFontFlags.Italic; } // roman font is a serif font if ((OTM.otmTextMetric.tmPitchAndFamily >> 4) == 1) { FontFlags |= PdfFontFlags.Serif; } if ((OTM.otmTextMetric.tmPitchAndFamily >> 4) == 4) { FontFlags |= PdfFontFlags.Script; } // #define SYMBOL_CHARSET 2 if (OTM.otmTextMetric.tmCharSet == 2) { FontFlags |= PdfFontFlags.Symbolic; SymbolicFont = true; } else { FontFlags |= PdfFontFlags.Nonsymbolic; SymbolicFont = false; } // #define TMPF_FIXED_PITCH 0x01 (Note very carefully that those meanings are the opposite of what the constant name implies.) if ((OTM.otmTextMetric.tmPitchAndFamily & 1) == 0) { FontFlags |= PdfFontFlags.FixedPitch; } // strikeout PdfStrikeoutPosition = WindowsToPdf(OTM.otmsStrikeoutPosition); PdfStrikeoutWidth = WindowsToPdf((Int32)OTM.otmsStrikeoutSize); // underline PdfUnderlinePosition = WindowsToPdf(OTM.otmsUnderscorePosition); PdfUnderlineWidth = WindowsToPdf(OTM.otmsUnderscoreSize); // subscript PdfSubscriptSize = WindowsToPdf(OTM.otmptSubscriptSize.Y); PdfSubscriptPosition = WindowsToPdf(OTM.otmptSubscriptOffset.Y); // superscript PdfSuperscriptSize = WindowsToPdf(OTM.otmptSuperscriptSize.Y); PdfSuperscriptPosition = WindowsToPdf(OTM.otmptSuperscriptOffset.Y); PdfItalicAngle = (Double)OTM.otmItalicAngle / 10.0; PdfFontWeight = OTM.otmTextMetric.tmWeight; // exit return; }
//////////////////////////////////////////////////////////////////// // Character substitution // This program accepts character codes 32 to 126 and 160 to 255 // If the font supports characters above 255, you can map // this codes into the valid region. //////////////////////////////////////////////////////////////////// public void CharSubstitution ( Int32 OrigFrom, Int32 OrigTo, Int32 DestFrom ) { // font must be embedded if (!EmbeddedFont) { throw new ApplicationException("Character substitution is allowed only for embedded fonts"); } // create new character substitution array if (CharSubArray == null) { // create new substitute to original array CharSubArray = new Int32[256]; for (Int32 CharCode = 0; CharCode < 256; CharCode++) { CharSubArray[CharCode] = CharCode; } // create new original character to substitute OrigToSubArray = new List <OrigToSub>(); } // character count Int32 Count = OrigTo - OrigFrom + 1; // get character width for origin array Double[] SubWidthArray = FontInfo.GetCharWidthApi(OrigFrom, OrigTo); // get array of glyph bounding box and width for origin array BoundingBox[] SubGlyphArray = FontInfo.GetGlyphMetricsApi(OrigFrom, OrigTo); // replace existing character width and bounding box for (Int32 Ptr = 0; Ptr < Count; Ptr++) { // destination must be 33 to 126 or 161 to 255 // note: space and non breaking space cannot be used for substitution Int32 DestChar = DestFrom + Ptr; if (DestChar <= ' ' || DestChar > '~' && DestChar <= 160 || DestChar > 255) { throw new ApplicationException("Invalid character substitution. Destination must be 33 to 126 or 161 to 255."); } // search origin to substitute array Int32 OrigChar = OrigFrom + Ptr; OrigToSub origToSub = new OrigToSub(OrigChar, DestChar); Int32 index = OrigToSubArray.BinarySearch(origToSub); // duplicate origin overlaping substitution ranges if (index >= 0) { throw new ApplicationException("CharSubstitution duplicate origin character"); } // test for duplicate destination foreach (OrigToSub OTS in OrigToSubArray) { if (OTS.Sub == DestChar) { throw new ApplicationException("CharSubstitution duplicate destibation character"); } } // add a new record OrigToSubArray.Insert(~index, origToSub); // save origin char in destination array CharSubArray[DestChar] = OrigChar; // change character width and glyph bounding box to origin value CharWidthArray[DestChar] = SubWidthArray[Ptr]; GlyphArray[DestChar] = SubGlyphArray[Ptr]; } // exit return; }