Resize image gdi+ graphics .net - c#

I have this method for shrinking down an image for a website that I'm working on:
static byte[] createSmallerImage(
BlogPhoto blogPhoto,
int newMaxWidth,
int newMaxHeight)
{
Image img;
using (MemoryStream originalImage =
new MemoryStream(blogPhoto.BlogPhotoImage))
{
img = Image.FromStream(originalImage);
}
int newWidth;
int newHeight;
byte[] arr;
if (img.Width > img.Height)
{
if (img.Width <= newMaxWidth)
{
using (MemoryStream thumbStr = new MemoryStream())
{
img.Save(thumbStr, ImageFormat.Jpeg);
img.Dispose();
arr = thumbStr.ToArray();
}
return arr;
}
newWidth = newMaxWidth;
newHeight =
(int)(((float)newWidth / (float)img.Width) * (float)img.Height);
}
else
{
if (img.Height <= newMaxHeight)
{
using (MemoryStream thumbStr = new MemoryStream())
{
img.Save(thumbStr, ImageFormat.Jpeg);
img.Dispose();
arr = thumbStr.ToArray();
}
return arr;
}
newHeight = newMaxHeight;
newWidth =
(int)(((float)newHeight / (float)img.Height) * (float)img.Width);
}
Image thumb = new Bitmap(newWidth, newHeight);
Graphics g = Graphics.FromImage(thumb);
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.SmoothingMode = SmoothingMode.HighQuality;
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
g.CompositingQuality = CompositingQuality.HighQuality;
g.DrawImage(img, 0f, 0f, (float)newWidth, (float)newHeight);
using (MemoryStream thumbStr = new MemoryStream())
{
thumb.Save(thumbStr, ImageFormat.Jpeg);
arr = thumbStr.ToArray();
}
g.Dispose();
img.Dispose();
return arr;
}
Most of the time it works great but sometimes it gives me this exception:A generic error occurred in GDI+. Error Code -2147467259. Source: "System.Drawing". This occurs on the Image.Save(... I tried to make this code as defensive as possible but am still not getting whats causing this. If someone knows the answer that'd be great, critiques are welcome too.

I personally use this code, with no streams (I don't care about perfs, though) for resizing a picture:
public Image resizeImage(int newWidth, int newHeight, string stPhotoPath)
{
Image imgPhoto = Image.FromFile(stPhotoPath);
int sourceWidth = imgPhoto.Width;
int sourceHeight = imgPhoto.Height;
//Consider vertical pics
if (sourceWidth < sourceHeight)
{
int buff = newWidth;
newWidth = newHeight;
newHeight = buff;
}
int sourceX = 0, sourceY = 0, destX = 0, destY = 0;
float nPercent = 0, nPercentW = 0, nPercentH = 0;
nPercentW = ((float)newWidth / (float)sourceWidth);
nPercentH = ((float)newHeight / (float)sourceHeight);
if (nPercentH < nPercentW)
{
nPercent = nPercentH;
destX = System.Convert.ToInt16((newWidth -
(sourceWidth * nPercent)) / 2);
}
else
{
nPercent = nPercentW;
destY = System.Convert.ToInt16((newHeight -
(sourceHeight * nPercent)) / 2);
}
int destWidth = (int)(sourceWidth * nPercent);
int destHeight = (int)(sourceHeight * nPercent);
Bitmap bmPhoto = new Bitmap(newWidth, newHeight,
PixelFormat.Format24bppRgb);
bmPhoto.SetResolution(imgPhoto.HorizontalResolution,
imgPhoto.VerticalResolution);
Graphics grPhoto = Graphics.FromImage(bmPhoto);
grPhoto.Clear(Color.Black);
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;
}
Hope this helps.

Look at the documentation for Image.FromStream()
http://msdn.microsoft.com/en-us/library/93z9ee4x.aspx
You need to keep the stream open for the lifetime of the Image. Keep the first MemoryStream open longer, and it should work.

One thing to look at is blogPhoto and the underlying data going away. Where does it get loaded from? Is it loaded from a stream? Is that stream closed before createSmallerImage? Images loaded from streams where the stream is closed work 95% of the time and only occaisonally throw a generic GDI+ error.

I don't know what can be happening, but maybe with less MemoryStreams problem go away:
using (Image original = Image.FromStream(new MemoryStream(blogPhoto)))
{
using (MemoryStream thumbData = new MemoryStream())
{
int newWidth;
int newHeight;
if ((original.Width <= newMaxWidth) ||
(original.Height <= newMaxHeight))
{
original.Save(thumbData, ImageFormat.Jpeg);
return thumbData.ToArray();
}
if (original.Width > original.Height)
{
newWidth = newMaxWidth;
newHeight = (int)(((float)newWidth /
(float)original.Width) * (float)original.Height);
}
else
{
newHeight = newMaxHeight;
newWidth = (int)(((float)newHeight /
(float)original.Height) * (float)original.Width);
}
//original.GetThumbnailImage(newWidth, newHeight, null, IntPtr.Zero)
// .Save(thumbData, ImageFormat.Jpeg);
//return thumbData.ToArray();
using (Image thumb = new Bitmap(newWidth, newHeight))
{
Graphics g = Graphics.FromImage(thumb);
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.SmoothingMode = SmoothingMode.HighQuality;
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
g.CompositingQuality = CompositingQuality.HighQuality;
g.DrawImage(original, 0f, 0f, (float)newWidth, (float)newHeight);
thumb.Save(thumbData, ImageFormat.Jpeg);
}
}
}

Related

C# Can't convert byte to image

The code works on the tutorial I've watched but not on mine.
Here's my code:
private void AddButton()
{
foreach (TblProductType category in cse.TblProductType)
{
Button btn = new Button();
btn.Text = category.Description;
btn.Size = new Size(100, 100);
btn.ForeColor = Color.White;
byte [] dataCategory1 = category.Productimage;
MemoryStream stm = new MemoryStream(dataCategory1);
btn.Image = Image.FromStream(stm);
btn.Image = ResizeImage(btn.Image, btn.Size);
btn.Tag = category.ProductTypes;
flow1.Controls.Add(btn);
this.Controls.Add(flow1);
btn.Click += btn_Click
}
}
We may need a little more surrounding code, or a more information to the exact nature of your problem, but i suspect the most likely cause of this issue is whatever is happening in ResizeImage.
Here's a function which resizes a System.Drawing.Image, perhaps give that a try and see if it fixes your problem?
public static Image ResizeImage(int newWidth, int newHeight, Image image) {
int sourceWidth = image.Width;
int sourceHeight = image.Height;
//Consider vertical pics
if (sourceWidth < sourceHeight) {
int buff = newWidth;
newWidth = newHeight;
newHeight = buff;
}
int sourceX = 0, sourceY = 0, destX = 0, destY = 0;
float percent = 0, percentW = 0, percentH = 0;
percentW = ((float)newWidth / (float)sourceWidth);
percentH = ((float)newHeight / (float)sourceHeight);
if (percentH < percentW) {
percent = percentH;
destX = System.Convert.ToInt16((newWidth -
(sourceWidth * percent)) / 2);
} else {
percent = percentW;
destY = System.Convert.ToInt16((newHeight -
(sourceHeight * percent)) / 2);
}
int destWidth = (int)(sourceWidth * percent);
int destHeight = (int)(sourceHeight * percent);
Bitmap bitmap = new Bitmap(newWidth, newHeight,
PixelFormat.Format24bppRgb);
bitmap.SetResolution(image.HorizontalResolution,
image.VerticalResolution);
Graphics graphic = Graphics.FromImage(bitmap);
graphic.Clear(Color.Black);
graphic.InterpolationMode =
System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
graphic.DrawImage(image,
new Rectangle(destX, destY, destWidth, destHeight),
new Rectangle(sourceX, sourceY, sourceWidth, sourceHeight),
GraphicsUnit.Pixel);
graphic.Dispose();
image.Dispose();
return bitmap;
}
Here, try this:
In my problem I saved my chart to an memoryStream.. then saved that memoryStream to byte array and then saved byte array to an image. It works for me.
using (MemoryStream memoryStream = new MemoryStream())
{
//saved my chart to an memoryStream
Chart2.SaveImage(memoryStream, ChartImageFormat.Png);
//saved memorystream to byte array
byte[] byteArrayIn = memoryStream.ToArray();
//saving byte back to an Image
Image image1 = new Image();
image1.ImageUrl = "data:image/png;base64," + Convert.ToBase64String(byteArrayIn, 0, byteArrayIn.Length);
newChart.Controls.Add(image1);
divRadarChart.Visible = false;
}

Image resize results in an image with original dimensions

I am trying to resize images. This code results in images with the original dimensions (no resize is performed).
Image original = Image.FromFile(Server.MapPath("~/SavedFiles/Audios/") + fileNameF);
Image resized = ResizeImage(original, new Size(200, 200));
MemoryStream memStream = new MemoryStream();
resized.Save(memStream, ImageFormat.Jpeg);
On button click, I am calling this code:
public static Image ResizeImage(Image image, Size size, bool preserveAspectRatio = true)
{
int newWidth;
int newHeight;
if (preserveAspectRatio)
{
int originalWidth = image.Width;
int originalHeight = image.Height;
float percentWidth = (float)size.Width / (float)originalWidth;
float percentHeight = (float)size.Height / (float)originalHeight;
float percent = percentHeight < percentWidth ? percentHeight : percentWidth;
newWidth = (int)(originalWidth * percent);
newHeight = (int)(originalHeight * percent);
}
else
{
newWidth = size.Width;
newHeight = size.Height;
}
Image newImage = new Bitmap(newWidth, newHeight);
using (Graphics graphicsHandle = Graphics.FromImage(image))
{
graphicsHandle.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphicsHandle.DrawImage(newImage, 0, 0, newWidth, newHeight);
}
return newImage;
}
This is how I do it based on your code, I tested is using my image in the file and locate it in the specified folder too. It works fine. Your code only have but small issues (see my comments on the Stream and especially in the newImage declaration):
private void button1_Click(object sender, EventArgs e) {
Image original = Image.FromFile(Application.StartupPath + "\\ChessSet_Orig.JPG");
Image resized = ResizeImage(original, new Size(200, 200));
FileStream fileStream = new FileStream(Application.StartupPath + "\\ChessSet_resized.JPG", FileMode.Create); //I use file stream instead of Memory stream here
resized.Save(fileStream, ImageFormat.Jpeg);
fileStream.Close(); //close after use
}
public static Image ResizeImage(Image image, Size size, bool preserveAspectRatio = true) {
int newWidth;
int newHeight;
if (preserveAspectRatio) {
int originalWidth = image.Width;
int originalHeight = image.Height;
float percentWidth = (float)size.Width / (float)originalWidth;
float percentHeight = (float)size.Height / (float)originalHeight;
float percent = percentHeight < percentWidth ? percentHeight : percentWidth;
newWidth = (int)(originalWidth * percent);
newHeight = (int)(originalHeight * percent);
} else {
newWidth = size.Width;
newHeight = size.Height;
}
Image newImage = new System.Drawing.Bitmap(image, newWidth, newHeight); // I specify the new image from the original together with the new width and height
using (Graphics graphicsHandle = Graphics.FromImage(image)) {
graphicsHandle.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphicsHandle.DrawImage(newImage, 0, 0, newWidth, newHeight);
}
return newImage;
}
Here is the result,
The original image size is 820 x 760

parameter not valid at saving bitmap

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.

Image after resize has white border

I am trying to make function for resizing images.
public static Bitmap FixedSize(Bitmap imgPhoto, int Width, int Height, InterpolationMode im)
{
if ((Width == 0) && (Height == 0))
return imgPhoto;
if ((Width < 0) || (Height < 0))
return imgPhoto;
int destWidth = Width;
int destHeight = Height;
int srcWidth = imgPhoto.Size.Width;
int srcHeight = imgPhoto.Size.Height;
if (Width == 0)
destWidth = (int)(((float)Height / (float)srcHeight) * (float)srcWidth);
if (Height == 0)
destHeight = (int)(((float)Width / (float)srcWidth) * (float)srcHeight);
Bitmap bmPhoto = new Bitmap(destWidth, destHeight,
PixelFormat.Format24bppRgb);
bmPhoto.SetResolution(imgPhoto.HorizontalResolution,
imgPhoto.VerticalResolution);
Graphics grPhoto = Graphics.FromImage(bmPhoto);
grPhoto.Clear(Color.White);
grPhoto.InterpolationMode = im;
grPhoto.DrawImage(imgPhoto,
new Rectangle(new Point(0, 0), new Size(destWidth, destHeight)),
new Rectangle(0, 0, srcWidth, srcHeight),
GraphicsUnit.Pixel);
grPhoto.Dispose();
return new Bitmap(bmPhoto);
}
When I debug the code, all numbers seems OK but when I save the image it has a white line on left and on top border. Any idea what should be wrong? I tried to search and I used exactly the same code which should work but the line is still there.
Thanks.
public static Bitmap ResizeImage(Bitmap image, int percent)
{
try
{
int maxWidth = (int)(image.Width * (percent * .01));
int maxHeight = (int)(image.Height * (percent * .01));
Size size = GetSize(image, maxWidth, maxHeight);
Bitmap newImage = new Bitmap(size.Width, size.Height, PixelFormat.Format24bppRgb);
SetGraphics(image, size, newImage);
return newImage;
}
finally { }
}
public static void SetGraphics(Bitmap image, Size size, Bitmap newImage)
{
using (Graphics graphics = Graphics.FromImage(newImage))
{
graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.DrawImage(image, 0, 0, size.Width, size.Height);
}
}
Mark this, If it helps you.

Image resize asp.net mvc application

POST EDITED ADDED THE LINK
Read a very good post on image resize [here][1] in asp.net mvc.
http://dotnetslackers.com/articles/aspnet/Testing-Inbound-Routes.aspx
I need this logic to work for the images that are uploaded in cdn also.Say for example i have uploaded an image in cdn and now i want to fetch it from my controller and resize it.Also the image should not be saved in my server as it will not be good idea as it consumes valuable resource.The image has to be read from CDN and re sized without saving it locally in server.How can we achieve this using the methodology given in the above post.
Thanks,
S.
If you use ASP.Net MVC3, you can try new helper - WebImage.
This is my test code.
public ActionResult GetImg(float rate)
{
WebClient client = new WebClient();
byte[] imgContent = client.DownloadData("ImgUrl");
WebImage img = new WebImage(imgContent);
img.Resize((int)(img.Width * rate), (int)(img.Height * rate));
img.Write();
return null;
}
You can use the GDI+ features in the System.Drawing namespace
Bitmap newBitmap = new Bitmap(destWidth, destHeight);
Graphics g = Graphics.FromImage((Image)newBitmap);
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.DrawImage(sourceImage, 0, 0, destWidth, destHeight);
g.Dispose();
Here's what I use. Works great.
private static Image ResizeImage(Image imgToResize, Size size)
{
int sourceWidth = imgToResize.Width;
int sourceHeight = imgToResize.Height;
float nPercent = 0;
float nPercentW = 0;
float nPercentH = 0;
nPercentW = ((float)size.Width / (float)sourceWidth);
nPercentH = ((float)size.Height / (float)sourceHeight);
if (nPercentH < nPercentW)
nPercent = nPercentH;
else
nPercent = nPercentW;
int destWidth = (int)(sourceWidth * nPercent);
int destHeight = (int)(sourceHeight * nPercent);
Bitmap b = new Bitmap(destWidth, destHeight);
Graphics g = Graphics.FromImage((Image)b);
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.DrawImage(imgToResize, 0, 0, destWidth, destHeight);
g.Dispose();
return (Image)b;
}

Categories