I have been looking all over for a way to resize an image before it is uploaded to my database. Right now the files are just upload and if they are not the correct size then my pages look like a mess. How would I resize the image before I upload it to my database, I would like to upload an original sized image, and correct size. Is this possible with ASP.net. I have seen some tutorials on image resizing but none of them were helpful, if anyone can help that would be great. I started looking at this tutorial but wasnt able to implement it in my SQL upload.
Thanks
Something like this, I am using MVC thus the HttpPostedFileBase. However this is taking the input of a file input type and returning a byte array, perfect for uploading to DB.
using System.Drawing;
using System.Drawing.Drawing2D;
private static byte[] PrepImageForUpload(HttpPostedFileBase FileData)
{
using (Bitmap origImage = new Bitmap(FileData.InputStream))
{
int maxWidth = 165;
int newWidth = origImage.Width;
int newHeight = origImage.Height;
if (origImage.Width < newWidth) //Force to max width
{
newWidth = maxWidth;
newHeight = origImage.Height * maxWidth / origImage.Width;
}
using (Bitmap newImage = new Bitmap(newWidth, newHeight))
{
using (Graphics gr = Graphics.FromImage(newImage))
{
gr.SmoothingMode = SmoothingMode.AntiAlias;
gr.InterpolationMode = InterpolationMode.HighQualityBicubic;
gr.PixelOffsetMode = PixelOffsetMode.HighQuality;
gr.DrawImage(origImage, new Rectangle(0, 0, newWidth, newHeight));
MemoryStream ms = new MemoryStream();
newImage.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
return ms.ToArray();
}
}
}
}
Related
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".
I have images stored in DB as binary, to show them I want to compress them to smaller images (4000 x 3000) to (400 x 300), which basicly works however the images look awefull, can somebody point me to the right direction?
I am using now:
System.IO.MemoryStream myMemStream = new System.IO.MemoryStream(bytes);
System.Drawing.Image fullsizeImage = System.Drawing.Image.FromStream(myMemStream);
Type typeoff = fullsizeImage.GetType();
double height = fullsizeImage.Height;
double width = Convert.ToDouble(fullsizeImage.Width);
double aspect = setWidth / width;
setHeight = Convert.ToInt32(aspect * height);
System.Drawing.Image newImage = fullsizeImage.GetThumbnailImage(Convert.ToInt32(setWidth), setHeight, null, IntPtr.Zero);
System.IO.MemoryStream myResult = new System.IO.MemoryStream();
using (System.IO.MemoryStream imageMemStream = new System.IO.MemoryStream(bytes))
{
using (Bitmap bitmap = new Bitmap(imageMemStream))
{
ImageFormat imageFormat = bitmap.RawFormat;
if (bitmap.RawFormat.Equals(System.Drawing.Imaging.ImageFormat.Jpeg))
{
newImage.Save(myResult, System.Drawing.Imaging.ImageFormat.Jpeg);
}
if (bitmap.RawFormat.Equals(System.Drawing.Imaging.ImageFormat.Gif))
{
newImage.Save(myResult, System.Drawing.Imaging.ImageFormat.Gif);
}
if (bitmap.RawFormat.Equals(System.Drawing.Imaging.ImageFormat.Bmp))
{
newImage.Save(myResult, System.Drawing.Imaging.ImageFormat.Bmp);
}
if (bitmap.RawFormat.Equals(System.Drawing.Imaging.ImageFormat.Png))
{
newImage.Save(myResult, System.Drawing.Imaging.ImageFormat.Png);
}
if (bitmap.RawFormat.Equals(System.Drawing.Imaging.ImageFormat.Icon))
{
newImage.Save(myResult, System.Drawing.Imaging.ImageFormat.Icon);
}
}
}
_bytes = myResult.ToArray(); //Returns a new byte array.
Have been looking to this but have no idea yet how to implenet ths with my binary in and output:
Bitmap image = new Bitmap(fullsizeImage, Convert.ToInt32(newWidth), setHeight);
using (Graphics gr = Graphics.FromImage(image))
{
gr.SmoothingMode = SmoothingMode.HighQuality;
gr.InterpolationMode = InterpolationMode.HighQualityBicubic;
gr.PixelOffsetMode = PixelOffsetMode.HighQuality;
gr.DrawImage(fullsizeImage, new Rectangle(0, 0, Convert.ToInt32(newWidth), setHeight));
_bytes = gr.T.ToArray();
}
Probebly I do something wrong but have no idea where to look to do this right, have not much experience in image compression.
Any help would be appriciated
UPDATE
trying to get out of the Image the mime type but not very lucky to get it, using this and cant find any other, code has a null return.
public byte[] imageToByteArray(System.Drawing.Image newImage)
{
System.IO.MemoryStream ms = new System.IO.MemoryStream();
ImageFormat format = newImage.RawFormat;
if (ImageCodecInfo.GetImageDecoders().FirstOrDefault(c => c.FormatID == format.Guid) != null)
{
ImageCodecInfo codec = ImageCodecInfo.GetImageDecoders().FirstOrDefault(c => c.FormatID == format.Guid);
string mimeType = codec.MimeType;
}
newImage.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
return ms.ToArray();
You can use this function to create the reduced Images:
public static Image ShrinkImage(Image original, int scale)
{
Bitmap bmp = new Bitmap(original.Width / scale, original.Height / scale,
original.PixelFormat);
using (Graphics G = Graphics.FromImage(bmp))
{
G.InterpolationMode = InterpolationMode.HighQualityBicubic;
G.SmoothingMode = SmoothingMode.HighQuality;
Rectangle srcRect = new Rectangle(0,0,original.Width, original.Height);
Rectangle destRect = new Rectangle(0,0,bmp.Width, bmp.Height);
G.DrawImage(original, destRect, srcRect, GraphicsUnit.Pixel);
bmp.SetResolution( original.HorizontalResolution, original.VerticalResolution);
}
return (Image)bmp;
}
Note that it can only work with real Bitmap Images, not with Icons; but it makes little sense trying to reduce icons anyway!
Also note that you may or may not want to change the Dpi of the new Images. In the code I don't but maybe you want to scale it up or set it to a fixed value..
Don't forget to Dispose of your Images, when you're done with them!
I have made an httphandler that shrinks an image and returns it as PNG. This works fine on my Vista PC with IE 9, but not on some old XP machines with IE 8. It seems strange that this should be a browser issue, but to me it looks like that. But, I am thinking that since I produce the PNG on the server, I must do something wrong in the code.
The httphandler (simplified):
<%# WebHandler Language="C#" Class="ShowPicture" %>
using System.Data;
using System;
using System.IO;
using System.Web;
public class ShowPicture : IHttpHandler {
public void ProcessRequest (HttpContext context) {
context.Response.ContentType = "image/png";
// byteArray comes from database
// maxWidth and maxHeight comes from Request
context.Response.BinaryWrite(
Common.ResizeImageFromArray(byteArray, maxWidth, maxHeight));
}
And the function called (simplified as well):
public static byte[] ResizeImageFromArray(byte[] array, int maxWidth, int maxHeight)
{
byte[] picArray = array;
if (maxWidth > 0 || maxHeight > 0) // Resize the image
{
Bitmap dbbmp = (Bitmap)Bitmap.FromStream(new MemoryStream(array));
if (dbbmp.Width > maxWidth || dbbmp.Height > maxHeight)
{
// Calculate the max width/height factor
Bitmap resized = new Bitmap(dbbmp, newWidth, newHeight);
MemoryStream ms = new MemoryStream();
resized.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
picArray = new Byte[ms.Length - 1];
ms.Position = 0;
ms.Read(picArray, 0, picArray.Length);
ms.Close();
}
}
return picArray;
}
I appreciate any ideas and/or input. Thanks in advance.
To resize with different format:
Bitmap resizedBitmap = new Bitmap(newWidth, newHeight, PixelFormat.Format32bppArgb);
Graphics g = Graphics.FromImage(resizedBitmap);
g.DrawImage(originalBitmap, new Rectangle(Point.Empty, resizedBitmap.Size), new Rectangle(Point.Empty, originalBitmap.Size), GraphicsUnit.Pixel);
g.Dispose();
With that you will have yopur scaled bitmap, also you can play with the Graphics object options to get better quality/faster processing times.
Also, to convert your MemoryStream to array is better to use ms.ToArray();
picArray = ms.ToArray();
This way you don't need to create the array by yourself.
I'm really trying to nail out a little more performance out of this tidbit of code. It's not a heavly used bit of code but is used every time a new image is uploaded, and 4 times for each image (100px, 200px, 500px, 700px). So when there are any more than 2 or 3 images processing, it gets a little busy on the server. Also I'm trying to figure out how to make it correctly process images with a low resolution. Currently it just chops it off half way through, not plesent.
Examples: Original, large, xLarge
public static byte[] ResizeImageFile(byte[] imageFile, int targetSize)
{
using (System.Drawing.Image oldImage = System.Drawing.Image.FromStream(new MemoryStream(imageFile)))
{
Size newSize = CalculateDimensions(oldImage.Size, targetSize);
using (Bitmap newImage = new Bitmap(newSize.Width, newSize.Height, PixelFormat.Format32bppRgb))
{
newImage.SetResolution(oldImage.HorizontalResolution, oldImage.VerticalResolution);
using (Graphics canvas = Graphics.FromImage(newImage))
{
canvas.SmoothingMode = SmoothingMode.AntiAlias;
canvas.InterpolationMode = InterpolationMode.HighQualityBicubic;
canvas.PixelOffsetMode = PixelOffsetMode.HighQuality;
canvas.DrawImage(oldImage, new Rectangle(new Point(0, 0), newSize));
MemoryStream m = new MemoryStream();
newImage.Save(m, ImageFormat.Jpeg);
return m.GetBuffer();
}
}
}
}
private static Size CalculateDimensions(Size oldSize, int targetSize)
{
Size newSize = new Size();
if (oldSize.Width > oldSize.Height)
{
newSize.Width = targetSize;
newSize.Height = (int)(oldSize.Height * (float)targetSize / (float)oldSize.Width);
}
else
{
newSize.Width = (int)(oldSize.Width * (float)targetSize / (float)oldSize.Height);
newSize.Height = targetSize;
}
return newSize;
}
Thanks for and help!
The first thought that comes to mind is, have you thought about Multithreading it? i.e. calling this method for each image (or batch of images) in a separate thread? That way, if your server has a few cores you can get things done quicker. Just a thought...
(Threading is a great tip.)
Try to call your method with the smallest possible image as input each time, instead of the original image. If the original image is, say 2000px, then create the 700px image from it and then use your newly created 700px image to create the 500px, etc...
With the HighQualityBicubic setting I doubt that you'll notice any difference in the 100px image. (But it of course it needs to be verified.)
For completeness, here is the solution to the second part of the question which was never answered. When processing a low resolution image the image was being cut off. The solution now, seems obvious. The problem lies in this bit of code from above:
using (Bitmap newImage = new Bitmap(newSize.Width, newSize.Height,
PixelFormat.Format32bppRgb))
The problem being that I'm selecting the PixelFormat, not letting it be the format of the original image. The correct code is here:
public static byte[] ResizeImageFile(byte[] imageFile, int targetSize)
{
using (System.Drawing.Image oldImage = System.Drawing.Image.FromStream(new MemoryStream(imageFile)))
{
Size newSize = CalculateDimensions(oldImage.Size, targetSize);
using (Bitmap newImage = new Bitmap(newSize.Width, newSize.Height,
oldImage.PixelFormat))
{
newImage.SetResolution(oldImage.HorizontalResolution,
oldImage.VerticalResolution);
using (Graphics canvas = Graphics.FromImage(newImage))
{
canvas.SmoothingMode = SmoothingMode.AntiAlias;
canvas.InterpolationMode = InterpolationMode.HighQualityBicubic;
canvas.PixelOffsetMode = PixelOffsetMode.HighQuality;
canvas.DrawImage(oldImage, new Rectangle(new Point(0, 0), newSize));
MemoryStream m = new MemoryStream();
newImage.Save(m, ImageFormat.Jpeg);
return m.GetBuffer();
}
}
}
}
i am using this code to take a jpg image and save it as a thumbnail but it seems very slow ..
Image thumbNail = image.GetThumbnailImage(width, height, null, new IntPtr());
is there any faster way to generate a large amount of thumbnails from a directory of images?
Try Draw Image - Re Edited
public Image ResizeImage(Image openImage, int NewWidth, int NewHeight) {
var openBitmap = new Bitmap(openImage);
var newBitmap = new Bitmap(NewWidth, NewHeight);
using (Graphics g = Graphics.FromImage(openBitmap))
{
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
g.DrawImage(newBitmap, new Rectangle(0, 0, NewWidth, NewHeight));
}
openBitmap.Dispose(); //Clear The Old Large Bitmap From Memory
return (Image)newBitmap;
}
Typical 3-4mb Image Takes Between 4-8ms
1) By far the fastest and most reliable way to create .Jpg thumbnails is to use partial decompression.
Jpg's have a unique aspect in that it's possible to extract a 1/8 size or 1/16 size (or any power of 2 size) copy of the original without decompressing or sampling the entire original image.
Ever notice how programs like Picassa or Windows Explorer seem to create thumbnails super fast? This is how they do it (when they are not already cached).
This functionality is easily available in any library based on the Independent JPEG Group library code, and most of them are. For example ImageMagick which has a .NET layer available.
2) You can further increase speed by using a hardware accelerated library like libjpeg turbo, although it may require interop.
3) Some explanation of this special .jpg feature is here.
Try it:
public bool GenerateThumbNail(string fileName, string thumbNailFileName,
ImageFormat format, int height, int width)
{
try
{
using (Image img = Image.FromFile(fileName))
{
Image thumbNail = new Bitmap(width, height, img.PixelFormat);
Graphics g = Graphics.FromImage(thumbNail);
g.CompositingQuality = CompositingQuality.HighQuality;
g.SmoothingMode = SmoothingMode.HighQuality;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
Rectangle rect = new Rectangle(0, 0, width, height);
g.DrawImage(img, rect);
thumbNail.Save(thumbNailFileName, format);
}
return true;
}
catch (Exception)
{
return false;
}
}
It uses DrawImage too.