JPG/TIFF/BMPなどの画像の形式などを変換

Win32 API を使用して、BMPからJPGなどの変換を行う処理です。
今回は、GDI+というものを使用します。

簡単に流れを解説すると
・画像を読み込む
・保存時のエンコード(形式)を指定する
・保存時のパラメータを設定(ここで縮小や回転などいろいろ設定)
・保存

なのですが、保存時のパラメータは複数設定できるようになっているのですが、自分が試した範囲では、JPGのクオリティと回転は同時に効きませんでした。
あとは、JPG→JPGの場合は回転できましたが、BMP→JPGの時は回転できませんでした。
いろいろサイトを見ていると結構制限があるような感じでした。
今回のサンプルは、MSDNのここの情報を参考に作ってます。
あと、GetEncoderClsid()という関数がありますが、これは、MSDNのコチラから拾ってきた関数です。↑のサンプルで使用しているのに含まれていない不親切さ。

で、サンプルは続きで。
必要なライブラリ:gdiplus.lib

#include <windows.h>
#include <stdio.h>
#include <tchar.h>

//GDI+で必要
#include <shlobj.h>
#include <gdiplus.h>
#include <Gdiplusinit.h>


using namespace Gdiplus;

// helper function
INT GetEncoderClsid(const WCHAR* format, CLSID* pClsid);


int _tmain(int argc, _TCHAR* argv[])
{
//GDI+の初期化
GdiplusStartupInput gdiplusStartupInput;
ULONG_PTR gdiplusToken;
GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

CLSID encoderClsid;
//1つしかパラメータを指定しない場合はこちら
//EncoderParameters encoderParameters;
//複数のパラメータを指定する場合はこちら
EncoderParameters* encoderParameters = (EncoderParameters*)malloc(sizeof(EncoderParameters) + 4 * sizeof(EncoderParameter));
ULONG colordepth;
ULONG quality;
ULONG transformation;
Status stat;

// ファイルを指定してオブジェクトを作成.
Image* image = new Image(TEXT("c:\\test.bmp"));


//画像のフォーマット
GUID guid;
image->GetRawFormat(&guid);
if(guid == ImageFormatUndefined) printf("Format : Undefined(0x%x)\n",guid);
else if(guid == ImageFormatMemoryBMP) printf("Format : MemoryBMP(0x%x)\n",guid);
else if(guid == ImageFormatBMP) printf("Format : BMP(0x%x)\n",guid);
else if(guid == ImageFormatJPEG) printf("Format : JPEG(0x%x)\n",guid);
else if(guid == ImageFormatPNG) printf("Format : PNG(0x%x)\n",guid);
else if(guid == ImageFormatGIF) printf("Format : GIF(0x%x)\n",guid);
else if(guid == ImageFormatTIFF) printf("Format : TIFF(0x%x)\n",guid);
else printf("Format : Error(0x%x)\n",guid);

//サイズ
UINT width = image->GetWidth();
UINT height = image->GetHeight();
printf("Width : %u\n", width);
printf("Height: %u\n", height);

//解像度
REAL res_hori = image->GetHorizontalResolution();
REAL res_ver = image->GetVerticalResolution();
printf("HorizontalResolution : %d\n", res_hori);
printf("GetVerticalResolution: %d\n", res_ver);

//ファイルタイプ
ImageType type = image->GetType();
switch(type){
case ImageTypeUnknown: printf("ImageType : ImageTypeUnknown(%d)\n",type); break;
case ImageTypeBitmap: printf("ImageType : ImageTypeBitmap(%d)\n",type); break;
case ImageTypeMetafile: printf("ImageType : ImageTypeMetafile(%d)\n",type); break;
default: printf("ImageType : Error(%d)\n",type); break;
}

//カラーフォーマット
PixelFormat pixelFormat = image->GetPixelFormat();
switch(pixelFormat){
case PixelFormat8bppIndexed: printf("PixelFormat : 8bppIndexed(0x%x)\n",pixelFormat); break;
case PixelFormat16bppRGB555: printf("PixelFormat : 16bppRGB555(0x%x)\n",pixelFormat); break;
case PixelFormat16bppRGB565: printf("PixelFormat : 16bppRGB565(0x%x)\n",pixelFormat); break;
case PixelFormat24bppRGB: printf("PixelFormat : 24bppRGB(0x%x)\n",pixelFormat); break;
case PixelFormat32bppRGB: printf("PixelFormat : 32bppRGB(0x%x)\n",pixelFormat); break;
case PixelFormat32bppARGB: printf("PixelFormat : 32bppARGB(0x%x)\n",pixelFormat); break;
default: printf("PixelFormat : Othre(0x%x)\n",pixelFormat); break;
}


//保存するときのエンコーダをJPGに設定
GetEncoderClsid(L"image/jpeg", &encoderClsid);


//パラメータの数を指定
encoderParameters->Count = 3;
//色深度
encoderParameters->Parameter[2].Guid = EncoderColorDepth;
encoderParameters->Parameter[2].Type = EncoderParameterValueTypeLong;
encoderParameters->Parameter[2].NumberOfValues = 1;
colordepth = 24;
encoderParameters->Parameter[2].Value = &colordepth;
//クオリティの設定
encoderParameters->Parameter[1].Guid = EncoderQuality;
encoderParameters->Parameter[1].Type = EncoderParameterValueTypeLong;
encoderParameters->Parameter[1].NumberOfValues = 1;
quality = 80; //0~100
encoderParameters->Parameter[1].Value = &quality;
//回転の設定
encoderParameters->Parameter[0].Guid = EncoderTransformation;
encoderParameters->Parameter[0].Type = EncoderParameterValueTypeLong;
encoderParameters->Parameter[0].NumberOfValues = 1;
transformation = EncoderValueTransformRotate90;
encoderParameters->Parameter[0].Value = &transformation;


//各種処理をして保存
stat = image->Save(TEXT("c:\\testFromBMP.jpg"), &encoderClsid, encoderParameters);

//結果
if(stat == Ok){
wprintf(TEXT("成功\n"));
}else{
wprintf(TEXT("失敗(0x%x)\n"), stat);
}

//オブジェクトの破棄
delete image;

//GDI+の終了処理
GdiplusShutdown(gdiplusToken);


//一時停止
getchar();

return 0;
}



int GetEncoderClsid(const WCHAR* format, CLSID* pClsid)
{
UINT num = 0; // number of image encoders
UINT size = 0; // size of the image encoder array in bytes

ImageCodecInfo* pImageCodecInfo = NULL;

GetImageEncodersSize(&num, &size);
if(size == 0)
return -1; // Failure

pImageCodecInfo = (ImageCodecInfo*)(malloc(size));
if(pImageCodecInfo == NULL)
return -1; // Failure

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; // Success
}
}

free(pImageCodecInfo);
return -1; // Failure
}