【Swingアプリ開発】画像ビューアアプリの解答例

2025-08-06

以下は、Swingを使用した基本的な画像ビューアアプリケーションの完全な実装例です。画像の表示、拡大/縮小、回転機能を備えています。

import javax.swing.*;
import javax.swing.filechooser.FileNameExtensionFilter;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;

public class ImageViewerApp {
    private static BufferedImage currentImage;
    private static double scale = 1.0;
    private static int rotation = 0;
    private static JLabel imageLabel;

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            // メインウィンドウの作成
            JFrame frame = new JFrame("画像ビューア");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setSize(800, 600);

            // 画像表示用ラベル
            imageLabel = new JLabel("", SwingConstants.CENTER);
            JScrollPane scrollPane = new JScrollPane(imageLabel);
            frame.add(scrollPane, BorderLayout.CENTER);

            // ツールバーの作成
            JToolBar toolBar = new JToolBar();
            toolBar.setFloatable(false);

            // ツールバーボタン
            JButton openButton = new JButton("開く");
            JButton zoomInButton = new JButton("拡大");
            JButton zoomOutButton = new JButton("縮小");
            JButton rotateLeftButton = new JButton("左回転");
            JButton rotateRightButton = new JButton("右回転");
            JButton resetButton = new JButton("リセット");

            // ボタンにアクションを追加
            openButton.addActionListener(e -> openImage(frame));
            zoomInButton.addActionListener(e -> zoom(1.25));
            zoomOutButton.addActionListener(e -> zoom(0.8));
            rotateLeftButton.addActionListener(e -> rotate(-90));
            rotateRightButton.addActionListener(e -> rotate(90));
            resetButton.addActionListener(e -> reset());

            // ボタンをツールバーに追加
            toolBar.add(openButton);
            toolBar.addSeparator();
            toolBar.add(zoomInButton);
            toolBar.add(zoomOutButton);
            toolBar.addSeparator();
            toolBar.add(rotateLeftButton);
            toolBar.add(rotateRightButton);
            toolBar.addSeparator();
            toolBar.add(resetButton);

            frame.add(toolBar, BorderLayout.NORTH);

            // ステータスバー
            JLabel statusBar = new JLabel("準備完了");
            frame.add(statusBar, BorderLayout.SOUTH);

            frame.setVisible(true);
        });
    }

    // 画像を開くメソッド
    private static void openImage(JFrame parent) {
        JFileChooser fileChooser = new JFileChooser();
        fileChooser.setFileFilter(new FileNameExtensionFilter(
            "画像ファイル", ImageIO.getReaderFileSuffixes()));

        if (fileChooser.showOpenDialog(parent) == JFileChooser.APPROVE_OPTION) {
            File selectedFile = fileChooser.getSelectedFile();
            try {
                currentImage = ImageIO.read(selectedFile);
                scale = 1.0;
                rotation = 0;
                updateImage();
            } catch (Exception ex) {
                JOptionPane.showMessageDialog(parent, 
                    "画像を読み込めませんでした", 
                    "エラー", 
                    JOptionPane.ERROR_MESSAGE);
                ex.printStackTrace();
            }
        }
    }

    // 画像をズームするメソッド
    private static void zoom(double factor) {
        scale *= factor;
        updateImage();
    }

    // 画像を回転するメソッド
    private static void rotate(int degrees) {
        rotation += degrees;
        rotation %= 360;
        updateImage();
    }

    // 表示をリセットするメソッド
    private static void reset() {
        scale = 1.0;
        rotation = 0;
        updateImage();
    }

    // 画像表示を更新するメソッド
    private static void updateImage() {
        if (currentImage == null) return;

        // 元の画像をコピー
        BufferedImage image = new BufferedImage(
            currentImage.getWidth(), 
            currentImage.getHeight(), 
            currentImage.getType());
        Graphics2D g2d = image.createGraphics();
        g2d.drawImage(currentImage, 0, 0, null);
        g2d.dispose();

        // 回転処理
        if (rotation != 0) {
            double radians = Math.toRadians(rotation);
            double sin = Math.abs(Math.sin(radians));
            double cos = Math.abs(Math.cos(radians));

            int newWidth = (int) Math.floor(image.getWidth() * cos + image.getHeight() * sin);
            int newHeight = (int) Math.floor(image.getHeight() * cos + image.getWidth() * sin);

            BufferedImage rotated = new BufferedImage(newWidth, newHeight, image.getType());
            Graphics2D g = rotated.createGraphics();

            AffineTransform at = new AffineTransform();
            at.translate(newWidth / 2, newHeight / 2);
            at.rotate(radians);
            at.translate(-image.getWidth() / 2, -image.getHeight() / 2);

            g.setTransform(at);
            g.drawImage(image, 0, 0, null);
            g.dispose();

            image = rotated;
        }

        // スケーリング処理
        int scaledWidth = (int)(image.getWidth() * scale);
        int scaledHeight = (int)(image.getHeight() * scale);
        Image scaledImage = image.getScaledInstance(scaledWidth, scaledHeight, Image.SCALE_SMOOTH);

        // ラベルに画像を設定
        imageLabel.setIcon(new ImageIcon(scaledImage));
    }
}

この画像ビューアアプリの特徴

  1. 基本機能:
  • 画像ファイルの読み込みと表示
  • 拡大/縮小機能(25%ずつ変更)
  • 左右90度回転機能
  • 表示リセット機能
  1. UI構成:
  • ツールバーに主要機能を配置
  • スクロール可能な画像表示領域
  • ステータスバー(今後の拡張用)
  1. 技術的特徴:
  • ImageIOを使用した画像読み込み
  • AffineTransformを使用した画像回転
  • スムーズなスケーリング処理

拡張可能なポイント

この基本実装をさらに発展させるためのアイデア:

  1. 追加機能:
  • スライドショー機能
  • 画像フィルタ(グレースケール、セピア調など)
  • 切り抜きツール
  • 画像の保存機能
  1. UI改善:
  • サムネイルビューの追加
  • ズームスライダーの実装
  • マウスホイールでのズーム対応
  1. パフォーマンス向上:
  • 大きな画像の処理最適化
  • バックグラウンドでの画像読み込み

例えば、画像保存機能を追加するには:

// ツールバーに保存ボタンを追加
JButton saveButton = new JButton("保存");
saveButton.addActionListener(e -> saveImage(frame));
toolBar.add(saveButton);

// 保存メソッドの実装
private static void saveImage(JFrame parent) {
    if (currentImage == null) return;

    JFileChooser fileChooser = new JFileChooser();
    fileChooser.setFileFilter(new FileNameExtensionFilter(
        "PNG画像", "png"));

    if (fileChooser.showSaveDialog(parent) == JFileChooser.APPROVE_OPTION) {
        File file = fileChooser.getSelectedFile();
        if (!file.getName().toLowerCase().endsWith(".png")) {
            file = new File(file.getAbsolutePath() + ".png");
        }

        try {
            ImageIO.write(currentImage, "png", file);
        } catch (IOException ex) {
            JOptionPane.showMessageDialog(parent, 
                "画像を保存できませんでした", 
                "エラー", 
                JOptionPane.ERROR_MESSAGE);
            ex.printStackTrace();
        }
    }
}

この画像ビューアアプリは、Swingでの画像処理の基本を理解するのに最適です。基本機能を実装した後、必要に応じて機能を追加していくことで、より実用的なアプリケーションに発展させることができます。