Sauver un JPEG depuis le presse papier

Class Image, Bitmap GDI+

GDI+

Voir version :

Pas de dépendances

Télécharger :

#include <Windows.h>
#include <GdiPlus.h>
#include <stdio.h>
#pragma comment(lib, "gdiplus.lib")

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

    Gdiplus::ImageCodecInfo* pImageCodecInfo = NULL;

    Gdiplus::GetImageEncodersSize(&num, &size);
    if(size == 0)
        return -1;  // Failure

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

    Gdiplus::GetImageEncoders(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
}

void SauverJPG(const wchar_t* fic,int width,int height,const char* flux)
{
    Gdiplus::Bitmap B(width,height);
    int i,j,curs;
    HWND Hcon = GetConsoleWindow();
    HDC Hdc = GetDC(Hcon);  
    for(curs=0,j=height-1;j>=0;j--)
    {
        for(i=0;i<width;i++,curs+=4)
        {
            Gdiplus::Color col(flux[curs+2],flux[curs+1],flux[curs]);
            B.SetPixel(i,j,col);
        }
    }
    CLSID jpgClsid;
    GetEncoderClsid(L"image/jpeg", &jpgClsid);
    if (B.Save(fic,&jpgClsid,NULL)==Gdiplus::Ok)
        printf("Sauvegarde ok\n");
    else
        printf("Sauvegarde echoue\n");
    ReleaseDC(Hcon, Hdc);
}

int main(void)
{
    unsigned long m_gdiplusToken;
    Gdiplus::GdiplusStartupInput gdiplusStartupInput;
    Gdiplus::GdiplusStartup(&m_gdiplusToken, &gdiplusStartupInput, NULL);
    if(OpenClipboard(NULL))
    {
        HANDLE h;
        h = GetClipboardData(CF_DIBV5);
        if(h)
        {
            BITMAPV5HEADER head;
            char *brut = (char *)GlobalLock(h);
            head = *((BITMAPV5HEADER*)brut);
            SauverJPG(L"out.jpg",head.bV5Width,head.bV5Height,brut+head.bV5Size);
            GlobalUnlock(h);
            CloseClipboard();
        }
        else
            printf("Pas d'image dans le presse papier\n");
        CloseClipboard();
    }
    Gdiplus::GdiplusShutdown(m_gdiplusToken);
    return 0;
}




Commentaires

	Voici une partie de la librairie Windows appelée GDI (Graphic Device Interface).

	Notez que cette partie est en C++, et non plus en C.

	Avant de lancer le programme, faite un screenshot (la touche impr ecran, l'outil snipping tool, un copier dans Paint, ce que vous voulez...)
	L'essentiel est d'avoir une image dans le presse papier.
	
	Lancez le programme : un fichier out.jpg se crée : votre image est sauvegardée !

	Pour la partie lecture du presse papier, je vous renvoie au §4.10.3 de ce recueil.
	Au lieu de dessiner l'image, nous allons la passer à la fonction SauverJPG.

	Tout d'abord, la librairie GDI d'initialise avec :

	unsigned long m_gdiplusToken;
	Gdiplus::GdiplusStartupInput gdiplusStartupInput;
	Gdiplus::GdiplusStartup(&m_gdiplusToken, &gdiplusStartupInput, NULL);

	et se libère avec : 

	Gdiplus::GdiplusShutdown(m_gdiplusToken);

La classe Bitmap :
------------------

	Ce qui est intéressant dans ce paragraphe est la classe Gdiplus::Bitmap

	Cette classe permet de charger plusieurs formats d'image (BMP, GIF, JPG, PNG...) de les manipuler et également de les sauver !

	Cette classe hérite de la classe Gdiplus::Image

	Voici les documentations pour voir toutes les méthodes disponibles :

	https://msdn.microsoft.com/en-us/library/windows/desktop/ms534420(v=vs.85).aspx
	https://msdn.microsoft.com/en-us/library/windows/desktop/ms534462(v=vs.85).aspx

	Tout d'abord, nous construisons une instance de Bitmap en passant la taille voulue (width et height)

	Puis nous remplissons chaque pixel dans le for en créeant des pixels de type Gdiplus::Color
	https://msdn.microsoft.com/en-us/library/windows/desktop/ms534427(v=vs.85).aspx

	Puis nous sauvegardons avec la méthode Save.

	La petite difficulté est qu'il faut récupérer un identifiant du codec d'encodage de l'image.
	En effet, Windows sait lire et écrire des JPG, des PNG, etc... Il a des codecs pour ça.

	Nous allons, grâce à la fonction GetEncoderClsid, récupérer le codec jpg pour l'utiliser, et sauver notre image en JPG.

	Cette fonction, je l'ai prise directement sur la MSDN ici :
	https://msdn.microsoft.com/en-us/library/windows/desktop/ms533843(v=vs.85).aspx

	Son fonctionnement est simple (mais est en C) :
	Gdiplus::GetImageEncodersSize récupère le nombre de codecs d'écriture présents.
	Gdiplus::GetImageEncoders les récupère dans un tableau.

	On fait un for, et si l'encodeur correspond à celui demandé, on renvoie le bon CLSID : l'identifiant du codec à passer à Save.