/** * Copyright © 2002 Instituto Superior Técnico * * This file is part of FenixEdu Academic. * * FenixEdu Academic 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 3 of the License, or * (at your option) any later version. * * FenixEdu Academic 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 FenixEdu Academic. If not, see <http://www.gnu.org/licenses/>. */ package org.fenixedu.academic.domain.photograph; import java.awt.Color; import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import javax.imageio.ImageIO; import org.fenixedu.academic.domain.exceptions.DomainException; import org.fenixedu.academic.util.ContentType; import org.imgscalr.Scalr; import org.imgscalr.Scalr.Method; import org.imgscalr.Scalr.Mode; public abstract class Picture extends Picture_Base { public Picture() { super(); } public void delete() { super.deleteDomainObject(); } public byte[] getBytes() { return getPictureData(); } public void setupPictureMetadata(byte[] pictureData) { BufferedImage buffer = Picture.readImage(pictureData); setWidth(buffer.getWidth()); setHeight(buffer.getHeight()); } static public BufferedImage readImage(byte[] imageData) { ByteArrayInputStream bais = new ByteArrayInputStream(imageData); try { return ImageIO.read(bais); } catch (IOException ioe) { throw new DomainException("error.photograph.imageio.failedReadingImageFromByteArray", ioe); } } static public byte[] writeImageAsBytes(BufferedImage image, ContentType fileFormat) { ByteArrayOutputStream out = new ByteArrayOutputStream(); try { ImageIO.write(image, fileFormat.getFileExtention(), out); return out.toByteArray(); } catch (IOException ioe) { throw new DomainException("error.photograph.imageio.failedWritingImageToByteArray", ioe); } } static public byte[] writeImage(BufferedImage image, ContentType fileFormat) { return writeImageAsBytes(image, fileFormat); } /** * Executes an {@link AspectRatio} transformation by fitting the image to the new aspect ratio. * Note that it uses an RGBA color space making the resulting image not suitable to be rendered * as a JPEG. Before rendering as JPEG apply a filler on the background. * * @param source * @param xRatio * @param yRatio * @return {@link BufferedImage} */ static public BufferedImage transformFit(BufferedImage source, int xRatio, int yRatio) { int destW, destH; BufferedImage scaled, padded, finale; if ((1.0 * source.getWidth() / source.getHeight()) < (1.0 * xRatio / yRatio)) { destH = source.getHeight(); destW = (int) Math.round((destH * xRatio * 1.0) / (yRatio * 1.0)); scaled = Scalr.resize(source, Method.QUALITY, Mode.FIT_TO_HEIGHT, destW, destH); int padding = (int) Math.round((destW - source.getWidth()) / 2.0); padded = (padding != 0) ? Scalr.pad(scaled, padding, new Color(255, 255, 255, 0)) : scaled; finale = Scalr.crop(padded, 0, padding, destW, destH); } else { destW = source.getWidth(); destH = (int) Math.round((destW * yRatio * 1.0) / (xRatio * 1.0)); scaled = Scalr.resize(source, Method.QUALITY, Mode.FIT_TO_WIDTH, destW, destH); int padding = (int) Math.round((destH - source.getHeight()) / 2.0); padded = (padding != 0) ? Scalr.pad(scaled, padding, new Color(255, 255, 255, 0)) : scaled; //Scalr.pad() instead of ignoring padding = 0, it throws an Exception finale = Scalr.crop(padded, padding, 0, destW, destH); } return finale; } /** * Executes an {@link AspectRatio} transformation by zooming the image into the new aspect ratio. * Note that it uses an RGBA color space making the resulting image not suitable to be rendered * as a JPEG. Before rendering as JPEG apply a filler on the background. * * @param source * @param xRatio * @param yRatio * @return {@link BufferedImage} */ static public BufferedImage transformZoom(BufferedImage source, int xRatio, int yRatio) { int destW, destH; BufferedImage scaled, finale; if ((1.0 * source.getWidth() / source.getHeight()) > (1.0 * xRatio / yRatio)) { destH = source.getHeight(); destW = (int) Math.round((destH * xRatio * 1.0) / (yRatio * 1.0)); //scaled = Scalr.resize(source, Method.QUALITY, Mode.FIT_TO_WIDTH, destW, destH); int padding = (int) Math.round((source.getWidth() - destW) / 2.0); finale = Scalr.crop(source, padding, 0, destW, destH); } else { destW = source.getWidth(); destH = (int) Math.round((destW * yRatio * 1.0) / (xRatio * 1.0)); //scaled = Scalr.resize(source, Method.QUALITY, Mode.FIT_TO_HEIGHT, destW, destH); int padding = (int) Math.round((source.getHeight() - destH) / 2.0); finale = Scalr.crop(source, 0, padding, destW, destH); } return finale; } static public BufferedImage transform(BufferedImage source, AspectRatio aspectRatio, PictureMode pictureMode) { switch (pictureMode) { case FIT: return Picture.transformFit(source, aspectRatio.getXRatio(), aspectRatio.getYRatio()); case ZOOM: return Picture.transformZoom(source, aspectRatio.getXRatio(), aspectRatio.getYRatio()); default: return Picture.transformFit(source, aspectRatio.getXRatio(), aspectRatio.getYRatio()); } } static public BufferedImage fitTo(BufferedImage source, int width, int height) { Mode mode; if (source.getHeight() > source.getWidth()) { mode = Mode.FIT_TO_HEIGHT; } else { mode = Mode.FIT_TO_WIDTH; } return Scalr.resize(source, Method.QUALITY, mode, width, height); } static public BufferedImage fitTo(BufferedImage source, PictureSize pictureSize) { return Picture.fitTo(source, pictureSize.getWidth(), pictureSize.getHeight()); } }