appleton
appleton

Reputation: 168

Rotating a CImage and preserving its alpha/transparency channel

I have some existing code that uses a CImage which has an alpha channel, and I need to rotate it.

I have found the following suggestion which converts the CImage to a GDI+ Bitmap and then rotates it, and the rotated result ends up back in the CImage.

Bitmap* gdiPlusBitmap=Bitmap::FromHBITMAP(atlBitmap.Detach());
gdiPlusBitmap->RotateFlip(Rotate90FlipNone);
HBITMAP hbmp;
gdiPlusBitmap->GetHBITMAP(Color::White, &hbmp);
atlBitmap.Attach(hbmp);

Apparently it works without actually copying the bitmap bytes, which is great, but the problem is that if you create a Bitmap object from a HBITMAP it throws away the alpha channel.

Apparently to preserve the alpha channel you must instead create the Bitmap using the constructor

Bitmap(
  [in]  INT width,
  [in]  INT height,
  [in]  INT stride,
  [in]  PixelFormat format,
  [in]  BYTE *scan0
);

So I'm trying to adapt the above to use this constructor, but the interaction between CImage and Bitmap is a bit confusing. I think I need to create the Bitmap like this

Bitmap* gdiPlusBitmap = new Bitmap(
            pCImage->GetWidth(),
            pCImage->GetHeight(),
            pCImage->GetPitch(),
            PixelFormat32bppARGB,
            (BYTE *)pCImage->GetBits());
nGDIStatus = gdiPlusBitmap->RotateFlip(Rotate90FlipNone);

but I'm not sure how to make the CImage pick up the changes (so that I end up with the original CImage rotated), or where to delete the Bitmap object.

Does anyone know the correct way to do this, preserving the alpha channel ?

Ideally I'd like to avoid copying the bitmap data, but it's not mandatory.

Upvotes: 2

Views: 2071

Answers (1)

Barmak Shemirani
Barmak Shemirani

Reputation: 31609

You can use Gdiplus::Graphics to draw bitmap on CImage.

Note, hard coding PixelFormat32bppARGB can cause problems if image doesn't support alpha channel. I added some basic error check.

CImage image;
if (S_OK != image.Load(L"c:\\test\\test.png"))
{
    AfxMessageBox(L"can't open");
    return 0;
}

int bpp = image.GetBPP();

//get pixel format:
HBITMAP hbmp = image.Detach();
Gdiplus::Bitmap* bmpTemp = Gdiplus::Bitmap::FromHBITMAP(hbmp, 0);
Gdiplus::PixelFormat pixel_format = bmpTemp->GetPixelFormat();
if (bpp == 32)
    pixel_format = PixelFormat32bppARGB;
image.Attach(hbmp);

//rotate:   
Gdiplus::Bitmap bmp(image.GetWidth(), image.GetHeight(), image.GetPitch(), pixel_format, static_cast<BYTE*>(image.GetBits()));
bmp.RotateFlip(Gdiplus::Rotate90FlipNone);

//convert back to image:
image.Destroy();
if (image.Create(bmp.GetWidth(), bmp.GetHeight(), 32, CImage::createAlphaChannel))
{
    Gdiplus::Bitmap dst(image.GetWidth(), image.GetHeight(), image.GetPitch(), PixelFormat32bppARGB, static_cast<BYTE*>(image.GetBits()));
    Gdiplus::Graphics graphics(&dst);
    graphics.DrawImage(&bmp, 0, 0);
}

Upvotes: 1

Related Questions