// ImageGif.cpp: implementation of the CImageGif class. // ////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include "ImageGif.h" #include "Image.h" #ifdef _DEBUG #undef THIS_FILE static char THIS_FILE[]=__FILE__; #define new DEBUG_NEW #endif ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// CImageGif::CImageGif() { m_globalColorTable = NULL; m_image = NULL; m_current = NULL; m_graphicControl = NULL; m_plainText = NULL; m_application = NULL; m_comment = NULL; m_stream = NULL; m_index = 0; } CImageGif::~CImageGif() { Delete(); } BOOL CImageGif::Load(LPCTSTR fileName) { CFile file; CFileException fe; unsigned long fileSize; int colorSize = 0; if (m_image) Delete(); // ÆÄÀÏ ¿­±â if (!file.Open(fileName, CFile::modeRead|CFile::shareDenyWrite, &fe)) return FALSE; // ÆÄÀÏÀÇ ±æÀ̸¦ ±¸ÇÔ fileSize = file.GetLength(); // ÆÄÀÏ Çì´õ Àбâ if (file.Read((void *)&m_header, 13) != 13) return FALSE; // Æ÷¸Ë È®ÀÎ if (m_header.signature[0] != 'G' || m_header.signature[1] != 'I' || m_header.signature[2] != 'F') return FALSE; // ¹öÀü È®ÀÎ if (m_header.version[0] != '8' || ((m_header.version[1] != '7') && (m_header.version[1] != '9')) || m_header.version[2] != 'a') return FALSE; if (m_header.packed & 0x80) { // Àü¿ª ÆÈ·¹Æ® Àбâ m_globalColorTable = new SGifColorTable[256]; colorSize = 2 << (m_header.packed & 0x07); if (file.Read((void *)m_globalColorTable, colorSize * 3) != (unsigned int)colorSize*3) { delete[] m_globalColorTable; m_globalColorTable = NULL; return FALSE; } } // Read Gif Stream... m_size = fileSize - sizeof(SGifHeader) - colorSize * 3; m_stream = new BYTE[m_size]; if (file.Read((void *)m_stream, m_size) != m_size) { delete[] m_globalColorTable; m_globalColorTable = NULL; delete[] m_stream; m_stream = NULL; return FALSE; } file.Close(); // Read Gif Image from Stream... BOOL value = TRUE; while (value) { switch (ReadByte()) { case GIF_INTRODUSER: // Extension switch (ReadByte()) { case GIF_EXT_GRAPHIC_CTRL: AddGraphicControl(); break; case GIF_EXT_PLAIN_TEXT: AddPlainText(); break; case GIF_EXT_APPLICATION: AddApplication(); break; case GIF_EXT_COMMENT: AddComment(); break; default: Delete(); value = FALSE; break; } break; case GIF_DESC_IMAGE: AddImage(); break; case GIF_TERMINATOR: case GIF_TRAILER: value = FALSE; break; default: Delete(); value = FALSE; break; } } delete[] m_stream; m_stream = NULL; m_index = 0; return TRUE; } BOOL CImageGif::Play(CDC *pDC) { m_pDC = pDC; m_current = m_image; m_startTime = GetTickCount(); return TRUE; } void CImageGif::RealPlay() { HDC memDC; HBITMAP hBitmap, oldBitmap; m_endTime = GetTickCount(); if (100 <= (m_endTime - m_startTime)) { m_startTime = m_endTime; if (m_current->next == NULL) m_current = m_image; else m_current = m_current->next; } memDC = ::CreateCompatibleDC(m_pDC->m_hDC); hBitmap = ConvertToBitmap(m_pDC->m_hDC); oldBitmap = (HBITMAP)SelectObject(memDC, hBitmap); ::BitBlt(m_pDC->m_hDC, m_x, m_y, m_current->info.width, m_current->info.height, memDC, 0, 0, SRCCOPY); SelectObject(memDC, oldBitmap); DeleteObject(hBitmap); DeleteDC(memDC); } void CImageGif::Move(int x, int y) { m_x = x; m_y = y; } // Function : CImageGif::ConvertToImage // Descript : GIF À̹ÌÁö¸¦ CImage·Î º¯°æÇÑ´Ù. // - CImage::Create()À» ¸ÕÀú ÇÏ°í »ç¿ëÇØ¾ß ÇÑ´Ù. // Return : BOOL // Argument : HGLOBAL hHandle BOOL CImageGif::ConvertToImage(HGLOBAL hHandle) { unsigned long srcIndexY; unsigned long desIndexY; unsigned long desIndex; SGifColorTable *palette; BYTE color; if (m_current == NULL) return FALSE; unsigned long dx = m_current->info.width; unsigned long dy = m_current->info.height; unsigned long columns = (dx * 3 + 3) & ~3; // À̹ÌÁöÀÇ ÆÈ·¹Æ®°¡ ¾ø´Â °æ¿ì Àü¿ª ÆÈ·¹Æ®¸¦ °¡Á®¿Â´Ù. if (m_current->localColorTable) palette = m_current->localColorTable; else palette = m_globalColorTable; if (hHandle == NULL) return FALSE; // ¸Þ¸ð¸® °íÁ¤ BYTE * address = (BYTE *) ::GlobalLock(hHandle); for (unsigned long y = 0; y < dy; y++) { // Y Ãà »óÀÇ ½ÃÀÛ À§Ä¡°ª desIndexY = y * columns; srcIndexY = (dy - 1 - y) * dx; for (unsigned long x = 0; x < dx; x++) { desIndex = desIndexY + x * 3; color = m_current->image[srcIndexY + x]; if (m_header.bgColor == color) { // ¹è°æ»öÀ¸·Î ¹Ù²Û´Ù. // address[desIndex ] = MASK_BGCOLOR; // address[desIndex + 1] = MASK_BGCOLOR; // address[desIndex + 2] = MASK_BGCOLOR; address[desIndex ] = palette[color].blue; address[desIndex + 1] = palette[color].green; address[desIndex + 2] = palette[color].red; } else { // ÆÈ·¹Æ®¿¡¼­ À̹ÌÁöÀÇ »ö»óÀ» °¡Á®¿Â´Ù. address[desIndex ] = palette[color].blue; address[desIndex + 1] = palette[color].green; address[desIndex + 2] = palette[color].red; } } } // ¸Þ¸ð¸® ¹Ý³³ GlobalUnlock(hHandle); return TRUE; } HBITMAP CImageGif::ConvertToBitmap(HDC hDC) { HBITMAP hBitmap; BYTE *pBitmap; BITMAPINFOHEADER *pHeader; BYTE *pColorTable; BYTE *pImage; SGifColorTable *colorTable; unsigned long srcIndexY; unsigned long desIndexY; unsigned long x, y; unsigned long dx, dy; unsigned long columns; if (m_current == NULL) return FALSE; dx = m_current->info.width; dy = m_current->info.height; columns = (dx + 3) & ~3; unsigned long imageSize = columns * dy; pBitmap = new BYTE[sizeof(BITMAPINFOHEADER) + 256*sizeof(RGBQUAD) + imageSize]; pHeader = (BITMAPINFOHEADER *)pBitmap; pColorTable = pBitmap + sizeof(BITMAPINFOHEADER); pImage = pColorTable + 256*sizeof(RGBQUAD); // set header pHeader->biSize = sizeof(BITMAPINFOHEADER); pHeader->biWidth = m_current->info.width; pHeader->biHeight = m_current->info.height; pHeader->biPlanes = 1; pHeader->biBitCount = 8; pHeader->biCompression = BI_RGB; pHeader->biSizeImage = 0; pHeader->biXPelsPerMeter= 0; pHeader->biYPelsPerMeter= 0; pHeader->biClrUsed = 256; pHeader->biClrImportant = 256; // set color-table colorTable = (m_current->localColorTable)? m_current->localColorTable: m_globalColorTable; for (int i = 0, j = 0; j < 256; j++) { pColorTable[i++] = (j == m_header.bgColor)? 0: colorTable[j].blue; pColorTable[i++] = (j == m_header.bgColor)? 0: colorTable[j].green; pColorTable[i++] = (j == m_header.bgColor)? 0: colorTable[j].red; pColorTable[i++] = (BYTE)0; } // Set Background Color int bgColorIndex; if (m_header.bgColor == 0) { bgColorIndex = (int)m_current->image[0] * 4; } else { bgColorIndex = m_header.bgColor * 4; } pColorTable[bgColorIndex ] = 0; pColorTable[bgColorIndex + 1] = 0; pColorTable[bgColorIndex + 2] = 0; // copy image-data for (y = 0; y < dy; y++) { desIndexY = y * columns; srcIndexY = (dy - 1 - y) * dx; for (x = 0; x < dx; x++) { pImage[desIndexY + x] = m_current->image[srcIndexY + x]; } } // create bitmap image hBitmap = CreateDIBitmap(hDC, pHeader, CBM_INIT, pImage, (BITMAPINFO *)pBitmap, DIB_RGB_COLORS); delete[] pBitmap; return hBitmap; } void CImageGif::Delete() { SGifImage *image; SGifGraphicControlExt *graphicControl; SGifPlainTextExt *plainText; SGifApplicationExt *application; SGifCommentExt *comment; if (m_globalColorTable) { delete[] m_globalColorTable; m_globalColorTable = NULL; } while (m_image) { if (m_image->localColorTable) delete[] m_image->localColorTable; if (m_image->image) delete[] m_image->image; image = m_image->next; delete m_image; m_image = image; } while (m_graphicControl) { graphicControl = m_graphicControl->next; delete m_graphicControl; m_graphicControl = graphicControl; } while (m_plainText) { if (m_plainText->plainTextData) delete[] m_plainText->plainTextData; plainText = m_plainText->next; delete m_plainText; m_plainText = plainText; } while (m_application) { if (m_application->applicationData) delete[] m_application->applicationData; application = m_application->next; delete m_application; m_application = application; } while (m_comment) { if (m_comment->commentData) delete[] m_comment->commentData; comment = m_comment->next; delete m_comment; m_comment = comment; } } BOOL CImageGif::AddGraphicControl() { SGifGraphicControlExt *graphicControl, *current; int blockSize; blockSize = ReadByte(); graphicControl = new SGifGraphicControlExt; graphicControl->next = NULL; ReadN((BYTE *)graphicControl, blockSize); if (ReadByte()) { delete graphicControl; return FALSE; } // add if (m_graphicControl) { current = m_graphicControl; while (current->next) current = current->next; current->next = graphicControl; } else { m_graphicControl = graphicControl; } return TRUE; } BOOL CImageGif::AddPlainText() { SGifPlainTextExt *plainText, *current; int blockSize; blockSize = ReadByte(); plainText = new SGifPlainTextExt; plainText->next = NULL; ReadN((BYTE *)plainText, blockSize); plainText->dataSize = ReadByte(); plainText->plainTextData = new BYTE[plainText->dataSize]; ReadN((BYTE *)(plainText->plainTextData), plainText->dataSize); if (ReadByte()) { delete plainText; return FALSE; } // add if (m_plainText) { current = m_plainText; while (current->next) current = current->next; current->next = plainText; } else { m_plainText = plainText; } return TRUE; } BOOL CImageGif::AddApplication() { SGifApplicationExt *application, *current; int blockSize; blockSize = ReadByte(); application = new SGifApplicationExt; application->next = NULL; ReadN((BYTE *)application, blockSize); application->dataSize = ReadByte(); application->applicationData = new BYTE[application->dataSize]; ReadN((BYTE *)(application->applicationData), application->dataSize); if (ReadByte()) { delete application; return FALSE; } // add if (m_application) { current = m_application; while (current->next) current = current->next; current->next = application; } else { m_application = application; } return TRUE; } BOOL CImageGif::AddComment() { SGifCommentExt *comment, *current; comment = new SGifCommentExt; comment->next = NULL; comment->dataSize = ReadByte(); comment->commentData = new BYTE[comment->dataSize]; ReadN((BYTE *)(comment->commentData), comment->dataSize); if (ReadByte()) { delete comment; return FALSE; } // add if (m_comment) { current = m_comment; while (current->next) current = current->next; current->next = comment; } else { m_comment = comment; } return TRUE; } BOOL CImageGif::AddImage() { SGifImage *image, *current; BYTE codeSize; WORD tableSize, iTable; WORD finishCode, resetCode; WORD code, code1, code2, oldCode; SLzwTable *lzwTable; int colorSize = 0; // Image image = new SGifImage; image->next = NULL; ReadN((BYTE *)&(image->info), 9); image->localColorTable = NULL; if (image->info.packed & 0x80) { // Local Color Table image->localColorTable = new SGifColorTable[256]; colorSize = 2 << ( image->info.packed & 0x07); ReadN((BYTE *)image->localColorTable, colorSize * 3); } image->size = image->info.height * image->info.width; image->image = new BYTE[image->size]; // Set and Clear... m_current = image; lzwTable = new SLzwTable[4096]; memset((void *)lzwTable, 0, 4096*sizeof(SLzwTable)); // ¹®Á¦ °¡´É¼º... // start Decoding codeSize = ReadByte(); tableSize = (1 << codeSize) + 2; finishCode = tableSize - 1; resetCode = finishCode - 1; codeSize++; m_codeSize = codeSize; iTable = tableSize; SetDecode(); while ((code = ReadCode()) != finishCode) { if (code == resetCode) { m_codeSize = codeSize; iTable = tableSize; oldCode = ReadCode(); if (oldCode > iTable) { // free image if (image->localColorTable) delete[] image->localColorTable; if (image->image) delete[] image->image; delete image; delete[] lzwTable; return FALSE; } Output((BYTE)oldCode); } else if (code < iTable) { // Code exist in the LZW-Table code1 = code; code2 = 0; while (code1 >= tableSize) { lzwTable[code1].next = code2; code2 = code1; code1 = lzwTable[code1].previous; if (code1 >= code2) { // free image if (image->localColorTable) delete[] image->localColorTable; if (image->image) delete[] image->image; delete image; delete[] lzwTable; return FALSE; } } Output((BYTE)code1); while (code2 != 0) { Output(lzwTable[code2].bits); code2 = lzwTable[code2].next; } lzwTable[iTable].bits = (BYTE)code1; lzwTable[iTable].previous = oldCode; iTable++; if (iTable == (1 << m_codeSize)) { m_codeSize++; if (m_codeSize > 12) m_codeSize = 12; } oldCode = code; } else { // Code doesn't exist int LZW-Table code1 = oldCode; code2 = 0; while (code1 >= tableSize) { lzwTable[code1].next = code2; code2 = code1; code1 = lzwTable[code1].previous; if (code1 >= code2) { // free image if (image->localColorTable) delete[] image->localColorTable; if (image->image) delete[] image->image; delete image; delete[] lzwTable; return FALSE; } } Output((BYTE)code1); while (code2 != 0) { Output(lzwTable[code2].bits); code2 = lzwTable[code2].next; } Output((BYTE)code1); lzwTable[iTable].bits = (BYTE)code1; lzwTable[iTable].previous = oldCode; iTable++; if (iTable == (1 << m_codeSize)) { m_codeSize++; if (m_codeSize > 12) m_codeSize = 12; } oldCode = code; } } delete[] lzwTable; if (ReadByte()) { if (image->localColorTable) delete[] image->localColorTable; if (image->image) delete[] image->image; delete image; return FALSE; } // add if (m_image) { current = m_image; while (current->next) current = current->next; current->next = image; } else { m_image = image; } return TRUE; } void CImageGif::SetDecode() { m_readBlock = 0; m_code = 0; m_remain = 0; m_x = 0; m_y = 0; m_pass = 0; } BYTE CImageGif::ReadByte() { BYTE value = (m_index < m_size) ? m_stream[m_index] : 0; m_index++; return value; } BOOL CImageGif::ReadN(BYTE *array, int n) { int i; for (i = 0; i < n && m_index < m_size; i++) array[i] = m_stream[m_index++]; return (i == n) ? TRUE: FALSE; } WORD CImageGif::ReadCode() { unsigned long newByte; WORD word = 1; while (m_remain < m_codeSize) { if (m_readBlock <= 0) { m_readBlock = ReadByte(); if (m_readBlock == 0) { m_index--; return 0xFF; } } m_readBlock--; newByte = (unsigned long)ReadByte(); newByte <<= m_remain; m_code |= newByte; m_remain += 8; } word <<= m_codeSize; word--; word &= (WORD)m_code; m_code >>= m_codeSize; m_remain -= m_codeSize; return word; } void CImageGif::Output(BYTE pixel) { unsigned long index; if(m_x >= m_current->info.width) { m_x = 0; if (m_current->info.packed & 0x40) { // interlaced mode switch (m_pass) { case 0: m_y += 8; break; case 1: m_y += 8; break; case 2: m_y += 4; break; case 3: m_y += 2; break; } if (m_y >= m_current->info.height) { m_pass += 1; m_y = 8 >> m_pass; } } else { // Non-interlaced mode m_y++; } } index = m_y * m_current->info.width + m_x; m_x++; if (index >= m_current->size) return; m_current->image[index] = pixel; } // Function : CImage::LoadGIF // Descript : GIF À̹ÌÁö¸¦ ·Îµå ÇÑ´Ù. // Return : BOOL // Argument : LPCTSTR lpszFileName BOOL CImage::LoadGIF(LPCTSTR lpszFileName) { CImageGif gifImage; if (gifImage.Load(lpszFileName)) { // In case of animat-gif, First image is converted to DIB. // Make DIB gifImage.m_current = gifImage.m_image; Create(gifImage.m_current->info.width, gifImage.m_current->info.height); gifImage.ConvertToImage(m_hImage); // If this is animate-gif then you consider animate-flag. // if (gifImage.m_image->next) animate = TRUE; } else return FALSE; return TRUE; }