프로그래밍 관련/MFC

[MFC] GDI+를 이용한 이미지처리 (Gray, 투명, 회전), 선그리기 관련

AlrepondTech 2016. 11. 30. 16:55
반응형

 

 

=================================

=================================

=================================

 

 

 

Image image(LPSTREAM);

 

    int nImageWidth = image.GetWidth();
    int nImageHeight = image.GetHeight();

 

 

    // 투명도 값
    REAL rTransparency = 1.0f;    // 0.1f ~ 1.0f

 

    ColorMatrix colorMatrix = {1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
        0.0f, 1.0f, 0.0f, 0.0f, 0.0f,
        0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
        0.0f, 0.0f, 0.0f, rTransparency, 0.0f,
        0.0f, 0.0f, 0.0f, 0.0f, 1.0f};

 

    ImageAttributes imageAtt;
    imageAtt.SetColorMatrix(&colorMatrix, ColorMatrixFlagsDefault, ColorAdjustTypeBitmap);

 

    //if( graphics.DrawImage(&image, x, y, w, h) != Ok ) return FALSE;

 

    graphics.DrawImage(
        &image, 
        Rect(x, y, w, h), // Destination rectangle
        0,                       // Source rectangle X 
        0,                       // Source rectangle Y
        nImageWidth,     // Source image rectangle width
        nImageHeight,    // Source image rectangle height
        UnitPixel, 
        &imageAtt);

출처 : http://k.80port.net/board/view.php?id=techboard&page=1&sn1=&divpage=1&sn=off&ss=on&sc=on&select_arrange=headnum&desc=asc&no=179

 

 

 

=================================

=================================

=================================

 

 

 

출처: http://petabyte.tistory.com/27

 

 

GDI+를 이용하면 잼난것을 많이 할수 있다.
Gdiplus::ImageAttributes를 이용하면 되는데..
오래전부터 써온것이지만. 몇가지 자주쓰는것을 정리해보면...

* Gray처리
Gdiplus::ImageAttributes ia;
  Gdiplus::ColorMatrix gm;

  float m[5][5]=
  {
   { 0.299f, 0.299f, 0.299f, 0, 0 },
   { 0.588f, 0.588f, 0.588f, 0, 0 },
   { 0.111f, 0.111f, 0.111f, 0, 0 },
   { 0, 0, 0, 1, 0 },
   { 0, 0, 0, 0, 1 },
  };

  memcpy(gm.m, m, sizeof(m));

  ia.SetColorMatrix(&gm);

* 투명처리
Gdiplus::ImageAttributes ia;
 Gdiplus::ColorMap cm;
 cm.oldColor = Gdiplus::Color(255, 255,  0, 255);   // 투명색
 cm.newColor = Gdiplus::Color(  0,   0,  0,   0);
 ia.SetRemapTable(1, &cm);

* 회전
 Gdiplus::Matrix mat;
 mat.RotateAt(angle, Gdiplus::PointF(float(x), float(y))); // 좌표기준으로 회전

 g.SetTransform(&mat);

 

=================================

=================================

=================================

 

 

 

출처: http://use1348.tistory.com/3

 

 

// File에서 Bitmap을 Loading 한다
BOOL LoadBitmap(Bitmap **ppBitmap, LPCTSTR lpszBitmap)
{
CFileFind ff;
if(!ff.FindFile(lpszBitmap))
return FALSE;

WCHAR wFile[MAX_PATH];
MultiByteToWideChar( CP_ACP, 0, lpszBitmap, -1, wFile, MAX_PATH );

*ppBitmap = Bitmap::FromFile(wFile, TRUE);
if(*ppBitmap == NULL)
return FALSE;

return TRUE;
}

 

...

 

Bitmap* pBitmap = NULL;

LoadBitmap(&pBitmap, _T("C:\\연습.png"));

 

ColorMatrix colorMatrix = 
{
1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, m_rTransparency, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f, 1.0f
};

ImageAttributes ia;
ia.SetColorMatrix(&colorMatrix, ColorMatrixFlagsDefault, ColorAdjustTypeBitmap);

Graphics graphics(lpDrawItemStruct->hDC);
graphics.DrawImage(pBitmap, Rect(0, 0, pBitmap->GetWidth(), pBitmap->GetHeight()), 0, 0, pBitmap->GetWidth(), pBitmap->GetHeight(), UnitPixel, &ia);

 

 

 

=================================

=================================

=================================

 

 

 

출처 : 

http://blog.naver.com/najira00/60058229279

 

여지껏 GDI를 사용하다가 vc++ 2005로 갈아타게 되는 김에 GDI+를 한번 공부해보았습니다.
GDI+는 GDI에 업그레이드 버젼이며, 
자세한 정보및 강좌는 제 블로그 Library란에 보시면 강좌가 링크되어있습니다.
저는 잘 못느끼겠지만..속도는 GDI보다 느리다고 하더군요.
그렇지만 한번 GDI+로 코딩하면서 느낀것은 너무너무 간편하다는 점이였습니다.
코딩이 달랑 몇줄에 끝나기도 하고...
별다른 코딩없이 JPG등의 파일을 생성하기도 하고 제어하기도 한다는점이 매력적이였습니다.
왠만한 함수들은 이미 구현이 되어있더군요.
어쨌든 gdi+를 처음 해보시려고 하는 분들에게 작은 도움이 되지 않을까 해서 이렇게 글을 올려봅니다.
참고로 제 환경은 vc++ 2005입니다.

GDI+를 사용하기 위한 설정방법
먼저 GDI+를 사용하기 위해서는 h파일에 다음과 같이 선언해주셔야합니다.
#include <GdiPlus.h> //header 포함
using namespace Gdiplus; //네임스페이스 설정

그후 cpp 파일에 전역 변수로 토큰을 생성합니다.
참고로 토큰은 각 클래스 별로 이름이 달라야합니다.
ULONG_PTR g_GdiPlusTokenBoxData; //다른 class에서 만들때는 g_GdiPlusTokenAnother; 이런식으로 이전과 동일하면 안됩니다.
그후 class의 생성자와 소멸자 부분에 각각 gdi+ 사용 함수와 제거 함수를 넣어주어야합니다.
생성자 부분에는
//->gdi+ start
GdiplusStartupInput GdiplusStartupInput;
GdiplusStartup(&토큰변수이름(여기서는 g_GdiPlusTokenBoxData), &GdiplusStartupInput, NULL);

소멸자 부분에는
//->gdi+ shutdown 
GdiplusShutdown(토큰변수이름(여기서는 g_GdiPlusTokenBoxData));

이렇게 하면 gdi+를 사용하실 준비가 끝난것입니다.

이미지 출력 (JPG 파일(혹은 외부 이미지)을 가져와 GDI+로 출력)
기존 GDI에서는 dc얻어오고, dc만들고, bitmap 만들고 벼라별 코딩을 다해야했습니다.
사실 그게 어렵거나 긴 코딩은 아니지만..GDI+에서는 확연할 정도로 코딩이 짧아집니다.
단 몇줄이면 이미지를 출력할수 있고, 복잡하지 않아서 나중에 수정할때도 편리합니다.
CPaintDC dc(this); //혹은 CCLientDC dc(this); //On_Paint라면 처음부터 존재하고, OnPaint가 아니라면 CClient로 생성합니다.
Graphics ScreenG(dc.GetSafeHdc()); //dc에서 dc핸들을 가져와서 Graphics에 연결합니다. 
                                                      //이제 이곳에다 그리면 바로바로 출력됩니다. 여기서 ScreenG변수가 모니터라고 보시면됩니다.
Bitmap *pBitmap; //Bitmap 포인터변수입니다. 기존 GDI에서 쓰던게 아니니 대소문자에 조심해주세요
pBitmap = (Bitmap*)Image::FromFile(가져올JPG경로); //외부 이미지를 가져옵니다.
ScreenG.DrawImage(pBitmap, 0, 0); //모니터에 가져온 이미지를 뿌려줍니다. 
                                                   //여기서 2,3번째 인자에 0이 들어가면 이미지 전체가 출력됩니다.
                                                   //당연히 스크린좌표는 아니고 해당 핸들에 부여된 영역을 의미합니다.
delete pBitmap; //delete 안해주시면 메모리에 남아 코딩에 따라서 어마어마한 메모리 누수가 발생할수 있습니다.
                       //포인터가 아닌 Bitmap은 지우실 필요없고, 또한 해당 변수에 이미지랑 연결도 안해놓고 delete 하면 에러납니다.

이미지 출력 (RESOURCE에서 이미지를 가져와 GDI+로 출력)
위에 처럼 경로에 있는걸 가져올수도 있지만, 당연히 RESOURCE에 이미지도 가져올수 있습니다.
참고로 리소스에 이미지를 추가하시려면 vc++왼쪽탭에 리소스뷰에 오른쪽 마우스 버튼 클릭->리소스 추가->가져오기를 선택하시고 원하는 이미지를 선택하시고 이름 수정 원하시면 수정하시면 됩니다.),
어쨌든..이미지 하나를 IDB_BITMAP에 저장해두었다면
위 코드에서 한줄만 바꿔주시면 됩니다.
CPaintDC dc(this);
Graphics ScreenG(dc.GetSafeHdc());
Bitmap *pBitmap;
pBitmap = Bitmap::FromResource(AfxGetInstanceHandle(),(WCHAR*)MAKEINTRESOURCE(리소스명(여기서는 IDB_BITMAP)));
ScreenG.DrawImage(pBitmap, 0, 0);
delete pBitmap;
이렇게 하시면 리소스에 있는 이미지도 가져와서 뿌려주실수 있습니다.

이미지 출력 (원하는 영역에 원하는 크기만큼 출력)
위에 코드는 단순히 절대크기의 이미지를 출력하는 방법입니다.
해당 핸들에 부여된 시작점 0,0 부터 이미지 크기 그대로 출력하는 방법입니다.
원하는 영역에서 원하는 크기만큼 출력하고 싶다면 DrawImage 인자만 바꾸어 넣으시면 됩니다.
ScreenG.DrawImage(pBitmap, Rect(x, y, sizex, sizey), 0, 0, sizex, sizey, UnitPixel);
여기서 x와 y는 모니터에 뿌려줄 시작 위치입니다.
sizex와 sizey는 해당 이미지의 크기입니다.
이 코딩을 해석하면 pBitmap에 연결된 이미지를,
원본 이미지의 0, 0 위치부터 sizex, sizey크기만큼을,
모니터에(dc에 핸들에 부여된 영역기준) x, y 위치부터 sizex, sizey 만큼 그려줘라.
라는 의미입니다.
여기서 Rect(x, y, sizex, sizey)를 수정하면 이미지를 작게, 혹은 크게 그려줄수 있습니다.
0, 0, sizex, sizey 부분도 역시 수정하면 원본 이미지의 원하는 위치를 선택할수 있습니다.

참고로 Bitmap 변수는 pBitmap->GetWidth(), pBitmap->GetHeight()를 통해 이미지 가로 세로 크기를 구할수 있습니다.
예) ScreenG.DrawImage(pBitmap, Rect(x, y, sizex, sizey), 0, 0, pBitmap->GetWidth(), pBitmap->GetHeight(), UnitPixel);

이미지 회전 (원하는 이미지를 회전)
이미지를 회전 시킬수 있습니다.
원하는 포인터를 제자리에서 회전할수 있고, 원하는 위치를 기준으로도 회전 시킬수 있습니다.
회전을 위해서는 가장 쉬운게 RotateFlip()이란느 함수입니다.
그런데, 이 함수는... 정해진 각밖에 못움직입니다.
만약 자유롭게 회전 시키려고 하면 쓸수가 없습니다.
그래서 RotateAt()함수와 Matrix 변수를 이용해야합니다.
CPaintDC dc(this);
Graphics ScreenG(dc.GetSafeHdc());
Bitmap *pBitmap;
pBitmap = (Bitmap*)Image::FromFile(가져올JPG경로);
Gdiplus::Matrix matrix;
matrix.RotateAt(원하는 각도(예:235.7), Gdiplus::PointF((float)(pBitmap->GetWidth()/2), (float)(pBitmap->GetHeight()/2)));
                           //해당 이미지의 정중앙을 기준으로 235.7도 돌리라는 얘기입니다. 
                           //참고로 가운데를 기준으로 돌리기 위해서는 이미지의 가로세로 사이즈가 홀수여야 깔끔하게 돌아갈겁니다.
ScreenG.SetTransform(&matrix); //ScreenG를 위에 규칙대로 돌려버렸습니다.
ScreenG.DrawImage(pBitmap, 0, 0); //이미 돌아간 ScreenG에 pBitmap 이미지를 그려줍니다. 알아서 같이 돌아가게됩니다.
delete pBitmap;

이미지 틀기 (원하는 이미지를 사각형이 아닌 평행사변형으로 출력)
이방법은 제 블로그 Library에 가셔서 GDI+강좌 링크에 가서 보세요.
저는 쓸데가 없어서 안해보았습니다.

이미지 출력 (Bitmap 이미지 투명화)
투명화도 쉽게 할수 있습니다.
ImageAttributes 변수를 만들고 low와 high colorkey를 설정합니다.
RGB()가 아닌 Color 변수가 인자로 들어가며, low와 high 사이에 존재하는 모든 색은 자동으로 투명화 처리됩니다.
한 색깔만 투명화 시키고자 할때는 둘다 똑같은 같으로 넣어주면 됩니다.
ImageAttributes imageAttr;
imageAttr.SetColorKey(투명화시킬 low Color(예:Color(243,109,109)), 투명화시킬 high Color(예:Color(243,109,109)));
ScreenG.DrawImage(pBitmap, Rect(0, 0, sizex, sizey), 0, 0, sizex, sizey, UnitPixel, &imageAttr);

Bitmap 변수 제거(메모리 누수 방지)
위에 쓴것처럼 포인터로 만들어진 Bitmap 변수에 값이 존재한다면, 반드시 delete 해주어야 합니다.
그러나 코딩에 따라 해당 변수가 멤버 변수라서 값을 넣어줄때도 있고 아닐때도 있다면, delete 시킬 기준이 필요합니다.
해당 번지가 비었는지 아닌지를..알 방법이 없더군요..
그래서 편법을 사용했습니다.
Bitmap *m_pBitmap; 선언후에,
m_pBitmap = NULL; 을 넣어서 초기화 해주고
포인터 값을 넣어줄때는 그냥 넣어주고, 
delete 시킬때는 반드시 NULL인지 확인하고 NULL이면 지워주고 다시 NULL을 넣어줍니다.
if (m_pBitmap != NULL) {
    delete m_pBitmap;
    m_pBitmap = NULL;
}
그러면 변수가 비워졌는지 아닌지 판별이 가능해집니다.

더블버퍼링(GDI+를 이용한 더블버퍼링)
더블 버퍼링이란 이미지를 출력할때 바로 모니터에 내보내면서 깜빡이는 문제를 해결하기 위한 방법입니다.
메모리에 먼저 그리고 싶은걸 모두 그려주고, 이미 그려진 메모리에 이미지를 단한번 출력함으로써 깜빡임을 방지합니다.
GDI+를 이용해서 더블버퍼링을 하는 법 역시 GDI+에 비해 간단합니다.
CPaintDC dc(this);
Graphics ScreenG(dc.GetSafeHdc()); //dc의 핸들을 가져와 실제 모니터에 내보낼 Graphics변수입니다
Bitmap *pBitmap; //출력할 이미지 변수입니다
pBitmap = (Bitmap*)Image::FromFile(가져올JPG경로);
Bitmap memBitmap(pBitmap->Width(), pBitmap->Height()); //가져온 이미지의 크기만큼 Bitmap 파일을 하나 만듭니다.
Graphics memG(&memBitmap); //메모리에 그려줄 Graphics변수입니다.
memG.DrawImage(pBitmap, 0, 0); //메모리에 먼저 이미지를 그려줍니다.
ScreenG.DrawImage(&memBitmap, 0, 0); //메모리에 이미 그려진걸 가져옵니다.
delete pBitmapBack; //memBitmap은 delete해줄수 없습니다. 자동으로 메모리에서 사라지니 포인터 변수만 delete해주세요

JPG 파일 생성 (GDI+로 이미지를 JPG파일로 생성)
그냥 가지고 가셔서 붙여넣으시면 됩니다. -.-;
CLSID Clsid;
EncoderParameters Para;
UINT num, size;
ImageCodecInfo *arCod;
GetImageEncodersSize(&num, &size);
arCod=(ImageCodecInfo *)malloc(size);
GetImageEncoders(num,size,arCod);
for (UINT i = 0;i < num; i++) {
        if(wcscmp(arCod[i].MimeType,L"image/jpeg") == 0) {
            Clsid=arCod[i].Clsid;
            break;
        }    
}
free(arCod);
ULONG Quality = 100; //jpg 화질입니다. 100이 가장 높으며, 수가 줄어들수록 퀄리티가 떨어집니다.
Para.Count = 1;
Para.Parameter[0].Guid = EncoderQuality;
Para.Parameter[0].Type = EncoderParameterValueTypeLong;
Para.Parameter[0].NumberOfValues = 1;
Para.Parameter[0].Value = &Quality;
pBitmap->Save(생성할 파일경로와이름, &Clsid, &Para); //pBitmap의 이미지를 jpg 파일로 생성합니다.

글자 출력 (GDI+ 글자 출력)
CString strTemp = 원하는 글자;
FontFamily  fontFamily(L"Verdana");
Font font(&fontFamily, 9, FontStyleBold, UnitPoint); //verdana라는 글자체로 9의 크기로, 굵은 font를 생성합니다.
StringFormat stringFormat;
stringFormat.SetAlignment(StringAlignmentNear); //다 써진 글자가 영역에 상단에 맞춰지게합니다.
stringFormat.SetLineAlignment(StringAlignmentNear); //글이 다음줄로 갱신될때 왼쪽부터 쓰게합니다.
stringFormat.SetTrimming(StringTrimmingNone);
SolidBrush  brush(Color(48,58,118)); //글자의 색상을 설정합니다.
memG.DrawString(strTemp, 글자수, &font, RectF(x, y, sizex, sizey), &stringFormat, &brush); 
                                                                              //x, y위치에서 sizex, sizey만큼 크기로 글자를 출력합니다.

데이터 형 변환 (GDI -> GDI+ 데이터형 변환 : CBitmap을 -> Bitmap으로)
부득이하게 CBitmap 파일을 Bitmap으로 바꿔야 한다면, 다음 방법으로 바꿔줄수 있습니다.
Bitmap포인터변수 = Bitmap::FromHBITMAP((HBITMAP)CBitmap변수.m_hObject, NULL);

데이터 형 변환 (GDI+ -> GDI 데이터형 변환 : Bitmap -> CBitmap으로)
위에 방법처럼 쉽게 바꾸는 법이 있는지 몰라서 -_-;; 
진짜 한참 찾고 알아봤는데... 도저히 모르겠더군요 --;
그냥 CBitmap에다가 직접 Bitmap을 그려버렸습니다. ㅋㅋ
무식한 방법인지는 몰라도 문제는 없더군요 -.-;; 혹시 그냥 바꾸는 법 아시는 분은 알려주시면 너무너무 감사드립니다.
여기서 중요한건 Graphics에 Bitmap이 아닌 CBitmap을 연결해서 그려주면 Graphics로도 CBitmap을 활용할수 있다는점입니다.

Bitmap *pBitmap ; 
pBitmap = (Bitmap*)Image::FromFile(가져올JPG경로);

CClientDC dc(this);
CDC memDC;
CBitmap memBitmap; //Bitmap을 받아서 그리게될 CBitmap입니다.
memDC.CreateCompatibleDC(&dc);
memBitmap.CreateCompatibleBitmap(&dc, pBitmap->GetWidth(), pBitmap->GetHeight());
memDC.SelectObject(memBitmap);

Graphics graphicsMem(memDC.GetSafeHdc());
graphicsMem.DrawImage(pBitmap, 0, 0); //CBitmap 변수에 Bitmap 이미지를 그려줍니다.
delete pBitmap; //기존에 pBitmap이 존재할 이유가 없으므로 delete 시킵니다.

 

 

 

 

=================================

=================================

=================================

 

 

 

츨처: http://egloos.zum.com/ditongs/v/1324609

 

GDI+에 가장 큰 매력이라면 Alpha와 Antialias가 아닐까한다. 근데 이 두가지 기능이 시원스럽게 섞이지 않아 고생을 좀 했다. 현재 진행하고 있는 이미지 관련 프로젝트에서는 부드러운 판서를 위해 안티얼라이싱을 기본적으로 제공한다. 모든 픽셀에 대해서 안타얼라이어싱을 한다는 이야기인데, 다 좋다! 문제가 붉어지기 시작한 것은 이렇게 그려진 이미지를 지우는것이다. 일반적인 GDI에서는 투명값으로 예약한 색으로 덮어 그리고 TransparetBlt () 함수에 마지막 인자로 투명값을 주면 끝이었는데... 안티얼라이어싱이 적용되어 버리면 투명값이 뭉개져버리는것이다. 그럼 투명값을 적용할때만 안티얼라이싱을 해제하고 지우면 되지 않냐고 하겠지만 문제는, 다음 그 위치에 다시 그려지게 될 경우엔 투명값과 안티얼라이싱이 되어버리기 때문에 소위말하는 떵 (- _-;)이 생겨 버리게 되었다. 어떻게 이 문제를 해결해야할까.

GDI+에서 쌩으로 Bitmap을 하나 만들게 되면 모든 비트 픽셀이 제로(0)이다. 그럼 이렇게 생성한 이미지를 화면에 그리면 어떻게 될까? 검은색으로 나올까? 정답은 아무것도 출력되지 않는다. 정확하게 말하면 아무것도 출력되지 않는것이 아니고 이전 이미지가 그대로 그려지는것이다. 이유인즉, 알파값이란 이전 픽셀과의 섞는 농도인데 현재 알파값이 제로이기 때문에 섞어도 이전 그 픽셀이기 때문이다. 자! 그렇다면 지워질 영역에다가 알파값 제로인 색을 그리게 되면 투명하게 적용되지 않을까? 문제는 어떻게 알파값이 제로인 픽셀을 그리냐는것이다. 알파값이 제로이기 때문에 무조건 무시되어 버리기 때문이다. 왜 GDI+에서는 비트스트림을 숫제로 받아 처리하지 못할까. 비트스트림을 받아올 수 있다면 포인터 연산으로 해당 픽셀값을 변경할 수 있을텐데... 

내가 찾은바론 제약이 있긴 하나 원하는 칼라 그대로 (알파값마저) 그릴 수 있는 함수가 GDI+에 딱 하나 존재했다. Graphics 클래스에 있었다. (난 사실 Image쪽에 있을 줄 알았는데..) 그 함수는 Clear() 이다. 이 함수는 인자를 하나 받는데 그 인자가 바로 우리가 적용하고자 하는 칼라이다. 이 함수를 이용해서 그리면 알파값 그대로 그릴 수가 있다. 근데 이 함수가 동작하는 영역은 현재 적용된 Clip 영역이었다. 고로 투명값을 적용하기 위해서는

1. Region을 이용하여 지워져야 할 영역을 계산한다.
2. Graphics.GetClip () 함수를 이용해서 이전 클리핑 영역을 저장한다.
3. Graphics.SetClip () 함수를 이용해서 새로 적용될 클리핑 영역을 선택한다.
4. Graphics.Clear (Color (0, 0,0,0)); 호출하여 강제로 알파값을 제로로 만든다. 
5. 상태를 복구하기 위해서 2번에서 저장한 영역을 3번 처럼 적용한다.

 

 

 

 

반응형

 

728x90

 

 

=================================

=================================

=================================

 

 

 

출처: http://stackoverflow.com/questions/11684455/how-to-draw-transparent-bmp-with-gdi

 

I'm currently editing some old GDI code to use GDI+ and ran into a problem when it comes to draw a BMP file with transparent background. The old GDI code did not use any obvious extra code to draw the background transparent so I'm wondering how to achieve this using GDI+.

My current code looks like this

HINSTANCE hinstance = GetModuleHandle(NULL); bmp = Gdiplus::Bitmap::FromResource(hinstance, MAKEINTRESOURCEW(IDB_BMP)); Gdiplus::Graphics graphics(pDC->m_hDC); graphics.DrawImage(&bmp, posX, posY);

I also tried to create a new bitmap from the resource by using the clone method and by drawing the bitmap to a newly created one but neither did help. Both times I used PixelFormat32bppPARGB.

Then I tried to use alpha blending but this way the whole image gets transparent and not only the background:

Gdiplus::ColorMatrix clrMatrix = {      1.0f, 0.0f, 0.0f, 0.0f, 0.0f,     0.0f, 1.0f, 0.0f, 0.0f, 0.0f,     0.0f, 0.0f, 1.0f, 0.0f, 0.0f,     0.0f, 0.0f, 0.0f, 0.5f, 0.0f,     0.0f, 0.0f, 0.0f, 0.0f, 1.0f };  Gdiplus::ImageAttributes imgAttr; imgAttr.SetColorMatrix(&clrMatrix);  graphics.DrawImage(&bmp, destRect, 0, 0, width(), height(), Gdiplus::UnitPixel, &imgAttr);

The transparency information is already contained in the image but I don't have a clue how to apply it when drawing the image. How does one achieve this?

 

-------------------------------------------------------------------------------------------------------

 

 

A late answer but:
ImageAttributes imAtt; imAtt.SetColorKey(Color(255,255,255), Color(255,255,255), ColorAdjustTypeBitmap);
Will make white (255,255,255) transparent on any bitmap you use this image attribute with.

--------------------------------------------------------------------------------------------------------

 

 

I had the same problem. Transparent BMPs have not been shown correctly and unfortunately, PNGs cannot be loaded directly from resources (except by adding quite a bit of code which copies them into a stream and loads them from the stream). I wanted to avoid this code.
The bitmaps that I'm using also use only two colours (background and logo). Having an alpha channel means that I would need to save them with a much higher colour depth instead of only 2 bit colour depth.

Evan's answer was exactly was I was looking for :-)

Instead of white, I'm using the colour of the top left pixel as transparent colour:

Gdiplus::Color ColourOfTopLeftPixel; Gdiplus::Status eStatus = m_pBitmap->GetPixel(0, 0, &ColourOfTopLeftPixel); _ASSERTE(eStatus == Gdiplus::Ok);  // The following makes every pixel with the same colour as the top left pixel (ColourOfTopLeftPixel) transparent. Gdiplus::ImageAttributes ImgAtt; ImgAtt.SetColorKey(ColourOfTopLeftPixel, ColourOfTopLeftPixel, Gdiplus::ColorAdjustTypeBitmap);
shareimprove this answer

 

 

 

=================================

=================================

=================================

 

 

 

출처: http://egloos.zum.com/icarosss/v/1191630

 

 

카메라 캡쳐 영상에 이미지를 입히다 보니 투명한 이미지를 그려야할 필요성이 있었다.
단순히 Transparent 이미지가 아닌 진짜 투명한 이미지.. 이것도 GDI+를 이용하면 쉽게 해결이 된다.

  // 4행4열값을 변경 (0.0f ~ 1.0f )
  ColorMatrix colorMatrix = {1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
                                        0.0f, 1.0f, 0.0f, 0.0f, 0.0f,
                                        0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
                                        0.0f, 0.0f, 0.0f, 0.5f, 0.0f,
                                        0.0f, 0.0f, 0.0f, 0.0f, 1.0f};


  ImageAttributes imageAtt;
  imageAtt.SetColorMatrix(&colorMatrix, ColorMatrixFlagsDefault,
    ColorAdjustTypeBitmap);
  Image image(lpszW); // 이미지 path
  g.DrawImage(...);

 

 

 

=================================

=================================

=================================

 

 

 

출처: http://blog.naver.com/PostView.nhn?blogId=hextrial&logNo=60117613964

 

 

 

1. stdafx.h 에

#include <GdiPlus.h>
#pragma comment (lib,"gdiplus")
using namespace Gdiplus;

추가

 

2. // gdi plus 초기화 관련

App파일에

(ex] Module.cpp)

// 유일한 CModuleApp 개체입니다.

...

CModuleApp theApp;

ULONG_PTR gdiplusToken;

..

BOOL CModuleApp::InitInstance(){ .... // gdi plus 초기화
 GdiplusStartupInput gdiplusStartupInput;
 if(::GdiplusStartup(&gdiplusToken, &gdiplusStartupInput,NULL)!=Ok)
 {
  AfxMessageBox(_T("ERROR: Failed to initialize GDI+"));
  return FALSE;
 }
...}

 

3. ~App 클래스에 ExitInstance()가상함수를 재정의 하고 GDI+라이브러리를 해제하는 코드를 추가한다

int CModuleApp::ExitInstance()
{
 // TODO: 여기에 특수화된 코드를 추가 및/또는 기본 클래스를 호출합니다.
 
 ::GdiplusShutdown(gdiplusToken);
 return CWinApp::ExitInstance();
}

 

4. 초기화 부분

 HRSRC hResource = FindResource(AfxGetApp()->m_hInstance, MAKEINTRESOURCE(IDB_HUD_DIALS), TEXT("PNG"));
 if(!hResource) return;     

 DWORD imageSize = SizeofResource(AfxGetApp()->m_hInstance, hResource);    
 HGLOBAL hGlobal = LoadResource(AfxGetApp()->m_hInstance, hResource);    
 LPVOID pData = LockResource(hGlobal);   

 HGLOBAL hBuffer = GlobalAlloc(GMEM_MOVEABLE, imageSize);
 LPVOID pBuffer = GlobalLock(hBuffer);

 CopyMemory(pBuffer,pData,imageSize);    
 GlobalUnlock(hBuffer);  

 
 HRESULT hr = CreateStreamOnHGlobal(hBuffer, TRUE, &pStream);

 

5. 그리는 부분

 

  CClientDC dc(&m_CtrlStatic_Cam);
  Graphics Hud_graphic(dc);
  Image imagePNG(pStream);
  // pStream->Release();    
  if (imagePNG.GetLastStatus() != Ok) return;
  Hud_graphic.DrawImage(&imagePNG, 0, 0, imagePNG.GetWidth(), imagePNG.GetHeight());

 

 

 

 

 

 

=================================

=================================

=================================

 

 

 

 

출처: http://pjw0703.blogspot.kr/2011/04/mfc-gdi.html

 

MFC에서 GDI+ 사용하기

 
1. Anti alias 라인을 그리기 위한 GDI+ 를 사용

Step1. stdafx.h 에 선언추가

#include 
#pragma comment(lib, "gdiplus")
using namespace Gdiplus;



Step2. 초기화

[ProjectName]App.c 파일의 InitInstance() 함수에 초기화를 추가한다.

GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

그리고 아래 두 라인을 광역변수로 추가한다.

GdiplusStartupInput gdiplusStartupInput;
ULONG_PTR gdiplusToken;



Step3. 정리

[ProjectName]App.c 파일의 ExitInstance() 함수(없으면 만든다)에 정리코드를 추가한다.

GdiplusShutdown(gdiplusToken);



Step4. 사용

Graphics graphics( pDC->m_hDC );
graphics.SetSmoothingMode( SmoothingModeAntiAlias );
Color c(50,200,255);
Pen p(c, 1.0);
Gdiplus::PointF p1, p2;
p1.X = 0.0;
p1.Y = 0.0;
p2.X = 100.0;
p2.Y = 10.0;

graphics.DrawLine (&p, p1, p2);



2. Pen : 연결된 선의 꺽임 처리

p.SetLineJoin (LineJoinRound);

enum LineJoin
{
    LineJoinMiter = 0,
    LineJoinBevel = 1,
    LineJoinRound = 2,
    LineJoinMiterClipped = 3
};

 


 

 
3. Pen : 선의 시작과 끝부분 처리

p.SetStartCap(LineCapRoundAnchor);
p.SetEndCap(LineCapArrowAnchor);

enum LineCap
{
    LineCapFlat = 0,
    LineCapSquare = 1,
    LineCapTriangel = 3,

    LineCapNoAnchor = 0x10,
    LineCapSquareAnchor = 0x11,
    LineCapRoundAnchor = 0x12,
    LineCapDiamondAnchor = 0x13,
    LineCapArrowAnchor = 0x14,

    LineCapCustom = 0xff,
    LineCapAnchorMask = 0xf0
}

 


 




4. 안티엘러어싱 적용

graphics.SetSmoothingMode(SmoothingModeHighQuality);

enum SmoothingMode
{
//XP이상 사용가능
SmoothingModeInvalid =QualityModeInvalid,
SmoothingModeDefault =QualityModeDefault,
SmoothingModeHighSpeed =QualityModeLow,
SmoothingModeHighQuality =QualityModeHigh,
SmoothingModeNone,
SmoothingModeAntiAlias,
#if(GDIPVER>=0x0110)
//비스타 이상 버전에서만 사용가능..
SmoothingModeAntiAlias8x4 =SmoothingModeAntiAlias,
SmoothingModeAntiAlias8x8 
#endif//(GDIPVER>=0x0110)
};

 



5. 부드러운 선그리기

graphics.DrawCurve(&p, points, 6, 0.5f);

Struct DrawCurve(const Pen* pen, const Pointf* points, INT count, REAL tension); 
arg1: Pen클래스 객체의 주소
arg2: Point배열 클래스의 주소
arg3: 두번째로 전달 받은 Point배열의 클래스 객체의 수..
arg4: 곡선을 그릴때 각이 생기지 않도록 끝을 강제로 늘려주는 장력을 명시 한다.

 


 


 

 

=================================

=================================

=================================

 

 

반응형