오랜만에 gxLib를 업그레이드하여 올립니다. 이번 업그레이드는 어떻게하면 좀더 빠르게 이미지를 출력할 수 있을까하는 고심을 담아 보았습니다. 그래서 추가한 것 중의 하나가 gx_get_compatible_dc() 함수입니다.

 

gx_get_compatible_dc()

시간이 제일 많이 걸리는 gx_bitblt() 함수는 같은 Type에, 같은 크기를 가진 dc 끼리의 복사는 bit 단위가 아닌 byte 단위로 복사를, 그것도 memcpy() 함수를 사용하기 때문에 매우 빠르게 복사 작업을 수행합니다.

 

예를 들어 같은 bmp_t 형태의 두 개의 dc가 크기도 똑 같다면, gx_bitblt() 함수 내에서 아래의 조건문을 만족하게 되고, 조건문에 따라 byte_bitblt() 함수를 호출하게 됩니다.

    if (    ( dc_sour->dc_type        == dc_dest->dc_type        )              // 두 개의 DC가 모두 같은 Type 이고 
        &&  ( dc_sour->bits_per_pixel == dc_dest->bits_per_pixel ) )            // DC의 픽셀당 크기가 같다면
    {
       switch( dc_dest->colors)
       {
       case  8  :
       case  15 :
       case  16 :
       case  24 :
       case  32 :   printf( "byte_bitblt()\n");
                    byte_bitblt( dc_dest, dest_x, dest_y, dc_sour, sour_x, sour_y, sour_w, sour_h, dc_sour->bits_per_pixel / 8);
                    break;
       default  :   printf( "8 bit 이하의 byte_bitblt()를 구현해야 합니다. \n");
       }
    }

byte_bitblt()에서는 dc의 칼라 깊이에 따라 바이트 단위로 복사하게 됩니다.

static void  byte_bitblt( dc_t *dc_dest, int dest_x, int dest_y, 
                dc_t *dc_sour, int sour_x, int sour_y, 
                               int sour_w, int sour_h, int bytes_per_pixel)
//-------------------------------------------------------------------------------
// 설명: DC영역에 다른 DC를 복사한다.
// 인수: dc_dest           : 출력 목적지 Device Context Handle
//       dest_x, dest_y    : 출력 x, y 좌표
//       dc_sour           : 출력할 대상 Device Context Handle
//       sour_x, sour_y    : dc_sour에서 복사 시작 좌표
//       sour_w, sour_h    : dc_sour에서 복사 종료 좌표
//       bytes_per_pixel   : pixel 당 바이트 개수
{
   int   bytes_per_line = sour_w *bytes_per_pixel;                                // 복사 영역의 라인당 바이트 수
   char *pdest          = (char*)dc_dest->mapped +dc_dest->bytes_per_line*dest_y +dest_x*bytes_per_pixel;
   char *psour          = (char*)dc_sour->mapped +dc_sour->bytes_per_line*sour_y +sour_x*bytes_per_pixel;

   while( 0 < sour_h)
   {
      memcpy( pdest, psour, bytes_per_line);
      pdest += dc_dest->bytes_per_line;
      psour += dc_sour->bytes_per_line;
      sour_h--;
   }
}

이렇게 byte_bitblt()를 이용하기 위해서는 dc가 서로 같은 Type이고 같은 크기이어야 하는데, 같은 Type에 같은 크기의 dc를 조금 더 편하게 구하기 위해, gxLib 0.7.1에서는 gx_get_compatible_dc() 함수를 추가하게 되었습니다. 아래의 코드는 스크린 DC와 동일한 DC를 생성한 것입니다.

dc_screen = gx_get_screen_dc();
dc_buffer = gx_get_compatible_dc( dc_screen);

이제 dc_screen과 dc_buffer을 복사할 때, bit단위가 아닌 byte 단위로 복사하는 byte_bitblt()를 사용하게 되어 더윽 빠르게 복사가 진행됩니다.

gx_open_file()

gx_get_compatible_dc() 활용을 좀더 편하게 하기 위해서 gx_open_file()도 추가했습니다. gx_open_file()은 함수 이름에서 알 수 있듯이 dc로 파일을 읽어 들이는 것입니다. 그러나 bmp나 png와 같은 dc는 몰라도, screen이나 메모리를 이용하게 만든 buffer dc 같은 경우 파일 특성이 없기 때문에 파일에서 바로 읽어 들일 수 없습니다.

 

대신에 bmp_t, jpg_t, png_t를 이용해서 피일을 읽어 드린 뒤 복사해야 하는데, 매번 이와 같은 작업을 코딩해야 한다면 즐거운 적업은 아닐 것입니다. 그래서 gx_open_file()을 만들어서, 이와 같은 번거로운 작업을 대신하게 했습니다.

dc_fore = gx_get_compatible_dc( dc_screen);
dc_back = gx_get_compatible_dc( dc_screen);
dc_mask = gx_get_compatible_dc( dc_screen);

gx_open_file( dc_fore, "gx_bitblt_mask_fore.bmp");
gx_open_file( dc_back, "gx_bitblt_mask_back.bmp");
gx_open_file( dc_mask, "gx_bitblt_mask_mask.bmp");

주의하실 것은 gx_open_file()이 파일의 헤더를 분석하지 않고 파일 이름의 확장자에 따라 읽어 들인다는 점입니다. 그러므로 파일의 확장자에 주의 하셔야 하며, 대소문자에는 관계 없습니다.

 

gx_open_file() 사용에 관해서는 sample.c 에서 test_open_file() 루틴을 참고하십시오.

gx_bitblt_mask()

gx_bitblt() 함수가 특정 사각 영역을 그대로 복사한다면, gx_bitblt_mask()는 마스크의 이미지룰 추가하여, 마스크 이미지 중의 특정 칼라 값에 해당하는 부분만 복사하게 해줍니다.

 

gx_bitblt() 함수는 지정된 영역을 그대로 복사합니다.

gx_bitblt_mask()는 인수로 마스크에 해당하는 이미지를 추가로 지정하며, 영역을 지정하더라도 모두 복사하는 것이 아니라 마스크의 칼라 값을 만족하는 부분만 출력하게 됩니다.

만일 복사 영역에 마스크 이미지에 없는 색상을 지점하면 복사는 이루어 지지 않습니다. sample.c에서 test_bitblt_mask()마스크 루틴을 확이하세요.