Example usage for java.awt.image BufferedImage TYPE_INT_ARGB

List of usage examples for java.awt.image BufferedImage TYPE_INT_ARGB

Introduction

In this page you can find the example usage for java.awt.image BufferedImage TYPE_INT_ARGB.

Prototype

int TYPE_INT_ARGB

To view the source code for java.awt.image BufferedImage TYPE_INT_ARGB.

Click Source Link

Document

Represents an image with 8-bit RGBA color components packed into integer pixels.

Usage

From source file:edu.umn.cs.spatialHadoop.operations.GeometricPlot.java

private static <S extends Shape> void plotLocal(Path inFile, Path outFile, OperationsParams params)
        throws IOException {
    int width = params.getInt("width", 1000);
    int height = params.getInt("height", 1000);

    Color strokeColor = params.getColor("color", Color.BLACK);
    int color = strokeColor.getRGB();

    String hdfDataset = (String) params.get("dataset");
    Shape shape = hdfDataset != null ? new NASARectangle() : (Shape) params.getShape("shape", null);
    Shape plotRange = params.getShape("rect", null);

    boolean keepAspectRatio = params.is("keep-ratio", true);

    String valueRangeStr = (String) params.get("valuerange");
    MinMax valueRange;/*from  w  w  w  .j  a  v a  2 s.  com*/
    if (valueRangeStr == null) {
        valueRange = null;
    } else {
        String[] parts = valueRangeStr.split(",");
        valueRange = new MinMax(Integer.parseInt(parts[0]), Integer.parseInt(parts[1]));
    }

    InputSplit[] splits;
    FileSystem inFs = inFile.getFileSystem(params);
    FileStatus inFStatus = inFs.getFileStatus(inFile);
    if (inFStatus != null && !inFStatus.isDir()) {
        // One file, retrieve it immediately.
        // This is useful if the input is a hidden file which is automatically
        // skipped by FileInputFormat. We need to plot a hidden file for the case
        // of plotting partition boundaries of a spatial index
        splits = new InputSplit[] { new FileSplit(inFile, 0, inFStatus.getLen(), new String[0]) };
    } else {
        JobConf job = new JobConf(params);
        ShapeInputFormat<Shape> inputFormat = new ShapeInputFormat<Shape>();
        ShapeInputFormat.addInputPath(job, inFile);
        splits = inputFormat.getSplits(job, 1);
    }

    boolean vflip = params.is("vflip");

    Rectangle fileMbr;
    if (plotRange != null) {
        fileMbr = plotRange.getMBR();
    } else if (hdfDataset != null) {
        // Plotting a NASA file
        fileMbr = new Rectangle(-180, -90, 180, 90);
    } else {
        fileMbr = FileMBR.fileMBR(inFile, params);
    }

    if (keepAspectRatio) {
        // Adjust width and height to maintain aspect ratio
        if (fileMbr.getWidth() / fileMbr.getHeight() > (double) width / height) {
            // Fix width and change height
            height = (int) (fileMbr.getHeight() * width / fileMbr.getWidth());
        } else {
            width = (int) (fileMbr.getWidth() * height / fileMbr.getHeight());
        }
    }

    boolean adaptiveSample = shape instanceof Point && params.getBoolean("sample", false);
    float adaptiveSampleRatio = 0.0f;
    if (adaptiveSample) {
        // Calculate the sample ratio
        long recordCount = FileMBR.fileMBR(inFile, params).recordCount;
        adaptiveSampleRatio = params.getFloat(AdaptiveSampleFactor, 1.0f) * width * height / recordCount;
    }

    boolean gradualFade = !(shape instanceof Point) && params.getBoolean("fade", false);

    if (hdfDataset != null) {
        // Collects some stats about the HDF file
        if (valueRange == null)
            valueRange = Aggregate.aggregate(new Path[] { inFile }, params);
        NASAPoint.minValue = valueRange.minValue;
        NASAPoint.maxValue = valueRange.maxValue;
        NASAPoint.setColor1(params.getColor("color1", Color.BLUE));
        NASAPoint.setColor2(params.getColor("color2", Color.RED));
        NASAPoint.gradientType = params.getGradientType("gradient", NASAPoint.GradientType.GT_HUE);
    }

    double scale2 = (double) width * height / (fileMbr.getWidth() * fileMbr.getHeight());
    double scale = Math.sqrt(scale2);

    // Create an image
    BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
    Graphics2D graphics = image.createGraphics();
    Color bg_color = params.getColor("bgcolor", new Color(0, 0, 0, 0));
    graphics.setBackground(bg_color);
    graphics.clearRect(0, 0, width, height);
    graphics.setColor(strokeColor);

    for (InputSplit split : splits) {
        if (hdfDataset != null) {
            // Read points from the HDF file
            RecordReader<NASADataset, NASAShape> reader = new HDFRecordReader(params, (FileSplit) split,
                    hdfDataset, true);
            NASADataset dataset = reader.createKey();

            while (reader.next(dataset, (NASAShape) shape)) {
                // Skip with a fixed ratio if adaptive sample is set
                if (adaptiveSample && Math.random() > adaptiveSampleRatio)
                    continue;
                if (plotRange == null || shape.isIntersected(shape)) {
                    shape.draw(graphics, fileMbr, width, height, 0.0);
                }
            }
            reader.close();
        } else {
            RecordReader<Rectangle, Shape> reader = new ShapeRecordReader<Shape>(params, (FileSplit) split);
            Rectangle cell = reader.createKey();
            while (reader.next(cell, shape)) {
                // Skip with a fixed ratio if adaptive sample is set
                if (adaptiveSample && Math.random() > adaptiveSampleRatio)
                    continue;
                Rectangle shapeMBR = shape.getMBR();
                if (shapeMBR != null) {
                    if (plotRange == null || shapeMBR.isIntersected(plotRange)) {
                        if (gradualFade) {
                            double sizeInPixels = (shapeMBR.getWidth() + shapeMBR.getHeight()) * scale;
                            if (sizeInPixels < 1.0 && Math.round(sizeInPixels * 255) < 1.0) {
                                // This shape can be safely skipped as it is too small to be plotted
                                continue;
                            } else {
                                int alpha = (int) Math.round(sizeInPixels * 255);
                                graphics.setColor(new Color((alpha << 24) | color, true));
                            }
                        }
                        shape.draw(graphics, fileMbr, width, height, scale2);
                    }
                }
            }
            reader.close();
        }
    }
    // Write image to output
    graphics.dispose();
    if (vflip) {
        AffineTransform tx = AffineTransform.getScaleInstance(1, -1);
        tx.translate(0, -image.getHeight());
        AffineTransformOp op = new AffineTransformOp(tx, AffineTransformOp.TYPE_NEAREST_NEIGHBOR);
        image = op.filter(image, null);
    }
    FileSystem outFs = outFile.getFileSystem(params);
    OutputStream out = outFs.create(outFile, true);
    ImageIO.write(image, "png", out);
    out.close();

}

From source file:ded.ui.DiagramController.java

/** Check to see if the font is rendering properly.  I have had a
  * lot of trouble getting this to work on a wide range of
  * machines and JVMs.  If the font rendering does not work, just
  * alert the user to the problem but keep going. */
public void checkFontRendering() {
    // Render the glyph for 'A' in a box just large enough to
    // contain it when rendered properly.
    int width = 9;
    int height = 11;
    BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
    Graphics g = bi.createGraphics();
    ColorModel colorModel = bi.getColorModel();

    g.setColor(Color.WHITE);/*from w  w w.  j  a  v a  2s.c  o m*/
    g.fillRect(0, 0, width, height);

    g.setColor(Color.BLACK);
    g.setFont(this.dedWindow.diagramFont);
    g.drawString("A", 0, 10);

    // Print that glyph as a string.
    StringBuilder sb = new StringBuilder();
    for (int y = 0; y < height; y++) {
        int bits = 0;
        for (int x = 0; x < width; x++) {
            int pixel = bi.getRGB(x, y);
            int red = colorModel.getRed(pixel);
            int green = colorModel.getGreen(pixel);
            int blue = colorModel.getBlue(pixel);
            int alpha = colorModel.getAlpha(pixel);
            boolean isWhite = (red == 255 && green == 255 && blue == 255 && alpha == 255);
            boolean isBlack = (red == 0 && green == 0 && blue == 0 && alpha == 255);
            sb.append(
                    isWhite ? "_" : isBlack ? "X" : ("(" + red + "," + green + "," + blue + "," + alpha + ")"));

            bits <<= 1;
            if (!isWhite) {
                bits |= 1;
            }
        }
        sb.append(String.format("  (0x%03X)\n", bits));
    }

    // Also include some of the font metrics.
    FontMetrics fm = g.getFontMetrics();
    sb.append("fm: ascent=" + fm.getAscent() + " leading=" + fm.getLeading() + " charWidth('A')="
            + fm.charWidth('A') + " descent=" + fm.getDescent() + " height=" + fm.getHeight() + "\n");

    String actualGlyph = sb.toString();

    g.dispose();

    // The expected glyph and metrics.
    String expectedGlyph = "_________  (0x000)\n" + "____X____  (0x010)\n" + "___X_X___  (0x028)\n"
            + "___X_X___  (0x028)\n" + "__X___X__  (0x044)\n" + "__X___X__  (0x044)\n" + "__XXXXX__  (0x07C)\n"
            + "_X_____X_  (0x082)\n" + "_X_____X_  (0x082)\n" + "_X_____X_  (0x082)\n" + "_________  (0x000)\n"
            + "fm: ascent=10 leading=1 charWidth('A')=9 descent=3 height=14\n";

    if (!expectedGlyph.equals(actualGlyph)) {
        // Currently, this is known to happen when using OpenJDK 6
        // and 7, with 6 being close to right and 7 being very bad.
        // I also have reports of it happening on certain Mac OS/X
        // systems, but I haven't been able to determine what the
        // important factor there is.
        String warningMessage = "There is a problem with the font rendering.  The glyph "
                + "for the letter 'A' should look like:\n" + expectedGlyph + "but it renders as:\n"
                + actualGlyph + "\n" + "This probably means there is a bug in the TrueType "
                + "font library.  You might try a different Java version.  "
                + "(I'm working on how to solve this permanently.)";
        System.err.println(warningMessage);
        this.log(warningMessage);
        SwingUtil.errorMessageBox(null /*component*/, warningMessage);
    }
}

From source file:userinterface.graph.Graph.java

/**
 * Renders the current graph to a JPEG file.
 * // w w w  .ja  v a2  s  .  co m
 * @param file
 *             The file to export the JPEG data to.
 * @throws GraphException, IOException
 *             If file cannot be written to.
 */
public void exportToPNG(File file, int width, int height, boolean alpha) throws GraphException, IOException {

    FileOutputStream fileOutputStream = new FileOutputStream(file);

    KeypointPNGEncoderAdapter encoder = new KeypointPNGEncoderAdapter();
    encoder.setEncodingAlpha(alpha);

    Paint bgPaint = chart.getBackgroundPaint();

    if (alpha) {
        chart.setBackgroundPaint(null);
    }

    BufferedImage bufferedImage = chart.createBufferedImage(width, height,
            alpha ? BufferedImage.TYPE_INT_ARGB : BufferedImage.TYPE_INT_RGB, null);

    if (alpha) {
        chart.setBackgroundPaint(bgPaint);
    }

    encoder.encode(bufferedImage, fileOutputStream);

    fileOutputStream.flush();
    fileOutputStream.close();

    //ChartUtilities.saveChartAsPNG(file, this.chart, width, height, null, alpha, 9);
}

From source file:com.aurel.track.attachment.AttachBL.java

private static BufferedImage toBufferedImage(Image image) {
    if (image instanceof BufferedImage) {
        return (BufferedImage) image;
    }/*from w  w  w.java  2s.  c o  m*/

    // This code ensures that all the pixels in the image are loaded
    image = new ImageIcon(image).getImage();

    // Determine if the image has transparent pixels; for this method's
    // implementation, see Determining If an Image Has Transparent Pixels
    boolean hasAlpha = hasAlpha(image);

    // Create a buffered image with a format that's compatible with the screen
    BufferedImage bimage = null;
    GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
    try {
        // Determine the type of transparency of the new buffered image
        int transparency = Transparency.OPAQUE;
        if (hasAlpha) {
            transparency = Transparency.BITMASK;
        }

        // Create the buffered image
        GraphicsDevice gs = ge.getDefaultScreenDevice();
        GraphicsConfiguration gc = gs.getDefaultConfiguration();
        bimage = gc.createCompatibleImage(image.getWidth(null), image.getHeight(null), transparency);
    } catch (HeadlessException e) {
        // The system does not have a screen
    }

    if (bimage == null) {
        // Create a buffered image using the default color model
        int type = BufferedImage.TYPE_INT_RGB;
        if (hasAlpha) {
            type = BufferedImage.TYPE_INT_ARGB;
        }
        bimage = new BufferedImage(image.getWidth(null), image.getHeight(null), type);
    }

    // Copy image to buffered image
    Graphics g = bimage.createGraphics();

    // Paint the image onto the buffered image
    g.drawImage(image, 0, 0, null);
    g.dispose();

    return bimage;
}

From source file:au.org.ala.biocache.web.WMSController.java

@RequestMapping(value = { "/ogc/legendGraphic" }, method = RequestMethod.GET)
public void getLegendGraphic(@RequestParam(value = "ENV", required = false, defaultValue = "") String env,
        @RequestParam(value = "STYLE", required = false, defaultValue = "8b0000;opacity=1;size=5") String style,
        @RequestParam(value = "WIDTH", required = false, defaultValue = "30") Integer width,
        @RequestParam(value = "HEIGHT", required = false, defaultValue = "20") Integer height,
        HttpServletRequest request, HttpServletResponse response) throws Exception {

    try {/*  w  ww.j av a  2 s.  c  o m*/
        if (StringUtils.trimToNull(env) == null && StringUtils.trimToNull(style) == null) {
            style = "8b0000;opacity=1;size=5";
        }

        WmsEnv wmsEnv = new WmsEnv(env, style);
        BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g = (Graphics2D) img.getGraphics();
        int size = width > height ? height : width;
        Paint fill = new Color(wmsEnv.colour | wmsEnv.alpha << 24);
        g.setPaint(fill);
        g.fillOval(0, 0, size, size);
        OutputStream out = response.getOutputStream();
        logger.debug("WMS - GetLegendGraphic requested : " + request.getQueryString());
        response.setContentType("image/png");
        ImageIO.write(img, "png", out);
        out.close();
    } catch (Exception e) {
        logger.error(e.getMessage(), e);
    }
}

From source file:com.simiacryptus.mindseye.lang.Tensor.java

/**
 * To rgb png buffered png./*from w w w . jav  a  2  s .c o m*/
 *
 * @param redBand   the red band
 * @param greenBand the green band
 * @param blueBand  the blue band
 * @param alphaMask the alphaList mask
 * @return the buffered png
 */
@Nonnull
public BufferedImage toRgbImageAlphaMask(final int redBand, final int greenBand, final int blueBand,
        Tensor alphaMask) {
    assert alphaMask.getDimensions()[0] == getDimensions()[0];
    assert alphaMask.getDimensions()[1] == getDimensions()[1];
    @Nonnull
    final int[] dims = getDimensions();
    @Nonnull
    final BufferedImage img = new BufferedImage(dims[0], dims[1], BufferedImage.TYPE_INT_ARGB);
    for (int x = 0; x < img.getWidth(); x++) {
        for (int y = 0; y < img.getHeight(); y++) {
            final double red = Tensor.bound8bit(this.get(x, y, redBand));
            final double green = Tensor.bound8bit(this.get(x, y, greenBand));
            final double blue = Tensor.bound8bit(this.get(x, y, blueBand));
            final double alpha = Tensor.bound8bit(alphaMask.get(x, y, 0));
            img.setRGB(x, y, (int) (red + ((int) green << 8) + ((int) blue << 16) + ((int) alpha << 24)));
        }
    }
    return img;
}

From source file:net.pms.medialibrary.commons.helpers.FileImportHelper.java

/**
 * Creates a buffered image from an image
 * @param image the image//from   w ww  .  j  a v a2s .  c o  m
 * @return the buffered image
 */
public static BufferedImage getBufferedImage(Image image) {
    if (image instanceof BufferedImage) {
        return (BufferedImage) image;
    }

    // This code ensures that all the pixels in the image are loaded
    image = new ImageIcon(image).getImage();

    // Determine if the image has transparent pixels; for this method's
    // implementation, see Determining If an Image Has Transparent Pixels
    boolean hasAlpha = hasAlpha(image);

    // Create a buffered image with a format that's compatible with the screen
    BufferedImage bimage = null;
    GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
    try {
        // Determine the type of transparency of the new buffered image
        int transparency = Transparency.OPAQUE;
        if (hasAlpha) {
            transparency = Transparency.BITMASK;
        }

        // Create the buffered image
        GraphicsDevice gs = ge.getDefaultScreenDevice();
        GraphicsConfiguration gc = gs.getDefaultConfiguration();
        bimage = gc.createCompatibleImage(image.getWidth(null), image.getHeight(null), transparency);
    } catch (HeadlessException e) {
        // The system does not have a screen
    }

    if (bimage == null) {
        // Create a buffered image using the default color model
        int type = BufferedImage.TYPE_INT_RGB;
        if (hasAlpha) {
            type = BufferedImage.TYPE_INT_ARGB;
        }
        bimage = new BufferedImage(image.getWidth(null), image.getHeight(null), type);
    }

    // Copy image to buffered image
    Graphics g = bimage.createGraphics();

    // Paint the image onto the buffered image
    g.drawImage(image, 0, 0, null);
    g.dispose();

    return bimage;
}

From source file:edu.umn.cs.spatialHadoop.operations.GeometricPlot.java

/**
 * Draws an image that can be used as a scale for heat maps generated using
 * Plot or PlotPyramid.//from   w  ww.j  a va 2s. c  om
 * @param output - Output path
 * @param valueRange - Range of values of interest
 * @param width - Width of the generated image
 * @param height - Height of the generated image
 * @throws IOException
 */
public static void drawScale(Path output, MinMax valueRange, int width, int height) throws IOException {
    BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
    Graphics2D g = image.createGraphics();
    g.setBackground(Color.BLACK);
    g.clearRect(0, 0, width, height);

    // fix this part to work according to color1, color2 and gradient type
    for (int y = 0; y < height; y++) {
        Color color = NASARectangle.calculateColor(y);
        g.setColor(color);
        g.drawRect(width * 3 / 4, y, width / 4, 1);
    }

    int fontSize = 24;
    g.setFont(new Font("Arial", Font.BOLD, fontSize));
    int step = (valueRange.maxValue - valueRange.minValue) * fontSize * 10 / height;
    step = (int) Math.pow(10, Math.round(Math.log10(step)));
    int min_value = valueRange.minValue / step * step;
    int max_value = valueRange.maxValue / step * step;

    for (int value = min_value; value <= max_value; value += step) {
        int y = fontSize + (height - fontSize)
                - value * (height - fontSize) / (valueRange.maxValue - valueRange.minValue);
        g.setColor(Color.WHITE);
        g.drawString(String.valueOf(value), 5, y);
    }

    g.dispose();

    FileSystem fs = output.getFileSystem(new Configuration());
    FSDataOutputStream outStream = fs.create(output, true);
    ImageIO.write(image, "png", outStream);
    outStream.close();
}

From source file:ded.ui.DiagramController.java

/** Get and log some details related to display scaling, particularly
  * to help diagnose the graphics bugs on HiDPI/Retina displays. */
public void logDisplayScaling() {
    // Based on code from
    // http://lubosplavucha.com/java/2013/09/02/retina-support-in-java-for-awt-swing/

    try {/*from w ww.java  2 s. c om*/
        // Dump a bunch of possibly interesting JVM properties.
        String propertyNames[] = { "awt.toolkit", "java.awt.graphicsenv", "java.runtime.name",
                "java.runtime.version", "java.vendor", "java.version", "java.vm.name", "java.vm.vendor",
                "java.vm.version", };
        for (String name : propertyNames) {
            this.log("property " + name + ": " + System.getProperty(name));
        }

        // Try a property specific to the Apple JVM.
        this.log("apple.awt.contentScaleFactor: "
                + Toolkit.getDefaultToolkit().getDesktopProperty("apple.awt.contentScaleFactor"));

        // Try something specific to OpenJDK.  Here, we
        // reflectively query some private field.  Yuck.
        GraphicsDevice gd = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
        try {
            Field field = gd.getClass().getDeclaredField("scale");
            field.setAccessible(true);
            this.log("GraphicsEnvironment.scale: " + field.get(gd));
        } catch (NoSuchFieldException e) {
            this.log("GraphicsEnvironment does not have a 'scale' field");
        }

        // Check some details of "compatible" images.
        GraphicsConfiguration gc = gd.getDefaultConfiguration();
        BufferedImage bi = gc.createCompatibleImage(64, 64);
        ColorModel cm = bi.getColorModel();
        this.log("compatible image color model: " + cm);

        // Do the same for a specific imageType that seems to be
        // commonly used, and that I am using when saving to PNG.
        bi = new BufferedImage(64, 64, BufferedImage.TYPE_INT_ARGB);
        cm = bi.getColorModel();
        this.log("TYPE_INT_ARGB color model: " + cm);

        // And one more.
        bi = new BufferedImage(64, 64, BufferedImage.TYPE_INT_RGB);
        cm = bi.getColorModel();
        this.log("TYPE_INT_RGB color model: " + cm);
    } catch (Exception e) {
        this.log("exception during logDisplayScaling(): " + Util.getExceptionMessage(e));
        this.logNoNewline(Util.getExceptionStackTrace(e));
    }
}

From source file:DefaultGraphics2D.java

/**
 * Draws as much of the specified area of the specified image as is currently
 * available, scaling it on the fly to fit inside the specified area of the
 * destination drawable surface. Transparent pixels do not affect whatever
 * pixels are already there.//www  .  jav  a2 s  . c o  m
 * <p>
 * This method returns immediately in all cases, even if the image area to be
 * drawn has not yet been scaled, dithered, and converted for the current
 * output device. If the current output representation is not yet complete
 * then <code>drawImage</code> returns <code>false</code>. As more of the
 * image becomes available, the process that draws the image notifies the
 * specified image observer.
 * <p>
 * This method always uses the unscaled version of the image to render the
 * scaled rectangle and performs the required scaling on the fly. It does not
 * use a cached, scaled version of the image for this operation. Scaling of
 * the image from source to destination is performed such that the first
 * coordinate of the source rectangle is mapped to the first coordinate of the
 * destination rectangle, and the second source coordinate is mapped to the
 * second destination coordinate. The subimage is scaled and flipped as needed
 * to preserve those mappings.
 * 
 * @param img
 *          the specified image to be drawn
 * @param dx1
 *          the <i>x</i> coordinate of the first corner of the destination
 *          rectangle.
 * @param dy1
 *          the <i>y</i> coordinate of the first corner of the destination
 *          rectangle.
 * @param dx2
 *          the <i>x</i> coordinate of the second corner of the destination
 *          rectangle.
 * @param dy2
 *          the <i>y</i> coordinate of the second corner of the destination
 *          rectangle.
 * @param sx1
 *          the <i>x</i> coordinate of the first corner of the source
 *          rectangle.
 * @param sy1
 *          the <i>y</i> coordinate of the first corner of the source
 *          rectangle.
 * @param sx2
 *          the <i>x</i> coordinate of the second corner of the source
 *          rectangle.
 * @param sy2
 *          the <i>y</i> coordinate of the second corner of the source
 *          rectangle.
 * @param observer
 *          object to be notified as more of the image is scaled and
 *          converted.
 * @see java.awt.Image
 * @see java.awt.image.ImageObserver
 * @see java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int,
 *      int, int, int)
 * @since JDK1.1
 */
public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2,
        ImageObserver observer) {
    BufferedImage src = new BufferedImage(img.getWidth(null), img.getHeight(null), BufferedImage.TYPE_INT_ARGB);
    Graphics2D g = src.createGraphics();
    g.drawImage(img, 0, 0, null);
    g.dispose();

    src = src.getSubimage(sx1, sy1, sx2 - sx1, sy2 - sy1);

    return drawImage(src, dx1, dy1, dx2 - dx1, dy2 - dy1, observer);
}