Как извлечь ALT-тексты и изображения из PDF-файла

У меня есть PDF-файл, содержащий текст и изображения. Все изображения имеют ALT-текст для удобства чтения.

Может ли кто-нибудь сказать мне, как я могу извлечь пары значений <BufferedImage, String>, где BufferedImage — это изображение, а String — это ALT-текст?

Для меня не имеет значения, использую ли я PDFBox или Apache Tika.

Пример PDF: Репозиторий GitHub с примером PDF

@TilmanHausherr готово

Tristate 04.07.2024 14:30
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
1
56
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вот код, который расширяет решение из Apache PDFBox PDFTextStripper для доступа к текстовым частям страницы, как я могу? . Он был протестирован только на вашем файле, поэтому вы можете столкнуться с сюрпризами. Размещение getNumberTreeAsMap неэффективно, и его следует переместить вверх. Нулевые проверки и проверки классов отсутствуют.

public static void main(String[] args) throws IOException
{
    PDDocument document = Loader.loadPDF(new File("mixed-3-images.pdf"));
    PDFMarkedContentExtractor markedContentExtractor = new PDFMarkedContentExtractor();
    PDPage page = document.getPage(0); //TODO expand
    markedContentExtractor.processPage(page);
    List<PDMarkedContent> markedContents = markedContentExtractor.getMarkedContents();
    for (PDMarkedContent pdMarkedContent : markedContents)
    {
        COSDictionary pdmcProperties = pdMarkedContent.getProperties();
        if (pdmcProperties == null)
            continue;
        // actual answer starts here
        if (pdMarkedContent.getContents().size() >= 1 && pdMarkedContent.getContents().get(0) instanceof PDImageXObject)
        {
            PDImageXObject img = (PDImageXObject) pdMarkedContent.getContents().get(0);
            int mcid = pdmcProperties.getInt(COSName.MCID);
            System.out.println("MCID: " + mcid + "; " + img.getImage());
            
            PDStructureTreeRoot structureTreeRoot = document.getDocumentCatalog().getStructureTreeRoot();
            int sp = page.getStructParents();
            PDNumberTreeNode parentTree = structureTreeRoot.getParentTree();
            Map<Integer, COSObjectable> numberTreeAsMap = getNumberTreeAsMap(parentTree);
            PDParentTreeValue val = (PDParentTreeValue) numberTreeAsMap.get(sp);
            COSArray mcidArray = (COSArray) val.getCOSObject();
            COSDictionary obj = (COSDictionary) mcidArray.getObject(mcid);
            System.out.println("ALT: " + obj.getDictionaryObject(COSName.ALT));
        }
    }
}

// from PDMergerUtility source code
// PDNumberTreeNode.getNumbers() only brings one level, this is why we need this
static Map<Integer, COSObjectable> getNumberTreeAsMap(PDNumberTreeNode tree) throws IOException
{
    if (tree == null)
    {
        return new LinkedHashMap<>();
    }
    Map<Integer, COSObjectable> numbers = tree.getNumbers();
    if (numbers == null)
    {
        numbers = new LinkedHashMap<>();
    }
    else
    {
        // must copy because the map is read only
        numbers = new LinkedHashMap<>(numbers);
    }
    List<PDNumberTreeNode> kids = tree.getKids();
    if (kids != null)
    {
        for (PDNumberTreeNode kid : kids)
        {
            numbers.putAll(getNumberTreeAsMap(kid));
        }
    }
    return numbers;
}

выход:

MCID: 25; BufferedImage@6475472c: type = 1 DirectColorModel: rmask=ff0000 gmask=ff00 bmask=ff amask=0 IntegerInterleavedRaster: width = 478 height = 699 #Bands = 3 xOff = 0 yOff = 0 dataOffset[0] 0
ALT: COSString{Japanese Mask }

То же самое со второй страницей:

MCID: 6; BufferedImage@43aaf813: type = 1 DirectColorModel: rmask=ff0000 gmask=ff00 bmask=ff amask=0 IntegerInterleavedRaster: width = 461 height = 645 #Bands = 3 xOff = 0 yOff = 0 dataOffset[0] 0
ALT: COSString{Black Dog and White Cat }
MCID: 7; BufferedImage@328cf0e1: type = 1 DirectColorModel: rmask=ff0000 gmask=ff00 bmask=ff amask=0 IntegerInterleavedRaster: width = 413 height = 645 #Bands = 3 xOff = 0 yOff = 0 dataOffset[0] 0
ALT: null
MCID: 8; BufferedImage@201b6b6f: type = 1 DirectColorModel: rmask=ff0000 gmask=ff00 bmask=ff amask=0 IntegerInterleavedRaster: width = 913 height = 877 #Bands = 3 xOff = 0 yOff = 0 dataOffset[0] 0
ALT: null

Другие вопросы по теме