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.
Related
(How) is it possible to create a qr code using ZXing.Net without a quiet zone?
This is my current code:
BarcodeWriter barcodeWriter = new BarcodeWriter();
barcodeWriter.Format = BarcodeFormat.QR_CODE;
barcodeWriter.Renderer = new BitmapRenderer();
EncodingOptions encodingOptions = new EncodingOptions();
encodingOptions.Width = 500;
encodingOptions.Height = 500;
encodingOptions.Margin = 0;
encodingOptions.Hints.Add(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.L);
barcodeWriter.Options = encodingOptions;
bitmap = barcodeWriter.Write(compressedText);
Thanks!
ZXing.Net doesn't support image scaling with anti-aliasing. That means it can only resize by integer values. In your case you should create the smallest possible image and resize the resulting image with an image manipulation library or the Bitmap and Graphics classes from the framework.
var barcodeWriter = new BarcodeWriter
{
Format = BarcodeFormat.QR_CODE
};
// set width and height to 1 to get the smallest possible representation without a quiet zone around the qr code
var encodingOptions = new EncodingOptions
{
Width = 1,
Height = 1,
Margin = 0
};
encodingOptions.Hints.Add(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.L);
barcodeWriter.Options = encodingOptions;
var bitmap = barcodeWriter.Write(compressedText);
// scale the image to the desired size
var scaledBitmap = ScaleImage(bitmap, 500, 500);
private static Bitmap ScaleImage(Bitmap bmp, int maxWidth, int maxHeight)
{
var ratioX = (double)maxWidth / bmp.Width;
var ratioY = (double)maxHeight / bmp.Height;
var ratio = Math.Min(ratioX, ratioY);
var newWidth = (int)(bmp.Width * ratio);
var newHeight = (int)(bmp.Height * ratio);
var newImage = new Bitmap(newWidth, newHeight, PixelFormat.Format24bppRgb);
using (var graphics = Graphics.FromImage(newImage))
{
graphics.InterpolationMode = InterpolationMode.NearestNeighbor;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
graphics.DrawImage(bmp, 0, 0, newWidth, newHeight);
}
return newImage;
}
I need to convert some System.Drawing based code to use this .NET Core compatible library:
https://github.com/SixLabors/ImageSharp
The System.Drawing based code below resizes an image and crops of the edges, returning the memory stream to then be saved. Is this possible with the ImageSharp library?
private static Stream Resize(Stream inStream, int newWidth, int newHeight)
{
var img = Image.Load(inStream);
if (newWidth != img.Width || newHeight != img.Height)
{
var ratioX = (double)newWidth / img.Width;
var ratioY = (double)newHeight / img.Height;
var ratio = Math.Max(ratioX, ratioY);
var width = (int)(img.Width * ratio);
var height = (int)(img.Height * ratio);
var newImage = new Bitmap(width, height);
Graphics.FromImage(newImage).DrawImage(img, 0, 0, width, height);
img = newImage;
if (img.Width != newWidth || img.Height != newHeight)
{
var startX = (Math.Max(img.Width, newWidth) - Math.Min(img.Width, newWidth)) / 2;
var startY = (Math.Max(img.Height, newHeight) - Math.Min(img.Height, newHeight)) / 2;
img = Crop(img, newWidth, newHeight, startX, startY);
}
}
var ms = new MemoryStream();
img.Save(ms, ImageFormat.Jpeg);
ms.Position = 0;
return ms;
}
private static Image Crop(Image image, int newWidth, int newHeight, int startX = 0, int startY = 0)
{
if (image.Height < newHeight)
newHeight = image.Height;
if (image.Width < newWidth)
newWidth = image.Width;
using (var bmp = new Bitmap(newWidth, newHeight, PixelFormat.Format24bppRgb))
{
bmp.SetResolution(72, 72);
using (var g = Graphics.FromImage(bmp))
{
g.SmoothingMode = SmoothingMode.AntiAlias;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
g.DrawImage(image, new Rectangle(0, 0, newWidth, newHeight), startX, startY, newWidth, newHeight, GraphicsUnit.Pixel);
var ms = new MemoryStream();
bmp.Save(ms, ImageFormat.Jpeg);
image.Dispose();
var outimage = Image.FromStream(ms);
return outimage;
}
}
}
Yeah, super easy.
using (var inStream = ...)
using (var outStream = new MemoryStream())
using (var image = Image.Load(inStream, out IImageFormat format))
{
image.Mutate(
i => i.Resize(width, height)
.Crop(new Rectangle(x, y, cropWidth, cropHeight)));
image.Save(outStream, format);
}
EDIT
If you want to leave the original image untouched you can use the Clone method instead.
using (var inStream = ...)
using (var outStream = new MemoryStream())
using (var image = Image.Load(inStream, out IImageFormat format))
{
var clone = image.Clone(
i => i.Resize(width, height)
.Crop(new Rectangle(x, y, cropWidth, cropHeight)));
clone.Save(outStream, format);
}
You might even be able to optimize this into a single method call to Resize via the overload that accepts a ResizeOptions instance with `ResizeMode.Crop. That would allow you to resize to a ratio then crop off any excess outside that ratio.
So here's relevent code after so far after converting to not use original methods:
using (var fullSizeStream = new MemoryStream())
using (var smallStream = new MemoryStream())
using (var thumbStream = new MemoryStream())
using (var reviewThumbStream = new MemoryStream())
using (var image = Image.Load(inStream))
{
// Save original constrained
var clone = image.Clone(context => context
.Resize(new ResizeOptions
{
Mode = ResizeMode.Max,
Size = new Size(1280, 1280)
}));
clone.Save(fullSizeStream, new JpegEncoder { Quality = 80 });
//Save three sizes Cropped:
var jpegEncoder = new JpegEncoder { Quality = 75 };
clone = image.Clone(context => context
.Resize(new ResizeOptions
{
Mode = ResizeMode.Crop,
Size = new Size(277, 277)
}));
clone.Save(smallStream, jpegEncoder);
clone = image.Clone(context => context
.Resize(new ResizeOptions
{
Mode = ResizeMode.Crop,
Size = new Size(100, 100)
}));
clone.Save(thumbStream, jpegEncoder);
clone = image.Clone(context => context
.Resize(new ResizeOptions
{
Mode = ResizeMode.Crop,
Size = new Size(50, 50)
}));
clone.Save(reviewThumbStream, jpegEncoder);
//...then I just save the streams to blob storage
}
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;
}
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 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);
}
}
}