Cfile23.uf .135D39524D273E3334486D

클립보드 기능 구현

이번에는 자주 사용하는 기능인 C&P(Copy & Paste)를 구현해 보도록 하겠습니다.

C&P를 구현하기 위해서는 이미지를 DIB(장치 독립 비트맵;Device Independent Bitmap)으로 변환하여 클립보드 영역에 넘겨주거나, 클립보드 영역에서 데이터를 받아오면 됩니다.

클립보드 영역으로 데이터를 넘겨주기 위하여 CopyClipBoard맴버함수, CopyToHandle 맴버 함수를 추가하여, ID_EDIT_COPY이벤트 핸들러에 등록합니다.

먼저 CopyClipBoard 맴버 함수를 Doc Class에 작성하겠습니다.

Cfile28.uf .1110DD4D4D273E3214FDCF

 

반환 형식 : void

함수 이름 : CopyClipBoard

매개 변수 형식 : IplImage *

매개 변수 이름 : m_pCopyImage

Cfile23.uf .135D39524D273E3334486D

Cfile10.uf .1113BB474D273E341606F4

다음과 같이 코딩합니다.

HANDLE hDIB = CopyToHandle(m_pCopyImage);

if(::OpenClipboard(AfxGetMainWnd()->GetSafeHwnd())){

        if(::EmptyClipboard()){

                if(NULL == ::SetClipboardData(CF_DIB, hDIB)){

                        AfxMessageBox(TEXT("클립보드에 영상을 저장하는 도중 오류가 발생했습니다."));

                }

        }

}

::CloseClipBoard();

이번에는 아까와 같은 방법으로 CopyToHandle 맴버 함수를 작성합니다.

반환 형식 : HANDLE

함수 이름 : CopyToHandle

매개 변수 형식 : IplImage *

매개 변수 이름 : image

 

Cfile25.uf .1858CF504D273E340666D8

 

다음과 같이 코딩합니다. (출처 : 오픈소스 OpenCV를 이용한 컴퓨터 비전 실무 프로그래밍 p237)

       int nChannels = image->nChannels;  

        int bpp = 8*nChannels;  

        IplImage *flip_image = cvCloneImage( image );  

        cvFlip( image, flip_image, 0 );   

        int bmpDataSize = flip_image->imageSize;  

        // 비트맵 헤더 구성   

        BITMAPINFOHEADER bmpHeader;  

        bmpHeader.biSize = sizeof(BITMAPINFOHEADER); // 이 구조체의 크기  

        bmpHeader.biHeight = image->height; // 영상의 높이  

        bmpHeader.biWidth = image->width;   // 영상의 너비  

        bmpHeader.biPlanes = 1; // 비트 플레인 수 (항상 1임)  

        bmpHeader.biBitCount = bpp; // 한 화소당 비트 개수   

        bmpHeader.biCompression = BI_RGB; // BI_RGB : 압축하지 않음  

        bmpHeader.biSizeImage = bmpDataSize; // 영상의 크기  

        if(8 == bpp) bmpHeader.biClrUsed = bmpHeader.biClrImportant  = 256;   

        else if(24 == bpp) bmpHeader.biClrUsed = bmpHeader.biClrImportant  = 0;

        int bmpAllSize = sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD)*256 + bmpDataSize*sizeof(char);  

        HGLOBAL hDIB = (HGLOBAL)::GlobalAlloc(GMEM_MOVEABLE| GMEM_ZEROINIT,  

                                                                                  bmpAllSize );  

        if(NULL == hDIB) return NULL;  

        LPSTR pDIB = (LPSTR)::GlobalLock((HGLOBAL)hDIB);  

        memcpy( pDIB, &bmpHeader, sizeof(BITMAPINFOHEADER) );  

 

        if(8 == bpp){  

                RGBQUAD palette[256];  

                memcpy( pDIB+sizeof(BITMAPINFOHEADER), palette, sizeof(RGBQUAD)*256 );  

                memcpy( pDIB+sizeof(BITMAPINFOHEADER)+sizeof(RGBQUAD)*256,   

                                flip_image->imageData, bmpDataSize );  

        }   

        else if(24 == bpp){  

                memcpy( pDIB+sizeof(BITMAPINFOHEADER),   

                                flip_image->imageData, bmpDataSize );  

        } 

        ::GlobalUnlock((HGLOBAL)hDIB);  

        cvReleaseImage( &flip_image );  

   

        return hDIB;

이제 ID_EDIT_COPY에 대한 이벤트 핸들러만 수정해 주면 끝입니다.

이벤트 핸들러를 수정하기 위해 다음과 같이 합니다.

Cfile29.uf .156138574D273E353B7FC5

void CMFC_OpenCVView::OnEditCopy()

{

        // TODO: 여기에 명령 처리기 코드를 추가합니다.

        CMFC_OpenCVDoc* pDoc = GetDocument();  

        ASSERT_VALID(pDoc);

        pDoc->CopyClipBoard( pDoc->m_CvvImage.GetImage() ); 

}

 

프로그램에서 Copy하여 그림판 같은 곳에 Paste했을 때 정상적으로 동작한다면 성공.

Cfile2.uf .1646014B4D273E361A6057

 

이번에는 Paste기능을 구현해 보도록 하겠습니다. Paste는 Copy의 역순입니다.

CreateFromHandle맴버 함수를 작성하고, ID_EDIT_PASTE에 이벤트 핸들러를 등록하고, 마지막으로 클립보드 영역에 DIB 데이터가 존재할 경우에만 ID_EDIT_PASTE가 동작하도록 하기 위해서 OnUpdateEditPaste 맴버 함수를 작성하겠습니다. 이번에는 모든 함수가 App Class에서 작성될 것이고, 코드만 첨부합니다.

void CMFC_OpenCVApp::OnEditPaste()

{

        // TODO: 여기에 명령 처리기 코드를 추가합니다.

        POSITION pos = GetFirstDocTemplatePosition();  

        CDocTemplate *pTemplate = GetNextDocTemplate(pos);  

        CMFC_OpenCVDoc *pDoc = (CMFC_OpenCVDoc* )pTemplate->OpenDocumentFile(NULL);   

  

        if( pDoc ){  

                HANDLE hDIB = NULL;  

                if (::OpenClipboard(AfxGetMainWnd()->GetSafeHwnd())) hDIB = ::GetClipboardData(CF_DIB);  

  

                if( hDIB ){  

                        IplImage *image = CreateFromHandle( hDIB );  

          

                        pDoc->m_CvvImage.CopyOf( image, image->nChannels*8 );  

  

                        POSITION pos = pDoc->GetFirstViewPosition();  

                        CMFC_OpenCVView *pView = (CMFC_OpenCVView *)pDoc->GetNextView(pos);  

  

                        CSize sizeTotal = CSize(pDoc->m_CvvImage.Width(),  

                        pDoc->m_CvvImage.Height());  

  

                        pView->SetScrollSizes(MM_TEXT, sizeTotal);  

                        pView->ResizeParentToFit(FALSE);  

                }  

  

                ::CloseClipboard();  

        } 

}
IplImage * CMFC_OpenCVApp::CreateFromHandle(HANDLE hDIB)

{

    LPSTR pDIB = (LPSTR)::GlobalLock((HGLOBAL)hDIB);    

    BITMAPINFOHEADER bmpHeader;   

    memcpy( &bmpHeader, pDIB, sizeof(BITMAPINFOHEADER) );    

      

    int height = bmpHeader.biHeight;  

    int width = bmpHeader.biWidth;  

    int nChannels = bmpHeader.biBitCount/8;  

    int bmpDataSize = bmpHeader.biSizeImage;  

    char *imageData = (char *)calloc( bmpDataSize, sizeof(char) );  

  

    if(8 == bmpHeader.biBitCount)

        memcpy( imageData, pDIB+sizeof(BITMAPINFOHEADER)+sizeof(RGBQUAD)*256,   

                bmpDataSize );

    else if(24 == bmpHeader.biBitCount)

        memcpy( imageData, pDIB+sizeof(BITMAPINFOHEADER), bmpDataSize );  

 

    IplImage *flip_image = cvCreateImage(cvSize(width,height), IPL_DEPTH_8U, nChannels);  

    memcpy( flip_image->imageData, imageData, bmpDataSize );  

 

    IplImage *recover_image = cvCloneImage( flip_image );  

    cvFlip( flip_image, recover_image, 0 );  

  

    ::GlobalUnlock((HGLOBAL)hDIB);    

 

    free(imageData);  

    cvReleaseImage( &flip_image );  

  

    return recover_image;  

}
void CMFC_OpenCVApp::OnUpdateEditPaste(CCmdUI *pCmdUI)

{

        // TODO: 여기에 명령 업데이트 UI 처리기 코드를 추가합니다.

        if( !IsClipboardFormatAvailable(CF_DIB) ) pCmdUI->Enable( FALSE );

}

 

App Class의 헤더 파일에 #include <cv.h>를 추가해 줘야 합니다.

 

Cfile5.uf .114B54504D273E372AE244

cfile25.uf.19311C444D273F25031758.pdfcfile7.uf.1227C1444D273F261C4D3D.zip

Similar Posts

  • HVR-2000 Series 이용하기

    이번 시간에는 조금 더 재미있는 것을 해 보겠습니다. 바로 요놈입니다.   바로 HyVision System의 HVR-2000 Series입니다. 일반적인 웹캠이야 그냥 연결만 해주면 바로 써먹을 수 있었는데, 요놈은 조금 다릅니다.   USB드라이버야 당연히 깔아줘야 하는거고… 별도의 SDK를 이용해서 Cam에 접근하게 됩니다.   하이비전시스템에서 HVR SDK Interface Guide를 친절하게 작성해 주셔서 별 무리 없이 실습을 진행 해 볼…

  • |

    2계층과 4계층의 오류제어, 흐름제어

    오류제어 및 흐름제어 기능은 계층 2와 4에도 있다. 이들의 차잇점을 쓰시오. 2계층과 4계층의 차이점.2계층은 서로 연결된 두 노드간의 제어이며, 4계층은 단대단 제어이다.따라서 4계층의 오류제어와 흐름제어는 단말과 네트워크를 포함한 제어 기술이다.2계층의 오류 제어는 오류제어를 담당한다. 4계층의 오류제어는 송신측과 수신측 단대단 오류 제어이다.2계층의 흐름제어는 역시 인접노드간의 흐름 제어이고, 4계층의 흐름제어는 단대단 흐름제어이다. 관련된 글: 고속 네트워크 프로토콜의…

  • 데이터 종속성과 정규화

    함수종속 어떤 릴레이션 R에서 X와 Y를 의 애트리뷰트 집합의 부분집합이라 하자.  X의 값 각각에 대해 시간에 관계 없이 Y의 값이 오직 하나만 연관되어 있을 때 Y는 X에 함수종속이라 하고 X →Y로 표기한다. 이 때, X를 결정자, Y를 종속자라고 한다. 제 1 정규형(1NF) 어떤 릴레이션 R에 속한 모든 도메인이 원자값만으로 되어 있다면 제 1 정규형이라고 한다. 제 2…

  • AcroEdit에서 C/C++ Compile 하기…

    이제 슬슬 공부나 해볼까하고 마음먹던중;;; 그냥 갑자기 C를 하고 싶어졌습니다… 이제까지 하려고 하려고 해도… 귀찮아서 접어두었던 C 책 한권을 꺼내서;;; 첫장을 펼처보니 “Turbo C++”를 설치하라는 겁니다… 전 착한 학생이기 때문에(~ㅋ) 하라는데로 설치했죠;;; 설치하고 보니 이게 왼걸;;; 구석기시대에서나 볼수있는 인터페이스;;; ㄷㄷ;;; 그래서 부대안에 있을때 사용했던 AcroEdit과 연결하기로 마음먹었습니다… 열심히 컴파일러를 찾아 해매였는데…;;; 이게 왠걸;;; 도처히 못찾겠습니다.;;;…

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다