I have this method in FileUtility Class to save my images.
public static void SaveImage(System.IO.Stream file, string savePath, Size size, bool enforceRatio, bool testReverse = false)
{
var image = Image.FromStream(file);
var imageEncoders = ImageCodecInfo.GetImageEncoders();
int enc = Path.GetExtension(savePath).ToLower().Contains("png") ? 4 : 1;
EncoderParameters encoderParameters = new EncoderParameters(1);
encoderParameters.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 90L);
Size s = new Size(size.Width, size.Height);
if (testReverse)
{
if (image.Width <= image.Height)
{
if (size.Width <= size.Height)
{
s.Width = size.Width;
s.Height = size.Height;
}
else
{
s.Width = size.Height;
s.Height = size.Width;
}
}
else
{
if (size.Width <= size.Height)
{
s.Width = size.Height;
s.Height = size.Width;
}
else
{
s.Width = size.Width;
s.Height = size.Height;
}
}
}
var canvasWidth = s.Width;
var canvasHeight = s.Height;
var newImageWidth = s.Width;
var newImageHeight = s.Height;
var xPosition = 0;
var yPosition = 0;
if (enforceRatio)
{
var ratioX = s.Width / (double)image.Width;
var ratioY = s.Height / (double)image.Height;
var ratio = ratioX < ratioY ? ratioX : ratioY;
newImageHeight = (int)(image.Height * ratio);
newImageWidth = (int)(image.Width * ratio);
}
var thumbnail = new Bitmap(canvasWidth, canvasHeight);
var graphic = Graphics.FromImage(thumbnail);
if (enforceRatio)
{
graphic.Clear(Color.White);
}
graphic.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphic.SmoothingMode = SmoothingMode.HighQuality;
graphic.PixelOffsetMode = PixelOffsetMode.HighQuality;
graphic.CompositingQuality = CompositingQuality.HighQuality;
graphic.DrawImage(image, xPosition, yPosition, newImageWidth, newImageHeight);
thumbnail.Save(savePath, imageEncoders[enc], encoderParameters);
}
It work well. But for some images files (not every file) I get
Argument Exception : Parameter is not valid
in first line var image = Image.FromStream(file);
I call method like this:
FileUtility.SaveImage(add2.IconSquare.InputStream, Server.MapPath(program.IconSquare), new System.Drawing.Size { Width = 250, Height = 250 }, false);
That add2.IconSquare is a HttpPostedFileBase
public HttpPostedFileBase IconSquare { get; set; }
The only thing is that add2 come from another action with TempData.
var add2 = TempData["Create_Step2"] as AddStep2;
I mean I take files from user in Action Create_Step2 and save them in TempData then I try to save them in Action Create_Step3. Can anyone tell me what I doing wrong?
Related
We are resizing the image and we are facing a issue.Only portion of image is getting resized and we are using below code.
public Bitmap ScaleImage(Bitmap image, int maxWidth, int maxHeight)
{
var ratioX = (double)maxWidth / image.Width;
var ratioY = (double)maxHeight / image.Height;
var ratio = 1.0;
if (maxWidth == 0)
{
ratio = ratioY;
}
else if (maxHeight == 0)
{
ratio = ratioX;
}
else
{
ratio = Math.Min(ratioX, ratioY);
}
var newWidth = (int)(image.Width * ratio);
var newHeight = (int)(image.Height * ratio);
Graphics graphicsObj;
var newImage = new Bitmap(newWidth, newHeight, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
//var newImage = new Bitmap(newWidth, newHeight);
graphicsObj = Graphics.FromImage(newImage);
graphicsObj.Clear(Color.White);
Graphics.FromImage(newImage).DrawImage(image, 0, 0, newWidth, newHeight);
return newImage;
}
Please follow this link for example.
I want to reduce image size and save reduced image to my image folder. Following is what I have done to save image but problem is reduce image is not saved into my image folder.
HOW TO SAVE reduced IMAGE IN MY IMAGE FOLDER IN MVC4..?
Below is my code to save the image:
public ActionResult AddProduct(TblProduct ObjProducts)
{
HttpPostedFileBase File = Request.Files[0];
if (ModelState.IsValid) {
string filename = Path.GetFileName(File.FileName);
string targetPath = Server.MapPath("Images/" + filename);
///save file
string oldImage = File.FileName;
string NewFileName = ObjProducts.ManualP_Id + ".JPG";
string pic = System.IO.Path.GetFileName(NewFileName);
string path = System.IO.Path.Combine(Server.MapPath("~/Images/ProductImg"), NewFileName);
File.SaveAs(path);
ObjProducts.Image =NewFileName;
ObjProducts.IsActive = true;
ObjProducts.IsDelete = false;
ObjProducts.CreatedDate = DateTime.Now;
db.TblProducts.Add(ObjProducts);
db.SaveChanges();
return RedirectToAction("DisplayProduct", "PanelProduct");
}
return View();
}
try this
Image img = Image.FromStream(httpPostedFileBase.InputStream, true, true);
var bitmap = new Bitmap(newWidth,newHeight);
using (Graphics g = Graphics.FromImage(bitmap)) {
g.SmoothingMode = SmoothingMode.HighQuality;
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
g.CompositingQuality = CompositingQuality.HighQuality;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.DrawImage(img,
new Rectangle(0,0,newWidth,newHeight),
clipRectangle, GraphicsUnit.Pixel);
}
bitmap.Save(path,ImageFormat.Jpeg);
you can use below function to scale and compress your image to the desired resolution:
int Height = 600;
int Width = 800;
private Image Scale(Image imgPhoto)
{
float sourceWidth = imgPhoto.Width;
float sourceHeight = imgPhoto.Height;
float destHeight = 0;
float destWidth = 0;
int sourceX = 0;
int sourceY = 0;
int destX = 0;
int destY = 0;
// force resize, might distort image
if (Width != 0 && Height != 0)
{
destWidth = Width;
destHeight = Height;
}
// change size proportially depending on width or height
else if (Height != 0)
{
destWidth = (float)(Height * sourceWidth) / sourceHeight;
destHeight = Height;
}
else
{
destWidth = Width;
destHeight = (float)(sourceHeight * Width / sourceWidth);
}
Bitmap bmPhoto = new Bitmap((int)destWidth, (int)destHeight,PixelFormat.Format32bppPArgb);
bmPhoto.SetResolution(imgPhoto.HorizontalResolution, imgPhoto.VerticalResolution);
Graphics grPhoto = Graphics.FromImage(bmPhoto);
grPhoto.InterpolationMode = InterpolationMode.HighQualityBicubic;
grPhoto.DrawImage(imgPhoto,new Rectangle(destX, destY, (int)destWidth, (int)destHeight),
new Rectangle(sourceX, sourceY, (int)sourceWidth, (int)sourceHeight),GraphicsUnit.Pixel);
grPhoto.Dispose();
return bmPhoto;
}
I have a routine that scans a folder for images, then for each image, converts it to a thumbnail, and then uploads that thumbnail to a database. It will only run if there isn't any items for that particular folder in the db. My problem is I am receiving an out of memory exception after processing a couple of folders and I'm not sure where the leak is occurring. I have tried disposing of everything disposable that I can in the loop, but obviously something is still falling though the cracks.
private bool LoadImages(int folderid, int parentid) {
ProgressScreen tfrm = new ProgressScreen();
tfrm.Hide();
DataTable mtable = new DataTable();
List<FileInfo> lfile;
mtable = Requests.ProcessSQLCommand(sqlconn, "Select f.ID, f.FolderName,f.FolderPath,f.ParentID,f.Root from Folders f where f.ID = " + folderid);
DataTable ptable = Requests.ProcessSQLCommand(sqlconn, "Select Root from Folders where ID = " + parentid);
if (ptable != null && ptable.Rows.Count > 0) {
if (ptable.Rows[0]["Root"].ToString().ToLower() == "true") {
return false;
}
}
bool process = true;
DirectoryInfo di = new DirectoryInfo(mtable.Rows[0]["FolderPath"].ToString());
FileInfo[] smFiles = di.GetFiles("*.jpg", SearchOption.TopDirectoryOnly);
lfile = smFiles.ToList<FileInfo>();
if (lfile.Count <= 0) {
process = false;
}
if (process) {
tfrm.Show(this);
for (int c = 0; c < lfile.Count; c++) {
if (((FileInfo)lfile[c]).Extension == ".txt") {
lfile.RemoveAt(c);
}
if (((FileInfo)lfile[c]).FullName.ToLower().Contains("cover")) {
lfile.RemoveAt(c);
}
}
for (int b = 0; b < lfile.Count; b++) {
Cursor.Current = Cursors.WaitCursor;
this.Enabled = false;
try {
tfrm.Location = new Point((Screen.PrimaryScreen.WorkingArea.Width / 2) - (tfrm.Width / 2), (Screen.PrimaryScreen.WorkingArea.Height / 2) - (tfrm.Height / 2));
} catch {
}
tfrm.SetProgress((int)(((double)(b + 1) / (double)lfile.Count) * 100), "Loading Images", lfile[b].Name.ToString());
tfrm.Refresh();
int recid = 0;
DataTable ttable = Requests.ProcessSQLCommand(sqlconn, "Insert into Image (Name,FolderID,ParentID) VALUES ('" + lfile[b].Name + "'," + folderid + "," + parentid + ") Select SCOPE_IDENTITY()");
if (ttable != null && ttable.Rows.Count > 0) {
recid = int.Parse(ttable.Rows[0][0].ToString());
}
if (recid > 0) {
Image timg = null;
byte[] traw = new byte[0];
traw = File.ReadAllBytes(lfile[b].FullName);
MemoryStream tstream = new MemoryStream(traw);
timg = System.Drawing.Image.FromStream(tstream);
tstream.Dispose();
timg = Requests.FixedSize(timg, 600, 600);
tstream = new MemoryStream();
timg.Save(tstream, System.Drawing.Imaging.ImageFormat.Png);
timg.Dispose();
traw = new byte[0];
traw = tstream.ToArray();
tstream.Dispose();
System.Data.SqlClient.SqlConnection con = new System.Data.SqlClient.SqlConnection(sqlconn);
con.Open();
System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand("Update Image set [Thumb] = Convert(VarBinary(MAX),#Image) where ID = " + recid, con);
cmd.Parameters.AddWithValue("#Image", traw);
cmd.ExecuteNonQuery();
con.Dispose();
}
}
this.Enabled = true;
Cursor.Current = Cursors.Default;
tfrm.Close();
tfrm.Dispose();
System.Windows.Forms.Application.UseWaitCursor = false;
return true;
} else {
return false;
}
}
the Fixed size method:
public static Image FixedSize(Image imgPhoto, int Width, int Height) {
int sourceWidth = imgPhoto.Width;
int sourceHeight = imgPhoto.Height;
int sourceX = 0;
int sourceY = 0;
int destX = 0;
int destY = 0;
float nPercent = 0;
float nPercentW = 0;
float nPercentH = 0;
nPercentW = ((float)Width / (float)sourceWidth);
nPercentH = ((float)Height / (float)sourceHeight);
if (nPercentH < nPercentW) {
nPercent = nPercentH;
destX = System.Convert.ToInt16((Width - (sourceWidth * nPercent)) / 2);
} else {
nPercent = nPercentW;
destY = System.Convert.ToInt16((Height - (sourceHeight * nPercent)) / 2);
}
int destWidth = (int)(sourceWidth * nPercent);
int destHeight = (int)(sourceHeight * nPercent);
Bitmap bmPhoto = new Bitmap(Width, Height, PixelFormat.Format24bppRgb);
bmPhoto.SetResolution(imgPhoto.HorizontalResolution, imgPhoto.VerticalResolution);
Graphics grPhoto = Graphics.FromImage(bmPhoto);
grPhoto.Clear(Color.Magenta);
grPhoto.InterpolationMode = InterpolationMode.HighQualityBicubic;
grPhoto.DrawImage(imgPhoto, new Rectangle(destX, destY, destWidth, destHeight), new Rectangle(sourceX, sourceY, sourceWidth, sourceHeight), GraphicsUnit.Pixel);
grPhoto.Dispose();
return bmPhoto;
}
the original images (before fixed size) range anywhere from 2MB to 20MB, the image returned (max(len(image)) in the table is around 750 KB. (Edit: Corrected files sizes)
Number of images per folder ~100-150
I've looked and debugged, but cannot find what is causing the OOM issues, could someone point me at the error, or offer a better optimization for what I am doing?
If this was a code review, there would be many things I'd suggest as improvements in this code...
But anyway, specifically to your question.. you memory leak is in following lines of code (please don't take it personally, but it was hard to spot, because the code is not as clean)
timg = System.Drawing.Image.FromStream(tstream);
tstream.Dispose();
timg = Requests.FixedSize(timg, 600, 600);
....
timg.Dispose();
You have 2 timg here.. one is original, and the second one is the one you get back from Requests.FixedSize. The timg you passed to Requests.FixedSize does not get disposed.
I'm resizing an image using the following code:
private void ResizeImage(string path)
{
var maxWidth = 700;
var ms = new MemoryStream(System.IO.File.ReadAllBytes(Server.MapPath(path)));
var imgToResize = Bitmap.FromStream(ms);
var sourceWidth = imgToResize.Width;
var sourceHeight = imgToResize.Height;
if (sourceWidth > maxWidth)
{
var nPercent = ((float)maxWidth / (float)sourceWidth);
var newWidth = (int)(sourceWidth * nPercent);
var newHeight = (int)(sourceHeight * nPercent);
var newImage = new Bitmap(newWidth, newHeight, PixelFormat.Format24bppRgb);
using (Graphics graphics = Graphics.FromImage(newImage))
{
graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.DrawImage(imgToResize, 0, 0, newWidth, newHeight);
}
imgToResize.Dispose();
var codecInfo = this.GetEncoderInfo(ImageFormat.Jpeg);
var encoder = System.Drawing.Imaging.Encoder.Quality;
var encParams = new EncoderParameters(1);
var encParam = new EncoderParameter(encoder, 60);
encParams.Param[0] = encParam;
newImage.Save(Server.MapPath(path), codecInfo, encParams);
}
}
private ImageCodecInfo GetEncoderInfo(ImageFormat format)
{
return ImageCodecInfo.GetImageDecoders().SingleOrDefault(c => c.FormatID == format.Guid);
}
at the last line [newImage.Save(...)] it throws an exception saying Parameter is not valid.
what exactly is wrong here ?
Your new EncoderParameter(encoder, 60); does not work properly. There is no signature with a single Int32. Use 60L instead.
This question already has answers here:
Closed 13 years ago.
Possible Duplicate:
Resize an Image C#
How can I programmatically resize an image in C# so that it'll fit in a winforms control?
Scaling an image into a PictureBox:
class ImageHandling
{
public static Rectangle GetScaledRectangle(Image img, Rectangle thumbRect)
{
if (img.Width < thumbRect.Width && img.Height < thumbRect.Height)
return new Rectangle(thumbRect.X + ((thumbRect.Width - img.Width) / 2), thumbRect.Y + ((thumbRect.Height - img.Height) / 2), img.Width, img.Height);
int sourceWidth = img.Width;
int sourceHeight = img.Height;
float nPercent = 0;
float nPercentW = 0;
float nPercentH = 0;
nPercentW = ((float)thumbRect.Width / (float)sourceWidth);
nPercentH = ((float)thumbRect.Height / (float)sourceHeight);
if (nPercentH < nPercentW)
nPercent = nPercentH;
else
nPercent = nPercentW;
int destWidth = (int)(sourceWidth * nPercent);
int destHeight = (int)(sourceHeight * nPercent);
if (destWidth.Equals(0))
destWidth = 1;
if (destHeight.Equals(0))
destHeight = 1;
Rectangle retRect = new Rectangle(thumbRect.X, thumbRect.Y, destWidth, destHeight);
if (retRect.Height < thumbRect.Height)
retRect.Y = retRect.Y + Convert.ToInt32(((float)thumbRect.Height - (float)retRect.Height) / (float)2);
if (retRect.Width < thumbRect.Width)
retRect.X = retRect.X + Convert.ToInt32(((float)thumbRect.Width - (float)retRect.Width) / (float)2);
return retRect;
}
public static Image GetResizedImage(Image img, Rectangle rect)
{
Bitmap b = new Bitmap(rect.Width, rect.Height);
Graphics g = Graphics.FromImage((Image)b);
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.DrawImage(img, 0, 0, rect.Width, rect.Height);
g.Dispose();
try
{
return (Image)b.Clone();
}
finally
{
b.Dispose();
b = null;
g = null;
}
}
}
And how to use it:
Image img = Image.FromFile(imageFilePath);
Rectangle newRect = GetScaledRectangle(img, pictureBox1.ClientRectangle);
pictureBox1.Image = ImageHandling.GetResizedImage(img, newRect);
Sacle and center an ImageBox:
private void LoadAndResizeImage(string sImagepath, int iMaxHeight, int iMaxWidth, int iMinX, int iMinY)
{
int wdt = iMaxWidth;
int hgt = iMaxHeight;
int partialX = iMinX;
int partialY = iMinY;
pictureBox1.ImageLocation = sImagepath;
if ((pictureBox1.Image.Height > iMaxHeight) || (pictureBox1.Image.Width > iMaxWidth))
{
if ((pictureBox1.Image.Width / iMaxWidth) > (pictureBox1.Image.Height / iMaxHeight))
{
wdt = iMaxWidth;
double ratio = (double)pictureBox1.Image.Height / (double)pictureBox1.Image.Width;
hgt = (int)(iMaxWidth * ratio);
}
else
{
hgt = iMaxHeight;
double ratio = (double)pictureBox1.Image.Width / (double)pictureBox1.Image.Height;
wdt = (int)(iMaxHeight * ratio);
}
}
else
{
hgt = pictureBox1.Image.Height;
wdt = pictureBox1.Image.Width;
}
if (wdt < iMaxWidth)
{
partialX = (iMaxWidth - wdt) / 2;
partialX += iMinX;
}
else
{
partialX = iMinX;
}
if (hgt < iMaxHeight)
{
partialY = (iMaxHeight - hgt) / 2;
partialY += iMinY;
}
else
{
partialY = iMinY;
}
//Set size
pictureBox1.Height = hgt;
pictureBox1.Width = wdt;
pictureBox1.Left = partialX;
pictureBox1.Top = partialY;
}