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;
}