001/*
002 *  Copyright 2016 Anyware Services
003 *
004 *  Licensed under the Apache License, Version 2.0 (the "License");
005 *  you may not use this file except in compliance with the License.
006 *  You may obtain a copy of the License at
007 *
008 *      http://www.apache.org/licenses/LICENSE-2.0
009 *
010 *  Unless required by applicable law or agreed to in writing, software
011 *  distributed under the License is distributed on an "AS IS" BASIS,
012 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *  See the License for the specific language governing permissions and
014 *  limitations under the License.
015 */
016package org.ametys.core.resources;
017
018import java.io.IOException;
019import java.io.InputStream;
020import java.io.OutputStream;
021import java.io.Serializable;
022import java.util.Arrays;
023import java.util.Collection;
024import java.util.Map;
025import java.util.regex.Matcher;
026import java.util.regex.Pattern;
027
028import org.apache.avalon.framework.component.Component;
029import org.apache.avalon.framework.parameters.Parameters;
030import org.apache.cocoon.ProcessingException;
031import org.apache.cocoon.ResourceNotFoundException;
032import org.apache.commons.lang.StringUtils;
033import org.apache.excalibur.source.Source;
034import org.apache.excalibur.source.SourceException;
035
036import org.ametys.core.util.ImageHelper;
037
038/**
039 * Resource handler for images
040 */
041public class ImageResourceHandler extends AbstractResourceHandler implements Component
042{
043    private static final Pattern _SIZE_PATTERN = Pattern.compile("^(.*)(?:_(max)?([0-9]+)x([0-9]+))(\\.[^./]+)$");
044
045    private static final Collection<String> __ALLOWED_FORMATS = Arrays.asList(new String[]{"png", "gif", "jpg", "jpeg"});
046
047    @Override
048    public Source setup(String location, Map objectModel, Parameters par, Map<String, Object> additionalParameters) throws IOException, ProcessingException
049    {
050        Source source = null;
051        try 
052        {
053            source = _resolver.resolveURI(location);
054        } 
055        catch (SourceException e) 
056        {
057            // Nothing
058        }
059        
060        // Compute the locale
061        if (source == null || !source.exists())
062        {
063            Matcher sizeMatcher = _SIZE_PATTERN.matcher(location);
064            if (sizeMatcher.matches())
065            {
066                String computedLocation = sizeMatcher.group(1) + sizeMatcher.group(5);
067                
068                source = _resolver.resolveURI(computedLocation);
069                if (!source.exists())
070                {
071                    throw new ResourceNotFoundException("Resource not found for URI : " + source.getURI());
072                }
073                
074                boolean isMaxSize = sizeMatcher.group(2) != null;
075                String height = sizeMatcher.group(3);
076                String width = sizeMatcher.group(4);
077
078                additionalParameters.put("height", isMaxSize ? 0 : Integer.parseInt(height));
079                additionalParameters.put("width", isMaxSize ? 0 : Integer.parseInt(width));
080                additionalParameters.put("maxHeight", isMaxSize ? Integer.parseInt(height) : 0);
081                additionalParameters.put("maxWidth", isMaxSize ? Integer.parseInt(width) : 0);
082            }
083            else
084            {
085                throw new ResourceNotFoundException("Resource not found for URI : " + location);
086            }
087        }
088        
089        return source;
090    }
091
092    @Override
093    public void generateResource(Source source, OutputStream out, Map objectModel, Parameters parameters, Map<String, Object> additionalParameters) throws IOException, ProcessingException
094    {
095        String format = StringUtils.substringAfterLast(source.getURI(), ".").toLowerCase();
096        format = __ALLOWED_FORMATS.contains(format) ? format : "png";
097        
098        int width = (int) additionalParameters.getOrDefault("width", 0);
099        int height = (int) additionalParameters.getOrDefault("height", 0);
100        int maxWidth = (int) additionalParameters.getOrDefault("maxWidth", 0);
101        int maxHeight = (int) additionalParameters.getOrDefault("maxHeight", 0);
102        
103        try (InputStream is = source.getInputStream())
104        {
105            ImageHelper.generateThumbnail(is, out, format, height, width, maxHeight, maxWidth);
106        }
107    }
108
109    @Override
110    public Serializable getKey(Source source, Map objectModel, Parameters parameters, Map<String, Object> additionalParameters)
111    {
112        int width = (int) additionalParameters.getOrDefault("width", 0);
113        int height = (int) additionalParameters.getOrDefault("height", 0);
114        int maxWidth = (int) additionalParameters.getOrDefault("maxWidth", 0);
115        int maxHeight = (int) additionalParameters.getOrDefault("maxHeight", 0);
116        
117        return source.getURI() + "###" + width + "x" + height + "x" + maxWidth + "x" + maxHeight;
118    }
119}