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

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

The newest version!
/*
 * ===========================================
 * Java Pdf Extraction Decoding Access Library
 * ===========================================
 *
 * Project Info:  http://www.idrsolutions.com
 * Help section for developers at http://www.idrsolutions.com/java-pdf-library-support/
 *
 * (C) Copyright 1997-2014, IDRsolutions and Contributors.
 *
 * 	This file is part of JPedal
 *
     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


 *
 * ---------------
 * PatchContext.java
 * ---------------
 */
package com.idrsolutions.pdf.color.shading;

import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
import java.awt.geom.Rectangle2D;
import java.awt.image.ColorModel;
import java.awt.image.Raster;
import java.awt.image.BufferedImage;

import java.util.ArrayList;

import org.jpedal.objects.raw.PdfDictionary;
import org.jpedal.objects.raw.PdfObject;
import org.jpedal.color.GenericColorSpace;
import org.jpedal.examples.handlers.DefaultImageHelper;
import org.jpedal.external.ImageHelper;
import org.jpedal.utils.LogWriter;

public class PatchContext implements PaintContext {

    private double scaling=1f;
    
    private ImageHelper images = new DefaultImageHelper();

    private ArrayList patches;

    private  int offX, offY,pHeight;
    private final int type;

    private final float[][] CTM;
    float[][] matrix;
    boolean debugSaveOut;

    private Rectangle deviceBounds;
    // Cache the pattern bounds to improve performance
    private Rectangle2D patternBounds;
    // If the shading is passed from the SH command
    private final boolean isFromSH;
    
    public PatchContext(final PdfObject shadingObj, final float[] domain, final float[][] CTM, final GenericColorSpace shadingColorSpace,
                        final float[][] matrix, final int type){
        patches = new ArrayList();
        this.CTM = CTM;
        this.matrix = matrix;
        this.type = type;
        
        
        /**
         * If the context is initialised from the SH command, CTM and matrix are
         * the same and therefore should share the same reference.
         */
        //noinspection ArrayEquality
        isFromSH = CTM == matrix;
        

        //specific Tensor values
        final int BitsPerComponent=shadingObj.getInt(PdfDictionary.BitsPerComponent);
        final int BitsPerFlag=shadingObj.getInt(PdfDictionary.BitsPerFlag);
        final int BitsPerCoordinate=shadingObj.getInt(PdfDictionary.BitsPerCoordinate);

        final int compCount=shadingColorSpace.getColorComponentCount();

        //Decode the coordinate data
        final byte[] bytes = shadingObj.getDecodedStream();
        final ShadingDatastreamReader c = new ShadingDatastreamReader(bytes,BitsPerCoordinate,BitsPerComponent,compCount,BitsPerFlag,shadingColorSpace,type);
        patches = c.getPatches();
    }
    
    @Override
    public void dispose() {}

    public void setValues(final int pHeight, final float scaling, final int offX, final int offY) {
        this.offX = offX;
        this.offY = offY;
        this.pHeight = pHeight;
        this.scaling = scaling;
    }

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

    /**
     * setup the raster with the colors
     * */
    @Override
    public Raster getRaster(int xstart, int ystart, final int w, final int h) {
        double dh, dw, dx, dy;
        final GeneralPath bounds;
        
        if(pHeight == 0){
            final BufferedImage result = new BufferedImage(w,h,BufferedImage.TYPE_INT_ARGB);
            return result.getData();
        }

        /**
         * We have to handle shadings passed from the SH command differently
         * as the CTM and the matrix passed through in the constructor are the both
         * just the CTM. 
         */
        if(isFromSH){
            final Rectangle2D patternRect = getPatternBounds();
            
            if(patternRect == null){
                return new BufferedImage(w,h,BufferedImage.TYPE_INT_ARGB).getData();
            }
            
            bounds = new GeneralPath(patternRect);

            dw = deviceBounds.width / bounds.getBounds2D().getWidth();
            dh = deviceBounds.height / bounds.getBounds2D().getHeight();
            
            dx = -((bounds.getBounds2D().getX() * dw) + (xstart - deviceBounds.getX()));
            dy = -((bounds.getBounds2D().getY() * dh) + (ystart - deviceBounds.getY()));
        }else{
            //check if CTM is set and use other matrix if not
            boolean flip = false;
            if (CTM[0][0]==1 && CTM[1][1]==1) {
                dx = matrix[2][0];
                dy = matrix[2][1];
                dw = matrix[0][0];
                dh = -matrix[1][1];

            } else {
                dx = CTM[2][0];
                dy = CTM[2][1];
                dw = CTM[0][0];
                dh = -CTM[1][1];

                if (dh < 0) {
                    flip = true;
                }
            }
            if (Math.abs(dh) < 1) {
                dh *= 255f;
            }
            if (Math.abs(dw) < 1) {
                dw *= 255f;
            }

            if (type == ShadedPaint.TENSOR) {
                if(CTM[0][0]!=1) {
                    dw = 1.1*matrix[0][0]/CTM[0][0];
                    dh = 1.1*matrix[1][1]/CTM[1][1];
                } else {
                    dx /= 2;
                    dy /= 2;
                    dw = matrix[0][0]*1.05;
                    dh = matrix[1][1]*1.05;
                }
            }

            if (flip) {
                dy -= dh;
                dh = - dh;
            }

            //convert to screen coords
            dx /= scaling;
            dy = pHeight - (dy / scaling);
            dh /= scaling;
            dw /= scaling;

            //include offset in screen raster coords
            xstart -= offX;
            ystart -= offY;

            //Generate shade coords version of raster bounds
            final float shadeCoordsLeft=(float) ((xstart-dx)/dw);
            final float shadeCoordsTop=(float) ((ystart-dy)/dh);
            final float shadeCoordsRight=(float) (shadeCoordsLeft+(w/dw));
            final float shadeCoordsBottom=(float) (shadeCoordsTop+(h/dh));
            bounds = new GeneralPath();
            bounds.moveTo(shadeCoordsLeft,  shadeCoordsTop);
            bounds.lineTo(shadeCoordsRight, shadeCoordsTop);
            bounds.lineTo(shadeCoordsRight, shadeCoordsBottom);
            bounds.lineTo(shadeCoordsLeft,  shadeCoordsBottom);
            bounds.lineTo(shadeCoordsLeft,  shadeCoordsTop);
            
            dx -= xstart;
            dy -= ystart;
        }
        
        //Create image and set transform
        final BufferedImage result = new BufferedImage(w,h,BufferedImage.TYPE_INT_ARGB);
        final Graphics2D g2 = ((Graphics2D)result.getGraphics());
        final AffineTransform trans = new AffineTransform();
        trans.translate(dx,dy);
        trans.scale(dw, dh);
        g2.setTransform(trans);
               
        //draw background if more than one patch
        final boolean drawBack = patches.size() != 1;

        //Draw patches onto raster
        for (final Object patche1 : patches) {
            final CoonsPatch p = (CoonsPatch) patche1;
            //check it won't draw offscreen
            if (p.getBounds2D().intersects(bounds.getBounds2D())) {
                p.printOntoG2(g2, bounds.getBounds2D(), drawBack);
            }
        }
        
        if (debugSaveOut) {
            final BufferedImage out = new BufferedImage(500,500,BufferedImage.TYPE_INT_ARGB);
            final Graphics2D og2 = ((Graphics2D)out.getGraphics());
            final AffineTransform otrans = new AffineTransform();
            otrans.scale(500,500);
            og2.setTransform(otrans);

            //Draw patches onto raster
            for (final Object patche : patches) {
                final CoonsPatch p = (CoonsPatch) patche;
                //check it won't draw offscreen
                p.printOntoG2(og2, bounds.getBounds2D(), drawBack);
            }

            try {
                this.images.write(out, "png","C:/users/sam/desktop/new/"+this+".png");
            } catch (final Exception e) {
                //tell user and log
                if(LogWriter.isOutput()) {
                    LogWriter.writeLog("Exception: " + e.getMessage());
                }
            }
        }

        return result.getData();
    }
    /**
     * Used when Tensor is passed in via SH command
     * @param db Bounding rectangle of the shade in device space
     */
    public void setRect(final Rectangle db){
        deviceBounds = db;
    }
    
    /**
     * Get the bounds of the shading in Pattern space. 
     * Used to scale the pattern to device space.
     */
    private Rectangle2D getPatternBounds(){
        if(patternBounds != null) {
            return patternBounds;
        }
        
        double minX, minY, maxX, maxY;
        if(patches.size() < 1) {
            return null;
        }
        
        // Set values to compare against
        final CoonsPatch firstPatch = (CoonsPatch)patches.get(0);
        Rectangle2D firstRect = firstPatch.getBounds2D();
        minX = firstRect.getMinX();
        minY = firstRect.getMinY();
        maxX = firstRect.getMaxX();
        maxY = firstRect.getMaxY();
        
        for(int i = 1; i < patches.size(); i++){
            final CoonsPatch p = (CoonsPatch)patches.get(i);
            Rectangle2D pRect = p.getBounds2D();
            if(pRect.getMinX() < minX){
                minX = pRect.getMinX();
            }
            if(pRect.getMinY() < minY){
                minY = pRect.getMinY();
            }
            if(pRect.getMaxX() > maxX){
                maxX = pRect.getMaxX();
            }
            if(pRect.getMaxY() > maxY){
                maxY = pRect.getMaxY();
            }
        }
        
        final GeneralPath bounds = new GeneralPath();
        bounds.moveTo(minX, minY);
        bounds.lineTo(maxX, minY);
        bounds.lineTo(maxX, maxY);
        bounds.lineTo(minX, maxY);
        
        patternBounds = bounds.getBounds2D();
        
        return bounds.getBounds2D();
    }

    
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy