resize时,某些图像正在旋转

简而言之,以下代码的目的是根据目标大小和乘数(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 { ///  /// The _width ///  private readonly int _width; ///  /// The _height ///  private readonly int _height; ///  /// Initializes a new instance of the  class. ///  /// The width. /// The height. public TargetSize(int width, int height) { _height = height; _width = width; } ///  /// Calculates the scale factor. ///  /// The width. /// The height. ///  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云端硬盘 。 如果您右键单击图像(在FireFox中我没有测试过其他浏览器)并单击“ 将图像另存为...”,则图像不会随上面的代码一起旋转。 如果单击标题中的下载按钮,则图像会随我的代码一起旋转….这是狗图像的另一个副本 ,用我的代码翻转180度。 所有这一切都很奇怪,我不知道我做错了什么……

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


根据评论进行编辑:

旋转/翻转的图像将以相同的方式一致地执行。 例如,这张狗图片将始终翻转180度。 有些照片会放在一边(旋转90度或270度)。 我已经validation了当dog图片翻转180度时, targetSizenewHeightscaleFactortargetSize (私有变量)和image.Height/image.Width变量都是正数。

我不相信这是特定工具的神器。 我看到旋转通过; Windows资源管理器,Windows图像查看器,Macintosh图像查看器,FireFox等中的预览实际上我的公司的iOS开发人员在我们的应用程序中看到了这个问题。 我认为太多的工具都会看到它,因为它是一个观众问题。

感谢Chris Farmer 1和Mark Ransom 2的出色帮助,我能够回答我自己的问题。

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

使用此处的数据 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); } } } } 

一个善于观察的人会注意到,大多数附加代码都是从这个相关问题的答案中提取出来的 。


1谁是对的钱,但我不明白他在开什么车。

2谁向我展示了克里斯·法默试图说的话。

3此处确认了 Orientation键值。