Package org.structr.web.common

Source Code of org.structr.web.common.ImageHelper$Thumbnail

/**
* Copyright (C) 2010-2014 Morgner UG (haftungsbeschränkt)
*
* This file is part of Structr <http://structr.org>.
*
* Structr 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.
*
* Structr 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 Structr.  If not, see <http://www.gnu.org/licenses/>.
*/
package org.structr.web.common;

import com.mortennobel.imagescaling.ResampleOp;
import org.apache.commons.io.output.ByteArrayOutputStream;
import org.apache.commons.lang3.StringUtils;
import org.structr.common.error.FrameworkException;
import org.structr.web.entity.Image;
import org.structr.util.Base64;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import org.apache.commons.io.IOUtils;
import org.structr.common.SecurityContext;
import org.structr.core.app.StructrApp;
import org.structr.core.entity.AbstractNode;
import org.structr.core.property.PropertyMap;
import static org.structr.web.common.FileHelper.setFileData;

/**
*
* @author Axel Morgner
*/

import org.structr.dynamic.File;

public abstract class ImageHelper extends FileHelper {

  private static final Logger logger = Logger.getLogger(ImageHelper.class.getName());
  //private static Thumbnail tn        = new Thumbnail();

  //~--- methods --------------------------------------------------------

  /**
   * Create a new image node from the given image data
   *
   * @param securityContext
   * @param imageStream
   * @param contentType
   * @param imageType defaults to Image.class if null
   * @param name
   * @param markAsThumbnail
   * @return image
   * @throws FrameworkException
   * @throws IOException
   */
  public static Image createImage(final SecurityContext securityContext, final InputStream imageStream, final String contentType, final Class<? extends Image> imageType, final String name, final boolean markAsThumbnail)
    throws FrameworkException, IOException {

    return createImage(securityContext, IOUtils.toByteArray(imageStream), contentType, imageType, name, markAsThumbnail);

  }

  /**
   * Create a new image node from the given image data
   *
   * @param securityContext
   * @param imageData
   * @param contentType
   * @param imageType defaults to Image.class if null
   * @param name
   * @param markAsThumbnail
   * @return image
   * @throws FrameworkException
   * @throws IOException
   */
  public static Image createImage(final SecurityContext securityContext, final byte[] imageData, final String contentType, final Class<? extends Image> imageType, final String name, final boolean markAsThumbnail)
    throws FrameworkException, IOException {

    PropertyMap props                          = new PropertyMap();

    props.put(AbstractNode.type, imageType == null ? Image.class.getSimpleName() : imageType.getSimpleName());
    props.put(Image.isThumbnail, markAsThumbnail);
    props.put(AbstractNode.name, name);

    Image newImage = StructrApp.getInstance(securityContext).create(imageType, props);

    if (imageData != null && imageData.length > 0) {

      setFileData(newImage, imageData, contentType);

    }

    return newImage;

  }

  /**
   * Write image data to the given image node and set checksum and size.
   *
   * @param img
   * @param imageData
   * @param contentType
   * @throws FrameworkException
   * @throws IOException
   */
  public static void setImageData(final Image img, final byte[] imageData, final String contentType)
    throws FrameworkException, IOException {

    setFileData(img, imageData, contentType);

  }

  public static Thumbnail createThumbnail(final Image originalImage, final int maxWidth, final int maxHeight) {

    return createThumbnail(originalImage, maxWidth, maxHeight, false);

  }

  public static Thumbnail createThumbnail(final Image originalImage, final int maxWidth, final int maxHeight, final boolean crop) {

    // String contentType = (String) originalImage.getProperty(Image.CONTENT_TYPE_KEY);
    ByteArrayOutputStream baos = new ByteArrayOutputStream();

    Thumbnail tn        = new Thumbnail();

    try {

      // read image
      long start           = System.nanoTime();
      InputStream in       = originalImage.getInputStream();

      if (in == null) {
        logger.log(Level.FINE, "InputStream of original image {0} ({1}) is null", new Object[] { originalImage.getName(), originalImage.getId() });
        return null;
      }

      BufferedImage source = null;

      try {

        source = ImageIO.read(in);

      } catch (IOException t) {

        logger.log(Level.WARNING, "Could not read original image {0} ({1})", new Object[] { originalImage.getName(), originalImage.getId() });
        return null;

      } finally {
        if (in != null) {
          in.close();
        }
      }

      if (source != null) {

        int sourceWidth  = source.getWidth();
        int sourceHeight = source.getHeight();

        // Update image dimensions
        originalImage.setProperty(Image.width, sourceWidth);
        originalImage.setProperty(Image.height, sourceHeight);

        // float aspectRatio = sourceWidth/sourceHeight;
        float scaleX = 1.0f * sourceWidth / maxWidth;
        float scaleY = 1.0f * sourceHeight / maxHeight;
        float scale;

        if (crop) {

          scale = Math.min(scaleX, scaleY);
        } else {

          scale = Math.max(scaleX, scaleY);
        }

//                              System.out.println("Source (w,h): " + sourceWidth + ", " + sourceHeight + ", Scale (x,y,res): " + scaleX + ", " + scaleY + ", " + scale);
        // Don't scale up
        if (scale > 1.0000f) {

          int destWidth  = Math.max(3, Math.round(sourceWidth / scale));
          int destHeight = Math.max(3, Math.round(sourceHeight / scale));

//                                      System.out.println("Dest (w,h): " + destWidth + ", " + destHeight);
          ResampleOp resampleOp = new ResampleOp(destWidth, destHeight);

          // resampleOp.setUnsharpenMask(AdvancedResizeOp.UnsharpenMask.Soft);
          BufferedImage resampled = resampleOp.filter(source, null);
          BufferedImage result    = null;

          if (crop) {

            int offsetX = Math.abs(maxWidth - destWidth) / 2;
            int offsetY = Math.abs(maxHeight - destHeight) / 2;

            logger.log(Level.FINE, "Offset and Size (x,y,w,h): {0},{1},{2},{3}", new Object[] { offsetX, offsetY, maxWidth, maxHeight });

            result = resampled.getSubimage(offsetX, offsetY, maxWidth, maxHeight);

            tn.setWidth(maxWidth);
            tn.setHeight(maxHeight);

          } else {

            result = resampled;

            tn.setWidth(destWidth);
            tn.setHeight(destHeight);

          }

          ImageIO.write(result, Thumbnail.FORMAT, baos);

        } else {

          // Thumbnail is source image
          ImageIO.write(source, Thumbnail.FORMAT, baos);
          tn.setWidth(sourceWidth);
          tn.setHeight(sourceHeight);
        }

      } else {

        logger.log(Level.FINE, "Thumbnail could not be created");
        return null;
      }

      long end  = System.nanoTime();
      long time = (end - start) / 1000000;

      logger.log(Level.FINE, "Thumbnail created. Reading, scaling and writing took {0} ms", time);
      tn.setBytes(baos.toByteArray());

      return tn;
    } catch (IOException | FrameworkException t) {

      logger.log(Level.SEVERE, "Error creating thumbnail", t);

    } finally {

      try {

        if (baos != null) {

          baos.close();
        }

      } catch (Exception ignore) {}

    }

    return null;
  }

  /**
   * Let ImageIO read and write a JPEG image. This should normalize all types of weird
   * image sub formats, e.g. when extracting images from a flash file.
   *
   * Some images can not be read by ImageIO (or the browser) because they
   * have an JPEG EOI and SOI marker at the beginning of the file.
   *
   * This method detects and removes the bytes, so that the image
   * can be read again.
   *
   * @param original
   * @return normalized image
   */
  public static byte[] normalizeJpegImage(final byte[] original) {

    if (original == null) {

      return new byte[] {};
    }

    ByteArrayInputStream in = new ByteArrayInputStream(original);

    // If JPEG image starts with ff d9 ffd8, strip this sequence from the beginning
    // FF D9 = EOI (end of image)
    // FF D8 = SOI (start of image)
    if ((original[0] == (byte) 0xff) && (original[1] == (byte) 0xd9) && (original[2] == (byte) 0xff) && (original[3] == (byte) 0xd8)) {

      in.skip(4);
    }

    ByteArrayOutputStream out = new ByteArrayOutputStream();
    BufferedImage source;

    try {

      source = ImageIO.read(in);

      // If ImageIO cannot read it, return original
      if (source == null) {

        return original;
      }

      ImageIO.write(source, "jpeg", out);

    } catch (IOException ex) {

      logger.log(Level.SEVERE, null, ex);

      if (in != null) {

        try {

          in.close();

        } catch (IOException ignore) {}

      }

    } finally {}

    return out.toByteArray();

  }

  //~--- get methods ----------------------------------------------------

  public static String getBase64String(final File file) {

    try {
         InputStream dataStream = file.getInputStream();

         if (dataStream != null)
         return Base64.encodeToString(IOUtils.toByteArray(file.getInputStream()), false);

    } catch (IOException ex) {
      logger.log(Level.SEVERE, "Could not get base64 string from file ", ex);
    }

    return null;
  }

  /**
   * Check if url points to an image by extension
   *
   * TODO: Improve method to check file type by peeping at the
   * content
   *
   * @param urlString
   * @return true if is of image type
   */
  public static boolean isImageType(final String urlString) {

    if ((urlString == null) || StringUtils.isBlank(urlString)) {

      return false;
    }

    String extension         = urlString.toLowerCase().substring(urlString.lastIndexOf(".") + 1);
    String[] imageExtensions = {

      "png", "gif", "jpg", "jpeg", "bmp", "tif", "tiff"
    };

    for (String ext : imageExtensions) {

      if (ext.equals(extension)) {

        return true;
      }

    }

    return false;

  }

  /**
   * Check if url points to an Flash object by extension
   *
   * TODO: Improve method to check file type by peeping at the
   * content
   *
   * @param urlString
   * @return true if is swf file
   */
  public static boolean isSwfType(final String urlString) {

    if ((urlString == null) || StringUtils.isBlank(urlString)) {

      return false;
    }

    String extension         = urlString.toLowerCase().substring(urlString.lastIndexOf(".") + 1);
    String[] imageExtensions = { "swf" };

    for (String ext : imageExtensions) {

      if (ext.equals(extension)) {

        return true;
      }

    }

    return false;

  }

  //~--- inner classes --------------------------------------------------

  public static class Base64URIData {

    private String contentType;
    private String data;

    //~--- constructors -------------------------------------------

    public Base64URIData(final String rawData) {

      String[] parts = StringUtils.split(rawData, ",");

      data        = parts[1];
      contentType = StringUtils.substringBetween(parts[0], "data:", ";base64");

    }

    //~--- get methods --------------------------------------------

    public String getContentType() {

      return contentType;

    }

    public String getData() {

      return data;

    }

    public byte[] getBinaryData() {

      return Base64.decode(data);

    }

  }


  public static class Thumbnail {

    public static final String FORMAT = "png";

    //~--- fields -------------------------------------------------

    private byte[] bytes;
    private int height;
    private int width;

    //~--- constructors -------------------------------------------

    public Thumbnail() {}

    public Thumbnail(final byte[] bytes) {

      this.bytes = bytes;

    }

    public Thumbnail(final int width, final int height) {

      this.width  = width;
      this.height = height;

    }

    public Thumbnail(final byte[] bytes, final int width, final int height) {

      this.bytes  = bytes;
      this.width  = width;
      this.height = height;

    }

    //~--- get methods --------------------------------------------

    public byte[] getBytes() {

      return bytes;

    }

    public int getWidth() {

      return width;

    }

    public int getHeight() {

      return height;

    }

    //~--- set methods --------------------------------------------

    public void setBytes(final byte[] bytes) {

      this.bytes = bytes;

    }

    public void setWidth(final int width) {

      this.width = width;

    }

    public void setHeight(final int height) {

      this.height = height;

    }

  }

}
TOP

Related Classes of org.structr.web.common.ImageHelper$Thumbnail

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.