• Welcome to Jose's Read Only Forum 2023.
 

GDI+: GdipSaveImageToFile

Started by José Roca, June 23, 2008, 03:07:44 AM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

José Roca

 
Transforming a JPEG Image Without Loss of Information



When you compress a JPEG image, some of the information in the image is lost. If you open a JPEG file, alter the image, and save it to another JPEG file, the quality will decrease. If you repeat that process many times, you will see a substantial degradation in the image quality.

Because JPEG is one of the most popular image formats on the Web, and because people often like to modify JPEG images, GDI+ provides the following transformations that can be performed on JPEG images without loss of information:

    * Rotate 90 degrees
    * Rotate 180 degrees
    * Rotate 270 degrees
    * Flip horizontally
    * Flip vertically

You can apply one of the transformations shown in the preceding list when you call the GdipSaveImageToFile. If the following conditions are met, then the transformation will  proceed without loss of information:

    * The file used to construct the Image object is a JPEG file.
    * The width and height of the image are both multiples of 16.

If the width and height of the image are not both multiples of 16, GDI+ will do its best to preserve the image quality when you apply one of the rotation or flipping transformations shown in the preceding list.

To transform a JPEG image, initialize an EncoderParameters structure and pass the address of that object to the GdipSaveImageToFile function. Initialize the EncoderParameters structure so that it has an array that consists of one EncoderParameter structure.

Initialize that one EncoderParameter structure so that its Value member points to a DWORD variable that holds one of the following elements of the EncoderValue enumeration:

    * EncoderValueTransformRotate90,
    * EncoderValueTransformRotate180,
    * EncoderValueTransformRotate270,
    * EncoderValueTransformFlipHorizontal,
    * EncoderValueTransformFlipVertical

Set the Guid member of the EncoderParameter structure to $EncoderTransformation.

The following console application creates an Image object from a JPEG file and then saves the image to a new file. During the save process, the image is rotated 90 degrees. If the width and height of the image are both multiples of 16, the process of rotating and saving the image causes no loss of information.

C++


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


PowerBASIC

The main function relies on the helper function GdiPlusGetEncoderClsid to retrieve the guid of the TIFF encoder.


#COMPILE EXE
#DIM ALL
#INCLUDE "GDIPLUS.INC"
#INCLUDE "GDIPUTILS.INC"

' ========================================================================================
' Main
' ========================================================================================
FUNCTION PBMAIN

   LOCAL hStatus AS LONG
   LOCAL token AS DWORD
   LOCAL StartupInput AS GdiplusStartupInput
   LOCAL EncoderClsid AS GUID
   LOCAL pImage AS DWORD
   LOCAL eps AS EncoderParameters
   LOCAL ep AS EncoderParameter
   LOCAL nWidth AS DWORD
   LOCAL nHeight AS DWORD
   LOCAL transformation AS DWORD
   LOCAL strFileName AS STRING

   ' // Initialize GDI+
   StartupInput.GdiplusVersion = 1
   hStatus = GdiplusStartup(token, StartupInput, BYVAL %NULL)
   IF hStatus THEN
      PRINT "Error initializing GDI+"
      EXIT FUNCTION
   END IF

   strFileName = UCODE$("Shapes.jpg")
   hStatus = GdipLoadImageFromFile(STRPTR(strFileName), pImage)

   ' // Determine whether the width and height of the image are multiples of 16.
   hStatus = GdipGetImageWidth(pImage, nWidth)
   hStatus = GdipGetImageHeight(pImage, nHeight)

   PRINT "The width of the image is" & STR$(nWidth)
   IF (nWidth / 16 - nWidth \ 16) = 0 THEN
      PRINT "which is a multiple of 16."
   ELSE
      PRINT "which is not a multiple of 16."
   END IF

   PRINT "The height of the image is" & STR$(nHeight)
   IF (nHeight / 16 - nHeight \ 16) = 0 THEN
      PRINT "which is a multiple of 16."
   ELSE
      PRINT "which is not a multiple of 16."
   END IF

   ' // Get the CLSID of the JPEG encoder.
   EncoderClsid = GUID$(GdiPlusGetEncoderClsid("image/jpeg"))

   ' // Before we call GdipSaveImageToFile, we must initialize an
   ' // EncoderParameters structure The EncoderParameters structure
   ' // has an array of EncoderParameter structures. In this
   ' // case, there is only one EncoderParameter structure in the array.
   ' // The one EncoderParameter structure has an array of values.
   ' // In this case, there is only one value (of type DWORD)
   ' // in the array. We will set that value to %EncoderValueTransformRotate90.

   eps.count = 1
   eps.Parameter(0).pGuid = $EncoderTransformation
   eps.Parameter(0).dwType = %EncoderParameterValueTypeLong
   eps.Parameter(0).NumberOfValues = 1

   ' // Rotate and save the image.
   transformation = %EncoderValueTransformRotate90
   eps.Parameter(0).Value = VARPTR(transformation)
   strFileName = UCODE$("ShapesR90.jpg")
   hStatus = GdipSaveImageToFile(pImage, STRPTR(strFileName), EncoderClsid, eps)
   IF hStatus = %StatusOk THEN
      PRINT "ShapesR90.jpg saved successfully"
   ELSE
      PRINT "Attempt to save ShapesR90.jpg failed"
   END IF

   ' // Cleanup
   IF pImage THEN GdipDisposeImage(pImage)

   ' // Shutdown GDI+
   GdiplusShutdown token

   WAITKEY$

END FUNCTION
' ========================================================================================