how to rotate a bitmap image in c++ using MFC? - c++

how to rotate a bitmap image in c++ using MFC? i dont wanna use GDI. is it possible by only changing x and y values in this code?
CBitmap img;
CDC dc;
BITMAP bmp;
img.LoadBitmapW(IDB_BITMAP1);
img.GetBitmap(&bmp);
CDC* pDC = this->GetDC();
dc.CreateCompatibleDC(pDC);
CBitmap* pOld = dc.SelectObject(&img);
for(int y = 0; y < bmp.bmHeight; y++)
{
for(int x = 0; x < bmp.bmWidth; x++)
{
COLORREF rgb = dc.GetPixel(x, y);
BYTE r = GetRValue(rgb);
BYTE g = GetGValue(rgb);
BYTE b = GetBValue(rgb);
dc.SetPixel(x, y, RGB(r,g,b));
}
}
pDC->BitBlt(200, 200, bmp.bmWidth, bmp.bmHeight, &dc, 0, 0, SRCCOPY);
dc.SelectObject(pOld);
please someone reply soon, as this is the last day to work on project, tommorrow is its submission.

Asking about doing drawing with MFC but not using GDI is a bit like asking about how to go swimming without getting wet. As far as drawing goes, MFC is a thin wrapper around GDI, so anything you do with MFC gets translated quite directly to GDI with just a bit of syntactic sugar added (and in this area, the amount of syntactic sugar was based on a diabetic's diet).
That said, yes, exchanging x and y in your loops could do roughly the right thing (depending on the direction of rotation you want, for one thing) -- though in all honesty you should think really hard about scrapping that code completely. You're using SetPixel (i.e., GDI) to do the drawing in any case; there are lots better ways to do it than this (from the looks of things, you could benefit immensely from CreateDIBSection).

Related

Win32 C++ effective storage or creation of bitmaps used for colour picker background

I am writing an HSV colour picker in plain win32 c++.
I have a Sat/Val box and a Hue slider exactly like the image on the left here:
Up until now I was just generating the background of the Sat-Val box whenever I needed it.
But now that I have a simple prototype and I am circling around to refactor and clean up I have realized that it actually takes a sizeable amount of time to generate the background bitmap for the sat-val box.
Since scrolling the hue slider should update the sat-val box with the appropriate hue, and it should be responsive and fast, I guess I cannot generate the background on the fly because it's too costly.
I have been using a very simple function like this:
HBITMAP ColorPicker::genSVBackground(uint32_t hue)
{
uint32_t width = 256;
uint32_t height = 256;
HDC hDC = GetDC(hwnd);
HDC memDC = CreateCompatibleDC(hDC);
HBITMAP bitmap = CreateCompatibleBitmap(hDC, width, height);
HGDIOBJ oldObj = SelectObject(memDC, bitmap);
for (uint32_t y = 0; y < height; ++y) {
for (uint32_t x = 0; x < width; ++x) {
RGBColor rgbCol = hsv_to_rgb(HSVColor(hue, x, 255 - y));
COLORREF col = (rgbCol.blue << 16) | (rgbCol.green << 8) | (rgbCol.red);
SetPixel(memDC, x, y, col);
}
}
SelectObject(memDC, oldObj);
DeleteDC(memDC);
return bitmap;
}
So the first question is:
Can I make this faster? Fast enough that I can still generate it on the fly? Should I?
And if I cannot make it faster, or if there's really no point and I might as well just use an external resource instead.
What is the best approach to go about storing this in an external resource?
Should I create one giant array that describes a 'cube' of hue x sat x val (my hue, sat and val system is 0-255 each) so I can just load the entire thing into memory and index certain positions to read out an entire background slice?
I know how to do the specifics of the resource storage/loading I'm just not sure if I'm approaching this problem the right way.
Should I store each slice as a separate resource? 256 of them?
Is there a standard way to solving this kind of thing?
I think the source of your slowness is writing one pixel at a time to the memory DC.
Instead of calling SetPixel 256x256 times in a loop, blast an entire matrix of pixels to the DC at once. At the very least, that's 64K function invocations.
I used to do this kind of buffering with GDI+ all the time. I'd create a Bitmap object and then call the LockBits method on it. Do my rendering directly on the returned pointer, and then UnlockBits. It's been a while since I've done the pure Win32 variations of this, but I'm sure it's possible.

ATL CImage::SetPixel not working for monochrome BMPs (nBPP=1)

I'm trying to code a program that changes a BMP file and adds some modifications in particular locations. The BMPs I'm trying to modify are monochrome (1 bit per pixel) as the image size needs to be quite small. I'm using the ATL CImage class to do this.
However, I can't seem to use SetPixel to change a particular pixel for monochrome BMPs.
(I've modified this code a bit for simplicity. 'color' comes from another part of the program and only ever returns RGB(255,255,255) or RGB(0,0,0))
CImage bmp;
bmp.Create(180, 1369, 1);
for (int y = 0; y < 1369; y++)
{
for (int x = 0; x < 180; x++) {
bmp.SetPixel(x, y, color);
}
}
This code returns a black BMP when displayed. If I modify the '1' in bmp.Create, which is the number of bits per pixel, to anything larger than 8, the code works as expected. However, that fix does not suit me as I end up with a BMP that is too large.
Is there any way of making SetPixel work here?
It appears that when you use Create() to make a monochrome bitmap that it creates one where both colors are black. You'll need to adjust the color table:
RGBQUAD colors[2] = { 0 };
bmp.GetColorTable(0, 2, colors);
colors[1].rgbRed = colors[1].rgbGreen = colors[1].rgbBlue = 0xff;
bmp.SetColorTable(0, 2, colors);
Then if you SetPixel to RGB(0xff,0xff,0xff) it should work properly

Trying to render web browser control using IViewObject::Draw() into HDC fails with IE8 but succeeds with IE11

I have an MFC dialog window where I added a WebBrowser control (that encapsulates the Internet Explorer engine.)
The goal of the following code is to render the contents of the said web browser control into a device context that I can later use for printing:
//MFC code, error checks are omitted for brevity
//'m_browser' = is a web browser control of type `CExplorer1`
IDispatch* pHtmlDoc = m_browser.get_Document();
CComPtr<IHTMLDocument2> pHtmlDocument2;
pHtmlDoc->QueryInterface(IID_IHTMLDocument2, (void**)&pHtmlDocument2));
//Get IViewObject2 for the entire document that we will use to render into a DC
CComPtr<IViewObject2> pViewObject;
pHtmlDocument2->QueryInterface(IID_IViewObject2, (void **)&pViewObject));
CComPtr<IHTMLElement> pBody;
pHtmlDocument2->get_body(&pBody));
CComPtr<IHTMLElement2> pBody2;
pBody->QueryInterface(IID_IHTMLElement2, (void **)&pBody2));
//Get default printer DC
CPrintDialog pd(TRUE, PD_ALLPAGES | PD_USEDEVMODECOPIES | PD_NOPAGENUMS | PD_HIDEPRINTTOFILE | PD_NOSELECTION);
pd.m_pd.Flags |= PD_RETURNDC | PD_RETURNDEFAULT;
pd.DoModal(); //corrected later
HDC hPrintDC = pd.CreatePrinterDC();
//Calc bitmap width based on printer DC specs
//Note that this width will be larger than
//the width of the WebControl window itself due to
//printer's much higher DPI setting...
int n_bitmapWidth = ::GetDeviceCaps(hPrintDC, HORZRES); //Use entire printable area
//Get full size of the document
long n_scrollWidth;
long n_scrollHeight;
pBody2->get_scrollWidth(&n_scrollWidth);
pBody2->get_scrollHeight(&n_scrollHeight);
//Calc proportional size of the bitmap in the DC to render
int nWidth = n_bitmapWidth;
int nHeight = n_bitmapWidth * n_scrollHeight / n_scrollWidth;
//Create memory DC to render into
HDC hDc = ::GetDC(hWnd);
HDC hCompDc = ::CreateCompatibleDC(hDC);
//I'm using a raw DIB section here as I'll need to access
//its bitmap bits directly later in my code...
BITMAPINFOHEADER infoHeader = {0};
infoHeader.biSize = sizeof(infoHeader);
infoHeader.biWidth = nWidth;
infoHeader.biHeight = -nHeight;
infoHeader.biPlanes = 1;
infoHeader.biBitCount = 24;
infoHeader.biCompression = BI_RGB;
BITMAPINFO info;
info.bmiHeader = infoHeader;
//Create a bitmap as DIB section of size `nWidth` by `nHeight` pixels
BYTE* pMemory = 0;
HBITMAP hBitmap = ::CreateDIBSection(hDc, &info, DIB_RGB_COLORS, (void**)&pMemory, 0, 0);
HBITMAP hOldBmp = (HBITMAP)::SelectObject(hCompDc, hBitmap);
RECT rcAll = {0, 0, nWidth, nHeight};
::FillRect(hCompDc, &rcAll, (HBRUSH)::GetStockObject(WHITE_BRUSH));
RECTL rectPrnt = {0, 0, nWidth, nHeight};
//Do the upscaling & render -- note that IE8 fails to render it here!!!!
pViewObject->Draw(DVASPECT_CONTENT, //DVASPECT_DOCPRINT
-1, NULL, NULL, NULL, hCompDc,
&rectPrnt,
NULL,
NULL, 0));
::SelectObject(hCompDc, hOldBmp);
//Now the bitmap in `hCompDc` contains the resulting pixels
//For debugging purposes, save it as .bmp file
BITMAPFILEHEADER fileHeader = {0};
fileHeader.bfType = 0x4d42;
fileHeader.bfSize = 0;
fileHeader.bfReserved1 = 0;
fileHeader.bfReserved2 = 0;
fileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
CFile file(
L"path-to\\test.bmp",
CFile::modeCreate | CFile::modeReadWrite | CFile::shareDenyNone);
file.Write((char*)&fileHeader, sizeof(fileHeader));
file.Write((char*)&infoHeader, sizeof(infoHeader));
int bytes = (((24 * nWidth + 31) & (~31)) / 8) * nHeight;
file.Write(pMemory, bytes);
//Clean up
::DeleteObject(hBitmap);
::DeleteDC(hCompDc);
::ReleaseDC(hWnd, hDc);
::DeleteDC(hPrintDC);
This code works fine if I have the latest IE11 installed on my development machine. But if, for instance, someone has IE8 installed on their Windows 7, the IViewObject::Draw method will render only a small part of the document (equal to the size of the web browser control itself.)
The best way to describe it is to illustrate it with the examples:
Normally rendered test page with IE11 installed:
and here's what happens with IE8 installed:
Does anyone have any idea what am I doing wrong here that IE8 doesn't like?
EDIT1: Did some more digging into the IViewObject::Draw function with WinDbg and then found the source code for it. Here's CServer::Draw() that is IViewObject::Draw, and then CDoc::Draw() that is called internally from CServer::Draw().
First, thanks for the interesting question. While not so practical - not a lot of people use IE8 today - it was not so trivial to solve. I'll describe what is the problem and provide a simplistic but working solution that you can improve.
Before I go into IE8 solution, a couple of points:
The solution with window resize to fit scroll size is not stable if you can encounter large documents. If you don't know what to anticipate, you need to refactor the solution for later explorers as well, to avoid relying on resizing window to scroll size.
Why carry giant bitmap? Metafiles etc. may fit better. Any large enough page at this resolution is going to blow memory on PC with the naive DIB creation. Google page in provided sample renders to 100Mb bitmap file while emf, from which rasterization is done, takes less than 1Mb.
While I don't know exact requirements and limitations of your project, I'm 99% sure that drawing into gigantic DIB is not the best solution. Even EMF, while better, is not the best either. If you need, for example, add a signature and then print, there are better ways to handle this. This, of course, just a side note, not related to the question itself.
IE8 rendering problem
In IE8 renderer there is a bug. Draw() will be clipped at pixel dimensions of actual display area (the visible rectangle you see is the original display area in the scale of rendering context).
So, if you have a scaled target that is larger than the actual size, while scaled, it will be clipped to the size in scaled pixels anyway (so it has much less content than original rectangle).
If it doesn't clip for somebody on genuine IE8, then there are remainders of later IE in the system or there is other non-scratch setup, system update or alike.
Workaround possibilities
Good news it is possible to workaround, bad news workarounds are a bit nasty.
First, it is still possible to workaround with IViewObject. But, because there is arbitrary scaling involved and accessible source rectangle is very small, this solution has some complexities that I think are beyong an SO answer. So I would not dive into this path.
Instead, we can render through another, now outdated API: IHTMLElementRender. It allows to render the page with DrawToDC into arbitrary context. Unfortunately, it is not so simple as it may appear and goes beyond just providing device context.
First, there is similar bug of clipping. It can be handled easier because clipping occurs at large values beyond screen dimensions. Second, when using device context transformations it either will not work or will mess the rendered html, so you can't actually rely on scale or translate. Both problems require relatively non-trivial handling and complicate one another.
The solution
I'll describe and provide sample code for non-optimal but working on most simple pages solution. In general, it is possible to achieve a perfect and more efficient solution, but, again, this goes beyond the scope of an answer. Obviously, it is IE8 only, so you'll need to check browser version and execute different handlers for IE8 vs. IE9 or higher, but you can take some ideas to improve other browsers rendering too.
There are two interrelated workarounds here.
Up-scaling
First, how do we upscale the vector content to the printer quality if we can't transform? The workaround here is to render to a context compatible with printer dc. What will happen is that content will be rendered at printer DPI. Note it will not fit exactly printer width, it will scale to printerDPI/screenDPI.
Later, on rasterization, we downscale to fit the printer width. We render initially to EMF, so there is no much of a quality loss (that will occur on the printer itself anyway). If you need higher quality (I doubt it), there are two possibilities - modify the solution to render for target width (this is not trivial) or work with resulting emf instead of bitmap and let printer to make the downscale fit.
Another note is that you currently use just printer width, but there may be non-printable margins that you need to query from printer and account for them. So it may re-scaled by printer even if you provide bitmap in exact printer dimensions. But again, I doubt this resolution disparity will make any difference for your project.
Clipping
Second to overcome is the clipping. To overcome this limitation, we render content in small chunks so they are not clipped by the renderer. After rendering a chunk, we change the scroll position of the document and render next chunk to the appropriate position in the target DC. This can be optimized to use larger chunks e.g. nearest DPI multiple to 1024 (using window resize), but I didn't implement that (it is just a speed optimization). If you don't make this optimization, ensure that minimum browser window size is not too small.
Note, doing this scroll on an arbitrary fractional scale will be an approximation and is not so simple to implement in generic case. But with regular printer and screen we can make integer chunk steps in multiplies of DPI, e.g. if screen is 96 DPI and printer is 600DPI, we make steps in the same multiple of 96 and 600 on each context and everything is much simpler. However, the remainder from top or bottom after processing all whole chunks will not be in DPI multiplies so we can't scroll as easily there.
In general, we can approximate scroll position in printer space and hope there will be no misfit between final chunks. What I did instead is appending an absolutely positioned div with chunk size at the right bottom of the page.
Note, this can interfere with some pages and change the layout (probably not the case with simple reports). If that is a problem, you'll need to add remainder handling after loops instead of adding an element. Most simple solution in that case is still to pad with div but not with the full chunk size but just to make content width multiple of screen DPI.
Even simpler idea, as I've realized later, is just to resize window to the nearest multiple of DPI and take this window size as a chunk size. You can try that instead of div, this will simplify the code and fix pages that may interfere with the injected div.
The code
This is just a sample.
No error handling. You need to add checks for every COM and API call, etc.
No code style, just quick and dirty.
Not sure all acquired resources are released as needed, do your checks
You must disable page borders on browser control for this sample to work (if you need borders around browser, just render them separately, built-in are not consistent anyway). On IE8 this is not so trivial but there are many answers here or on the web. Anyway, I will include this patch in sample solution project. You can render with borders as well and exclude them, but this will be unnecessary complication for a problem that has simple solution.
The full solution project can be found at this link, I'll post only the relevant code here.
The code below renders the page and saves in c:\temp\test.emf + c:\temp\test.bmp
void convertEmfToBitmap(const RECT& fitRect, HDC hTargetDC, HENHMETAFILE hMetafile, LPCTSTR fileName);
CComPtr<IHTMLDOMNode> appendPadElement(IHTMLDocument2* pDoc, IHTMLElement* pBody, long left, long top, long width, long height);
void removeElement(IHTMLElement* pParent, IHTMLDOMNode* pChild);
void CMFCApplication1Dlg::OnBnClickedButton2()
{
COleVariant varNull;
COleVariant varUrl = L"http://www.google.com/search?q=ie+8+must+die";
m_browser.Navigate2(varUrl, varNull, varNull, varNull, varNull);
}
void CMFCApplication1Dlg::OnBnClickedButton1()
{
//get html interfaces
IDispatch* pHtmlDoc = m_browser.get_Document();
CComPtr<IHTMLDocument2> pHtmlDocument2;
pHtmlDoc->QueryInterface(IID_IHTMLDocument2, (void**)&pHtmlDocument2);
CComPtr<IHTMLElement> pBody;
pHtmlDocument2->get_body(&pBody);
CComPtr<IHTMLElement2> pBody2;
pBody->QueryInterface(IID_IHTMLElement2, (void**)&pBody2);
CComPtr<IHTMLBodyElement> pBodyElement;
pBody->QueryInterface(IID_IHTMLBodyElement, (void**)&pBodyElement);
CComPtr<IHTMLElement> pHtml;
pBody->get_parentElement(&pHtml);
CComPtr<IHTMLElement2> pHtml2;
pHtml->QueryInterface(IID_IHTMLElement2, (void**)&pHtml2);
CComPtr<IHTMLStyle> pHtmlStyle;
pHtml->get_style(&pHtmlStyle);
CComPtr<IHTMLStyle> pBodyStyle;
pBody->get_style(&pBodyStyle);
//get screen info
HDC hWndDc = ::GetDC(m_hWnd);
const int wndLogPx = GetDeviceCaps(hWndDc, LOGPIXELSX);
const int wndLogPy = GetDeviceCaps(hWndDc, LOGPIXELSY);
//keep current values
SIZE keptBrowserSize = { m_browser.get_Width(), m_browser.get_Height() };
SIZE keptScrollPos;
//set reasonable viewport size
//m_browser.put_Width(docSize.cx);
//m_browser.put_Height(docSize.cy*2);
pHtml2->get_scrollLeft(&keptScrollPos.cx);
pHtml2->get_scrollTop(&keptScrollPos.cy);
COleVariant keptOverflow;
pBodyStyle->get_overflow(&keptOverflow.bstrVal);
//setup style and hide scroll bars
pHtmlStyle->put_border(L"0px;");
pHtmlStyle->put_overflow(L"hidden");
pBodyStyle->put_border(L"0px;");
pBodyStyle->put_overflow(L"hidden");
//get document size and visible area in screen pixels
SIZE docSize;
pBody2->get_scrollWidth(&docSize.cx);
pBody2->get_scrollHeight(&docSize.cy);
RECT clientRect = { 0 };
pHtml2->get_clientWidth(&clientRect.right);
pHtml2->get_clientHeight(&clientRect.bottom);
//derive chunk size
const SIZE clientChunkSize = {
clientRect.right - clientRect.right % wndLogPx,
clientRect.bottom - clientRect.bottom % wndLogPy };
//pad with absolutely positioned element to have enough scroll area for all chunks
//alternatively, browser can be resized to chunk multiplies (simplest), to DPI multiplies (more work).
//This pad also can be made smaller, to modulus DPI, but then need more work in the loops below
CComPtr<IHTMLDOMNode> pPadNode =
appendPadElement(pHtmlDocument2, pBody, docSize.cx, docSize.cy, clientChunkSize.cx, clientChunkSize.cy);
//get printer info
CPrintDialog pd(TRUE, PD_ALLPAGES | PD_USEDEVMODECOPIES | PD_NOPAGENUMS | PD_HIDEPRINTTOFILE | PD_NOSELECTION);
pd.m_pd.Flags |= PD_RETURNDC | PD_RETURNDEFAULT;
pd.DoModal();
HDC hPrintDC = pd.CreatePrinterDC();
const int printLogPx = GetDeviceCaps(hPrintDC, LOGPIXELSX);
const int printLogPy = GetDeviceCaps(hPrintDC, LOGPIXELSY);
const int printHorRes = ::GetDeviceCaps(hPrintDC, HORZRES);
const SIZE printChunkSize = { printLogPx * clientChunkSize.cx / wndLogPx, printLogPy * clientChunkSize.cy / wndLogPy };
//browser total unscaled print area in printer pixel space
const RECT printRectPx = { 0, 0, docSize.cx* printLogPx / wndLogPx, docSize.cy*printLogPy / wndLogPy };
//unscaled target EMF size in 0.01 mm with printer resolution
const RECT outRect001Mm = { 0, 0, 2540 * docSize.cx / wndLogPx, 2540 * docSize.cy / wndLogPy };
HDC hMetaDC = CreateEnhMetaFile(hPrintDC, L"c:\\temp\\test.emf", &outRect001Mm, NULL);
::FillRect(hMetaDC, &printRectPx, (HBRUSH)::GetStockObject(BLACK_BRUSH));
//unscaled chunk EMF size in pixels with printer resolution
const RECT chunkRectPx = { 0, 0, printChunkSize.cx, printChunkSize.cy };
//unscaled chunk EMF size in 0.01 mm with printer resolution
const RECT chunkRect001Mm = { 0, 0, 2540 * clientChunkSize.cx / wndLogPx, 2540 * clientChunkSize.cy / wndLogPy };
////////
//render page content to metafile by small chunks
//get renderer interface
CComPtr<IHTMLElementRender> pRender;
pHtml->QueryInterface(IID_IHTMLElementRender, (void**)&pRender);
COleVariant printName = L"EMF";
pRender->SetDocumentPrinter(printName.bstrVal, hMetaDC);
//current positions and target area
RECT chunkDestRectPx = { 0, 0, printChunkSize.cx, printChunkSize.cy };
POINT clientPos = { 0, 0 };
POINT printPos = { 0, 0 };
//loop over chunks left to right top to bottom until scroll area is completely covered
const SIZE lastScroll = { docSize.cx, docSize.cy};
while (clientPos.y < lastScroll.cy)
{
while (clientPos.x < lastScroll.cx)
{
//update horizontal scroll position and set target area
pHtml2->put_scrollLeft(clientPos.x);
chunkDestRectPx.left = printPos.x;
chunkDestRectPx.right = printPos.x + printChunkSize.cx;
//render to new emf, can be optimized to avoid recreation
HDC hChunkDC = CreateEnhMetaFile(hPrintDC, NULL, &chunkRect001Mm, NULL);
::FillRect(hChunkDC, &chunkRectPx, (HBRUSH)::GetStockObject(WHITE_BRUSH));
pRender->DrawToDC(hChunkDC);
HENHMETAFILE hChunkMetafile = CloseEnhMetaFile(hChunkDC);
//copy chunk to the main metafile
PlayEnhMetaFile(hMetaDC, hChunkMetafile, &chunkDestRectPx);
DeleteEnhMetaFile(hChunkMetafile);
//update horizontal positions
clientPos.x += clientChunkSize.cx;
printPos.x += printChunkSize.cx;
}
//reset horizontal positions
clientPos.x = 0;
printPos.x = 0;
//update vertical positions
clientPos.y += clientChunkSize.cy;
printPos.y += printChunkSize.cy;
pHtml2->put_scrollTop(clientPos.y);
chunkDestRectPx.top = printPos.y;
chunkDestRectPx.bottom = printPos.y + printChunkSize.cy;
}
//restore changed values on browser
//if for large pages on slow PC you get content scrolling during rendering and it is a problem,
//you can either hide the browser and show "working" or place on top first chunk content
pBodyStyle->put_overflow(keptOverflow.bstrVal);
pHtml2->put_scrollLeft(keptScrollPos.cx);
pHtml2->put_scrollTop(keptScrollPos.cy);
m_browser.put_Width(keptBrowserSize.cx);
m_browser.put_Height(keptBrowserSize.cy);
removeElement(pBody, pPadNode);
//draw to bitmap and close metafile
HENHMETAFILE hMetafile = CloseEnhMetaFile(hMetaDC);
RECT fitRect = { 0, 0, printHorRes, docSize.cy * printHorRes / docSize.cx };
convertEmfToBitmap(fitRect, hWndDc, hMetafile, L"c:\\temp\\test.bmp");
DeleteEnhMetaFile(hMetafile);
//cleanup - probably more here
::ReleaseDC(m_hWnd, hWndDc);
::DeleteDC(hPrintDC);
//{
// std::stringstream ss;
// ss << "====" << docSize.cx << "x" << docSize.cy << " -> " << fitRect.right << "x" << fitRect.bottom << "" << "\n";
// OutputDebugStringA(ss.str().c_str());
//}
}
///////////////
////some util
void convertEmfToBitmap(const RECT& fitRect, HDC hTargetDC, HENHMETAFILE hMetafile, LPCTSTR fileName)
{
//Create memory DC to render into
HDC hCompDc = ::CreateCompatibleDC(hTargetDC);
//NOTE this
BITMAPINFOHEADER infoHeader = { 0 };
infoHeader.biSize = sizeof(infoHeader);
infoHeader.biWidth = fitRect.right;
infoHeader.biHeight = -fitRect.bottom;
infoHeader.biPlanes = 1;
infoHeader.biBitCount = 24;
infoHeader.biCompression = BI_RGB;
BITMAPINFO info;
info.bmiHeader = infoHeader;
//create bitmap
BYTE* pMemory = 0;
HBITMAP hBitmap = ::CreateDIBSection(hCompDc, &info, DIB_RGB_COLORS, (void**)&pMemory, 0, 0);
HBITMAP hOldBmp = (HBITMAP)::SelectObject(hCompDc, hBitmap);
PlayEnhMetaFile(hCompDc, hMetafile, &fitRect);
BITMAPFILEHEADER fileHeader = { 0 };
fileHeader.bfType = 0x4d42;
fileHeader.bfSize = 0;
fileHeader.bfReserved1 = 0;
fileHeader.bfReserved2 = 0;
fileHeader.bfOffBits = sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER);
CFile file(
fileName,
CFile::modeCreate | CFile::modeReadWrite | CFile::shareDenyNone);
file.Write((char*)&fileHeader, sizeof(fileHeader));
file.Write((char*)&infoHeader, sizeof(infoHeader));
int bytes = (((24 * infoHeader.biWidth + 31) & (~31)) / 8) * abs(infoHeader.biHeight);
file.Write(pMemory, bytes);
::SelectObject(hCompDc, hOldBmp);
//Clean up
if (hBitmap)
::DeleteObject(hBitmap);
::DeleteDC(hCompDc);
}
CComPtr<IHTMLDOMNode> appendPadElement(IHTMLDocument2* pDoc, IHTMLElement* pBody, long left, long top, long width, long height)
{
CComPtr<IHTMLElement> pPadElement;
pDoc->createElement(L"DIV", &pPadElement);
CComPtr<IHTMLStyle> pPadStyle;
pPadElement->get_style(&pPadStyle);
CComPtr<IHTMLStyle2> pPadStyle2;
pPadStyle->QueryInterface(IID_IHTMLStyle2, (void**)&pPadStyle2);
pPadStyle2->put_position(L"absolute");
CComVariant value = width;
pPadStyle->put_width(value);
value = height;
pPadStyle->put_height(value);
pPadStyle->put_posLeft((float)left);
pPadStyle->put_posTop((float)top);
CComPtr<IHTMLDOMNode> pPadNode;
pPadElement->QueryInterface(IID_IHTMLDOMNode, (void**)&pPadNode);
CComPtr<IHTMLDOMNode> pBodyNode;
pBody->QueryInterface(IID_IHTMLDOMNode, (void **)&pBodyNode);
pBodyNode->appendChild(pPadNode, NULL);
return pPadNode;
}
void removeElement(IHTMLElement* pParent, IHTMLDOMNode* pChild)
{
CComPtr<IHTMLDOMNode> pNode;
pParent->QueryInterface(IID_IHTMLDOMNode, (void **)&pNode);
pNode->removeChild(pChild, NULL);
}
Sample page output (4958x7656)
I have taken your code and run it on IE11 when the WebBrowser control is smaller then the page size. It rendered a portion of the page equal to control's size. Not sure why you say IE8 and IE11 are any different.
It seems that common approach to taking full page screenshots is adjusting WebBrowser size before taking screenshot, like this:
const long oldH = m_browser.get_Height();
const long oldW = m_browser.get_Width();
m_browser.put_Height(n_scrollHeight);
m_browser.put_Width(n_scrollWidth);
//Do the upscaling & render -- note that IE8 fails to render it here!!!!
pViewObject->Draw(DVASPECT_CONTENT, //DVASPECT_DOCPRINT
-1, NULL, NULL, NULL, hCompDc,
&rectPrnt,
NULL,
NULL, 0);
m_browser.put_Height(oldH);
m_browser.put_Width(oldW);
This seems to work well, even on large pages such as the one you're currently reading (I have taken screenshot 1920x8477). It works both on my IE11 and on IE8 virtual machine
It has a side effect of resetting scrollbars, but that can be solved, for example by using an invisible copy of WebBrowser for screenshots.
PS: You could have done a better job by providing example code that can be compiled, at least ;)

Drawing keeps getting stuck to the screen in SDL

In my program what I am drawing gets stuck on to the screen I am drawing on, by this I mean that what I previously drawed onto the screen stays after I call SDL_UpdateWindowSurface(). Here is my code.
void tower_manager::render()
{
m_tower.draw(camx, camy,m_screen);
//SDL_BlitSurface(test, NULL, m_screen, NULL);
SDL_Rect rect = { 32, 32, 32, 32 };
//draw the tower walls;
for (int x = 0; x < towerWidth; x++)
{
for (int y = 0; y < towerHeight * 2; y += 2)
{
rect.x = x*blockSize - camx;
rect.y = y*blockSize - camy;
SDL_BlitSurface(test, NULL, m_screen, &rect);
}
}
SDL_UpdateWindowSurface(m_window);
}
Apparently I need at least 10 reputation to post images so I cant post a screen shot but here is an example, you know what happens to the desktop when a windows application freezes and it keeps drawing the same window over and over again and you can draw it around to make art and stuff? That's exactly what it looks like is happening here. Also I have another issue when I call the tower objects method that is originally going to draw the tower using the same code it does not draw or do anything at all(i am passing in a pointer to the screen I am drawing to in its parameter).
You would want to clear the surface regions that you are drawing to. If you don't, then the screen surface retains the old renderings from previous frames and you are drawing on top of them. This causes a smearing artifact.
An old optimization (no longer so useful with SDL2 or OpenGL) here is to keep track of dirty rectangles and clear each of them, but the simplest way is to just clear the entire surface each frame before rendering.
So, once per frame do something like this:
SDL_FillRect(m_screen, NULL, 0x000000);

Getting a bitmap to change colour when a limit is reached

Okay I am having some problems with being able to change bitmaps when a certain parameter is greater than another. I am a massive newbie to this and my coding isn't great (at all). I have code that reads the limits (parameters) and displays as text which is this:
CFont* def_font = argDC->SelectObject(&m_Font);
CString csText;
int StartPos = WindowRect.Width()/5;
CRect TextRect(StartPos, WindowRect.top + 5, StartPos + 100, WindowRect.top + 35);
csText.Format(_T("%.2ft"), argSystemDataPtr->GetMaxSWL());
int32_t iSWLDigits = csText.GetLength();
if (iSWLDigits < m_SWLDigitsNum)
{
m_RedPanelBitmap.LoadBitmapW(IDB_BITMAP_PANEL_RED);
//argDC->FillSolidRect(TextRect, RGB(255, 255, 255));
}
m_SWLDigitsNum = iSWLDigits;
argDC->DrawText(csText, TextRect, DT_LEFT);
The bitmaps that are usually displayed are green but if a limit is breached like the one above then I want the bitmap to change to a red one. Here is what I've got for the green ones.
CRect PanelRect1, PanelRect2;
CRect PanelsRect(WindowRect);
const int BarHeight = 30;
PanelsRect.OffsetRect(0,m_bShowTitleBar?BarHeight:-BarHeight);
PanelsRect.DeflateRect(0,m_bShowTitleBar?BarHeight*-1:BarHeight);
m_GreenPanelBitmap.Detach();
m_GreenPanelBitmap.LoadBitmapW(IDB_BITMAP_PANEL_GREEN);
CBitmap* pOld = memDC.SelectObject(&m_GreenPanelBitmap);
BITMAP bits;
m_GreenPanelBitmap.GetObject(sizeof(BITMAP),&bits);
PanelRect1.SetRect(0,PanelsRect.top, PanelsRect.right /2 , PanelsRect.Height()/3);
PanelRect2.SetRect(0,PanelsRect.top+PanelRect1.Height(), PanelsRect.right /2 ,(PanelsRect.Height()/3) + PanelRect1.Height());
//Now draw the Panels
if (pOld != NULL)
{
argDC->StretchBlt(PanelRect1.left ,PanelRect1.top,PanelRect1.Width(),PanelRect1.Height(),
&memDC,0,0,bits.bmWidth-1, bits.bmHeight-1, SRCCOPY);
argDC->StretchBlt(PanelRect2.left,PanelRect2.top,PanelRect2.Width(),PanelRect2.Height(),
&memDC,0,0,bits.bmWidth-1, bits.bmHeight-1, SRCCOPY);
memDC.SelectObject(pOld);
I would be extremely grateful for any help, I understand there probably is a simple answer but I've been scratching my head over it and can't seem to find an answer anywhere else on how change the m_GreenPanelBitmap to m_RedPanelBitmap when this statement is true.
`if (iSWLDigits < m_SWLDigitsNum).`
Well, I do think your question is a bit messy but...
On the second code snippet you posted (I suppose from a OnPaint method in a dialog) you are displaying the green bitmap by using StretchBlt.
If your problem is you need to display one bitmap or another depending on a condition you should load both images (maybe you can do that elsewhere to avoid loading the images everytime the dialog is painted) and then display the one you really need based on the condition. Something like that:
bool bCondition = /*whatever*/
m_GreenPanelBitmap.LoadBitmapW(IDB_BITMAP_PANEL_GREEN);
m_RedPanelBitmap.LoadBitmapW(IDB_BITMAP_PANEL_RED);
CBitmap* pBitmapToDisplay = bCondition ? &m_GreenPanelBitmap : &m_RedPanelBitmap;
CBitmap* pOld = memDC.SelectObject(pBitmapToDisplay);
BITMAP bits;
pBitmapToDisplay->GetObject(sizeof(BITMAP),&bits);
PanelRect1.SetRect(0,PanelsRect.top, PanelsRect.right /2 , PanelsRect.Height()/3);
PanelRect2.SetRect(0,PanelsRect.top+PanelRect1.Height(), PanelsRect.right /2, PanelsRect.Height()/3) + PanelRect1.Height());
argDC->StretchBlt(PanelRect1.left ,PanelRect1.top,PanelRect1.Width(),PanelRect1.Height(),
&memDC,0,0,bits.bmWidth-1, bits.bmHeight-1, SRCCOPY);
memDC.SelectObject(pOld);
Maybe with a more detailed question we would be able to help you more.