Share via


JPEG 画像のロスレス変換

JPEG 画像を圧縮すると、画像内の情報の一部が失われます。 JPEG ファイルを開き、画像を変更し、別の JPEG ファイルに保存すると、品質が低下します。 そのプロセスを何度も繰り返すと、画質が大幅に低下します。

JPEG は Web 上で最も一般的な画像形式の 1 つであり、多くの場合、JPEG 画像を変更することが好きであるため、GDI+ は、情報を失うことなく JPEG 画像に対して実行できる次の変換を提供します。

  • 90 度回転
  • 180 度回転
  • 270 度回転
  • 左右反転
  • 上下反転

Image オブジェクトの Save メソッドを呼び出すときに、前の一覧に示した変換のいずれかを適用できます。 次の条件が満たされると、情報を失うことなく変換が続行されます。

  • Image オブジェクトの構築に使用されるファイルは JPEG ファイルです。
  • 画像の幅と高さはどちらも 16 の倍数です。

イメージの幅と高さが両方とも 16 の倍数でない場合、GDI+ は、前の一覧に示した回転変換または反転変換のいずれかを適用するときに、画質を維持するために最善を尽くします。

JPEG イメージを変換するには、EncoderParameters オブジェクトを初期化し、そのオブジェクトのアドレスを Image クラスの Save メソッドに渡します。 EncoderParameters オブジェクトを初期化して、1 つの EncoderParameter オブジェクトで構成される配列を作成します。 1 つの EncoderParameter オブジェクトを初期化し、その Value メンバーが EncoderValue 列挙体の次のいずれかの要素を保持する ULONG 変数を指すようにします。

  • EncoderValueTransformRotate90,
  • EncoderValueTransformRotate180,
  • EncoderValueTransformRotate270,
  • EncoderValueTransformFlipHorizontal、
  • EncoderValueTransformFlipVertical

EncoderParameter オブジェクトの Guid メンバーを EncoderTransformation に設定します。

次のコンソール アプリケーションでは、JPEG ファイルから Image オブジェクトを作成し、そのイメージを新しいファイルに保存します。 保存処理中に、画像は 90 度回転します。 画像の幅と高さが両方とも 16 の倍数である場合、画像を回転および保存するプロセスによって情報が失われる可能性はありません。

メイン関数は、ヘルパー関数 GetEncoderClsid に依存しています。これは、「エンコーダーのクラス識別子の取得」に示されています。

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

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

INT main()
{
   // Initialize GDI+.
   GdiplusStartupInput gdiplusStartupInput;
   ULONG_PTR gdiplusToken;
   GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

   CLSID             encoderClsid;
   EncoderParameters encoderParameters;
   ULONG             transformation;
   UINT              width;
   UINT              height;
   Status            stat;

   // Get a JPEG image from the disk.
   Image* image = new Image(L"Shapes.jpg");

   // Determine whether the width and height of the image 
   // are multiples of 16.
   width = image->GetWidth();
   height = image->GetHeight();

   printf("The width of the image is %u", width);
   if(width / 16.0 - width / 16 == 0)
      printf(", which is a multiple of 16.\n");
   else
      printf(", which is not a multiple of 16.\n");

   printf("The height of the image is %u", height);
   if(height / 16.0 - height / 16 == 0)
      printf(", which is a multiple of 16.\n");
   else
      printf(", which is not a multiple of 16.\n");

   // Get the CLSID of the JPEG encoder.
   GetEncoderClsid(L"image/jpeg", &encoderClsid);

   // Before we call Image::Save, we must initialize an
   // EncoderParameters object. The EncoderParameters object
   // has an array of EncoderParameter objects. In this
   // case, there is only one EncoderParameter object in the array.
   // The one EncoderParameter object has an array of values.
   // In this case, there is only one value (of type ULONG)
   // in the array. We will set that value to EncoderValueTransformRotate90.

   encoderParameters.Count = 1;
   encoderParameters.Parameter[0].Guid = EncoderTransformation;
   encoderParameters.Parameter[0].Type = EncoderParameterValueTypeLong;
   encoderParameters.Parameter[0].NumberOfValues = 1;

   // Rotate and save the image.
   transformation = EncoderValueTransformRotate90;
   encoderParameters.Parameter[0].Value = &transformation;
   stat = image->Save(L"ShapesR90.jpg", &encoderClsid, &encoderParameters);

   if(stat == Ok)
      wprintf(L"%s saved successfully.\n", L"ShapesR90.jpg");
   else
      wprintf(L"%d  Attempt to save %s failed.\n", stat, L"ShapesR90.jpg");

   delete image;
   GdiplusShutdown(gdiplusToken);
   return 0;
}