Package ch.entwine.weblounge.preview.jai

Source Code of ch.entwine.weblounge.preview.jai.JAIPreviewGenerator

/*
*  Weblounge: Web Content Management System
*  Copyright (c) 2003 - 2011 The Weblounge Team
*  http://entwinemedia.com/weblounge
*
*  This program is free software; you can redistribute it and/or
*  modify it under the terms of the GNU Lesser General Public License
*  as published by the Free Software Foundation; either version 2
*  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 Lesser General Public License for more details.
*
*  You should have received a copy of the GNU Lesser General Public License
*  along with this program; if not, write to the Free Software Foundation
*  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

package ch.entwine.weblounge.preview.jai;

import ch.entwine.weblounge.common.content.Resource;
import ch.entwine.weblounge.common.content.ResourceContent;
import ch.entwine.weblounge.common.content.image.ImagePreviewGenerator;
import ch.entwine.weblounge.common.content.image.ImageResource;
import ch.entwine.weblounge.common.content.image.ImageStyle;
import ch.entwine.weblounge.common.impl.content.image.ImageStyleUtils;
import ch.entwine.weblounge.common.language.Language;
import ch.entwine.weblounge.common.site.Environment;
import ch.entwine.weblounge.common.site.ImageScalingMode;

import com.sun.media.jai.codec.FileCacheSeekableStream;
import com.sun.media.jai.codec.SeekableStream;

import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.awt.RenderingHints;
import java.awt.image.renderable.ParameterBlock;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import javax.imageio.ImageIO;
import javax.media.jai.BorderExtender;
import javax.media.jai.Interpolation;
import javax.media.jai.JAI;
import javax.media.jai.RenderedOp;

/**
* Utility class used for dealing with images and image styles.
*/
public final class JAIPreviewGenerator implements ImagePreviewGenerator {

  /** The logging facility */
  private static final Logger logger = LoggerFactory.getLogger(JAIPreviewGenerator.class);

  /**
   * {@inheritDoc}
   *
   * @see ch.entwine.weblounge.common.content.PreviewGenerator#supports(ch.entwine.weblounge.common.content.Resource)
   */
  public boolean supports(Resource<?> resource) {
    return (resource instanceof ImageResource);
  }

  /**
   * {@inheritDoc}
   *
   * @see ch.entwine.weblounge.common.content.PreviewGenerator#supports(java.lang.String)
   */
  public boolean supports(String format) {
    if (format == null)
      throw new IllegalArgumentException("Format cannot be null");
    return ImageIO.getImageWritersBySuffix(format.toLowerCase()).hasNext();
  }

  /**
   * {@inheritDoc}
   *
   * @see ch.entwine.weblounge.common.content.PreviewGenerator#createPreview(ch.entwine.weblounge.common.content.Resource,
   *      ch.entwine.weblounge.common.site.Environment,
   *      ch.entwine.weblounge.common.language.Language,
   *      ch.entwine.weblounge.common.content.image.ImageStyle, String,
   *      java.io.InputStream, java.io.OutputStream)
   */
  public void createPreview(Resource<?> resource, Environment environment,
      Language language, ImageStyle style, String format, InputStream is,
      OutputStream os) throws IOException {
    if (format == null) {
      if (resource == null)
        throw new IllegalArgumentException("Resource cannot be null");
      if (resource.getContent(language) == null) {
        logger.warn("Skipping creation of preview for {} in language '{}': no content", resource, language.getIdentifier());
        return;
      }
      String mimetype = resource.getContent(language).getMimetype();
      logger.trace("Image preview is generated using the resource's mimetype '{}'", mimetype);
      format = mimetype.substring(mimetype.indexOf("/") + 1);
    }
    style(is, os, format, style);
  }

  /**
   * {@inheritDoc}
   *
   * @see ch.entwine.weblounge.common.content.image.ImagePreviewGenerator#createPreview(java.io.File,
   *      ch.entwine.weblounge.common.site.Environment,
   *      ch.entwine.weblounge.common.language.Language,
   *      ch.entwine.weblounge.common.content.image.ImageStyle,
   *      java.lang.String, java.io.InputStream, java.io.OutputStream)
   */
  public void createPreview(File imageFile, Environment environment,
      Language language, ImageStyle style, String format, InputStream is,
      OutputStream os) throws IOException {

    if (format == null) {
      if (imageFile == null)
        throw new IllegalArgumentException("Image file cannot be null");
      format = FilenameUtils.getExtension(imageFile.getName());
      logger.trace("Image preview is generated as '{}'", format);
    }

    style(is, os, format, style);
  }

  /**
   * {@inheritDoc}
   *
   * @see ch.entwine.weblounge.common.content.PreviewGenerator#getContentType(ch.entwine.weblounge.common.content.Resource,
   *      ch.entwine.weblounge.common.language.Language,
   *      ch.entwine.weblounge.common.content.image.ImageStyle)
   */
  public String getContentType(Resource<?> resource, Language language,
      ImageStyle style) {
    String mimetype = resource.getContent(language).getMimetype();
    return mimetype;
  }

  /**
   * {@inheritDoc}
   *
   * @see ch.entwine.weblounge.common.content.PreviewGenerator#getSuffix(ch.entwine.weblounge.common.content.Resource,
   *      ch.entwine.weblounge.common.language.Language,
   *      ch.entwine.weblounge.common.content.image.ImageStyle)
   */
  public String getSuffix(Resource<?> resource, Language language,
      ImageStyle style) {

    // Load the resource
    ResourceContent content = resource.getContent(language);
    if (content == null) {
      content = resource.getOriginalContent();
      if (content == null) {
        logger.warn("Trying to get filename suffix for {}, which has no content", resource);
        return null;
      }
    }

    // Get the file name
    String filename = content.getFilename();
    if (StringUtils.isBlank(filename)) {
      logger.warn("Trying to get filename suffix for {}, which has no filename", resource);
      return null;
    }

    // Add the file identifier name
    if (StringUtils.isNotBlank(style.getIdentifier())) {
      filename += "-" + style.getIdentifier();
    }

    return FilenameUtils.getExtension(filename);
  }

  /**
   * {@inheritDoc}
   *
   * @see ch.entwine.weblounge.common.content.PreviewGenerator#getPriority()
   */
  public int getPriority() {
    return 0;
  }

  /**
   * Resizes the given image to what is defined by the image style and writes
   * the result to the output stream.
   *
   * @param is
   *          the input stream
   * @param os
   *          the output stream
   * @param format
   *          the image format
   * @param style
   *          the style
   * @throws IllegalArgumentException
   *           if the image is in an unsupported format
   * @throws IllegalArgumentException
   *           if the input stream is empty
   * @throws IOException
   *           if reading from or writing to the stream fails
   * @throws OutOfMemoryError
   *           if the image is too large to be processed in memory
   */
  private void style(InputStream is, OutputStream os, String format,
      ImageStyle style) throws IllegalArgumentException, IOException,
      OutOfMemoryError {

    // Does the input stream contain any data?
    if (is.available() == 0)
      throw new IllegalArgumentException("Empty input stream was passed to image styling");

    // Do we need to do any work at all?
    if (style == null || ImageScalingMode.None.equals(style.getScalingMode())) {
      logger.trace("No scaling needed, performing a noop stream copy");
      IOUtils.copy(is, os);
      return;
    }

    SeekableStream seekableInputStream = null;
    RenderedOp image = null;
    try {
      // Load the image from the given input stream
      seekableInputStream = new FileCacheSeekableStream(is);
      image = JAI.create("stream", seekableInputStream);
      if (image == null)
        throw new IOException("Error reading image from input stream");

      // Get the original image size
      int imageWidth = image.getWidth();
      int imageHeight = image.getHeight();

      // Resizing
      float scale = ImageStyleUtils.getScale(imageWidth, imageHeight, style);

      RenderingHints scaleHints = new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
      scaleHints.put(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
      scaleHints.put(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
      scaleHints.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);

      int scaledWidth = Math.round(scale * image.getWidth());
      int scaledHeight = Math.round(scale * image.getHeight());
      int cropX = 0;
      int cropY = 0;

      // If either one of scaledWidth or scaledHeight is < 1.0, then
      // the scale needs to be adapted to scale to 1.0 exactly and accomplish
      // the rest by cropping.

      if (scaledWidth < 1.0f) {
        scale = 1.0f / imageWidth;
        scaledWidth = 1;
        cropY = imageHeight - scaledHeight;
        scaledHeight = Math.round(imageHeight * scale);
      } else if (scaledHeight < 1.0f) {
        scale = 1.0f / imageHeight;
        scaledHeight = 1;
        cropX = imageWidth - scaledWidth;
        scaledWidth = Math.round(imageWidth * scale);
      }

      if (scale > 1.0) {
        ParameterBlock scaleParams = new ParameterBlock();
        scaleParams.addSource(image);
        scaleParams.add(scale).add(scale).add(0.0f).add(0.0f);
        scaleParams.add(Interpolation.getInstance(Interpolation.INTERP_BICUBIC_2));
        image = JAI.create("scale", scaleParams, scaleHints);
      } else if (scale < 1.0) {
        ParameterBlock subsampleAverageParams = new ParameterBlock();
        subsampleAverageParams.addSource(image);
        subsampleAverageParams.add(Double.valueOf(scale));
        subsampleAverageParams.add(Double.valueOf(scale));
        image = JAI.create("subsampleaverage", subsampleAverageParams, scaleHints);
      }

      // Cropping
      cropX = (int) Math.max(cropX, (float) Math.ceil(ImageStyleUtils.getCropX(scaledWidth, scaledHeight, style)));
      cropY = (int) Math.max(cropY, (float) Math.ceil(ImageStyleUtils.getCropY(scaledWidth, scaledHeight, style)));

      if ((cropX > 0 && Math.floor(cropX / 2.0f) > 0) || (cropY > 0 && Math.floor(cropY / 2.0f) > 0)) {

        ParameterBlock cropTopLeftParams = new ParameterBlock();
        cropTopLeftParams.addSource(image);
        cropTopLeftParams.add(cropX > 0 ? ((float) Math.floor(cropX / 2.0f)) : 0.0f);
        cropTopLeftParams.add(cropY > 0 ? ((float) Math.floor(cropY / 2.0f)) : 0.0f);
        cropTopLeftParams.add(scaledWidth - Math.max(cropX, 0.0f)); // width
        cropTopLeftParams.add(scaledHeight - Math.max(cropY, 0.0f)); // height

        RenderingHints croppingHints = new RenderingHints(JAI.KEY_BORDER_EXTENDER, BorderExtender.createInstance(BorderExtender.BORDER_COPY));

        image = JAI.create("crop", cropTopLeftParams, croppingHints);
      }

      // Write resized/cropped image encoded as JPEG to the output stream
      ParameterBlock encodeParams = new ParameterBlock();
      encodeParams.addSource(image);
      encodeParams.add(os);
      encodeParams.add("jpeg");
      JAI.create("encode", encodeParams);

    } catch (Throwable t) {
      if (t.getClass().getName().contains("ImageFormat")) {
        throw new IllegalArgumentException(t.getMessage());
      }
    } finally {
      IOUtils.closeQuietly(seekableInputStream);
      if (image != null)
        image.dispose();
    }
  }

}
TOP

Related Classes of ch.entwine.weblounge.preview.jai.JAIPreviewGenerator

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.