Package org.apache.pdfbox.pdmodel.graphics.shading

Source Code of org.apache.pdfbox.pdmodel.graphics.shading.Type4ShadingContext

/*
* 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.pdfbox.pdmodel.graphics.shading;

import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.awt.image.ColorModel;
import java.io.EOFException;
import java.io.IOException;
import java.util.ArrayList;
import javax.imageio.stream.ImageInputStream;
import javax.imageio.stream.MemoryCacheImageInputStream;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.pdfbox.cos.COSArray;
import org.apache.pdfbox.cos.COSDictionary;
import org.apache.pdfbox.cos.COSName;
import org.apache.pdfbox.cos.COSStream;
import org.apache.pdfbox.pdmodel.common.PDRange;
import org.apache.pdfbox.util.Matrix;

/**
* This represents the Paint of a type 4 (Gouraud triangle mesh) shading
* context.
*
* @author Tilman Hausherr
*/
class Type4ShadingContext extends GouraudShadingContext
{
    private static final Log LOG = LogFactory.getLog(Type4ShadingContext.class);

    private int bitsPerFlag;

    /**
     * Constructor creates an instance to be used for fill operations.
     *
     * @param shadingType4 the shading type to be used
     * @param colorModelValue the color model to be used
     * @param xform transformation for user to device space
     * @param ctm current transformation matrix
     * @param pageHeight height of the current page
     *
     */
    public Type4ShadingContext(PDShadingType4 shadingType4, ColorModel colorModelValue,
            AffineTransform xform, Matrix ctm, int pageHeight) throws IOException
    {
        super(shadingType4, colorModelValue, xform, ctm, pageHeight);

        ArrayList<Vertex> vertexList = new ArrayList<Vertex>();

        LOG.debug("Type4ShadingContext");

        bitsPerColorComponent = shadingType4.getBitsPerComponent();
        LOG.debug("bitsPerColorComponent: " + bitsPerColorComponent);
        bitsPerCoordinate = shadingType4.getBitsPerCoordinate();
        LOG.debug(Math.pow(2, bitsPerCoordinate) - 1);
        long maxSrcCoord = (int) Math.pow(2, bitsPerCoordinate) - 1;
        long maxSrcColor = (int) Math.pow(2, bitsPerColorComponent) - 1;
        LOG.debug("maxSrcCoord: " + maxSrcCoord);
        LOG.debug("maxSrcColor: " + maxSrcColor);

        COSDictionary cosDictionary = shadingType4.getCOSDictionary();
        COSStream cosStream = (COSStream) cosDictionary;

        //The Decode key specifies how
        //to decode coordinate and color component data into the ranges of values
        //appropriate for each. The ranges are specified as [xmin xmax ymin ymax c1,min,
        //c1,max,..., cn, min, cn,max].
        //
        // see p344
        COSArray decode = (COSArray) cosDictionary.getDictionaryObject(COSName.DECODE);
        LOG.debug("decode: " + decode);
        PDRange rangeX = shadingType4.getDecodeForParameter(0);
        PDRange rangeY = shadingType4.getDecodeForParameter(1);
        LOG.debug("rangeX: " + rangeX.getMin() + ", " + rangeX.getMax());
        LOG.debug("rangeY: " + rangeY.getMin() + ", " + rangeY.getMax());

        PDRange[] colRangeTab = new PDRange[numberOfColorComponents];
        for (int i = 0; i < numberOfColorComponents; ++i)
        {
            colRangeTab[i] = shadingType4.getDecodeForParameter(2 + i);
        }

        LOG.debug("bitsPerCoordinate: " + bitsPerCoordinate);
        bitsPerFlag = shadingType4.getBitsPerFlag();
        LOG.debug("bitsPerFlag: " + bitsPerFlag); //TODO handle cases where bitperflag isn't 8
        LOG.debug("Stream size: " + cosStream.getInt(COSName.LENGTH));

        // get background values if available
        COSArray bg = shadingType4.getBackground();
        if (bg != null)
        {
            background = bg.toFloatArray();
        }

        //TODO missing: BBox, AntiAlias (p. 305 in 1.7 spec)
        // p318:
        //  reading in sequence from higher-order to lower-order bit positions
        ImageInputStream mciis = new MemoryCacheImageInputStream(cosStream.getFilteredStream());
        while (true)
        {
            try
            {
                byte flag = (byte) (mciis.readBits(bitsPerFlag) & 3);
                LOG.debug("flag: " + flag);
                switch (flag)
                {
                    case 0:
                        Vertex v1 = readVertex(mciis, flag, maxSrcCoord, maxSrcColor, rangeX, rangeY, colRangeTab);
                        Vertex v2 = readVertex(mciis, (byte) mciis.readBits(bitsPerFlag), maxSrcCoord, maxSrcColor,
                                rangeX, rangeY, colRangeTab);
                        Vertex v3 = readVertex(mciis, (byte) mciis.readBits(bitsPerFlag), maxSrcCoord, maxSrcColor,
                                rangeX, rangeY, colRangeTab);

                        // add them after they're read, so that they are never added if there is a premature EOF
                        vertexList.add(v1);
                        vertexList.add(v2);
                        vertexList.add(v3);
                        break;
                    case 1:
                    case 2:
                        vertexList.add(readVertex(mciis, flag, maxSrcCoord, maxSrcColor, rangeX, rangeY, colRangeTab));
                        break;
                    default:
                        LOG.warn("bad flag: " + flag);
                        break;
                }
            }
            catch (EOFException ex)
            {
                LOG.debug("EOF");
                if (vertexList.size() < 3)
                {
                    LOG.warn("Incomplete mesh is ignored");
                    vertexList.clear();
                }
                else if (vertexList.size() > 1 && vertexList.get(0).flag != 0)
                {
                    LOG.warn("Mesh with incorrect start flag " + vertexList.get(0).flag + " is ignored");
                    vertexList.clear();
                }
                // check that there are 3 entries if there is a 0 flag
                int vi = 0;
                while (vi < vertexList.size())
                {
                    if (vertexList.get(vi).flag == 0)
                    {
                        if (vi + 2 >= vertexList.size())
                        {
                            LOG.warn("Mesh with incomplete triangle");
                            // remove rest
                            while (vertexList.size() >= vi + 1)
                            {
                                vertexList.remove(vi);
                            }
                            break;
                        }
                        vi += 3;
                    }
                    else
                    {
                        ++vi;
                    }
                }
                break;
            }
        }
        mciis.close();
        transformVertices(vertexList, ctm, xform, pageHeight);
        createTriangleList(vertexList);
    }

    /**
     * Create GouraudTriangle list from vertices, see p.316 of pdf spec 1.7.
     *
     * @param vertexList list of vertices
     */
    private void createTriangleList(ArrayList<Vertex> vertexList)
    {
        Point2D a = null, b = null, c = null;
        float[] aColor = null, bColor = null, cColor = null;
        int vi = 0;
        while (vi < vertexList.size())
        {
            Vertex v = vertexList.get(vi);
            switch (v.flag)
            {
                case 0:
                    a = v.point;
                    aColor = v.color;
                    ++vi;

                    v = vertexList.get(vi);
                    b = v.point;
                    bColor = v.color;
                    ++vi;

                    v = vertexList.get(vi);
                    c = v.point;
                    cColor = v.color;
                    break;

                case 1:
                    a = b;
                    aColor = bColor;

                    b = c;
                    bColor = cColor;

                    v = vertexList.get(vi);
                    c = v.point;
                    cColor = v.color;
                    break;

                case 2:
                    b = c;
                    bColor = cColor;

                    v = vertexList.get(vi);
                    c = v.point;
                    cColor = v.color;
                    break;

                default:
                    break;
            }
            ++vi;
            GouraudTriangle g = new GouraudTriangle(a, aColor, b, bColor, c, cColor);
            if (!g.isEmpty())
            {
                triangleList.add(g);
            }
            else
            {
                LOG.debug("triangle is empty!");
            }
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void dispose()
    {
        super.dispose();
    }
}
TOP

Related Classes of org.apache.pdfbox.pdmodel.graphics.shading.Type4ShadingContext

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.