C#在不损失太多质量的情况下旋转JPG

本文关键字:情况下 旋转 JPG 损失 太多 | 更新日期: 2023-09-27 18:26:06

所以我正在从目录中读取文件,弄清楚它们需要以何种方式旋转。旋转然后保存。那部分工作。。。问题是,在它保存文件后,它会被重新压缩,我从1.5meg的图像变成了250k的图像。我需要将文件大小保持在原始大小左右。我尝试使用jhead.exe并从命令行调用它,但无法正确传递任何参数。这是我用来检测、旋转和保存的代码片段。

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;
}

C#在不损失太多质量的情况下旋转JPG

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);

这将使用100%的质量-但要注意,jpegs仍然是有损压缩-如果您需要较少损失的质量,请尝试使用png。

无损jpeg编辑的关键是使用始终相同的QualityLevel和BitmapCreateOptions.PreservePixelFormat|BitmapCreateOptions.IgnoreColorProfile与BitmapCacheOption.None.

请注意,即使您使用质量等级100,质量也会下降。这种方法第一次就下降了,因为它从未知的QualityLevel变为80,但每隔一次jpeg编辑都是无损的。

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;
}

简单。。。

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://learn.microsoft.com/en-us/windows/win32/gdiplus/-gdiplus-transforming-a-jpeg-image-without-loss-of-information-use