C++Builder Programming Forum
C++Builder  |  Delphi  |  FireMonkey  |  C/C++  |  Free Pascal  |  Firebird
볼랜드포럼 BorlandForum
 경고! 게시물 작성자의 사전 허락없는 메일주소 추출행위 절대 금지
C++빌더 포럼
Q & A
FAQ
팁&트릭
강좌/문서
자료실
컴포넌트/라이브러리
메신저 프로젝트
볼랜드포럼 홈
헤드라인 뉴스
IT 뉴스
공지사항
자유게시판
해피 브레이크
공동 프로젝트
구인/구직
회원 장터
건의사항
운영진 게시판
회원 메뉴
북마크
볼랜드포럼 광고 모집

C++빌더 팁&트릭
C++Builder Programming Tip&Tricks
[42] 팁! 비트맵에서 아이콘 생성하기~
박지훈.임프 [cbuilder] 9432 읽음    1999-06-04 00:00
우핫~ 새해들어 첫 팁이 나갑니다~ ^^
모두들 연초 연휴 잘 보내셨죠? 오늘은 저의 휴일이 시작되는 날.. 그리고
대부분의 분들에겐 평일이 시작되는 날이군요.. 호홋~ (아이러닉해~ ^^)

오늘의 팁은, 전에 원맨님이 질문하시기도 하셨던, 비트맵으로부터 아이콘을
생성하는 방법입니다.
먼저, 저번에도 여러차례 언급했지만.. 윈도우즈의 '아이콘' 이라는 거시 먼지
간단히 알아보고 지나갑시다...


아이콘은, 비트맵이나 wmf, emf 등과 마찬가지로 이미지 리소스죠.
하지만, 단순한 이미지 리소스가 아니라, 여러가지 목적으로 설계된, 좀 독특한
리소스입니다.
아이콘은, 그 자체로서 투명 바탕을 가지기 위해 기본적인 이미지(xor 마스크)
외에 투명처리를 위한 2진픽셀 이미지인 and 마스크를 가집니다.
(전에 잘못 거꾸로 알려드렸는데.. 실제 이미지가 xor 마스크더군요.. 쩝~
잘못을 알려주신 원맨님 감사~)

그 외에도, 아이콘은 그 자체로서 커서로 사용될 수 있기 위해 기준위치라고
할 수 있는 핫스팟(hot spot)을 가지죠.
또한, 커서파일도 아이콘과 동일한 포맷을 사용하므로, 커서인지 아이콘인지
판별하기 위한 BOOL값 한바이트를 가집니다.


이러한 기본적인 정보를 가지므로.. 윈32 api상의 아이콘 헤더라고 할 수 있는
ICONINFO 구조체는, 다음과 같은 구조로 되어있습니다.
typedef struct _ICONINFO {
   BOOL    fIcon;
   DWORD   xHotspot;
   DWORD   yHotspot;
   HBITMAP hbmMask;
   HBITMAP hbmColor;
} ICONINFO;


첫번째 필드인 ficon은, 아이콘인지 커서인지 판별하는 바이트입니다.
당근 true일때 아이콘이죠. false이면 커서.
두번째, 세번째는 앞에서 말한 핫스팟의 x, y 좌표입니다.
만약 윈도우즈 기본 커서인 화살표 커서처럼, 핫스팟이 가장 왼쪽 위 라면,
핫스팟은 0, 0이 되겠죠? (아이콘일 경우 이 값은 무시되고, 항상 아이콘의 중앙이
핫스팟이 됩니다)
그 다음 필드인 hbmMask와 hbmColor는 각각 and 마스크와 xor 마스크입니다.

구조체를 보셨다시시피, 가장 중요한 것이 두개의 마스크 비트맵을 만들어내는
것입니다. and 마스크는 이진(흑백) 이미지이므로 비트맵을 생성한 직후에
Monochrome 속성을 true로 잡아주어야 합니다. 그 외엔, 그림은 맘대로 그려주면
되구요.

자아.. 그다음으로 중요한 것이.. 이렇게 구성한 구조체로부터 실제로 아이콘
객체(아이콘의 핸들, HICON)을 만들어내는 것입니다. HICON 핸들을 얻을 수
있으면 이걸 빈 TIcon 객체에 할당해서 빌더에서 여러가지 용도로 사용할 수
있습니다.
이 역할을 해주는 것은 api 함수 CreateIconIndirect() 입니다. 이 함수에 인자로
위 구조체의 주소를 넘겨주면 HICON이 넘어오죠.

자아.. 그럼 이제 예제 소스를 보실까요..?
(이 소스는.. 안타깝게도 주소가 기억이 안나는데.. 어딘가 홈페이이지였던가..
에서 들고온 소스입니다. 내용을 보시면 아시겠지만.. 너무도 친절한 주석에,
진행과정을 잘 보여주려는 주인아찌의 노력이 눈물(?)겹습니다..

void __fastcall TForm1::Button1Click(TObject *Sender)
{
    // Get the icon size
    int IconSizeX = GetSystemMetrics(SM_CXICON);
    int IconSizeY = GetSystemMetrics(SM_CYICON);
 
    // Create the "And" mask
    Graphics::TBitmap * AndMask = new Graphics::TBitmap;
    AndMask->Monochrome = true;
    AndMask->Width = IconSizeX;
    AndMask->Height = IconSizeY;
    // Draw on the "And" mask
    AndMask->Canvas->Brush->Color = clWhite;
    AndMask->Canvas->FillRect(Rect(0, 0, IconSizeX, IconSizeY));
    AndMask->Canvas->Brush->Color = clBlack;
    AndMask->Canvas->Ellipse(4, 4, IconSizeX - 4, IconSizeY - 4);
 
    // Draw as a test
    Form1->Canvas->Draw(IconSizeX * 2, IconSizeY, AndMask);
 
    // Create the "XOr" mask
    Graphics::TBitmap * XOrMask = new Graphics::TBitmap;
    XOrMask->Width = IconSizeX;
    XOrMask->Height = IconSizeY;
    // Draw on the "XOr" mask
    XOrMask->Canvas->Brush->Color = clBlack;
    XOrMask->Canvas->FillRect(Rect(0, 0, IconSizeX, IconSizeY));
    XOrMask->Canvas->Pen->Color = clRed;
    XOrMask->Canvas->Brush->Color = clRed;
    XOrMask->Canvas->Ellipse(4, 4, IconSizeX - 4, IconSizeY - 4);
 
    // Draw as a test
    Form1->Canvas->Draw(IconSizeX * 4, IconSizeY, XOrMask);
 
    // Create a icon 
    TIcon * Icon = new TIcon;
    TIconInfo IconInfo;
    IconInfo.fIcon = true;
    IconInfo.xHotspot = 0;
    IconInfo.yHotspot = 0;
    IconInfo.hbmMask = AndMask->Handle;
    IconInfo.hbmColor = XOrMask->Handle;
    Icon->Handle = CreateIconIndirect(&IconInfo);
 
    // Destroy the temporary bitmaps
    delete AndMask;
    delete XOrMask;
 
    // Draw as a test
    Form1->Canvas->Draw(IconSizeX * 6, IconSizeY, Icon);
 
    // Assign the application icon
    Application->Icon = Icon;
 
    // Force a repaint
    InvalidateRect(Application->Handle, NULL, true);
 
    // Free the icon
    delete Icon;
}


이 예제는, 어케 된건지 알기쉽게 중간중간의 각 마스크를 생성할때마다
화면에 그려주어서 정말 알기 쉬운데다가..
친절한 그 사이트 주인아찌(으~~ 어디였는지 기억이 안나요~~~)는 주석까지
달아놓으셔서.. 별로 설명할 것이 없습니다만.. ^^

참고로 말씀드리자면, GetSystemMetrics()는 시스템의 여러가지 설정에 대한
정보를 알려주는 api 함수로서, 인자에 따라 마우스 인스톨 여부나, 버튼 갯수,
메뉴에 나타날 체크마크의 크기 등 여러가지를 알아낼 수 있습니다.
여기에 SM_CXICON 나 SM_CYICON을 인자로 넘겨주면 시스템에 설정된 아이콘의
가로/세로 크기를 돌려줍니다.
(디폴트가 32x32이긴 하지만, 이것이 변경가능하단 건 웬만한 분은 다 아실겁니다.)

뭐.. 그담엔 정말 설명할 것이 없군요.
만약 이렇게 만든 TIcon을 파일로 저장하시려면, 당근 TIcon::SaveToFile() 메소드
를 사용하면 되겠죠?

오늘의 팁은 요기까지입니다. 참고로.. 아이콘 라이브러리 파일(.icl)을
생성하려면?
전에도 한번 언급한 것 같은데.. icl 파일은 아이콘 리소스를 무쟈게 갖고 있는
그냥 단순한 16비트 dll일 뿐입니다. 뭐.. 복잡하게 생각할 필요는 없고,
dll의 머리통과 꼬랑지를 프로그램 리소스에 포함시켜서 갖고 있다가 나중에
TFileStream으로 머리통을 먼저 쓰고, 그다음으로 TIcon::SaveToStream() 메소드를
써서 각 아이콘들을 저장하고.. 마지막으로 dll 꼬랑지를 써준후 클로즈하면
되겠지요? ^^

흠.. 잡담인데...
제가 첨으로 만들었던 진지한(?) 프로그램이 아이콘 에디터였습니다. (92년~93년)
도스용이었지만 당시로는 정말 획기적인 여러가지 기능을 갖고 있었는데..
마소에 우수 공개 소프트로 선정되기도 했었죠... (자랑임다... ^^)
에디팅 기능으로선 어떤 아이콘 에디터보다 더 강력했다고 자부..할뻔 했죠. ^^;;;
대학교 갈아타기하는 동안 신경을 안써서 완죤 사장되었어요.. T.T
일도 이제 거의 마무리되었고 했으니.. 전부터 계획해왔던 다른 몇가지 아이디어와
함께, 낼부터라도 좀씩 손을 댈 생각이랍니다..

기대해보세요.. 다시한번 왕좌(...?)를 되찾는 날이 머지 않았습니다..
마이크로앤젤로.. 아이콘포지.. 이지아이콘.. 우습다.. 푸핫핫핫~~~ ^^
몇년간 아이콘 에디터를 손대지 못한 동안, 상상을 초월하는 엄청난
아이디어들을 많이 구상해뒀거든요.. 흐흐흐흐...
제 프로그래밍 인생(?)에 있어 기념적인 작품인만큼..
아무리 강력해지고 아무리 상용프로그램보다 낫더라도, 반드시 공개 s/w 노선을
끝까지 지킬 생각이랍니다.. (모르죠.. 나중에 굶고 배고프면.. 쩝.. 쉐어웨어라고
등록좀 해주세요... 하고 메시지박스라도 띄울지.. ^^)

아.. 잡담 썰좀 풀었습니다..
신성한 팁! 쓰면서 사적인 광고를 때려서 죄송합니다..
뭐.. 돈벌자고 한짓도 아니니까 이해는 해주세요.. ^^
그럼.. 내일도 다시 멋진 팁으로 돌아올 것을 약속드리면서..
황야의 임프.. 석양속으로 사라집니다..



독립문에서 임펠리테리였습니다.

+ -

관련 글 리스트
42 팁! 비트맵에서 아이콘 생성하기~ 박지훈.임프 9432 1999/06/04
Google
Copyright © 1999-2015, borlandforum.com. All right reserved.