//------------------------------------------------------------------------
// Copyright (c) 2003 David Poon
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom
// the Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
//------------------------------------------------------------------------
#include <stdexcept>
#include <cstdio>
#include "dib24.h"
// HIMETRIC units per inch - taken from MFC source code for CDC class.
const int DIB24::HIMETRIC_INCH = 2540;
int DIB24::m_logpixelsx = 0;
int DIB24::m_logpixelsy = 0;
DIB24::DIB24()
{
dc = 0;
hBitmap = 0;
width = 0;
height = 0;
pitch = 0;
m_hPrevObj = 0;
m_pBits = 0;
memset(&info, 0, sizeof(BITMAPINFO));
if (!m_logpixelsx && !m_logpixelsy)
{
HDC hScreenDC = CreateCompatibleDC(GetDC(0));
if (!hScreenDC)
{
throw std::runtime_error(
_T("failed to init m_logpixelsx and/or m_logpixelsy"));
}
m_logpixelsx = GetDeviceCaps(hScreenDC, LOGPIXELSX);
m_logpixelsy = GetDeviceCaps(hScreenDC, LOGPIXELSY);
DeleteDC(hScreenDC);
}
}
DIB24::~DIB24()
{
destroy();
}
bool DIB24::create(int widthPixels, int heightPixels)
{
destroy();
width = widthPixels;
height = heightPixels;
pitch = ((width * 24 + 31) & ~31) >> 3;
dc = CreateCompatibleDC(0);
if (!dc)
return false;
memset(&info, 0, sizeof(info));
info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
info.bmiHeader.biBitCount = 24;
info.bmiHeader.biWidth = width;
info.bmiHeader.biHeight = -height;
info.bmiHeader.biCompression = BI_RGB;
info.bmiHeader.biPlanes = 1;
hBitmap = CreateDIBSection(dc, &info, DIB_RGB_COLORS,
reinterpret_cast<void**>(&m_pBits), 0, 0);
if (!hBitmap)
{
destroy();
return false;
}
GdiFlush();
return true;
}
void DIB24::destroy()
{
deselectObject();
if (hBitmap)
{
DeleteObject(hBitmap);
hBitmap = 0;
}
if (dc)
{
DeleteDC(dc);
dc = 0;
}
}
bool DIB24::loadDesktop()
{
// Takes a screen capture of the current Windows desktop and stores
// the image in the DIB24 object.
HWND hDesktop = GetDesktopWindow();
if (!hDesktop)
return false;
int desktopWidth = GetSystemMetrics(SM_CXSCREEN);
int desktopHeight = GetSystemMetrics(SM_CYSCREEN);
HDC hDesktopDC = GetDCEx(hDesktop, 0, DCX_CACHE | DCX_WINDOW);
if (!hDesktopDC)
return false;
if (!create(desktopWidth, desktopHeight))
{
ReleaseDC(hDesktop, hDesktopDC);
return false;
}
selectObject();
if (!BitBlt(dc, 0, 0, width, height, hDesktopDC, 0, 0, SRCCOPY))
{
destroy();
ReleaseDC(hDesktop, hDesktopDC);
return false;
}
deselectObject();
ReleaseDC(hDesktop, hDesktopDC);
return true;
}
bool DIB24::loadBitmap(LPCTSTR filename)
{
// Loads a BMP image and stores it in the DIB24 object.
HANDLE hImage = LoadImage(GetModuleHandle(0), filename, IMAGE_BITMAP,
0, 0, LR_CREATEDIBSECTION | LR_LOADFROMFILE);
if (!hImage)
return false;
BITMAP bitmap = {0};
if (!GetObject(hImage, sizeof(bitmap), &bitmap))
{
DeleteObject(hImage);
return false;
}
HDC hImageDC = CreateCompatibleDC(0);
if (!hImageDC)
{
DeleteObject(hImage);
return false;
}
SelectObject(hImageDC, hImage);
int h = (bitmap.bmHeight < 0) ? -bitmap.bmHeight : bitmap.bmHeight;
if (create(bitmap.bmWidth, h))
{
selectObject();
if (!BitBlt(dc, 0, 0, width, height, hImageDC, 0, 0, SRCCOPY))
{
destroy();
DeleteDC(hImageDC);
DeleteObject(hImage);
return false;
}
deselectObject();
}
DeleteDC(hImageDC);
DeleteObject(hImage);
return true;
}
bool DIB24::loadPicture(LPCTSTR filename)
{
// Loads an image using the IPicture COM interface and stores the
// image in the DIB24 object.
//
// Supported image formats: BMP, EMF, GIF, ICO, JPG, WMF.
bool status = false;
FILE *fp = _tfopen(filename, _T("rb"));
if (fp)
{
fseek(fp, 0, SEEK_END);
long length = ftell(fp);
HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE, length);
if (hGlobal)
{
void *p = GlobalLock(hGlobal);
if (!p)
{
fclose(fp);
}
else
{
rewind(fp);
fread(p, length, 1, fp);
GlobalUnlock(hGlobal);
fclose(fp);
IStream *pIStream = 0;
HRESULT hr = 0;
hr = CreateStreamOnHGlobal(hGlobal, TRUE, &pIStream);
if (SUCCEEDED(hr))
{
IPicture *pIPicture = 0;
hr = OleLoadPicture(pIStream, length, FALSE,
IID_IPicture, reinterpret_cast<LPVOID*>(&pIPicture));
if (SUCCEEDED(hr))
{
LONG lWidth = 0;
LONG lHeight = 0;
pIPicture->get_Width(&lWidth);
pIPicture->get_Height(&lHeight);
//int w = MulDiv(lWidth, m_logpixelsx, HIMETRIC_INCH);
//int h = MulDiv(lHeight, m_logpixelsy, HIMETRIC_INCH);
int w = (lWidth * m_logpixelsx) / HIMETRIC_INCH;
int h = (lHeight * m_logpixelsy) / HIMETRIC_INCH;
if (create(w, h))
{
selectObject();
hr = pIPicture->Render(dc, 0, 0, width, height,
0, lHeight, lWidth, -lHeight, 0);
if (SUCCEEDED(hr))
status = true;
deselectObject();
}
pIPicture->Release();
}
pIStream->Release();
}
}
}
GlobalFree(hGlobal);
}
return status;
}
void DIB24::selectObject()
{
if (dc)
m_hPrevObj = SelectObject(dc, hBitmap);
}
void DIB24::deselectObject()
{
if (dc && m_hPrevObj)
{
SelectObject(dc, m_hPrevObj);
m_hPrevObj = 0;
}
}
void DIB24::copyByteAligned(BYTE *pDest)
{
// 'pDest' must already point to a chunk of allocated memory of the
// correct size (i.e., width pixels X height pixels X 24 bits).
//
// The returned image will be byte aligned, and the pixel format
// will be BGR (as per Windows DIB standards).
if (pDest)
{
const int widthBytes = width * 3;
for (int y = 0; y < height; ++y)
memcpy(&pDest[widthBytes * y], &m_pBits[pitch * y], widthBytes);
}
} |