ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • PCX
    GUI/GDI 2009. 4. 8. 22:19
    Run Length Encoding


    typedef struct PCX_HEADER {
      char manufacturer;         // 1
      char version;                    // 2
      char encoding;                // 3
      char bits_per_pixel;            // 4   
      short int  xmin,ymin;            // 5 , 6, 7, 8
      short int  xmax,ymax;            // 9 10, 11, 12
      short int  hres;                // 13, 14
      short int  vres;                // 15, 16
      char palette16[48];            // 17-64
      char reserved;                // 65
      char color_planes;            // 66
      short int  bytes_per_line;    // 67, 68
      short int  palette_type;        // 69, 70
      char filler[58];                // 71 - 128
    } pcx_header;


    void CImageProDoc::LoadPCX()
    {
        int i, x, y;
        int run_length;
        unsigned char c;
        pcx_header pcxhead;
        CString fname;
        CFile file;
        CFileDialog dlg(TRUE);

        if(dlg.DoModal()==IDOK) {
            fname = dlg.GetFileName();           // 파일 이름 받아오기
            file.Open(fname, CFile::modeRead);    // 파일 열기

            if (strcmp(strchr(fname, '.'), ".PCX") == 0 ||     // 파일 확장자 확인
                strcmp(strchr(fname, '.'), ".pcx") == 0)
            {
                file.Read(&pcxhead, sizeof(pcx_header));     // 헤더를 읽어 들임
                imageWidth = (pcxhead.xmax-pcxhead.xmin) + 1; // 영상의 넓이 계산
                imageHeight = (pcxhead.ymax-pcxhead.ymin) + 1; // 영상의 높이 계산

                depth = pcxhead.color_planes;
               if (depth != 1) return;

                // 기억장소 할당
                inputImg=(unsigned char **) malloc(imageHeight*sizeof(unsigned char *));
               
                for (i = 0; i < imageHeight; i++) {
                    inputImg[i] = (unsigned char *) malloc(imageWidth * depth);
                }

                for (y = 0; y < imageHeight; y++) 
                    for (x = 0; x < imageWidth; ) 
                    {
                        file.Read(&c, 1);           // 한 바이트를 읽어 들임 
                        if((c & 0xc0) == 0xc0)    // 런 길이를 포함하는 바이트이면
                        {
                          run_length = c & 0x3f;  // 런 길이 계산
                          file.Read(&c, 1);         // 데이터를 읽어들임
                          while(run_length--)      // 런 길이만큼 저장
                            inputImg[y][x++] = c;
                        }
                        else               // 런 길이를 포함하는 바이트가 아니면
                        {
                          inputImg[y][x++] = c;
                        }
                    }
            }
        }
    }

    void CImageProDoc::SavePCX()
    {
        int x, y;
        int run_length;
        unsigned char c;
        unsigned char cur;
        pcx_header pcxhead;
        CString fname;
        CFile file;
        CFileDialog dlg(TRUE);

        if(dlg.DoModal()==IDOK) {
            fname = dlg.GetFileName();           // 파일 이름 받아오기
            file.Open(fname, CFile::modeCreate | CFile::modeWrite);    // 파일 열기

            if (strcmp(strchr(fname, '.'), ".PCX") == 0 ||     // 파일 확장자 확인
                strcmp(strchr(fname, '.'), ".pcx") == 0)
            {
               memset(&pcxhead, 0, 128);         // 헤더 내용을 0으로 초기화

               pcxhead.manufacturer = 10;        // 기본 값
               pcxhead.version = 5;                    
               pcxhead.encoding = 1;             // 런 길이 부호화 사용
               pcxhead.bits_per_pixel = 8;
               pcxhead.xmin = 0;   
               pcxhead.ymin = 0;
               pcxhead.xmax = imageWidth - 1;
               pcxhead.ymax = imageHeight - 1;   
               pcxhead.hres = 150;                 // 150 DPI
               pcxhead.vres = 150;                 // 150 DPI
               pcxhead.color_planes = 1;             // 흑백 영상
               pcxhead.bytes_per_line = imageWidth;   
               pcxhead.palette_type = 1;       

               file.Write(&pcxhead, 128);        // 헤더 출력

               for (y = 0; y < imageHeight; y++)  {  // 각 라인에 대하여
                    run_length = 0;
                    for (x = 0; x < imageWidth; x++) {  // 각 픽셀에 대하여
                        cur = inputImg[y][x];
                        run_length++;

                       
                        if (x < imageWidth - 1 && cur == inputImg[y][x+1] && run_length < 63) {
                            // 라인의 끝이 아니고 다음에 같은 픽셀이 반복되고 런길이가 63보다 작으면
                            //   ==> 다음 픽셀로 이동
                        }
                        else if (run_length > 1 || (0xC0 & cur) == 0xC0) {
                            // 런 길이가 1보다 크거나 런 길이가 1이지만 상위 두 비트 값이 1인 경우
                            //   ==> 런 길이 바이트와 데이터 바이트 저장
                            c = 0xC0 | (unsigned char) run_length;
                            file.Write(&c, 1);            
                            file.Write(&cur, 1);
                            run_length = 0;
                        }
                        else {
                            // 런 길이가 1이고 상위 두 비트 값이 1이 아닌 경우
                            //   ==> 데이터 바이트만 저장
                            file.Write(&cur, 1);
                            run_length = 0;
                        }
                    }
               }
            }
            file.Close();
        }
    }


    void CImageProView::OnDraw(CDC* pDC)
    {
        CImageProDoc* pDoc = GetDocument();
        ASSERT_VALID(pDoc);

       if (pDoc->inputImg == NULL) return;

        if (pDoc->depth == 1) {
            for(int y=0; y < pDoc->imageHeight; y++)         // 입력 영상 출력
                for(int x=0; x < pDoc->imageWidth; x++)
                        pDC->SetPixel(x, y, RGB(pDoc->inputImg[y][x],
                                                pDoc->inputImg[y][x],
                                                pDoc->inputImg[y][x]));
     }

    void CImageProView::OnLoadPCX()
    {
       CImageProDoc* pDoc = GetDocument();  
       ASSERT_VALID(pDoc);

       pDoc->LoadPCX();     
       Invalidate(FALSE);   
    }

    void CImageProView::OnSavePCX()
    {
       CImageProDoc* pDoc = GetDocument();  
       ASSERT_VALID(pDoc);

       if (pDoc->inputImg == NULL) return;
       pDoc->SavePCX();     
       Invalidate(FALSE);
    }

Designed by Tistory.