# 绘制图像

> 原文： [https://docs.oracle.com/javase/tutorial/https://docs.oracle.com/javase/tutorial/images/drawimage.html](https://docs.oracle.com/javase/tutorial/https://docs.oracle.com/javase/tutorial/images/drawimage.html)

如您所知，`Graphics.drawImage`方法在特定位置绘制图像：

```
boolean Graphics.drawImage(Image img,
                   int x, int y,
                   ImageObserver observer);

```

`x,y`位置指定图像左上角的位置。 `observer`参数通知应用程序对异步加载的映像的更新。 `observer`参数不经常直接使用， [`BufferedImage`](https://docs.oracle.com/javase/8/docs/api/java/awt/image/BufferedImage.html) 类不需要，因此它通常为空。

所描述的方法仅解决了要绘制整个图像的情况，将图像像素映射到用户空间坐标 1：1。有时，应用程序需要绘制图像的一部分（子图像），或缩放图像以覆盖绘图表面的特定区域，或者在绘制之前变换或过滤图像。

`drawImage()`方法的重载执行这些操作。例如，`drawImage()`方法的以下重载使您可以绘制与当前可用的指定图像的指定区域一样多的数量，将其缩放以适合目标可绘制表面的指定区域：

```
boolean Graphics.drawImage(Image img,
       int dstx1, int dsty1, int dstx2, int dsty2,
       int srcx1, int srcy1, int srcx2, int srcy2,
       ImageObserver observer);

```

`src`参数表示要复制和绘制的图像区域。 `dst`参数显示源区域要覆盖的目标区域。 `dstx1, dsty1`坐标定义绘制图像的位置。目标区域的宽度和高度尺寸通过以下表达式计算：`(dstx2-dstx1), (dsty2-dsty1)`。如果源和目标区域的维度不同，则 Java 2D API 将根据需要向上扩展或缩小。

以下代码示例将图像划分为四个象限，并将源图像的每个象限随机绘制到目标的不同象限。

&lt;applet alt="Divides an image into four quadrants and randomly draws each quadrant of the source image into a different quadrant of the destination." archive="examples/lib/JumbledImageApplet.jar" code="JumbledImageApplet" height="250" width="400"&gt;&lt;param name="permissions" value="sandbox"&gt;&lt;/applet&gt;

* * *

**Note:**  If you don't see the applet running, you need to install at least the [Java SE Development Kit (JDK) 7](http://www.oracle.com/technetwork/java/javase/downloads/index.html) release.

* * *

该 applet 的完整代码位于 [`JumbledImageApplet.java`](examples/JumbledImageApplet.java) 中。

此示例使用以下代码绘制混乱的`duke_skateboard.jpg`图像。它迭代源的四个子图像，依次绘制成随机选择的目标象限。

```
/* divide the image 'bi' into four rectangular
 * areas and draw each of these areas in to a
 * different part of the image, so as to jumble
 * up the image.  'cells' is an array which has
 * been populated with values which redirect
 * drawing of one subarea to another subarea.
 */
int cellWidth = bi.getWidth(null)/2;
int cellHeight = bi.getHeight(null)/2;
for (int x=0; x<2; x++) {
    int sx = x*cellWidth;
    for (int y=0; y<2; y++) {
        int sy = y*cellHeight;
        int cell = cells[x*2+y];
        int dx = (cell / 2) * cellWidth;
        int dy = (cell % 2) * cellHeight;
        g.drawImage(bi,
                    dx, dy, 
                    x+cellWidth, dy+cellHeight,
                    sx, sy,
                    sx+cellWidth, sy+cellHeight,
                    null);
    }
}

```

## 过滤图像

除了复制和缩放图像外，Java 2D API 还可以过滤图像。 _ 过滤 _ 通过将算法应用于源图像的像素来绘制或生成新图像。可以使用以下方法应用图像过滤器：

```
void Graphics2D.drawImage(BufferedImage img,
                          BufferedImageOp op,
                          int x, int y)

```

`BufferedImageOp`参数实现过滤器。以下小程序表示在文本顶部绘制的图像。拖动滑块可在图像中显示更多或更少的文本，并使图像或多或少透明。

&lt;applet alt="Represents an image drawn on top of text" archive="examples/lib/SeeThroughImageApplet.jar" code="SeeThroughImageApplet" height="250" width="400"&gt;&lt;param name="permissions" value="sandbox"&gt;&lt;/applet&gt;

* * *

**Note:**  If you don't see the applet running, you need to install at least the [Java SE Development Kit (JDK) 7](http://www.oracle.com/technetwork/java/javase/downloads/index.html) release.

* * *

以下代码显示了如何通过使用 _alpha_ 通道操作`BufferedImage`对象并使用`RescaleOp`对象重新调整该 Alpha 通道来完成滤镜操作。 alpha 通道决定每个像素的半透明度。它还指定此图像覆盖的程度。

```
/* Create an ARGB BufferedImage */
BufferedImage img = ImageIO.read(imageSrc);
int w = img.getWidth(null);
int h = img.getHeight(null);
BufferedImage bi = new
    BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
Graphics g = bi.getGraphics();
g.drawImage(img, 0, 0, null);

/*
 * Create a rescale filter op that makes the image
 * 50% opaque.
 */
float[] scales = { 1f, 1f, 1f, 0.5f };
float[] offsets = new float[4];
RescaleOp rop = new RescaleOp(scales, offsets, null);

/* Draw the image, applying the filter */
g2d.drawImage(bi, rop, 0, 0);

```

[`SeeThroughImageApplet.java`](examples/SeeThroughImageApplet.java) 中表示的完整示例包括使用滑块从最初的 50％调整透明度的代码。此示例还需要 [duke_skateboard.jpg](examples/duke_skateboard.jpg) 图像。

`RescaleOp`对象只是可以创建的许多过滤器之一。 Java 2D API 有几个内置的过滤器，包括：

*   `ConvolveOp`。从源图像中的周围像素计算每个输出像素。它可用于模糊或锐化图像。
*   `AffineTransformOp`。此滤镜通过对像素位置应用变换，将源中的像素映射到目标中的不同位置。
*   `LookupOp`。此过滤器使用应用程序提供的查找表来重新映射像素颜色。
*   `RescaleOp`。此滤镜将颜色乘以某个因子。可用于使图像变亮或变暗，增加或减少其不透明度等。

以下示例使用每个描述的过滤器以及缩放：

&lt;applet alt="Demonstrates filters and scaling" archive="examples/lib/ImageDrawingApplet.jar" code="ImageDrawingApplet" height="250" width="400"&gt;&lt;param name="permissions" value="sandbox"&gt;&lt;/applet&gt;

* * *

**Note:**  If you don't see the applet running, you need to install at least the [Java SE Development Kit (JDK) 7](http://www.oracle.com/technetwork/java/javase/downloads/index.html) release.

* * *

这个小程序的完整代码在 [`ImageDrawingApplet.java`](examples/ImageDrawingApplet.java) 中，这个小程序需要 [bld.jpg](examples/bld.jpg) 图像。

使用下拉菜单选择图像缩放或过滤操作。