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

Reply via email to