/* * JBoss, Home of Professional Open Source. * Copyright 2011, Red Hat, Inc., and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * * This 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 2.1 of * the License, or (at your option) any later version. * * This software 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 this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.jboss.capedwarf.images; import java.awt.image.BufferedImage; import java.util.Collection; import java.util.concurrent.Callable; import java.util.concurrent.Future; import com.google.appengine.api.blobstore.BlobKey; import com.google.appengine.api.files.AppEngineFile; import com.google.appengine.api.files.FileServiceFactory; import com.google.appengine.api.images.Composite; import com.google.appengine.api.images.Image; import com.google.appengine.api.images.ImagesServiceFactory; import com.google.appengine.api.images.InputSettings; import com.google.appengine.api.images.OutputSettings; import com.google.appengine.api.images.ServingUrlOptions; import com.google.appengine.api.images.Transform; import org.infinispan.AdvancedCache; import org.jboss.capedwarf.common.app.Application; import org.jboss.capedwarf.common.async.Wrappers; import org.jboss.capedwarf.common.infinispan.InfinispanUtils; import org.jboss.capedwarf.files.ExposedFileService; import org.jboss.capedwarf.images.transform.CapedwarfTransform; import org.jboss.capedwarf.images.transform.CapedwarfTransformFactory; import org.jboss.capedwarf.images.util.ImageUtils; import org.jboss.capedwarf.shared.config.CacheName; /** * @author <a href="mailto:marko.luksa@gmail.com">Marko Luksa</a> * @author <a href="mailto:ales.justin@jboss.org">Ales Justin</a> */ public class CapedwarfImagesService implements ExposedImagesService { private final AdvancedCache<ImageId, BlobKey> imageIdStore; private final AdvancedCache<BlobKey, ImageId> blobKeyStore; private ExposedFileService fileService = (ExposedFileService) FileServiceFactory.getFileService(); public CapedwarfImagesService() { String appId = Application.getAppId(); imageIdStore = InfinispanUtils.<ImageId, BlobKey>getCache(appId, CacheName.DIST).getAdvancedCache(); blobKeyStore = InfinispanUtils.<BlobKey, ImageId>getCache(appId, CacheName.DIST).getAdvancedCache(); } public Image applyTransform(Transform transform, Image image) { return applyTransform(transform, image, OutputEncoding.PNG); } public Image applyTransform(Transform transform, Image image, OutputEncoding outputEncoding) { return applyTransform(transform, image, new OutputSettings(outputEncoding)); } public Image applyTransform(Transform transform, Image image, OutputSettings outputSettings) { return applyTransform(transform, image, new InputSettings(), outputSettings); } public Image applyTransform(Transform transform, Image image, InputSettings inputSettings, OutputSettings outputSettings) { BufferedImage bufferedImage = convertToBufferedImage(image); BufferedImage transformedBufferedImage = applyTransform(transform, bufferedImage); return createImage(transformedBufferedImage, outputSettings); } private Image createImage(BufferedImage transformedBufferedImage, OutputSettings outputSettings) { byte[] transformedImageData = getByteArray(transformedBufferedImage, outputSettings); return ImagesServiceFactory.makeImage(transformedImageData); } public static BufferedImage applyTransform(Transform transform, BufferedImage bufferedImage) { CapedwarfTransform capedwarfTransform = CapedwarfTransformFactory.createJBossTransform(transform); return capedwarfTransform.applyTo(bufferedImage); } private BufferedImage convertToBufferedImage(Image image) { return ImageUtils.convertToBufferedImage(image.getImageData()); } public Future<Image> applyTransformAsync(Transform transform, Image image) { return applyTransformAsync(transform, image, OutputEncoding.PNG); } public Future<Image> applyTransformAsync(Transform transform, Image image, OutputEncoding outputEncoding) { return applyTransformAsync(transform, image, new OutputSettings(outputEncoding)); } public Future<Image> applyTransformAsync(Transform transform, Image image, OutputSettings outputSettings) { return applyTransformAsync(transform, image, new InputSettings(), outputSettings); } public Future<Image> applyTransformAsync(final Transform transform, final Image image, final InputSettings inputSettings, final OutputSettings outputSettings) { return Wrappers.future(new Callable<Image>() { public Image call() throws Exception { return applyTransform(transform, image, inputSettings, outputSettings); } }); } public Image composite(Collection<Composite> composites, int width, int height, long color) { return composite(composites, width, height, color, OutputEncoding.PNG); } public Image composite(Collection<Composite> composites, int width, int height, long color, OutputEncoding outputEncoding) { return composite(composites, width, height, color, new OutputSettings(outputEncoding)); } public Image composite(Collection<Composite> composites, int width, int height, long color, OutputSettings outputSettings) { CompositeImageBuilder compositeImageBuilder = new CompositeImageBuilder(composites, width, height, color); BufferedImage image = compositeImageBuilder.createBufferedImage(); return createImage(image, outputSettings); } public int[][] histogram(Image image) { return ImageUtils.histogram(convertToBufferedImage(image)); } public String getServingUrl(ServingUrlOptions options) { ServingUrlOptionsHelper helper = new ServingUrlOptionsHelper(options); return getServingUrl( helper.getBlobKey(), helper.hasImageSize() ? helper.getImageSize() : -1, helper.hasCrop() && helper.getCrop(), helper.hasSecureUrl() && helper.getSecureUrl()); } public String getServingUrl(BlobKey blobKey) { return getServingUrl(blobKey, false); } public String getServingUrl(BlobKey blobKey, boolean secureUrl) { return getServingUrl(blobKey, -1, false, secureUrl); } public String getServingUrl(BlobKey blobKey, int imageSize, boolean crop) { return getServingUrl(blobKey, imageSize, crop, false); } public String getServingUrl(BlobKey blobKey, int imageSize, boolean crop, boolean secureUrl) { if (blobKey == null) { throw new IllegalArgumentException("Null blob key!"); } ImageId imageId = getImageId(blobKey); if (imageId == null) { AppEngineFile file = fileService.getBlobFile(blobKey); if (!fileService.exists(file)) { throw new IllegalArgumentException("Could not read blob"); } imageId = ImageId.newRandomImageId(); imageIdStore.put(imageId, blobKey); blobKeyStore.put(blobKey, imageId); } return ImageServlet.getServingUrl(imageId, imageSize, crop, secureUrl); } public void deleteServingUrl(BlobKey blobKey) { ImageId imageId = blobKeyStore.remove(blobKey); if (imageId != null) { imageIdStore.remove(imageId); } } private byte[] getByteArray(BufferedImage bufferedImage, OutputSettings outputSettings) { String formatName = getFormatName(outputSettings.getOutputEncoding()); return ImageUtils.getByteArray(bufferedImage, formatName); } private String getFormatName(OutputEncoding outputEncoding) { switch (outputEncoding) { case PNG: return "PNG"; case JPEG: return "JPG"; case WEBP: return "WEBP"; default: throw new IllegalArgumentException("Unsupported OutputEncoding " + outputEncoding); } } @Override public BlobKey getBlobKey(ImageId imageId) { return imageIdStore.get(imageId); } @Override public ImageId getImageId(BlobKey blobKey) { return blobKeyStore.get(blobKey); } }