📢 Webサイト閉鎖と移転のお知らせ
このWebサイトは2026年9月に閉鎖いたします。
新しい記事は移転先で追加しております。(旧サイトでは記事を追加しておりません)

 
(同じ利用者による、間の8版が非表示)
27行目: 27行目:
<br><br>
<br><br>


== QImageクラス / QBitmapクラス / QPixmapクラス ==
== QImageクラス / QPixmapクラス / QBitmapクラス ==
QImageクラス、QBitmapクラス、QPixmapクラスの3つのクラスは、Qtで画像を扱う時に使用される重要なクラスである。<br>
QImageクラス、QBitmapクラス、QPixmapクラスの3つのクラスは、Qtで画像を扱う時に使用される重要なクラスである。<br>
それぞれのクラスは異なる用途と特徴を持つ。<br>
それぞれのクラスは異なる用途と特徴を持つ。<br>
60行目: 60行目:
* QImageクラス
* QImageクラス
*: 画像処理や詳細な編集が必要な場合に使用する。
*: 画像処理や詳細な編集が必要な場合に使用する。
* QPixmapクラス
*: GUIでの高速な画像表示が必要な場合に使用する。
* QBitmapクラス
* QBitmapクラス
*: モノクロの単純な画像やマスクが必要な場合に使用する。
*: モノクロの単純な画像やマスクが必要な場合に使用する。
* QPixmapクラス
*: GUIでの高速な画像表示が必要な場合に使用する。
<br>
<br>
また、これらのクラス間では相互変換が可能である。<br>
また、これらのクラス間では相互変換が可能である。<br>
71行目: 71行目:
<br><br>
<br><br>


== QGraphicsViewクラスを使用する ==
== QImageクラスの使用例 ==
==== 画像の拡大 ====
以下の例では、QImageクラスを使用して、画像を拡大している。<br>
<br>
<syntaxhighlight lang="c++">
#include <QImage>
#include <QSize>
#include <QFileInfo>
int main()
{
    // 入力ファイルの存在確認
    if (!QFileInfo::exists("input.jpg")) return -1;
    // 画像の読み込み
    QImage image("input.jpg");
    if (image.isNull()) return -1;
    // 画像の拡大
    QImage resizedImage = image.scaled(QSize(800, 600), Qt::KeepAspectRatio, Qt::SmoothTransformation);
    // 拡大した画像の保存
    if (!resizedImage.save("output.jpg")) return -1;
    return 0;
}
</syntaxhighlight>
<br>
==== 画像の縮小 ====
以下の例では、QImageクラスを使用して、指定された最大サイズ (例: 400x300ピクセル) に収まるように縮小する。<br>
元の画像が既このサイズ以下の場合は、縮小処理は行わない。<br>
<br>
<syntaxhighlight lang="c++">
#include <QImage>
#include <QSize>
#include <QFileInfo>
QImage shrinkImage(QImage &image, int maxWidth, int maxHeight)
{
    QSize originalSize = image.size();
    QSize newSize      = originalSize;
    // アスペクト比を維持しながら、指定された最大サイズに収まるように縮小
    if (originalSize.width() > maxWidth || originalSize.height() > maxHeight) {
      newSize.scale(maxWidth, maxHeight, Qt::KeepAspectRatio);
    }
    // 元のサイズより小さい場合のみ縮小を行う
    // 縮小の必要がない場合は元の画像をそのまま
    if (newSize != originalSize) {
      return image.scaled(newSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
    }
    else {
      return image;
    }
}
int main()
{
    // 入力ファイルの存在確認
    if (!QFileInfo::exists("input.jpg")) return -1;
    // 画像の読み込み
    QImage image("input.jpg");
    if (image.isNull()) return -1;
    // 画像の縮小
    QImage resizedImage = shrinkImage(image, 400, 300)
    // 縮小した画像の保存
    if (!resizedImage.save("output.jpg")) return -1;
    return 0;
}
</syntaxhighlight>
<br>
==== 画像の回転 ====
以下の例では、QImageクラスを使用して、画像を回転している。<br>
<br>
<syntaxhighlight lang="c++">
#include <QApplication>
#include <QImage>
#include <QTransform>
#include <QFileDialog>
int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    // 画像を読み込む
    QImage image("input.jpg");
    if (image.isNull()) return -1;
    // 回転角度を指定 (例: 90度)
    double angle = 90.0;
    // QTransformクラスを使用して画像を回転
    QTransform transform;
    transform.rotate(angle);
    QImage rotatedImage = image.transformed(transform, Qt::SmoothTransformation);
    if (rotatedImage.isNull()) return -1;
    // 回転した画像を保存
    if (!rotatedImage.save("output.jpg")) return -1;
    return 0;
}
</syntaxhighlight>
<br><br>
 
== QPixmapクラスの使用例 ==
==== 画像ビューアウィジェット ====
以下の例では、画像ビューアウィジェットのクラスを定義している。<br>
<br>
<syntaxhighlight lang="c++">
// ImageViewer.hファイル
#include <QWidget>
#include <QPixmap>
#include <QLabel>
#include <QVBoxLayout>
#include <QPushButton>
#include <QFileDialog>
#include <QMessageBox>
class ImageViewer : public QWidget
{
    Q_OBJECT
private:
    QLabel      *imageLabel;  // 画像表示用ラベル
    QPushButton *loadButton;  // 画像読み込みボタン
public:
    // コンストラクタ: ウィジェットの初期化
    ImageViewer(QWidget *parent = nullptr) : QWidget(parent)
    {
      // 画像を表示するためのQLabel
      imageLabel = new QLabel(this);
      imageLabel->setAlignment(Qt::AlignCenter);
      // 画像読み込みボタン
      loadButton = new QPushButton("画像を読み込む", this);
      // ボタンクリック時にloadImage()スロットを呼び出す
      connect(loadButton, &QPushButton::clicked, this, &ImageViewer::loadImage);
      // レイアウトの設定
      QVBoxLayout *layout = new QVBoxLayout(this);
      layout->addWidget(imageLabel);
      layout->addWidget(loadButton);
      setLayout(layout);
    }
private slots:
    // 画像読み込み処理を行うスロット
    void loadImage()
    {
      // ファイル選択ダイアログを表示
      QString fileName = QFileDialog::getOpenFileName(this, "画像を開く", "", "画像ファイル (*.png *.jpg *.bmp)");
      if (!fileName.isEmpty()) {
          // 選択されたファイルからQPixmapを作成
          QPixmap pixmap(fileName);
          if (pixmap.isNull()) {
            // 画像読み込みに失敗した場合はエラーメッセージを表示
            QMessageBox::critical(this, "エラー", "画像の読み込みに失敗");
            return;
          }
          // 読み込んだ画像をラベルに表示 (アスペクト比を保持してリサイズ)
          imageLabel->setPixmap(pixmap.scaled(imageLabel->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation));
      }
    }
};
</syntaxhighlight>
<br>
==== アニメーションスプライトシート ====
以下の例では、スプライトシートを使用したアニメーションクラスを定義している。<br>
<br>
<syntaxhighlight lang="c++">
// AnimatedSprite.hファイル
#include <QWidget>
#include <QPixmap>
#include <QTimer>
#include <QPainter>
class AnimatedSprite : public QWidget
{
    Q_OBJECT
private:
    QPixmap spriteSheet;  // スプライトシート
    QTimer *timer;        // アニメーション用タイマ
    int currentFrame;    // 現在のフレーム番号
    int frameWidth;      // 1フレームの幅
    int frameHeight;      // 1フレームの高さ
 
protected:
    // ペイントイベント: 現在のフレームを描画
    void paintEvent(QPaintEvent *event) override
    {
      Q_UNUSED(event);
      QPainter painter(this);
      // スプライトシートから現在のフレームを切り出して描画
      painter.drawPixmap(0, 0, spriteSheet, currentFrame * frameWidth, 0, frameWidth, frameHeight);
    }
public:
    // コンストラクタ: スプライトシートの読み込みとタイマの設定
    AnimatedSprite(QWidget *parent = nullptr) : QWidget(parent), currentFrame(0)
    {
      // スプライトシートの読み込み
      spriteSheet.load(":/sprites/character.png");  // スプライトシートのリソースパス
      if (spriteSheet.isNull()) {
          qWarning() << "スプライトシートの読み込みに失敗";
          return;
      }
      // スプライトシートの各フレームのサイズを計算
      frameWidth = spriteSheet.width() / 4;  // 4フレームあると仮定
      frameHeight = spriteSheet.height();
      // アニメーション用タイマの設定
      timer = new QTimer(this);
      connect(timer, &QTimer::timeout, this, &AnimatedSprite::nextFrame);
      timer->start(100);  // 100[mS]ごとにフレーム更新
      // ウィジェットのサイズを1フレームのサイズに固定
      setFixedSize(frameWidth, frameHeight);
    }
private slots:
    // 次のフレームに進むスロット
    void nextFrame()
    {
      currentFrame = (currentFrame + 1) % 4;  // 4フレームを循環
      update();                              // ウィジェットの再描画をリクエスト
    }
};
</syntaxhighlight>
<br>
==== 非同期で画像を読み込む ====
以下の例では、大きなサイズの画像を非同期で読み込むウィジェットを定義している。<br>
<br>
<syntaxhighlight lang="c++">
// AsyncImageLoader.hファイル
#include <QWidget>
#include <QPixmap>
#include <QLabel>
#include <QPushButton>
#include <QVBoxLayout>
#include <QFuture>
#include <QtConcurrent>
#include <QFileDialog>
#include <QMessageBox>
class AsyncImageLoader : public QWidget
{
    Q_OBJECT
private:
    QLabel *imageLabel;      // 画像表示用ラベル
    QPushButton *loadButton;  // 画像読み込みボタン
 
public:
    // コンストラクタ: ウィジェットの初期化
    AsyncImageLoader(QWidget *parent = nullptr) : QWidget(parent)
    {
      // 画像表示用ラベル
      imageLabel = new QLabel(this);
      imageLabel->setAlignment(Qt::AlignCenter);
      // 画像読み込みボタン
      loadButton = new QPushButton("大きな画像を読み込む", this);
      connect(loadButton, &QPushButton::clicked, this, &AsyncImageLoader::loadImageAsync);
      // レイアウトの設定
      QVBoxLayout *layout = new QVBoxLayout(this);
      layout->addWidget(imageLabel);
      layout->addWidget(loadButton);
      setLayout(layout);
    }
private slots:
    // 非同期で画像を読み込むスロット
    void loadImageAsync()
    {
      // ファイル選択ダイアログを表示
      QString fileName = QFileDialog::getOpenFileName(this, "大きな画像を開く", "", "画像ファイル (*.png *.jpg *.bmp)");
      if (!fileName.isEmpty()) {
          // UIの更新(ボタンを無効化し、テキストを変更)
          loadButton->setEnabled(false);
          loadButton->setText("読み込み中...");
          // 非同期で画像を読み込む
          QFuture<QPixmap> future = QtConcurrent::run([fileName]() {
            return QPixmap(fileName);
          });
          // 非同期処理の完了を監視するためのQFutureWatcherを設定
          QFutureWatcher<QPixmap> *watcher = new QFutureWatcher<QPixmap>(this);
          connect(watcher, &QFutureWatcher<QPixmap>::finished, this, [this, watcher]() {
            QPixmap pixmap = watcher->result();
            if (pixmap.isNull()) {
                // 画像読み込みに失敗した場合はエラーメッセージを表示
                QMessageBox::critical(this, "エラー", "画像の読み込みに失敗");
            }
            else {
                // 読み込んだ画像をラベルに表示 (アスペクト比を保持してリサイズ)
                imageLabel->setPixmap(pixmap.scaled(imageLabel->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation));
            }
            // UIの更新 (ボタンを再度有効化して、元のテキストに戻す)
            loadButton->setEnabled(true);
            loadButton->setText("大きな画像を読み込む");
            // watcherのメモリを解放
            watcher->deleteLater();
          });
          // 非同期処理の監視を開始
          watcher->setFuture(future);
      }
    }
};
</syntaxhighlight>
<br><br>
 
== QBitmapクラスの使用例 ==
==== 描画ツール ====
以下の例では、1ビット深度の描画ツールクラスを定義している。<br>
<br>
<syntaxhighlight lang="c++">
// SimpleDrawingTool.hファイル
#include <QWidget>
#include <QBitmap>
#include <QPainter>
#include <QMouseEvent>
#include <QPushButton>
#include <QVBoxLayout>
#include <QLabel>
#include <QMessageBox>
class SimpleDraingTool : public QWidget
{
    Q_OBJECT
private:
    QLabel      *drawingLabel;  // 描画エリア用ラベル
    QPushButton *clearButton;  // クリアボタン
    QBitmap    bitmap;        // 描画用ビットマップ
    bool        drawing;        // 描画中フラグ
    // 描画用ビットマップを初期化する関数
    void initializeBitmap()
    {
      bitmap = QBitmap(300, 300);
      bitmap.fill(Qt::color0);  // 背景を黒で初期化
      updateLabel();
    }
    // 指定された位置に点を描画する関数
    void drawPoint(const QPoint &pos)
    {
      QPainter painter(&bitmap);
      painter.setPen(Qt::color1);  // 白で描画
      painter.drawPoint(pos);
      updateLabel();
    }
    // ラベルの表示を更新する関数
    void updateLabel()
    {
      drawingLabel->setPixmap(QPixmap::fromImage(bitmap.toImage()));
    }
public:
    // コンストラクタ: ウィジェットの初期化
    SimpleDraingTool(QWidget *parent = nullptr) : QWidget(parent), drawing(false)
    {
      // 描画エリア用ラベル
      drawingLabel = new QLabel(this);
      drawingLabel->setAlignment(Qt::AlignCenter);
      // クリアボタン
      clearButton = new QPushButton("クリア", this);
      connect(clearButton, &QPushButton::clicked, this, &SimpleDraingTool::clearDrawing);
      // レイアウトの設定
      QVBoxLayout *layout = new QVBoxLayout(this);
      layout->addWidget(drawingLabel);
      layout->addWidget(clearButton);
      setLayout(layout);
      // 描画用ビットマップの初期化
      initializeBitmap();
    }
protected:
    // マウスボタンが押下された時のイベントハンドラ
    void mousePressEvent(QMouseEvent *event) override
    {
      if (event->button() == Qt::LeftButton) {
          drawing = true;
          drawPoint(event->pos());
      }
    }
    // マウスが移動した時のイベントハンドラ
    void mouseMoveEvent(QMouseEvent *event) override
    {
      if ((event->buttons() & Qt::LeftButton) && drawing) {
          drawPoint(event->pos());
      }
    }
    // マウスボタンが離された時のイベントハンドラ
    void mouseReleaseEvent(QMouseEvent *event) override
    {
      if (event->button() == Qt::LeftButton && drawing) {
          drawing = false;
      }
    }
private slots:
    // 描画をクリアするスロット
    void clearDrawing()
    {
      try {
          initializeBitmap();
          updateLabel();
      }
      catch (const std::exception& e) {
          QMessageBox::critical(this, "エラー", QString("描画のクリアに失敗: %1").arg(e.what()));
      }
    }
};
</syntaxhighlight>
<br>
==== カスタムカーソル作成器 ====
以下の例では、カスタムカーソルを作成および適用するウィジェットクラスを定義している。<br>
<br>
<syntaxhighlight lang="c++">
// CustomCursorCreator.hファイル
#include <QWidget>
#include <QBitmap>
#include <QPainter>
#include <QPushButton>
#include <QVBoxLayout>
#include <QCursor>
#include <QMessageBox>
class CustomCursorCreator : public QWidget
{
    Q_OBJECT
private:
    QPushButton *createButton;  // カーソル作成ボタン
public:
    // コンストラクタ: ウィジェットの初期化
    CustomCursorCreator(QWidget *parent = nullptr) : QWidget(parent)
    {
      // カーソル作成ボタン
      createButton = new QPushButton("カスタムカーソルを作成", this);
      connect(createButton, &QPushButton::clicked, this, &CustomCursorCreator::createAndApplyCursor);
      // レイアウトの設定
      QVBoxLayout *layout = new QVBoxLayout(this);
      layout->addWidget(createButton);
      setLayout(layout);
    }
private slots:
    // カスタムカーソルを作成・適用するスロット
    void createAndApplyCursor()
    {
      try {
          // 32x32ピクセルのビットマップを作成
          QBitmap bitmap(32, 32);
          bitmap.fill(Qt::color0);  // 透明で初期化
          // ビットマップ上に描画
          QPainter painter(&bitmap);
          painter.setPen(Qt::color1);  // 不透明な色で描画
          // 簡単な十字型のカーソルを描画
          painter.drawLine(16, 0, 16, 31);  // 縦線
          painter.drawLine(0, 16, 31, 16);  // 横線
          // マスクを作成 (カーソルの形状を定義)
          QBitmap mask = bitmap;
          // カーソルを作成・適用
          QCursor cursor(bitmap, mask, 16, 16);  // ホットスポットを中心に設定
          this->setCursor(cursor);
          QMessageBox::information(this, "成功", "カスタムカーソルを作成・適用");
      }
      catch (const std::exception& e) {
          QMessageBox::critical(this, "エラー", QString("カーソルの作成に失敗: %1").arg(e.what()));
      }
    }
};
</syntaxhighlight>
<br>
==== モノクロパターン生成器 ====
以下の例では、ランダムなモノクロパターンを生成し表示するウィジェットクラスを定義している。<br>
<br>
<syntaxhighlight lang="c++">
// MonochromePatternGenerator.hファイル
#include <QWidget>
#include <QBitmap>
#include <QPainter>
#include <QPushButton>
#include <QVBoxLayout>
#include <QLabel>
#include <QRandomGenerator>
#include <QMessageBox>
class MonochromePatternGenerator : public QWidget
{
    Q_OBJECT
private:
    QLabel      *patternLabel;    // パターン表示用ラベル
    QPushButton *generateButton;  // パターン生成ボタン
public:
    // コンストラクタ: ウィジェットの初期化を行います
    MonochromePatternGenerator(QWidget *parent = nullptr) : QWidget(parent)
    {
      // パターン表示用ラベル
      patternLabel = new QLabel(this);
      patternLabel->setAlignment(Qt::AlignCenter);
      // パターン生成ボタン
      generateButton = new QPushButton("新しいパターンを生成", this);
      connect(generateButton, &QPushButton::clicked, this, &MonochromePatternGenerator::generatePattern);
      // レイアウトの設定
      QVBoxLayout *layout = new QVBoxLayout(this);
      layout->addWidget(patternLabel);
      layout->addWidget(generateButton);
      setLayout(layout);
      // 初期パターンを生成
      generatePattern();
    }
private slots:
    // ランダムなモノクロパターンを生成するスロット
    void generatePattern()
    {
      try {
          // 100x100ピクセルのビットマップを作成
          QBitmap bitmap(100, 100);
          bitmap.fill(Qt::color0);    // 黒で初期化
          QPainter painter(&bitmap);
          painter.setPen(Qt::color1);  // 白で描画
          // ランダムなパターンを生成
          for (int y = 0; y < 100; y++) {
            for (int x = 0; x < 100; x++) {
                if (QRandomGenerator::global()->generateDouble() > 0.5) {
                  painter.drawPoint(x, y);
                }
            }
          }
          // パターンをラベルに表示
          patternLabel->setPixmap(QPixmap::fromImage(bitmap.toImage().scaled(200, 200, Qt::KeepAspectRatio, Qt::FastTransformation)));
      }
      catch (const std::exception& e) {
          QMessageBox::critical(this, "エラー", QString("パターンの生成に失敗: %1").arg(e.what()));
      }
    }
};
</syntaxhighlight>
<br><br>
 
== QGraphicsViewクラスの使用 ==
画像を表示する機能を持っているウィジェットは無いため、ビュークラスを継承して派生クラスを作成する。<br>
画像を表示する機能を持っているウィジェットは無いため、ビュークラスを継承して派生クラスを作成する。<br>
(元々、<code>QGraphicsView</code>クラスは、<code>QGraphicsScene</code>クラスを表示するためのものである)<br>
(元々、<code>QGraphicsView</code>クラスは、<code>QGraphicsScene</code>クラスを表示するためのものである)<br>
155行目: 744行目:
  }
  }
  </syntaxhighlight>
  </syntaxhighlight>
<br><br>
<br>
 
==== 画像の拡大・縮小・移動 ====
== 画像の拡大・縮小・移動 ==
画像を表示する機能には、拡大・縮小、移動等の制御が必要になる場合が多い。<br>
画像を表示する機能には、拡大・縮小、移動等の制御が必要になる場合が多い。<br>
これらの機能を実装するには、<code>QTransform</code>クラスを使用する。<br>
これらの機能を実装するには、<code>QTransform</code>クラスを使用する。<br>
296行目: 884行目:
  }
  }
  </syntaxhighlight>
  </syntaxhighlight>
<br><br>
<br>
 
==== 画像のクリック位置の座標を逆算する ====
== 画像のクリック位置の座標を逆算する ==
画像上において、クリックする位置の座標を取得して、ピクセル値を取得する操作がある。<br>
画像上において、クリックする位置の座標を取得して、ピクセル値を取得する操作がある。<br>
<br>
<br>
339行目: 926行目:
  }
  }
  </syntaxhighlight>
  </syntaxhighlight>
<br><br>
<br>
 
==== 拡大・縮小時の画像の解像度を上げる ====
== 拡大・縮小時の画像の解像度を上げる ==
上記のセクション群では、画像を拡大・縮小する場合、画像の解像度はビューポートのサイズのままである。<br>
上記のセクション群では、画像を拡大・縮小する場合、画像の解像度はビューポートのサイズのままである。<br>
また、描画および再描画ごとに表示用の画像を作成しているため非効率である。<br>
また、描画および再描画ごとに表示用の画像を作成しているため非効率である。<br>
455行目: 1,041行目:
  </syntaxhighlight>
  </syntaxhighlight>
<br><br>
<br><br>


__FORCETOC__
__FORCETOC__
[[カテゴリ:Qt]]
[[カテゴリ:Qt]]