All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.vectorprint.report.itext.DefaultElementProducer Maven / Gradle / Ivy

Go to download

This powerful reporting library aims to simplify producing reports using iText. The most demanding and coding intensive tasks when producing reports with iText are how to get from data to report elements, how to style those blocks and how to evaluate (debug) the resulting report layout. Exactly those three tasks are simplified by this library: xml configuration and/or annotations to transform existing Java data objects into report block, provide styling information (css like, syntax independent) seperate from code, a firebug like debug mode to help evaluate your report.

There is a newer version: 9.2
Show newest version
package com.vectorprint.report.itext;

/*
 * #%L
 * VectorPrintReport4.0
 * %%
 * Copyright (C) 2012 - 2013 VectorPrint
 * %%
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see .
 * #L%
 */
//~--- non-JDK imports --------------------------------------------------------
import com.itextpdf.text.Anchor;
import com.itextpdf.text.BadElementException;
import com.itextpdf.text.Chapter;
import com.itextpdf.text.ChapterAutoNumber;
import com.itextpdf.text.Chunk;
import com.itextpdf.text.Element;
import com.itextpdf.text.Image;
import com.itextpdf.text.ListItem;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.Phrase;
import com.itextpdf.text.Section;
import com.itextpdf.text.TextElementArray;
import com.itextpdf.text.io.RandomAccessSourceFactory;
import com.itextpdf.text.pdf.ColumnText;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfLayer;
import com.itextpdf.text.pdf.PdfPCell;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfWriter;
import com.itextpdf.text.pdf.RandomAccessFileOrArray;
import com.itextpdf.text.pdf.codec.TiffImage;
import com.vectorprint.IOHelper;
import com.vectorprint.VectorPrintException;
import com.vectorprint.VectorPrintRuntimeException;
import com.vectorprint.configuration.EnhancedMap;
import com.vectorprint.configuration.annotation.Setting;
import com.vectorprint.configuration.annotation.SettingsField;
import com.vectorprint.report.ReportConstants;
import com.vectorprint.report.data.types.Formatter;
import com.vectorprint.report.data.types.ReportValue;
import com.vectorprint.report.itext.debug.DebuggablePdfPCell;
import com.vectorprint.report.itext.style.BaseStyler;
import com.vectorprint.report.itext.style.StyleHelper;
import static com.vectorprint.report.itext.style.StyleHelper.toCollection;
import com.vectorprint.report.itext.style.StylerFactory;
import com.vectorprint.report.itext.style.StylerFactoryHelper;
import com.vectorprint.report.itext.style.stylers.Advanced;
import com.vectorprint.report.itext.style.stylers.SimpleColumns;
import com.vectorprint.report.itext.style.stylers.Link;
import com.vectorprint.report.itext.style.stylers.NoWrap;
import java.awt.AlphaComposite;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.security.Key;
import java.security.cert.Certificate;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;

//~--- JDK imports ------------------------------------------------------------
/**
 * Responsible for creating and styling parts of the report, for formatting data and adding data to the report part. For
 * styling {@link BaseStyler}s are used that can be found using a {@link StylerFactory}, Formatting data is done using a
 * {@link Formatter}.
 *
 * @author Eduard Drenth at VectorPrint.nl
 */
public class DefaultElementProducer implements ElementProducer {

   private static final Logger log = Logger.getLogger(DefaultElementProducer.class.getName());
   /**
    * the suffix used when
    * {@link #startLayerInGroup(java.lang.String, com.itextpdf.text.pdf.PdfContentByte) starting a layer}.
    */
   public static final String CHILD_LAYERSUFFIX = "_child";
   /**
    * prefix for generic tags used for {@link Advanced advanced stylers}.
    *
    * @see EventHelper#addDelayedStyler(java.lang.String, java.util.Collection, com.itextpdf.text.Chunk)
    */
   public static final String ADV = "adv";
   @Setting(keys = ReportConstants.DEBUG)
   private boolean debug = false;
   private int genericTag = -1;
   private final Formatter formatter;
   @SettingsField
   private EnhancedMap settings;
   private EventHelper ph;
   private StyleHelper styleHelper;

   public DefaultElementProducer() {
      this(new Formatter());
   }

   public DefaultElementProducer(Formatter f) {
      this.formatter = f;
   }

   /**
    * leaves object creation to the first styler in the list
    *
    * @param 
    * @param stylers
    * @param data
    * @param clazz
    * @return
    * @throws VectorPrintException
    */
   public  E createElementByStyler(Collection stylers, Object data, Class clazz) throws VectorPrintException {

      // pdfptable, Section and others do not have a default constructor, a styler creates it
      return styleHelper.style(clazz, data, stylers);
   }

   /**
    * Creates and styles a cell with data in it. If the data is an instance of Element it is added as is to the cell,
    * otherwise a {@link #createPhrase(java.lang.Object, java.util.Collection) phrase} is created from the data.
    *
    * @param data
    * @param stylers
    * @return
    * @throws VectorPrintException
    */
   public PdfPCell createCell(Object data, Collection stylers) throws VectorPrintException {
      DebuggablePdfPCell cell;

      /*
       * only when creating an instance of PdfPCell with its content (Phrase/Image/Chunk) in the constructor
       * alignment will work!
       */
      if (null != data) {
         if (data instanceof Phrase) {
            cell = new DebuggablePdfPCell((Phrase) data);
         } else if (data instanceof Chunk) {
            cell = new DebuggablePdfPCell(new Phrase((Chunk) data));
         } else if (data instanceof Image) {
            cell = new DebuggablePdfPCell((Image) data);
         } else if (data instanceof Element) {
            if (data instanceof PdfPTable) {
               cell = new DebuggablePdfPCell((PdfPTable) data);
            } else {
               throw new VectorPrintException(String.format("%s not supported for a cell", data.getClass().getName()));
            }
         } else {

            //
            cell = new DebuggablePdfPCell(createPhrase(data, stylers));
         }
      } else {

         //
         cell = new DebuggablePdfPCell();
      }

      StylerFactoryHelper.SETTINGS_ANNOTATION_PROCESSOR.initSettings(cell, settings);

      return styleHelper.style(cell, data, stylers);
   }

   /**
    * Create a piece of text (part of a Phrase), style it and ad the data.
    *
    * @param data
    * @param stylers
    * @return
    * @throws VectorPrintException
    */
   public Chunk createChunk(Object data, Collection stylers) throws VectorPrintException {
      Chunk c = styleHelper.style(new Chunk(), data, stylers);

      if (data != null) {
         c.append(formatValue(data));
      }

      if (notDelayedStyle(c, ADV + (++advancedTag), stylers) && debug) {
         c.setGenericTag(String.valueOf(++genericTag));
      }

      return c;
   }

   /**
    * Create a Phrase, style it and add the data
    *
    * @param data
    * @param stylers
    * @return
    * @throws VectorPrintException
    */
   public Phrase createPhrase(Object data, Collection stylers) throws VectorPrintException {
      return initTextElementArray(styleHelper.style(new Phrase(), data, stylers), data, stylers);
   }

   /**
    * Create a Paragraph, style it and add the data
    *
    * @param data
    * @param stylers
    * @return
    * @throws VectorPrintException
    */
   public Paragraph createParagraph(Object data, Collection stylers) throws VectorPrintException {
      return initTextElementArray(styleHelper.style(new Paragraph(), data, stylers), data, stylers);
   }

   /**
    * Create a Anchor, style it and add the data
    *
    * @param data
    * @param stylers
    * @return
    * @throws VectorPrintException
    */
   public Anchor createAnchor(Object data, Collection stylers) throws VectorPrintException {
      return initTextElementArray(styleHelper.style(new Anchor(), data, stylers), data, stylers);
   }

   /**
    * Create a ListItem, style it and add the data
    *
    * @param data
    * @param stylers
    * @return
    * @throws VectorPrintException
    */
   public ListItem createListItem(Object data, Collection stylers) throws VectorPrintException {
      return initTextElementArray(styleHelper.style(new ListItem(), data, stylers), data, stylers);
   }

   private 

P initTextElementArray(P text, Object data, Collection stylers) { if (data != null) { text.add(new Chunk(formatValue(data))); } boolean first = true; for (Chunk c : (List) text.getChunks()) { styleLink(stylers, first, c, data); if (first) { first = false; } if (notDelayedStyle(c, ADV + (++advancedTag), stylers) && debug) { c.setGenericTag(String.valueOf(++genericTag)); } } return text; } private void styleLink(Collection stylers, boolean first, Chunk c, Object data) { if (stylers != null && !stylers.isEmpty()) { try { Collection l = StyleHelper.getStylers(stylers, Link.class); for (Link link : l) { if (first && link.isParameterSet(Link.ANCHOR)) { link.style(c, data); } else if (link.isParameterSet(Link.GOTO) || link.isParameterSet(com.vectorprint.report.itext.style.stylers.Image.URLPARAM)) { link.style(c, data); } } } catch (VectorPrintException ex) { log.log(Level.WARNING, null, ex); } } } private int advancedTag = -1; int getAdvancedTag() { return advancedTag; } /** * register advanced stylers together with data(part) with the EventHelper to do the styling later * * @param c * @param data * @param stylers * @return * @see PageHelper#onGenericTag(com.itextpdf.text.pdf.PdfWriter, com.itextpdf.text.Document, * com.itextpdf.text.Rectangle, java.lang.String) */ private boolean notDelayedStyle(Chunk c, String gt, Collection stylers) { if (stylers == null) { return true; } try { Collection a = new ArrayList(stylers.size()); for (Advanced adv : StyleHelper.getStylers(stylers, Advanced.class)) { Advanced.EVENTMODE mode = adv.getEventmode(); if (Advanced.EVENTMODE.ALL.equals(mode) || Advanced.EVENTMODE.TEXT.equals(mode)) { // remember data and chunk adv.addDelayedData(gt, c); a.add(adv); } } if (a.size() > 0) { styleHelper.delayedStyle(c, gt, a, ph); return false; } } catch (VectorPrintException ex) { log.log(Level.SEVERE, null, ex); } return true; } /** * Calls {@link #createTableCell(java.lang.Object, java.util.Collection, boolean) } * * @param val * @param style * @param noWrap * @return * @throws com.vectorprint.VectorPrintException */ public PdfPCell createTableCell(Object val, BaseStyler style, boolean noWrap) throws VectorPrintException { return createTableCell(val, toCollection(style), noWrap); } /** * When noWrap is true a {@link NoWrap} is added to the stylers. Calls * {@link #createCell(java.lang.Object, java.util.Collection) } * * @param val * @param stylers * @param noWrap * @return * @throws com.vectorprint.VectorPrintException */ public PdfPCell createTableCell(Object val, Collection stylers, boolean noWrap) throws VectorPrintException { if (noWrap) { stylers.add(new NoWrap()); } return createCell(val, stylers); } /** * When data is an instance of {@link ReportValue}, {@link Formatter#formatValue(com.vectorprint.report.data.types.ReportValue) * } * is called, otherwise String.valueOf is used. * * @param data * @return */ @Override public String formatValue(Object data) { if (data instanceof ReportValue) { return formatter.formatValue((ReportValue) data); } else { return String.valueOf(data); } } @Override public void loadPdf(URL pdf, PdfWriter writer, byte[] password, ImageProcessor imageProcessor, int... pages) throws VectorPrintException { try { if (log.isLoggable(Level.FINE)) { log.fine(String.format("loading pdf from %s", String.valueOf(pdf))); } if ("file".equals(pdf.getProtocol())) { loadPdf(new File(pdf.getFile()), writer, password, imageProcessor, pages); } else { loadPdf(pdf.openStream(), writer, password, imageProcessor, pages); } } catch (IOException ex) { throw new VectorPrintException(String.format("unable to load image %s", pdf.toString()), ex); } } /** * loads an image using {@link ImageIO } * * @param image * @param opacity the value of opacity * @throws VectorPrintException * @return the com.itextpdf.text.Image */ @Override public Image loadImage(URL image, float opacity) throws VectorPrintException { try { if (log.isLoggable(Level.FINE)) { log.fine(String.format("loading image from %s", String.valueOf(image))); } BufferedImage awtim = null; if ("file".equals(image.getProtocol())) { awtim = makeImageTranslucent(ImageIO.read(new File(image.getFile())), opacity); } else { awtim = makeImageTranslucent(ImageIO.read(image), opacity); } return Image.getInstance(awtim, null); } catch (BadElementException ex) { throw new VectorPrintException(String.format("unable to load image %s", image.toString()), ex); } catch (IOException ex) { throw new VectorPrintException(String.format("unable to load image %s", image.toString()), ex); } } /** * returns a transparent image when opacity < 1 * * @param source * @param opacity * @return */ public static BufferedImage makeImageTranslucent(BufferedImage source, float opacity) { if (opacity == 1) { return source; } BufferedImage translucent = new BufferedImage(source.getWidth(), source.getHeight(), BufferedImage.TRANSLUCENT); Graphics2D g = translucent.createGraphics(); g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, opacity)); g.drawImage(source, null, 0, 0); g.dispose(); return translucent; } @Override public void loadPdf(InputStream pdf, PdfWriter writer, byte[] password, ImageProcessor imageProcessor, int... pages) throws VectorPrintException { File f = null; try { f = File.createTempFile("pdf.", "pdf"); f.deleteOnExit(); IOHelper.load(pdf, new FileOutputStream(f), ReportConstants.DEFAULTBUFFERSIZE, true); loadPdf(f, writer, password, imageProcessor, pages); } catch (IOException ex) { throw new VectorPrintException(String.format("unable to load pdf"), ex); } finally { if (f != null) { f.delete(); } } } @Override public void loadPdf(File pdf, PdfWriter writer, byte[] password, ImageProcessor imageProcessor, int... pages) throws VectorPrintException { RandomAccessFileOrArray ra = null; try { RandomAccessSourceFactory rasf = new RandomAccessSourceFactory(); ra = new RandomAccessFileOrArray(rasf.createBestSource(pdf.getPath())); PdfReader reader = new PdfReader(ra, password); if (pages == null) { for (int i = 0; i < reader.getNumberOfPages();) { imageProcessor.processImage(Image.getInstance(writer.getImportedPage(reader, ++i))); writer.freeReader(reader); } } else { for (int i : pages) { imageProcessor.processImage(Image.getInstance(writer.getImportedPage(reader, i))); writer.freeReader(reader); } } } catch (BadElementException ex) { throw new VectorPrintException(String.format("unable to load image %s", pdf.toString()), ex); } catch (IOException ex) { throw new VectorPrintException(String.format("unable to load image %s", pdf.toString()), ex); } finally { if (ra != null) { try { ra.close(); } catch (IOException ex) { } } } } @Override public void loadPdf(InputStream pdf, PdfWriter writer, Certificate certificate, Key key, String securityProvider, ImageProcessor imageProcessor, int... pages) throws VectorPrintException { // first download, then load File f = null; try { f = File.createTempFile("pdf.", "pdf"); f.deleteOnExit(); IOHelper.load(pdf, new FileOutputStream(f), ReportConstants.DEFAULTBUFFERSIZE, true); PdfReader reader = new PdfReader(f.getPath(), certificate, key, securityProvider); if (pages == null) { for (int i = 0; i < reader.getNumberOfPages();) { imageProcessor.processImage(Image.getInstance(writer.getImportedPage(reader, ++i))); writer.freeReader(reader); } } else { for (int i : pages) { imageProcessor.processImage(Image.getInstance(writer.getImportedPage(reader, i))); writer.freeReader(reader); } } } catch (BadElementException ex) { throw new VectorPrintException(String.format("unable to load image %s", pdf.toString()), ex); } catch (IOException ex) { throw new VectorPrintException(String.format("unable to load image %s", pdf.toString()), ex); } finally { if (f != null) { f.delete(); } } } /** * * @param image the value of image * @param opacity the value of opacity * @throws VectorPrintException */ @Override public Image loadImage(InputStream image, float opacity) throws VectorPrintException { try { BufferedImage awtim = makeImageTranslucent(ImageIO.read(image), opacity); Image img = Image.getInstance(awtim, null); return img; } catch (BadElementException ex) { throw new VectorPrintException(ex); } catch (IOException ex) { throw new VectorPrintException(ex); } } /** * * @param image the value of image * @param opacity the value of opacity * @throws VectorPrintException */ @Override public Image loadImage(File image, float opacity) throws VectorPrintException { try { BufferedImage awtim = makeImageTranslucent(ImageIO.read(image), opacity); Image img = Image.getInstance(awtim, null); return img; } catch (BadElementException ex) { throw new VectorPrintException(ex); } catch (IOException ex) { throw new VectorPrintException(ex); } } @Override public E createElement(Object data, Class elementClass, List stylers) throws VectorPrintException, InstantiationException, IllegalAccessException { if (PdfPCell.class.equals(elementClass)) { return (E) createCell(data, stylers); } else if (Chunk.class.equals(elementClass)) { return (E) createChunk(data, stylers); } else if (Phrase.class.isAssignableFrom(elementClass)) { return (E) initTextElementArray(styleHelper.style((Phrase) elementClass.newInstance(), data, stylers), data, stylers); } else if (PdfPTable.class.equals(elementClass)) { return createElementByStyler(stylers, data, elementClass); } else if (Image.class.equals(elementClass)) { return createElementByStyler(stylers, data, elementClass); } else if (ChapterAutoNumber.class.equals(elementClass)) { ChapterAutoNumber can = new ChapterAutoNumber(formatValue(data)); return (E) styleHelper.style(can, data, stylers); } return styleHelper.style(elementClass.newInstance(), data, stylers); } private final Map> sections = new HashMap>(10); public void clearSections() { sections.clear(); } /** * create the Section, style the title, style the section and return the styled section. * * @param title * @param nesting * @param stylers * @return * @throws VectorPrintException * @throws InstantiationException * @throws IllegalAccessException */ @Override public Section getIndex(String title, int nesting, List stylers) throws VectorPrintException, InstantiationException, IllegalAccessException { if (nesting < 1) { throw new VectorPrintException("chapter numbering starts with 1, wrong number: " + nesting); } if (sections.get(nesting) == null) { sections.put(nesting, new ArrayList

(10)); } Section current; if (nesting == 1) { List
chapters = sections.get(1); current = new Chapter(createElement(title, Paragraph.class, stylers), chapters.size() + 1); chapters.add(current); } else { List
parents = sections.get(nesting - 1); Section parent = parents.get(parents.size() - 1); current = parent.addSection(createParagraph(title, stylers)); sections.get(nesting).add(current); } return styleHelper.style(current, null, stylers); } void setPh(EventHelper ph) { this.ph = ph; } private final Map layerGroups = new HashMap(2); @Override public PdfLayer startLayerInGroup(String groupId, PdfContentByte canvas) { PdfLayer pl; try { pl = new PdfLayer(groupId + CHILD_LAYERSUFFIX, canvas.getPdfWriter()); } catch (IOException ex) { throw new VectorPrintRuntimeException(ex); } initLayerGroup(groupId, canvas).addChild(pl); canvas.beginLayer(pl); return pl; } @Override public PdfLayer initLayerGroup(String layerId, PdfContentByte canvas) { if (!layerGroups.containsKey(layerId)) { PdfLayer parent; try { parent = new PdfLayer(layerId, canvas.getPdfWriter()); } catch (IOException ex) { throw new VectorPrintRuntimeException(ex); } layerGroups.put(layerId, parent); canvas.beginLayer(parent); canvas.endLayer(); } return layerGroups.get(layerId); } public void setStyleHelper(StyleHelper styleHelper) { this.styleHelper = styleHelper; } @Override public void loadTiff(File tiff, ImageProcessor imageProcessor, int... pages) throws VectorPrintException { RandomAccessFileOrArray ra = null; try { RandomAccessSourceFactory rasf = new RandomAccessSourceFactory(); ra = new RandomAccessFileOrArray(rasf.createBestSource(tiff.getPath())); if (pages == null) { for (int i = 0; i < TiffImage.getNumberOfPages(ra);) { imageProcessor.processImage(TiffImage.getTiffImage(ra, ++i)); } } else { for (int i : pages) { imageProcessor.processImage(TiffImage.getTiffImage(ra, i)); } } } catch (IOException ex) { throw new VectorPrintException(String.format("unable to load tiff %s", tiff.toString()), ex); } finally { if (ra != null) { try { ra.close(); } catch (IOException ex) { } } } } /** * Creates tempfile and calls {@link loadTiff(File, ImageProcessor, int...) } * * @param tiff * @param imageProcessor * @param pages * @throws VectorPrintException */ @Override public void loadTiff(InputStream tiff, ImageProcessor imageProcessor, int... pages) throws VectorPrintException { File f = null; try { f = File.createTempFile("tiff.", "tiff"); f.deleteOnExit(); IOHelper.load(tiff, new FileOutputStream(f), ReportConstants.DEFAULTBUFFERSIZE, true); loadTiff(f, imageProcessor, pages); } catch (IOException ex) { throw new VectorPrintException(String.format("unable to load tiff"), ex); } finally { if (f != null) { f.delete(); } } } /** * Calls {@link loadTiff(InputStream, ImageProcessor, int... ) } * * @param tiff * @param imageProcessor * @param pages * @throws VectorPrintException */ @Override public void loadTiff(URL tiff, ImageProcessor imageProcessor, int... pages) throws VectorPrintException { try { if (log.isLoggable(Level.FINE)) { log.fine(String.format("loading tiff from %s", String.valueOf(tiff))); } if ("file".equals(tiff.getProtocol())) { loadTiff(new File(tiff.getFile()), imageProcessor, pages); } else { loadTiff(tiff.openStream(), imageProcessor, pages); } } catch (IOException ex) { throw new VectorPrintException(String.format("unable to load image %s", tiff.toString()), ex); } } @Override public Formatter getFormatter() { return formatter; } @Override public StyleHelper getStyleHelper() { return styleHelper; } /** * Creates a ColumnText, adds the data using addText and returns the {@link SimpleColumns} that can be used to * {@link SimpleColumns#write() write out} or to * {@link SimpleColumns#addContent(java.lang.Object, java.lang.String...) add more data} to the document. * * @param stylers * @return * @throws VectorPrintException */ @Override public SimpleColumns createColumns(List stylers) throws VectorPrintException { ColumnText mct = styleHelper.style(ColumnText.class, null, stylers); SimpleColumns sc = StyleHelper.getStylers(stylers, SimpleColumns.class).get(0); return sc; } public void setSettings(EnhancedMap settings) { this.settings = settings; StylerFactoryHelper.SETTINGS_ANNOTATION_PROCESSOR.initSettings(formatter, settings); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy