¿Cómo puedo formatear el texto con iTextSharp?

Resuelto IrfanRaza asked hace 13 años • 2 respuestas

Estoy usando iTextSharp para leer contenidos de texto de PDF. Puedo leer eso también. Pero estoy perdiendo el formato del texto, como la fuente, el color, etc. ¿Hay alguna forma de obtener ese formato también?

A continuación se muestra el segmento de código que estoy usando para el texto exacto:

PdfReader reader = new PdfReader("F:\\EBooks\\AspectsOfAjax.pdf");
textBox1.Text = ExtractTextFromPDFBytes(reader.GetPageContent(1));

private string ExtractTextFromPDFBytes(byte[] input)
{
    if (input == null || input.Length == 0) return "";
    try
    {
        string resultString = "";
        // Flag showing if we are we currently inside a text object
        bool inTextObject = false;
        // Flag showing if the next character is literal  e.g. '\\' to get a '\' character or '\(' to get '('
        bool nextLiteral = false;
        // () Bracket nesting level. Text appears inside ()
        int bracketDepth = 0;
        // Keep previous chars to get extract numbers etc.:
        char[] previousCharacters = new char[_numberOfCharsToKeep];
        for (int j = 0; j < _numberOfCharsToKeep; j++) previousCharacters[j] = ' ';
        for (int i = 0; i < input.Length; i++)
        {
            char c = (char)input[i];
            if (inTextObject)
            {
                // Position the text
                if (bracketDepth == 0)
                {
                    if (CheckToken(new string[] { "TD", "Td" }, previousCharacters))
                    {
                        resultString += "\n\r";
                    }
                    else
                    {
                        if (CheckToken(new string[] {"'", "T*", "\""}, previousCharacters))
                        {
                            resultString += "\n";
                        }
                        else
                        {
                            if (CheckToken(new string[] { "Tj" }, previousCharacters))
                            {
                                resultString += " ";
                            }
                        }
                    }
                }
                // End of a text object, also go to a new line.
                if (bracketDepth == 0 && CheckToken( new string[]{"ET"}, previousCharacters))
                {
                    inTextObject = false;
                    resultString += " ";
                }
                else
                {
                    // Start outputting text
                    if ((c == '(') && (bracketDepth == 0) && (!nextLiteral))
                    {
                        bracketDepth = 1;
                    }
                    else
                    {
                        // Stop outputting text
                        if ((c == ')') && (bracketDepth == 1) && (!nextLiteral))
                        {
                            bracketDepth = 0;
                        }
                        else
                        {
                            // Just a normal text character:
                            if (bracketDepth == 1)
                            {
                                // Only print out next character no matter what. 
                                // Do not interpret.
                                if (c == '\\' && !nextLiteral)
                                {
                                    nextLiteral = true;
                                }
                                else
                                {
                                    if (((c >= ' ') && (c <= '~')) || ((c >= 128) && (c < 255)))
                                    {
                                        resultString += c.ToString();
                                    }
                                    nextLiteral = false;
                                }
                            }
                        }
                    }
                }
            }
            // Store the recent characters for when we have to go back for a checking
            for (int j = 0; j < _numberOfCharsToKeep - 1; j++)
            {
                previousCharacters[j] = previousCharacters[j + 1];
            }
            previousCharacters[_numberOfCharsToKeep - 1] = c;

            // Start of a text object
            if (!inTextObject && CheckToken(new string[]{"BT"}, previousCharacters))
            {
                inTextObject = true;
            }
        }
        return resultString;
    }
    catch
    {
        return "";
    }
}

private bool CheckToken(string[] tokens, char[] recent)
{
    foreach(string token in tokens)
    {
        if ((recent[_numberOfCharsToKeep - 3] == token[0]) &&
            (recent[_numberOfCharsToKeep - 2] == token[1]) &&
            ((recent[_numberOfCharsToKeep - 1] == ' ') ||
            (recent[_numberOfCharsToKeep - 1] == 0x0d) ||
            (recent[_numberOfCharsToKeep - 1] == 0x0a)) &&
            ((recent[_numberOfCharsToKeep - 4] == ' ') ||
            (recent[_numberOfCharsToKeep - 4] == 0x0d) ||
            (recent[_numberOfCharsToKeep - 4] == 0x0a))
            )
        {
            return true;
        }
    }
    return false;
}
IrfanRaza avatar Jul 30 '11 15:07 IrfanRaza
Aceptado

Déjame intentar señalarte en una dirección diferente. iTextSharp tiene un sistema de extracción de texto realmente hermoso y simple que maneja algunos de los tokens básicos. Desafortunadamente, no maneja información de color, pero según @Mark Storer, puede que no sea demasiado difícil implementarlo usted mismo .

COMENZAR A EDITAR

Comencé a trabajar en la implementación de información de color. Consulte la publicación de mi blog aquí para obtener más detalles. (Perdón por el mal formato, ahora nos vamos a cenar).

FINALIZAR EDITAR

El siguiente código combina varias preguntas y respuestas, incluida esta para obtener la altura de la fuente (aunque no es exacta), así como otra (que por mi vida ya no puedo encontrar) que muestra cómo detectar falsa negrita.

Devuelve PostscriptFontNamealgunos caracteres adicionales delante del nombre de la fuente, creo que tiene que ver con el momento en que incrustas subconjuntos de fuentes.

A continuación se muestra una aplicación WinForms completa dirigida a iTextSharp 5.1.1.0 y extrae texto como HTML.

Captura de pantalla del PDF de muestra

Captura de pantalla del PDF de muestra

Texto de muestra extraído como HTML

<span style="font-family:NJNSWD+Papyrus-Regular;font-size:11.61407">Hello </span>
<span style="font-family:NJNSWD+Papyrus-Regular-Bold;font-size:11.61407">w</span>
<span style="font-family:NJNSWD+Papyrus-Regular-Bold;font-size:37.87201">o</span>
<span style="font-family:NJNSWD+Papyrus-Regular-Bold;font-size:11.61407">rl</span>
<span style="font-family:NJNSWD+Papyrus-Regular;font-size:11.61407">d </span>
<br />
<span style="font-family:NJNSWD+Papyrus-Regular;font-size:11.61407">Test </span>

Código

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using iTextSharp.text.pdf.parser;
using iTextSharp.text.pdf;

namespace WindowsFormsApplication2
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            PdfReader reader = new PdfReader(System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "Document.pdf"));
            TextWithFontExtractionStategy S = new TextWithFontExtractionStategy();
            string F = iTextSharp.text.pdf.parser.PdfTextExtractor.GetTextFromPage(reader, 1, S);
            Console.WriteLine(F);

            this.Close();
        }

        public class TextWithFontExtractionStategy : iTextSharp.text.pdf.parser.ITextExtractionStrategy
        {
            //HTML buffer
            private StringBuilder result = new StringBuilder();

            //Store last used properties
            private Vector lastBaseLine;
            private string lastFont;
            private float lastFontSize;

            //http://api.itextpdf.com/itext/com/itextpdf/text/pdf/parser/TextRenderInfo.html
            private enum TextRenderMode
            {
                FillText = 0,
                StrokeText = 1,
                FillThenStrokeText = 2,
                Invisible = 3,
                FillTextAndAddToPathForClipping = 4,
                StrokeTextAndAddToPathForClipping = 5,
                FillThenStrokeTextAndAddToPathForClipping = 6,
                AddTextToPaddForClipping = 7
            }



            public void RenderText(iTextSharp.text.pdf.parser.TextRenderInfo renderInfo)
            {
                string curFont = renderInfo.GetFont().PostscriptFontName;
                //Check if faux bold is used
                if ((renderInfo.GetTextRenderMode() == (int)TextRenderMode.FillThenStrokeText))
                {
                    curFont += "-Bold";
                }

                //This code assumes that if the baseline changes then we're on a newline
                Vector curBaseline = renderInfo.GetBaseline().GetStartPoint();
                Vector topRight = renderInfo.GetAscentLine().GetEndPoint();
                iTextSharp.text.Rectangle rect = new iTextSharp.text.Rectangle(curBaseline[Vector.I1], curBaseline[Vector.I2], topRight[Vector.I1], topRight[Vector.I2]);
                Single curFontSize = rect.Height;

                //See if something has changed, either the baseline, the font or the font size
                if ((this.lastBaseLine == null) || (curBaseline[Vector.I2] != lastBaseLine[Vector.I2]) || (curFontSize != lastFontSize) || (curFont != lastFont))
                {
                    //if we've put down at least one span tag close it
                    if ((this.lastBaseLine != null))
                    {
                        this.result.AppendLine("</span>");
                    }
                    //If the baseline has changed then insert a line break
                    if ((this.lastBaseLine != null) && curBaseline[Vector.I2] != lastBaseLine[Vector.I2])
                    {
                        this.result.AppendLine("<br />");
                    }
                    //Create an HTML tag with appropriate styles
                    this.result.AppendFormat("<span style=\"font-family:{0};font-size:{1}\">", curFont, curFontSize);
                }

                //Append the current text
                this.result.Append(renderInfo.GetText());

                //Set currently used properties
                this.lastBaseLine = curBaseline;
                this.lastFontSize = curFontSize;
                this.lastFont = curFont;
            }

            public string GetResultantText()
            {
                //If we wrote anything then we'll always have a missing closing tag so close it here
                if (result.Length > 0)
                {
                    result.Append("</span>");
                }
                return result.ToString();
            }

            //Not needed
            public void BeginTextBlock() { }
            public void EndTextBlock() { }
            public void RenderImage(ImageRenderInfo renderInfo) { }
        }
    }
}
Chris Haas avatar Jul 30 '2011 15:07 Chris Haas