Идентификация текста на основе вывода в PDF с использованием PDFBOX

Iam с помощью PDF BOX для получения информации о цвете текста в PDF. Я смог получить результат, используя следующий код. Но я сомневаюсь в том, что представляет собой StrokingColor, что представляет собой цвет без поглаживания. Исходя из этого, как я могу решить, какой текст имеет цвет. Кто-нибудь предлагает мне? Мой выходной результат выглядит так: DeviceRGB DeviceCMYK java.awt.Color [r = 63, g = 240, b = 0] java.awt.Color [r = 35, g = 31, b = 32] 34.934998 31.11 31.875

PDDocument doc = null; try { doc = PDDocument.load(strFilepath); PDFStreamEngine engine = new PDFStreamEngine(ResourceLoader.loadProperties("org/apache/pdfbox/resources/PageDrawer.properties")); PDPage page = (PDPage)doc.getDocumentCatalog().getAllPages().get(1); engine.processStream(page, page.findResources(), page.getContents().getStream()); PDGraphicsState graphicState = engine.getGraphicsState(); System.out.println(graphicState.getStrokingColor().getColorSpace().getName()); System.out.println(graphicState.getNonStrokingColor().getColorSpace().getName()); System.out.println(graphicState.getNonStrokingColor().getJavaColor()); System.out.println(graphicState.getStrokingColor().getJavaColor()); float colorSpaceValues[] = graphicState.getStrokingColor().getColorSpaceValue(); for (float c : colorSpaceValues) { System.out.println(c * 255); } } finally { if (doc != null) { doc.close(); } } 

Согласно разъяснениям в комментариях, OP хочет

сравните цвета шрифтов одной страницы pdf с другой страницей pdf […], если есть текст «Образец» в черном цвете и какой-то другой текст «sample1» в сером цвете …. Мне нужно знать, что образец – > черный цвет, sample1 -> серый цвет, подобный этому .. я хочу полный текст и его цвет

PDFBox имеет механизм извлечения текста, PDFTextStripper . Есть некоторые проблемы в использовании этого для задачи, хотя, среди них:

  • Первоначально он не предназначен для извлечения информации о цвете рядом с текстом; Объекты TextPosition он использует, даже не имеют атрибута для цвета. Таким образом, нам придется несколько расширить его.

    • Сначала мы зарегистрируем слушателей для операций с цветом, чтобы отслеживать цвета вообще.

    • Кроме того, мы сохраним информацию о цвете для объекта TextPosition в другой структуре (я бы предпочел бы расширить положение текста соответственно, но из-за нескольких недоступных частных членов, что означало бы довольно хлопот).

    • Это уже было подробно показано в этом ответе ; для фона, посмотрите там.

  • PDF позволяет много способов рисования текста. Буквы могут быть заполнены одним цветом, а его граница может быть поглажена другим. Их граница может даже служить в качестве обтравочного контура для следующих операций рисования. Мы будем рассматривать только наполнение и поглаживание цветов.

  • Текст, нарисованный позже, может быть покрыт другими рисунками, полностью скрывая его или изменяя его цвет. На данный момент мы будем игнорировать это.

Как указано, мы расширяем PDFTextStripper следующим образом:

 import java.io.IOException; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.pdfbox.util.PDFTextStripper; import org.apache.pdfbox.util.TextPosition; public class ColorTextStripper extends PDFTextStripper { public ColorTextStripper() throws IOException { super(); setSuppressDuplicateOverlappingText(false); registerOperatorProcessor("CS", new org.apache.pdfbox.util.operator.SetStrokingColorSpace()); registerOperatorProcessor("cs", new org.apache.pdfbox.util.operator.SetNonStrokingColorSpace()); registerOperatorProcessor("SC", new org.apache.pdfbox.util.operator.SetStrokingColor()); registerOperatorProcessor("sc", new org.apache.pdfbox.util.operator.SetNonStrokingColor()); registerOperatorProcessor("SCN", new org.apache.pdfbox.util.operator.SetStrokingColor()); registerOperatorProcessor("scn", new org.apache.pdfbox.util.operator.SetNonStrokingColor()); registerOperatorProcessor("G", new org.apache.pdfbox.util.operator.SetStrokingGrayColor()); registerOperatorProcessor("g", new org.apache.pdfbox.util.operator.SetNonStrokingGrayColor()); registerOperatorProcessor("RG", new org.apache.pdfbox.util.operator.SetStrokingRGBColor()); registerOperatorProcessor("rg", new org.apache.pdfbox.util.operator.SetNonStrokingRGBColor()); 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().getColorSpaceValue()); nonStrokingColor.put(text, getGraphicsState().getNonStrokingColor().getColorSpaceValue()); super.processTextPosition(text); } Map renderingMode = new HashMap(); Map strokingColor = new HashMap(); Map nonStrokingColor = new HashMap(); final static List FILLING_MODES = Arrays.asList(0, 2, 4, 6); final static List STROKING_MODES = Arrays.asList(1, 2, 5, 6); final static List CLIPPING_MODES = Arrays.asList(4, 5, 6, 7); @Override protected void writeString(String text, List textPositions) throws IOException { for (TextPosition textPosition: textPositions) { Integer charRenderingMode = renderingMode.get(textPosition); float[] charStrokingColor = strokingColor.get(textPosition); float[] charNonStrokingColor = nonStrokingColor.get(textPosition); StringBuilder textBuilder = new StringBuilder(); textBuilder.append(textPosition.getCharacter()) .append("{"); if (FILLING_MODES.contains(charRenderingMode)) { textBuilder.append("FILL:") .append(toString(charNonStrokingColor)) .append(';'); } if (STROKING_MODES.contains(charRenderingMode)) { textBuilder.append("STROKE:") .append(toString(charStrokingColor)) .append(';'); } if (CLIPPING_MODES.contains(charRenderingMode)) { textBuilder.append("CLIP;"); } textBuilder.append("}"); writeString(textBuilder.toString()); } } String toString(float[] values) { if (values == null) return "null"; StringBuilder builder = new StringBuilder(); switch(values.length) { case 1: builder.append("GRAY"); break; case 3: builder.append("RGB"); break; case 4: builder.append("CMYK"); break; default: builder.append("UNKNOWN"); } for (float f: values) { builder.append(' ') .append(f); } return builder.toString(); } } 

Вы можете назвать это следующим образом:

 PDFTextStripper stripper = new ColorTextStripper(); PDDocument document = PDDocument.load(SOURCE_FILE); String text = stripper.getText(document); 

Полученный текст содержит следующее:

 P{FILL:RGB 0.803 0.076 0.086;}e{FILL:RGB 0.803 0.076 0.086;}l{FILL:RGB 0.803 0.076 0.086;}l{FILL:RGB 0.803 0.076 0.086;}e{FILL:RGB 0.803 0.076 0.086;} 

а также

 G{FILL:RGB 0.102 0.101 0.095;}r{FILL:RGB 0.102 0.101 0.095;}a{FILL:RGB 0.102 0.101 0.095;}z{FILL:RGB 0.102 0.101 0.095;}i{FILL:RGB 0.102 0.101 0.095;}e{FILL:RGB 0.102 0.101 0.095;} 

для Пелле и Граци из этого

Пелле и Граци

или

 K{FILL:RGB 0.0 0.322 0.573;}E{FILL:RGB 0.0 0.322 0.573;}Y{FILL:RGB 0.0 0.322 0.573;} 

а также

 C{FILL:GRAY 0.0;}o{FILL:GRAY 0.0;}m{FILL:GRAY 0.0;}b{FILL:GRAY 0.0;}i{FILL:GRAY 0.0;}n{FILL:GRAY 0.0;}e{FILL:GRAY 0.0;}d{FILL:GRAY 0.0;} 

для KEY и в сочетании :

КЛЮЧ и комбинированный

Вместо того, чтобы сериализовать всю информацию в результат String , вы, конечно, можете также создать class, содержащий как цвет, так и информацию о символах структурированным способом. Так же, как и теперь, результат String создается в writeString , вы можете изменить этот метод, чтобы добавить экземпляры такого classа в некоторый список в нем.

Требования

Для выполнения этой работы требуется хотя бы PDFBox версия 1.8.4. Я тестировал его с использованием 2.0.0-SNAPSHOT, но 1.8.4 должен быть достаточным. 1.8.3, с другой стороны, имеет ошибку, которая иногда пересылает неправильные объекты TextPosition в writeString , ср. PDFBOX-1804 и более ранние версии не предоставляют коллекцию TextPosition для writeString .

Давайте будем гением компьютера.