약속한데로... 자세한 설명을 해 드리죠.

1. 초기화 과정입니다.

BOOL CCaptureDlg::OnInitDialog()
{
// VC++ 에서 지원한는 Smart Poniter 라는 것으로 구현 했습니다.
// 전병선씨가 지은 ATL/COM 프로그램밍 책에 보시면 자세히 설명하는데
// 사 보셔도 좋고요. 앞으로 ATL 을 공부하시는데 도움이 될겁니다.
// 연락 주시면 가지고 있는 COM 관련 추천 책들도 알려 드리죠.


// InitInstance() 에 AfxOleInit() 가 추가 되어 있는지 확인한다.
m_pZlib = IZlibAtlPtr(__uuidof(ZlibAtl));

// 만일 ZlibUtil 이 이벤트를 받고 싶을때 다음의 리마크를 없애세요.
// 이벤트 처리는 ZlibUtil 가 같이 샘플로 제공된 createzipstg 에 이벤트
// 처리를 윈한 코드들이 들어 갔으니까 참고 하세요.
// 만일 안 쓰시겠다면 다음 코드들은 지워도 됩니다.

// m_pEvent = new CZlibEvent(this);
// BOOL bAdvised = AfxConnectionAdvise(m_pZlib, DIID__IZlibAtlEvents,
// m_pEvent->GetInterface(&IID_IUnknown),
// TRUE, &m_dwCookie);
}


2. 캡쳐 하기입니다.

void CCaptureDlg::OnCapture()
{
// TODO: Add your control notification handler code here
UpdateData(TRUE);

// CDib 는 밑에 김서영님의 올린 것을 Wrap 한 함수입니다.
// 참고해서 읽어 보세요.

CDib dib;
CRect rect(atoi(m_szX),atoi(m_szY),atoi(m_szX)+atoi(m_szW),atoi(m_szY)+atoi(m_szH));
CSize destSize(atoi(m_szW),atoi(m_szH));

if(m_hDIB) {
GlobalFree(m_hDIB); // 전에 가지고 있던 메모리를 해제함.
}

UINT size;
dib.WriteWindowToDIB(rect, destSize, m_hDIB, size);

HBITMAP hBitmap;

// BitmapFromDib 는 MS 사 ShowDib(dib.c) 라는 샘플에 있던 것으로
// Bitmap Image 가지고 할수 있는 Wrap 함수들입니다.
// 쓸만한것이 상당히 많으니까 한번씩 이름만이라도 보시면 도움이
// 되겠군요.
hBitmap = BitmapFromDib (m_hDIB, NULL);

// m_Picture.m_pPict 는 CPitureHodler 라는 클래스로 ActiveX
// 의 Picture Proprety 를 Wrap 클래스 입니다.
// 멤버 함수들은 MSDN 을 참고 하시고...
// 여기서는 그냥 BITMAP Handle 을 통해서 Picture 을 생성하면
// 되겠습니다.
m_Picture.m_pPict.CreateFromBitmap(hBitmap, NULL);

// 화면 재 갱신을 하시면 m_Picture 의 OnPaint() 에서
// 화면의 크기를 계산하고 m_pPict 의 Render 를 Call 해서
// 화면에 직접 그림니다.

// 게으른 관계로 ActiveX Picture Wrap Class 를 써서
// 화면 출력을 구현했습니다.
m_Picture.Invalidate();
}


3. 압축하기 인데 상당히 소스가 길어 보이죠...
파라미터로 화일명과 DIB 에 대한 핸들을 주면 됩니다.

BOOL CCaptureDlg::WriteDIBToZip( LPSTR szFile, HANDLE hdib)
{
BITMAPFILEHEADER hdr;
LPBITMAPINFOHEADER lpbi;

if (!hdib)
return FALSE;

lpbi = (LPBITMAPINFOHEADER)GlobalLock (hdib);

/* Fill in the fields of the file header */
// BITMPAP FILE 에 대한 설명이군요.
hdr.bfType = BFT_BITMAP;
hdr.bfSize = GlobalSize (hdib) + SIZEOF_BITMAPFILEHEADER_PACKED;
hdr.bfReserved1 = 0;
hdr.bfReserved2 = 0;
hdr.bfOffBits = (DWORD) (SIZEOF_BITMAPFILEHEADER_PACKED + lpbi->biSize +
PaletteSize(lpbi));

try {
/* Write the file header */

IStreamPtr pstrmInMem;
ULONG cbWritten = 0;
ULONG cbTotal = 0;
HRESULT hr = S_OK;

// 화일을 대신할 Stream 을 만든다.
// 하나의 화일로 되어 있으면 그것을 바로 메모리로 옮기고 압축하면
// 좋겠지만 그러하지 않으니까... 일단 만듭니다.
hr = CreateStreamOnHGlobal(NULL, TRUE, &pstrmInMem);
_com_util::CheckError(hr);

#ifdef FIXDWORDALIGNMENT
hr = pstrmInMem->Write(hdr, (UINT)(SIZEOF_BITMAPFILEHEADER_PACKED), &cbWritten);
_com_util::CheckError(hr);

cbTotal += cbWritten;
#else
/* write bfType*/
hr = pstrmInMem->Write(&hdr.bfType, (UINT)sizeof (WORD), &cbWritten);
_com_util::CheckError(hr);
cbTotal += cbWritten;

/* now pass over extra word, and only write next 3 DWORDS!*/
hr = pstrmInMem->Write(&hdr.bfSize, sizeof(DWORD) * 3, &cbWritten);
_com_util::CheckError(hr);
cbTotal += cbWritten;
#endif

/* this struct already DWORD aligned!*/
/* Write the DIB header and the bits */
hr = pstrmInMem->Write(lpbi, GlobalSize (hdib), &cbWritten);
_com_util::CheckError(hr);
cbTotal += cbWritten;

// 이제 pstrmInMem 는 Bitmap 화일과 같습니다.

// pstrmInMem 을 압축하겠습니다.
#ifdef USE_MEMORY // 메모리를 사용할 경우.

// SafeArray 는 컴퍼넌트간 메모리를 통한 복사를 위한 함수입니다.
// 1. Create 하기(Create)
// 2. 메모리를 Lock 하기(AccessData)
// 메모리를 데이타를 써넣고
// 3. 메모리를 UnLock 하기(UnaccessData)
// 4. Create 된것을 지우기 (Destroy)
_variant_t var;
PCHAR pBuf;
PBYTE pArr;
DWORD dwLen = cbTotal; // 크기 지정함
SAFEARRAY FAR* psa;
SAFEARRAYBOUND rgsabound[1];
rgsabound[0].lLbound = 0;
rgsabound[0].cElements = dwLen;
psa = SafeArrayCreate(VT_UI1, 1, rgsabound); //1. 동적으로 메모리 생성
if(psa == NULL) {
_com_issue_error(S_OK);
}

hr = SafeArrayAccessData(psa, (PVOID *)&pBuf); // 2. Lock 하기
_com_util::CheckError(hr);

memset(pBuf, 0, dwLen);

HGLOBAL global;
GetHGlobalFromStream(pstrmInMem, &global);

LPVOID pVoid = GlobalLock(global);
CopyMemory(pBuf, pVoid, dwLen); // 데이타 쓰기
GlobalUnlock(global);

hr = SafeArrayUnaccessData(psa); // 3. Unlock 하기
_com_util::CheckError(hr);

var.vt = VT_ARRAY|VT_UI1|VT_BYREF; // VARAINT (MSDN 참조) 에 ARRAY 를 포인터로
var.parray = psa; // 넘긴다고 지정함.
m_pZlib->PutMode(MEM_TO_ZMEM); // ZLibUtil 에게 메모리(SafeArray) 사용을
// 알림

m_pZlib->PutInMemory(var); // variant 데이타 넘김(이미 데이타는 저장됨)

hr = m_pZlib->Compress(); // ZLibUtil 에게 압축을 지시함
_com_util::CheckError(hr);

SafeArrayDestroy(psa); // 4. Create 된 데이타 지우기
_variant_t outvar; // 이미 압축된 결과 데이타는 컴퍼넌트 안에
outvar = m_pZlib->GetOutMemory(); // 들어 있다.
// ZLibUtil 에게 데이타 요구함(Variant)
LONG lLbound, lUbound; // Vairant(outvar) 에 이미 데이타가들어와 있음
hr = SafeArrayGetLBound(outvar.parray, 1, &lLbound); // 크기를 알아냄(최하)
_com_util::CheckError(hr);

hr = SafeArrayGetUBound(outvar.parray, 1, &lUbound); // 크기를 알아냄(최상)
_com_util::CheckError(hr);
hr = SafeArrayAccessData(outvar.parray, (PVOID *)&pArr); // 실제 데이타 위치
_com_util::CheckError(hr); // 메모리 포인터

ULONG StoreLen; // 받을때 SafeArray 쓰는 것도 같습니다.
// 이미 컴퍼넌트가 Create 했으므로 2,3 과정만 하면 됩니다.
// 4 과정은 컴퍼넌트가 수행할 겁니다.
StoreLen = lLbound + lUbound+1; // 실제 받을 데이타 크기.

CFile file;
if(file.Open(szFile, CFile::modeCreate | CFile::modeWrite) ) {
file.WriteHuge(pArr, StoreLen);
file.Close();
}
else {
hr = SafeArrayUnaccessData(outvar.parray); // 3과정
_com_util::CheckError(hr);

_com_issue_error(S_OK);
}

hr = SafeArrayUnaccessData(outvar.parray);
_com_util::CheckError(hr);


#else // Stream 으로 사용할 경우
IStreamPtr pstrmOutMem;

hr = CreateStreamOnHGlobal(NULL, TRUE, &pstrmOutMem); // OutStream
_com_util::CheckError(hr); // 메모리에 화일을 대신할 메모리 Stream 을 만든다.

m_pZlib->PutMode(STREAM_TO_ZSTREAM); // Stream 압축을 지정함

LARGE_INTEGER li;
li.LowPart = li.HighPart = 0;

pstrmInMem->Seek(li, STREAM_SEEK_SET, NULL); // 이미 써넣으면서 뒤로 위치했으므로
// 앞으로 되돌림.
m_pZlib->PutInStream(pstrmInMem); // In 지정
m_pZlib->PutOutStream(pstrmOutMem); // Out 지정

m_pZlib->Compress(); // 압축
pstrmOutMem->Seek(li, STREAM_SEEK_SET, NULL);// 컴퍼넌트가 보낸데이타를 맨앞에서
// 부터 읽을 준비를 함.

CFile file;
if(file.Open(szFile, CFile::modeCreate | CFile::modeWrite) ) {
while(TRUE) {
char buf[8192];
ULONG cbRead = 0;
pstrmOutMem->Read(buf, 8192, &cbRead); // 8192로 계속 읽어 옵니다.

if(cbRead == 0)
break;

file.Write(buf, cbRead);
}
file.Close();
}
else {
_com_issue_error(S_OK);
}

#endif
}
catch (_com_error e){
HRESULT hr = e.Error();
if(hr != S_OK)
ShowMessage(e);

GlobalUnlock (hdib); // Lock 된 데이타 UnLock 함
return FALSE;
}

GlobalUnlock (hdib);
return TRUE;
}

4. 읽어 오기

HANDLE CCaptureDlg::LoadDIBFromZip( LPSTR szFile)
{
BITMAPINFOHEADER bi;
LPBITMAPINFOHEADER lpbi;
DWORD dwLen = 0;
DWORD dwBits;
HANDLE hdib = NULL;
HANDLE h;
ULONG cbRead = 0;

/* Open the file and read the DIB information */
// 이미 메모리에 대한 설명은 저장하기에서 했으므로
// 간단히 Stream 으로 가지고 작업 하기로 하겠습니다.
try {
IStreamPtr pstrmInMem;
IStreamPtr pstrmOutMem;
HRESULT hr = S_OK;

hr = CreateStreamOnHGlobal(NULL, TRUE, &pstrmInMem);
_com_util::CheckError(hr);

hr = CreateStreamOnHGlobal(NULL, TRUE, &pstrmOutMem);
_com_util::CheckError(hr);

CFile file;

if(file.Open(szFile, CFile::modeRead)) {
while(TRUE) {
char buf[8192];
ULONG cbWritten = 0;
UINT cbRead = file.Read(buf, 8192);

if(cbRead == 0)
break;

pstrmInMem->Write(buf, cbRead, &cbWritten);
}

m_pZlib->PutMode(ZSTREAM_TO_STREAM); // 압축된 스트림에서 스트림으로

LARGE_INTEGER li;
li.LowPart = li.HighPart = 0;

pstrmInMem->Seek(li, STREAM_SEEK_SET, NULL); // 읽어 오면서 뒤로간
// InStream 을 되 돌림
m_pZlib->PutInStream(pstrmInMem); // InStream 지정
m_pZlib->PutOutStream(pstrmOutMem); // OutStream 지정

m_pZlib->Decompress(); // 풀기
pstrmOutMem->Seek(li, STREAM_SEEK_SET, NULL);// 컴퍼넌트에서 온 데이타를
// 앞에서 쓸수 있도록 되돌림
}
else
return NULL;

file.Close();
hdib = ReadDibBitmapInfoFromStream(pstrmOutMem);
//ReadDibBitmapInfo 라는 함수가 있는데 이것은 화일 핸들로 파라미터로
//받는데 단지 Stream 을 받을수 있도록 수정했을뿐 내부 내용은
//ReadDibBitmapInfo 가 같습니다.
if (!hdib)
return NULL;
DibInfo(hdib,&bi);

/* Calculate the memory needed to hold the DIB */
dwBits = bi.biSizeImage;
dwLen = bi.biSize + (DWORD)PaletteSize (&bi) + dwBits;

/* Try to increase the size of the bitmap info. buffer to hold the DIB */
h = GlobalReAlloc(hdib, dwLen, GHND);
if (!h){
GlobalFree(hdib);
hdib = NULL;
}
else
hdib = h;

/* Read in the bits */
if (hdib){

lpbi = (LPBITMAPINFOHEADER)GlobalLock(hdib);

pstrmOutMem->Read((LPSTR)lpbi + (WORD)lpbi->biSize + PaletteSize(lpbi), dwBits, &cbRead);
GlobalUnlock(hdib);
}
}
catch (_com_error e){

}

return hdib;
}




이름 : 김서영 번호 : 52 게시일 : 1999.10.15 18:39:58 조회 : 196

안녕하세요
김서영입니다.
전에 시삽님이 올려놓으라고 하셨는데 지금에서야 올립니다.
죄송합니다.
Codeguru에서 가져온건데 제가 따로있는것을 붙여서 조금 수정했습니다.
많이는 아니고요

감사합니다.

BOOL CDib::WriteWindowToDIB(CRect &rect, CSize &destSize,HANDLE& hDIB, UINT& size)
{
CBitmap bitmap;
CDC memDC,screenDC;

screenDC.CreateDC("DISPLAY",NULL,NULL,NULL);
memDC.CreateCompatibleDC(&screenDC);
bitmap.CreateCompatibleBitmap(&screenDC, destSize.cx, destSize.cy);
CBitmap* pOldBitmap = memDC.SelectObject(&bitmap);
//영역에 대한 캡쳐 BitBlt를 이용해도 되는데..........
memDC.StretchBlt(0,
0,
destSize.cx,
destSize.cy,
&screenDC,
rect.left,
rect.top,
rect.Width(),
rect.Height(),
SRCCOPY);
CPalette pal;
//현재 해상도가 256칼라 이하라면 팔레트 추가
if( screenDC.GetDeviceCaps(RASTERCAPS) & RC_PALETTE )
{
UINT nSize = sizeof(LOGPALETTE) + (sizeof(PALETTEENTRY) * 256);
LOGPALETTE *pLP = (LOGPALETTE *) new BYTE[nSize];
pLP->palVersion = 0x300;
pLP->palNumEntries = GetSystemPaletteEntries(
screenDC,
0,
255,
pLP->palPalEntry );
// Create the palette
pal.CreatePalette( pLP );
delete[] pLP;
}

memDC.SelectObject(pOldBitmap);

// Convert the bitmap to a DIB
hDIB = NULL;
hDIB = DDBToDIB(bitmap, BI_RGB, &pal , size);

screenDC.DeleteDC();

if( hDIB == NULL )
return FALSE;

return TRUE;
}

HANDLE CDib::DDBToDIB(CBitmap& bitmap, DWORD dwCompression, CPalette* pPal, UINT &size)
{
BITMAP bm;
BITMAPINFOHEADER bi;
LPBITMAPINFOHEADER lpbi;
DWORD dwLen;
HANDLE hDIB;
HANDLE handle;
HDC hDC;
HPALETTE hPal;

ASSERT( bitmap.GetSafeHandle() );

// The function has no arg for bitfields
if( dwCompression == BI_BITFIELDS )
return NULL;

// If a palette has not been supplied use defaul palette
hPal = (HPALETTE) pPal->GetSafeHandle();
if (hPal==NULL)
hPal = (HPALETTE) GetStockObject(DEFAULT_PALETTE);

// Get bitmap information
bitmap.GetObject(sizeof(bm),(LPSTR)&bm);

// Initialize the bitmapinfoheader
bi.biSize = sizeof(BITMAPINFOHEADER);
bi.biWidth = bm.bmWidth;
bi.biHeight = bm.bmHeight;
bi.biPlanes = 1;
bi.biBitCount = bm.bmPlanes * bm.bmBitsPixel;
bi.biCompression = dwCompression;
bi.biSizeImage = 0;
bi.biXPelsPerMeter = 0;
bi.biYPelsPerMeter = 0;
bi.biClrUsed = 0;
bi.biClrImportant = 0;

// Compute the size of the infoheader and the color table
int nColors = (1 << bi.biBitCount);
if( nColors > 256 )
nColors = 0;
dwLen = bi.biSize + nColors * sizeof(RGBQUAD);

// We need a device context to get the DIB from
hDC = ::GetDC(NULL);
hPal = SelectPalette(hDC,hPal,FALSE);
RealizePalette(hDC);

// Allocate enough memory to hold bitmapinfoheader and color table
hDIB = GlobalAlloc(GMEM_FIXED,dwLen);

if (!hDIB){
SelectPalette(hDC,hPal,FALSE);
::ReleaseDC(NULL,hDC);
return NULL;
}

lpbi = (LPBITMAPINFOHEADER)hDIB;

*lpbi = bi;

// Call GetDIBits with a NULL lpBits param, so the device driver
// will calculate the biSizeImage field
GetDIBits(hDC,
(HBITMAP)bitmap.GetSafeHandle(),
0L,
(DWORD)bi.biHeight,
(LPBYTE)NULL,
(LPBITMAPINFO)lpbi,
(DWORD)DIB_RGB_COLORS);

bi = *lpbi;

// If the driver did not fill in the biSizeImage field, then compute it
// Each scan line of the image is aligned on a DWORD (32bit) boundary
if (bi.biSizeImage == 0){
bi.biSizeImage = ((((bi.biWidth * bi.biBitCount) + 31) & ~31) / Cool
* bi.biHeight;

// If a compression scheme is used the result may infact be larger
// Increase the size to account for this.
if (dwCompression != BI_RGB)
bi.biSizeImage = (bi.biSizeImage * 3) / 2;
}

// Realloc the buffer so that it can hold all the bits
dwLen += bi.biSizeImage;
if (handle = GlobalReAlloc(hDIB, dwLen, GMEM_MOVEABLE))
hDIB = handle;
else{
GlobalFree(hDIB);

// Reselect the original palette
SelectPalette(hDC,hPal,FALSE);
::ReleaseDC(NULL,hDC);
return NULL;
}

// Get the bitmap bits
lpbi = (LPBITMAPINFOHEADER)hDIB;

// FINALLY get the DIB
BOOL bGotBits = GetDIBits( hDC,
(HBITMAP)bitmap.GetSafeHandle(),
0L, // Start scan line
(DWORD)bi.biHeight, // # of scan lines
(LPBYTE)lpbi // address for bitmap bits
+ (bi.biSize + nColors * sizeof(RGBQUAD)),
(LPBITMAPINFO)lpbi, // address of bitmapinfo
(DWORD)DIB_RGB_COLORS);// Use RGB for color table

if( !bGotBits )
{
GlobalFree(hDIB);

SelectPalette(hDC,hPal,FALSE);
::ReleaseDC(NULL,hDC);
return NULL;
}

SelectPalette(hDC,hPal,FALSE);
::ReleaseDC(NULL,hDC);
size = dwLen;

return hDIB;
}

//*******************************************************
// 팔레트 생성
//********************************************************
BOOL CDib::CreatePalette(HGLOBAL* hDIB, CPalette *pPal)
{
//수신된 데이타 영역에서 비트맵 정보영역을 추출
BITMAPINFO &bmInfo = *(LPBITMAPINFO)hDIB ;

//몇가지 색상을 사용하는지
int nColors = bmInfo.bmiHeader.biClrUsed ? bmInfo.bmiHeader.biClrUsed :
1 << bmInfo.bmiHeader.biBitCount;
// 256칼라 이하일때 팔레트의 생성
if( nColors <= 256 )
{
UINT nSize = sizeof(LOGPALETTE) + (sizeof(PALETTEENTRY) * nColors);
LOGPALETTE *pLP = (LOGPALETTE *) new BYTE[nSize];
if( !(pLP)) pLP = (LOGPALETTE *) new BYTE[nSize];
if(pLP)
{
pLP->palVersion = 0x300;
pLP->palNumEntries = nColors;
}else return FALSE;

for( int i=0; i < nColors; i++)
{
pLP->palPalEntry[i].peRed = bmInfo.bmiColors[i].rgbRed;
pLP->palPalEntry[i].peGreen = bmInfo.bmiColors[i].rgbGreen;
pLP->palPalEntry[i].peBlue = bmInfo.bmiColors[i].rgbBlue;
pLP->palPalEntry[i].peFlags = 0;
}
pPal->CreatePalette( pLP );

delete[] pLP;
}
return TRUE;
}

+ Recent posts