001    /*
002     * Apache License
003     * Version 2.0, January 2004
004     * http://www.apache.org/licenses/
005     *
006     * Copyright 2008-2010 by chenillekit.org
007     *
008     * Licensed under the Apache License, Version 2.0 (the "License");
009     * you may not use this file except in compliance with the License.
010     * You may obtain a copy of the License at
011     *
012     * http://www.apache.org/licenses/LICENSE-2.0
013     */
014    
015    package org.chenillekit.tapestry.core.services.impl;
016    
017    import java.awt.image.BufferedImage;
018    import java.io.File;
019    import java.io.FileNotFoundException;
020    import java.io.FileOutputStream;
021    import java.io.IOException;
022    import java.util.zip.CRC32;
023    import java.util.zip.Checksum;
024    
025    import org.apache.tapestry5.Asset;
026    import org.apache.tapestry5.internal.services.ContextResource;
027    import org.apache.tapestry5.ioc.Resource;
028    import org.apache.tapestry5.ioc.internal.util.InternalUtils;
029    import org.apache.tapestry5.services.AssetFactory;
030    import org.apache.tapestry5.services.Context;
031    
032    import org.chenillekit.image.services.ImageService;
033    import org.chenillekit.tapestry.core.ChenilleKitCoreConstants;
034    import org.chenillekit.tapestry.core.services.ThumbNailService;
035    import org.slf4j.Logger;
036    
037    /**
038     * @version $Id: ThumbNailServiceImpl.java 726 2010-11-03 19:42:33Z homburgs $
039     */
040    public class ThumbNailServiceImpl implements ThumbNailService
041    {
042        private Logger logger;
043        private ImageService imageService;
044        private File thumbnailDirectory;
045        private Context context;
046        private AssetFactory assetFactory;
047    
048        public ThumbNailServiceImpl(Logger logger, ImageService imageService, Context context, AssetFactory assetFactory)
049        {
050            this.logger = logger;
051            this.imageService = imageService;
052            this.context = context;
053            this.assetFactory = assetFactory;
054    
055            thumbnailDirectory = context.getRealFile(ChenilleKitCoreConstants.__THUMBNAL_DIRECTORY__);
056            if (!thumbnailDirectory.exists())
057                throw new RuntimeException("path: '" + thumbnailDirectory.getAbsolutePath() + "' not found.");
058    
059            if (this.logger.isDebugEnabled())
060                this.logger.debug("thumbnail location: {}", thumbnailDirectory.getPath());
061        }
062    
063        /**
064         * converts the original image <em>originalAsset</em> to a thumbnail
065         *
066         * @param originalAsset the original image
067         * @param height        scale down to <em>height</em>
068         * @param quality       reduce to the given image quality
069         *
070         * @return the thumbnail of the original image
071         */
072        public Asset convertToThumbnail(Asset originalAsset, int height, float quality)
073        {
074            Asset thumbnailAsset;
075            FileOutputStream output = null;
076            String thumbnailFileName = String.valueOf(buildChecksumFromURI(originalAsset.toClientURL(), height, quality).getValue());
077    
078            try
079            {
080                if (logger.isDebugEnabled())
081                    logger.debug("original image: {}", originalAsset.toClientURL());
082    
083                File outputFile = new File(thumbnailDirectory.getAbsolutePath() + "/" + thumbnailFileName);
084                if (!outputFile.exists())
085                {
086                    output = new FileOutputStream(outputFile, false);
087                    BufferedImage bufferedImage = imageService.scaleImage(originalAsset.getResource(), height);
088                    imageService.reduceImageQuality(bufferedImage, quality, output);
089                    output.flush();
090                }
091                else
092                {
093                    if (logger.isDebugEnabled())
094                        logger.debug("cached thumbnail '{}'", outputFile.toURI().toASCIIString());
095                }
096    
097                Resource thumbRes = new ContextResource(context, ChenilleKitCoreConstants.__THUMBNAL_DIRECTORY__ + "/" + thumbnailFileName);
098    
099                if (logger.isDebugEnabled())
100                    logger.debug("thumbnailed image: {}", thumbRes.toURL().toExternalForm());
101    
102                return assetFactory.createAsset(thumbRes);
103            }
104            catch (FileNotFoundException e)
105            {
106                throw new RuntimeException(e);
107            }
108            catch (IOException e)
109            {
110                throw new RuntimeException(e);
111            }
112            finally
113            {
114                if (output != null)
115                    InternalUtils.close(output);
116            }
117        }
118    
119        /**
120         * get the path where generated thumbnail should stored.
121         *
122         * @return thumbnail path
123         */
124        public String getThumbnailPath()
125        {
126            return thumbnailDirectory.getAbsolutePath();
127        }
128    
129        /**
130         * computes the crc32 checksum from the original asset client url.
131         *
132         * @param clientURL the original asset client url
133         * @param height    the height of the image
134         * @param quality   the quality of the image
135         *
136         * @return the computed checksum
137         */
138        private Checksum buildChecksumFromURI(String clientURL, int height, float quality)
139        {
140            CRC32 checksum = new CRC32();
141            checksum.update(String.format("%s_%d_%f", clientURL, height, quality).getBytes());
142            return checksum;
143        }
144    }