I'm using ASP.Net MVC 5 and I want to create an avatar for my user profiles. I'm not sure if what I'm doing so far is the right way, especially for security reasons so I wanted to get some advice.
What I'm doing so far
In View:
#using (Html.BeginForm("ManageUser", "Account", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<input type="file" name="file" />
<input type="submit" value="Add Avatar" />
}
In controller:
internal static bool SaveAvatar(User user, HttpPostedFileBase file)
{
if (file == null || file.ContentLength <= 0 || file.ContentLength > MAX_LENGTH)
return false;
//I think I should convert the file somehow instead of saving it
var path = HostingEnvironment.MapPath("~/img/avatar/") + string.Format("{0}.png", user.UserName);
file.SaveAs(path);
user.HasAvatar = true;
return true;
}
I have several concerns:
In the code above, as I commented, I think instead of just saving
what user has sent to me, I should somehow use a library to convert
the image to a PNG file and save it. If so, is there a good and simple library to do this?
I wonder whether using the user's name as a file would be good idea. After all, they choose this name and it is not something I decide.
Is it a good idea to use plain images or should I create a controller to validate requests or rout the requests to a hidden image?
If what I'm doing is TOTALLY wrong and you know a better source to learn the right way, please point me in the right direction. Thanks.
you can use this class for Upload a file to server :
public static class FileUpload
{
public static char DirSeparator = System.IO.Path.DirectorySeparatorChar;
public static string FilesPath = HttpContext.Current.Server.MapPath("~\\Content" + DirSeparator + "Uploads" + DirSeparator);
public static string UploadFile(HttpPostedFileBase file)
{
// Check if we have a file
if (null == file) return "";
// Make sure the file has content
if (!(file.ContentLength > 0)) return "";
string fileName =DateTime.Now.Millisecond+ file.FileName;
string fileExt = Path.GetExtension(file.FileName);
// Make sure we were able to determine a proper extension
if (null == fileExt) return "";
// Check if the directory we are saving to exists
if (!Directory.Exists(FilesPath))
{
// If it doesn't exist, create the directory
Directory.CreateDirectory(FilesPath);
}
// Set our full path for saving
string path = FilesPath + DirSeparator + fileName;
// Save our file
file.SaveAs(Path.GetFullPath(path));
// Save our thumbnail as well
ResizeImage(file, 70, 70);
// Return the filename
return fileName;
}
public static void DeleteFile(string fileName)
{
// Don't do anything if there is no name
if (fileName.Length == 0) return;
// Set our full path for deleting
string path = FilesPath + DirSeparator + fileName;
string thumbPath = FilesPath + DirSeparator + "Thumbnails" + DirSeparator + fileName;
RemoveFile(path);
RemoveFile(thumbPath);
}
private static void RemoveFile(string path)
{
// Check if our file exists
if (File.Exists(Path.GetFullPath(path)))
{
// Delete our file
File.Delete(Path.GetFullPath(path));
}
}
public static void ResizeImage(HttpPostedFileBase file, int width, int height)
{
string thumbnailDirectory = String.Format(#"{0}{1}{2}", FilesPath, DirSeparator, "Thumbnails");
// Check if the directory we are saving to exists
if (!Directory.Exists(thumbnailDirectory))
{
// If it doesn't exist, create the directory
Directory.CreateDirectory(thumbnailDirectory);
}
// Final path we will save our thumbnail
string imagePath = String.Format(#"{0}{1}{2}", thumbnailDirectory, DirSeparator, file.FileName);
// Create a stream to save the file to when we're done resizing
FileStream stream = new FileStream(Path.GetFullPath(imagePath), FileMode.OpenOrCreate);
// Convert our uploaded file to an image
Image OrigImage = Image.FromStream(file.InputStream);
// Create a new bitmap with the size of our thumbnail
Bitmap TempBitmap = new Bitmap(width, height);
// Create a new image that contains are quality information
Graphics NewImage = Graphics.FromImage(TempBitmap);
NewImage.CompositingQuality = CompositingQuality.HighQuality;
NewImage.SmoothingMode = SmoothingMode.HighQuality;
NewImage.InterpolationMode = InterpolationMode.HighQualityBicubic;
// Create a rectangle and draw the image
Rectangle imageRectangle = new Rectangle(0, 0, width, height);
NewImage.DrawImage(OrigImage, imageRectangle);
// Save the final file
TempBitmap.Save(stream, OrigImage.RawFormat);
// Clean up the resources
NewImage.Dispose();
TempBitmap.Dispose();
OrigImage.Dispose();
stream.Close();
stream.Dispose();
}
}
you can also save the thumbnail of their photos using ResizeImage method and In the controller I'll save file name in the database this way:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(User user, HttpPostedFileBase file)
{
// TODO: Add insert logic here
user.Pictuer = FileUpload.UploadFile(file);
db.User.Add(user);
db.SaveChanges();
return RedirectToAction("Index");
}
also for convert uploaded images you can use this code inside UploadFile method :
System.Drawing.Image image1 = System.Drawing.Image.FromFile(#"C:\test.bmp");
// Save the image in JPEG format.
image1.Save(#"C:\test.jpg", System.Drawing.Imaging.ImageFormat.Jpeg);
// Save the image in GIF format.
image1.Save(#"C:\test.gif", System.Drawing.Imaging.ImageFormat.Gif);
// Save the image in PNG format.
image1.Save(#"C:\test.png", System.Drawing.Imaging.ImageFormat.Png);
I found this post very helpful and I wanted to share my implementation of Sirwan Afifi's excellent answer. I needed the resize function to take and return an image so it's a little different. However I've also added a boolean to preserve the aspect ratio of an image if you want.
public static Image ResizeImage(Image img, int width, int height, bool preserveAspectRatio = false)
{
int newWidth;
int newHeight;
if (preserveAspectRatio)
{
int originalWidth = img.Width;
int originalHeight = img.Height;
float percentWidth = (float)width / (float)originalWidth;
float percentHeight = (float)height / (float)originalHeight;
float percent = percentHeight < percentWidth ? percentHeight : percentWidth;
//Rounding to get the set width to the exact pixel
newWidth = (float)originalWidth * percent < (float)width ? (int)(Math.Ceiling((float)originalWidth * percent)) : (int)((float)originalWidth * percent);
//Rounding to get the set height to the exact pixel
newHeight = (float)originalHeight * percent < (float)height ? (int)(Math.Ceiling((float)originalHeight * percent)) : (int)((float)originalHeight * percent);
}
else
{
newWidth = width;
newHeight = height;
}
// Create a new bitmap with the size
Bitmap TempBitmap = new Bitmap(newWidth, newHeight);
// Create a new image that contains are quality information
Graphics NewImage = Graphics.FromImage(TempBitmap);
NewImage.CompositingQuality = CompositingQuality.HighQuality;
NewImage.SmoothingMode = SmoothingMode.HighQuality;
NewImage.InterpolationMode = InterpolationMode.HighQualityBicubic;
// Create a rectangle and draw the image
Rectangle imageRectangle = new Rectangle(0, 0, newWidth, newHeight);
NewImage.DrawImage(img, imageRectangle);
return TempBitmap;
}
Related
I'm trying to minify image from url, my code is this
public static string GetBreaker(string fileName)
{
string cacheBreaker = null;
try
{
if (fileName.StartsWith("~"))
{
fileName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, fileName.Remove(0));
}
cacheBreaker = File.GetLastWriteTime(fileName).ToFileTime().ToString();
}
catch { }
return string.IsNullOrEmpty(cacheBreaker) ? string.Empty : string.Format("?cachebreaker={0}", cacheBreaker);
}
public static void SaveJpeg(string path, System.Drawing.Image img, int quality)
{
if (quality < 0 || quality > 100)
throw new ArgumentOutOfRangeException("quality must be between 0 and 100.");
EncoderParameter qualityParam =
new EncoderParameter(Encoder.Quality, quality);
ImageCodecInfo jpegCodec = GetEncoderInfo("image/jpeg");
EncoderParameters encoderParams = new EncoderParameters(1);
encoderParams.Param[0] = qualityParam;
img.Save(path, jpegCodec, encoderParams);
}
private static ImageCodecInfo GetEncoderInfo(string mimeType)
{
ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders();
for (int i = 0; i < codecs.Length; i++)
if (codecs[i].MimeType == mimeType)
return codecs[i];
return null;
}
protected void Button1_Click(object sender, EventArgs e)
{
System.Drawing.Image myImage = System.Drawing.Image.FromFile(ImageUrltxt.Text.ToString());
SaveJpeg(#"~/mintemp/demo.jpg", myImage, 50);
}
I'm getting error like this:
URI formats are not supported.
in
System.Drawing.Image myImage = System.Drawing.Image.FromFile(ImageUrltxt.Text.ToString());
Can anyone help me to solve out this problem. I'm very new to programming. Thanks in advance, sorry for my bad English.
1. First you have to check out your uri path is correct or not eg:
string uriPath = "file:\\C:\\Users\\john\\documents\\visual studio 2010\\Projects\\proj";
or
string localPath = new Uri(uriPath).LocalPath;
2. You have to add the uri of the image as correct Please check your uri path of image is correct.
SaveJpeg(#"~/mintemp/demo.jpg", myImage, 50);
3. This is coded in c# (for reference) resizing and compressing of image in c#
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
private Boolean CheckFileType(String fileName)
{
String ext = Path.GetExtension(fileName) ;
switch (ext.ToLower())
{
case ".gif":
return true;
case ".png":
return true;
case ".jpg":
return true;
case ".jpeg":
return true;
case ".bmp":
return true;
default:
return false;
}
}
protected void Button1_Click(object sender, EventArgs e)
{
const int bmpW = 300;// //New image target width
const int bmpH = 226;// //New Image target height
if (FileUpload1.HasFile)
{
//Clear the error label text
lblError.Text = "";
//Check to make sure the file to upload has a picture file format extention
//and set the target width and height
if (this.CheckFileType(FileUpload1.FileName))
{
Int32 newWidth = bmpW;
Int32 newHeight = bmpH;
//Use the uploaded filename for saving without the "." extension
String upName = FileUpload1.FileName.Substring(0, FileUpload1.FileName.IndexOf("."));
//Mid(FileUpload1.FileName, 1, (InStr(FileUpload1.FileName, ".") - 1)) ;
//Set the save path of the resized image, you will need this directory already created in your web site
String filePath = "~/Upload/" + upName + ".jpg";
//Create a new Bitmap using the uploaded picture as a Stream
//Set the new bitmap resolution to 72 pixels per inch
Bitmap upBmp = (Bitmap)Bitmap.FromStream(FileUpload1.PostedFile.InputStream);
Bitmap newBmp = new Bitmap(newWidth, newHeight, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
newBmp.SetResolution(72, 72);
//Get the uploaded image width and height
Int32 upWidth = upBmp.Width;
Int32 upHeight = upBmp.Height;
Int32 newX = 0; //Set the new top left drawing position on the image canvas
Int32 newY = 0;
Decimal reDuce;
//Keep the aspect ratio of image the same if not 4:3 and work out the newX and newY positions
//to ensure the image is always in the centre of the canvas vertically and horizontally
if (upWidth > upHeight)
{
//Landscape picture
reDuce = newWidth / upWidth;
//calculate the width percentage reduction as decimal
newHeight = ((Int32)(upHeight * reDuce));
//reduce the uploaded image height by the reduce amount
newY = ((Int32)((bmpH - newHeight) / 2));
//Position the image centrally down the canvas
newX = 0; //Picture will be full width
}
else
{
if (upWidth < upHeight)
{
//Portrait picture
reDuce = newHeight / upHeight;
//calculate the height percentage reduction as decimal
newWidth = ((Int32)(upWidth * reDuce));
//reduce the uploaded image height by the reduce amount
newX = ((Int32)((bmpW - newWidth) / 2));
//Position the image centrally across the canvas
newY = 0; //Picture will be full hieght
}
else
{
if (upWidth == upHeight)
{
//square picture
reDuce = newHeight / upHeight;
//calculate the height percentage reduction as decimal
newWidth = ((Int32)((upWidth * reDuce)));
//reduce the uploaded image height by the reduce amount
newX = ((Int32)(((bmpW - newWidth) / 2))); //Position the image centrally across the canvas
newY = ((Int32)(((bmpH - newHeight) / 2))); //Position the image centrally down the canvas
}
}
}
//Create a new image from the uploaded picture using the Graphics class
//Clear the graphic and set the background colour to white
//Use Antialias and High Quality Bicubic to maintain a good quality picture
//Save the new bitmap image using //Png// picture format and the calculated canvas positioning
Graphics newGraphic = Graphics.FromImage(newBmp);
try
{
newGraphic.Clear(Color.White);
newGraphic.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
newGraphic.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
newGraphic.DrawImage(upBmp, newX, newY, newWidth, newHeight);
newBmp.Save(MapPath(filePath), System.Drawing.Imaging.ImageFormat.Jpeg);
//Show the uploaded resized picture in the image control
Image1.ImageUrl = filePath;
Image1.Visible = true;
}
catch (Exception ex)
{
lblError.Text = ex.ToString();
throw ex;
}
finally
{
upBmp.Dispose();
newBmp.Dispose();
newGraphic.Dispose();
}
}
else
{
lblError.Text = "Please select a picture with a file format extension of either Bmp, Jpg, Jpeg, Gif or Png.";
}
}
}
}
For uploading image I am using plupload on client side. Then in my controlled I have next logic:
public ActionResult UploadFile()
{
try
{
var file = Request.Files.Count > 0 ? Request.Files[0] : null;
using (var fileStream = new MemoryStream())
{
using (var oldImage = new Bitmap(file.InputStream))
{
var format = oldImage.RawFormat;
using (var newImage = ImageUtility.ResizeImage(oldImage, 800, 2000))
{
newImage.Save(fileStream, format);
}
byte[] bits = fileStream.ToArray();
}
}
{
catch (Exception ex)
{
}
}
ImageUtility.ResizeImage Method:
public static class ImageUtility
{
public static Bitmap ResizeImage(Bitmap image, int width, int height)
{
if (image.Width <= width && image.Height <= height)
{
return image;
}
int newWidth;
int newHeight;
if (image.Width > image.Height)
{
newWidth = width;
newHeight = (int)(image.Height * ((float)width / image.Width));
}
else
{
newHeight = height;
newWidth = (int)(image.Width * ((float)height / image.Height));
}
var newImage = new Bitmap(newWidth, newHeight);
using (var graphics = Graphics.FromImage(newImage))
{
graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
graphics.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
graphics.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
graphics.FillRectangle(Brushes.Transparent, 0, 0, newWidth, newHeight);
graphics.DrawImage(image, 0, 0, newWidth, newHeight);
return newImage;
}
}
}
The issue which i have here that Image size is increased.
I uploaded image of 1.62MB and after this controller is called and it creates instance if Bitmap and then save Bitmap to filestream and read bits with "fileStream.ToArray();" I am getting 2.35MB in "bits".
Can anyone tell me what's the reason of increasing the image size after I save it as bitmap. I need Bitmap because I need to check with and height of uploaded image and resize it if I need.
The answer is simple, the bitmap takes up more memory the whatever format the image was in previously because it's uncompressed it stays in that uncompressed format after saving it.
jpeg, png, gif, etc. are compressed and therefore use less bytes tha a bitmap which is uncompressed.
If you just want to save the original image, just save file.InputStream.
If you need to resize, you can use a library to apply jpg/png/etc compression and then save the result.
What is the goal here? Are you merely trying to upload an image? Does it need to be validated as an image? Or are you just trying to upload the file?
If upload is the goal, without any regard to validation, just move the bits and save them with the name of the file. As soon as you do this ...
using (var oldImage = new Bitmap(file.InputStream))
... you are converting to a bitmap. Here is where you are telling the bitmap what format to use (raw).
var format = oldImage.RawFormat;
If you merely want to move the file (upload), you can run the memory stream to a filestream object and you save the bits.
If you want a few checks on whether the image is empty, etc, you can try this page (http://www.codeproject.com/Articles/1956/NET-Image-Uploading), but realize it is still putting it in an image, which is not your desire if you simply want to save "as is".
SO what I'm trying to do here is to import a list of .JPG images that are of a large size and I would like to scale them down without too much of a quality loss and then output them as a .JPG/.PNG to not take up too much memory like .BMP's do.
I know that you can only manipulate images when they are .bmp's.
Here's some of the sample code I have(I only know how to import them)
private void LoadImages()
{
for (int i = 0; i < trees.Length; i++)
{
string d = imagePath + trees[i].latinName + ".JPG";
treesImage[i] = Image.FromFile(d);
}
//the image path is a constant
//trees[i].latinName is a string property
//treesImage is an array of Images created.
//so I'd like(preferably within my for loop to create the .bmp's and scale down
//using a const value such as const int width = 400, const int height = 300;
//and I'd lke to save the image to a different diretory than imagePath
}
if there is anything else you would like to know post below and I'll edit the question
Try this:
int newWidth = 75;
int newHeight = 50;
for (int i = 0; i < trees.Length; i++)
{
string d = imagePath + trees[i].latinName + ".JPG";
Image image = Image.FromFile(d);
//new image with size you need
Bitmap smallImage = new Bitmap(newWidth, newHeight);
Graphics g = Graphics.FromImage(smallImage);
//draw scaled old image to new with correct size
//g.drawImage(Image sourceImage, Rectangle destination, Rectangle source, GraphicsUnit gu)
g.DrawImage(image, new Rectangle(0, 0, smallImage.Width, smallImage.Height), new Rectangle(0, 0, image.Width, image.Height), GraphicsUnit.Pixel);
//format of new image is defined by it's name (.png/.jpg)
smallImage.Save(trees[i].latinName + "_new.png");
}
I am doing a small project where I have to display all images from database to Listview.
I am passing image id,width,and height as querystring parameter.
<asp:Image ID="Image1" runat="server" ImageUrl='<%#"~/Handler/ImageHandler.ashx?ImgHeight=150&ImgWidth=200&ImgID="+Eval("Image_ID")%>' Height="150px" Width="200px"/>
public void ProcessRequest (HttpContext context)
{
string imgwidth = context.Request.QueryString["ImgWidth"];
string imgheight = context.Request.QueryString["ImgHeight"];
string imageid = context.Request.QueryString["ImgID"];
if (imgwidth != string.Empty && imgheight != string.Empty && (imgwidth != null && imgheight != null))
{
if (!System.Web.UI.WebControls.Unit.Parse(imgwidth).IsEmpty && !System.Web.UI.WebControls.Unit.Parse(imgheight).IsEmpty)
{
//create unit object for height and width. This is to convert parameter passed in differen unit like pixel, inch into generic unit.
System.Web.UI.WebControls.Unit widthUnit=System.Web.UI.WebControls.Unit.Parse(imgwidth);
System.Web.UI.WebControls.Unit heightUnit = System.Web.UI.WebControls.Unit.Parse(imgheight);
//AFTER THIS ???
}
}
}
when I display image directly from database some images get stretch and doesn't look good, this is because the image size is large. So I need to display the images just for thumbsnail in image gallery.
You could use GetThumbnailImage Method
refer the code
public Void GenerateImage(int iWidth,int iHeight,byte[] ImageBytes)
{
System.Drawing.Image image = byteArrayToImage(ImageBytes)
// create the actual thumbnail image
System.Drawing.Image thumbnailImage = image.GetThumbnailImage(iWidth, iHeight, new System.Drawing.Image.GetThumbnailImageAbort(ThumbnailCallback), IntPtr.Zero);
// make a memory stream to work with the image bytes
MemoryStream imageStream = new MemoryStream();
// put the image into the memory stream
thumbnailImage.Save(imageStream, System.Drawing.Imaging.Imageformat.Jpeg);
// make byte array the same size as the image
byte[] imageContent = new Byte[imageStream.Length];
// rewind the memory stream
imageStream.Position = 0;
// load the byte array with the image
imageStream.Read(imageContent, 0, (int)imageStream.Length);
// return byte array to caller with image type
Response.ContentType = "image/jpeg";
Response.BinaryWrite(imageContent);
}
public bool ThumbnailCallback()
{
return true;
}
public Image byteArrayToImage(byte[] byteArrayIn)
{
MemoryStream ms = new MemoryStream(byteArrayIn);
Image returnImage = Image.FromStream(ms);
return returnImage;
}
You could use this code to give the image a new size, while preserving the aspect ratio:
public static Image ResizeCanvas(Image original, Size newSize, Color background)
{
int xStart = (newSize.Width / 2) - (original.Width / 2);
int yStart = (newSize.Height / 2) - (original.Height / 2);
// Create blank canvas
Bitmap resizedImg = new Bitmap(newSize.Width, newSize.Height);
Graphics gfx = Graphics.FromImage(resizedImg);
// Fill canvas
gfx.FillRectangle(new SolidBrush(background), new Rectangle(new Point(0, 0), newSize));
gfx.DrawImage(original, xStart, yStart, original.Width, original.Height);
return resizedImg;
}
I tried this:
string str = System.IO.Path.GetFileName(txtImage.Text);
string pth = System.IO.Directory.GetCurrentDirectory() + "\\Subject";
string fullpath = pth + "\\" + str;
Image NewImage = clsImage.ResizeImage(fullpath, 130, 140, true);
NewImage.Save(fullpath, ImageFormat.Jpeg);
public static Image ResizeImage(string file, int width, int height, bool onlyResizeIfWider)
{
if (File.Exists(file) == false)
return null;
try
{
using (Image image = Image.FromFile(file))
{
// Prevent using images internal thumbnail
image.RotateFlip(RotateFlipType.Rotate180FlipNone);
image.RotateFlip(RotateFlipType.Rotate180FlipNone);
if (onlyResizeIfWider == true)
{
if (image.Width <= width)
{
width = image.Width;
}
}
int newHeight = image.Height * width / image.Width;
if (newHeight > height)
{
// Resize with height instead
width = image.Width * height / image.Height;
newHeight = height;
}
Image NewImage = image.GetThumbnailImage(width, newHeight, null, IntPtr.Zero);
return NewImage;
}
}
catch (Exception )
{
return null;
}
}
Running the above code, I get an image 4-5 KB in size with very poor image quality.
The original image file is no more than 1.5 MB large. How can I improve the image quality of the results?
I think you should use Image Resizer, its free and resizing an image is very easy using it.
var settings = new ResizeSettings {
MaxWidth = thumbnailSize,
MaxHeight = thumbnailSize,
Format = "jpg"
};
settings.Add("quality", quality.ToString());
ImageBuilder.Current.Build(inStream, outStream, settings);
resized = outStream.ToArray();
You can also install it using Nuget package manager.
PM> Install-Package ImageResizer