C# 获取EXIF方向标签,旋转至正确方向,处理图像并以正确方向保存图像

C# 获取EXIF方向标签,旋转至正确方向,处理图像并以正确方向保存图像,c#,.net,gdi+,exif,system.drawing,C#,.net,Gdi+,Exif,System.drawing,我的程序批量处理一些图像。我当前需要读取图像的exif方向标记,将其旋转到正确的方向,进行一些处理,并保存图像,不带任何exif方向标记,但旋转正确。(或带正确方向的exif标记) 我正在阅读EXIF并使用以下工具进行旋转: 这很有效。但在保存此图像时,exif旋转标记仍然存在,这使得图像方向错误。 我能做的就是 var bmp = new Bitmap(OS.FileName); var exif = new EXIFextractor(ref bmp

我的程序批量处理一些图像。我当前需要读取图像的exif方向标记,将其旋转到正确的方向,进行一些处理,并保存图像,不带任何exif方向标记,但旋转正确。(或带正确方向的exif标记)

我正在阅读EXIF并使用以下工具进行旋转:

这很有效。但在保存此图像时,exif旋转标记仍然存在,这使得图像方向错误。 我能做的就是

       var bmp = new Bitmap(OS.FileName);       
       var exif = new EXIFextractor(ref bmp, "n");
       exif.setTag(0x112, "1");
       bmp.save("strippedexifimage");
但是,当在循环中使用此代码时,我的程序会慢50%左右。有其他方法吗?可能是在应用旋转后反向旋转图像的代码,这是否有效

更新:

@汉斯·帕桑:你的答案是正确的,但它产生的结果与图书馆产生的结果是一样的。当我使用bitmap.save()时,库和您的代码都可以工作。但是当我根据用户选择的格式使用以下代码保存图像时。Imgformat可以是
Imgformat=“image/png”;,imgformat=“image/jpeg”等一些图像仍然使用错误的exif方向标记保存。ie:我在windows资源管理器中看到错误的图像预览,当我用MS Paint打开图像时,图像的方向正确。我做错了什么?请帮忙

private void saveJpeg(string path, Bitmap img, long quality)
        {


            EncoderParameter qualityParam = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, quality);


            ImageCodecInfo Codec = this.getEncoderInfo(imgformat);
             if (Codec == null)
              return;

            EncoderParameters encoderParams = new EncoderParameters(1);
            encoderParams.Param[0] = qualityParam;    
            img.Save(path + ext, Codec, encoderParams);
        }



 private 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;
        }
private void saveJpeg(字符串路径、位图img、长质量)
{
EncoderParameter qualityParam=新的编码器参数(System.Drawing.Imaging.Encoder.Quality,Quality);
ImageCodecInfo Codec=this.getEncoderInfo(imgformat);
如果(编解码器==null)
返回;
EncoderParameters encoderParams=新的EncoderParameters(1);
encoderParams.Param[0]=qualityParam;
保存(路径+文本、编解码器、编码器参数);
}
私有ImageCodeInfo getEncoderInfo(字符串mimeType)
{
//获取所有图像格式的图像编解码器
ImageCodecInfo[]codecs=ImageCodecInfo.GetImageEncoders();
//找到正确的图像编解码器
对于(int i=0;i
使用库实现功能可以节省大量时间。否则,当库设计糟糕或难以使用时,您将被困数天
ref bmp
是第一个响亮的警报,您试图将该值指定为字符串,这让您感到绝望。这是有吸引力的,因为您不必考虑“类型”在正确的StasgAug()超载中可能意味着什么。它是类型3,需要一个包含两个元素的字节[]。这是根本无法发现的,您只能在不需要时正确使用库

扔掉图书馆,这没用。存储方向的EXIF标记的id为0x112,编码为16位值。只需使用System.Drawing直接读取值并强制返回1。像这样:

static void FixImageOrientation(Image srce) {
    const int ExifOrientationId = 0x112;
    // Read orientation tag
    if (!srce.PropertyIdList.Contains(ExifOrientationId)) return;
    var prop = srce.GetPropertyItem(ExifOrientationId);
    var orient = BitConverter.ToInt16(prop.Value, 0);
    // Force value to 1
    prop.Value = BitConverter.GetBytes((short)1);
    srce.SetPropertyItem(prop);

    // Rotate/flip image according to <orient>
    switch (orient) {
        // etc...
    }
}
static void FixImageOrientation(图像srce){
常量int ExifOrientationId=0x112;
//读取方向标签
如果(!srce.PropertyIdList.Contains(ExifOrientationId))返回;
var prop=srce.GetPropertyItem(ExifOrientationId);
var orient=位转换器.ToInt16(属性值,0);
//强制值为1
prop.Value=BitConverter.GetBytes((短)1);
srce.SetPropertyItem(道具);
//根据需要旋转/翻转图像
开关(方向){
//等等。。。
}
}

非常感谢。我搜索了一下是否有直接通过代码执行的方法,但找不到任何方法。
orient
是否返回我的开关盒中的值(我的意思是1,2,3..等等)呵呵,我还记得在某个时候抓取了特定的库。。。然后扔掉它,重新编写我需要的规格部分。像往常一样,好建议,汉斯@atlaste我有以不同格式保存图像的代码。我希望保留这些代码,因为整个工作流都依赖于它。当我使用savejpeg方法时会出现错误。请告诉我这里出了什么问题。@techno我想缩略图不会看方向标记,或者这是缓存的结果(缩略图通常是缓存的)。在软件中,你唯一可以确定的是,通过检查数据规格,你没有犯错误。第三方软件的行为……嗯,这不是你可以控制的。因此,除了“我会遵循规格”之外,你的问题没有好的答案@atlaste这不是缩略图缓存的问题。有一个叫做“我通过命令行使用它并从图像(如
exiv2 rm myimage.jpg
)中删除所有exif数据”的实用程序。一旦我这样做,程序生成的错误旋转图像将返回到原始方向。我尝试将其合并到代码中。渲染的实际时间使用exiv2和库提取exif,使用我的旧版本程序的图像大约需要34秒。请看ImageMagick。我认为它可以满足您的所有要求。您可以为它编写代码..或者按原样使用它。:)
  var exif = new EXIFextractor(ref bmp, "n")
static void FixImageOrientation(Image srce) {
    const int ExifOrientationId = 0x112;
    // Read orientation tag
    if (!srce.PropertyIdList.Contains(ExifOrientationId)) return;
    var prop = srce.GetPropertyItem(ExifOrientationId);
    var orient = BitConverter.ToInt16(prop.Value, 0);
    // Force value to 1
    prop.Value = BitConverter.GetBytes((short)1);
    srce.SetPropertyItem(prop);

    // Rotate/flip image according to <orient>
    switch (orient) {
        // etc...
    }
}