c# itextsharp syntax-highlighting

c# - Resalte las palabras en un pdf usando itextsharp, sin mostrar las palabras resaltadas en el navegador



syntax-highlighting (2)

Está utilizando una anotación de marcado para resaltar texto. ¡Eso es genial! No hay nada malo con su código, ni con iText. Sin embargo: no todos los lectores de PDF admiten esa funcionalidad.

Si desea ver el texto resaltado en cada visor de PDF, una solución (subóptima) podría ser agregar un rectángulo amarillo a la secuencia de contenido debajo del contenido existente (suponiendo que el contenido existente no sea opaco).

Esto se demuestra en el ejemplo HighLightByAddingContent :

public void manipulatePdf(String src, String dest) throws IOException, DocumentException { PdfReader reader = new PdfReader(src); PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(dest)); PdfContentByte canvas = stamper.getUnderContent(1); canvas.saveState(); canvas.setColorFill(BaseColor.YELLOW); canvas.rectangle(36, 786, 66, 16); canvas.fill(); canvas.restoreState(); stamper.close(); reader.close(); }

En este ejemplo, tomamos un archivo llamado hello.pdf y agregamos un rectángulo amarillo, con el archivo hello_highlighted.pdf como resultado.

Tenga en cuenta que no verá el rectángulo amarillo si lo agrega bajo una forma opaca (por ejemplo, debajo de una imagen). En ese caso, puede agregar un rectángulo transparente sobre el contenido existente.

Actualización: mi ejemplo fue escrito en Java. No debería ser un problema para un desarrollador portar esto a C #. Solo es cuestión de cambiar algunas minúsculas a mayúsculas. Por ejemplo, stamper.GetUnderContent(1) lugar de stamper.getUnderContent(1) , canvas.SaveState() lugar de canvas.saveState() , y así sucesivamente.

Las palabras resaltadas no se muestran en el navegador usando itextsharp.

Adobe

Navegador

CÓDIGO

List<iTextSharp.text.Rectangle> MatchesFound = strategy.GetTextLocations(splitText[i].Trim(), StringComparison.CurrentCultureIgnoreCase); foreach (Rectangle rect in MatchesFound) { float[] quad = { rect.Left - 3.0f, rect.Bottom, rect.Right, rect.Bottom, rect.Left - 3.0f, rect.Top + 1.0f, rect.Right, rect.Top + 1.0f }; //Create our hightlight PdfAnnotation highlight = PdfAnnotation.CreateMarkup(stamper.Writer, rect, null, PdfAnnotation.MARKUP_HIGHLIGHT, quad); //Set the color highlight.Color = BaseColor.YELLOW; //Add the annotation stamper.AddAnnotation(highlight, pageno); }

Amablemente ayúdame a resolver este problema.

Código de actualización

private void highlightPDF() { //Create a simple test file string outputFile = Server.MapPath("~/pdf/16193037V_Dhana-FI_NK-QA_Completed.pdf"); string filename = "HL" + Convert.ToString(Session["Filename"]) + ".pdf"; Session["Filename"] = "HL" + Convert.ToString(Session["Filename"]); //Create a new file from our test file with highlighting string highLightFile = Server.MapPath("~/pdf/" + filename); //Bind a reader and stamper to our test PDF PdfReader reader = new PdfReader(outputFile); iTextSharp.text.pdf.PdfContentByte canvas; int pageno = Convert.ToInt16(txtPageno.Text); using (FileStream fs = new FileStream(highLightFile, FileMode.Create, FileAccess.Write, FileShare.None)) { using (PdfStamper stamper = new PdfStamper(reader, fs)) { canvas = stamper.GetUnderContent(pageno); myLocationTextExtractionStrategy strategy = new myLocationTextExtractionStrategy(); strategy.UndercontentCharacterSpacing = canvas.CharacterSpacing; strategy.UndercontentHorizontalScaling = canvas.HorizontalScaling; string currentText = PdfTextExtractor.GetTextFromPage(reader, pageno, strategy); string text = txtHighlight.Text.Replace("/r/n", "").Replace("//n", "/n").Replace(" ", " "); string[] splitText = text.Split(new string[] { "/n" }, StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < splitText.Length; i++) { List<iTextSharp.text.Rectangle> MatchesFound = strategy.GetTextLocations(splitText[i].Trim(), StringComparison.CurrentCultureIgnoreCase); foreach (Rectangle rect in MatchesFound) { canvas.SaveState(); canvas.SetColorFill(BaseColor.YELLOW); canvas.Rectangle(rect); canvas.Fill(); canvas.RestoreState(); } } } } reader.Close(); }

No está resaltando el texto. Pasé el texto y la página no para resaltar el texto.


Ante todo...

¿Por qué el código OP (actualizado) no funciona?

En realidad hay dos factores.

En primer lugar , hay un problema en el código del OP para agregar un rectángulo a una ruta que usa

canvas.Rectangle(rect);

Desafortunadamente, esto no es lo que él espera: la clase Rectangle tiene múltiples propiedades más allá de las meras coordenadas de un rectángulo, la información más importante sobre los bordes seleccionados, los colores del borde y un color interior, y PdfContentByte.Rectangle(Rectangle) dibuja un rectángulo de acuerdo con esas propiedades .

Sin embargo, en el caso que nos ocupa, rect solo se usa para transportar las coordenadas de un rectángulo, por lo que todas esas propiedades adicionales son false o null . Por lo tanto, canvas.Rectangle(rect) no hace nada!

En cambio, el OP debería usar

canvas.Rectangle(rect.Left, rect.Bottom, rect.Width, rect.Height);

aquí.

Además , @Bruno mencionó en su respuesta

Tenga en cuenta que no verá el rectángulo amarillo si lo agrega bajo una forma opaca (por ejemplo, debajo de una imagen).

Desafortunadamente, este es exactamente el caso aquí: el documento en realidad es un documento escaneado, cada página ha sido una imagen de relleno de página bajo la cual se dibuja el texto equivalente (probablemente después de OCR) para permitir copiar y pegar texto.

Por lo tanto, cualquiera que sea el código del OP en el UnderContent , estará oculto por esa misma imagen.

Por lo tanto, intentemos algo diferente ...

Cómo hacer que funcione

@Bruno en su respuesta también indicó una solución para tal caso:

En ese caso, puede agregar un rectángulo transparente sobre el contenido existente.

Siguiendo este consejo reemplazamos

canvas = stamper.GetUnderContent(pageno);

por

canvas = stamper.GetOverContent(pageno); PdfGState state = new PdfGState(); state.FillOpacity = .3f; canvas.SetGState(state);

Al seleccionar la palabra "soporte" en la tercera página del documento, obtenemos:

El amarillo es bastante pálido aquí.

Usando un valor de Opacity de .6 lugar obtenemos

Ahora el amarillo es más intenso pero el texto comienza a palidecer.

Para tareas como esta, prefiero usar el modo de mezcla Darken . Esto se puede hacer usando

state.BlendMode = new PdfName("Darken");

en lugar de state.FillOpacity = .3f . Esto resulta en

Esta OMI se ve mejor.

Como lo hizo el cliente

El OP comentó

El cliente ha dado un pdf. En eso, resaltaron el texto, el texto resaltado se muestra en el navegador

El PDF del cliente en realidad usa anotaciones, al igual que el OP en su código original, pero en contraste cada una de las anotaciones del cliente contiene un flujo de apariencia que las anotaciones destacadas generadas por iText no.

Proporcionar una apariencia es opcional y los lectores de PDF deberían generar una apariencia si no se proporciona ninguna. Obviamente, sin embargo, hay numerosos lectores de PDF que dependen de las apariencias que trae el PDF.

Por cierto, las apariencias en el PDF del cliente realmente usan el modo de mezcla Multiplicar . Para los colores blanco y negro subyacentes, Darken y Multiply tienen el mismo resultado.

Hacer que funcione con anotaciones

En un comentario, el OP se preguntó

Una duda más, si el usuario resaltó erróneamente, ¿cómo eliminar el color amarillo (o cambiar el amarillo al blanco)? Cambié de amarillo a blanco pero no funciona. canvas.SetColorFill (BaseColor.WHITE);

Deshacer un cambio en el contenido de la página generalmente es más difícil que deshacer la adición de una anotación. Por lo tanto, hagamos que el código original del OP también funcione, es decir, agregue una secuencia de apariencia a las anotaciones resaltadas.

Como informó el OP en otro comentario, su primer intento de agregar una secuencia de apariencia falló:

PdfAppearance appearance = PdfAppearance.CreateAppearance(stamper.Writer, rect.Width, rect.Height); appearance.Rectangle(rect.Left, rect.Bottom, rect.Width, rect.Height); appearance.SetColorFill(BaseColor.WHITE); appearance.Fill(); highlight.SetAppearance( PdfAnnotation.APPEARANCE_NORMAL, appearance ); stamper.AddAnnotation(highlight, pageno);

Pero no está funcionando.

Los problemas en su intento son:

  • El origen de la plantilla de apariencia está en la esquina inferior izquierda del área de anotación, no de la página. Para colorear el área en cuestión, por lo tanto, el rectángulo debe tener su esquina inferior izquierda en (0, 0).
  • Estrictamente hablando, el color debe establecerse antes de comenzar la construcción del camino.
  • Se debe usar un color diferente al blanco para resaltar.
  • Se debe usar la transparencia o un modo de representación adecuado para permitir que el texto original marcado marque .

Por lo tanto, el siguiente código muestra cómo hacerlo.

private void highlightPDFAnnotation(string outputFile, string highLightFile, int pageno, string[] splitText) { PdfReader reader = new PdfReader(outputFile); iTextSharp.text.pdf.PdfContentByte canvas; using (FileStream fs = new FileStream(highLightFile, FileMode.Create, FileAccess.Write, FileShare.None)) { using (PdfStamper stamper = new PdfStamper(reader, fs)) { myLocationTextExtractionStrategy strategy = new myLocationTextExtractionStrategy(); strategy.UndercontentHorizontalScaling = 100; string currentText = PdfTextExtractor.GetTextFromPage(reader, pageno, strategy); for (int i = 0; i < splitText.Length; i++) { List<iTextSharp.text.Rectangle> MatchesFound = strategy.GetTextLocations(splitText[i].Trim(), StringComparison.CurrentCultureIgnoreCase); foreach (Rectangle rect in MatchesFound) { float[] quad = { rect.Left - 3.0f, rect.Bottom, rect.Right, rect.Bottom, rect.Left - 3.0f, rect.Top + 1.0f, rect.Right, rect.Top + 1.0f }; //Create our hightlight PdfAnnotation highlight = PdfAnnotation.CreateMarkup(stamper.Writer, rect, null, PdfAnnotation.MARKUP_HIGHLIGHT, quad); //Set the color highlight.Color = BaseColor.YELLOW; PdfAppearance appearance = PdfAppearance.CreateAppearance(stamper.Writer, rect.Width, rect.Height); PdfGState state = new PdfGState(); state.BlendMode = new PdfName("Multiply"); appearance.SetGState(state); appearance.Rectangle(0, 0, rect.Width, rect.Height); appearance.SetColorFill(BaseColor.YELLOW); appearance.Fill(); highlight.SetAppearance(PdfAnnotation.APPEARANCE_NORMAL, appearance); //Add the annotation stamper.AddAnnotation(highlight, pageno); } } } } reader.Close(); }

Chrome también muestra estas anotaciones y, como anotaciones, pueden eliminarse fácilmente.