void CanvasD2D::DrawBitmap(Gdiplus::Bitmap* bitmap, const Gdiplus::Rect& dstRect, const Gdiplus::Rect& srcRect) { if (srcRect.Width != dstRect.Width || srcRect.Height != dstRect.Height) { // If the bitmap needs to be scaled, get rid of the D2D target and use the GDI+ code path // to draw the bitmap. This is due to antialiasing differences between GDI+ and D2D on // scaled bitmaps. EndTargetDraw(); } if (!m_Target) // Use GDI+ if D2D render target has not been created. { m_GdipGraphics->DrawImage( bitmap, dstRect, srcRect.X, srcRect.Y, srcRect.Width, srcRect.Height, Gdiplus::UnitPixel); return; } // The D2D DrawBitmap seems to perform exactly like Gdiplus::Graphics::DrawImage since we are // not using a hardware accelerated render target. Nevertheless, we will use it to avoid // the EndDraw() call needed for GDI+ drawing. Util::WICBitmapLockGDIP* bitmapLock = new Util::WICBitmapLockGDIP(); Gdiplus::Rect lockRect(0, 0, bitmap->GetWidth(), bitmap->GetHeight()); Gdiplus::Status status = bitmap->LockBits( &lockRect, Gdiplus::ImageLockModeRead, PixelFormat32bppPARGB, bitmapLock->GetBitmapData()); if (status == Gdiplus::Ok) { D2D1_BITMAP_PROPERTIES props = D2D1::BitmapProperties( D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED)); Microsoft::WRL::ComPtr<ID2D1Bitmap> d2dBitmap; HRESULT hr = m_Target->CreateSharedBitmap( __uuidof(IWICBitmapLock), bitmapLock, &props, d2dBitmap.GetAddressOf()); if (SUCCEEDED(hr)) { auto rDst = ToRectF(dstRect); auto rSrc = ToRectF(srcRect); m_Target->DrawBitmap(d2dBitmap.Get(), rDst, 1.0F, D2D1_BITMAP_INTERPOLATION_MODE_LINEAR, rSrc); } // D2D will still use the pixel data after this call (at the next Flush() or EndDraw()). bitmap->UnlockBits(bitmapLock->GetBitmapData()); } bitmapLock->Release(); }
void CanvasD2D::DrawMaskedBitmap(Gdiplus::Bitmap* bitmap, Gdiplus::Bitmap* maskBitmap, const Gdiplus::Rect& dstRect, const Gdiplus::Rect& srcRect, const Gdiplus::Rect& srcRect2) { if (!BeginTargetDraw()) return; auto rDst = ToRectF(dstRect); auto rSrc = ToRectF(srcRect); Util::WICBitmapLockGDIP* bitmapLock = new Util::WICBitmapLockGDIP(); Gdiplus::Rect lockRect(srcRect2); Gdiplus::Status status = bitmap->LockBits( &lockRect, Gdiplus::ImageLockModeRead, PixelFormat32bppPARGB, bitmapLock->GetBitmapData()); if (status == Gdiplus::Ok) { D2D1_BITMAP_PROPERTIES props = D2D1::BitmapProperties( D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED)); Microsoft::WRL::ComPtr<ID2D1Bitmap> d2dBitmap; HRESULT hr = m_Target->CreateSharedBitmap( __uuidof(IWICBitmapLock), bitmapLock, &props, d2dBitmap.GetAddressOf()); if (SUCCEEDED(hr)) { // Create bitmap brush from original |bitmap|. Microsoft::WRL::ComPtr<ID2D1BitmapBrush> brush; D2D1_BITMAP_BRUSH_PROPERTIES propertiesXClampYClamp = D2D1::BitmapBrushProperties( D2D1_EXTEND_MODE_CLAMP, D2D1_EXTEND_MODE_CLAMP, D2D1_BITMAP_INTERPOLATION_MODE_LINEAR); // "Move" and "scale" the |bitmap| to match the destination. D2D1_MATRIX_3X2_F translate = D2D1::Matrix3x2F::Translation(rDst.left, rDst.top); D2D1_MATRIX_3X2_F scale = D2D1::Matrix3x2F::Scale( D2D1::SizeF((rDst.right - rDst.left) / (float)srcRect2.Width, (rDst.bottom - rDst.top) / (float)srcRect2.Height)); D2D1_BRUSH_PROPERTIES brushProps = D2D1::BrushProperties(1.0F, scale * translate); hr = m_Target->CreateBitmapBrush( d2dBitmap.Get(), propertiesXClampYClamp, brushProps, brush.GetAddressOf()); // Load the |maskBitmap| and use the bitmap brush to "fill" its contents. // Note: The image must be aliased when applying the opacity mask. if (SUCCEEDED(hr)) { Util::WICBitmapLockGDIP* maskBitmapLock = new Util::WICBitmapLockGDIP(); Gdiplus::Rect maskLockRect(0, 0, maskBitmap->GetWidth(), maskBitmap->GetHeight()); status = maskBitmap->LockBits( &maskLockRect, Gdiplus::ImageLockModeRead, PixelFormat32bppPARGB, maskBitmapLock->GetBitmapData()); if (status == Gdiplus::Ok) { D2D1_BITMAP_PROPERTIES maskProps = D2D1::BitmapProperties( D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED)); Microsoft::WRL::ComPtr<ID2D1Bitmap> d2dMaskBitmap; hr = m_Target->CreateSharedBitmap( __uuidof(IWICBitmapLock), maskBitmapLock, &props, d2dMaskBitmap.GetAddressOf()); if (SUCCEEDED(hr)) { m_Target->SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED); // required m_Target->FillOpacityMask( d2dMaskBitmap.Get(), brush.Get(), D2D1_OPACITY_MASK_CONTENT_GRAPHICS, &rDst, &rSrc); m_Target->SetAntialiasMode(D2D1_ANTIALIAS_MODE_PER_PRIMITIVE); } maskBitmap->UnlockBits(bitmapLock->GetBitmapData()); } maskBitmapLock->Release(); } } bitmap->UnlockBits(bitmapLock->GetBitmapData()); } bitmapLock->Release(); }