2020년 7월 1일 수요일

FreeImage

적당히 구글에 FreeImage git 치고 가장 최근 버전을 다운후 컴파일해서 끌고오자.

그리고 Source 에서 헤더만 긁어오자. FreeImage.h, Utility.h 가 자주 쓰인다.

많은 종류의 이미지 확장자들을 커버하면서 빠른 속도를 자랑하는 FreeImage.

하는 일은 이미지 파일을 bmp 말고 자신의 비트맵으로 빼주고 여러 속성을 알아내는 함수 제공.

png 파일들을 처리해서 keyframe 을 만들 프로그램이 필요해서 만드는 겸 같이 정리중.

1. 에러 처리용 함수 정의

1

2

3

4

5

6

7

8

9

10

11

auto FreeImageErrorHandler = [](FREE_IMAGE_FORMAT fif, const char* message)

{

char buff[1024];

const char* format = (fif != FIF_UNKNOWN) ? FreeImage_GetFormatFromFIF(fif) : "Unknown Error";

const char* text = (message != nullptr) ? message : "Unknown Error";

snprintf(buff, sizeof(buff), "%s , Format : %s.", text, format);

MessageBoxA(Setting::Get()->GetHWND(), buff, nullptr, MB_OK);

};

FreeImage_SetOutputMessage(FreeImageErrorHandler);

FreeImage_SetOutputMessage 함수로 내부 에러 처리용 함수를 지정 가능함.

FreeImage_GetFormatFromFIF 함수로 Free_Image_format 을 string 으로 변환 함.

저 포맷이 뭐냐면 그냥 확장자임.

현재 winapi 로 만들고 있으니까 그냥 api 용 함수 중에 제일 만만한 MessageBox 로 처리했음.

2. Load

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

const bool ImageImporter::Load(const std::string& path, Texture* texture

{

if (!texture)

{

return false;

}

if (!FileSystem::IsExist(path))

{

return false;

}

FREE_IMAGE_FORMAT format = FreeImage_GetFileType(path.c_str(), 0);

format = (format == FIF_UNKNOWN) ? FreeImage_GetFIFFromFilename(path.c_str()) : format;

// 모르는 형식은 파일 이름에서 가져옴

if (!FreeImage_FIFSupportsReading(format))

{

MessageBoxA(Setting::Get()->GetHWND(), "Unknown or unsupported format", nullptr, MB_OK);

return false;

}

FIBITMAP* bitmap = FreeImage_Load(format, path.c_str()); // 1 Load

}

위는 정확히는 Load 의 일부임.

FreeImage_GetFileType 이걸로 파일을 해석해서 확장자를 알아오고, 실패하면 FreeImage_GetFIFFromFilename 이걸로 그냥 파일명에서 확장자를 가져옴.

확장자를 알아야지 이미지파일을 해석할 수 있지 않겠음?

FIBITMAP* bitmap = FreeImage_Load(format, path.c_str()); // 1 Load

그리고 위 함수가 핵심.

FreeImage 는 위에서 뽑아낸 FIBITMAP 으로 모든 걸 다함.

FreeImage_Unload(bitmap)

위 함수로 FIBITMAP 메모리 해제하는걸 잊지 말자.

3. Correcting

핵심은 32bit 짜리인 byte로 픽셀 하나를 처리하면 내가 사용할 Direct는 ABGR 로 읽는다는 것이다.

FIBITMAP 은 ARGB 형식이다.

R 과 B 를 바꿔줄 필요가 있다.

그럼 RGBA 로 DirectX 는 읽어 줄 것이다.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

FIBITMAP* ImageImporter::ApplyBitmapCorrections(FIBITMAP* bitmap)

{

if (!bitmap)

{

MessageBoxA(Setting::Get()->GetHWND(), "Invalid Parameter", nullptr, MB_OK);

return nullptr;

}

unsigned int channels = ComputeChannelCount(bitmap);

if (channels == 1)

{

int bpp = ComputeBitsPerChannel(bitmap);

if (bpp == 16)

{

FIBITMAP* previousBitmap = bitmap;

bitmap = FreeImage_ConvertTo8Bits(previousBitmap);

FreeImage_Unload(previousBitmap);

}

}

//32bit 로 변환

if (FreeImage_GetBPP(bitmap) < 32)

bitmap = ConvertTo32Bits(bitmap);

if (FreeImage_GetBPP(bitmap) == 32)

{

if (FreeImage_GetRedMask(bitmap) == 0x00ff0000 && ComputeChannelCount(bitmap) >= 2)

{

bool swapped = SwapRedBlue32_Wrapper(bitmap); // 내장함수 아님 알아서 구현하면 됨

if (!swapped)

MessageBoxA(Setting::Get()->GetHWND(), "Failed to swap red with blue channel", nullptr, MB_OK);

}

}

//수직으로 뒤집기 -> 이건 뒤집어서 나오니까 일단 이래보자 심정임

FreeImage_FlipVertical(bitmap);

return bitmap;

}

4. Rescale

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

FIBITMAP* ImageImporter::Rescale(FIBITMAP* bitmap, const uint& width, const uint& height)

{

if (!bitmap || width == 0 || height == 0)

{

return nullptr;

}

FIBITMAP* previousBitmap = bitmap;

bitmap = FreeImage_Rescale(previousBitmap, width, height, Rescale::rescaleFilter);

if (!bitmap)

{

return previousBitmap;

}

FreeImage_Unload(previousBitmap);

return bitmap;

}

함수만 적고 넘어가도 되지만 굳이 전체 함수를 가져온 이유는 FIBITMAP 쓰는 법을 각인하기 위해서.

저거 처럼 FIBITMAP 의 복사본이 나오므로 기존 것을 복사하고 지우고 하는 작업이 필요하다.

5. 이미지 속성

width = FreeImage_GetWidth()

height = FreeImage_GetHeight()

byte per line = FreeImage_GetLine() ( BPP * width)

BPP (bit per pixel) = FreeImage_GetBPP()

BPC (bit per color / channel) = FreeImage_GetImageType() 에서 FREE_IMAGE_TYPE 보고 결정하면 됨.

(이때 FIT_BITMAP 은 BYTE 가 단위임. 즉 8 비트이고 예제에도 그렇게 쓰던데 주석에는 왜 그렇제 적었는지 모르겠음.)

numChannel = BPP / BPC ;

numColorUsed = FreeImage_GetColorsUsed()

grayScale = (FreeImage_GetColorType(bitmap) == FIC_MINISBLACK)

( FIC_RGBALPHA 나 FIC_RGB 가 보통임)

BYTE* data = FreeImage_GetBits(bitmap); // 데이터 얻어내기

댓글 없음:

댓글 쓰기

List