I'm trying to scale an image and save that image to a new location. Now i'm having this error "A generic error occurred in GDI+ at System.Drawing.Image.Save".
I've found a couple of answers on stackoverflow, unfortunately without any results.
public static void SaveImageScaled(String imagePath, string destPath, Size newSize, String filename)
{
using (Bitmap bmpOriginal = (Bitmap)Image.FromFile(imagePath))
using (Bitmap bmpResized = new Bitmap(newSize.Width, newSize.Height))
using (Graphics g = Graphics.FromImage(bmpResized))
{
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.DrawImage(
bmpOriginal,
new Rectangle(Point.Empty, bmpResized.Size),
new Rectangle(Point.Empty, bmpOriginal.Size),
GraphicsUnit.Pixel);
// Lower the quality;
long qualityPercentage = 75L;
ImageCodecInfo[] myImageCodecInfoList = ImageCodecInfo.GetImageEncoders();
ImageCodecInfo myImageCodecInfo = myImageCodecInfoList.Where(x => x.FormatID == bmpOriginal.RawFormat.Guid).First();
Encoder myEncoder = Encoder.Quality;
EncoderParameters myEncoderParameters = new EncoderParameters(1);
EncoderParameter myEncoderParameter = new EncoderParameter(myEncoder, qualityPercentage);
myEncoderParameters.Param[0] = myEncoderParameter;
if (!Directory.Exists(destPath))
Directory.CreateDirectory(destPath);
// ERROR
bmpResized.Save(destPath + filename, myImageCodecInfo, myEncoderParameters);
}
}
This code created a directory with insufficient write-acces. Changed the permissions on a higher directory level, and solved the issue.
if (!Directory.Exists(destPath))
Directory.CreateDirectory(destPath);
Related
Below is my code to capture a screenshot. I tried to use "EncoderParameters" to reduce the file size but it seems doesn't work.
My screen resolution: 1920 x 1080:
Without Encoder setting, just save the bitmap image directly: 75KB
Encoder JPG 100%: 350KB
Encoder JPG 50%: 92KB
Encoder JPG 0%: 40KB (Can't see anything with this setting)
Is there anyway to reduce the image size less than 10KB? If not, what is the best method to reduce the file size as much as possible?
Bitmap bmp = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);
Graphics graph = Graphics.FromImage(bmp as Image);
graph.CopyFromScreen(0, 0, 0, 0, bmp.Size);
ImageCodecInfo jpgEncoder = GetEncoder(ImageFormat.Jpeg);
System.Drawing.Imaging.Encoder myEncoder =
System.Drawing.Imaging.Encoder.Quality;
EncoderParameters myEncoderParameters = new EncoderParameters(1);
EncoderParameter myEncoderParameter = new EncoderParameter(myEncoder, 50L);
myEncoderParameters.Param[0] = myEncoderParameter;
bmp.Save("TestPhotoQualityFifty.jpg", jpgEncoder, myEncoderParameters);
myEncoderParameter = new EncoderParameter(myEncoder, 100L);
myEncoderParameters.Param[0] = myEncoderParameter;
bmp.Save("TestPhotoQualityHundred.jpg", jpgEncoder, myEncoderParameters);
myEncoderParameter = new EncoderParameter(myEncoder, 0L);
myEncoderParameters.Param[0] = myEncoderParameter;
bmp.Save("TestPhotoQualityZero.jpg", jpgEncoder, myEncoderParameters);
I want to display an Image on a C# winForms application, but only with the quality of 50%, is it possible with the standard Picturebox?
Maybe resize the image programmatically to 50% of the size and then stretch it to the Picturebox?
Image img = Image.FromFile(imgFile)
** Resize the Image here, or do something else **
pictureBox.Image = img;
pictureBox.SizeMode = PictureBoxSizeMode.StretchImage;
You can change the quality of Picture by following function,
private void VaryQualityLevel()
{
// Get a bitmap.
Bitmap bmp1 = new Bitmap(#"c:\TestPhoto.jpg");
ImageCodecInfo jgpEncoder = GetEncoder(ImageFormat.Jpeg);
// Create an Encoder object based on the GUID
// for the Quality parameter category.
System.Drawing.Imaging.Encoder myEncoder =
System.Drawing.Imaging.Encoder.Quality;
// Create an EncoderParameters object.
// An EncoderParameters object has an array of EncoderParameter
// objects. In this case, there is only one
// EncoderParameter object in the array.
EncoderParameters myEncoderParameters = new EncoderParameters(1);
EncoderParameter myEncoderParameter = new EncoderParameter(myEncoder,
50L);
myEncoderParameters.Param[0] = myEncoderParameter;
bmp1.Save(#"c:\TestPhotoQualityFifty.jpg", jgpEncoder,
myEncoderParameters);
myEncoderParameter = new EncoderParameter(myEncoder, 100L);
myEncoderParameters.Param[0] = myEncoderParameter;
bmp1.Save(#"c:\TestPhotoQualityHundred.jpg", jgpEncoder,
myEncoderParameters);
// Save the bitmap as a JPG file with zero quality level compression.
myEncoderParameter = new EncoderParameter(myEncoder, 0L);
myEncoderParameters.Param[0] = myEncoderParameter;
bmp1.Save(#"c:\TestPhotoQualityZero.jpg", jgpEncoder,
myEncoderParameters);
}
after assign 50% Quality Image on picture box,
pictureBox.Image = "c:\TestPhotoQualityFifty.jpg";
verify this stackoverflow.com/questions/1484759/quality-of-a-saved-jpg-in-c-sharp
I suggest you to first read this -
How to: Set JPEG Compression Level
Turning off JPEG color downsampling for Bitmap.Save()
You can save it to MemoryStream and then load a new bitmap from this
MemoryStream.
Try this approach:
// Get a bitmap.
Bitmap bmp1 = new Bitmap(#"c:\TestPhoto.jpg");
ImageCodecInfo jpgEncoder = GetEncoder(ImageFormat.Jpeg);
// Create an Encoder object based on the GUID
// for the Quality parameter category.
System.Drawing.Imaging.Encoder myEncoder =
System.Drawing.Imaging.Encoder.Quality;
// Create an EncoderParameters object.
// An EncoderParameters object has an array of EncoderParameter
// objects. In this case, there is only one
// EncoderParameter object in the array.
EncoderParameters myEncoderParameters = new EncoderParameters(1);
EncoderParameter myEncoderParameter = new EncoderParameter(myEncoder, 50L);
myEncoderParameters.Param[0] = myEncoderParameter;
MemoryStream ms = new MemoryStream();
bmp1.Save(ms, jpgEncoder, myEncoderParameters);
pictureBox.Image = Image.FromStream(ms);
.....
private ImageCodecInfo GetEncoder(ImageFormat format)
{
ImageCodecInfo[] codecs = ImageCodecInfo.GetImageDecoders();
foreach (ImageCodecInfo codec in codecs)
{
if (codec.FormatID == format.Guid)
{
return codec;
}
}
return null;
}
I pass an array to a method and I use a foreach loop. The parameter I'm passing to new Bitmap() is not valid for some reason. I get the error "Parameter is not valid." The parameter is a string path (as it should be).
Can anyone tell me what's wrong?
If I highlight the parameter name, this is what it shows me, which seems to be correct:
"C:\Reinstatement Image Transporter\Image Processing\NYH004402800_REINSTMT_0e2837ae.jpg"
public static void CompressPictures(string[] processingFiles)
{
string originalFileName = "";
foreach (string file in processingFiles)
{
//I'm getting the error right here:
Bitmap pic = new Bitmap(file);
ImageCodecInfo jgpEncoder = GetEncoder(ImageFormat.Jpeg);
Encoder myEncoder = Encoder.Quality;
EncoderParameters myEncoderParameters = new EncoderParameters(1);
EncoderParameter myEncoderParameter = new EncoderParameter(myEncoder, 50L);
myEncoderParameter = new EncoderParameter(myEncoder, 0L);
myEncoderParameters.Param[0] = myEncoderParameter;
originalFileName = Path.GetFileNameWithoutExtension(file.Remove(file.Length - 1, 1));
pic.Save(AppVars.ProcessingPolicyImagesFolder + originalFileName, jgpEncoder, myEncoderParameters);
}
}
(Per the comments on the question above: It was a simple FileNotFound error.)
I need to get a picture from the user, with different format extensions, and I want to always save it as "jpg", for easy handling.
is there a good way do that in c# without arming the quality?
From: http://msdn.microsoft.com/en-us/library/system.drawing.imaging.encoderparameter.aspx
private void VaryQualityLevel()
{
// Get a bitmap.
Bitmap bmp1 = new Bitmap(#"c:\TestPhoto.jpg");
ImageCodecInfo jpgEncoder = GetEncoder(ImageFormat.Jpeg);
// Create an Encoder object based on the GUID
// for the Quality parameter category.
System.Drawing.Imaging.Encoder myEncoder =
System.Drawing.Imaging.Encoder.Quality;
// Create an EncoderParameters object.
// An EncoderParameters object has an array of EncoderParameter
// objects. In this case, there is only one
// EncoderParameter object in the array.
EncoderParameters myEncoderParameters = new EncoderParameters(1);
EncoderParameter myEncoderParameter = new EncoderParameter(myEncoder,
50L);
myEncoderParameters.Param[0] = myEncoderParameter;
bmp1.Save(#"c:\TestPhotoQualityFifty.jpg", jpgEncoder,
myEncoderParameters);
myEncoderParameter = new EncoderParameter(myEncoder, 100L);
myEncoderParameters.Param[0] = myEncoderParameter;
bmp1.Save(#"c:\TestPhotoQualityHundred.jpg", jpgEncoder,
myEncoderParameters);
// Save the bitmap as a JPG file with zero quality level compression.
myEncoderParameter = new EncoderParameter(myEncoder, 0L);
myEncoderParameters.Param[0] = myEncoderParameter;
bmp1.Save(#"c:\TestPhotoQualityZero.jpg", jpgEncoder,
myEncoderParameters);
}
...
private ImageCodecInfo GetEncoder(ImageFormat format)
{
ImageCodecInfo[] codecs = ImageCodecInfo.GetImageDecoders();
foreach (ImageCodecInfo codec in codecs)
{
if (codec.FormatID == format.Guid)
{
return codec;
}
}
return null;
}
I use this simple extension to convert a stream, all it does is convert it though and does nothing for quality.
public static Stream ConvertImage(this Stream originalStream, ImageFormat format)
{
var image = Image.FromStream(originalStream);
var stream = new MemoryStream();
image.Save(stream, format);
stream.Position = 0;
return stream;
}
usage:
var outputStream = gifStream.ConvertImage(ImageFormat.Png);
Windows GDI+ provides the Image class and the Bitmap class for storing
images in memory and manipulating images in memory. GDI+ writes images
to disk files with the help of image encoders and loads images from
disk files with the help of image decoders.
Check Image.Save Method overloads to implement your functionality. which support various image format of type ImageFormat Class.
follow example on Image.Save Method (String, ImageCodecInfo, EncoderParameters), which will let you save Jpg file with encoding etc.
code snippet:
using System;
using System.Drawing;
using System.Drawing.Imaging;
class Example_SetJPEGQuality
{
public static void Main()
{
Bitmap myBitmap;
ImageCodecInfo myImageCodecInfo;
Encoder myEncoder;
EncoderParameter myEncoderParameter;
EncoderParameters myEncoderParameters;
// Create a Bitmap object based on a BMP file.
myBitmap = new Bitmap("Shapes.bmp");
// Get an ImageCodecInfo object that represents the JPEG codec.
myImageCodecInfo = GetEncoderInfo("image/jpeg");
// Create an Encoder object based on the GUID
// for the Quality parameter category.
myEncoder = Encoder.Quality;
// Create an EncoderParameters object.
// An EncoderParameters object has an array of EncoderParameter
// objects. In this case, there is only one
// EncoderParameter object in the array.
myEncoderParameters = new EncoderParameters(1);
// Save the bitmap as a JPEG file with quality level 25.
myEncoderParameter = new EncoderParameter(myEncoder, 25L);
myEncoderParameters.Param[0] = myEncoderParameter;
myBitmap.Save("Shapes025.jpg", myImageCodecInfo, myEncoderParameters);
// Save the bitmap as a JPEG file with quality level 50.
myEncoderParameter = new EncoderParameter(myEncoder, 50L);
myEncoderParameters.Param[0] = myEncoderParameter;
myBitmap.Save("Shapes050.jpg", myImageCodecInfo, myEncoderParameters);
// Save the bitmap as a JPEG file with quality level 75.
myEncoderParameter = new EncoderParameter(myEncoder, 75L);
myEncoderParameters.Param[0] = myEncoderParameter;
myBitmap.Save("Shapes075.jpg", myImageCodecInfo, myEncoderParameters);
}
// Codec info
private static ImageCodecInfo GetEncoderInfo(String mimeType)
{
int j;
ImageCodecInfo[] encoders;
encoders = ImageCodecInfo.GetImageEncoders();
for(j = 0; j < encoders.Length; ++j)
{
if(encoders[j].MimeType == mimeType)
return encoders[j];
}
return null;
}
}
Hope this help..
Try this:
public static class BitmapExtension
{
public static void Save(this Bitmap bitmap, String fileName, ImageFormat imageFormat, long quality = 75L)
{
using (var encoderParameters = new EncoderParameters(1))
using (encoderParameters.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, quality))
{
ImageCodecInfo[] codecs = ImageCodecInfo.GetImageDecoders();
bitmap.Save(fileName, codecs.Single(codec => codec.FormatID == imageFormat.Guid), encoderParameters);
}
}
}
...
Bitmap bitmap = new Bitmap("myImage.bmp");
bitmap.Save("myImage.jpg", ImageFormat.Jpeg, 50L);
Is there any way to convert a bmp image to jpg/png without losing the quality in C#? Using Image class we can convert bmp to jpg but the quality of output image is very poor. Can we gain the quality level as good as an image converted to jpg using photoshop with highest quality?
var qualityEncoder = Encoder.Quality;
var quality = (long)<desired quality>;
var ratio = new EncoderParameter(qualityEncoder, quality );
var codecParams = new EncoderParameters(1);
codecParams.Param[0] = ratio;
var jpegCodecInfo = <one of the codec infos from ImageCodecInfo.GetImageEncoders() with mime type = "image/jpeg">;
bmp.Save(fileName, jpegCodecInfo, codecParams); // Save to JPG
public static class BitmapExtensions
{
public static void SaveJPG100(this Bitmap bmp, string filename)
{
EncoderParameters encoderParameters = new EncoderParameters(1);
encoderParameters.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 100L);
bmp.Save(filename, GetEncoder(ImageFormat.Jpeg), encoderParameters);
}
public static void SaveJPG100(this Bitmap bmp, Stream stream)
{
EncoderParameters encoderParameters = new EncoderParameters(1);
encoderParameters.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 100L);
bmp.Save(stream, GetEncoder(ImageFormat.Jpeg), encoderParameters);
}
public static ImageCodecInfo GetEncoder(ImageFormat format)
{
ImageCodecInfo[] codecs = ImageCodecInfo.GetImageDecoders();
foreach (ImageCodecInfo codec in codecs)
{
if (codec.FormatID == format.Guid)
{
return codec;
}
}
return null;
}
}
Provided BitmapExtensions by jestro are great, I used them. However would like to show the corrected version - works for Image parent class which is more convenient as I think and provides a way to supply quality:
public static class ImageExtensions
{
public static void SaveJpeg(this Image img, string filePath, long quality)
{
var encoderParameters = new EncoderParameters(1);
encoderParameters.Param[0] = new EncoderParameter(Encoder.Quality, quality);
img.Save(filePath, GetEncoder(ImageFormat.Jpeg), encoderParameters);
}
public static void SaveJpeg(this Image img, Stream stream, long quality)
{
var encoderParameters = new EncoderParameters(1);
encoderParameters.Param[0] = new EncoderParameter(Encoder.Quality, quality);
img.Save(stream, GetEncoder(ImageFormat.Jpeg), encoderParameters);
}
static ImageCodecInfo GetEncoder(ImageFormat format)
{
ImageCodecInfo[] codecs = ImageCodecInfo.GetImageDecoders();
return codecs.Single(codec => codec.FormatID == format.Guid);
}
}
Fundamentally you won't be able to keep the same quality because jpg is (so far as I'm aware) always lossy even with the highest possible quality settings.
If bit-accurate quality is really important, consider using png, which has some modes which are lossless.
Just want to say that JPEG is by nature a lossy format. So in thoery even at the highest settings you are going to have some information loss, but it depends a lot on the image.But png is lossless.
I am working on an expense report app, and I am really pleased with the default quality settings for JPG (and PNG) when saving from a Bitmap object.
https://msdn.microsoft.com/en-us/library/9t4syfhh%28v=vs.110%29.aspx
Bitmap finalBitmap = ....; //from disk or whatever
finalBitmap.Save(xpsFileName + ".final.jpg", ImageFormat.Jpeg);
finalBitmap.Save(xpsFileName + ".final.png", ImageFormat.Png);
I'm on .NET 4.6...perhaps the quality has improved in subsequent framework releases.
You can try:
Bitmap.InterpolationMode = InterpolationMode.HighQualityBicubic;
and
Bitmap.CompositingQuality = CompositingQuality.HighQuality;
Which does keep the quality fairly high, but not the highest possible.