Package org.pentaho.reporting.engine.classic.core.modules.output.table.html.helper

Source Code of org.pentaho.reporting.engine.classic.core.modules.output.table.html.helper.DefaultHtmlContentGenerator$ImageData

/*
* 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) 2006 - 2013 Pentaho Corporation..  All rights reserved.
*/

package org.pentaho.reporting.engine.classic.core.modules.output.table.html.helper;

import java.awt.Image;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.util.HashMap;
import java.util.HashSet;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.pentaho.reporting.engine.classic.core.ImageContainer;
import org.pentaho.reporting.engine.classic.core.LocalImageContainer;
import org.pentaho.reporting.engine.classic.core.URLImageContainer;
import org.pentaho.reporting.engine.classic.core.layout.output.RenderUtility;
import org.pentaho.reporting.engine.classic.core.modules.output.table.html.HtmlContentGenerator;
import org.pentaho.reporting.engine.classic.core.modules.output.table.html.URLRewriteException;
import org.pentaho.reporting.libraries.base.encoder.UnsupportedEncoderException;
import org.pentaho.reporting.libraries.base.util.IOUtils;
import org.pentaho.reporting.libraries.base.util.StringUtils;
import org.pentaho.reporting.libraries.repository.ContentCreationException;
import org.pentaho.reporting.libraries.repository.ContentIOException;
import org.pentaho.reporting.libraries.repository.ContentItem;
import org.pentaho.reporting.libraries.repository.ContentLocation;
import org.pentaho.reporting.libraries.repository.LibRepositoryBoot;
import org.pentaho.reporting.libraries.repository.NameGenerator;
import org.pentaho.reporting.libraries.resourceloader.Resource;
import org.pentaho.reporting.libraries.resourceloader.ResourceData;
import org.pentaho.reporting.libraries.resourceloader.ResourceException;
import org.pentaho.reporting.libraries.resourceloader.ResourceKey;
import org.pentaho.reporting.libraries.resourceloader.ResourceLoadingException;
import org.pentaho.reporting.libraries.resourceloader.ResourceManager;

public class DefaultHtmlContentGenerator implements HtmlContentGenerator
{
  private static class ImageData
  {
    private byte[] imageData;
    private String mimeType;
    private String originalFileName;

    private ImageData(final byte[] imageData, final String mimeType, final String originalFileName)
    {
      if (imageData == null)
      {
        throw new NullPointerException();
      }
      if (mimeType == null)
      {
        throw new NullPointerException();
      }
      if (originalFileName == null)
      {
        throw new NullPointerException();
      }

      this.imageData = imageData;
      this.mimeType = mimeType;
      this.originalFileName = originalFileName;
    }

    public byte[] getImageData()
    {
      return imageData;
    }

    public String getMimeType()
    {
      return mimeType;
    }

    public String getOriginalFileName()
    {
      return originalFileName;
    }
  }

  private static final Log logger = LogFactory.getLog(DefaultHtmlContentGenerator.class);

  private final HashSet<String> validRawTypes;
  private ResourceManager resourceManager;
  private HashMap<ResourceKey, String> knownResources;
  private HashMap<String, String> knownImages;
  private boolean copyExternalImages;
  private ContentLocation dataLocation;
  private NameGenerator dataNameGenerator;
  private ContentUrlReWriteService rewriterService;

  public DefaultHtmlContentGenerator(final ResourceManager resourceManager)
  {
    this.knownImages = new HashMap<String, String>();
    this.resourceManager = resourceManager;
    this.knownResources = new HashMap<ResourceKey, String>();

    this.validRawTypes = new HashSet<String>();
    this.validRawTypes.add("image/gif");
    this.validRawTypes.add("image/x-xbitmap");
    this.validRawTypes.add("image/gi_");
    this.validRawTypes.add("image/jpeg");
    this.validRawTypes.add("image/jpg");
    this.validRawTypes.add("image/jp_");
    this.validRawTypes.add("application/jpg");
    this.validRawTypes.add("application/x-jpg");
    this.validRawTypes.add("image/pjpeg");
    this.validRawTypes.add("image/pipeg");
    this.validRawTypes.add("image/vnd.swiftview-jpeg");
    this.validRawTypes.add("image/x-xbitmap");
    this.validRawTypes.add("image/png");
    this.validRawTypes.add("application/png");
    this.validRawTypes.add("application/x-png");

  }

  public void setDataWriter(final ContentLocation dataLocation,
                            final NameGenerator dataNameGenerator,
                            final ContentUrlReWriteService rewriterService)
  {
    this.dataNameGenerator = dataNameGenerator;
    this.dataLocation = dataLocation;
    this.rewriterService = rewriterService;
  }

  public void setCopyExternalImages(final boolean copyExternalImages)
  {
    this.copyExternalImages = copyExternalImages;
  }

  public boolean isCopyExternalImages()
  {
    return copyExternalImages;
  }

  public ResourceManager getResourceManager()
  {
    return resourceManager;
  }

  public void registerFailure(final ResourceKey source)
  {
    knownResources.put(source, null);
  }

  public void registerContent(final ResourceKey source, final String name)
  {
    knownResources.put(source, name);
  }

  public boolean isRegistered(final ResourceKey source)
  {
    return knownResources.containsKey(source);
  }

  public String getRegisteredName(final ResourceKey source)
  {
    final String o = knownResources.get(source);
    if (o != null)
    {
      return o;
    }
    return null;
  }

  public String writeRaw(final ResourceKey source) throws IOException
  {
    if (source == null)
    {
      throw new NullPointerException();
    }

    if (copyExternalImages == false)
    {
      final Object identifier = source.getIdentifier();
      if (identifier instanceof URL)
      {
        final URL url = (URL) identifier;
        final String protocol = url.getProtocol();
        if ("http".equalsIgnoreCase(protocol) ||
            "https".equalsIgnoreCase(protocol) ||
            "ftp".equalsIgnoreCase(protocol))
        {
          return url.toExternalForm();
        }
      }
    }

    if (dataLocation == null)
    {
      return null;
    }

    try
    {
      final ResourceData resourceData = resourceManager.load(source);
      final String mimeType = queryMimeType(resourceData);
      if (isValidImage(mimeType))
      {
        // lets do some voodo ..
        final ContentItem item = dataLocation.createItem
            (dataNameGenerator.generateName(extractFilename(resourceData), mimeType));
        if (item.isWriteable())
        {
          item.setAttribute(LibRepositoryBoot.REPOSITORY_DOMAIN, LibRepositoryBoot.CONTENT_TYPE, mimeType);

          // write it out ..
          final InputStream stream = new BufferedInputStream(resourceData.getResourceAsStream(resourceManager));
          try
          {
            final OutputStream outputStream = new BufferedOutputStream(item.getOutputStream());
            try
            {
              IOUtils.getInstance().copyStreams(stream, outputStream);
            }
            finally
            {
              outputStream.close();
            }
          }
          finally
          {
            stream.close();
          }

          return rewriterService.rewriteContentDataItem(item);
        }
      }
    }
    catch (ResourceLoadingException e)
    {
      // Ok, loading the resource failed. Not a problem, so we will
      // recode the raw-object instead ..
    }
    catch (ContentIOException e)
    {
      // ignore it ..
    }
    catch (URLRewriteException e)
    {
      logger.warn("Rewriting the URL failed.", e);
      throw new RuntimeException("Failed", e);
    }
    return null;
  }

  public String writeImage(final ImageContainer image,
                           final String encoderType,
                           final float quality,
                           final boolean alpha)
      throws ContentIOException, IOException
  {
    if (image == null)
    {
      throw new NullPointerException();
    }

    if (dataLocation == null)
    {
      return null;
    }

    final String cacheKey;
    if (image instanceof URLImageContainer)
    {
      final URLImageContainer uic = (URLImageContainer) image;
      cacheKey = uic.getSourceURLString();
      final String retval = knownImages.get(cacheKey);
      if (retval != null)
      {
        return retval;
      }

      final String sourceURLString = uic.getSourceURLString();
      if (uic.isLoadable() == false && sourceURLString != null)
      {
        knownImages.put(cacheKey, sourceURLString);
        return sourceURLString;
      }
    }
    else
    {
      cacheKey = null;
    }

    try
    {
      final ImageData data = getImageData(image, encoderType, quality, alpha);
      if (data == null)
      {
        return null;
      }
      // write the encoded picture ...
      final String filename = IOUtils.getInstance().stripFileExtension(data.getOriginalFileName());
      final ContentItem dataFile = dataLocation.createItem
          (dataNameGenerator.generateName(filename, data.getMimeType()));
      final String contentURL = rewriterService.rewriteContentDataItem(dataFile);

      // a png encoder is included in JCommon ...
      final OutputStream out = new BufferedOutputStream(dataFile.getOutputStream());
      try
      {
        out.write(data.getImageData());
        out.flush();
      }
      finally
      {
        out.close();
      }
      if (cacheKey != null)
      {
        knownImages.put(cacheKey, contentURL);
      }

      return contentURL;
    }
    catch (ContentCreationException cce)
    {
      // Can't create the content
      logger.warn("Failed to create the content image: Reason given was: " + cce.getMessage());
      return null;
    }
    catch (URLRewriteException re)
    {
      // cannot handle this ..
      logger.warn("Failed to write the URL: Reason given was: " + re.getMessage());
      return null;
    }
    catch (UnsupportedEncoderException e)
    {
      logger.warn("Failed to write the URL: Reason given was: " + e.getMessage());
      return null;
    }
  }

  private String queryMimeType(final ResourceData resourceData)
      throws ResourceLoadingException, IOException
  {
    final Object contentType = resourceData.getAttribute(ResourceData.CONTENT_TYPE);
    if (contentType instanceof String)
    {
      return (String) contentType;
    }

    // now we are getting very primitive .. (Kids, dont do this at home)
    final byte[] data = new byte[12];
    resourceData.getResource(resourceManager, data, 0, data.length);
    return queryMimeType(data);
  }

  private String queryMimeType(final byte[] data) throws IOException
  {
    final ByteArrayInputStream stream = new ByteArrayInputStream(data);
    if (isGIF(stream))
    {
      return "image/gif";
    }
    stream.reset();
    if (isJPEG(stream))
    {
      return "image/jpeg";
    }
    stream.reset();
    if (isPNG(stream))
    {
      return "image/png";
    }
    return null;
  }

  private boolean isPNG(final ByteArrayInputStream data)
  {
    final int[] PNF_FINGERPRINT = {137, 80, 78, 71, 13, 10, 26, 10};
    for (int i = 0; i < PNF_FINGERPRINT.length; i++)
    {
      if (PNF_FINGERPRINT[i] != data.read())
      {
        return false;
      }
    }
    return true;
  }

  private boolean isJPEG(final InputStream data) throws IOException
  {
    final int[] JPG_FINGERPRINT_1 = {0xFF, 0xD8, 0xFF, 0xE0};
    for (int i = 0; i < JPG_FINGERPRINT_1.length; i++)
    {
      if (JPG_FINGERPRINT_1[i] != data.read())
      {
        return false;
      }
    }
    // then skip two bytes ..
    if (data.read() == -1)
    {
      return false;
    }
    if (data.read() == -1)
    {
      return false;
    }

    final int[] JPG_FINGERPRINT_2 = {0x4A, 0x46, 0x49, 0x46, 0x00};
    for (int i = 0; i < JPG_FINGERPRINT_2.length; i++)
    {
      if (JPG_FINGERPRINT_2[i] != data.read())
      {
        return false;
      }
    }
    return true;
  }

  private boolean isGIF(final InputStream data) throws IOException
  {
    final int[] GIF_FINGERPRINT = {'G', 'I', 'F', '8'};
    for (int i = 0; i < GIF_FINGERPRINT.length; i++)
    {
      if (GIF_FINGERPRINT[i] != data.read())
      {
        return false;
      }
    }
    return true;
  }

  private String extractFilename(final ResourceData resourceData)
  {
    final String filename = (String) resourceData.getAttribute(ResourceData.FILENAME);
    if (filename == null)
    {
      return "image";
    }

    final String pureFileName = IOUtils.getInstance().getFileName(filename);
    return IOUtils.getInstance().stripFileExtension(pureFileName);
  }

  private boolean isValidImage(final String mimeType)
  {
    return validRawTypes.contains(mimeType);
  }


  private ImageData getImageData(final ImageContainer image,
                                 final String encoderType,
                                 final float quality,
                                 final boolean alpha) throws IOException, UnsupportedEncoderException
  {
    ResourceManager resourceManager = getResourceManager();
    ResourceKey url = null;
    // The image has an assigned URL ...
    if (image instanceof URLImageContainer)
    {
      final URLImageContainer urlImage = (URLImageContainer) image;

      url = urlImage.getResourceKey();
      // if we have an source to load the image data from ..
      if (url != null)
      {
        if (urlImage.isLoadable() && isSupportedImageFormat(url))
        {
          try
          {
            final ResourceData data = resourceManager.load(url);
            final byte[] imageData = data.getResource(resourceManager);
            final String mimeType = queryMimeType(imageData);
            final URL maybeRealURL = resourceManager.toURL(url);
            if (maybeRealURL != null)
            {
              final String originalFileName = IOUtils.getInstance().getFileName(maybeRealURL);
              return new ImageData(imageData, mimeType, originalFileName);
            }
            else
            {
              return new ImageData(imageData, mimeType, "picture");
            }
          }
          catch (ResourceException re)
          {
            // ok, try as local ...
            logger.debug("Failed to process image as raw-data, trying as processed data next", re);
          }
        }
      }
    }

    if (image instanceof LocalImageContainer)
    {
      // Check, whether the imagereference contains an AWT image.
      // if so, then we can use that image instance for the recoding
      final LocalImageContainer li = (LocalImageContainer) image;
      Image awtImage = li.getImage();
      if (awtImage == null)
      {
        if (url != null)
        {
          try
          {
            final Resource resource = resourceManager.createDirectly(url, Image.class);
            awtImage = (Image) resource.getResource();
          }
          catch (ResourceException e)
          {
            // ignore.
          }
        }
      }
      if (awtImage != null)
      {
        // now encode the image. We don't need to create digest data
        // for the image contents, as the image is perfectly identifyable
        // by its URL
        final byte[] imageData = RenderUtility.encodeImage(awtImage, encoderType, quality, alpha);
        final String originalFileName;
        if (url != null)
        {
          final URL maybeRealURL = resourceManager.toURL(url);
          if (maybeRealURL != null)
          {
            originalFileName = IOUtils.getInstance().getFileName(maybeRealURL);
          }
          else
          {
            // we just need the picture part, the file-extension will be replaced by one that matches
            // the mime-type.
            originalFileName = "picture";
          }
        }
        else
        {
          // we just need the picture part, the file-extension will be replaced by one that matches
          // the mime-type.
          originalFileName = "picture";
        }
        return new ImageData(imageData, encoderType, originalFileName);
      }
    }
    return null;
  }


  /**
   * Tests, whether the given URL points to a supported file format for common browsers. Returns true if the URL
   * references a JPEG, PNG or GIF image, false otherwise.
   * <p/>
   * The checked filetypes are the ones recommended by the W3C.
   *
   * @param key the url that should be tested.
   * @return true, if the content type is supported by the browsers, false otherwise.
   */
  protected boolean isSupportedImageFormat(final ResourceKey key)
  {
    ResourceManager resourceManager = getResourceManager();
    final URL url = resourceManager.toURL(key);
    if (url == null)
    {
      return false;
    }

    final String file = url.getFile();
    if (StringUtils.endsWithIgnoreCase(file, ".jpg"))
    {
      return true;
    }
    if (StringUtils.endsWithIgnoreCase(file, ".jpeg"))
    {
      return true;
    }
    if (StringUtils.endsWithIgnoreCase(file, ".png"))
    {
      return true;
    }
    if (StringUtils.endsWithIgnoreCase(file, ".gif"))
    {
      return true;
    }
    return false;
  }

  public ContentItem createItem(final String name, final String mimeType) throws ContentIOException
  {
    return dataLocation.createItem(dataNameGenerator.generateName(name, mimeType));
  }


  public boolean isExternalContentAvailable()
  {
    return dataLocation != null;
  }
}
TOP

Related Classes of org.pentaho.reporting.engine.classic.core.modules.output.table.html.helper.DefaultHtmlContentGenerator$ImageData

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.