이 페이지는 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. 최소한의 클래스와 메소드를 가진다.

Retrieved from http://wiki.zeropage.org/wiki.php/ProjectSemiPhotoshop/SpikeSolution
last modified 2021-02-07 05:24:06