Here is my Code, I am trying to stitch two pictures together and as soon as I get to line 42 "Image img = Image.FromFile(file.FullName);" I get an out of memory error. What should I do?
namespace Practicing_Stiching
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void cmdCombine_Click(object sender, EventArgs e)
{
//Change the path to location where your images are stored.
DirectoryInfo directory = new DirectoryInfo(#"C:\Users\Elder Zollinger\Desktop\Images");
if (directory != null)
{
FileInfo[] files = directory.GetFiles();
CombineImages(files);
}
}
private void CombineImages(FileInfo[] files)
{
//change the location to store the final image.
string finalImage = #"C:\Users\Elder Zollinger\Desktop\Images";
List<int> imageHeights = new List<int>();
int nIndex = 0;
int width = 0;
foreach (FileInfo file in files)
{
Image img = Image.FromFile(file.FullName);
imageHeights.Add(img.Height);
width += img.Width;
img.Dispose();
}
imageHeights.Sort();
int height = imageHeights[imageHeights.Count - 1];
Bitmap img3 = new Bitmap(width, height);
Graphics g = Graphics.FromImage(img3);
g.Clear(SystemColors.AppWorkspace);
foreach (FileInfo file in files)
{
Image img = Image.FromFile(file.FullName);
if (nIndex == 0)
{
g.DrawImage(img, new Point(0, 0));
nIndex++;
width = img.Width;
}
else
{
g.DrawImage(img, new Point(width, 0));
width += img.Width;
}
img.Dispose();
}
g.Dispose();
img3.Save(finalImage, System.Drawing.Imaging.ImageFormat.Jpeg);
img3.Dispose();
imageLocation.Image = Image.FromFile(finalImage);
}
}
}
That's likely GDI playing tricks on you.
You see, when GDI encounters an unknown file, it will quite likely cause an OutOfMemoryException. Since you're not filtering the input images at all, I'd expect that you're simply grabbing a non-image file (or an image type that GDI doesn't understand).
Oh, and a bit sideways - make sure you set JPEG quality when saving JPEGs - the default is something like 75, which is rather bad for a lot of images. And please, do use using - it's very handy to ensure proper and timely clean-up :)
Get more memory!
But seriously, you don't appear to be filtering out files that are not image files. There are some hidden files in folders that you may be trying to open as an image accidentally, such as "Thumbs.db". Make sure that the file is an image with something like if (Path.GetExtension(file.FullPath) != ".png") continue;.
Also, on objects that you are calling .Dispose() on, consider wrapping them in a using() instead. For example:
using(var img = Image.FromFile(file.FullPath))
{
// ...
}
Related
This question may sound familiar but i have searched internet and couldn't find a solution to it.
I know for printing we can use Crystal Report but i am discarding that idea because of it's certain disadvantages. Here are some of the disadvantages:-
Needs installation on PC and if the Visual Studio version is 2017 then you have to download 200MB+ setup.
If you have made certain objects like textobject and lines in one section and you have to add something in the middle of it then you have to manually set location of every object otherwise if you collectively select all the object and move it then their original location and the spacing between each object gets lost.
Currently i am using VS2008 and it has crystal report integrated in it which has a well know problem of sometime changing the text of every textobject and adding an "i" in it for some reason.
I also tried to download an alternate to crystal report. But its interface is not that friendly.
Alternate that i am choosing
Now i have designed my report on Windows Form. When i am trying to print, its quality is worse as compared to Crystal Reports print. Here is the code for it
private System.IO.Stream streamToPrint;
string streamType;
private void printDoc_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e)
{
System.Drawing.Image image = System.Drawing.Image.FromStream(this.streamToPrint);
int x = e.MarginBounds.X;
int y = e.MarginBounds.Y;
int width = image.Width;
int height = image.Height;
if ((width / e.MarginBounds.Width) > (height / e.MarginBounds.Height))
{
width = e.MarginBounds.Width;
height = image.Height * e.MarginBounds.Width / image.Width;
}
else
{
height = e.MarginBounds.Height;
width = image.Width * e.MarginBounds.Height / image.Height;
}
System.Drawing.Rectangle destRect = new System.Drawing.Rectangle(x, y, width, height);
e.Graphics.DrawImage(image, destRect, 0, 0, image.Width, image.Height, System.Drawing.GraphicsUnit.Pixel);
}
private void btnPrint_Click(object sender, EventArgs e)
{
string fileName = Application.StartupPath + "\\PrintPage.jpg";
using (Graphics gfx = this.CreateGraphics())
{
using (Bitmap bmp = new Bitmap(this.Width, this.Height, gfx))
{
this.DrawToBitmap(bmp, new Rectangle(0, 0, this.Width, this.Height));
bmp.Save(fileName);
}
}
FileStream fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read);
StartPrint(fileStream, "Image");
fileStream.Close();
if (System.IO.File.Exists(fileName))
{
System.IO.File.Delete(fileName);
}
}
public void StartPrint(Stream streamToPrint, string streamType)
{
this.printDoc.PrintPage += new PrintPageEventHandler(printDoc_PrintPage);
this.streamToPrint = streamToPrint;
this.streamType = streamType;
System.Windows.Forms.PrintDialog PrintDialog1 = new PrintDialog();
PrintDialog1.AllowSomePages = true;
PrintDialog1.ShowHelp = true;
PrintDialog1.Document = printDoc;
DialogResult result = PrintDialog1.ShowDialog();
if (result == DialogResult.OK)
{
printDoc.Print();
//docToPrint.Print();
}
}
private void Frm_Test_Shown(object sender, EventArgs e)
{
try
{
btnPrint_Click(sender, e);
}
catch (Exception ex) { clsUtility.ShowErrMsg(ex.Message); }
}
I understand the reason why it is doing so because of the image and screen resolution thing (Ref : https://stackoverflow.com/a/12547806/2994869). The workaround people mentioned was to increase the size of windows form and it's object by 6 times but that had the same result still the quality is worse.
Is there any workaround or any trick that i can do to print a windows form so that quality is near to that of Crystal Report's.
For high quality you need to create a source with higher resolution than the screen, which is all you can get from DrawToBitmap.
Using DrawToBitmap will only help if you can enlarge a single control a lot. For the whole form it will not help.
You will need to fully re-create the parts you want to print and use as many DrawString and other DrawXXX methods as needed. Yes, a lot of work. (But fun ;-)
But the code you show also blunders by using a jpg file format, which was created for soft images (i.e. photographs). Change that to png and compare!
This is the code i'm using now:
int imagescount = 0;
private void SaveImageFromWebBrowser()
{
Bitmap bitmap = new Bitmap(webBrowser1.Width, webBrowser1.Height);
webBrowser1.DrawToBitmap(bitmap, new Rectangle(0, 0, webBrowser1.Width, webBrowser1.Height));
bitmap.Save(#"e:\webbrowserimages\wbImage" + imagescount.ToString("D6") + ".bmp",
System.Drawing.Imaging.ImageFormat.Bmp);
bitmap.Dispose();
imagescount++;
}
The problem is some images are larger and then there are scrollbars other images smaller so the webbroswer not need the scrollbars.
But the large images with the scrollbars the image on the hard disk i see the whole webbroswer control with the scrollbars !
I want to get the whole image in the WebBbrowser control. Only the image to save not the whole control !
First you need to add a reference to your project called: Microsoft.mshtml
Then:
int imagescount = 0;
private void SaveImageFromWebBrowser()
{
IHTMLDocument2 doc = (IHTMLDocument2)webBrowser1.Document.DomDocument;
IHTMLControlRange imgRange = (IHTMLControlRange)((HTMLBody)doc.body).createControlRange();
foreach (IHTMLImgElement img in doc.images)
{
imgRange.add((IHTMLControlElement)img);
imgRange.execCommand("Copy", false, null);
using (Bitmap bmp = (Bitmap)Clipboard.GetDataObject().GetData(DataFormats.Bitmap))
{
bmp.Save(#"e:\webbrowserimages\Image" + imagescount.ToString("D6") + ".bmp",
System.Drawing.Imaging.ImageFormat.Bmp);
}
imagescount++;
}
}
Working perfect.
I am trying to port my app in windows phone . i have to upload an image on server So it is in small Size For uploading i have done this thing in Widows Successfully but problem is when i failed in it .. here is my code for windows App
public void CompressImage(int i, int j)
{
bmp1.SetPixel(j, i, Color.FromArgb(bmp.GetPixel(j, i).R, bmp.GetPixel(j, i).G, bmp.GetPixel(j, i).B));
}
private void bLoadImage_Click(object sender, EventArgs e)
{
OpenFileDialog file = new OpenFileDialog();
if (file.ShowDialog() == DialogResult.OK)
{
pictureBox1.Image = new Bitmap(file.FileName);
}
}
private void bCompression_Click(object sender, EventArgs e)
{
bmp = new Bitmap(pictureBox1.Image);
bmp1 = new Bitmap(bmp.Width, bmp.Height);
for (int i = 1; i < bmp.Height; i++)
for (int j = 1; j < bmp.Width; j++)
{
CompressImage(i, j);
}
pictureBox2.Image = bmp1;
bmp1.Save("Picture.jpeg", System.Drawing.Imaging.ImageFormat.Jpeg);
}
After Searching on google i found out that windows Phone does not support Bitmap .. any idea how i can do the same thing in windows phone or any other alternative for doing this
You should use WriteablBitmap to reduce size of image. WriteablBitmap has number of methods for images in windows phone Here is more about writeablebitmapex.
Try to load your original image to WriteableBitmap object, then you can use SaveJpeg() extension method from System.Windows.Media.Imaging namespace, to save new image with reduced size. For example :
.......
WriteableBitmap wb = new WriteableBitmap(bitmapImageObject);
wb.SaveJpeg(stream, 120, 160, 0, 100);
.......
When you are taking picture you can choose the resolution with which the picture will be taken. This can be done by
PhotoCamera cam;
After camera initizalition.
Following code when image is capturing (in the method that captures the image)
IEnumerable<Size> resList = cam.AvailableResolutions;
Size res;
if (resList.Count() > 0)
{
res = resList.ElementAt<Size>(0);
cam.Resolution = res;
}
This sample chooses the first resolution
You can try this. It worked for me. It reduced my 9.70MB file into 270KB.
WriteableBitmap cameraCapturedImage = PictureDecoder.DecodeJpeg(e.ChosenPhoto, 1024, 1024);
using (IsolatedStorageFileStream myFileStream = myStore.CreateFile(fileName))
{
System.Windows.Media.Imaging.Extensions.SaveJpeg(cameraCapturedImage, myFileStream, cameraCapturedImage.PixelWidth, cameraCapturedImage.PixelHeight, 0, 85);
myFileStream.Close();
}
N.B: fileName is the name of file to save size reduced image.
I've got an image upload page that works just fine when I only upload the files.
I added a 'Create Thumbnail' function. It looks like the file system has a handle on the images when the thumbnail process starts.
I get the 'unspecified GDI+ error' only when the image is over about 250K. When the files are below 250K, thumbnails are created as expected.
What are my options? Is there an elegant solution here? I want something not hacky.
Also, I am using HttpFileCollection so we can upload multiple images at one time. I've tried to use .Dispose on the Thumbnail creation, but it fails before we get to this point.
public void Upload_Click(object Sender, EventArgs e)
{
string directory = Server.MapPath(#"~\images\");
HttpFileCollection hfc = Request.Files;
for (int i = 0; i < hfc.Count; i++)
{
HttpPostedFile hpf = hfc[i];
if (hpf.ContentLength > 0)
{
string fileName = hpf.FileName;
fileName = fileName.Replace(" ", "");
hpf.SaveAs(fileName);
createThumbnail(fileName);
}
}
}
private void createThumbnail(string filename)
{
Image image = Image.FromFile(filename);
Image thumb = image.GetThumbnailImage(100,100, () => false, IntPtr.Zero);
thumb.Save(filename);
image.Dispose();
thumb.Dispose();
}
Please let me know if this works any better:
public string ImageDirectory { get { return Server.MapPath(#"~\images\"); } }
public void OnUploadClick(object sender, EventArgs e)
{
var files = HttpContext.Request.Files.AllKeys.AsEnumerable()
.Select(k =>HttpContext.Request.Files[k]);
foreach(var file in files)
{
if(file.ContentLength <= 0)
continue;
string savePath = GetFullSavePath(file);
var dimensions = new Size(100, 100);
CreateThumbnail(file,savePath,dimensions);
}
}
private void CreateThumbnail(HttpPostedFile file,string savePath, Size dimensions)
{
using (var image = Image.FromStream(file.InputStream))
{
using (var thumb = image.GetThumbnailImage(dimensions.Width, dimensions.Height, () => false, IntPtr.Zero))
{
thumb.Save(savePath);
}
}
}
private string GetFullSavePath(HttpPostedFile file)
{
string fileName = System.IO.Path.GetFileName(file.FileName).Replace(" ", "");
string savePath = System.IO.Path.Combine(this.ImageDirectory, fileName);
return savePath;
}
Edit -
The foreach should have followed more to this pattern:
var files = HttpContext.Request.Files.AllKeys.AsEnumerable()
.Select(k =>HttpContext.Request.Files[k]);
foreach(var file in files)
{
}
You can try this code to create your thumbnails.
MemoryStream ms = new MemoryStream(File.ReadAllBytes(path));
Bitmap originalBMP = new Bitmap(ms);
int maxWidth = 200;
int maxHeight = 200;
// Calculate the new image dimensions
int origWidth = originalBMP.Width;
int origHeight = originalBMP.Height;
double sngRatio = Convert.ToDouble(origWidth) / Convert.ToDouble(origHeight);
// New dimensions
int newWidth = 0;
int newHeight = 0;
try
{
// max 200 by 200
if ((origWidth <= maxWidth && origHeight <= maxHeight) || origWidth <= maxWidth)
{
newWidth = origWidth;
newHeight = origHeight;
}
else
{
// Width longer (shrink width)
newWidth = 200;
newHeight = Convert.ToInt32(Convert.ToDouble(newWidth) / sngRatio);
}
// Create a new bitmap which will hold the previous resized bitmap
Bitmap newBMP = new Bitmap(originalBMP, newWidth, newHeight);
// Create a graphic based on the new bitmap
Graphics oGraphics = Graphics.FromImage(newBMP);
// Set the properties for the new graphic file
oGraphics.SmoothingMode = SmoothingMode.AntiAlias;
oGraphics.InterpolationMode = InterpolationMode.High;
// Draw the new graphic based on the resized bitmap
oGraphics.CompositingQuality = CompositingQuality.HighSpeed;
oGraphics.DrawImage(originalBMP, 0, 0, newWidth, newHeight);
// Save the new graphic file to the server
EncoderParameters p = new EncoderParameters(1);
p.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Compression, 70); // Percent Compression
MemoryStream savedBmp = new MemoryStream();
newBMP.Save(savedBmp, ImageCodecInfo.GetImageEncoders()[1], p);
// Once finished with the bitmap objects, we deallocate them.
originalBMP.Dispose();
newBMP.Dispose();
oGraphics.Dispose();
savedBmp.Dispose();
Certainly a bit more work but it does give you greater control.
I'm writing a CSS sprite engine in C#, however I'm having a few issues. I create the master image, set all the properties to that then iterate the sprites and draw those to the master image. However when I come to save the master image it only appears to be just the empty master image with transparent background and none of the sprites. I'm very confused at where I'm going wrong.
The code I'm using is:
// Work out the width/height required
int max_width = 0;
int max_height = 0;
foreach(SpriteInformation sprite in sprites) {
if (max_width < (sprite.Left + greatest_width)) max_width = sprite.Left + greatest_width;
if (max_height < (sprite.Top + greatest_height)) max_height = sprite.Top + greatest_height;
}
// Create new master bitmap
Bitmap bitmap = new Bitmap(max_width,max_height,PixelFormat.Format32bppArgb);
Graphics graphics = Graphics.FromImage(bitmap);
// Set background color
SolidBrush brush;
if (cbxBackground.Checked) {
if (txtColor.Text == "") {
brush = new SolidBrush(Color.Black);
} else {
brush = new SolidBrush(pnlColor.BackColor);
}
} else {
if (txtColor.Text == "") {
brush = new SolidBrush(Color.White);
} else {
brush = new SolidBrush(pnlColor.BackColor);
}
}
//graphics.FillRectangle(brush,0,0,bitmap.Width,bitmap.Height);
bitmap.MakeTransparent(brush.Color);
graphics.Clear(brush.Color);
// Copy images into place
ImageAttributes attr = new ImageAttributes();
//attr.SetColorKey(brush.Color,brush.Color);
foreach(SpriteInformation sprite in sprites) {
Rectangle source = new Rectangle(0,0,sprite.Width,sprite.Height);
Rectangle dest = new Rectangle(sprite.Left,sprite.Top,sprite.Width,sprite.Height);
graphics.DrawImage(sprite.Sprite,dest,0,0,sprite.Width,sprite.Height,GraphicsUnit.Pixel,attr);
}
// Save image
string format = ddlFormat.Items[ddlFormat.SelectedIndex].ToString();
if (format == "PNG") {
dlgSave.Filter = "PNG Images|*.png|All Files|*.*";
dlgSave.DefaultExt = ",png";
if (dlgSave.ShowDialog() == DialogResult.OK) {
bitmap.Save(dlgSave.FileName,ImageFormat.Png);
}
} else if (format == "JPEG") {
} else {
}
What are sprite.Left and Top? If they aren't 0 that may be a problem. I think you have dest and source the wrong way round?
http://msdn.microsoft.com/en-us/library/ms142045.aspx
Try a simpler DrawImage variant if you haven't already.
e.g. DrawImage(sprite.Sprite,0,0)
You draw to "graphics", but then then you save "bitmap"? I'm not sure if that graphics internally works with your original "bitmap" object...