Скопируйте растровое изображение в буфер обмена в Win 10 с активным GDI Scaling
У меня есть настольное приложение MFC, которое генерирует графическое изображение, и я хочу, чтобы пользователь мог копировать его в буфер обмена как растровое изображение. Я использую стандартные процедуры буфера обмена API, и они до сих пор работали нормально. Однако теперь я активировал GDI Scaling (через манифест), чтобы программа могла работать (достаточно хорошо) на дисплеях HiDPI, и я обнаружил, что изображение, помещенное в буфер обмена, является лишь верхним левым квадрантом фактического изображения. Вероятно, это связано с внутренним масштабированием изображения - дисплей работает на 200%. Как мне скопировать все изображение?
1 ответ
Ключ дан в ответе на предыдущий вопрос: Сохранение растровых изображений в Windows 10 с активным масштабированием GDI, но мне понадобилось некоторое время, чтобы адаптировать этот ответ к моей конкретной проблеме, поэтому я решил поделиться, если это будет полезно для других, (Отказ от ответственности - я не эксперт, так что может быть лучше...)
bool CopyRectToClipboard(CWnd *pW, CRect rctCopy)
{
if (!pW->OpenClipboard())
return false;
if (!EmptyClipboard())
return false;
CClientDC dc(pW);
CDC dcMem;
VERIFY(dcMem.CreateCompatibleDC(&dc));
CBitmap bmTrial; // need a trial bitmap to get GDI Scaled size
VERIFY(bmTrial.CreateCompatibleBitmap(&dc, rctCopy.Width(), rctCopy.Height()));
// see https://stackru.com/questions/51169846/saving-bitmaps-on-windows-10-with-gdi-scaling-active
BITMAPINFO bi = {};
bi.bmiHeader.biSize = sizeof(bi);
int result = GetDIBits(dc.GetSafeHdc(), (HBITMAP)bmTrial.GetSafeHandle(), 0, 0, NULL, &bi, DIB_RGB_COLORS);
CBitmap bm;
VERIFY(bm.CreateCompatibleBitmap(&dc, bi.bmiHeader.biWidth, bi.bmiHeader.biHeight));
ASSERT(bm.m_hObject != NULL);
CBitmap* pbmOld = dcMem.SelectObject(&bm);
//dcMem.PatBlt(0, 0, bi.bmiHeader.biWidth, bi.bmiHeader.biHeight, WHITENESS); // legacy
VERIFY(dcMem.BitBlt(0, 0, bi.bmiHeader.biWidth, bi.bmiHeader.biHeight,
&dc, rctCopy.left - 1, rctCopy.top - 1, SRCCOPY));
HGDIOBJ hBM = bm.Detach();
VERIFY(::EmptyClipboard());
VERIFY(::SetClipboardData(CF_BITMAP, hBM));
VERIFY(::CloseClipboard());
dcMem.SelectObject(pbmOld);
dcMem.DeleteDC();
return true;
}