package NTNU.IDATT1002.service; import NTNU.IDATT1002.models.Image; import NTNU.IDATT1002.models.ImageAlbum; import NTNU.IDATT1002.models.Metadata; import com.itextpdf.text.*; import com.itextpdf.text.pdf.PdfWriter; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.util.Date; /** * Class PdfDocument. Generates a pdf document displaying a given image album. * * @author Eirik Steira * @version 1.0 22.03.20 */ public class PdfDocument implements ImageAlbumDocument { /** * Height ratio satisfying a 16:9 ratio. */ private final double HEIGHT_RATIO = 5.3; private ImageAlbum imageAlbum; private Document document; private String DESTINATION_FILE; private String defaultTitle = "Album"; /** * Standard fonts. */ private Font headerFont = new Font(Font.FontFamily.TIMES_ROMAN, 18, Font.BOLD); private Font subFont = new Font(Font.FontFamily.TIMES_ROMAN, 16, Font.BOLD); private Font smallFont = new Font(Font.FontFamily.TIMES_ROMAN, 12); public PdfDocument(ImageAlbum imageAlbum, String DESTINATION_FILE) { this.imageAlbum = imageAlbum; this.DESTINATION_FILE = DESTINATION_FILE; this.document = new Document(); } public File getDocument() { return new File(DESTINATION_FILE); } /** * Create a new pdf document. */ public void createDocument() { try { generatePdfDocument(); } catch (IOException | DocumentException e) { e.printStackTrace(); } } /** * Try to generate a pdf document. * * @throws IOException * @throws DocumentException */ private void generatePdfDocument() throws IOException, DocumentException { PdfWriter.getInstance(document, new FileOutputStream(DESTINATION_FILE)); document.open(); addHeadlines(); addContent(); document.close(); } /** * Add default headlines to the document, ie document title, ownership and date. * * @throws DocumentException */ private void addHeadlines() throws DocumentException { Paragraph headline = new Paragraph(); addEmptyLineTo(headline, 1); headline.add(new Paragraph(defaultTitle, headerFont)); addEmptyLineTo(headline, 1); headline.add(new Paragraph( "Generated by: " + imageAlbum.getUser().getUsername() + ", " + new Date(), smallFont)); addEmptyLineTo(headline, 2); document.add(headline); } /** * Add main content to the document. This entails image album meta and all images. * * @throws DocumentException * @throws IOException */ private void addContent() throws DocumentException, IOException { addImageAlbumMeta(); addImagesContainer(); } /** * Add image album meta to the document, such as title, user etc. * * @throws DocumentException */ private void addImageAlbumMeta() throws DocumentException { Paragraph imageAlbumMeta = new Paragraph(); String imageAlbumMetaContent = formatImageAlbumMeta(); imageAlbumMeta.add(new Paragraph( imageAlbumMetaContent, smallFont)); addEmptyLineTo(imageAlbumMeta, 1); document.add(imageAlbumMeta); } /** * Add container to contain images and a headline. * * @throws DocumentException * @throws IOException */ private void addImagesContainer() throws DocumentException, IOException { Paragraph imagesContainer = new Paragraph(); imagesContainer.add(new Paragraph("Images:", subFont)); document.add(imagesContainer); addAllImages(); } /** * Add all images in the album to the document. * * @throws IOException * @throws DocumentException */ private void addAllImages() throws IOException, DocumentException { for (Image image : imageAlbum.getImages()) addSingleImage(image); } /** * Add a single image to the document. * * @param image the image to add. * @throws IOException * @throws DocumentException */ private void addSingleImage(Image image) throws IOException, DocumentException { com.itextpdf.text.Image displayImage = getImageFileFromBytes(image.getRawImage()); scaleImage(displayImage); document.add(displayImage); addImageMetaData(image); } /** * Convert an array of bytes to {@link com.itextpdf.text.Image}. * * @param imageBytes the array of bytes to convert * @return the image to display * @throws IOException * @throws BadElementException */ private com.itextpdf.text.Image getImageFileFromBytes(byte[] imageBytes) throws IOException, BadElementException { return com.itextpdf.text.Image.getInstance(imageBytes); } /** * Scale given {@link com.itextpdf.text.Image image} to stretch * half the width of the page, remaining a 16:9 ratio. * * @param image the image to scale */ private void scaleImage(com.itextpdf.text.Image image) { float documentWidth = PageSize.A4.getWidth() - 2 * PageSize.A4.getBorder(); float scaledHeight = (float) (documentWidth / 2 * HEIGHT_RATIO); image.scaleToFit(documentWidth / 2, scaledHeight); } /** * Add an images metadata to the document. * * @param image the image holding the metadata * @throws DocumentException */ private void addImageMetaData(Image image) throws DocumentException { Metadata metadata = image.getMetadata(); if (metadata != null) document.add(new Paragraph(metadata.toString())); } /** * Format the album meta. * * @return the formatted album */ private String formatImageAlbumMeta() { return new StringBuilder() .append("Title: ") .append(imageAlbum.getTitle()) .append("\n") .append("User: ") .append(imageAlbum.getUser().getUsername()) .append("\n") .append("Created at: ") .append(imageAlbum.getCreatedAt()) .append("\n") .append("Description: ") .append(imageAlbum.getDescription()) .append("\n") .append("Tags: ") .append(formatTags()) .toString(); } /** * Format the albums tags, separated by a comma. * * @return the formatted tags */ private String formatTags() { StringBuilder tags = new StringBuilder(); imageAlbum.getTags().forEach(tag -> tags.append(tag.getName()).append(", ")); return tags.toString(); } /** * Add an empty line to the document. * * @param paragraph the paragraph to insert an empty line into * @param number the number of empty lines desired */ private void addEmptyLineTo(Paragraph paragraph, int number) { for (int i = 0; i < number; i++) { paragraph.add(new Paragraph(" ")); } } }