/** * render inline area to PDF * * @param area inline area to render */ public void RenderWordArea(WordArea area) { // TODO: I don't understand why we are locking the private member // _wordAreaPDF. Maybe this string buffer was originally static? (MG) lock (_wordAreaPDF) { StringBuilder pdf = _wordAreaPDF; pdf.Length = 0; GdiKerningPairs kerning = null; bool kerningAvailable = false; // If no options are supplied, by default we do not enable kerning if (options != null && options.Kerning) { kerning = area.GetFontState().Kerning; if (kerning != null && (kerning.Count > 0)) { kerningAvailable = true; } } String name = area.GetFontState().FontName; int size = area.GetFontState().FontSize; // This assumes that *all* CIDFonts use a /ToUnicode mapping Font font = (Font)area.GetFontState().FontInfo.GetFontByName(name); bool useMultiByte = font.MultiByteFont; string startText = useMultiByte ? "<" : "("; string endText = useMultiByte ? "> " : ") "; if ((!name.Equals(this.currentFontName)) || (size != this.currentFontSize)) { CloseText(); this.currentFontName = name; this.currentFontSize = size; pdf = pdf.Append("/" + name + " " + PdfNumber.doubleOut(size / 1000f) + " Tf\n"); } // Do letter spacing (must be outside of [...] TJ] float letterspacing = ((float)area.GetFontState().LetterSpacing) / 1000f; if (letterspacing != this.currentLetterSpacing) { this.currentLetterSpacing = letterspacing; CloseText(); pdf.Append(PdfNumber.doubleOut(letterspacing)); pdf.Append(" Tc\n"); } PdfColor areaColor = this.currentFill; if (areaColor == null || areaColor.getRed() != (double)area.getRed() || areaColor.getGreen() != (double)area.getGreen() || areaColor.getBlue() != (double)area.getBlue()) { areaColor = new PdfColor((double)area.getRed(), (double)area.getGreen(), (double)area.getBlue()); CloseText(); this.currentFill = areaColor; pdf.Append(this.currentFill.getColorSpaceOut(true)); } int rx = this.currentXPosition; int bl = this.currentYPosition; AddWordLines(area, rx, bl, size, areaColor); if (!textOpen || bl != prevWordY) { CloseText(); pdf.Append("1 0 0 1 " + PdfNumber.doubleOut(rx / 1000f) + " " + PdfNumber.doubleOut(bl / 1000f) + " Tm [" + startText); prevWordY = bl; textOpen = true; } else { // express the space between words in thousandths of an em int space = prevWordX - rx + prevWordWidth; float emDiff = (float)space / (float)currentFontSize * 1000f; // this prevents a problem in Acrobat Reader where large // numbers cause text to disappear or default to a limit if (emDiff < -33000) { CloseText(); pdf.Append("1 0 0 1 " + PdfNumber.doubleOut(rx / 1000f) + " " + PdfNumber.doubleOut(bl / 1000f) + " Tm [" + startText); textOpen = true; } else { pdf.Append(PdfNumber.doubleOut(emDiff)); pdf.Append(" "); pdf.Append(startText); } } prevWordWidth = area.getContentWidth(); prevWordX = rx; string s; if (area.getPageNumberID() != null) { // This text is a page number, so resolve it s = idReferences.getPageNumber(area.getPageNumberID()); if (s == null) { s = String.Empty; } } else { s = area.getText(); } int wordLength = s.Length; for (int index = 0; index < wordLength; index++) { ushort ch = area.GetFontState().MapCharacter(s[index]); if (!useMultiByte) { if (ch > 127) { pdf.Append("\\"); pdf.Append(Convert.ToString((int)ch, 8)); } else { switch (ch) { case '(': case ')': case '\\': pdf.Append("\\"); break; } pdf.Append((char)ch); } } else { pdf.Append(GetUnicodeString(ch)); } if (kerningAvailable && (index + 1) < wordLength) { ushort ch2 = area.GetFontState().MapCharacter(s[index + 1]); AddKerning(pdf, ch, ch2, kerning, startText, endText); } } pdf.Append(endText); currentStream.Write(pdf.ToString()); this.currentXPosition += area.getContentWidth(); } }