- O que é um Memory DC?
Para permitir que aplicações direcionem sua saída para a memória em vez de enviar diretamente para o disopsitivo físico, utiliza-se um contexto de dispositivo especial denominado Memory Device Context (DC de memória). O DC de memória permite que o sistema trate uma porção da memória como um dispositivo virtual. Trata-se de um array de bits na memória que a aplicação pode utilizar temporariamente para armazenar dados de cor de bitmaps criados em superfícies de dibujo convenientes. Como o bitmap é compatível com o dispositivo, o DC de memória também é conhecido como contexto de dispositivo compatível.
- Por que encapsular o Memory DC?
Os procedimentos nativos para configuração envolvem múltiplas etapas, e qualquer erro pode resultar em falha na renderização do bitmap. O objetivo é encapsular essas etapas em uma classe, tornando a utilização diária mais simples, conforme ilustrado:
// Criar memory DC
CDC memDc;
memDc.CreateCompatibleDC(&deviceContext);
// Criar bitmap compatível
CBitmap bitmap;
bitmap.CreateCompatibleBitmap(&memDc, 100, 100);
CBitmap* oldBitmap = memDc.SelectObject(&bitmap);
// Desenhar no memory DC
BOOL success = memDc.Ellipse(0, 0, 100, 100);
// Copiar do memory DC para o DC de exibição
deviceContext.BitBlt(0, 0, 100, 100, &memDc, 0, 0, SRCCOPY);
- Implementação do Memory DC
3.1. Arquivo de Cabeçalho
#pragma once
#include <afxwin.h>
class CMemoryCanvas : public CDC
{
CSize dimensions;
public:
// Transferência não escalonada
void BitTrans(
int destX,
int destY,
int destWidth,
int destHeight,
CDC* targetContext,
int sourceX,
int sourceY,
COLORREF transparentColor
);
// Transferência escalonada
void StretchTrans(
int destX,
int destY,
int destWidth,
int destHeight,
CDC* targetContext,
int sourceX,
int sourceY,
int sourceWidth,
int sourceHeight,
COLORREF transparentColor
);
BOOL LoadFromResource(UINT resourceId, CDC* targetContext = NULL);
BOOL LoadFromFile(LPCTSTR filePath, CDC* targetContext = NULL);
BOOL DeleteCanvas();
BOOL Initialize(int width, int height, CDC* targetContext = NULL);
CMemoryCanvas(int width, int height, CDC* targetContext = NULL)
{
Initialize(width, height, targetContext);
}
CMemoryCanvas()
{
dimensions.cx = dimensions.cy = 0;
}
CMemoryCanvas(UINT resourceId, CDC* targetContext = NULL)
{
LoadFromResource(resourceId, targetContext);
}
CMemoryCanvas(LPCTSTR filePath, CDC* targetContext = NULL)
{
LoadFromFile(filePath, targetContext);
}
~CMemoryCanvas()
{
DeleteCanvas();
}
inline int GetWidth() const
{
return dimensions.cx;
}
inline int GetHeight() const
{
return dimensions.cy;
}
};
3.2. Arquivo de Implementação
#include "pch.h"
#include "CMemoryCanvas.h"
void CMemoryCanvas::BitTrans(int destX, int destY, int destWidth,
int destHeight, CDC* targetContext, int sourceX, int sourceY, COLORREF transparentColor)
{
CMemoryCanvas tempCanvas(destWidth, destHeight, targetContext);
CBitmap maskBitmap;
maskBitmap.CreateBitmap(destWidth, destHeight, 1, 1, NULL);
CDC maskContext;
maskContext.CreateCompatibleDC(targetContext);
maskContext.SelectObject(maskBitmap);
tempCanvas.BitBlt(0, 0, destWidth, destHeight, this, sourceX, sourceY, SRCCOPY);
tempCanvas.SetBkColor(transparentColor);
maskContext.BitBlt(0, 0, destWidth, destHeight, &tempCanvas, 0, 0, SRCCOPY);
tempCanvas.SetBkColor(RGB(0, 0, 0));
tempCanvas.SetTextColor(RGB(255, 255, 255));
tempCanvas.BitBlt(0, 0, destWidth, destHeight, &maskContext, 0, 0, SRCAND);
targetContext->SetBkColor(RGB(255, 255, 255));
targetContext->SetTextColor(RGB(0, 0, 0));
targetContext->BitBlt(destX, destY, destWidth, destHeight, &maskContext, 0, 0, SRCAND);
targetContext->BitBlt(destX, destY, destWidth, destHeight, &tempCanvas, 0, 0, SRCPAINT);
}
void CMemoryCanvas::StretchTrans(int destX, int destY, int destWidth,
int destHeight, CDC* targetContext, int sourceX, int sourceY,
int sourceWidth, int sourceHeight, COLORREF transparentColor)
{
CMemoryCanvas tempCanvas(destWidth, destHeight, targetContext);
CBitmap maskBitmap;
maskBitmap.CreateBitmap(destWidth, destHeight, 1, 1, NULL);
CDC maskContext;
maskContext.CreateCompatibleDC(targetContext);
maskContext.SelectObject(maskBitmap);
if (destWidth == sourceWidth && destHeight == sourceHeight)
tempCanvas.BitBlt(0, 0, destWidth, destHeight, this, sourceX, sourceY, SRCCOPY);
else
tempCanvas.StretchBlt(0, 0, destWidth, destHeight,
this, sourceX, sourceY, sourceWidth, sourceHeight, SRCCOPY);
tempCanvas.SetBkColor(transparentColor);
maskContext.BitBlt(0, 0, destWidth, destHeight, &tempCanvas, 0, 0, SRCCOPY);
tempCanvas.SetBkColor(RGB(0, 0, 0));
tempCanvas.SetTextColor(RGB(255, 255, 255));
tempCanvas.BitBlt(0, 0, destWidth, destHeight, &maskContext, 0, 0, SRCAND);
targetContext->SetBkColor(RGB(255, 255, 255));
targetContext->SetTextColor(RGB(0, 0, 0));
targetContext->BitBlt(destX, destY, destWidth, destHeight, &maskContext, 0, 0, SRCAND);
targetContext->BitBlt(destX, destY, destWidth, destHeight, &tempCanvas, 0, 0, SRCPAINT);
}
BOOL CMemoryCanvas::LoadFromResource(UINT resourceId, CDC* targetContext)
{
CBitmap bitmap;
if (!bitmap.LoadBitmap(resourceId))
{
dimensions.cx = dimensions.cy = 0;
return FALSE;
}
BITMAP bmpInfo;
bitmap.GetBitmap(&bmpInfo);
dimensions.SetSize(bmpInfo.bmWidth, bmpInfo.bmHeight);
CreateCompatibleDC(targetContext);
SelectObject(bitmap);
return TRUE;
}
BOOL CMemoryCanvas::LoadFromFile(LPCTSTR filePath, CDC* targetContext)
{
BITMAP bitmap;
HBITMAP hBitmap = (HBITMAP)::LoadImage(NULL, filePath,
IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
if (!hBitmap)
{
dimensions.cx = dimensions.cy = 0;
return FALSE;
}
::GetObject(hBitmap, sizeof(bitmap), &bitmap);
dimensions.SetSize(bitmap.bmWidth, bitmap.bmHeight);
CreateCompatibleDC(targetContext);
SelectObject(hBitmap);
return TRUE;
}
BOOL CMemoryCanvas::DeleteCanvas()
{
if (!GetSafeHdc())
return TRUE;
CBitmap* currentBitmap = GetCurrentBitmap();
currentBitmap->DeleteObject();
return CDC::DeleteDC();
}
BOOL CMemoryCanvas::Initialize(int width, int height, CDC* targetContext)
{
CreateCompatibleDC(targetContext);
CBitmap bitmap;
if (targetContext)
bitmap.CreateCompatibleBitmap(targetContext, width, height);
else
bitmap.CreateCompatibleBitmap(&CClientDC(NULL), width, height);
dimensions.cx = width;
dimensions.cy = height;
SelectObject(bitmap);
return TRUE;
}