소연의_개발일지
article thumbnail

 

 

단축키

ctrl + K + O →  헤더 파일로 이동

 


C++ 접근 지정자

C++에서 클래스나 구조체의 멤버에 대한 접근 지정자(access specifier)는 총 3가지이다: private, public, protected.

각 접근 지정자에 대한 설명은 다음과 같다.

 

1. private

  • private으로 지정된 멤버는 해당 클래스 내에서만 접근이 가능하다.
  • 외부에서 직접 접근하려고 하면 컴파일 에러가 발생한다.
  • 기본적으로 클래스의 멤버들은 private으로 설정된다.
class MyClass {
private:
    int myPrivateVar;
};

2. public

  • public으로 지정된 멤버는 어디서든지 접근이 가능하다.
  • 주로 클래스의 인터페이스로 사용되는 메서드들을 public으로 지정한다.
class MyClass {
public:
    void myPublicMethod() {}
};

3. protected

  • protected로 지정된 멤버는 해당 클래스와 파생된 클래스 내에서만 접근이 가능하다.
  • private과 유사하지만, 상속을 받은 클래스에서도 접근이 가능하다는 차이점이 있다.
class BaseClass {
protected:
    int myProtectedVar;
};

class DerivedClass : public BaseClass {
public:
    void accessProtectedVar() {
        myProtectedVar = 10; // 가능
    }
};

이러한 접근 지정자들은 객체 지향 프로그래밍에서 캡슐화(encapsulation)의 원칙을 구현하기 위해 사용된다.

멤버 변수와 함수의 접근을 적절히 제한함으로써 클래스의 내부 동작을 보호하고 안정성을 유지하는 데 도움을 준다.


그림 그리기

mfcImage라는 프로젝트를 생성했다.

UI는 아래와 같은 식으로 제작했고, 우측 상단의 image 버튼의 ID는 IDC_BTN_IMAGE 이다.

mfcCImageDIg.h 파일 다이얼로그에 이미지 변수를 private로 생성한다.

// CmfcCImageDlg 대화 상자
class CmfcCImageDlg : public CDialogEx
{
// 외부에서 사용하지 않는다는 표시를 해줌 private
private: 
	CImage m_image;

 

다이얼로그 UI에서 우측 상단의 버튼 image를 더블클릭하여 클릭했을 때 발생할 이벤트 함수르 생성한다.

void CmfcCImageDlg::OnBnClickedBtnImage()
{
}

 

 

mfcCImageDIg.h 파일에서 버튼 클릭 이벤트 함수 밑에 삽입할 이미지 변수를 생성한다.

  • nWidth, nHeight: 가로폭, 세로폭
  • m_image.Create(가로, 세로, gray level): 가로폭과 세로폭, gray Level 에 맞춰 이미지 생성
  • CClient DC dc(this): 클라이언트 형태의 변수를 dc라고 선언한 후 초기화를 this에 한다고 설정(this는 현재 다이얼로그)
  • m_image.Draw(dc, 0, 0) : dc 객체의 0.0에 이미지를 그리겠다고 선언한다.
void CmfcCImageDlg::OnBnClickedBtnImage()
{
	// 클래스에서 사용하는 변수(n이 붙는다)
	// 멤버변수 지역변수
	int nWidth = 640; // 가로폭
	int nHeight = 480; // 세로폭	
	int nBpp = 8; // gray level

	// 이미지 생성
	m_image.Create(640, 480, 8);

	// 이미지 그리기
	CClientDC dc(this); // 클라이언트 형태의 변수를 dc로 만들고 초기화를 this로 하겠다. -> this는 현재 가지고 있는 다이얼로그를 의미함
	m_image.Draw(dc, 0, 0); // 그리기 (어디에 그릴지, 위치를 x, y 축을 설정해 준다.)


}

 

코드를 실행시킨 후 버튼을 누르면 0.0 위치에 크기만큼 검은 화면이 나타난다.

 

위에서 설정한 변수를 사용하여 코드를 수정한다.

파라미터로 넘겨주는 값은 숫자를 쓰면 나중에 디버깅할때나 유지보수에 불편한다.

void CmfcCImageDlg::OnBnClickedBtnImage()
{
	// 클래스에서 사용하는 변수(n이 붙는다)
	// 멤버변수 지역변수
	int nWidth = 640; // 가로폭
	int nHeight = 480; // 세로폭	
	int nBpp = 8; // gray level

	// 이미지 생성
	m_image.Create(nWidth, nHeight, nBpp); // 모든 변수를 만들때는 파라마터 값에 숫자를 안 주는게 중요하다. -> 위에서 설정한 변수를 사용해 준다.

	// 이미지 그리기
	CClientDC dc(this); // 클라이언트 형태의 변수를 dc로 만들고 초기화를 this로 하겠다. -> this는 현재 가지고 있는 다이얼로그를 의미함
	m_image.Draw(dc, 0, 0); // 그리기 (어디에 그릴지, 위치를 x, y 축을 설정해 준다.)


}

 

 

이 코드 내에 rgb값을 설정해준다.

void CmfcCImageDlg::OnBnClickedBtnImage()
{
	// 클래스에서 사용하는 변수(n이 붙는다)
	// 멤버변수 지역변수
	int nWidth = 640; // 가로폭
	int nHeight = 480; // 세로폭	
	int nBpp = 8; // gray level

	// 이미지 생성
	m_image.Create(nWidth, nHeight, nBpp); // 모든 변수를 만들때는 파라마터 값에 숫자를 안 주는게 중요하다. -> 위에서 설정한 변수를 사용해 준다.

	// 조건 작성
	// 흑백을 기준으로 display 하게 되어있기 때문에 컬러로 할려면 설정을 따로 해줘야 한다.

	if (nBpp == 8) {
		static RGBQUAD rgb[256]; // RGBQUAD 구조체 타입의 배열인 'RGB'를 선언하고 초기화하는 코드
		for (int i = 0; i < 25; i++) // 각각 RGB값 설정
			rgb[i].rgbRed = rgb[i].rgbGreen = rgb[i].rgbBlue = i;
		m_image.SetColorTable(0, 256, rgb);
	}

	// 이미지 그리기
	CClientDC dc(this); // 클라이언트 형태의 변수를 dc로 만들고 초기화를 this로 하겠다. -> this는 현재 가지고 있는 다이얼로그를 의미함
	m_image.Draw(dc, 0, 0); // 그리기 (어디에 그릴지, 위치를 x, y 축을 설정해 준다.)


}

 

 

이미지 색 변환하기

아래의 코드를 추가해 준다. 아래 코드는 각 픽셀마다 색을 할당해 주는 코드이다.

	for (int j = 0; j < nHeight; j++) {
		for (int i = 0; i < nWidth; i++) {
			// 2d 이미지 좌표 (i, j)를 1D메모리 주소로 변환한다. 
			// 255는 해당 픽셀의 값에 할당된다. 255를 할당하면 흰색으로 표시된다.
			// nBpp=8이 그레이스케일이미지므로 0(검은색) 부터 255(흰색)까지 값이 할당된다.
			fm[j * nPitch + i] = 255; 
			
		}
	}

전체 코드

  • GetPitch() 함수
    • 이미지의 픽셀 데이터가 메모리에서 연속적으로 배열되는 방식을 설명하기 위해 사용되는 값
    • 이 값은 이미지의 한 줄(한 행)의 데이터가 메모리에서 차지하는 바이트 수를 나타냄
    • 일반적으로 이미지 데이터는 행 단위로 연속적으로 저장되며, 각 행의 끝과 다음 행의 시작 사이에는 일정한 간격(패딩)이 있을 수 있음
    • GetPich() 함수는 이러한 간격을 고려하여 이미지 데이터의 한 행이 메모리에서 차지하는 바이트 수를 반환한다. 이를 통해 이미지 데이터를 직접 다룰 때 각 픽셀의 위치를 올바르게 계산할 수 있다.
void CmfcCImageDlg::OnBnClickedBtnImage()
{
	// 클래스에서 사용하는 변수(n이 붙는다)
	// 멤버변수 지역변수
	int nWidth = 640; // 가로폭
	int nHeight = 480; // 세로폭	
	int nBpp = 8; // gray level

	// 이미지 생성
	m_image.Create(nWidth, nHeight, nBpp); // 모든 변수를 만들때는 파라마터 값에 숫자를 안 주는게 중요하다. -> 위에서 설정한 변수를 사용해 준다.

	// 조건 작성
	// 흑백을 기준으로 display 하게 되어있기 때문에 컬러로 할려면 설정을 따로 해줘야 한다.

	if (nBpp == 8) {
		static RGBQUAD rgb[256];
		for (int i = 0; i < 256; i++)
			rgb[i].rgbRed = rgb[i].rgbGreen = rgb[i].rgbBlue = i;
		m_image.SetColorTable(0, 256, rgb);
	}

	int nPitch = m_image.GetPitch();
	unsigned char* fm = (unsigned char*)m_image.GetBits(); // 내가 만든 이미지의 첫번째 포인터의 값을 가져오겠다.
	
	// fm은 이미지 데이터의 시작 포인터를 가리킨다. 이미지 데이터는 메모리에 연속적으로 배열된 행으로 구성된다.
	// 각 행의 끝과 다음 행의 시작 사이에는 간격(nPitch)가 있을 수 있다.

	
	for (int j = 0; j < nHeight; j++) {
		for (int i = 0; i < nWidth; i++) {
			// 2d 이미지 좌표 (i, j)를 1D메모리 주소로 변환한다. 
			// 255는 해당 픽셀의 값에 할당된다. 255를 할당하면 흰색으로 표시된다.
			// nBpp=8이 그레이스케일이미지므로 0(검은색) 부터 255(흰색)까지 값이 할당된다.
			fm[j * nPitch + i] = 255; 
			
		}
	}

	// 이미지 그리기
	CClientDC dc(this); // 클라이언트 형태의 변수를 dc로 만들고 초기화를 this로 하겠다. -> this는 현재 가지고 있는 다이얼로그를 의미함
	m_image.Draw(dc, 0, 0); // 그리기 (어디에 그릴지, 위치를 x, y 축을 설정해 준다.)


}

적용 사진

흰색 사각형이 0, 0 에 위치한다.

 

 

여기서 255 값을 j%255로 바꾸면 아래와 같이 그라데이션 모양이 나온다.

 

특정 위치에 원하는 색으로 점 찍기(각 숫자는 y축, x축에 위치하게 된다)

= 뒤에 원하는 색을 지정해 준다.

	// 특정 위치에 원하는 색으로 점 찍기(y, x)
	fm[12 * nPitch + 16] = 0;
	fm[0*nPitch + 0] = 255;

 

사진 저장하기

<이미지 객체>.Save(_T("<사진경로>"));
// 이미지 저장하기
	m_image.Save(_T("c:\\image\\save.bmp"));

 

전체 코드

더보기
void CmfcCImageDlg::OnBnClickedBtnImage()
{
	// 클래스에서 사용하는 변수(n이 붙는다)
	// 멤버변수 지역변수
	int nWidth = 32; // 가로폭 픽셀
	int nHeight = 24; // 세로폭 픽셀
	int nBpp = 8; // gray level

	// 이미지 생성
	m_image.Create(nWidth, nHeight, nBpp); // 모든 변수를 만들때는 파라마터 값에 숫자를 안 주는게 중요하다. -> 위에서 설정한 변수를 사용해 준다.

	// 조건 작성
	// 흑백을 기준으로 display 하게 되어있기 때문에 컬러로 할려면 설정을 따로 해줘야 한다.

	if (nBpp == 8) {
		static RGBQUAD rgb[256];
		for (int i = 0; i < 256; i++)
			rgb[i].rgbRed = rgb[i].rgbGreen = rgb[i].rgbBlue = i;
		m_image.SetColorTable(0, 256, rgb);
	}

	int nPitch = m_image.GetPitch();
	unsigned char* fm = (unsigned char*)m_image.GetBits(); // 내가 만든 이미지의 첫번째 포인터의 값을 가져오겠다.
	
	// fm은 이미지 데이터의 시작 포인터를 가리킨다. 이미지 데이터는 메모리에 연속적으로 배열된 행으로 구성된다.
	// 각 행의 끝과 다음 행의 시작 사이에는 간격(nPitch)가 있을 수 있다.

	
	for (int j = 0; j < nHeight; j++) {
		for (int i = 0; i < nWidth; i++) {
			// 2d 이미지 좌표 (i, j)를 1D메모리 주소로 변환한다. 
			// 255는 해당 픽셀의 값에 할당된다. 255를 할당하면 흰색으로 표시된다.
			// nBpp=8이 그레이스케일이미지므로 0(검은색) 부터 255(흰색)까지 값이 할당된다.
			fm[j * nPitch + i] = (j*10)%255; 
			
		}
	}

	// 특정 위치에 원하는 색으로 점 찍기(x, y)
	fm[12 * nPitch + 16] = 0;
	fm[0*nPitch + 0] = 255;

	// 이미지 그리기
	CClientDC dc(this); // 클라이언트 형태의 변수를 dc로 만들고 초기화를 this로 하겠다. -> this는 현재 가지고 있는 다이얼로그를 의미함
	m_image.Draw(dc, 0, 0); // 그리기 (어디에 그릴지, 위치를 x, y 축을 설정해 준다.)
	
	// 이미지 저장하기
	m_image.Save(_T("c:\\image\\save.bmp"));

저장한 사진을 보면 0, 0 위치에 흰색이, 가운데에 검은색 점이 찍혀있는걸 확인할 수 있다.

 

이 사진들은 가로로 나열되어 저장된다.(아래 사진 참조)


이미지 데이터가 메모리에 어떻게 배열되어 있는지 이해하기(nPitch)

이미지 데이터는 일반적으로 행 기반(row-based)으로 메모리에 저장된다. 그러나 각 행(row)이 꼭 연속적인 메모리 공간에 위치하는 것은 아니다. 대신 각 행의 시작과 다음 행의 시작 사이에 추가적인 메모리 공간(padding 또는 stride라고 부릅니다)이 존재할 수 있다.

이 때, nPitch는 다음과 같은 의미를 가진다.
1. 양수 값: 각 행의 시작과 다음 행의 시작 사이의 전체 바이트 수를 나타낸다. (픽셀 데이터 + 추가 메모리 공간)
2. 음수 값: 일부 구현에서는 이미지 데이터가 메모리에 상단에서 하단이 아닌, 하단에서 상단으로 저장되기 때문에 음수 값을 가질 수 있다.

따라서, j * nPitch는 j번째 행의 시작 주소를 나타낸다. 그리고 + i를 통해 그 행에서 i번째 픽셀에 접근한다.
for문에서 fm[j * nPitch + i] 를 사용하는 이유는, 이미지 데이터들이 아래와 같이 배열로 저장되기 때문이다.


memset 사용하기

 

아래 한 줄의 코드를

memset(fm, 0xff, nWidth * nHeight); // 메모리를 어떠한 값으로 연결할 것인지

이 코드 대신 대체할 수 있다. 

	for (int j = 0; j < nHeight; j++) {
		for (int i = 0; i < nWidth; i++) {
			// 2d 이미지 좌표 (i, j)를 1D메모리 주소로 변환한다. 
			// 255는 해당 픽셀의 값에 할당된다. 255를 할당하면 흰색으로 표시된다.
			// nBpp=8이 그레이스케일이미지므로 0(검은색) 부터 255(흰색)까지 값이 할당된다.
			fm[j * nPitch + i] = (j*60)%255; 
			
		}
	}

하지만 이미지 생성 부분에서 nHeight에 -(마이너스)를 붙여줘야 한다.

그 이유는 MFC의 CImage 클래스의 특별한 특성과 관련이 있다.

// 이미지 생성
	m_image.Create(nWidth, -nHeight, nBpp);

 

CImage는 nHeight 값이 음수일 때와 양수일 때 이미지 데이터를 메모리에 다르게 저장한다.

1. nHeight가 양수일 때:
이미지 데이터는 일반적인 행 순서로 저장된다. 첫 번째 행이 메모리의 첫 번째 위치에 있고, 마지막 행이 마지막 위치에 있다. 하지만 이 경우에는 nPitch (stride 또는 간격) 때문에 각 행 간에 추가 메모리 공간이 있을 수 있다.

2. nHeight가 음수일 때:
이미지 데이터는 메모리에 역순으로 저장된다. 마지막 행이 메모리의 첫 번째 위치에 있고, 첫 번째 행이 마지막 위치에 있다. 이 방식은 BMP 이미지 형식과 같이 데이터가 기본적으로 역순으로 저장되는 경우에 유용하다.

memset(fm, 0xff, nWidth * nHeight); 코드는 모든 픽셀 값을 255(0xff)로 설정한다. 그러나 원래의 루프는 각 픽셀에 (j*60)%255 값을 할당하므로, 두 코드 사이에는 차이가 있다. memset은 모든 픽셀을 흰색으로 만들지만, 원래의 루프는 행에 따라 다양한 그레이스케일 값을 픽셀에 할당하게 된다.

이미지 저장 & 로드하기

// 전역변수로 선언
CString g_strFileImage = _T("c:\\image\\save.bmp");
void CmfcCImageDlg::OnBnClickedButton2()
{
	// 이미지 저장하기
	m_image.Save(g_strFileImage);
}


void CmfcCImageDlg::OnBnClickedButton3()
{
	// 이미지가 없으면 제거
	if (m_image != NULL) {
		m_image.Destroy();
	}
	// 이미지 로드하기
	m_image.Load(g_strFileImage);

	CClientDC dc(this); 
	m_image.Draw(dc, 0, 0);
}

 

 

함수화 해보기

아래 부분이 반복되기 때문에 함수화를 하여 간단하게 해 보자.

CClientDC dc(this); 
m_image.Draw(dc, 0, 0);

 

사각형 움직이게 하기

 

void CmfcCImageDlg::OnBnClickedBtnImage()
{
	// 클래스에서 사용하는 변수(n이 붙는다)
	// 멤버변수 지역변수
	int nWidth = 640; // 가로폭 픽셀
	int nHeight = 480; // 세로폭 픽셀
	int nBpp = 8; // gray level

	// 이미지 생성
	m_image.Create(nWidth, -nHeight, nBpp); // 모든 변수를 만들때는 파라마터 값에 숫자를 안 주는게 중요하다. -> 위에서 설정한 변수를 사용해 준다.
	BOOL vaildImgPos(int x, int y);

	// 조건 작성
	// 흑백을 기준으로 display 하게 되어있기 때문에 컬러로 할려면 설정을 따로 해줘야 한다.

	if (nBpp == 8) {
		static RGBQUAD rgb[256];
		for (int i = 0; i < 256; i++)
			rgb[i].rgbRed = rgb[i].rgbGreen = rgb[i].rgbBlue = i;
		m_image.SetColorTable(0, 256, rgb);
	}

	int nPitch = m_image.GetPitch();
	unsigned char* fm = (unsigned char*)m_image.GetBits(); // 내가 만든 이미지의 첫번째 포인터의 값을 가져오겠다.
	
	// fm은 이미지 데이터의 시작 포인터를 가리킨다. 이미지 데이터는 메모리에 연속적으로 배열된 행으로 구성된다.
	// 각 행의 끝과 다음 행의 시작 사이에는 간격(nPitch)가 있을 수 있다.


	memset(fm, 0xff, nWidth * nHeight); // 메모리를 어떠한 값으로 연결할 것인지
	
	//for (int j = 0; j < nHeight; j++) {
	//	for (int i = 0; i < nWidth; i++) {
	//		// 2d 이미지 좌표 (i, j)를 1D메모리 주소로 변환한다. 
	//		// 255는 해당 픽셀의 값에 할당된다. 255를 할당하면 흰색으로 표시된다.
	//		// nBpp=8이 그레이스케일이미지므로 0(검은색) 부터 255(흰색)까지 값이 할당된다.
	//		fm[j * nPitch + i] = (j*60)%255; 
	//		
	//	}
	//}

	

	// 이미지 그리기
	UpdateDisplay(); // 이미지 업데이트 하는 함수 호출

}

// 전역변수로 선언
CString g_strFileImage = _T("c:\\image\\save.bmp");
void CmfcCImageDlg::OnBnClickedButton2()
{
	// 이미지 저장하기
	m_image.Save(g_strFileImage);
}


void CmfcCImageDlg::OnBnClickedButton3()
{
	// 이미지가 없으면 제거
	if (m_image != NULL) {
		m_image.Destroy();
	}
	// 이미지 로드하기
	m_image.Load(g_strFileImage);

	UpdateDisplay();
}

// 이미지 업데이트 하는 함수 생성
void CmfcCImageDlg::UpdateDisplay() 
{
	CClientDC dc(this);
	m_image.Draw(dc, 0, 0);
}

void CmfcCImageDlg::moveRect()
{
	static int nSttX = 0;
	static int nSttY = 0;
	int nGray = 80;
	int nWidth = m_image.GetWidth(); // 가로폭 픽셀
	int nHeight = m_image.GetHeight(); // 세로폭 픽셀
	unsigned char* fm = (unsigned char*)m_image.GetBits(); // 내가 만든 이미지의 첫번째 포인터의 값을 가져오겠다.
	int nPitch = m_image.GetPitch();
	memset(fm, 0xff, nWidth * nHeight); // 메모리를 어떠한 값으로 연결할 것인지

	for (int j = nSttY; j < nSttY + 48; j++) {
		for (int i= nSttX;i < nSttX + 64;i++) {
			
			if(vaildImgPos(i, j))
				fm[j * nPitch + i] = nGray;
		}
	}
	nSttX++;
	nSttY++;
	UpdateDisplay();
}

void CmfcCImageDlg::OnBnClickedBtnAction()
{
	for (int i = 0;i < 640; i++) {
		moveRect();
		Sleep(1);
	}
	
}

BOOL CmfcCImageDlg::vaildImgPos(int x, int y) 
{
	int nWidth = m_image.GetWidth(); // 가로폭 픽셀
	int nHeight = m_image.GetHeight(); // 세로폭 픽셀

	CRect rect(0, 0, nWidth, nHeight);
	// 주어진 x, y 에 대해서 영역 안에 들어가면 그 값을 리턴해 준다.
	return rect.PtInRect(CPoint(x, y)); // Cpoint값으로 바꿔 준다.

}

 

원 움직이게 하기

사각형을 움직이는 로직을 원으로 바꾸려면, 주어진 원의 중심(nSttX, nSttY)와 반지름(r) 을 이용하여 각 픽셀이 원 내부에 있는지 여부를 판단해야 한다.

 

원의 내부에 있는 픽셀을 회색으로 채우려면, 주어진 픽셀 (i, j)가 원의 중심(nSttX, nSttY)로부터 거리가 r보다 작거나 같은지 검사해야 한다.

 


코드에서 (dx*dx + dy*dy <= r*r) 부분이 원의 내부에 있는 픽셀을 확인하는 조건이다.(위의 공식 참고)

여기서 (i, j) 픽셀의 원점 (nSttX, nSttY)에 대한 상대적인 위치는 (dx, dy)이다.

 

void CmfcCImageDlg::OnBnClickedBtnImage()
{
	// 클래스에서 사용하는 변수(n이 붙는다)
	// 멤버변수 지역변수
	int nWidth = 640; // 가로폭 픽셀
	int nHeight = 480; // 세로폭 픽셀
	int nBpp = 8; // gray level

	// 이미지 생성
	m_image.Create(nWidth, -nHeight, nBpp); // 모든 변수를 만들때는 파라마터 값에 숫자를 안 주는게 중요하다. -> 위에서 설정한 변수를 사용해 준다.
	BOOL vaildImgPos(int x, int y);

	// 조건 작성
	// 흑백을 기준으로 display 하게 되어있기 때문에 컬러로 할려면 설정을 따로 해줘야 한다.

	if (nBpp == 8) {
		static RGBQUAD rgb[256];
		for (int i = 0; i < 256; i++)
			rgb[i].rgbRed = rgb[i].rgbGreen = rgb[i].rgbBlue = i;
		m_image.SetColorTable(0, 256, rgb);
	}

	int nPitch = m_image.GetPitch();
	unsigned char* fm = (unsigned char*)m_image.GetBits(); // 내가 만든 이미지의 첫번째 포인터의 값을 가져오겠다.
	
	// fm은 이미지 데이터의 시작 포인터를 가리킨다. 이미지 데이터는 메모리에 연속적으로 배열된 행으로 구성된다.
	// 각 행의 끝과 다음 행의 시작 사이에는 간격(nPitch)가 있을 수 있다.


	memset(fm, 0xff, nWidth * nHeight); // 메모리를 어떠한 값으로 연결할 것인지
	
	//for (int j = 0; j < nHeight; j++) {
	//	for (int i = 0; i < nWidth; i++) {
	//		// 2d 이미지 좌표 (i, j)를 1D메모리 주소로 변환한다. 
	//		// 255는 해당 픽셀의 값에 할당된다. 255를 할당하면 흰색으로 표시된다.
	//		// nBpp=8이 그레이스케일이미지므로 0(검은색) 부터 255(흰색)까지 값이 할당된다.
	//		fm[j * nPitch + i] = (j*60)%255; 
	//		
	//	}
	//}

	

	// 이미지 그리기
	UpdateDisplay(); // 이미지 업데이트 하는 함수 호출

}

// 전역변수로 선언
CString g_strFileImage = _T("c:\\image\\save.bmp");
void CmfcCImageDlg::OnBnClickedButton2()
{
	// 이미지 저장하기
	m_image.Save(g_strFileImage);
}


void CmfcCImageDlg::OnBnClickedButton3()
{
	// 이미지가 없으면 제거
	if (m_image != NULL) {
		m_image.Destroy();
	}
	// 이미지 로드하기
	m_image.Load(g_strFileImage);

	UpdateDisplay();
}

// 이미지 업데이트 하는 함수 생성
void CmfcCImageDlg::UpdateDisplay() 
{
	CClientDC dc(this);
	m_image.Draw(dc, 0, 0);
}

void CmfcCImageDlg::moveCircle()
{
	static int nSttX = 0;
	static int nSttY = 0;
	int nGray = 80;
	int nWidth = m_image.GetWidth(); // 가로폭 픽셀
	int nHeight = m_image.GetHeight(); // 세로폭 픽셀
	unsigned char* fm = (unsigned char*)m_image.GetBits(); // 내가 만든 이미지의 첫번째 포인터의 값을 가져오겠다.
	int nPitch = m_image.GetPitch();
	
	// 전체 이미지를 흰색으로 초기화한다.
	memset(fm, 0xff, nWidth * nHeight); // 메모리를 어떠한 값으로 연결할 것인지

	// 원의 반지름을 설정한다.
	int r = 24;

	for (int j = nSttY - r; j < nSttY + r; j++) {
		for (int i = nSttX - r; i < nSttX + r; i++) {
			int dx = i - nSttX;
			int dy = j - nSttY;
			if (vaildImgPos(i, j) && (dx * dx + dy * dy <= r * r)) {
				// 픽셀이 이미지 내에 있고, 원의 내부에 있는 경우에만 그레이로 채웁니다.
				fm[j * nPitch + i] = nGray;
			}
		}
	}
	nSttX++;
	nSttY++;
	UpdateDisplay();
}

void CmfcCImageDlg::OnBnClickedBtnAction()
{
	for (int i = 0;i < 640; i++) {
		moveCircle();
		Sleep(1);
	}
	
}

BOOL CmfcCImageDlg::vaildImgPos(int x, int y) 
{
	int nWidth = m_image.GetWidth(); // 가로폭 픽셀
	int nHeight = m_image.GetHeight(); // 세로폭 픽셀

	CRect rect(0, 0, nWidth, nHeight);
	// 주어진 x, y 에 대해서 영역 안에 들어가면 그 값을 리턴해 준다.
	return rect.PtInRect(CPoint(x, y)); // Cpoint값으로 바꿔 준다.

}
profile

소연의_개발일지

@ssoyxon

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!