问题
So I'm reading in files from a directory, figuring out which way they need to be rotated. Rotating and then saving. That part works... The issue is, after it saves the file it gets recompressed and I go from 1.5meg images to 250k images. I need to keep the file size around the original. I tried using jhead.exe and calling it from a command line but couldn't get any of my arguments to pass in correctly. Here's my code snipit to detect, rotate, and save.
foreach (FileInfo f in dir.GetFiles("*.jpg"))
{
try
{
string ExportName = "";
Bitmap originalImage = new Bitmap(f.FullName.ToString());
Info inf = new Info(originalImage);
gma.Drawing.ImageInfo.Orientation orientation = gma.Drawing.ImageInfo.Orientation.TopLeft;
try
{
orientation = inf.Orientation;
}
catch
{
orientation = gma.Drawing.ImageInfo.Orientation.TopLeft;
}
originalImage = CheckRotation(originalImage, orientation);
progressBar.Value = progressBar.Value + 1;
originalImage.Save(f.FullName.ToString(), ImageFormat.Jpeg);
Application.DoEvents();
}
private Bitmap CheckRotation(Bitmap inputImage, gma.Drawing.ImageInfo.Orientation orientation)
{
Bitmap rotatedImage = inputImage;
switch (orientation)
{
case gma.Drawing.ImageInfo.Orientation.LeftBottom:
rotatedImage.RotateFlip(RotateFlipType.Rotate90FlipXY);
break;
case gma.Drawing.ImageInfo.Orientation.RightTop:
rotatedImage.RotateFlip(RotateFlipType.Rotate90FlipNone);
break;
default:
break;
}
return rotatedImage;
}
回答1:
ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders();
ImageCodecInfo ici = null;
foreach (ImageCodecInfo codec in codecs)
{
if (codec.MimeType == "image/jpeg")
ici = codec;
}
EncoderParameters ep = new EncoderParameters();
ep.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, (long)100);
originalImage.Save(f.FullName.ToString(), ici, ep);
This will use 100% quality - but beware, jpegs are still lossy compression - try using a png if you need loss-less quality.
回答2:
The key for lossless jpeg edit is to use always same QualityLevel and BitmapCreateOptions.PreservePixelFormat | BitmapCreateOptions.IgnoreColorProfile with BitmapCacheOption.None.
And be aware that even if you use QualityLevel 100, quality will go down. With this method goes down just first time, because it goes from unknown QualityLevel to 80, but every other jpeg edit is lossless.
RotateJpeg(@"d:\!test\TestInTest\20160209_143609.jpg", 80, Rotation.Rotate90);
public bool RotateJpeg(string filePath, int quality, Rotation rotation) {
var original = new FileInfo(filePath);
if (!original.Exists) return false;
var temp = new FileInfo(original.FullName.Replace(".", "_temp."));
const BitmapCreateOptions createOptions = BitmapCreateOptions.PreservePixelFormat | BitmapCreateOptions.IgnoreColorProfile;
try {
using (Stream originalFileStream = File.Open(original.FullName, FileMode.Open, FileAccess.Read)) {
JpegBitmapEncoder encoder = new JpegBitmapEncoder {QualityLevel = quality, Rotation = rotation};
//BitmapCreateOptions.PreservePixelFormat | BitmapCreateOptions.IgnoreColorProfile and BitmapCacheOption.None
//is a KEY to lossless jpeg edit if the QualityLevel is the same
encoder.Frames.Add(BitmapFrame.Create(originalFileStream, createOptions, BitmapCacheOption.None));
using (Stream newFileStream = File.Open(temp.FullName, FileMode.Create, FileAccess.ReadWrite)) {
encoder.Save(newFileStream);
}
}
}
catch (Exception) {
return false;
}
try {
temp.CreationTime = original.CreationTime;
original.Delete();
temp.MoveTo(original.FullName);
}
catch (Exception) {
return false;
}
return true;
}
回答3:
Easy...
public static void Rotate90(string fileName)
{
Image Pic;
string FileNameTemp;
Encoder Enc = Encoder.Transformation;
EncoderParameters EncParms = new EncoderParameters(1);
EncoderParameter EncParm;
ImageCodecInfo CodecInfo = GetEncoderInfo("image/jpeg");
// load the image to change
Pic = Image.FromFile(fileName);
// we cannot store in the same image, so use a temporary image instead
FileNameTemp = fileName + ".temp";
// for rewriting without recompression we must rotate the image 90 degrees
EncParm = new EncoderParameter(Enc,(long)EncoderValue.TransformRotate90);
EncParms.Param[0] = EncParm;
// now write the rotated image with new description
Pic.Save(FileNameTemp,CodecInfo,EncParms);
Pic.Dispose();
Pic = null;
// delete the original file, will be replaced later
System.IO.File.Delete(fileName);
System.IO.File.Move(FileNameTemp, fileName);
}
来源:https://stackoverflow.com/questions/9505608/c-sharp-rotating-jpg-without-losing-too-much-quality