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;
}
Related
I'm building an Image upload tool that resizes an image to fit a fixed size but it's adding a black background instead of a transparent one to the filler space around the image.
I've read that the Bitmap needs to be set to a PixelFormat with an Alpha layer and that I can set the Graphics clear colour to transparent but I'm still getting the same problem.
My images are mostly jpegs. Here is the code:
private void ResizeImage(Image Original, Int32 newWidth, Int32 newHeight, String pathToSave)
{
int sourceX = 0;
int sourceY = 0;
int destX = 0;
int destY = 0;
int originalWidth = Original.Width;
int originalHeight = Original.Height;
float nPercent = 0;
float nPercentW = 0;
float nPercentH = 0;
nPercentW = ((float)newWidth / (float)originalWidth);
nPercentH = ((float)newHeight / (float)originalHeight);
if (nPercentH < nPercentW)
{
nPercent = nPercentH;
destX = System.Convert.ToInt16((newWidth -
(originalWidth * nPercent)) / 2);
}
else
{
nPercent = nPercentW;
destY = System.Convert.ToInt16((newHeight -
(originalHeight * nPercent)) / 2);
}
int destWidth = (int)(originalWidth * nPercent);
int destHeight = (int)(originalHeight * nPercent);
Bitmap bmp = new Bitmap(newWidth, newHeight, PixelFormat.Format32bppArgb);
bmp.SetResolution(Original.HorizontalResolution, Original.VerticalResolution);
using (Graphics Graphic = Graphics.FromImage(bmp))
{
Graphic.CompositingQuality = CompositingQuality.HighQuality;
Graphic.Clear(Color.Red);
Graphic.CompositingMode = CompositingMode.SourceCopy;
Graphic.SmoothingMode = SmoothingMode.AntiAlias;
Graphic.InterpolationMode = InterpolationMode.HighQualityBicubic;
Graphic.PixelOffsetMode = PixelOffsetMode.HighQuality;
Graphic.DrawImage(
Original,
new Rectangle(destX, destY, destWidth, destHeight),
new Rectangle(sourceX, sourceY, originalWidth, originalHeight),
GraphicsUnit.Pixel
);
bmp.Save(pathToSave,Original.RawFormat);
}
}
Graphic.Clear(Color.Red);
No, you made that background red, not black. Use Color.Transparent if you want to have the alpha of the background set to 0. Or just omit the Clear(), it is the default for a new bitmap. And avoid Original.RawFormat in the Save() call, you don't want to use an image format that doesn't support transparency. Png is always good. And be sure that whatever method you use to display the resulting bitmap supports transparency as well. With a well defined background color. You'll get black when it doesn't, Color.Transparent has R, G and B at 0. Black.
What is the input format of your image? If it is jpg, the it is probably because jpg does not support transparency. You can try to use an output format of PNG which does support transparency:
bmp.Save(pathToSave, ImageFormat.Png);
Im using the following code to resize an image preserving the aspect ratio
public Bitmap resizeImage(System.Drawing.Image imgToResize, SizeF 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((System.Drawing.Image)b);
// Used to Prevent White Line Border
// g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
g.DrawImage(imgToResize, 0, 0, destWidth, destHeight);
g.Dispose();
return b;
}
But images with large width gets compressed and the contents seem packed up into a small space.What im trying to achieve is this : Resize the Large Size/Large Resolution image because processing this will take huge time,So when the image width or height exceeds say 1000 i want to resize the image to a Smaller size eg:1000 Width or Height which ever is larger,so that i can save computation time.But it seems the above code is forcibly trying to fit the image into the 1000X1000 Box when i do
if (y.Width > 1000 || y.Height > 1000)
{
y = new Bitmap( resizeImage(y, new Size(1000, 1000)));
}
Try this, its a bit neater
public static Bitmap ResizeImage(Bitmap source, Size size)
{
var scale = Math.Min(size.Width / (double)source.Width, size.Height / (double)source.Height);
var bmp = new Bitmap((int)(source.Width * scale), (int)(source.Height * scale));
using (var graph = Graphics.FromImage(bmp))
{
graph.InterpolationMode = InterpolationMode.High;
graph.CompositingQuality = CompositingQuality.HighQuality;
graph.SmoothingMode = SmoothingMode.AntiAlias;
graph.DrawImage(source, 0, 0, bmp.Width, bmp.Height);
}
return bmp;
}
Im using the following code (adapted from Example #2 here ) to Resize an Image keeping the aspect ratio.But i keep getting a white border around the resized images.What im i doing wrong.
Bitmap ResizekeepAspectRatio(Bitmap 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.White);
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;
}
UPDATE:
Sample Resized Image
Zooming in Corner Reveals White Border
Try to change the line
Bitmap bmPhoto = new Bitmap(Width, Height,
PixelFormat.Format24bppRgb);
To
Bitmap bmPhoto = new Bitmap(destWidth, destHeight,
PixelFormat.Format24bppRgb);
Since you want to keep the aspect ratio most of the time you will end up having extra space around the image so if you don't need that extra space then make the new picture size fit to the new destination size
Edit:
Try to comment out the line grPhoto.InterpolationMode = InterpolationMode.HighQualityBicubic
I'm building an Image upload tool that resizes an image to fit a fixed size but it's adding a black background instead of a transparent one to the filler space around the image.
I've read that the Bitmap needs to be set to a PixelFormat with an Alpha layer and that I can set the Graphics clear colour to transparent but I'm still getting the same problem.
My images are mostly jpegs. Here is the code:
private void ResizeImage(Image Original, Int32 newWidth, Int32 newHeight, String pathToSave)
{
int sourceX = 0;
int sourceY = 0;
int destX = 0;
int destY = 0;
int originalWidth = Original.Width;
int originalHeight = Original.Height;
float nPercent = 0;
float nPercentW = 0;
float nPercentH = 0;
nPercentW = ((float)newWidth / (float)originalWidth);
nPercentH = ((float)newHeight / (float)originalHeight);
if (nPercentH < nPercentW)
{
nPercent = nPercentH;
destX = System.Convert.ToInt16((newWidth -
(originalWidth * nPercent)) / 2);
}
else
{
nPercent = nPercentW;
destY = System.Convert.ToInt16((newHeight -
(originalHeight * nPercent)) / 2);
}
int destWidth = (int)(originalWidth * nPercent);
int destHeight = (int)(originalHeight * nPercent);
Bitmap bmp = new Bitmap(newWidth, newHeight, PixelFormat.Format32bppArgb);
bmp.SetResolution(Original.HorizontalResolution, Original.VerticalResolution);
using (Graphics Graphic = Graphics.FromImage(bmp))
{
Graphic.CompositingQuality = CompositingQuality.HighQuality;
Graphic.Clear(Color.Red);
Graphic.CompositingMode = CompositingMode.SourceCopy;
Graphic.SmoothingMode = SmoothingMode.AntiAlias;
Graphic.InterpolationMode = InterpolationMode.HighQualityBicubic;
Graphic.PixelOffsetMode = PixelOffsetMode.HighQuality;
Graphic.DrawImage(
Original,
new Rectangle(destX, destY, destWidth, destHeight),
new Rectangle(sourceX, sourceY, originalWidth, originalHeight),
GraphicsUnit.Pixel
);
bmp.Save(pathToSave,Original.RawFormat);
}
}
Graphic.Clear(Color.Red);
No, you made that background red, not black. Use Color.Transparent if you want to have the alpha of the background set to 0. Or just omit the Clear(), it is the default for a new bitmap. And avoid Original.RawFormat in the Save() call, you don't want to use an image format that doesn't support transparency. Png is always good. And be sure that whatever method you use to display the resulting bitmap supports transparency as well. With a well defined background color. You'll get black when it doesn't, Color.Transparent has R, G and B at 0. Black.
What is the input format of your image? If it is jpg, the it is probably because jpg does not support transparency. You can try to use an output format of PNG which does support transparency:
bmp.Save(pathToSave, ImageFormat.Png);
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);
}
}
}