I want to load a bitmap from file, perform some operations on it, and save it back under the same file name. The pattern is this:
Bitmap in = gcnew Bitmap(fileName);
Bitmap out = gcnew Bitmap(in.Width, in.Height, in.PixelFormat);
fill [out] with data from [in]
out.Save(fileName);
but this doesn't work. That's obvious. I cannot save to a file which is still opened (because of bitmap in). The question is: how the heck do I close bitmap in?! I've tried many ways but nothing works. Calling Dispose worked in C# but this method is protected in C++. Calling delete also doesn't work. What's the solution?
EDIT:
Operating on one bitmap doesn't work either. But I found a problem. Calling delete worked. I forgot to declare my bitmaps as pointers
Bitmap^ in = gcnew Bitmap(fileName);
Bitmap^ out = gcnew Bitmap(in.Width, in.Height, in.PixelFormat);
fill [out] with data from [in]
delete in;
out.Save(fileName);
This is a common trap in C++/CLI coding, you are using stack semantics. In other words, you didn't declare the reference type variable with the ^ hat. Which makes the compiler automatically emit the Dispose() call at the end of the scope block. Very convenient and a simulation of the RAII pattern in C++ but it gets in the way here. You want to dispose the in bitmap before saving the new bitmap.
Two ways to do this. You could play a game with the scope blocks by adding braces:
Bitmap^ out;
try {
{
Bitmap in(fileName);
out = gcnew Bitmap(in.Width, in.Height, in.PixelFormat);
// etc..
} // <== "in" gets disposed here
out->Save(fileName);
}
finally {
delete out;
}
But that's kinda ugly, especially since it needs to be mixed up for out in this very specific case. The alternative is to just do everything explicitly:
Bitmap^ out;
Bitmap^ in;
try {
in = gcnew Bitmap(fileName);
out = gcnew Bitmap(in->Width, in->Height, in->PixelFormat);
// etc..
delete in;
in = nullptr;
out->Save(fileName);
}
finally {
delete in;
delete out;
}
You don't need an out Bitmap. Just edit in and save it. Also I'd advise using the CImage class instead
CImage image;
image.Load(filename);
fill [image] with whatever data you want
image.Save(filename);
Related
How do I call a box.redraw from a routine?
I have a timer callback from which I a have to assign a new picture to box1.
My programm crashes at this point.
...
Fl_Window *win = NULL;
Fl_Box *box1 = NULL;
static void get_new_pic(void*) { // Timer callback
const char *filename = "pic2.png";
Fl_PNG_Image png(filename);
box1->image(png);
box1->redraw(); // this kicks the application
Fl::repeat_timeout(2,CB_Hole_Info);
}
int main() {
win = new Fl_Window(240,240); // make a window
box1 = new Fl_Box(0,0,240,180); // widget that will contain image
const char *filename = "pic1.png";
Fl_PNG_Image png(filename);
box1->image(png);
Fl::add_timeout(2, get_new_pic, buff); // setup a timer
win->show();
return(Fl::run());
}
Regards
Your way of adding the image in the timeout is correct. However, you allocate the image on the stack: Fl_PNG_Image png(filename);, so when you leave the timer, the image is automatically deleted together with the stack. When the box is actually drawn, the image is not there anymore.
FLTK does not copy the image. It just links to it.
You'd have to write Fl_PNG_Image *png = new Fl_PNG_Image(filename); and fix the rest of the code to use a pointer and make sure that the image is deleted at the very end.
You declared png1 and png2 as global variables (used in get_new_pic()) but you also declared local variables with the same name in main() which "shadow" the global variables.
Please remove Fl_PNG_Image * from the two assignments in main() so these assignments use the global variables as intended.
Hint: you should also assign a solid background to the box like
box1->box(FL_FLAT_BOX);
I'm trying to update a label value from a background thread. I understand that there are several example, but I'm still having trouble understanding why the below code throw an stack overflow error. It seems like every time setTitle() is executed it goes through the true part of the if statement.
Set title Function:
void setTitle(char data[])
{
String^ temp = gcnew String(data);
if(this->lastSeen1->InvokeRequired)
{
setTitleDelegate^ d = gcnew setTitleDelegate(this, &setTitle);
d->Invoke(data);
}else
{
this->lastSeen1->Text = temp;
this->lastSeen1->Visible = true;
}
}
delegate:
delegate void setTitleDelegate(char data[]);
Thank you
Well, because of this:
d->Invoke(data);
See, here you're calling Delegate::Invoke, which basically means that setTitle just calls itself immediately. You need to call Control::Invoke instead, so you need to call it on an instance of Control, something like this:
this->lastSeen1->Invoke(d, /* any args here */);
I don't know why you're passing a char[] here, it's better not to mix native and managed data structures too much, if you can then just use String^ instead (but even then, C++/CLI isn't really meant for UI development either...).
I hope this falls within the realm of this forum:
I want to use the windows shell(?) to allow users to select a number of files before allowing my programme to do a few things to them. For this I found the MSDN sample "CommonFileDialogModes" - http://msdn.microsoft.com/en-us/library/windows/desktop/dd940350%28v=vs.85%29.aspx
In the sample under this class:
class CFileOpenBasketPickerCallback : public IFileDialogEvents, public IFileDialogControlEvents
they have this function:
// IFileDialogEvents
IFACEMETHODIMP OnFileOk(IFileDialog *pfd)
{
// if this button is in the "Add" mode then do this, otherwise return S_OK
IFileOpenDialog *pfod;
HRESULT hr = pfd->QueryInterface(IID_PPV_ARGS(&pfod));
if (SUCCEEDED(hr))
{
IShellItemArray *psia;
hr = pfod->GetSelectedItems(&psia);
if (SUCCEEDED(hr))
{
ReportSelectedItems(pfd, psia);
psia->Release();
}
pfod->Release();
}
return S_FALSE; // S_FALSE keeps the dialog up; return S_OK to allow it to dismiss.
}
which calls:
void ReportSelectedItems(IUnknown *punkSite, IShellItemArray *psia)
{
DWORD cItems;
HRESULT hr = psia->GetCount(&cItems);
for (DWORD i = 0; SUCCEEDED(hr) && (i < cItems); i++)
{
IShellItem *psi;
hr = psia->GetItemAt(i, &psi);
if (SUCCEEDED(hr))
{
PWSTR pszName;
hr = GetIDListName(psi, &pszName);
// .. I've cut some of this out for the example
CoTaskMemFree(pszName);
}
psi->Release();
}
}
}
Now I know pszName contains the names of the files selected. So I can add some extra code in to write this to disk. That works fine. But I dont want to write it to disk. I want to pass it back to the original functions that called this. The arguments for ReportSelectedItems can be altered, but IFACEMETHODIMP OnFileOk(IFileDialog *pfd) cannot as it is inherited. Adding a vector& file_names to the argument will stop it compiling.
So how should I deal with this? I could use a global variable for file_names, but everything I am learning about programming is telling me not to. It would be a quick fix, but I worry that would encourage me to be lazy in the future. I find it difficult to read the windows code and I don't really want to delve too much into the details of it. I can't even find what is calling the OnFileOk function, even though I know it is from one of the two base classes.
Do I really need to work at understanding all the library code just to get this one function doing what I'd like? Is there an faster way of going about this?
So to summarize, how would I get information from this inherited function without using a global variable or writing to disk? As I mentined before, I don't have much of a grasp of the code I am working with. And for future reference, how should I deal with this type of situation? I use c++ and would like to avoid c# and c as much as possible.
Thanks as always.
It seems a fairly big omission for Microsoft to have left out any sort of user data associated with the IFileDialog callbacks, but that does seem to be the case.
I'm assuming that simply calling GetSelectedItems() once the dialog returns is something you don't want to do for some reason - because that would obviously be the simplest solution.
From a quick look at the docs one way you may be able to pass data back from the event callback is using the owner window that you pass to IFileDialog::Show() (which is actually IModalWindow::Show()).
In the event handler, you get given the IFileDialog* pointer. From this, you can QI the address of the IOleWindow interface which will give you the dialog's window:
IFACEMETHODIMP OnFileOk(IFileDialog *pfd)
{
CComPtr<IOleWindow> pWindow;
if (SUCCEEDED(pfd->QueryInterface(IID_IOleWindow, reinterpret_cast<void**>(&pWindow))))
{
HWND hwndDlg;
if (SUCCEEDED(pWindow->GetWindow(&hwndDlg)))
{
HWND hwndOwner;
if (hwndOwner = GetWindow(hwndDlg, GW_OWNER))
{
// hwndOwner is the owner window of the dialog
}
}
}
// more code
}
Now assuming that hwndOwner is your own window, you can associate any data you like with it using SetProp()/GetProp() - so you could use this as a mechanism to pass data back from within the callback.
A simple solution was to add member data inside the inherited class and link it from the constructor:
class CFileOpenBasketPickerCallback : public IFileDialogEvents, public IFileDialogControlEvents
{
public:
CFileOpenBasketPickerCallback(vector<wstring>& files) : files_(files)
{
}
// functions
private:
vector<wstring>& files_;
};
When constructing the object
vector<std::wstring> files
CFileOpenBasketPickerCallback foacb(files);
And in IFACEMETHODIMP OnFileOk(IFileDialog *pfd)
ReportSelectedItems(pfd, psia, files_);
ReportSelectedItems is not a member so you can alter the arguments.
I am struggling with memory issues, I think I missed something and would greatly appreciate if someone can point me to what I understand/do wrong.
What I want to do
My gui runs in the main thread. I am launching a computation on a separate thread T. The result of this computation is a bunch of opencv images. I want to display them in my gui during the computation.
How I understand I should do it
Launch computation thread.
When a new image is computed, convert it to a QImage, wrap it in a custom QEvent, and post it to my gui.
Only use heap memory.
How I implemented it
In my computation thread, when a new image is ready :
std::shared_ptr<cv::Mat> cvimRGB = std::shared_ptr<cv::Mat>(new cv::Mat);
cv::Mat cvimBGR;
cv::Mat cvim = MyNewComputedImage;
cvim.convertTo(cvimBGR,CV_8UC3);
cv::cvtColor(cvimBGR,*cvimRGB,cv::COLOR_BGR2RGB);
std::shared_ptr<QImage> qim = std::shared_ptr<QImage>(
new QImage((uint8_t*) cvimRGB->data,cvimRGB->cols,cvimRGB->rows,cvimRGB->step,QImage::Format_RGB888));
ImageAddedEvent* iae = new ImageAddedEvent(qim,i);
QCoreApplication::postEvent(gui, iae);
In my event handler :
bool mosaicage::event(QEvent * e){
if (e->type() == ImageAdded) {
ImageAddedEvent* ie = dynamic_cast<ImageAddedEvent*>(e);
QImage qim(*(ie->newImage));
QPixmap pm(QPixmap::fromImage(qim));
auto p = scene.addPixmap(pm);
images_on_display.push_back(p);
return true;
} else {
return QWidget::event(e);
}
}
My custom event is defined as follow :
class ImageAddedEvent: public QEvent {
public:
ImageAddedEvent();
~ImageAddedEvent();
ImageAddedEvent(std::shared_ptr<QImage> im, int i);
std::shared_ptr<QImage> newImage;
int index;
};
What happens
In debug mode, I get crap on display.
In release mode, I get an access violation error.
I am pretty confident about the part where I convert cv::Mat to qimage because I did not change it, I used to update the display from the computation thread but I learned better. It worked though (when it did not crash).
How I fixed it
The problem was in the memory pointed by the QImage, which was taken charge of by the cv::Mat I constructed it from. If I want to keep this way of constructing the QImage, using data managed by someone else, I must keep the data valid. Hence I moved the cv::Mat to the custom event :
class ImageAddedEvent: public QEvent {
public:
ImageAddedEvent();
~ImageAddedEvent();
ImageAddedEvent(cv::Mat im, int i);
QImage newImage;
cv::Mat cvim;
int index;
};
I changed the constructor of the event to initialize the QImage with the cv::Mat data :
ImageAddedEvent::ImageAddedEvent(cv::Mat cvimRGB, int i) : QEvent(ImageAdded),
index(i),
cvim(cvimRGB)
{
newImage = QImage((uint8_t*) cvim.data,cvim.cols,cvim.rows,cvim.step,QImage::Format_RGB888);
}
And now I only have to pass a cv::Mat to my event constructor :
cv::Mat cvimBGR,cvimRGB;
cv::Mat cvim = MyNewImage;
cvim.convertTo(cvimBGR,CV_8UC3);
cv::cvtColor(cvimBGR,cvimRGB,cv::COLOR_BGR2RGB);
ImageAddedEvent* iae = new ImageAddedEvent(cvimRGB,i);
QCoreApplication::postEvent(gui, iae);
et voilĂ , again, thanks for the help!
you are using the wrong constructor
from the doc(emph mine):
The buffer must remain valid throughout the life of the QImage and all copies that have not been modified or otherwise detached from the original buffer. The image does not delete the buffer at destruction. You can provide a function pointer cleanupFunction along with an extra pointer cleanupInfo that will be called when the last copy is destroyed.
and you are using the stack allocated cvimRGB for the data pointer which (I believe) will clean up the buffer in it's destructor before the event is handled, leading to accessing "crap" data
so you should create a fresh Qimage and then copy the data
std::shared_ptr<cv::Mat> cvimRGB = std::shared_ptr<cv::Mat>(new cv::Mat);
cv::Mat cvimBGR;
cv::Mat cvim = MyNewComputedImage;
cvim.convertTo(cvimBGR,CV_8UC3);
cv::cvtColor(cvimBGR,*cvimRGB,cv::COLOR_BGR2RGB);
QImage qim = QImage(cvimRGB->cols,cvimRGB->rows,QImage::Format_RGB888));
//copy from cvimRGB->data to qim.bits()
ImageAddedEvent* iae = new ImageAddedEvent(qim,i);
QCoreApplication::postEvent(gui, iae);
or detach cvimRGB->data and let the cleanupFunction delete the buffer
on another note there is no need to use std::shared_ptr<QImage> as QImage will not copy the underlying data unless needed, This is known in Qt as implicit data sharing
to call the gui you can provide a Q_INVOKABLE method (or just a slot) in gui and use QMetaObject::invokeMethod(gui, "imageUpdated", Q_ARG(QImage, qim));
I'm working on a GUI with Qt, I have a problem with playing with threads . I create a small GUi with two button stream and stopstream. my Problem is that I can't restart stream after stoping it:
below is a part of the code :
MainThread::MainThread(QWidget *parent):QWidget(parent){
bstream = new QPushButton("&stream");
bstopstream = new QPushButton("STOP stream");
bcapture = new QPushButton("capture a frame");
Allbox = new QVBoxLayout(this);
Allbox->addWidget(bstream);
Allbox->addWidget(bcapture);
Allbox->addWidget(bstopstream);
connect(bstream,SIGNAL(clicked()),this, SLOT(startingstream()));
connect(bcapture,SIGNAL(clicked()),this, SLOT(captureAFrame()));
connect(bstopstream,SIGNAL(clicked()),this, SLOT(stopstreaming()));
setLayout(Allbox);
}
void MainThread::stopstreaming(){
cv::destroyAllWindows();
stream.terminate();
stream.wait();
stream.~Streaming();
}
void MainThread::startingstream(){
if(stream.isRunning()) return;
stream.start();
}
stream.~Streaming();
This calls the destructor of your stream object. You should not call it manually, formally the object is dead after that and it may behave "interesting" after that.
For example, assume an object like this:
void stream::play() {
buff_->start();
}
void stream::~stream() {
delete buff_;
}
then the line buff_->start() might do funky things, essentially yielding undefined behaviour.
Or if it is written like this (though you should never need to manually set something to zero in a destructor; as said, the object is supposed to be dead after destruction):
void stream::play() {
if (buff_) buff_->start();
}
void stream::~stream() {
delete buff_;
buff_ = 0;
}
then it might do plain nothing.