jjzjj

c# - 调整大小时,某些图像正在旋转

coder 2024-06-01 原文

简而言之,以下代码的目的是根据目标大小和乘数(1x、2x、3x)调整图像大小。这工作正常,除了出于某种原因我还没有确定一些图像正在旋转。

public void ResizeImage(TargetSize targetSize, ResizeMultiplier multiplier, Stream input, Stream output)
{
    using (var image = Image.FromStream(input))
    {
        // Calculate the resize factor
        var scaleFactor = targetSize.CalculateScaleFactor(image.Width, image.Height);
        scaleFactor /= (int)multiplier; // Enum is effectively named constant with a value of 1, 2, or 3

        var newWidth = (int)Math.Floor(image.Width / scaleFactor);
        var newHeight = (int)Math.Floor(image.Height / scaleFactor);
        using (var newBitmap = new Bitmap(newWidth, newHeight))
        {
            using (var imageScaler = Graphics.FromImage(newBitmap))
            {
                imageScaler.CompositingQuality = CompositingQuality.HighQuality;
                imageScaler.SmoothingMode = SmoothingMode.HighQuality;
                imageScaler.InterpolationMode = InterpolationMode.HighQualityBicubic;

                var imageRectangle = new Rectangle(0, 0, newWidth, newHeight);
                imageScaler.DrawImage(image, imageRectangle);

                newBitmap.Save(output, image.RawFormat);
            }
        }
    }
}

// Class definition for the class used in the method above
public class TargetSize
{
    /// <summary>
    /// The _width
    /// </summary>
    private readonly int _width;

    /// <summary>
    /// The _height
    /// </summary>
    private readonly int _height;

    /// <summary>
    /// Initializes a new instance of the <see cref="TargetSize"/> class.
    /// </summary>
    /// <param name="width">The width.</param>
    /// <param name="height">The height.</param>
    public TargetSize(int width, int height)
    {
        _height = height;
        _width = width;
    }

    /// <summary>
    /// Calculates the scale factor.
    /// </summary>
    /// <param name="width">The width.</param>
    /// <param name="height">The height.</param>
    /// <returns></returns>
    public decimal CalculateScaleFactor(int width, int height)
    {
        // Scale proportinately
        var heightScaleFactor = decimal.Divide(height, _height);
        var widthScaleFactor = decimal.Divide(width, _width);

        // Use the smaller of the two as the final scale factor so the image is never undersized.
        return widthScaleFactor > heightScaleFactor ? heightScaleFactor : widthScaleFactor;
    }
}

// NUnit integration test case I'm using to exercise the above code
[Test]
public void ResizeImage_Persistant_Single()
{
    // Read the image from disk
    using (var fileStream = File.OpenRead(@"TestData\dog.jpg"))
    {
        using (var outputStream = new MemoryStream())
        {
            // Call the resize image method detailed above. ResizeMultiplier.Medium casts to 2.
            _sut.ResizeImage(new TargetSize(200, 200), ResizeMultiplier.Medium, fileStream, outputStream);
            using (var newImage = Image.FromStream(outputStream))
            {
                // Save the resized image to disk
                newImage.Save(@"TestData\ImageResizerTests.ResizeImage_Persistant_Single.jpg");
            }
        }
    }
}

例如这张图片:

适当缩放但这张图片:

颠倒了。值得一提的是,图片在预览区上传到本站时,也出现了上下颠倒的现象。这个事实(我显然刚刚发现)强烈地让我觉得这张照片有些有趣。不管我的代码需要处理它。

Imgur“修复”了上面的文件(因为当我通过我的代码运行它时它现在不旋转)所以我将它上传到 Google Drive 。如果您右键单击图像(在 FireFox 中我没有测试过其他浏览器)并单击 Save Image As... 那么图像不会随着我上面的代码旋转。如果您单击标题中的下载按钮,那么图像会随着我的代码旋转……这里是 another copy用我的代码翻转 180 度的狗图像。这一切都非常奇怪,我不知道我做错了什么......

需要说明的是,我的目标是在不旋转图像的情况下调整图像大小。


根据评论进行编辑:

旋转/翻转的图像将以相同的方式一致地旋转/翻转。例如,这张狗图片将始终翻转 180 度。有些图片会侧放(旋转 90 或 270 度)。我已经验证了 newWidth , newHeight , scaleFactor , targetSize (私有(private)变量)和image.Height/image.Width当狗图片翻转 180 度时变量都是正的。

我认为这不是特定工具的产物。我看到旋转通过; Windows Explorer、Windows Image Viewer、库存 Macintosh 图像查看器、FireFox 等中的预览。实际上,我公司的一位 iOS 开发人员在我们的应用程序中看到了这个问题,引起了我的注意。我认为有太多工具将其视为查看器问题。

最佳答案

感谢 Chris Farmer 的大力帮助1Mark Ransom 2 我能够回答我自己的问题。

核心问题是某些图像上的 EXIF 数据改变了图像的方向。当我调整图像大小时,所有 EXIF 数据都被剥离了。由于 EXIF 数据被剥离,观看者不知道图像的方向应该不同。这使我认为调整大小的代码正在旋转一些图像。值得注意的是,当您在 Windows 资源管理器中右键单击图像时,此方向信息不会显示在详细信息 View 中。您需要在图像属性对象中搜索它或使用像 this one 这样的在线 View 。 .

使用 data from here 3 我能够创建以下命名常量:

private const int OrientationKey = 0x0112;
private const int NotSpecified = 0;
private const int NormalOrientation = 1;
private const int MirrorHorizontal = 2;
private const int UpsideDown = 3;
private const int MirrorVertical = 4;
private const int MirrorHorizontalAndRotateRight = 5;
private const int RotateLeft = 6;
private const int MirorHorizontalAndRotateLeft = 7;
private const int RotateRight = 8;

使用这些命名常量,我扩展了我的 ResizeImage 方法来读取:

public void ResizeImage(TargetSize targetSize, ResizeMultiplier multiplier, Stream input, Stream output)
{
    using (var image = Image.FromStream(input))
    {
        // Calculate the resize factor
        var scaleFactor = targetSize.CalculateScaleFactor(image.Width, image.Height);
        scaleFactor /= (int)multiplier; 

        var newWidth = (int)Math.Floor(image.Width / scaleFactor);
        var newHeight = (int)Math.Floor(image.Height / scaleFactor);
        using (var newBitmap = new Bitmap(newWidth, newHeight))
        {
            using (var imageScaler = Graphics.FromImage(newBitmap))
            {
                imageScaler.CompositingQuality = CompositingQuality.HighQuality;
                imageScaler.SmoothingMode = SmoothingMode.HighQuality;
                imageScaler.InterpolationMode = InterpolationMode.HighQualityBicubic;

                var imageRectangle = new Rectangle(0, 0, newWidth, newHeight);
                imageScaler.DrawImage(image, imageRectangle);

                // Fix orientation if needed.
                if (image.PropertyIdList.Contains(OrientationKey))
                {
                    var orientation = (int)image.GetPropertyItem(OrientationKey).Value[0];
                    switch (orientation)
                    {
                        case NotSpecified: // Assume it is good.
                        case NormalOrientation:
                            // No rotation required.
                            break;
                        case MirrorHorizontal:
                            newBitmap.RotateFlip(RotateFlipType.RotateNoneFlipX);
                            break;
                        case UpsideDown:
                            newBitmap.RotateFlip(RotateFlipType.Rotate180FlipNone);
                            break;
                        case MirrorVertical:
                            newBitmap.RotateFlip(RotateFlipType.Rotate180FlipX);
                            break;
                        case MirrorHorizontalAndRotateRight:
                            newBitmap.RotateFlip(RotateFlipType.Rotate90FlipX);
                            break;
                        case RotateLeft:
                            newBitmap.RotateFlip(RotateFlipType.Rotate90FlipNone);
                            break;
                        case MirorHorizontalAndRotateLeft:
                            newBitmap.RotateFlip(RotateFlipType.Rotate270FlipX);
                            break;
                        case RotateRight:
                            newBitmap.RotateFlip(RotateFlipType.Rotate270FlipNone);
                            break;
                        default:
                            throw new NotImplementedException("An orientation of " + orientation + " isn't implemented.");
                    }
                }
                newBitmap.Save(output, image.RawFormat);
            }
        }
    }
}

细心的人会注意到大部分附加代码都被提取了 from this answer一个相关的问题。


1:谁是对的,但我不明白他的目的。

2:谁向我展示了 Chris Farmer 想说的话。

3:Orientation 键值为 confirmed here .

关于c# - 调整大小时,某些图像正在旋转,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33310562/

有关c# - 调整大小时,某些图像正在旋转的更多相关文章

  1. ruby-on-rails - 在 Rails 中将文件大小字符串转换为等效千字节 - 2

    我的目标是转换表单输入,例如“100兆字节”或“1GB”,并将其转换为我可以存储在数据库中的文件大小(以千字节为单位)。目前,我有这个:defquota_convert@regex=/([0-9]+)(.*)s/@sizes=%w{kilobytemegabytegigabyte}m=self.quota.match(@regex)if@sizes.include?m[2]eval("self.quota=#{m[1]}.#{m[2]}")endend这有效,但前提是输入是倍数(“gigabytes”,而不是“gigabyte”)并且由于使用了eval看起来疯狂不安全。所以,功能正常,

  2. ruby-on-rails - 在 Rails 和 ActiveRecord 中查询时忽略某些字段 - 2

    我知道我可以指定某些字段来使用pluck查询数据库。ids=Item.where('due_at但是我想知道,是否有一种方法可以指定我想避免从数据库查询的某些字段。某种反拔?posts=Post.where(published:true).do_not_lookup(:enormous_field) 最佳答案 Model#attribute_names应该返回列/属性数组。您可以排除其中一些并传递给pluck或select方法。像这样:posts=Post.where(published:true).select(Post.attr

  3. c# - 如何在 ruby​​ 中调用 C# dll? - 2

    如何在ruby​​中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL

  4. C# 到 Ruby sha1 base64 编码 - 2

    我正在尝试在Ruby中复制Convert.ToBase64String()行为。这是我的C#代码:varsha1=newSHA1CryptoServiceProvider();varpasswordBytes=Encoding.UTF8.GetBytes("password");varpasswordHash=sha1.ComputeHash(passwordBytes);returnConvert.ToBase64String(passwordHash);//returns"W6ph5Mm5Pz8GgiULbPgzG37mj9g="当我在Ruby中尝试同样的事情时,我得到了相同sha

  5. ruby-on-rails - 添加回形针新样式不影响旧上传的图像 - 2

    我有带有Logo图像的公司模型has_attached_file:logo我用他们的Logo创建了许多公司。现在,我需要添加新样式has_attached_file:logo,:styles=>{:small=>"30x15>",:medium=>"155x85>"}我是否应该重新上传所有旧数据以重新生成新样式?我不这么认为……或者有什么rake任务可以重新生成样式吗? 最佳答案 参见Thumbnail-Generation.如果rake任务不适合你,你应该能够在控制台中使用一个片段来调用重新处理!关于相关公司

  6. 旋转矩阵的几何意义 - 2

    点向量坐标矩阵的几何意义介绍旋转矩阵的几何含义之前,先介绍一下点向量坐标矩阵的几何含义点:在一维空间下就是一个标量,如同一条直线上,以任意某一个位置为0点,以一定的尺度间隔为1,2,3...,相反方向为-1,-2,-3...;如此就形成了一维坐标系,这时候任何一个点都可以用一个数值表示,如点p1=5,即即从原点出发沿着x轴正方向移动5个尺度;点p2=-3,负方向移动3个尺度;     在一维坐标系上过原点做垂直于一维坐标系的直线,则形成了二维坐标系,此时描述一个点需要两个数值来表示点p3=(3,2),即从原点出发沿着x轴正方向移动3个尺度,在此基础上沿着y轴正方向移动两个尺度的位置就是点p3。

  7. Unity 3D 制作开关门动画,旋转门制作,推拉门制作,门把手动画制作 - 2

    Unity自动旋转动画1.开门需要门把手先动,门再动2.关门需要门先动,门把手再动3.中途播放过程中不可以再次进行操作觉得太复杂?查看我的文章开关门简易进阶版效果:如果这个门可以直接打开的话,就不需要放置"门把手"如果门把手还有钥匙需要旋转,那就可以把钥匙放在门把手的"门把手",理论上是可以无限套娃的可调整参数有:角度,反向,轴向,速度运行时点击Test进行测试自己写的代码比较垃圾,命名与结构比较拉,高手轻点喷,新手有类似的需求可以拿去做参考上代码usingSystem.Collections;usingSystem.Collections.Generic;usingUnityEngine;u

  8. 基于C#实现简易绘图工具【100010177】 - 2

    C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.

  9. ruby-on-rails - 在 Ruby (on Rails) 中使用 imgur API 获取图像 - 2

    我正在尝试使用Ruby2.0.0和Rails4.0.0提供的API从imgur中提取图像。我已尝试按照Ruby2.0.0文档中列出的各种方式构建http请求,但均无济于事。代码如下:require'net/http'require'net/https'defimgurheaders={"Authorization"=>"Client-ID"+my_client_id}path="/3/gallery/image/#{img_id}.json"uri=URI("https://api.imgur.com"+path)request,data=Net::HTTP::Get.new(path

  10. python ffmpeg 使用 pyav 转换 一组图像 到 视频 - 2

    2022/8/4更新支持加入水印水印必须包含透明图像,并且水印图像大小要等于原图像的大小pythonconvert_image_to_video.py-f30-mwatermark.pngim_dirout.mkv2022/6/21更新让命令行参数更加易用新的命令行使用方法pythonconvert_image_to_video.py-f30im_dirout.mkvFFMPEG命令行转换一组JPG图像到视频时,是将这组图像视为MJPG流。我需要转换一组PNG图像到视频,FFMPEG就不认了。pyav内置了ffmpeg库,不需要系统带有ffmpeg工具因此我使用ffmpeg的python包装p

随机推荐