From d5614b7548291102367b30b7652d938655437d7e Mon Sep 17 00:00:00 2001 From: Jorge Diaz Date: Thu, 20 Nov 2025 21:48:16 -0500 Subject: [PATCH 1/5] removed sign artifact plugin --- pom.xml | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/pom.xml b/pom.xml index 1f7bea9ad..90cf5ebbd 100644 --- a/pom.xml +++ b/pom.xml @@ -308,20 +308,6 @@ ${maven-repository-plugin.version} - - org.apache.maven.plugins - maven-gpg-plugin - ${maven-gpg-plugin.version} - - - sign-artifacts - verify - - sign - - - - org.sonatype.plugins nexus-staging-maven-plugin From d7f8d1806139b56bf3e32bb0f923db2b09b2acbd Mon Sep 17 00:00:00 2001 From: aminamani83 Date: Thu, 20 Nov 2025 22:11:13 -0500 Subject: [PATCH 2/5] Before Starting Refactoring --- openpdf/src/main/java/com/lowagie/text/pdf/PdfDocument.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openpdf/src/main/java/com/lowagie/text/pdf/PdfDocument.java b/openpdf/src/main/java/com/lowagie/text/pdf/PdfDocument.java index b3274956f..768b18127 100644 --- a/openpdf/src/main/java/com/lowagie/text/pdf/PdfDocument.java +++ b/openpdf/src/main/java/com/lowagie/text/pdf/PdfDocument.java @@ -407,6 +407,8 @@ void setLeading(float leading) { /** The current active PdfAction when processing an Anchor. */ protected PdfAction anchorAction = null; + // We are going to apply Refactoring Here + /** * Signals that an Element was added to the Document. * From d17aafb01f0c274dbb9904793dddeef6cffabe9e Mon Sep 17 00:00:00 2001 From: Joshua Onyema Date: Sun, 23 Nov 2025 01:24:59 -0500 Subject: [PATCH 3/5] Restored changes --- .../java/com/lowagie/text/HeaderFooter.java | 271 ++- .../main/java/com/lowagie/text/Rectangle.java | 1793 +++++++++-------- .../com/lowagie/text/pdf/PdfDocument.java | 257 ++- .../com/lowagie/text/FooterTableTest.java | 58 + .../com/lowagie/text/pdf/FooterImageTest.java | 140 ++ .../src/test/resources/GitHub-Mark-32px.png | Bin 0 -> 1714 bytes 6 files changed, 1471 insertions(+), 1048 deletions(-) create mode 100644 openpdf/src/test/java/com/lowagie/text/FooterTableTest.java create mode 100644 openpdf/src/test/java/com/lowagie/text/pdf/FooterImageTest.java create mode 100644 openpdf/src/test/resources/GitHub-Mark-32px.png diff --git a/openpdf/src/main/java/com/lowagie/text/HeaderFooter.java b/openpdf/src/main/java/com/lowagie/text/HeaderFooter.java index 5b4e8b181..9faa5d805 100644 --- a/openpdf/src/main/java/com/lowagie/text/HeaderFooter.java +++ b/openpdf/src/main/java/com/lowagie/text/HeaderFooter.java @@ -49,81 +49,105 @@ package com.lowagie.text; +import java.util.ArrayList; +import java.util.List; + +import com.lowagie.text.pdf.PdfPTable; /** - * A HeaderFooter-object is a Rectangle with text - * that can be put above and/or below every page. - *

- * Example: - *

+ * A HeaderFooter-object is a Rectangle with text that can be put above and/or below every
+ * page.
+ * 

+ * Example:

+ * + *
  * HeaderFooter header = new HeaderFooter(new Phrase("This is a header."), false);
  * HeaderFooter footer = new HeaderFooter(new Phrase("This is page "), new Phrase("."));
  * document.setHeader(header);
  * document.setFooter(footer);
- * 
+ *
+ * + *
*/ public class HeaderFooter extends Rectangle { - + // membervariables - -/** Does the page contain a pagenumber? */ + + /** + * Does the page contain a pagenumber? + */ private boolean numbered; - -/** This is the Phrase that comes before the pagenumber. */ + + /** + * This is the Phrase that comes before the pagenumber. + */ private Phrase before = null; - -/** This is number of the page. */ + + /** + * This is number of the page. + */ private int pageN; - -/** This is the Phrase that comes after the pagenumber. */ + + /** + * This is the Phrase that comes after the pagenumber. + */ private Phrase after = null; - -/** This is alignment of the header/footer. */ + + /** + * This is alignment of the header/footer. + */ private int alignment; - + + /** + * This is the List containing non-text Element. + */ + private java.util.List specialContent = null; + + /** + * This is the padding of height of header/footer. + */ + private float padding; + // constructors - -/** - * Constructs a HeaderFooter-object. - * - * @param before the Phrase before the pagenumber - * @param after the Phrase before the pagenumber - */ - + + /** + * Constructs a HeaderFooter-object. + * + * @param before the Phrase before the pagenumber + * @param after the Phrase before the pagenumber + */ public HeaderFooter(Phrase before, Phrase after) { super(0, 0, 0, 0); setBorder(TOP + BOTTOM); setBorderWidth(1); - + numbered = true; this.before = before; this.after = after; } - -/** - * Constructs a Header-object with a pagenumber at the end. - * - * @param before the Phrase before the pagenumber - * @param numbered page will be numbered if true - */ - + + /** + * Constructs a Header-object with a pagenumber at the end. + * + * @param before the Phrase before the pagenumber + * @param numbered page will be numbered if true + */ public HeaderFooter(Phrase before, boolean numbered) { super(0, 0, 0, 0); setBorder(TOP + BOTTOM); setBorderWidth(1); - + this.numbered = numbered; this.before = before; } -/** - * Constructs a Header-object with a pagenumber at the beginning. - * - * @param numbered page will be numbered if true - * @param after the Phrase after the pagenumber - */ - + /** + * Constructs a Header-object with a pagenumber at the beginning. + * + * @param numbered page will be numbered if true + * @param after the Phrase after the pagenumber + */ public HeaderFooter(boolean numbered, Phrase after) { super(0, 0, 0, 0); setBorder(TOP + BOTTOM); @@ -133,82 +157,133 @@ public HeaderFooter(boolean numbered, Phrase after) { this.after = after; } -/** - * Constructs a Header-object with only a pagenumber. - * - * @param numbered true if the page has to be numbered - */ - + /** + * Constructs a Header-object with only a pagenumber. + * + * @param numbered true if the page has to be numbered + */ public HeaderFooter(boolean numbered) { this(null, true); this.numbered = numbered; } // methods - -/** - * Checks if the HeaderFooter contains a page number. - * - * @return true if the page has to be numbered - */ - + + /** + * Checks if the HeaderFooter contains a page number. + * + * @return true if the page has to be numbered + */ public boolean isNumbered() { return numbered; } - -/** - * Gets the part that comes before the pageNumber. - * - * @return a Phrase - */ - + + /** + * Gets the part that comes before the pageNumber. + * + * @return a Phrase + */ public Phrase getBefore() { return before; } - -/** - * Gets the part that comes after the pageNumber. - * - * @return a Phrase - */ - + + /** + * Gets the part that comes after the pageNumber. + * + * @return a Phrase + */ public Phrase getAfter() { return after; } - -/** - * Sets the page number. - * - * @param pageN the new page number - */ - + + /** + * Sets the page number. + * + * @param pageN the new page number + */ public void setPageNumber(int pageN) { this.pageN = pageN; } - -/** - * Sets the alignment. - * - * @param alignment the new alignment - */ - + + /** + * Sets the alignment. + * + * @param alignment the new alignment + */ public void setAlignment(int alignment) { this.alignment = alignment; } + /** + * Gets padding of height of header/footer. + * + * @return the padding of height + */ + public float getPadding() { + return padding; + } + + /** + * Sets padding of height of header/footer. + * + * @param padding the new padding of height + */ + public void setPadding(float padding) { + this.padding = padding; + } + + /** + * Increases current padding by adding new value into it + * + * @param augment the new value + */ + public void addPadding(float augment) { + padding += augment; + } + + /** + * Adds non-text Element into specialContent + * + * @param element the new non-text Element + */ + public void addSpecialContent(Element element) { + if (specialContent == null) { + specialContent = new ArrayList<>(); + } + specialContent.add(element); + } + + /** + * Gets specialContent + * + * @return specialContent + */ + public List getSpecialContent() { + return specialContent; + } + // methods to retrieve the membervariables - -/** - * Gets the Paragraph that can be used as header or footer. - * - * @return a Paragraph - */ - + + /** + * Gets the Paragraph that can be used as header or footer. + * + * @return a Paragraph + */ public Paragraph paragraph() { Paragraph paragraph; + if (before != null) { paragraph = new Paragraph(before.getLeading()); paragraph.add(before); + + // Adding a Paragraph to another Paraghraph adds a newline that needs to be removed in headers and footers + if (before instanceof Paragraph + && + paragraph.size() >= 2 + && + "\n".equals(paragraph.get(paragraph.size() - 1).toString())) { + paragraph.remove(paragraph.size() - 1); + } } else { paragraph = new Paragraph(); } @@ -221,10 +296,13 @@ public Paragraph paragraph() { paragraph.addSpecial(new Chunk(String.valueOf(pageN))); } } + if (after != null) { paragraph.addSpecial(after); } + paragraph.setAlignment(alignment); + return paragraph; } @@ -232,6 +310,7 @@ private Font getFont() { if (before != null) { return before.getFont(); } + if (after != null) { return after.getFont(); } @@ -242,11 +321,9 @@ private Font getFont() { /** * Gets the alignment of this HeaderFooter. * - * @return alignment + * @return alignment */ - - public int alignment() { - return alignment; - } - + public int alignment() { + return alignment; + } } \ No newline at end of file diff --git a/openpdf/src/main/java/com/lowagie/text/Rectangle.java b/openpdf/src/main/java/com/lowagie/text/Rectangle.java index c1238d0af..19651ad21 100644 --- a/openpdf/src/main/java/com/lowagie/text/Rectangle.java +++ b/openpdf/src/main/java/com/lowagie/text/Rectangle.java @@ -55,13 +55,13 @@ /** * A Rectangle is the representation of a geometric figure. - * + * * Rectangles support constant width borders using * {@link #setBorderWidth(float)}and {@link #setBorder(int)}. They also support * borders that vary in width/color on each side using methods like * {@link #setBorderWidthLeft(float)}or * {@link #setBorderColorLeft(java.awt.Color)}. - * + * * @see Element * @see Table * @see Cell @@ -69,904 +69,913 @@ */ public class Rectangle implements Element { - // CONSTANTS: + // CONSTANTS: + + /** This is the value that will be used as undefined . */ + public static final int UNDEFINED = -1; + + /** This represents one side of the border of the Rectangle. */ + public static final int TOP = 1; + + /** This represents one side of the border of the Rectangle. */ + public static final int BOTTOM = 2; + + /** This represents one side of the border of the Rectangle. */ + public static final int LEFT = 4; + + /** This represents one side of the border of the Rectangle. */ + public static final int RIGHT = 8; + + /** This represents a rectangle without borders. */ + public static final int NO_BORDER = 0; + + /** This represents a type of border. */ + public static final int BOX = TOP + BOTTOM + LEFT + RIGHT; + + // MEMBER VARIABLES: + + /** the lower left x-coordinate. */ + protected float llx; + + /** the lower left y-coordinate. */ + protected float lly; + + /** the upper right x-coordinate. */ + protected float urx; + + /** the upper right y-coordinate. */ + protected float ury; + + protected float ruy; + + /** The rotation of the Rectangle */ + protected int rotation = 0; + + /** This is the color of the background of this rectangle. */ + protected Color backgroundColor = null; + + /** This represents the status of the 4 sides of the rectangle. */ + protected int border = UNDEFINED; + + /** Whether variable width/color borders are used. */ + protected boolean useVariableBorders = false; + + /** This is the width of the border around this rectangle. */ + protected float borderWidth = UNDEFINED; + + /** The width of the left border of this rectangle. */ + protected float borderWidthLeft = UNDEFINED; + + /** The width of the right border of this rectangle. */ + protected float borderWidthRight = UNDEFINED; + + /** The width of the top border of this rectangle. */ + protected float borderWidthTop = UNDEFINED; + + /** The width of the bottom border of this rectangle. */ + protected float borderWidthBottom = UNDEFINED; + + /** The color of the border of this rectangle. */ + protected Color borderColor = null; + + /** The color of the left border of this rectangle. */ + protected Color borderColorLeft = null; + + /** The color of the right border of this rectangle. */ + protected Color borderColorRight = null; + + /** The color of the top border of this rectangle. */ + protected Color borderColorTop = null; + + /** The color of the bottom border of this rectangle. */ + protected Color borderColorBottom = null; + + // CONSTRUCTORS: + + /** + * Constructs a Rectangle -object. + * + * @param llx + * lower left x + * @param lly + * lower left y + * @param urx + * upper right x + * @param ury + * upper right y + */ + public Rectangle(float llx, float lly, float urx, float ury) { + this.llx = llx; + this.lly = lly; + this.urx = urx; + this.ury = ury; + } + + /** + * Constructs a Rectangle -object starting from the origin (0, + * 0). + * + * @param urx + * upper right x + * @param ury + * upper right y + */ + public Rectangle(float urx, float ury) { + this(0, 0, urx, ury); + } + + // OJO... Modificacion de + // flopez------------------------------------------------- + /** + * Constructs a Rectangle -object. + * + * @param llx + * lower left x + * @param lly + * lower left y + * @param urx + * upper right x + * @param ury + * upper right y + * @param rotation + * 0, 90, 180, or 270 grades + */ + public Rectangle(float llx, float lly, float urx, float ury, int rotation) { + this(llx, lly, urx, ury); + setRotation(rotation); + } + + /** + * Constructs a Rectangle -object starting from the origin (0, + * 0). + * + * @param urx + * upper right x + * @param ury + * upper right y + * @param rotation + * 0, 90, 180, or 270 grades + */ + public Rectangle(float urx, float ury, int rotation) { + this(0, 0, urx, ury); + setRotation(rotation); + } + + /** + * Sets the rotation of the rectangle. Valid values are 0, 90, 180, and 270. + * + * @param rotation + * the new rotation value + * @since iText 5.0.6 + */ + public void setRotation(final int rotation) { + int mod = rotation % 360; + if ((mod == 90) || (mod == 180) || (mod == 270)) { + this.rotation = mod; + } else { + this.rotation = 0; + } + } + + // ****************************************************************************** + + /** + * Constructs a Rectangle -object. + * + * @param rect + * another Rectangle + */ + public Rectangle(Rectangle rect) { + this(rect.llx, rect.lly, rect.urx, rect.ury); + cloneNonPositionParameters(rect); + } - /** This is the value that will be used as undefined . */ - public static final int UNDEFINED = -1; + // IMPLEMENTATION OF THE ELEMENT INTERFACE:e + + /** + * Processes the element by adding it (or the different parts) to an + * ElementListener. + * + * @param listener + * an ElementListener + * @return true if the element was processed successfully + */ + @Override + public boolean process(ElementListener listener) { + try { + return listener.add(this); + } catch (DocumentException de) { + return false; + } + } - /** This represents one side of the border of the Rectangle. */ - public static final int TOP = 1; + /** + * Gets the type of the text element. + * + * @return a type + */ + @Override + public int type() { + return Element.RECTANGLE; + } - /** This represents one side of the border of the Rectangle. */ - public static final int BOTTOM = 2; + /** + * Gets all the chunks in this element. + * + * @return an ArrayList + */ + @Override + public ArrayList getChunks() { + return new ArrayList<>(); + } - /** This represents one side of the border of the Rectangle. */ - public static final int LEFT = 4; + /** + * @see com.lowagie.text.Element#isContent() + * @since iText 2.0.8 + */ + @Override + public boolean isContent() { + return true; + } - /** This represents one side of the border of the Rectangle. */ - public static final int RIGHT = 8; + /** + * @see com.lowagie.text.Element#isNestable() + * @since iText 2.0.8 + */ + @Override + public boolean isNestable() { + return false; + } - /** This represents a rectangle without borders. */ - public static final int NO_BORDER = 0; + // METHODS TO GET/SET THE DIMENSIONS: - /** This represents a type of border. */ - public static final int BOX = TOP + BOTTOM + LEFT + RIGHT; + /** + * Sets the lower left x-coordinate. + * + * @param llx + * the new value + */ + public void setLeft(float llx) { + this.llx = llx; + } - // MEMBER VARIABLES: + /** + * Returns the lower left x-coordinate. + * + * @return the lower left x-coordinate + */ + public float getLeft() { + return llx; + } - /** the lower left x-coordinate. */ - protected float llx; - - /** the lower left y-coordinate. */ - protected float lly; - - /** the upper right x-coordinate. */ - protected float urx; - - /** the upper right y-coordinate. */ - protected float ury; - - /** The rotation of the Rectangle */ - protected int rotation = 0; - - /** This is the color of the background of this rectangle. */ - protected Color backgroundColor = null; - - /** This represents the status of the 4 sides of the rectangle. */ - protected int border = UNDEFINED; - - /** Whether variable width/color borders are used. */ - protected boolean useVariableBorders = false; - - /** This is the width of the border around this rectangle. */ - protected float borderWidth = UNDEFINED; - - /** The width of the left border of this rectangle. */ - protected float borderWidthLeft = UNDEFINED; - - /** The width of the right border of this rectangle. */ - protected float borderWidthRight = UNDEFINED; - - /** The width of the top border of this rectangle. */ - protected float borderWidthTop = UNDEFINED; - - /** The width of the bottom border of this rectangle. */ - protected float borderWidthBottom = UNDEFINED; - - /** The color of the border of this rectangle. */ - protected Color borderColor = null; - - /** The color of the left border of this rectangle. */ - protected Color borderColorLeft = null; - - /** The color of the right border of this rectangle. */ - protected Color borderColorRight = null; - - /** The color of the top border of this rectangle. */ - protected Color borderColorTop = null; - - /** The color of the bottom border of this rectangle. */ - protected Color borderColorBottom = null; - - // CONSTRUCTORS: - - /** - * Constructs a Rectangle -object. - * - * @param llx - * lower left x - * @param lly - * lower left y - * @param urx - * upper right x - * @param ury - * upper right y - */ - public Rectangle(float llx, float lly, float urx, float ury) { - this.llx = llx; - this.lly = lly; - this.urx = urx; - this.ury = ury; - } - - /** - * Constructs a Rectangle -object starting from the origin (0, - * 0). - * - * @param urx - * upper right x - * @param ury - * upper right y - */ - public Rectangle(float urx, float ury) { - this(0, 0, urx, ury); - } - - // OJO... Modificacion de - // flopez------------------------------------------------- - /** - * Constructs a Rectangle -object. - * - * @param llx - * lower left x - * @param lly - * lower left y - * @param urx - * upper right x - * @param ury - * upper right y - * @param rotation - * 0, 90, 180, or 270 grades - */ - public Rectangle(float llx, float lly, float urx, float ury, int rotation) { - this(llx, lly, urx, ury); - setRotation(rotation); - } - - /** - * Constructs a Rectangle -object starting from the origin (0, - * 0). - * - * @param urx - * upper right x - * @param ury - * upper right y - * @param rotation - * 0, 90, 180, or 270 grades - */ - public Rectangle(float urx, float ury, int rotation) { - this(0, 0, urx, ury); - setRotation(rotation); - } - - /** - * Sets the rotation of the rectangle. Valid values are 0, 90, 180, and 270. - * - * @param rotation - * the new rotation value - * @since iText 5.0.6 - */ - public void setRotation(final int rotation) { - int mod = rotation % 360; - if ((mod == 90) || (mod == 180) || (mod == 270)) { - this.rotation = mod; - } else { - this.rotation = 0; - } - } - - // ****************************************************************************** - - /** - * Constructs a Rectangle -object. - * - * @param rect - * another Rectangle - */ - public Rectangle(Rectangle rect) { - this(rect.llx, rect.lly, rect.urx, rect.ury); - cloneNonPositionParameters(rect); - } - - // IMPLEMENTATION OF THE ELEMENT INTERFACE:e - - /** - * Processes the element by adding it (or the different parts) to an - * ElementListener. - * - * @param listener - * an ElementListener - * @return true if the element was processed successfully - */ - @Override - public boolean process(ElementListener listener) { - try { - return listener.add(this); - } catch (DocumentException de) { - return false; - } - } - - /** - * Gets the type of the text element. - * - * @return a type - */ - @Override - public int type() { - return Element.RECTANGLE; - } - - /** - * Gets all the chunks in this element. - * - * @return an ArrayList - */ - @Override - public ArrayList getChunks() { - return new ArrayList<>(); - } - - /** - * @see com.lowagie.text.Element#isContent() - * @since iText 2.0.8 - */ - @Override - public boolean isContent() { - return true; - } - - /** - * @see com.lowagie.text.Element#isNestable() - * @since iText 2.0.8 - */ - @Override - public boolean isNestable() { - return false; - } - - // METHODS TO GET/SET THE DIMENSIONS: - - /** - * Sets the lower left x-coordinate. - * - * @param llx - * the new value - */ - public void setLeft(float llx) { - this.llx = llx; - } - - /** - * Returns the lower left x-coordinate. - * - * @return the lower left x-coordinate - */ - public float getLeft() { - return llx; - } - - /** - * Returns the lower left x-coordinate, considering a given margin. - * - * @param margin - * a margin - * @return the lower left x-coordinate - */ - public float getLeft(float margin) { - return llx + margin; - } - - /** - * Sets the upper right x-coordinate. - * - * @param urx - * the new value - */ - public void setRight(float urx) { - this.urx = urx; - } - - /** - * Returns the upper right x-coordinate. - * - * @return the upper right x-coordinate - */ - public float getRight() { - return urx; - } - - /** - * Returns the upper right x-coordinate, considering a given margin. - * - * @param margin - * a margin - * @return the upper right x-coordinate - */ - public float getRight(float margin) { - return urx - margin; - } - - /** - * Returns the width of the rectangle. - * - * @return the width - */ - public float getWidth() { - return urx - llx; - } - - /** - * Sets the upper right y-coordinate. - * - * @param ury - * the new value - */ - public void setTop(float ury) { - this.ury = ury; - } - - /** - * Returns the upper right y-coordinate. - * - * @return the upper right y-coordinate - */ - public float getTop() { - return ury; - } - - /** - * Returns the upper right y-coordinate, considering a given margin. - * - * @param margin - * a margin - * @return the upper right y-coordinate - */ - public float getTop(float margin) { - return ury - margin; - } - - /** - * Sets the lower left y-coordinate. - * - * @param lly - * the new value - */ - public void setBottom(float lly) { - this.lly = lly; - } - - /** - * Returns the lower left y-coordinate. - * - * @return the lower left y-coordinate - */ - public float getBottom() { - return lly; - } - - /** - * Returns the lower left y-coordinate, considering a given margin. - * - * @param margin - * a margin - * @return the lower left y-coordinate - */ - public float getBottom(float margin) { - return lly + margin; - } - - /** - * Returns the height of the rectangle. - * - * @return the height - */ - public float getHeight() { - return ury - lly; - } - - /** - * Normalizes the rectangle. Switches lower left with upper right if - * necessary. - */ - public void normalize() { - if (llx > urx) { - float a = llx; - llx = urx; - urx = a; - } - if (lly > ury) { - float a = lly; - lly = ury; - ury = a; - } - } - - // METHODS TO GET/SET THE ROTATION: - - /** - * Gets the rotation of the rectangle - * - * @return a rotation value - */ - public int getRotation() { - return rotation; - } - - /** - * Rotates the rectangle. Swaps the values of llx and lly and of urx and ury. - * - * @return the rotated Rectangle - */ - public Rectangle rotate() { - Rectangle rect = new Rectangle(lly, llx, ury, urx); - rect.rotation = rotation + 90; - rect.rotation %= 360; - return rect; - } - - // METHODS TO GET/SET THE BACKGROUND COLOR: - - /** - * Gets the backgroundcolor. - * - * @return a Color - */ - public Color getBackgroundColor() { - return backgroundColor; - } - - /** - * Sets the backgroundcolor of the rectangle. - * - * @param backgroundColor - * a Color - */ - - public void setBackgroundColor(Color backgroundColor) { - this.backgroundColor = backgroundColor; - } - - /** - * Gets the grayscale. - * - * @return the grayscale color of the background or 0 if the background has no - * grayscale color. - */ - public float getGrayFill() { - if (backgroundColor instanceof GrayColor) - return ((GrayColor) backgroundColor).getGray(); - return 0; - } - - /** - * Sets the the background color to a grayscale value. - * - * @param value - * the new grayscale value - */ - public void setGrayFill(float value) { - backgroundColor = new GrayColor(value); - } - - // METHODS TO GET/SET THE BORDER: - - /** - * Returns the exact type of the border. - * - * @return a value - */ - public int getBorder() { - return border; - } - - /** - * Indicates whether some type of border is set. - * - * @return a boolean - */ - public boolean hasBorders() { - switch (border) { - case UNDEFINED: - case NO_BORDER: - return false; - default: - return borderWidth > 0 || borderWidthLeft > 0 || borderWidthRight > 0 - || borderWidthTop > 0 || borderWidthBottom > 0; - } - } - - /** - * Indicates whether the specified type of border is set. - * - * @param type - * the type of border - * @return a boolean - */ - public boolean hasBorder(int type) { - if (border == UNDEFINED) - return false; - return (border & type) == type; - } - - /** - * Enables/Disables the border on the specified sides. The border is specified - * as an integer bitwise combination of the constants: - * LEFT, RIGHT, TOP, BOTTOM. - * - * @see #enableBorderSide(int) - * @see #disableBorderSide(int) - * @param border - * the new value - */ - public void setBorder(int border) { - this.border = border; - } - - /** - * Indicates whether variable width borders are being used. Returns true if - * setBorderWidthLeft, setBorderWidthRight, - * setBorderWidthTop, or setBorderWidthBottom has been called. - * - * @return true if variable width borders are in use - */ - public boolean isUseVariableBorders() { - return useVariableBorders; - } - - /** - * Sets a parameter indicating if the rectangle has variable borders - * - * @param useVariableBorders - * indication if the rectangle has variable borders - */ - public void setUseVariableBorders(boolean useVariableBorders) { - this.useVariableBorders = useVariableBorders; - } - - /** - * Enables the border on the specified side. - * - * @param side - * the side to enable. One of LEFT, RIGHT, TOP, BOTTOM - */ - public void enableBorderSide(int side) { - if (border == UNDEFINED) - border = 0; - border |= side; - } - - /** - * Disables the border on the specified side. - * - * @param side - * the side to disable. One of LEFT, RIGHT, TOP, BOTTOM - */ - public void disableBorderSide(int side) { - if (border == UNDEFINED) - border = 0; - border &= ~side; - } - - // METHODS TO GET/SET THE BORDER WIDTH: - - /** - * Gets the borderwidth. - * - * @return a value - */ - public float getBorderWidth() { - return borderWidth; - } - - /** - * Sets the borderwidth of the table. - * - * @param borderWidth - * the new value - */ - public void setBorderWidth(float borderWidth) { - this.borderWidth = borderWidth; - } - - /** - * Helper function returning the border width of a specific side. - * - * @param variableWidthValue - * a variable width (could be undefined) - * @param side - * the border you want to check - * @return the variableWidthValue if not undefined, otherwise the borderWidth - */ - private float getVariableBorderWidth(float variableWidthValue, int side) { - if ((border & side) != 0) - return variableWidthValue != UNDEFINED ? variableWidthValue : borderWidth; - return 0; - } - - /** - * Helper function updating the border flag for a side based on the specified - * width. A width of 0 will disable the border on that side. Any other width - * enables it. - * - * @param width - * width of border - * @param side - * border side constant - */ - private void updateBorderBasedOnWidth(float width, int side) { - useVariableBorders = true; - if (width > 0) - enableBorderSide(side); - else - disableBorderSide(side); - } - - /** - * Gets the width of the left border. - * - * @return a width - */ - public float getBorderWidthLeft() { - return getVariableBorderWidth(borderWidthLeft, LEFT); - } - - /** - * Sets the width of the left border. - * - * @param borderWidthLeft - * a width - */ - public void setBorderWidthLeft(float borderWidthLeft) { - this.borderWidthLeft = borderWidthLeft; - updateBorderBasedOnWidth(borderWidthLeft, LEFT); - } - - /** - * Gets the width of the right border. - * - * @return a width - */ - public float getBorderWidthRight() { - return getVariableBorderWidth(borderWidthRight, RIGHT); - } - - /** - * Sets the width of the right border. - * - * @param borderWidthRight - * a width - */ - public void setBorderWidthRight(float borderWidthRight) { - this.borderWidthRight = borderWidthRight; - updateBorderBasedOnWidth(borderWidthRight, RIGHT); - } - - /** - * Gets the width of the top border. - * - * @return a width - */ - public float getBorderWidthTop() { - return getVariableBorderWidth(borderWidthTop, TOP); - } - - /** - * Sets the width of the top border. - * - * @param borderWidthTop - * a width - */ - public void setBorderWidthTop(float borderWidthTop) { - this.borderWidthTop = borderWidthTop; - updateBorderBasedOnWidth(borderWidthTop, TOP); - } - - /** - * Gets the width of the bottom border. - * - * @return a width - */ - public float getBorderWidthBottom() { - return getVariableBorderWidth(borderWidthBottom, BOTTOM); - } - - /** - * Sets the width of the bottom border. - * - * @param borderWidthBottom - * a width - */ - public void setBorderWidthBottom(float borderWidthBottom) { - this.borderWidthBottom = borderWidthBottom; - updateBorderBasedOnWidth(borderWidthBottom, BOTTOM); - } - - // METHODS TO GET/SET THE BORDER COLOR: - - /** - * Gets the color of the border. - * - * @return a Color - */ - public Color getBorderColor() { - return borderColor; - } - - /** - * Sets the color of the border. - * - * @param borderColor - * a Color - */ - public void setBorderColor(Color borderColor) { - this.borderColor = borderColor; - } - - /** - * Gets the color of the left border. - * - * @return a Color - */ - public Color getBorderColorLeft() { - if (borderColorLeft == null) - return borderColor; - return borderColorLeft; - } - - /** - * Sets the color of the left border. - * - * @param borderColorLeft - * a Color - */ - public void setBorderColorLeft(Color borderColorLeft) { - this.borderColorLeft = borderColorLeft; - } - - /** - * Gets the color of the right border. - * - * @return a Color - */ - public Color getBorderColorRight() { - if (borderColorRight == null) - return borderColor; - return borderColorRight; - } - - /** - * Sets the color of the right border. - * - * @param borderColorRight - * a Color - */ - public void setBorderColorRight(Color borderColorRight) { - this.borderColorRight = borderColorRight; - } - - /** - * Gets the color of the top border. - * - * @return a Color - */ - public Color getBorderColorTop() { - if (borderColorTop == null) - return borderColor; - return borderColorTop; - } - - /** - * Sets the color of the top border. - * - * @param borderColorTop - * a Color - */ - public void setBorderColorTop(Color borderColorTop) { - this.borderColorTop = borderColorTop; - } - - /** - * Gets the color of the bottom border. - * - * @return a Color - */ - public Color getBorderColorBottom() { - if (borderColorBottom == null) - return borderColor; - return borderColorBottom; - } - - /** - * Sets the color of the bottom border. - * - * @param borderColorBottom - * a Color - */ - public void setBorderColorBottom(Color borderColorBottom) { - this.borderColorBottom = borderColorBottom; - } - - // SPECIAL METHODS: - - /** - * Gets a Rectangle that is altered to fit on the page. - * - * @param top - * the top position - * @param bottom - * the bottom position - * @return a Rectangle - */ - public Rectangle rectangle(float top, float bottom) { - Rectangle tmp = new Rectangle(this); - if (getTop() > top) { - tmp.setTop(top); - tmp.disableBorderSide(TOP); - } - if (getBottom() < bottom) { - tmp.setBottom(bottom); - tmp.disableBorderSide(BOTTOM); - } - return tmp; - } - - /** - * Copies each of the parameters, except the position, from a - * Rectangle object - * - * @param rect - * Rectangle to copy from - */ - public void cloneNonPositionParameters(Rectangle rect) { - this.rotation = rect.rotation; - this.backgroundColor = rect.backgroundColor; - this.border = rect.border; - this.useVariableBorders = rect.useVariableBorders; - this.borderWidth = rect.borderWidth; - this.borderWidthLeft = rect.borderWidthLeft; - this.borderWidthRight = rect.borderWidthRight; - this.borderWidthTop = rect.borderWidthTop; - this.borderWidthBottom = rect.borderWidthBottom; - this.borderColor = rect.borderColor; - this.borderColorLeft = rect.borderColorLeft; - this.borderColorRight = rect.borderColorRight; - this.borderColorTop = rect.borderColorTop; - this.borderColorBottom = rect.borderColorBottom; - } - - /** - * Copies each of the parameters, except the position, from a - * Rectangle object if the value is set there - * - * @param rect - * Rectangle to copy from - */ - public void softCloneNonPositionParameters(Rectangle rect) { - if (rect.rotation != 0) - this.rotation = rect.rotation; - if (rect.backgroundColor != null) - this.backgroundColor = rect.backgroundColor; - if (rect.border != UNDEFINED) - this.border = rect.border; - if (useVariableBorders) - this.useVariableBorders = rect.useVariableBorders; - if (rect.borderWidth != UNDEFINED) - this.borderWidth = rect.borderWidth; - if (rect.borderWidthLeft != UNDEFINED) - this.borderWidthLeft = rect.borderWidthLeft; - if (rect.borderWidthRight != UNDEFINED) - this.borderWidthRight = rect.borderWidthRight; - if (rect.borderWidthTop != UNDEFINED) - this.borderWidthTop = rect.borderWidthTop; - if (rect.borderWidthBottom != UNDEFINED) - this.borderWidthBottom = rect.borderWidthBottom; - if (rect.borderColor != null) - this.borderColor = rect.borderColor; - if (rect.borderColorLeft != null) - this.borderColorLeft = rect.borderColorLeft; - if (rect.borderColorRight != null) - this.borderColorRight = rect.borderColorRight; - if (rect.borderColorTop != null) - this.borderColorTop = rect.borderColorTop; - if (rect.borderColorBottom != null) - this.borderColorBottom = rect.borderColorBottom; - } - - /** - * @return a String representation of the rectangle - * @see java.lang.Object#toString() - */ - @Override - public String toString() { - StringBuilder buf = new StringBuilder("Rectangle: "); - buf.append(getWidth()); - buf.append('x'); - buf.append(getHeight()); - buf.append(" (rot: "); - buf.append(rotation); - buf.append(" degrees)"); - return buf.toString(); - } + /** + * Returns the lower left x-coordinate, considering a given margin. + * + * @param margin + * a margin + * @return the lower left x-coordinate + */ + public float getLeft(float margin) { + return llx + margin; + } + + /** + * Sets the upper right x-coordinate. + * + * @param urx + * the new value + */ + public void setRight(float urx) { + this.urx = urx; + } + + /** + * Returns the upper right x-coordinate. + * + * @return the upper right x-coordinate + */ + public float getRight() { + return urx; + } + + /** + * Returns the upper right x-coordinate, considering a given margin. + * + * @param margin + * a margin + * @return the upper right x-coordinate + */ + public float getRight(float margin) { + return urx - margin; + } + + /** + * Returns the width of the rectangle. + * + * @return the width + */ + public float getWidth() { + return urx - llx; + } + + /** + * Sets the upper right y-coordinate. + * + * @param ury + * the new value + */ + public void setTop(float ury) { + this.ury = ury; + } + + /** + * Returns the upper right y-coordinate. + * + * @return the upper right y-coordinate + */ + public float getTop() { + return ury; + } + + /** + * Returns the upper right y-coordinate, considering a given margin. + * + * @param margin + * a margin + * @return the upper right y-coordinate + */ + public float getTop(float margin) { + return ury - margin; + } + + public float getRelativeTop(){ + return ruy; + } + + public void setRelativeTop(float ruy){ + this.ruy = ruy; + } + /** + * Sets the lower left y-coordinate. + * + * @param lly + * the new value + */ + public void setBottom(float lly) { + this.lly = lly; + } + + /** + * Returns the lower left y-coordinate. + * + * @return the lower left y-coordinate + */ + public float getBottom() { + return lly; + } + + /** + * Returns the lower left y-coordinate, considering a given margin. + * + * @param margin + * a margin + * @return the lower left y-coordinate + */ + public float getBottom(float margin) { + return lly + margin; + } + + /** + * Returns the height of the rectangle. + * + * @return the height + */ + public float getHeight() { + return ury - lly; + } + + /** + * Normalizes the rectangle. Switches lower left with upper right if + * necessary. + */ + public void normalize() { + if (llx > urx) { + float a = llx; + llx = urx; + urx = a; + } + if (lly > ury) { + float a = lly; + lly = ury; + ury = a; + } + } + + // METHODS TO GET/SET THE ROTATION: + + /** + * Gets the rotation of the rectangle + * + * @return a rotation value + */ + public int getRotation() { + return rotation; + } + + /** + * Rotates the rectangle. Swaps the values of llx and lly and of urx and ury. + * + * @return the rotated Rectangle + */ + public Rectangle rotate() { + Rectangle rect = new Rectangle(lly, llx, ury, urx); + rect.rotation = rotation + 90; + rect.rotation %= 360; + return rect; + } + + // METHODS TO GET/SET THE BACKGROUND COLOR: + + /** + * Gets the backgroundcolor. + * + * @return a Color + */ + public Color getBackgroundColor() { + return backgroundColor; + } + + /** + * Sets the backgroundcolor of the rectangle. + * + * @param backgroundColor + * a Color + */ + + public void setBackgroundColor(Color backgroundColor) { + this.backgroundColor = backgroundColor; + } + + /** + * Gets the grayscale. + * + * @return the grayscale color of the background or 0 if the background has no + * grayscale color. + */ + public float getGrayFill() { + if (backgroundColor instanceof GrayColor) + return ((GrayColor) backgroundColor).getGray(); + return 0; + } + + /** + * Sets the the background color to a grayscale value. + * + * @param value + * the new grayscale value + */ + public void setGrayFill(float value) { + backgroundColor = new GrayColor(value); + } + + // METHODS TO GET/SET THE BORDER: + + /** + * Returns the exact type of the border. + * + * @return a value + */ + public int getBorder() { + return border; + } + + /** + * Indicates whether some type of border is set. + * + * @return a boolean + */ + public boolean hasBorders() { + switch (border) { + case UNDEFINED: + case NO_BORDER: + return false; + default: + return borderWidth > 0 || borderWidthLeft > 0 || borderWidthRight > 0 + || borderWidthTop > 0 || borderWidthBottom > 0; + } + } + + /** + * Indicates whether the specified type of border is set. + * + * @param type + * the type of border + * @return a boolean + */ + public boolean hasBorder(int type) { + if (border == UNDEFINED) + return false; + return (border & type) == type; + } + + /** + * Enables/Disables the border on the specified sides. The border is specified + * as an integer bitwise combination of the constants: + * LEFT, RIGHT, TOP, BOTTOM. + * + * @see #enableBorderSide(int) + * @see #disableBorderSide(int) + * @param border + * the new value + */ + public void setBorder(int border) { + this.border = border; + } + + /** + * Indicates whether variable width borders are being used. Returns true if + * setBorderWidthLeft, setBorderWidthRight, + * setBorderWidthTop, or setBorderWidthBottom has been called. + * + * @return true if variable width borders are in use + */ + public boolean isUseVariableBorders() { + return useVariableBorders; + } + + /** + * Sets a parameter indicating if the rectangle has variable borders + * + * @param useVariableBorders + * indication if the rectangle has variable borders + */ + public void setUseVariableBorders(boolean useVariableBorders) { + this.useVariableBorders = useVariableBorders; + } + + /** + * Enables the border on the specified side. + * + * @param side + * the side to enable. One of LEFT, RIGHT, TOP, BOTTOM + */ + public void enableBorderSide(int side) { + if (border == UNDEFINED) + border = 0; + border |= side; + } + + /** + * Disables the border on the specified side. + * + * @param side + * the side to disable. One of LEFT, RIGHT, TOP, BOTTOM + */ + public void disableBorderSide(int side) { + if (border == UNDEFINED) + border = 0; + border &= ~side; + } + + // METHODS TO GET/SET THE BORDER WIDTH: + + /** + * Gets the borderwidth. + * + * @return a value + */ + public float getBorderWidth() { + return borderWidth; + } + + /** + * Sets the borderwidth of the table. + * + * @param borderWidth + * the new value + */ + public void setBorderWidth(float borderWidth) { + this.borderWidth = borderWidth; + } + + /** + * Helper function returning the border width of a specific side. + * + * @param variableWidthValue + * a variable width (could be undefined) + * @param side + * the border you want to check + * @return the variableWidthValue if not undefined, otherwise the borderWidth + */ + private float getVariableBorderWidth(float variableWidthValue, int side) { + if ((border & side) != 0) + return variableWidthValue != UNDEFINED ? variableWidthValue : borderWidth; + return 0; + } + + /** + * Helper function updating the border flag for a side based on the specified + * width. A width of 0 will disable the border on that side. Any other width + * enables it. + * + * @param width + * width of border + * @param side + * border side constant + */ + private void updateBorderBasedOnWidth(float width, int side) { + useVariableBorders = true; + if (width > 0) + enableBorderSide(side); + else + disableBorderSide(side); + } + + /** + * Gets the width of the left border. + * + * @return a width + */ + public float getBorderWidthLeft() { + return getVariableBorderWidth(borderWidthLeft, LEFT); + } + + /** + * Sets the width of the left border. + * + * @param borderWidthLeft + * a width + */ + public void setBorderWidthLeft(float borderWidthLeft) { + this.borderWidthLeft = borderWidthLeft; + updateBorderBasedOnWidth(borderWidthLeft, LEFT); + } + + /** + * Gets the width of the right border. + * + * @return a width + */ + public float getBorderWidthRight() { + return getVariableBorderWidth(borderWidthRight, RIGHT); + } + + /** + * Sets the width of the right border. + * + * @param borderWidthRight + * a width + */ + public void setBorderWidthRight(float borderWidthRight) { + this.borderWidthRight = borderWidthRight; + updateBorderBasedOnWidth(borderWidthRight, RIGHT); + } + + /** + * Gets the width of the top border. + * + * @return a width + */ + public float getBorderWidthTop() { + return getVariableBorderWidth(borderWidthTop, TOP); + } + + /** + * Sets the width of the top border. + * + * @param borderWidthTop + * a width + */ + public void setBorderWidthTop(float borderWidthTop) { + this.borderWidthTop = borderWidthTop; + updateBorderBasedOnWidth(borderWidthTop, TOP); + } + + /** + * Gets the width of the bottom border. + * + * @return a width + */ + public float getBorderWidthBottom() { + return getVariableBorderWidth(borderWidthBottom, BOTTOM); + } + + /** + * Sets the width of the bottom border. + * + * @param borderWidthBottom + * a width + */ + public void setBorderWidthBottom(float borderWidthBottom) { + this.borderWidthBottom = borderWidthBottom; + updateBorderBasedOnWidth(borderWidthBottom, BOTTOM); + } + + // METHODS TO GET/SET THE BORDER COLOR: + + /** + * Gets the color of the border. + * + * @return a Color + */ + public Color getBorderColor() { + return borderColor; + } + + /** + * Sets the color of the border. + * + * @param borderColor + * a Color + */ + public void setBorderColor(Color borderColor) { + this.borderColor = borderColor; + } + + /** + * Gets the color of the left border. + * + * @return a Color + */ + public Color getBorderColorLeft() { + if (borderColorLeft == null) + return borderColor; + return borderColorLeft; + } + + /** + * Sets the color of the left border. + * + * @param borderColorLeft + * a Color + */ + public void setBorderColorLeft(Color borderColorLeft) { + this.borderColorLeft = borderColorLeft; + } + + /** + * Gets the color of the right border. + * + * @return a Color + */ + public Color getBorderColorRight() { + if (borderColorRight == null) + return borderColor; + return borderColorRight; + } + + /** + * Sets the color of the right border. + * + * @param borderColorRight + * a Color + */ + public void setBorderColorRight(Color borderColorRight) { + this.borderColorRight = borderColorRight; + } + + /** + * Gets the color of the top border. + * + * @return a Color + */ + public Color getBorderColorTop() { + if (borderColorTop == null) + return borderColor; + return borderColorTop; + } + + /** + * Sets the color of the top border. + * + * @param borderColorTop + * a Color + */ + public void setBorderColorTop(Color borderColorTop) { + this.borderColorTop = borderColorTop; + } + + /** + * Gets the color of the bottom border. + * + * @return a Color + */ + public Color getBorderColorBottom() { + if (borderColorBottom == null) + return borderColor; + return borderColorBottom; + } + + /** + * Sets the color of the bottom border. + * + * @param borderColorBottom + * a Color + */ + public void setBorderColorBottom(Color borderColorBottom) { + this.borderColorBottom = borderColorBottom; + } + + // SPECIAL METHODS: + + /** + * Gets a Rectangle that is altered to fit on the page. + * + * @param top + * the top position + * @param bottom + * the bottom position + * @return a Rectangle + */ + public Rectangle rectangle(float top, float bottom) { + Rectangle tmp = new Rectangle(this); + if (getTop() > top) { + tmp.setTop(top); + tmp.disableBorderSide(TOP); + } + if (getBottom() < bottom) { + tmp.setBottom(bottom); + tmp.disableBorderSide(BOTTOM); + } + return tmp; + } + + /** + * Copies each of the parameters, except the position, from a + * Rectangle object + * + * @param rect + * Rectangle to copy from + */ + public void cloneNonPositionParameters(Rectangle rect) { + this.rotation = rect.rotation; + this.backgroundColor = rect.backgroundColor; + this.border = rect.border; + this.useVariableBorders = rect.useVariableBorders; + this.borderWidth = rect.borderWidth; + this.borderWidthLeft = rect.borderWidthLeft; + this.borderWidthRight = rect.borderWidthRight; + this.borderWidthTop = rect.borderWidthTop; + this.borderWidthBottom = rect.borderWidthBottom; + this.borderColor = rect.borderColor; + this.borderColorLeft = rect.borderColorLeft; + this.borderColorRight = rect.borderColorRight; + this.borderColorTop = rect.borderColorTop; + this.borderColorBottom = rect.borderColorBottom; + } + + /** + * Copies each of the parameters, except the position, from a + * Rectangle object if the value is set there + * + * @param rect + * Rectangle to copy from + */ + public void softCloneNonPositionParameters(Rectangle rect) { + if (rect.rotation != 0) + this.rotation = rect.rotation; + if (rect.backgroundColor != null) + this.backgroundColor = rect.backgroundColor; + if (rect.border != UNDEFINED) + this.border = rect.border; + if (useVariableBorders) + this.useVariableBorders = rect.useVariableBorders; + if (rect.borderWidth != UNDEFINED) + this.borderWidth = rect.borderWidth; + if (rect.borderWidthLeft != UNDEFINED) + this.borderWidthLeft = rect.borderWidthLeft; + if (rect.borderWidthRight != UNDEFINED) + this.borderWidthRight = rect.borderWidthRight; + if (rect.borderWidthTop != UNDEFINED) + this.borderWidthTop = rect.borderWidthTop; + if (rect.borderWidthBottom != UNDEFINED) + this.borderWidthBottom = rect.borderWidthBottom; + if (rect.borderColor != null) + this.borderColor = rect.borderColor; + if (rect.borderColorLeft != null) + this.borderColorLeft = rect.borderColorLeft; + if (rect.borderColorRight != null) + this.borderColorRight = rect.borderColorRight; + if (rect.borderColorTop != null) + this.borderColorTop = rect.borderColorTop; + if (rect.borderColorBottom != null) + this.borderColorBottom = rect.borderColorBottom; + } + + /** + * @return a String representation of the rectangle + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + StringBuilder buf = new StringBuilder("Rectangle: "); + buf.append(getWidth()); + buf.append('x'); + buf.append(getHeight()); + buf.append(" (rot: "); + buf.append(rotation); + buf.append(" degrees)"); + return buf.toString(); + } } \ No newline at end of file diff --git a/openpdf/src/main/java/com/lowagie/text/pdf/PdfDocument.java b/openpdf/src/main/java/com/lowagie/text/pdf/PdfDocument.java index 768b18127..edba26e84 100644 --- a/openpdf/src/main/java/com/lowagie/text/pdf/PdfDocument.java +++ b/openpdf/src/main/java/com/lowagie/text/pdf/PdfDocument.java @@ -407,8 +407,6 @@ void setLeading(float leading) { /** The current active PdfAction when processing an Anchor. */ protected PdfAction anchorAction = null; - // We are going to apply Refactoring Here - /** * Signals that an Element was added to the Document. * @@ -569,7 +567,7 @@ public boolean add(Element element) throws DocumentException { PdfPageEvent pageEvent = writer.getPageEvent(); boolean hasTitle = section.isNotAddedYet() - && section.getTitle() != null; + && section.getTitle() != null; // if the section is a chapter, we begin a new page if (section.isTriggerNewPage()) { @@ -678,17 +676,22 @@ public boolean add(Element element) throws DocumentException { break; } case Element.PTABLE: { - PdfPTable ptable = (PdfPTable)element; + PdfPTable ptable = (PdfPTable) element; if (ptable.size() <= ptable.getHeaderRows()) break; //nothing to do - // before every table, we add a new line and flush all lines - ensureNewLine(); - flushLines(); + if(isDoFooter) { + delayTableAddition(ptable); + } else { + // before every table, we add a new line and flush all lines + ensureNewLine(); + flushLines(); + + addPTable(ptable); + pageEmpty = false; + newLine(); + } - addPTable(ptable); - pageEmpty = false; - newLine(); break; } case Element.MULTI_COLUMN_TEXT: { @@ -715,15 +718,15 @@ public boolean add(Element element) throws DocumentException { break; } else if (element instanceof Table) { try { - PdfPTable ptable = ((Table)element).createPdfPTable(); - if (ptable.size() <= ptable.getHeaderRows()) - break; //nothing to do - // before every table, we add a new line and flush all lines - ensureNewLine(); - flushLines(); - addPTable(ptable); - pageEmpty = false; - break; + PdfPTable ptable = ((Table)element).createPdfPTable(); + if (ptable.size() <= ptable.getHeaderRows()) + break; //nothing to do + // before every table, we add a new line and flush all lines + ensureNewLine(); + flushLines(); + addPTable(ptable); + pageEmpty = false; + break; } catch(BadElementException bee) { // constructing the PdfTable @@ -747,7 +750,12 @@ public boolean add(Element element) throws DocumentException { case Element.IMGRAW: case Element.IMGTEMPLATE: { //carriageReturn(); suggestion by Marc Campforts - add((Image) element); + if(isDoFooter){ + addDelay((Image) element); + }else{ + add((Image) element); + } + break; } case Element.YMARK: { @@ -779,37 +787,45 @@ public boolean add(Element element) throws DocumentException { } } + + /** + * Integrate a paragraph into a table, so it can be a whole. + *

Note: This is not a table with square, it's just like the paragraph, but + * it cannot be separated. + * @param paragraph the {@code Paragraph} incoming paragraphs to be consolidated + * @return {@code PdfPTable} the whole which will be used later + */ static PdfPTable createInOneCell(Paragraph paragraph) { PdfPTable table = new PdfPTable(1); table.setWidthPercentage(100f); - PdfPCell cell = new PdfPCell(); cell.setBorder(Table.NO_BORDER); cell.setPadding(0); - - for (int i=0; i(boxSize); if (pageSize.getBackgroundColor() != null - || pageSize.hasBorders() - || pageSize.getBorderColor() != null) { + || pageSize.hasBorders() + || pageSize.getBorderColor() != null) { add(pageSize); } @@ -1303,7 +1319,7 @@ protected void carriageReturn() { public float getVerticalPosition(boolean ensureNewLine) { // ensuring that a new line has been started. if (ensureNewLine) { - ensureNewLine(); + ensureNewLine(); } return top() - currentHeight - indentation.indentTop; } @@ -1315,14 +1331,14 @@ public float getVerticalPosition(boolean ensureNewLine) { * Ensures that a new line has been started. */ protected void ensureNewLine() { - try { - if ((lastElementType == Element.PHRASE) || - (lastElementType == Element.CHUNK)) { - newLine(); - flushLines(); - } - } catch (DocumentException ex) { - throw new ExceptionConverter(ex); + try { + if ((lastElementType == Element.PHRASE) || + (lastElementType == Element.CHUNK)) { + newLine(); + flushLines(); + } + } catch (DocumentException ex) { + throw new ExceptionConverter(ex); } } @@ -1403,7 +1419,7 @@ void writeLineToContent(PdfLine line, PdfContentByte text, PdfContentByte graphi int lineLen; boolean isJustified; float hangingCorrection = 0; - float hScale = 1; + float hScale; float lastHScale = Float.NaN; float baseWordSpacing = 0; float baseCharacterSpacing = 0; @@ -1517,9 +1533,9 @@ else if (isJustified) { float[] extra = (float[]) bgr[1]; graphics.rectangle(xMarker - extra[0], - yMarker + descender - extra[1] + chunk.getTextRise(), - width - subtract + extra[0] + extra[2], - ascender - descender + extra[1] + extra[3]); + yMarker + descender - extra[1] + chunk.getTextRise(), + width - subtract + extra[0] + extra[2], + ascender - descender + extra[1] + extra[3]); graphics.fill(); graphics.setGrayFill(0); @@ -1532,7 +1548,7 @@ else if (isJustified) { if (nextChunk == null) subtract += hangingCorrection; Object[][] unders = (Object[][]) chunk.getAttribute(Chunk.UNDERLINE); - Color scolor = null; + Color scolor; for (Object[] obj : unders) { scolor = (Color) obj[0]; float[] ps = (float[]) obj[1]; @@ -2489,7 +2505,7 @@ protected void add(Image image) throws DocumentException { if (image == imageWait) imageWait = null; boolean textwrap = (image.getAlignment() & Image.TEXTWRAP) == Image.TEXTWRAP - && !((image.getAlignment() & Image.MIDDLE) == Image.MIDDLE); + && !((image.getAlignment() & Image.MIDDLE) == Image.MIDDLE); boolean underlying = (image.getAlignment() & Image.UNDERLYING) == Image.UNDERLYING; float diff = leading / 2; if (textwrap) { @@ -2528,7 +2544,120 @@ protected void add(Image image) throws DocumentException { } } -// [M4] Adding a PdfPTable + /** + * write non-text Element into document + */ + + protected void flushSpecial() { + if(footer.getSpecialContent() == null){ + return; + } + for (Element element : footer.getSpecialContent()) { + switch (element.type()) { + case Element.JPEG: + case Element.JPEG2000: + case Element.JBIG2: + case Element.IMGRAW: + case Element.IMGTEMPLATE: { + Image image = (Image) element; + boolean textwrap = (image.getAlignment() & Image.TEXTWRAP) == Image.TEXTWRAP + && !((image.getAlignment() & Image.MIDDLE) == Image.MIDDLE); + float diff = leading / 2; + if (textwrap) { + diff += leading; + } + float lowerleft = footer.getTop() - image.getRelativeTop() - image.getScaledHeight() - diff; + + float[] mt = image.matrix(); + float startPosition = indentLeft() - mt[4]; + if ((image.getAlignment() & Image.RIGHT) == Image.RIGHT) + startPosition = indentRight() - image.getScaledWidth() - mt[4]; + if ((image.getAlignment() & Image.MIDDLE) == Image.MIDDLE) + startPosition = indentLeft() + ((indentRight() - indentLeft() - image.getScaledWidth()) / 2) - mt[4]; + if (image.hasAbsoluteX()) startPosition = image.getAbsoluteX(); + + if (!textwrap) { + if ((image.getAlignment() & Image.RIGHT) == Image.RIGHT) + startPosition -= image.getIndentationRight(); + else if ((image.getAlignment() & Image.MIDDLE) == Image.MIDDLE) + startPosition += image.getIndentationLeft() - image.getIndentationRight(); + else startPosition += image.getIndentationLeft(); + } + graphics.addImage(image, mt[0], mt[1], mt[2], mt[3], startPosition, lowerleft - mt[5]); + break; + } + case Element.PTABLE: + PdfPTable ptable = (PdfPTable) element; + + ColumnText ct = new ColumnText(writer.getDirectContent()); + ct.addElement(ptable); + + ct.setSimpleColumn(indentLeft(), footer.getBottom(), indentRight(), footer.getTop()); + ct.go(); + + break; + } + } + footer.setPadding(0); + } + + /** + * Occupies space for Image that will be added later instead of now + * + * @param image the new Image + */ + + protected void addDelay(Image image) { + if (image.hasAbsoluteY()) { + System.out.println("Warning: absoluteY of image is invalid in footer"); + } + + image.setRelativeTop(currentHeight); // set the offset relative to the top + image.setAlignment(image.getAlignment() | footer.alignment()); + footer.addSpecialContent(image); + + // add indentation for text + boolean textwrap = (image.getAlignment() & Image.TEXTWRAP) == Image.TEXTWRAP + && !((image.getAlignment() & Image.MIDDLE) == Image.MIDDLE); + boolean underlying = (image.getAlignment() & Image.UNDERLYING) == Image.UNDERLYING; + float diff = leading / 2; + if (textwrap) { + if (imageEnd < 0 || imageEnd < currentHeight + image.getScaledHeight() + diff) { + imageEnd = currentHeight + image.getScaledHeight() + diff; + } + if ((image.getAlignment() & Image.RIGHT) == Image.RIGHT) { + // indentation suggested by Pelikan Stephan + indentation.imageIndentRight += image.getScaledWidth() + image.getIndentationLeft(); + } else { + // indentation suggested by Pelikan Stephan + indentation.imageIndentLeft += image.getScaledWidth() + image.getIndentationRight(); + } + } + // move text + if (!(textwrap || underlying)) { + currentHeight += image.getScaledHeight() + diff; + flushLines(); + text.moveText(0, -(image.getScaledHeight() + diff)); + newLine(); + } else { + footer.addPadding(image.getScaledHeight() + diff); + } + } + + /** + * Occupies space for PdfPTable that will be added later instead of now + * + * @param table the new PdfPTable + */ + protected void delayTableAddition(PdfPTable table) { + setTableWidth(table); + final float footerPadding = table.getTotalHeight() - (0.75f * leading); + + footer.addSpecialContent(table); + footer.addPadding(footerPadding); + } + + // [M4] Adding a PdfPTable /** Adds a PdfPTable to the document. * @param ptable the PdfPTable to be added to the document. @@ -2582,14 +2711,18 @@ void addPTable(PdfPTable ptable) throws DocumentException { */ boolean fitsPage(PdfPTable table, float margin) { + setTableWidth(table); + // ensuring that a new line has been started. + ensureNewLine(); + return table.getTotalHeight() + ((currentHeight > 0) ? table.spacingBefore() : 0f) + <= indentTop() - currentHeight - indentBottom() - margin; + } + + private void setTableWidth(final PdfPTable table) { if (!table.isLockedWidth()) { float totalWidth = (indentRight() - indentLeft()) * table.getWidthPercentage() / 100; table.setTotalWidth(totalWidth); } - // ensuring that a new line has been started. - ensureNewLine(); - return table.getTotalHeight() + ((currentHeight > 0) ? table.spacingBefore() : 0f) - <= indentTop() - currentHeight - indentBottom() - margin; } // [M4'] Adding a Table @@ -3074,7 +3207,7 @@ protected void renderCells(RenderingContext ctx, java.util.List cells, boolean h // we paint the borders of the cells Rectangle cellRect = cell.rectangle(tableRect.getTop(), indentBottom); - //cellRect.setBottom(cellRect.bottom()); + //cellRect.setBottom(cellRect.bottom()); if (cellRect.getHeight() > 0) { ctx.lostTableBottom = indentBottom; ctx.cellGraphics.rectangle(cellRect); @@ -3104,8 +3237,12 @@ float bottom(Table table) { } // [M5] header/footer + /** This is the flag meaning whether document is creating footer. */ + private boolean isDoFooter = false; + protected void doFooter() throws DocumentException { if (footer == null) return; + isDoFooter = true; // Begin added by Edgar Leonardo Prieto Perilla // Avoid footer indentation float tmpIndentLeft = indentation.indentLeft; @@ -3131,11 +3268,12 @@ protected void doFooter() throws DocumentException { text.moveText(left(), indentBottom()); flushLines(); text.moveText(-left(), -bottom()); - footer.setTop(bottom(currentHeight)); + footer.setTop(bottom(Math.max(footer.getPadding(), currentHeight))); footer.setBottom(bottom() - (0.75f * leading)); footer.setLeft(left()); footer.setRight(right()); graphics.rectangle(footer); + flushSpecial(); indentation.indentBottom = currentHeight + leading * 2; currentHeight = 0; // Begin added by Edgar Leonardo Prieto Perilla @@ -3147,6 +3285,7 @@ protected void doFooter() throws DocumentException { indentation.imageIndentRight = tmpImageIndentRight; // End added: Bonf (Marc Schneider) 2003-07-29 // End added by Edgar Leonardo Prieto Perilla + isDoFooter = false; } protected void doHeader() throws DocumentException { @@ -3192,4 +3331,4 @@ protected void doHeader() throws DocumentException { // End added: Bonf (Marc Schneider) 2003-07-29 // End Added by Edgar Leonardo Prieto Perilla } -} +} \ No newline at end of file diff --git a/openpdf/src/test/java/com/lowagie/text/FooterTableTest.java b/openpdf/src/test/java/com/lowagie/text/FooterTableTest.java new file mode 100644 index 000000000..a04f6a257 --- /dev/null +++ b/openpdf/src/test/java/com/lowagie/text/FooterTableTest.java @@ -0,0 +1,58 @@ +package com.lowagie.text; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.Objects; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import com.lowagie.text.pdf.PdfPTable; +import com.lowagie.text.pdf.PdfWriter; + +public class FooterTableTest { + @Test + public void imageLeftAlignmentPositionTest() throws IOException { + Document document = new Document(PageSize.A4); + PdfWriter.getInstance(document, new ByteArrayOutputStream()); + + Image jpg = Image.getInstance(Objects.requireNonNull(getClass().getClassLoader().getResource("GitHub-Mark-32px.png"))); + jpg.setAlignment(Image.RIGHT); + + PdfPTable table = new PdfPTable(3); + table.getDefaultCell().setBorder(Table.NO_BORDER); + table.addCell("1.1"); + table.addCell("1.2"); + table.addCell("1.3"); + table.addCell("2.1"); + table.addCell(new Phrase("center")); + table.addCell("2.3"); + table.addCell("3.1"); + table.addCell("3.2"); + table.addCell("3.3"); + + Paragraph footerParagraph = new Paragraph(); + ; + footerParagraph.add(jpg); + footerParagraph.add(table); + + HeaderFooter footer = new HeaderFooter(footerParagraph, false); + document.setFooter(footer); + + document.open(); + document.add(new Paragraph("This is a test line.")); + document.add(new Paragraph("Second line")); + document.newPage(); + document.add(new Paragraph("second")); + document.newPage(); + document.add(new Paragraph("third")); + document.close(); + + float tableHeight = table.getTotalHeight(); + float footerTop = footer.getTop(); + float tableBottom = footerTop - table.getTotalHeight(); + Assertions.assertEquals(48.0, tableHeight); + Assertions.assertEquals(76.0, footerTop); + Assertions.assertEquals(28.0, tableBottom); + } +} \ No newline at end of file diff --git a/openpdf/src/test/java/com/lowagie/text/pdf/FooterImageTest.java b/openpdf/src/test/java/com/lowagie/text/pdf/FooterImageTest.java new file mode 100644 index 000000000..a18a26115 --- /dev/null +++ b/openpdf/src/test/java/com/lowagie/text/pdf/FooterImageTest.java @@ -0,0 +1,140 @@ +package com.lowagie.text.pdf; + +import com.lowagie.text.*; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.Objects; + +class FooterImageTest { + @Test + void onlyTextFooterUpperBoundTest() throws IOException { + Document document = new Document(PageSize.A4); + PdfWriter.getInstance(document, new ByteArrayOutputStream()); + + Paragraph footerParagraph = new Paragraph(); + String test = "This is a test line."; + String footerstr = "footer"; + footerParagraph.add(footerstr); + HeaderFooter footer = new HeaderFooter(footerParagraph, false); + document.setFooter(footer); + + document.open(); + document.add(new Paragraph(test)); + document.close(); + Assertions.assertEquals(52.0, footer.getTop()); + } + + @Test + void imageLeftAlignmentPositionTest() throws IOException { + Document document = new Document(PageSize.A4); + Image jpg = Image.getInstance(Objects.requireNonNull(getClass().getClassLoader().getResource("GitHub-Mark-32px.png"))); + PdfWriter.getInstance(document, new ByteArrayOutputStream()); + + Paragraph footerParagraph = new Paragraph(); + String test = "This is a test line."; + String footerstr = "footer"; + footerParagraph.add(jpg); + footerParagraph.add(footerstr); + HeaderFooter footer = new HeaderFooter(footerParagraph, false); + document.setFooter(footer); + + document.open(); + document.add(new Paragraph(test)); + document.close(); + + float footerTop = footer.getTop(); + float imageBottom = footerTop - jpg.getRelativeTop() - jpg.getScaledHeight(); + float imageIndentLeft = document.left() - jpg.matrix()[4]; + Assertions.assertEquals(92.0, footerTop); + Assertions.assertEquals(60.0, imageBottom); + Assertions.assertEquals(36.0, imageIndentLeft); + } + + @Test + void imageRightAlignmentPositionTest() throws IOException { + Document document = new Document(PageSize.A4); + Image jpg = Image.getInstance(Objects.requireNonNull(getClass().getClassLoader().getResource("GitHub-Mark-32px.png"))); + PdfWriter.getInstance(document, new ByteArrayOutputStream()); + jpg.setAlignment(Element.ALIGN_RIGHT); + + Paragraph footerParagraph = new Paragraph(); + String test = "This is a test line."; + footerParagraph.add(jpg); + HeaderFooter footer = new HeaderFooter(footerParagraph, false); + document.setFooter(footer); + + document.open(); + document.add(new Paragraph(test)); + document.close(); + + float footerTop = footer.getTop(); + float imageBottom = footerTop - jpg.getRelativeTop() - jpg.getScaledHeight(); + float imageIndentRight = document.right() - jpg.getScaledWidth() - jpg.matrix()[4]; + imageIndentRight -= jpg.getIndentationRight(); + Assertions.assertEquals(76.0, footerTop); + Assertions.assertEquals(44.0, imageBottom); + Assertions.assertEquals(527.0, imageIndentRight); + } + + @Test + void centerUnderlyingPositionTest() throws IOException { + Document document = new Document(PageSize.A4); + Image jpg = Image.getInstance(Objects.requireNonNull(getClass().getClassLoader().getResource("GitHub-Mark-32px.png"))); + jpg.setAlignment(Image.UNDERLYING); + + PdfWriter.getInstance(document, new ByteArrayOutputStream()); + + Paragraph footerParagraph = new Paragraph(); + String test = "This is a test line."; + footerParagraph.add(jpg); + HeaderFooter footer = new HeaderFooter(footerParagraph, true); + footer.setAlignment(Element.ALIGN_CENTER); + document.setFooter(footer); + + document.open(); + document.add(new Paragraph(test)); + document.close(); + + float footerTop = footer.getTop(); + float imageBottom = footerTop - jpg.getRelativeTop() - jpg.getScaledHeight(); + float imageIndentLeft = document.left() + (document.right() - document.left() - jpg.getScaledWidth()) / 2; + imageIndentLeft -= jpg.getIndentationRight() + jpg.matrix()[4]; + Assertions.assertEquals(76.0, footerTop); + Assertions.assertEquals(44.0, imageBottom); + Assertions.assertEquals(281.5, imageIndentLeft); + } + + @Test + void multiplePageWithImageAndNumberTest() throws IOException { + Document document = new Document(PageSize.A4); + Image jpg = Image.getInstance("src/test/resources/GitHub-Mark-32px.png"); + jpg.setAlignment(Image.UNDERLYING); + + PdfWriter.getInstance(document, new ByteArrayOutputStream()); + + Paragraph footerParagraph = new Paragraph(); + String test = "Github manual."; + footerParagraph.add(jpg); + HeaderFooter footer = new HeaderFooter(footerParagraph, true); + footer.setAlignment(Element.ALIGN_CENTER); + document.setFooter(footer); + + document.open(); + for (int i = 0; i < 100; i++) { + document.add(new Paragraph(test)); + } + document.close(); + + float footerTop = footer.getTop(); + float imageBottom = footerTop - jpg.getRelativeTop() - jpg.getScaledHeight(); + float imageIndentLeft = document.left() + (document.right() - document.left() - jpg.getScaledWidth()) / 2; + imageIndentLeft -= jpg.getIndentationRight() + jpg.matrix()[4]; + Assertions.assertEquals(76.0, footerTop); + Assertions.assertEquals(44.0, imageBottom); + Assertions.assertEquals(281.5, imageIndentLeft); + + } +} \ No newline at end of file diff --git a/openpdf/src/test/resources/GitHub-Mark-32px.png b/openpdf/src/test/resources/GitHub-Mark-32px.png new file mode 100644 index 0000000000000000000000000000000000000000..8b25551a97921681334176ee143b41510a117d86 GIT binary patch literal 1714 zcmaJ?X;2eq7*4oFu!ne{XxAht2qc?8LXr|_LPCfTpaBK7K$c{I0Ld=NLIOeuC;@2) zZ$K%a)k+m-s0>xHmKxL%0V&0TRzzznhgyqrIC$F)0{WwLXLrBvd*^wc_uSc%h%m9E z{W5z3f#4_!7RvAyFh6!S_*<8qJ%KOIm?#E|L=rJQq=gB5C6WLG5;c?r%V0>EmEH#X z5eSwPRa6WXBMs#$5H%GtW2go-in9p>zW@UYDNNWc^XOXZQ? z1QjEV00I#$3^1wQUJ8&-2UsjB-G|9y(LDhMNN3PM{APL4eYi{(m*ERcUnJa{R+-3^ z34^A6;U^v`8N*O6ji%S@sd{fJqD`XFIUJ5zgTe5^5nj414F(y!G&=H(f)Lgzv?>%+ zAsWD}2qhpH7>|TU`X&W6IxDNuO_vET7|j5oG&&VDr!)hUO8+0KR?nh!m<)a!?|%yG zqOwq!CWCcIhE{<$E|F|@g>nP6FoYr6C<8>D?ID9%&5J(4oSbR1I^byW*g@__U z4QsF&uJSEcFeleM3~ChjEQGbHOjsGDMbyAl(p=Ttv9RaVo8~I#js@@Y9C^_2U})yn zzSHU%6FxuY?d;&65MyR({^lU*3$z$ZllDb(o&<7d;A_`h2U+3~BJ2Hv`{W}KEU801#cv_B|9Cm!ynR{S`AMsSn z;7E=B;mb!wx$L;S>yGXG^6=&WlQn9$s?&L%Y1D8TI^MlKB1DqsEng$>f4=xYWBoPI z_S1p!sJ#d2?YI4kPA{k}Eby?F=f-J9zIc`YDl^pzjVm~9ebE?Hn?t0Nx+la|D0MB; z9)2xv1G>a1|A9kQ>~DV<=X3-4yC&n!m8-3K#P z{X@0zRuQsy$+N ziSCoLJU{Z$nQy4A4Y5UJ07$5FA~qL2%Q+cLaqDU?Lz3?=BC5;Nk6BbTmmceEaM>-Z zi>O&-dSE=%ex;vcvCOk{*JQ5^_4M z4lW7%l9IqY(z7pV(?I@@8=KPFO82)O{VDI18-*d-k$YmI^XiuPs_LuFw<^ZcD}yP5 c*NrbeloN*74g`U%%F6r~k%+>C^#XapzmV0H-2eap literal 0 HcmV?d00001 From f3d4505e076f7e52e0551e78abf64a184eca0771 Mon Sep 17 00:00:00 2001 From: Joshua Onyema Date: Sun, 23 Nov 2025 02:11:35 -0500 Subject: [PATCH 4/5] updated test to print out the pdfs to confirm change --- .../com/lowagie/text/FooterTableTest.java | 11 ++++-- .../com/lowagie/text/pdf/FooterImageTest.java | 34 +++++++++++++++---- 2 files changed, 36 insertions(+), 9 deletions(-) diff --git a/openpdf/src/test/java/com/lowagie/text/FooterTableTest.java b/openpdf/src/test/java/com/lowagie/text/FooterTableTest.java index a04f6a257..978f4e1cd 100644 --- a/openpdf/src/test/java/com/lowagie/text/FooterTableTest.java +++ b/openpdf/src/test/java/com/lowagie/text/FooterTableTest.java @@ -1,6 +1,6 @@ package com.lowagie.text; -import java.io.ByteArrayOutputStream; +import java.io.FileOutputStream; import java.io.IOException; import java.util.Objects; @@ -14,7 +14,7 @@ public class FooterTableTest { @Test public void imageLeftAlignmentPositionTest() throws IOException { Document document = new Document(PageSize.A4); - PdfWriter.getInstance(document, new ByteArrayOutputStream()); + PdfWriter.getInstance(document, new FileOutputStream("footer-table-test.pdf")); Image jpg = Image.getInstance(Objects.requireNonNull(getClass().getClassLoader().getResource("GitHub-Mark-32px.png"))); jpg.setAlignment(Image.RIGHT); @@ -32,7 +32,6 @@ public void imageLeftAlignmentPositionTest() throws IOException { table.addCell("3.3"); Paragraph footerParagraph = new Paragraph(); - ; footerParagraph.add(jpg); footerParagraph.add(table); @@ -55,4 +54,10 @@ public void imageLeftAlignmentPositionTest() throws IOException { Assertions.assertEquals(76.0, footerTop); Assertions.assertEquals(28.0, tableBottom); } + + public static void main(String[] args) throws IOException { + FooterTableTest test = new FooterTableTest(); + test.imageLeftAlignmentPositionTest(); + System.out.println("PDF generated: footer-table-test.pdf"); + } } \ No newline at end of file diff --git a/openpdf/src/test/java/com/lowagie/text/pdf/FooterImageTest.java b/openpdf/src/test/java/com/lowagie/text/pdf/FooterImageTest.java index a18a26115..7548a26c0 100644 --- a/openpdf/src/test/java/com/lowagie/text/pdf/FooterImageTest.java +++ b/openpdf/src/test/java/com/lowagie/text/pdf/FooterImageTest.java @@ -4,7 +4,7 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import java.io.ByteArrayOutputStream; +import java.io.FileOutputStream; import java.io.IOException; import java.util.Objects; @@ -12,7 +12,7 @@ class FooterImageTest { @Test void onlyTextFooterUpperBoundTest() throws IOException { Document document = new Document(PageSize.A4); - PdfWriter.getInstance(document, new ByteArrayOutputStream()); + PdfWriter.getInstance(document, new FileOutputStream("footer-only-text.pdf")); Paragraph footerParagraph = new Paragraph(); String test = "This is a test line."; @@ -31,7 +31,7 @@ void onlyTextFooterUpperBoundTest() throws IOException { void imageLeftAlignmentPositionTest() throws IOException { Document document = new Document(PageSize.A4); Image jpg = Image.getInstance(Objects.requireNonNull(getClass().getClassLoader().getResource("GitHub-Mark-32px.png"))); - PdfWriter.getInstance(document, new ByteArrayOutputStream()); + PdfWriter.getInstance(document, new FileOutputStream("footer-image-left.pdf")); Paragraph footerParagraph = new Paragraph(); String test = "This is a test line."; @@ -57,7 +57,7 @@ void imageLeftAlignmentPositionTest() throws IOException { void imageRightAlignmentPositionTest() throws IOException { Document document = new Document(PageSize.A4); Image jpg = Image.getInstance(Objects.requireNonNull(getClass().getClassLoader().getResource("GitHub-Mark-32px.png"))); - PdfWriter.getInstance(document, new ByteArrayOutputStream()); + PdfWriter.getInstance(document, new FileOutputStream("footer-image-right.pdf")); jpg.setAlignment(Element.ALIGN_RIGHT); Paragraph footerParagraph = new Paragraph(); @@ -85,7 +85,7 @@ void centerUnderlyingPositionTest() throws IOException { Image jpg = Image.getInstance(Objects.requireNonNull(getClass().getClassLoader().getResource("GitHub-Mark-32px.png"))); jpg.setAlignment(Image.UNDERLYING); - PdfWriter.getInstance(document, new ByteArrayOutputStream()); + PdfWriter.getInstance(document, new FileOutputStream("footer-image-center.pdf")); Paragraph footerParagraph = new Paragraph(); String test = "This is a test line."; @@ -113,7 +113,7 @@ void multiplePageWithImageAndNumberTest() throws IOException { Image jpg = Image.getInstance("src/test/resources/GitHub-Mark-32px.png"); jpg.setAlignment(Image.UNDERLYING); - PdfWriter.getInstance(document, new ByteArrayOutputStream()); + PdfWriter.getInstance(document, new FileOutputStream("footer-image-multiple-pages.pdf")); Paragraph footerParagraph = new Paragraph(); String test = "Github manual."; @@ -137,4 +137,26 @@ void multiplePageWithImageAndNumberTest() throws IOException { Assertions.assertEquals(281.5, imageIndentLeft); } + + public static void main(String[] args) throws IOException { + FooterImageTest test = new FooterImageTest(); + System.out.println("Generating PDFs..."); + + test.onlyTextFooterUpperBoundTest(); + System.out.println("✓ Generated: footer-only-text.pdf"); + + test.imageLeftAlignmentPositionTest(); + System.out.println("✓ Generated: footer-image-left.pdf"); + + test.imageRightAlignmentPositionTest(); + System.out.println("✓ Generated: footer-image-right.pdf"); + + test.centerUnderlyingPositionTest(); + System.out.println("✓ Generated: footer-image-center.pdf"); + + test.multiplePageWithImageAndNumberTest(); + System.out.println("✓ Generated: footer-image-multiple-pages.pdf"); + + System.out.println("\nAll PDFs generated successfully!"); + } } \ No newline at end of file From 5315e8f33a9433d6725d128bf6883b27e6d27db0 Mon Sep 17 00:00:00 2001 From: Joshua Onyema Date: Sun, 23 Nov 2025 03:21:11 -0500 Subject: [PATCH 5/5] final changes --- .../main/java/com/lowagie/text/Rectangle.java | 8 +++---- .../com/lowagie/text/pdf/PdfDocument.java | 20 ++++++++--------- .../com/lowagie/text/FooterTableTest.java | 5 ++--- .../com/lowagie/text/pdf/FooterImageTest.java | 22 ++++++++----------- 4 files changed, 25 insertions(+), 30 deletions(-) diff --git a/openpdf/src/main/java/com/lowagie/text/Rectangle.java b/openpdf/src/main/java/com/lowagie/text/Rectangle.java index 19651ad21..d93a2719b 100644 --- a/openpdf/src/main/java/com/lowagie/text/Rectangle.java +++ b/openpdf/src/main/java/com/lowagie/text/Rectangle.java @@ -106,7 +106,7 @@ public class Rectangle implements Element { /** the upper right y-coordinate. */ protected float ury; - protected float ruy; + protected float aFloat; /** The rotation of the Rectangle */ protected int rotation = 0; @@ -409,11 +409,11 @@ public float getTop(float margin) { } public float getRelativeTop(){ - return ruy; + return aFloat; } - public void setRelativeTop(float ruy){ - this.ruy = ruy; + public void setRelativeTop(float relativeTop){ + this.aFloat = relativeTop; } /** * Sets the lower left y-coordinate. diff --git a/openpdf/src/main/java/com/lowagie/text/pdf/PdfDocument.java b/openpdf/src/main/java/com/lowagie/text/pdf/PdfDocument.java index edba26e84..f320b2117 100644 --- a/openpdf/src/main/java/com/lowagie/text/pdf/PdfDocument.java +++ b/openpdf/src/main/java/com/lowagie/text/pdf/PdfDocument.java @@ -2568,12 +2568,12 @@ protected void flushSpecial() { } float lowerleft = footer.getTop() - image.getRelativeTop() - image.getScaledHeight() - diff; - float[] mt = image.matrix(); - float startPosition = indentLeft() - mt[4]; + float[] matrix = image.matrix(); + float startPosition = indentLeft() - matrix[4]; if ((image.getAlignment() & Image.RIGHT) == Image.RIGHT) - startPosition = indentRight() - image.getScaledWidth() - mt[4]; + startPosition = indentRight() - image.getScaledWidth() - matrix[4]; if ((image.getAlignment() & Image.MIDDLE) == Image.MIDDLE) - startPosition = indentLeft() + ((indentRight() - indentLeft() - image.getScaledWidth()) / 2) - mt[4]; + startPosition = indentLeft() + ((indentRight() - indentLeft() - image.getScaledWidth()) / 2) - matrix[4]; if (image.hasAbsoluteX()) startPosition = image.getAbsoluteX(); if (!textwrap) { @@ -2583,17 +2583,17 @@ else if ((image.getAlignment() & Image.MIDDLE) == Image.MIDDLE) startPosition += image.getIndentationLeft() - image.getIndentationRight(); else startPosition += image.getIndentationLeft(); } - graphics.addImage(image, mt[0], mt[1], mt[2], mt[3], startPosition, lowerleft - mt[5]); + graphics.addImage(image, matrix[0], matrix[1], matrix[2], matrix[3], startPosition, lowerleft - matrix[5]); break; } case Element.PTABLE: - PdfPTable ptable = (PdfPTable) element; + PdfPTable pdfPTable = (PdfPTable) element; - ColumnText ct = new ColumnText(writer.getDirectContent()); - ct.addElement(ptable); + ColumnText columnText = new ColumnText(writer.getDirectContent()); + columnText.addElement(pdfPTable); - ct.setSimpleColumn(indentLeft(), footer.getBottom(), indentRight(), footer.getTop()); - ct.go(); + columnText.setSimpleColumn(indentLeft(), footer.getBottom(), indentRight(), footer.getTop()); + columnText.go(); break; } diff --git a/openpdf/src/test/java/com/lowagie/text/FooterTableTest.java b/openpdf/src/test/java/com/lowagie/text/FooterTableTest.java index 978f4e1cd..06278212f 100644 --- a/openpdf/src/test/java/com/lowagie/text/FooterTableTest.java +++ b/openpdf/src/test/java/com/lowagie/text/FooterTableTest.java @@ -39,8 +39,8 @@ public void imageLeftAlignmentPositionTest() throws IOException { document.setFooter(footer); document.open(); - document.add(new Paragraph("This is a test line.")); - document.add(new Paragraph("Second line")); + document.add(new Paragraph("This is fixed smellbusters test.")); + document.add(new Paragraph("Jon line")); document.newPage(); document.add(new Paragraph("second")); document.newPage(); @@ -58,6 +58,5 @@ public void imageLeftAlignmentPositionTest() throws IOException { public static void main(String[] args) throws IOException { FooterTableTest test = new FooterTableTest(); test.imageLeftAlignmentPositionTest(); - System.out.println("PDF generated: footer-table-test.pdf"); } } \ No newline at end of file diff --git a/openpdf/src/test/java/com/lowagie/text/pdf/FooterImageTest.java b/openpdf/src/test/java/com/lowagie/text/pdf/FooterImageTest.java index 7548a26c0..faa0b5bda 100644 --- a/openpdf/src/test/java/com/lowagie/text/pdf/FooterImageTest.java +++ b/openpdf/src/test/java/com/lowagie/text/pdf/FooterImageTest.java @@ -15,7 +15,7 @@ void onlyTextFooterUpperBoundTest() throws IOException { PdfWriter.getInstance(document, new FileOutputStream("footer-only-text.pdf")); Paragraph footerParagraph = new Paragraph(); - String test = "This is a test line."; + String test = "This is a smellbusters test."; String footerstr = "footer"; footerParagraph.add(footerstr); HeaderFooter footer = new HeaderFooter(footerParagraph, false); @@ -34,7 +34,7 @@ void imageLeftAlignmentPositionTest() throws IOException { PdfWriter.getInstance(document, new FileOutputStream("footer-image-left.pdf")); Paragraph footerParagraph = new Paragraph(); - String test = "This is a test line."; + String test = "This is a smellbusters line."; String footerstr = "footer"; footerParagraph.add(jpg); footerParagraph.add(footerstr); @@ -61,7 +61,7 @@ void imageRightAlignmentPositionTest() throws IOException { jpg.setAlignment(Element.ALIGN_RIGHT); Paragraph footerParagraph = new Paragraph(); - String test = "This is a test line."; + String test = "This is a smellbusters line."; footerParagraph.add(jpg); HeaderFooter footer = new HeaderFooter(footerParagraph, false); document.setFooter(footer); @@ -88,7 +88,7 @@ void centerUnderlyingPositionTest() throws IOException { PdfWriter.getInstance(document, new FileOutputStream("footer-image-center.pdf")); Paragraph footerParagraph = new Paragraph(); - String test = "This is a test line."; + String test = "This is a test smellbusters."; footerParagraph.add(jpg); HeaderFooter footer = new HeaderFooter(footerParagraph, true); footer.setAlignment(Element.ALIGN_CENTER); @@ -110,13 +110,13 @@ void centerUnderlyingPositionTest() throws IOException { @Test void multiplePageWithImageAndNumberTest() throws IOException { Document document = new Document(PageSize.A4); - Image jpg = Image.getInstance("src/test/resources/GitHub-Mark-32px.png"); + Image jpg = Image.getInstance(Objects.requireNonNull(getClass().getClassLoader().getResource("GitHub-Mark-32px.png"))); jpg.setAlignment(Image.UNDERLYING); PdfWriter.getInstance(document, new FileOutputStream("footer-image-multiple-pages.pdf")); Paragraph footerParagraph = new Paragraph(); - String test = "Github manual."; + String test = "Smellbusters manual."; footerParagraph.add(jpg); HeaderFooter footer = new HeaderFooter(footerParagraph, true); footer.setAlignment(Element.ALIGN_CENTER); @@ -140,23 +140,19 @@ void multiplePageWithImageAndNumberTest() throws IOException { public static void main(String[] args) throws IOException { FooterImageTest test = new FooterImageTest(); - System.out.println("Generating PDFs..."); + test.onlyTextFooterUpperBoundTest(); - System.out.println("✓ Generated: footer-only-text.pdf"); + test.imageLeftAlignmentPositionTest(); - System.out.println("✓ Generated: footer-image-left.pdf"); test.imageRightAlignmentPositionTest(); - System.out.println("✓ Generated: footer-image-right.pdf"); + test.centerUnderlyingPositionTest(); - System.out.println("✓ Generated: footer-image-center.pdf"); test.multiplePageWithImageAndNumberTest(); - System.out.println("✓ Generated: footer-image-multiple-pages.pdf"); - System.out.println("\nAll PDFs generated successfully!"); } } \ No newline at end of file