Example usage for java.awt Graphics2D rotate

List of usage examples for java.awt Graphics2D rotate

Introduction

In this page you can find the example usage for java.awt Graphics2D rotate.

Prototype

public abstract void rotate(double theta);

Source Link

Document

Concatenates the current Graphics2D Transform with a rotation transform.

Usage

From source file:net.sf.firemox.clickable.target.card.VirtualCard.java

@SuppressWarnings("null")
@Override//from w  w w  .  j  a v a  2s.co  m
public void paintComponent(Graphics g) {
    final Graphics2D g2D = (Graphics2D) g;

    // Renderer
    g2D.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
    g2D.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
    g2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    g2D.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);

    // Optimization card painting
    final MZone container = card.getContainer();
    final boolean shortPaint = container == null || !container.isMustBePainted(card);

    // tap/reverse operation : PI/2, PI, -PI/2 rotation
    if (!shortPaint) {
        if (container.isMustBePaintedReversed(card)) {
            if (card.tapped) {
                g2D.translate(rotateTransformY, CardFactory.cardWidth + rotateTransformX);
                g2D.rotate(angle - Math.PI / 2);
            } else {
                g2D.translate(CardFactory.cardWidth + rotateTransformX,
                        CardFactory.cardHeight + rotateTransformY);
                g2D.rotate(Math.PI - angle);
            }
        } else {
            if (card.tapped) {
                g2D.translate(CardFactory.cardHeight + rotateTransformY, rotateTransformX);
                g2D.rotate(Math.PI / 2 + angle);
            } else {
                g2D.translate(rotateTransformX, rotateTransformY);
                g2D.rotate(angle);
            }
        }
    }

    if (container != null) {
        if (container.isVisibleForOpponent() && !card.isVisibleForOpponent() && card.isVisibleForYou()) {
            /*
             * This card is visible for you but not for opponent in despite of the
             * fact the container is public.
             */
            g2D.drawImage(card.scaledImage(), null, null);
            g2D.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f));
            g2D.drawImage(DatabaseFactory.scaledBackImage, null, null);
        } else if (!card.isVisibleForYou()) {
            g2D.drawImage(DatabaseFactory.scaledBackImage, null, null);
        } else {
            g2D.drawImage(card.scaledImage(), null, null);
        }
    }

    if (shortPaint)
        return;

    /*
     * The card picture is displayed as a rounded rectangle with 0,90,180 or
     * 270
     */
    if (card.isHighLighted && (card.isVisibleForYou() || StackManager.idHandedPlayer == 0)) {
        // Draw the rounded colored rectangle
        g2D.setColor(card.highLightColor);
        g2D.draw3DRect(0, 0, CardFactory.cardWidth - 2, CardFactory.cardHeight - 2, false);
    }

    // Draw the eventual progress bar
    card.database.updatePaintNotification(card, g);

    // Cursor for our pretty pictures
    int px = 3;
    int py = 3;
    int maxX = CardFactory.cardWidth - 2;

    // for in-play, visible cards
    if (card.isVisibleForYou() || (container != null && container.isVisibleForYou())) {

        // draw registers above the card's picture
        if (refreshToolTipFilter().powerANDtoughness) {
            // power / toughness
            final String powerANDtoughness = String.valueOf(card.getValue(IdTokens.POWER)) + "/"
                    + card.getValue(IdTokens.TOUGHNESS);
            g2D.setFont(g2D.getFont().deriveFont(Font.BOLD, 13));
            final Rectangle2D stringDim = g2D.getFontMetrics().getStringBounds(powerANDtoughness, g2D);
            g2D.setColor(CardFactory.powerToughnessColor);
            g2D.drawString(powerANDtoughness, (int) (CardFactory.cardWidth - stringDim.getWidth() - 3),
                    CardFactory.cardHeight - 5);
            g2D.setColor(Color.BLUE);
            g2D.drawString(powerANDtoughness, (int) (CardFactory.cardWidth - stringDim.getWidth() - 3),
                    CardFactory.cardHeight - 6);
        }

        /*
         * START drawing additional pictures
         */

        // draw state pictures
        for (StatePicture statePicture : CardFactory.statePictures) {
            if (px + 13 > maxX) {
                px = 3;
                py += 13;
            }
            if (statePicture.paint(card, g2D, px, py)) {
                px += 13;
            }
        }

        // draw properties
        if (card.cachedProperties != null) {
            for (Integer property : card.cachedProperties) {
                if (Configuration.getBoolean("card.property.picture", true)
                        && CardFactory.propertyPictures.get(property) != null) {
                    // There is an associated picture to this property
                    if (px + 13 > maxX) {
                        px = 3;
                        py += 13;
                    }
                    g2D.drawImage(CardFactory.propertyPictures.get(property), px, py, 12, 12, null);
                    px += 13;
                }
            }
        }
    }

    // draw attached objects
    int startX = 3;
    int startY = CardFactory.cardHeight - 18;
    if (card.registerModifiers != null) {
        for (int i = card.registerModifiers.length; i-- > 0;) {
            if (card.registerModifiers[i] != null) {
                startX = card.registerModifiers[i].paintObject(g, startX, startY);
            }
        }
    }
    if (card.propertyModifier != null) {
        startX = card.propertyModifier.paintObject(g, startX, startY);
    }
    if (card.idCardModifier != null) {
        card.idCardModifier.paintObject(g, startX, startY);
        /*
         * END drawing additional pictures
         */
    }

    // Draw the target Id if helper said it
    final String id = TargetHelper.getInstance().getMyId(card);
    if (id != null) {
        if (px + 13 > maxX) {
            px = 3;
            py += 13;
        }
        if (id == TargetHelper.STR_CONTEXT1) {
            // TODO I am in the context 1, draw a picture
            g2D.setColor(Color.BLUE);
            g2D.setFont(g2D.getFont().deriveFont(Font.BOLD, 60 / id.length()));
            g2D.drawString(id, 5, CardFactory.cardHeight - 15);
        } else if (id == TargetHelper.STR_CONTEXT2) {
            // TODO I am in the context 2, draw a picture
            g2D.setColor(Color.BLUE);
            g2D.setFont(g2D.getFont().deriveFont(Font.BOLD, 60 / id.length()));
            g2D.drawString(id, 5, CardFactory.cardHeight - 15);
        } else if (id != TargetHelper.STR_SOURCE) {
            // } else if (id == TargetHelper.STR_SOURCE) {
            // TODO I am the source, draw a picture
            // } else {
            // I am a target
            g2D.drawImage(TargetHelper.getInstance().getTargetPictureSml(), px, py, null);
            py += 12;
        }
    }

    g2D.dispose();
}

From source file:spinworld.gui.RadarPlot.java

private void drawTicks(Graphics2D g2, Rectangle2D radarArea, double axisAngle, int cat) {
    double[] ticks = { 0.5d, 1d };
    for (int i = 0; i < ticks.length; i++) {
        double tick = ticks[i];
        Point2D middlePoint = getWebPoint(radarArea, axisAngle, tick);
        double xt = middlePoint.getX();
        double yt = middlePoint.getY();
        double angrad = Math.toRadians(-axisAngle);
        g2.translate(xt, yt);//from  w  w w.  jav  a2 s .c o  m
        g2.rotate(angrad);
        g2.drawLine(0, (int) -TICK_MARK_LENGTH / 2, 0, (int) TICK_MARK_LENGTH / 2);
        g2.rotate(-angrad);
        g2.translate(-xt, -yt);
        drawTickLabel(g2, radarArea, middlePoint, axisAngle, cat, tick);
    }
}

From source file:org.apache.fop.util.BitmapImageUtilTestCase.java

private BufferedImage createTestImage() {
    BufferedImage buf = new BufferedImage(640, 480, BufferedImage.TYPE_INT_RGB);
    Graphics2D g2d = buf.createGraphics();
    g2d.setBackground(Color.WHITE);
    g2d.clearRect(0, 0, buf.getWidth(), buf.getHeight());

    //A few rectangles rotated and with different color
    Graphics2D copy = (Graphics2D) g2d.create();
    copy.translate(170, 170);// www  .j a v a2  s.  c om
    int c = 12;
    for (int i = 0; i < c; i++) {
        float f = ((i + 1) / (float) c);
        Color col = new Color(0.0f, 1 - f, 0.0f);
        copy.setColor(col);
        copy.fillRect(0, 0, 120, 120);
        copy.rotate(-2 * Math.PI / c);
    }
    copy.dispose();

    //the same in gray scales
    copy = (Graphics2D) g2d.create();
    copy.translate(470, 310);
    c = 12;
    for (int i = 0; i < c; i++) {
        float f = ((i + 1) / (float) c);
        Color col = new Color(f, f, f);
        copy.setColor(col);
        copy.fillRect(0, 0, 120, 120);
        copy.rotate(-2 * Math.PI / c);
    }
    copy.dispose();
    return buf;
}

From source file:org.gitools.ui.app.heatmap.drawer.AbstractHeatmapDrawer.java

protected static void paintCell(Decoration decoration, Color gridColor, int gridSize, int offsetX, int offsetY,
        int width, int height, Graphics2D g, Rectangle box) {

    int y = box.y + offsetY;
    int x = box.x + offsetX;

    g.setColor(decoration.getBgColor());
    g.fillRect(x, y, width, height);//from  w  w  w.  j  a v  a 2s  . c  om

    g.setColor(gridColor);
    g.fillRect(x, y + height, width, gridSize);

    String text = decoration.getFormatedValue();
    if (!StringUtils.isEmpty(text)) {

        Font font = g.getFont();

        boolean isRotated = decoration.isRotate();

        int fontHeight = (int) font.getSize2D();

        if (fontHeight <= (isRotated ? width : height)) {

            int textWidth = (int) g.getFontMetrics().getStringBounds(text, g).getWidth();
            //TODO: textWidth depends on SuperScript

            if (textWidth < (isRotated ? height : width)) {

                int leftMargin = ((width - textWidth) / 2) + 1;
                int bottomMargin = ((height - fontHeight) / 2) + 1;

                if (isRotated) {
                    leftMargin = ((width - fontHeight) / 2) + 1;
                    bottomMargin = height - (((height - textWidth) / 2));
                }

                g.setColor(Colors.bestForegroundColor(decoration.getBgColor()));
                if (text.matches("[0-9\\.]+e-?[0-9]+")) {
                    int e_pos = text.indexOf("e") + 3;
                    text = text.replaceAll("e(-?[0-9]+)", "10$1");
                    int superscriptEnd = text.length();
                    AttributedString attText = new AttributedString(text);
                    attText.addAttribute(TextAttribute.SUPERSCRIPT, TextAttribute.SUPERSCRIPT_SUPER, e_pos,
                            superscriptEnd);
                    if (isRotated) {
                        g.rotate(radianAngle90);
                        g.drawString(attText.getIterator(), y + height - bottomMargin, -x - leftMargin - 1);
                        g.rotate(-radianAngle90);
                    } else {
                        g.drawString(attText.getIterator(), x + leftMargin, y + height - bottomMargin);
                    }
                } else {

                    if (isRotated) {
                        g.rotate(radianAngle90);
                        g.drawString(text, y + height - bottomMargin, -x - leftMargin - 1);

                        if ("CoCA-08".equals(text)) {
                            System.out.println("x = " + x + " leftMargin = " + leftMargin + " width = " + width
                                    + " fontHeight = " + fontHeight);
                        }

                        g.rotate(-radianAngle90);
                    } else {
                        g.drawString(text, x + leftMargin, y + height - bottomMargin);
                    }
                }
            }
        }
    }

}

From source file:org.jcurl.core.swing.RockLocationDisplayBase.java

/**
 * Draw one rock at it's wc position. Builds the coordinate transform and
 * calls {@link #paintRockRC(Graphics2D, boolean, int)}.
 * /*  ww w  . j  a v  a  2 s  .c om*/
 * @param g
 * @param rock
 * @param isDark
 * @param idx
 * @see RockPainter#paintRockRC(Graphics2D, boolean, int)
 */
protected void paintRockWC(final Graphics2D g, final Rock rock, final boolean isDark, final int idx) {
    final AffineTransform t = g.getTransform();
    g.translate(JCurlDisplay.SCALE * rock.getX(), JCurlDisplay.SCALE * rock.getY());
    g.rotate(Math.PI + rock.getZ());
    // make the right-handed coordinate system left handed again (for
    // un-flipped text display)
    g.scale(-1, 1);
    paintRockRC(g, isDark, idx);
    g.setTransform(t);
}

From source file:org.jimcat.services.imagemanager.ImageUtil.java

/**
 * this methode will create a rotated version of the given img. if the
 * rotation is ROTATION_0 the original image will be returned
 * //w w w.  j a va2  s. c o m
 * @param img -
 *            the image to rotate
 * @param rotation -
 *            describing the requested rotation
 * @return - the rotated image
 */
public static BufferedImage rotateImage(BufferedImage img, ImageRotation rotation) {

    // check if there must be a rotation
    if (rotation == ImageRotation.ROTATION_0) {
        return img;
    }

    // get resulting dimension
    Dimension resultDim = null;
    if (rotation == ImageRotation.ROTATION_180) {
        // same dimension
        resultDim = new Dimension(img.getWidth(), img.getHeight());
    } else {
        // transpned dimension
        resultDim = new Dimension(img.getHeight(), img.getWidth());
    }

    // create resulting image
    // resulting image type
    int type = getImageType(img);

    // calculate next scaling step
    int width = resultDim.width;
    int height = resultDim.height;
    BufferedImage tmp = new BufferedImage(width, height, type);
    Graphics2D g2 = tmp.createGraphics();

    // rotate image
    g2.rotate(rotation.getAngle());

    // move ordinal back to starting point
    if (rotation == ImageRotation.ROTATION_90) {
        g2.translate(0, -width);
    } else if (rotation == ImageRotation.ROTATION_180) {
        g2.translate(-width, -height);
    } else if (rotation == ImageRotation.ROTATION_270) {
        g2.translate(-height, 0);
    }

    g2.drawImage(img, 0, 0, null);
    g2.dispose();

    // return result
    return tmp;
}

From source file:org.openstreetmap.josm.tools.ImageProvider.java

/**
 * Creates a rotated version of the input image.
 *
 * @param c The component to get properties useful for painting, e.g. the foreground or
 * background color.//from  ww w . j  ava  2  s . co  m
 * @param img the image to be rotated.
 * @param rotatedAngle the rotated angle, in degree, clockwise. It could be any double but we
 * will mod it with 360 before using it.
 *
 * @return the image after rotating.
 */
public static Image createRotatedImage(Component c, Image img, double rotatedAngle) {
    // convert rotatedAngle to a value from 0 to 360
    double originalAngle = rotatedAngle % 360;
    if (rotatedAngle != 0 && originalAngle == 0) {
        originalAngle = 360.0;
    }

    // convert originalAngle to a value from 0 to 90
    double angle = originalAngle % 90;
    if (originalAngle != 0.0 && angle == 0.0) {
        angle = 90.0;
    }

    double radian = Math.toRadians(angle);

    new ImageIcon(img); // load completely
    int iw = img.getWidth(null);
    int ih = img.getHeight(null);
    int w;
    int h;

    if ((originalAngle >= 0 && originalAngle <= 90) || (originalAngle > 180 && originalAngle <= 270)) {
        w = (int) (iw * Math.sin(DEGREE_90 - radian) + ih * Math.sin(radian));
        h = (int) (iw * Math.sin(radian) + ih * Math.sin(DEGREE_90 - radian));
    } else {
        w = (int) (ih * Math.sin(DEGREE_90 - radian) + iw * Math.sin(radian));
        h = (int) (ih * Math.sin(radian) + iw * Math.sin(DEGREE_90 - radian));
    }
    BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
    Graphics g = image.getGraphics();
    Graphics2D g2d = (Graphics2D) g.create();

    // calculate the center of the icon.
    int cx = iw / 2;
    int cy = ih / 2;

    // move the graphics center point to the center of the icon.
    g2d.translate(w / 2, h / 2);

    // rotate the graphics about the center point of the icon
    g2d.rotate(Math.toRadians(originalAngle));

    g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
    g2d.drawImage(img, -cx, -cy, c);

    g2d.dispose();
    new ImageIcon(image); // load completely
    return image;
}

From source file:org.simmi.GeneSetHead.java

License:asdf

public void repaintGCSkew(List<Sequence> selclist, Graphics2D g2, int size, GeneGroup gg, String selspec) {
    g2.setColor(Color.white);/*ww w.  ja  v  a2s  .c  o  m*/
    g2.fillRect(0, 0, 1024, 1024);
    g2.setFont(g2.getFont().deriveFont(10.0f));
    int total = 0;
    int g = 0;
    int c = 0;
    double gcstotal = 0.0;
    for (Sequence ctg : selclist) {
        //Sequence ctg = clist.get( u );
        if (gg != null) {
            for (Tegeval tv : gg.getTegevals()) {
                if (tv.getContshort() == ctg) {
                    int i = tv.start;

                    int x1 = (int) (512.0 + (384.0 - 100.0) * Math.cos((i + total) * 2.0 * Math.PI / size));
                    int y1 = (int) (512.0 + (384.0 - 100.0) * Math.sin((i + total) * 2.0 * Math.PI / size));
                    int x2 = (int) (512.0 + (384.0 + 100.0) * Math.cos((i + total) * 2.0 * Math.PI / size));
                    int y2 = (int) (512.0 + (384.0 + 100.0) * Math.sin((i + total) * 2.0 * Math.PI / size));

                    g2.setColor(Color.green);
                    g2.drawLine(x1, y1, x2, y2);
                }
            }
        }

        double horn = total * 2.0 * Math.PI / size;
        double horn2 = (total + ctg.length()) * 2.0 * Math.PI / size;

        int x1 = (int) (512.0 + (384.0 - 100.0) * Math.cos(horn));
        int y1 = (int) (512.0 + (384.0 - 100.0) * Math.sin(horn));
        int x2 = (int) (512.0 + (384.0 + 100.0) * Math.cos(horn));
        int y2 = (int) (512.0 + (384.0 + 100.0) * Math.sin(horn));
        g2.setColor(Color.black);
        g2.drawLine(x1, y1, x2, y2);

        int xoff = (int) (512.0 + (384.0 + 100.0) * Math.cos(horn2));
        int yoff = (int) (512.0 + (384.0 + 100.0) * Math.sin(horn2));
        if (horn < Math.PI) {
            g2.translate(x2, y2);
            g2.rotate(horn + Math.PI / 2.0);
            g2.drawString(ctg.getName(), 0, 0);
            g2.rotate(-horn - Math.PI / 2.0);
            g2.translate(-x2, -y2);
        } else {
            g2.translate(xoff, yoff);
            g2.rotate(horn2 + Math.PI / 2.0);
            g2.drawString(ctg.getName(), -g2.getFontMetrics().stringWidth(ctg.getName()), 0);
            g2.rotate(-horn2 - Math.PI / 2.0);
            g2.translate(-xoff, -yoff);
        }

        for (int i = 0; i < ctg.length(); i += 500) {
            for (int k = i; k < Math.min(ctg.length(), i + 500); k++) {
                char chr = ctg.charAt(k);
                if (chr == 'g' || chr == 'G') {
                    g++;
                } else if (chr == 'c' || chr == 'C') {
                    c++;
                }
            }

            int gcount = 0;
            int ccount = 0;
            int acount = 0;
            int tcount = 0;
            for (int k = i; k < Math.min(ctg.length(), i + 10000); k++) {
                char chr = k - 5000 < 0 ? ctg.charAt(ctg.length() + (k - 5000)) : ctg.charAt(k - 5000);
                if (chr == 'g' || chr == 'G') {
                    gcount++;
                } else if (chr == 'c' || chr == 'C') {
                    ccount++;
                } else if (chr == 'a' || chr == 'A')
                    acount++;
                else if (chr == 't' || chr == 'T')
                    tcount++;
            }

            if (gcount > 0 || ccount > 0) {
                double gcskew = (gcount - ccount) / (double) (gcount + ccount);

                gcstotal += gcskew;

                x1 = (int) (512.0 + (384.0) * Math.cos((i + total) * 2.0 * Math.PI / size));
                y1 = (int) (512.0 + (384.0) * Math.sin((i + total) * 2.0 * Math.PI / size));
                x2 = (int) (512.0 + (384.0 + gcskew * 100.0) * Math.cos((i + total) * 2.0 * Math.PI / size));
                y2 = (int) (512.0 + (384.0 + gcskew * 100.0) * Math.sin((i + total) * 2.0 * Math.PI / size));

                if (gcskew >= 0)
                    g2.setColor(Color.blue);
                else
                    g2.setColor(Color.red);
                g2.drawLine(x1, y1, x2, y2);
            }

            if (acount > 0 || tcount > 0) {
                double atskew = (acount - tcount) / (double) (acount + tcount);

                x1 = (int) (512.0 + (300.0) * Math.cos((i + total) * 2.0 * Math.PI / size));
                y1 = (int) (512.0 + (300.0) * Math.sin((i + total) * 2.0 * Math.PI / size));
                x2 = (int) (512.0 + (300.0 + atskew * 100.0) * Math.cos((i + total) * 2.0 * Math.PI / size));
                y2 = (int) (512.0 + (300.0 + atskew * 100.0) * Math.sin((i + total) * 2.0 * Math.PI / size));

                if (atskew >= 0)
                    g2.setColor(Color.blue);
                else
                    g2.setColor(Color.red);
                g2.drawLine(x1, y1, x2, y2);
            }
        }
        total += ctg.length();
    }

    g2.setColor(Color.black);
    g2.setFont(g2.getFont().deriveFont(java.awt.Font.ITALIC).deriveFont(32.0f));
    String[] specsplit; // = selspec.split("_");

    if (selspec.contains("hermus"))
        specsplit = selspec.split("_");
    else {
        Matcher m = Pattern.compile("\\d").matcher(selspec);
        int firstDigitLocation = m.find() ? m.start() : 0;
        if (firstDigitLocation == 0)
            specsplit = new String[] { "Thermus", selspec };
        else
            specsplit = new String[] { "Thermus", selspec.substring(0, firstDigitLocation),
                    selspec.substring(firstDigitLocation) };
    }

    int k = 0;
    for (String spec : specsplit) {
        int strw = g2.getFontMetrics().stringWidth(spec);
        g2.drawString(spec, (1024 - strw) / 2, 1024 / 2 - specsplit.length * 32 / 2 + 32 + k * 32);
        k++;
    }

    /*double gcs = gcstotal/total; //(g-c)/(g+c);
    String gcstr = Double.toString( Math.round( gcs*1000000.0 ) );
    g2.drawString( gcstr+"ppm", 768, 512 );*/
}

From source file:org.uva.itast.blended.omr.BufferedImageUtil.java

/**
 * Rotates 90, -90 deegrees/*from ww  w  .  j ava  2 s  .  c o m*/
 * @param imageToRotate
 * @param degrees 90 or -90 rotation.
 * @return
 */
public static BufferedImage rotateImage(BufferedImage imageToRotate, float degrees) {
    if (degrees != 90.0 && degrees != -90.0)
        throw new IllegalArgumentException("Only implemented +90 and -90 rotation");

    BufferedImage rotatedImage = new BufferedImage(imageToRotate.getHeight(null), imageToRotate.getWidth(null),
            imageToRotate.getType());

    Graphics2D g2d = (Graphics2D) rotatedImage.getGraphics();
    g2d.rotate(Math.toRadians(degrees));
    g2d.drawImage(imageToRotate, 0, -rotatedImage.getWidth(null), null);

    return rotatedImage;
}

From source file:ucar.unidata.idv.ui.ImageGenerator.java

/**
 * Process the image/* w ww.  ja va2 s . c  om*/
 *
 * @param image The image
 * @param filename File to write the image to
 * @param node Node to process
 * @param props Extra properties
 * @param viewManager The viewmanager this image came from
 * @param imageProps  the image properties
 *
 *
 * @return The processed image
 * @throws Throwable On badness
 */
protected BufferedImage processImage(BufferedImage image, String filename, Element node, Hashtable props,
        ViewManager viewManager, Hashtable imageProps) throws Throwable {

    if (node == null) {
        return image;
    }

    if (props == null) {
        props = new Hashtable();
    }
    if (viewManager != null) {
        Animation animation = viewManager.getAnimation();
        props.put(PROP_ANIMATIONTIME, "");
        if (animation != null) {
            if (animation.getAniValue() != null) {
                props.put(PROP_ANIMATIONTIME, animation.getAniValue());
            }
        }
    }
    getProperties().putAll(props);

    NodeList elements = XmlUtil.getElements(node);
    Hashtable seenColorTable = new Hashtable();
    for (int childIdx = 0; childIdx < elements.getLength(); childIdx++) {
        boolean shouldIterateChildren = true;
        BufferedImage newImage = null;
        int imageWidth = image.getWidth(null);
        int imageHeight = image.getHeight(null);
        Element child = (Element) elements.item(childIdx);
        String tagName = child.getTagName();

        if (tagName.equals(TAG_RESIZE)) {
            newImage = ImageUtils.toBufferedImage(resize(image, child));
        } else if (tagName.equals(TAG_FILESET)) {
            //ignore
        } else if (tagName.equals(TAG_OUTPUT)) {
            processTagOutput(child);
        } else if (tagName.equals(TAG_DISPLAYLIST)) {
            if (viewManager != null) {
                newImage = ImageUtils.toBufferedImage(image, true);
                Graphics g = newImage.getGraphics();
                String valign = applyMacros(child, ATTR_VALIGN, VALUE_BOTTOM);
                Font font = getFont(child);
                if (XmlUtil.hasAttribute(child, ATTR_MATTEBG)) {
                    int height = viewManager.paintDisplayList((Graphics2D) g, null, imageWidth, imageHeight,
                            valign.equals(VALUE_BOTTOM), null, font);

                    int top = (valign.equals(VALUE_TOP) ? height : 0);
                    int bottom = (valign.equals(VALUE_BOTTOM) ? height : 0);
                    newImage = ImageUtils.matte(image, top, bottom, 0, 0,
                            applyMacros(child, ATTR_MATTEBG, Color.white));
                    g = newImage.getGraphics();
                    imageHeight += height;
                }

                Color c = applyMacros(child, ATTR_COLOR, (Color) null);
                viewManager.paintDisplayList((Graphics2D) g, null, imageWidth, imageHeight,
                        valign.equals(VALUE_BOTTOM), c, font);
            }
        } else if (tagName.equals(TAG_COLORBAR) || tagName.equals(TAG_KML_COLORBAR)) {
            // only do one colorbar if we are writing to kml
            Integer index = (Integer) props.get(PROP_IMAGEINDEX);
            if ((index != null) && (index.intValue() > 0) && tagName.equals(TAG_KML_COLORBAR)) {
                continue;
            }

            boolean showLines = applyMacros(child, ATTR_SHOWLINES, false);

            List<DisplayControlImpl> controls = (List<DisplayControlImpl>) ((viewManager != null)
                    ? viewManager.getControls()
                    : new ArrayList());

            if (XmlUtil.hasAttribute(child, ATTR_DISPLAY)) {
                DisplayControlImpl display = ((controls.size() > 0)
                        ? findDisplayControl(XmlUtil.getAttribute(child, ATTR_DISPLAY), controls)
                        : findDisplayControl(child));
                if (display == null) {
                    error("Could not find display:" + XmlUtil.toString(node));
                    return null;
                }
                controls = Misc.newList(display);
            }

            int width = applyMacros(child, ATTR_WIDTH, 150);
            int height = applyMacros(child, ATTR_HEIGHT, 20);
            int ticks = applyMacros(child, ATTR_TICKMARKS, 0);
            double interval = applyMacros(child, ATTR_INTERVAL, -1.0);
            String valuesStr = applyMacros(child, ATTR_VALUES, (String) null);
            Color c = applyMacros(child, ATTR_COLOR, Color.black);

            Color lineColor = applyMacros(child, ATTR_LINECOLOR, c);

            Rectangle imageRect = new Rectangle(0, 0, imageWidth, imageHeight);

            Point pp = ImageUtils.parsePoint(applyMacros(child, ATTR_PLACE, "ll,10,-10"), imageRect);
            Point ap = ImageUtils.parsePoint(applyMacros(child, ATTR_ANCHOR, "ll"),
                    new Rectangle(0, 0, width, height));

            String orientation = applyMacros(child, ATTR_ORIENTATION, VALUE_BOTTOM);
            boolean vertical = orientation.equals(VALUE_RIGHT) || orientation.equals(VALUE_LEFT);
            int baseY = pp.y - ap.y + (vertical ? 0 : height);
            int baseX = pp.x - ap.x;

            List colorTables = new ArrayList();
            List ranges = new ArrayList();
            List units = new ArrayList();

            boolean forKml = tagName.equals(TAG_KML_COLORBAR);

            for (int i = 0; i < controls.size(); i++) {
                DisplayControlImpl control = (DisplayControlImpl) controls.get(i);
                ColorTable colorTable = control.getColorTable();
                if (colorTable == null) {
                    continue;
                }
                Range range = control.getRangeForColorTable();
                //only do unique color tables
                Object[] key = { colorTable, range };
                if (seenColorTable.get(key) != null) {
                    continue;
                }
                seenColorTable.put(key, key);
                colorTables.add(colorTable);
                ranges.add(range);
                units.add(control.getDisplayUnit());
            }

            for (int i = 0; i < colorTables.size(); i++) {
                ColorTable colorTable = (ColorTable) colorTables.get(i);
                Range range = (Range) ranges.get(i);
                Unit unit = (Unit) units.get(i);
                Image imageToDrawIn;
                if (forKml) {
                    if (vertical) {
                        baseX = 0;
                        baseY = 0;
                    } else {
                        baseX = 0;
                        baseY = height;
                    }
                    int space = applyMacros(child, ATTR_SPACE, (vertical ? width : height));
                    imageToDrawIn = new BufferedImage(width + (vertical ? space : 0),
                            height + (vertical ? 0 : space), BufferedImage.TYPE_INT_RGB);
                } else {
                    imageToDrawIn = newImage = ImageUtils.toBufferedImage(image);
                }
                Graphics g = imageToDrawIn.getGraphics();
                if (forKml) {
                    Color bgColor = applyMacros(child, ATTR_BACKGROUND, Color.white);
                    g.setColor(bgColor);
                    g.fillRect(0, 0, imageToDrawIn.getWidth(null), imageToDrawIn.getHeight(null));
                }
                boolean includeAlpha = applyMacros(child, ATTR_TRANSPARENCY, true);

                float[][] ctValues;

                if (includeAlpha) {
                    ctValues = colorTable.getAlphaTable();
                } else {
                    ctValues = colorTable.getNonAlphaTable();
                }
                ColorMap colorMap = new BaseRGBMap(ctValues);
                ColorPreview preview = new ColorPreview(colorMap, (vertical ? width : height));
                if (vertical) {
                    preview.setSize(new Dimension(height, width));
                } else {
                    preview.setSize(new Dimension(width, height));
                }
                Image previewImage = ColorTableCanvas.getImage(colorTable, (vertical ? height : width),
                        (vertical ? width : height), includeAlpha);

                if (vertical) {
                    int imageType = includeAlpha ? BufferedImage.TYPE_INT_ARGB : BufferedImage.TYPE_INT_RGB;

                    BufferedImage tmpImage = new BufferedImage(width, height, imageType);

                    Graphics2D tmpG = (Graphics2D) tmpImage.getGraphics();
                    tmpG.rotate(Math.toRadians(90.0));
                    tmpG.drawImage(previewImage, 0, 0 - width, null);
                    previewImage = tmpImage;
                }
                if (forKml) {
                    g.drawImage(previewImage, 0, 0, null);
                } else {
                    g.drawImage(previewImage, baseX, (vertical ? baseY : baseY - height), null);
                }
                if (showLines) {
                    g.setColor(lineColor);
                    g.drawRect(baseX, (vertical ? baseY : baseY - height), width - 1,
                            height - (vertical ? 1 : 0));
                }
                setFont(g, child);
                FontMetrics fm = g.getFontMetrics();
                List values = new ArrayList();
                String suffixFrequency = XmlUtil.getAttribute(child, ATTR_SUFFIXFREQUENCY,
                        XmlUtil.getAttribute(child, ATTR_SHOWUNIT, "false")).toLowerCase();
                String unitDefault = (!suffixFrequency.equals("false")) ? " %unit%" : "";
                String labelSuffix = applyMacros(child, ATTR_SUFFIX, unitDefault);
                if (unit != null) {
                    labelSuffix = labelSuffix.replace("%unit%", "" + unit);
                } else {
                    labelSuffix = labelSuffix.replace("%unit%", "");
                }
                if (valuesStr != null) {
                    double[] valueArray = Misc.parseDoubles(valuesStr, ",");
                    for (int valueIdx = 0; valueIdx < valueArray.length; valueIdx++) {
                        values.add(new Double(valueArray[valueIdx]));
                    }
                } else if (ticks > 0) {
                    int spacing = ((ticks == 1) ? 0 : (vertical ? height : width) / (ticks - 1));
                    for (int tickIdx = 0; tickIdx < ticks; tickIdx++) {
                        double percent = ((ticks > 1) ? (double) tickIdx / (double) (ticks - 1) : 0.0);
                        values.add(new Double(range.getValueOfPercent(percent)));
                    }
                } else if (interval > 0) {
                    double value = range.getMin();
                    double max = range.getMax();
                    while (value <= max) {
                        values.add(new Double(value));
                        value += interval;
                    }
                }
                for (int valueIdx = 0; valueIdx < values.size(); valueIdx++) {
                    double value = ((Double) values.get(valueIdx)).doubleValue();
                    int x;
                    int y;
                    if (vertical) {
                        if (orientation.equals(VALUE_RIGHT)) {
                            x = baseX + width;
                        } else {
                            x = baseX;
                        }
                        y = baseY + (int) (range.getPercent(value) * height);
                        if (y > baseY + height) {
                            break;
                        }
                    } else {
                        if (orientation.equals(VALUE_BOTTOM)) {
                            y = baseY;
                        } else {
                            y = baseY - height;
                        }

                        if (range != null) {
                            x = baseX + (int) (range.getPercent(value) * width);
                        } else {
                            x = baseX;
                        }

                        if (x > baseX + width) {
                            break;
                        }
                    }
                    String tickLabel = getIdv().getDisplayConventions().format(value);
                    if (suffixFrequency.equals(VALUE_LAST) && (valueIdx == values.size() - 1)) {
                        tickLabel += labelSuffix;
                    } else if (suffixFrequency.equals(VALUE_FIRST) && (valueIdx == 0)) {
                        tickLabel += labelSuffix;
                    } else if (suffixFrequency.equals(VALUE_ALL) || suffixFrequency.equals("true")) {
                        tickLabel += labelSuffix;
                    }

                    Rectangle2D rect = fm.getStringBounds(tickLabel, g);
                    g.setColor(lineColor);
                    if (orientation.equals(VALUE_RIGHT)) {
                        g.drawLine(x + 1, y, x, y);
                        if (showLines) {
                            g.drawLine(x, y, x - width, y);
                        }
                    } else if (orientation.equals(VALUE_LEFT)) {
                        g.drawLine(x - 1, y, x, y);
                        if (showLines) {
                            g.drawLine(x, y, x + width, y);
                        }
                    } else if (orientation.equals(VALUE_BOTTOM)) {
                        g.drawLine(x, y + 1, x, y);
                        if (showLines) {
                            g.drawLine(x, y, x, y - height);
                        }
                    } else {
                        g.drawLine(x, y - 1, x, y);
                        if (showLines) {
                            g.drawLine(x, y, x, y + height);
                        }
                    }
                    g.setColor(c);
                    if (orientation.equals(VALUE_RIGHT)) {
                        int yLoc = y + (int) (rect.getHeight() / 2) - 2;
                        if (forKml) {
                            if (valueIdx == 0) {
                                yLoc = y + (int) (rect.getHeight()) - 2;
                            } else if (valueIdx == values.size() - 1) {
                                yLoc = y - (int) (rect.getHeight()) + 6;
                            }
                        }
                        g.drawString(tickLabel, x + 2, yLoc);
                    } else if (orientation.equals(VALUE_LEFT)) {
                        int xLoc = x - 2 - (int) rect.getWidth();
                        g.drawString(tickLabel, xLoc, y + (int) (rect.getHeight() / 2) - 2);
                    } else if (orientation.equals(VALUE_BOTTOM)) {
                        int xLoc = x - (int) (rect.getWidth() / 2);
                        if (forKml) {
                            if (valueIdx == 0) {
                                xLoc = x + 2;
                            } else if (valueIdx == values.size() - 1) {
                                xLoc = x - (int) rect.getWidth() + 2;
                            }
                        }
                        g.drawString(tickLabel, xLoc, y + (int) rect.getHeight() + 2);
                    } else {
                        g.drawString(tickLabel, x - (int) (rect.getWidth() / 2), y - 2);
                    }
                }
                if (vertical) {
                    baseX += width + 30;
                } else {
                    baseY += height + 30;
                }
                if (forKml) {
                    String tmpImageFile = applyMacros(child, ATTR_FILE,
                            getIdv().getStore().getTmpFile("testcolorbar${viewindex}.png"));
                    String template = "<ScreenOverlay><name>${kml.name}</name><Icon><href>${icon}</href></Icon>\n"
                            + "<overlayXY x=\"${kml.overlayXY.x}\" y=\"${kml.overlayXY.y}\" xunits=\"${kml.overlayXY.xunits}\" yunits=\"${kml.overlayXY.yunits}\"/>\n"
                            + "<screenXY x=\"${kml.screenXY.x}\" y=\"${kml.screenXY.y}\" xunits=\"${kml.screenXY.xunits}\" yunits=\"${kml.screenXY.yunits}\"/>\n"
                            + "<size x=\"${kml.size.x}\" y=\"${kml.size.y}\" xunits=\"${kml.size.xunits}\" yunits=\"${kml.size.yunits}\"/>\n"
                            + "</ScreenOverlay>\n";
                    String[] macros = { "kml.name", "kml.overlayXY.x", "kml.overlayXY.y",
                            "kml.overlayXY.xunits", "kml.overlayXY.yunits", "kml.screenXY.x", "kml.screenXY.y",
                            "kml.screenXY.xunits", "kml.screenXY.yunits", "kml.size.x", "kml.size.y",
                            "kml.size.xunits", "kml.size.yunits" };
                    String[] macroValues = { "", "0", "1", "fraction", "fraction", "0", "1", "fraction",
                            "fraction", "-1", "-1", "pixels", "pixels" };

                    for (int macroIdx = 0; macroIdx < macros.length; macroIdx++) {
                        template = template.replace("${" + macros[macroIdx] + "}",
                                applyMacros(child, macros[macroIdx], macroValues[macroIdx]));
                    }
                    template = template.replace("${icon}", IOUtil.getFileTail(tmpImageFile));
                    imageProps.put("kml", template);
                    List kmlFiles = (List) imageProps.get("kmlfiles");
                    //TODO: Only do the first one for now
                    if (kmlFiles == null) {
                        kmlFiles = new ArrayList();
                        imageProps.put("kmlfiles", kmlFiles);
                    }
                    kmlFiles.add(tmpImageFile);

                    //                        System.out.println(template);
                    ImageUtils.writeImageToFile(imageToDrawIn, tmpImageFile);
                }
            }

        } else if (tagName.equals(TAG_TRANSPARENT) || tagName.equals(TAG_BGTRANSPARENT)) {
            Color c = null;
            if (tagName.equals(TAG_BGTRANSPARENT)) {
                c = viewManager.getBackground();
            } else {
                c = applyMacros(child, ATTR_COLOR, (Color) null);
            }
            //                System.err.println ("c:" + c);
            int[] redRange = { 0, 0 };
            int[] greenRange = { 0, 0 };
            int[] blueRange = { 0, 0 };
            if (c != null) {
                //                    System.err.println("got color");
                redRange[0] = redRange[1] = c.getRed();
                greenRange[0] = greenRange[1] = c.getGreen();
                blueRange[0] = blueRange[1] = c.getBlue();
            } else {
            }
            newImage = ImageUtils.makeColorTransparent(image, redRange, greenRange, blueRange);
        } else if (tagName.equals(TAG_SHOW)) {
            JComponent contents = new JLabel(new ImageIcon(image));
            String message = applyMacros(child, ATTR_MESSAGE, (String) null);
            if (message != null) {
                contents = GuiUtils.topCenter(new JLabel(message), contents);
            }
            if (!GuiUtils.askOkCancel("Continue?", contents)) {
                throw new MyQuitException();
            }
        } else if (tagName.equals(TAG_MATTE)) {
            newImage = doMatte(image, child, 0);
        } else if (tagName.equals(TAG_LATLONLABELS)) {
            newImage = doLatLonLabels(child, viewManager, image, imageProps);
        } else if (tagName.equals(TAG_WRITE)) {
            ImageUtils.writeImageToFile(image, getImageFileName(applyMacros(child, ATTR_FILE)));

        } else if (tagName.equals(TAG_PUBLISH)) {
            getIdv().getPublishManager().publishIslImage(this, node, image);
        } else if (tagName.equals(TAG_CLIP)) {
            int[] ul;
            int[] lr;
            if (XmlUtil.hasAttribute(child, ATTR_DISPLAY)) {
                //                    System.err.println("Clipping from display");
                DisplayControlImpl dc = findDisplayControl(child);
                if (dc == null) {
                    throw new IllegalArgumentException("Could not find display:" + XmlUtil.toString(node));
                }
                NavigatedDisplay display = (NavigatedDisplay) viewManager.getMaster();
                MapProjection mapProjection = dc.getDataProjection();
                java.awt.geom.Rectangle2D rect = mapProjection.getDefaultMapArea();
                LatLonPoint llplr = mapProjection.getLatLon(new double[][] { { rect.getX() + rect.getWidth() },
                        { rect.getY() + rect.getHeight() } });
                LatLonPoint llpul = mapProjection
                        .getLatLon(new double[][] { { rect.getX() }, { rect.getY() } });
                EarthLocation ulEl = new EarthLocationTuple(llpul, new Real(RealType.Altitude, 0));
                EarthLocation lrEl = new EarthLocationTuple(llplr, new Real(RealType.Altitude, 0));
                ul = display.getScreenCoordinates(display.getSpatialCoordinates(ulEl, null));
                lr = display.getScreenCoordinates(display.getSpatialCoordinates(lrEl, null));
                //System.err.println("ul:" + ulEl + " lr:" + lrEl);
                if (ul[0] > lr[0]) {
                    int tmp = ul[0];
                    ul[0] = lr[0];
                    lr[0] = tmp;
                }
                if (ul[1] > lr[1]) {
                    int tmp = ul[1];
                    ul[1] = lr[1];
                    lr[1] = tmp;
                }
                imageProps.put(ATTR_NORTH, new Double(ulEl.getLatitude().getValue()));
                imageProps.put(ATTR_WEST, new Double(ulEl.getLongitude().getValue()));
                imageProps.put(ATTR_SOUTH, new Double(lrEl.getLatitude().getValue()));
                imageProps.put(ATTR_EAST, new Double(lrEl.getLongitude().getValue()));
            } else if ((viewManager != null) && XmlUtil.hasAttribute(child, ATTR_NORTH)) {
                NavigatedDisplay display = (NavigatedDisplay) viewManager.getMaster();
                EarthLocation el1 = DisplayControlImpl.makeEarthLocation(toDouble(child, ATTR_NORTH),
                        toDouble(child, ATTR_WEST), 0);
                EarthLocation el2 = DisplayControlImpl.makeEarthLocation(toDouble(child, ATTR_SOUTH),
                        toDouble(child, ATTR_EAST), 0);
                ul = display.getScreenCoordinates(display.getSpatialCoordinates(el1, null));
                lr = display.getScreenCoordinates(display.getSpatialCoordinates(el2, null));
                imageProps.put(ATTR_NORTH, new Double(el1.getLatitude().getValue()));
                imageProps.put(ATTR_WEST, new Double(el1.getLongitude().getValue()));
                imageProps.put(ATTR_SOUTH, new Double(el2.getLatitude().getValue()));
                imageProps.put(ATTR_EAST, new Double(el2.getLongitude().getValue()));
            } else if (XmlUtil.hasAttribute(child, ATTR_LEFT)) {
                ul = new int[] { (int) toDouble(child, ATTR_LEFT, imageWidth),
                        (int) toDouble(child, ATTR_TOP, imageHeight) };
                lr = new int[] { (int) toDouble(child, ATTR_RIGHT, imageWidth),
                        (int) toDouble(child, ATTR_BOTTOM, imageHeight) };
            } else if (viewManager != null) {
                //TODO: Clip on visad coordinates
                NavigatedDisplay display = (NavigatedDisplay) viewManager.getMaster();
                ul = display.getScreenCoordinates(new double[] { -1, 1, 0 });
                lr = display.getScreenCoordinates(new double[] { 1, -1, 0 });
                int space = applyMacros(child, ATTR_SPACE, 0);
                int hspace = applyMacros(child, ATTR_HSPACE, space);
                int vspace = applyMacros(child, ATTR_VSPACE, space);
                ul[0] -= applyMacros(child, ATTR_SPACE_LEFT, hspace);
                ul[1] -= applyMacros(child, ATTR_SPACE_TOP, vspace);
                lr[0] += applyMacros(child, ATTR_SPACE_RIGHT, hspace);
                lr[1] += applyMacros(child, ATTR_SPACE_BOTTOM, vspace);
            } else {
                continue;
            }

            for (String attr : (List<String>) Misc.newList(ATTR_NORTH, ATTR_SOUTH, ATTR_EAST, ATTR_WEST)) {
                String kmlAttr = "kml." + attr;
                if (XmlUtil.hasAttribute(child, kmlAttr)) {
                    imageProps.put(attr, new Double(applyMacros(child, kmlAttr, 0.0)));
                }
            }

            ul[0] = Math.max(0, ul[0]);
            ul[1] = Math.max(0, ul[1]);

            lr[0] = Math.min(lr[0], imageWidth);
            lr[1] = Math.min(lr[1], imageHeight);

            newImage = ImageUtils.clip(image, ul, lr);
        } else if (tagName.equals(TAG_SPLIT)) {
            shouldIterateChildren = false;
            int width = image.getWidth(null);
            int height = image.getHeight(null);
            int cols = applyMacros(child, ATTR_COLUMNS, 2);
            int rows = applyMacros(child, ATTR_ROWS, 2);
            String file = applyMacros(child, ATTR_FILE);
            int cnt = 0;
            int hSpace = width / cols;
            int vSpace = height / rows;
            for (int row = 0; row < rows; row++) {
                for (int col = 0; col < cols; col++) {
                    pushProperties();
                    Hashtable myprops = new Hashtable();
                    putProperty("row", new Integer(row));
                    putProperty("column", new Integer(col));
                    putProperty("count", new Integer(++cnt));
                    String realFile = applyMacros(file, myprops);
                    Image splitImage = image.getSubimage(hSpace * col, vSpace * row, hSpace, vSpace);
                    processImage(ImageUtils.toBufferedImage(splitImage), realFile, child, myprops, viewManager,
                            new Hashtable());
                    popProperties();
                }
            }
        } else if (tagName.equals(TAG_THUMBNAIL)) {
            shouldIterateChildren = false;
            BufferedImage thumbImage = ImageUtils.toBufferedImage(resize(image, child));
            String thumbFile = applyMacros(child, ATTR_FILE, (String) null);
            if (thumbFile == null) {
                thumbFile = IOUtil.stripExtension(filename) + "_thumb" + IOUtil.getFileExtension(filename);
            }
            processImage(thumbImage, thumbFile, child, null, viewManager, new Hashtable());
        } else if (tagName.equals(TAG_KML)) {
            //NOOP
        } else if (tagName.equals(TAG_KMZFILE)) {
            //NOOP
        } else if (tagName.equals(TAG_OVERLAY)) {
            double transparency = applyMacros(child, ATTR_TRANSPARENCY, 0.0);
            Graphics2D g = image.createGraphics();
            String imagePath = applyMacros(child, ATTR_IMAGE, (String) null);

            float scale = (float) applyMacros(child, ATTR_SCALE, 1.0);

            Rectangle imageRect = new Rectangle(0, 0, imageWidth, imageHeight);
            Point pp = ImageUtils.parsePoint(applyMacros(child, ATTR_PLACE, "lr,-10,-10"), imageRect);
            String text = applyMacros(child, ATTR_TEXT, (String) null);
            Color bg = applyMacros(child, ATTR_BACKGROUND, (Color) null);
            if (text != null) {
                double angle = Math.toRadians(applyMacros(child, ATTR_ANGLE, 0.0));
                text = applyMacros(text);
                Color c = applyMacros(child, ATTR_COLOR, Color.white);
                if ((c != null) && (transparency > 0)) {
                    c = new Color(c.getRed(), c.getGreen(), c.getBlue(), ImageUtils.toAlpha(transparency));
                }
                //Color bg = applyMacros(child, ATTR_BACKGROUND,
                //                       (Color) null);
                if ((bg != null) && (transparency > 0)) {
                    bg = new Color(bg.getRed(), bg.getGreen(), bg.getBlue(), ImageUtils.toAlpha(transparency));
                }
                setFont(g, child);
                FontMetrics fm = g.getFontMetrics();
                Rectangle2D rect = fm.getStringBounds(text, g);
                int width = (int) rect.getWidth();
                int height = (int) (rect.getHeight());

                Point ap = ImageUtils.parsePoint(applyMacros(child, ATTR_ANCHOR, "lr,-10,-10"),
                        new Rectangle(0, 0, width, height));

                g.rotate(angle);

                if (bg != null) {
                    g.setColor(bg);
                    g.fillRect(pp.x - ap.x - 1, pp.y - ap.y - 1, (int) width + 2, (int) height + 2);
                }
                g.setColor(c);
                g.drawString(text, pp.x - ap.x, pp.y - ap.y + height);
            }

            if (imagePath != null) {
                Image overlay = ImageUtils.readImage(imagePath);
                if (overlay != null) {
                    if (transparency > 0) {
                        overlay = ImageUtils.setAlpha(overlay, transparency);
                    }

                    int width = overlay.getWidth(null);
                    int height = overlay.getHeight(null);
                    int scaledWidth = Math.round(width * scale);
                    int scaledHeight = Math.round(height * scale);

                    Image scaled = getScaledImage(overlay, scaledWidth, scaledHeight);
                    Rectangle overlayRect = new Rectangle(0, 0, scaledWidth, scaledHeight);
                    Point ap = ImageUtils.parsePoint(applyMacros(child, ATTR_ANCHOR, "lr,-10,-10"),
                            overlayRect);
                    g.drawImage(scaled, pp.x - ap.x, pp.y - ap.y, bg, null);
                }
            }
        } else {
            error("Unknown tag:" + tagName);
        }
        if (newImage != null) {
            String newFileName = applyMacros(child, ATTR_FILE, (String) null);
            if (shouldIterateChildren) {
                logger.trace("newFileName='{}' viewManager={} newImage={}", newFileName, viewManager, newImage);
                newImage = processImage(newImage, newFileName, child, null, viewManager, new Hashtable());
                logger.trace("finished processImage; result: {}", newImage);
            }
            if (newFileName != null) {
                logger.trace("calling writeImageToFile...");
                ImageUtils.writeImageToFile(newImage, getImageFileName(newFileName));
                logger.trace("finished writeImageToFile");
                debug("Writing image:" + newFileName);
            }
            if (!applyMacros(child, ATTR_COPY, false)) {
                image = newImage;
            }
        }
    }

    if (filename != null) {
        float quality = (float) applyMacros(node, ATTR_QUALITY, 1.0);
        List<String> fileToks = StringUtil.split(filename, ",", true, true);
        for (String file : fileToks) {
            file = getImageFileName(file);
            debug("Writing image:" + file);
            if (file.endsWith(FileManager.SUFFIX_KMZ) || file.endsWith(FileManager.SUFFIX_KML)) {
                GeoLocationInfo bounds = null;
                if (viewManager != null) {
                    bounds = viewManager.getVisibleGeoBounds();
                    ImageSequenceGrabber.subsetBounds(bounds, imageProps);
                    String tmpImageFile = getOutputPath(file);
                    ImageUtils.writeImageToFile(image, tmpImageFile, quality);
                    ImageWrapper imageWrapper = new ImageWrapper(tmpImageFile, null, bounds, null);
                    imageWrapper.setProperties(imageProps);
                    new ImageSequenceGrabber(file, getIdv(), this, node,
                            (List<ImageWrapper>) Misc.newList(imageWrapper), null, 1);
                }
            } else {
                logger.trace("another writeImageToFile call...");
                ImageUtils.writeImageToFile(image, file, quality);
                logger.trace("and it's done.");
            }
        }
    }
    logger.trace("result: {}", image);
    return image;
}