调整大小时某些图像正在旋转
Posted
技术标签:
【中文标题】调整大小时某些图像正在旋转【英文标题】:Some images are being rotated when resized 【发布时间】:2016-01-23 11:24:34 【问题描述】:简而言之,以下代码的目的是根据目标大小和乘数(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 度。这一切都很离奇,不知道自己做错了什么……
要明确我的目标是在不旋转图像的情况下调整图像大小。
基于 cmets 的编辑:
旋转/翻转的图像会以相同的方式始终如一地进行。例如,这张狗图片将始终翻转 180 度。有些图片会侧放(旋转 90 或 270 度)。我已经验证了当狗图片翻转 180 度时,newWidth
、newHeight
、scaleFactor
、targetSize
(私有变量)和image.Height/image.Width
变量都是正数。
我不相信这是特定工具的产物。我看到了旋转; Windows Explorer、Windows Image Viewer、库存 Macintosh 图像查看器、FireFox 等中的预览。这个问题实际上是由我公司的一位 ios 开发人员在我们的应用程序中看到的。我认为有太多工具看到了这一点,而不是查看器问题。
【问题讨论】:
这可能是一个愚蠢的问题,但你确定这不是你用来查看图像的任何工具的产物吗?一些图像查看器可能会尝试通过将面部定向为直立和/或使用其他图像提示来“纠正”方向来帮助您。 相机 EXIF 信息有时可用于自动旋转图像,但我从未见过它会颠倒某些东西。 根据我在regex.info/exif.cgi 找到的第一个在线EXIF 查看器,这只狗确实旋转了180 度(Orientation
字段)。
【参考方案1】:
感谢Chris Farmer1 和Mark Ransom2 的出色帮助,我能够回答自己的问题。
核心问题是某些图像的 EXIF 数据改变了图像的方向。当我调整图像大小时,所有的 EXIF 数据都被剥离了。由于 EXIF 数据被剥离,观众不知道图像应该以不同的方向定位。这使我认为调整大小的代码正在旋转一些图像。值得注意的是,当您在 Windows 资源管理器中右键单击图像时,此方向信息不会显示在详细信息视图中。您需要在图像属性对象中搜索或使用this one 等在线视图。
使用data from here3 我能够创建以下命名常量:
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:方向键值为confirmed here。
【讨论】:
什么是ResizeMultiplier
? OrientationKey
?以上是关于调整大小时某些图像正在旋转的主要内容,如果未能解决你的问题,请参考以下文章
使用 node sharp 包调整图像大小并上传到 s3 时,它会旋转