MY QUESTION: Is there a way to get a windows form to release an open image without closing the form.
MY PROBLEM: I am working on a windows form in c++. I have a program that allows users to edit .bmp images. The user selects the image they would like to edit from a dataGridView. The images are displayed in an image column in the dataGridView. When I load the image into the dataGridView control, the form opens the image file and prevents any further editing of the image file. The image file cannot be edited even if the dataGridView control is deleted. The form must completely close before it releases the image file.
MY CODE:
namespace EditImageTest {
public ref class Form1 : public System::Windows::Forms::Form {
public: Form1(void) {
// create an image column & dataGridView.
System::Windows::Forms::DataGridViewImageColumn^ c = gcnew System::Windows::Forms::DataGridViewImageColumn();
c->ImageLayout = System::Windows::Forms::DataGridViewImageCellLayout::Zoom;
System::Windows::Forms::DataGridView^ dgv = gcnew System::Windows::Forms::DataGridView();
// add column to dataGridView.
dgv->Columns->Add(c);
// add dataGridView to form.
this->Controls->Add(dgv);
// add .bmp image on desktop to dataGridView.
dgv->Rows>Add(System::Drawing::Image::FromFile("C:\\Users\\User\\Desktop\\1.bmp"));
// the form has now opened the .bmp image file preventing any edits on this file.
// you can not even manualy delete this file now.
// attempt to open the .bmp image for editing.
FILE* f;
fopen_s(&f,"C:\\Users\\User\\Desktop\\1.bmp","w");
if(f) {
// write garbage in the .bmp image.
fwrite("SOME TEXT",sizeof(unsigned char),9,f);
// close the .bmp image.
fclose(f);
}
}
protected: ~Form1() { if (components) { delete components; } }
private: System::ComponentModel::Container ^components;
};
}
The Image class creates a memory-mapped file to map the bitmap's pixel data into memory. That's efficient, it won't take space in the swapfile and if the RAM pages are unmapped then they can always be reloaded from the file. Tends to matter for bitmaps, they can be quite large.
But the MMF does create a lock on the file, it won't be released until you dispose the object with the delete operator. Which of course can't happen until after the window is closed.
You avoid this by making a deep copy of the image, allowing the lock to be released quickly. Do so with the Bitmap(Image^) constructor:
auto img = System::Drawing::Image::FromFile("C:\\Users\\User\\Desktop\\1.bmp"));
dgv->Rows>Add(gcnew Bitmap(img));
delete img;
Related
This is my sample UI, the white box is a textbox which will have some items, my main question is that when i click "Save/Refresh" qpushbutton, i want to save all of the qtextbox text into a textfile/sample_name.xml into a designated folder, but i dont wanna go through Qfiledialog box and having to decide/browse a location in which the file needs to be saved, i just want it to be saved at a fixed place in C-drive ,
and also the text in the qtextbox should again be loaded with that sample_name.xml file, i know the content is gonna be the same as i just saved it , but still i need it for some other functionality.
How can i acheive this without the involvement of qfiledialog ?
Using Qt classes, the required code could look like that:
The following code should be in a "slot" function that is connected to the clicked() signal of your button.
QString text = ui->textField->text(); // get the text from your UI component
QFile file(QStringLiteral("C:/fixed_path.txt")); // define the file to write
if (file.open(QIODevice::WriteOnly)) // open the file and check that everything is ok
{
file.write(text.toUtf8()); // write your data in the file
file.close(); // close the file
}
You will have to provide a static path within the function that listens at your Save button. Your listener function would be of a similar format:
void save(){
//assuming content of textbox has been stored in variable 'content'
ofstream myfile;
myfile.open ("path_to_file", ios::trunc);
myfile << content;
myfile.close();
}
Similarly on reopening this view, you'll run a reload function and read the file into a variable, and set it's value into the textbox
In our C++/Qt4.8 application we are using QImage to add images to our documents we print. Sometimes we expierence issues with printing the image, and the image will be printed out blank (just a empty page).
We added logging into our application and added an audit log on our resources folder where the images are.
We initialize our image in this way. And pass it as argument to mPainter (instance of QPainter)
QImage image( strImage );
mPainter.drawImage( QRect( 0, 0, pageRect().width(), pageRect().height() ), image );
The drawImage fuction of mPainter will call the following QPainter function :
inline void QPainter::drawImage(const QRect &r, const QImage &image)
{
drawImage(r, image, QRectF(0, 0, image.width(), image.height()));
}
The windows audit shows us that the application successfully tried to acces the files.
But sometimes the following code will returns false and goes into the else:
QImage* imageToPrint = new QImage;
if (imageToPrint->load("C:/ApplicationName/Resources/page-001.jpg"))
{
//fuction body
}
else
{
if (QFile::exists("C:/ApplicationName/Resources/page-001-copy.jpg"))
{
//Copy the image and try to print with this one.
QFile::copy("C:/ApplicationName/Resources/page-001-copy.jpg", "C:/ApplicationName/Resources/page-001-unixtimestamp.jpg");
printImage("C:/ApplicationName/Resources/page-001-unixtimestamp.jpg");
QFile::remove("C:/ApplicationName/Resources/page-001-unixtimestamp.jpg");
}
}
The strangest thing is that the application can access, copy and delete files in the directory. But sometimes can't read the data from the file. Even the newly created copy with the unixtimestamp can't be loaded (But does exist following the code) and will print a blank page.
Has anybody has this problem? Our does anyone has a solution for this?
Thanks in advance!
This is the last bit of the problem I have saving image to database and retrieving it. What I am trying to do now is to make it generic (before it was ico files and it worked) by using TWICImage. I am able to save and load it, but I get an exception while saving to the database.
Could not convert variant of type (Array Byte) into type (Integer)
If I click ok, everything is as usual. It is saved and loads and displays just fine. It must me something that I did wrong, but can't figure it out.
Here is the loading from file code snippet:
if (dlgOpenPictureFile->Execute())
{
TWICImage *Image = new TWICImage();
Image->LoadFromFile(dlgOpenPictureFile->FileName);
imgLogo->Picture = NULL;
imgLogo->Picture->Assign(Image);
if (dscMain->DataSet->State == dsBrowse)
{
dscMain->Edit();
}
TStream *StreamLogo = NULL;
try
{
StreamLogo = dscMain->DataSet->CreateBlobStream(dscMain->DataSet->FieldByName("Image"), bmWrite);
imgLogo->Picture->Graphic->SaveToStream(StreamLogo);
}
__finally
{
//at the time of delete it writes to the underlying buffer
delete StreamLogo;
delete Image;
}
}
dscMain is the datasource which we later post. The Image is of the type varbinary in the database.
Any insights to this problem is very much appreciated.
Edit:
After some testing, it looks like this is happening only for .png and .gif files.
IDE: Rad Studio Berlin
OS: Windows 10
I am working in an application where there is a conbobox and a picturebox. The user selects a path and the conbobox loads paths to 2000 images, and displays the first one. When the user changes the index of the conbobox the image displayed changes, but I don't know how to delete the image in the picturebox.
If I just overwrite the image it doesnt do the job, as when I do it repeatedly the program crashes because of memory. How do I delete a image Inside the picturebox?
EDIT:
I made few changes and can't seem to reproduce the error again.. so maybe it was something else. but just for checking, is this code leaking memory?
tips: config is a singleton containing where some info, in this case, where the images are.
private: System::Void comboBox_image1_SelectedIndexChanged(System::Object^ sender, System::EventArgs^ e) {
System::String^ aux;
DIC_config* config=DIC_config::Instance();
if(config->images_path!=NULL){
aux=gcnew System::String(config->images_path);
aux=aux+"\\CAM_0\\Snap_0_0"+(this->comboBox_image1->SelectedIndex+1)+".bmp";
System::IO::FileStream^ image_file=gcnew System::IO::FileStream(aux,System::IO::FileMode::Open,System::IO::FileAccess::Read);
System::Drawing::Bitmap^ img = gcnew System::Drawing::Bitmap(image_file);
this->pictureBox_image1->Image=img;
//img->~Bitmap(); this doesnt work, deletes the image of picturebox and makes the program chrash
}
}
You have to dispose the old image. Forgetting to do so makes it likely your program runs out of unmanaged memory when the garbage collector doesn't run frequently enough. Bitmap objects are quite small, you can allocate thousands of them without ever triggering a GC, but can consume a lot of unmanaged memory for the pixel data. You dispose objects in C++/CLI with the delete operator, it calls IDisposable::Dispose().
Do note that the FileStream you use is also a disposable object. Doing it this way requires you to keep the stream opened while the bitmap is in use and close it afterwards. You correctly did not dispose the stream but forgot closing it. Too hard to get right, it is much easier to use the Bitmap constructor that accepts a string for the file path so the Bitmap class manages the underlying stream itself. Fix:
aux = config->images_path;
aux += ....;
System::Drawing::Bitmap^ img = gcnew System::Drawing::Bitmap(aux);
delete this->pictureBox_image1->Image;
this->pictureBox_image1->Image = img;
This doesn't work because you are trying to call destructor of the class, not the instance. Furthermore you do not need to call it as System::Drawing::Bitmap is under control of garbage collector, so the finalizer ( !Bitmap() ) will be called automatically if it's not referenced any longer.
What you can do if you want to close it in picturebox is
delete this->pictureBox_image1->Image;
image_file->Close(); //after closing/deleting the open bitmap
btw. your code is not pure c++, but c++/cli, so I've added the tag
First set a null pointer to the Image property and refresh the pictureBox, as given below,
pictureBox_image1->Image = nullptr;
pictureBox_image1->Refresh();
We have a requirement that a user can load any standard image into a dialog, the image is displayed, and the image saved as a specific format (JPG) in a database. It seems CImage is the class to be using since it can load and save BMP/GIF/JPG/PNG. But is there an easy way to save the JPG as a BLOB in the database without calling CImage::Save and then loading the file to memory - we don't want to save the file even temporarily.
Any ideas?
CImage::Save has two overloads. You could use
HRESULT Save(
IStream* pStream,
REFGUID guidFileType
) const throw();
to save the image to an IStream. You could write your own simple IStream implementation or could try to use the CreateStreamOnHGlobal function, which creates an IStream object on an HGLOBAL.