Pelles C forum

C language => Windows questions => Topic started by: liut on May 09, 2017, 09:49:42 AM

Title: Gdi+ image operation
Post by: liut on May 09, 2017, 09:49:42 AM
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!!
Title: Re: Gdi+ image operation
Post by: frankie on May 09, 2017, 11:03:40 AM
You may want switch to a native GDI+ usage using fGdiPlusFlat.h, that is also included in fsdk (http://forum.pellesc.de/index.php?topic=7017.0) .
You can get the manual for fGdiPlusFlat.h here (http://www.johnfindlay.plus.com/pellesc/GdiPlus/GdiPlusTests.zip).
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: [Select]
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)
Or
Code: [Select]
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)
Title: Re: Gdi+ image operation
Post by: liut on May 10, 2017, 03:58:02 AM
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 :)
Title: Re: Gdi+ image operation
Post by: frankie on May 10, 2017, 02:46:14 PM
Hello liut.
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...
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.

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
Everything can be done. GpBitmap and GPImage can be used indifferently.
Code: [Select]
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

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); 
Have you took a look to the fGdiPlusFlat.h? Or on MSDN (https://msdn.microsoft.com/en-us/library/vs/alm/ms533969(v=vs.85).aspx)?
You can use GdipSaveImageToFile and image format got from GetImageEncoders, you can find a sample here (https://msdn.microsoft.com/en-us/library/windows/desktop/ms533843(v=vs.85).aspx).

   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


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.
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.
Title: Re: Gdi+ image operation
Post by: liut on May 11, 2017, 09:48:47 AM
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!!
Title: Re: Gdi+ image operation
Post by: TimoVJL on May 11, 2017, 12:34:08 PM
Maybe those are constants.
Code: [Select]
const CLSID CLSID_image_bmp =  {0x557CF400,0x1A04,0x11D3,0x9A,0x73,0x00,0x00,0xF8,0x1E,0xF3,0x2E};
const CLSID CLSID_image_jpeg = {0x557CF401,0x1A04,0x11D3,0x9A,0x73,0x00,0x00,0xF8,0x1E,0xF3,0x2E};
const CLSID CLSID_image_gif =  {0x557CF402,0x1A04,0x11D3,0x9A,0x73,0x00,0x00,0xF8,0x1E,0xF3,0x2E};
const CLSID CLSID_image_tiff = {0x557CF405,0x1A04,0x11D3,0x9A,0x73,0x00,0x00,0xF8,0x1E,0xF3,0x2E};
const CLSID CLSID_image_png =  {0x557CF406,0x1A04,0x11D3,0x9A,0x73,0x00,0x00,0xF8,0x1E,0xF3,0x2E};
const CLSID CLSID_image_ico =  {0x557CF407,0x1A04,0x11D3,0x9A,0x73,0x00,0x00,0xF8,0x1E,0xF3,0x2E};
EDIT: with one variable
Code: [Select]
CLSID CLSID_image =  {0x557CF400,0x1A04,0x11D3,0x9A,0x73,0x00,0x00,0xF8,0x1E,0xF3,0x2E};just change one byte like
Code: [Select]
*(BYTE*)&CLSID_image = 6; // PNG
Code: [Select]
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <objbase.h>
#pragma comment(lib, "ole32.lib")

CLSID CLSID_image =  {0x557CF400,0x1A04,0x11D3,0x9A,0x73,0x00,0x00,0xF8,0x1E,0xF3,0x2E};

void __cdecl WinMainCRTStartup(void)
{
wchar_t *pwc, wcTmp[555];
pwc = wcTmp;
for (char i=0; i<=7;i++) {
*(BYTE*)&CLSID_image = i;
pwc += StringFromGUID2(&CLSID_image, pwc, 39);
*(pwc-1) = 10;
}
MessageBoxW(0, wcTmp, 0, 0);
ExitProcess(0);
}
Title: Re: Gdi+ image operation
Post by: liut on May 12, 2017, 03:32:53 AM
Thanks Timo. It works with these const perfectly!
Title: Re: Gdi+ image operation
Post by: frankie on May 12, 2017, 05:28:25 PM
Sorry I was wrong with use of GdipSaveImageToFile.
I edited the post above.
Title: Re: Gdi+ image operation
Post by: bitcoin on January 07, 2019, 03:31:21 PM
How I can make screenshot with gdi? I tried source code , but i get 'Access violation' in string GdipGetImageEncodersSize(&num, &size);
Why?
Title: Re: Gdi+ image operation
Post by: bitcoin on January 07, 2019, 04:20:35 PM
Updated. I found a mistake and made it. It looks like a piece of shit, but it works. Maybe someone will come in handy (I doubt, because this is an example of "how not to code" and I am the worst coder on the planet, I have to kill myself).

Code: [Select]
void MakeScr(void)
{
GUID  FormatPNG = {0x557CF406,0x1A04,0x11d3,0x9A,0x73,0x00,0x00,0xf8,0x1e,0xf3,0x2e};     
const CLSID CLSID_image_png =  {0x557CF406,0x1A04,0x11D3,0x9A,0x73,0x00,0x00,0xF8,0x1E,0xF3,0x2E};

const GUID EncoderQuality = {0x1d5be4b5, 0xfa4a, 0x452d, 0x9c, 0xdd, 0x5d, 0xb3, 0x51, 0x05, 0xe7, 0xeb};


GdiplusStartupInput gdiplusStartupInput = {1,0,0,0};
ULONG_PTR gdiplusToken;

//i dont know how to check errors here, only log, if != 0 - error
  printf("%d",GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL));
 
HDC dc, hdc;
HBITMAP hbitmap;

dc = GetDC(0);

int Height, Width;
Height = GetSystemMetrics(SM_CYSCREEN);
Width = GetSystemMetrics(SM_CXSCREEN);

hbitmap = CreateCompatibleBitmap(dc, Width, Height);


hdc = CreateCompatibleDC(dc);

SelectObject(hdc, hbitmap);
BitBlt(hdc, 0, 0, Width, Height, dc, 0, 0, SRCCOPY);

GpBitmap *newBp;
printf ("%d \n",GdipCreateBitmapFromHBITMAP(hbitmap,0,&newBp));


CLSID encoderClsid;
EncoderParameters para;
ULONG quality;

//GetEncoderClsid(L"image/png",&encoderClsid); -

printf("%d\n",GdipSaveImageToFile(newBp, L"mybitmap.png", &FormatPNG, NULL));

    DeleteObject(hbitmap);
 
    //GdiplusShutdown?
    return 0;
}
Title: Re: Gdi+ image operation
Post by: TimoVJL on January 08, 2019, 12:31:35 PM
As you are making a function, some release functions should be called too.
Like ReleaseDC(), GdipDisposeImage() to release resources.
Also printf () needs a console, so better to use like OutputDebugString() for checking values.
Code: [Select]
#define WIN32_LEAN_AND_MEAN
#include <windows.h>

#pragma comment(lib, "gdiplus.lib")

typedef int GpStatus;
#define WINGDIPAPI __stdcall
#define GDIPCONST const

typedef void GpBitmap;

typedef struct
{
    UINT32 GdiplusVersion ;
    void* DebugEventCallback ;
    BOOL SuppressBackgroundThread ;
    BOOL SuppressExternalCodecs ;
} GDIPLUSSTARTUPINPUT ;
/*
typedef int (_stdcall *NotificationHookProc)(ULONG_PTR *token);
typedef VOID (_stdcall *NotificationUnhookProc)(ULONG_PTR token);
*/
typedef struct
{
    void* NotificationHook; //NotificationHookProc NotificationHook;
    void* NotificationUnhook; //NotificationUnhookProc NotificationUnhook;
} GDIPLUSSTARTUPOUTPUT ;

int __stdcall GdiplusStartup(ULONG_PTR*, const GDIPLUSSTARTUPINPUT*, GDIPLUSSTARTUPOUTPUT*) ;
VOID __stdcall GdiplusShutdown(ULONG_PTR) ;

typedef void GpImage;
int __stdcall GdipSaveImageToFile(GpImage *image, WCHAR* filename, GDIPCONST CLSID* clsidEncoder, void*);
int __stdcall GdipCreateBitmapFromHBITMAP(HBITMAP hbm, HPALETTE hpal, GpBitmap** bitmap);
int __stdcall GdipDisposeImage(GpImage*);

void MakeScr(void)
{
const CLSID CLSID_image_png = { 0x557CF406, 0x1A04, 0x11D3, 0x9A, 0x73, 0x00, 0x00, 0xF8, 0x1E, 0xF3, 0x2E };
GDIPLUSSTARTUPINPUT gdiplusStartupInput = { 1, 0, 0, 1 };
ULONG_PTR gdiplusToken;

GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

HDC dc, hdc;
HBITMAP hbitmap;

// HWND hWnd = GetDesktopWindow();
dc = GetDC(0);

int Height, Width;
Height = GetSystemMetrics(SM_CYSCREEN);
Width = GetSystemMetrics(SM_CXSCREEN);

hbitmap = CreateCompatibleBitmap(dc, Width, Height);
hdc = CreateCompatibleDC(dc);
SelectObject(hdc, hbitmap);
BitBlt(hdc, 0, 0, Width, Height, dc, 0, 0, SRCCOPY);
DeleteDC(hdc);
ReleaseDC(0, dc);

GpBitmap *newBp;
GdipCreateBitmapFromHBITMAP(hbitmap, 0, &newBp);
DeleteObject(hbitmap);

GdipSaveImageToFile(newBp, L"mybitmap.png", &CLSID_image_png, NULL);
GdipDisposeImage(newBp);


//GdiplusShutdown?
GdiplusShutdown(gdiplusToken);
}

void __cdecl WinMainCRTStartup(void)
{
MakeScr();
ExitProcess(0);
}
Title: Re: Gdi+ image operation
Post by: frankie on January 08, 2019, 02:58:03 PM
After the excellent post of Timo, this is just another sample natively using fGdiPlusFlat.h

Code: [Select]
#include <windows.h>
#include <fGdiPlusFlat.h>
#include <stdio.h>
#pragma comment(lib, "User32.lib")
#pragma comment(lib, "gdi32.lib")
#pragma comment(lib, "gdiplus.lib")

#define GDI_ERR_CASE(x) case (x): return (const char *)#x
const char *GetGdiPlusErrorText(Status err)
{
switch (err)
{
GDI_ERR_CASE(Ok);
GDI_ERR_CASE(GenericError);
GDI_ERR_CASE(InvalidParameter);
GDI_ERR_CASE(OutOfMemory);
GDI_ERR_CASE(ObjectBusy);
GDI_ERR_CASE(InsufficientBuffer);
GDI_ERR_CASE(NotImplemented);
GDI_ERR_CASE(Win32Error);
GDI_ERR_CASE(WrongState);
GDI_ERR_CASE(Aborted);
GDI_ERR_CASE(FileNotFound);
GDI_ERR_CASE(ValueOverflow);
GDI_ERR_CASE(AccessDenied);
GDI_ERR_CASE(UnknownImageFormat);
GDI_ERR_CASE(FontFamilyNotFound);
GDI_ERR_CASE(FontStyleNotFound);
GDI_ERR_CASE(NotTrueTypeFont);
GDI_ERR_CASE(UnsupportedGdiplusVersion);
GDI_ERR_CASE(GdiplusNotInitialized);
GDI_ERR_CASE(PropertyNotFound);
GDI_ERR_CASE(PropertyNotSupported);
}

return (const char *)"Unknown error.";
}

BOOL 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 FALSE; // Failure

pImageCodecInfo = (ImageCodecInfo *) (malloc(size));
if (pImageCodecInfo == NULL)
return FALSE; // 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 TRUE; // Success
}
}

free(pImageCodecInfo);
return FALSE; // Failure
}

BOOL SaveScrToFile(const WCHAR *szFileName, const WCHAR *ImgFormat)
{
BOOL bReturn = FALSE;

HDC hDcScreen   = GetDC(NULL); //Acquire screen DC
int Height      = GetSystemMetrics(SM_CYSCREEN); //Get Screen dimensions
int Width       = GetSystemMetrics(SM_CXSCREEN);
HBITMAP hbitmap = CreateCompatibleBitmap(hDcScreen, Width, Height);
HDC hdc         = CreateCompatibleDC(hDcScreen); //Create our memory DC for copy
HGDIOBJ hOldBmp = SelectObject(hdc, hbitmap);
BOOL bRes       = BitBlt(hdc, 0, 0, Width, Height, hDcScreen, 0, 0, SRCCOPY);
ReleaseDC(NULL, hDcScreen); //Release screen DC
if (!bRes) //Test result from BitBlt
goto Clean; //BitBlt failed!
GpBitmap * newBp;
Status sRes = GdipCreateBitmapFromHBITMAP(hbitmap, 0, &newBp);
if (Ok != sRes)
{
printf("Error %d='%s'calling GdipCreateBitmapFromHBITMAP.\n", sRes, GetGdiPlusErrorText(sRes));
goto Clean;
}
CLSID encoderClsid;
if(!GetEncoderClsid(ImgFormat,&encoderClsid)) //Retrieve encoder CLSID
goto Clean; //Encoder not available
sRes = GdipSaveImageToFile(newBp, szFileName, &encoderClsid, NULL);
GdipDisposeImage(newBp);
if (Ok != sRes)
{
printf("Error %d='%s'calling GdipSaveImageToFile.\n", sRes, GetGdiPlusErrorText(sRes));
goto Clean;
}
else
bReturn = TRUE;
Clean:
SelectObject(hdc, hOldBmp); //Select back old bitmap
DeleteObject(hbitmap); //Delete user bitmap
DeleteDC(hdc); //Delete memory DC
return bReturn;
}

int main(void)
{
GdiplusStartupInput gdiplusStartupInput = { 1, 0, 0, 0 };
ULONG_PTR gdiplusToken;
BOOL bReturn = FALSE;

printf("Saving screen to file \"MyScreen.png\".\n");
//Normally you init and shutdown GDI+ from main, so if you have other
//functions using GDI+ you don't have to restart it each time.
Status sRes = GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
if (Ok != sRes)
{
printf("Error %d='%s'calling GdiplusStartup.\n", sRes, GetGdiPlusErrorText(sRes));
return bReturn;
}

if (SaveScrToFile(L"MyScreen.png", L"image/png"))
{
printf("File saved correctly!\n");
bReturn = TRUE;
}
else
{
printf("File not savedy!\n");
bReturn = FALSE;
}
GdiplusShutdown(gdiplusToken);
return !bReturn; //Negation to make return value conformant: OK=0, whatever=NOT_OK
}

EDIT: Fixed code.
Title: Re: Gdi+ image operation
Post by: bitcoin on January 08, 2019, 03:57:53 PM
frankie,TimoVJL, thank you, it works.
Are there diffences between GUID and CLSID?
Title: Re: Gdi+ image operation
Post by: frankie on January 08, 2019, 06:00:46 PM
You're welcome.
The GUID, Globally Unique Identifier, and the CLSID, CLass ID, are both a 128 bits long code that is guarantee to be unique all over the world.
With a slight difference in the standard representation, a doubleword, 2 words and 8 bytes for GUID and a doubleword, 3 words and 6 bytes for CLSID, they anyways counts 128bits total (16 bytes).
Title: Re: Gdi+ image operation
Post by: bitcoin on February 24, 2023, 01:51:00 PM
Hello!
How I can compress the image? I use source code

Code: [Select]
void MakeShot(void)
{
GUID png_clsid = { 0x557CF406,0x1A04,0x11d3,0x9A,0x73,0x00,0x00,0xf8,0x1e,0xf3,0x2e };

GdiplusStartupInput gdiplusStartupInput = { 1,0,0,0 };
ULONG_PTR gdiplusToken;

GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

HDC dc, hdc;
HBITMAP hbitmap;

dc = GetDC(0);

int Height, Width;
Height = GetSystemMetrics(SM_CYSCREEN);
Width = GetSystemMetrics(SM_CXSCREEN);

hbitmap = CreateCompatibleBitmap(dc, Width, Height);

hdc = CreateCompatibleDC(dc);

SelectObject(hdc, hbitmap);

BitBlt(hdc, 0, 0, Width, Height, dc, 0, 0, SRCCOPY);

GpBitmap* newBp;
GdipCreateBitmapFromHBITMAP(hbitmap, 0, &newBp);



EncoderParameters para;
para.Count = 1;
para.Parameter[0].Guid = EncoderQuality;
para.Parameter[0].Type = EncoderParameterValueTypeLong;
para.Parameter[0].NumberOfValues = 1;
int quality = 15;
para.Parameter[0].Value = &quality;

GdipSaveImageToFile(newBp, L"mybitmap.png", &png_clsid, &para);


GdipSaveImageToStream(newBp, iSend, &png_clsid, NULL);


DeleteObject(hbitmap);

GdiplusShutdown(gdiplusToken);

But int quality - has no effect! I got same images, compress don't work, why?
Title: Re: Gdi+ image operation
Post by: John Z on February 24, 2023, 03:34:18 PM
Hi bitcoin,

Well I'm taking a stab in the dark at it.....

Isn't the png format always a lossless compression?  In lossless compression the quality value
would be meaningless so the compression would always be the same....

jpg is not necessarily lossless so the quality value less than 100 has an effect on the compression
and therefore the size.

John Z
Title: Re: Gdi+ image operation
Post by: bitcoin on February 24, 2023, 04:30:23 PM
Isn't the png format always a lossless compression?  In lossless compression the quality value
would be meaningless so the compression would always be the same....
May be, you are right..
Title: Re: Gdi+ image operation
Post by: frankie on February 25, 2023, 10:45:42 PM
As John said the PNG format is lossless, what could be changed is the compression level (see this (https://www.howtogeek.com/203979/is-the-png-format-lossless-since-it-has-a-compression-parameter/)).
You may want use the "EncoderCompression" GUID instead of "EncoderQuality".
I made same experiments, PNG encoder only accepts a custom parameter block that is undocumented. I made many searches in the net, but no info seems to be available.
Title: Re: Gdi+ image operation
Post by: Robert on March 02, 2023, 04:33:35 AM
Hey frankie:

All this talk about GDI+ reminded me that I noticed a recent update to your FSDK.

https://github.com/Frankie-PellesC/fSDK (https://github.com/Frankie-PellesC/fSDK)

I must have missed the announcement but anyway Thank You for the FSDK GDI+ User Manual.

A monumental piece of work. Truly a tour de force.
Title: Re: Gdi+ image operation
Post by: frankie on March 02, 2023, 10:12:31 AM
Hello Robert
Thanks
You're right There was no announcement. The manual has been realized many years ago, 2016, together with the 'fGdiPlusFlat.h' and posted on the forum (here (https://forum.pellesc.de/index.php?topic=6949.msg26326#msg26326)).
Few days ago looking at my github pages I realized that the manual was missing and simply, and silently, added it.  :)
My SDK is getting old and would need some mainteinance and upgrade, but unfortunately I'm too busy to afford the job up to now  :(
I hope I could do it in the future.  :P