「Qtの応用 - ImageMagick」の版間の差分

提供:MochiuWiki : SUSE, EC, PCB
ナビゲーションに移動 検索に移動
 
(同じ利用者による、間の7版が非表示)
15行目: 15行目:
ImageMagickライブラリは高度な画像処理機能を提供する強力なツールとして活用できる。<br>
ImageMagickライブラリは高度な画像処理機能を提供する強力なツールとして活用できる。<br>
上記の例は基本的な使用方法の一部であり、さらに多くの機能や最適化オプションが用意されている。<br>
上記の例は基本的な使用方法の一部であり、さらに多くの機能や最適化オプションが用意されている。<br>
<br><br>
== ImageMagickのインストール ==
==== パッケージ管理システムからインストール ====
# RHEL
sudo dnf install ImageMagick-devel libMagick++-devel
# SUSE
sudo zypper install ImageMagick-devel libMagick++-devel
<br>
==== ソースコードからインストール ====
まず、ImageMagickのビルドに必要なライブラリをインストールする。<br>
# RHEL
# SUSE
sudo zypper install make gcc libtool libzip-devel zlib-devel libzstd-devel fontconfig-devel freetype2-devel libxml2-devel \
                    libdjvulibre-devel libraqm-devel liblcms2-devel pango-devel cairo-devel \
                    libjpeg8-devel libjxl-devel libjbig-devel openjpeg2-devel libheif-devel liblqr-devel \
                    libpng16-devel openexr-devel libtiff-devel libraw-devel libraw1394-devel libwebp-devel libwmf-devel
<br>
[https://imagemagick.org/script/install-source.php ImageMagickの公式Webサイト]または[https://github.com/ImageMagick/ImageMagick Github]にアクセスして、ソースコードをダウンロードする。<br>
ダウンロードしたファイルを解凍する。<br>
tar ImageMagick.tar.gz または tar xf ImageMagick-<バージョン>.tar.gz
cd ImageMagick-<バージョン>
<br>
ImageMagickをビルドおよびインストールする。<br>
mkdir build && cd build
../configure --prefix=<ImageMagickのインストールディレクトリ> \
              --with-modules
make -j $(nproc)
make install
<br>
~/.profileファイル等に、ImageMagickへの環境変数<code>PATH</code>等を追記する。<br>
vi ~/.profile
<br>
<syntaxhighlight lang="sh">
# ~/.profileファイル等
export PATH="/<ImageMagickのインストールディレクトリ>/bin:$PATH"
export LD_LIBRARY_PATH="<ImageMagickのインストールディレクトリ>/lib:$LD_LIBRARY_PATH"
</syntaxhighlight>
<br>
ImageMagickが正しく動作していることを確認する。<br>
magick logo: logo.gif
identify logo.gif
display logo.gif
<br>
ImageMagickを動作させるため、以下に示すライブラリをインストールする。<br>
# RHEL
sudo dnf install libraqm0
# SUSE
sudo zypper install libraqm0
<br><br>
<br><br>


88行目: 142行目:
  }
  }
  </syntaxhighlight>
  </syntaxhighlight>
<br><br>
== ImageMagickのインストール ==
==== パッケージ管理システムからインストール ====
# RHEL
sudo dnf install ImageMagick-devel libMagick++-devel
# SUSE
sudo zypper install ImageMagick-devel libMagick++-devel
<br>
==== ソースコードからインストール ====
<br><br>
<br><br>


118行目: 161行目:
<br>
<br>
まず、QtプロジェクトでImageMagickを使用するには、QtプロジェクトファイルまたはCMakeLists.txtファイルを使用して、必要なライブラリをリンクする必要がある。<br>
まず、QtプロジェクトでImageMagickを使用するには、QtプロジェクトファイルまたはCMakeLists.txtファイルを使用して、必要なライブラリをリンクする必要がある。<br>
また、Pkg-configを使用する場合は、ImageMagickライブラリのパスを確認する。<br>
pkg-config --modversion Magick++
pkg-config --cflags --libs Magick++
<br>
<br>
* Qtプロジェクトファイルを使用する場合
* Qtプロジェクトファイルを使用する場合
334行目: 380行目:
   
   
     return app.exec();
     return app.exec();
}
</syntaxhighlight>
<br><br>
== 画像のリサイズと形式変換 ==
<syntaxhighlight lang="c++">
#include <Magick++.h>
#include <stdexcept>
#include <filesystem>
/**
  * @brief 画像のリサイズと形式変換を行う
  * @param inputPath 入力画像のパス
  * @param outputPath 出力画像のパス
  * @param width 目標の幅
  * @param height 目標の高さ
  * @param maintainAspectRatio アスペクト比を維持するかどうか
  */
void resizeAndConvert(const std::string& inputPath,
                      const std::string& outputPath,
                      size_t width,
                      size_t height,
                      bool maintainAspectRatio = true)
{
    try {
      Magick::Image image(inputPath);
      image.resize(Magick::Geometry(width, height, 0, 0, maintainAspectRatio));
      image.quality(90);  // JPEG品質を設定
      image.write(outputPath);
    }
    catch (const Magick::Exception& e) {
      throw std::runtime_error("リサイズ処理でエラーが発生: " + std::string(e.what()));
    }
}
// 使用例
try {
    // 画像のリサイズと形式変換
    ImageUtils::resizeAndConvert("input.jpg", "output.png", 800, 600 );
}
catch (const std::exception &e) {
    std::cerr << "エラーが発生: " << e.what() << std::endl;
    return -1;
}
</syntaxhighlight>
<br><br>
== フィルタの適用 ==
<syntaxhighlight lang="c++">
#include <Magick++.h>
#include <stdexcept>
/**
  * @brief 画像に各種フィルタを適用する
  * @param inputPath 入力画像のパス
  * @param outputPath 出力画像のパス
  * @param blurRadius ぼかしの半径
  * @param sharpenRadius シャープの半径
  */
void applyFilters(const std::string& inputPath,
                  const std::string& outputPath,
                  double blurRadius = 0.0,
                  double sharpenRadius = 0.0)
{
    try {
      Magick::Image image(inputPath);
      // ノイズ除去
      image.reduceNoise();
      // ぼかし処理 (指定された場合)
      if (blurRadius > 0.0) {
          image.blur(0.0, blurRadius);
      }
      // シャープ処理 (指定された場合)
      if (sharpenRadius > 0.0) {
          image.sharpen(0.0, sharpenRadius);
      }
      // コントラスト調整
      image.normalize();
      image.write(outputPath);
    }
    catch (const Magick::Exception &e) {
        throw std::runtime_error("フィルタ処理でエラーが発生: " + std::string(e.what()));
    }
}
// 使用例
try {
    applyFilters("input.jpg", "filtered.jpg"
                2.0,  // ブラー
                1.0  // シャープ
    );
}
catch (const std::exception &e) {
    std::cerr << "エラーが発生: " << e.what() << std::endl;
    return -1;
}
</syntaxhighlight>
<br><br>
== 透かしの追加 ==
<syntaxhighlight lang="c++">
#include <Magick++.h>
#include <stdexcept>
/**
  * @brief 画像に透かしを追加する
  * @param inputPath 入力画像のパス
  * @param watermarkPath 透かし画像のパス
  * @param outputPath 出力画像のパス
  * @param opacity 透かしの不透明度(0.0-1.0)
  */
void addWatermark(const std::string& inputPath,
                  const std::string& watermarkPath,
                  const std::string& outputPath,
                  double opacity = 0.5)
{
    try {
      Magick::Image baseImage(inputPath);
      Magick::Image watermark(watermarkPath);
      // 透かしのサイズを調整 (元画像の1/4サイズにリサイズ)
      watermark.resize(Magick::Geometry(baseImage.columns() / 4, baseImage.rows() / 4));
      // 透かしの不透明度を設定
      watermark.opacity(static_cast<unsigned int>(65535 * (1.0 - opacity)));
      // 透かしを右下に配置
      baseImage.composite(watermark, baseImage.columns() - watermark.columns() - 10,
                          baseImage.rows() - watermark.rows() - 10, Magick::OverCompositeOp);
      baseImage.write(outputPath);
    }
    catch (const Magick::Exception &e) {
      throw std::runtime_error("透かし処理でエラーが発生: " + std::string(e.what()));
    }
}
// 使用例
try {
    addWatermark("input.jpg", "watermark.png",
                "watermarked.jpg",  // 透かし画像
                0.7                // 透かしのOpacity
    );
}
catch (const std::exception &e) {
    std::cerr << "エラーが発生: " << e.what() << std::endl;
    return -1;
}
</syntaxhighlight>
<br><br>
== バッチ処理 (画像の一括変換) ==
<syntaxhighlight lang="c++">
#include <Magick++.h>
#include <filesystem>
#include <vector>
#include <stdexcept>
/**
  * @brief 画像のバッチ処理(一括リサイズ)を行う
  * @param inputDir 入力ディレクトリ
  * @param outputDir 出力ディレクトリ
  * @param width 目標の幅
  * @param height 目標の高さ
  * @param extensions 処理対象の拡張子リスト
  */
void batchResize(const std::string& inputDir,
                  const std::string& outputDir,
                  size_t width,
                  size_t height,
                  const std::vector<std::string>& extensions = {".jpg", ".jpeg", ".png"})
{
    namespace fs = std::filesystem;
    try {
      // 出力ディレクトリが存在しない場合は作成
      if (!fs::exists(outputDir)) fs::create_directories(outputDir);
      // ディレクトリ内のファイルを走査
      for (const auto& entry : fs::directory_iterator(inputDir)) {
          if (!entry.is_regular_file()) continue;
          // 拡張子のチェック
          std::string ext = entry.path().extension().string();
          std::transform(ext.begin(), ext.end(), ext.begin(), ::tolower);
          if (std::find(extensions.begin(), extensions.end(), ext) != extensions.end()) {
            std::string outPath = (fs::path(outputDir) / entry.path().filename()).string();
            resizeAndConvert(entry.path().string(), outPath, width, height);
          }
      }
    }
    catch (const std::exception &e) {
      throw std::runtime_error("バッチ処理でエラーが発生: " + std::string(e.what()));
    }
}
// 使用例
try {
    // 1024x768に変換
    batchResize("input_folder", "output_folder", 1024, 768);
}
catch (const std::exception &e) {
    std::cerr << "エラーが発生: " << e.what() << std::endl;
    return -1;
}
</syntaxhighlight>
<br><br>
== 画像に効果を適用  (セピア、モノクロ等) ==
<syntaxhighlight lang="c++">
#include <Magick++.h>
#include <stdexcept>
/**
  * @brief 画像に効果を適用する(セピア、モノクロなど)
  * @param inputPath 入力画像のパス
  * @param outputPath 出力画像のパス
  * @param effectType 効果の種類(1:セピア, 2:モノクロ, 3:ネガティブ)
  */
void applyEffect(const std::string& inputPath,
                  const std::string& outputPath,
                  int effectType)
{
    try {
      Magick::Image image(inputPath);
      switch (effectType) {
          case 1: // セピア
            image.modulate(100, 50, 100);  // 彩度を下げる
            image.colorize(30, 30, 0, "rgb(112,66,20)");
            break;
          case 2: // モノクロ
            image.type(Magick::GrayscaleType);
            break;
          case 3: // ネガティブ
            image.negate();
            break;
          default:
            throw std::runtime_error("未知の効果タイプです");
            break;
      }
      image.write(outputPath);
    }
    catch (const Magick::Exception &e) {
      throw std::runtime_error("効果の適用でエラーが発生: " + std::string(e.what()));
    }
}
// 使用例
try {
    applyEffect("input.jpg", "sepia.jpg",
                1  // セピア効果
    );
}
catch (const std::exception &e) {
    std::cerr << "エラーが発生: " << e.what() << std::endl;
    return -1;
}
</syntaxhighlight>
<br><br>
== 画像形式の変換 ==
<syntaxhighlight lang="c++">
#include <Magick++.h>
#include <stdexcept>
/**
  * @brief 画像形式を変換する(例:JPG → PNG)
  * @param inputPath 入力画像のパス
  * @param outputPath 出力画像のパス(拡張子で形式を判断)
  * @param quality 出力画質(0-100)
  */
void convertFormat(const std::string& inputPath,
                    const std::string& outputPath,
                    int quality = 90)
{
    try {
      Magick::Image image(inputPath);
      image.quality(quality);
      image.write(outputPath);
    }
    catch (const Magick::Exception &e) {
      throw std::runtime_error("形式変換でエラーが発生: " + std::string(e.what()));
    }
  }
  }
  </syntaxhighlight>
  </syntaxhighlight>

2024年11月11日 (月) 20:04時点における最新版

概要

ImageMagickライブラリは、画像処理を行う場合の強力なツールである。
画像の読み込み、編集、変換、保存等、包括的な画像処理機能を提供している。

ImageMagickライブラリは200以上の画像フォーマットをサポートしており、プロフェッショナルな画像処理が可能である。

画像の変換や編集において、ぼかし、シャープ化、回転、リサイズ等の基本的な操作から高度なフィルタ処理まで実行できる。
また、画像のメタデータの読み取りや編集も可能である。

ImageMagickライブラリのパフォーマンスについて、大量の画像処理を行う場合はメモリ使用量に注意が必要となる。
必要に応じて、画像のキャッシュサイズを調整することができる。

スレッド安全性のにおいて、ImageMagickライブラリは基本的にスレッドセーフであるが、初期化処理は必ずメインスレッドで行う必要がある。

ImageMagickライブラリは高度な画像処理機能を提供する強力なツールとして活用できる。
上記の例は基本的な使用方法の一部であり、さらに多くの機能や最適化オプションが用意されている。


ImageMagickのインストール

パッケージ管理システムからインストール

# RHEL
sudo dnf install ImageMagick-devel libMagick++-devel

# SUSE
sudo zypper install ImageMagick-devel libMagick++-devel


ソースコードからインストール

まず、ImageMagickのビルドに必要なライブラリをインストールする。

# RHEL

# SUSE
sudo zypper install make gcc libtool libzip-devel zlib-devel libzstd-devel fontconfig-devel freetype2-devel libxml2-devel \
                    libdjvulibre-devel libraqm-devel liblcms2-devel pango-devel cairo-devel \
                    libjpeg8-devel libjxl-devel libjbig-devel openjpeg2-devel libheif-devel liblqr-devel \
                    libpng16-devel openexr-devel libtiff-devel libraw-devel libraw1394-devel libwebp-devel libwmf-devel


ImageMagickの公式WebサイトまたはGithubにアクセスして、ソースコードをダウンロードする。
ダウンロードしたファイルを解凍する。

tar ImageMagick.tar.gz または tar xf ImageMagick-<バージョン>.tar.gz
cd ImageMagick-<バージョン>


ImageMagickをビルドおよびインストールする。

mkdir build && cd build

../configure --prefix=<ImageMagickのインストールディレクトリ> \
             --with-modules
make -j $(nproc)
make install


~/.profileファイル等に、ImageMagickへの環境変数PATH等を追記する。

vi ~/.profile


 # ~/.profileファイル等
 
 export PATH="/<ImageMagickのインストールディレクトリ>/bin:$PATH"
 export LD_LIBRARY_PATH="<ImageMagickのインストールディレクトリ>/lib:$LD_LIBRARY_PATH"


ImageMagickが正しく動作していることを確認する。

magick logo: logo.gif
identify logo.gif
display logo.gif


ImageMagickを動作させるため、以下に示すライブラリをインストールする。

# RHEL
sudo dnf install libraqm0 

# SUSE
sudo zypper install libraqm0 



画像の読み込み

 #include <Magick++.h>
 
 // ライブラリの初期化
 Magick::InitializeMagick(nullptr);
 
 // 画像の読み込み
 Magick::Image image;
 image.read("input.jpg");



画像のサイズ変更

 #include <Magick++.h>
 
 // ライブラリの初期化
 Magick::InitializeMagick(nullptr);
 
 // 画像のリサイズ
 image.resize(Magick::Geometry(800, 600));



画像の保存

 #include <Magick++.h>
 
 // ライブラリの初期化
 Magick::InitializeMagick(nullptr);
 
 // 画像の保存
 image.write("output.png");



画質調整

JPEG画質の設定やノイズ除去等、画質に関する詳細な制御が可能である。

 #include <Magick++.h>
 
 // ライブラリの初期化
 Magick::InitializeMagick(nullptr);
 
 Magick::Image image("input.jpg");
 
 // JPEG品質を85%に設定
 image.quality(85);
 
 image.write("output.jpg");



エラーハンドリング

ImageMagickライブラリは、専用の例外処理を使用してエラーを処理する。

 
 #include <Magick++.h>
 
 // ライブラリの初期化
 Magick::InitializeMagick(nullptr);
 
 try {
    Magick::Image image;
    image.read("nonexistent.jpg");
 }
 catch (Magick::Exception &error) {
    qDebug() << "エラー: " << QString::fromStdString(error.what());
 }



基本的な使用例

以下の例では、ImageMagickライブラリを使用して、画像処理 (ノイズ除去、コントラスト調整、シャープネス強調、カラーバランス調整) を行っている。

  • 非同期処理
    QtConcurrentクラスを使用して画像処理を非同期で実行する。(メインスレッドをブロックせずに実行)
    QFutureWatcherクラスを使用して、処理の完了を監視する。
    シグナル / スロットによる非同期通信を行う。

  • ストリーミング処理
    画像処理をパイプライン形式で実装する。
    進捗状況をリアルタイムで通知する。
    段階的な画像処理を行う。(ノイズ除去、コントラスト調整等)

  • その他の機能
    スマートポインタを使用したメモリ管理


まず、QtプロジェクトでImageMagickを使用するには、QtプロジェクトファイルまたはCMakeLists.txtファイルを使用して、必要なライブラリをリンクする必要がある。
また、Pkg-configを使用する場合は、ImageMagickライブラリのパスを確認する。

pkg-config --modversion Magick++
pkg-config --cflags --libs Magick++


  • Qtプロジェクトファイルを使用する場合
 # pkg-configを使用
 CONFIG    += link_pkgconfig
 PKGCONFIG += Magick++ ImageMagick
 
 # より詳細な設定が必要な場合は、特定のバージョンを指定することもできる
 # ImageMagick 7を使用する場合
 CONFIG    += link_pkgconfig
 PKGCONFIG += Magick++-7.Q16HDRI
  • CMakeLists.txtファイルを使用する場合
 # CMakeLists.txtファイル
 
 # Qt 5 または Qt 6コンポーネントを検索
 find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Core Concurrent)
 find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Core Concurrent)
 
 if(NOT Qt${QT_VERSION_MAJOR}_FOUND)
    find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Core Concurrent)
 endif()
 
 pkg_check_modules(QT_CORE Qt${QT_VERSION_MAJOR}Core REQUIRED IMPORTED_TARGET)
 pkg_check_modules(QT_CORE Qt${QT_VERSION_MAJOR}Concurrent REQUIRED IMPORTED_TARGET)
 
 # ImageMagick++を検索
 find_package(ImageMagick REQUIRED COMPONENTS Magick++)
 if(NOT ImageMagick_FOUND)
    message(FATAL_ERROR "ImageMagick++が見つかりません")
 endif()
 
 # インクルードディレクトリを設定
 target_include_directories(${PROJECT_NAME} PRIVATE
    # ...略
    ${ImageMagick_INCLUDE_DIRS}
 )
 
 # 各ライブラリをリンク
 target_link_libraries(${PROJECT_NAME} PRIVATE
    Qt${QT_VERSION_MAJOR}::Core
    Qt${QT_VERSION_MAJOR}::Concurrent
    ${ImageMagick_LIBRARIES}
 )


 // ImageProcessor.hファイル
 
 #include <QObject>
 #include <QFile>
 #include <QFuture>
 #include <QFutureWatcher>
 #include <QtConcurrent>
 #include <memory>
 #include <stdexcept>
 #include <Magick++.h>
 #include <QDebug>
 
 class ImageProcessor : public QObject
 {
    Q_OBJECT
 
 
 private:
    std::unique_ptr<QFutureWatcher<void>> m_futureWatcher;
 
    // 画像処理の実装
    void processImage(const QString& inputPath, const QString& outputPath)
    {
       try {
          // ImageMagickの初期化
          Magick::InitializeMagick(nullptr);
 
          // 画像の読み込み
          Magick::Image image;
          image.read(inputPath.toStdString());
 
          // ストリーミング処理の実行
          processImageStream(image);
 
          // 画像の保存
          image.write(outputPath.toStdString());
 
          emit progressUpdated(100);
       }
       catch (const Magick::Exception &e) {
          throw std::runtime_error(QString("ImageMagick処理エラー: %1").arg(e.what()).toStdString());
       }
       catch (const std::exception &e) {
          throw std::runtime_error(QString("一般エラー: %1").arg(e.what()).toStdString());
       }
    }
 
    // ストリーミング処理の実装
    void processImageStream(Magick::Image& image)
    {
       try {
          // 画像処理のパイプライン
          // 1. ノイズ除去
          image.reduceNoise();
          emit progressUpdated(25);
 
          // 2. コントラスト調整
          image.normalize();
          emit progressUpdated(50);
 
          // 3. シャープネス強調
          image.sharpen(0, 1.0);
          emit progressUpdated(75);
 
          // 4. カラーバランス調整
          image.modulate(100, 100, 100);
          emit progressUpdated(90);
       }
       catch (Magick::Exception &e) {
          qDebug() << "エラー: " << QString::fromStdString(e.what());
       }
       catch (const Magick::Exception &e) {
          throw std::runtime_error(QString("ストリーム処理エラー: %1").arg(e.what()).toStdString());
       }
    }
 
 public:
    explicit ImageProcessor(QObject* parent = nullptr) : QObject(parent), m_futureWatcher(std::make_unique<QFutureWatcher<void>>())
    {
       // 非同期処理完了時のシグナルとスロットを接続
       connect(m_futureWatcher.get(), &QFutureWatcher<void>::finished, this, &ImageProcessor::handleProcessingFinished);
    }
 
    ~ImageProcessor() = default;
 
    // 画像処理を開始する
    void processImageAsync(const QString& inputPath, const QString& outputPath)
    {
       try {
          // 入力ファイルの存在確認
          if (!QFile::exists(inputPath)) {
             emit errorOccurred("入力ファイルが存在しない: " + inputPath);
             return;
          }
 
          // 非同期処理を開始
          QFuture<void> future = QtConcurrent::run([this, inputPath, outputPath]() {
             try {
                processImage(inputPath, outputPath);
             }
             catch (const std::exception& e) {
                // 非同期処理内でのエラーをメインスレッドに通知
                QMetaObject::invokeMethod(this, "errorOccurred", Qt::QueuedConnection, Q_ARG(QString, QString("画像処理エラー: %1").arg(e.what())));
             }
          });
 
          m_futureWatcher->setFuture(future);
       }
       catch (const std::exception &e) {
          emit errorOccurred(QString("非同期処理の開始に失敗: %1").arg(e.what()));
       }
    }
 
 signals:
    void progressUpdated(int percentage);      // 進捗状況を通知するシグナル
    void processingCompleted();                // 処理完了を通知するシグナル
    void errorOccurred(const QString& error);  // エラーを通知するシグナル
 
 private slots:
    // 非同期処理完了時のスロット
    void handleProcessingFinished()
    {
       try {
          // 非同期処理の結果を確認
          m_futureWatcher->result();
          emit processingCompleted();
       }
       catch (const std::exception& e) {
          emit errorOccurred(QString("処理完了時のエラー: %1").arg(e.what()));
       }
    }
 };


 // main.cppファイル
 
 #include <QCoreApplication>
 #include "ImageProcessor.h"
 
 int main(int argc, char *argv[])
 {
    QCoreApplication app(argc, argv);
 
    ImageProcessor processor;
 
    // 進捗処理シグナルの接続
    QObject::connect(&processor, &ImageProcessor::progressUpdated, [](int percentage) {
       qDebug() << "進捗: " << percentage << "%";
    });
 
    // 処理完了シグナルの接続
    QObject::connect(&processor, &ImageProcessor::processingCompleted, []() {
       qDebug() << "処理が完了しました";
       QCoreApplication::quit();
    });
 
    // エラーシグナルの接続
    QObject::connect(&processor, &ImageProcessor::errorOccurred, [](const QString& error) {
       qDebug() << "エラー: " << error;
       QCoreApplication::quit();
    });
 
    // 画像処理の開始
    processor.processImageAsync("input.jpg", "output.jpg");
 
    return app.exec();
 }



画像のリサイズと形式変換

 #include <Magick++.h>
 #include <stdexcept>
 #include <filesystem>
 
 /**
  * @brief 画像のリサイズと形式変換を行う
  * @param inputPath 入力画像のパス
  * @param outputPath 出力画像のパス
  * @param width 目標の幅
  * @param height 目標の高さ
  * @param maintainAspectRatio アスペクト比を維持するかどうか
  */
 void resizeAndConvert(const std::string& inputPath, 
                      const std::string& outputPath,
                      size_t width, 
                      size_t height,
                      bool maintainAspectRatio = true)
 {
    try {
       Magick::Image image(inputPath);
       image.resize(Magick::Geometry(width, height, 0, 0, maintainAspectRatio));
       image.quality(90);  // JPEG品質を設定
       image.write(outputPath);
    }
    catch (const Magick::Exception& e) {
       throw std::runtime_error("リサイズ処理でエラーが発生: " + std::string(e.what()));
    }
 }
 
 // 使用例
 try {
    // 画像のリサイズと形式変換
    ImageUtils::resizeAndConvert("input.jpg", "output.png", 800, 600 );
 }
 catch (const std::exception &e) {
    std::cerr << "エラーが発生: " << e.what() << std::endl;
    return -1;
 }



フィルタの適用

 #include <Magick++.h>
 #include <stdexcept>
 
 /**
  * @brief 画像に各種フィルタを適用する
  * @param inputPath 入力画像のパス
  * @param outputPath 出力画像のパス
  * @param blurRadius ぼかしの半径
  * @param sharpenRadius シャープの半径
  */
 void applyFilters(const std::string& inputPath,
                   const std::string& outputPath,
                   double blurRadius = 0.0,
                   double sharpenRadius = 0.0)
 {
    try {
       Magick::Image image(inputPath);
 
       // ノイズ除去
       image.reduceNoise();
 
       // ぼかし処理 (指定された場合)
       if (blurRadius > 0.0) {
          image.blur(0.0, blurRadius);
       }
 
       // シャープ処理 (指定された場合)
       if (sharpenRadius > 0.0) {
          image.sharpen(0.0, sharpenRadius);
       }
 
       // コントラスト調整
       image.normalize();
 
       image.write(outputPath);
    }
    catch (const Magick::Exception &e) {
        throw std::runtime_error("フィルタ処理でエラーが発生: " + std::string(e.what()));
    }
 }
 
 // 使用例
 try {
    applyFilters("input.jpg", "filtered.jpg"
                 2.0,  // ブラー
                 1.0   // シャープ
    );
 }
 catch (const std::exception &e) {
    std::cerr << "エラーが発生: " << e.what() << std::endl;
    return -1;
 }



透かしの追加

 #include <Magick++.h>
 #include <stdexcept>
 
 /**
  * @brief 画像に透かしを追加する
  * @param inputPath 入力画像のパス
  * @param watermarkPath 透かし画像のパス
  * @param outputPath 出力画像のパス
  * @param opacity 透かしの不透明度(0.0-1.0)
  */
 void addWatermark(const std::string& inputPath,
                   const std::string& watermarkPath,
                   const std::string& outputPath,
                   double opacity = 0.5)
 {
    try {
       Magick::Image baseImage(inputPath);
       Magick::Image watermark(watermarkPath);
 
       // 透かしのサイズを調整 (元画像の1/4サイズにリサイズ)
       watermark.resize(Magick::Geometry(baseImage.columns() / 4, baseImage.rows() / 4));
 
       // 透かしの不透明度を設定
       watermark.opacity(static_cast<unsigned int>(65535 * (1.0 - opacity)));
 
       // 透かしを右下に配置
       baseImage.composite(watermark, baseImage.columns() - watermark.columns() - 10,
                           baseImage.rows() - watermark.rows() - 10, Magick::OverCompositeOp);
 
       baseImage.write(outputPath);
    }
    catch (const Magick::Exception &e) {
       throw std::runtime_error("透かし処理でエラーが発生: " + std::string(e.what()));
    }
 }
 
 // 使用例
 try {
    addWatermark("input.jpg", "watermark.png",
                 "watermarked.jpg",  // 透かし画像
                 0.7                 // 透かしのOpacity
    );
 }
 catch (const std::exception &e) {
    std::cerr << "エラーが発生: " << e.what() << std::endl;
    return -1;
 }



バッチ処理 (画像の一括変換)

 #include <Magick++.h>
 #include <filesystem>
 #include <vector>
 #include <stdexcept>
 
 /**
  * @brief 画像のバッチ処理(一括リサイズ)を行う
  * @param inputDir 入力ディレクトリ
  * @param outputDir 出力ディレクトリ
  * @param width 目標の幅
  * @param height 目標の高さ
  * @param extensions 処理対象の拡張子リスト
  */
 void batchResize(const std::string& inputDir,
                  const std::string& outputDir,
                  size_t width,
                  size_t height,
                  const std::vector<std::string>& extensions = {".jpg", ".jpeg", ".png"})
 {
    namespace fs = std::filesystem;
 
    try {
       // 出力ディレクトリが存在しない場合は作成
       if (!fs::exists(outputDir)) fs::create_directories(outputDir);
 
       // ディレクトリ内のファイルを走査
       for (const auto& entry : fs::directory_iterator(inputDir)) {
          if (!entry.is_regular_file()) continue;
 
          // 拡張子のチェック
          std::string ext = entry.path().extension().string();
          std::transform(ext.begin(), ext.end(), ext.begin(), ::tolower);
 
          if (std::find(extensions.begin(), extensions.end(), ext) != extensions.end()) {
             std::string outPath = (fs::path(outputDir) / entry.path().filename()).string();
             resizeAndConvert(entry.path().string(), outPath, width, height);
          }
       }
    }
    catch (const std::exception &e) {
       throw std::runtime_error("バッチ処理でエラーが発生: " + std::string(e.what()));
    }
 }
 
 // 使用例
 try {
    // 1024x768に変換
    batchResize("input_folder", "output_folder", 1024, 768);
 }
 catch (const std::exception &e) {
    std::cerr << "エラーが発生: " << e.what() << std::endl;
    return -1;
 }



画像に効果を適用 (セピア、モノクロ等)

 #include <Magick++.h>
 #include <stdexcept>
 
 /**
  * @brief 画像に効果を適用する(セピア、モノクロなど)
  * @param inputPath 入力画像のパス
  * @param outputPath 出力画像のパス
  * @param effectType 効果の種類(1:セピア, 2:モノクロ, 3:ネガティブ)
  */
 void applyEffect(const std::string& inputPath,
                  const std::string& outputPath,
                  int effectType)
 {
    try {
       Magick::Image image(inputPath);
 
       switch (effectType) {
          case 1: // セピア
             image.modulate(100, 50, 100);  // 彩度を下げる
             image.colorize(30, 30, 0, "rgb(112,66,20)");
             break;
          case 2: // モノクロ
             image.type(Magick::GrayscaleType);
             break;
          case 3: // ネガティブ
             image.negate();
             break;
          default:
             throw std::runtime_error("未知の効果タイプです");
             break;
       }
 
       image.write(outputPath);
    }
    catch (const Magick::Exception &e) {
       throw std::runtime_error("効果の適用でエラーが発生: " + std::string(e.what()));
    }
 }
 
 // 使用例
 try {
    applyEffect("input.jpg", "sepia.jpg",
                1  // セピア効果
    );
 }
 catch (const std::exception &e) {
    std::cerr << "エラーが発生: " << e.what() << std::endl;
    return -1;
 }



画像形式の変換

 #include <Magick++.h>
 #include <stdexcept>
 
 /**
  * @brief 画像形式を変換する(例:JPG → PNG)
  * @param inputPath 入力画像のパス
  * @param outputPath 出力画像のパス(拡張子で形式を判断)
  * @param quality 出力画質(0-100)
  */
 void convertFormat(const std::string& inputPath,
                    const std::string& outputPath,
                    int quality = 90)
 {
    try {
       Magick::Image image(inputPath);
       image.quality(quality);
       image.write(outputPath);
    }
    catch (const Magick::Exception &e) {
       throw std::runtime_error("形式変換でエラーが発生: " + std::string(e.what()));
    }
 }