diff --git a/poi-ooxml/build.gradle b/poi-ooxml/build.gradle index 454a84821eb..78457475e03 100644 --- a/poi-ooxml/build.gradle +++ b/poi-ooxml/build.gradle @@ -114,6 +114,9 @@ dependencies { testImplementation project(path:':poi', configuration:'tests') testImplementation project(path:':poi-ooxml-lite-agent', configuration: 'archives') testRuntimeOnly "org.apiguardian:apiguardian-api:${apiGuardianVersion}" + testRuntimeOnly("net.sf.saxon:Saxon-HE:${saxonVersion}") { + exclude group: 'xml-apis', module: 'xml-apis' + } testImplementation 'org.xmlunit:xmlunit-core:2.9.1' testImplementation 'org.reflections:reflections:0.10.2' testImplementation 'org.openjdk.jmh:jmh-core:1.36' @@ -134,6 +137,7 @@ dependencies { javadocs project(':poi') javadocs project(':poi-scratchpad') + } final String MODULE_NAME = 'org.apache.poi.ooxml' diff --git a/poi-ooxml/src/test/java/org/apache/poi/xwpf/usermodel/TestXWPFDocument.java b/poi-ooxml/src/test/java/org/apache/poi/xwpf/usermodel/TestXWPFDocument.java index fe672899137..03236cc265f 100644 --- a/poi-ooxml/src/test/java/org/apache/poi/xwpf/usermodel/TestXWPFDocument.java +++ b/poi-ooxml/src/test/java/org/apache/poi/xwpf/usermodel/TestXWPFDocument.java @@ -17,6 +17,7 @@ Licensed to the Apache Software Foundation (ASF) under one or more package org.apache.poi.xwpf.usermodel; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; @@ -25,13 +26,16 @@ Licensed to the Apache Software Foundation (ASF) under one or more import static org.junit.jupiter.api.Assertions.assertSame; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.params.provider.Arguments.arguments; -import java.io.IOException; -import java.io.OutputStream; -import java.util.Arrays; +import java.io.*; +import java.nio.file.Files; +import java.util.*; import java.util.List; -import java.util.Optional; +import java.util.stream.Collectors; +import java.util.stream.IntStream; +import org.apache.commons.collections4.ListUtils; import org.apache.poi.POIDataSamples; import org.apache.poi.common.usermodel.PictureType; import org.apache.poi.ooxml.POIXMLDocumentPart; @@ -42,11 +46,18 @@ Licensed to the Apache Software Foundation (ASF) under one or more import org.apache.poi.openxml4j.opc.PackagePart; import org.apache.poi.openxml4j.opc.PackagePartName; import org.apache.poi.openxml4j.opc.PackagingURIHelper; +import org.apache.poi.util.Units; import org.apache.poi.xwpf.XWPFTestDataSamples; import org.apache.poi.xwpf.extractor.XWPFWordExtractor; import org.apache.xmlbeans.XmlCursor; +import org.apache.xmlbeans.XmlException; +import org.apache.xmlbeans.XmlObject; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps; import org.openxmlformats.schemas.officeDocument.x2006.extendedProperties.CTProperties; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTP; @@ -55,7 +66,7 @@ public final class TestXWPFDocument { @Test void testContainsMainContentType() throws Exception { try (XWPFDocument doc = XWPFTestDataSamples.openSampleDocument("sample.docx"); - OPCPackage pack = doc.getPackage()) { + OPCPackage pack = doc.getPackage()) { String ct = XWPFRelation.DOCUMENT.getContentType(); boolean found = pack.getParts().stream().anyMatch(p -> ct.equals(p.getContentType())); assertTrue(found); @@ -480,20 +491,117 @@ void testInsertNewParagraphWithSdt() throws IOException { } } + @ParameterizedTest(name = "insert {0} pictures into document with {1} shapes") + @MethodSource("documentsAndNumberOfPictures") + void testInsertImagesIntoDocumentWithExistingShapes(int numberOfPictures, int numberOfShapes) throws Exception { + String pathToDocument = String.format("/bugfixing/shape in footer/document with shapes %d.docx", numberOfShapes); + + InputStream docxContents = getClass().getResourceAsStream(pathToDocument); + XWPFDocument document = new XWPFDocument(docxContents); + workaround(document); + + IntStream.rangeClosed(1, numberOfPictures).forEach( + i -> addImage(document.createParagraph(), "/bugfixing/" + i + ".png")); + +/* + document.write(Files.newOutputStream(new File( + System.getProperty("user.home"), + String.format("/Desktop/out/%d_%d-out.docx", numberOfPictures, numberOfShapes)).toPath())); +*/ + + Set docPrIds = new HashSet<>(); + XWPFParagraph p = document.getParagraphs().get(0); + XmlCursor paragraphCursor = p.getCTP().newCursor(); + paragraphCursor.selectPath("//*:docPr"); + while (paragraphCursor.hasNextSelection()) { + paragraphCursor.toNextSelection(); + paragraphCursor.toFirstAttribute(); + boolean newItem = docPrIds.add(paragraphCursor.getTextValue()); + assertTrue(newItem); + } + } + + private XWPFDocument workaround(XWPFDocument document) { + try { + for (XWPFParagraph paragraph : bodyAndFooterParagraphs(document)) { + for (XWPFRun run : paragraph.getRuns()) { + XmlCursor cursor = run.getCTR().newCursor(); + cursor.selectPath( + "declare namespace w='http://schemas.openxmlformats.org/wordprocessingml/2006/main' " + + "declare namespace mc='http://schemas.openxmlformats.org/markup-compatibility/2006' " + + "declare namespace wp='http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing' " + + ".//wp:docPr"); + + while (cursor.hasNextSelection()) { + cursor.toNextSelection(); + XmlObject obj = cursor.getObject(); + + CTNonVisualDrawingProps docPr = CTNonVisualDrawingProps.Factory.parse(obj.xmlText()); + + document.getDrawingIdManager().reserve(docPr.getId()); + } + } + } + + ByteArrayOutputStream outStream = new ByteArrayOutputStream(); + document.write(outStream); + byte[] byteArray = outStream.toByteArray(); + return new XWPFDocument(new ByteArrayInputStream(byteArray)); + + } catch (XmlException | IOException e) { + throw new RuntimeException(e); + } + } + + private List bodyAndFooterParagraphs(XWPFDocument document) { + + List footerParagraphs = document.getFooterList().stream() + .flatMap(f -> f.getParagraphs().stream()) + .collect(Collectors.toList()); + + return ListUtils.union(document.getParagraphs(), footerParagraphs); + } + + private void addImage(XWPFParagraph paragraph, String path) { + XWPFRun run = paragraph.getRuns().stream().findFirst().orElse(paragraph.createRun()); + + try { + run.addPicture( + getClass().getResourceAsStream(path), + Document.PICTURE_TYPE_PNG, + "some image.png", + 10 * Units.EMU_PER_PIXEL, + 10 * Units.EMU_PER_PIXEL + ); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + + public static List documentsAndNumberOfPictures() { + return IntStream.rangeClosed(0, 10) + .boxed() + .flatMap(files -> + IntStream.rangeClosed(0, 10) + .mapToObj(shapes -> arguments(files, shapes))) + .collect(Collectors.toList()); + } + @Test @Disabled("XWPF should be able to write to a new Stream when opened Read-Only") void testWriteFromReadOnlyOPC() throws Exception { try (OPCPackage opc = OPCPackage.open( POIDataSamples.getDocumentInstance().getFile("SampleDoc.docx"), PackageAccess.READ - ); - XWPFDocument doc = new XWPFDocument(opc); - XWPFWordExtractor ext = new XWPFWordExtractor(doc) + ); + XWPFDocument doc = new XWPFDocument(opc); + XWPFWordExtractor ext = new XWPFWordExtractor(doc) ) { final String origText = ext.getText(); try (XWPFDocument doc2 = XWPFTestDataSamples.writeOutAndReadBack(doc); - XWPFWordExtractor ext2 = new XWPFWordExtractor(doc2)) { + XWPFWordExtractor ext2 = new XWPFWordExtractor(doc2)) { assertEquals(origText, ext2.getText()); } } diff --git a/poi-ooxml/src/test/resources/.DS_Store b/poi-ooxml/src/test/resources/.DS_Store new file mode 100644 index 00000000000..43aab2c7843 Binary files /dev/null and b/poi-ooxml/src/test/resources/.DS_Store differ diff --git a/poi-ooxml/src/test/resources/bugfixing/0.png b/poi-ooxml/src/test/resources/bugfixing/0.png new file mode 100644 index 00000000000..b7a204cb681 Binary files /dev/null and b/poi-ooxml/src/test/resources/bugfixing/0.png differ diff --git a/poi-ooxml/src/test/resources/bugfixing/1.png b/poi-ooxml/src/test/resources/bugfixing/1.png new file mode 100644 index 00000000000..2822e8f1f87 Binary files /dev/null and b/poi-ooxml/src/test/resources/bugfixing/1.png differ diff --git a/poi-ooxml/src/test/resources/bugfixing/10.png b/poi-ooxml/src/test/resources/bugfixing/10.png new file mode 100644 index 00000000000..f16aed97ac5 Binary files /dev/null and b/poi-ooxml/src/test/resources/bugfixing/10.png differ diff --git a/poi-ooxml/src/test/resources/bugfixing/2.png b/poi-ooxml/src/test/resources/bugfixing/2.png new file mode 100644 index 00000000000..30df4cad3e3 Binary files /dev/null and b/poi-ooxml/src/test/resources/bugfixing/2.png differ diff --git a/poi-ooxml/src/test/resources/bugfixing/3.png b/poi-ooxml/src/test/resources/bugfixing/3.png new file mode 100644 index 00000000000..092e13140e5 Binary files /dev/null and b/poi-ooxml/src/test/resources/bugfixing/3.png differ diff --git a/poi-ooxml/src/test/resources/bugfixing/4.png b/poi-ooxml/src/test/resources/bugfixing/4.png new file mode 100644 index 00000000000..e0f97409f9c Binary files /dev/null and b/poi-ooxml/src/test/resources/bugfixing/4.png differ diff --git a/poi-ooxml/src/test/resources/bugfixing/5.png b/poi-ooxml/src/test/resources/bugfixing/5.png new file mode 100644 index 00000000000..21bb62f7f10 Binary files /dev/null and b/poi-ooxml/src/test/resources/bugfixing/5.png differ diff --git a/poi-ooxml/src/test/resources/bugfixing/6.png b/poi-ooxml/src/test/resources/bugfixing/6.png new file mode 100644 index 00000000000..a0b801ceef2 Binary files /dev/null and b/poi-ooxml/src/test/resources/bugfixing/6.png differ diff --git a/poi-ooxml/src/test/resources/bugfixing/7.png b/poi-ooxml/src/test/resources/bugfixing/7.png new file mode 100644 index 00000000000..b75ecabf41f Binary files /dev/null and b/poi-ooxml/src/test/resources/bugfixing/7.png differ diff --git a/poi-ooxml/src/test/resources/bugfixing/8.png b/poi-ooxml/src/test/resources/bugfixing/8.png new file mode 100644 index 00000000000..e4cc8825602 Binary files /dev/null and b/poi-ooxml/src/test/resources/bugfixing/8.png differ diff --git a/poi-ooxml/src/test/resources/bugfixing/9.png b/poi-ooxml/src/test/resources/bugfixing/9.png new file mode 100644 index 00000000000..43e88fb3f39 Binary files /dev/null and b/poi-ooxml/src/test/resources/bugfixing/9.png differ diff --git a/poi-ooxml/src/test/resources/bugfixing/document with shapes 0.docx b/poi-ooxml/src/test/resources/bugfixing/document with shapes 0.docx new file mode 100644 index 00000000000..89caecdb86d Binary files /dev/null and b/poi-ooxml/src/test/resources/bugfixing/document with shapes 0.docx differ diff --git a/poi-ooxml/src/test/resources/bugfixing/document with shapes 1.docx b/poi-ooxml/src/test/resources/bugfixing/document with shapes 1.docx new file mode 100644 index 00000000000..0c12d582692 Binary files /dev/null and b/poi-ooxml/src/test/resources/bugfixing/document with shapes 1.docx differ diff --git a/poi-ooxml/src/test/resources/bugfixing/document with shapes 10.docx b/poi-ooxml/src/test/resources/bugfixing/document with shapes 10.docx new file mode 100644 index 00000000000..0d757179bdf Binary files /dev/null and b/poi-ooxml/src/test/resources/bugfixing/document with shapes 10.docx differ diff --git a/poi-ooxml/src/test/resources/bugfixing/document with shapes 2.docx b/poi-ooxml/src/test/resources/bugfixing/document with shapes 2.docx new file mode 100644 index 00000000000..3d6de5f4578 Binary files /dev/null and b/poi-ooxml/src/test/resources/bugfixing/document with shapes 2.docx differ diff --git a/poi-ooxml/src/test/resources/bugfixing/document with shapes 3.docx b/poi-ooxml/src/test/resources/bugfixing/document with shapes 3.docx new file mode 100644 index 00000000000..f5e8f836787 Binary files /dev/null and b/poi-ooxml/src/test/resources/bugfixing/document with shapes 3.docx differ diff --git a/poi-ooxml/src/test/resources/bugfixing/document with shapes 4.docx b/poi-ooxml/src/test/resources/bugfixing/document with shapes 4.docx new file mode 100644 index 00000000000..b04f31ea666 Binary files /dev/null and b/poi-ooxml/src/test/resources/bugfixing/document with shapes 4.docx differ diff --git a/poi-ooxml/src/test/resources/bugfixing/document with shapes 5.docx b/poi-ooxml/src/test/resources/bugfixing/document with shapes 5.docx new file mode 100644 index 00000000000..cbd9a87ada1 Binary files /dev/null and b/poi-ooxml/src/test/resources/bugfixing/document with shapes 5.docx differ diff --git a/poi-ooxml/src/test/resources/bugfixing/document with shapes 6.docx b/poi-ooxml/src/test/resources/bugfixing/document with shapes 6.docx new file mode 100644 index 00000000000..8916365bc0e Binary files /dev/null and b/poi-ooxml/src/test/resources/bugfixing/document with shapes 6.docx differ diff --git a/poi-ooxml/src/test/resources/bugfixing/document with shapes 7.docx b/poi-ooxml/src/test/resources/bugfixing/document with shapes 7.docx new file mode 100644 index 00000000000..b6277d92f48 Binary files /dev/null and b/poi-ooxml/src/test/resources/bugfixing/document with shapes 7.docx differ diff --git a/poi-ooxml/src/test/resources/bugfixing/document with shapes 8.docx b/poi-ooxml/src/test/resources/bugfixing/document with shapes 8.docx new file mode 100644 index 00000000000..bd6c05d1703 Binary files /dev/null and b/poi-ooxml/src/test/resources/bugfixing/document with shapes 8.docx differ diff --git a/poi-ooxml/src/test/resources/bugfixing/document with shapes 9.docx b/poi-ooxml/src/test/resources/bugfixing/document with shapes 9.docx new file mode 100644 index 00000000000..930c78b58aa Binary files /dev/null and b/poi-ooxml/src/test/resources/bugfixing/document with shapes 9.docx differ diff --git a/poi-ooxml/src/test/resources/bugfixing/shape in footer/document with shapes 0.docx b/poi-ooxml/src/test/resources/bugfixing/shape in footer/document with shapes 0.docx new file mode 100644 index 00000000000..89caecdb86d Binary files /dev/null and b/poi-ooxml/src/test/resources/bugfixing/shape in footer/document with shapes 0.docx differ diff --git a/poi-ooxml/src/test/resources/bugfixing/shape in footer/document with shapes 1.docx b/poi-ooxml/src/test/resources/bugfixing/shape in footer/document with shapes 1.docx new file mode 100644 index 00000000000..3afc320c7f2 Binary files /dev/null and b/poi-ooxml/src/test/resources/bugfixing/shape in footer/document with shapes 1.docx differ diff --git a/poi-ooxml/src/test/resources/bugfixing/shape in footer/document with shapes 10.docx b/poi-ooxml/src/test/resources/bugfixing/shape in footer/document with shapes 10.docx new file mode 100644 index 00000000000..267c99f5a66 Binary files /dev/null and b/poi-ooxml/src/test/resources/bugfixing/shape in footer/document with shapes 10.docx differ diff --git a/poi-ooxml/src/test/resources/bugfixing/shape in footer/document with shapes 2.docx b/poi-ooxml/src/test/resources/bugfixing/shape in footer/document with shapes 2.docx new file mode 100644 index 00000000000..e3f98638ce2 Binary files /dev/null and b/poi-ooxml/src/test/resources/bugfixing/shape in footer/document with shapes 2.docx differ diff --git a/poi-ooxml/src/test/resources/bugfixing/shape in footer/document with shapes 3.docx b/poi-ooxml/src/test/resources/bugfixing/shape in footer/document with shapes 3.docx new file mode 100644 index 00000000000..88d64120911 Binary files /dev/null and b/poi-ooxml/src/test/resources/bugfixing/shape in footer/document with shapes 3.docx differ diff --git a/poi-ooxml/src/test/resources/bugfixing/shape in footer/document with shapes 4.docx b/poi-ooxml/src/test/resources/bugfixing/shape in footer/document with shapes 4.docx new file mode 100644 index 00000000000..c55d43d1ded Binary files /dev/null and b/poi-ooxml/src/test/resources/bugfixing/shape in footer/document with shapes 4.docx differ diff --git a/poi-ooxml/src/test/resources/bugfixing/shape in footer/document with shapes 5.docx b/poi-ooxml/src/test/resources/bugfixing/shape in footer/document with shapes 5.docx new file mode 100644 index 00000000000..168001b21bb Binary files /dev/null and b/poi-ooxml/src/test/resources/bugfixing/shape in footer/document with shapes 5.docx differ diff --git a/poi-ooxml/src/test/resources/bugfixing/shape in footer/document with shapes 6.docx b/poi-ooxml/src/test/resources/bugfixing/shape in footer/document with shapes 6.docx new file mode 100644 index 00000000000..7cdebc3efe5 Binary files /dev/null and b/poi-ooxml/src/test/resources/bugfixing/shape in footer/document with shapes 6.docx differ diff --git a/poi-ooxml/src/test/resources/bugfixing/shape in footer/document with shapes 7.docx b/poi-ooxml/src/test/resources/bugfixing/shape in footer/document with shapes 7.docx new file mode 100644 index 00000000000..b489abbc3ef Binary files /dev/null and b/poi-ooxml/src/test/resources/bugfixing/shape in footer/document with shapes 7.docx differ diff --git a/poi-ooxml/src/test/resources/bugfixing/shape in footer/document with shapes 8.docx b/poi-ooxml/src/test/resources/bugfixing/shape in footer/document with shapes 8.docx new file mode 100644 index 00000000000..8aac7b30ba0 Binary files /dev/null and b/poi-ooxml/src/test/resources/bugfixing/shape in footer/document with shapes 8.docx differ diff --git a/poi-ooxml/src/test/resources/bugfixing/shape in footer/document with shapes 9.docx b/poi-ooxml/src/test/resources/bugfixing/shape in footer/document with shapes 9.docx new file mode 100644 index 00000000000..380467ccfbc Binary files /dev/null and b/poi-ooxml/src/test/resources/bugfixing/shape in footer/document with shapes 9.docx differ diff --git a/poi-ooxml/src/test/resources/bugfixing/some image.png b/poi-ooxml/src/test/resources/bugfixing/some image.png new file mode 100644 index 00000000000..b495b1a7ed7 Binary files /dev/null and b/poi-ooxml/src/test/resources/bugfixing/some image.png differ