Author: mir
Date: Thu Sep 23 15:20:35 2010
New Revision: 1000494

URL: http://svn.apache.org/viewvc?rev=1000494&view=rev
Log:
CLEREZZA-232: besides resizing, images can now additionally be cropped to match 
a given resolution exactly. This is configurable over the felix webconsole

Modified:
    
incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.platform.content.representations/org.apache.clerezza.platform.content.representations.core/src/main/java/org/apache/clerezza/platform/content/representations/core/AlternativeRepresentationGenerator.java
    
incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.platform.content.representations/org.apache.clerezza.platform.content.representations.core/src/main/java/org/apache/clerezza/platform/content/representations/core/ThumbnailService.java

Modified: 
incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.platform.content.representations/org.apache.clerezza.platform.content.representations.core/src/main/java/org/apache/clerezza/platform/content/representations/core/AlternativeRepresentationGenerator.java
URL: 
http://svn.apache.org/viewvc/incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.platform.content.representations/org.apache.clerezza.platform.content.representations.core/src/main/java/org/apache/clerezza/platform/content/representations/core/AlternativeRepresentationGenerator.java?rev=1000494&r1=1000493&r2=1000494&view=diff
==============================================================================
--- 
incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.platform.content.representations/org.apache.clerezza.platform.content.representations.core/src/main/java/org/apache/clerezza/platform/content/representations/core/AlternativeRepresentationGenerator.java
 (original)
+++ 
incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.platform.content.representations/org.apache.clerezza.platform.content.representations.core/src/main/java/org/apache/clerezza/platform/content/representations/core/AlternativeRepresentationGenerator.java
 Thu Sep 23 15:20:35 2010
@@ -93,16 +93,25 @@ public class AlternativeRepresentationGe
                        return width;
                }
        }
+       final static String EXACT_APPENDIX = "-exact";
 
        @Reference
        private ImageProcessor imageProcessor;
+
        @Property(value="100x100,200x200", description="Specifies the 
resolutions of alternative" +
                        " representations in the format [width]x[height]. 
Multiple resolutions" +
                        " are separated by comma (e.g. 100x100,30x30)")
        public static final String RESOLUTIONS = "resolutions";
+
+       @Property(value="100x100,200x200", description="Specifies the exact 
resolutions of alternative" +
+                       " representations in the format [width]x[height]. 
Multiple resolutions" +
+                       " are separated by comma (e.g. 100x100,30x30). The 
image will be cropped if it has not " +
+                       "the needed proportions")
+       public static final String EXACT_RESOLUTIONS = "exact_resolutions";
        
        private volatile ServiceTracker discobitTracker;
        private Resolution[] resolutions;
+       private Resolution[] exactResolutions;
 
        /**
         * Indicates if data given to the AlternativeRepresentationGenerator is 
a
@@ -118,7 +127,8 @@ public class AlternativeRepresentationGe
        };
 
        protected void activate(ComponentContext context) {
-               setupResolutionArray((String) 
context.getProperties().get(RESOLUTIONS));
+               resolutions = createResolutionArray((String) 
context.getProperties().get(RESOLUTIONS));
+               exactResolutions = createResolutionArray((String) 
context.getProperties().get(EXACT_RESOLUTIONS));
                discobitTracker = new ServiceTracker(context.getBundleContext(),
                                DiscobitsHandler.class.getName(), null);
                new Thread() {
@@ -129,12 +139,13 @@ public class AlternativeRepresentationGe
                }.start();
        }
 
-       private void setupResolutionArray(String resolutionsString) {
+       private Resolution[] createResolutionArray(String resolutionsString) {
                String[] resoultionStrings = resolutionsString.split(",");
-               resolutions = new Resolution[resoultionStrings.length];
+               Resolution[] resolutionArray = new 
Resolution[resoultionStrings.length];
                for (int i = 0; i < resoultionStrings.length; i++) {
-                       resolutions[i] = new 
Resolution(resoultionStrings[i].trim());
+                       resolutionArray[i] = new 
Resolution(resoultionStrings[i].trim());
                }
+               return resolutionArray;
        }
 
        protected void deactivate(ComponentContext context) {
@@ -153,12 +164,17 @@ public class AlternativeRepresentationGe
        }
        
        public UriRef generateAlternativeImage(GraphNode infoBitNode, int 
width, int height) {
+               return generateAlternativeImage(infoBitNode, width, height, 
false);
+       }
+       
+       public UriRef generateAlternativeImage(GraphNode infoBitNode, int 
width, int height, 
+                       boolean exact) {
                try {
                        isAltRepresentation.set(Boolean.TRUE);
                        InfoDiscobit infoBit = 
InfoDiscobit.createInstance(infoBitNode);
                        BufferedImage buffImage = ImageIO.read(new 
ByteArrayInputStream(infoBit.getData()));
                        return generateAlternativeImage(buffImage, new 
Resolution(width, height), 
-                                       
MediaType.valueOf(infoBit.getContentType()), infoBitNode);
+                                       
MediaType.valueOf(infoBit.getContentType()), infoBitNode, exact);
                } catch (IOException ex) {
                        throw new RuntimeException(ex);
                } finally {
@@ -175,7 +191,12 @@ public class AlternativeRepresentationGe
                        int imgHeigth = buffImage.getHeight();
                        for (Resolution resolution : resolutions) {
                                if (imgWidth > resolution.getWidth() || 
imgHeigth > resolution.getHeight()) {
-                                       generateAlternativeImage( buffImage, 
resolution, mediaType, node);
+                                       generateAlternativeImage(buffImage, 
resolution, mediaType, node, false);
+                               }
+                       }
+                       for (Resolution resolution : exactResolutions) {
+                               if (imgWidth > resolution.getWidth() && 
imgHeigth > resolution.getHeight()) {
+                                       generateAlternativeImage(buffImage, 
resolution, mediaType, node, true);
                                }
                        }
                } catch (IOException ex) {
@@ -186,13 +207,21 @@ public class AlternativeRepresentationGe
        }
 
        private UriRef generateAlternativeImage(BufferedImage buffImage, 
Resolution resolution,
-                       MediaType mediaType, GraphNode node) throws IOException 
{
-               BufferedImage alternativeImage = 
imageProcessor.makeAThumbnail(buffImage,
-                               resolution.getWidth(), resolution.getHeight());
+                       MediaType mediaType, GraphNode node, boolean extact) 
throws IOException {
+               BufferedImage alternativeImage;
+               if (extact) {
+                       alternativeImage = resizeAndCrop(resolution, buffImage);
+                       if (alternativeImage == null) {
+                               return null;
+                       }
+               } else {
+                       alternativeImage = 
imageProcessor.makeAThumbnail(buffImage,
+                                       resolution.getWidth(), 
resolution.getHeight());
+               }
                byte[] alternativeImageBytes = 
bufferedImage2ByteArray(alternativeImage, mediaType);
                DiscobitsHandler contentHandler = (DiscobitsHandler) 
discobitTracker.getService();
                
-               UriRef thumbnailUri = createThumbnailUri((UriRef) 
node.getNode(), alternativeImage);
+               UriRef thumbnailUri = createThumbnailUri((UriRef) 
node.getNode(), alternativeImage, extact);
                contentHandler.put(thumbnailUri, mediaType, 
alternativeImageBytes);
                Lock writeLock = node.writeLock();
                writeLock.lock();
@@ -203,6 +232,36 @@ public class AlternativeRepresentationGe
                        writeLock.unlock();
                }
        }
+       
+               private BufferedImage resizeAndCrop(Resolution resolution, 
BufferedImage buffImage) {
+               BufferedImage alternativeImage;
+               int imageHeight = 0;
+               int imageWidth = 0;
+               int widthDiff = buffImage.getWidth() - resolution.getWidth() ;
+               int heightDiff = buffImage.getHeight() - resolution.getHeight();
+               // resize if both dimension are bigger than the dimensions of 
the needed resolution
+               if (widthDiff >= 0 && heightDiff >= 0) {
+                       if (widthDiff < heightDiff) {
+                               imageWidth = resolution.getWidth();
+                       } else {
+                               imageHeight = resolution.getHeight();
+                       }
+                       alternativeImage = 
imageProcessor.resizeProportional(buffImage, imageWidth, imageHeight);
+               } else {
+                       return null;
+               }
+               // crop image to fit exact the resolution
+               if (widthDiff < heightDiff) {
+                       heightDiff = alternativeImage.getHeight() - 
resolution.getHeight();
+                       alternativeImage = alternativeImage.getSubimage(0, 
heightDiff/2, resolution.getWidth(),
+                                       resolution.getHeight());
+               } else {
+                       widthDiff = alternativeImage.getWidth() - 
resolution.getWidth();
+                       alternativeImage = 
alternativeImage.getSubimage(widthDiff/2, 0, resolution.getWidth(),
+                                       resolution.getHeight());
+               }
+               return alternativeImage;
+       }
 
        private byte[] bufferedImage2ByteArray(BufferedImage image,
                        MediaType mediaType) throws IOException {
@@ -213,8 +272,8 @@ public class AlternativeRepresentationGe
                return bytes;
        }
 
-       private UriRef createThumbnailUri(UriRef uriRef, BufferedImage img) {
-               String resolution = "-" + img.getWidth() + "x" + 
img.getHeight();
+       private UriRef createThumbnailUri(UriRef uriRef, BufferedImage img, 
boolean exact) {
+               String resolution = "-" + img.getWidth() + "x" + 
img.getHeight() + (exact ? EXACT_APPENDIX: "");
                String oldUri = uriRef.getUnicodeString();
                String newUri;
                int lastIndexOfDot = oldUri.lastIndexOf(".");

Modified: 
incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.platform.content.representations/org.apache.clerezza.platform.content.representations.core/src/main/java/org/apache/clerezza/platform/content/representations/core/ThumbnailService.java
URL: 
http://svn.apache.org/viewvc/incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.platform.content.representations/org.apache.clerezza.platform.content.representations.core/src/main/java/org/apache/clerezza/platform/content/representations/core/ThumbnailService.java?rev=1000494&r1=1000493&r2=1000494&view=diff
==============================================================================
--- 
incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.platform.content.representations/org.apache.clerezza.platform.content.representations.core/src/main/java/org/apache/clerezza/platform/content/representations/core/ThumbnailService.java
 (original)
+++ 
incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.platform.content.representations/org.apache.clerezza.platform.content.representations.core/src/main/java/org/apache/clerezza/platform/content/representations/core/ThumbnailService.java
 Thu Sep 23 15:20:35 2010
@@ -25,6 +25,7 @@ import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Map;
 import java.util.concurrent.locks.Lock;
+import javax.ws.rs.DefaultValue;
 import javax.ws.rs.GET;
 import javax.ws.rs.Path;
 import javax.ws.rs.QueryParam;
@@ -116,12 +117,13 @@ public class ThumbnailService implements
        @GET
        public Response getThumbnailUri(@QueryParam("uri") UriRef infoBitUri,
                        @QueryParam("width") Integer width, 
@QueryParam("height") Integer height,
-                       @Context UriInfo uriInfo) {
+                       @DefaultValue("false") @QueryParam("exact") Boolean 
exact, @Context UriInfo uriInfo) {
                return RedirectUtil.createSeeOtherResponse(
-                               getThumbnailUri(infoBitUri, width, 
height).getUnicodeString(), uriInfo);
+                               getThumbnailUri(infoBitUri, width, height, 
exact).getUnicodeString(), uriInfo);
        }
 
-       public UriRef getThumbnailUri(UriRef infoBitUri, Integer width,  
Integer height) {
+       public UriRef getThumbnailUri(UriRef infoBitUri, Integer width,  
Integer height,
+                       boolean exact) {
                if ((width == null) && (height == null)) {
                        throw new IllegalArgumentException("height and/or width 
must be specified");
                }
@@ -132,7 +134,7 @@ public class ThumbnailService implements
                        height = Integer.MAX_VALUE;
                }
                GraphNode infoBitNode = new GraphNode(infoBitUri, 
cgProvider.getContentGraph());
-               UriRef thumbnailUri = getGeneratedThumbnailUri(infoBitNode, 
width, height);
+               UriRef thumbnailUri = getGeneratedThumbnailUri(infoBitNode, 
width, height, exact);
                if (thumbnailUri == null) {
                        TypedLiteral mediaTypeLiteral = null;
                        Lock readLock = infoBitNode.readLock();
@@ -152,8 +154,9 @@ public class ThumbnailService implements
                                if (mediaType.getType().startsWith("image")) {
                                        try {
                                                thumbnailUri = 
altRepGen.generateAlternativeImage(infoBitNode, width,
-                                                               height);
+                                                               height, exact);
                                        } catch (Exception ex) {
+                                               ex.printStackTrace();
                                                // Was worth a try. eLets go on
                                        }
                                }
@@ -167,7 +170,6 @@ public class ThumbnailService implements
                                }
                        }
                }
-
                if (thumbnailUri == null) {
                        thumbnailUri = new 
UriRef(getDefaultIconUrl(getStyleBundle()));
                }
@@ -213,8 +215,8 @@ public class ThumbnailService implements
        }
 
        private UriRef getGeneratedThumbnailUri(GraphNode infoBitNode,
-                       Integer width, Integer height) {
-               if (isFittingImage(infoBitNode, width, height)) {
+                       Integer width, Integer height, boolean exact) {
+               if (isFittingImage(infoBitNode, width, height, exact)) {
                        return (UriRef) infoBitNode.getNode();
                }
                UriRef resultThumbnailUri = null;
@@ -227,8 +229,11 @@ public class ThumbnailService implements
                                UriRef thumbnailUri = (UriRef) 
thumbnails.next();
                                GraphNode thumbnailNode = new 
GraphNode(thumbnailUri,
                                                cgProvider.getContentGraph());
-                               int thumbnailPixels = 
getSurfaceSizeIfFitting(thumbnailNode, width, height);
+                               int thumbnailPixels = 
getSurfaceSizeIfFitting(thumbnailNode, width, height, exact);
                                if (thumbnailPixels > pixels) {
+                                       if (exact) {
+                                               return thumbnailUri;
+                                       }
                                        resultThumbnailUri = thumbnailUri;
                                        pixels = thumbnailPixels;
                                }
@@ -243,7 +248,15 @@ public class ThumbnailService implements
         * returns the surface in pixel if the image fits withing width and 
height,
         * or -1 if it doesn't fit
         */
-       private int getSurfaceSizeIfFitting(GraphNode infoBitNode, Integer 
width, Integer height) {
+       private int getSurfaceSizeIfFitting(GraphNode infoBitNode, Integer 
width, Integer height,
+                       boolean exact) {
+               Resource imageRes = infoBitNode.getNode();
+               if (imageRes instanceof UriRef) {
+                       String imageUri = ((UriRef)imageRes).getUnicodeString();
+                       if (!exact && 
imageUri.contains(AlternativeRepresentationGenerator.EXACT_APPENDIX)) {
+                               return -1;
+                       }
+               }               
                Iterator<Resource> exifWidths = 
infoBitNode.getObjects(EXIF.width);
                Iterator<Resource> exifHeights = 
infoBitNode.getObjects(EXIF.height);
                if (!exifWidths.hasNext() || !exifHeights.hasNext()) {
@@ -254,8 +267,14 @@ public class ThumbnailService implements
                                Integer.class, (TypedLiteral) 
exifWidths.next());
                Integer thumbnailHeight = 
LiteralFactory.getInstance().createObject(
                                Integer.class, (TypedLiteral) 
exifHeights.next());
-               if (thumbnailHeight <= height && thumbnailWidth <= width) {
-                       return thumbnailWidth * thumbnailHeight;
+               if (exact) {
+                       if (thumbnailHeight == height && thumbnailWidth == 
width) {
+                               return 1;
+                       }
+               } else {
+                       if (thumbnailHeight <= height && thumbnailWidth <= 
width) {
+                               return thumbnailWidth * thumbnailHeight;
+                       }
                }
                return -1;
        }
@@ -263,7 +282,8 @@ public class ThumbnailService implements
        /**
         * returns true if infoBitNode is an image and fits
         */
-       private boolean isFittingImage(GraphNode infoBitNode, Integer width, 
Integer height) {
+       private boolean isFittingImage(GraphNode infoBitNode, Integer width, 
Integer height,
+                       boolean exact) {
                Lock readLock = infoBitNode.readLock();
                readLock.lock();
                try {
@@ -272,7 +292,7 @@ public class ThumbnailService implements
                                return false;
                        }
                        if 
(mediaTypesIter.next().getLexicalForm().startsWith("image")) {
-                               return getSurfaceSizeIfFitting(infoBitNode, 
width, height) > -1;
+                               return getSurfaceSizeIfFitting(infoBitNode, 
width, height, exact) > -1;
                        } else {
                                return false;
                        }


Reply via email to