I inserted bitmaps in CImageList in one Function and needed to change some of the images later in another function. But I am unable to extract the CBitmap. The code goes something like this:
CBitmap GetIndividualBitmap(CImageList oImgList, int nBmpNo)
{
IMAGEINFO imgInfo;
imagelist.GetImageInfo(index,imgInfo);
CBitmap bmp;
bmp.FromHandle(imgInfo.hbmImage);
return bmp;
}
However all I get is a black screen. Could anyone please point out where I am going wrong?
Ok there are a number of errors in your code
1)You are passing the Image list by object which means it will copy it across. Passing it by reference is a far better plan.
2) You are not passing a pointer to the IMAGEINFO struct into the GetImageInfo.
3) You misunderstand how "FromHandle" works. FromHandle is a static function that returns a pointer to a Bitmap. In your code you are calling the function and then ignoring the CBitmap* returned and returning a copy of your newly constructed object (ie it contains nothing) which results in your black screen.
Taking all those into account you should have code that looks like this:
CBitmap* GetIndividualBitmap(CImageList& oImgList, int nBmpNo)
{
IMAGEINFO imgInfo;
oImgList.GetImageInfo( nBmpNo, &imgInfo );
return CBitmap::FromHandle( imgInfo.hbmImage );
}
Related
I meet this problem when I deal with image streams from multi-cameras. I create a map and put all images into it based on the camera id, so I have:
std::mat<uint32_t, cv::Mat> images;
I will add image into that map by calling addImages as soon as receiving data from a specific camera:
void addImages(uint32_t camera_id, CameraData imgData)
{
cv::Mat img = cv::Mat(imgData.height(), imgData.width(), CV_8UC3, (void *)imgData.ptr);
images.insert(make_pair(camera_id, img));
cv::imshow("origin image", img);
}
When I show images from that map somewhere else, strange thing happens. The image changes and I can tell that its color differs from the original one.
void showImage(uint32_t camera_id)
{
cv::imshow("get image", images[camera_id]);
cv::waitKey(1);
}
But when I change addImages codes a little bit, images are same as original ones which is expected.
void addImages(uint32_t camera_id, CameraData imgData)
{
cv::Mat img = cv::Mat(imgData.height(), imgData.width(), CV_8UC3, (void *)imgData.ptr);
// NOTE THIS LINE!!!
images.insert(make_pair(camera_id, img.clone()));
cv::imshow("origin image", img);
}
So, my question is, what is the difference? Is there any other way to solve this problem?
This line seems incorrect.
cv::Mat img = cv::Mat(imgData.height(), imgData.width(), CV_8UC3, (void *)imgData.ptr);
Here's a quote from the documentation on the fourth parameter to this constructor
Pointer to the user data. Matrix constructors that take data and step
parameters do not allocate matrix data. Instead, they just initialize
the matrix header that points to the specified data, which means that
no data is copied.
In other words the Mat object just stores this pointer, it doesn't copy the data from it.
Now when your addImages function exits it destroys the imgData object which (presumably) invalidates the pointer you have just stored in the img object. That results in the problem you see.
The second version creates a clone of the img object which does copy the image data and so breaks the connection between the img object and the imgData object.
You might be able to fix this problem by passing the imgData parameter by reference. This means the imgData object would not be destroyed at the end of the function. But you would still have a situation where the Mat object and the CameraData object are sharing image data. So that might not be a good solution, but only you could say that for sure.
I have a draw(SkCanvas* canvas) function.
In main() I write:
SkBitmap myBitmap;
myBitmap.allocN32Pixels(640, 480);
SkCanvas *myCanvas(&myBitmap);
draw(myCanvas);
But Visual Studio generates this error:
"a value of type "SkBitmap *" cannot be used to initialize an entity of type "SkCanvas*"
What am I doing wrong?
My draw() function clutters the post and is completely useless for this question otherwise I've posted it.
This is the construction for SkCanvas.
/** Construct a canvas with the specified bitmap to draw into.
#param bitmap Specifies a bitmap for the canvas to draw into. Its
structure are copied to the canvas.
*/
explicit SkCanvas(const SkBitmap& bitmap);
SkCanvas *myCanvas(&myBitmap);
this is a pointer to a canvas. The pointer types of SkCanvas* and SkBitmap* are unrelated.
SkCanvas myCanvas(&myBitmap);
this is a value of type myCanvas, initialized with a pointer to bitmap. If SkCanvas has a ctor taking a SkBitmap*, this should work.
It does not. It does have:
explicit SkCanvas(const SkBitmap& bitmap);
so this means:
SkCanvas myCanvas(myBitmap);
You'll probably also need to change the draw call to this:
draw(&myCanvas);
assuming that works. As a guess, you also need a refresher on the difference between pointers and values.
In my program I have a function that creates an outline of another sf::Text string which is as follows:
void textDisplay::createOutline(std::vector<textDisplay> &textDisplayVector, std::vector<textDisplay> &textDisplayVector2, textDisplay &textDisplay2)
{
//create text2 npc dialogue outline
textDisplay2.text.setString(textDisplayVector.back().text.getString());
textDisplay2.text.setPosition(textDisplayVector.back().text.getPosition().x + 1, textDisplayVector.back().text.getPosition().y + 1);
textDisplay2.text.setCharacterSize(textDisplayVector.back().text.getCharacterSize());
textDisplay2.text.setColor(sf::Color::Black);
//textDisplay2.text.setFont(textDisplayVector.back().text.getFont());
textDisplayVector2.push_back(textDisplay2);
}
I want to also copy the text's font, but i get this error:
'no suitable constructor exists to convert from "const sf::Font *" to "sf::Font"'.
I looked at the sfml documentation and I believe the issue lies with getFont() using a pointer rather than a reference. I have no idea how to implement this though. How can this commented out line of code that uses setFont() and getFont() be improved so that it works? All of the other lines of code work properly.
Like you suspect, the problem is that sf::Text::getFont returns a pointer to a Font, while sf::Text::setFont expects a reference to a Font as argument. Pointer != reference, therefore you get an error.
The solution is simple: Dereference (using the * operator) the pointer returned by getFont:
textDisplay2.text.setFont(*textDisplayVector.back().text.getFont());
// ^
// |
// Notice the dereference operator here
I am completely confused by MFC wrapper for directd2d intefaces. Take a look at the following for example:-
BOOL CreateCompatibleRenderTarget(
CBitmapRenderTarget& bitmapTarget,
CD2DSizeF sizeDesired = CD2DSizeF(0.,
0.),
CD2DSizeU sizePixelDesired = CD2DSizeU(0,
0),
D2D1_PIXEL_FORMAT* desiredFormat = NULL,
D2D1_COMPATIBLE_RENDER_TARGET_OPTIONS options = D2D1_COMPATIBLE_RENDER_TARGET_OPTIONS_NONE
);
bitmapTarget When this method returns, contains the address of a
pointer to a new bitmap render target. This parameter is passed
uninitialized.
I am completely puzzled by what I should pass to the the function. As on contrary to documentation it receives the object and not the pointer to the uninitialized as in Directd2d IDL. And the object must be initialized.
Now one can tell that CBitmapRenderTarget is an object created with default contstructor. However this is not working with the GetBimap member of the CBitmapRenderTarget which also follows the same patter in documentation:-
BOOL GetBitmap(
CD2DBitmap& bitmap
);
bitmap When this method returns, contains the valid bitmap for this
render target. This bitmap can be used for drawing operations.
However the CD2DBitmap DOES NOT HAVE the default ctor, so I cannot create the object in a first place. The question is how do I correctly call to GetBitmap of CBitmapRenderTarget API. How do I create the uninitialized CD2DBitmap object ???
I encountered same issue. Looking at the CD2DBitmap implementation, there's no constructor without argument, and one with the only the parent CRenderTarget* ans an argument, but it's protected so not usable from outside. So apparently the only way is to use one of the 3 public constructors which are only crating Bitmap from existing resources (from handle, resource id or file path).
On my case, as a workaround because my intent is to replace this bitbap by a new one (GetBitmap), I created the Bitamp from a PNG file stored on my resources :
CD2DBitmap bitmap(GetRenderTarget(), (UINT)IDB_LOGO_PETIT, _T("PNG"));
m_pTraceRenderTarget->GetBitmap(bitmap);
But you can use any other CD2DBitmap constructor:
CD2DBitmap(CRenderTarget* pParentTarget, UINT uiResID, LPCTSTR lpszType = NULL, CD2DSizeU sizeDest = CD2DSizeU(0, 0), BOOL bAutoDestroy = TRUE);
CD2DBitmap(CRenderTarget* pParentTarget, LPCTSTR lpszPath, CD2DSizeU sizeDest = CD2DSizeU(0, 0), BOOL bAutoDestroy = TRUE);
CD2DBitmap(CRenderTarget* pParentTarget, HBITMAP hbmpSrc, CD2DSizeU sizeDest = CD2DSizeU(0, 0), BOOL bAutoDestroy = TRUE);
In my situation, the Drawing::Bitmap is created using a pointer to the pixel data. On the MSDN you can find a constructor doing exactly this:
Bitmap(int width, int height, int stride, PixelFormat format, IntPtr scan0);
From the documentation it is clear this constructor creates just the header and required things around the provided data. It is also noted, the caller have to release the pixel data array.
The caller is responsible for allocating and freeing the block of memory specified by the scan0 parameter. However, the memory should
not be released until the related Bitmap is released.
My problem is, if I pass a Bitmap with linked pixel data to another class, then I'm not able to release the underlying data. See my example bellow:
Drawing::Image^ FirstClass::GetImage(std::string ImagePath)
{
IplImage* cvImg = cvLoadImage(ImagePath.c_str());
Drawing::Image^ ManagedImg = gcnew Bitmap(
cvImg->width,
cvImg->height,
cvImg->widthStep,
Drawing::Imaging::PixelFormat::Format24bppRgb,
(System::IntPtr)cvImg->imageData);
return ManagedImg;
}
Void SecondClass::RefreshImage()
{
// Release the last image first
if (MyImage!=nullptr)
{
???
}
MyImage = GetImage(...);
}
A simple workaround is to pass, the IplImage* to the SecondClass, create the managed Bitmap there and then call cvReleaseImage(&Native_MyImage); there. However this works, I really want to know how to do it properly without passing IplImage*.
You need to pass pointers to pixels in some way.
For me, a better way would be to wrap IplImage* and ManagedImg into a single class that manages both of them. The destructor of the class would be responsible for destroying ManagedImg and then for calling cvReleaseImage() for stored value of the IplImage*. And then your GetImage function could return a pointer to this wrapper class, not to Drawing::Image.