package io.lumify.core.model.artifactThumbnails;
import com.altamiracorp.bigtable.model.ModelSession;
import com.altamiracorp.bigtable.model.Repository;
import com.altamiracorp.bigtable.model.Row;
import io.lumify.core.exception.LumifyResourceNotFoundException;
import io.lumify.core.model.ontology.OntologyRepository;
import io.lumify.core.model.properties.types.BooleanLumifyProperty;
import io.lumify.core.model.properties.types.IntegerLumifyProperty;
import io.lumify.core.user.User;
import io.lumify.core.util.LumifyLogger;
import io.lumify.core.util.LumifyLoggerFactory;
import org.securegraph.Vertex;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import static com.google.common.base.Preconditions.checkNotNull;
public abstract class ArtifactThumbnailRepository extends Repository<BigTableArtifactThumbnail> {
private static final LumifyLogger LOGGER = LumifyLoggerFactory.getLogger(ArtifactThumbnailRepository.class);
public static int FRAMES_PER_PREVIEW = 20;
public static int PREVIEW_FRAME_WIDTH = 360;
public static int PREVIEW_FRAME_HEIGHT = 240;
private BooleanLumifyProperty yAxisFlippedProperty;
private IntegerLumifyProperty clockwiseRotationProperty;
public ArtifactThumbnailRepository(ModelSession modelSession, final OntologyRepository ontologyRepository) {
super(modelSession);
String yAxisFlippedPropertyIri = ontologyRepository.getPropertyIRIByIntent("media.yAxisFlipped");
if (yAxisFlippedPropertyIri != null) {
this.yAxisFlippedProperty = new BooleanLumifyProperty(yAxisFlippedPropertyIri);
}
String clockwiseRotationPropertyIri = ontologyRepository.getPropertyIRIByIntent("media.clockwiseRotation");
if (clockwiseRotationPropertyIri != null) {
this.clockwiseRotationProperty = new IntegerLumifyProperty(clockwiseRotationPropertyIri);
}
}
public abstract BigTableArtifactThumbnail fromRow(Row row);
public abstract Row toRow(BigTableArtifactThumbnail artifactThumbnail);
public abstract String getTableName();
public abstract ArtifactThumbnail getThumbnail(Object artifactVertexId, String thumbnailType, int width, int height, User user);
public abstract byte[] getThumbnailData(Object artifactVertexId, String thumbnailType, int width, int height, User user);
public abstract ArtifactThumbnail createThumbnail(Vertex artifactVertex, String thumbnailType, InputStream in, int[] boundaryDims, User user) throws IOException;
public ArtifactThumbnail generateThumbnail(Vertex artifactVertex, InputStream in, int[] boundaryDims) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
String format;
int type;
try {
BufferedImage originalImage = ImageIO.read(in);
checkNotNull(originalImage, "Could not generateThumbnail: read original image for artifact " + artifactVertex.getId());
type = ImageUtils.thumbnailType(originalImage);
format = ImageUtils.thumbnailFormat(originalImage);
BufferedImage transformedImage = getTransformedImage(originalImage, artifactVertex);
//Get new image dimensions, which will be used for the icon.
int[] transformedImageDims = new int[]{transformedImage.getWidth(), transformedImage.getHeight()};
int[] newImageDims = getScaledDimension(transformedImageDims, boundaryDims);
if (newImageDims[0] >= transformedImageDims[0] || newImageDims[1] >= transformedImageDims[1]) {
LOGGER.info("Original image dimensions %d x %d are smaller "
+ "than requested dimensions %d x %d returning original.",
transformedImageDims[0], transformedImageDims[1],
newImageDims[0], newImageDims[1]);
}
//Resize the image.
BufferedImage resizedImage = new BufferedImage(newImageDims[0], newImageDims[1], type);
Graphics2D g = resizedImage.createGraphics();
if (transformedImage.getColorModel().getNumComponents() > 3) {
g.drawImage(transformedImage, 0, 0, resizedImage.getWidth(), resizedImage.getHeight(), null);
} else {
g.drawImage(transformedImage, 0, 0, resizedImage.getWidth(), resizedImage.getHeight(), Color.BLACK, null);
}
g.dispose();
//Write the bufferedImage to a file.
ImageIO.write(resizedImage, format, out);
} catch (IOException e) {
throw new LumifyResourceNotFoundException("Error reading inputstream");
}
return new ArtifactThumbnail(out.toByteArray(), type, format);
}
public BufferedImage getTransformedImage(BufferedImage originalImage, Vertex artifactVertex) {
int cwRotationNeeded = 0;
if (clockwiseRotationProperty != null) {
Integer nullable = clockwiseRotationProperty.getPropertyValue(artifactVertex);
if (nullable != null) {
cwRotationNeeded = nullable;
}
}
boolean yAxisFlipNeeded = false;
if (yAxisFlippedProperty != null) {
Boolean nullable = yAxisFlippedProperty.getPropertyValue(artifactVertex);
if (nullable != null) {
yAxisFlipNeeded = nullable;
}
}
//Rotate and flip image.
return ImageUtils.reOrientImage(originalImage, yAxisFlipNeeded, cwRotationNeeded);
}
public int[] getScaledDimension(int[] imgSize, int[] boundary) {
int originalWidth = imgSize[0];
int originalHeight = imgSize[1];
int boundWidth = boundary[0];
int boundHeight = boundary[1];
int newWidth = originalWidth;
int newHeight = originalHeight;
if (originalWidth > boundWidth) {
newWidth = boundWidth;
newHeight = (newWidth * originalHeight) / originalWidth;
}
if (newHeight > boundHeight) {
newHeight = boundHeight;
newWidth = (newHeight * originalWidth) / originalHeight;
}
return new int[]{newWidth, newHeight};
}
}