У меня есть PDF-файл, содержащий текст и изображения. Все изображения имеют ALT-текст для удобства чтения.
Может ли кто-нибудь сказать мне, как я могу извлечь пары значений <BufferedImage, String>, где BufferedImage — это изображение, а String — это ALT-текст?
Для меня не имеет значения, использую ли я PDFBox или Apache Tika.
Пример PDF: Репозиторий GitHub с примером PDF
Вот код, который расширяет решение из 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
@TilmanHausherr готово