다음을 통해 공유


JPEG 이미지의 무손실 변형

JPEG 이미지를 압축하면 이미지의 일부 정보가 손실됩니다. JPEG 파일을 열고, 이미지를 변경하고, 다른 JPEG 파일에 저장하면 품질이 저하됩니다. 이 프로세스를 여러 번 반복하면 이미지 품질이 크게 저하됩니다.

JPEG는 웹에서 가장 인기 있는 이미지 형식 중 하나이며 사람들이 JPEG 이미지를 수정하는 것을 좋아하기 때문에 GDI+는 정보 손실 없이 JPEG 이미지에서 수행할 수 있는 다음과 같은 변환을 제공합니다.

  • 90도 회전
  • 180도 회전
  • 270도 회전
  • 가로로 대칭 이동
  • 세로로 대칭 이동

Image 개체의 Save 메서드를 호출할 때 이전 목록에 표시된 변환 중 하나를 적용할 수 있습니다. 다음 조건이 충족되면 정보가 손실되지 않고 변환이 진행됩니다.

  • Image 개체를 생성하는 데 사용되는 파일은 JPEG 파일입니다.
  • 이미지의 너비와 높이는 모두 16의 배수입니다.

이미지의 너비와 높이가 모두 16의 배수가 아닌 경우 GDI+는 이전 목록에 표시된 회전 또는 대칭 이동 변환 중 하나를 적용할 때 이미지 품질을 유지하기 위해 최선을 다합니다.

JPEG 이미지를 변환하려면 EncoderParameters 개체를 초기화하고 해당 개체의 주소를 Image 클래스의 Save 메서드에 전달합니다. EncoderParameters 개체를 초기화하여 하나의 EncoderParameter 개체로 구성된 배열이 있도록 합니다. 해당 Value 멤버가 EncoderValue 열거형의 다음 요소 중 하나를 포함하는 ULONG 변수를 가리키도록 EncoderParameter 개체를 초기화합니다.

  • 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;
}