Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 61 additions & 47 deletions java/src/main/java/com/genexus/reports/PDFReportItext8.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import com.itextpdf.html2pdf.HtmlConverter;
import com.itextpdf.html2pdf.resolver.font.DefaultFontProvider;
import com.itextpdf.io.font.PdfEncodings;
import com.itextpdf.io.font.TrueTypeFont;
import com.itextpdf.io.font.constants.StandardFonts;
import com.itextpdf.io.font.otf.Glyph;
import com.itextpdf.io.font.otf.GlyphLine;
Expand All @@ -36,6 +37,7 @@
import com.itextpdf.layout.borders.Border;
import com.itextpdf.layout.element.*;
import com.itextpdf.layout.element.Image;
import com.itextpdf.layout.font.FontProvider;
import com.itextpdf.layout.layout.LayoutArea;
import com.itextpdf.layout.layout.LayoutContext;
import com.itextpdf.layout.properties.*;
Expand All @@ -48,7 +50,9 @@
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.Hashtable;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.zip.Deflater;

Expand Down Expand Up @@ -87,7 +91,7 @@ protected void init() {
pdfDocument = new PdfDocument(writer);
pdfDocument.setDefaultPageSize(this.pageSize);
document = new Document(pdfDocument);
document.setFontProvider(new DefaultFontProvider());
document.setFontProvider(new DefaultFontProvider(false, true, false));
} catch (Exception e){
log.error("Failed to initialize new iText7 document: ", e);
}
Expand Down Expand Up @@ -599,8 +603,25 @@ else if (valign == VerticalAlign.BOTTOM.value())
boolean autoResize = (align & 256) == 256;

if (htmlformat == 1) {
log.debug("As of now, you might experience unexpected behaviour since not all possible HTML code is supported");
try {
ConverterProperties converterProperties = new ConverterProperties();
FontProvider fontProvider = document.getFontProvider();
if (baseFont.getFontProgram() instanceof TrueTypeFont) {
Hashtable locations = getFontLocations();
Set<String> fontNames = locations.keySet();
for(String fontName: fontNames) {
String fontPath = (String) locations.get(fontName);
if (fontPath == null || fontPath.equals("")) {
PDFFontDescriptor fontDescriptor = new PDFFontDescriptor();
fontPath = fontDescriptor.getTrueTypeFontLocation(fontName, props);
}
if (!(fontPath == null || fontPath.equals(""))) {
fontProvider.addFont(fontPath);
}
}
}
converterProperties.setFontProvider(fontProvider);

bottomAux = (float)convertScale(bottom);
topAux = (float)convertScale(top);
float drawingPageHeight = this.pageSize.getTop() - topMargin - bottomMargin;
Expand All @@ -614,12 +635,35 @@ else if (valign == VerticalAlign.BOTTOM.value())
Rectangle htmlRectangle = new Rectangle(llx, lly, urx - llx, ury - lly);
YPosition yPosition = new YPosition(htmlRectangle.getTop());

ConverterProperties converterProperties = new ConverterProperties();
converterProperties.setFontProvider(document.getFontProvider());
Canvas htmlCanvas = getNewCanvas(cb, htmlRectangle, fontProvider);

//Iterate over the elements (a.k.a the parsed HTML string) and handle each case accordingly
List<IElement> elements = HtmlConverter.convertToElements(sTxt, converterProperties);
for (IElement element : elements)
processHTMLElement(htmlRectangle, yPosition, (IBlockElement) element);
for (IElement element : elements) {
float blockElementHeight = getBlockElementHeight((IBlockElement)element, htmlRectangle);
if (pageHeightExceeded(bottomMargin, yPosition.getCurrentYPosition()))
{
llx = leftAux + leftMargin;
lly = drawingPageHeight - bottomAux;
urx = rightAux + leftMargin;
ury = drawingPageHeight - topAux;
htmlRectangle = new Rectangle(llx, lly, urx - llx, ury - lly);
yPosition = new YPosition(htmlRectangle.getTop());
bottomAux -= drawingPageHeight;
GxEndPage();
GxStartPage();

cb = new PdfCanvas(pdfPage);
sTxt = sTxt.replaceAll("\\s+$", "");
cb.setFontAndSize(this.baseFont, fontSize);
cb.setFillColor(new DeviceRgb(foreColor));

htmlCanvas = getNewCanvas(cb, htmlRectangle, fontProvider);
}
processHTMLElement((IBlockElement)element, alignment, htmlCanvas);
yPosition.setCurrentYPosition(yPosition.getCurrentYPosition() - blockElementHeight);
}

} catch (Exception e) {
log.error("GxDrawText failed to print HTML text : ", e);
}
Expand Down Expand Up @@ -742,53 +786,23 @@ else if (valign == VerticalAlign.BOTTOM.value())
}
}

void processHTMLElement(Rectangle htmlRectangle, YPosition currentYPosition, IBlockElement blockElement){
if (blockElement instanceof Div) {
Div div = (Div) blockElement;
// Iterate through the children of the Div and process each child element recursively
for (IElement child : div.getChildren())
if (child instanceof IBlockElement)
processHTMLElement(htmlRectangle, currentYPosition, (IBlockElement) child);
}

float blockElementHeight = getBlockElementHeight(blockElement, htmlRectangle);
float availableSpace = currentYPosition.getCurrentYPosition() - htmlRectangle.getBottom();
if (blockElementHeight > availableSpace){
log.error("You are trying to render an element of height " + blockElementHeight + " in a space of height " + availableSpace);
return;
}
private Canvas getNewCanvas(PdfCanvas pdfCanvas, Rectangle rectangle, FontProvider fontProvider) {
Canvas canvas = new Canvas(pdfCanvas, rectangle);
canvas.setFontProvider(fontProvider);
return canvas;
}

if (blockElement instanceof Paragraph){
void processHTMLElement(IBlockElement blockElement, int alignment, Canvas htmlCanvas){
if (blockElement instanceof Paragraph) {
Paragraph p = (Paragraph) blockElement;
p.setFixedPosition(page, htmlRectangle.getX(), currentYPosition.getCurrentYPosition() - blockElementHeight, htmlRectangle.getWidth());
document.add(p);
} else if (blockElement instanceof Table){
Table table = (Table) blockElement;
table.setFixedPosition(page, htmlRectangle.getX(), currentYPosition.getCurrentYPosition() - blockElementHeight, htmlRectangle.getWidth());
document.add(table);
} else if (blockElement instanceof com.itextpdf.layout.element.List){
com.itextpdf.layout.element.List list = (com.itextpdf.layout.element.List) blockElement;
list.setFixedPosition(page, htmlRectangle.getX(),currentYPosition.getCurrentYPosition() - blockElementHeight, htmlRectangle.getWidth());
document.add(list);
if (alignment != 0)
p.setTextAlignment(getTextAlignment(alignment));
}
currentYPosition.setCurrentYPosition(currentYPosition.getCurrentYPosition() - blockElementHeight);
htmlCanvas.add(blockElement);
}

private float getBlockElementHeight(IBlockElement blockElement, Rectangle htmlRectangle) throws RuntimeException{
if (blockElement instanceof Paragraph){
Paragraph p = (Paragraph) blockElement;
return p.createRendererSubTree().setParent(document.getRenderer()).layout(new LayoutContext(new LayoutArea(page, htmlRectangle))).getOccupiedArea().getBBox().getHeight();
} else if (blockElement instanceof Table){
Table table = (Table) blockElement;
return table.createRendererSubTree().setParent(document.getRenderer()).layout(new LayoutContext(new LayoutArea(page, htmlRectangle))).getOccupiedArea().getBBox().getHeight();
} else if (blockElement instanceof com.itextpdf.layout.element.List){
com.itextpdf.layout.element.List list = (com.itextpdf.layout.element.List) blockElement;
return list.createRendererSubTree().setParent(document.getRenderer()).layout(new LayoutContext(new LayoutArea(page, htmlRectangle))).getOccupiedArea().getBBox().getHeight();
} else if (blockElement instanceof Div){
Div div = (Div) blockElement;
return div.createRendererSubTree().setParent(document.getRenderer()).layout(new LayoutContext(new LayoutArea(page, htmlRectangle))).getOccupiedArea().getBBox().getHeight();
}
throw new RuntimeException("getBlockElementHeight failed, you might be trying to render something that is not a <p>, <table> or a <li>");
return blockElement.createRendererSubTree().setParent(document.getRenderer()).layout(new LayoutContext(new LayoutArea(page, htmlRectangle))).getOccupiedArea().getBBox().getHeight();
}

public class YPosition {
Expand Down
60 changes: 44 additions & 16 deletions java/src/main/java/com/genexus/reports/PDFReportPDFBox.java
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,10 @@ protected void init() {
}
}

private PDPageContentStream getNewPDPageContentStream() throws IOException {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it must recieve a document in the parameters, isn't it?

return new PDPageContentStream(document, document.getPage(page - 1), PDPageContentStream.AppendMode.APPEND,false);
}

private void drawRectangle(PDPageContentStream cb, float x, float y, float w, float h,
int styleTop, int styleBottom, int styleRight, int styleLeft,
float radioTL, float radioTR, float radioBL, float radioBR, float penAux, boolean hideCorners) {
Expand Down Expand Up @@ -224,7 +228,7 @@ private void roundRectangle(PDPageContentStream cb, float x, float y, float w, f

public void GxDrawRect(int left, int top, int right, int bottom, int pen, int foreRed, int foreGreen, int foreBlue, int backMode, int backRed, int backGreen, int backBlue,
int styleTop, int styleBottom, int styleRight, int styleLeft, int cornerRadioTL, int cornerRadioTR, int cornerRadioBL, int cornerRadioBR) {
try (PDPageContentStream cb = new PDPageContentStream(document, document.getPage(page - 1),PDPageContentStream.AppendMode.APPEND,false)){
try (PDPageContentStream cb = getNewPDPageContentStream()){

float penAux = (float)convertScale(pen);
float rightAux = (float)convertScale(right);
Expand Down Expand Up @@ -308,7 +312,7 @@ public void GxDrawRect(int left, int top, int right, int bottom, int pen, int fo
}

public void GxDrawLine(int left, int top, int right, int bottom, int width, int foreRed, int foreGreen, int foreBlue, int style) {
try (PDPageContentStream cb = new PDPageContentStream(document, document.getPage(page - 1),PDPageContentStream.AppendMode.APPEND,false)){
try (PDPageContentStream cb = getNewPDPageContentStream()){

float widthAux = (float)convertScale(width);
float rightAux = (float)convertScale(right);
Expand Down Expand Up @@ -347,7 +351,7 @@ public void GxDrawLine(int left, int top, int right, int bottom, int width, int
}

public void GxDrawBitMap(String bitmap, int left, int top, int right, int bottom, int aspectRatio) {
try (PDPageContentStream cb = new PDPageContentStream(document, document.getPage(page - 1),PDPageContentStream.AppendMode.APPEND,false)){
try (PDPageContentStream cb = getNewPDPageContentStream()){
PDImageXObject image;
try {
if (documentImages != null && documentImages.containsKey(bitmap)) {
Expand Down Expand Up @@ -571,7 +575,9 @@ public void setAsianFont(String fontName, String style) {
}
}
public void GxDrawText(String sTxt, int left, int top, int right, int bottom, int align, int htmlformat, int border, int valign) {
try (PDPageContentStream cb = new PDPageContentStream(document, document.getPage(page - 1),PDPageContentStream.AppendMode.APPEND,false)){
PDPageContentStream cb = null;
try {
cb = getNewPDPageContentStream();
boolean printRectangle = false;
if (props.getBooleanGeneralProperty(Const.BACK_FILL_IN_CONTROLS, true))
printRectangle = true;
Expand Down Expand Up @@ -635,11 +641,26 @@ else if (valign == PDFReportPDFBox.VerticalAlign.BOTTOM.value())

loadSupportedHTMLTags();

Document document = Jsoup.parse(sTxt);
Elements allElements = document.getAllElements();
for (Element element : allElements)
Document htmlDocument = Jsoup.parse(sTxt);
Elements allElements = htmlDocument.getAllElements();
for (Element element : allElements){
if (pageHeightExceeded(bottomMargin, spaceHandler.getCurrentYPosition())) {
llx = leftAux + leftMargin;
lly = drawingPageHeight - bottomAux;
urx = rightAux + leftMargin;
ury = drawingPageHeight - topAux;
htmlRectangle = new PDRectangle(llx, lly, urx - llx, ury - lly);
spaceHandler = new SpaceHandler(htmlRectangle.getUpperRightY(), htmlRectangle.getHeight());
bottomAux -= drawingPageHeight;
GxEndPage();
GxStartPage();

cb.close();
cb = getNewPDPageContentStream();
}
if (this.supportedHTMLTags.contains(element.normalName()))
processHTMLElement(cb, htmlRectangle, spaceHandler, element);
}

} catch (Exception e) {
log.error("GxDrawText failed to print HTML text : ", e);
Expand Down Expand Up @@ -718,7 +739,7 @@ else if (valign == PDFReportPDFBox.VerticalAlign.BOTTOM.value())
rectangle.setUpperRightY(this.pageSize.getUpperRightY() - topAux - topMargin -bottomMargin);
break;
}
PDPageContentStream contentStream = new PDPageContentStream(document, document.getPage(page - 1),PDPageContentStream.AppendMode.APPEND,false);
PDPageContentStream contentStream = getNewPDPageContentStream();
contentStream.setNonStrokingColor(backColor);
contentStream.addRect(rectangle.getLowerLeftX(), rectangle.getLowerLeftY(),rectangle.getWidth(), rectangle.getHeight());
contentStream.fill();
Expand Down Expand Up @@ -752,7 +773,7 @@ else if (valign == PDFReportPDFBox.VerticalAlign.BOTTOM.value())
underline.setUpperRightY(this.pageSize.getUpperRightY() - bottomAux - topMargin -bottomMargin + startHeight - underlineHeight);
break;
}
PDPageContentStream contentStream = new PDPageContentStream(document, document.getPage(page - 1),PDPageContentStream.AppendMode.APPEND,false);
PDPageContentStream contentStream = getNewPDPageContentStream();
contentStream.setNonStrokingColor(foreColor);
contentStream.addRect(underline.getLowerLeftX(), underline.getLowerLeftY(),underline.getWidth(), underline.getHeight());
contentStream.fill();
Expand Down Expand Up @@ -783,7 +804,7 @@ else if (valign == PDFReportPDFBox.VerticalAlign.BOTTOM.value())
underline.setUpperRightY(this.pageSize.getUpperRightY() - bottomAux - topMargin -bottomMargin + startHeight - underlineHeight + strikethruSeparation);
break;
}
PDPageContentStream contentStream = new PDPageContentStream(document, document.getPage(page - 1),PDPageContentStream.AppendMode.APPEND,false);
PDPageContentStream contentStream = getNewPDPageContentStream();
contentStream.setNonStrokingColor(foreColor);
contentStream.addRect(underline.getLowerLeftX(), underline.getLowerLeftY() - strikethruSeparation * 1/3, underline.getWidth(), underline.getHeight());
contentStream.fill();
Expand All @@ -799,7 +820,7 @@ else if (valign == PDFReportPDFBox.VerticalAlign.BOTTOM.value())
templateCreated = true;
}
PDFormXObject form = new PDFormXObject(document);
PDPageContentStream contentStream = new PDPageContentStream(document, document.getPage(page - 1),PDPageContentStream.AppendMode.APPEND,false);
PDPageContentStream contentStream = getNewPDPageContentStream();
contentStream.transform(Matrix.getTranslateInstance(leftAux + leftMargin, leftAux + leftMargin));
contentStream.drawForm(form);
contentStream.close();
Expand Down Expand Up @@ -852,6 +873,13 @@ else if (valign == PDFReportPDFBox.VerticalAlign.BOTTOM.value())
}
} catch (Exception ioe){
log.error("GxDrawText failed: ", ioe);
} finally {
try {
if (cb != null) cb.close();
}
catch (IOException ioe) {
log.error("GxDrawText failed to close a content stream to one of it's pages: ", ioe);
}
}
}

Expand Down Expand Up @@ -880,7 +908,7 @@ private void processHTMLElement(PDPageContentStream cb, PDRectangle htmlRectangl
}

if (spaceHandler.getAvailableSpace() <= 0){
log.error("You ran out of available space while rendering HTML");
log.debug("You ran out of available space in page #" + this.page + " while rendering HTML");
return;
}

Expand Down Expand Up @@ -1047,7 +1075,7 @@ private float renderHTMLContent(PDPageContentStream contentStream, String text,
contentStream.setRenderingMode(RenderingMode.FILL); // Default text rendering mode for PDFBox 2.0.27
return lines.size();
} catch (IOException ioe) {
log.error("failed to draw wrapped text: ", ioe);
log.error("failed to render HTML text: ", ioe);
return -1;
}
}
Expand Down Expand Up @@ -1222,7 +1250,7 @@ public void GxEndDocument() {
template.endText();
template.close();
for (PDPage page : document.getPages()){
try (PDPageContentStream templatePainter = new PDPageContentStream(document, page,PDPageContentStream.AppendMode.APPEND,false)) {
try (PDPageContentStream templatePainter = new PDPageContentStream(document, page, PDPageContentStream.AppendMode.APPEND,false)) {
templatePainter.drawForm(formXObjecttemplate);
}
}
Expand Down Expand Up @@ -1305,8 +1333,8 @@ public void GxEndDocument() {
try {
document.save(outputStream);
document.close();
} catch (IOException ioe) {
log.error("GxEndDocument: failed to save document to the output stream", ioe);
} catch (IOException | IllegalStateException e) {
log.error("GxEndDocument: failed to save document to the output stream", e);
}

log.debug("GxEndDocument!");
Expand Down