이 페이지는 ["ProjectSemiPhotoshop"]의 Spike Solution 페이지 입니다. ---- ["ProjectSemiPhotoshop/요구사항"]에 있는 스토리의 난이도를 추정하고 문제 영역 전반을 다루는 페이지입니다. 기존 테스트만 하는 방식을 떠나.. 팀플 시간관계상 소스 구현을 재활용/체계화하는 목적으로 두었습니다. == Spike Solution == === 이미지 클래스 전체 모습 === {{{~cpp class CImage { protected: HDIB m_hImage; //image handle HDIB m_hUndoImage; //undo image handle CSize m_Size; //image size public: BOOL InitDIB(BOOL bCreatePalette = TRUE); void SetHandle(HANDLE hHandle); BOOL CreateDIBPalette(); virtual ~CImage() { Free(); } void Free(); int GetBitCount(); HDIB GetHandle() {return m_hImage;} BOOL IsDataNull() {return (m_hImage == NULL);} CSize GetSize() {return m_Size;} int GetHeight() {return m_Size.cy;} int GetWidth() {return m_Size.cx;} int GetRealWidth() {return WIDTHBYTES((GetWidth()*GetBitCount()));} HDIB GetUndoHandle() {return m_hUndoImage;} CPalette *GetPalette() {return m_pPal;} BOOL Draw(HDC hDC, LPRECT sourceRect, LPRECT destRect); BOOL Save(LPCTSTR lpszFileName); BOOL Load(LPCTSTR lpszFileName); protected: BOOL LoadBMP(LPCTSTR lpszFileName); BOOL SaveBMP(LPCTSTR lpszFileName); }; /****************************************************** DIB와 관련된 전역 함수 ******************************************************/ LPSTR WINAPI FindDIBBits(LPSTR lpbi) { return (lpbi + *(LPDWORD)lpbi + ::PaletteSize(lpbi)); } DWORD WINAPI DIBWidth(LPSTR lpDIB) { LPBITMAPINFOHEADER lpbmi; // pointer to a Win 3.0-style DIB LPBITMAPCOREHEADER lpbmc; // pointer to an other-style DIB /* point to the header (whether Win 3.0 and old) */ lpbmi = (LPBITMAPINFOHEADER)lpDIB; lpbmc = (LPBITMAPCOREHEADER)lpDIB; /* return the DIB width if it is a Win 3.0 DIB */ if (IS_WIN30_DIB(lpDIB)) return lpbmi->biWidth; else /* it is an other-style DIB, so return its width */ return (DWORD)lpbmc->bcWidth; } DWORD WINAPI DIBHeight(LPSTR lpDIB) { LPBITMAPINFOHEADER lpbmi; // pointer to a Win 3.0-style DIB LPBITMAPCOREHEADER lpbmc; // pointer to an other-style DIB /* point to the header (whether old or Win 3.0 */ lpbmi = (LPBITMAPINFOHEADER)lpDIB; lpbmc = (LPBITMAPCOREHEADER)lpDIB; /* return the DIB height if it is a Win 3.0 DIB */ if (IS_WIN30_DIB(lpDIB)) return lpbmi->biHeight; else /* it is an other-style DIB, so return its height */ return (DWORD)lpbmc->bcHeight; } WORD WINAPI PaletteSize(LPSTR lpbi) { /* calculate the size required by the palette */ if (IS_WIN30_DIB (lpbi)) return (WORD)(::DIBNumColors(lpbi) * sizeof(RGBQUAD)); else return (WORD)(::DIBNumColors(lpbi) * sizeof(RGBTRIPLE)); } WORD WINAPI DIBNumColors(LPSTR lpbi) { WORD wBitCount; // DIB bit count /* If this is a Windows-style DIB, the number of colors in the * color table can be less than the number of bits per pixel * allows for (i.e. lpbi->biClrUsed can be set to some value). * If this is the case, return the appropriate value. */ if (IS_WIN30_DIB(lpbi)) { DWORD dwClrUsed; dwClrUsed = ((LPBITMAPINFOHEADER)lpbi)->biClrUsed; if (dwClrUsed != 0) return (WORD)dwClrUsed; } /* Calculate the number of colors in the color table based on * the number of bits per pixel for the DIB. */ if (IS_WIN30_DIB(lpbi)) wBitCount = ((LPBITMAPINFOHEADER)lpbi)->biBitCount; else wBitCount = ((LPBITMAPCOREHEADER)lpbi)->bcBitCount; /* return number of colors based on bits per pixel */ switch (wBitCount) { case 1: return 2; case 4: return 16; case 8: return 256; default: return 0; } } /****************************************************** 클립보드를 위한 전역 함수 ******************************************************/ HGLOBAL WINAPI CopyHandle (HGLOBAL h) { if (h == NULL) return NULL; DWORD dwLen = ::GlobalSize((HGLOBAL) h); HGLOBAL hCopy = ::GlobalAlloc(GHND, dwLen); if (hCopy != NULL) { void* lpCopy = ::GlobalLock((HGLOBAL) hCopy); void* lp = ::GlobalLock((HGLOBAL) h); memcpy(lpCopy, lp, dwLen); ::GlobalUnlock(hCopy); ::GlobalUnlock(h); } return hCopy; } }}} === 이미지 화일 읽고 쓰기 === {{{~cpp BOOL CImage::Load(LPCTSTR lpszFileName) { CString filetype; filetype = lpszFileName; filetype.MakeUpper(); if(filetype.Find(".BMP") > -1) return LoadBMP(lpszFileName); else if(filetype.Find(".TIF") > -1) return LoadTIF(lpszFileName); else if(filetype.Find(".GIF") > -1) return LoadGIF(lpszFileName); else if(filetype.Find(".JPG") > -1) return LoadJPG(lpszFileName); else return FALSE; } }}} {{{~cpp BOOL CImage::LoadBMP(LPCTSTR lpszFileName) { CFile file; CFileException fe; LPSTR pDIB; DWORD dwBitsSize; BITMAPFILEHEADER bmfHeader; // 읽기 모드로 파일 열기 if(!file.Open(lpszFileName, CFile::modeRead|CFile::shareDenyWrite, &fe)) return FALSE; // 파일의 길이를 구함 dwBitsSize = file.GetLength(); // 파일 헤더 읽기 if(file.Read((LPSTR)&bmfHeader, sizeof(bmfHeader))!=sizeof(bmfHeader)) return FALSE; // BMP 파일임을 나타내는 "BM" 마커가 있는지 확인 if (bmfHeader.bfType != DIB_HEADER_MARKER) return FALSE; // 메모리 할당 if((m_hImage = (HDIB)::GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, dwBitsSize)) == NULL) return FALSE; // 메모리 고정 pDIB = (LPSTR) ::GlobalLock((HGLOBAL) m_hImage); // 파일 읽기 if (file.ReadHuge(pDIB, dwBitsSize - sizeof(BITMAPFILEHEADER)) != dwBitsSize - sizeof(BITMAPFILEHEADER) ) { ::GlobalUnlock((HGLOBAL) m_hImage); ::GlobalFree((HGLOBAL) m_hImage); return FALSE; } // 메모리 풀어줌 ::GlobalUnlock((HGLOBAL) m_hImage); // DIB 초기화 InitDIB(); return TRUE; } }}} {{{~cpp BOOL CImage::Save(LPCTSTR lpszFileName) { CString filetype; filetype = lpszFileName; filetype.MakeUpper(); if(filetype.Find(".BMP") > -1) return SaveBMP(lpszFileName); else if(filetype.Find(".TIF") > -1) return SaveTIF(lpszFileName); else if(filetype.Find(".GIF") > -1) return SaveGIF(lpszFileName); else if(filetype.Find(".JPG") > -1) return SaveJPG(lpszFileName); else return FALSE; } }}} {{{~cpp BOOL CImage::SaveBMP(LPCTSTR lpszFileName) { CFile file; CFileException fe; BITMAPFILEHEADER bmfHdr; LPBITMAPINFOHEADER lpBI; DWORD dwDIBSize; // 쓰기 모드로 파일 열기 if (!file.Open(lpszFileName, CFile::modeCreate | CFile::modeWrite | CFile::shareDenyWrite, &fe)) return FALSE; // 메모리 핸들이 유효한지 확인 if (m_hImage == NULL) return FALSE; // 메모리 고정 lpBI = (LPBITMAPINFOHEADER)::GlobalLock((HGLOBAL)m_hImage); if (lpBI == NULL) return FALSE; // 비트맵 파일 헤더 정보를 설정 bmfHdr.bfType = DIB_HEADER_MARKER; // "BM" dwDIBSize = *(LPDWORD)lpBI + ::PaletteSize((LPSTR)lpBI); if((lpBI->biCompression==BI_RLE8) || (lpBI->biCompression==BI_RLE4)) dwDIBSize += lpBI->biSizeImage; else { DWORD dwBmBitsSize; // Size of Bitmap Bits only dwBmBitsSize = WIDTHBYTES((lpBI->biWidth)*((DWORD)lpBI->biBitCount)) * lpBI->biHeight; dwDIBSize += dwBmBitsSize; lpBI->biSizeImage = dwBmBitsSize; } bmfHdr.bfSize = dwDIBSize + sizeof(BITMAPFILEHEADER); bmfHdr.bfReserved1 = 0; bmfHdr.bfReserved2 = 0; bmfHdr.bfOffBits=(DWORD)sizeof(BITMAPFILEHEADER)+lpBI->biSize + PaletteSize((LPSTR)lpBI); TRY { // 비트맵 파일 헤더를 파일에 쓰기 file.Write((LPSTR)&bmfHdr, sizeof(BITMAPFILEHEADER)); // 나머지 데이터를 파일에 쓰기 file.WriteHuge(lpBI, dwDIBSize); } CATCH (CFileException, e) { ::GlobalUnlock((HGLOBAL) m_hImage); THROW_LAST(); } END_CATCH // 메모리 풀어줌 ::GlobalUnlock((HGLOBAL) m_hImage); return TRUE; } }}} === 모자이크 처리 부분 === {{{~cpp HDIB CMyImage::MosaicProcess() { LPSTR pDIB; LPSTR pPixels; int i,j; long lw; // 실제 쓰여진 Width값입니다. int avrcolor; // 변환 후의 Color값입니다. // 메모리 고정 pDIB = (LPSTR) ::GlobalLock((HGLOBAL) m_hImage); //이미지데이타 처음 위치를 구합니다. pPixels = DataBits(pDIB); // 이미지 가로는 4의 배수로 저장됨으로 값을 더 더합니다. lw = m_Size.cx + (m_Size.cx%4>0?(4-m_Size.cx%4):0); // 네칸의 픽셀값을 동일한 값으로 평균화 합니다. for (i=0;i