From c85aeaef4bce723d543cf5fc154f11816d766e65 Mon Sep 17 00:00:00 2001 From: Ivo Majic Date: Mon, 1 Jul 2024 22:59:52 +0200 Subject: [PATCH 1/2] #682 Fixed an issue with OpenPDF converter manifesting while rendering an ODT into PDF. A problematic ODT would need to have a table containing merged cells for the issue to pop up. --- .../pdf/internal/stylable/StylableTable.java | 51 +++++++++++++++++- .../core/AbstractODFDOMConverterTest.java | 7 +++ .../odfdom/converter/core/Issue682.odt | Bin 0 -> 12802 bytes 3 files changed, 56 insertions(+), 2 deletions(-) create mode 100644 thirdparties-extension/fr.opensagres.odfdom.converter.pdf.openpdf/src/test/resources/org/odftoolkit/odfdom/converter/core/Issue682.odt diff --git a/thirdparties-extension/fr.opensagres.odfdom.converter.pdf.openpdf/src/main/java/fr/opensagres/odfdom/converter/pdf/internal/stylable/StylableTable.java b/thirdparties-extension/fr.opensagres.odfdom.converter.pdf.openpdf/src/main/java/fr/opensagres/odfdom/converter/pdf/internal/stylable/StylableTable.java index 88d3f321b..243145952 100644 --- a/thirdparties-extension/fr.opensagres.odfdom.converter.pdf.openpdf/src/main/java/fr/opensagres/odfdom/converter/pdf/internal/stylable/StylableTable.java +++ b/thirdparties-extension/fr.opensagres.odfdom.converter.pdf.openpdf/src/main/java/fr/opensagres/odfdom/converter/pdf/internal/stylable/StylableTable.java @@ -26,11 +26,14 @@ import com.lowagie.text.Element; +import com.lowagie.text.pdf.PdfPCell; import fr.opensagres.odfdom.converter.pdf.internal.styles.Style; import fr.opensagres.odfdom.converter.pdf.internal.styles.StyleTableProperties; import fr.opensagres.odfdom.converter.pdf.internal.styles.StyleTableRowProperties; import fr.opensagres.xdocreport.openpdf.extension.ExtendedPdfPTable; +import java.util.Arrays; + public class StylableTable extends ExtendedPdfPTable implements IStylableContainer @@ -45,6 +48,10 @@ public class StylableTable private boolean inTableRow; + // keeps an indication of how many rows are already occupied (by row- or col-spans from the rows above) + private int[] spansFromAbove; + private int spansFromAboveIdx; + private Style currentRowStyle; public StylableTable( StylableDocument ownerDocument, IStylableContainer parent, int numColumns ) @@ -57,6 +64,10 @@ public StylableTable( StylableDocument ownerDocument, IStylableContainer parent, super.setSplitLate( false ); this.ownerDocument = ownerDocument; this.parent = parent; + + this.spansFromAbove = new int[numColumns]; + Arrays.fill(spansFromAbove, 0); + this.spansFromAboveIdx = 0; } public Style getCurrentRowStyle() @@ -74,10 +85,43 @@ public void endTableHeaderRows() inTableHeaderRows = false; } + private void fitCellIntoSpansFromAbove(PdfPCell cell) { + int rowSpan = cell.getRowspan(); + int colSpan = cell.getColspan(); + + // skip all the cell places already spanned from above + while (spansFromAbove[spansFromAboveIdx] > 0){ + if (spansFromAboveIdx < getNumberOfColumns()) { + spansFromAbove[spansFromAboveIdx]--; + spansFromAboveIdx++; + } + if (spansFromAboveIdx >= getNumberOfColumns()) { + // we have no more place in the current row; finish it up, and start a new one + endTableRow(); + beginTableRow(currentRowStyle); + } + } + + for (int col = 0; col < colSpan; col++){ + if (spansFromAbove[spansFromAboveIdx] > 0){ + break; // this is an error situation. cell spans over a cell that already has been spanned from above + } + else { + spansFromAbove[spansFromAboveIdx] = rowSpan - 1; + } + spansFromAboveIdx++; + } + } + + private boolean reachedEndOfRow(){ + return spansFromAboveIdx == getNumberOfColumns(); + } + public void beginTableRow( Style currentRowStyle ) { // beginTableRow/addElement/endTableRow protects before too many/too less cells in a row than declared inTableRow = true; + spansFromAboveIdx = 0; this.currentRowStyle = currentRowStyle; if ( inTableHeaderRows ) { @@ -89,7 +133,7 @@ public void beginTableRow( Style currentRowStyle ) public void endTableRow() { // fill row with empty cells if necessary - while ( currentRowIdx != 0 ) + while ( ! reachedEndOfRow() ) { StylableTableCell cell = new StylableTableCell( ownerDocument, this ); if ( currentRowStyle != null ) @@ -107,9 +151,12 @@ public void addElement( Element element ) { if ( inTableRow ) { + if (element instanceof PdfPCell){ + fitCellIntoSpansFromAbove ((PdfPCell) element); + } super.addElement( element ); } - if ( currentRowIdx == 0 ) + if ( reachedEndOfRow() ) { // row fully filled, end row endTableRow(); diff --git a/thirdparties-extension/fr.opensagres.odfdom.converter.pdf.openpdf/src/test/java/org/odftoolkit/odfdom/converter/core/AbstractODFDOMConverterTest.java b/thirdparties-extension/fr.opensagres.odfdom.converter.pdf.openpdf/src/test/java/org/odftoolkit/odfdom/converter/core/AbstractODFDOMConverterTest.java index dfc5812bb..5f737d568 100644 --- a/thirdparties-extension/fr.opensagres.odfdom.converter.pdf.openpdf/src/test/java/org/odftoolkit/odfdom/converter/core/AbstractODFDOMConverterTest.java +++ b/thirdparties-extension/fr.opensagres.odfdom.converter.pdf.openpdf/src/test/java/org/odftoolkit/odfdom/converter/core/AbstractODFDOMConverterTest.java @@ -125,6 +125,13 @@ public void Issue377() { doGenerate( "Issue377.odt" ); } + + @Test + public void Issue682() + throws Exception + { + doGenerate( "Issue682.odt" ); + } @Test public void ODTBig() diff --git a/thirdparties-extension/fr.opensagres.odfdom.converter.pdf.openpdf/src/test/resources/org/odftoolkit/odfdom/converter/core/Issue682.odt b/thirdparties-extension/fr.opensagres.odfdom.converter.pdf.openpdf/src/test/resources/org/odftoolkit/odfdom/converter/core/Issue682.odt new file mode 100644 index 0000000000000000000000000000000000000000..aec42193ebd418c61597c63ac6148e5cc6208349 GIT binary patch literal 12802 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 literal 0 HcmV?d00001 From de938b7762ec35499b214be956dee35d40ae3bb2 Mon Sep 17 00:00:00 2001 From: Ivo Majic Date: Wed, 3 Jul 2024 10:57:55 +0200 Subject: [PATCH 2/2] #682 Fixed a bug in the previous solution. --- .../pdf/internal/stylable/StylableTable.java | 11 ++++++++--- .../odfdom/converter/core/Issue682.odt | Bin 12802 -> 13670 bytes 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/thirdparties-extension/fr.opensagres.odfdom.converter.pdf.openpdf/src/main/java/fr/opensagres/odfdom/converter/pdf/internal/stylable/StylableTable.java b/thirdparties-extension/fr.opensagres.odfdom.converter.pdf.openpdf/src/main/java/fr/opensagres/odfdom/converter/pdf/internal/stylable/StylableTable.java index 243145952..d97687d79 100644 --- a/thirdparties-extension/fr.opensagres.odfdom.converter.pdf.openpdf/src/main/java/fr/opensagres/odfdom/converter/pdf/internal/stylable/StylableTable.java +++ b/thirdparties-extension/fr.opensagres.odfdom.converter.pdf.openpdf/src/main/java/fr/opensagres/odfdom/converter/pdf/internal/stylable/StylableTable.java @@ -33,6 +33,7 @@ import fr.opensagres.xdocreport.openpdf.extension.ExtendedPdfPTable; import java.util.Arrays; +import java.util.stream.IntStream; public class StylableTable extends ExtendedPdfPTable @@ -90,8 +91,8 @@ private void fitCellIntoSpansFromAbove(PdfPCell cell) { int colSpan = cell.getColspan(); // skip all the cell places already spanned from above - while (spansFromAbove[spansFromAboveIdx] > 0){ - if (spansFromAboveIdx < getNumberOfColumns()) { + do { + if (spansFromAboveIdx < getNumberOfColumns() && spansFromAbove[spansFromAboveIdx] > 0) { spansFromAbove[spansFromAboveIdx]--; spansFromAboveIdx++; } @@ -101,6 +102,7 @@ private void fitCellIntoSpansFromAbove(PdfPCell cell) { beginTableRow(currentRowStyle); } } + while (spansFromAbove[spansFromAboveIdx] > 0); for (int col = 0; col < colSpan; col++){ if (spansFromAbove[spansFromAboveIdx] > 0){ @@ -114,7 +116,10 @@ private void fitCellIntoSpansFromAbove(PdfPCell cell) { } private boolean reachedEndOfRow(){ - return spansFromAboveIdx == getNumberOfColumns(); + return spansFromAboveIdx == getNumberOfColumns() + // we might reach end of row by not yet reaching getNumberOfColumns() with spansFromAboveIdx, but in that + // case all the remaining columns in the row have to be spanned from above + || IntStream.range(spansFromAboveIdx, getNumberOfColumns()).noneMatch(idx -> spansFromAbove[idx] == 0); } public void beginTableRow( Style currentRowStyle ) diff --git a/thirdparties-extension/fr.opensagres.odfdom.converter.pdf.openpdf/src/test/resources/org/odftoolkit/odfdom/converter/core/Issue682.odt b/thirdparties-extension/fr.opensagres.odfdom.converter.pdf.openpdf/src/test/resources/org/odftoolkit/odfdom/converter/core/Issue682.odt index aec42193ebd418c61597c63ac6148e5cc6208349..87fd77b3632b443b6d23332c7a2ea3dd22ed03f8 100644 GIT binary patch delta 11180 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 delta 10200 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