C language > Windows questions

Gdi+ image operation

(1/4) > >>

liut:
Hello, I'm trying to use this lib (author by JohnF) for some image operations:

http://www.johnfindlay.plus.com/pellesc/GdiPlus/GdiPlusLibLib.zip

I can use the image decoder and encoder for an image's format conversion, and can also get the width/height of the image. However, I can't find a way to scale an image and save to another. I look into the h files, maybe lack of some api for bitmap/graphics class.

Can anybody show me an example code with this lib? Tks!!

frankie:
You may want switch to a native GDI+ usage using fGdiPlusFlat.h, that is also included in fsdk .
You can get the manual for fGdiPlusFlat.h here.
For an example of image cropping and scaling see chapter 7.5 "Cropping and Scaling Images" page 37.
Anyway under GdiPlusLibLib you should use:

--- Code: ---GpStatus GpGraphics_DrawImageRcRcI(GP_GRAPHICS * this, GP_IMAGE * image, const RECTI * destRect, INT srcx, INT srcy, INT
                                                          srcwidth, INT srcheight, GpUnit srcUnit, const GP_IMAGEATTRIBUTES * imageAttributes,
                                                          DrawImageAbort callback, VOID* callbackData)

--- End code ---
Or

--- Code: ---GpStatus GpGraphics_DrawImagePtsRcI(GP_GRAPHICS * this, GP_IMAGE * image,
                                                   const POINTI * destPoints, INT count, INT srcx, INT srcy,
                                                   INT srcwidth, INT srcheight, GpUnit srcUnit, const GP_IMAGEATTRIBUTES * imageAttributes,
                                                   DrawImageAbort callback, VOID* callbackData)

--- End code ---

liut:
Thanks Frankie. Actually I have read the manual of gdi+flat before and compared with gdi+liblib, their exported apis are similar. The actual problems:
1. No exported api for creating a graphic object via an existing bitmap object. I refered others' C++ code, it should like this:
     Image image(L"d:\\abc.jpg");   // create an image object, it can be done
     Bitmap bitmap(100, 100, PixelFormat32bppARGB);   // create a bitmap object with specified width/height/color, it can be done
     Graphics graph(&bitmap);   // create a graphic object via bitmap object,  no api for this
     graph.DrawImage(&image, Rect(0,0,100,100));   // draw image to this graphic object, it can be done

2. No exported api for saving a bitmap object to file. I check gdi+ manual of Microsoft, bitmap class is inherited from image class, so it should support the save method too. But I can't find api for this (only we have GpImage_SaveFile()):
    bitmap.Save(L"d:\\new_abc.jpg",   &encoderClsid,   &encoderParameters); 

BTW, in the manual the content for "cropping and scaling images", the code purpose is mainly for displaying an image, it should not be enough for me.
If no more idea, I may consider using gdi/hdc as an intermediate way to convert them, but it looks quite stupid :)

frankie:
Hello liut.

--- Quote from: liut on May 10, 2017, 03:58:02 AM ---Actually I have read the manual of gdi+flat before and compared with gdi+liblib, their exported apis are similar. The actual problems:
1. No exported api for creating ...
2. No exported api for saving a bitmap object to file...

--- End quote ---
fGdiPlusFlat.h is not a library. It doesn't contain any helper class or function.
NeverthelessfGdiPlusFlat.h  exports the whole GDI+ API. All functions existent in GDI+ are available in fGdiPlusFlat.h.


--- Quote from: liut on May 10, 2017, 03:58:02 AM ---I check gdi+ manual of Microsoft, bitmap class is inherited from image class, so it a graphic object via an existing bitmap object. I refered others' C++ code, it should like this:
     Image image(L"d:\\abc.jpg");   // create an image object, it can be done
     Bitmap bitmap(100, 100, PixelFormat32bppARGB);   // create a bitmap object with specified width/height/color, it can be done
     Graphics graph(&bitmap);   // create a graphic object via bitmap object,  no api for this
     graph.DrawImage(&image, Rect(0,0,100,100));   // draw image to this graphic object, it can be done

--- End quote ---
Everything can be done. GpBitmap and GPImage can be used indifferently.

--- Code: --- GpImage *image = NULL;
GdipLoadImageFromFile(L"d:\\abc.jpg", &image); // create an image object
GpBitmap *bitmap = NULL;
GdipCreateBitmapFromScan0(100, 100, 0, PixelFormat32bppARGB, NULL, &bitmap); // create a bitmap object with specified width/height/color
GpGraphics *graph;
GdipGetImageGraphicsContext(bitmap, &graph); // create a graphic object via bitmap object
GdipDrawImageI(graph, image, 100, 100); // draw image to this graphic object, it can be done

--- End code ---


--- Quote from: liut on May 10, 2017, 03:58:02 AM ---2. No exported api for saving a bitmap object to file. I check gdi+ manual of Microsoft, bitmap class is inherited from image class, so it should support the save method too. But I can't find api for this (only we have GpImage_SaveFile()):
    bitmap.Save(L"d:\\new_abc.jpg",   &encoderClsid,   &encoderParameters); 

--- End quote ---
Have you took a look to the fGdiPlusFlat.h? Or on MSDN?
You can use GdipSaveImageToFile and image format got from GetImageEncoders, you can find a sample here.

   GdipSaveImageToFile(bitmap, L"mybitmap.bmp", &ImageFormatBMP, NULL);   //save bitmap in bitmap format
   GdipSaveImageToFile(bitmap, L"mybitmap.png", &ImageFormatPNG, NULL);   //save bitmap in PNG format
   GdipSaveImageToFile(image,  L"myimage.bmp",  &ImageFormatBMP, NULL);   //save bitmap in bitmap format
   GdipSaveImageToFile(image,  L"myimage.png",  &ImageFormatPNG, NULL);   //save bitmap in PNG format


--- Quote from: liut on May 10, 2017, 03:58:02 AM ---BTW, in the manual the content for "cropping and scaling images", the code purpose is mainly for displaying an image, it should not be enough for me.

--- End quote ---
As I told the file fGdiPlusFlat.h is the complete GDI+ flat API, so everything that can be done in C++ with GDI+ can be done in C. Of course it is not straightforward, and you have to practice to use it (is a bare naked API).
The first page of the manual try to give an idea of how to use them, following the base rules and consulting the reference online it should be not so difficult to program with it.

liut:
Thanks again frankie!! Finally I make it works! Here is the complete code for reference:

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

#include "fGdiPlusFlat.h"

// The helper function code comes from Microsoft guideline without modification
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;

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

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

   GdipGetImageEncoders(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
}

int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow)
{
   GpStatus stat;

   ULONG_PTR gdiplusToken;

   GdiplusStartup(&gdiplusToken, &gdiplusStartupInputDef, NULL);

   GpImage *image=NULL;
   GdipLoadImageFromFile(L"d:\\Runner.jpg",&image);

   UINT width,height;
   GdipGetImageWidth(image,&width);
   GdipGetImageHeight(image,&height);

   PixelFormat pixfmt;
   GdipGetImagePixelFormat(image, &pixfmt);

   if(image){
      GpBitmap *bitmap=NULL;
      GdipCreateBitmapFromScan0(width/2, height/2, 0, pixfmt, NULL, &bitmap);

      if(bitmap){
         GpGraphics *graph=NULL;
         GdipGetImageGraphicsContext(bitmap, &graph);

         if(graph){
            GdipDrawImageRectI(graph, image, 0, 0, width/2, height/2);

            // Draw a line
            //GpPen *pen;
            //GdipCreatePen1(MakeARGB(255, 0, 0, 255), 2.0, UnitPixel, &pen);
            //GdipDrawLineI(graph, pen, 0, 0, 60, 30);

            CLSID encoderClsid;
            GetEncoderClsid(L"image/jpeg", &encoderClsid);

            // For jpeg encoder
            EncoderParameters para;
            ULONG quality;
            
            para.Count = 1;
            para.Parameter[0].Guid = EncoderQuality;
            para.Parameter[0].Type = EncoderParameterValueTypeLong;
            para.Parameter[0].NumberOfValues = 1;
            quality = 95;  // jpg quality level 95.
            para.Parameter[0].Value = &quality;

            //stat=GdipSaveImageToFile(bitmap, L"d:\\mybitmap.bmp", &ImageFormatBMP, NULL);  // Always return 10 (FileNotFound?) if directly using const ImageFormatXXX...
            stat=GdipSaveImageToFile(bitmap, L"d:\\mybitmap.jpg", &encoderClsid, &para);  // para for jpeg, NULL for bmp
            if(stat==Ok){
               MessageBox(NULL,"ok","ok",MB_OK);
            }
            else{
               char text[100];

               sprintf(text,"%d",stat);
               MessageBox(NULL,text,"GdipSaveImageToFile",MB_OK);
            }

            GdipDeleteGraphics(graph);
         }
      }

       GdipDisposeImage(image);
   }

   GdiplusShutdown(gdiplusToken);

   return 0;
}


There is still an issue: I can't directly use the const ImageFormatXXX in GdipSaveImageToFile(), and still need to use the helper function to get the clsid for the encoder. Anyway it's good enough for me!!

Navigation

[0] Message Index

[#] Next page

Go to full version