public static void drawImage()

in batik-awt-util/src/main/java/org/apache/batik/ext/awt/image/GraphicsUtil.java [96:384]


    public static void drawImage(Graphics2D g2d,
                                 CachableRed cr) {

        // System.out.println("DrawImage G: " + g2d);

        AffineTransform at = null;
        while (true) {
            if (cr instanceof AffineRed) {
                AffineRed ar = (AffineRed)cr;
                if (at == null)
                    at = ar.getTransform();
                else
                    at.concatenate(ar.getTransform());
                cr = ar.getSource();
                continue;
            } else if (cr instanceof TranslateRed) {
                TranslateRed tr = (TranslateRed)cr;
                // System.out.println("testing Translate");
                int dx = tr.getDeltaX();
                int dy = tr.getDeltaY();
                if (at == null)
                    at = AffineTransform.getTranslateInstance(dx, dy);
                else
                    at.translate(dx, dy);
                cr = tr.getSource();
                continue;
            }
            break;
        }
        AffineTransform g2dAt   = g2d.getTransform();
        if ((at == null) || (at.isIdentity()))
            at = g2dAt;
        else
            at.preConcatenate(g2dAt);

        ColorModel srcCM = cr.getColorModel();
        ColorModel g2dCM = getDestinationColorModel(g2d);
        ColorSpace g2dCS = null;
        if (g2dCM != null)
            g2dCS = g2dCM.getColorSpace();
        if (g2dCS == null)
            // Assume device is sRGB
            g2dCS = ColorSpace.getInstance(ColorSpace.CS_sRGB);

        ColorModel drawCM = g2dCM;
        if ((g2dCM == null) || !g2dCM.hasAlpha()) {
            // If we can't find out about our device or the device
            // does not support alpha just use SRGB unpremultiplied
            // (Just because this seems to work for us).
            drawCM = sRGB_Unpre;
        }

        if (cr instanceof BufferedImageCachableRed) {
            // There is a huge win if we can use the BI directly here.
            // This results in something like a 10x performance gain
            // for images, the best thing is this is the common case.
            if (g2dCS.equals(srcCM.getColorSpace()) &&
                drawCM.equals(srcCM)) {
                // System.err.println("Fast Case");
                g2d.setTransform(at);
                BufferedImageCachableRed bicr;
                bicr = (BufferedImageCachableRed)cr;
                g2d.drawImage(bicr.getBufferedImage(),
                              bicr.getMinX(), bicr.getMinY(), null);
                g2d.setTransform(g2dAt);
                return;
            }
        }

        // Scaling down so do it before color conversion.
        double determinant = at.getDeterminant();
        if (!at.isIdentity() && (determinant <= 1.0)) {
            if (at.getType() != AffineTransform.TYPE_TRANSLATION)
                cr = new AffineRed(cr, at, g2d.getRenderingHints());
            else {
                int xloc = cr.getMinX() + (int)at.getTranslateX();
                int yloc = cr.getMinY() + (int)at.getTranslateY();
                cr = new TranslateRed(cr, xloc, yloc);
            }
        }

        if (g2dCS != srcCM.getColorSpace()) {
            // System.out.println("srcCS: " + srcCM.getColorSpace());
            // System.out.println("g2dCS: " + g2dCS);
            // System.out.println("sRGB: " +
            //                    ColorSpace.getInstance(ColorSpace.CS_sRGB));
            // System.out.println("LsRGB: " +
            //                    ColorSpace.getInstance
            //                    (ColorSpace.CS_LINEAR_RGB));
            if      (g2dCS == ColorSpace.getInstance(ColorSpace.CS_sRGB))
                cr = convertTosRGB(cr);
            else if (g2dCS == ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB))
                cr = convertToLsRGB(cr);
        }
        srcCM = cr.getColorModel();
        if (!drawCM.equals(srcCM))
            cr = FormatRed.construct(cr, drawCM);

        // Scaling up so do it after color conversion.
        if (!at.isIdentity() && (determinant > 1.0))
            cr = new AffineRed(cr, at, g2d.getRenderingHints());

        // Now CR is in device space, so clear the g2d transform.
        g2d.setTransform(IDENTITY);

        // Ugly Hack alert.  This Makes it use our SrcOver implementation
        // Which doesn't seem to have as many bugs as the JDK one when
        // going between different src's and destinations (of course it's
        // also a lot slower).
        Composite g2dComposite = g2d.getComposite();
        if (g2d.getRenderingHint(RenderingHintsKeyExt.KEY_TRANSCODING) ==
            RenderingHintsKeyExt.VALUE_TRANSCODING_PRINTING) {
            if (SVGComposite.OVER.equals(g2dComposite)) {
                g2d.setComposite(SVGComposite.OVER);
            }
        }
        Rectangle crR  = cr.getBounds();
        Shape     clip = g2d.getClip();

        try {
            Rectangle clipR;
            if (clip == null) {
                clip  = crR;
                clipR = crR;
            } else {
                clipR   = clip.getBounds();

                if ( ! clipR.intersects(crR) )
                    return; // Nothing to draw...
                clipR = clipR.intersection(crR);
            }

            Rectangle gcR = getDestinationBounds(g2d);
            // System.out.println("ClipRects: " + clipR + " -> " + gcR);
            if (gcR != null) {
                if ( ! clipR.intersects(gcR) )
                    return; // Nothing to draw...
                clipR = clipR.intersection(gcR);
            }

            // System.out.println("Starting Draw: " + cr);
            // long startTime = System.currentTimeMillis();

            boolean useDrawRenderedImage = false;

            srcCM = cr.getColorModel();
            SampleModel srcSM = cr.getSampleModel();
            if ((srcSM.getWidth()*srcSM.getHeight()) >=
                (clipR.width*clipR.height))
                // if srcSM tiles are around the clip size
                // then just draw the renderedImage
                useDrawRenderedImage = true;

            Object atpHint = g2d.getRenderingHint
                (RenderingHintsKeyExt.KEY_AVOID_TILE_PAINTING);

            if (atpHint == RenderingHintsKeyExt.VALUE_AVOID_TILE_PAINTING_ON)
                useDrawRenderedImage = true; //for PDF and PS transcoders

            if (atpHint == RenderingHintsKeyExt.VALUE_AVOID_TILE_PAINTING_OFF)
                useDrawRenderedImage = false;


            WritableRaster wr;
            if (useDrawRenderedImage) {
                // This can be significantly faster but can also
                // require much more memory, so we only use it when
                // the clip size is smaller than the tile size.
                Raster r = cr.getData(clipR);
                wr = ((WritableRaster)r).createWritableChild
                    (clipR.x, clipR.y, clipR.width, clipR.height,
                     0, 0, null);

                BufferedImage bi = new BufferedImage
                    (srcCM, wr, srcCM.isAlphaPremultiplied(), null);

                // Any of the drawImage calls that take an
                // Affine are prone to the 'CGGStackRestore: gstack
                // underflow' bug on Mac OS X.  This should work
                // around that problem.
                g2d.drawImage(bi, clipR.x, clipR.y, null);
            } else {
                // Use tiles to draw image...
                wr = Raster.createWritableRaster(srcSM, new Point(0,0));
                BufferedImage bi = new BufferedImage
                    (srcCM, wr, srcCM.isAlphaPremultiplied(), null);

                int xt0 = cr.getMinTileX();
                int xt1 = xt0+cr.getNumXTiles();
                int yt0 = cr.getMinTileY();
                int yt1 = yt0+cr.getNumYTiles();
                int tw  = srcSM.getWidth();
                int th  = srcSM.getHeight();

                Rectangle tR  = new Rectangle(0,0,tw,th);
                Rectangle iR  = new Rectangle(0,0,0,0);

                if (false) {
                    System.err.println("SrcCM: " + srcCM);
                    System.err.println("CR: " + cr);
                    System.err.println("CRR: " + crR + " TG: [" +
                                       xt0 + ',' +
                                       yt0 + ',' +
                                       xt1 + ',' +
                                       yt1 +"] Off: " +
                                       cr.getTileGridXOffset() + ',' +
                                       cr.getTileGridYOffset());
                }

                int yloc = yt0*th+cr.getTileGridYOffset();
                int skip = (clipR.y-yloc)/th;
                if (skip <0) skip = 0;
                yt0+=skip;

                int xloc = xt0*tw+cr.getTileGridXOffset();
                skip = (clipR.x-xloc)/tw;
                if (skip <0) skip = 0;
                xt0+=skip;

                int endX = clipR.x+clipR.width-1;
                int endY = clipR.y+clipR.height-1;

                if (false) {
                    System.out.println("clipR: " + clipR + " TG: [" +
                                       xt0 + ',' +
                                       yt0 + ',' +
                                       xt1 + ',' +
                                       yt1 +"] Off: " +
                                       cr.getTileGridXOffset() + ',' +
                                       cr.getTileGridYOffset());
                }


                yloc = yt0*th+cr.getTileGridYOffset();
                int minX = xt0*tw+cr.getTileGridXOffset();
                int xStep = tw;
                xloc = minX;
                for (int y=yt0; y<yt1; y++, yloc += th) {
                    if (yloc > endY) break;
                    for (int x=xt0; x<xt1; x++, xloc+=xStep) {
                        if ((xloc<minX) || (xloc > endX)) break;
                        tR.x = xloc;
                        tR.y = yloc;
                        Rectangle2D.intersect(crR, tR, iR);

                        WritableRaster twr;
                        twr = wr.createWritableChild(0, 0,
                                                     iR.width, iR.height,
                                                     iR.x, iR.y, null);

                        // System.out.println("Generating tile: " + twr);
                        cr.copyData(twr);

                        // Make sure we only draw the region that was written.
                        BufferedImage subBI;
                        subBI = bi.getSubimage(0, 0, iR.width,  iR.height);

                        if (false) {
                            System.out.println("Drawing: " + tR);
                            System.out.println("IR: "      + iR);
                        }

                        // For some reason using the transform version
                        // causes a gStackUnderflow error but if I just
                        // use the drawImage with an x & y it works.
                        g2d.drawImage(subBI, iR.x, iR.y, null);
                        // AffineTransform trans
                        //  = AffineTransform.getTranslateInstance(iR.x, iR.y);
                        // g2d.drawImage(subBI, trans, null);

                        // String label = "sub [" + x + ", " + y + "]: ";
                        // org.ImageDisplay.showImage
                        //     (label, subBI);
                    }
                    xStep = -xStep; // Reverse directions.
                    xloc += xStep;   // Get back in bounds.
                }
            }
            // long endTime = System.currentTimeMillis();
            // System.out.println("Time: " + (endTime-startTime));


        } finally {
            g2d.setTransform(g2dAt);
            g2d.setComposite(g2dComposite);
        }

        // System.out.println("Finished Draw");
    }