All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.idrsolutions.pdf.color.shading.TensorContext Maven / Gradle / Ivy

There is a newer version: 20151002
Show newest version
/*
 * ===========================================
 * Java Pdf Extraction Decoding Access Library
 * ===========================================
 *
 * Project Info:  http://www.idrsolutions.com
 * Help section for developers at http://www.idrsolutions.com/support/
 *
 * (C) Copyright 1997-2015 IDRsolutions and Contributors.
 *
 * This file is part of JPedal/JPDF2HTML5
 *
     This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA


 *
 * ---------------
 * TensorContext.java
 * ---------------
 */

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.idrsolutions.pdf.color.shading;

import java.awt.Color;
import java.awt.PaintContext;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.DataBufferInt;
import java.awt.image.Raster;
import java.awt.image.WritableRaster;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.jpedal.color.GenericColorSpace;
import org.jpedal.function.PDFFunction;
import org.jpedal.objects.raw.PdfDictionary;
import org.jpedal.objects.raw.PdfObject;

/**
 *
 * @author suda
 */
public class TensorContext implements PaintContext {

    private GenericColorSpace shadingColorSpace;
    private final float[] background;
    private int bitsPerCoordinate;
    private int bitsPerComponent;
    private int bitsPerFlag;
    private int colCompCount;
    private float[] decodeArr;
//    private final float[][] CTM;
    private float[][] matrix;
    private ArrayList pp; //patch points
    private ArrayList pc; // patch colors
    private final ArrayList shapes;
    private BitReader reader;
    private PDFFunction[] function;
    private final Shape67[] duplicates;
    private final boolean isRecursive;

    /**
     * constructor uses cached shapes values to create a context
     *
     * @param shapes
     * @param background
     * @param pageHeight
     * @param scaling
     * @param offX
     * @param offY
     */
    TensorContext(final AffineTransform xform, final ArrayList shapes, final float[] background, int pageHeight, float scaling, int offX, int offY) {

        this.shapes = shapes;
        this.background = background;
        
        duplicates = new Shape67[shapes.size()];
        for (int i = 0; i < shapes.size(); i++) {
            
                Shape67 temp = shapes.get(i).cloneShape();
                temp.applyTransformation(xform);
                duplicates[i] = temp;
        }
        isRecursive = duplicates.length<50;
     
    }

    TensorContext(AffineTransform xform, final GenericColorSpace shadingColorSpace,
            final float[] background,
            final PdfObject shadingObject, float[][] matrix, int pageHeight, float scaling, int offX, int offY, PDFFunction[] function) {
        this.shadingColorSpace = shadingColorSpace;
        this.background = background;
        bitsPerComponent = shadingObject.getInt(PdfDictionary.BitsPerComponent);
        bitsPerFlag = shadingObject.getInt(PdfDictionary.BitsPerFlag);
        bitsPerCoordinate = shadingObject.getInt(PdfDictionary.BitsPerCoordinate);
        decodeArr = shadingObject.getFloatArray(PdfDictionary.Decode);
        boolean hasSmallBits = bitsPerFlag < 8 || bitsPerComponent < 8 || bitsPerCoordinate < 8;
        reader = new BitReader(shadingObject.getDecodedStream(), hasSmallBits);
        colCompCount = shadingColorSpace.getColorComponentCount();
        if (decodeArr != null) {
            colCompCount = (decodeArr.length - 4) / 2;
        }

        this.function = function;
        this.matrix = matrix;

        pp = new ArrayList();
        pc = new ArrayList();
        shapes = new ArrayList();

        process();
        adjustPoints();

        duplicates = new Shape67[shapes.size()];
        for (int i = 0; i < shapes.size(); i++) {
            Shape67 temp = shapes.get(i).cloneShape();
            temp.applyTransformation(xform);
            duplicates[i] = temp;
        }
        isRecursive = duplicates.length<50;
    }

    /**
     * process the datastream and update the variables
     */
    private void process() {
        while (reader.getPointer() < reader.getTotalBitLen()) {
            int flag = reader.getPositive(bitsPerFlag);
            Point2D a4[] = new Point2D[4];
            Color a2[] = new Color[2];
            float[] cc = new float[colCompCount];
            switch (flag) {
                case 0:
                    for (int i = 0; i < 12; i++) {
                        Point2D p = getPointCoords();
                        pp.add(p);
                    }

                    for (int i = 0; i < 4; i++) {
                        getPointCoords(); //ignore this data at the moment
                    }

                    for (int i = 0; i < 4; i++) {
                        for (int z = 0; z < colCompCount; z++) {
                            cc[z] = reader.getFloat(bitsPerComponent);
                        }
                        Color color = calculateColor(cc);
                        pc.add(color);
                    }
                    break;
                case 1:
                    a4[0] = pp.get(pp.size() - 9);
                    a4[1] = pp.get(pp.size() - 8);
                    a4[2] = pp.get(pp.size() - 7);
                    a4[3] = pp.get(pp.size() - 6);

                    pp.addAll(Arrays.asList(a4).subList(0, 4));
                    for (int i = 0; i < 8; i++) {
                        Point2D p = getPointCoords();
                        pp.add(p);
                    }
                    for (int i = 0; i < 4; i++) {
                        getPointCoords();
                    }
                    a2[0] = pc.get(pc.size() - 3);
                    a2[1] = pc.get(pc.size() - 2);

                    pc.addAll(Arrays.asList(a2));

                    for (int i = 0; i < 2; i++) {
                        for (int z = 0; z < colCompCount; z++) {
                            cc[z] = reader.getFloat(bitsPerComponent);
                        }
                        Color color = calculateColor(cc);
                        pc.add(color);
                    }

                    //do color mapping
                    break;
                case 2:
                    a4[0] = pp.get(pp.size() - 6);
                    a4[1] = pp.get(pp.size() - 5);
                    a4[2] = pp.get(pp.size() - 4);
                    a4[3] = pp.get(pp.size() - 3);

                    pp.addAll(Arrays.asList(a4).subList(0, 4));
                    for (int i = 0; i < 8; i++) {
                        Point2D p = getPointCoords();
                        pp.add(p);
                    }
                    for (int i = 0; i < 4; i++) {
                        getPointCoords();
                    }
                    a2[0] = pc.get(pc.size() - 2);
                    a2[1] = pc.get(pc.size() - 1);

                    pc.addAll(Arrays.asList(a2));

                    for (int i = 0; i < 2; i++) {
                        for (int z = 0; z < colCompCount; z++) {
                            cc[z] = reader.getFloat(bitsPerComponent);
                        }
                        Color color = calculateColor(cc);
                        pc.add(color);
                    }
                    // do color mapping                    

                    break;
                case 3:
                    a4[0] = pp.get(pp.size() - 3);
                    a4[1] = pp.get(pp.size() - 2);
                    a4[2] = pp.get(pp.size() - 1);
                    a4[3] = pp.get(pp.size() - 12);

                    pp.addAll(Arrays.asList(a4).subList(0, 4));
                    for (int i = 0; i < 8; i++) {
                        Point2D p = getPointCoords();
                        pp.add(p);
                    }
                    for (int i = 0; i < 4; i++) {
                        getPointCoords();
                    }

                    a2[0] = pc.get(pc.size() - 1);
                    a2[1] = pc.get(pc.size() - 4);

                    pc.addAll(Arrays.asList(a2));

                    for (int i = 0; i < 2; i++) {
                        for (int z = 0; z < colCompCount; z++) {
                            cc[z] = reader.getFloat(bitsPerComponent);
                        }
                        Color color = calculateColor(cc);
                        pc.add(color);
                    }
                    break;
            }
        }
    }

    /**
     * convert small points to x,y full space points
     */
    private void adjustPoints() {

        if (decodeArr != null) { //some odd files have decode array as null
            float xMin = decodeArr[0];
            float xMax = decodeArr[1];
            float yMin = decodeArr[2];
            float yMax = decodeArr[3];

            float xw = xMax - xMin;
            float yw = yMax - yMin;

            ArrayList tempPoints = new ArrayList();
            for (Point2D p : pp) {
                double xx = p.getX();
                double yy = p.getY();
                xx = (xw * xx) + xMin;
                yy = (yw * yy) + yMin;
                tempPoints.add(new Point2D.Double(xx, yy));
            }
            pp.clear();
            for (Point2D t : tempPoints) {
                pp.add(t);
            }
        }

        Point2D[] pArr = new Point2D[pp.size()];
        for (int i = 0; i < pArr.length; i++) {
            pArr[i] = pp.get(i);
        }
        int totalPatches = pp.size() / 12;
        int offset = 0;
        double[] mm = {matrix[0][0], matrix[0][1], matrix[1][0], matrix[1][1], matrix[2][0], matrix[2][1]};
        AffineTransform affine = new AffineTransform(mm);
        for (int i = 0; i < totalPatches; i++) {
            Point2D[] pointArr = new Point2D[12];
            Color[] colors = {pc.get(i * 4), pc.get(i * 4 + 1), pc.get(i * 4 + 2), pc.get(i * 4 + 3)};
            System.arraycopy(pArr, offset, pointArr, 0, 12);
            Shape67 sh = new Shape67(pointArr, colors);
            sh.applyTransformation(affine);
            shapes.add(sh);
            offset += 12;
        }

    }

    private Point2D getPointCoords() {
        double x = 0;
        double y = 0;

        for (int z = 0; z < 2; z++) {
            switch (z) {
                case 0:
                    x = reader.getFloat(bitsPerCoordinate);
                    break;
                case 1:
                    y = reader.getFloat(bitsPerCoordinate);
                    break;
            }
        }
        return new Point2D.Double(x, y);
    }

    @Override
    public void dispose() {
        reader = null;
    }

    @Override
    public ColorModel getColorModel() {
        return ColorModel.getRGBdefault();
    }

    @Override
    public Raster getRaster(int xStart, int yStart, int w, int h) {

        final WritableRaster raster = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB).getRaster();
        int[] data = ((DataBufferInt) raster.getDataBuffer()).getData();

        if (background != null) {
            int pos = 0;
            shadingColorSpace.setColor(background, 4);
            final Color c = (Color) shadingColorSpace.getColor();
            for (int y = 0; y < h; y++) {
                for (int x = 0; x < w; x++) {
                    data[pos++] = 255 << 24 | c.getRGB();
                }
            }
        }

        Rectangle rect = new Rectangle(xStart, yStart, w, h);

        List foundList = new ArrayList();
        for (Shape67 sh : duplicates) {
            if (sh.getShape().intersects(rect)) {
                foundList.add(sh);
            }
        }

        for (Shape67 sh : foundList) {
            GeneralPath path = sh.getShape();
            for (int y = 0; y < h; y++) {
                for (int x = 0; x < w; x++) {
//                    float[] xy = PixelFactory.convertPhysicalToPDF(false, x, y, offX, offY, 1 / scaling, xStart, yStart, 0, pageHeight);
//                    float[] xy = ShadingUtils.getPixelPDF(false, rotation, x, y, xStart,yStart, offX, offY, 0, pageHeight, scaling);
//                    float[] xy = ShadingUtils.getPdfCoords(inversed, x, y, xStart, yStart);
                    int xx = x+xStart;
                    int yy = y+yStart;
                    // check with bounds first before going to shape to speedup execution
                    if (path.contains(xx, yy)) {
                        Point p = new Point(xx, yy);
                        Color result = sh.findPointColor(p,isRecursive);
                        if (result != null) {
                            final int base = (y * w + x);
                            data[base] = 255 << 24 | result.getRGB();
                        }
                    }
                }
            }
        }

//        if(pageHeight == 0){
//            return null;
//        }
//
//        for (Shape67 sh : shapes) {
//            GeneralPath path = sh.getShape();
//            Rectangle bounds = sh.getBoundingBox();
//            for (int y = 0; y < h; y++) {
//                for (int x = 0; x < w; x++) {
////                    float[] xy = PixelFactory.convertPhysicalToPDF(false, x, y, offX, offY, 1 / scaling, xStart, yStart, 0, pageHeight);
//                    float[] xy = ShadingUtils.getPixelPDF(false, rotation, x, y, xStart,yStart, offX, offY, 0, pageHeight, scaling);
////                    float[] xy = ShadingUtils.getPdfCoords(inversed, x, y, xStart, yStart);
//                    // check with bounds first before going to shape to speedup execution
//                    if (bounds.contains(xy[0], xy[1]) && path.contains(xy[0], xy[1])) {
//
//                        Point2D p = new Point2D.Float(xy[0],xy[1]);
//                        Color result = sh.findPointColor(p);
//                        if (result != null) {
//                            final int base = (y * w + x);
//                            data[base] = 255<<24 | result.getRGB();
//                        }
//                    }
//                }
//            }
//        }
        return raster;
    }

    private Color calculateColor(final float[] val) {
        final Color col;
        if (function == null) {
            shadingColorSpace.setColor(val, colCompCount);
            col = new Color(shadingColorSpace.getColor().getRGB());
        } else {
            final float[] colValues = ShadingFactory.applyFunctions(function, val);
            shadingColorSpace.setColor(colValues, colValues.length);
            col = (Color) shadingColorSpace.getColor();
        }
        return col;
    }

    public ArrayList getShapes() {
        return shapes;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy