How to have code that prints to a Device Context save the printout to a BMP file - visual-c++

I am struggling to adapt some code that has printing support to DCs (Device Contexts) and having it print to a Bitmap that can then be saved to disk.
I have tried the following code:
// The include files needed for my code
#include "atlimage.h"
#include "afxglobals.h"
// My attempt to get a DC which allows me to draw onto a CBitmap of A4 size
// (21.0x29.7 cm) in 300dpi, or 2480x3508 pixels in 24bit
HBITMAP BMP = CreateBitmap(2480,3508,1,24,NULL);
CBitmap* BitMap = CBitmap::FromHandle(BMP);
CMemDC A4(*CDC::FromHandle(CreateCompatibleDC(NULL)),CRect(0,0,1,1));
// This is where it fails. The SelectObject returns NULL, which means "failed"
// It may be caused by earlier code, but this is where I can detect the problem
// for the first time.
CBitmap* bmp = A4.GetDC().SelectObject(BitMap);
if (bmp == NULL)
TRACE("Error=%08X\n",GetLastError());
//
// The actual code that does the printing:
//
Graphs[0]->Print(A4.GetDC(),CRect(0,20,75,75));
Graphs[1]->Print(A4.GetDC(),CRect(75,20,100,75));
// And the saving to disk
CImage IMG;
IMG.Attach(*BitMap);
HRESULT res = IMG.Save("D:\\AUDIO.BMP");
IMG.Detach();
// Cleanup
DeleteObject(BMP);
DeleteDC(A4.GetDC());
TRACE("Result=%d\n",res);
The first TRACE prints out 00000000 as the error code, so I cannot tell (from this) why it fails.
I'd prefer not to use GDI+ if possible, but if GDI+ (which I don't have experience with) makes it much easier, I won't refuse it. I am using Visual Studio 2008 and cannot update to a newer version (it is part of a much bigger project that will take more time to upgrade to a newer version than I have time right now).
The caveat is that I only have printing routines that take a DC, and am not able to change this, so it must be done via a DC.
Any help would be appreciated...

Assuming that the error you refer to happens when you attempt to select the bitmap into the memory DC, the most likely explanation is that they are not compatible.
You have created a memory DC that is compatible with your desktop and that's most likely a 32bpp bitmap. Then you create a 24bpp bitmap, which I think is the problem.
To make sure everything is compatible, try this instead:
HDC hDC = CreateCompatibleDC(NULL);
HBITMAP BMP = CreateCompatibleBitmap(hDC, 2480,3508);
CBitmap* BitMap = CBitmap::FromHandle(BMP);
CMemDC A4(*CDC::FromHandle(hDC),CRect(0,0,1,1));
So, you create a bitmap and a DC that are compatible with the same original DC. Then the SelectObject should not fail.
Maybe update your question or comment on this answer if you don't get further.

Related

Why will MFC not load a bitmap resource in single modual (.cpp) VS PROJECT?

I have code that was first developed with Visual C++ Version 1.52 (working and self taught). I am now trying to convert it to a Visual Studio project. It is a single module project written with MFC. I used the 'project from existing code' option to generate the project which executes just fine but for loading bitmap resources. I tested the same relevant code (LoadBitmap and LoadImage) in MFC multi-module projects code and they work just fine. I am able to load bitmap files directly from disk. If I delete the bitmap files from the project there is 22k less size of the code. The total bitmap file size is 18k. The only error message that I get is '_WIN32_WINNT not defined. Defaulting to _WIN32_WINNT_MAXVER (see WinSDKVer.h)'. I am assuming that the default is adequate. At this point I am thinking that it is a link properties issue because of MFC, but I don't know what that might be. Any ideas? Thank you.
//header
//
class CMainWindow : public CFrameWnd
{
public:
CMainWindow();
//{{AFX_MSG( CMainWindow )
afx_msg void OnPaint();
afx_msg void OnDestroy();
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
//}}AFX_MSG
//protected:
BOOL flag;
BOOL game, turn;
CWnd tictic1, tictic2, tictic3, tictic4, tictic5, tictic6, tictic7, tictic8, tictic9;
CRect RCT;
int id, count;
CBitmap O, X;
//body
//
CMainWindow::CMainWindow()
{
LoadAccelTable("MainAccelTable");
Create(NULL, "Tic Tac Toe\0",
WS_OVERLAPPEDWINDOW, rectDefault, NULL, NULL, 0, NULL);
flag = TRUE;
id = 0;
O.LoadBitmap(IDB_BITMAP1);
X.LoadBitmap(IDB_BITMAP2);
If I transplant the relevant code into VS generated MFC documents it works. The only difference is that all of my code is original Visual C++ Version 1.52 MFC code, in a single .cpp document but all the rest of the code seems to work fine.
Uh, when I has collecting observations for this query, I deleted the two relevant bitmap files from the resources in order the report the difference in file size. After I added them back in, the functions then work properly. I think that what I had originally done was when first importing the new resources, I tried selecting the two as a group and when they displayed right, in the resource file, I assumed that it had worked. It apparently didn't. Duh!
Uh, development; after cleaning up my code, I rebuilt it and it wouldn't load bitmap resources. I deleted the resources then installed them again and the program has worked since. So you tell me. I think that it's serendipitous. Duh!

How to load an svg to CanvasVirtualControl in C++/winrt?

I've been loading drawing svg images successfully in a UWP app built with C++/winrt but in the latest release find that the call to load the svg throws an exception.
The crash happens in an IAsync method that is hard to trace, but I've narrowed the problem down to the one line that loads the SVG.
This is normally looping to read lots of files, but very simple reduction of the problem still displays the issue:
winrt::Microsoft::Graphics::Canvas::UI::Xaml::CanvasVirtualControl resourceCreator
winrt::Windows::Storage::StorageFile nextFile = nullptr;
winrt::Microsoft::Graphics::Canvas::Svg::CanvasSvgDocument nextSvg = nullptr;
winrt::Windows::Storage::Streams::IRandomAccessStream fileStream = nullptr;
//This is called from within the lambda handling CreateResources for the CanvasVirtualControl
//The VirtualControl is provided as the resourceCreator argument
IAsyncAction loadSVGs(winrt::Microsoft::Graphics::Canvas::UI::Xaml::CanvasVirtualControl resourceCreator)
{
nextFile = m_symbol_resource_files.GetAt(i);
fileStream = co_await nextFile.OpenReadAsync();
nextSvg = co_await CanvasSvgDocument::LoadAsync(resourceCreator,fileStream);
}
The call to LoadAsync fails with
exception: winrt:hresult_invalid_argument at memory location 0x0C93F1CB
void resume()const{
->_coro_resume(_Ptr);
}
If I continue past the exception I find that the resource has in fact loaded and is usable. But if running outside Visual Studio the app will often quit at this line. Could it be that the CanvasVirtualControl is not acceptable?
Or is there a better way to load the svg from file? I haven't been able to work out the CanvasDocument's LoadFromXML, as it takes a System.String argument not available in C++/winrt and the winrt std::wstring is not acceptable as a substitute [Correction: in fact hstring will work as an argument and that can be created from std::wstring].
[Update]I have not yet created a simple demo project displaying this behavior, but I think I have a line on the cause and would like to extend my question. I've tried both the LoadFromXml and the LoadAsync methods of the CanvasSvgDocument, and the second of these used to be fine, but now both fail the same way and it seems to me that the ResourceCreator argument may be the trouble. I am creating these resources in the CreateResources handler and I pass the sender - CanvasVirtualControl - as the resourceCreator. The listed argument for both the CanvasSvgDocument calls, however, is ICanvasResourceCreator. I had thought this was a convenience and that the CanvasVirtualControl could be passed directly for that argument (and so it used to be). But perhaps this is incorrect, maybe always was and is now being noticed as incorrect? If so, how would the sender in the CreateResources handler properly be passed to the CanvasSvgDocument method?
I created a blank app to use CanvasVirtualControl to load SVG, it worked well. Can you provide a simple sample that can be reproduced? And I checked the LoadFromXML method, the parameter it needs is hstring type instead of System.String.
In addition, about loading the svg from file, do you have to use win2d to load svg? If not, you could try to use Image control by SvgImageSource to load svg, like below:
.xaml:
<Image x:Name="MyImage" Width="300" Height="200"></Image>
.cpp:
winrt::Windows::Storage::StorageFile nextFile = nullptr;
winrt::Microsoft::Graphics::Canvas::Svg::CanvasSvgDocument nextSvg = nullptr;
winrt::Windows::Storage::Streams::IRandomAccessStream fileStream = nullptr;
nextFile = co_await KnownFolders::PicturesLibrary().GetFileAsync(L"Freesample.svg");
fileStream = co_await nextFile.OpenReadAsync();
SvgImageSource sourcee = SvgImageSource();
co_await sourcee.SetSourceAsync(fileStream);
MyImage().Source(sourcee);

Why must you call SelectObject before calling GetTextExtendPoint32

I understand that for GetTextExtendPoint32 to work correctly, it needs to know the correct font. However, I'm confused as to why SelectObject needs to be called. Example I wanted to calc the length of the text for a check box.
Works:
Size sizeChkBox;
CString csChkBox;
m_ChxBox.GetWindowText(csChkBox);
CDC* dc = m_ChkBox.GetDC();
HFONT hfontChK = (HFONT)GetWindowFont(m_ChkBox.GetSafeHwnd());
SelectObject(*dc, hfontChK);
GetTextExtentPoint32(*dc, csChkBox, strlen(csChkBox), &sizeChkBox);
Doesn't Work:
Size sizeChkBox;
CString csChkBox;
m_ChxBox.GetWindowText(csChkBox);
CDC* dc = m_ChkBox.GetDC();
GetTextExtentPoint32(*dc, csChkBox, strlen(csChkBox), &sizeChkBox);
I guess my question really is why doesn't dc have the correct font already since its "made from the checkbox"?
GetDC(HWND) creates an HDC with all default settings, set up for drawing on a given window. It doesn't actually interrogate the window for its properties: in particular, it doesn't send WM_GETFONT to it.
Realize that WM_SETFONT and WM_GETFONT work only by convention. Nothing says that a window must handle these messages, or use the font provided in its WM_PAINT implementation. Standard controls tend to do this, as a common courtesy, but this is by no means a universal requirement.

OpenCL clCreateFromGLTexture using a different texture target

The aim of my project is to get live camera feed from on an Android device, use OpenCL to perform real-time filtering on those images and render the output on display.
I aim to do this in real-time that's why I am using OpenCL-OpenGL interop.
I have successfully managed to create a shared context using EGLContext and EGLDisplay. Now I am trying to use clCreateFromGLTexture so I can access these images in OpenCL kernel. The problem however is android requires that when bind the texture the target must be GL_TEXTURE_EXTERNAL_OES as it says here: (http://developer.android.com/reference/android/graphics/SurfaceTexture.html), however this texture target is not valid texture target when using clCreateFromGLTexture (https://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/clCreateFromGLTexture2D.html).
So I am not sure how to go about this.
This is how I create a GL Texture in android:
GLES20.glGenTextures(1, texture_id, 0);
GLES20.glBindTexture(texture_target, texture_target);
and this is how I am trying to create a cl memory object:
glTexImage2D(texture_target, 0, GL_RGBA, 640, 480, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
cl_mem camera_image = clCreateFromGLTexture(m_context, CL_MEM_READ_WRITE, texture_target, 0, texture_id, &err);
The error I get when I try to create cl memory object from GL texture is CL_INVALID_VALUE.
I am pretty new to OpenGL so there could be something basic I might have over looked.
The texture you receive from the camera is not the usual texture you'd expect. You even have to specify the extension in a shader if you read from it.
You need to perform an additional copy from the GL_TEXTURE_EXTERNAL_OES target to another texture which is created in the usual way. With luck you can bind both of them into fbo's and then just issue blit. If that doesn't work you can always use the normal texture as a rendertarget and simply draw a quad textured with the camera image.

Render bitmap to SpriteBatch in DirectXTK

I need to port some C++ application to Windows Phone 8 (it is already on Android, iOS, WinCE and Win32). Currently I need to solving how to display graphic. I can get rendered bitmap from core application and I after succesfully initialize DirectXTK I'm able to render some DDS texture (DirectXTK::SpriteBatch). Now I need to transform my bitmap to texture and then render it. Can you help me with this out? Or is there some way to put bitmap directly to backbuffer and show it on display without SpriteBatch?
Thank you very much
Tomas
DirectX toolkit has WICTextureLoader. You can use it instead of DDSTextureLoader for loading .bmp(bitmap) file. Hope this help!
http://directxtk.codeplex.com/wikipage?title=WICTextureLoader&referringTitle=DirectXTK
Since WICTextureLoader is not supported on Windows Phone 8 the only way to render a bitmap to a texture is by mapping the texture to the CPU and copy your bitmap resource onto the mapped texture's resource.
ID3D11DeviceContext::Map()
http://msdn.microsoft.com/en-us/library/windows/desktop/ff476457(v=vs.85).aspx
D3D11_MAPPED_SUBRESOURCE mappedBuffer;
HRESULT hr = pContext->Map(pTexture, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedBuffer);
if(hr == S_OK)
{
// copy your bitmap onto mappedBuffer.pData
...
pContext->Unmap(pTex, 0);
}

Resources