Implementando uma Classe Wrapper para Memory DC no MFC

  1. 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.

  1. 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);
  1. 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;
}

Tags: mfc cdc memory-dc bitmap gdi

Publicado em 6-28 02:19