U E D R , A S I H C RSS

Project Semi Photoshop/Spike Solution

이 페이지는 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<m_Size.cy;i+=2)
	{
		for (j=0;j<m_Size.cx;j+=2)
		{
			avrcolor = 0;
			avrcolor += (int)((BYTE *)pPixels)[i*lw+j];
			avrcolor += (int)((BYTE *)pPixels)[i*lw+(j+1)];
			avrcolor += (int)((BYTE *)pPixels)[(i+1)*lw+j];
			avrcolor += (int)((BYTE *)pPixels)[(i+1)*lw+(j+1)];
			avrcolor/=4;
			((BYTE *)pPixels)[i*lw+j] = (char)avrcolor;
			((BYTE *)pPixels)[i*lw+(j+1)] = (char)avrcolor;
			((BYTE *)pPixels)[(i+1)*lw+j] = (char)avrcolor;
			((BYTE *)pPixels)[(i+1)*lw+(j+1)] = (char)avrcolor;
		}
	}
	// 메모리 놓아줌
	::GlobalUnlock((HGLOBAL) m_hImage);

	return (HDIB)pDIB;
}

이미지 화일 읽고 쓰기

이미지 화일 읽고 쓰기

이미지 화일 읽고 쓰기

이미지 화일 읽고 쓰기

이미지 화일 읽고 쓰기


추정 요약

=== ===

Thread

내 생각엔 SpikeSolution 과정에서 중복된 코드가 나올것 같고 나중에 이것들을 묶어서 단순한 설계를 구현시킬 수 있을 것 같다.
오 신기하다. 이걸로 솔루션이 세개쯤인거네, 우리조는 선택도 할수 있네 대단한조 ;; --neocoin

지금 위키 참 맘에 안드네.. BR테그 쓰는 법이 뭐라구? ㅡ.ㅡ
~cpp [[BR]] 이것, 하지만 쓰지 않고 얼마든지 방법이 ;;


관하여

* 배포 계획 수립 회의
  1. 성공적인 제품을 정의하기 위해 충분한 스토리를 작성한다.
  2. 필요한 조사를 수행한다.
  3. 각 스토리 구현의 난이도를 추정한다.
  4. 스토리 구현 속도를 추정한다.
  5. 비즈니스 가치와 난이도에 기반하여 첫번째 배포를 하기 위한 스토리를 선택한다.

* 코드의 공동 소유

* 단순한 설계
  1. 모든 테스트를 실행한다.
  2. 모든 아이디어를 표현한다.
  3. 중복된 코드를 포함하지 않는다.
  4. 최소한의 클래스와 메소드를 가진다.

Valid XHTML 1.0! Valid CSS! powered by MoniWiki
last modified 2009-05-27 07:09:19
Processing time 0.0866 sec