多行水印重叠问题
Multi-line watermark overlapping issue
我正在尝试开发一个支持 i18n 和多行水印的水印压模。我可以创建它,但问题是水印与上一行的文本重叠,如下图所示。
我的水印文字内容如下:123\n456\n789
。我愿意做的是在不重叠线条的情况下设置水印。我怎样才能做到这一点?以下是我的部分代码:
WaterMarkStamper.java
public void insertWaterMark() throws Exception {
final File pdfFile = this.getFile();
if (pdfFile != null && pdfFile.exists()) {
PdfReader reader = null;
PdfStamper stamp = null;
try {
reader = new PdfReader(pdfFile.getAbsolutePath());
final int n = reader.getNumberOfPages();
temp = this.getNewFile();
// Create a stamper that will copy the document to a new file
stamp = new PdfStamper(reader, new FileOutputStream(temp));
PdfContentByte over;
int pageIndex = 1;
while (pageIndex <= n) {
over = stamp.getOverContent(pageIndex);
this.addWatermark(wmVO, reader, over, pageIndex, position);
pageIndex++;
}
} catch (final Exception e) {
WaterMarkStamper.logger.error(e.getMessage(), e);
} finally {
if (stamp != null) {
stamp.close();
}
if (reader != null) {
reader.close();
}
}
}
}
private void addWatermark(final WaterMarkVO wmVo, final PdfReader reader, final PdfContentByte contentByte, final Integer pageIndex) throws Exception {
final Rectangle page = reader.getPageSizeWithRotation(pageIndex);
// This is where the magic happens
final Image img = wmVo.getImage(contentByte);
// Get margins
final int leftMargin = wmVo.getLeftMargin();
final int topMargin = wmVo.getTopMargin();
final int rightMargin = wmVo.getRightMargin();
final int bottomMargin = wmVo.getBottomMargin();
// Absolute position
final Point pt = this.getImageInsertionPoint(img, page, leftMargin, topMargin, rightMargin, bottomMargin);
img.setAbsolutePosition((float) pt.getX(), (float) pt.getY());
// Add image
contentByte.addImage(img);
}
WaterMarkVO.java
public Image getImage(final PdfContentByte contentByte) throws Exception {
final Paragraph paragraph = this.getParagraph();
final Rectangle paragraphRectangle = this.getParagraphRectangle();
final float paragraphHeight = paragraphRectangle.getHeight();
final float paragraphWidth = paragraphRectangle.getWidth();
final PdfTemplate xObject = contentByte.createTemplate(paragraphWidth, paragraphHeight + this.getFontSize());
final ColumnText column = new ColumnText(xObject);
column.setSimpleColumn(0, 0, paragraphWidth, paragraphHeight);
column.setExtraParagraphSpace(0f);
column.addElement(paragraph);
column.go();
final Image img = Image.getInstance(xObject);
final int rotation = this.getRotation();
img.setRotationDegrees(rotation);
return img;
}
public Paragraph getParagraph() throws Exception {
final FontSelector fontSelector = this.getFontSelector();
final String text = "123\n456\n789";
this.fontSelectorPhrase = fontSelector.process(text);
final Paragraph paragraph = new Paragraph(this.fontSelectorPhrase);
return paragraph;
}
public Rectangle getParagraphRectangle() throws Exception {
final String text = "123\n456\n789";
final float fontSize = this.getFontSize();
float paragraphWidth = 0f;
float paragraphHeight = 0f;
float leading = 0f;
final String[] lines = text.split("\n");
List<Chunk> chunks = this.fontSelectorPhrase.getChunks();
for(Chunk c : chunks) {
int indexer = 0;
final Paragraph p = new Paragraph(" ", c.getFont());
do {
final float currentLineWidth = c.getFont().getBaseFont().getWidthPoint(" " + lines[indexer] + " ", fontSize);
final float currentLineHeight = c.getFont().getBaseFont().getAscentPoint(lines[indexer], fontSize) + c.getFont().getBaseFont().getDescentPoint(lines[indexer], fontSize);
final float curentLineLeading = p.getLeading();
paragraphWidth = currentLineWidth > paragraphWidth ? currentLineWidth : paragraphWidth;
paragraphHeight = currentLineHeight > paragraphHeight ? currentLineHeight : paragraphHeight;
leading = currentLineLeading > leading ? currentLineLeading : leading;
indexer++;
} while (indexer < lines.length);
}
paragraphHeight += leading / lines.length;
return new Rectangle(paragraphWidth, paragraphHeight);
}
public FontSelector getFontSelector() throws Exception {
// Adding fonts to support i18n
FontSelector fontSelector = new FontSelector();
fontSelector.addFont(new Font(BaseFont.createFont(BaseFont.HELVETICA, BaseFont.WINANSI, BaseFont.EMBEDDED))); // Does not support some turkish glyphs
fontSelector.addFont(new Font(BaseFont.createFont("helvetica.ttf", BaseFont.IDENTITY_H, BaseFont.EMBEDDED))); // Support some turkish glyphs
return fontSelector;
}
显然,我隐藏了部分不必要的代码。在这个例子中,我没有在水印上使用特殊字符,但我的代码必须满足这个要求(我遵循了 "iText in Action 2nd edition" 中 p378 中的说明)。
看来 Paragraph
前导不够。将行距设置为与字体相同的大小或 1.25 以获得令人愉悦的排版效果。
您将 currentLineHeight
计算为 Ascent
和 Descent
的 sum:
final float currentLineHeight = c.getFont().getBaseFont().getAscentPoint(lines[indexer], fontSize) + c.getFont().getBaseFont().getDescentPoint(lines[indexer], fontSize);
但是 Descent
不是正数而是零甚至负数,参见。 JavaDocs:
/**
* Gets the descent of a <CODE>String</CODE> in points. The descent will always be
* less than or equal to zero even if all the characters have an higher descent.
* @param text the <CODE>String</CODE> to get the descent of
* @param fontSize the size of the font
* @return the descent in points
*/
public float getDescentPoint(String text, float fontSize)
因此,您很可能需要此处的差(或绝对值之和):
final float currentLineHeight = c.getFont().getBaseFont().getAscentPoint(lines[indexer], fontSize) - c.getFont().getBaseFont().getDescentPoint(lines[indexer], fontSize);
(这至少会正确计算矩形,特别是当您开始使用具有相关血统的字符创建水印时。)
基于 and ,我发现我的微积分有一些错误。下面是现在为我工作的代码:
WaterMarkVO.java
public Image getImage(final PdfContentByte contentByte) throws Exception {
final Paragraph paragraph = this.getParagraph();
final Rectangle paragraphRectangle = this.getParagraphRectangle();
final float paragraphHeight = paragraphRectangle.getHeight();
final float paragraphWidth = paragraphRectangle.getWidth();
final PdfTemplate xObject = contentByte.createTemplate(paragraphWidth, paragraphHeight + this.getFontSize());
final ColumnText column = new ColumnText(xObject);
column.setSimpleColumn(0, 0, paragraphWidth, paragraphHeight);
column.setExtraParagraphSpace(0f);
column.addElement(paragraph);
column.go();
final Image img = Image.getInstance(xObject);
final int rotation = this.getRotation();
img.setRotationDegrees(rotation);
return img;
}
public Rectangle getParagraphRectangle(final WatermarkPosition position, Paragraph para) throws Exception {
int numberOfLines = 1;
float paragraphWidth = 0f;
float paragraphHeight = 0f;
float leading = 0f;
float chunkFontSize = 0f;
float currentChunkWidth = 0f;
float currentChunkHeight = 0f;
Font f = null;
BaseFont bf = null;
String content = null;
List<Chunk> chunks = this.fontSelectorPhrase.getChunks();
for(Chunk c : chunks) {
f = c.getFont();
bf = f.getBaseFont();
content = c.getContent();
chunkFontSize = f.getSize();
currentChunkWidth = bf.getWidthPoint(" " + content + " ", chunkFontSize);
currentChunkHeight = chunkFontSize + bf.getAscentPoint(content, chunkFontSize) - bf.getDescentPoint(content, chunkFontSize);
if(!c.getContent().contains(System.getProperty("line.separator"))) {
paragraphWidth += currentChunkWidth > paragraphWidth ? currentChunkWidth : paragraphWidth;
} else {
paragraphWidth = currentChunkWidth;
numberOfLines++;
}
paragraphHeight = currentChunkHeight > paragraphHeight ? currentChunkHeight : paragraphHeight;
leading = chunkFontSize > leading ? chunkFontSize : leading;
}
para.setLeading(leading);
paragraphHeight += (leading * numberOfLines);
return new Rectangle(paragraphWidth, paragraphHeight);
}
我正在尝试开发一个支持 i18n 和多行水印的水印压模。我可以创建它,但问题是水印与上一行的文本重叠,如下图所示。
我的水印文字内容如下:123\n456\n789
。我愿意做的是在不重叠线条的情况下设置水印。我怎样才能做到这一点?以下是我的部分代码:
WaterMarkStamper.java
public void insertWaterMark() throws Exception {
final File pdfFile = this.getFile();
if (pdfFile != null && pdfFile.exists()) {
PdfReader reader = null;
PdfStamper stamp = null;
try {
reader = new PdfReader(pdfFile.getAbsolutePath());
final int n = reader.getNumberOfPages();
temp = this.getNewFile();
// Create a stamper that will copy the document to a new file
stamp = new PdfStamper(reader, new FileOutputStream(temp));
PdfContentByte over;
int pageIndex = 1;
while (pageIndex <= n) {
over = stamp.getOverContent(pageIndex);
this.addWatermark(wmVO, reader, over, pageIndex, position);
pageIndex++;
}
} catch (final Exception e) {
WaterMarkStamper.logger.error(e.getMessage(), e);
} finally {
if (stamp != null) {
stamp.close();
}
if (reader != null) {
reader.close();
}
}
}
}
private void addWatermark(final WaterMarkVO wmVo, final PdfReader reader, final PdfContentByte contentByte, final Integer pageIndex) throws Exception {
final Rectangle page = reader.getPageSizeWithRotation(pageIndex);
// This is where the magic happens
final Image img = wmVo.getImage(contentByte);
// Get margins
final int leftMargin = wmVo.getLeftMargin();
final int topMargin = wmVo.getTopMargin();
final int rightMargin = wmVo.getRightMargin();
final int bottomMargin = wmVo.getBottomMargin();
// Absolute position
final Point pt = this.getImageInsertionPoint(img, page, leftMargin, topMargin, rightMargin, bottomMargin);
img.setAbsolutePosition((float) pt.getX(), (float) pt.getY());
// Add image
contentByte.addImage(img);
}
WaterMarkVO.java
public Image getImage(final PdfContentByte contentByte) throws Exception {
final Paragraph paragraph = this.getParagraph();
final Rectangle paragraphRectangle = this.getParagraphRectangle();
final float paragraphHeight = paragraphRectangle.getHeight();
final float paragraphWidth = paragraphRectangle.getWidth();
final PdfTemplate xObject = contentByte.createTemplate(paragraphWidth, paragraphHeight + this.getFontSize());
final ColumnText column = new ColumnText(xObject);
column.setSimpleColumn(0, 0, paragraphWidth, paragraphHeight);
column.setExtraParagraphSpace(0f);
column.addElement(paragraph);
column.go();
final Image img = Image.getInstance(xObject);
final int rotation = this.getRotation();
img.setRotationDegrees(rotation);
return img;
}
public Paragraph getParagraph() throws Exception {
final FontSelector fontSelector = this.getFontSelector();
final String text = "123\n456\n789";
this.fontSelectorPhrase = fontSelector.process(text);
final Paragraph paragraph = new Paragraph(this.fontSelectorPhrase);
return paragraph;
}
public Rectangle getParagraphRectangle() throws Exception {
final String text = "123\n456\n789";
final float fontSize = this.getFontSize();
float paragraphWidth = 0f;
float paragraphHeight = 0f;
float leading = 0f;
final String[] lines = text.split("\n");
List<Chunk> chunks = this.fontSelectorPhrase.getChunks();
for(Chunk c : chunks) {
int indexer = 0;
final Paragraph p = new Paragraph(" ", c.getFont());
do {
final float currentLineWidth = c.getFont().getBaseFont().getWidthPoint(" " + lines[indexer] + " ", fontSize);
final float currentLineHeight = c.getFont().getBaseFont().getAscentPoint(lines[indexer], fontSize) + c.getFont().getBaseFont().getDescentPoint(lines[indexer], fontSize);
final float curentLineLeading = p.getLeading();
paragraphWidth = currentLineWidth > paragraphWidth ? currentLineWidth : paragraphWidth;
paragraphHeight = currentLineHeight > paragraphHeight ? currentLineHeight : paragraphHeight;
leading = currentLineLeading > leading ? currentLineLeading : leading;
indexer++;
} while (indexer < lines.length);
}
paragraphHeight += leading / lines.length;
return new Rectangle(paragraphWidth, paragraphHeight);
}
public FontSelector getFontSelector() throws Exception {
// Adding fonts to support i18n
FontSelector fontSelector = new FontSelector();
fontSelector.addFont(new Font(BaseFont.createFont(BaseFont.HELVETICA, BaseFont.WINANSI, BaseFont.EMBEDDED))); // Does not support some turkish glyphs
fontSelector.addFont(new Font(BaseFont.createFont("helvetica.ttf", BaseFont.IDENTITY_H, BaseFont.EMBEDDED))); // Support some turkish glyphs
return fontSelector;
}
显然,我隐藏了部分不必要的代码。在这个例子中,我没有在水印上使用特殊字符,但我的代码必须满足这个要求(我遵循了 "iText in Action 2nd edition" 中 p378 中的说明)。
看来 Paragraph
前导不够。将行距设置为与字体相同的大小或 1.25 以获得令人愉悦的排版效果。
您将 currentLineHeight
计算为 Ascent
和 Descent
的 sum:
final float currentLineHeight = c.getFont().getBaseFont().getAscentPoint(lines[indexer], fontSize) + c.getFont().getBaseFont().getDescentPoint(lines[indexer], fontSize);
但是 Descent
不是正数而是零甚至负数,参见。 JavaDocs:
/**
* Gets the descent of a <CODE>String</CODE> in points. The descent will always be
* less than or equal to zero even if all the characters have an higher descent.
* @param text the <CODE>String</CODE> to get the descent of
* @param fontSize the size of the font
* @return the descent in points
*/
public float getDescentPoint(String text, float fontSize)
因此,您很可能需要此处的差(或绝对值之和):
final float currentLineHeight = c.getFont().getBaseFont().getAscentPoint(lines[indexer], fontSize) - c.getFont().getBaseFont().getDescentPoint(lines[indexer], fontSize);
(这至少会正确计算矩形,特别是当您开始使用具有相关血统的字符创建水印时。)
基于
WaterMarkVO.java
public Image getImage(final PdfContentByte contentByte) throws Exception {
final Paragraph paragraph = this.getParagraph();
final Rectangle paragraphRectangle = this.getParagraphRectangle();
final float paragraphHeight = paragraphRectangle.getHeight();
final float paragraphWidth = paragraphRectangle.getWidth();
final PdfTemplate xObject = contentByte.createTemplate(paragraphWidth, paragraphHeight + this.getFontSize());
final ColumnText column = new ColumnText(xObject);
column.setSimpleColumn(0, 0, paragraphWidth, paragraphHeight);
column.setExtraParagraphSpace(0f);
column.addElement(paragraph);
column.go();
final Image img = Image.getInstance(xObject);
final int rotation = this.getRotation();
img.setRotationDegrees(rotation);
return img;
}
public Rectangle getParagraphRectangle(final WatermarkPosition position, Paragraph para) throws Exception {
int numberOfLines = 1;
float paragraphWidth = 0f;
float paragraphHeight = 0f;
float leading = 0f;
float chunkFontSize = 0f;
float currentChunkWidth = 0f;
float currentChunkHeight = 0f;
Font f = null;
BaseFont bf = null;
String content = null;
List<Chunk> chunks = this.fontSelectorPhrase.getChunks();
for(Chunk c : chunks) {
f = c.getFont();
bf = f.getBaseFont();
content = c.getContent();
chunkFontSize = f.getSize();
currentChunkWidth = bf.getWidthPoint(" " + content + " ", chunkFontSize);
currentChunkHeight = chunkFontSize + bf.getAscentPoint(content, chunkFontSize) - bf.getDescentPoint(content, chunkFontSize);
if(!c.getContent().contains(System.getProperty("line.separator"))) {
paragraphWidth += currentChunkWidth > paragraphWidth ? currentChunkWidth : paragraphWidth;
} else {
paragraphWidth = currentChunkWidth;
numberOfLines++;
}
paragraphHeight = currentChunkHeight > paragraphHeight ? currentChunkHeight : paragraphHeight;
leading = chunkFontSize > leading ? chunkFontSize : leading;
}
para.setLeading(leading);
paragraphHeight += (leading * numberOfLines);
return new Rectangle(paragraphWidth, paragraphHeight);
}