package alien4cloud.images; import java.awt.image.BufferedImage; import java.beans.IntrospectionException; import java.io.ByteArrayInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.UUID; import javax.annotation.PostConstruct; import javax.annotation.Resource; import javax.imageio.ImageIO; import lombok.extern.slf4j.Slf4j; import org.elasticsearch.mapping.MappingBuilder; import org.springframework.beans.factory.annotation.Required; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import alien4cloud.dao.ESGenericIdDAO; import alien4cloud.exception.IndexingServiceException; import alien4cloud.exception.NotFoundException; import alien4cloud.images.exception.ImageUploadException; import alien4cloud.utils.ImageQuality; import alien4cloud.utils.ImageResizeUtil; /** * A dao to store/load images. */ @Slf4j @Component("image-dao") public class ImageDAO extends ESGenericIdDAO implements IImageDAO { @Resource private MappingBuilder mappingBuilder; private Path rootPath; @Required @Value("${directories.alien}/${directories.images}") public void setRootPath(String path) throws IOException { this.rootPath = Paths.get(path).toAbsolutePath(); if (!Files.exists(rootPath)) { Files.createDirectories(rootPath); } } @PostConstruct public void initEnvironment() { // init ES annotation scanning try { mappingBuilder.initialize(ImageData.class.getPackage().getName()); } catch (IntrospectionException | IOException e) { throw new IndexingServiceException("Could not initialize elastic search mapping builder", e); } // init indexes and mapped classes initIndices(ImageData.class.getSimpleName().toLowerCase(), null, ImageData.class); initCompleted(); } @Override public String writeImage(byte[] imageBytes) { String iconId = UUID.randomUUID().toString(); ImageData imageData = new ImageData(); imageData.setData(imageBytes); imageData.setId(iconId); writeImage(imageData); return iconId; } @Override public void writeImage(final ImageData imageData) { // resize the image to store the different available qualities. InputStream is = new ByteArrayInputStream(imageData.getData()); try { BufferedImage original = ImageIO.read(is); if (original == null) { throw new ImageUploadException("The image is not valid and cannot be read"); } resizeAndWrite(getImageId(ImageQuality.QUALITY_16, imageData.getId()), original, ImageQuality.QUALITY_16.getSize()); resizeAndWrite(getImageId(ImageQuality.QUALITY_32, imageData.getId()), original, ImageQuality.QUALITY_32.getSize()); resizeAndWrite(getImageId(ImageQuality.QUALITY_64, imageData.getId()), original, ImageQuality.QUALITY_64.getSize()); resizeAndWrite(getImageId(ImageQuality.QUALITY_128, imageData.getId()), original, ImageQuality.QUALITY_128.getSize()); // resizeAndWrite(getImageId(ImageQuality.QUALITY_512, imageData.getId()), original, ImageQuality.QUALITY_512.getSize()); saveAsPng(imageData.getId(), original); } catch (IOException e) { throw new ImageUploadException("Unable to write uploaded image to data source", e); } } private void resizeAndWrite(final String imageId, final BufferedImage original, final int size) throws IOException { BufferedImage target = ImageResizeUtil.resizeImageWithHint(original, size, size, true); saveAsPng(imageId, target); } private void saveAsPng(String imageId, BufferedImage target) throws IOException { FileOutputStream fos = new FileOutputStream(rootPath.resolve(imageId + ".png").toFile()); try { ImageIO.write(target, "png", fos); fos.flush(); } finally { fos.close(); } // save in elastic search ImageData imageData = new ImageData(); imageData.setId(imageId); imageData.setMime("image/png"); this.save(imageData); } @Override public ImageData readImage(final String id, ImageQuality imageQuality) { ImageData imageData = findById(ImageData.class, getImageId(imageQuality, id)); if (imageData == null) { throw new NotFoundException("Unable to find image."); } if (imageData.getData() == null) { try { imageData.setData(Files.readAllBytes(rootPath.resolve(imageData.getId() + ".png"))); } catch (IOException e) { throw new NotFoundException("Unable to find image on disk."); } } return imageData; } @Override public void delete(String id) { delete(ImageData.class, id); } private String getImageId(final ImageQuality imageQuality, final String id) { switch (imageQuality) { case QUALITY_16: return imageQuality.name() + id; case QUALITY_32: return imageQuality.name() + id; case QUALITY_64: return imageQuality.name() + id; case QUALITY_128: return imageQuality.name() + id; case QUALITY_512: return imageQuality.name() + id; default: return id; } } }