画像のサイズ変更

概要

この記事では、GDI+ を利用して画像 (ファイル) のサイズ変更を行う方法を紹介します。言語は C++ を使います。

GDI+ の利用

GDI+ は従来の GDI と異なり、便利なクラスライブラリとして提供されています。C# などからも簡単に利用可能であるために、.NET Framework の一部と思われがちですが、実際には独立しており、ネイティブコードとして実行されます。C# での情報は比較的たくさんあるでしょうから、ここでは C++ を使ったコードサンプルを示します。

下記のコードは C:\foo.jpg を 207x156 のサイズに変換して C:\foo_s_80.jpg という名前で保存します。フォーマットは JPEG で、画像品質は 80 としています。品質の最大値は 100 です。


#include <windows.h>
#include <stdio.h>
#include <gdiplus.h>
using namespace Gdiplus;


// 戻り値
//     成功時 - GetImageEncoders が返す配列のインデックス
//     失敗時 - -1

int GetEncoderClsid(const WCHAR* format, CLSID* pClsid) {

    UINT  num = 0;
    UINT  size = 0;

    ImageCodecInfo* pImageCodecInfo = NULL;

    GetImageEncodersSize(&num, &size);
    if(size == 0) {
        return -1; // 失敗 - GetImageEncodersSize 失敗
    }

    pImageCodecInfo = (ImageCodecInfo*)(malloc(size));
    if(pImageCodecInfo == NULL) {
        return -1; // 失敗 - メモリ割り当て不可
    }

    GetImageEncoders(num, size, pImageCodecInfo);

    for(UINT j = 0; j < num; ++j) {
        if( wcscmp(pImageCodecInfo[j].MimeType, format) == 0 ) {
            *pClsid = pImageCodecInfo[j].Clsid;
            free(pImageCodecInfo);
            return j;  // 成功
        }  
    }

    free(pImageCodecInfo);

    return -1;  // 失敗 - 要求した種類のエンコーダが存在しなかった
}


int main() { 

    // GDI+ の初期化
    GdiplusStartupInput gdiplusStartupInput;
    ULONG_PTR gdiplusToken;
    GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

    // 原画像から Image オブジェクトを作成する
    Image* pImgOrg = Image::FromFile ( L"C:\\foo.jpg");

    // これから作成する画像用に Bitmap オブジェクトを作成
    Bitmap* pBitmap = new Bitmap ( 207, 156 );

    // Bitmap オブジェクトから Graphics オブジェクトを作成する
    // ここで作成した Bitmap オブジェクトに描画し、それを保存する。
    Graphics* pGrfx = Graphics::FromImage ( pBitmap );

    // ターゲットとなる矩形を Rect オブジェクトで表現しておく
    // ここでは 207x156 (px) の矩形
    Gdiplus::Rect rectDist ( 0, 0, 207, 156);

    // 原画像の全体を rectDist で表した矩形領域へ写像する。
    // "原画像の全体" は第3引数~第6引数で表している。原画像の一部をクリップするなら
    // ここでクリップしたい領域を指定する。
    pGrfx->DrawImage (
        pImgOrg,
        rectDist,
        0, 0, pImgOrg->GetWidth (), pImgOrg->GetHeight (),
        UnitPixel);

    //
    // Bitmap の保存
    //

    // エンコーダの CLSID 取得
    // ここでは JPEG 画像を指定している. もし GIF ならば GetEncoderClsid の
    // 第一引数に L"image/gif" を渡す。
 
   CLSID     encoderClsid;
    if ( -1 == GetEncoderClsid(L"image/jpeg", &encoderClsid) ) {
        return FALSE;
    }

    // 品質指定
    LONG lQuality = 80;
 
    EncoderParameters EncoderParams; 
    EncoderParams.Parameter[0].Guid = EncoderQuality;
    EncoderParams.Parameter[0].NumberOfValues = 1;
    EncoderParams.Parameter[0].Type = EncoderParameterValueTypeLong;
    EncoderParams.Parameter[0].Value = (VOID*) &lQuality;
    EncoderParams.Count = 1;

    // Bitmap オブジェクトをファイルに保存。
    pBitmap->Save ( L"C:\\foo_s_80.jpg" , &encoderClsid, &EncoderParams );

    //
    // クリーンアップ
    //

    delete pImgOrg;
    delete pBitmap;
 
    GdiplusShutdown(gdiplusToken);

    return TRUE;
}

サンプルコードのダウンロード [VC++ 2003 プロジェクト, resize.zip]

ここまでお読みいただき、誠にありがとうございます。SNS 等でこの記事をシェアしていただけますと、大変励みになります。どうぞよろしくお願いします。

© 2024 Web/DB プログラミング徹底解説