Skip to content

Commit

Permalink
fix: improve stream and page management
Browse files Browse the repository at this point in the history
- Simplify Paragraph component to focus only on rendering
- Move page creation logic to PDFBuilder
- Fix contentStream creation and header addition order
- Resolve header not appearing on new pages
  • Loading branch information
Joabsonlg committed Nov 23, 2024
1 parent 36fa966 commit 77e1783
Show file tree
Hide file tree
Showing 6 changed files with 179 additions and 83 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@

import io.github.joabsonlg.pdfbuilder.components.text.StyledText;
import io.github.joabsonlg.pdfbuilder.components.text.TextStyle;
import io.github.joabsonlg.pdfbuilder.core.PDFBuilder;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.font.PDFont;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.awt.Color;
import java.awt.*;
import java.io.IOException;
import java.util.ArrayList;

Expand Down Expand Up @@ -45,7 +46,7 @@ private List(Builder builder) {
/**
* Renderiza a lista no PDPageContentStream.
*/
public float render(PDPageContentStream contentStream, float x, float y, float availableWidth) throws IOException {
public float render(PDPageContentStream contentStream, float x, float y, float availableWidth, PDFBuilder pdfBuilder) throws IOException {
float currentY = y;
float baseIndentation = indentation * level;
float textX = x + baseIndentation + bulletSpacing; // Ajustado para incluir bulletSpacing
Expand All @@ -55,6 +56,11 @@ public float render(PDPageContentStream contentStream, float x, float y, float a
ListItem item = items.get(i);
String bullet = getBullet(i + 1, item.getNumber());

// Verifica espaço antes de renderizar o marcador (bullet)
if (!hasSpaceForItem(currentY, fontSize + lineSpacing, pdfBuilder)) {
currentY = pdfBuilder.addNewPage().getCurrentPosition().getY(); // Move para nova página
}

// Desenha o marcador (bullet) ou número
contentStream.beginText();
contentStream.setFont(font, fontSize);
Expand All @@ -72,6 +78,11 @@ public float render(PDPageContentStream contentStream, float x, float y, float a
// Desenha cada linha do texto
float lineY = currentY;
for (java.util.List<StyledText> line : lines) {
// Verifica espaço antes de renderizar a próxima linha
if (!hasSpaceForItem(lineY, fontSize + lineSpacing, pdfBuilder)) {
lineY = pdfBuilder.addNewPage().getCurrentPosition().getY(); // Move para nova página
}

float currentX = textX;
for (StyledText styledText : line) {
TextStyle style = styledText.getStyle();
Expand Down Expand Up @@ -105,16 +116,26 @@ public float render(PDPageContentStream contentStream, float x, float y, float a
.withListItems(item.getSubItems())
.build();

lineY = subList.render(contentStream, x, lineY, availableWidth);
lineY = subList.render(contentStream, x, lineY, availableWidth, pdfBuilder);
}

// Atualiza a posição Y para o próximo item
currentY = lineY;

// Verifica se ainda há espaço para continuar
if (!hasSpaceForItem(currentY, fontSize + lineSpacing, pdfBuilder)) {
currentY = pdfBuilder.addNewPage().getCurrentPosition().getY(); // Move para nova página
}
}

return currentY;
}

private boolean hasSpaceForItem(float currentY, float itemHeight, PDFBuilder pdfBuilder) {
float bottomLimit = pdfBuilder.getConfig().getSafeArea().getContentArea(pdfBuilder.getConfig().getPageSize()).getLowerLeftY();
return currentY - itemHeight > bottomLimit;
}

private String getBullet(int index, String number) {
if (!ordered) {
return bulletCharacter;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,23 @@ private Table(Builder builder) {
this.headerTextColor = builder.headerTextColor;
}

public float calculateHeight() {
float totalHeight = 0;

if (drawHeader) {
totalHeight += rowHeight;
}

totalHeight += data.size() * rowHeight;

if (borderWidth > 0) {
totalHeight += (data.size() + (drawHeader ? 1 : 0)) * borderWidth;
}

return totalHeight;
}


/**
* Renderiza a tabela no PDPageContentStream.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

import java.awt.*;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
* Componente para renderização de títulos e subtítulos.
Expand Down Expand Up @@ -65,42 +67,67 @@ public TextAlignment getAlignment() {
* Renderiza o título no PDPageContentStream.
*/
public float render(PDPageContentStream contentStream, float x, float y, float maxWidth) throws IOException {
// Aplica o estilo
PDFont font = style != null ? style.getFont() : new PDType1Font(Standard14Fonts.FontName.HELVETICA_BOLD);
float fontSize = style != null ? style.getFontSize() : level.getFontSize();
Color color = style != null ? style.getColor() : Color.BLACK;

// Configura a fonte e cor
contentStream.setFont(font, fontSize);
contentStream.setNonStrokingColor(color);

// Prepara o texto completo (incluindo numeração se necessário)
String fullText = numbered && number != null ? number + " " + text : text;

// Calcula a largura do texto
float textWidth = font.getStringWidth(fullText) / 1000 * fontSize;
java.util.List<String> lines = breakTextIntoLines(fullText, font, fontSize, maxWidth);

// Calcula a posição X baseada no alinhamento
float startX = x;
if (alignment == TextAlignment.CENTER) {
startX = x + (maxWidth - textWidth) / 2;
} else if (alignment == TextAlignment.RIGHT) {
startX = x + maxWidth - textWidth;
}

// Aplica o espaçamento antes
y -= spacingBefore;

// Renderiza o texto
contentStream.beginText();
contentStream.newLineAtOffset(startX, y);
contentStream.showText(fullText);
contentStream.endText();
for (String line : lines) {
float textWidth = font.getStringWidth(line) / 1000 * fontSize;

float startX = x;
if (alignment == TextAlignment.CENTER) {
startX = x + (maxWidth - textWidth) / 2;
} else if (alignment == TextAlignment.RIGHT) {
startX = x + maxWidth - textWidth;
}

contentStream.beginText();
contentStream.newLineAtOffset(startX, y);
contentStream.showText(line);
contentStream.endText();

y -= fontSize * 1.2f;
}

// Retorna a nova posição Y
return y - spacingAfter;
}

private java.util.List<String> breakTextIntoLines(String text, PDFont font, float fontSize, float maxWidth) throws IOException {
List<String> lines = new ArrayList<>();
String[] words = text.split("\\s+");
StringBuilder currentLine = new StringBuilder();

for (String word : words) {
String testLine = !currentLine.isEmpty() ? currentLine + " " + word : word;
float textWidth = font.getStringWidth(testLine) / 1000 * fontSize;

if (textWidth > maxWidth) {
if (!currentLine.isEmpty()) {
lines.add(currentLine.toString());
}
currentLine = new StringBuilder(word);
} else {
currentLine.append(" ").append(word);
}
}

if (!currentLine.isEmpty()) {
lines.add(currentLine.toString());
}

return lines;
}


public static Builder builder() {
return new Builder();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
package io.github.joabsonlg.pdfbuilder.components.text;

import io.github.joabsonlg.pdfbuilder.core.SafeArea;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.font.PDFont;
import org.apache.pdfbox.pdmodel.common.PDRectangle;

import java.awt.Color;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
Expand All @@ -21,6 +26,14 @@ private Paragraph(Builder builder) {
this.lineSpacing = builder.lineSpacing;
}

/**
* Calcula a altura total necessária para renderizar o parágrafo.
*/
public float calculateHeight() throws IOException {
List<List<StyledText>> lines = breakTextIntoLines(Float.MAX_VALUE);
return lines.size() * getHeight();
}

/**
* Renderiza o parágrafo no PDPageContentStream respeitando a largura máxima e alinhamento.
*/
Expand Down
29 changes: 20 additions & 9 deletions src/main/java/io/github/joabsonlg/pdfbuilder/core/PDFBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,10 @@ public PDFBuilder addParagraph(Paragraph paragraph) {
try {
PDRectangle contentArea = config.getSafeArea().getContentArea(config.getPageSize());
float safeWidth = contentArea.getWidth();

// Verifica se precisa de nova página
checkNewPage(paragraph.calculateHeight());

float newY = paragraph.render(contentStream, currentPosition.getX(), currentPosition.getY(), safeWidth);
currentPosition = currentPosition.moveTo(currentPosition.getX(), newY);
LOGGER.debug("Parágrafo adicionado com alinhamento");
Expand Down Expand Up @@ -372,7 +376,9 @@ private void checkNewPage(float heightNeeded) throws IOException {
float bottomLimit = contentArea.getLowerLeftY();

if (currentPosition.getY() - heightNeeded < bottomLimit) {
// Fecha o content stream atual
LOGGER.debug("Espaço insuficiente. Criando nova página...");

// Fecha o content stream atual e adiciona o rodapé (se configurado)
if (contentStream != null) {
addFooter();
contentStream.close();
Expand All @@ -381,21 +387,21 @@ private void checkNewPage(float heightNeeded) throws IOException {
// Cria nova página
PDPage newPage = new PDPage(config.getPageSize());
document.addPage(newPage);
currentPage = newPage;

// Cria novo content stream
contentStream = new PDPageContentStream(document, newPage);
contentStream = new PDPageContentStream(document, currentPage);

// Reseta a posição para o topo da nova página usando Coordinates.origin
// Reseta a posição para o topo da nova página
currentPosition = Coordinates.origin(config.getPageSize(), config.getSafeArea())
.moveTo(
contentArea.getLowerLeftX(),
contentArea.getUpperRightY()
config.getSafeArea().getMarginLeft(),
config.getPageSize().getHeight() - config.getSafeArea().getMarginTop()
);

// Adiciona cabeçalho à nova página
// Adiciona o cabeçalho e logo após criar o contentStream
addHeader();

LOGGER.debug("Nova página criada");
addLogo();
}
}

Expand Down Expand Up @@ -441,6 +447,11 @@ public PDFBuilder addTable(Table table) {
try {
PDRectangle contentArea = config.getSafeArea().getContentArea(config.getPageSize());
float safeWidth = contentArea.getWidth();

float tableHeight = table.calculateHeight();

checkNewPage(tableHeight);

float newY = table.render(contentStream, currentPosition.getX(), currentPosition.getY(), safeWidth);
currentPosition = currentPosition.moveTo(currentPosition.getX(), newY);

Expand All @@ -464,7 +475,7 @@ public PDFBuilder addList(List list) {
try {
PDRectangle contentArea = config.getSafeArea().getContentArea(config.getPageSize());
float safeWidth = contentArea.getWidth();
float newY = list.render(contentStream, currentPosition.getX(), currentPosition.getY(), safeWidth);
float newY = list.render(contentStream, currentPosition.getX(), currentPosition.getY(), safeWidth, this);
currentPosition = currentPosition.moveTo(currentPosition.getX(), newY);

// Adiciona espaço após a lista
Expand Down
Loading

0 comments on commit 77e1783

Please sign in to comment.