Package org.apache.cocoon.reading.imageop

Source Code of org.apache.cocoon.reading.imageop.ImageOpReader

/*
* 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.
*/
package org.apache.cocoon.reading.imageop;

import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.WritableRaster;

import javax.imageio.ImageIO;
import javax.imageio.ImageTypeSpecifier;
import javax.imageio.ImageWriter;
import javax.imageio.stream.ImageOutputStream;
import javax.imageio.spi.ImageWriterSpi;

import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;

import java.util.ArrayList;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;

import org.apache.avalon.framework.configuration.Configurable;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;

import org.apache.avalon.framework.component.Composable;
import org.apache.avalon.framework.component.ComponentException;
import org.apache.avalon.framework.component.ComponentManager;
import org.apache.avalon.framework.component.ComponentSelector;

import org.apache.avalon.framework.parameters.Parameters;

import org.apache.cocoon.ProcessingException;

import org.apache.cocoon.environment.SourceResolver;

import org.apache.cocoon.reading.ResourceReader;

import org.xml.sax.SAXException;

/**
* The <code>ImageOpReader</code> component is used to serve binary image data
* in a sitemap pipeline. It makes use of HTTP Headers to determine if
* the requested resource should be written to the <code>OutputStream</code>
* or if it can signal that it hasn't changed.
*/
final public class ImageOpReader extends ResourceReader
    implements Configurable, Composable
{
    private final static String FORMAT_DEFAULT = "png";
   
    private String            m_Format;
    private ArrayList         m_EffectsStack;
    private ComponentSelector m_OperationSelector;
   
    /**
     * Read reader configuration
     */
    public void configure(Configuration configuration)
        throws ConfigurationException
    {
        super.configure( configuration );
        Configuration effects = configuration.getChild( "effects" );
        try
        {
            configureEffects( effects );
        } catch( ComponentException e )
        {
            throw new ConfigurationException( "Unable to configure ImageOperations", e );
        }
    }

    public void compose( ComponentManager man )
        throws ComponentException
    {
        m_OperationSelector = (ComponentSelector) man.lookup( "org.apache.cocoon.reading.imageop.ImageOperationSelector" );
    }
   
    public void setup(SourceResolver resolver, Map objectModel, String src, Parameters par)
        throws ProcessingException, SAXException, IOException
    {
        super.setup(resolver, objectModel, src, par);
        m_Format = par.getParameter("output-format", FORMAT_DEFAULT);
        if(getLogger().isInfoEnabled()) {
            getLogger().info( src + " --> " + m_Format );
        }
        setupEffectsStack( par );
    }

    protected void processStream( InputStream inputStream )
        throws IOException, ProcessingException
    {
        if( m_EffectsStack.size() > 0 )
        {
            // since we create the image on the fly
            response.setHeader("Accept-Ranges", "none");

            BufferedImage image = ImageIO.read( inputStream );
            if( image == null )
                throw new ProcessingException( "Unable to decode the InputStream. Possibly an unknown format." );               

            image = applyEffectsStack( image );
                       
            write( image );
        } else {
            // only read the resource - no modifications requested
            if (getLogger().isDebugEnabled()) {
                getLogger().debug("passing original resource");
            }
            super.processStream(inputStream);
        }
    }

    /**
     * Generate the unique key.
     * This key must be unique inside the space of this component.
     *
     * @return The generated key consists of the src and width and height, and the color transform
     * parameters
    */
    public Serializable getKey()
    {
        StringBuffer b = new StringBuffer( 200 );
        b.append( this.inputSource.getURI() );
        b.append( ':' );
        b.append( m_Format );
        b.append( ':' );
        b.append( super.getKey() );
        b.append( ':' );
        Iterator list = m_EffectsStack.iterator();
        while( list.hasNext() )
        {
            ImageOperation op = (ImageOperation) list.next();
            b.append( op.getKey() );
            b.append( ':' );
        }
        String key = b.toString();
        b.setLength( 0 );   // Seems to be something odd (memory leak?)
                            // going on if this isn't done. (JDK1.4.2)
        return key;
    }
   
    private void configureEffects( Configuration conf )
        throws ConfigurationException, ComponentException
    {
        m_EffectsStack = new ArrayList();
       
        Configuration[] ops = conf.getChildren( "op" );
        for( int i=0 ; i < ops.length ; i++ )
        {
            String type = ops[i].getAttribute( "type" );
            String prefix = ops[i].getAttribute( "prefix", type + "-" );
            ImageOperation op = (ImageOperation) m_OperationSelector.select( type );
            op.setPrefix( prefix );
            m_EffectsStack.add( op );
        }
    }

    private void setupEffectsStack( Parameters params )
        throws ProcessingException
    {
        Iterator list = m_EffectsStack.iterator();
        while( list.hasNext() )
        {
            ImageOperation op = (ImageOperation) list.next();
            op.setup( params );
        }
    }
   
    private BufferedImage applyEffectsStack( BufferedImage image )
    {
        if( m_EffectsStack.size() == 0 )
            return image;
        Iterator list = m_EffectsStack.iterator();
        WritableRaster src = image.getRaster();
        while( list.hasNext() )
        {
            ImageOperation op = (ImageOperation) list.next();
            WritableRaster r = op.apply( src );
            if(getLogger().isDebugEnabled()) {
                getLogger().debug( "In Bounds: " + r.getBounds() );
            }
            src = r.createWritableTranslatedChild( 0, 0 );
        }
        ColorModel cm = image.getColorModel();
        if(getLogger().isDebugEnabled()) {
            getLogger().debug( "Out Bounds: " + src.getBounds() );
        }
        BufferedImage newImage = new BufferedImage( cm, src, true, new Hashtable() );
        // Not sure what this should really be --------------^^^^^
       
        int minX = newImage.getMinX();
        int minY = newImage.getMinY();
        int width = newImage.getWidth();
        int height = newImage.getHeight();       
        if(getLogger().isInfoEnabled()) {
            getLogger().info( "Image: " + minX + ", " + minY + ", " + width + ", " + height );
        }
       
        return newImage;
    }
   
    private void write( BufferedImage image )
        throws ProcessingException, IOException
    {
        ImageTypeSpecifier its = ImageTypeSpecifier.createFromRenderedImage( image );
        Iterator writers = ImageIO.getImageWriters( its, m_Format );
        ImageWriter writer = null;
        if( writers.hasNext() )
        {
            writer = (ImageWriter) writers.next();
        }
        if( writer == null )
            throw new ProcessingException( "Unable to find a ImageWriter: " + m_Format );

        ImageWriterSpi spi = writer.getOriginatingProvider();
        String[] mimetypes = spi.getMIMETypes();
        if(getLogger().isInfoEnabled()) {
            getLogger().info( "Setting content-type: " + mimetypes[0] );
        }
        response.setHeader("Content-Type", mimetypes[0] );
        ImageOutputStream output = ImageIO.createImageOutputStream( out );
        try
        {
            writer.setOutput( output );
            writer.write( image );
        } finally
        {
            writer.dispose();
            output.close();
            out.flush();
            // Niclas Hedhman: Stream is closed in superclass.
        }
    }
/*   
    private void printRaster( WritableRaster r )
    {
        DataBuffer data = r.getDataBuffer();
        int numBanks = data.getNumBanks();
        int size = data.getSize();
        for( int i=0 ; i < size ; i++ )
        {
            long value = 0;
            for( int j=0 ; j < numBanks ; j++ )
            {
                int v = data.getElem( j, i );
                if( v < 256 )
                    value = value << 8 ;
                else
                    value = value << 16;
                value = value + v;
            }
            if(getLogger().isDebugEnabled()) {
                getLogger().debug( Long.toHexString( value ) );
            }
        }
    }
*/
TOP

Related Classes of org.apache.cocoon.reading.imageop.ImageOpReader

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.