letras letra cursiva azules pdf font-size detect pdfbox

pdf - azules - letra cursiva iphone instagram



Cómo determinar el estilo negrita artificial, el estilo de cursiva artificial y el estilo de contorno artificial de un texto usando PDFBOX (2)

Estoy usando PDFBox para validar un documento pdf. Hay ciertos requisitos para verificar los siguientes tipos de texto presentes en un PDF

  • Texto de estilo negrita artificial
  • Texto de estilo cursiva artificial.
  • Texto de estilo de contorno artificial

Busqué en la lista de API de PDFBOX pero no pude encontrar ese tipo de API.

¿Puede alguien ayudarme y decirme cómo determinar los diferentes tipos de estilos de fuente / texto artificial para que estén presentes en un PDF usando PDFBOX.


El procedimiento general y un problema de PDFBox

En teoría, uno debe comenzar esto derivando una clase de PDFTextStripper y anulando su método:

/** * Write a Java string to the output stream. The default implementation will ignore the <code>textPositions</code> * and just calls {@link #writeString(String)}. * * @param text The text to write to the stream. * @param textPositions The TextPositions belonging to the text. * @throws IOException If there is an error when writing the text. */ protected void writeString(String text, List<TextPosition> textPositions) throws IOException { writeString(text); }

Entonces, su reemplazo debe usar List<TextPosition> textPositions lugar del String text ; cada TextPosition representa esencialmente una sola letra y la información sobre el estado gráfico activo cuando se dibujó esa letra.

Desafortunadamente, la lista de textPositions no contiene los contenidos correctos en la versión actual 1.8.3. Por ejemplo, para la línea "Esto es texto normal". desde su PDF, el método writeString se llama cuatro veces, una para las cadenas "This", "is", "normal" y "text". Lamentablemente, la lista textPositions contiene las instancias de TextPosition para las letras de la última cadena "texto".

En realidad, esto ya se reconoció como el problema de PDFBox PDFBOX-1804, que mientras tanto se resolvió como arreglado para las versiones 1.8.4 y 2.0.0.

Dicho esto, tan pronto como tenga una versión de PDFBox que esté arreglada, puede verificar algunos estilos artificiales de la siguiente manera:

Texto en cursiva artificial

Este estilo de texto se crea así en el contenido de la página:

BT /F0 1 Tf 24 0 5.10137 24 66 695.5877 Tm 0 Tr [<03>]TJ ...

La parte relevante ocurre al establecer la matriz de texto Tm . El 5.10137 es un factor por el cual se corta el texto.

Cuando comprueba una posición de TextPosition textPosition como se indicó anteriormente, puede consultar este valor usando

textPosition.getTextPos().getValue(1, 0)

Si este valor relevante es mayor que 0.0, tiene cursivas artificiales. Si es relevante menos de 0.0, tiene cursiva artificial hacia atrás.

Texto en negrita o contorno artificial

Estos estilos artificiales utilizan letras de impresión dobles con diferentes modos de representación; por ejemplo, la ''T'' mayúscula, en caso de negrita:

0 0 0 1 k ... BT /F0 1 Tf 24 0 0 24 66.36 729.86 Tm <03>Tj 4 M 0.72 w 0 0 Td 1 Tr 0 0 0 1 K <03>Tj ET

(es decir, primero dibujar la letra en modo regular, rellenar el área de la letra y luego dibujarla en modo de contorno, dibujando una línea a lo largo del borde de la letra, ambas en negro, CMYK 0, 0, 0, 1; esto deja la impresión de letra más gruesa).

y en caso de esquema:

BT /F0 1 Tf 24 0 0 24 66 661.75 Tm 0 0 0 0 k <03>Tj /GS1 gs 4 M 0.288 w 0 0 Td 1 Tr 0 0 0 1 K <03>Tj ET

(es decir, primero dibujando la letra en modo regular blanco, CMYK 0, 0, 0, 0, llenando el área de la letra, y luego dibujándola en modo de contorno, dibujando una línea a lo largo del borde de la letra, en negro, CMYK 0, 0, 0 , 1; esto deja la impresión de una letra negra sobre blanco).

Desafortunadamente, el PDF PDFTextStripper no realiza un seguimiento del modo de representación de texto. Además, elimina explícitamente las apariciones de caracteres duplicados en aproximadamente la misma posición. Por lo tanto, no está a la tarea de reconocer estos estilos artificiales.

Si realmente necesita hacerlo, deberá cambiar TextPosition para que también contenga el modo de representación, PDFStreamEngine para agregarlo a las instancias de TextPosition generadas, y PDFTextStripper para no colocar glifos duplicados en processTextPosition .

Correcciones

escribí

Desafortunadamente, el PDF PDFTextStripper no realiza un seguimiento del modo de representación de texto.

Esto no es del todo cierto, puede encontrar el modo de representación actual usando getGraphicsState().getTextState().getRenderingMode() . Esto significa que durante processTextPosition usted tiene el modo de renderizado disponible y puede intentar almacenar la información del modo de representación (y el color!) Para la posición del texto dada en TextPosition parte, por ejemplo, en algún Map<TextPosition, ...> , para usarlo posteriormente.

Además, elimina explícitamente las apariciones de caracteres duplicados en aproximadamente la misma posición.

Puede desactivar esto llamando a setSuppressDuplicateOverlappingText(false) .

Con estos dos cambios, también debería poder realizar las pruebas necesarias para verificar el en negrita artificial y el contorno.

El último cambio podría no ser necesario si almacena y comprueba los estilos al principio de processTextPosition .

Cómo recuperar el modo de renderizado y el color

Como se menciona en Correcciones , de hecho es posible recuperar el modo de renderizado y la información de color al recopilar esa información en una anulación de processTextPosition .

A esto, el OP comentó que

Siempre el color acariciante y sin caricias viene como negro

Esto fue un poco sorprendente al principio, pero después de mirar las PDFTextStripper.properties (desde el cual se inicializaron los operadores compatibles durante la extracción de texto), el motivo quedó claro:

# The following operators are not relevant to text extraction, # so we can silently ignore them. ... K k

Por lo tanto, los operadores de configuración de color (especialmente aquellos para colores CMYK como en el presente documento) se ignoran en este contexto. Afortunadamente, las implementaciones de estos operadores para PageDrawer se pueden usar en este contexto.

Por lo tanto, la siguiente prueba de concepto muestra cómo se puede recuperar toda la información requerida.

public class TextWithStateStripperSimple extends PDFTextStripper { public TextWithStateStripperSimple() throws IOException { super(); setSuppressDuplicateOverlappingText(false); registerOperatorProcessor("K", new org.apache.pdfbox.util.operator.SetStrokingCMYKColor()); registerOperatorProcessor("k", new org.apache.pdfbox.util.operator.SetNonStrokingCMYKColor()); } @Override protected void processTextPosition(TextPosition text) { renderingMode.put(text, getGraphicsState().getTextState().getRenderingMode()); strokingColor.put(text, getGraphicsState().getStrokingColor()); nonStrokingColor.put(text, getGraphicsState().getNonStrokingColor()); super.processTextPosition(text); } Map<TextPosition, Integer> renderingMode = new HashMap<TextPosition, Integer>(); Map<TextPosition, PDColorState> strokingColor = new HashMap<TextPosition, PDColorState>(); Map<TextPosition, PDColorState> nonStrokingColor = new HashMap<TextPosition, PDColorState>(); protected void writeString(String text, List<TextPosition> textPositions) throws IOException { writeString(text + ''/n''); for (TextPosition textPosition: textPositions) { StringBuilder textBuilder = new StringBuilder(); textBuilder.append(textPosition.getCharacter()) .append(" - shear by ") .append(textPosition.getTextPos().getValue(1, 0)) .append(" - ") .append(textPosition.getX()) .append(" ") .append(textPosition.getY()) .append(" - ") .append(renderingMode.get(textPosition)) .append(" - ") .append(toString(strokingColor.get(textPosition))) .append(" - ") .append(toString(nonStrokingColor.get(textPosition))) .append(''/n''); writeString(textBuilder.toString()); } } String toString(PDColorState colorState) { if (colorState == null) return "null"; StringBuilder builder = new StringBuilder(); for (float f: colorState.getColorSpaceValue()) { builder.append('' '') .append(f); } return builder.toString(); } }

Usando esto obtienes el punto ''.'' en texto normal como:

. - shear by 0.0 - 256.5701 88.6875 - 0 - 0.0 0.0 0.0 1.0 - 0.0 0.0 0.0 1.0

En texto en negrita artificial obtienes;

. - shear by 0.0 - 378.86 122.140015 - 0 - 0.0 0.0 0.0 1.0 - 0.0 0.0 0.0 1.0 . - shear by 0.0 - 378.86002 122.140015 - 1 - 0.0 0.0 0.0 1.0 - 0.0 0.0 0.0 1.0

En cursiva artificial:

. - shear by 5.10137 - 327.121 156.4123 - 0 - 0.0 0.0 0.0 1.0 - 0.0 0.0 0.0 1.0

Y en el esquema artificial:

. - shear by 0.0 - 357.25 190.25 - 0 - 0.0 0.0 0.0 1.0 - 0.0 0.0 0.0 0.0 . - shear by 0.0 - 357.25 190.25 - 1 - 0.0 0.0 0.0 1.0 - 0.0 0.0 0.0 0.0

Entonces, ahí está, toda la información requerida para el reconocimiento de esos estilos artificiales. Ahora solo tienes que analizar los datos.

Por cierto, eche un vistazo al caso negrita artificial: las coordenadas pueden no ser siempre idénticas, sino simplemente muy similares. Por lo tanto, se requiere cierta indulgencia para probar si dos objetos de posición de texto describen la misma posición.


Mi solución para este problema fue crear una nueva clase que amplíe la clase PDFTextStripper y anule la función:

getCharactersByArticle()

nota: PDFBox versión 1.8.5

Clase CustomPDFTextStripper

public class CustomPDFTextStripper extends PDFTextStripper { public CustomPDFTextStripper() throws IOException { super(); } public Vector<List<TextPosition>> getCharactersByArticle(){ return charactersByArticle; } }

De esta forma puedo analizar el documento pdf y luego obtener el TextPosition de una función de extracción personalizada:

private void extractTextPosition() throws FileNotFoundException, IOException { PDFParser parser = new PDFParser(new FileInputStream(pdf)); parser.parse(); StringWriter outString = new StringWriter(); CustomPDFTextStripper stripper = new CustomPDFTextStripper(); stripper.writeText(parser.getPDDocument(), outString); Vector<List<TextPosition>> vectorlistoftps = stripper.getCharactersByArticle(); for (int i = 0; i < vectorlistoftps.size(); i++) { List<TextPosition> tplist = vectorlistoftps.get(i); for (int j = 0; j < tplist.size(); j++) { TextPosition text = tplist.get(j); System.out.println(" String " + "[x: " + text.getXDirAdj() + ", y: " + text.getY() + ", height:" + text.getHeightDir() + ", space: " + text.getWidthOfSpace() + ", width: " + text.getWidthDirAdj() + ", yScale: " + text.getYScale() + "]" + text.getCharacter()); } } }

TextPositions contiene mucha información sobre los caracteres del documento pdf.

SALIDA:

Cadena [x: 168.24, y: 64.15997, altura: 6.061287, espacio: 8.9664, ancho: 3.4879303, y Escala: 8.9664] J

Cadena [x: 171.69745, y: 64.15997, altura: 6.061287, espacio: 8.9664, ancho: 2.2416077, y Escala: 8.9664] N

Cadena [x: 176.25777, y: 64.15997, altura: 6.0343876, espacio: 8.9664, ancho: 6.4737396, y Escala: 8.9664] N

Cadena [x: 182.73778, y: 64.15997, altura: 4.214208, espacio: 8.9664, ancho: 3.981079, y Escala: 8.9664] e .....