노무현 대통령 배너


2007. 7. 13. 14:41

리눅스 그래픽 - 칼라 지정

리눅스 그래픽 - 칼라 지정 [2007/04/08 10:17, Linux]

임베디드 리눅스 포럼 보다도 찾아 오시는 손님이 많으셔서 제 글의 잘못된 내용이나 기타 내용을 지적 받을 수 있는 기회가 많을 것으로 생각되고, 또한 제가 고생하던 부분을 보여 드림으로써 다른 분들께 도움을 드리고자 올립니다.

혹, 내용에 문제가 있거나 틀린 부분이 있으면, 여기 블로그의 댓글, 또는 포럼의 강좌 게시판에 글을 올려 주신다면 감사하겠습니다.

포럼의 리눅스 그래픽 - 칼라 지정의 글을 보시면 동영상도 함께 보실 수 있습니다.


이번 시간에는 각 해상도 별로 칼라 값을 지정하는 방법입니다. 16bit, 24bit, 32bit는 크게 어려움이 없습니다. 다만 8bit 에서는 color map 을 사용하기 때문에 다소 까다로운 점이 있습니다. 이런 이유로 16bit, 24bit, 32bit 에 대해서 먼저 알아 보고 마지막에 8bit에 대해서 자세히 알아 보도록 하겠습니다.

16bit 에서의 칼라 지정

16bit에서 칼라를 지정하는 방법은 2가지가 있습니다. Green 칼라만 6bit로 해서 16bit 모두를 사용하는 경우와.

R GB
5bit6bit5bit

또 한 가지는 MSB bit는 사용하지 않고, RGB 모두 5 bit를 사용하여 실제로는 15bit를 사용하는 것입니다.

사용 안함 R GB
1 bit 5bit5bit5bit

왜 이거 하나 통일하지 못했는지 이유는 모르겠습니다만, 프로그램 작성하는 사람으로서는 참 짜증나는 일임에 틀림없습니다.

프레임버퍼 설정 중에 15bit를 선택했을 때 MSB를 사용하지 않는 15bit 칼라를 사용하고, 16bit를 선택했을 때 Green의 6bit를 사용하는 줄 알았는데, 15bit color 은 맞는지 모르겠습니다만, 웹에서 얻은 자료를 보면 16bit 모드에서 반드시 Green 이 6bit 라고 말하기 어려운 것 같습니다. 그래픽 카드에 따라서는 15bit처럼 설정이되는 경우가 있는 것으로 생각됩니다. 아쉽게도 제 가상 P.C.가 15bit를 지원하지 못해 확인을 못했습니다.

그러나 프레임 버퍼의 변경 가능 정보에서 각 RGB에 대한 정보가 나오므로 이 값을 이용하면 15bit와 16bit 처리를 구분하여 처리할 수 있습니다.

프레임 버퍼의 변경 가능 정보에는 RGB에 대한 정보가 있습니다.

struct fb_var_screeninfo.red.length // R 비트의 크기
struct fb_var_screeninfo.green.length // G 비트의 크기
struct fb_var_screeninfo.blue.length // B 비트의 크기

struct fb_var_screeninfo.red.offset // R 값을 위한 shift 횟수
struct fb_var_screeninfo.green.offset // G 값을 위한 shift 횟수
struct fb_var_screeninfo.blue.offset // B 값을 위한 shift 횟수

RGB Length 정보로 R,G,B 각 bit의 크기를 알 수 있습니다.

struct fb_var_screeninfo15bit 16bit
red.length55
green.length56
red.legnth55

RGB offset 정보로 R,G,B로 얼만큼 shift 해야 색상값을 구할 수 있는지 알 수 있습니다.

struct fb_var_screeninfo15bit 16bit
red.offset1011
green.offset55
red.offset00

아래에 색상을 출력하는 예를 올렸습니다.

#include #include #include #include         // open/close#include          // O_RDWR#include      // ioctl#include       // mmap PROT_#include int   main( int argc, char **argv){   int      screen_width;   int      screen_height;   int      bits_per_pixel;   int      line_length;   int      fb_fd;   struct   fb_var_screeninfo  fbvar;   struct   fb_fix_screeninfo  fbfix;   void     *fb_mapped;   int      mem_size;   unsigned short *ptr;   int      coor_y;   int      coor_x;   int      color_r;   int      color_g;   int      color_b;   int      color;   if ( access( "/dev/fb", F_OK))   {      printf( "프레임 버퍼 장치가 없습니다.n");      return 0;   }   if ( 0 > ( fb_fd = open( "/dev/fb", O_RDWR)))   {      printf( "프레임 버퍼에 접근할 수 없습니다.n");      return 0;   }   if ( ioctl( fb_fd, FBIOGET_VSCREENINFO, &fbvar))   {      printf( "FBIOGET_VSCREENINFO를 실행하지 못했습니다.n");      return 0;   }   if ( ioctl( fb_fd, FBIOGET_FSCREENINFO, &fbfix))   {      printf( "FBIOGET_FSCREENINFO 실행하지 못했습니다.n");      return 0;   }   screen_width   = fbvar.xres;                    // 스크린의 픽셀 폭   screen_height  = fbvar.yres;                    // 스크린의 픽셀 높이   bits_per_pixel = fbvar.bits_per_pixel;          // 픽셀 당 비트 개수   line_length    = fbfix.line_length;             // 한개 라인 당 바이트 개수   mem_size       = line_length * screen_height;   fb_mapped      = ( void *)mmap( 0,                                   mem_size,                                   PROT_READ|PROT_WRITE,                                   MAP_SHARED,                                   fb_fd,                                   0);   color_r   = 0x1f;   color_g   = 0x00;   color_b   = 0x00;      color   =   (color_r << fbvar.red.offset  )            | (color_g << fbvar.green.offset)            | (color_b << fbvar.blue.offset );         for ( coor_y = 0; coor_y < 20; coor_y++)   {      ptr   = ( unsigned short*)fb_mapped + screen_width * coor_y;      for ( coor_x = 0; coor_x < 200; coor_x++)      {        *ptr++  = color;      }   }   color_r   = 0x00;   color_g   = 0x3f;   color_b   = 0x00;      color   =   (color_r << fbvar.red.offset  )            | (color_g << fbvar.green.offset)            | (color_b << fbvar.blue.offset );         for ( coor_y = 20; coor_y < 40; coor_y++)   {      ptr   = ( unsigned short*)fb_mapped + screen_width * coor_y;      for ( coor_x = 0; coor_x < 200; coor_x++)      {        *ptr++  = color;      }   }   color_r   = 0x00;   color_g   = 0x00;   color_b   = 0x1f;      color   =   (color_r << fbvar.red.offset  )            | (color_g << fbvar.green.offset)            | (color_b << fbvar.blue.offset );         for ( coor_y = 40; coor_y < 60; coor_y++)   {      ptr   = ( unsigned short*)fb_mapped + screen_width * coor_y;      for ( coor_x = 0; coor_x < 200; coor_x++)      {        *ptr++  = color;      }   }   munmap( fb_mapped, mem_size);   close( fb_fd);   return 0;}

실행한 후의 결과입니다.

사용자 삽입 이미지





24bit와 32bit 칼라 지정은 위의 방법과 대동소이하므로 설명을 생락하겠습니다.

8bit 에서의 칼라 지정

15, 16, 24, 32bit에서는 R,G,B 값에 따라 비트나 값을 세팅하는 방법으로 간단히 색상을 만들 수 있었습니다. 그러나 8bit 에서는 R,G,B 값을 이용하여 바로 색상을 선택하는 것이 아니라 이미 색상이 만들어진 색상 테이블인 Color Map 에서 원하는 색상값을 구하고, 그 색상값에 해당하는 인덱스 번호를 지정해 주어야 합니다.

즉,

인덱스색상
0검정
1파랑
2녹색
3하늘색
4빨강
:
255검정

Color Map이 이렇게 되어 있고 녹색을 찍고 싶으면,

*ptr = 2

이렇게 원하는 색상 번호의 인덱스를 대입해 주어야 합니다.

아래의 소스는 Color Map 에 지정된 색상을 모두 보여 줍니다. 소스의 이해를 돕기 위해, 일부러 변수를 많이 사용하고 가급적 주석을 많이 달도록 노력했습니다.

#include #include #include #include         // open/close#include          // O_RDWR#include      // ioctl#include       // mmap PROT_#include int   main( int argc, char **argv){   int      screen_width;                    // 화면의 픽셀 폭   int      screen_height;                   // 화면의 픽셀 높이   int      bits_per_pixel;                  // 픽셀당 비트 개수   int      line_length;                     // 라인당 바이트 개수   int      fb_fd;                           // 프레임 버퍼 디스크립터   struct   fb_var_screeninfo  fbvar;        // 프레임 버퍼 변경 가능 정보   struct   fb_fix_screeninfo  fbfix;        // 프레임 버퍼 고정 정보   void     *fb_mapped;                      // 프레임 버퍼를 메모리 매핑한 포인터   int      mem_size;                        // 프레임 버퍼의 전체 메모리 용량   unsigned char *ptr;                      // 프레임 버퍼 중 점을 찍을 위치 포인터   unsigned color;                          // 점의 색상   int      cell_x;                          // 16x16 바둑판에서 한개의 셀에 대한 x 픽셀 위치   int      cell_y;                          // 16x16 바둑판에서 한개의 셀에 대한 y 픽셀 위치   int      coor_x;                          // 16x16 바둑판을 그리기 위한 loop 변수   int      coor_y;                          // 16x16 바둑판을 그리기 위한 loop 변수   if ( access( "/dev/fb", F_OK))   {      printf( "프레임 버퍼 장치가 없습니다.n");      return 0;   }   if ( 0 > ( fb_fd = open( "/dev/fb", O_RDWR)))   {      printf( "프레임 버퍼에 접근할 수 없습니다.n");      return 0;   }   ioctl( fb_fd, FBIOGET_VSCREENINFO, &fbvar);   ioctl( fb_fd, FBIOGET_FSCREENINFO, &fbfix);   screen_width   = fbvar.xres;                    // 스크린의 픽셀 폭   screen_height  = fbvar.yres;                    // 스크린의 픽셀 높이   bits_per_pixel = fbvar.bits_per_pixel;          // 픽셀 당 비트 개수   line_length    = fbfix.line_length;             // 한개 라인 당 바이트 개수   mem_size       = line_length * screen_height;   fb_mapped      = ( void *)mmap( 0,               // 프레임 버퍼에 대한 매핑                                   mem_size,                                   PROT_READ|PROT_WRITE,                                   MAP_SHARED,                                   fb_fd,                                   0);   color   = 0;   for ( cell_y = 0; cell_y < 256; cell_y += 16)         // 16x16 바둑판의 y 좌표   {      for ( cell_x = 0; cell_x < 256; cell_x += 16)      // 16x16 바툭판의 x 좌료      {         for ( coor_y = cell_y; coor_y < cell_y+16; coor_y++)           // y 좌표         {            for ( coor_x = cell_x; coor_x < cell_x+16; coor_x++)        // x 좌료            {               ptr  = ( unsigned char*)fb_mapped + screen_width * coor_y + +coor_x;              *ptr  = color;            }         }         color++;                   // color 인덱스를 증가      }   }   munmap( fb_mapped, mem_size);   close( fb_fd);   return 0;}

실행하시면 화면에 Color Map 의 기본 색상이 출력됩니다.

사용자 삽입 이미지











Color Map

또한 8bit 에서는 Color Map을 사용하기 때문에 Color Map 에 지정된 색상을 변경하면 그 칼라 인텍스를 사용한 색상 들은 모두 같은 색으로 변경할 수 있습니다.

Color Map 정보를 읽어 들이거나 변경하기 위해서는 struct fb_cmap 구조체를 사용합니다. fb_cmap 의 구조는 아래와 같습니다.

struct fb_cmap {
? __u32 start;???/* First entry?*/
? __u32 len;??? /* Number of entries */
? __u16 *red;??? /* Red values?*/
? __u16 *green;
? __u16 *blue;
? __u16 *transp;?/* transparency, can be NULL */
};

값을 읽어 들이려면,

fbcmap.start = 0; // 읽어 들일 첫 번째 인덱스 번호
fbcmap.len = 256; // 몇 개까지 읽어 들이겠다는 개수
fbcmap.red = calloc( 256, sizeof( __u16)); // 정보를 받을 read 값 메모리 확보
fbcmap.green = calloc( 256, sizeof( __u16)); // 정보를 받을 green 값 메모리 확보
fbcmap.blue = calloc( 256, sizeof( __u16)); // 정보를 받을 blue 값 메모리 확보
fbcmap.transp = NULL; // transparent 정보는 NULL로 설정

ioctl( fb_fd, FBIOGETCMAP, &fbcmap); // Color Map 값을 구한다.

값을 적용하려면 역시 fbcmap 값을 저장한 후 FBIOPUTCMAP 를 사용하면 됩니다.

ioctl( fb_fd, FBIOPUTCMAP, &fbcmap); // Color Map 에 적용

아래는 32번부터 16개의 칼라 값을 수정하는 예제 입니다.

#include #include #include #include         // open/close#include          // O_RDWR#include      // ioctl#include       // mmap PROT_#include int   main( int argc, char **argv){   int      screen_width;                    // 화면의 픽셀 폭   int      screen_height;                   // 화면의 픽셀 높이   int      bits_per_pixel;                  // 픽셀당 비트 개수   int      line_length;                     // 라인당 바이트 개수   int      fb_fd;                           // 프레임 버퍼 디스크립터   struct   fb_var_screeninfo  fbvar;        // 프레임 버퍼 변경 가능 정보   struct   fb_fix_screeninfo  fbfix;        // 프레임 버퍼 고정 정보   void     *fb_mapped;                      // 프레임 버퍼를 메모리 매핑한 포인터   int      mem_size;                        // 프레임 버퍼의 전체 메모리 용량   unsigned char *ptr;                       // 프레임 버퍼 중 점을 찍을 위치 포인터   unsigned color;                           // 점의 색상   int      cell_x;                          // 16x16 바둑판에서 한개의 셀에 대한 x 픽셀 위치   int      cell_y;                          // 16x16 바둑판에서 한개의 셀에 대한 y 픽셀 위치   int      coor_x;                          // 16x16 바둑판을 그리기 위한 loop 변수   int      coor_y;                          // 16x16 바둑판을 그리기 위한 loop 변수   struct   fb_cmap             fbcmap;   int      ndx_color;   if ( access( "/dev/fb", F_OK))   {      printf( "프레임 버퍼 장치가 없습니다.n");      return 0;   }   if ( 0 > ( fb_fd = open( "/dev/fb", O_RDWR)))   {      printf( "프레임 버퍼에 접근할 수 없습니다.n");      return 0;   }   ioctl( fb_fd, FBIOGET_VSCREENINFO, &fbvar);   ioctl( fb_fd, FBIOGET_FSCREENINFO, &fbfix);   screen_width   = fbvar.xres;                    // 스크린의 픽셀 폭   screen_height  = fbvar.yres;                    // 스크린의 픽셀 높이   bits_per_pixel = fbvar.bits_per_pixel;          // 픽셀 당 비트 개수   line_length    = fbfix.line_length;             // 한개 라인 당 바이트 개수   mem_size       = line_length * screen_height;   fb_mapped      = ( void *)mmap( 0,               // 프레임 버퍼에 대한 매핑                                   mem_size,                                   PROT_READ|PROT_WRITE,                                   MAP_SHARED,                                   fb_fd,                                   0);   color   = 0;   for ( cell_y = 0; cell_y < 256; cell_y += 16)         // 16x16 바둑판의 y 좌표   {      for ( cell_x = 0; cell_x < 256; cell_x += 16)      // 16x16 바툭판의 x 좌료      {         for ( coor_y = cell_y; coor_y < cell_y+16; coor_y++)      // y 좌표         {            for ( coor_x = cell_x; coor_x < cell_x+16; coor_x++)   // x 좌료            {               ptr  = ( unsigned char*)fb_mapped + screen_width * coor_y + +coor_x;              *ptr  = color;            }         }         color++;                                       // color 인덱스를 증가      }   }                           // Color Map의 256 색상 값을 읽어 들입니다.                              fbcmap.start   = 0;                                // 첫 번째 Color Map 부터   fbcmap.len     = 256;                              // 총 256개의 정보를 구한다.   fbcmap.red     = calloc( 256, sizeof( __u16));     // 정보를 받을 read  값 메모리 확보   fbcmap.green   = calloc( 256, sizeof( __u16));     // 정보를 받을 green 값 메모리 확보   fbcmap.blue    = calloc( 256, sizeof( __u16));     // 정보를 받을 blue  값 메모리 확보   fbcmap.transp  = NULL;                             // transparent 정보는 NULL로 설정   ioctl( fb_fd, FBIOGETCMAP, &fbcmap);               // Color Map 값을 구한다.                           // 이 중에 32번째에서 16개의 색상값을 변경해 보겠습니다.   fbcmap.start   = 32;                                 // 변경을 시작할 인덱스 번호는 32   fbcmap.len     = 16;                               // 총 16개를 변경할 것임   for ( ndx_color= 0; ndx_color < 16; ndx_color++)   // 16개의 칼라 값을 설정   {      fbcmap.red[ndx_color]   = 0;                    // red와 green의 값을 0으로 초기화      fbcmap.green[ndx_color] = 0;   }      for ( color= 0; color < 0xffff; color+=20)         // blue 값을 0에서 20씩 증가 시킨다.   {      for ( ndx_color = 0; ndx_color < 16; ndx_color++)   // 칼라맵의 16개에 대해 blue 색상 변경      {         fbcmap.blue[ndx_color]   = color;      }      ioctl( fb_fd, FBIOPUTCMAP, &fbcmap);            // Color Map 에 적용   }                      free( fbcmap.red);   free( fbcmap.green);   free( fbcmap.blue);   munmap( fb_mapped, mem_size);   close( fb_fd);   return 0;}

사용자 삽입 이미지