Hi Steven, that's really cool, I like it very much, confratulations! The most important thing is IMHO the Pipeline APIs are adaptable to build various kind of Pipeline not just SAX/XML... and that's great! Thanks to share your work with us! Best regards, Simone
2009/1/14 Steven Dolg <[email protected]>: > Hi, > > I planned to come up with an Imaging Module for quite some time now. > There were several situations in some of the projects I worked on where such > a module would have been handy IMO. > I also thought this might serve as another example of how the Pipeline API > could be used. > > > I did not invest much time (only a couple of hours this afternoon) and I'm > actually not very versatile in using the Imaging API and/or Java2D. > So please don't blame me when the implementation of the transformations is > not ideal or not really fast. > (Actually if someone know how to implement some or all of those > manipulations better, I'd love to hear about that). > The transformers still miss alot of configuration possiblities (most of it > is simply hardwired) and are not really suited to be used in the Sitemap, > yet. > But I intend to continue working on this... > > > So far I created the following transformers: > * CropImageTransformer > Crops the image to an area of the configured size. The area is centered on > the image > > * MaxSizeImageTransformer > Reduces the size of the image so that it fits inside the given dimensions. > The aspect ratio of the image is maintained. If the image already fits > inside the given bound it will remain unchanged. > > *RotateImageTransformer > Rotates the whole image by a given amount. Any value is possible. > > *ScaleImageTransformer > Scales the image by a given factor, maininting the aspect ratio. > > *WatermarkImageTransformer > Write a configurable text centered on the image. Color and transparancy of > the text is configurable. > > > Additionally there is an ImageGenerator and an ImageSerializer. > Both ImageGenerator and ImageSerializer use the Imaging API of Java. So by > default the image formats JPG, PNG, GIF and BMP are supported (IIRC). > Additional formats may be supported by registering them with the Imaging > API. > > All the components mentioned above a fully compatible to each other - and > not compatible to any other Cocoon 3 components currently available - and > the transformers can be combined in every way. > The basic rules of the PipelineAPI still apply of course (Generator -> > Transformer* -> Serializer) > > I have provided a unit test that uses several pipelines using all > components. > > Attached you can find the patch for the code and a sample image (in case you > have none handy). > The generator uses the URL mechanism already implemented in other generators > in Cocoon 3, so images can also be loaded directly from a web site or some > other location. > > > Regards, > Steven > > Index: > cocoon-imaging/src/test/java/org/apache/cocoon/imaging/PipelineTest.java > =================================================================== > --- cocoon-imaging/src/test/java/org/apache/cocoon/imaging/PipelineTest.java > (revision 0) > +++ cocoon-imaging/src/test/java/org/apache/cocoon/imaging/PipelineTest.java > (revision 0) > @@ -0,0 +1,130 @@ > +package org.apache.cocoon.imaging; > + > +import java.io.File; > +import java.io.FileOutputStream; > + > +import org.apache.cocoon.imaging.components.CropImageTransformer; > +import org.apache.cocoon.imaging.components.MaxSizeImageTransformer; > +import org.apache.cocoon.imaging.components.RotateImageTransformer; > +import org.apache.cocoon.imaging.components.ScaleImageTransformer; > +import org.apache.cocoon.imaging.components.WatermarkImageTransformer; > +import org.apache.cocoon.pipeline.NonCachingPipeline; > +import org.apache.cocoon.pipeline.Pipeline; > +import org.junit.Test; > + > +public class PipelineTest { > + > + @Test > + public void writeUnchanged() throws Exception { > + Pipeline pipeline = new NonCachingPipeline(); > + > + // just read and write the image without changing it > + // this might be used to change the image format, etc. as soon as > this is supported by the > + // ImageSerializer > + pipeline.addComponent(new ImageGenerator(new > File("src/test/resources/sample.JPG").toURI().toURL())); > + pipeline.addComponent(new ImageSerializer()); > + > + FileOutputStream outputStream = new > FileOutputStream("target/unchanged.jpg"); > + pipeline.setup(outputStream); > + pipeline.execute(); > + outputStream.close(); > + } > + > + @Test > + public void addWatermark() throws Exception { > + Pipeline pipeline = new NonCachingPipeline(); > + > + pipeline.addComponent(new ImageGenerator(new > File("src/test/resources/sample.JPG").toURI().toURL())); > + // write the given text centered on the image, using the specified > color and alpha values > + pipeline.addComponent(new WatermarkImageTransformer("Cocoon 3 > Imaging", "0xFFFFFF", 128)); > + pipeline.addComponent(new ImageSerializer()); > + > + FileOutputStream outputStream = new > FileOutputStream("target/watermark.jpg"); > + pipeline.setup(outputStream); > + pipeline.execute(); > + outputStream.close(); > + } > + > + @Test > + public void scaleImage() throws Exception { > + Pipeline pipeline = new NonCachingPipeline(); > + > + pipeline.addComponent(new ImageGenerator(new > File("src/test/resources/sample.JPG").toURI().toURL())); > + // scale the image to 50% of the original size, maintaining the > aspect ratio > + pipeline.addComponent(new ScaleImageTransformer(0.5)); > + pipeline.addComponent(new ImageSerializer()); > + > + FileOutputStream outputStream = new > FileOutputStream("target/scaled.jpg"); > + pipeline.setup(outputStream); > + pipeline.execute(); > + outputStream.close(); > + } > + > + @Test > + public void cropImage() throws Exception { > + Pipeline pipeline = new NonCachingPipeline(); > + > + pipeline.addComponent(new ImageGenerator(new > File("src/test/resources/sample.JPG").toURI().toURL())); > + // reduce the image to the given area (centered) > + pipeline.addComponent(new CropImageTransformer(600, 400)); > + pipeline.addComponent(new ImageSerializer()); > + > + FileOutputStream outputStream = new > FileOutputStream("target/cropped.jpg"); > + pipeline.setup(outputStream); > + pipeline.execute(); > + outputStream.close(); > + } > + > + @Test > + public void createThumbnail() throws Exception { > + Pipeline pipeline = new NonCachingPipeline(); > + > + pipeline.addComponent(new ImageGenerator(new > File("src/test/resources/sample.JPG").toURI().toURL())); > + // scale the image so that it's size does not exceed the given > values, maintaining aspect > + // ration > + pipeline.addComponent(new MaxSizeImageTransformer(100, 100)); > + pipeline.addComponent(new ImageSerializer()); > + > + FileOutputStream outputStream = new > FileOutputStream("target/thumbnail.jpg"); > + pipeline.setup(outputStream); > + pipeline.execute(); > + outputStream.close(); > + } > + > + @Test > + public void rotateImage() throws Exception { > + Pipeline pipeline = new NonCachingPipeline(); > + > + pipeline.addComponent(new ImageGenerator(new > File("src/test/resources/sample.JPG").toURI().toURL())); > + // rotate the image by the given amount in radians (negative > rotates counterclockwise) > + // will change the size of the image if necessary (iow if the angle > is not a multiple of PI) > + pipeline.addComponent(new RotateImageTransformer(-Math.PI / 2)); > + pipeline.addComponent(new ImageSerializer()); > + > + FileOutputStream outputStream = new > FileOutputStream("target/rotated.jpg"); > + pipeline.setup(outputStream); > + pipeline.execute(); > + outputStream.close(); > + } > + > + @Test > + public void multipleTransformations() throws Exception { > + Pipeline pipeline = new NonCachingPipeline(); > + > + pipeline.addComponent(new ImageGenerator(new > File("src/test/resources/sample.JPG").toURI().toURL())); > + // scale to 15% of the original size > + pipeline.addComponent(new ScaleImageTransformer(0.15)); > + // rotate by 45° counterclockwise, fill the remaining area with the > given color > + pipeline.addComponent(new RotateImageTransformer(-Math.PI / 4, > "0xFF8000")); > + // add the given text to the image, using the given color and alpha > values > + pipeline.addComponent(new WatermarkImageTransformer("Cocoon 3 > Imaging", "0x1C93BB", 255)); > + // resize to so that is fits into the given size > + pipeline.addComponent(new MaxSizeImageTransformer(150, 150)); > + pipeline.addComponent(new ImageSerializer()); > + > + FileOutputStream outputStream = new > FileOutputStream("target/multiple.jpg"); > + pipeline.setup(outputStream); > + pipeline.execute(); > + outputStream.close(); > + } > +} > > Property changes on: > cocoon-imaging\src\test\java\org\apache\cocoon\imaging\PipelineTest.java > ___________________________________________________________________ > Added: svn:mime-type > + text/plain > Added: svn:keywords > + Id > Added: svn:eol-style > + native > > Index: cocoon-imaging/src/test/resources/sample.JPG > =================================================================== > Cannot display: file marked as a binary type. > svn:mime-type = image/jpeg > > Property changes on: cocoon-imaging\src\test\resources\sample.JPG > ___________________________________________________________________ > Added: svn:mime-type > + image/jpeg > > Index: > cocoon-imaging/src/main/java/org/apache/cocoon/imaging/utils/ImageUtils.java > =================================================================== > --- > cocoon-imaging/src/main/java/org/apache/cocoon/imaging/utils/ImageUtils.java > (revision 0) > +++ > cocoon-imaging/src/main/java/org/apache/cocoon/imaging/utils/ImageUtils.java > (revision 0) > @@ -0,0 +1,32 @@ > +package org.apache.cocoon.imaging.utils; > + > +import java.awt.geom.AffineTransform; > +import java.awt.image.AffineTransformOp; > +import java.awt.image.BufferedImage; > +import java.awt.image.BufferedImageOp; > +import java.awt.image.ColorModel; > +import java.awt.image.WritableRaster; > + > +public class ImageUtils { > + > + public static BufferedImage createCompatibleImage(BufferedImage image, > int targetWidth, int targetHeight) { > + ColorModel colorModel = image.getColorModel(); > + WritableRaster raster = > colorModel.createCompatibleWritableRaster(targetWidth, targetHeight); > + > + return new BufferedImage(colorModel, raster, > colorModel.isAlphaPremultiplied(), null); > + } > + > + public static BufferedImage getScaledImage(BufferedImage image, double > scaleFactor) { > + // calculate the target size > + int targetWidth = (int) (image.getWidth() * scaleFactor); > + int targetHeight = (int) (image.getHeight() * scaleFactor); > + > + // build the target image > + BufferedImage result = createCompatibleImage(image, targetWidth, > targetHeight); > + > + // apply the transformation > + BufferedImageOp op = new > AffineTransformOp(AffineTransform.getScaleInstance(scaleFactor, > scaleFactor), > + AffineTransformOp.TYPE_BICUBIC); > + return op.filter(image, result); > + } > +} > > Property changes on: > cocoon-imaging\src\main\java\org\apache\cocoon\imaging\utils\ImageUtils.java > ___________________________________________________________________ > Added: svn:mime-type > + text/plain > Added: svn:keywords > + Id > Added: svn:eol-style > + native > > Index: > cocoon-imaging/src/main/java/org/apache/cocoon/imaging/components/WatermarkImageTransformer.java > =================================================================== > --- > cocoon-imaging/src/main/java/org/apache/cocoon/imaging/components/WatermarkImageTransformer.java > (revision 0) > +++ > cocoon-imaging/src/main/java/org/apache/cocoon/imaging/components/WatermarkImageTransformer.java > (revision 0) > @@ -0,0 +1,58 @@ > +package org.apache.cocoon.imaging.components; > + > +import java.awt.Color; > +import java.awt.Font; > +import java.awt.Graphics2D; > +import java.awt.RenderingHints; > +import java.awt.font.LineMetrics; > +import java.awt.geom.Rectangle2D; > +import java.awt.image.BufferedImage; > + > +import org.apache.cocoon.imaging.AbstractImageTransformer; > + > +public class WatermarkImageTransformer extends AbstractImageTransformer { > + > + private final int alpha; > + private final String color; > + private final String text; > + > + public WatermarkImageTransformer() { > + this("WATERMARK", "0xFF0000", 80); > + } > + > + public WatermarkImageTransformer(String text, String color, int alpha) > { > + super(); > + > + this.color = color; > + this.text = text; > + this.alpha = alpha; > + } > + > + /** > + * {...@inheritdoc} > + * > + * @see > org.apache.cocoon.imaging.AbstractImageTransformer#transformImage(java.awt.image.BufferedImage) > + */ > + @Override > + protected BufferedImage transformImage(BufferedImage bufferedImage) { > + int width = bufferedImage.getWidth(); > + int height = bufferedImage.getHeight(); > + > + Graphics2D graphics = bufferedImage.createGraphics(); > + graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, > RenderingHints.VALUE_ANTIALIAS_ON); > + graphics.setRenderingHint(RenderingHints.KEY_RENDERING, > RenderingHints.VALUE_RENDER_QUALITY); > + > + Color rawColor = Color.decode(this.color); > + graphics.setColor(new Color(rawColor.getRed(), rawColor.getGreen(), > rawColor.getBlue(), this.alpha)); > + graphics.setFont(new Font("Arial", Font.BOLD | Font.ITALIC, 24)); > + > + Rectangle2D stringBounds = > graphics.getFontMetrics().getStringBounds(this.text, graphics); > + LineMetrics lineMetrics = > graphics.getFontMetrics().getLineMetrics(this.text, graphics); > + > + int x = (int) (width - stringBounds.getWidth()) / 2; > + int y = (int) ((height - stringBounds.getHeight()) / 2 + > lineMetrics.getAscent()); > + graphics.drawString(this.text, x, y); > + > + return bufferedImage; > + } > +} > > Property changes on: > cocoon-imaging\src\main\java\org\apache\cocoon\imaging\components\WatermarkImageTransformer.java > ___________________________________________________________________ > Added: svn:mime-type > + text/plain > Added: svn:keywords > + Id > Added: svn:eol-style > + native > > Index: > cocoon-imaging/src/main/java/org/apache/cocoon/imaging/components/RotateImageTransformer.java > =================================================================== > --- > cocoon-imaging/src/main/java/org/apache/cocoon/imaging/components/RotateImageTransformer.java > (revision 0) > +++ > cocoon-imaging/src/main/java/org/apache/cocoon/imaging/components/RotateImageTransformer.java > (revision 0) > @@ -0,0 +1,61 @@ > +package org.apache.cocoon.imaging.components; > + > +import java.awt.Color; > +import java.awt.Graphics2D; > +import java.awt.geom.AffineTransform; > +import java.awt.geom.Rectangle2D; > +import java.awt.image.AffineTransformOp; > +import java.awt.image.BufferedImage; > +import java.awt.image.BufferedImageOp; > + > +import org.apache.cocoon.imaging.AbstractImageTransformer; > +import org.apache.cocoon.imaging.utils.ImageUtils; > + > +public class RotateImageTransformer extends AbstractImageTransformer { > + > + private final String background; > + private final double radians; > + > + public RotateImageTransformer() { > + this(Math.PI / 2); > + } > + > + public RotateImageTransformer(double radians) { > + this(radians, null); > + } > + > + public RotateImageTransformer(double radians, String background) { > + super(); > + this.radians = radians; > + this.background = background; > + } > + > + @Override > + protected BufferedImage transformImage(BufferedImage image) { > + // create the transformation for rotating the image > + AffineTransform transformation = > AffineTransform.getRotateInstance(this.radians); > + > + // calculate the target bounds after the rotation > + Rectangle2D transformedBounds = > transformation.createTransformedShape( > + new Rectangle2D.Double(0, 0, image.getWidth(), > image.getHeight())).getBounds2D(); > + > + // create the target image > + int targetWidth = (int) transformedBounds.getWidth(); > + int targetHeight = (int) transformedBounds.getHeight(); > + BufferedImage result = ImageUtils.createCompatibleImage(image, > targetWidth, targetHeight); > + > + if (this.background != null) { > + // fill with background > + Graphics2D graphics = result.createGraphics(); > + graphics.setColor(Color.decode(this.background)); > + graphics.fillRect(0, 0, targetWidth, targetHeight); > + } > + > + // prepend a transformation that moves the image back to the (0, 0) > coordinates > + > > transformation.preConcatenate(AffineTransform.getTranslateInstance(-transformedBounds.getX(), > -transformedBounds.getY())); > + > + // apply the transformation > + BufferedImageOp op = new AffineTransformOp(transformation, > AffineTransformOp.TYPE_BICUBIC); > + return op.filter(image, result); > + } > +} > > Property changes on: > cocoon-imaging\src\main\java\org\apache\cocoon\imaging\components\RotateImageTransformer.java > ___________________________________________________________________ > Added: svn:mime-type > + text/plain > Added: svn:keywords > + Id > Added: svn:eol-style > + native > > Index: > cocoon-imaging/src/main/java/org/apache/cocoon/imaging/components/MaxSizeImageTransformer.java > =================================================================== > --- > cocoon-imaging/src/main/java/org/apache/cocoon/imaging/components/MaxSizeImageTransformer.java > (revision 0) > +++ > cocoon-imaging/src/main/java/org/apache/cocoon/imaging/components/MaxSizeImageTransformer.java > (revision 0) > @@ -0,0 +1,58 @@ > +package org.apache.cocoon.imaging.components; > + > +import java.awt.image.BufferedImage; > + > +import org.apache.cocoon.imaging.AbstractImageTransformer; > +import org.apache.cocoon.imaging.utils.ImageUtils; > + > +public class MaxSizeImageTransformer extends AbstractImageTransformer { > + > + private int maxHeight; > + private int maxWidth; > + > + public MaxSizeImageTransformer() { > + this(-1, -1); > + } > + > + public MaxSizeImageTransformer(int maxWidth, int maxHeight) { > + super(); > + > + this.maxHeight = maxHeight; > + this.maxWidth = maxWidth; > + } > + > + @Override > + protected BufferedImage transformImage(BufferedImage image) { > + double scaleFactor = this.getScaleFactor(image); > + if (scaleFactor == 1) { > + // no scaling needed > + return image; > + } > + > + return ImageUtils.getScaledImage(image, scaleFactor); > + } > + > + private double getScaleFactor(BufferedImage image) { > + int imageWidth = image.getWidth(); > + int imageHeight = image.getHeight(); > + > + if (this.maxHeight == -1 && this.maxWidth == -1) { > + return 1; > + } > + > + if (imageWidth <= this.maxWidth && imageHeight <= this.maxHeight) { > + return 1; > + } > + > + double imageRatio = (double) imageWidth / imageHeight; > + double maxRatio = (double) this.maxWidth / this.maxHeight; > + > + if (imageRatio > maxRatio) { > + // scale by width > + return (double) this.maxWidth / image.getWidth(); > + } > + > + // scale by height > + return (double) this.maxHeight / image.getHeight(); > + } > +} > > Property changes on: > cocoon-imaging\src\main\java\org\apache\cocoon\imaging\components\MaxSizeImageTransformer.java > ___________________________________________________________________ > Added: svn:mime-type > + text/plain > Added: svn:keywords > + Id > Added: svn:eol-style > + native > > Index: > cocoon-imaging/src/main/java/org/apache/cocoon/imaging/components/CropImageTransformer.java > =================================================================== > --- > cocoon-imaging/src/main/java/org/apache/cocoon/imaging/components/CropImageTransformer.java > (revision 0) > +++ > cocoon-imaging/src/main/java/org/apache/cocoon/imaging/components/CropImageTransformer.java > (revision 0) > @@ -0,0 +1,36 @@ > +package org.apache.cocoon.imaging.components; > + > +import java.awt.image.BufferedImage; > + > +import org.apache.cocoon.imaging.AbstractImageTransformer; > + > +public class CropImageTransformer extends AbstractImageTransformer { > + > + private int cropHeight; > + private int cropWidth; > + > + public CropImageTransformer(int cropWidth, int cropHeight) { > + super(); > + > + this.cropWidth = cropWidth; > + this.cropHeight = cropHeight; > + } > + > + @Override > + protected BufferedImage transformImage(BufferedImage image) { > + int imageWidth = image.getWidth(); > + int imageHeight = image.getHeight(); > + > + if (imageWidth < this.cropWidth && imageHeight < this.cropHeight) { > + return image; > + } > + > + int targetWidth = Math.min(this.cropWidth, imageWidth); > + int targetHeight = Math.min(this.cropHeight, imageHeight); > + > + int dx = (imageWidth - targetWidth) / 2; > + int dy = (imageHeight - targetHeight) / 2; > + > + return image.getSubimage(dx, dy, targetWidth, targetHeight); > + } > +} > > Property changes on: > cocoon-imaging\src\main\java\org\apache\cocoon\imaging\components\CropImageTransformer.java > ___________________________________________________________________ > Added: svn:mime-type > + text/plain > Added: svn:keywords > + Id > Added: svn:eol-style > + native > > Index: > cocoon-imaging/src/main/java/org/apache/cocoon/imaging/components/ScaleImageTransformer.java > =================================================================== > --- > cocoon-imaging/src/main/java/org/apache/cocoon/imaging/components/ScaleImageTransformer.java > (revision 0) > +++ > cocoon-imaging/src/main/java/org/apache/cocoon/imaging/components/ScaleImageTransformer.java > (revision 0) > @@ -0,0 +1,25 @@ > +package org.apache.cocoon.imaging.components; > + > +import java.awt.image.BufferedImage; > + > +import org.apache.cocoon.imaging.AbstractImageTransformer; > +import org.apache.cocoon.imaging.utils.ImageUtils; > + > +public class ScaleImageTransformer extends AbstractImageTransformer { > + > + private double scaleFactor; > + > + public ScaleImageTransformer(double scaleFactor) { > + super(); > + this.scaleFactor = scaleFactor; > + } > + > + @Override > + protected BufferedImage transformImage(BufferedImage image) { > + if (this.scaleFactor <= 0) { > + return image; > + } > + > + return ImageUtils.getScaledImage(image, this.scaleFactor); > + } > +} > > Property changes on: > cocoon-imaging\src\main\java\org\apache\cocoon\imaging\components\ScaleImageTransformer.java > ___________________________________________________________________ > Added: svn:mime-type > + text/plain > Added: svn:keywords > + Id > Added: svn:eol-style > + native > > Index: > cocoon-imaging/src/main/java/org/apache/cocoon/imaging/ImageProducer.java > =================================================================== > --- > cocoon-imaging/src/main/java/org/apache/cocoon/imaging/ImageProducer.java > (revision 0) > +++ > cocoon-imaging/src/main/java/org/apache/cocoon/imaging/ImageProducer.java > (revision 0) > @@ -0,0 +1,7 @@ > +package org.apache.cocoon.imaging; > + > +import org.apache.cocoon.pipeline.component.Producer; > + > +public interface ImageProducer extends Producer { > + > +} > > Property changes on: > cocoon-imaging\src\main\java\org\apache\cocoon\imaging\ImageProducer.java > ___________________________________________________________________ > Added: svn:mime-type > + text/plain > Added: svn:keywords > + Id > Added: svn:eol-style > + native > > Index: > cocoon-imaging/src/main/java/org/apache/cocoon/imaging/AbstractImageTransformer.java > =================================================================== > --- > cocoon-imaging/src/main/java/org/apache/cocoon/imaging/AbstractImageTransformer.java > (revision 0) > +++ > cocoon-imaging/src/main/java/org/apache/cocoon/imaging/AbstractImageTransformer.java > (revision 0) > @@ -0,0 +1,13 @@ > +package org.apache.cocoon.imaging; > + > +import java.awt.image.BufferedImage; > + > +public abstract class AbstractImageTransformer extends > AbstractImageProducer implements ImageConsumer { > + > + public void process(BufferedImage image) { > + BufferedImage transformedImage = this.transformImage(image); > + this.getConsumer().process(transformedImage); > + } > + > + protected abstract BufferedImage transformImage(BufferedImage image); > +} > > Property changes on: > cocoon-imaging\src\main\java\org\apache\cocoon\imaging\AbstractImageTransformer.java > ___________________________________________________________________ > Added: svn:mime-type > + text/plain > Added: svn:keywords > + Id > Added: svn:eol-style > + native > > Index: > cocoon-imaging/src/main/java/org/apache/cocoon/imaging/ImageGenerator.java > =================================================================== > --- > cocoon-imaging/src/main/java/org/apache/cocoon/imaging/ImageGenerator.java > (revision 0) > +++ > cocoon-imaging/src/main/java/org/apache/cocoon/imaging/ImageGenerator.java > (revision 0) > @@ -0,0 +1,40 @@ > +package org.apache.cocoon.imaging; > + > +import java.awt.image.BufferedImage; > +import java.io.IOException; > +import java.net.URL; > + > +import javax.imageio.ImageIO; > + > +import org.apache.cocoon.imaging.utils.ImageUtils; > +import org.apache.cocoon.pipeline.ProcessingException; > +import org.apache.cocoon.pipeline.component.Starter; > + > +public class ImageGenerator extends AbstractImageProducer implements > Starter { > + > + private final URL source; > + > + public ImageGenerator() { > + this(null); > + } > + > + public ImageGenerator(URL source) { > + super(); > + this.source = source; > + } > + > + public void execute() { > + BufferedImage image; > + try { > + image = ImageIO.read(this.source); > + } catch (IOException e) { > + throw new ProcessingException("Could not load image from " + > this.source, e); > + } > + > + // make sure the WritableRaster of the image is okay > + BufferedImage bufferedImage = > ImageUtils.createCompatibleImage(image, image.getWidth(), > image.getHeight()); > + image.copyData(bufferedImage.getRaster()); > + > + this.getConsumer().process(bufferedImage); > + } > +} > > Property changes on: > cocoon-imaging\src\main\java\org\apache\cocoon\imaging\ImageGenerator.java > ___________________________________________________________________ > Added: svn:mime-type > + text/plain > Added: svn:keywords > + Id > Added: svn:eol-style > + native > > Index: > cocoon-imaging/src/main/java/org/apache/cocoon/imaging/AbstractImageProducer.java > =================================================================== > --- > cocoon-imaging/src/main/java/org/apache/cocoon/imaging/AbstractImageProducer.java > (revision 0) > +++ > cocoon-imaging/src/main/java/org/apache/cocoon/imaging/AbstractImageProducer.java > (revision 0) > @@ -0,0 +1,24 @@ > +package org.apache.cocoon.imaging; > + > +import org.apache.cocoon.pipeline.SetupException; > +import org.apache.cocoon.pipeline.component.AbstractPipelineComponent; > +import org.apache.cocoon.pipeline.component.Consumer; > + > +public abstract class AbstractImageProducer extends > AbstractPipelineComponent implements ImageProducer { > + > + private ImageConsumer consumer; > + > + public final void setConsumer(Consumer consumer) { > + if (!(consumer instanceof ImageConsumer)) { > + throw new SetupException("ImageProducer cannot accept consumer > of type " > + + (consumer == null ? "null" : consumer.getClass() + ". > A component of type " + ImageConsumer.class > + + " is required.")); > + } > + > + this.consumer = (ImageConsumer) consumer; > + } > + > + protected ImageConsumer getConsumer() { > + return this.consumer; > + } > +} > > Property changes on: > cocoon-imaging\src\main\java\org\apache\cocoon\imaging\AbstractImageProducer.java > ___________________________________________________________________ > Added: svn:mime-type > + text/plain > Added: svn:keywords > + Id > Added: svn:eol-style > + native > > Index: > cocoon-imaging/src/main/java/org/apache/cocoon/imaging/ImageSerializer.java > =================================================================== > --- > cocoon-imaging/src/main/java/org/apache/cocoon/imaging/ImageSerializer.java > (revision 0) > +++ > cocoon-imaging/src/main/java/org/apache/cocoon/imaging/ImageSerializer.java > (revision 0) > @@ -0,0 +1,33 @@ > +package org.apache.cocoon.imaging; > + > +import java.awt.image.BufferedImage; > +import java.io.IOException; > +import java.io.OutputStream; > + > +import javax.imageio.ImageIO; > + > +import org.apache.cocoon.pipeline.ProcessingException; > +import org.apache.cocoon.pipeline.component.AbstractPipelineComponent; > +import org.apache.cocoon.pipeline.component.Finisher; > + > +public class ImageSerializer extends AbstractPipelineComponent implements > ImageConsumer, Finisher { > + > + private OutputStream outputStream; > + > + public String getContentType() { > + return "image/jpeg"; > + } > + > + public void process(BufferedImage image) { > + try { > + ImageIO.write(image, "JPG", this.outputStream); > + this.outputStream.flush(); > + } catch (IOException e) { > + throw new ProcessingException("Failed to write image data to > the output.", e); > + } > + } > + > + public void setOutputStream(OutputStream outputStream) { > + this.outputStream = outputStream; > + } > +} > > Property changes on: > cocoon-imaging\src\main\java\org\apache\cocoon\imaging\ImageSerializer.java > ___________________________________________________________________ > Added: svn:mime-type > + text/plain > Added: svn:keywords > + Id > Added: svn:eol-style > + native > > Index: > cocoon-imaging/src/main/java/org/apache/cocoon/imaging/ImageConsumer.java > =================================================================== > --- > cocoon-imaging/src/main/java/org/apache/cocoon/imaging/ImageConsumer.java > (revision 0) > +++ > cocoon-imaging/src/main/java/org/apache/cocoon/imaging/ImageConsumer.java > (revision 0) > @@ -0,0 +1,11 @@ > +package org.apache.cocoon.imaging; > + > +import java.awt.image.BufferedImage; > + > +import org.apache.cocoon.pipeline.component.Consumer; > + > +public interface ImageConsumer extends Consumer { > + > + void process(BufferedImage image); > + > +} > > Property changes on: > cocoon-imaging\src\main\java\org\apache\cocoon\imaging\ImageConsumer.java > ___________________________________________________________________ > Added: svn:mime-type > + text/plain > Added: svn:keywords > + Id > Added: svn:eol-style > + native > > Index: cocoon-imaging/pom.xml > =================================================================== > --- cocoon-imaging/pom.xml (revision 0) > +++ cocoon-imaging/pom.xml (revision 0) > @@ -0,0 +1,65 @@ > +<?xml version="1.0" encoding="UTF-8"?> > +<!-- > + Licensed to the Apache Software Foundation (ASF) under one > + or more contributor license agreements. See the NOTICE file > + distributed with this work for additional information > + regarding copyright ownership. The ASF licenses this file > + to you 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. > + --> > +<!-- $Id$ --> > +<project xmlns="http://maven.apache.org/POM/4.0.0" > xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" > xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 > http://maven.apache.org/maven-v4_0_0.xsd"> > + > + <modelVersion>4.0.0</modelVersion> > + <packaging>jar</packaging> > + > + <parent> > + <groupId>org.apache.cocoon.parent</groupId> > + <artifactId>cocoon-parent</artifactId> > + <version>3.0.0-alpha-2-SNAPSHOT</version> > + <relativePath>../parent</relativePath> > + </parent> > + > + <groupId>org.apache.cocoon.imaging</groupId> > + <artifactId>cocoon-imaging</artifactId> > + <name>Cocoon 3: Imaging</name> > + <version>3.0.0-alpha-2-SNAPSHOT</version> > + <description>Cocoon 3 Imaging pipeline components.</description> > + > + <dependencies> > + <dependency> > + <groupId>org.apache.cocoon.pipeline</groupId> > + <artifactId>cocoon-pipeline</artifactId> > + </dependency> > + <dependency> > + <groupId>commons-logging</groupId> > + <artifactId>commons-logging</artifactId> > + <exclusions> > + <exclusion> > + <artifactId>logkit</artifactId> > + <groupId>logkit</groupId> > + </exclusion> > + <exclusion> > + <artifactId>avalon-framework</artifactId> > + <groupId>avalon-framework</groupId> > + </exclusion> > + </exclusions> > + </dependency> > + > + <dependency> > + <groupId>junit</groupId> > + <artifactId>junit</artifactId> > + <scope>test</scope> > + </dependency> > + </dependencies> > +</project> > > Property changes on: cocoon-imaging\pom.xml > ___________________________________________________________________ > Added: svn:mime-type > + text/xml > Added: svn:keywords > + Id > Added: svn:eol-style > + native > > Index: pom.xml > =================================================================== > --- pom.xml (revision 734187) > +++ pom.xml (working copy) > @@ -40,6 +40,7 @@ > <module>cocoon-stringtemplate</module> > <module>parent</module> > <module>cocoon-sax</module> > + <module>cocoon-imaging</module> > </modules> > > <build> > > -- My LinkedIn profile: http://www.linkedin.com/in/simonetripodi My GoogleCode profile: http://code.google.com/u/simone.tripodi/ My Picasa: http://picasaweb.google.com/simone.tripodi/ My Tube: http://www.youtube.com/user/stripodi My Del.icio.us: http://del.icio.us/simone.tripodi
