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

org.jpedal.render.BaseDisplay Maven / Gradle / Ivy

/*
 * ===========================================
 * 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-2017 IDRsolutions and Contributors.
 *
 * This file is part of JPedal/JPDF2HTML5
 *
 @LICENSE@
 *
 * ---------------
 * BaseDisplay.java
 * ---------------
 */
package org.jpedal.render;

import com.idrsolutions.pdf.color.blends.BlendMode;

import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.geom.Area;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import org.jpedal.color.PdfColor;
import org.jpedal.color.PdfPaint;
import org.jpedal.exception.PdfException;
import org.jpedal.fonts.PdfFont;
import org.jpedal.fonts.glyph.PdfGlyph;
import org.jpedal.io.ObjectStore;
import org.jpedal.objects.GraphicsState;
import org.jpedal.objects.PdfShape;
import org.jpedal.objects.raw.PdfDictionary;
import org.jpedal.parser.DecoderOptions;
import org.jpedal.render.utils.ShapeUtils;
import org.jpedal.utils.LogWriter;
import org.jpedal.utils.repositories.Vector_Int;
import org.jpedal.utils.repositories.Vector_Object;
import org.jpedal.utils.repositories.generic.Vector_Rectangle_Int;

public abstract class BaseDisplay implements DynamicVectorRenderer {

    /**
     * holds object type
     */
    protected Vector_Int objectType;

    /**
     * default array size
     */
    protected static final int defaultSize = 5000;

    protected int type;

    boolean isType3Font;

    public int currentTokenNumber = -1;

    /**
     * set flag to show if we add a background
     */
    protected boolean addBackground = true;

    /**
     * holds rectangular outline to test in redraw
     */
    protected Vector_Rectangle_Int areas;

    protected ObjectStore objectStoreRef;

    protected int currentItem = -1;

    //Used purely to keep track of rendering for colour change functionality
    //must NEVER be made static
    protected int itemToRender = -1;

    //used to track end of PDF page in display
    //must NEVER be made static
    protected int endItem = -1;

    Area lastClip;

    boolean hasClips;

    int blendMode = PdfDictionary.Normal;

    /**
     * shows if colours over-ridden for type3 font
     */
    boolean colorsLocked;

    Graphics2D g2;

    //used by type3 fonts as identifier
    String rawKey;

    /**
     * global colours if set
     */
    PdfPaint fillCol, strokeCol;

    public int rawPageNumber;

    public static boolean invertHighlight;

    boolean isPrinting;

    org.jpedal.external.ImageHandler customImageHandler;

    org.jpedal.external.ColorHandler customColorHandler;

    double cropX, cropH;

    float scaling = 1, lastScaling;

    /**
     * initial Q & D object to hold data
     */
    protected Vector_Object pageObjects;

    protected final Map imageIDtoName = new HashMap(10);

    /**
     * real size of pdf page
     */
    int w, h;

    /**
     * background color
     */
    protected Color backgroundColor = Color.WHITE;
    protected static Color textColor;
    protected static int colorThresholdToReplace = 255;
    protected static boolean enhanceFractionalLines = true;

    protected boolean changeLineArtAndText;

    /**
     * allow user to control
     */
    public static RenderingHints userHints;

    @Override
    public void setG2(final Graphics2D g2) {
        this.g2 = g2;
        //If user hints has been defined use these values.
        if (userHints != null) {
            this.g2.setRenderingHints(userHints);
        }
    }

    @Override
    public void init(final int width, final int height, final Color backgroundColor) {
        w = width;
        h = height;
        this.backgroundColor = backgroundColor;
    }

    protected void paintBackground(final Shape dirtyRegion) {
        if (addBackground && g2 != null) {
            g2.setColor(backgroundColor);

            if (dirtyRegion == null) {
                g2.fill(new Rectangle(0, 0, (int) (w * scaling), (int) (h * scaling)));
            } else {
                g2.fill(dirtyRegion);
            }
        }
    }


    protected static boolean checkColorThreshold(final int col) {

        final int r = (col) & 0xFF;
        final int g = (col >> 8) & 0xFF;
        final int b = (col >> 16) & 0xFF;

        return r <= colorThresholdToReplace && g <= colorThresholdToReplace && b <= colorThresholdToReplace;
    }

    void renderEmbeddedText(final int text_fill_type, final Object rawglyph, final int glyphType,
                            final AffineTransform glyphAT, final Rectangle textHighlight,
                            PdfPaint strokePaint, PdfPaint fillPaint,
                            final float strokeOpacity, final float fillOpacity, final int lineWidth) {

        //ensure stroke only shows up
        float strokeOnlyLine = 0;
        if (text_fill_type == GraphicsState.STROKE && lineWidth >= 1.0) {
            strokeOnlyLine = lineWidth;
        }

        //get glyph to draw
        final PdfGlyph glyph = (PdfGlyph) rawglyph;

        final AffineTransform at = g2.getTransform();

        //and also as flat values so we can test below
        final double[] affValues = new double[6];
        at.getMatrix(affValues);

        if (glyph != null) {

            //set transform
            g2.transform(glyphAT);

            //type of draw operation to use
            final Composite comp = g2.getComposite();

            if ((text_fill_type & GraphicsState.FILL) == GraphicsState.FILL) {

                //If we have an alt text color, its within threshold and not an additional item, use alt color
                if (textColor != null && (itemToRender == -1 || (endItem == -1 || itemToRender <= endItem)) && checkColorThreshold(fillPaint.getRGB())) {
                    fillPaint = new PdfColor(textColor.getRed(), textColor.getGreen(), textColor.getBlue());
                }

//                fillPaint.setScaling(cropX, cropH, scaling, 0, 0);
                fillPaint.setScaling(cropX, cropH, scaling, (float) glyphAT.getTranslateX(), (float) glyphAT.getTranslateY());

                if (customColorHandler != null) {
                    customColorHandler.setPaint(g2, fillPaint, rawPageNumber, isPrinting);
                } else if (DecoderOptions.Helper != null) {
                    DecoderOptions.Helper.setPaint(g2, fillPaint, rawPageNumber, isPrinting);
                } else {
                    g2.setPaint(fillPaint);
                }

                renderComposite(fillOpacity);

                if (textHighlight != null) {
                    if (invertHighlight) {
                        final Color color = g2.getColor();
                        g2.setColor(new Color(255 - color.getRed(), 255 - color.getGreen(), 255 - color.getBlue()));
                    } else if (DecoderOptions.backgroundColor != null) {
                        g2.setColor(DecoderOptions.backgroundColor);
                    }
                }


                //pass down color for drawing text
                if (glyphType == DynamicVectorRenderer.TYPE3 && !glyph.ignoreColors()) {
                    glyph.setT3Colors(strokePaint, fillPaint, false);
                }

                glyph.render(GraphicsState.FILL, g2, scaling, false);

                //reset opacity
                g2.setComposite(comp);

            }

            if (text_fill_type == GraphicsState.STROKE) {
                glyph.setStrokedOnly(true);
            }

            //creates shadow printing to Mac so added work around
            if (DecoderOptions.isRunningOnMac && isPrinting && text_fill_type == GraphicsState.FILLSTROKE) {
            } else if ((text_fill_type & GraphicsState.STROKE) == GraphicsState.STROKE) {

                if (strokePaint != null) {
                    //If we have an alt text color, its within threshold and not an additional item, use alt color
                    if (textColor != null && (itemToRender == -1 || (endItem == -1 || itemToRender <= endItem)) && checkColorThreshold(strokePaint.getRGB())) {
                        strokePaint = new PdfColor(textColor.getRed(), textColor.getGreen(), textColor.getBlue());
                    }
                    strokePaint.setScaling(cropX, cropH, scaling, 0, 0);
                }

                if (customColorHandler != null) {
                    customColorHandler.setPaint(g2, strokePaint, rawPageNumber, isPrinting);
                } else if (DecoderOptions.Helper != null) {
                    DecoderOptions.Helper.setPaint(g2, strokePaint, rawPageNumber, isPrinting);
                } else {
                    g2.setPaint(strokePaint);
                }

                renderComposite(strokeOpacity);

                if (textHighlight != null) {
                    if (invertHighlight) {
                        final Color color = g2.getColor();
                        g2.setColor(new Color(255 - color.getRed(), 255 - color.getGreen(), 255 - color.getBlue()));
                    } else if (DecoderOptions.backgroundColor != null) {
                        g2.setColor(DecoderOptions.backgroundColor);
                    }
                }

                try {
                    glyph.render(GraphicsState.STROKE, g2, strokeOnlyLine, false);
                } catch (final Exception e) {
                    LogWriter.writeLog("Exception: " + e.getMessage());
                }

                //reset opacity
                g2.setComposite(comp);
            }

            //restore transform
            g2.setTransform(at);

        }
    }

    void renderShape(final Shape defaultClip, final int fillType, PdfPaint strokeCol, PdfPaint fillCol,
                     final Stroke shapeStroke, Shape currentShape, final float strokeOpacity,
                     final float fillOpacity) {

        boolean clipChanged = false;

        final Shape clip = g2.getClip();

        final Composite comp = g2.getComposite();


        //check for 1 x 1 complex shape (after scaling) and replace with dot
        if (type == DISPLAY_SCREEN && !isPrinting && currentShape.getBounds().getWidth() * scaling == 1 &&
                currentShape.getBounds().getHeight() * scaling == 1 && ((BasicStroke) shapeStroke).getLineWidth() * scaling < 1) {
            currentShape = new Rectangle(currentShape.getBounds().x, currentShape.getBounds().y, 1, 1);
        }

        //SoftClip Dev Code (Must replace SwingDisplay ln 2250 - 2273 with "clips.addElement(clip);" to work
//        if(clip != null && !(clip.getBounds().getWidth() == 0 || clip.getBounds().getHeight() == 0) &&
//                clip.getBounds().equals(currentShape.getBounds())) {
//
//            // Create a translucent intermediate image in which we can perform
//            // the soft clipping
//            final GraphicsConfiguration gc = g2.getDeviceConfiguration();
//            final float scaling = (float) g2.getTransform().getScaleX();
//            int width = (int) (clip.getBounds().width * scaling) + 1;
//            int height = (int) (clip.getBounds().height * scaling) + 1;
//
//            if(width < 1){
//                width = 1;
//            }
//
//            if (height < 1){
//                height = 1;
//            }
//
//            final  BufferedImage softClipImage = gc.createCompatibleImage(width, height, Transparency.TRANSLUCENT);
//            final Graphics2D localG2 = softClipImage.createGraphics();
//
//            //Set up Graphics to corrent scaling for clearer output
//            localG2.scale(scaling, scaling);
//            localG2.translate(-clip.getBounds().x, -clip.getBounds().y);
//
//            // Clear the image so all pixels have zero alpha
//            localG2.setComposite(AlphaComposite.Clear);
//            localG2.fillRect(0, 0, softClipImage.getWidth(), softClipImage.getHeight());
//
//            //Render clip as the only area the shape can draw to
//            localG2.setComposite(AlphaComposite.Src);
//            localG2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
//
//            //stroke and fill (do fill first so we don't overwrite Stroke)
//            if (fillType == GraphicsState.FILL || fillType == GraphicsState.FILLSTROKE) {
//                // Fill color is null if the shape is a pattern
//                if (fillCol != null) {
//                    if ((fillCol.getRGB() != -1) &&
//                            //If we have an alt text color, are changing line art as well, its within threshold and not an additional item, use alt color
//
//                            (changeLineArtAndText && textColor != null && !fillCol.isPattern() && (itemToRender == -1 || (endItem == -1 || itemToRender <= endItem)) && checkColorThreshold(fillCol.getRGB()))) {
//                        fillCol = new PdfColor(textColor.getRed(), textColor.getGreen(), textColor.getBlue());
//
//                    }
//
//                    fillCol.setScaling(cropX, cropH, scaling, 0, 0);
//                }
//
//                if (customColorHandler != null) {
//                    customColorHandler.setPaint(g2, fillCol, rawPageNumber, isPrinting);
//                } else if (DecoderOptions.Helper != null) {
//                    DecoderOptions.Helper.setPaint(g2, fillCol, rawPageNumber, isPrinting);
//                } else {
//                    localG2.setPaint(fillCol);
//                }
//
//    //            renderComposite(fillOpacity);
//
//                try {
//                    //thin lines do not appear unless we use fillRect
//                    final double iw = currentShape.getBounds2D().getWidth();
//                    final double ih = currentShape.getBounds2D().getHeight();
//
//                    if ((ih == 0d || iw == 0d) && ((BasicStroke) g2.getStroke()).getLineWidth() <= 1.0f) {
//                        localG2.fillRect(currentShape.getBounds().x, currentShape.getBounds().y, currentShape.getBounds().width, currentShape.getBounds().height);
//                    } else {
//                        localG2.fill(currentShape);
//                    }
//
//                } catch (final Exception e) {
//                    LogWriter.writeLog("Exception " + e + " filling shape");
//                }
//
//    //            g2.setComposite(comp);
//            }
//
//            if ((fillType == GraphicsState.STROKE) || (fillType == GraphicsState.FILLSTROKE)) {
//
//                //set values for drawing the shape
//                final Stroke currentStroke = g2.getStroke();
//
//                //fix for using large width on point to draw line
//                if (currentShape.getBounds2D().getWidth() < 1.0f && ((BasicStroke) shapeStroke).getLineWidth() > 10) {
//                    localG2.setStroke(new BasicStroke(1));
//                } else {
//                    //Adjust line width to 1 if less than 1
//                    //ignore if using T3Display (such as ap image generation in html / svg conversion
//                    if (enhanceFractionalLines && ((((BasicStroke) shapeStroke).getLineWidth() * scaling < 1) &&
//                            !isPrinting && !(this instanceof T3Display))) {
//                        localG2.setStroke(new BasicStroke(1 / scaling, ((BasicStroke) shapeStroke).getEndCap(), ((BasicStroke) shapeStroke).getLineJoin(), ((BasicStroke) shapeStroke).getMiterLimit(), ((BasicStroke) shapeStroke).getDashArray(), ((BasicStroke) shapeStroke).getDashPhase()));
//                    } else {
//                        localG2.setStroke(shapeStroke);
//                    }
//                }
//
//                //If we have an alt text color, are changing line art, its within threshold and not an additional item, use alt color
//                if (changeLineArtAndText && textColor != null && !strokeCol.isPattern() && (itemToRender == -1 || (endItem == -1 || itemToRender <= endItem)) && checkColorThreshold(strokeCol.getRGB())) {
//                    strokeCol = new PdfColor(textColor.getRed(), textColor.getGreen(), textColor.getBlue());
//                }
//
//                strokeCol.setScaling(cropX, cropH, scaling, 0, 0);
//
//                if (customColorHandler != null) {
//                    customColorHandler.setPaint(g2, strokeCol, rawPageNumber, isPrinting);
//                } else if (DecoderOptions.Helper != null) {
//                    DecoderOptions.Helper.setPaint(g2, strokeCol, rawPageNumber, isPrinting);
//                } else {
//                    localG2.setPaint(strokeCol);
//                }
//
//    //            renderComposite(strokeOpacity);
//
//                if (!isPrinting && clip.getBounds2D().getWidth() % 1 > 0.65f && clip.getBounds2D().getHeight() % 1 > 0.1f) {
//                    if (currentShape.getBounds().getWidth() == clip.getBounds().getWidth()) {
//                        localG2.setClip(ClipUtils.convertPDFClipToJavaClip(new Area(clip)));  //use null or visible screen area
////                        clipChanged = true;
//                    }
//                }
//
//                //breaks printing so disabled there
//                if (!isPrinting) {
//                    final Double lheight = clip.getBounds2D().getHeight();
//                    final Double lwidth = clip.getBounds2D().getWidth();
//                    if ((lheight < 1 && lheight > 0) || (lwidth < 1 && lwidth > 0)) {
//                        g2.setClip(defaultClip);  //use null or visible screen area
////                        clipChanged = true;
//                    }
//                }
//
//                localG2.draw(currentShape);
//                g2.setStroke(currentStroke);
//    //            g2.setComposite(comp);
//            }
//
//
//            localG2.setComposite(new Composite() {
//                final CompositeContext lightenContext = new LightenContext();
//
//                @Override
//                public CompositeContext createContext(final ColorModel srcColorModel, final ColorModel dstColorModel, final RenderingHints hints) {
//                    return lightenContext;
//                }
//
//                class LightenContext implements CompositeContext {
//
//                    @Override
//                    public void compose(final Raster src, final Raster dstIn, final WritableRaster dstOut) {
//                        final int width = dstIn.getWidth();
//                        final int height = dstIn.getHeight();
//                        final int[] srcRow = new int[width];
//                        final int[] dstRow = new int[width];
//                        for (int y = 0; y < height; ++y) {
//                            src.getDataElements(0, y, width, 1, srcRow);
//                            dstIn.getDataElements(0, y, width, 1, dstRow);
//
//                            for (int x = 0; x < width; ++x) {
//                                final int s = srcRow[x];
//                                final int d = dstRow[x];
//                                final int a = ((s >> 24) & 0xFF);
//                                final int r = ((s >> 16) & 0xFF);
//                                final int g = ((s >> 8) & 0xFF);
//                                final int b = ((s) & 0xFF);
//
//                                final int da = ((d >> 24) & 0xFF);
//                                final int dr = ((d >> 16) & 0xFF);
//                                final int dg = ((d >> 8) & 0xFF);
//                                final int db = ((d) & 0xFF);
//                                System.out.println("S: "+a+", "+r+", "+g+", "+b+"             "+"D: "+da+", "+dr+", "+dg+", "+db);
//                                dstRow[x] = (da * (a/255))<<24 | dr<<16 | dg<<8 | db;
//                            }
//
//                            dstOut.setDataElements(0, y, width, 1, dstRow);
//                        }
//                    }
//
//                    @Override
//                    public void dispose() {
//                    }
//                }
//            });
//
////            ShowGUIMessage.showGUIMessage("Before", softClipImage, "Before");
//            System.out.println("Clip : " + clip.getBounds());
//            localG2.setColor(Color.WHITE);
//            localG2.fill(clip);
////            ShowGUIMessage.showGUIMessage("After", softClipImage, "After");
//
//            AffineTransform origTrans = g2.getTransform();
//            g2.setClip(null);
//            clipChanged = true;
//            g2.translate(clip.getBounds().x, clip.getBounds().y);
//            g2.scale(1f / scaling, 1f / scaling);
//
//            final RenderingHints hints = g2.getRenderingHints();
//            g2.setRenderingHints(new RenderingHints(null));
//            g2.drawImage(softClipImage, 0, 0, null);
//            g2.setRenderingHints(hints);
//            g2.scale(scaling, scaling);
//            g2.translate(-clip.getBounds().x, -clip.getBounds().y);
//
//            g2.setTransform(origTrans);
//            g2.setComposite(comp);
//            g2.setClip(clip);
//        } else {

        //stroke and fill (do fill first so we don't overwrite Stroke)
        if (fillType == GraphicsState.FILL || fillType == GraphicsState.FILLSTROKE) {
            // Fill color is null if the shape is a pattern
            if (fillCol != null) {
                if ((fillCol.getRGB() != -1) &&
                        //If we have an alt text color, are changing line art as well, its within threshold and not an additional item, use alt color

                        (changeLineArtAndText && textColor != null && !fillCol.isPattern() && (itemToRender == -1 || (endItem == -1 || itemToRender <= endItem)) && checkColorThreshold(fillCol.getRGB()))) {
                    fillCol = new PdfColor(textColor.getRed(), textColor.getGreen(), textColor.getBlue());

                }

                fillCol.setScaling(cropX, cropH, scaling, 0, 0);
            }

            if (customColorHandler != null) {
                customColorHandler.setPaint(g2, fillCol, rawPageNumber, isPrinting);
            } else if (DecoderOptions.Helper != null) {
                DecoderOptions.Helper.setPaint(g2, fillCol, rawPageNumber, isPrinting);
            } else {
                g2.setPaint(fillCol);
            }

            renderComposite(fillOpacity);

            try {
                //thin lines do not appear unless we use fillRect
                final double iw = currentShape.getBounds2D().getWidth();
                final double ih = currentShape.getBounds2D().getHeight();

                if ((ih == 0d || iw == 0d) && ((BasicStroke) g2.getStroke()).getLineWidth() <= 1.0f) {
                    g2.fillRect(currentShape.getBounds().x, currentShape.getBounds().y, currentShape.getBounds().width, currentShape.getBounds().height);
                } else {
                    g2.fill(currentShape);
                }

            } catch (final Exception e) {
                LogWriter.writeLog("Exception " + e + " filling shape");
            }

            g2.setComposite(comp);
        }

        if ((fillType == GraphicsState.STROKE) || (fillType == GraphicsState.FILLSTROKE)) {

            //set values for drawing the shape
            final Stroke currentStroke = g2.getStroke();

            //fix for using large width on point to draw line
            if (currentShape.getBounds2D().getWidth() < 1.0f && ((BasicStroke) shapeStroke).getLineWidth() > 10) {
                g2.setStroke(new BasicStroke(1));
            } else {
                //Adjust line width to 1 if less than 1
                //ignore if using T3Display (such as ap image generation in html / svg conversion
                if (enhanceFractionalLines && ((((BasicStroke) shapeStroke).getLineWidth() * scaling < 1) &&
                        !isPrinting && !(this instanceof T3Display))) {
                    g2.setStroke(new BasicStroke(1 / scaling, ((BasicStroke) shapeStroke).getEndCap(), ((BasicStroke) shapeStroke).getLineJoin(), ((BasicStroke) shapeStroke).getMiterLimit(), ((BasicStroke) shapeStroke).getDashArray(), ((BasicStroke) shapeStroke).getDashPhase()));
                } else {
                    g2.setStroke(shapeStroke);
                }
            }

            //If we have an alt text color, are changing line art, its within threshold and not an additional item, use alt color
            if (changeLineArtAndText && textColor != null && !strokeCol.isPattern() && (itemToRender == -1 || (endItem == -1 || itemToRender <= endItem)) && checkColorThreshold(strokeCol.getRGB())) {
                strokeCol = new PdfColor(textColor.getRed(), textColor.getGreen(), textColor.getBlue());
            }

            strokeCol.setScaling(cropX, cropH, scaling, 0, 0);

            if (customColorHandler != null) {
                customColorHandler.setPaint(g2, strokeCol, rawPageNumber, isPrinting);
            } else if (DecoderOptions.Helper != null) {
                DecoderOptions.Helper.setPaint(g2, strokeCol, rawPageNumber, isPrinting);
            } else {
                g2.setPaint(strokeCol);
            }

            renderComposite(strokeOpacity);

            if (!isPrinting && clip != null && clip.getBounds2D().getWidth() % 1 > 0.65f && clip.getBounds2D().getHeight() % 1 > 0.1f) {
                if (currentShape.getBounds().getWidth() == clip.getBounds().getWidth()) {
                    g2.setClip(ClipUtils.convertPDFClipToJavaClip(new Area(clip)));  //use null or visible screen area
                    clipChanged = true;
                }
            }

            //breaks printing so disabled there
            if (!isPrinting && clip != null) {
                final Double height = clip.getBounds2D().getHeight();
                final Double width = clip.getBounds2D().getWidth();
                if ((height < 1 && height > 0) || (width < 1 && width > 0)) {
                    g2.setClip(defaultClip);  //use null or visible screen area
                    clipChanged = true;
                }
            }

            g2.draw(currentShape);
            g2.setStroke(currentStroke);
            g2.setComposite(comp);
        }
//        }

        if (clipChanged) {
            g2.setClip(clip);
        }
    }

    void renderImage(final AffineTransform imageAf, BufferedImage image, final float alpha,
                     final GraphicsState currentGraphicsState, final float x, final float y) {

        final boolean renderDirect = (currentGraphicsState != null);

        if (image == null || g2 == null) {
            return;
        }

        final AffineTransform before = g2.getTransform();

        final Composite c = g2.getComposite();
        renderComposite(alpha);

        final AffineTransform upside_down;

        float CTM[][] = new float[3][3];
        if (currentGraphicsState != null) {
            CTM = currentGraphicsState.CTM;
        } else {
            final double[] values = new double[6];
            imageAf.getMatrix(values);
            CTM[0][0] = (float) values[0];
            CTM[0][1] = (float) values[1];
            CTM[1][0] = (float) values[2];
            CTM[1][1] = (float) values[3];
            CTM[2][0] = x;
            CTM[2][1] = y;
        }

        final int w = image.getWidth();
        final int h = image.getHeight();

        final double[] values = {CTM[0][0] / w, CTM[0][1] / w, -CTM[1][0] / h, -CTM[1][1] / h, 0, 0};
        upside_down = new AffineTransform(values);

        g2.translate(CTM[2][0] + CTM[1][0], CTM[2][1] + CTM[1][1]);

        //allow user to over-ride
        boolean useCustomRenderer = customImageHandler != null;

        if (useCustomRenderer) {
            useCustomRenderer = customImageHandler.drawImageOnscreen(image, 0, upside_down, null, g2, renderDirect, objectStoreRef, isPrinting);

            //exit if done
            if (useCustomRenderer) {
                g2.setComposite(c);
                return;
            }
        }

        //hack to make bw
        if (customColorHandler != null) {
            final BufferedImage newImage = customColorHandler.processImage(image, rawPageNumber, isPrinting);
            if (newImage != null) {
                image = newImage;
            }
        } else if (DecoderOptions.Helper != null) {
            final BufferedImage newImage = DecoderOptions.Helper.processImage(image, rawPageNumber, isPrinting);
            if (newImage != null) {
                image = newImage;
            }
        }

        final Shape g2clip = g2.getClip();
        boolean isClipReset = false;

        //hack to fix clipping issues due to sub-pixels
        if (g2clip != null) {

            final double cy = g2.getClip().getBounds2D().getY();
            final double ch = g2.getClip().getBounds2D().getHeight();
            double diff = image.getHeight() - ch;
            if (diff < 0) {
                diff = -diff;
            }

            if (diff > 0 && diff < 1 && cy < 0 && image.getHeight() > 1 && image.getHeight() < 10) {

                final boolean isSimpleOutline = ShapeUtils.isSimpleOutline(g2.getClip());

                if (isSimpleOutline) {
                    final double cx = g2.getClip().getBounds2D().getX();
                    final double cw = g2.getClip().getBounds2D().getWidth();

                    g2.setClip(new Rectangle((int) cx, (int) cy, (int) cw, (int) ch));

                    isClipReset = false;
                }
            }
        }

        //Draw image as normal
        g2.drawImage(image, upside_down, null);

        if (isClipReset) {
            g2.setClip(g2clip);
        }

        g2.setTransform(before);

        g2.setComposite(c);

    }

    @Override
    public void setScalingValues(final double cropX, final double cropH, final float scaling) {

        this.cropX = cropX;
        this.cropH = cropH;
        this.scaling = scaling;

    }

    /**
     * turn object into byte[] so we can move across
     * this way should be much faster than the stadard Java serialise.
     * 
* NOT PART OF API and subject to change (DO NOT USE) * * @throws java.io.IOException */ @Override public byte[] serializeToByteArray(final Set fontsAlreadyOnClient) throws IOException { return new byte[0]; } @Override public void drawShape(final PdfShape pdfShape, final GraphicsState currentGraphicsState, final int cmd) { // throw new UnsupportedOperationException("Not supported yet."); } @Override public void drawEmbeddedText(final float[][] Trm, final int fontSize, final PdfGlyph embeddedGlyph, final Object javaGlyph, final int type, final GraphicsState gs, final double[] at, final String glyf, final PdfFont currentFontData, final float glyfWidth) { //throw new UnsupportedOperationException("Not supported yet."); } @Override public void paint(final Rectangle[] highlights, final AffineTransform viewScaling, final Rectangle userAnnot) { // throw new UnsupportedOperationException("Not supported yet."); } @Override public int drawImage(final int pageNumber, final BufferedImage image, final GraphicsState currentGraphicsState, final boolean alreadyCached, final String name, final int previousUse) { return -1; } @Override public void drawAdditionalObjectsOverPage(final int[] type, final Color[] colors, final Object[] obj) throws PdfException { } @Override public void drawText(final float[][] Trm, final String text, final GraphicsState currentGraphicsState, final float x, final float y, final Font javaFont) { //throw new UnsupportedOperationException("Not supported yet."); } @Override public void setGraphicsState(final int fillType, final float value, final int BM) { //throw new UnsupportedOperationException("Not supported yet."); } @Override public void drawTR(final int value) { //throw new UnsupportedOperationException("Not supported yet."); } @Override public void drawClip(final GraphicsState currentGraphicsState, final Shape defaultClip, final boolean alwaysDraw) { // throw new UnsupportedOperationException("Not supported yet."); } /** * used by some custom version of DynamicVectorRenderer */ @Override public void writeCustom(final int key, final Object value) { switch (key) { case CUSTOM_IMAGE_HANDLER: this.customImageHandler = (org.jpedal.external.ImageHandler) value; break; case CUSTOM_COLOR_HANDLER: this.customColorHandler = (org.jpedal.external.ColorHandler) value; break; case PAINT_BACKGROUND: paintBackground((Shape) value); break; } } @Override public void setValue(final int key, final int i) { switch (key) { case ALT_BACKGROUND_COLOR: backgroundColor = new Color(i); break; case ALT_FOREGROUND_COLOR: textColor = new Color(i); break; case FOREGROUND_INCLUDE_LINEART: changeLineArtAndText = i > 0; break; case COLOR_REPLACEMENT_THRESHOLD: colorThresholdToReplace = i; break; case ENHANCE_FRACTIONAL_LINES: enhanceFractionalLines = i != 0; break; case TOKEN_NUMBER: this.currentTokenNumber = i; break; } } @Override public int getValue(final int key) { switch (key) { case TOKEN_NUMBER: return currentTokenNumber; //used by HTML to get font handing mode, etc //this is the unused 'dummy' default implementation required for other modes as in Interface default: return -1; } } /** * allow user to read */ @Override public boolean getBooleanValue(final int key) { return false; } /** * only used in HTML5 and SVG conversion * * @param fontObjID * @param s * @param potentialWidth */ @Override public void saveAdvanceWidth(final int fontObjID, final String s, final int potentialWidth) { } /*save shape in array to draw*/ @Override public void drawShape(final Object currentShape, final GraphicsState currentGraphicsState) { System.out.println("drawShape in BaseDisplay Should never be called"); } /*save shape in array to draw*/ @Override public void eliminateHiddenText(final Shape currentShape, final GraphicsState gs, final int count, final boolean ignoreScaling) { } protected void renderComposite(final float alpha) { if (blendMode == PdfDictionary.Normal || blendMode == PdfDictionary.Compatible) { if (alpha != 1.0f) { g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha)); } } else { /// if (alpha != 1.0f){ - possible fix for 19888 to test final Composite comp = new BlendMode(blendMode, alpha); g2.setComposite(comp); } } @Override public boolean isHTMLorSVG() { return false; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy