You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@cocoon.apache.org by jo...@apache.org on 2004/03/09 00:34:12 UTC
cvs commit: cocoon-2.2/src/webapp/samples/imagereader samples.xml sitemap.xmap
joerg 2004/03/08 15:34:12
Modified: . status.xml
src/java/org/apache/cocoon/reading ImageReader.java
src/webapp/samples/imagereader samples.xml sitemap.xmap
Log:
fixed bug 27020, thanks to Peter Horsfield: Added grayscaling and color transformation to the ImageReader.,
ported the latest changes on ImageReader in 2.1 to 2.2 (handleJVMBug and so on)
Revision Changes Path
1.187 +4 -1 cocoon-2.2/status.xml
Index: status.xml
===================================================================
RCS file: /home/cvs/cocoon-2.2/status.xml,v
retrieving revision 1.186
retrieving revision 1.187
diff -u -r1.186 -r1.187
--- status.xml 8 Mar 2004 21:21:10 -0000 1.186
+++ status.xml 8 Mar 2004 23:34:12 -0000 1.187
@@ -189,6 +189,9 @@
<changes>
<release version="@version@" date="@date@">
+ <action dev="JH" type="add" fixes-bug="27020" due-to="Peter Horsfield" due-to-email="peter@xml.grumpykitty.biz">
+ Added grayscaling and color transformation to the ImageReader.
+ </action>
<action dev="JH" type="fix" fixes-bug="26851" due-to="Marco Rolappe" due-to-email="m_rolappe@web.de">
LinkStatusGenerator now handles also links with a specified charset.
</action>
1.6 +164 -41 cocoon-2.2/src/java/org/apache/cocoon/reading/ImageReader.java
Index: ImageReader.java
===================================================================
RCS file: /home/cvs/cocoon-2.2/src/java/org/apache/cocoon/reading/ImageReader.java,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -r1.5 -r1.6
--- ImageReader.java 8 Mar 2004 14:03:32 -0000 1.5
+++ ImageReader.java 8 Mar 2004 23:34:12 -0000 1.6
@@ -15,26 +15,28 @@
*/
package org.apache.cocoon.reading;
-import org.apache.avalon.framework.parameters.Parameters;
+import java.awt.color.ColorSpace;
+import java.awt.geom.AffineTransform;
+import java.awt.image.AffineTransformOp;
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorConvertOp;
+import java.awt.image.RescaleOp;
+import java.awt.image.WritableRaster;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.Serializable;
+import java.util.Map;
+import org.apache.avalon.framework.parameters.Parameters;
import org.apache.cocoon.ProcessingException;
import org.apache.cocoon.environment.SourceResolver;
+import org.xml.sax.SAXException;
import com.sun.image.codec.jpeg.ImageFormatException;
import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGDecodeParam;
import com.sun.image.codec.jpeg.JPEGImageDecoder;
import com.sun.image.codec.jpeg.JPEGImageEncoder;
-import org.xml.sax.SAXException;
-
-import java.awt.geom.AffineTransform;
-import java.awt.image.AffineTransformOp;
-import java.awt.image.Raster;
-import java.awt.image.WritableRaster;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.Serializable;
-import java.util.Map;
/**
* The <code>ImageReader</code> component is used to serve binary image data
@@ -52,13 +54,25 @@
* <dd>This parameter is optional. When specified it determines the height
* of the image that should be served.
* </dd>
+ * <dt><scale(Red|Green|Blue)></dt>
+ * <dd>This parameter is optional. When specified it will cause the
+ * specified color component in the image to be multiplied by the
+ * specified floating point value.
+ * </dd>
+ * <dt><offset(Red|Green|Blue)></dt>
+ * <dd>This parameter is optional. When specified it will cause the
+ * specified color component in the image to be incremented by the
+ * specified floating point value.
+ * </dd>
+ * <dt><grayscale></dt>
+ * <dd>This parameter is optional. When specified and set to true it
+ * will cause each image pixel to be normalized.
+ * </dd>
* </dl>
*
- * @author <a href="mailto:stefano@apache.org">Stefano Mazzocchi</a>
- * @author <a href="mailto:stephan@apache.org">Stephan Michels</a>
- * @author <a href="mailto:tcurdt@apache.org">Torsten Curdt</a>
+ * @author <a href="mailto:dev@cocoon.apache.org">The Apache Cocoon Team</a>
* @version CVS $Id$
- *
+ *
* @avalon.component
* @avalon.service type=Reader
* @x-avalon.lifestyle type=pooled
@@ -67,9 +81,17 @@
private int width;
private int height;
+
+ private float[] scaleColor = new float[3];
+ private float[] offsetColor = new float[3];
+ private RescaleOp colorFilter = null;
+
private boolean enlarge;
private final static String ENLARGE_DEFAULT = "true";
+ private ColorConvertOp grayscaleFilter = null;
+ private final static String GRAYSCALE_DEFAULT = "false";
+
public void setup(SourceResolver resolver, Map objectModel, String src, Parameters par)
throws ProcessingException, SAXException, IOException {
@@ -78,6 +100,39 @@
width = par.getParameterAsInteger("width", 0);
height = par.getParameterAsInteger("height", 0);
+ scaleColor[0] = par.getParameterAsFloat("scaleRed", -1.0f);
+ scaleColor[1] = par.getParameterAsFloat("scaleGreen", -1.0f);
+ scaleColor[2] = par.getParameterAsFloat("scaleBlue", -1.0f);
+ offsetColor[0] = par.getParameterAsFloat("offsetRed", 0.0f);
+ offsetColor[1] = par.getParameterAsFloat("offsetGreen", 0.0f);
+ offsetColor[2] = par.getParameterAsFloat("offsetBlue", 0.0f);
+
+ boolean filterColor = false;
+
+ for (int i = 0; i < 3; ++i) {
+ if (scaleColor[i] != -1.0f) {
+ filterColor = true;
+ } else {
+ scaleColor[i] = 1.0f;
+ }
+ if (offsetColor[i] != 0.0f) {
+ filterColor = true;
+ }
+ }
+
+ if (filterColor) {
+ colorFilter = new RescaleOp(scaleColor, offsetColor, null);
+ } else {
+ colorFilter = null;
+ }
+
+ String grayscalePar = par.getParameter("grayscale", GRAYSCALE_DEFAULT);
+ if ("true".equalsIgnoreCase(grayscalePar) || "yes".equalsIgnoreCase(grayscalePar)){
+ grayscaleFilter = new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_GRAY), null);
+ } else {
+ grayscaleFilter = null;
+ }
+
String enlargePar = par.getParameter("allow-enlarging", ENLARGE_DEFAULT);
if ("true".equalsIgnoreCase(enlargePar) || "yes".equalsIgnoreCase(enlargePar)){
enlarge = true;
@@ -116,7 +171,7 @@
}
if (!enlarge) {
- if ((nw > ow && nh <= 0) || (oh > nh && nw <=0)) {
+ if ((nw > ow && nh <= 0) || (nh > oh && nw <=0)) {
wm = 1.0d;
hm = 1.0d;
} else if (nw > ow) {
@@ -129,17 +184,17 @@
}
protected void processStream() throws IOException, ProcessingException {
- if (width > 0 || height > 0) {
+ if (width > 0 || height > 0 || null != colorFilter || null != grayscaleFilter) {
if (getLogger().isDebugEnabled()) {
- getLogger().debug("image " + ((width==0)?"?":Integer.toString(width))
- + "x" + ((height==0)?"?":Integer.toString(height))
+ getLogger().debug("image " + ((width == 0) ? "?" : Integer.toString(width))
+ + "x" + ((height == 0) ? "?" : Integer.toString(height))
+ " expires: " + expires);
}
// since we create the image on the fly
response.setHeader("Accept-Ranges", "none");
- /**
+ /*
* NOTE (SM):
* Due to Bug Id 4502892 (which is found in *all* JVM implementations from
* 1.2.x and 1.3.x on all OS!), we must buffer the JPEG generation to avoid
@@ -163,27 +218,55 @@
try {
JPEGImageDecoder decoder = JPEGCodec.createJPEGDecoder(inputStream);
- Raster original = decoder.decodeAsRaster();
- JPEGDecodeParam decodeParam = decoder.getJPEGDecodeParam();
- double ow = decodeParam.getWidth();
- double oh = decodeParam.getHeight();
- AffineTransformOp filter = new AffineTransformOp(getTransform(ow, oh, width, height), AffineTransformOp.TYPE_BILINEAR);
- WritableRaster scaled = filter.createCompatibleDestRaster(original);
- filter.filter(original, scaled);
-
- // JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
-
- ByteArrayOutputStream bstream = new ByteArrayOutputStream();
- JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(bstream);
- encoder.encode(scaled);
- out.write(bstream.toByteArray());
+ BufferedImage original = decoder.decodeAsBufferedImage();
+ BufferedImage currentImage = original;
+
+ if (width > 0 || height > 0) {
+ JPEGDecodeParam decodeParam = decoder.getJPEGDecodeParam();
+ double ow = decodeParam.getWidth();
+ double oh = decodeParam.getHeight();
+
+ AffineTransformOp filter = new AffineTransformOp(getTransform(ow, oh, width, height), AffineTransformOp.TYPE_BILINEAR);
+ WritableRaster scaledRaster = filter.createCompatibleDestRaster(currentImage.getRaster());
+
+ filter.filter(currentImage.getRaster(), scaledRaster);
+
+ currentImage = new BufferedImage(original.getColorModel(), scaledRaster, true, null);
+ }
+
+ if (null != grayscaleFilter) {
+ grayscaleFilter.filter(currentImage, currentImage);
+ }
+
+ if (null != colorFilter) {
+ colorFilter.filter(currentImage, currentImage);
+ }
+
+ if (!handleJVMBug()) {
+ if (getLogger().isDebugEnabled()) {
+ getLogger().debug( "No need to handle JVM bug" );
+ }
+ JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
+ encoder.encode(currentImage);
+ } else {
+ if (getLogger().isDebugEnabled()) {
+ getLogger().debug( "Need to handle JVM bug" );
+ }
+ ByteArrayOutputStream bstream = new ByteArrayOutputStream();
+ JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(bstream);
+ encoder.encode(currentImage);
+ out.write(bstream.toByteArray());
+ }
out.flush();
} catch (ImageFormatException e) {
throw new ProcessingException("Error reading the image. Note that only JPEG images are currently supported.");
+ } finally {
+ // Bugzilla Bug 25069, close inputStream in finally block
+ // this will close inputStream even if processStream throws
+ // an exception
+ inputStream.close();
}
-
- inputStream.close();
} else {
// only read the resource - no modifications requested
if (getLogger().isDebugEnabled()) {
@@ -197,14 +280,54 @@
* Generate the unique key.
* This key must be unique inside the space of this component.
*
- * @return The generated key consists from src and width and height
+ * @return The generated key consists of the src and width and height, and the color transform
* parameters
*/
public Serializable getKey() {
- if (width > 0 || height > 0) {
- return this.inputSource.getURI() + ':' + this.width + ':' + this.height;
+ return this.inputSource.getURI()
+ + ':' + this.width
+ + ':' + this.height
+ + ":" + this.scaleColor[0]
+ + ":" + this.scaleColor[1]
+ + ":" + this.scaleColor[2]
+ + ":" + this.offsetColor[0]
+ + ":" + this.offsetColor[1]
+ + ":" + this.offsetColor[2]
+ + ":" + ((null == this.grayscaleFilter) ? "color" : "grayscale")
+ + ":" + super.getKey();
+ }
+
+ /**
+ * Determine if workaround for Bug Id 4502892 is neccessary.
+ * This method assumes that Bug is present if
+ * java.version is undeterminable, and for java.version
+ * 1.1, 1.2, 1.3, all other java.version do not need the Bug handling
+ *
+ * @return true if we should handle the JVM bug, else false
+ */
+ protected boolean handleJVMBug() {
+ // java.version=1.4.0
+ String java_version = System.getProperty( "java.version", "0.0.0" );
+ boolean handleJVMBug = true;
+
+ char major = java_version.charAt(0);
+ char minor = java_version.charAt(2);
+
+ // make 0.0, 1.1, 1.2, 1.3 handleJVMBug = true
+ if (major == '0' || major == '1') {
+ if (minor == '0' || minor == '1' || minor == '2' || minor == '3') {
+ handleJVMBug = true;
+ } else {
+ handleJVMBug = false;
+ }
} else {
- return super.getKey();
+ handleJVMBug = true;
}
+ if (getLogger().isDebugEnabled()) {
+ getLogger().debug( "Running java.version " + String.valueOf(java_version) +
+ " need to handle JVM bug " + String.valueOf(handleJVMBug) );
+ }
+
+ return handleJVMBug;
}
}
1.2 +61 -13 cocoon-2.2/src/webapp/samples/imagereader/samples.xml
Index: samples.xml
===================================================================
RCS file: /home/cvs/cocoon-2.2/src/webapp/samples/imagereader/samples.xml,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- samples.xml 10 Aug 2003 11:42:47 -0000 1.1
+++ samples.xml 8 Mar 2004 23:34:12 -0000 1.2
@@ -1,19 +1,67 @@
+<?xml version="1.0"?>
+<!--
+ Copyright 1999-2004 The Apache Software Foundation
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
<samples xmlns:xlink="http://www.w3.org/1999/xlink">
-
- <group name="Main examples page.">
- <sample name="Back" href="..">to Cocoon examples main page</sample>
- </group>
-
- <group name="ImageReader">
- <sample href="image-0" name="Image">
- Image of original size
- </sample>
- <sample href="image-250" name="Image 250x250">
- Image scaled up to the size 250 x 250
+
+ <group name="Main examples page.">
+ <sample name="Back" href="..">to Cocoon examples main page</sample>
+ </group>
+
+ <group name="The Original">
+ <sample href="image" name="Image">
+ Image of original size and color.
</sample>
- <sample href="image-50" name="Image 50x50">
- Image scaled down to the size 50 x 50
+ </group>
+
+ <group name="ImageReader - Size Scaling">
+ <sample href="image-size-50" name="Image 50x50">
+ Image scaled down to the size 50 x 50.
</sample>
+ <sample href="image-size-250" name="Image 250x250">
+ Image scaled up to the size 250 x 250.
+ </sample>
+ </group>
+
+ <group name="ImageReader - Grayscaling">
+ <sample href="image-grayscale" name="Image grayscaled.">
+ The image in gray.
+ </sample>
</group>
+ <group name="ImageReader - Color Scaling">
+ <sample href="image-color-scale-2-1-1" name="Image tinted red.">
+ The values for the color red are duplicated.
+ </sample>
+ <sample href="image-color-scale-1-2-1" name="Image tinted green.">
+ The values for the color green are duplicated.
+ </sample>
+ <sample href="image-color-scale-1-1-2" name="Image tinted blue.">
+ The values for the color blue are duplicated.
+ </sample>
+ </group>
+
+ <group name="ImageReader - Color Offset">
+ <sample href="image-color-offset-50-0-0" name="Image tinted red.">
+ The values for the color red are incremented by 50.
+ </sample>
+ <sample href="image-color-offset-0-50-0" name="Image tinted green.">
+ The values for the color green are incremented by 50.
+ </sample>
+ <sample href="image-color-offset-0-0-50" name="Image tinted blue.">
+ The values for the color blue are incremented by 50.
+ </sample>
+ </group>
</samples>
1.3 +43 -2 cocoon-2.2/src/webapp/samples/imagereader/sitemap.xmap
Index: sitemap.xmap
===================================================================
RCS file: /home/cvs/cocoon-2.2/src/webapp/samples/imagereader/sitemap.xmap,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- sitemap.xmap 10 Aug 2003 11:42:47 -0000 1.2
+++ sitemap.xmap 8 Mar 2004 23:34:12 -0000 1.3
@@ -1,4 +1,19 @@
<?xml version="1.0"?>
+<!--
+ Copyright 1999-2004 The Apache Software Foundation
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
<!--
CVS $Id$
@@ -28,10 +43,36 @@
<map:serialize/>
</map:match>
- <map:match pattern="image-*">
+ <map:match pattern="image">
+ <map:read src="logo.jpg"/>
+ </map:match>
+
+ <map:match pattern="image-size-*">
<map:read type="image" src="logo.jpg">
<map:parameter name="width" value="{1}"/>
<map:parameter name="height" value="{1}"/>
+ </map:read>
+ </map:match>
+
+ <map:match pattern="image-grayscale">
+ <map:read type="image" src="logo.jpg">
+ <map:parameter name="grayscale" value="true"/>
+ </map:read>
+ </map:match>
+
+ <map:match pattern="image-color-scale-*-*-*">
+ <map:read type="image" src="logo.jpg">
+ <map:parameter name="scaleRed" value="{1}"/>
+ <map:parameter name="scaleGreen" value="{2}"/>
+ <map:parameter name="scaleBlue" value="{3}"/>
+ </map:read>
+ </map:match>
+
+ <map:match pattern="image-color-offset-*-*-*">
+ <map:read type="image" src="logo.jpg">
+ <map:parameter name="offsetRed" value="{1}"/>
+ <map:parameter name="offsetGreen" value="{2}"/>
+ <map:parameter name="offsetBlue" value="{3}"/>
</map:read>
</map:match>
</map:pipeline>