GDI+ Сохранить Bitmap в PNG на СИ!

Discussion in 'С/С++, C#, Rust, Swift, Go, Java, Perl, Ruby' started by slesh, 5 Apr 2011.

  1. slesh

    slesh Elder - Старейшина

    Joined:
    5 Mar 2007
    Messages:
    2,702
    Likes Received:
    1,224
    Reputations:
    455
    Собственно говоря стал такой вопрос:
    Требуется сохранить Bitmap в PNG файл. Или хотя бы перекодировать его в буфер но уже в PNG формате.

    Но главная особенность надо именно на Си, а не С++
    GDI+ Заставить работать на Си довольно сложновато как.

    Вариант использование сторонних либ неподходил, слишком много веса дают
     
  2. GRRRL Power

    GRRRL Power Elder - Старейшина

    Joined:
    13 Jul 2010
    Messages:
    823
    Likes Received:
    185
    Reputations:
    84
    В документации сказано, что
    Неясно, в чем проблема использовать C++.
     
  3. slesh

    slesh Elder - Старейшина

    Joined:
    5 Mar 2007
    Messages:
    2,702
    Likes Received:
    1,224
    Reputations:
    455
    2 GRRRL Power в хидерах GDI+ в некоторых местах есть поддержка Си.
    Использовать С++ не хочется по религиозным взглядам.
     
  4. slesh

    slesh Elder - Старейшина

    Joined:
    5 Mar 2007
    Messages:
    2,702
    Likes Received:
    1,224
    Reputations:
    455
    Вот еще накопал что через Ole это можно делать. В частности OleCreatePictureIndirect но пока исходников нормальный не нашел. Хотя всё равно хотелосьбы на GDI+ и на СИ )
    Начал копать в сторону Классов GDI+ там обычная обёрка над над импортируемыми функциями, так возможно и получится переписать
     
    #4 slesh, 5 Apr 2011
    Last edited: 5 Apr 2011
  5. alexey-m

    alexey-m Elder - Старейшина

    Joined:
    15 Jul 2009
    Messages:
    518
    Likes Received:
    100
    Reputations:
    37
    slesh, не знаю в чем сложность я в свое время делал так и работало без проблем:

    заполнял GdiplusStartupInput;
    запускал GDI+: Startup(gdiplusToken, StartupInput, nil);
    загружал картинку, к примеру из файла LoadImageFromFile(Source, image);
    и сохранял уже в нужном формате через SaveImageToFile(image,Source, encoderClsid,nil);
    где encoderClsid: CLSID = '{557CF400-1A04-11D3-9A73-0000F81EF32E}'; но это для BMP для PNG смотреть надо.
    DisposeImage(image)
    Shutdown(gdiplusToken);

    из хидеров надо всего пару типов ну и сами функции выдернуть)
     
  6. slesh

    slesh Elder - Старейшина

    Joined:
    5 Mar 2007
    Messages:
    2,702
    Likes Received:
    1,224
    Reputations:
    455
    2 alexey-m вот этим самым сейчас и занимаюсь.

    Фуф. Сделал ) Чуть позже выложу код. Путаница была с гуидами, те что по дефолту прописаны - не пахали
     
    #6 slesh, 6 Apr 2011
    Last edited: 6 Apr 2011
  7. slesh

    slesh Elder - Старейшина

    Joined:
    5 Mar 2007
    Messages:
    2,702
    Likes Received:
    1,224
    Reputations:
    455
    Вот как и обещал кода, может кому нибудь пригодится.
    Код чисто на Си, без использования заголовочных файлов от GDI+

    PHP:
    #include <windows.h>
    // Структура для инициализации GDI+
    typedef struct _GDIPSI
    {
        
    DWORD    Ver;
        
    void*    Callback;
        
    BOOL    SuppressBackgroundThread;
        
    BOOL    SuppressExternalCodecs;
    GDIPSI, *PGDIPSI;

    // Контектс для GDI+ для хранения адресов функций
    typedef struct _GDIP_CTX
    {
        
    HMODULE        hModule;
        
    ULONG_PTR    Token;
        
    int (__stdcall *GdiplusStartup)(ULONG_PTRtokenPGDIPSI inputvoidoutput);
        
    int (__stdcall *GdipCreateBitmapFromHBITMAP)(HBITMAP hBitmapHPALETTE hPalettevoid** GdiImage);
        
    int (__stdcall *GdipSaveImageToFile)(voidGdiImageWCHARFileNameCLSIDEncodervoidParams);
        
    int (__stdcall *GdipDisposeImage)(voidGdiImage);
        
    void (__stdcall *GdiplusShutdown)(ULONG_PTR token);
    GDIP_CTX, *PGDIP_CTX;

    // Инициализация GDI+, загрузка библиотеки, поиск адресов.
    int GDIP_Init(PGDIP_CTX ctx)
    {
        
    int        ret 0;
        
    GDIPSI    si;

        
    si.Callback NULL;
        
    si.SuppressBackgroundThread 0;
        
    si.SuppressExternalCodecs 0;
        
    si.Ver 1;

        
    ctx->hModule LoadLibraryA("gdiplus.dll");
        if (
    ctx->hModule)
        {
            
    ctx->GdiplusStartup = (void*)GetProcAddress(ctx->hModule"GdiplusStartup");
            
    ctx->GdipCreateBitmapFromHBITMAP = (void*)GetProcAddress(ctx->hModule"GdipCreateBitmapFromHBITMAP");
            
    ctx->GdipSaveImageToFile = (void*)GetProcAddress(ctx->hModule"GdipSaveImageToFile");
            
    ctx->GdipDisposeImage = (void*)GetProcAddress(ctx->hModule"GdipDisposeImage");
            
    ctx->GdiplusShutdown = (void*)GetProcAddress(ctx->hModule"GdiplusShutdown");

            if (
    ctx->GdiplusStartup    &&
                
    ctx->GdipCreateBitmapFromHBITMAP &&
                
    ctx->GdipSaveImageToFile &&
                
    ctx->GdipDisposeImage &&
                
    ctx->GdiplusShutdown &&
                !
    ctx->GdiplusStartup(&ctx->Token, &siNULL))
            {
                
    ret 1;
            }
            else
            {
                
    FreeLibrary(ctx->hModule);
                
    ctx->hModule NULL;
            }
        }

        return 
    ret;
    }

    // Выгрузка GDI+ Библиотеки 
    void GDIP_Destroy(PGDIP_CTX ctx)
    {
        if (
    ctx->hModule)
        {
            
    ctx->GdiplusShutdown(ctx->Token);
            
    FreeLibrary(ctx->hModule);
            
    ctx->hModule NULL;
        }
    }

    // Сохранение Битмапа в PNG файл
    int GDIP_SaveBitmapAsPNG(PGDIP_CTX ctxHBITMAP BitmapWCHARFileName)
    {
        
    int    ret 0;
        
    void*    GdiImage NULL;
        
    GUID    FormatPNG = {0x557CF406,0x1A04,0x11d3,0x9A,0x73,0x00,0x00,0xf8,0x1e,0xf3,0x2e};    

        
    // Создадим GDI+ битмап из обычного GDI битмапа
        
    if (!ctx->GdipCreateBitmapFromHBITMAP(BitmapNULL, &GdiImage))
        {
            
    // Сохраним GDI+ битмап в файл 
            
    if (!ctx->GdipSaveImageToFile(GdiImageFileName, &FormatPNGNULL))
            {
                
    ret 1;
            }
            
            
    ctx->GdipDisposeImage(GdiImage);
        }

        return 
    ret;
    }


    int main(int argccharargv[])
    {
        
    HBITMAP        hBitmap;
        
    GDIP_CTX    ctx;

        
    // Инициализируем GDI+
        
    if (GDIP_Init(&ctx))
        {
            
    // Загрузим какой-нибудь битмап из ресурсов
            
    hBitmap LoadBitmapA(GetModuleHandle(NULL), MAKEINTRESOURCE(IDB_BITMAP1)); 
            if (
    hBitmap)
            {
                
    // Сохраняем наш битмап в PNG файл
                
    GDIP_SaveBitmapAsPNG(&ctxhBitmapL"c:\\1.png"); 
                
    // Уничтожим наш битмап
                
    DeleteObject(hBitmap);
            }
            
    // Выгружаетм GDI+
            
    GDIP_Destroy(&ctx); 
        }

        return 
    0;
    }
     
    #7 slesh, 6 Apr 2011
    Last edited: 6 Apr 2011