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.