I am writing a winform application in C# to open an image and overlay another image on top of it.
The bottom image is a .jpg and the top one is a .bmp converted from .svg. The .jpg and the .svg are the only ones I want to keep in the folder. The .bmp works as a temp.
I was using the following code to overlay the images. But I am having trouble to delete the temp .bmp as it is used by another process. I think it is this combine code still have access to the last .bmp file.
Could anyone help me on this? Thanks.
private void buttonSearch_Click(object sender, EventArgs e)
{
FailInfo.Text = "";
deletebmp(strFolderPath);
...
// Check if the specified front image exists. Yes, show the file name and convert SVG to BMP. No, show the error msg.
if (File.Exists(strFilePathF))
{
labelFront.Text = strFileNameF;
var svgConvert = SvgDocument.Open(svgFilePathF);
svgConvert.Draw().Save(bmpFilePathF);
pictureBoxFront.Image = Image.FromFile(strFilePathF);
}
else
{
labelFront.Text = "Couldn't find the file!";
pictureBoxFront.Image = null;
}
// Check if the specified back image exists. Yes, show the file name and convert SVG to BMP. No, show the error msg.
if (File.Exists(strFilePathBF))
{
labelBack.Text = strFileNameBF;
strFilePathB = strFilePathBF;
pictureBoxBack.Image = Image.FromFile(strFilePathB);
labelResult.Text = "FAIL";
labelResult.BackColor = Color.FromArgb(255, 0, 0);
var svgConvert = SvgDocument.Open(svgFilePathBF);
bmpFilePathB = strFolderPath + strFileNameBF + ".bmp";
svgConvert.Draw().Save(bmpFilePathB);
svgFilePathB = svgFilePathBF;
inspectionres(svgFilePathB);
labelreason.Visible = true;
}
else if (File.Exists(strFilePathBP))
{
labelBack.Text = strFileNameBP;
strFilePathB = strFilePathBP;
pictureBoxBack.Image = Image.FromFile(strFilePathB);
labelResult.Text = "PASS";
labelResult.BackColor = Color.FromArgb(0, 255, 0);
var svgConvert = SvgDocument.Open(svgFilePathBP);
bmpFilePathB = strFolderPath + strFileNameBP + ".bmp";
svgConvert.Draw().Save(bmpFilePathB);
svgFilePathB = svgFilePathBP;
inspectionres(svgFilePathB);
labelreason.Visible = false;
}
else
{
labelBack.Text = "Couldn't find the file!";
pictureBoxBack.Image = null;
labelResult.Text = "ERROR";
labelResult.BackColor = Color.FromArgb(0, 255, 255);
labelreason.Visible = false;
}
}
//
// Overlay the SVG file on top of the JPEG file
//
private Bitmap Combine(string jpegFile, string bmpFile)
{
Image image1 = Image.FromFile(jpegFile);
Image image2 = Image.FromFile(bmpFile);
Bitmap temp = new Bitmap(image1.Width, image1.Height);
using (Graphics g = Graphics.FromImage(temp))
{
g.DrawImageUnscaled(image1, 0, 0);
g.DrawImageUnscaled(image2, 0, 0);
}
return temp;
}
//
// Show the overlaid graphic in the picturebox
//
private void checkBoxOverlay_CheckedChanged(object sender, EventArgs e)
{
try
{
if (FindFront)
if (checkBoxOverlay.Checked)
pictureBoxFront.Image = Combine(strFilePathF, bmpFilePathF);
else
pictureBoxFront.Image = Image.FromFile(strFilePathF);
else
pictureBoxFront.Image = null;
if (FindBack)
if (checkBoxOverlay.Checked)
pictureBoxBack.Image = Combine(strFilePathB, bmpFilePathB);
else
pictureBoxBack.Image = Image.FromFile(strFilePathB);
else
pictureBoxBack.Image = null;
}
catch (Exception ex)
{
MessageBox.Show("Error loading image" + ex.Message);
}
}
//
// Option of changing the image folder
//
private void buttonPath_Click(object sender, EventArgs e)
{
FolderBrowserDialog FolderBrowserDialog1 = new FolderBrowserDialog();
if (FolderBrowserDialog1.ShowDialog() == DialogResult.OK)
{
strFolderPath = FolderBrowserDialog1.SelectedPath + "\\";
}
}
//
// Pull the inspection result info from the SVG file
//
private void inspectionres(string filename)
{
XDocument document = XDocument.Load(filename);
XElement svg_Element = document.Root;
string sb = null;
var faillist = (from svg_path in svg_Element.Descendants("{http://www.w3.org/2000/svg}text") select svg_path).ToList();
foreach (var item in faillist)
{
sb += item.ToString();
}
}
//
// Delete all the .bmp files generated from .svg files
//
private void deletebmp(string path)
{
// Unload the images from the picturebox if applicable
pictureBoxFront.Image = null;
pictureBoxBack.Image = null;
string[] files = Directory.GetFiles(path, "*.bmp");
for (int i = 0; i < files.Length; i ++ )
File.Delete(files[i]);
}
}
Image implements IDisposable, so simply setting the pictureBox.Image property to null will not release resources (in your case, the file). Your Combine method also leaves the images open. You have to call Dispose before attempting to delete the file:
Image image1 = Image.FromFile(path1);
File.Delete(path1); // error - file is locked
Image image2 = Image.FromFile(path2);
image2.Dispose();
File.Delete(path2); // works
An alternative approach (and I assume you're using WinForms here, in WPF it's a little different) would be to load the bitmap from the file manually (using FromStream). Then, you can close the stream immediately and delete the file:
Image image;
using (Stream stream = File.OpenRead(path))
{
image = System.Drawing.Image.FromStream(stream);
}
pictureBox.Image = image;
File.Delete("e:\\temp\\copy1.png"); //works
Vesan's answer didn't helped me so I found an different solution.
So I can safe/open an image and if I want instantly delete the image.
i used it for my dataGridView_SelectionChanged:
private void dataGridViewAnzeige_SelectionChanged(object sender, EventArgs e)
{
var imageAsByteArray = File.ReadAllBytes(path);
pictureBox1.Image = byteArrayToImage(imageAsByteArray);
}
public Image byteArrayToImage(byte[] byteArrayIn)
{
MemoryStream ms = new MemoryStream(byteArrayIn);
Image returnImage = Image.FromStream(ms);
return returnImage;
}
All above answers are perfectly fine, but I've got a different approach.
Using Image abstract class, you will not get quite a lot of options for manipulating and resizing image.
Rather you do as follows:-
Bitmap img = new Bitmap(item);
img.SetResolution(100, 100);
Image imgNew = Image.FromHbitmap(img.GetHbitmap());
pictureBox1.Image = imgNew;
img.Dispose();
Related
I've created an image uploader for users to upload/crop their profile pics. When a user uploads a file, it gets saved to a file that gets accessed immediately after for them to crop it.
I've tried using Path.GetTempPath() as well as Path.GetTempFileName(), but my cropper was unable to locate the file locations for some reason.
Any suggestions are greatly appreciated.
UPDATE: So I added File.Delete(filePath) to the end of btnCropClick, but I get an error saying The process cannot access the file because it is being used by another process. How can I "release" that file to be deleted instantly ?
Below is the code for where a user uploads their orignal image of choice
protected void btnUploadClick(object sender, EventArgs e)
{
//Upload Original Image Here
String UploadFileName = "";
String UploadFilePath = "";
if (fileUploader.HasFile)
{
String ext = Path.GetExtension(fileUploader.FileName).ToLower();
if (ext == ".jpg" || ext == ".jpeg" || ext == ".png")
{
UploadFileName = "orig_" + Guid.NewGuid().ToString() + ext;
UploadFilePath = Path.Combine(Server.MapPath("images/OriginalImages"), UploadFileName);
try
{
fileUploader.SaveAs(UploadFilePath); //TODO: Need to make this a temp file that gets "destroyed" later
imgUpload.ImageUrl = "images/OriginalImages/" + UploadFileName;
panCrop.Visible = true;
}
catch (Exception ex)
{
lblMsg.Text = "Error! Please Try Again. ";
}
}
else
{
lblMsg.Text = "Invalid File Type Selected. | Please Choose .jpg, .jpeg, or .png file only.";
}
}
else
{
lblMsg.Text = "Please Click 'Choose File' & Select An Image To Upload";
}
}
And here is the code for the cropper (Not sure anything in here needs to be changed, but I'll include it anyway for context & relevancy
protected void btnCropClick(object sender, EventArgs e)
{
//Crop Image Here & Save
String fileName = Path.GetFileName(imgUpload.ImageUrl);
String filePath = Path.Combine(Server.MapPath("images/OriginalImages"), fileName);
String cropFileName = "";
String cropFilePath = "";
if (File.Exists(filePath))
{
System.Drawing.Image orgImg = System.Drawing.Image.FromFile(filePath);
Rectangle CropArea = new Rectangle(
Convert.ToInt32(X.Value),
Convert.ToInt32(Y.Value),
Convert.ToInt32(W.Value),
Convert.ToInt32(H.Value)
);
try
{
Bitmap bitMap = new Bitmap(CropArea.Width, CropArea.Height);
using (Graphics g = Graphics.FromImage(bitMap))
{
g.DrawImage(orgImg, new Rectangle(0, 0, bitMap.Width, bitMap.Height), CropArea, GraphicsUnit.Pixel);
Bitmap resized = new Bitmap(bitMap, new Size(200, 200)); //Resize image to save as 200x200
cropFileName = "crop_" + fileName; //+UserID so each fileName is unique
cropFilePath = Path.Combine(Server.MapPath("images/CroppedImages"), cropFileName);
resized.Save(cropFilePath); //Where final, cropped image is saved
imgHeadshot.ImageUrl = "images/CroppedImages/" + cropFileName;
}
}
catch (Exception ex)
{
throw;
}
panCrop.Visible = false;
}
}
Was able to dispose of the original file by adding:
orgImg.Dispose();
bitMap.Dispose();
File.Delete(filePath);
to the end of btnCropClick method.
I wrote a small code to make a slideshow program on a different screen. Everything is running fine also the delete and copy part, unless I do it right after the first picture is shown. If I do it later the debugger steps in.
private void timer1_Tick(object sender, EventArgs e)
{
string[] images = Directory.GetFiles(#"D:\reflexscherm\root\Logo-teams2", "*.*");
counter++;
var maxcount = images.Count();
textBox1.Text = maxcount.ToString();
if (counter > maxcount - 1)
{
counter = 0;
maxcount = images.Count();
}
//pb1.Image.Dispose();
pb1.Image = Image.FromFile(images[counter]);
//Image oldImage = pb1.Image;
//pb1.Image.Dispose();
//oldImage.Dispose();
//pb1.Image = Image.FromFile(images[counter]);
}
private void button2_Click(object sender, EventArgs e)
{
timer1.Stop();
Image oldImage = pb1.Image;
pb1.Image = Image.FromFile(#"D:\reflexscherm\root\sponsor1\x. Groot-logo-REFLEX.jpg");
pb1.Image.Dispose();
oldImage.Dispose();
string[] files = System.IO.Directory.GetFiles(sourcepath);
string[] delfiles = Directory.GetFiles(targetpath);
this.Hide();
foreach (string d in delfiles)
{
Image oldI = pb1.Image;
pb1.Image = Image.FromFile(#"D:\reflexscherm\root\sponsor1\x. Groot-logo-REFLEX.jpg");
//pb1.Image.Dispose();
oldI.Dispose();
File.Delete(d);
}
foreach (string s in files)
{
string fname = s.Substring(sourcepath.Length + 1);
File.Copy(Path.Combine(sourcepath, fname), Path.Combine(targetpath, fname), true);
this.Show();
timer1.Start();
}
What I am looking for is some help to adjust the code, so when I change files in sourcefolder then program copies the files from the sourcefolder to the targetfolder. I know how to use filewatcher. I am using a button to test the code.
Method 1: Preserve a copy and assign a Control's property
Use this method when a Bitmap object is handled in more than one place, so we need to preserve it for further elaborations/assignments and save to disc after.
Assign, store and dispose of the source Bitmap immediately, deleting the Image file:
Bitmap bitmap = null;
//---------------------------------------------
string imagePath = #"[Path of the Image]";
bitmap?.Dispose();
pictureBox1.Image?.Dispose();
using (Bitmap tempImage = new Bitmap(imagePath, true))
{
bitmap = new Bitmap(tempImage);
pictureBox1.Image = bitmap;
}
File.Delete(imagePath);
Method 2: Assign the Bitmap and dispose of it immediately
This method can be used when you need to assign a Bitmap to a Control and then move/delete the Image file. The Image is disposed of immediately, so it's only available through a Control's property: if we ask to have it back, sometimes what we get is not exactly what we gave.
string imagePath = #"[Path of the Image]";
using (Image image = Image.FromFile(imagePath, true))
{
pictureBox1.Image?.Dispose();
pictureBox1.Image = new Bitmap(image);
}
File.Delete(imagePath);
Note that the old image assigned to the Control, if any, is disposed of before assigning a new one.
Also note I'm always specifying to preserve the internal ICM informations, if any, specifying true as the second parameter of both new Bitmap(imagePath, true) and Image.FromFile(imagePath, true).
Some images won't look as the original if we don't.
You should use a readonly File Access if you don't want it to be locked:
using( FileStream stream = new FileStream( path, FileMode.Open, FileAccess.Read ) )
{
image = Image.FromStream( stream );
}
Hope it helps...
I had the same problem before, i did the following:
this.photo.Dispose();
this.photo.Refresh();
this.photo.Image.Dispose();
this.photo.Image = null;
this.photo.ImageLocation = null;
and it worths it.
I’m using WinForms. In my form I have a picturebox. On form load, my program opens an image document into my picturebox from my C:/image directory. The problem is when my program opens that image I cannot go into my C:/image directory and delete this picture because my application is using it. When I go to C:/image directory and try to delete the picture I get this error.
My goal is to have control over the image document that means i have the ability to delete the specific document even if its being used by my application.
Test: I tested if you can delete an image while viewing it at the same time with "Windows Photo Viewer" installed into in my computer, and that application lets you. Windows photo viewer doesn't lock the images. When you delete an image from the directory the image goes away in windows photo viewer as well. I want to accomplish something similar.
Suggested code: I tried implementing this but, i think i'm implementing it incorrectly.
Image img;
using (var bmpTemp = new Bitmap("image_file_path"))
{
img = new Bitmap(bmpTemp);
}
Below i provided my code i wrote to load the picture into my picture box.
private void Form1_Load(object sender, EventArgs e) //When form load you do this:
{
try // Get the tif file from C:\image\ folder
{
string path = #"C:\image\";
string[] filename = Directory.GetFiles(path, "*.tif"); //gets a specific image doc.
pictureBox1.Load(filename[0]);
lblFile.Text = filename[0];
RefreshImage(); // refreshing and showing the new file
opened = true; // the files was opened.
Image img1 = Image.FromFile(lblFile.Text);
pictureBox1.Image = img1;
pictureBox1.Width = img1.Width;
pictureBox1.Height = img1.Height;
picWidth = pictureBox1.Width;
picHeight = pictureBox1.Height;
getRatio();
}
catch (Exception ex)
{
MessageBox.Show("No files or " + ex.Message);
}
}
Make a copy of the image file bits before creating the image:
private void Form1_Load(object sender, EventArgs e) //When form load you do this:
{
try // Get the tif file from C:\image\ folder
{
string path = #"C:\image\";
string[] filename = Directory.GetFiles(path, "*.tif"); //gets a specific image doc.
FileInfo fi = new FileInfo(filename[0]);
byte [] buff = new byte[fi.Length];
using ( FileStream fs = File.OpenRead(fileToDisplay) )
{
fs.Read(buff, 0, (int)fi.Length);
}
MemoryStream ms = new MemoryStream(buff);
Bitmap img1 = new Bitmap(ms);
opened = true; // the files was opened.
pictureBox1.Image = img1;
pictureBox1.Width = img1.Width;
pictureBox1.Height = img1.Height;
picWidth = pictureBox1.Width;
picHeight = pictureBox1.Height;
getRatio();
}
catch (Exception ex)
{
MessageBox.Show("No files or " + ex.Message);
}
}
My utility is supposed to resize either .jpg or .png files.
It seems to work fine in one location (at work, where I don't have IrfanView installed). But at home, when I open a *.jpg and then save it (resized), I see:
However, the image still displays fine in either case (whether I select "Yes" or "No" in the dialog.
IOW, I'm able to load and save both jpgs and pngs, and they save as such, and display fine. But IrfanView claims they are messed up.
Actually, I'm not sure how the image is saved; I was assuming it just saved it in the proper format "behind the scenes" based on the extension. Anyway, as this is a rather simple utility, I will just show all the code:
using System;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
namespace FileResizingUtil
{
public partial class FormFileResizer : Form
{
private Image _imgToResize;
String _originalFilename = String.Empty;
public FormFileResizer()
{
InitializeComponent();
}
private void buttonChooseImage_Click(object sender, EventArgs e)
{
OpenFileDialog ofd = new OpenFileDialog
{
InitialDirectory = "c:\\",
Filter = "JPG files (*.jpg)|*.jpg| PNG files (*.png)|*.png", FilterIndex = 2, RestoreDirectory = true
};
if (ofd.ShowDialog() == DialogResult.OK)
{
try
{
_originalFilename = ofd.FileName;
_imgToResize = Image.FromFile(_originalFilename);
}
catch (Exception ex)
{
MessageBox.Show("Error: Could not read file from disk. Original error: " + ex.Message);
}
}
// If made it to here, it must be good
String preamble = labelImgSelected.Text;
labelImgSelected.Text = String.Format("{0}{1}", preamble, _originalFilename);
textBoxOrigHeight.Text = _imgToResize.Height.ToString();
textBoxOrigWidth.Text = _imgToResize.Width.ToString();
buttonApplyPercentageChange.Enabled = true;
//buttonResizeImage.Enabled = true;
}
private void buttonResizeImage_Click(object sender, EventArgs e)
{
// Really large images take awhile, so show an hourglass
Cursor.Current = Cursors.WaitCursor;
try
{
var size = new Size { Height = Convert.ToInt32(textBoxNewHeight.Text), Width = int.Parse(textBoxNewWidth.Text) };
// Two different ways of getting the int val
Image resizedImg = FileResizeUtils.GetResizedImage(_imgToResize, size);
String fileNameSansExtension = Path.GetFileNameWithoutExtension(_originalFilename);
String fileNameExtension = Path.GetExtension(_originalFilename);
String newFilename = String.Format("{0}{1}_{2}{3}", fileNameSansExtension, size.Height, size.Width, fileNameExtension);
// If used a different extension (jpg where the original was png, or vice versa) would the Save be intelligent enough to actually save in the other format?
resizedImg.Save(newFilename);
MessageBox.Show(String.Format("Done! File saved as {0}", newFilename));
Recycle();
}
finally
{
Cursor.Current = Cursors.Default;
}
}
private void Recycle()
{
buttonResizeImage.Enabled = false;
buttonApplyPercentageChange.Enabled = false;
labelImgSelected.Text = "Image selected: ";
textBoxOrigHeight.Text = String.Empty;
textBoxOrigWidth.Text = String.Empty;
// Retain the percentage vals, as it may be that all in a batch need to be the same pair of vals
}
private void buttonApplyPercentageChange_Click(object sender, EventArgs e)
{
int origHeight = _imgToResize.Height;
int origWidth = _imgToResize.Width;
// Two ways to convert the val
double heightFactor = (double)numericUpDownHeight.Value / 100.0;
double widthFactor = Convert.ToDouble(numericUpDownWidth.Value) / 100.0;
if (heightFactor < 0 || widthFactor < 0)
{
// show an error - no negative values allowed- using updown, so that should not be possible
}
var newHeight = Convert.ToInt32(origHeight * heightFactor);
var newWidth = Convert.ToInt32(origWidth * widthFactor);
textBoxNewHeight.Text = newHeight.ToString();
textBoxNewWidth.Text = newWidth.ToString();
buttonResizeImage.Enabled = true;
}
private void textBoxNewHeight_TextChanged(object sender, EventArgs e)
{
EnableResizeButtonIfValidDimensionsEntered();
}
private void EnableResizeButtonIfValidDimensionsEntered()
{
if (String.IsNullOrWhiteSpace(textBoxOrigHeight.Text)) return;
String candidateHeight = textBoxNewHeight.Text;
String candidateWidth = textBoxNewWidth.Text;
int validHeight;
int validWidth;
buttonResizeImage.Enabled = (int.TryParse(candidateHeight, out validHeight)) &&
(int.TryParse(candidateWidth, out validWidth));
}
private void numericUpDownHeight_ValueChanged(object sender, EventArgs e)
{
if (checkBoxRetainRatio.Checked)
{
numericUpDownWidth.Value = numericUpDownHeight.Value;
}
}
private void numericUpDownWidth_ValueChanged(object sender, EventArgs e)
{
if (checkBoxRetainRatio.Checked)
{
numericUpDownHeight.Value = numericUpDownWidth.Value;
}
}
}
}
..and the GUI (just prior to hitting the "Resize Image" button:
UPDATE
Based on Eugene Sh.'ls comment, I changed my Save method to the following block:
bool success = true;
. . .
if (fileNameExtension != null && fileNameExtension.ToLower().Contains("jpg"))
{
resizedImg.Save(newFilename, ImageFormat.Jpeg);
}
else if (fileNameExtension != null &&
fileNameExtension.ToLower().Contains("png"))
{
resizedImg.Save(newFilename, ImageFormat.Png);
}
else
{
success = false;
}
if (success)
{
MessageBox.Show(String.Format("Done! File saved as {0}", newFilename));
}
else
{
MessageBox.Show("Something went awry. The file was not saved");
}
UPDATE 2
So here is my new code, implementing the suggestion, and supporting several new file types:
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Windows.Forms;
namespace FileResizingUtil
{
public partial class FormFileResizer : Form
{
private Image _imgToResize;
String _originalFilename = String.Empty;
public FormFileResizer()
{
InitializeComponent();
}
private void buttonChooseImage_Click(object sender, EventArgs e)
{
OpenFileDialog ofd = new OpenFileDialog
{
InitialDirectory = "c:\\",
Filter = "JPG files (*.jpg)|*.jpg| PNG files (*.png)|*.png| BMP files (*.bmp)|*.bmp| TIFF files (*.tiff)|*.png| ICO files (*.ico)|*.ico| EMF files (*.emf)|*.emf| WMF files (*.wmf)|*.wmf",
FilterIndex = 1, RestoreDirectory = true
};
if (ofd.ShowDialog() == DialogResult.OK)
{
try
{
_originalFilename = ofd.FileName;
_imgToResize = Image.FromFile(_originalFilename);
}
catch (Exception ex)
{
MessageBox.Show("Error: Could not read file from disk. Original error: " + ex.Message);
}
}
if (String.IsNullOrWhiteSpace(_originalFilename)) return;
// If made it to here, it must be good
String preamble = labelImgSelected.Text;
labelImgSelected.Text = String.Format("{0}{1}", preamble, _originalFilename);
textBoxOrigHeight.Text = _imgToResize.Height.ToString();
textBoxOrigWidth.Text = _imgToResize.Width.ToString();
buttonApplyPercentageChange.Enabled = true;
}
private void buttonResizeImage_Click(object sender, EventArgs e)
{
bool success = true;
// Really large images take awhile, so show an hourglass
Cursor.Current = Cursors.WaitCursor;
try
{
// Two different ways of getting the int val
var size = new Size { Height = Convert.ToInt32(textBoxNewHeight.Text), Width = int.Parse(textBoxNewWidth.Text) };
Image resizedImg = FileResizeUtils.GetResizedImage(_imgToResize, size);
String fileNameSansExtension = Path.GetFileNameWithoutExtension(_originalFilename);
String fileNameExtension = Path.GetExtension(_originalFilename);
String newFilename = String.Format("{0}{1}_{2}{3}", fileNameSansExtension, size.Height, size.Width, fileNameExtension);
if (fileNameExtension != null && fileNameExtension.ToLower().Contains("jpg"))
{
resizedImg.Save(newFilename, ImageFormat.Jpeg);
}
else if (fileNameExtension != null && fileNameExtension.ToLower().Contains("png"))
{
resizedImg.Save(newFilename, ImageFormat.Png);
}
else if (fileNameExtension != null && fileNameExtension.ToLower().Contains("bmp"))
{
resizedImg.Save(newFilename, ImageFormat.Bmp);
}
else if (fileNameExtension != null && fileNameExtension.ToLower().Contains("ico"))
{
resizedImg.Save(newFilename, ImageFormat.Icon);
}
else if (fileNameExtension != null && fileNameExtension.ToLower().Contains("tiff"))
{
resizedImg.Save(newFilename, ImageFormat.Tiff);
}
else if (fileNameExtension != null && fileNameExtension.ToLower().Contains("emf"))
{
resizedImg.Save(newFilename, ImageFormat.Emf);
}
else if (fileNameExtension != null && fileNameExtension.ToLower().Contains("wmf"))
{
resizedImg.Save(newFilename, ImageFormat.Wmf);
}
else
{
success = false;
}
MessageBox.Show(success
? String.Format("Done! File saved as {0}", newFilename)
: "Something went awry. The file was not saved");
Recycle();
}
finally
{
Cursor.Current = Cursors.Default;
}
}
private void Recycle()
{
buttonResizeImage.Enabled = false;
buttonApplyPercentageChange.Enabled = false;
labelImgSelected.Text = "Image selected: ";
textBoxOrigHeight.Text = String.Empty;
textBoxOrigWidth.Text = String.Empty;
// Retain the percentage vals, as it may be that all in a batch need to be the same pair of vals
}
private void buttonApplyPercentageChange_Click(object sender, EventArgs e)
{
int origHeight = _imgToResize.Height;
int origWidth = _imgToResize.Width;
// Two ways to convert the val
double heightFactor = (double)numericUpDownHeight.Value / 100.0;
double widthFactor = Convert.ToDouble(numericUpDownWidth.Value) / 100.0;
if (heightFactor < 0 || widthFactor < 0)
{
// show an error - no negative values allowed- using updown, so that should not be possible
}
var newHeight = Convert.ToInt32(origHeight * heightFactor);
var newWidth = Convert.ToInt32(origWidth * widthFactor);
textBoxNewHeight.Text = newHeight.ToString();
textBoxNewWidth.Text = newWidth.ToString();
buttonResizeImage.Enabled = true;
}
private void textBoxNewHeight_TextChanged(object sender, EventArgs e)
{
EnableResizeButtonIfValidDimensionsEntered();
}
private void EnableResizeButtonIfValidDimensionsEntered()
{
if (String.IsNullOrWhiteSpace(textBoxOrigHeight.Text)) return;
String candidateHeight = textBoxNewHeight.Text;
String candidateWidth = textBoxNewWidth.Text;
int validHeight;
int validWidth;
buttonResizeImage.Enabled = (int.TryParse(candidateHeight, out validHeight)) &&
(int.TryParse(candidateWidth, out validWidth));
}
private void numericUpDownHeight_ValueChanged(object sender, EventArgs e)
{
if (checkBoxRetainRatio.Checked)
{
numericUpDownWidth.Value = numericUpDownHeight.Value;
}
}
private void numericUpDownWidth_ValueChanged(object sender, EventArgs e)
{
if (checkBoxRetainRatio.Checked)
{
numericUpDownHeight.Value = numericUpDownWidth.Value;
}
}
}
}
From the Image.Save documentation:
If no encoder exists for the file format of the image, the Portable
Network Graphics (PNG) encoder is used. When you use the Save method
to save a graphic image as a Windows Metafile Format (WMF) or Enhanced
Metafile Format (EMF) file, the resulting file is saved as a Portable
Network Graphics (PNG) file. This behavior occurs because the GDI+
component of the .NET Framework does not have an encoder that you can
use to save files as .wmf or .emf files.
If you want to save in a different format, use the overloaded Save method, taking format as a second parameter:
Save(String, ImageFormat)
Most image viewers don't use the extension of the file to determine the type of the file, but use so called "magic numbers" (http://en.wikipedia.org/wiki/Magic_number_(programming)#Magic_numbers_in_files). They basically check the first X bytes of the file wich is often unique to a specific image format.
My guess is, that the library you're using saves the file as PNG as default (edit: see Eugenes answer), not considering what extension you put there. IrfanView notices, that the magic number and the extension don't match but still shows the image by defaulting to the magic number.
Go to a console and print out the file. If it is a PNG file, you will see PNG displayed and it stops.
If is is JPEG, you will get a lot of garbage but should see EXIF or JFIF at the top. The very start is FF D8
Because the JPEG and PNG have different signatures, the application can tell them apart from their contents and invite the appropriate decoder.
Image applications normally identify the type of image from the contents of the stream, not the extension.
In my windows application I use Windows Media Player dlls to play a video.
In my form I have a button to take a picture of the current video frame.
I did a lot of tests and code examinations but I couldn't find out why taking a picture of the current frame fails.
I tried this code, but the resulting image was black:
private Graphics g = null;
private void btnTakePicture_Click(object sender, EventArgs e)
{
if (!string.IsNullOrEmpty(axWMVMovie.URL))
{
axWMVMovie.Ctlcontrols.pause();
if (saveFileDialog1.ShowDialog() == DialogResult.OK)
{
System.Drawing.Image ret = null;
try
{
Bitmap bitmap = new Bitmap(axWMVMovie.Width, axWMVMovie.Height);
{
g = Graphics.FromImage(bitmap);
{
Graphics gg = axWMVMovie.CreateGraphics();
{
timerTakePicFromVideo.Start();
}
}
using (MemoryStream ms = new MemoryStream())
{
bitmap.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
ret = System.Drawing.Image.FromStream(ms);
ret.Save(saveFileDialog1.FileName);
}
}
}
catch
{
}
}
}
}
private void timerTakePicFromVideo_Tick(object sender, EventArgs e)
{
timerTakePicFromVideo.Stop();
g.CopyFromScreen(axWMVMovie.PointToScreen(new System.Drawing.Point()).X,
axWMVMovie.PointToScreen(new System.Drawing.Point()).Y, 0, 0,
new System.Drawing.Size(axWMVMovie.Width, axWMVMovie.Height));
}
I use Timer because when the user selects the save path, function takes image from the file user specified in save file dialog. Video format is WMV.
I took your code and modified it. I put the code to capture the photo a little bit up and now it works. I create the picture right before the saveFileDialog pops up, so you will really get only the picture and not the saveFileDialog within your pic.
if (!string.IsNullOrEmpty(axWindowsMediaPlayer1.URL))
{
axWindowsMediaPlayer1.Ctlcontrols.pause();
System.Drawing.Image ret = null;
try
{
// take picture BEFORE saveFileDialog pops up!!
Bitmap bitmap = new Bitmap(axWindowsMediaPlayer1.Width, axWindowsMediaPlayer1.Height);
{
Graphics g = Graphics.FromImage(bitmap);
{
Graphics gg = axWindowsMediaPlayer1.CreateGraphics();
{
//timerTakePicFromVideo.Start();
this.BringToFront();
g.CopyFromScreen(
axWindowsMediaPlayer1.PointToScreen(
new System.Drawing.Point()).X,
axWindowsMediaPlayer1.PointToScreen(
new System.Drawing.Point()).Y,
0, 0,
new System.Drawing.Size(
axWindowsMediaPlayer1.Width,
axWindowsMediaPlayer1.Height)
);
}
}
// afterwards save bitmap file if user wants to
if (saveFileDialog1.ShowDialog() == DialogResult.OK)
{
using (MemoryStream ms = new MemoryStream())
{
bitmap.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
ret = System.Drawing.Image.FromStream(ms);
ret.Save(saveFileDialog1.FileName);
}
}
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
}
With previous answer a trick to avoid getting the controls on the capture is to do this before you capture :
string uimode_previus = axWindowsMediaPlayer2.uiMode;
axWindowsMediaPlayer2.uiMode = "none";
then when capture is done set the uimode back to previous like this :
axWindowsMediaPlayer2.uiMode = uimode_previus ;
In that way you only get the actual shoot from the current frame.
it is a little workaround but it does the job.
Here is working example
private void button8_Click_1(object sender, EventArgs e)
{
string uimode_previus = axWindowsMediaPlayer2.uiMode;
axWindowsMediaPlayer2.uiMode = "none";
if (!string.IsNullOrEmpty(axWindowsMediaPlayer2.URL))
{
ret = null;
try
{
// take picture BEFORE saveFileDialog pops up!!
Bitmap bitmap = new Bitmap(axWindowsMediaPlayer2.Width, axWindowsMediaPlayer2.Height);
{
Graphics g = Graphics.FromImage(bitmap);
{
Graphics gg = axWindowsMediaPlayer2.CreateGraphics();
{
//timerTakePicFromVideo.Start();
this.BringToFront();
g.CopyFromScreen(axWindowsMediaPlayer2.PointToScreen(
new System.Drawing.Point()).X,
axWindowsMediaPlayer2.PointToScreen(
new System.Drawing.Point()).Y,
0, 0,
new System.Drawing.Size(
axWindowsMediaPlayer2.Width - 0,
axWindowsMediaPlayer2.Height - 0)
);
}
}
// afterwards save bitmap file if user wants to
try
{
using (MemoryStream ms = new MemoryStream())
{
string rute = axWindowsMediaPlayer2.URL.ToString().Replace(".", "Review_."); //
bitmap.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
ret = new Bitmap(System.Drawing.Image.FromStream(ms));
ret.Save(rute.Replace(".mp4", ".Png"));
}
// open captured frame in new form
TeamEasy.ShowPictureForm spf = new ShowPictureForm();
spf.ImagePictureBox.Image = ret;
spf.ShowDialog();
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
}
axWindowsMediaPlayer2.uiMode = uimode_previus;
// restore the UImode of player
}