i am getting Invalid Parameter Error when calling System.Drawing.Image.Save function.
i google and found a few suggestions but nothing works.
what i am trying to do is that, when i upload an image and if it's lager than 100kb i would like to reduce the image size to half. please help.
System.Drawing.Image FullsizeImage = System.Drawing.Image.FromFile(realpath);
FullsizeImage = System.Drawing.Image.FromFile(realpath);
int fileSize = (int)new System.IO.FileInfo(realpath).Length;
while (fileSize > 100000) //If Larger than 100KB
{
SaveJpeg(realpath, FullsizeImage);
fileSize = (int)new System.IO.FileInfo(realpath).Length;
}
private static ImageCodecInfo GetEncoderInfo(string mimeType)
{
// Get image codecs for all image formats
ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders();
// Find the correct image codec
for (int i = 0; i < codecs.Length; i++)
if (codecs[i].MimeType == mimeType)
return codecs[i];
return null;
}
public static void SaveJpeg(string path, Image img)
{
Image NewImage = img;
img.Dispose();
EncoderParameter qualityParam = new EncoderParameter(Encoder.Quality, 85L);
EncoderParameters encoderParams = new EncoderParameters(1);
encoderParams.Param[0] = qualityParam;
ImageCodecInfo jpegCodec = GetEncoderInfo(GetMimeType(path.Substring(path.LastIndexOf('.'), path.Length - path.LastIndexOf('.'))));
//THE ERROR IS HERE!!!!!!
NewImage.Save(path, jpegCodec, encoderParams);
//THE ERROR IS HERE!!!!!!
}
public static string GetMimeType(string extension)
{
if (extension == null)
{
throw new ArgumentNullException("extension");
}
if (!extension.StartsWith("."))
{
extension = "." + extension;
}
switch (extension.ToLower())
{
#region Big freaking list of mime types
// combination of values from Windows 7 Registry and
// from C:\Windows\System32\inetsrv\config\applicationHost.config
// some added, including .7z and .dat
case ".323": return "text/h323";
// more extension here..
#endregion
default:
// if you have logging, log: "No mime type is registered for extension: " + extension);
return "application/octet-stream";
}
}
EDIT : I modified the code as below, now the image is saving without any exception! Thanks! but another problem here. the file size is not getting reduced. which mean my while loop can never exit. please help and thanks again.
using (MemoryStream ms = new MemoryStream(File.ReadAllBytes(realpath)))
{
using (Image FullsizeImage = Image.FromStream(ms))
{
//code here
int fileSize = (int)new System.IO.FileInfo(realpath).Length;
while (fileSize > 100000) //If Larger than 100KB
{
SaveJpeg(realpath, FullsizeImage, 85L);
fileSize = (int)new System.IO.FileInfo(realpath).Length;
}
}
}
Can someone help me please, my problem is not solved yet :(
Because you're disposing an image object.
public static void SaveJpeg(string path, Image img)
{
Image NewImage = img;
img.Dispose(); <------- Here
...
}
EDIT: Method Image.FromFile file opens a stream and that file wont be closed till your method is not terminated. Try to use MemoryStream.
using (MemoryStream ms = new MemoryStream(File.ReadAllBytes(realPath)))
{
using (Image img = Image.FromStream(ms))
{
ImageCodecInfo myImageCodecInfo;
Encoder myEncoder;
EncoderParameter myEncoderParameter;
EncoderParameters myEncoderParameters;
myImageCodecInfo = GetEncoderInfo("image/jpeg");
myEncoder = Encoder.Quality;
myEncoderParameters = new EncoderParameters(1);
myEncoderParameter = new EncoderParameter(myEncoder, 85L);
myEncoderParameters.Param[0] = myEncoderParameter;
img.Save(realPath, myImageCodecInfo, myEncoderParameters);
}
}
Related
I am trying to convert a pdf file existing on server into tiff image(As my PDF may have more than 1 frame). I tried multiple links and found spire.pdf
I am following a tutorial
https://www.e-iceblue.com/Tutorials/Spire.PDF/Spire.PDF-Program-Guide/Conversion/Save-PDF-Document-as-tiff-image.html
public ActionResult OpenFilee(string fileID)
{
PdfDocument doc = new PdfDocument();
doc.LoadFromFile(Path.Combine(Server.MapPath("~/SafetyUploadedFiles/") +
fileID));
JoinTiffImages(SaveAsImage(doc), "res.tiff", EncoderValue.CompressionLZW);
System.Diagnostics.Process.Start("res.tiff");
return View();
}
private static Image[] SaveAsImage(PdfDocument document)
{
Image[] images = new Image[document.Pages.Count];
for (int i = 0; i < document.Pages.Count; i++)
{
images[i] = document.SaveAsImage(i);
}
return images;
}
private static ImageCodecInfo GetEncoderInfo(string mimeType)
{
ImageCodecInfo[] encoders = ImageCodecInfo.GetImageEncoders();
for (int j = 0; j < encoders.Length; j++)
{
if (encoders[j].MimeType == mimeType)
return encoders[j];
}
throw new Exception(mimeType + " mime type not found in ImageCodecInfo");
}
public static void JoinTiffImages(Image[] images, string outFile, EncoderValue compressEncoder)
{
//use the save encoder
Encoder enc = Encoder.SaveFlag;
EncoderParameters ep = new EncoderParameters(2);
ep.Param[0] = new EncoderParameter(enc, (long)EncoderValue.MultiFrame);
ep.Param[1] = new EncoderParameter(Encoder.Compression, (long)compressEncoder);
Image pages = images[0];
int frame = 0;
ImageCodecInfo info = GetEncoderInfo("image/tiff");
foreach (Image img in images)
{
if (frame == 0)
{
pages = img;
//save the first frame
pages.Save(outFile, info, ep);
}
else
{
//save the intermediate frames
ep.Param[0] = new EncoderParameter(enc, (long)EncoderValue.FrameDimensionPage);
pages.SaveAdd(img, ep);
}
if (frame == images.Length - 1)
{
//flush and close.
ep.Param[0] = new EncoderParameter(enc, (long)EncoderValue.Flush);
pages.SaveAdd(ep);
}
frame++;
}
}
Getting this error
A generic error occurred in GDI+.
on the following line:
pages.Save(outFile, info, ep);
I am making a function where I pass an Image and that will compress the image and return that image object. Following is my code:
public Image CompressImage(Image img)
{
ImageCodecInfo jpegCodec = null;
EncoderParameter imageQualitysParameter = new EncoderParameter(
System.Drawing.Imaging.Encoder.Quality, 50L);
ImageCodecInfo[] alleCodecs = ImageCodecInfo.GetImageEncoders();
EncoderParameters codecParameter = new EncoderParameters(1);
codecParameter.Param[0] = imageQualitysParameter;
for (int i = 0; i < alleCodecs.Length; i++)
{
if (alleCodecs[i].MimeType == "image/jpeg")
{
jpegCodec = alleCodecs[i];
break;
}
}
Image img1;
using (Stream memory = new MemoryStream())
{
img.Save(memory, jpegCodec, codecParameter);
img1 = Image.FromStream(memory);
memory.Close();
memory.Dispose();
}
return img1;
}
But When I am saving it in the memory stream, it is showing error
An unhandled exception of type 'System.ArgumentException' occurred in EnexolImageConversionApp.exe
Additional information: Parameter is not valid.
on line
img.Save(memory, jpegCodec, codecParameter);
Try this code - it selects proper ImageCodecInfo by comparing ImageFormat.Guid and ImageCodecInfo.FormatID:
using System.Drawing.Imaging;
using System.IO;
public static byte[] SaveImageToByteArray(Image image, int jpegQuality = 90)
{
using (var ms = new MemoryStream())
{
var jpegEncoder = GetEncoder(ImageFormat.Jpeg);
var encoderParameters = new EncoderParameters(1);
encoderParameters.Param[0] = new EncoderParameter(Encoder.Quality, (long)jpegQuality);
image.Save(ms, jpegEncoder, encoderParameters);
return ms.ToArray();
}
}
private static ImageCodecInfo GetEncoder(ImageFormat format)
{
var codecs = ImageCodecInfo.GetImageDecoders();
foreach (ImageCodecInfo codec in codecs)
{
if (codec.FormatID == format.Guid)
{
return codec;
}
}
return null;
}
Last step will be loading image again from received byte array.
For better issue understanding please provide exception details, including stacktrace.
I want to upload an optimized images to Amazon.
So that I have found this article that explains how to optimize an image with a compression level.
The problem is that this example saves the image to disk and I need to save it to Amazon storage.
I have this code:
public static ImageCodecInfo OptimizeImage(Image image, string fileName, long compression, string type)
{
var encoderParams = new EncoderParameters(1)
{
Param = {[0] = new EncoderParameter(Encoder.Quality, compression)}
};
return GetEncoderInfo(type);
}
private static ImageCodecInfo GetEncoderInfo(string mime_type)
{
ImageCodecInfo[] encoders = ImageCodecInfo.GetImageEncoders();
for (int i = 0; i <= encoders.Length; i++)
{
if (encoders[i].MimeType == mime_type)
return encoders[i];
}
return null;
}
I should have a Stream or byte[] object in order to send it to the UploadImageToAmazon method as parameter.
So, I have an Image object and its ImageCodecInfo, how can I convert it to Stream or to byte[]?
Or if you could suggest me how to optimize images and upload them into amazon would be also good.
Thanks.
You can save an Image object to a Stream with Image.Save Method (Stream, ImageFormat)
Edit :
If I recap with the code provided in the example you linked:
private void SaveJpg(Image image, string file_name, long compression)
{
try
{
EncoderParameters encoder_params = new EncoderParameters(1);
encoder_params.Param[0] = new EncoderParameter(
System.Drawing.Imaging.Encoder.Quality, compression);
ImageCodecInfo image_codec_info =
GetEncoderInfo("image/jpeg");
File.Delete(file_name);
using(var imageStream = new Stream()){
// save to stream
image.Save(imageStream, image_codec_info, encoder_params);
// upload
UploadImageToAmazon(imageStream);
}
}
catch (Exception ex)
{
MessageBox.Show("Error saving file '" + file_name +
"'\nTry a different file name.\n" + ex.Message,
"Save Error", MessageBoxButtons.OK,
MessageBoxIcon.Error);
}
}
i have use a controller action with use of file uploader and i want to compress the image and compress process perform after save the image, so my problem is : i want save only compress image and delete the orignal one. but this code shows error : file because it is being used by another process
My Code is :
public ActionResult submitgeneralinfo(HttpPostedFileBase file, int? EmployeeId, GeneralInfoViewModel model)
{
var ext = Path.GetExtension(file.FileName);
uniquefilename = Convert.ToString(ID) + ext;
var path = Path.Combine(Server.MapPath("~/Attachements/GeneralInfodp/"), uniquefilename);
var compaths = Path.Combine(Server.MapPath("~/Attachements/GeneralInfodp/"), "com" + uniquefilename);
file.SaveAs(path);
file.InputStream.Dispose();
CompressImage(Image.FromFile(path), 30, compaths);
file.InputStream.Close();
file.InputStream.Dispose();
GC.Collect();
FileInfo file3 = new FileInfo(path);
if (file3.Exists)
{
file3.Delete(); // error :- file because it is being used by another process
}
}
private void CompressImage(Image sourceImage, int imageQuality, string savePath)
{
try
{
//Create an ImageCodecInfo-object for the codec information
ImageCodecInfo jpegCodec = null;
//Set quality factor for compression
EncoderParameter imageQualitysParameter = new EncoderParameter(
System.Drawing.Imaging.Encoder.Quality, imageQuality);
//List all avaible codecs (system wide)
ImageCodecInfo[] alleCodecs = ImageCodecInfo.GetImageEncoders();
EncoderParameters codecParameter = new EncoderParameters(1);
codecParameter.Param[0] = imageQualitysParameter;
//Find and choose JPEG codec
for (int i = 0; i < alleCodecs.Length; i++)
{
if (alleCodecs[i].MimeType == "image/jpeg")
{
jpegCodec = alleCodecs[i];
break;
}
}
//Save compressed image
sourceImage.Save(savePath, jpegCodec, codecParameter);
}
catch (Exception e)
{
}
}
Save image direct in low size with using WebImage
[HttpPost]
public ActionResult Index(HttpPostedFileBase file)
{
WebImage img = new WebImage(file.InputStream);
if (img.Width > 1000)
img.Resize(1000, 1000);
img.Save("path");
return View();
}
I have a web application that allows users to upload images of various formats (PNG, JPEG, GIF). Unfortunately my users are not necessarily technical and end up uploading images that are of way too high quality (and size) than is required.
Is there a way for me to compress these images when serving them? By compress I mean lossy compression, reducing the quality and not necessarily the size. Should I be storing the file format as well if different formats are compressed differently?
Of course you can compress images on the fly using C# and .NET.
Here is a function to do so. First it sets up an Encoder object of type jpg and adds one parameter for the new quailty to it. This is then used to write the image with its new quality to a MemoryStream.
Then an image created from that stream is drawn onto itself with the new dimensions..:
//..
using System.Drawing.Imaging;
using System.IO;
//..
private Image compressImage(string fileName, int newWidth, int newHeight,
int newQuality) // set quality to 1-100, eg 50
{
using (Image image = Image.FromFile(fileName))
using (Image memImage= new Bitmap(image, newWidth, newHeight))
{
ImageCodecInfo myImageCodecInfo;
System.Drawing.Imaging.Encoder myEncoder;
EncoderParameter myEncoderParameter;
EncoderParameters myEncoderParameters;
myImageCodecInfo = GetEncoderInfo("image/jpeg");
myEncoder = System.Drawing.Imaging.Encoder.Quality;
myEncoderParameters = new EncoderParameters(1);
myEncoderParameter = new EncoderParameter(myEncoder, newQuality);
myEncoderParameters.Param[0] = myEncoderParameter;
MemoryStream memStream = new MemoryStream();
memImage.Save(memStream, myImageCodecInfo, myEncoderParameters);
Image newImage = Image.FromStream(memStream);
ImageAttributes imageAttributes = new ImageAttributes();
using (Graphics g = Graphics.FromImage(newImage))
{
g.InterpolationMode =
System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic; //**
g.DrawImage(newImage, new Rectangle(Point.Empty, newImage.Size), 0, 0,
newImage.Width, newImage.Height, GraphicsUnit.Pixel, imageAttributes);
}
return newImage;
}
}
private static ImageCodecInfo GetEncoderInfo(String mimeType)
{
ImageCodecInfo[] encoders;
encoders = ImageCodecInfo.GetImageEncoders();
foreach (ImageCodecInfo ici in encoders)
if (ici.MimeType == mimeType) return ici;
return null;
}
Setting the new dimensions is up to you. If you never want to change the dimensions, take out the parameters and set the values to the old dimensions in the code block If you only sometimes want to change you could pass them in as 0 or -1 and do the check inside..
Quality should be around 30-60%, depending on the motifs. Screenshots with text don't scale down well and need around 60-80% to look good and crispy.
This function returns a jpeg version of the file. If you want, you could create a different Encoder, but for scalable quality, jpeg usually is the best choice.
Obviously you could as well pass in an image instead of a filename or save the newImage to disk instead of returning it. (You should dispose of it in that case.)
Also: you could check the memStream.Length to see if the results are too big and adjust the quality..
Edit: Correction //**
Here is a small application written in .net 4.0 that compresses images in live.
Maybe it can help
https://github.com/user5934951/CompressImageLiveNet
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace export
{
class Program
{
static void Main(string[] args)
{
foreach (string file in Directory.EnumerateFiles(#"C:\Temp\Images"))
{
FileInfo file_info = new FileInfo(file);
var filePathOriginal = Path.Combine(#"C:\Temp\Images",
String.Format("{0}", file_info.Name));
if (File.Exists(filePathOriginal) && file_info.Name.Contains(".png"))
{
Task.Factory.StartNew(() => VaryQualityLevel(filePathOriginal));
Console.WriteLine("Compressed {0}. {1}", count, file_info.Name);
count++;
}
}
Console.WriteLine("End Compressing {0} Images{2}{2}Date: {1}{2}", count, DateTime.Now, Environment.NewLine);
Console.WriteLine("Done");
Console.ReadLine();
}
static void VaryQualityLevel(string file)
{
var img = new Bitmap(file);
try
{
SaveJpeg(img, file);
img.Dispose();
if (File.Exists(file))
File.Delete(file);
File.Move(file + 1, file);
}
catch (Exception ex)
{
// Keep going
}
}
static void SaveJpeg(Image img, string filename)
{
EncoderParameter qualityParam = new EncoderParameter(Encoder.Quality, 100L);
ImageCodecInfo jpegCodec = GetEncoder(ImageFormat.Jpeg);
EncoderParameters encoderParams = new EncoderParameters(1);
encoderParams.Param[0] = qualityParam;
img.Save(filename + 1, jpegCodec, encoderParams);
}
static ImageCodecInfo GetEncoder(ImageFormat format)
{
ImageCodecInfo[] codecs = ImageCodecInfo.GetImageDecoders();
foreach (ImageCodecInfo codec in codecs)
{
if (codec.FormatID == format.Guid)
{
return codec;
}
}
return null;
}
}