Development

[Image] 이미지 압축 클래스 제작

알 수 없는 사용자 2009. 1. 7. 11:18

이미지 압축에서 기본은 RLE(Run Length Encoding)라는 압축입니다. 이는 비손실 압축방식이며

복잡한 압축 알고리즘이 많지만 보다 적용하기 간단하다는 장점이 있습니다.

그렇지만 여전히 그 조금 부족한 부분이 있는데요.

그건 바로 복잡한 패턴을 가진 이미지일경우

오히려 압축한 데이터가 원본보다 더 커진다는데 있습니다.

게임 프로그래밍에서는 엄밀히 말해서 2D에서는 이방식을 많이 사용하고 있습니다.

왜냐하면 많은 공간이 키컬러(Key Color;투명색)이 차지하는 이미지가 많기 때문이죠.

따라서 RLE 방식을 조금 개선하여 만들어본 이미지 압축루틴을 소개할까 합니다.

아울러서 고속 블렌딩 기법도 팁으로 소개도 해드리죠... 오늘은 늦은 관계로

일단 클래스 해더만 보도록 하겠습니다.

다음 이미지 해더 정보는 보통 비트맵 해더와 비슷합니다. 간단히 매직번호로

이미지데이터를 식별하도록 하며 버저정보도 지원하도록 하죠. 이때 DWORD로 하였으므로

비트연산으로 한꺼번에 매직과 버전을 dwSignature 에 넣을 수 있도록 매크로도 만들었습니다.

// JR-Image Header

#define JRI_MAGIC            (0x01<<24|'I'<<16|'R'<<8|'J')
#define JRI_VERSION(x)     ((x&0xFF000000)>>24)

struct JRI_HEADER
{
        DWORD   dwSignature;       // 파일식별코드
        DWORD   dwWidth;            // 이미지의 넓이
        DWORD   dwHeight;           // 이미지의 높이
        DWORD   dwRGBBitCount;  // Used RGB Bit Count - 15, 16, 24
        DWORD   dwSize;              // Compressed size
        DWORD   dwBitmapSize;     // Uncompressed size
        DWORD   dwColorKey;        // 투명색
};

/**

 * JRI 압축형식의 이미지 클래스

 *  @author 장지락

 * @date 2004-03-03 1:50오전

 * @version 1.0

 */

class CImageEx
{
        public:
                // JRI static member data
                JRI_HEADER              *               m_lpHeader;
                WORD                    *               m_lpImage;

                // JRI dynamic member data(runtime)
                BOOL                                    m_bIndirected;
                BOOL                                    m_bAutoColorKey;
                RECT                                    m_ClipRect;

        public:
                CImageEx();
                virtual ~CImageEx();

                /**
                 * JRI 생성
                 */
                HRESULT         Create(const char * cszFilename );
                HRESULT         Create(const BYTE * lpCache, DWORD lSize, BOOL bIndirected=FALSE);
                HRESULT         Change(const BYTE * lpCache, DWORD lSize);

                /**
                 * Image Validate
                 */
                static
                HRESULT         Validate(const BYTE * lpHead);

               
                DWORD           GetWidth(){ return m_lpHeader->dwWidth; }
                DWORD           GetHeight(){ return m_lpHeader->dwHeight; }


                /**
                 * Clipper
                 */
                BOOL            ClipRect(RECT * Rect);
                BOOL            ClipRect(RECT * srcRect, RECT * destRect);
                BOOL            ValidateBlt(RECT * tRect, LONG * lDestX, LONG *lDestY, RECT * srcRect);
               
                /**
                 * Display
                 */
                HRESULT         Blt(WORD * lpTarget, LONG x, LONG y, LONG dPitch, RECT *dstRect=NULL, RECT *srcRect=NULL);
                HRESULT         BltHFlip(WORD * lpTarget, LONG x, LONG y, LONG dPitch, RECT *dstRect=NULL, RECT *srcRect=NULL);

                /**
                 * Set AutoColorKey
                 */
                void            AutoColorKey(void){ m_bAutoColorKey=FALSE; }
               

                /**
                 *  Image convert
                 */
                HRESULT         RGB555To565(void);
                HRESULT         RGB565To555(void);
                HRESULT         BMP2JRI(LPCSTR szSrcBMP, LPCSTR szDstJRI, BYTE *pHeader=NULL);
                HRESULT         JRI2BMP(LPCSTR szSrcJRI, LPCSTR szDstBMP);

                /**
                 * JRI or BMP File I/O
                 */
                HRESULT         Open(const char * cszFilename ); // JRI Open
                HRESULT         Save(const char * cszFilename ); // JRI Save

                HRESULT         OpenAsBMP(const char * cszFilename );
                HRESULT         SaveAsBMP(const char * cszFilename );


                /**
                 * Save routine for AFSprite!
                 */
                HRESULT         Appendix(HANDLE hFile);

        protected:
                /**
                 * DECODE 관련
                 */            
                HRESULT         DecodeBlt1( const WORD * lpSource, WORD * lpTarget, LONG x, LONG y, LONG dPitch, RECT *dstRect=NULL, RECT *srcRect=NULL );
                HRESULT         DecodeBlt2( const WORD * lpSource, WORD * lpTarget, LONG x, LONG y, LONG dPitch, RECT *dstRect=NULL, RECT *srcRect=NULL );
                HRESULT         DecodeJRI( const WORD * lpSource, WORD * lpTarget );

                /**
                 * ENCODE 관련
                 */
                WORD    *       Encode( const BYTE * lpSrc, UINT nWidth, UINT nHeight, DWORD& dwRefSize );
                UINT            ProcessLn( BYTE* lpSrc, WORD* lpDst, WORD nWidth );
                WORD            CountRuns( BYTE * lpSrc, UINT nLength );
                WORD            CountSkip( BYTE * lpSrc, UINT nLength );
                WORD            CountDraw( BYTE * lpSrc, UINT nLength );

};

기본적인건 이렇구요... 좀더 객체지향적으로 꾸밀 수도 있겠죠... 인터페이스 클래스를

정의해서 상속받는것도 좋은 방법이 되겠지요...

그러나 여기선 그런건 일단 넘어가기로 하고... 위의 클래스 구조가 잡혔으니 다음엔 구현을 하나씩 하나씩 집어 가면서 예기하겠습니다.

좀 부족한 감이 있지만 일단 오늘은 이까지하고 혹시 질문 있으시면 댓글을 이용해주시길...

[P.S. 1] 게임 프로그래밍에 관심있으신 분은 한번쯤은 보셔야할 부분입니다.

[P.S. 2] 앗~ 빨간색으로 된건 아주 위험한 코드입니다. public이므로 외부에서 멋도 모르고

             호출했다면 segmentation fault가 나겠죠... 아무 생각없이 한 코드고 별로 이쁘지도

             않고... 쩜 옛날엔 이렇게나 생각없는 코드와 클래스 구성을 했네욥 ㅠ.ㅠ


출처 : http://cafe.naver.com/myprogramming/