Package org.apache.xmlgraphics.image.rendered

Source Code of org.apache.xmlgraphics.image.rendered.Any2sRGBRed

/*
* 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: Any2sRGBRed.java 496556 2007-01-16 00:59:48Z cam $ */

package org.apache.xmlgraphics.image.rendered;

import java.awt.color.ColorSpace;
import java.awt.image.BandCombineOp;
import java.awt.image.BufferedImage;
import java.awt.image.ColorConvertOp;
import java.awt.image.ColorModel;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferInt;
import java.awt.image.Raster;
import java.awt.image.SampleModel;
import java.awt.image.SinglePixelPackedSampleModel;
import java.awt.image.WritableRaster;

import org.apache.xmlgraphics.image.GraphicsUtil;

/**
* This function will tranform an image from any colorspace into a
* luminance image.  The alpha channel if any will be copied to the
* new image.
*
* @author <a href="mailto:Thomas.DeWeeese@Kodak.com">Thomas DeWeese</a>
* @version $Id: Any2sRGBRed.java 496556 2007-01-16 00:59:48Z cam $ */
public class Any2sRGBRed extends AbstractRed {

    boolean srcIsLsRGB = false;

    /**
     * Construct a luminace image from src.
     *
     * @param src The image to convert to a luminance image
     */
    public Any2sRGBRed(CachableRed src) {
        super(src,src.getBounds(),
              fixColorModel(src),
              fixSampleModel(src),
              src.getTileGridXOffset(),
              src.getTileGridYOffset(),
              null);

        ColorModel srcCM = src.getColorModel();
        if (srcCM == null) return;
        ColorSpace srcCS = srcCM.getColorSpace();
        if (srcCS == ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB))
            srcIsLsRGB = true;
    }

    public static boolean is_INT_PACK_COMP(SampleModel sm) {
        if(!(sm instanceof SinglePixelPackedSampleModel)) return false;

        // Check transfer types
        if(sm.getDataType() != DataBuffer.TYPE_INT)       return false;

        SinglePixelPackedSampleModel sppsm;
        sppsm = (SinglePixelPackedSampleModel)sm;

        int [] masks = sppsm.getBitMasks();
        if ((masks.length != 3) && (masks.length != 4)) return false;
        if(masks[0] != 0x00ff0000) return false;
        if(masks[1] != 0x0000ff00) return false;
        if(masks[2] != 0x000000ff) return false;
        if ((masks.length == 4) &&
            (masks[3] != 0xff000000)) return false;

        return true;
   }

    /**
     * Exponent for linear to sRGB convertion
     */
    private static final double GAMMA = 2.4;

    /**
     * Lookup tables for RGB lookups. The linearToSRGBLut is used
     * when noise values are considered to be on a linearScale. The
     * linearToLinear table is used when the values are considered to
     * be on the sRGB scale to begin with.
     */
    private static final int[] linearToSRGBLut = new int[256];
    static {
        final double scale = 1.0/255;
        final double exp   = 1.0/GAMMA;
        // System.out.print("L2S: ");
        for(int i=0; i<256; i++){
            double value = i*scale;
            if(value <= 0.0031308)
                value *= 12.92;
            else
                value = 1.055 * Math.pow(value, exp) - 0.055;

            linearToSRGBLut[i] = (int)Math.round(value*255.);
            // System.out.print(linearToSRGBLut[i] + ",");
        }
        // System.out.println("");
    }

    public static WritableRaster applyLut_INT(WritableRaster wr,
                                              final int []lut) {
        SinglePixelPackedSampleModel sm =
            (SinglePixelPackedSampleModel)wr.getSampleModel();
        DataBufferInt db = (DataBufferInt)wr.getDataBuffer();

        final int     srcBase
            = (db.getOffset() +
               sm.getOffset(wr.getMinX()-wr.getSampleModelTranslateX(),
                            wr.getMinY()-wr.getSampleModelTranslateY()));
        // Access the pixel data array
        final int[] pixels   = db.getBankData()[0];
        final int width      = wr.getWidth();
        final int height     = wr.getHeight();
        final int scanStride = sm.getScanlineStride();

        int end, pix;

        // For alpha premult we need to multiply all comps.
        for (int y=0; y<height; y++) {
            int sp  = srcBase + y*scanStride;
            end = sp + width;

            while (sp<end) {
                pix = pixels[sp];
                pixels[sp] =
                    ((     pix      &0xFF000000)|
                     (lut[(pix>>>16)&0xFF]<<16) |
                     (lut[(pix>>> 8)&0xFF]<< 8) |
                     (lut[(pix     )&0xFF]    ));
                sp++;
            }
        }

        return wr;
    }

    public WritableRaster copyData(WritableRaster wr) {

        // Get my source.
        CachableRed src   = (CachableRed)getSources().get(0);
        ColorModel  srcCM = src.getColorModel();
        SampleModel srcSM = src.getSampleModel();


        // Fast case, Linear SRGB source, INT Pack writable raster...
        if (srcIsLsRGB &&
            is_INT_PACK_COMP(wr.getSampleModel())) {
            src.copyData(wr);
            if (srcCM.hasAlpha())
                GraphicsUtil.coerceData(wr, srcCM, false);
            applyLut_INT(wr, linearToSRGBLut);
            return wr;
        }

        if (srcCM == null) {
            // We don't really know much about this source, let's
            // guess based on the number of bands...

            float [][] matrix = null;
            switch (srcSM.getNumBands()) {
            case 1:
                matrix = new float[3][1];
                matrix[0][0] = 1; // Red
                matrix[1][0] = 1; // Grn
                matrix[2][0] = 1; // Blu
                break;
            case 2:
                matrix = new float[4][2];
                matrix[0][0] = 1; // Red
                matrix[1][0] = 1; // Grn
                matrix[3][0] = 1; // Blu
                matrix[3][1] = 1; // Alpha
                break;
            case 3:
                matrix = new float[3][3];
                matrix[0][0] = 1; // Red
                matrix[1][1] = 1; // Grn
                matrix[2][2] = 1; // Blu
                break;
            default:
                matrix = new float[4][srcSM.getNumBands()];
                matrix[0][0] = 1; // Red
                matrix[1][1] = 1; // Grn
                matrix[2][2] = 1; // Blu
                matrix[3][3] = 1; // Alpha
                break;
            }
            Raster srcRas = src.getData(wr.getBounds());
            BandCombineOp op = new BandCombineOp(matrix, null);
            op.filter(srcRas, wr);
            return wr;
        }

        if (srcCM.getColorSpace() ==
            ColorSpace.getInstance(ColorSpace.CS_GRAY)) {

            // This is a little bit of a hack.  There is only
            // a linear grayscale ICC profile in the JDK so
            // many things use this when the data _really_
            // has sRGB gamma applied.
            try {
            float [][] matrix = null;
            switch (srcSM.getNumBands()) {
            case 1:
                matrix = new float[3][1];
                matrix[0][0] = 1; // Red
                matrix[1][0] = 1; // Grn
                matrix[2][0] = 1; // Blu
                break;
            case 2:
            default:
                matrix = new float[4][2];
                matrix[0][0] = 1; // Red
                matrix[1][0] = 1; // Grn
                matrix[3][0] = 1; // Blu
                matrix[4][1] = 1; // Alpha
                break;
            }
            Raster srcRas = src.getData(wr.getBounds());
            BandCombineOp op = new BandCombineOp(matrix, null);
            op.filter(srcRas, wr);
            } catch (Throwable t) {
                t.printStackTrace();
            }
            return wr;
        }

        ColorModel dstCM = getColorModel();
        if (srcCM.getColorSpace() == dstCM.getColorSpace()) {
            // No transform needed, just reformat data...
            // System.out.println("Bypassing");

            if (is_INT_PACK_COMP(srcSM))
                src.copyData(wr);
            else
                GraphicsUtil.copyData(src.getData(wr.getBounds()), wr);

            return wr;
        }

        Raster srcRas = src.getData(wr.getBounds());
        WritableRaster srcWr  = (WritableRaster)srcRas;

        // Divide out alpha if we have it.  We need to do this since
        // the color convert may not be a linear operation which may
        // lead to out of range values.
        ColorModel srcBICM = srcCM;
        if (srcCM.hasAlpha())
            srcBICM = GraphicsUtil.coerceData(srcWr, srcCM, false);

        BufferedImage srcBI, dstBI;
        srcBI = new BufferedImage(srcBICM,
                                  srcWr.createWritableTranslatedChild(0,0),
                                  false,
                                  null);

        // System.out.println("src: " + srcBI.getWidth() + "x" +
        //                    srcBI.getHeight());

        ColorConvertOp op = new ColorConvertOp(dstCM.getColorSpace(),
                                               null);
        dstBI = op.filter(srcBI, null);

        // System.out.println("After filter:");

        WritableRaster wr00 = wr.createWritableTranslatedChild(0,0);
        for (int i=0; i<dstCM.getColorSpace().getNumComponents(); i++)
            copyBand(dstBI.getRaster(), i, wr00,    i);

        if (dstCM.hasAlpha())
            copyBand(srcWr, srcSM.getNumBands()-1,
                     wr,    getSampleModel().getNumBands()-1);
        return wr;
    }

        /**
         * This function 'fixes' the source's color model.  Right now
         * it just selects if it should have one or two bands based on
         * if the source had an alpha channel.
         */
    protected static ColorModel fixColorModel(CachableRed src) {
        ColorModel  cm = src.getColorModel();
        if (cm != null) {
            if (cm.hasAlpha())
                return GraphicsUtil.sRGB_Unpre;

            return GraphicsUtil.sRGB;
        }
        else {
            // No ColorModel so try to make some intelligent
            // decisions based just on the number of bands...
            // 1 bands -> replicated into RGB
            // 2 bands -> Band 0 replicated into RGB & Band 1 -> alpha premult
            // 3 bands -> sRGB (not-linear?)
            // 4 bands -> sRGB premult (not-linear?)
            SampleModel sm = src.getSampleModel();

            switch (sm.getNumBands()) {
            case 1:
                return GraphicsUtil.sRGB;
            case 2:
                return GraphicsUtil.sRGB_Unpre;
            case 3:
                return GraphicsUtil.sRGB;
            }
            return GraphicsUtil.sRGB_Unpre;
        }
    }

    /**
     * This function 'fixes' the source's sample model.
     * Right now it just selects if it should have 3 or 4 bands
     * based on if the source had an alpha channel.
     */
    protected static SampleModel fixSampleModel(CachableRed src) {
        SampleModel sm = src.getSampleModel();
        ColorModel  cm = src.getColorModel();

        boolean alpha = false;

        if (cm != null)
            alpha = cm.hasAlpha();
        else {
            switch (sm.getNumBands()) {
            case 1: case 3:
                alpha = false;
                break;
            default:
                alpha = true;
                break;
            }
        }
        if (alpha)
            return new SinglePixelPackedSampleModel
                (DataBuffer.TYPE_INT,
                 sm.getWidth(),
                 sm.getHeight(),
                 new int [] {0xFF0000, 0xFF00, 0xFF, 0xFF000000});
        else
            return new SinglePixelPackedSampleModel
                (DataBuffer.TYPE_INT,
                 sm.getWidth(),
                 sm.getHeight(),
                 new int [] {0xFF0000, 0xFF00, 0xFF});
    }
}
TOP

Related Classes of org.apache.xmlgraphics.image.rendered.Any2sRGBRed

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.