Package org.pentaho.reporting.engine.classic.core.modules.output.pageable.pdf.internal

Source Code of org.pentaho.reporting.engine.classic.core.modules.output.pageable.pdf.internal.PdfLogicalPageDrawable

/*
* This program is free software; you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software
* Foundation.
*
* You should have received a copy of the GNU Lesser General Public License along with this
* program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
* or from the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* 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 Lesser General Public License for more details.
*
* Copyright (c) 2001 - 2009 Object Refinery Ltd, Pentaho Corporation and Contributors..  All rights reserved.
*/

package org.pentaho.reporting.engine.classic.core.modules.output.pageable.pdf.internal;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;

import com.lowagie.text.Rectangle;
import com.lowagie.text.pdf.BaseFont;
import com.lowagie.text.pdf.PdfAction;
import com.lowagie.text.pdf.PdfAnnotation;
import com.lowagie.text.pdf.PdfContentByte;
import com.lowagie.text.pdf.PdfDestination;
import com.lowagie.text.pdf.PdfName;
import com.lowagie.text.pdf.PdfObject;
import com.lowagie.text.pdf.PdfOutline;
import com.lowagie.text.pdf.PdfString;
import com.lowagie.text.pdf.PdfTextArray;
import com.lowagie.text.pdf.PdfWriter;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.pentaho.reporting.engine.classic.core.AttributeNames;
import org.pentaho.reporting.engine.classic.core.ElementAlignment;
import org.pentaho.reporting.engine.classic.core.InvalidReportStateException;
import org.pentaho.reporting.engine.classic.core.LocalImageContainer;
import org.pentaho.reporting.engine.classic.core.ReportAttributeMap;
import org.pentaho.reporting.engine.classic.core.URLImageContainer;
import org.pentaho.reporting.engine.classic.core.imagemap.ImageMap;
import org.pentaho.reporting.engine.classic.core.imagemap.ImageMapEntry;
import org.pentaho.reporting.engine.classic.core.layout.model.InlineRenderBox;
import org.pentaho.reporting.engine.classic.core.layout.model.LogicalPageBox;
import org.pentaho.reporting.engine.classic.core.layout.model.PhysicalPageBox;
import org.pentaho.reporting.engine.classic.core.layout.model.RenderNode;
import org.pentaho.reporting.engine.classic.core.layout.model.RenderableReplacedContentBox;
import org.pentaho.reporting.engine.classic.core.layout.model.RenderableText;
import org.pentaho.reporting.engine.classic.core.layout.output.OutputProcessorFeature;
import org.pentaho.reporting.engine.classic.core.layout.output.OutputProcessorMetaData;
import org.pentaho.reporting.engine.classic.core.layout.output.RenderUtility;
import org.pentaho.reporting.engine.classic.core.layout.text.Glyph;
import org.pentaho.reporting.engine.classic.core.layout.text.GlyphList;
import org.pentaho.reporting.engine.classic.core.modules.output.pageable.graphics.internal.LogicalPageDrawable;
import org.pentaho.reporting.engine.classic.core.style.BandStyleKeys;
import org.pentaho.reporting.engine.classic.core.style.ElementStyleKeys;
import org.pentaho.reporting.engine.classic.core.style.StyleSheet;
import org.pentaho.reporting.engine.classic.core.style.TextStyleKeys;
import org.pentaho.reporting.engine.classic.core.util.geom.StrictGeomUtility;
import org.pentaho.reporting.libraries.base.util.LFUMap;
import org.pentaho.reporting.libraries.base.util.StringUtils;
import org.pentaho.reporting.libraries.base.util.WaitingImageObserver;
import org.pentaho.reporting.libraries.fonts.encoding.CodePointBuffer;
import org.pentaho.reporting.libraries.fonts.itext.BaseFontFontMetrics;
import org.pentaho.reporting.libraries.fonts.text.Spacing;
import org.pentaho.reporting.libraries.resourceloader.Resource;
import org.pentaho.reporting.libraries.resourceloader.ResourceData;
import org.pentaho.reporting.libraries.resourceloader.ResourceKey;
import org.pentaho.reporting.libraries.resourceloader.ResourceManager;
import org.pentaho.reporting.libraries.resourceloader.factory.drawable.DrawableWrapper;
import org.pentaho.reporting.libraries.xmlns.LibXmlInfo;

/**
* Creation-Date: 17.07.2007, 18:41:46
*
* @author Thomas Morgner
*/
public class PdfLogicalPageDrawable extends LogicalPageDrawable
{
  private static final Log logger = LogFactory.getLog(PdfLogicalPageDrawable.class);

  protected static class PdfTextSpec extends TextSpec
  {
    private BaseFontFontMetrics fontMetrics;
    private PdfContentByte contentByte;

    protected PdfTextSpec(final StyleSheet layoutContext,
                          final PdfOutputProcessorMetaData metaData,
                          final PdfGraphics2D g2,
                          final BaseFontFontMetrics fontMetrics,
                          final PdfContentByte cb)
    {
      super(layoutContext, metaData, g2);
      if (fontMetrics == null)
      {
        throw new NullPointerException();
      }
      if (cb == null)
      {
        throw new NullPointerException();
      }
      this.fontMetrics = fontMetrics;
      this.contentByte = cb;
    }

    public BaseFontFontMetrics getFontMetrics()
    {
      return fontMetrics;
    }

    public PdfContentByte getContentByte()
    {
      return contentByte;
    }

    public void finishText()
    {
      contentByte.endText();
    }

    public void close()
    {
      //super.close(); // we do not dispose the graphics as we are working on the original object
    }
  }

  private static final float ITALIC_ANGLE = 0.21256f;

  private PdfWriter writer;
  private float globalHeight;
  private PdfOutputProcessorMetaData outputProcessorMetaData;
  private boolean globalEmbed;
  private LFUMap imageCache;
  private char version;

  public PdfLogicalPageDrawable(final LogicalPageBox rootBox,
                                final PdfOutputProcessorMetaData metaData,
                                final PdfWriter writer,
                                final PhysicalPageBox page,
                                final ResourceManager resourceManager,
                                final LFUMap imageCache,
                                final char version)
  {
    super(rootBox, metaData, resourceManager);
    this.version = version;
    if (writer == null)
    {
      throw new NullPointerException();
    }
    if (imageCache == null)
    {
      throw new NullPointerException();
    }

    if (page != null)
    {
      this.globalHeight = (float) StrictGeomUtility.toExternalValue(page.getHeight() - page.getImageableY());
    }
    else
    {
      this.globalHeight = rootBox.getPageHeight();
    }
    this.writer = writer;
    this.outputProcessorMetaData = metaData;
    this.globalEmbed = outputProcessorMetaData.isFeatureSupported(OutputProcessorFeature.EMBED_ALL_FONTS);
    this.imageCache = imageCache;
  }

  protected void processLinksAndAnchors(final RenderNode box)
  {
    final StyleSheet styleSheet = box.getStyleSheet();
    if (drawPdfScript(box) == false)
    {
      final String target = (String) styleSheet.getStyleProperty(ElementStyleKeys.HREF_TARGET);
      final String title = (String) styleSheet.getStyleProperty(ElementStyleKeys.HREF_TITLE);
      if (target != null || title != null)
      {
        final String window = (String) styleSheet.getStyleProperty(ElementStyleKeys.HREF_WINDOW);
        drawHyperlink(box, target, window, title);
      }
    }

    final String anchor = (String) styleSheet.getStyleProperty(ElementStyleKeys.ANCHOR_NAME);
    if (anchor != null)
    {
      drawAnchor(box);
    }

    final String bookmark = (String) styleSheet.getStyleProperty(BandStyleKeys.BOOKMARK);
    if (bookmark != null)
    {
      drawBookmark(box, bookmark);
    }
  }

  protected boolean drawPdfScript(final RenderNode box)
  {
    final Object attribute = box.getAttributes().getAttribute
        (AttributeNames.Pdf.NAMESPACE, AttributeNames.Pdf.SCRIPT_ACTION);
    if (attribute == null)
    {
      return false;
    }
   
    final String attributeText = String.valueOf(attribute);
    final PdfAction action = PdfAction.javaScript(attributeText, writer, false);

    final AffineTransform affineTransform = getGraphics().getTransform();
    final float translateX = (float) affineTransform.getTranslateX();

    final float leftX = translateX + (float) (StrictGeomUtility.toExternalValue(box.getX()));
    final float rightX = translateX + (float) (StrictGeomUtility.toExternalValue(box.getX() + box.getWidth()));
    final float lowerY = (float) (globalHeight - StrictGeomUtility.toExternalValue(box.getY() + box.getHeight()));
    final float upperY = (float) (globalHeight - StrictGeomUtility.toExternalValue(box.getY()));
    final PdfAnnotation annotation = new PdfAnnotation(writer, leftX, lowerY, rightX, upperY, action);
    writer.addAnnotation(annotation);
    return true;
  }
 
  protected void drawAnchor(final RenderNode content)
  {
    if (content.isNodeVisible(getDrawArea()) == false)
    {
      return;
    }
    final String anchorName = (String) content.getStyleSheet().getStyleProperty(ElementStyleKeys.ANCHOR_NAME);
    if (anchorName == null)
    {
      return;
    }
    final AffineTransform affineTransform = getGraphics().getTransform();
    final float translateX = (float) affineTransform.getTranslateX();

    final float upperY = translateX + (float) (globalHeight - StrictGeomUtility.toExternalValue(content.getY()));
    final float leftX = (float) (StrictGeomUtility.toExternalValue(content.getX()));
    final PdfDestination dest = new PdfDestination(PdfDestination.FIT, leftX, upperY, 0);
    writer.getDirectContent().localDestination(anchorName, dest);
  }

  protected void drawBookmark(final RenderNode box, final String bookmark)
  {
    if (box.isNodeVisible(getDrawArea()) == false)
    {
      return;
    }
    final PdfOutline root = writer.getDirectContent().getRootOutline();

    final AffineTransform affineTransform = getGraphics().getTransform();
    final float translateX = (float) affineTransform.getTranslateX();

    final float upperY = translateX + (float) (globalHeight - StrictGeomUtility.toExternalValue(box.getY()));
    final float leftX = (float) (StrictGeomUtility.toExternalValue(box.getX()));
    final PdfDestination dest = new PdfDestination(PdfDestination.FIT, leftX, upperY, 0);
    new PdfOutline(root, dest, bookmark);
    // destination will always point to the 'current' page
    // todo: Make this a hierarchy ..
  }

  protected void drawHyperlink(final RenderNode box, final String target, final String window, final String title)
  {
    if (box.isNodeVisible(getDrawArea()) == false)
    {
      return;
    }

    final PdfAction action = createActionForLink(target);

    final AffineTransform affineTransform = getGraphics().getTransform();
    final float translateX = (float) affineTransform.getTranslateX();

    final float leftX = translateX + (float) (StrictGeomUtility.toExternalValue(box.getX()));
    final float rightX = translateX + (float) (StrictGeomUtility.toExternalValue(box.getX() + box.getWidth()));
    final float lowerY = (float) (globalHeight - StrictGeomUtility.toExternalValue(box.getY() + box.getHeight()));
    final float upperY = (float) (globalHeight - StrictGeomUtility.toExternalValue(box.getY()));
   
    if (action != null)
    {
      final PdfAnnotation annotation = new PdfAnnotation(writer, leftX, lowerY, rightX, upperY, action);
      writer.addAnnotation(annotation);
    }
    else if (StringUtils.isEmpty(title) == false)
    {
      final Rectangle rect = new Rectangle(leftX, lowerY, rightX, upperY);
      final PdfAnnotation commentAnnotation = PdfAnnotation.createText(writer, rect, "Tooltip", title, false, null);
      commentAnnotation.setAppearance(PdfAnnotation.APPEARANCE_NORMAL,
          writer.getDirectContent().createAppearance(rect.getWidth(), rect.getHeight()));
      writer.addAnnotation(commentAnnotation);
    }
  }

  private PdfAction createActionForLink(final String target)
  {
    if (StringUtils.isEmpty(target))
    {
      return null;
    }
    final PdfAction action = new PdfAction();
    if (target.startsWith("#"))
    {
      // its a local link ..
      action.put(PdfName.S, PdfName.GOTO);
      action.put(PdfName.D, new PdfString(target.substring(1)));
    }
    else
    {
      action.put(PdfName.S, PdfName.URI);
      action.put(PdfName.URI, new PdfString(target));
    }
    return action;
  }

  protected void drawText(final RenderableText renderableText, final long contentX2)
  {
    if (renderableText.getLength() == 0)
    {
      return;
    }

    final long posX = renderableText.getX();
    final long posY = renderableText.getY();
    final float x1 = (float) (StrictGeomUtility.toExternalValue(posX));

    final PdfContentByte cb;
    PdfTextSpec textSpec = (PdfTextSpec) getTextSpec();
    if (textSpec == null)
    {
      final StyleSheet layoutContext = renderableText.getStyleSheet();

      // The code below may be weird, but at least it is predictable weird.
      final String fontName = getMetaData().getNormalizedFontFamilyName
          ((String) layoutContext.getStyleProperty(TextStyleKeys.FONT));
      final String encoding = (String) layoutContext.getStyleProperty(TextStyleKeys.FONTENCODING);
      final float fontSize = (float) layoutContext.getDoubleStyleProperty(TextStyleKeys.FONTSIZE, 10);

      final boolean embed = globalEmbed || layoutContext.getBooleanStyleProperty(TextStyleKeys.EMBEDDED_FONT);
      final boolean bold = layoutContext.getBooleanStyleProperty(TextStyleKeys.BOLD);
      final boolean italics = layoutContext.getBooleanStyleProperty(TextStyleKeys.ITALIC);

      final BaseFontFontMetrics fontMetrics = outputProcessorMetaData.getBaseFontFontMetrics
          (fontName, fontSize, bold, italics, encoding, embed, false);

      final PdfGraphics2D g2 = (PdfGraphics2D) getGraphics();
      final Color cssColor = (Color) layoutContext.getStyleProperty(ElementStyleKeys.PAINT);
      g2.setPaint(cssColor);
      g2.setFillPaint();
      g2.setStrokePaint();
      //final float translateY = (float) affineTransform.getTranslateY();

      cb = g2.getRawContentByte();

      textSpec = new PdfTextSpec(layoutContext, outputProcessorMetaData,
          g2, fontMetrics, cb);
      setTextSpec(textSpec);

      cb.beginText();
      cb.setFontAndSize(fontMetrics.getBaseFont(), fontSize);
    }
    else
    {
      cb = textSpec.getContentByte();
    }

    final BaseFontFontMetrics baseFontRecord = textSpec.getFontMetrics();
    final BaseFont baseFont = baseFontRecord.getBaseFont();
    final float ascent = baseFont.getFontDescriptor(BaseFont.BBOXURY, textSpec.getFontSize());
    final float y2 = (float) (StrictGeomUtility.toExternalValue(posY) + ascent);
    final float y = globalHeight - y2;


    final AffineTransform affineTransform = textSpec.getGraphics().getTransform();
    final float translateX = (float) affineTransform.getTranslateX();

    if (baseFontRecord.isTrueTypeFont() && textSpec.isBold())
    {
      final float strokeWidth = textSpec.getFontSize() / 30.0f; // right from iText ...
      if (strokeWidth == 1)
      {
        cb.setTextRenderingMode(PdfContentByte.TEXT_RENDER_MODE_FILL);
      }
      else
      {
        cb.setTextRenderingMode(PdfContentByte.TEXT_RENDER_MODE_FILL_STROKE);
        cb.setLineWidth(strokeWidth);
      }
    }
    else
    {
      cb.setTextRenderingMode(PdfContentByte.TEXT_RENDER_MODE_FILL);
    }

    // if the font does not declare to be italics already, emulate it ..
    if (baseFontRecord.isTrueTypeFont() && textSpec.isItalics())
    {
      final float italicAngle =
          baseFont.getFontDescriptor(BaseFont.ITALICANGLE, textSpec.getFontSize());
      if (italicAngle == 0)
      {
        // italics requested, but the font itself does not supply italics gylphs.
        cb.setTextMatrix(1, 0, PdfLogicalPageDrawable.ITALIC_ANGLE, 1, x1 + translateX, y);
      }
      else
      {
        cb.setTextMatrix(x1 + translateX, y);
      }
    }
    else
    {
      cb.setTextMatrix(x1 + translateX, y);
    }

    final OutputProcessorMetaData metaData = getMetaData();
    final GlyphList gs = renderableText.getGlyphs();
    final int offset = renderableText.getOffset();

    final CodePointBuffer codePointBuffer = getCodePointBuffer();
    if (metaData.isFeatureSupported(OutputProcessorFeature.FAST_FONTRENDERING) &&
        isNormalTextSpacing(renderableText))
    {
      final int maxLength = computeMaximumTextSize(renderableText, contentX2);
      final String text = gs.getText(renderableText.getOffset(), maxLength, codePointBuffer);

      cb.showText(text);
    }
    else
    {
      final PdfTextArray textArray = new PdfTextArray();
      final StringBuffer buffer = new StringBuffer(gs.getSize());
      final int maxPos = offset + computeMaximumTextSize(renderableText, contentX2);

      for (int i = offset; i < maxPos; i++)
      {
        final Glyph g = gs.getGlyph(i);
        final Spacing spacing = g.getSpacing();
        if (i != offset)
        {
          final int optimum = spacing.getOptimum();
          if (optimum != 0)
          {
            textArray.add(buffer.toString());
            textArray.add(-optimum / textSpec.getFontSize());
            buffer.setLength(0);
          }
        }

        final String text = gs.getGlyphAsString(i, codePointBuffer);
        buffer.append(text);
      }
      if (buffer.length() > 0)
      {
        textArray.add(buffer.toString());
      }
      cb.showText(textArray);
    }
  }


  protected boolean startInlineBox(final InlineRenderBox box)
  {
    final PdfTextSpec textSpec = (PdfTextSpec) getTextSpec();
    if (textSpec != null)
    {
      textSpec.finishText();
    }
    return super.startInlineBox(box);
  }

  protected void finishInlineBox(final InlineRenderBox box)
  {
    final PdfTextSpec textSpec = (PdfTextSpec) getTextSpec();
    if (textSpec != null)
    {
      textSpec.finishText();
    }
    super.finishInlineBox(box);
  }

  protected void drawReplacedContent(final RenderableReplacedContentBox content)
  {
    final Graphics2D g2 = getGraphics();
    final Object o = content.getContent().getRawObject();
    if (o instanceof DrawableWrapper)
    {
      final DrawableWrapper drawableWrapper = (DrawableWrapper) o;
      if (drawDrawable(content, g2, drawableWrapper))
      {
        drawImageMap(content);
      }
      return;
    }
    if (o instanceof Image)
    {
      if (drawImage(content, (Image) o))
      {
        drawImageMap(content);
      }
      return;
    }

    if (o instanceof URLImageContainer)
    {
      final URLImageContainer imageContainer = (URLImageContainer) o;
      if (imageContainer.isLoadable() == false)
      {
        PdfLogicalPageDrawable.logger.info
            ("URL-image cannot be rendered, as it was declared to be not loadable: " +
                imageContainer.getSourceURLString());
      }
      else
      {
        final ResourceKey resource = imageContainer.getResourceKey();
        if (resource == null)
        {
          PdfLogicalPageDrawable.logger.info("URL-image cannot be rendered, as it did not return a valid URL.");
        }
        else
        {
          try
          {
            final ResourceManager resourceManager = getResourceManager();
            final com.lowagie.text.Image instance;
            final Object maybeImage = imageCache.get(resource);
            if (maybeImage != null)
            {
              instance = (com.lowagie.text.Image) maybeImage;
            }
            else
            {
              final ResourceData data = resourceManager.load(resource);
              instance = com.lowagie.text.Image.getInstance(data.getResource(resourceManager));
              imageCache.put(resource, instance);
            }

            final Resource imageWrapped = resourceManager.create(resource, null, Image.class);
            final Image image = (Image) imageWrapped.getResource();

            if (drawImage(content, image, instance))
            {
              drawImageMap(content);
            }
            return;
          }
          catch (InvalidReportStateException re)
          {
            throw re;
          }
          catch (Exception e)
          {
            PdfLogicalPageDrawable.logger.info("URL-image cannot be rendered, as the image was not loadable.", e);
          }
        }
      }
    }

    if (o instanceof LocalImageContainer)
    {
      final LocalImageContainer imageContainer = (LocalImageContainer) o;
      final Image image = imageContainer.getImage();
      if (drawImage(content, image))
      {
        drawImageMap(content);
      }
    }
    else
    {
      PdfLogicalPageDrawable.logger.debug("Unable to handle " + o);
    }
  }

  protected void drawImageMap(final RenderableReplacedContentBox content)
  {
    if (version < '6')
    {
      return;
    }

    final ImageMap imageMap = RenderUtility.extractImageMap(content);
    // only generate a image map, if the user does not specify their own onw via the override.
    // Of course, they would have to provide the map by other means as well.

    if (imageMap == null)
    {
      return;
    }

    final ImageMapEntry[] imageMapEntries = imageMap.getMapEntries();
    for (int i = 0; i < imageMapEntries.length; i++)
    {
      final ImageMapEntry imageMapEntry = imageMapEntries[i];
      final String link = imageMapEntry.getAttribute(LibXmlInfo.XHTML_NAMESPACE, "href");
      final String tooltip = imageMapEntry.getAttribute(LibXmlInfo.XHTML_NAMESPACE, "title");
      if (StringUtils.isEmpty(tooltip))
      {
        continue;
      }

      final AffineTransform affineTransform = getGraphics().getTransform();
      final float translateX = (float) affineTransform.getTranslateX();
      final int x = (int) (translateX + StrictGeomUtility.toExternalValue(content.getX()));
      final int y = (int) StrictGeomUtility.toExternalValue(content.getY());
      final float[] translatedCoords = translateCoordinates(imageMapEntry.getAreaCoordinates(), x, y);

      final PolygonAnnotation polygonAnnotation = new PolygonAnnotation(writer, translatedCoords);
      polygonAnnotation.put(PdfName.CONTENTS, new PdfString(tooltip, PdfObject.TEXT_UNICODE));
      writer.addAnnotation(polygonAnnotation);
    }
  }


  private float[] translateCoordinates(final float[] coords, float dx, float dy)
  {
    final float[] floats = coords.clone();
    if (floats.length % 2 != 0)
    {
      throw new IllegalArgumentException("Corrdinates are not x/y pairs");
    }
    for (int i = 0; i < floats.length; i += 2)
    {
      floats[i] += dx;
      floats[i + 1] = globalHeight - floats[i + 1] + dy;
    }
    return floats;
  }

  private PdfAction createActionForTooltip(final String tooltip)
  {
    return null;
  }

  /**
   * @param content
   * @param image
   */
  protected boolean drawImage(final RenderableReplacedContentBox content,
                              final Image image,
                              final com.lowagie.text.Image itextImage)
  {
    final StyleSheet layoutContext = content.getStyleSheet();
    final boolean shouldScale = layoutContext.getBooleanStyleProperty(ElementStyleKeys.SCALE);

    final int x = (int) StrictGeomUtility.toExternalValue(content.getX());
    final int y = (int) StrictGeomUtility.toExternalValue(content.getY());
    final int width = (int) StrictGeomUtility.toExternalValue(content.getWidth());
    final int height = (int) StrictGeomUtility.toExternalValue(content.getHeight());

    if (width == 0 || height == 0)
    {
      PdfLogicalPageDrawable.logger.debug("Error: Image area is empty: " + content);
      return false;
    }

    final WaitingImageObserver obs = new WaitingImageObserver(image);
    obs.waitImageLoaded();
    final int imageWidth = image.getWidth(obs);
    final int imageHeight = image.getHeight(obs);
    if (imageWidth < 1 || imageHeight < 1)
    {
      return false;
    }

    final Rectangle2D.Double drawAreaBounds = new Rectangle2D.Double(x, y, width, height);
    final AffineTransform scaleTransform;

    final Graphics2D g2;
    if (shouldScale == false)
    {
      double deviceScaleFactor = 1;
      final double devResolution = getMetaData().getNumericFeatureValue(OutputProcessorFeature.DEVICE_RESOLUTION);
      if (getMetaData().isFeatureSupported(OutputProcessorFeature.IMAGE_RESOLUTION_MAPPING))
      {
        if (devResolution != 72.0 && devResolution > 0)
        {
          // Need to scale the device to its native resolution before attempting to draw the image..
          deviceScaleFactor = (72.0 / devResolution);
        }
      }

      final int clipWidth = Math.min(width, (int) Math.ceil(deviceScaleFactor * imageWidth));
      final int clipHeight = Math.min(height, (int) Math.ceil(deviceScaleFactor * imageHeight));
      final ElementAlignment horizontalAlignment =
          (ElementAlignment) layoutContext.getStyleProperty(ElementStyleKeys.ALIGNMENT);
      final ElementAlignment verticalAlignment =
          (ElementAlignment) layoutContext.getStyleProperty(ElementStyleKeys.VALIGNMENT);
      final int alignmentX = (int) RenderUtility.computeHorizontalAlignment(horizontalAlignment, width, clipWidth);
      final int alignmentY = (int) RenderUtility.computeVerticalAlignment(verticalAlignment, height, clipHeight);

      g2 = (Graphics2D) getGraphics().create();
      g2.clip(drawAreaBounds);
      g2.translate(x, y);
      g2.translate(alignmentX, alignmentY);
      g2.clip(new Rectangle2D.Float(0, 0, clipWidth, clipHeight));
      g2.scale(deviceScaleFactor, deviceScaleFactor);

      scaleTransform = null;
    }
    else
    {
      g2 = (Graphics2D) getGraphics().create();
      g2.clip(drawAreaBounds);
      g2.translate(x, y);
      g2.clip(new Rectangle2D.Float(0, 0, width, height));

      final double scaleX;
      final double scaleY;

      final boolean keepAspectRatio = layoutContext.getBooleanStyleProperty(ElementStyleKeys.KEEP_ASPECT_RATIO);
      if (keepAspectRatio)
      {
        final double scaleFactor = Math.min(width / (double) imageWidth, height / (double) imageHeight);
        scaleX = scaleFactor;
        scaleY = scaleFactor;
      }
      else
      {
        scaleX = width / (double) imageWidth;
        scaleY = height / (double) imageHeight;
      }

      final int clipWidth = (int) (scaleX * imageWidth);
      final int clipHeight = (int) (scaleY * imageHeight);

      final ElementAlignment horizontalAlignment =
          (ElementAlignment) layoutContext.getStyleProperty(ElementStyleKeys.ALIGNMENT);
      final ElementAlignment verticalAlignment =
          (ElementAlignment) layoutContext.getStyleProperty(ElementStyleKeys.VALIGNMENT);
      final int alignmentX = (int) RenderUtility.computeHorizontalAlignment(horizontalAlignment, width, clipWidth);
      final int alignmentY = (int) RenderUtility.computeVerticalAlignment(verticalAlignment, height, clipHeight);

      g2.translate(alignmentX, alignmentY);
      scaleTransform = AffineTransform.getScaleInstance(scaleX, scaleY);
    }

    final PdfGraphics2D pdfGraphics2D = (PdfGraphics2D) g2;
    pdfGraphics2D.drawPdfImage(itextImage, image, scaleTransform, null);
    g2.dispose();
    return true;
  }

}
TOP

Related Classes of org.pentaho.reporting.engine.classic.core.modules.output.pageable.pdf.internal.PdfLogicalPageDrawable

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.