【Java】BufferedImageの簡単な使い方

#はじめに
Javaにおいて標準機能で画像処理をしようとする場合、BufferedImageを用いることになると思います。
Javaはそもそも画像処理向きの言語ではないですし、OpenCVなどのライブラリを用いた方が簡単に処理できます。
しかし、ここではあえてBufferedImageの基本的な使い方を記しておこうと思います。

#画像の生成
コンストラクタを呼び出すだけです。
実際に動かす際にはwidth(幅)やheight(高さ), type(タイプ)に任意の値を入れてください。
ただし、typeは若干曲者なので、公式ドキュメントに目を通すことをお勧めします。

```Sample.java
    var bi = new BufferedImage(width, height, type);
```

#画像の読み込み
ImageIOクラスを用いることで簡単に実装できます。

```ImageUtil.java
    public static BufferedImage read(String filename) {
        try {
            return ImageIO.read(new File(filename));
        } catch (IOException e) {
            e.printStackTrace();
        }
        return new BufferedImage(0, 0, 0);
    }
```

#画像の書き出し
読み込みと同じように実装できます。
ただし、拡張子情報が必要なのでsubstringで抽出します。

```ImageUtil.java
    public static void write(BufferedImage bi, String filename) {
        try {
            String extension = filename.substring(filename.lastIndexOf(".") + 1);
            ImageIO.write(bi, extension, new File(filename));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
```

#パラメータの取得
画像の幅、高さ、タイプは以下の通り取得できます。
サンプルのbiはBufferedImageのインスタンスです。

```Sample.java
    int width = bi.getWidth();
    int height = bi.getHeight();
    int type = bi.getType();
```

#画素値の取得
インデックス(x,y)の画素値を取得します。
ビットシフトをしてからビットマスクをすることで、8bit（0~255）の値を取得することができます。
先頭からAlpha, Red, Green, Blueの順に画素は並んでいるので、このようなプログラムになります。

```ImageUtil.java
    public static int[] getRGB(BufferedImage bi, int x, int y) {
        int pixel = bi.getRGB(x, y);
        int red = pixel >> 16 & 0xff;
        int green = pixel >> 8 & 0xff;
        int blue = pixel & 0xff;
        return new int[]{red, green, blue};
    }

    public static int[] getARGB(BufferedImage bi, int x, int y) {
        int pixel = bi.getRGB(x, y);
        int alpha = pixel >>> 24;
        int red = pixel >> 16 & 0xff;
        int green = pixel >> 8 & 0xff;
        int blue = pixel & 0xff;
        return new int[]{alpha, red, green, blue};
    }
```

#画素値の設定
インデックス(x,y)に画素値を設定します。
取得時と同様にビット演算することで値を設定できます。

```ImageUtil.java
    public static void setRGB(BufferedImage bi, int x, int y, int[] rgb) {
        int pixel = 0xff000000 | rgb[0] << 16 | rgb[1] << 8 | rgb[2];
        bi.setRGB(x, y, pixel);
    }

    public static void setARGB(BufferedImage bi, int x, int y, int[] argb) {
        int pixel = argb[0] << 24 | argb[1] << 16 | argb[2] << 8 | argb[3];
        bi.setRGB(x, y, pixel);
    }
```

#画像の表示
これはおまけですが、SwingのJFrameを使用することで、簡単に画像を表示することができます。
下のプログラムはあくまでもサンプルなので、コンストラクタを編集することでウィンドウの設定を変更できます。

```ImageUtil.java
    /**
     * 画像を表示する
     *
     * @param bi BufferedImage型の画像
     */
    public static void show(BufferedImage bi) {
        new Viewer(bi);
    }

    /**
     * 画像表示用のフレーム
     */
    private static class Viewer extends JFrame {
        /**
         * 表示する画像
         */
        BufferedImage bi;

        /**
         * コンストラクタ
         *
         * @param bi BufferedImage型の画像
         */
        public Viewer(BufferedImage bi) {
            this.bi = bi;
            setDefaultCloseOperation(EXIT_ON_CLOSE);
            setSize(bi.getWidth(), bi.getHeight());
            setVisible(true);
            setResizable(false);
        }

        @Override
        public void paint(Graphics g) {
            g.drawImage(bi, 0, 0, null);
        }
    }
```