
org.structr.web.common.ImageHelper Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of structr-ui Show documentation
Show all versions of structr-ui Show documentation
Structr is an open source framework based on the popular Neo4j graph database.
The newest version!
/**
* Copyright (C) 2010-2016 Structr GmbH
*
* This file is part of Structr .
*
* 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 Affero 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 .
*/
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;
/**
*
*
*/
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 {
final 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);
final 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);
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
final Thumbnail tn = new Thumbnail();
try (final 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;
}
final long start = System.nanoTime();
final BufferedImage source = ImageIO.read(in);
if (source != null) {
final int sourceWidth = source.getWidth();
final int sourceHeight = source.getHeight();
// Update image dimensions
originalImage.setProperty(Image.width, sourceWidth);
originalImage.setProperty(Image.height, sourceHeight);
// float aspectRatio = sourceWidth/sourceHeight;
final float scaleX = 1.0f * sourceWidth / maxWidth;
final float scaleY = 1.0f * sourceHeight / maxHeight;
final float scale;
if (crop) {
scale = Math.min(scaleX, scaleY);
} else {
scale = Math.max(scaleX, scaleY);
}
// Don't scale up
if (scale > 1.0) {
final int destWidth = Math.max(4, Math.round(sourceWidth / scale));
final int destHeight = Math.max(4, Math.round(sourceHeight / scale));
//System.out.println(destWidth + " / " + destHeight);
final ResampleOp resampleOp = new ResampleOp(destWidth, destHeight);
final BufferedImage resampled = resampleOp.filter(source, null);
BufferedImage result = null;
if (crop) {
final int offsetX = Math.abs(maxWidth - destWidth) / 2;
final 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;
}
final long end = System.nanoTime();
final 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 (Throwable t) {
logger.log(Level.WARNING, "Unable to create thumbnail for image with ID {0}.", originalImage.getUuid());
}
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[] {};
}
final 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);
}
final 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 {
final 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;
}
final String extension = urlString.toLowerCase().substring(urlString.lastIndexOf(".") + 1);
final 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;
}
final String extension = urlString.toLowerCase().substring(urlString.lastIndexOf(".") + 1);
final 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) {
final 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;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy