상세 컨텐츠

본문 제목

GIF로 이미지를 저장 해보자! C++

멀티미디어/이미지(Image)

by cepiloth 2021. 11. 2. 10:08

본문

728x90
반응형

비트맵 데이터를 GIF를 저장해보자. 먼저 repo에서 header only https://github.com/charlietangora/gif-h 소스를 다운로드 받자. 기본 예제는 아래와 같다.

#include <vector>
#include <cstdint>
#include <gif.h>
int main()
{
	int width = 100;
	int height = 200;
	std::vector<uint8_t> black(width * height * 4, 0);
	std::vector<uint8_t> white(width * height * 4, 255);

	auto fileName = "bwgif.gif";
	int delay = 100;
	GifWriter g;
	GifBegin(&g, fileName, width, height, delay);
	GifWriteFrame(&g, black.data(), width, height, delay);
	GifWriteFrame(&g, white.data(), width, height, delay);
	GifEnd(&g);

	return 0;
}

 

위 코드를 실행하면 100 x 200 검정, 흰색 이미지가 생성된다. 아래 코드에서 GifWriteFrame 메서드가 여러 장에 파일을 만드는 것으로 확인된다. 

GifWriteFrame(&g, black.data(), width, height, delay);
GifWriteFrame(&g, white.data(), width, height, delay);

 

GITHUB README.md 를 확인하면 RGBA8 형식만 지원된다고 명시되어있다.

Only RGBA8 is currently supported as an input format. (The alpha is ignored.)

RGB 오더링이나 DEPTH 가 다른 비트맵은 지원되지 않는다.

 

GDIPLUS로 이미지를 로딩하고 GIF로 저장해보자.

#include <iostream>
using namespace std;
#include <windows.h> 

// Gdiplus 
#pragma comment( lib, "gdiplus.lib" ) 
#include <gdiplus.h> 

static const wchar_t* filename = L"G:\\bab.png";

#include <vector>
#include <cstdint>
#include "gif.h"

int main()
{
    // Start Gdiplus 
    Gdiplus::GdiplusStartupInput gdiplusStartupInput;
    ULONG_PTR gdiplusToken;
    Gdiplus::GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
    // GDIPLUS 인스턴스를 초기화 한다.
    
    // Load the image filename 패스로 이미지를 로딩한다.
    Gdiplus::Bitmap* bitmap = Gdiplus::Bitmap::FromFile(filename);

    // 로딩된 이미지의 format 정보를 확인한다. gif-h 라이브러리에서는 RGBA8 만 지원한다고 한다.
    Gdiplus::PixelFormat format;
    format = bitmap->GetPixelFormat();

    switch (format) {
        case    PixelFormat1bppIndexed:     cout << "PixelFormat1bppIndexed" << endl; break;
        case    PixelFormat4bppIndexed:     cout << "PixelFormat4bppIndexed" << endl; break;
        case    PixelFormat8bppIndexed:     cout << "PixelFormat8bppIndexed" << endl; break;
        case    PixelFormat16bppGrayScale:  cout << "PixelFormat16bppGrayScale" << endl; break;
        case    PixelFormat16bppRGB555:     cout << "PixelFormat16bppRGB555" << endl; break;
        case    PixelFormat16bppRGB565:     cout << "PixelFormat16bppRGB565" << endl; break;
        case    PixelFormat16bppARGB1555:   cout << "PixelFormat16bppARGB1555" << endl; break;
        case    PixelFormat24bppRGB:        cout << "PixelFormat24bppRGB" << endl; break;
        case    PixelFormat32bppRGB:        cout << "PixelFormat32bppRGB" << endl; break;
        case    PixelFormat32bppARGB:       cout << "PixelFormat32bppARGB" << endl; break;
        case    PixelFormat32bppPARGB:      cout << "PixelFormat32bppPARGB" << endl; break;
        case    PixelFormat48bppRGB:        cout << "PixelFormat48bppRGB" << endl; break;
        case    PixelFormat64bppARGB:       cout << "PixelFormat64bppARGB" << endl; break;
        case    PixelFormat64bppPARGB:      cout << "PixelFormat64bppPARGB" << endl; break;
        case    PixelFormat32bppCMYK:       cout << "PixelFormat32bppCMYK" << endl; break;
        case    PixelFormatMax:             cout << "PixelFormatMax" << endl; break;
        break;
    }
    const auto bpp = Gdiplus::GetPixelFormatSize(format);
    const auto w = bitmap->GetWidth();
    const auto h = bitmap->GetHeight();
    const auto size = w * h * bpp / 8;

    Gdiplus::BitmapData data;
    const Gdiplus::Rect rect(0, 0, w, h);
    bitmap->LockBits(&rect, Gdiplus::ImageLockModeRead, format, &data);
    // delete the image when done 
    auto fileName = "bwgif.gif";
    GifWriter g;
    GifBegin(&g, fileName, w, h, 20);
    GifWriteFrame(&g, reinterpret_cast<BYTE*>(data.Scan0), w, h, 50);
    GifEnd(&g);
    bitmap->UnlockBits(&data);
    delete bitmap;
    bitmap = nullptr;

    // Shutdown Gdiplus 
    Gdiplus::GdiplusShutdown(gdiplusToken);
	return 0;
}

 

쉽게 사용할 수 있으나 DEPTH 가 다른 경우에 대한 처리가 미비하다. 

728x90
반응형

관련글 더보기

댓글 영역