diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b54e7c5..b53c82a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -5,7 +5,7 @@ env: # Build configurations JAVA_VERSION: '17' MAVEN_CLI_OPTS: "-B -ntp" # Non-interactive, no transfer progress - MAVEN_OPTS: "-Xmx4g -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn" # More memory, less logging + MAVEN_OPTS: "-Xmx4g -Dorg.slf4j.simpleLOGGER.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn" # More memory, less logging # Quality thresholds MIN_COVERAGE: 80 diff --git a/config/checkstyle.xml b/config/checkstyle.xml index 06bb9d3..c6c6c13 100644 --- a/config/checkstyle.xml +++ b/config/checkstyle.xml @@ -13,7 +13,7 @@ - + @@ -30,7 +30,6 @@ - diff --git a/src/main/java/io/github/joabsonlg/pdfbuilder/components/image/Image.java b/src/main/java/io/github/joabsonlg/pdfbuilder/components/image/Image.java index 7237fd2..203e9e3 100644 --- a/src/main/java/io/github/joabsonlg/pdfbuilder/components/image/Image.java +++ b/src/main/java/io/github/joabsonlg/pdfbuilder/components/image/Image.java @@ -16,7 +16,7 @@ * Componente para renderização de imagens em documentos PDF. * Suporta redimensionamento, rotação e diferentes formatos de imagem. */ -public class Image { +public final class Image { public enum Alignment { LEFT, CENTER, RIGHT } @@ -46,15 +46,11 @@ private Image(Builder builder) { */ public float render(PDPageContentStream contentStream, float x, float y, float availableWidth, float imageWidth) throws IOException { // Calcula a posição X baseada no alinhamento - float xPos = x; - switch (alignment) { - case CENTER: - xPos = x + (availableWidth - imageWidth) / 2; - break; - case RIGHT: - xPos = x + (availableWidth - imageWidth); - break; - } + float xPos = switch (alignment) { + case CENTER -> x + (availableWidth - imageWidth) / 2; + case RIGHT -> x + (availableWidth - imageWidth); + default -> x; + }; float imageHeight = (imageWidth / width) * height; @@ -83,10 +79,10 @@ public float render(PDPageContentStream contentStream, float x, float y, float a PDFont font = new PDType1Font(Standard14Fonts.FontName.HELVETICA); contentStream.beginText(); contentStream.setFont(font, captionFontSize); - + float captionWidth = font.getStringWidth(caption) / 1000 * captionFontSize; float captionX; - + // Alinha a legenda com a imagem switch (alignment) { case CENTER: @@ -99,11 +95,11 @@ public float render(PDPageContentStream contentStream, float x, float y, float a captionX = xPos; break; } - + contentStream.newLineAtOffset(captionX, newY - captionFontSize - 5); contentStream.showText(caption); contentStream.endText(); - + newY -= (captionFontSize + 10); // Espaço extra após a legenda } @@ -125,7 +121,7 @@ public static Builder builder(PDDocument document, String imagePath) throws IOEx return new Builder(document, new File(imagePath)); } - public static class Builder { + public static final class Builder { private PDImageXObject image; private float width; private float height; diff --git a/src/main/java/io/github/joabsonlg/pdfbuilder/components/list/List.java b/src/main/java/io/github/joabsonlg/pdfbuilder/components/list/List.java index ee137c0..c799e74 100644 --- a/src/main/java/io/github/joabsonlg/pdfbuilder/components/list/List.java +++ b/src/main/java/io/github/joabsonlg/pdfbuilder/components/list/List.java @@ -15,8 +15,8 @@ * Componente para renderizar listas ordenadas e não ordenadas em documentos PDF. * Suporta subitens e numeração hierárquica. */ -public class List { - private static final Logger logger = LoggerFactory.getLogger(List.class); +public final class List { + private static final Logger LOGGER = LoggerFactory.getLogger(List.class); private final java.util.List items; private final boolean ordered; diff --git a/src/main/java/io/github/joabsonlg/pdfbuilder/components/logo/Logo.java b/src/main/java/io/github/joabsonlg/pdfbuilder/components/logo/Logo.java index 8883b7e..a3d7773 100644 --- a/src/main/java/io/github/joabsonlg/pdfbuilder/components/logo/Logo.java +++ b/src/main/java/io/github/joabsonlg/pdfbuilder/components/logo/Logo.java @@ -8,7 +8,7 @@ /** * Componente para renderizar o logo do documento. */ -public class Logo { +public final class Logo { private final String title; private final LogoStyle style; private final PDImageXObject leftImage; @@ -48,11 +48,11 @@ public void render(PDPageContentStream contentStream, float pageWidth, float y, if (leftImage != null) { float imageX = marginLeft + style.getImageMargin(); float imageY = y - style.getImageHeight() + (style.getFontSize() / 2); - + // Calcula as dimensões da imagem mantendo a proporção se necessário float imageWidth = style.getImageWidth(); float imageHeight = style.getImageHeight(); - + if (style.isMaintainAspectRatio()) { float aspectRatio = (float) leftImage.getHeight() / leftImage.getWidth(); if (imageWidth > 0) { @@ -61,7 +61,7 @@ public void render(PDPageContentStream contentStream, float pageWidth, float y, imageWidth = imageHeight / aspectRatio; } } - + contentStream.drawImage(leftImage, imageX, imageY, imageWidth, imageHeight); } @@ -76,11 +76,11 @@ public void render(PDPageContentStream contentStream, float pageWidth, float y, if (rightImage != null) { float imageX = pageWidth - marginRight - style.getImageWidth() - style.getImageMargin(); float imageY = y - style.getImageHeight() + (style.getFontSize() / 2); - + // Calcula as dimensões da imagem mantendo a proporção se necessário float imageWidth = style.getImageWidth(); float imageHeight = style.getImageHeight(); - + if (style.isMaintainAspectRatio()) { float aspectRatio = (float) rightImage.getHeight() / rightImage.getWidth(); if (imageWidth > 0) { @@ -89,7 +89,7 @@ public void render(PDPageContentStream contentStream, float pageWidth, float y, imageWidth = imageHeight / aspectRatio; } } - + contentStream.drawImage(rightImage, imageX, imageY, imageWidth, imageHeight); } @@ -115,7 +115,7 @@ public static Builder builder() { return new Builder(); } - public static class Builder { + public static final class Builder { private String title; private LogoStyle style; private PDImageXObject leftImage; diff --git a/src/main/java/io/github/joabsonlg/pdfbuilder/components/logo/LogoStyle.java b/src/main/java/io/github/joabsonlg/pdfbuilder/components/logo/LogoStyle.java index d267c51..402778b 100644 --- a/src/main/java/io/github/joabsonlg/pdfbuilder/components/logo/LogoStyle.java +++ b/src/main/java/io/github/joabsonlg/pdfbuilder/components/logo/LogoStyle.java @@ -11,8 +11,8 @@ /** * Configurações de estilo para o logo do documento. */ -public class LogoStyle { - private static final Logger logger = LoggerFactory.getLogger(LogoStyle.class); +public final class LogoStyle { + private static final Logger LOGGER = LoggerFactory.getLogger(LogoStyle.class); private final PDFont font; private final float fontSize; @@ -108,7 +108,7 @@ public Builder() { try { this.font = new PDType1Font(Standard14Fonts.FontName.HELVETICA_BOLD); } catch (Exception e) { - logger.error("Erro ao criar fonte padrão", e); + LOGGER.error("Erro ao criar fonte padrão", e); throw new RuntimeException("Erro ao criar fonte padrão", e); } } diff --git a/src/main/java/io/github/joabsonlg/pdfbuilder/components/page/PageNumbering.java b/src/main/java/io/github/joabsonlg/pdfbuilder/components/page/PageNumbering.java index b6353c0..55b5762 100644 --- a/src/main/java/io/github/joabsonlg/pdfbuilder/components/page/PageNumbering.java +++ b/src/main/java/io/github/joabsonlg/pdfbuilder/components/page/PageNumbering.java @@ -1,21 +1,20 @@ package io.github.joabsonlg.pdfbuilder.components.page; import io.github.joabsonlg.pdfbuilder.components.text.TextAlignment; -import io.github.joabsonlg.pdfbuilder.components.text.TextStyle; 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; /** * Componente para adicionar numeração de páginas em documentos PDF. * Suporta diferentes formatos e posicionamentos. */ -public class PageNumbering { - private static final Logger logger = LoggerFactory.getLogger(PageNumbering.class); +public final class PageNumbering { + private static final Logger LOGGER = LoggerFactory.getLogger(PageNumbering.class); private final Format format; private final Position position; @@ -41,10 +40,10 @@ private PageNumbering(Builder builder) { * Renderiza o número da página no documento. * * @param contentStream Stream do conteúdo da página - * @param pageWidth Largura da página - * @param pageHeight Altura da página - * @param pageNumber Número da página atual - * @param totalPages Total de páginas no documento + * @param pageWidth Largura da página + * @param pageHeight Altura da página + * @param pageNumber Número da página atual + * @param totalPages Total de páginas no documento */ public void render(PDPageContentStream contentStream, float pageWidth, float pageHeight, int pageNumber, int totalPages) throws IOException { String text = formatPageNumber(pageNumber, totalPages); @@ -151,13 +150,9 @@ public PageNumbering build() { * Formato da numeração de página. */ public enum Format { - /** Apenas o número da página (ex: "1") */ SIMPLE, - /** Número da página com total (ex: "1 de 10") */ WITH_TOTAL, - /** Número da página com traço e total (ex: "1 - 10") */ DASH_TOTAL, - /** Número da página com total entre parênteses (ex: "1 (10)") */ PARENTHESES_TOTAL } @@ -165,9 +160,7 @@ public enum Format { * Posição da numeração na página. */ public enum Position { - /** No topo da página */ TOP, - /** No rodapé da página */ BOTTOM } } diff --git a/src/main/java/io/github/joabsonlg/pdfbuilder/components/page/PageSection.java b/src/main/java/io/github/joabsonlg/pdfbuilder/components/page/PageSection.java index 66ec5aa..3668e51 100644 --- a/src/main/java/io/github/joabsonlg/pdfbuilder/components/page/PageSection.java +++ b/src/main/java/io/github/joabsonlg/pdfbuilder/components/page/PageSection.java @@ -11,7 +11,7 @@ /** * Componente para renderização de cabeçalhos e rodapés em documentos PDF. */ -public class PageSection { +public final class PageSection { private final String leftText; private final String centerText; private final String rightText; @@ -93,7 +93,7 @@ public void render(PDPageContentStream contentStream, float pageWidth, float y, float contentWidth = pageWidth - marginLeft - marginRight; float textY = y; float lineY = y - (fontSize / 2); // Move a linha para baixo do texto - + // Configura a fonte e cor contentStream.setFont(font, fontSize); contentStream.setNonStrokingColor(color); @@ -153,7 +153,7 @@ public static Builder builder() { return new Builder(); } - public static class Builder { + public static final class Builder { private String leftText; private String centerText; private String rightText; diff --git a/src/main/java/io/github/joabsonlg/pdfbuilder/components/page/PageSectionStyle.java b/src/main/java/io/github/joabsonlg/pdfbuilder/components/page/PageSectionStyle.java index b12aaa5..c587f78 100644 --- a/src/main/java/io/github/joabsonlg/pdfbuilder/components/page/PageSectionStyle.java +++ b/src/main/java/io/github/joabsonlg/pdfbuilder/components/page/PageSectionStyle.java @@ -1,17 +1,20 @@ package io.github.joabsonlg.pdfbuilder.components.page; -import io.github.joabsonlg.pdfbuilder.components.text.TextAlignment; import org.apache.pdfbox.pdmodel.font.PDType1Font; import org.apache.pdfbox.pdmodel.font.Standard14Fonts; -import java.awt.Color; +import java.awt.*; import java.time.LocalDate; import java.time.format.DateTimeFormatter; /** * Estilos predefinidos para cabeçalhos e rodapés. */ -public class PageSectionStyle { +public final class PageSectionStyle { + + private PageSectionStyle() { + throw new UnsupportedOperationException("This is a utility class and cannot be instantiated"); + } /** * Estilo minimalista com linha separadora fina. diff --git a/src/main/java/io/github/joabsonlg/pdfbuilder/components/table/Table.java b/src/main/java/io/github/joabsonlg/pdfbuilder/components/table/Table.java index da43d22..6c6e4e7 100644 --- a/src/main/java/io/github/joabsonlg/pdfbuilder/components/table/Table.java +++ b/src/main/java/io/github/joabsonlg/pdfbuilder/components/table/Table.java @@ -5,7 +5,7 @@ import org.apache.pdfbox.pdmodel.font.PDType1Font; import org.apache.pdfbox.pdmodel.font.Standard14Fonts; -import java.awt.Color; +import java.awt.*; import java.io.IOException; import java.util.ArrayList; import java.util.List; @@ -14,7 +14,7 @@ * Componente para renderização de tabelas em documentos PDF. * Suporta células com texto simples, alinhamento e cores de fundo. */ -public class Table { +public final class Table { private final List> data; private final float[] columnWidths; private final float rowHeight; @@ -90,15 +90,15 @@ private float drawRow(PDPageContentStream contentStream, List row, float // Primeiro, calcula a altura necessária para a linha float maxTextHeight = 0; List> wrappedTexts = new ArrayList<>(); - + for (int i = 0; i < row.size() && i < columnWidths.length; i++) { String cellText = row.get(i); float columnWidth = columnWidths[i]; float maxWidth = columnWidth - 10; // 5 pixels de padding de cada lado - + List lines = wrapText(cellText, font, fontSize, maxWidth); wrappedTexts.add(lines); - + float textHeight = lines.size() * fontSize; maxTextHeight = Math.max(maxTextHeight, textHeight); } @@ -127,14 +127,14 @@ private float drawRow(PDPageContentStream contentStream, List row, float // Calcula a altura total do texto float textHeight = lines.size() * fontSize; - + // Calcula a posição Y inicial para centralizar verticalmente todas as linhas float startY = y - actualRowHeight + (actualRowHeight - textHeight) / 2; // Desenha cada linha do texto for (int lineIndex = 0; lineIndex < lines.size(); lineIndex++) { String line = lines.get(lineIndex); - + // Calcula a posição X para centralizar a linha horizontalmente float textWidth = font.getStringWidth(line) / 1000 * fontSize; float textX = currentX + (columnWidth - textWidth) / 2; @@ -215,7 +215,7 @@ public static Builder builder() { return new Builder(); } - public static class Builder { + public static final class Builder { private List> data = new ArrayList<>(); private float[] columnWidths = new float[0]; private float rowHeight = 20f; diff --git a/src/main/java/io/github/joabsonlg/pdfbuilder/components/text/Heading.java b/src/main/java/io/github/joabsonlg/pdfbuilder/components/text/Heading.java index 5d0312b..744a273 100644 --- a/src/main/java/io/github/joabsonlg/pdfbuilder/components/text/Heading.java +++ b/src/main/java/io/github/joabsonlg/pdfbuilder/components/text/Heading.java @@ -5,14 +5,14 @@ import org.apache.pdfbox.pdmodel.font.PDType1Font; import org.apache.pdfbox.pdmodel.font.Standard14Fonts; -import java.awt.Color; +import java.awt.*; import java.io.IOException; /** * Componente para renderização de títulos e subtítulos. * Suporta numeração automática, diferentes níveis e espaçamento personalizado. */ -public class Heading { +public final class Heading { private final HeadingLevel level; private final String text; private final TextStyle style; diff --git a/src/main/java/io/github/joabsonlg/pdfbuilder/components/text/Paragraph.java b/src/main/java/io/github/joabsonlg/pdfbuilder/components/text/Paragraph.java index 0f78e14..5e3265b 100644 --- a/src/main/java/io/github/joabsonlg/pdfbuilder/components/text/Paragraph.java +++ b/src/main/java/io/github/joabsonlg/pdfbuilder/components/text/Paragraph.java @@ -2,6 +2,7 @@ import org.apache.pdfbox.pdmodel.PDPageContentStream; import org.apache.pdfbox.pdmodel.font.PDFont; + import java.io.IOException; import java.util.ArrayList; import java.util.List; @@ -9,7 +10,7 @@ /** * Componente para renderização de parágrafos com alinhamento e formatação rica. */ -public class Paragraph { +public final class Paragraph { private final List styledTexts; private final TextAlignment alignment; private final float lineSpacing; @@ -30,7 +31,7 @@ public float render(PDPageContentStream contentStream, float x, float y, float m for (List line : lines) { float startX = calculateStartX(line, x, maxWidth); float wordSpacing = calculateWordSpacing(line, maxWidth); - + float currentX = startX; for (int i = 0; i < line.size(); i++) { StyledText styledText = line.get(i); @@ -78,15 +79,15 @@ private float calculateWordSpacing(List line, float maxWidth) throws float totalTextWidth = 0; int spaces = line.size() - 1; - + for (StyledText styledText : line) { - totalTextWidth += getStringWidth(styledText.getText(), - styledText.getStyle().getFont(), - styledText.getStyle().getFontSize()); + totalTextWidth += getStringWidth(styledText.getText(), + styledText.getStyle().getFont(), + styledText.getStyle().getFontSize()); } float totalSpaceWidth = maxWidth - totalTextWidth; - + return totalSpaceWidth / spaces; } @@ -96,10 +97,10 @@ private float calculateStartX(List line, float baseX, float maxWidth for (int i = 0; i < line.size(); i++) { StyledText styledText = line.get(i); - lineWidth += getStringWidth(styledText.getText(), - styledText.getStyle().getFont(), - styledText.getStyle().getFontSize()); - + lineWidth += getStringWidth(styledText.getText(), + styledText.getStyle().getFont(), + styledText.getStyle().getFontSize()); + if (i < line.size() - 1) { lineWidth += spaceWidth; } @@ -154,7 +155,9 @@ private float getSpaceWidth(PDFont font, float fontSize) throws IOException { } public float getHeight() { - if (styledTexts.isEmpty()) return 0; + if (styledTexts.isEmpty()) { + return 0; + } return styledTexts.get(0).getStyle().getFontSize() * lineSpacing; } diff --git a/src/main/java/io/github/joabsonlg/pdfbuilder/components/text/SimpleText.java b/src/main/java/io/github/joabsonlg/pdfbuilder/components/text/SimpleText.java index c3a050b..2263bfc 100644 --- a/src/main/java/io/github/joabsonlg/pdfbuilder/components/text/SimpleText.java +++ b/src/main/java/io/github/joabsonlg/pdfbuilder/components/text/SimpleText.java @@ -2,7 +2,8 @@ import org.apache.pdfbox.pdmodel.PDPageContentStream; import org.apache.pdfbox.pdmodel.font.PDFont; -import java.awt.Color; + +import java.awt.*; import java.io.IOException; import java.util.ArrayList; import java.util.List; @@ -10,7 +11,7 @@ /** * Componente para renderização de texto simples. */ -public class SimpleText { +public final class SimpleText { private final String text; private final PDFont font; private final float fontSize; @@ -27,10 +28,11 @@ private SimpleText(String text, PDFont font, float fontSize, float lineSpacing, /** * Renderiza o texto no PDPageContentStream respeitando a largura máxima. + * * @param contentStream Stream de conteúdo do PDF - * @param x Posição X inicial - * @param y Posição Y inicial - * @param maxWidth Largura máxima disponível + * @param x Posição X inicial + * @param y Posição Y inicial + * @param maxWidth Largura máxima disponível * @return Posição Y final após renderizar todo o texto * @throws IOException se houver erro ao renderizar */ @@ -56,6 +58,7 @@ public float render(PDPageContentStream contentStream, float x, float y, float m /** * Quebra o texto em linhas respeitando a largura máxima. + * * @param maxWidth Largura máxima disponível * @return Lista de linhas * @throws IOException se houver erro no cálculo @@ -66,12 +69,12 @@ private List breakTextIntoLines(float maxWidth) throws IOException { StringBuilder currentLine = new StringBuilder(); for (String word : words) { - String testLine = currentLine.length() > 0 - ? currentLine + " " + word - : word; - + String testLine = currentLine.length() > 0 + ? currentLine + " " + word + : word; + float lineWidth = getStringWidth(testLine); - + if (lineWidth <= maxWidth) { currentLine = new StringBuilder(testLine); } else { @@ -101,6 +104,7 @@ private float getStringWidth(String str) throws IOException { /** * Calcula a altura da linha incluindo o espaçamento. + * * @return Altura em pontos */ public float getHeight() { diff --git a/src/main/java/io/github/joabsonlg/pdfbuilder/components/text/StyledText.java b/src/main/java/io/github/joabsonlg/pdfbuilder/components/text/StyledText.java index e37d8bb..8086793 100644 --- a/src/main/java/io/github/joabsonlg/pdfbuilder/components/text/StyledText.java +++ b/src/main/java/io/github/joabsonlg/pdfbuilder/components/text/StyledText.java @@ -12,6 +12,11 @@ public StyledText(String text, TextStyle style) { this.style = style; } - public String getText() { return text; } - public TextStyle getStyle() { return style; } + public String getText() { + return text; + } + + public TextStyle getStyle() { + return style; + } } diff --git a/src/main/java/io/github/joabsonlg/pdfbuilder/components/text/TextStyle.java b/src/main/java/io/github/joabsonlg/pdfbuilder/components/text/TextStyle.java index 0fbab48..aef7aa2 100644 --- a/src/main/java/io/github/joabsonlg/pdfbuilder/components/text/TextStyle.java +++ b/src/main/java/io/github/joabsonlg/pdfbuilder/components/text/TextStyle.java @@ -1,12 +1,13 @@ package io.github.joabsonlg.pdfbuilder.components.text; -import java.awt.Color; import org.apache.pdfbox.pdmodel.font.PDFont; +import java.awt.*; + /** * Define o estilo de formatação para um trecho de texto. */ -public class TextStyle { +public final class TextStyle { private final PDFont font; private final float fontSize; private final Color color; @@ -23,12 +24,29 @@ private TextStyle(Builder builder) { this.underlineOffset = builder.underlineOffset; } - public PDFont getFont() { return font; } - public float getFontSize() { return fontSize; } - public Color getColor() { return color; } - public boolean isUnderline() { return underline; } - public float getUnderlineThickness() { return underlineThickness; } - public float getUnderlineOffset() { return underlineOffset; } + public PDFont getFont() { + return font; + } + + public float getFontSize() { + return fontSize; + } + + public Color getColor() { + return color; + } + + public boolean isUnderline() { + return underline; + } + + public float getUnderlineThickness() { + return underlineThickness; + } + + public float getUnderlineOffset() { + return underlineOffset; + } public static Builder builder() { return new Builder(); diff --git a/src/main/java/io/github/joabsonlg/pdfbuilder/core/Coordinates.java b/src/main/java/io/github/joabsonlg/pdfbuilder/core/Coordinates.java index e0c14f3..74fc8b9 100644 --- a/src/main/java/io/github/joabsonlg/pdfbuilder/core/Coordinates.java +++ b/src/main/java/io/github/joabsonlg/pdfbuilder/core/Coordinates.java @@ -7,8 +7,8 @@ /** * Gerencia coordenadas e posicionamento no documento PDF. */ -public class Coordinates { - private static final Logger logger = LoggerFactory.getLogger(Coordinates.class); +public final class Coordinates { + private static final Logger LOGGER = LoggerFactory.getLogger(Coordinates.class); private final float x; private final float y; @@ -24,6 +24,7 @@ private Coordinates(float x, float y, PDRectangle pageSize, SafeArea safeArea) { /** * Cria uma nova instância de Coordinates na origem (0,0). + * * @param pageSize Tamanho da página * @param safeArea Área segura * @return Nova instância de Coordinates @@ -34,6 +35,7 @@ public static Coordinates origin(PDRectangle pageSize, SafeArea safeArea) { /** * Move para uma posição específica. + * * @param x Coordenada X * @param y Coordenada Y * @return Nova instância de Coordinates @@ -44,6 +46,7 @@ public Coordinates moveTo(float x, float y) { /** * Move relativamente à posição atual. + * * @param deltaX Deslocamento em X * @param deltaY Deslocamento em Y * @return Nova instância de Coordinates @@ -54,6 +57,7 @@ public Coordinates moveBy(float deltaX, float deltaY) { /** * Move para uma posição relativa à área de conteúdo. + * * @param percentX Porcentagem da largura (0-100) * @param percentY Porcentagem da altura (0-100) * @return Nova instância de Coordinates @@ -72,6 +76,7 @@ public Coordinates moveToContentPercent(float percentX, float percentY) { /** * Move para uma posição na área do cabeçalho. + * * @param percentX Porcentagem da largura (0-100) * @param percentY Porcentagem da altura do cabeçalho (0-100) * @return Nova instância de Coordinates @@ -94,6 +99,7 @@ public Coordinates moveToHeader(float percentX, float percentY) { /** * Move para uma posição na área do rodapé. + * * @param percentX Porcentagem da largura (0-100) * @param percentY Porcentagem da altura do rodapé (0-100) * @return Nova instância de Coordinates @@ -116,6 +122,7 @@ public Coordinates moveToFooter(float percentX, float percentY) { /** * Move para o topo da área de conteúdo. + * * @return Nova instância de Coordinates no topo da área de conteúdo */ public Coordinates moveToTop() { @@ -126,6 +133,7 @@ public Coordinates moveToTop() { /** * Verifica se a posição atual está dentro da área segura. + * * @return true se estiver dentro da área segura */ public boolean isInSafeArea() { @@ -135,6 +143,7 @@ public boolean isInSafeArea() { /** * Retorna a posição atual ajustada para estar dentro da área segura. * Se a posição atual estiver fora da área segura, move para o ponto mais próximo dentro dela. + * * @return Nova instância de Coordinates dentro da área segura */ public Coordinates ensureInSafeArea() { @@ -160,14 +169,25 @@ public Coordinates ensureInSafeArea() { newY = contentArea.getUpperRightY(); } - logger.debug("Ajustando coordenadas de ({},{}) para ({},{}) para respeitar área segura", - x, y, newX, newY); + LOGGER.debug("Ajustando coordenadas de ({},{}) para ({},{}) para respeitar área segura", + x, y, newX, newY); return new Coordinates(newX, newY, pageSize, safeArea); } // Getters - public float getX() { return x; } - public float getY() { return y; } - public PDRectangle getPageSize() { return pageSize; } - public SafeArea getSafeArea() { return safeArea; } + public float getX() { + return x; + } + + public float getY() { + return y; + } + + public PDRectangle getPageSize() { + return pageSize; + } + + public SafeArea getSafeArea() { + return safeArea; + } } diff --git a/src/main/java/io/github/joabsonlg/pdfbuilder/core/PDFBuilder.java b/src/main/java/io/github/joabsonlg/pdfbuilder/core/PDFBuilder.java index 7158b8c..a2dab38 100644 --- a/src/main/java/io/github/joabsonlg/pdfbuilder/core/PDFBuilder.java +++ b/src/main/java/io/github/joabsonlg/pdfbuilder/core/PDFBuilder.java @@ -19,7 +19,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.awt.Dimension; +import java.awt.*; import java.io.IOException; /** @@ -27,7 +27,7 @@ * Fornece uma API fluente para criação e manipulação de PDFs. */ public class PDFBuilder { - private static final Logger logger = LoggerFactory.getLogger(PDFBuilder.class); + private static final Logger LOGGER = LoggerFactory.getLogger(PDFBuilder.class); private static final float DEFAULT_FONT_SIZE = 12.0f; private final PDDocument document; @@ -45,6 +45,7 @@ public class PDFBuilder { /** * Cria uma nova instância do PDFBuilder com a configuração fornecida. + * * @param config Configuração do PDF */ public PDFBuilder(PDFConfiguration config) { @@ -55,16 +56,16 @@ public PDFBuilder(PDFConfiguration config) { this.lineSpacing = 1.5f; this.currentFontSize = DEFAULT_FONT_SIZE; this.resourceManager = new ResourceManager(document); - + try { this.contentStream = new PDPageContentStream(document, currentPage); // Inicializa a posição atual no topo da página this.currentPosition = Coordinates.origin(config.getPageSize(), config.getSafeArea()) - .moveTo( - config.getSafeArea().getMarginLeft(), - config.getPageSize().getHeight() - config.getSafeArea().getMarginTop() - ); - + .moveTo( + config.getSafeArea().getMarginLeft(), + config.getPageSize().getHeight() - config.getSafeArea().getMarginTop() + ); + // Adiciona o logo na primeira página se existir if (logo != null) { addLogo(); @@ -76,6 +77,7 @@ public PDFBuilder(PDFConfiguration config) { /** * Cria uma nova instância do PDFBuilder com configuração padrão. + * * @return Nova instância do PDFBuilder */ public static PDFBuilder create() { @@ -84,6 +86,7 @@ public static PDFBuilder create() { /** * Cria uma nova instância do PDFBuilder com configuração personalizada. + * * @param config Configuração personalizada * @return Nova instância do PDFBuilder */ @@ -96,12 +99,13 @@ public static PDFBuilder create(PDFConfiguration config) { /** * Adiciona uma nova página ao documento. + * * @return this para chamadas encadeadas */ public PDFBuilder addNewPage() { try { addNewPageInternal(); - logger.debug("Nova página adicionada ao documento"); + LOGGER.debug("Nova página adicionada ao documento"); return this; } catch (IOException e) { throw new RuntimeException("Erro ao adicionar nova página", e); @@ -126,14 +130,14 @@ private void addNewPageInternal() throws IOException { // Cria novo content stream contentStream = new PDPageContentStream(document, currentPage); - + // Reseta a posição para o topo da nova página currentPosition = Coordinates.origin(config.getPageSize(), config.getSafeArea()) - .moveTo( - config.getSafeArea().getMarginLeft(), - config.getPageSize().getHeight() - config.getSafeArea().getMarginTop() - ); - + .moveTo( + config.getSafeArea().getMarginLeft(), + config.getPageSize().getHeight() - config.getSafeArea().getMarginTop() + ); + // Adiciona logo à nova página if (logo != null) { addLogo(); @@ -142,6 +146,7 @@ private void addNewPageInternal() throws IOException { /** * Move para uma posição específica na página. + * * @param x Coordenada X * @param y Coordenada Y * @return this para chamadas encadeadas @@ -153,6 +158,7 @@ public PDFBuilder moveTo(float x, float y) { /** * Move relativamente à posição atual. + * * @param deltaX Deslocamento em X * @param deltaY Deslocamento em Y * @return this para chamadas encadeadas @@ -164,6 +170,7 @@ public PDFBuilder moveBy(float deltaX, float deltaY) { /** * Move para uma posição relativa à área de conteúdo. + * * @param percentX Porcentagem da largura (0-100) * @param percentY Porcentagem da altura (0-100) * @return this para chamadas encadeadas @@ -175,6 +182,7 @@ public PDFBuilder moveToContentPercent(float percentX, float percentY) { /** * Move para uma posição na área do cabeçalho. + * * @param percentX Porcentagem da largura (0-100) * @param percentY Porcentagem da altura do cabeçalho (0-100) * @return this para chamadas encadeadas @@ -186,6 +194,7 @@ public PDFBuilder moveToHeader(float percentX, float percentY) { /** * Move para uma posição na área do rodapé. + * * @param percentX Porcentagem da largura (0-100) * @param percentY Porcentagem da altura do rodapé (0-100) * @return this para chamadas encadeadas @@ -197,6 +206,7 @@ public PDFBuilder moveToFooter(float percentX, float percentY) { /** * Move para o topo da área de conteúdo. + * * @return this para chamadas encadeadas */ public PDFBuilder moveToTop() { @@ -208,6 +218,7 @@ public PDFBuilder moveToTop() { /** * Move para o início da linha atual. + * * @return this para chamadas encadeadas */ public PDFBuilder moveToStart() { @@ -219,6 +230,7 @@ public PDFBuilder moveToStart() { /** * Move para o final da área de conteúdo. + * * @return this para chamadas encadeadas */ public PDFBuilder moveToBottom() { @@ -230,6 +242,7 @@ public PDFBuilder moveToBottom() { /** * Move para a direita a partir da posição atual. + * * @param distance Distância a mover em pontos * @return this para chamadas encadeadas */ @@ -240,6 +253,7 @@ public PDFBuilder moveRight(float distance) { /** * Move para baixo a partir da posição atual. + * * @param distance Distância a mover em pontos * @return this para chamadas encadeadas */ @@ -250,6 +264,7 @@ public PDFBuilder moveDown(float distance) { /** * Adiciona texto na posição atual. + * * @param text Texto a ser adicionado * @return this para chamadas encadeadas */ @@ -262,7 +277,7 @@ public PDFBuilder addText(String text) { contentStream.showText(text); contentStream.endText(); - logger.debug("Texto adicionado: {}", text); + LOGGER.debug("Texto adicionado: {}", text); return this; } catch (IOException e) { throw new RuntimeException("Erro ao adicionar texto", e); @@ -271,6 +286,7 @@ public PDFBuilder addText(String text) { /** * Adiciona uma linha de texto e move para a próxima linha. + * * @param text Texto a ser adicionado * @return this para chamadas encadeadas */ @@ -288,7 +304,7 @@ public PDFBuilder addLine(String text) { moveDown(lineHeight); moveToStart(); - logger.debug("Linha de texto adicionada: {}", text); + LOGGER.debug("Linha de texto adicionada: {}", text); return this; } catch (IOException e) { throw new RuntimeException("Erro ao adicionar linha de texto", e); @@ -297,6 +313,7 @@ public PDFBuilder addLine(String text) { /** * Adiciona um componente de texto simples. + * * @param simpleText Componente de texto * @return this para chamadas encadeadas */ @@ -306,7 +323,7 @@ public PDFBuilder addSimpleText(SimpleText simpleText) { float safeWidth = contentArea.getWidth(); float newY = simpleText.render(contentStream, currentPosition.getX(), currentPosition.getY(), safeWidth); currentPosition = currentPosition.moveTo(currentPosition.getX(), newY); - logger.debug("SimpleText adicionado com quebra de linha automática"); + LOGGER.debug("SimpleText adicionado com quebra de linha automática"); return this; } catch (IOException e) { throw new RuntimeException("Erro ao adicionar SimpleText", e); @@ -315,6 +332,7 @@ public PDFBuilder addSimpleText(SimpleText simpleText) { /** * Adiciona um parágrafo com alinhamento. + * * @param paragraph Componente de parágrafo * @return this para chamadas encadeadas */ @@ -324,7 +342,7 @@ public PDFBuilder addParagraph(Paragraph paragraph) { float safeWidth = contentArea.getWidth(); float newY = paragraph.render(contentStream, currentPosition.getX(), currentPosition.getY(), safeWidth); currentPosition = currentPosition.moveTo(currentPosition.getX(), newY); - logger.debug("Parágrafo adicionado com alinhamento"); + LOGGER.debug("Parágrafo adicionado com alinhamento"); return this; } catch (IOException e) { throw new RuntimeException("Erro ao adicionar parágrafo", e); @@ -333,6 +351,7 @@ public PDFBuilder addParagraph(Paragraph paragraph) { /** * Adiciona um título ao documento. + * * @param heading Componente de título * @return this para chamadas encadeadas */ @@ -342,7 +361,7 @@ public PDFBuilder addHeading(Heading heading) { float safeWidth = contentArea.getWidth(); float newY = heading.render(contentStream, currentPosition.getX(), currentPosition.getY(), safeWidth); currentPosition = currentPosition.moveTo(currentPosition.getX(), newY); - logger.debug("Título adicionado ao documento"); + LOGGER.debug("Título adicionado ao documento"); return this; } catch (IOException e) { throw new RuntimeException("Erro ao adicionar título", e); @@ -351,42 +370,44 @@ public PDFBuilder addHeading(Heading heading) { /** * Verifica se é necessário criar uma nova página baseado na altura necessária. + * * @param heightNeeded Altura necessária para o próximo elemento */ private void checkNewPage(float heightNeeded) throws IOException { PDRectangle contentArea = config.getSafeArea().getContentArea(config.getPageSize()); float bottomLimit = contentArea.getLowerLeftY(); - + if (currentPosition.getY() - heightNeeded < bottomLimit) { // Fecha o content stream atual if (contentStream != null) { addFooter(); contentStream.close(); } - + // Cria nova página PDPage newPage = new PDPage(config.getPageSize()); document.addPage(newPage); - + // Cria novo content stream contentStream = new PDPageContentStream(document, newPage); - + // Reseta a posição para o topo da nova página usando Coordinates.origin currentPosition = Coordinates.origin(config.getPageSize(), config.getSafeArea()) - .moveTo( - contentArea.getLowerLeftX(), - contentArea.getUpperRightY() - ); - + .moveTo( + contentArea.getLowerLeftX(), + contentArea.getUpperRightY() + ); + // Adiciona cabeçalho à nova página addHeader(); - - logger.debug("Nova página criada"); + + LOGGER.debug("Nova página criada"); } } /** * Adiciona uma imagem ao documento. + * * @param image Componente de imagem * @return this para chamadas encadeadas */ @@ -398,18 +419,18 @@ public PDFBuilder addImage(Image image) { float aspectRatio = dimensions.height / (float) dimensions.width; float imageWidth = Math.min(safeWidth, dimensions.width); float imageHeight = imageWidth * aspectRatio; - + // Verifica se precisa de nova página checkNewPage(imageHeight); - + // Renderiza a imagem e atualiza a posição Y float newY = image.render(contentStream, currentPosition.getX(), currentPosition.getY(), safeWidth, imageWidth); currentPosition = currentPosition.moveTo(currentPosition.getX(), newY); - + // Adiciona espaço após a imagem moveDown(20); // 20 pontos de espaço após cada imagem - - logger.debug("Imagem adicionada com dimensões: {}x{}", imageWidth, imageHeight); + + LOGGER.debug("Imagem adicionada com dimensões: {}x{}", imageWidth, imageHeight); return this; } catch (IOException e) { throw new RuntimeException("Erro ao adicionar imagem", e); @@ -418,6 +439,7 @@ public PDFBuilder addImage(Image image) { /** * Adiciona uma tabela ao documento. + * * @param table Componente de tabela * @return this para chamadas encadeadas */ @@ -427,11 +449,11 @@ public PDFBuilder addTable(Table table) { float safeWidth = contentArea.getWidth(); float newY = table.render(contentStream, currentPosition.getX(), currentPosition.getY(), safeWidth); currentPosition = currentPosition.moveTo(currentPosition.getX(), newY); - + // Adiciona espaço após a tabela moveDown(20); // 20 pontos de espaço após a tabela - - logger.debug("Tabela adicionada ao documento"); + + LOGGER.debug("Tabela adicionada ao documento"); return this; } catch (IOException e) { throw new RuntimeException("Erro ao adicionar tabela", e); @@ -440,6 +462,7 @@ public PDFBuilder addTable(Table table) { /** * Adiciona uma lista ao documento. + * * @param list Componente de lista * @return this para chamadas encadeadas */ @@ -449,11 +472,11 @@ public PDFBuilder addList(List list) { float safeWidth = contentArea.getWidth(); float newY = list.render(contentStream, currentPosition.getX(), currentPosition.getY(), safeWidth); currentPosition = currentPosition.moveTo(currentPosition.getX(), newY); - + // Adiciona espaço após a lista moveDown(20); // 20 pontos de espaço após a lista - - logger.debug("Lista adicionada ao documento"); + + LOGGER.debug("Lista adicionada ao documento"); return this; } catch (IOException e) { throw new RuntimeException("Erro ao adicionar lista", e); @@ -462,6 +485,7 @@ public PDFBuilder addList(List list) { /** * Define o tamanho da fonte. + * * @param fontSize Tamanho da fonte em pontos * @return this para chamadas encadeadas */ @@ -475,6 +499,7 @@ public PDFBuilder setFontSize(float fontSize) { /** * Define o espaçamento entre linhas. + * * @param spacing Fator de espaçamento (1.0 = espaçamento simples) * @return this para chamadas encadeadas */ @@ -488,6 +513,7 @@ public PDFBuilder setLineSpacing(float spacing) { /** * Atualiza a configuração do builder. + * * @param config Nova configuração * @return this para chamadas encadeadas */ @@ -500,6 +526,7 @@ public PDFBuilder withConfiguration(PDFConfiguration config) { /** * Atualiza o tamanho da página. + * * @param pageSize Novo tamanho de página * @return this para chamadas encadeadas */ @@ -513,6 +540,7 @@ public PDFBuilder withPageSize(PDRectangle pageSize) { /** * Define a numeração de páginas. + * * @param pageNumbering Configuração de numeração de páginas * @return this para chamadas encadeadas */ @@ -523,6 +551,7 @@ public PDFBuilder setPageNumbering(PageNumbering pageNumbering) { /** * Define o cabeçalho do documento. + * * @param header Configuração do cabeçalho * @return this para chamadas encadeadas */ @@ -541,6 +570,7 @@ public PDFBuilder setHeader(PageSection header) { /** * Define o rodapé do documento. + * * @param footer Configuração do rodapé * @return this para chamadas encadeadas */ @@ -551,13 +581,14 @@ public PDFBuilder setFooter(PageSection footer) { /** * Define o logo do documento usando apenas um título. + * * @param title Título do logo * @return this para chamadas encadeadas */ public PDFBuilder setLogo(String title) { this.logo = Logo.builder() - .withTitle(title) - .build(); + .withTitle(title) + .build(); try { addLogo(); } catch (IOException e) { @@ -568,15 +599,16 @@ public PDFBuilder setLogo(String title) { /** * Define o logo do documento com título e estilo personalizado. + * * @param title Título do logo * @param style Estilo do logo * @return this para chamadas encadeadas */ public PDFBuilder setLogo(String title, LogoStyle style) { this.logo = Logo.builder() - .withTitle(title) - .withStyle(style) - .build(); + .withTitle(title) + .withStyle(style) + .build(); try { addLogo(); } catch (IOException e) { @@ -587,9 +619,10 @@ public PDFBuilder setLogo(String title, LogoStyle style) { /** * Define o logo do documento com imagens nas laterais. - * @param title Título do logo - * @param style Estilo do logo - * @param leftImagePath Caminho da imagem da esquerda + * + * @param title Título do logo + * @param style Estilo do logo + * @param leftImagePath Caminho da imagem da esquerda * @param rightImagePath Caminho da imagem da direita * @return this para chamadas encadeadas */ @@ -605,19 +638,19 @@ public PDFBuilder setLogo(String title, LogoStyle style, String leftImagePath, S } this.logo = Logo.builder() - .withTitle(title) - .withStyle(style) - .withLeftImage(leftImage) - .withRightImage(rightImage) - .build(); + .withTitle(title) + .withStyle(style) + .withLeftImage(leftImage) + .withRightImage(rightImage) + .build(); try { // Reseta a posição e adiciona o logo currentPosition = Coordinates.origin(config.getPageSize(), config.getSafeArea()) - .moveTo( - config.getSafeArea().getMarginLeft(), - config.getPageSize().getHeight() - config.getSafeArea().getMarginTop() - ); + .moveTo( + config.getSafeArea().getMarginLeft(), + config.getPageSize().getHeight() - config.getSafeArea().getMarginTop() + ); addLogo(); } catch (IOException e) { throw new RuntimeException("Erro ao adicionar logo", e); @@ -644,13 +677,13 @@ private void addFooter() throws IOException { float footerY = config.getSafeArea().getMarginBottom(); footer.render(contentStream, config.getPageSize().getWidth(), footerY, config.getSafeArea().getMarginLeft(), config.getSafeArea().getMarginRight()); - + // Adiciona numeração de página se configurada if (pageNumbering != null) { int pageNumber = document.getPages().indexOf(currentPage) + 1; int totalPages = document.getNumberOfPages(); - pageNumbering.render(contentStream, config.getPageSize().getWidth(), - config.getPageSize().getHeight(), pageNumber, totalPages); + pageNumbering.render(contentStream, config.getPageSize().getWidth(), + config.getPageSize().getHeight(), pageNumber, totalPages); } } } @@ -661,11 +694,11 @@ private void addFooter() throws IOException { private void addLogo() throws IOException { if (logo != null) { float y = currentPosition.getY(); - + // Renderiza o logo logo.render(contentStream, config.getPageSize().getWidth(), y, config.getSafeArea().getMarginLeft(), config.getSafeArea().getMarginRight()); - + // Atualiza a posição atual para logo abaixo do logo float logoHeight = logo.getTotalHeight(); currentPosition = currentPosition.moveBy(0, -logoHeight); @@ -674,6 +707,7 @@ private void addLogo() throws IOException { /** * Salva o documento no caminho especificado. + * * @param path Caminho para salvar o documento */ public void save(String path) { @@ -685,7 +719,7 @@ public void save(String path) { contentStream = null; } document.save(path); - logger.debug("Documento salvo em: {}", path); + LOGGER.debug("Documento salvo em: {}", path); } catch (IOException e) { throw new RuntimeException("Erro ao salvar documento", e); } @@ -702,7 +736,7 @@ public void close() { contentStream = null; } document.close(); - logger.debug("Builder fechado e recursos liberados"); + LOGGER.debug("Builder fechado e recursos liberados"); } catch (IOException e) { throw new RuntimeException("Erro ao fechar recursos", e); } @@ -710,6 +744,7 @@ public void close() { /** * Retorna o gerenciador de recursos do documento. + * * @return Gerenciador de recursos */ public ResourceManager getResourceManager() { @@ -717,8 +752,19 @@ public ResourceManager getResourceManager() { } // Getters - public PDDocument getDocument() { return document; } - public PDFConfiguration getConfig() { return config; } - public PDPage getCurrentPage() { return currentPage; } - public Coordinates getCurrentPosition() { return currentPosition; } + public PDDocument getDocument() { + return document; + } + + public PDFConfiguration getConfig() { + return config; + } + + public PDPage getCurrentPage() { + return currentPage; + } + + public Coordinates getCurrentPosition() { + return currentPosition; + } } diff --git a/src/main/java/io/github/joabsonlg/pdfbuilder/core/PDFConfiguration.java b/src/main/java/io/github/joabsonlg/pdfbuilder/core/PDFConfiguration.java index 1f39469..5f032f4 100644 --- a/src/main/java/io/github/joabsonlg/pdfbuilder/core/PDFConfiguration.java +++ b/src/main/java/io/github/joabsonlg/pdfbuilder/core/PDFConfiguration.java @@ -8,8 +8,8 @@ * Configurações globais para documentos PDF. * Esta classe usa o padrão Builder para uma configuração fluente. */ -public class PDFConfiguration { - private static final Logger logger = LoggerFactory.getLogger(PDFConfiguration.class); +public final class PDFConfiguration { + private static final Logger LOGGER = LoggerFactory.getLogger(PDFConfiguration.class); // Valores padrão private static final PDRectangle DEFAULT_PAGE_SIZE = PDRectangle.A4; @@ -40,21 +40,23 @@ private PDFConfiguration(Builder builder) { this.lineSpacing = builder.lineSpacing; this.safeArea = builder.safeArea; - logger.debug("PDFConfiguration criada com: pageSize={}, dpi={}, fontSize={}, lineSpacing={}", - pageSize, dpi, fontSize, lineSpacing); + LOGGER.debug("PDFConfiguration criada com: pageSize={}, dpi={}, fontSize={}, lineSpacing={}", + pageSize, dpi, fontSize, lineSpacing); } /** * Cria uma nova instância de PDFConfiguration com valores padrão. + * * @return Nova instância de PDFConfiguration */ public static Builder create() { - logger.debug("Criando nova configuração PDF com valores padrão"); + LOGGER.debug("Criando nova configuração PDF com valores padrão"); return new Builder(); } /** * Define o tamanho padrão da página. + * * @param pageSize Tamanho da página (ex: PDRectangle.A4) * @return Nova instância de PDFConfiguration * @throws IllegalArgumentException se pageSize for nulo @@ -70,6 +72,7 @@ public PDFConfiguration withPageSize(PDRectangle pageSize) { /** * Define a resolução DPI para imagens. + * * @param dpi Valor DPI (dots per inch) * @return Nova instância de PDFConfiguration * @throws IllegalArgumentException se dpi for menor ou igual a zero @@ -85,6 +88,7 @@ public PDFConfiguration withDPI(int dpi) { /** * Define a qualidade de compressão para imagens. + * * @param quality Valor entre 0.0 e 1.0 * @return Nova instância de PDFConfiguration * @throws IllegalArgumentException se o valor estiver fora do intervalo [0,1] @@ -100,6 +104,7 @@ public PDFConfiguration withCompressionQuality(float quality) { /** * Define o tamanho da fonte. + * * @param fontSize Tamanho da fonte em pontos * @return Nova instância de PDFConfiguration * @throws IllegalArgumentException se fontSize for menor ou igual a zero @@ -115,6 +120,7 @@ public PDFConfiguration withFontSize(float fontSize) { /** * Define o espaçamento entre linhas. + * * @param lineSpacing Espaçamento em pontos * @return Nova instância de PDFConfiguration * @throws IllegalArgumentException se lineSpacing for menor ou igual a zero @@ -130,6 +136,7 @@ public PDFConfiguration withLineSpacing(float lineSpacing) { /** * Define a área segura. + * * @param safeArea Área segura * @return Nova instância de PDFConfiguration * @throws IllegalArgumentException se safeArea for nulo @@ -169,13 +176,25 @@ public float getLineSpacing() { } // Métodos de conveniência para acessar margens - public float getMarginLeft() { return safeArea.getMarginLeft(); } - public float getMarginRight() { return safeArea.getMarginRight(); } - public float getMarginTop() { return safeArea.getMarginTop(); } - public float getMarginBottom() { return safeArea.getMarginBottom(); } + public float getMarginLeft() { + return safeArea.getMarginLeft(); + } + + public float getMarginRight() { + return safeArea.getMarginRight(); + } + + public float getMarginTop() { + return safeArea.getMarginTop(); + } + + public float getMarginBottom() { + return safeArea.getMarginBottom(); + } /** * Calcula a área útil da página (área dentro das margens). + * * @return PDRectangle representando a área útil */ public PDRectangle getContentArea() { @@ -192,7 +211,8 @@ public static class Builder { private float fontSize = DEFAULT_FONT_SIZE; private float lineSpacing = DEFAULT_LINE_SPACING; - public Builder() {} + public Builder() { + } public Builder(PDFConfiguration pdfConfiguration) { this.pageSize = pdfConfiguration.pageSize; diff --git a/src/main/java/io/github/joabsonlg/pdfbuilder/core/ResourceManager.java b/src/main/java/io/github/joabsonlg/pdfbuilder/core/ResourceManager.java index dc87197..d7253fb 100644 --- a/src/main/java/io/github/joabsonlg/pdfbuilder/core/ResourceManager.java +++ b/src/main/java/io/github/joabsonlg/pdfbuilder/core/ResourceManager.java @@ -20,7 +20,7 @@ * Responsável por carregar e gerenciar fontes e imagens. */ public class ResourceManager { - private static final Logger logger = LoggerFactory.getLogger(ResourceManager.class); + private static final Logger LOGGER = LoggerFactory.getLogger(ResourceManager.class); private final PDDocument document; private final Map fonts; @@ -37,7 +37,7 @@ public ResourceManager(PDDocument document) { this.images = new HashMap<>(); this.defaultFont = new PDType1Font(Standard14Fonts.FontName.HELVETICA); registerStandardFonts(); - logger.debug("ResourceManager inicializado"); + LOGGER.debug("ResourceManager inicializado"); } /** @@ -57,7 +57,7 @@ private void registerStandardFonts() { fonts.put("Courier-Oblique", new PDType1Font(Standard14Fonts.FontName.COURIER_OBLIQUE)); fonts.put("Courier-BoldOblique", new PDType1Font(Standard14Fonts.FontName.COURIER_BOLD_OBLIQUE)); - logger.debug("Fontes padrão registradas"); + LOGGER.debug("Fontes padrão registradas"); } /** @@ -71,7 +71,7 @@ public void setDefaultFont(String fontName) { throw new IllegalArgumentException("Fonte não registrada: " + fontName); } this.defaultFont = font; - logger.debug("Fonte padrão definida para: {}", fontName); + LOGGER.debug("Fonte padrão definida para: {}", fontName); } /** @@ -101,9 +101,9 @@ public void loadImage(String name, Path imagePath) throws IOException { try { PDImageXObject image = PDImageXObject.createFromFile(imagePath.toString(), document); images.put(name, image); - logger.debug("Imagem carregada: {} de {}", name, imagePath); + LOGGER.debug("Imagem carregada: {} de {}", name, imagePath); } catch (IOException e) { - logger.error("Erro ao carregar imagem {}: {}", imagePath, e.getMessage()); + LOGGER.error("Erro ao carregar imagem {}: {}", imagePath, e.getMessage()); throw e; } } @@ -118,9 +118,9 @@ public void loadImage(String name, InputStream inputStream) throws IOException { try { PDImageXObject image = PDImageXObject.createFromByteArray(document, inputStream.readAllBytes(), name); images.put(name, image); - logger.debug("Imagem carregada: {} do InputStream", name); + LOGGER.debug("Imagem carregada: {} do InputStream", name); } catch (IOException e) { - logger.error("Erro ao carregar imagem do InputStream: {}", e.getMessage()); + LOGGER.error("Erro ao carregar imagem do InputStream: {}", e.getMessage()); throw e; } } @@ -142,7 +142,7 @@ public PDImageXObject getImage(String name) { public boolean removeImage(String name) { PDImageXObject removed = images.remove(name); if (removed != null) { - logger.debug("Imagem removida: {}", name); + LOGGER.debug("Imagem removida: {}", name); return true; } return false; diff --git a/src/main/java/io/github/joabsonlg/pdfbuilder/core/SafeArea.java b/src/main/java/io/github/joabsonlg/pdfbuilder/core/SafeArea.java index d91965c..30d0aa1 100644 --- a/src/main/java/io/github/joabsonlg/pdfbuilder/core/SafeArea.java +++ b/src/main/java/io/github/joabsonlg/pdfbuilder/core/SafeArea.java @@ -5,10 +5,10 @@ /** * Define a área segura para renderização de conteúdo no PDF. */ -public class SafeArea { +public final class SafeArea { private static final float HEADER_HEIGHT = 40f; private static final float FOOTER_HEIGHT = 40f; - + private final float originalMarginLeft; private final float originalMarginRight; private final float originalMarginTop; @@ -35,6 +35,7 @@ private SafeArea(Builder builder) { /** * Retorna a área de conteúdo segura considerando as margens e áreas de cabeçalho/rodapé. + * * @param pageSize Tamanho da página * @return Retângulo representando a área segura */ @@ -42,20 +43,21 @@ public PDRectangle getContentArea(PDRectangle pageSize) { if (pageSize == null) { throw new IllegalArgumentException("pageSize não pode ser nulo"); } - + float extraTopMargin = hasHeader ? HEADER_HEIGHT : 0; float extraBottomMargin = hasFooter ? FOOTER_HEIGHT : 0; - + return new PDRectangle( - marginLeft, - marginBottom + extraBottomMargin, - pageSize.getWidth() - marginLeft - marginRight, - pageSize.getHeight() - marginTop - marginBottom - extraTopMargin - extraBottomMargin + marginLeft, + marginBottom + extraBottomMargin, + pageSize.getWidth() - marginLeft - marginRight, + pageSize.getHeight() - marginTop - marginBottom - extraTopMargin - extraBottomMargin ); } /** * Retorna a área do cabeçalho. + * * @param pageSize Tamanho da página * @return Retângulo representando a área do cabeçalho * @throws IllegalStateException se o cabeçalho não estiver habilitado @@ -67,17 +69,18 @@ public PDRectangle getHeaderArea(PDRectangle pageSize) { if (!hasHeader) { throw new IllegalStateException("Cabeçalho não está habilitado"); } - + return new PDRectangle( - marginLeft, - pageSize.getHeight() - marginTop - HEADER_HEIGHT, - pageSize.getWidth() - marginLeft - marginRight, - HEADER_HEIGHT + marginLeft, + pageSize.getHeight() - marginTop - HEADER_HEIGHT, + pageSize.getWidth() - marginLeft - marginRight, + HEADER_HEIGHT ); } /** * Retorna a área do rodapé. + * * @param pageSize Tamanho da página * @return Retângulo representando a área do rodapé * @throws IllegalStateException se o rodapé não estiver habilitado @@ -89,28 +92,29 @@ public PDRectangle getFooterArea(PDRectangle pageSize) { if (!hasFooter) { throw new IllegalStateException("Rodapé não está habilitado"); } - + return new PDRectangle( - marginLeft, - marginBottom, - pageSize.getWidth() - marginLeft - marginRight, - FOOTER_HEIGHT + marginLeft, + marginBottom, + pageSize.getWidth() - marginLeft - marginRight, + FOOTER_HEIGHT ); } /** * Verifica se um ponto está dentro da área segura. - * @param x Coordenada X do ponto - * @param y Coordenada Y do ponto + * + * @param x Coordenada X do ponto + * @param y Coordenada Y do ponto * @param pageSize Tamanho da página * @return true se o ponto estiver dentro da área segura */ public boolean isPointInSafeArea(float x, float y, PDRectangle pageSize) { PDRectangle contentArea = getContentArea(pageSize); - return x >= contentArea.getLowerLeftX() && - x <= contentArea.getUpperRightX() && - y >= contentArea.getLowerLeftY() && - y <= contentArea.getUpperRightY(); + return x >= contentArea.getLowerLeftX() && + x <= contentArea.getUpperRightX() && + y >= contentArea.getLowerLeftY() && + y <= contentArea.getUpperRightY(); } public void reset() { @@ -152,10 +156,21 @@ public void setMarginLeft(float marginLeft) { this.marginLeft = marginLeft; } - public boolean hasHeader() { return hasHeader; } - public boolean hasFooter() { return hasFooter; } - public float getHeaderHeight() { return HEADER_HEIGHT; } - public float getFooterHeight() { return FOOTER_HEIGHT; } + public boolean hasHeader() { + return hasHeader; + } + + public boolean hasFooter() { + return hasFooter; + } + + public float getHeaderHeight() { + return HEADER_HEIGHT; + } + + public float getFooterHeight() { + return FOOTER_HEIGHT; + } public static Builder builder() { return new Builder(); diff --git a/src/main/java/io/github/joabsonlg/pdfbuilder/examples/CompleteExample.java b/src/main/java/io/github/joabsonlg/pdfbuilder/examples/CompleteExample.java index 57f1e5e..721d95a 100644 --- a/src/main/java/io/github/joabsonlg/pdfbuilder/examples/CompleteExample.java +++ b/src/main/java/io/github/joabsonlg/pdfbuilder/examples/CompleteExample.java @@ -5,25 +5,29 @@ import io.github.joabsonlg.pdfbuilder.components.logo.LogoStyle; import io.github.joabsonlg.pdfbuilder.components.page.PageNumbering; import io.github.joabsonlg.pdfbuilder.components.page.PageSectionStyle; +import io.github.joabsonlg.pdfbuilder.components.table.Table; import io.github.joabsonlg.pdfbuilder.components.text.Heading; import io.github.joabsonlg.pdfbuilder.components.text.HeadingLevel; import io.github.joabsonlg.pdfbuilder.components.text.Paragraph; import io.github.joabsonlg.pdfbuilder.components.text.TextAlignment; import io.github.joabsonlg.pdfbuilder.components.text.TextStyle; -import io.github.joabsonlg.pdfbuilder.components.table.Table; import io.github.joabsonlg.pdfbuilder.core.PDFBuilder; import io.github.joabsonlg.pdfbuilder.core.PDFConfiguration; import io.github.joabsonlg.pdfbuilder.core.SafeArea; - import org.apache.pdfbox.pdmodel.common.PDRectangle; import org.apache.pdfbox.pdmodel.font.PDType1Font; import org.apache.pdfbox.pdmodel.font.Standard14Fonts; -import java.awt.Color; +import java.awt.*; import java.io.File; import java.util.ArrayList; -public class CompleteExample { +public final class CompleteExample { + + private CompleteExample() { + throw new UnsupportedOperationException("This is a utility class and cannot be instantiated"); + } + public static void main(String[] args) { try { // Configuração da área segura com header e footer @@ -111,19 +115,19 @@ public static void main(String[] args) { // Adiciona texto introdutório builder.addParagraph(Paragraph.builder() - .addStyledText("Este é um exemplo completo que demonstra todas as funcionalidades do ", + .addStyledText("Este é um exemplo completo que demonstra todas as funcionalidades do ", TextStyle.builder() - .withFont(defaultFont) - .withFontSize(12f) - .withColor(Color.BLACK) - .build()) + .withFont(defaultFont) + .withFontSize(12f) + .withColor(Color.BLACK) + .build()) .addStyledText("PDF Builder", boldStyle) - .addStyledText(". Abaixo você verá exemplos de cabeçalhos, rodapés, listas, tabelas e imagens.", + .addStyledText(". Abaixo você verá exemplos de cabeçalhos, rodapés, listas, tabelas e imagens.", TextStyle.builder() - .withFont(defaultFont) - .withFontSize(12f) - .withColor(Color.BLACK) - .build()) + .withFont(defaultFont) + .withFontSize(12f) + .withColor(Color.BLACK) + .build()) .build()); builder.moveDown(20); @@ -141,13 +145,13 @@ public static void main(String[] args) { // Cria uma lista com itens estilizados java.util.List items = new ArrayList<>(); - + ListItem item1 = new ListItem("Recursos do PDF Builder:", defaultFont, 12, Color.BLACK); item1.addSubItem(new ListItem("Cabeçalhos e Rodapés personalizados", defaultFont, 12, Color.BLACK)); item1.addSubItem(new ListItem("Numeração automática de páginas", defaultFont, 12, Color.BLACK)); item1.addSubItem(new ListItem("Suporte a imagens com legendas", defaultFont, 12, Color.BLACK)); items.add(item1); - + ListItem item2 = new ListItem("Formatação de Texto:", defaultFont, 12, Color.BLACK); item2.addSubItem(new ListItem("Diferentes estilos e cores", defaultFont, 12, Color.BLACK)); item2.addSubItem(new ListItem("Alinhamento personalizado", defaultFont, 12, Color.BLACK)); diff --git a/src/main/java/io/github/joabsonlg/pdfbuilder/examples/HeaderFooterDemo.java b/src/main/java/io/github/joabsonlg/pdfbuilder/examples/HeaderFooterDemo.java index 6a179e3..2f5d738 100644 --- a/src/main/java/io/github/joabsonlg/pdfbuilder/examples/HeaderFooterDemo.java +++ b/src/main/java/io/github/joabsonlg/pdfbuilder/examples/HeaderFooterDemo.java @@ -17,7 +17,12 @@ import java.awt.Color; -public class HeaderFooterDemo { +public final class HeaderFooterDemo { + + private HeaderFooterDemo() { + throw new UnsupportedOperationException("This is a utility class and cannot be instantiated"); + } + public static void main(String[] args) { try { // Configuração da área segura com header e footer diff --git a/src/main/java/io/github/joabsonlg/pdfbuilder/examples/HeadingDemo.java b/src/main/java/io/github/joabsonlg/pdfbuilder/examples/HeadingDemo.java index 04b5b25..17e03d6 100644 --- a/src/main/java/io/github/joabsonlg/pdfbuilder/examples/HeadingDemo.java +++ b/src/main/java/io/github/joabsonlg/pdfbuilder/examples/HeadingDemo.java @@ -15,8 +15,13 @@ /** * Demonstração do uso de títulos e subtítulos. */ -public class HeadingDemo { - private static final Logger logger = LoggerFactory.getLogger(HeadingDemo.class); +public final class HeadingDemo { + + private HeadingDemo() { + throw new UnsupportedOperationException("This is a utility class and cannot be instantiated"); + } + + private static final Logger LOGGER = LoggerFactory.getLogger(HeadingDemo.class); public static void main(String[] args) { try { @@ -84,7 +89,7 @@ public static void main(String[] args) { .addStyledText("Lorem ipsum dolor sit amet, consectetur adipiscing elit. " + "Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. " + "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris " + - "nisi ut aliquip ex ea commodo consequat.", + "nisi ut aliquip ex ea commodo consequat.", TextStyle.builder() .withFont(new PDType1Font(Standard14Fonts.FontName.HELVETICA)) .withFontSize(12f) @@ -101,10 +106,10 @@ public static void main(String[] args) { .addParagraph(text); builder.save("demo_titulos.pdf"); - logger.info("PDF gerado com sucesso: demo_titulos.pdf"); + LOGGER.info("PDF gerado com sucesso: demo_titulos.pdf"); } catch (Exception e) { - logger.error("Erro ao gerar o PDF: {}", e.getMessage(), e); + LOGGER.error("Erro ao gerar o PDF: {}", e.getMessage(), e); } } } diff --git a/src/main/java/io/github/joabsonlg/pdfbuilder/examples/ImageDemo.java b/src/main/java/io/github/joabsonlg/pdfbuilder/examples/ImageDemo.java index dd135fb..8f9c03f 100644 --- a/src/main/java/io/github/joabsonlg/pdfbuilder/examples/ImageDemo.java +++ b/src/main/java/io/github/joabsonlg/pdfbuilder/examples/ImageDemo.java @@ -19,8 +19,13 @@ /** * Demonstração do uso de imagens no PDF Builder. */ -public class ImageDemo { - private static final Logger logger = LoggerFactory.getLogger(ImageDemo.class); +public final class ImageDemo { + + private ImageDemo() { + throw new UnsupportedOperationException("This is a utility class and cannot be instantiated"); + } + + private static final Logger LOGGER = LoggerFactory.getLogger(ImageDemo.class); public static void main(String[] args) { try { @@ -63,7 +68,8 @@ public static void main(String[] args) { .build(); // Carrega e adiciona imagens - File imageFile = new File("C:\\Users\\joabs\\Documents\\Projetos\\MeusProjetos\\pdf-builder-workspace\\pdf-builder\\src\\main\\java\\br\\com\\nutit\\pdfbuilder\\examples\\sample-image.jpg"); + File imageFile = new File("C:\\Users\\joabs\\Documents\\Projetos\\MeusProjetos\\pdf-builder-workspace" + + "\\pdf-builder\\src\\main\\java\\br\\com\\nutit\\pdfbuilder\\examples\\sample-image.jpg"); // Imagem original Image originalImage = Image.builder(builder.getDocument(), imageFile) @@ -109,10 +115,10 @@ public static void main(String[] args) { .build()); builder.save("demo_imagens.pdf"); - logger.info("PDF gerado com sucesso: demo_imagens.pdf"); + LOGGER.info("PDF gerado com sucesso: demo_imagens.pdf"); } catch (Exception e) { - logger.error("Erro ao gerar o PDF: {}", e.getMessage(), e); + LOGGER.error("Erro ao gerar o PDF: {}", e.getMessage(), e); } } } diff --git a/src/main/java/io/github/joabsonlg/pdfbuilder/examples/ListDemo.java b/src/main/java/io/github/joabsonlg/pdfbuilder/examples/ListDemo.java index 2df377a..ddc2a41 100644 --- a/src/main/java/io/github/joabsonlg/pdfbuilder/examples/ListDemo.java +++ b/src/main/java/io/github/joabsonlg/pdfbuilder/examples/ListDemo.java @@ -20,7 +20,12 @@ import java.util.ArrayList; import java.util.Arrays; -public class ListDemo { +public final class ListDemo { + + private ListDemo() { + throw new UnsupportedOperationException("This is a utility class and cannot be instantiated"); + } + public static void main(String[] args) { try { // Configuração da área segura com header e footer @@ -74,21 +79,21 @@ public static void main(String[] args) { // Cria uma lista não ordenada com subitens java.util.List items = new ArrayList<>(); - + // Item 1 com subitens ListItem item1 = new ListItem("Frutas", defaultFont, 12, Color.BLACK); item1.addSubItem(new ListItem("Maçã", defaultFont, 12, Color.BLACK)); item1.addSubItem(new ListItem("Banana", defaultFont, 12, Color.BLACK)); item1.addSubItem(new ListItem("Laranja", defaultFont, 12, Color.BLACK)); items.add(item1); - + // Item 2 com subitens ListItem item2 = new ListItem("Vegetais", defaultFont, 12, Color.BLACK); item2.addSubItem(new ListItem("Cenoura", defaultFont, 12, Color.BLACK)); item2.addSubItem(new ListItem("Brócolis", defaultFont, 12, Color.BLACK)); item2.addSubItem(new ListItem("Alface", defaultFont, 12, Color.BLACK)); items.add(item2); - + // Item 3 sem subitens items.add(new ListItem("Grãos", defaultFont, 12, Color.BLACK)); @@ -119,62 +124,62 @@ public static void main(String[] args) { // Cria uma lista ordenada com subitens java.util.List orderedItems = new ArrayList<>(); - + // Item 1 com subitens numerados ListItem step1 = new ListItem("Preparar a massa", defaultFont, 12, new Color(44, 62, 80)); step1.setNumber("1."); - - ListItem step1_1 = new ListItem("Misturar farinha e sal", defaultFont, 12, new Color(44, 62, 80)); - step1_1.setNumber("1.1."); - - ListItem step1_2 = new ListItem("Adicionar água aos poucos", defaultFont, 12, new Color(44, 62, 80)); - step1_2.setNumber("1.2."); - + + ListItem step1s1 = new ListItem("Misturar farinha e sal", defaultFont, 12, new Color(44, 62, 80)); + step1s1.setNumber("1.1."); + + ListItem step1s2 = new ListItem("Adicionar água aos poucos", defaultFont, 12, new Color(44, 62, 80)); + step1s2.setNumber("1.2."); + // Item com texto estilizado String text = "O entusiasmo é a maior força da "; String highlightedWord = "alma"; String remainingText = ". Conserva-o e nunca te faltará poder para conseguires o que desejas."; - + java.util.List styledTexts = Arrays.asList( new StyledText(text, normalStyle), new StyledText(highlightedWord, boldStyle), new StyledText(remainingText, normalStyle) ); - - ListItem step1_3 = new ListItem(styledTexts); - step1_3.setNumber("1.3."); - - step1.addSubItem(step1_1); - step1.addSubItem(step1_2); - step1.addSubItem(step1_3); + + ListItem step1s3 = new ListItem(styledTexts); + step1s3.setNumber("1.3."); + + step1.addSubItem(step1s1); + step1.addSubItem(step1s2); + step1.addSubItem(step1s3); orderedItems.add(step1); - + // Item 2 com subitens numerados ListItem step2 = new ListItem("Preparar o recheio", defaultFont, 12, new Color(44, 62, 80)); step2.setNumber("2."); - - ListItem step2_1 = new ListItem("Cortar os ingredientes", defaultFont, 12, new Color(44, 62, 80)); - step2_1.setNumber("2.1."); - - ListItem step2_2 = new ListItem("Temperar a gosto", defaultFont, 12, new Color(44, 62, 80)); - step2_2.setNumber("2.2."); - - step2.addSubItem(step2_1); - step2.addSubItem(step2_2); + + ListItem step2s1 = new ListItem("Cortar os ingredientes", defaultFont, 12, new Color(44, 62, 80)); + step2s1.setNumber("2.1."); + + ListItem step2s2 = new ListItem("Temperar a gosto", defaultFont, 12, new Color(44, 62, 80)); + step2s2.setNumber("2.2."); + + step2.addSubItem(step2s1); + step2.addSubItem(step2s2); orderedItems.add(step2); - + // Item 3 com subitens numerados ListItem step3 = new ListItem("Finalizar", defaultFont, 12, new Color(44, 62, 80)); step3.setNumber("3."); - - ListItem step3_1 = new ListItem("Montar a receita", defaultFont, 12, new Color(44, 62, 80)); - step3_1.setNumber("3.1."); - - ListItem step3_2 = new ListItem("Levar ao forno", defaultFont, 12, new Color(44, 62, 80)); - step3_2.setNumber("3.2."); - - step3.addSubItem(step3_1); - step3.addSubItem(step3_2); + + ListItem step3s1 = new ListItem("Montar a receita", defaultFont, 12, new Color(44, 62, 80)); + step3s1.setNumber("3.1."); + + ListItem step3s2 = new ListItem("Levar ao forno", defaultFont, 12, new Color(44, 62, 80)); + step3s2.setNumber("3.2."); + + step3.addSubItem(step3s1); + step3.addSubItem(step3s2); orderedItems.add(step3); List orderedList = List.builder() diff --git a/src/main/java/io/github/joabsonlg/pdfbuilder/examples/PDFBuilderDemo.java b/src/main/java/io/github/joabsonlg/pdfbuilder/examples/PDFBuilderDemo.java index 62ab15d..2ca2197 100644 --- a/src/main/java/io/github/joabsonlg/pdfbuilder/examples/PDFBuilderDemo.java +++ b/src/main/java/io/github/joabsonlg/pdfbuilder/examples/PDFBuilderDemo.java @@ -4,17 +4,21 @@ import io.github.joabsonlg.pdfbuilder.core.PDFBuilder; import io.github.joabsonlg.pdfbuilder.core.PDFConfiguration; import io.github.joabsonlg.pdfbuilder.core.SafeArea; - import org.apache.pdfbox.pdmodel.common.PDRectangle; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.awt.Color; + +import java.awt.*; /** * Demonstração completa das funcionalidades implementadas no PDFBuilder. */ -public class PDFBuilderDemo { - private static final Logger logger = LoggerFactory.getLogger(PDFBuilderDemo.class); +public final class PDFBuilderDemo { + private static final Logger LOGGER = LoggerFactory.getLogger(PDFBuilderDemo.class); + + private PDFBuilderDemo() { + throw new UnsupportedOperationException("This is a utility class and cannot be instantiated"); + } public static void main(String[] args) { try { @@ -29,61 +33,62 @@ public static void main(String[] args) { PDFConfiguration config = PDFConfiguration.create() .withPageSize(PDRectangle.A4) .withSafeArea(safeArea) - .withDPI(300) - .withCompressionQuality(0.8f) - .withFontSize(12f) - .withLineSpacing(14f) - .build(); + .withDPI(300) + .withCompressionQuality(0.8f) + .withFontSize(12f) + .withLineSpacing(14f) + .build(); // 2. Criação do PDFBuilder PDFBuilder builder = new PDFBuilder(config); // 3. Demonstração de texto simples com formatação SimpleText title = SimpleText.builder() - .withText("Demonstração de Texto Simples") - .withFont(builder.getResourceManager().getFont("Helvetica-Bold")) - .withFontSize(24f) - .withLineSpacing(1.5f) - .withColor(new Color(0, 102, 204)) // Azul - .build(); + .withText("Demonstração de Texto Simples") + .withFont(builder.getResourceManager().getFont("Helvetica-Bold")) + .withFontSize(24f) + .withLineSpacing(1.5f) + .withColor(new Color(0, 102, 204)) // Azul + .build(); SimpleText subtitle = SimpleText.builder() - .withText("Usando o componente SimpleText") - .withFont(builder.getResourceManager().getFont("Times-Italic")) - .withFontSize(16f) - .withLineSpacing(1.3f) - .withColor(new Color(102, 102, 102)) // Cinza - .build(); + .withText("Usando o componente SimpleText") + .withFont(builder.getResourceManager().getFont("Times-Italic")) + .withFontSize(16f) + .withLineSpacing(1.3f) + .withColor(new Color(102, 102, 102)) // Cinza + .build(); SimpleText normalText = SimpleText.builder() - .withText("Este é um texto normal usando a fonte padrão.") - .withFont(builder.getResourceManager().getDefaultFont()) - .withFontSize(12f) - .build(); + .withText("Este é um texto normal usando a fonte padrão.") + .withFont(builder.getResourceManager().getDefaultFont()) + .withFontSize(12f) + .build(); SimpleText highlightText = SimpleText.builder() - .withText(" Este texto está destacado em vermelho! Este texto está destacado em vermelho! Este texto está destacado em vermelho! Este texto está destacado em vermelho!") - .withFont(builder.getResourceManager().getFont("Helvetica-Bold")) - .withFontSize(12f) - .withColor(new Color(204, 0, 0)) // Vermelho - .build(); + .withText(" Este texto está destacado em vermelho! Este texto está destacado em vermelho! Este " + + "texto está destacado em vermelho! Este texto está destacado em vermelho!") + .withFont(builder.getResourceManager().getFont("Helvetica-Bold")) + .withFontSize(12f) + .withColor(new Color(204, 0, 0)) // Vermelho + .build(); // 4. Adicionando os textos builder.addSimpleText(title) - .moveToStart() - .moveDown(30f) - .addSimpleText(subtitle) - .moveToStart() - .moveDown(60f) - .addSimpleText(normalText) - .addSimpleText(highlightText); + .moveToStart() + .moveDown(30f) + .addSimpleText(subtitle) + .moveToStart() + .moveDown(60f) + .addSimpleText(normalText) + .addSimpleText(highlightText); // 5. Salvar o PDF builder.save("demo_texto_simples.pdf"); - logger.info("PDF gerado com sucesso: demo_texto_simples.pdf"); + LOGGER.info("PDF gerado com sucesso: demo_texto_simples.pdf"); } catch (Exception e) { - logger.error("Erro ao gerar o PDF: {}", e.getMessage(), e); + LOGGER.error("Erro ao gerar o PDF: {}", e.getMessage(), e); } } } diff --git a/src/main/java/io/github/joabsonlg/pdfbuilder/examples/PageNumberingDemo.java b/src/main/java/io/github/joabsonlg/pdfbuilder/examples/PageNumberingDemo.java index 495a0cf..7f285be 100644 --- a/src/main/java/io/github/joabsonlg/pdfbuilder/examples/PageNumberingDemo.java +++ b/src/main/java/io/github/joabsonlg/pdfbuilder/examples/PageNumberingDemo.java @@ -16,7 +16,12 @@ import java.awt.Color; -public class PageNumberingDemo { +public final class PageNumberingDemo { + + private PageNumberingDemo() { + throw new UnsupportedOperationException("This is a utility class and cannot be instantiated"); + } + public static void main(String[] args) { try { // Configuração da área segura com header e footer @@ -75,7 +80,8 @@ public static void main(String[] args) { // Adiciona texto de exemplo String text = "Este é um exemplo de texto para a página " + i + ". " + - "O texto é repetido várias vezes para ocupar espaço e forçar a criação de uma nova página. ".repeat(10); + "O texto é repetido várias vezes para ocupar espaço e forçar a criação de uma nova página. " + .repeat(10); Paragraph paragraph = Paragraph.builder() .addStyledText(text, normalStyle) diff --git a/src/main/java/io/github/joabsonlg/pdfbuilder/examples/ParagraphDemo.java b/src/main/java/io/github/joabsonlg/pdfbuilder/examples/ParagraphDemo.java index d4edc1b..1aa92bf 100644 --- a/src/main/java/io/github/joabsonlg/pdfbuilder/examples/ParagraphDemo.java +++ b/src/main/java/io/github/joabsonlg/pdfbuilder/examples/ParagraphDemo.java @@ -18,8 +18,12 @@ /** * Demonstração dos diferentes tipos de alinhamento de parágrafos e formatação rica. */ -public class ParagraphDemo { - private static final Logger logger = LoggerFactory.getLogger(ParagraphDemo.class); +public final class ParagraphDemo { + private static final Logger LOGGER = LoggerFactory.getLogger(ParagraphDemo.class); + + private ParagraphDemo() { + throw new UnsupportedOperationException("This is a utility class and cannot be instantiated"); + } public static void main(String[] args) { try { @@ -100,7 +104,8 @@ public static void main(String[] args) { Paragraph justified = Paragraph.builder() .addStyledText("Alinhamento Justificado: ", boldStyle) - .addStyledText("Este é um exemplo de texto justificado que demonstra como as palavras são distribuídas uniformemente. ", normalStyle) + .addStyledText("Este é um exemplo de texto justificado que demonstra como as palavras são " + + "distribuídas uniformemente. ", normalStyle) .addStyledText("Observe que o espaçamento entre as palavras é ajustado ", italicStyle) .addStyledText("para que o texto fique alinhado em ambas as margens. ", underlineStyle) .addStyledText("Este é um recurso muito utilizado em livros e documentos formais.", colorStyle) @@ -118,10 +123,10 @@ public static void main(String[] args) { // 5. Salvando o PDF builder.save("demo_paragrafos_formatados.pdf"); - logger.info("PDF gerado com sucesso: demo_paragrafos_formatados.pdf"); + LOGGER.info("PDF gerado com sucesso: demo_paragrafos_formatados.pdf"); } catch (Exception e) { - logger.error("Erro ao gerar o PDF: {}", e.getMessage(), e); + LOGGER.error("Erro ao gerar o PDF: {}", e.getMessage(), e); } } } diff --git a/src/main/java/io/github/joabsonlg/pdfbuilder/examples/TableDemo.java b/src/main/java/io/github/joabsonlg/pdfbuilder/examples/TableDemo.java index c132084..9f622a5 100644 --- a/src/main/java/io/github/joabsonlg/pdfbuilder/examples/TableDemo.java +++ b/src/main/java/io/github/joabsonlg/pdfbuilder/examples/TableDemo.java @@ -1,19 +1,22 @@ package io.github.joabsonlg.pdfbuilder.examples; import io.github.joabsonlg.pdfbuilder.components.table.Table; +import io.github.joabsonlg.pdfbuilder.components.text.Heading; +import io.github.joabsonlg.pdfbuilder.components.text.HeadingLevel; import io.github.joabsonlg.pdfbuilder.core.PDFBuilder; import io.github.joabsonlg.pdfbuilder.core.PDFConfiguration; import io.github.joabsonlg.pdfbuilder.core.SafeArea; -import io.github.joabsonlg.pdfbuilder.components.text.Heading; -import io.github.joabsonlg.pdfbuilder.components.text.HeadingLevel; +import org.apache.pdfbox.pdmodel.common.PDRectangle; -import java.awt.Color; +import java.awt.*; import java.util.Arrays; import java.util.List; -import org.apache.pdfbox.pdmodel.common.PDRectangle; +public final class TableDemo { + private TableDemo() { + throw new UnsupportedOperationException("This is a utility class and cannot be instantiated"); + } -public class TableDemo { public static void main(String[] args) { try { // Configuração da área segura com header e footer @@ -84,11 +87,16 @@ public static void main(String[] args) { // Cria os dados da tabela com muitas colunas List> wideTableData = Arrays.asList( - Arrays.asList("ID", "Nome", "Idade", "Cidade", "Estado", "País", "Profissão", "Departamento", "Salário", "Data de Admissão"), - Arrays.asList("1", "João Silva", "25", "São Paulo", "SP", "Brasil", "Desenvolvedor", "TI", "5000", "01/01/2020"), - Arrays.asList("2", "Maria Santos", "30", "Rio de Janeiro", "RJ", "Brasil", "Gerente", "RH", "7000", "15/03/2018"), - Arrays.asList("3", "Pedro Costa", "28", "Belo Horizonte", "MG", "Brasil", "Analista", "Financeiro", "6000", "22/07/2019") + Arrays.asList("ID", "Nome", "Idade", "Cidade", "Estado", "País", "Profissão", "Departamento", + "Salário", "Data de Admissão"), + Arrays.asList("1", "João Silva", "25", "São Paulo", "SP", "Brasil", "Desenvolvedor", "TI", "5000", + "01/01/2020"), + Arrays.asList("2", "Maria Santos", "30", "Rio de Janeiro", "RJ", "Brasil", "Gerente", "RH", "7000", + "15/03/2018"), + Arrays.asList("3", "Pedro Costa", "28", "Belo Horizonte", "MG", "Brasil", "Analista", "Financeiro", + "6000", "22/07/2019") ); + // Cria uma tabela com muitas colunas Table wideTable = Table.builder() .withData(wideTableData) diff --git a/src/test/java/io/github/joabsonlg/pdfbuilder/components/logo/LogoTest.java b/src/test/java/io/github/joabsonlg/pdfbuilder/components/logo/LogoTest.java deleted file mode 100644 index 193291d..0000000 --- a/src/test/java/io/github/joabsonlg/pdfbuilder/components/logo/LogoTest.java +++ /dev/null @@ -1,128 +0,0 @@ -package io.github.joabsonlg.pdfbuilder.components.logo; - -import io.github.joabsonlg.pdfbuilder.core.PDFBuilder; -import io.github.joabsonlg.pdfbuilder.core.PDFConfiguration; -import org.apache.pdfbox.pdmodel.common.PDRectangle; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.io.TempDir; - -import java.awt.*; -import java.io.File; -import java.io.IOException; -import java.nio.file.Path; - -import static org.junit.jupiter.api.Assertions.*; - -class LogoTest { - private PDFBuilder builder; - private Logo logo; - private LogoStyle style; - - @TempDir - Path tempDir; - - @BeforeEach - void setUp() { - PDFConfiguration config = PDFConfiguration.create() - .withPageSize(PDRectangle.A4) - .withMargins(50f, 40f, 30f, 40f) - .build(); - builder = new PDFBuilder(config); - - style = LogoStyle.builder() - .withFontSize(16f) - .withColor(Color.BLACK) - .withImageWidth(50f) - .withImageHeight(30f) - .withMaintainAspectRatio(true) - .withMarginBottom(20f) - .withDrawLine(true) - .build(); - } - - @Test - void testLogoBuilder() { - logo = Logo.builder() - .withTitle("Test Title") - .withStyle(style) - .build(); - - assertNotNull(logo); - assertEquals("Test Title", logo.getTitle()); - assertEquals(style, logo.getStyle()); - } - - @Test - void testLogoWithImages() { - logo = Logo.builder() - .withTitle("Test Title") - .withStyle(style) - .withLeftImage("path/to/left.png") - .withRightImage("path/to/right.png") - .build(); - - assertNotNull(logo); - assertEquals("path/to/left.png", logo.getLeftImagePath()); - assertEquals("path/to/right.png", logo.getRightImagePath()); - } - - @Test - void testLogoStyleBuilder() { - LogoStyle style = LogoStyle.builder() - .withFontSize(16f) - .withColor(Color.BLACK) - .withImageWidth(50f) - .withImageHeight(30f) - .withMaintainAspectRatio(true) - .withMarginBottom(20f) - .withDrawLine(true) - .build(); - - assertNotNull(style); - assertEquals(16f, style.getFontSize()); - assertEquals(Color.BLACK, style.getColor()); - assertEquals(50f, style.getImageWidth()); - assertEquals(30f, style.getImageHeight()); - assertTrue(style.isMaintainAspectRatio()); - assertEquals(20f, style.getMarginBottom()); - assertTrue(style.isDrawLine()); - } - - @Test - void testLogoRender() throws IOException { - logo = Logo.builder() - .withTitle("Test Title") - .withStyle(style) - .build(); - - File outputFile = tempDir.resolve("test-logo.pdf").toFile(); - builder.setLogo(logo); - builder.save(outputFile.getAbsolutePath()); - - assertTrue(outputFile.exists()); - assertTrue(outputFile.length() > 0); - } - - @Test - void testLogoWithImagesRender() throws IOException { - // Este teste requer imagens reais para funcionar corretamente - // Você pode criar arquivos de imagem temporários ou usar recursos de teste - String leftImagePath = getClass().getResource("/test-left-logo.png").getPath(); - String rightImagePath = getClass().getResource("/test-right-logo.png").getPath(); - - logo = Logo.builder() - .withTitle("Test Title") - .withStyle(style) - .withLeftImage(leftImagePath) - .withRightImage(rightImagePath) - .build(); - - File outputFile = tempDir.resolve("test-logo-with-images.pdf").toFile(); - builder.setLogo(logo); - builder.save(outputFile.getAbsolutePath()); - - assertTrue(outputFile.exists()); - assertTrue(outputFile.length() > 0); - } -} diff --git a/src/test/java/io/github/joabsonlg/pdfbuilder/core/CoordinatesTest.java b/src/test/java/io/github/joabsonlg/pdfbuilder/core/CoordinatesTest.java deleted file mode 100644 index a351df9..0000000 --- a/src/test/java/io/github/joabsonlg/pdfbuilder/core/CoordinatesTest.java +++ /dev/null @@ -1,196 +0,0 @@ -package io.github.joabsonlg.pdfbuilder.core; - -import org.apache.pdfbox.pdmodel.common.PDRectangle; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.DisplayName; - -import static org.junit.jupiter.api.Assertions.*; - -class CoordinatesTest { - private PDRectangle pageSize; - private SafeArea safeArea; - private Coordinates coordinates; - - @BeforeEach - void setUp() { - pageSize = PDRectangle.A4; - safeArea = new SafeArea.Builder(pageSize) - .margins(50f, 50f, 50f, 50f) - .headerHeight(30f) - .footerHeight(20f) - .build(); - coordinates = Coordinates.origin(pageSize, safeArea); - } - - @Test - @DisplayName("Deve criar coordenadas na origem") - void shouldCreateAtOrigin() { - assertEquals(0f, coordinates.getX()); - assertEquals(0f, coordinates.getY()); - assertEquals(pageSize, coordinates.getPageSize()); - assertNotNull(coordinates.getSafeArea()); - } - - @Test - @DisplayName("Deve mover para posição específica") - void shouldMoveToPosition() { - Coordinates moved = coordinates.moveTo(100f, 200f); - - assertEquals(100f, moved.getX()); - assertEquals(200f, moved.getY()); - } - - @Test - @DisplayName("Deve mover relativamente") - void shouldMoveRelatively() { - Coordinates initial = coordinates.moveTo(50f, 50f); - Coordinates moved = initial.moveBy(25f, -25f); - - assertEquals(75f, moved.getX()); - assertEquals(25f, moved.getY()); - } - - @Test - @DisplayName("Deve mover para porcentagem da área de conteúdo") - void shouldMoveToContentPercent() { - Coordinates moved = coordinates.moveToContentPercent(50f, 50f); - PDRectangle contentArea = safeArea.getContentArea(); - - float expectedX = contentArea.getLowerLeftX() + (contentArea.getWidth() * 0.5f); - float expectedY = contentArea.getLowerLeftY() + (contentArea.getHeight() * 0.5f); - - assertEquals(expectedX, moved.getX(), 0.01f); - assertEquals(expectedY, moved.getY(), 0.01f); - } - - @Test - @DisplayName("Deve mover para área do cabeçalho") - void shouldMoveToHeader() { - Coordinates moved = coordinates.moveToHeader(50f, 50f); - PDRectangle headerArea = safeArea.getHeaderArea(); - - float expectedX = headerArea.getLowerLeftX() + (headerArea.getWidth() * 0.5f); - float expectedY = headerArea.getLowerLeftY() + (headerArea.getHeight() * 0.5f); - - assertEquals(expectedX, moved.getX(), 0.01f); - assertEquals(expectedY, moved.getY(), 0.01f); - } - - @Test - @DisplayName("Deve mover para área do rodapé") - void shouldMoveToFooter() { - Coordinates moved = coordinates.moveToFooter(50f, 50f); - PDRectangle footerArea = safeArea.getFooterArea(); - - float expectedX = footerArea.getLowerLeftX() + (footerArea.getWidth() * 0.5f); - float expectedY = footerArea.getLowerLeftY() + (footerArea.getHeight() * 0.5f); - - assertEquals(expectedX, moved.getX(), 0.01f); - assertEquals(expectedY, moved.getY(), 0.01f); - } - - @Test - @DisplayName("Deve validar ponto na área segura") - void shouldValidatePointInSafeArea() { - PDRectangle contentArea = safeArea.getContentArea(); - - // Ponto dentro da área segura - Coordinates inside = coordinates.moveTo( - contentArea.getLowerLeftX() + 10, - contentArea.getLowerLeftY() + 10 - ); - assertTrue(inside.isInSafeArea()); - - // Ponto fora da área segura - Coordinates outside = coordinates.moveTo(10f, 10f); - assertFalse(outside.isInSafeArea()); - } - - @Test - @DisplayName("Deve ajustar coordenadas para área segura") - void shouldAdjustToSafeArea() { - PDRectangle contentArea = safeArea.getContentArea(); - - // Ponto fora da área segura (muito à esquerda e abaixo) - Coordinates outside = coordinates.moveTo(10f, 10f); - Coordinates adjusted = outside.ensureInSafeArea(); - - assertEquals(contentArea.getLowerLeftX(), adjusted.getX()); - assertEquals(contentArea.getLowerLeftY(), adjusted.getY()); - - // Ponto fora da área segura (muito à direita e acima) - outside = coordinates.moveTo( - pageSize.getWidth() + 10, - pageSize.getHeight() + 10 - ); - adjusted = outside.ensureInSafeArea(); - - assertEquals(contentArea.getUpperRightX(), adjusted.getX()); - assertEquals(contentArea.getUpperRightY(), adjusted.getY()); - } - - @Test - @DisplayName("Deve rejeitar percentagens inválidas") - void shouldRejectInvalidPercentages() { - assertThrows(IllegalArgumentException.class, () -> - coordinates.moveToContentPercent(-1f, 50f)); - - assertThrows(IllegalArgumentException.class, () -> - coordinates.moveToContentPercent(50f, 101f)); - - assertThrows(IllegalArgumentException.class, () -> - coordinates.moveToHeader(-1f, 50f)); - - assertThrows(IllegalArgumentException.class, () -> - coordinates.moveToFooter(50f, 101f)); - } - - @Test - @DisplayName("Deve rejeitar movimento para cabeçalho quando não definido") - void shouldRejectHeaderMoveWhenNotDefined() { - SafeArea safeAreaNoHeader = new SafeArea.Builder(pageSize) - .margins(50f, 50f, 50f, 50f) - .build(); - Coordinates coords = Coordinates.origin(pageSize, safeAreaNoHeader); - - assertThrows(IllegalStateException.class, () -> - coords.moveToHeader(50f, 50f)); - } - - @Test - @DisplayName("Deve rejeitar movimento para rodapé quando não definido") - void shouldRejectFooterMoveWhenNotDefined() { - SafeArea safeAreaNoFooter = new SafeArea.Builder(pageSize) - .margins(50f, 50f, 50f, 50f) - .build(); - Coordinates coords = Coordinates.origin(pageSize, safeAreaNoFooter); - - assertThrows(IllegalStateException.class, () -> - coords.moveToFooter(50f, 50f)); - } - - @Test - @DisplayName("Deve mover para o topo da área de conteúdo") - void shouldMoveToTop() { - // Given - float marginTop = 50f; - float marginRight = 50f; - float marginBottom = 50f; - float marginLeft = 50f; - float headerHeight = 30f; - SafeArea safeArea = new SafeArea.Builder(pageSize) - .margins(marginTop, marginRight, marginBottom, marginLeft) - .headerHeight(headerHeight) - .build(); - Coordinates coords = Coordinates.origin(pageSize, safeArea); - - // When - Coordinates moved = coords.moveToTop(); - - // Then - float expectedY = pageSize.getHeight() - marginTop - headerHeight; - assertEquals(coords.getX(), moved.getX(), 0.1); // X não deve mudar - assertEquals(expectedY, moved.getY(), 0.1); - } -} diff --git a/src/test/java/io/github/joabsonlg/pdfbuilder/core/PDFBuilderTest.java b/src/test/java/io/github/joabsonlg/pdfbuilder/core/PDFBuilderTest.java deleted file mode 100644 index 142a2cc..0000000 --- a/src/test/java/io/github/joabsonlg/pdfbuilder/core/PDFBuilderTest.java +++ /dev/null @@ -1,327 +0,0 @@ -package io.github.joabsonlg.pdfbuilder.core; - -import org.apache.pdfbox.Loader; -import org.apache.pdfbox.pdmodel.PDDocument; -import org.apache.pdfbox.pdmodel.PDPage; -import org.apache.pdfbox.pdmodel.common.PDRectangle; -import org.apache.pdfbox.pdmodel.font.PDFont; -import org.apache.pdfbox.pdmodel.font.PDType1Font; -import org.apache.pdfbox.pdmodel.font.Standard14Fonts; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.io.TempDir; - -import java.io.File; -import java.io.IOException; -import java.nio.file.Path; - -import static org.junit.jupiter.api.Assertions.*; - -class PDFBuilderTest { - - @TempDir - Path tempDir; - - @Test - @DisplayName("Deve criar builder com configuração padrão") - void createWithDefaultConfiguration() { - PDFBuilder builder = PDFBuilder.create(); - assertNotNull(builder); - assertNotNull(builder.getDocument()); - assertNotNull(builder.getCurrentPage()); - assertNotNull(builder.getCurrentPosition()); - assertEquals(PDRectangle.A4, builder.getConfig().getPageSize()); - } - - @Test - @DisplayName("Deve criar builder com configuração personalizada") - void createWithCustomConfiguration() { - PDFConfiguration config = PDFConfiguration.create() - .withPageSize(PDRectangle.LETTER) - .withSafeArea(new SafeArea.Builder(PDRectangle.LETTER) - .margins(50f, 50f, 50f, 50f) - .build()) - .build(); - - PDFBuilder builder = PDFBuilder.create(config); - assertNotNull(builder); - assertEquals(PDRectangle.LETTER, builder.getConfig().getPageSize()); - assertEquals(50f, builder.getConfig().getSafeArea().getMarginTop()); - } - - @Test - @DisplayName("Deve criar nova página com tamanho correto") - void addNewPageCreatesNewPageWithCorrectSize() { - PDFBuilder builder = PDFBuilder.create(); - PDPage initialPage = builder.getCurrentPage(); - - builder.addNewPage(); - PDPage newPage = builder.getCurrentPage(); - - assertNotNull(newPage); - assertNotEquals(initialPage, newPage); - assertEquals(PDRectangle.A4, newPage.getMediaBox()); - } - - @Test - @DisplayName("Deve atualizar posição com moveTo") - void moveToUpdatesPosition() { - PDFBuilder builder = PDFBuilder.create(); - builder.moveTo(100, 200); - - Coordinates pos = builder.getCurrentPosition(); - assertEquals(100, pos.getX()); - assertEquals(200, pos.getY()); - } - - @Test - @DisplayName("Deve atualizar posição relativamente com moveBy") - void moveByUpdatesPositionRelatively() { - PDFBuilder builder = PDFBuilder.create(); - builder.moveTo(100, 100).moveBy(50, -25); - - Coordinates pos = builder.getCurrentPosition(); - assertEquals(150, pos.getX()); - assertEquals(75, pos.getY()); - } - - @Test - @DisplayName("Deve posicionar corretamente na área de conteúdo") - void moveToContentPercentPositionsCorrectly() { - SafeArea safeArea = new SafeArea.Builder(PDRectangle.A4) - .margins(50f, 50f, 50f, 50f) - .build(); - - PDFConfiguration config = PDFConfiguration.create() - .withSafeArea(safeArea) - .build(); - - PDFBuilder builder = PDFBuilder.create(config); - builder.moveToContentPercent(50, 50); - - Coordinates pos = builder.getCurrentPosition(); - PDRectangle contentArea = safeArea.getContentArea(); - float expectedX = contentArea.getLowerLeftX() + (contentArea.getWidth() * 0.5f); - float expectedY = contentArea.getLowerLeftY() + (contentArea.getHeight() * 0.5f); - - assertEquals(expectedX, pos.getX(), 0.1); - assertEquals(expectedY, pos.getY(), 0.1); - } - - @Test - @DisplayName("Deve posicionar corretamente na área do cabeçalho") - void moveToHeaderPositionsInHeaderArea() { - SafeArea safeArea = new SafeArea.Builder(PDRectangle.A4) - .margins(50f, 50f, 50f, 50f) - .headerHeight(100f) - .build(); - - PDFConfiguration config = PDFConfiguration.create() - .withSafeArea(safeArea) - .build(); - - PDFBuilder builder = PDFBuilder.create(config); - builder.moveToHeader(50, 50); - - Coordinates pos = builder.getCurrentPosition(); - PDRectangle headerArea = safeArea.getHeaderArea(); - float expectedY = headerArea.getLowerLeftY() + (headerArea.getHeight() * 0.5f); - assertTrue(pos.getY() >= expectedY); - } - - @Test - @DisplayName("Deve posicionar corretamente na área do rodapé") - void moveToFooterPositionsInFooterArea() { - SafeArea safeArea = new SafeArea.Builder(PDRectangle.A4) - .margins(50f, 50f, 50f, 50f) - .footerHeight(100f) - .build(); - - PDFConfiguration config = PDFConfiguration.create() - .withSafeArea(safeArea) - .build(); - - PDFBuilder builder = PDFBuilder.create(config); - builder.moveToFooter(50, 50); - - Coordinates pos = builder.getCurrentPosition(); - PDRectangle footerArea = safeArea.getFooterArea(); - float expectedY = footerArea.getLowerLeftY() + (footerArea.getHeight() * 0.5f); - assertTrue(pos.getY() <= expectedY + footerArea.getHeight()); - } - - @Test - @DisplayName("Deve criar arquivo PDF com texto") - void addTextAndSaveCreatesPDFFile() throws IOException { - PDFBuilder builder = PDFBuilder.create(); - String testText = "Hello, PDF!"; - - File outputFile = tempDir.resolve("test.pdf").toFile(); - - builder.moveTo(50, 700) - .addText(testText) - .save(outputFile.getAbsolutePath()); - - assertTrue(outputFile.exists()); - assertTrue(outputFile.length() > 0); - - try (PDDocument doc = Loader.loadPDF(outputFile)) { - assertEquals(1, doc.getNumberOfPages()); - } - } - - @Test - @DisplayName("Deve lançar exceção para configuração nula") - void throwsExceptionForNullConfiguration() { - assertThrows(IllegalArgumentException.class, () -> PDFBuilder.create(null)); - } - - @Test - @DisplayName("Deve criar PDF com configurações padrão") - void shouldCreatePDFWithDefaultSettings() throws IOException { - Path pdfPath = tempDir.resolve("test.pdf"); - - PDFBuilder builder = PDFBuilder.create(); - builder.save(pdfPath.toString()); - builder.close(); - - assertTrue(pdfPath.toFile().exists()); - assertTrue(pdfPath.toFile().length() > 0); - } - - @Test - @DisplayName("Deve criar PDF com configuração personalizada") - void shouldCreatePDFWithCustomConfiguration() { - SafeArea safeArea = new SafeArea.Builder(PDRectangle.A3) - .margins(100f, 100f, 100f, 100f) - .build(); - - PDFConfiguration config = PDFConfiguration.create() - .withPageSize(PDRectangle.A3) - .withSafeArea(safeArea) - .withDPI(600) - .build(); - - PDFBuilder builder = PDFBuilder.create(config); - - assertEquals(PDRectangle.A3, builder.getConfig().getPageSize()); - assertEquals(100f, builder.getConfig().getSafeArea().getMarginTop()); - assertEquals(600, builder.getConfig().getDpi()); - } - - @Test - @DisplayName("Deve criar PDF com margens personalizadas") - void shouldCreatePDFWithCustomMargins() { - SafeArea safeArea = new SafeArea.Builder(PDRectangle.A4) - .margins(100f, 100f, 100f, 100f) - .build(); - - PDFConfiguration config = PDFConfiguration.create() - .withSafeArea(safeArea) - .build(); - - PDFBuilder builder = PDFBuilder.create(config); - - assertEquals(100f, builder.getConfig().getSafeArea().getMarginTop()); - } - - @Test - @DisplayName("Deve atualizar tamanho da página via PDFBuilder") - void shouldUpdatePageSizeViaPDFBuilder() { - PDFBuilder builder = PDFBuilder.create() - .withPageSize(PDRectangle.A3); - - PDRectangle pageSize = builder.getConfig().getPageSize(); - assertEquals(PDRectangle.A3.getWidth(), pageSize.getWidth(), 0.001); - assertEquals(PDRectangle.A3.getHeight(), pageSize.getHeight(), 0.001); - } - - @Test - @DisplayName("Deve adicionar múltiplas páginas") - void shouldAddMultiplePages() { - PDFBuilder builder = PDFBuilder.create(); - int initialPageCount = builder.getDocument().getNumberOfPages(); - - builder.addNewPage() - .addNewPage(); - - assertEquals(initialPageCount + 2, builder.getDocument().getNumberOfPages()); - } - - @Test - @DisplayName("Deve usar novo tamanho de página ao adicionar página") - void shouldUseNewPageSizeWhenAddingPage() { - PDFBuilder builder = PDFBuilder.create() - .withPageSize(PDRectangle.A3) - .addNewPage(); - - PDPage currentPage = builder.getCurrentPage(); - assertEquals(PDRectangle.A3.getWidth(), currentPage.getMediaBox().getWidth(), 0.001); - assertEquals(PDRectangle.A3.getHeight(), currentPage.getMediaBox().getHeight(), 0.001); - } - - @Test - @DisplayName("Deve retornar uma instância de ResourceManager") - void shouldReturnResourceManagerInstance() { - PDFBuilder builder = PDFBuilder.create(); - assertNotNull(builder.getResourceManager()); - } - - @Test - @DisplayName("Deve manter a mesma instância de ResourceManager") - void shouldMaintainSameResourceManagerInstance() { - PDFBuilder builder = PDFBuilder.create(); - ResourceManager manager1 = builder.getResourceManager(); - ResourceManager manager2 = builder.getResourceManager(); - assertSame(manager1, manager2); - } - - @Test - @DisplayName("ResourceManager deve inicializar com fonte padrão") - void resourceManagerShouldInitializeWithDefaultFont() { - PDFBuilder builder = PDFBuilder.create(); - ResourceManager manager = builder.getResourceManager(); - PDFont helvetica = new PDType1Font(Standard14Fonts.FontName.HELVETICA); - assertEquals(helvetica.getName(), manager.getDefaultFont().getName()); - } - - @Test - @DisplayName("Deve adicionar texto usando sistema de coordenadas") - void shouldAddTextUsingCoordinates() throws IOException { - PDFBuilder builder = PDFBuilder.create(); - Path outputPath = tempDir.resolve("test.pdf"); - - builder.moveToTop() - .moveRight(50.0f) - .addText("Primeiro texto") - .moveDown(20.0f) - .moveToStart() - .moveRight(100.0f) - .addText("Segundo texto") - .moveToBottom() - .moveToStart() - .addText("Texto no final"); - - builder.save(outputPath.toString()); - assertTrue(outputPath.toFile().exists()); - assertTrue(outputPath.toFile().length() > 0); - } - - @Test - @DisplayName("Deve adicionar múltiplas linhas de texto") - void shouldAddMultipleLines() throws IOException { - PDFBuilder builder = PDFBuilder.create(); - Path outputPath = tempDir.resolve("test.pdf"); - - builder.moveToTop() - .addLine("Primeira linha") - .addLine("Segunda linha") - .addLine("Terceira linha") - .addLine("Quarta linha") - .addLine("Quinta linha"); - - builder.save(outputPath.toString()); - assertTrue(outputPath.toFile().exists()); - assertTrue(outputPath.toFile().length() > 0); - } -} diff --git a/src/test/java/io/github/joabsonlg/pdfbuilder/core/PDFConfigurationTest.java b/src/test/java/io/github/joabsonlg/pdfbuilder/core/PDFConfigurationTest.java deleted file mode 100644 index e22a344..0000000 --- a/src/test/java/io/github/joabsonlg/pdfbuilder/core/PDFConfigurationTest.java +++ /dev/null @@ -1,386 +0,0 @@ -package io.github.joabsonlg.pdfbuilder.core; - -import org.apache.pdfbox.pdmodel.common.PDRectangle; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.DisplayName; - -import static org.junit.jupiter.api.Assertions.*; - -class PDFConfigurationTest { - - @Test - @DisplayName("Deve criar configuração com valores padrão") - void shouldCreateWithDefaultValues() { - // When - PDFConfiguration config = PDFConfiguration.create().build(); - - // Then - assertEquals(PDRectangle.A4, config.getPageSize()); - assertEquals(50f, config.getMarginTop()); - assertEquals(50f, config.getMarginRight()); - assertEquals(50f, config.getMarginBottom()); - assertEquals(50f, config.getMarginLeft()); - assertEquals(300, config.getDpi()); - assertEquals(0.7f, config.getCompressionQuality(), 0.001f); - } - - @Test - @DisplayName("Deve configurar tamanho de página personalizado") - void shouldSetCustomPageSize() { - // When - PDFConfiguration config = PDFConfiguration.create() - .withPageSize(PDRectangle.A3) - .build(); - - // Then - assertEquals(PDRectangle.A3.getWidth(), config.getPageSize().getWidth(), 0.001f); - assertEquals(PDRectangle.A3.getHeight(), config.getPageSize().getHeight(), 0.001f); - } - - @Test - @DisplayName("Deve configurar margem uniforme") - void shouldSetUniformMargin() { - // Given - float margin = 100f; - - // When - PDFConfiguration config = PDFConfiguration.create() - .withMargin(margin) - .build(); - - // Then - assertEquals(margin, config.getMarginTop()); - assertEquals(margin, config.getMarginRight()); - assertEquals(margin, config.getMarginBottom()); - assertEquals(margin, config.getMarginLeft()); - } - - @Test - @DisplayName("Deve configurar margens individuais") - void shouldSetIndividualMargins() { - // Given - float top = 100f; - float right = 90f; - float bottom = 120f; - float left = 80f; - - // When - PDFConfiguration config = PDFConfiguration.create() - .withMargins(top, right, bottom, left) - .build(); - - // Then - assertEquals(top, config.getMarginTop()); - assertEquals(right, config.getMarginRight()); - assertEquals(bottom, config.getMarginBottom()); - assertEquals(left, config.getMarginLeft()); - } - - @Test - @DisplayName("Deve calcular área de conteúdo corretamente") - void shouldCalculateContentArea() { - // Given - PDFConfiguration config = PDFConfiguration.create() - .withPageSize(PDRectangle.A4) - .withMargin(50f) - .build(); - - // When - PDRectangle contentArea = config.getContentArea(); - - // Then - float expectedWidth = PDRectangle.A4.getWidth() - (2 * 50f); - float expectedHeight = PDRectangle.A4.getHeight() - (2 * 50f); - - assertEquals(expectedWidth, contentArea.getWidth(), 0.001f); - assertEquals(expectedHeight, contentArea.getHeight(), 0.001f); - } - - @Test - @DisplayName("Deve configurar DPI") - void shouldSetDPI() { - // Given - int dpi = 600; - - // When - PDFConfiguration config = PDFConfiguration.create() - .withDPI(dpi) - .build(); - - // Then - assertEquals(dpi, config.getDpi()); - } - - @Test - @DisplayName("Deve configurar qualidade de compressão") - void shouldSetCompressionQuality() { - // Given - float quality = 0.5f; - - // When - PDFConfiguration config = PDFConfiguration.create() - .withCompressionQuality(quality) - .build(); - - // Then - assertEquals(quality, config.getCompressionQuality(), 0.001f); - } - - @Test - @DisplayName("Deve rejeitar qualidade de compressão inválida") - void shouldRejectInvalidCompressionQuality() { - // Given - float invalidQuality = 1.5f; - - // Then - assertThrows(IllegalArgumentException.class, () -> { - PDFConfiguration.create().withCompressionQuality(invalidQuality).build(); - }); - } - - @Test - @DisplayName("Deve criar configuração com margem uniforme") - void shouldCreateConfigurationWithUniformMargin() { - PDFConfiguration config = PDFConfiguration.create() - .withMargin(100) - .build(); - assertEquals(100, config.getMarginTop()); - assertEquals(100, config.getMarginRight()); - assertEquals(100, config.getMarginBottom()); - assertEquals(100, config.getMarginLeft()); - } - - @Test - @DisplayName("Deve criar configuração com margens individuais") - void shouldCreateConfigurationWithIndividualMargins() { - PDFConfiguration config = PDFConfiguration.create() - .withMargins(50, 60, 70, 80) - .build(); - assertEquals(50, config.getMarginTop()); - assertEquals(60, config.getMarginRight()); - assertEquals(70, config.getMarginBottom()); - assertEquals(80, config.getMarginLeft()); - } - - @Test - @DisplayName("Deve criar configuração com tamanho de fonte") - void shouldCreateConfigurationWithFontSize() { - PDFConfiguration config = PDFConfiguration.create() - .withFontSize(14) - .build(); - assertEquals(14, config.getFontSize()); - } - - @Test - @DisplayName("Deve criar configuração com espaçamento entre linhas") - void shouldCreateConfigurationWithLineSpacing() { - PDFConfiguration config = PDFConfiguration.create() - .withLineSpacing(16) - .build(); - assertEquals(16, config.getLineSpacing()); - } - - @Test - @DisplayName("Deve manter valores padrão quando não configurados") - void shouldKeepDefaultValuesWhenNotConfigured() { - PDFConfiguration config = PDFConfiguration.create().build(); - assertEquals(50, config.getMarginTop()); // DEFAULT_MARGIN - assertEquals(12, config.getFontSize()); // DEFAULT_FONT_SIZE - assertEquals(14, config.getLineSpacing()); // DEFAULT_LINE_SPACING - } - - @Test - @DisplayName("Deve permitir configuração em cadeia") - void shouldAllowChainedConfiguration() { - PDFConfiguration config = PDFConfiguration.create() - .withMargin(100) - .withFontSize(16) - .withLineSpacing(18) - .build(); - - assertEquals(100, config.getMarginTop()); - assertEquals(16, config.getFontSize()); - assertEquals(18, config.getLineSpacing()); - } - - @Test - @DisplayName("Deve rejeitar margens negativas") - void shouldRejectNegativeMargins() { - assertThrows(IllegalArgumentException.class, () -> { - PDFConfiguration.create().withMargin(-1).build(); - }); - - assertThrows(IllegalArgumentException.class, () -> { - PDFConfiguration.create().withMargins(-1, 0, 0, 0).build(); - }); - } - - @Test - @DisplayName("Deve rejeitar tamanho de fonte negativo ou zero") - void shouldRejectNegativeOrZeroFontSize() { - assertThrows(IllegalArgumentException.class, () -> { - PDFConfiguration.create().withFontSize(-1).build(); - }); - - assertThrows(IllegalArgumentException.class, () -> { - PDFConfiguration.create().withFontSize(0).build(); - }); - } - - @Test - @DisplayName("Deve rejeitar espaçamento entre linhas negativo ou zero") - void shouldRejectNegativeOrZeroLineSpacing() { - assertThrows(IllegalArgumentException.class, () -> { - PDFConfiguration.create().withLineSpacing(-1).build(); - }); - - assertThrows(IllegalArgumentException.class, () -> { - PDFConfiguration.create().withLineSpacing(0).build(); - }); - } - - @Test - @DisplayName("Deve rejeitar DPI menor ou igual a zero") - void shouldRejectZeroOrNegativeDPI() { - assertThrows(IllegalArgumentException.class, () -> { - PDFConfiguration.create().withDPI(0).build(); - }); - - assertThrows(IllegalArgumentException.class, () -> { - PDFConfiguration.create().withDPI(-1).build(); - }); - } - - @Test - @DisplayName("Deve rejeitar tamanho de página nulo") - void shouldRejectNullPageSize() { - assertThrows(IllegalArgumentException.class, () -> { - PDFConfiguration.create().withPageSize(null).build(); - }); - } - - @Test - @DisplayName("Deve rejeitar margens negativas em qualquer posição") - void shouldRejectNegativeMarginsInAnyPosition() { - assertThrows(IllegalArgumentException.class, () -> { - PDFConfiguration.create().withMargins(0, -1, 0, 0).build(); - }); - - assertThrows(IllegalArgumentException.class, () -> { - PDFConfiguration.create().withMargins(0, 0, -1, 0).build(); - }); - - assertThrows(IllegalArgumentException.class, () -> { - PDFConfiguration.create().withMargins(0, 0, 0, -1).build(); - }); - } - - @Test - @DisplayName("Deve validar que getMargin retorna margem superior quando todas são iguais") - void shouldValidateUniformMarginGetter() { - PDFConfiguration config = PDFConfiguration.create() - .withMargin(100) - .build(); - - assertEquals(100, config.getMargin()); - assertEquals(config.getMarginTop(), config.getMargin()); - } - - @Test - @DisplayName("Deve manter valores padrão ao alterar apenas algumas configurações") - void shouldKeepDefaultValuesWhenPartiallyConfigured() { - PDFConfiguration config = PDFConfiguration.create() - .withMargin(100) - .withFontSize(16) - .build(); - - assertEquals(100, config.getMarginTop()); - assertEquals(16, config.getFontSize()); - assertEquals(14, config.getLineSpacing()); // valor padrão do lineSpacing - assertEquals(300, config.getDpi()); // valor padrão do DPI - assertEquals(0.7f, config.getCompressionQuality(), 0.001f); // valor padrão da qualidade de compressão - } - - @Test - @DisplayName("Deve validar consistência dos valores padrão") - void shouldValidateDefaultValuesConsistency() { - PDFConfiguration config = PDFConfiguration.create().build(); - - // Verifica se todos os valores padrão são consistentes - assertEquals(PDRectangle.A4, config.getPageSize()); - assertEquals(50f, config.getMarginTop()); - assertEquals(50f, config.getMarginRight()); - assertEquals(50f, config.getMarginBottom()); - assertEquals(50f, config.getMarginLeft()); - assertEquals(300, config.getDpi()); - assertEquals(0.7f, config.getCompressionQuality(), 0.001f); - assertEquals(12f, config.getFontSize()); - assertEquals(14f, config.getLineSpacing()); - } - - @Test - @DisplayName("Deve configurar área segura") - void shouldSetSafeArea() { - // Given - SafeArea safeArea = SafeArea.builder() - .withMargins(30f, 50f, 40f, 30f) - .withHeader(true) - .withFooter(true) - .build(); - - // When - PDFConfiguration config = PDFConfiguration.create() - .withSafeArea(safeArea) - .build(); - - // Then - assertEquals(safeArea, config.getSafeArea()); - assertEquals(30f, config.getSafeArea().getMarginLeft()); - assertEquals(50f, config.getSafeArea().getMarginRight()); - assertEquals(40f, config.getSafeArea().getMarginBottom()); - assertEquals(30f, config.getSafeArea().getMarginTop()); - assertTrue(config.getSafeArea().hasHeader()); - assertTrue(config.getSafeArea().hasFooter()); - } - - @Test - @DisplayName("Deve atualizar área segura ao alterar tamanho da página") - void shouldUpdateSafeAreaWhenChangingPageSize() { - // Given - PDFConfiguration configA4 = PDFConfiguration.create() - .withPageSize(PDRectangle.A4) - .build(); - - // When - PDFConfiguration configA3 = PDFConfiguration.create() - .withPageSize(PDRectangle.A3) - .build(); - - // Then - // Verifica se as margens foram mantidas - assertEquals(50f, configA4.getSafeArea().getMarginTop()); - assertEquals(50f, configA4.getSafeArea().getMarginRight()); - assertEquals(50f, configA4.getSafeArea().getMarginBottom()); - assertEquals(50f, configA4.getSafeArea().getMarginLeft()); - - assertEquals(50f, configA3.getSafeArea().getMarginTop()); - assertEquals(50f, configA3.getSafeArea().getMarginRight()); - assertEquals(50f, configA3.getSafeArea().getMarginBottom()); - assertEquals(50f, configA3.getSafeArea().getMarginLeft()); - - // Verifica que as áreas de conteúdo são diferentes - assertNotEquals( - configA4.getSafeArea().getContentArea(PDRectangle.A4).getWidth(), - configA3.getSafeArea().getContentArea(PDRectangle.A3).getWidth() - ); - } - - @Test - @DisplayName("Deve rejeitar área segura nula") - void shouldRejectNullSafeArea() { - assertThrows(IllegalArgumentException.class, () -> - PDFConfiguration.create() - .withSafeArea(null) - .build()); - } -} diff --git a/src/test/java/io/github/joabsonlg/pdfbuilder/core/SafeAreaTest.java b/src/test/java/io/github/joabsonlg/pdfbuilder/core/SafeAreaTest.java deleted file mode 100644 index 025e261..0000000 --- a/src/test/java/io/github/joabsonlg/pdfbuilder/core/SafeAreaTest.java +++ /dev/null @@ -1,179 +0,0 @@ -package io.github.joabsonlg.pdfbuilder.core; - -import org.apache.pdfbox.pdmodel.common.PDRectangle; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.DisplayName; - -import static org.junit.jupiter.api.Assertions.*; - -class SafeAreaTest { - - @Test - @DisplayName("Deve criar SafeArea com valores padrão") - void shouldCreateWithDefaultValues() { - SafeArea safeArea = new SafeArea.Builder(PDRectangle.A4).build(); - - assertEquals(50f, safeArea.getMarginTop()); - assertEquals(50f, safeArea.getMarginRight()); - assertEquals(50f, safeArea.getMarginBottom()); - assertEquals(50f, safeArea.getMarginLeft()); - assertEquals(0f, safeArea.getHeaderHeight()); - assertEquals(0f, safeArea.getFooterHeight()); - assertEquals(0f, safeArea.getBleedMargin()); - assertFalse(safeArea.isMirrored()); - } - - @Test - @DisplayName("Deve criar SafeArea com margens personalizadas") - void shouldCreateWithCustomMargins() { - SafeArea safeArea = new SafeArea.Builder(PDRectangle.A4) - .margins(70f, 60f, 50f, 40f) - .build(); - - assertEquals(70f, safeArea.getMarginTop()); - assertEquals(60f, safeArea.getMarginRight()); - assertEquals(50f, safeArea.getMarginBottom()); - assertEquals(40f, safeArea.getMarginLeft()); - } - - @Test - @DisplayName("Deve criar SafeArea com cabeçalho e rodapé") - void shouldCreateWithHeaderAndFooter() { - SafeArea safeArea = new SafeArea.Builder(PDRectangle.A4) - .headerHeight(50f) - .footerHeight(30f) - .build(); - - PDRectangle headerArea = safeArea.getHeaderArea(); - PDRectangle footerArea = safeArea.getFooterArea(); - - assertNotNull(headerArea); - assertNotNull(footerArea); - assertEquals(50f, headerArea.getHeight()); - assertEquals(30f, footerArea.getHeight()); - } - - @Test - @DisplayName("Deve calcular área de conteúdo corretamente") - void shouldCalculateContentArea() { - SafeArea safeArea = new SafeArea.Builder(PDRectangle.A4) - .margins(50f, 50f, 50f, 50f) - .headerHeight(30f) - .footerHeight(20f) - .build(); - - PDRectangle contentArea = safeArea.getContentArea(); - - assertEquals(50f, contentArea.getLowerLeftX()); - assertEquals(70f, contentArea.getLowerLeftY()); // marginBottom + footerHeight - assertEquals(495.28f, contentArea.getWidth(), 0.01f); - assertEquals(691.89f, contentArea.getHeight(), 0.01f); - } - - @Test - @DisplayName("Deve validar pontos na área segura") - void shouldValidatePointsInSafeArea() { - SafeArea safeArea = new SafeArea.Builder(PDRectangle.A4) - .margins(50f, 50f, 50f, 50f) - .build(); - - assertTrue(safeArea.isPointInSafeArea(100f, 100f)); - assertFalse(safeArea.isPointInSafeArea(10f, 10f)); - } - - @Test - @DisplayName("Deve calcular margens espelhadas corretamente") - void shouldCalculateMirroredMargins() { - SafeArea safeArea = new SafeArea.Builder(PDRectangle.A4) - .margins(50f, 60f, 50f, 40f) - .mirrored(true) - .build(); - - float[] normalMargins = safeArea.getMirrordMargins(false); - float[] mirroredMargins = safeArea.getMirrordMargins(true); - - // Página ímpar (normal) - assertEquals(50f, normalMargins[0]); // top - assertEquals(60f, normalMargins[1]); // right - assertEquals(50f, normalMargins[2]); // bottom - assertEquals(40f, normalMargins[3]); // left - - // Página par (espelhada) - assertEquals(50f, mirroredMargins[0]); // top - assertEquals(40f, mirroredMargins[1]); // right (trocado com left) - assertEquals(50f, mirroredMargins[2]); // bottom - assertEquals(60f, mirroredMargins[3]); // left (trocado com right) - } - - @Test - @DisplayName("Deve rejeitar valores negativos") - void shouldRejectNegativeValues() { - SafeArea.Builder builder = new SafeArea.Builder(PDRectangle.A4); - - assertThrows(IllegalArgumentException.class, () -> - builder.margins(-1f, 0f, 0f, 0f)); - - assertThrows(IllegalArgumentException.class, () -> - builder.headerHeight(-1f)); - - assertThrows(IllegalArgumentException.class, () -> - builder.footerHeight(-1f)); - - assertThrows(IllegalArgumentException.class, () -> - builder.bleedMargin(-1f)); - } - - @Test - @DisplayName("Deve rejeitar página nula") - void shouldRejectNullPage() { - assertThrows(IllegalArgumentException.class, () -> - new SafeArea.Builder(null)); - } - - @Test - @DisplayName("Deve calcular área com sangria") - void shouldCalculateAreaWithBleed() { - SafeArea safeArea = new SafeArea.Builder(PDRectangle.A4) - .margins(50f, 50f, 50f, 50f) - .bleedMargin(10f) - .build(); - - PDRectangle contentArea = safeArea.getContentArea(); - - assertEquals(60f, contentArea.getLowerLeftX()); // marginLeft + bleed - assertEquals(60f, contentArea.getLowerLeftY()); // marginBottom + bleed - assertEquals(475.28f, contentArea.getWidth(), 0.01f); // pageWidth - (margins + 2*bleed) - assertEquals(721.89f, contentArea.getHeight(), 0.01f); // pageHeight - (margins + 2*bleed) - } - - @Test - @DisplayName("Não deve retornar áreas de cabeçalho/rodapé quando altura é zero") - void shouldNotReturnHeaderFooterAreasWhenHeightIsZero() { - SafeArea safeArea = new SafeArea.Builder(PDRectangle.A4).build(); - - assertNull(safeArea.getHeaderArea()); - assertNull(safeArea.getFooterArea()); - } - - @Test - @DisplayName("Deve calcular posição do topo da área de conteúdo") - void shouldCalculateTopPosition() { - // Given - float marginTop = 50f; - float marginRight = 50f; - float marginBottom = 50f; - float marginLeft = 50f; - float headerHeight = 30f; - SafeArea safeArea = new SafeArea.Builder(PDRectangle.A4) - .margins(marginTop, marginRight, marginBottom, marginLeft) - .headerHeight(headerHeight) - .build(); - - // When - float topY = safeArea.moveToTop(); - - // Then - float expectedY = PDRectangle.A4.getHeight() - marginTop - headerHeight; - assertEquals(expectedY, topY, 0.1); - } -}