google-site-verification: google61fe8ba583a51912.html
PDF Generation with iText in Java

Table of Contents

  1. Introduction to iText
  2. Project Setup and Dependencies
  3. Basic PDF Creation
  4. Text Styling and Formatting
  5. Tables and Layouts
  6. Images and Graphics
  7. Advanced Features
  8. PDF Forms and Interactive Elements
  9. Security and Encryption
  10. Performance Optimization

Introduction to iText

iText is a powerful Java library for creating and manipulating PDF documents. It provides comprehensive features for generating complex PDFs with text, images, tables, forms, and security features.

Key Features:

  • Text manipulation: Advanced typography and formatting
  • Table creation: Complex table layouts with styling
  • Image support: Embed various image formats
  • Forms: Interactive PDF forms
  • Security: Encryption and digital signatures
  • Accessibility: PDF/UA compliance

Project Setup and Dependencies

1. Maven Dependencies

<!-- pom.xml --> <properties> <itext.version>7.2.5</itext.version> </properties> <dependencies> <!-- iText 7 Core --> <dependency> <groupId>com.itextpdf</groupId> <artifactId>itext7-core</artifactId> <version>${itext.version}</version> <type>pom</type> </dependency> <!-- PDF/A module --> <dependency> <groupId>com.itextpdf</groupId> <artifactId>pdfa</artifactId> <version>${itext.version}</version> </dependency> <!-- Forms module --> <dependency> <groupId>com.itextpdf</groupId> <artifactId>forms</artifactId> <version>${itext.version}</version> </dependency> <!-- Layout module (for advanced layouts) --> <dependency> <groupId>com.itextpdf</groupId> <artifactId>layout</artifactId> <version>${itext.version}</version> </dependency> <!-- HTML to PDF conversion --> <dependency> <groupId>com.itextpdf</groupId> <artifactId>html2pdf</artifactId> <version>${itext.version}</version> </dependency> <!-- Barcodes --> <dependency> <groupId>com.itextpdf</groupId> <artifactId>barcodes</artifactId> <version>${itext.version}</version> </dependency> </dependencies>

2. Spring Boot Configuration

// PdfConfig.java @Configuration public class PdfConfig { @Bean public PdfFontService pdfFontService() { return new PdfFontService(); } @Bean public LicenseKeyLoader licenseKeyLoader() { // For commercial use - load license key return new LicenseKeyLoader(); } } // LicenseKeyLoader.java @Component public class LicenseKeyLoader { private static final Logger logger = LoggerFactory.getLogger(LicenseKeyLoader.class); @PostConstruct public void loadLicense() { try { // For commercial use, load your license file // LicenseKey.loadLicenseFile("path/to/itextkey.xml"); logger.info("iText license loaded successfully"); } catch (Exception e) { logger.warn("iText license not loaded - using AGPL version"); } } }

Basic PDF Creation

1. Simple PDF Generation Service

// BasicPdfService.java @Service public class BasicPdfService { private static final Logger logger = LoggerFactory.getLogger(BasicPdfService.class); public byte[] createSimplePdf(String title, String content) throws IOException { try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) { PdfWriter writer = new PdfWriter(baos); PdfDocument pdfDoc = new PdfDocument(writer); Document document = new Document(pdfDoc); // Add title Paragraph titleParagraph = new Paragraph(title) .setFontSize(20) .setBold() .setTextAlignment(TextAlignment.CENTER); document.add(titleParagraph); // Add content Paragraph contentParagraph = new Paragraph(content) .setFontSize(12) .setTextAlignment(TextAlignment.JUSTIFIED); document.add(contentParagraph); document.close(); logger.info("Simple PDF created successfully"); return baos.toByteArray(); } catch (Exception e) { logger.error("Error creating PDF", e); throw new IOException("Failed to create PDF", e); } } public byte[] createMultiPagePdf(List<String> pages) throws IOException { try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) { PdfWriter writer = new PdfWriter(baos); PdfDocument pdfDoc = new PdfDocument(writer); Document document = new Document(pdfDoc); for (int i = 0; i < pages.size(); i++) { // Add page content Paragraph pageParagraph = new Paragraph("Page " + (i + 1) + "\n" + pages.get(i)) .setFontSize(12); document.add(pageParagraph); // Add page break if not last page if (i < pages.size() - 1) { document.add(new AreaBreak(AreaBreakType.NEXT_PAGE)); } } document.close(); return baos.toByteArray(); } } public void createPdfToFile(String filePath, String content) throws IOException { PdfWriter writer = new PdfWriter(filePath); PdfDocument pdfDoc = new PdfDocument(writer); Document document = new Document(pdfDoc); try { document.add(new Paragraph(content)); logger.info("PDF saved to: {}", filePath); } finally { document.close(); } } }

2. PDF Generation Controller

// PdfController.java @RestController @RequestMapping("/api/pdf") public class PdfController { private final BasicPdfService basicPdfService; private final AdvancedPdfService advancedPdfService; public PdfController(BasicPdfService basicPdfService, AdvancedPdfService advancedPdfService) { this.basicPdfService = basicPdfService; this.advancedPdfService = advancedPdfService; } @PostMapping("/simple") public ResponseEntity<byte[]> generateSimplePdf(@RequestBody SimplePdfRequest request) { try { byte[] pdfBytes = basicPdfService.createSimplePdf(request.getTitle(), request.getContent()); return ResponseEntity.ok() .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"document.pdf\"") .contentType(MediaType.APPLICATION_PDF) .body(pdfBytes); } catch (IOException e) { return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); } } @GetMapping("/download/{documentId}") public ResponseEntity<byte[]> downloadDocument(@PathVariable String documentId) { try { // In real application, fetch document data from database String title = "Document " + documentId; String content = "This is the content for document " + documentId; byte[] pdfBytes = basicPdfService.createSimplePdf(title, content); return ResponseEntity.ok() .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"document_" + documentId + ".pdf\"") .contentType(MediaType.APPLICATION_PDF) .body(pdfBytes); } catch (IOException e) { return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); } } } // SimplePdfRequest.java public class SimplePdfRequest { private String title; private String content; // Constructors, getters, and setters public SimplePdfRequest() {} public SimplePdfRequest(String title, String content) { this.title = title; this.content = content; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } }

Text Styling and Formatting

1. Font Service and Management

// PdfFontService.java @Service public class PdfFontService { private final Map<String, PdfFont> fontCache = new ConcurrentHashMap<>(); public PdfFont getDefaultFont() throws IOException { return getFont(PdfFontFactory.EmbeddingStrategy.PREFER_EMBEDDED); } public PdfFont getFont(PdfFontFactory.EmbeddingStrategy strategy) throws IOException { String cacheKey = "default-" + strategy.name(); return fontCache.computeIfAbsent(cacheKey, key -> { try { return PdfFontFactory.createFont(StandardFonts.HELVETICA, strategy); } catch (IOException e) { throw new RuntimeException("Failed to create font", e); } }); } public PdfFont getBoldFont() throws IOException { return getFont("bold", StandardFonts.HELVETICA_BOLD); } public PdfFont getItalicFont() throws IOException { return getFont("italic", StandardFonts.HELVETICA_OBLIQUE); } public PdfFont getFont(String name, String fontName) throws IOException { return fontCache.computeIfAbsent(name, key -> { try { return PdfFontFactory.createFont(fontName, PdfFontFactory.EmbeddingStrategy.PREFER_EMBEDDED); } catch (IOException e) { throw new RuntimeException("Failed to create font: " + fontName, e); } }); } public PdfFont loadCustomFont(String fontPath) throws IOException { return fontCache.computeIfAbsent(fontPath, key -> { try { return PdfFontFactory.createFont(fontPath, PdfFontFactory.EmbeddingStrategy.FORCE_EMBEDDED); } catch (IOException e) { throw new RuntimeException("Failed to load custom font: " + fontPath, e); } }); } }

2. Advanced Text Styling Service

// TextStylingService.java @Service public class TextStylingService { private final PdfFontService fontService; public TextStylingService(PdfFontService fontService) { this.fontService = fontService; } public Paragraph createTitle(String text) throws IOException { return new Paragraph(text) .setFont(fontService.getBoldFont()) .setFontSize(24) .setFontColor(ColorConstants.BLUE) .setTextAlignment(TextAlignment.CENTER) .setMarginBottom(20); } public Paragraph createHeading(String text, int level) throws IOException { float fontSize = switch (level) { case 1 -> 18; case 2 -> 16; case 3 -> 14; default -> 12; }; return new Paragraph(text) .setFont(fontService.getBoldFont()) .setFontSize(fontSize) .setFontColor(ColorConstants.DARK_GRAY) .setMarginBottom(10) .setMarginTop(15); } public Paragraph createBodyText(String text) throws IOException { return new Paragraph(text) .setFont(fontService.getDefaultFont()) .setFontSize(12) .setFontColor(ColorConstants.BLACK) .setTextAlignment(TextAlignment.JUSTIFIED) .setMarginBottom(8); } public Paragraph createHighlightedText(String text) throws IOException { return new Paragraph(text) .setFont(fontService.getBoldFont()) .setFontSize(12) .setFontColor(ColorConstants.RED) .setBackgroundColor(ColorConstants.YELLOW) .setPadding(5); } public Paragraph createQuote(String text, String author) throws IOException { Div quoteDiv = new Div() .setBackgroundColor(ColorConstants.LIGHT_GRAY) .setPadding(15) .setMargin(10); Paragraph quoteText = new Paragraph("\"" + text + "\"") .setFont(fontService.getItalicFont()) .setFontSize(12) .setFontColor(ColorConstants.DARK_GRAY); Paragraph authorText = new Paragraph("- " + author) .setFont(fontService.getDefaultFont()) .setFontSize(10) .setFontColor(ColorConstants.GRAY) .setTextAlignment(TextAlignment.RIGHT); quoteDiv.add(quoteText); quoteDiv.add(authorText); // Since we can't return Div as Paragraph, create a container paragraph return new Paragraph().add(quoteDiv); } public List createBulletedList(List<String> items) throws IOException { List list = new List() .setSymbolIndent(12) .setListSymbol("\u2022") // Bullet character .setFont(fontService.getDefaultFont()); for (String item : items) { list.add(new ListItem(item)); } return list; } public List createNumberedList(List<String> items) throws IOException { List list = new List() .setListSymbol(ListNumberingType.DECIMAL) .setFont(fontService.getDefaultFont()); for (String item : items) { list.add(new ListItem(item)); } return list; } }

3. Styled Document Service

// StyledPdfService.java @Service public class StyledPdfService { private final TextStylingService stylingService; private final PdfFontService fontService; public StyledPdfService(TextStylingService stylingService, PdfFontService fontService) { this.stylingService = stylingService; this.fontService = fontService; } public byte[] createStyledDocument(StyledDocumentRequest request) throws IOException { try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) { PdfWriter writer = new PdfWriter(baos); PdfDocument pdfDoc = new PdfDocument(writer); Document document = new Document(pdfDoc); // Add title document.add(stylingService.createTitle(request.getTitle())); // Add author and date Paragraph metaInfo = new Paragraph() .setFontSize(10) .setFontColor(ColorConstants.GRAY) .setTextAlignment(TextAlignment.CENTER) .add("Author: " + request.getAuthor() + " | ") .add("Date: " + LocalDate.now().toString()); document.add(metaInfo); document.add(new Paragraph().setHeight(20)); // Spacing // Add content sections for (DocumentSection section : request.getSections()) { document.add(stylingService.createHeading(section.getHeading(), section.getLevel())); for (String paragraph : section.getParagraphs()) { document.add(stylingService.createBodyText(paragraph)); } // Add lists if present if (!section.getBulletPoints().isEmpty()) { document.add(stylingService.createBulletedList(section.getBulletPoints())); } document.add(new Paragraph().setHeight(10)); // Section spacing } // Add footer Paragraph footer = new Paragraph("Generated by PDF Service") .setFontSize(8) .setFontColor(ColorConstants.LIGHT_GRAY) .setTextAlignment(TextAlignment.CENTER) .setMarginTop(20); document.add(footer); document.close(); return baos.toByteArray(); } } public byte[] createInvoice(InvoiceData invoice) throws IOException { try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) { PdfWriter writer = new PdfWriter(baos); PdfDocument pdfDoc = new PdfDocument(writer); Document document = new Document(pdfDoc); // Invoice header document.add(stylingService.createTitle("INVOICE")); // Company and client info in two columns float[] columnWidths = {1, 1}; Table headerTable = new Table(columnWidths); // From column Cell fromCell = new Cell() .add(stylingService.createHeading("From:", 3)) .add(new Paragraph(invoice.getFromCompany())) .add(new Paragraph(invoice.getFromAddress())) .add(new Paragraph(invoice.getFromEmail())) .add(new Paragraph(invoice.getFromPhone())); // To column Cell toCell = new Cell() .add(stylingService.createHeading("To:", 3)) .add(new Paragraph(invoice.getToCompany())) .add(new Paragraph(invoice.getToAddress())) .add(new Paragraph(invoice.getToEmail())); headerTable.addCell(fromCell); headerTable.addCell(toCell); document.add(headerTable); // Invoice details document.add(new Paragraph().setHeight(15)); float[] detailWidths = {1, 1, 1, 1}; Table detailTable = new Table(detailWidths); // Table headers detailTable.addHeaderCell(createHeaderCell("Invoice No")); detailTable.addHeaderCell(createHeaderCell("Date")); detailTable.addHeaderCell(createHeaderCell("Due Date")); detailTable.addHeaderCell(createHeaderCell("Total")); // Table data detailTable.addCell(createDataCell(invoice.getInvoiceNumber())); detailTable.addCell(createDataCell(invoice.getInvoiceDate().toString())); detailTable.addCell(createDataCell(invoice.getDueDate().toString())); detailTable.addCell(createDataCell("$" + invoice.getTotalAmount())); document.add(detailTable); document.close(); return baos.toByteArray(); } } private Cell createHeaderCell(String text) throws IOException { return new Cell() .add(new Paragraph(text) .setFont(fontService.getBoldFont()) .setFontSize(10)) .setBackgroundColor(ColorConstants.LIGHT_GRAY) .setPadding(5); } private Cell createDataCell(String text) throws IOException { return new Cell() .add(new Paragraph(text) .setFont(fontService.getDefaultFont()) .setFontSize(10)) .setPadding(5); } } // StyledDocumentRequest.java public class StyledDocumentRequest { private String title; private String author; private List<DocumentSection> sections; // Constructors, getters, and setters public StyledDocumentRequest() {} public StyledDocumentRequest(String title, String author, List<DocumentSection> sections) { this.title = title; this.author = author; this.sections = sections; } // Getters and setters... } // DocumentSection.java public class DocumentSection { private String heading; private int level = 2; private List<String> paragraphs; private List<String> bulletPoints; // Constructors, getters, and setters... } // InvoiceData.java public class InvoiceData { private String invoiceNumber; private LocalDate invoiceDate; private LocalDate dueDate; private String fromCompany; private String fromAddress; private String fromEmail; private String fromPhone; private String toCompany; private String toAddress; private String toEmail; private BigDecimal totalAmount; private List<InvoiceItem> items; // Constructors, getters, and setters... } // InvoiceItem.java public class InvoiceItem { private String description; private int quantity; private BigDecimal unitPrice; private BigDecimal total; // Constructors, getters, and setters... }

Tables and Layouts

1. Advanced Table Service

// TablePdfService.java @Service public class TablePdfService { private final PdfFontService fontService; public TablePdfService(PdfFontService fontService) { this.fontService = fontService; } public byte[] createDataTable(List<TableColumn> columns, List<Map<String, Object>> data) throws IOException { try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) { PdfWriter writer = new PdfWriter(baos); PdfDocument pdfDoc = new PdfDocument(writer); Document document = new Document(pdfDoc); // Create table with dynamic column widths float[] columnWidths = new float[columns.size()]; Arrays.fill(columnWidths, 1); // Equal widths by default Table table = new Table(columnWidths); // Add header row for (TableColumn column : columns) { Cell headerCell = new Cell() .add(new Paragraph(column.getHeader()) .setFont(fontService.getBoldFont()) .setFontSize(10)) .setBackgroundColor(ColorConstants.LIGHT_GRAY) .setTextAlignment(column.getAlignment()) .setPadding(5); table.addHeaderCell(headerCell); } // Add data rows for (Map<String, Object> row : data) { for (TableColumn column : columns) { Object value = row.get(column.getKey()); String text = value != null ? value.toString() : ""; Cell dataCell = new Cell() .add(new Paragraph(text) .setFont(fontService.getDefaultFont()) .setFontSize(9)) .setTextAlignment(column.getAlignment()) .setPadding(3); // Apply conditional formatting if (column.getConditionalColor() != null) { Color color = column.getConditionalColor().apply(value); if (color != null) { dataCell.setBackgroundColor(color); } } table.addCell(dataCell); } } document.add(table); document.close(); return baos.toByteArray(); } } public byte[] createComplexReport(ReportData report) throws IOException { try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) { PdfWriter writer = new PdfWriter(baos); PdfDocument pdfDoc = new PdfDocument(writer); Document document = new Document(pdfDoc); // Report title document.add(new Paragraph(report.getTitle()) .setFontSize(18) .setBold() .setTextAlignment(TextAlignment.CENTER)); // Summary section if (report.getSummary() != null) { document.add(new Paragraph("Summary") .setFontSize(14) .setBold() .setMarginTop(15)); document.add(new Paragraph(report.getSummary()) .setFontSize(10) .setMarginBottom(10)); } // Data tables for (ReportTable tableData : report.getTables()) { document.add(new Paragraph(tableData.getTitle()) .setFontSize(12) .setBold() .setMarginTop(10)); Table table = createReportTable(tableData); document.add(table); } document.close(); return baos.toByteArray(); } } private Table createReportTable(ReportTable tableData) throws IOException { float[] columnWidths = tableData.getColumnWidths(); Table table = new Table(columnWidths); // Header for (String header : tableData.getHeaders()) { table.addHeaderCell(createStyledCell(header, true, TextAlignment.CENTER)); } // Data for (List<String> row : tableData.getRows()) { for (int i = 0; i < row.size(); i++) { TextAlignment alignment = i == 0 ? TextAlignment.LEFT : TextAlignment.RIGHT; table.addCell(createStyledCell(row.get(i), false, alignment)); } } // Footer if exists if (tableData.getFooter() != null && !tableData.getFooter().isEmpty()) { for (String footer : tableData.getFooter()) { Cell footerCell = createStyledCell(footer, true, TextAlignment.RIGHT); footerCell.setColspan(tableData.getHeaders().size()); table.addCell(footerCell); } } return table; } private Cell createStyledCell(String text, boolean isHeader, TextAlignment alignment) throws IOException { Paragraph paragraph = new Paragraph(text) .setFont(isHeader ? fontService.getBoldFont() : fontService.getDefaultFont()) .setFontSize(isHeader ? 10 : 9); Cell cell = new Cell().add(paragraph).setTextAlignment(alignment).setPadding(4); if (isHeader) { cell.setBackgroundColor(ColorConstants.LIGHT_GRAY); } return cell; } public byte[] createMultiColumnLayout(List<ColumnContent> columns) throws IOException { try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) { PdfWriter writer = new PdfWriter(baos); PdfDocument pdfDoc = new PdfDocument(writer); Document document = new Document(pdfDoc); // Create multi-column layout float[] columnWidths = new float[columns.size()]; for (int i = 0; i < columns.size(); i++) { columnWidths[i] = columns.get(i).getWidth(); } Table layoutTable = new Table(columnWidths); for (ColumnContent column : columns) { Cell columnCell = new Cell() .setPadding(10) .setBorder(Border.NO_BORDER); // Add column title if (column.getTitle() != null) { columnCell.add(new Paragraph(column.getTitle()) .setFont(fontService.getBoldFont()) .setFontSize(12) .setMarginBottom(5)); } // Add column content for (String content : column.getContent()) { columnCell.add(new Paragraph(content) .setFont(fontService.getDefaultFont()) .setFontSize(10) .setMarginBottom(3)); } layoutTable.addCell(columnCell); } document.add(layoutTable); document.close(); return baos.toByteArray(); } } } // TableColumn.java public class TableColumn { private String key; private String header; private TextAlignment alignment = TextAlignment.LEFT; private Function<Object, Color> conditionalColor; // Constructors, getters, and setters... public TableColumn() {} public TableColumn(String key, String header) { this.key = key; this.header = header; } public TableColumn(String key, String header, TextAlignment alignment) { this.key = key; this.header = header; this.alignment = alignment; } // Getters and setters... } // ReportData.java public class ReportData { private String title; private String summary; private List<ReportTable> tables; // Constructors, getters, and setters... } // ReportTable.java public class ReportTable { private String title; private List<String> headers; private List<List<String>> rows; private List<String> footer; private float[] columnWidths; // Constructors, getters, and setters... } // ColumnContent.java public class ColumnContent { private String title; private List<String> content; private float width = 1f; // Relative width // Constructors, getters, and setters... }

Images and Graphics

1. Image Handling Service

// ImagePdfService.java @Service public class ImagePdfService { private static final Logger logger = LoggerFactory.getLogger(ImagePdfService.class); public byte[] createPdfWithImages(List<ImageData> images) throws IOException { try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) { PdfWriter writer = new PdfWriter(baos); PdfDocument pdfDoc = new PdfDocument(writer); Document document = new Document(pdfDoc); for (ImageData imageData : images) { try { Image image = createImage(imageData); // Add caption if provided if (imageData.getCaption() != null) { Paragraph caption = new Paragraph(imageData.getCaption()) .setFontSize(10) .setItalic() .setTextAlignment(TextAlignment.CENTER); document.add(caption); } document.add(image); document.add(new Paragraph().setHeight(10)); // Spacing } catch (Exception e) { logger.warn("Failed to add image: {}", imageData.getSource(), e); // Continue with next image } } document.close(); return baos.toByteArray(); } } public byte[] createImageGallery(List<ImageData> images, int columns) throws IOException { try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) { PdfWriter writer = new PdfWriter(baos); PdfDocument pdfDoc = new PdfDocument(writer); Document document = new Document(pdfDoc); // Calculate column widths float[] columnWidths = new float[columns]; Arrays.fill(columnWidths, 1f); Table galleryTable = new Table(columnWidths); galleryTable.setWidth(UnitValue.createPercentValue(100)); for (int i = 0; i < images.size(); i++) { ImageData imageData = images.get(i); try { Image image = createImage(imageData); image.setAutoScale(true); image.setHorizontalAlignment(HorizontalAlignment.CENTER); Cell cell = new Cell() .add(image) .setPadding(5) .setBorder(Border.NO_BORDER); if (imageData.getCaption() != null) { Paragraph caption = new Paragraph(imageData.getCaption()) .setFontSize(8) .setTextAlignment(TextAlignment.CENTER); cell.add(caption); } galleryTable.addCell(cell); } catch (Exception e) { logger.warn("Failed to add image to gallery: {}", imageData.getSource(), e); // Add empty cell to maintain layout galleryTable.addCell(new Cell().setBorder(Border.NO_BORDER)); } } // Fill remaining cells if needed int remainingCells = columns - (images.size() % columns); if (remainingCells < columns) { for (int i = 0; i < remainingCells; i++) { galleryTable.addCell(new Cell().setBorder(Border.NO_BORDER)); } } document.add(galleryTable); document.close(); return baos.toByteArray(); } } private Image createImage(ImageData imageData) throws IOException { Image image; if (imageData.getImageBytes() != null) { ImageDataFactory imageFactory = ImageDataFactory.create(imageData.getImageBytes()); image = new Image(imageFactory); } else if (imageData.getSource().startsWith("http")) { // Download image from URL byte[] imageBytes = downloadImage(imageData.getSource()); ImageDataFactory imageFactory = ImageDataFactory.create(imageBytes); image = new Image(imageFactory); } else { // Load from file system ImageDataFactory imageFactory = ImageDataFactory.create(imageData.getSource()); image = new Image(imageFactory); } // Apply scaling if (imageData.getMaxWidth() > 0 || imageData.getMaxHeight() > 0) { image.scaleToFit(imageData.getMaxWidth(), imageData.getMaxHeight()); } if (imageData.getWidth() > 0 && imageData.getHeight() > 0) { image.setFixedPosition(imageData.getX(), imageData.getY()); image.setFixedDimension(imageData.getWidth(), imageData.getHeight()); } return image; } private byte[] downloadImage(String imageUrl) throws IOException { try { URL url = new URL(imageUrl); try (InputStream in = url.openStream(); ByteArrayOutputStream baos = new ByteArrayOutputStream()) { byte[] buffer = new byte[4096]; int bytesRead; while ((bytesRead = in.read(buffer)) != -1) { baos.write(buffer, 0, bytesRead); } return baos.toByteArray(); } } catch (Exception e) { throw new IOException("Failed to download image from: " + imageUrl, e); } } public byte[] createPdfWithWatermark(String content, String watermarkText) throws IOException { try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) { PdfWriter writer = new PdfWriter(baos); PdfDocument pdfDoc = new PdfDocument(writer); // Add watermark handler pdfDoc.addEventHandler(PdfDocumentEvent.END_PAGE, new WatermarkEventHandler(watermarkText)); Document document = new Document(pdfDoc); document.add(new Paragraph(content)); document.close(); return baos.toByteArray(); } } private static class WatermarkEventHandler implements IEventHandler { private final String watermarkText; public WatermarkEventHandler(String watermarkText) { this.watermarkText = watermarkText; } @Override public void handleEvent(Event event) { PdfDocumentEvent docEvent = (PdfDocumentEvent) event; PdfPage page = docEvent.getPage(); PdfCanvas pdfCanvas = new PdfCanvas(page.newContentStreamBefore(), page.getResources(), docEvent.getDocument()); Canvas canvas = new Canvas(pdfCanvas, page.getPageSize()); canvas.setFontColor(ColorConstants.LIGHT_GRAY); canvas.setFontSize(60); canvas.showTextAligned(watermarkText, page.getPageSize().getWidth() / 2, page.getPageSize().getHeight() / 2, TextAlignment.CENTER, VerticalAlignment.MIDDLE, 45); // Rotate 45 degrees } } } // ImageData.java public class ImageData { private String source; private byte[] imageBytes; private String caption; private float maxWidth; private float maxHeight; private float width; private float height; private float x; private float y; // Constructors, getters, and setters... public ImageData() {} public ImageData(String source) { this.source = source; } public ImageData(byte[] imageBytes) { this.imageBytes = imageBytes; } // Getters and setters... }

Advanced Features

1. PDF/A Compliance

// PdfAComplianceService.java @Service public class PdfAComplianceService { public byte[] createPdfADocument(String title, String content) throws IOException { try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) { PdfWriter writer = new PdfWriter(baos); // Create PDF/A compliant document PdfADocument pdfDoc = new PdfADocument(writer, PdfAConformanceLevel.PDF_A_3B, new PdfOutputIntent("Custom", "", "http://www.color.org", "sRGB IEC61966-2.1", Files.readAllBytes(Paths.get("sRGB_CS_profile.icm")))); Document document = new Document(pdfDoc); // Add required metadata PdfDocumentInfo info = pdfDoc.getDocumentInfo(); info.setTitle(title); info.setAuthor("PDF Service"); info.setSubject("PDF/A Compliant Document"); info.setKeywords("PDF/A, compliance"); info.setCreator("iText PDF Service"); // Add content document.add(new Paragraph(title).setFontSize(18).setBold()); document.add(new Paragraph(content).setFontSize(12)); document.close(); return baos.toByteArray(); } } }

2. Barcode Generation

// BarcodeService.java @Service public class BarcodeService { public byte[] createPdfWithBarcode(String content, String barcodeData, BarcodeType type) throws IOException { try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) { PdfWriter writer = new PdfWriter(baos); PdfDocument pdfDoc = new PdfDocument(writer); Document document = new Document(pdfDoc); // Add content document.add(new Paragraph(content)); document.add(new Paragraph().setHeight(20)); // Add barcode document.add(new Paragraph("Barcode (" + type + "):")); Barcode barcode = createBarcode(barcodeData, type, pdfDoc); Image barcodeImage = new Image(barcode.createFormXObject(null, pdfDoc)); document.add(barcodeImage); document.close(); return baos.toByteArray(); } } private Barcode createBarcode(String data, BarcodeType type, PdfDocument pdfDoc) { return switch (type) { case CODE128 -> { Barcode128 barcode = new Barcode128(pdfDoc); barcode.setCode(data); barcode.setCodeType(Barcode128.CODE128); yield barcode; } case QR -> { BarcodeQRCode barcode = new BarcodeQRCode(data); yield barcode; } case PDF417 -> { BarcodePDF417 barcode = new BarcodePDF417(); barcode.setCode(data); yield barcode; } default -> throw new IllegalArgumentException("Unsupported barcode type: " + type); }; } public enum BarcodeType { CODE128, QR, PDF417 } }

PDF Forms and Interactive Elements

1. Interactive Form Service

// FormPdfService.java @Service public class FormPdfService { public byte[] createFillableForm(FormTemplate template) throws IOException { try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) { PdfWriter writer = new PdfWriter(baos); PdfDocument pdfDoc = new PdfDocument(writer); Document document = new Document(pdfDoc); // Add form title document.add(new Paragraph(template.getTitle()) .setFontSize(16) .setBold() .setTextAlignment(TextAlignment.CENTER)); // Create form PdfAcroForm form = PdfAcroForm.getAcroForm(pdfDoc, true); // Add form fields float yPosition = pdfDoc.getDefaultPageSize().getTop() - 100; for (FormField field : template.getFields()) { yPosition = addFormField(document, form, field, yPosition); yPosition -= 30; // Spacing between fields } document.close(); return baos.toByteArray(); } } private float addFormField(Document document, PdfAcroForm form, FormField field, float yPosition) { PdfPage page = document.getPdfDocument().getLastPage(); Rectangle rect = new Rectangle(50, yPosition - 20, 200, 20); PdfFormField formField; switch (field.getType()) { case TEXT: formField = PdfTextFormField.createText(document.getPdfDocument(), rect, field.getName()); if (field.getDefaultValue() != null) { formField.setValue(field.getDefaultValue()); } break; case CHECKBOX: formField = PdfFormField.createCheckBox(document.getPdfDocument(), rect, field.getName(), "Yes"); break; case COMBOBOX: formField = PdfFormField.createComboBox(document.getPdfDocument(), rect, field.getName(), field.getDefaultValue()); if (field.getOptions() != null) { for (String option : field.getOptions()) { formField.addOption(option); } } break; default: throw new IllegalArgumentException("Unsupported field type: " + field.getType()); } // Set field properties formField.setRequired(field.isRequired()); formField.setReadOnly(field.isReadOnly()); // Add field label try { document.add(new Paragraph(field.getLabel()) .setFixedPosition(50, yPosition, 200) .setFontSize(10)); } catch (IOException e) { throw new RuntimeException("Failed to add field label", e); } form.addField(formField); return yPosition; } public byte[] fillExistingForm(byte[] templatePdf, Map<String, String> formData) throws IOException { try (ByteArrayOutputStream baos = new ByteArrayOutputStream(); PdfReader reader = new PdfReader(new ByteArrayInputStream(templatePdf)); PdfWriter writer = new PdfWriter(baos); PdfDocument pdfDoc = new PdfDocument(reader, writer)) { PdfAcroForm form = PdfAcroForm.getAcroForm(pdfDoc, false); if (form != null) { for (Map.Entry<String, String> entry : formData.entrySet()) { PdfFormField field = form.getField(entry.getKey()); if (field != null) { field.setValue(entry.getValue()); } } form.flattenFields(); // Make form non-editable } pdfDoc.close(); return baos.toByteArray(); } } } // FormTemplate.java public class FormTemplate { private String title; private List<FormField> fields; // Constructors, getters, and setters... } // FormField.java public class FormField { private String name; private String label; private FieldType type; private String defaultValue; private List<String> options; private boolean required; private boolean readOnly; // Constructors, getters, and setters... } public enum FieldType { TEXT, CHECKBOX, COMBOBOX, RADIO, LIST }

Security and Encryption

1. PDF Security Service

// PdfSecurityService.java @Service public class PdfSecurityService { public byte[] encryptPdf(byte[] pdfBytes, String userPassword, String ownerPassword, EncryptionProperties properties) throws IOException { try (ByteArrayOutputStream baos = new ByteArrayOutputStream(); PdfReader reader = new PdfReader(new ByteArrayInputStream(pdfBytes)); PdfWriter writer = new PdfWriter(baos, new WriterProperties() .setStandardEncryption( userPassword.getBytes(), ownerPassword.getBytes(), properties.getPermissions(), properties.getEncryptionAlgorithm()))) { PdfDocument pdfDoc = new PdfDocument(reader, writer); pdfDoc.close(); return baos.toByteArray(); } } public byte[] addDigitalSignature(byte[] pdfBytes, Certificate[] chain, PrivateKey pk, String digestAlgorithm, String provider, String reason, String location) throws IOException { try (ByteArrayOutputStream baos = new ByteArrayOutputStream(); PdfReader reader = new PdfReader(new ByteArrayInputStream(pdfBytes)); PdfWriter writer = new PdfWriter(baos); PdfDocument pdfDoc = new PdfDocument(reader, writer)) { // Create signature appearance Rectangle rect = new Rectangle(36, 648, 200, 100); PdfSignatureAppearance appearance = new PdfSignatureAppearance(pdfDoc, rect); appearance.setReason(reason); appearance.setLocation(location); appearance.setPageNumber(1); // Create signature IExternalSignature signature = new PrivateKeySignature(pk, digestAlgorithm, provider); IExternalDigest digest = new BouncyCastleDigest(); PdfSigner.signDetached(appearance, digest, signature, chain, null, null, null, 0, PdfSigner.CryptoStandard.CMS); pdfDoc.close(); return baos.toByteArray(); } } public byte[] addWatermark(byte[] pdfBytes, String watermarkText) throws IOException { try (ByteArrayOutputStream baos = new ByteArrayOutputStream(); PdfReader reader = new PdfReader(new ByteArrayInputStream(pdfBytes)); PdfWriter writer = new PdfWriter(baos); PdfDocument pdfDoc = new PdfDocument(reader, writer)) { int pageCount = pdfDoc.getNumberOfPages(); for (int i = 1; i <= pageCount; i++) { PdfPage page = pdfDoc.getPage(i); PdfCanvas over = new PdfCanvas(page.newContentStreamAfter(), page.getResources(), pdfDoc); Canvas canvas = new Canvas(over, page.getPageSize()); canvas.setFontColor(ColorConstants.LIGHT_GRAY); canvas.setFontSize(48); canvas.setOpacity(0.3f); canvas.showTextAligned(watermarkText, page.getPageSize().getWidth() / 2, page.getPageSize().getHeight() / 2, TextAlignment.CENTER, VerticalAlignment.MIDDLE, 45); canvas.close(); } pdfDoc.close(); return baos.toByteArray(); } } } // EncryptionProperties.java public class EncryptionProperties { private int permissions = EncryptionConstants.ALLOW_SCREENREADERS; private int encryptionAlgorithm = EncryptionConstants.STANDARD_ENCRYPTION_128; // Constructors, getters, and setters... public EncryptionProperties() {} public EncryptionProperties(int permissions, int encryptionAlgorithm) { this.permissions = permissions; this.encryptionAlgorithm = encryptionAlgorithm; } // Getters and setters... }

Performance Optimization

1. PDF Generation with Caching

// OptimizedPdfService.java @Service public class OptimizedPdfService { private final Cache<String, byte[]> pdfCache; private final BasicPdfService basicPdfService; public OptimizedPdfService(BasicPdfService basicPdfService) { this.basicPdfService = basicPdfService; // Configure cache this.pdfCache = Caffeine.newBuilder() .maximumSize(1000) .expireAfterWrite(1, TimeUnit.HOURS) .build(); } public byte[] generateCachedPdf(String cacheKey, String title, String content) throws IOException { return pdfCache.get(cacheKey, key -> { try { return basicPdfService.createSimplePdf(title, content); } catch (IOException e) { throw new RuntimeException("Failed to generate PDF", e); } }); } public void invalidateCache(String cacheKey) { pdfCache.invalidate(cacheKey); } public void clearCache() { pdfCache.invalidateAll(); } } // BatchPdfService.java @Service public class BatchPdfService { private final ExecutorService executorService; public BatchPdfService() { this.executorService = Executors.newFixedThreadPool( Runtime.getRuntime().availableProcessors()); } public List<byte[]> generatePdfBatch(List<PdfGenerationTask> tasks) { List<CompletableFuture<byte[]>> futures = tasks.stream() .map(task -> CompletableFuture.supplyAsync(() -> { try { return generatePdf(task); } catch (Exception e) { throw new CompletionException(e); } }, executorService)) .collect(Collectors.toList()); return futures.stream() .map(CompletableFuture::join) .collect(Collectors.toList()); } private byte[] generatePdf(PdfGenerationTask task) throws IOException { // Implementation depends on task type // This is a simplified example try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) { PdfWriter writer = new PdfWriter(baos); PdfDocument pdfDoc = new PdfDocument(writer); Document document = new Document(pdfDoc); document.add(new Paragraph(task.getContent())); document.close(); return baos.toByteArray(); } } @PreDestroy public void cleanup() { executorService.shutdown(); } } // PdfGenerationTask.java public class PdfGenerationTask { private String id; private String content; private PdfTemplate template; // Constructors, getters, and setters... }

2. Memory Management

// MemoryOptimizedPdfService.java @Service public class MemoryOptimizedPdfService { private static final Logger logger = LoggerFactory.getLogger(MemoryOptimizedPdfService.class); public void createLargePdfInChunks(String outputPath, List<DocumentChunk> chunks) throws IOException { PdfWriter writer = new PdfWriter(outputPath); PdfDocument pdfDoc = new PdfDocument(writer); Document document = new Document(pdfDoc); try { for (DocumentChunk chunk : chunks) { processChunk(document, chunk); // Force garbage collection periodically for large documents if (chunk.getChunkNumber() % 10 == 0) { System.gc(); } } } finally { document.close(); } } private void processChunk(Document document, DocumentChunk chunk) throws IOException { switch (chunk.getType()) { case TEXT: document.add(new Paragraph(chunk.getContent())); break; case TABLE: // Add table processing break; case IMAGE: // Add image processing break; default: logger.warn("Unknown chunk type: {}", chunk.getType()); } } public byte[] createPdfWithMemoryLimit(String content, long maxMemoryBytes) throws IOException { MemoryLimitsAwareHandler memoryHandler = new MemoryLimitsAwareHandler(maxMemoryBytes); try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) { PdfWriter writer = new PdfWriter(baos); writer.setMemoryLimitsAwareHandler(memoryHandler); PdfDocument pdfDoc = new PdfDocument(writer); Document document = new Document(pdfDoc); document.add(new Paragraph(content)); document.close(); return baos.toByteArray(); } } } // DocumentChunk.java public class DocumentChunk { private int chunkNumber; private ChunkType type; private String content; // Constructors, getters, and setters... } enum ChunkType { TEXT, TABLE, IMAGE, HEADER, FOOTER }

Conclusion

iText provides a comprehensive solution for PDF generation in Java applications. Key takeaways:

  1. Choose the right iText version (AGPL for open source, commercial for proprietary software)
  2. Use proper font management for consistent typography
  3. Implement caching for frequently generated documents
  4. Handle memory carefully for large PDF generation
  5. Use appropriate security features for sensitive documents
  6. Consider PDF/A compliance for long-term archiving
  7. Implement proper error handling and logging
  8. Optimize performance with batch processing and threading

By following these patterns and best practices, you can build robust, efficient PDF generation services that meet your application's requirements.

Leave a Reply

Your email address will not be published. Required fields are marked *


Macro Nepal Helper