UIImage 数据始终处于横向模式
似乎当我在纵向模式下使用相机拍照时,UIImage
具有正确的尺寸/长宽比(1536x2048 / 3:4)和方向(右),导出到文件(使用 UIImage.AsPNG().Save()
),它始终以横向模式显示(2048x1536,4:3)。
这是真的吗,还是我做错了什么?是否有解决方法,例如使用 ALAssetsLibrary.WriteImageToSavedPhotosAlbum
?
更新:最初我认为UIImage.SaveToPhotosAlbum()
也发生了这种情况,但经过仔细检查,我意识到这种情况下的UIImage
并不是来自相机的原始数据,而是根据早期 AsPNG()
保存的数据重建的数据。
再次更新:看起来这是 iPhone 相机的一般“功能”,修复它的唯一方法是手动旋转图像。我尝试将此代码移植到MT,如下所示,但是什么我似乎所做的是发明一种新方法来创建正确尺寸和纵横比的空白图像。有人能发现这个错误吗?
public static class ImageUtils
{
static float DefaultMaxSize = 960;
public static UIImage ScaleAndRotateImage (UIImage image) {
return ScaleAndRotateImage(image, DefaultMaxSize);
}
public static UIImage ScaleAndRotateImage (UIImage image, float maxSize)
{
CGImage imgRef = image.CGImage;
float width = imgRef.Width;
float height = imgRef.Height;
CGAffineTransform transform = CGAffineTransform.MakeIdentity();
RectangleF bounds = new RectangleF (0, 0, width, height);
if (width > maxSize || height > maxSize) {
float ratio = width / height;
if (ratio > 1) {
bounds.Width = maxSize;
bounds.Height = bounds.Width / ratio;
} else {
bounds.Height = maxSize;
bounds.Width = bounds.Height * ratio;
}
}
float scaleRatio = bounds.Width / width;
SizeF imageSize = new SizeF (imgRef.Width, imgRef.Height);
float boundHeight;
UIImageOrientation orient = image.Orientation;
if (orient == UIImageOrientation.Up) {
//EXIF = 1
transform = CGAffineTransform.MakeIdentity();
} else if (orient == UIImageOrientation.UpMirrored) {
//EXIF = 2
transform = CGAffineTransform.MakeTranslation (imageSize.Width, 0);
transform.Scale (-1.0f, 1.0f);
} else if (orient == UIImageOrientation.Down) {
//EXIF = 3
transform = CGAffineTransform.MakeTranslation (imageSize.Width, imageSize.Height);
transform.Rotate ((float) Math.PI);
} else if (orient == UIImageOrientation.DownMirrored) {
//EXIF = 4
transform = CGAffineTransform.MakeTranslation (0, imageSize.Height);
transform.Scale (1.0f, -1.0f);
} else if (orient == UIImageOrientation.LeftMirrored) {
//EXIF = 5
boundHeight = bounds.Height;
bounds.Height = bounds.Width;
bounds.Width = boundHeight;
transform = CGAffineTransform.MakeTranslation (imageSize.Height, imageSize.Width);
transform.Scale (-1.0f, 1.0f);
transform.Rotate ((float)(3.0f * Math.PI / 2.0));
} else if (orient == UIImageOrientation.Left) {
//EXIF = 6
boundHeight = bounds.Height;
bounds.Height = bounds.Width;
bounds.Width = boundHeight;
transform = CGAffineTransform.MakeTranslation (0, imageSize.Width);
transform.Rotate ((float)(3.0f * Math.PI / 2.0));
} else if (orient == UIImageOrientation.RightMirrored) {
//EXIF = 7
boundHeight = bounds.Height;
bounds.Height = bounds.Width;
bounds.Width = boundHeight;
transform = CGAffineTransform.MakeScale (-1.0f, 1.0f);
transform.Rotate ((float)(Math.PI / 2.0));
} else if (orient == UIImageOrientation.Right) {
//EXIF = 8
boundHeight = bounds.Height;
bounds.Height = bounds.Width;
bounds.Width = boundHeight;
transform = CGAffineTransform.MakeTranslation (imageSize.Height, 0);
transform.Rotate ((float)(Math.PI / 2.0));
} else {
throw new InvalidOperationException ("Invalid image orientation");
}
UIGraphics.BeginImageContext(bounds.Size);
CGContext context = UIGraphics.GetCurrentContext ();
if (orient == UIImageOrientation.Right || orient == UIImageOrientation.Left) {
context.ScaleCTM (-scaleRatio, scaleRatio);
context.TranslateCTM (-height, 0f);
} else {
context.ScaleCTM (scaleRatio, -scaleRatio);
context.TranslateCTM (0f, -height);
}
context.ConcatCTM(transform);
context.DrawImage (new RectangleF(0, 0, width, height), imgRef);
UIImage imageCopy = UIGraphics.GetImageFromCurrentImageContext ();
UIGraphics.EndImageContext ();
return imageCopy;
}
}
It seems as though when I take a picture with the camera in portrait mode, the UIImage
has the correct size/aspect ratio (1536x2048 / 3:4) and orientation (Right), exported to a file (with UIImage.AsPNG().Save()
), it always comes out in landscape mode (2048x1536, 4:3).
Is this for real, or am I doing something wrong? And is there a workaround, e.g. with ALAssetsLibrary.WriteImageToSavedPhotosAlbum
?
Update: Originally I thought this also happened with UIImage.SaveToPhotosAlbum()
, but on closer inspection I realize that the UIImage
in that case was not the original from the camera, but rather one reconstituted from earlier AsPNG()
saved data.
Update again: It looks like this is a general 'feature' of the iPhone camera, and the only way to fix it is by manually rotating the image. I tried porting this code to MT, as shown below, but what I seem to have done is invent a new way to create blank images of the right size and aspect ratio. Can anyone spot the bug?
public static class ImageUtils
{
static float DefaultMaxSize = 960;
public static UIImage ScaleAndRotateImage (UIImage image) {
return ScaleAndRotateImage(image, DefaultMaxSize);
}
public static UIImage ScaleAndRotateImage (UIImage image, float maxSize)
{
CGImage imgRef = image.CGImage;
float width = imgRef.Width;
float height = imgRef.Height;
CGAffineTransform transform = CGAffineTransform.MakeIdentity();
RectangleF bounds = new RectangleF (0, 0, width, height);
if (width > maxSize || height > maxSize) {
float ratio = width / height;
if (ratio > 1) {
bounds.Width = maxSize;
bounds.Height = bounds.Width / ratio;
} else {
bounds.Height = maxSize;
bounds.Width = bounds.Height * ratio;
}
}
float scaleRatio = bounds.Width / width;
SizeF imageSize = new SizeF (imgRef.Width, imgRef.Height);
float boundHeight;
UIImageOrientation orient = image.Orientation;
if (orient == UIImageOrientation.Up) {
//EXIF = 1
transform = CGAffineTransform.MakeIdentity();
} else if (orient == UIImageOrientation.UpMirrored) {
//EXIF = 2
transform = CGAffineTransform.MakeTranslation (imageSize.Width, 0);
transform.Scale (-1.0f, 1.0f);
} else if (orient == UIImageOrientation.Down) {
//EXIF = 3
transform = CGAffineTransform.MakeTranslation (imageSize.Width, imageSize.Height);
transform.Rotate ((float) Math.PI);
} else if (orient == UIImageOrientation.DownMirrored) {
//EXIF = 4
transform = CGAffineTransform.MakeTranslation (0, imageSize.Height);
transform.Scale (1.0f, -1.0f);
} else if (orient == UIImageOrientation.LeftMirrored) {
//EXIF = 5
boundHeight = bounds.Height;
bounds.Height = bounds.Width;
bounds.Width = boundHeight;
transform = CGAffineTransform.MakeTranslation (imageSize.Height, imageSize.Width);
transform.Scale (-1.0f, 1.0f);
transform.Rotate ((float)(3.0f * Math.PI / 2.0));
} else if (orient == UIImageOrientation.Left) {
//EXIF = 6
boundHeight = bounds.Height;
bounds.Height = bounds.Width;
bounds.Width = boundHeight;
transform = CGAffineTransform.MakeTranslation (0, imageSize.Width);
transform.Rotate ((float)(3.0f * Math.PI / 2.0));
} else if (orient == UIImageOrientation.RightMirrored) {
//EXIF = 7
boundHeight = bounds.Height;
bounds.Height = bounds.Width;
bounds.Width = boundHeight;
transform = CGAffineTransform.MakeScale (-1.0f, 1.0f);
transform.Rotate ((float)(Math.PI / 2.0));
} else if (orient == UIImageOrientation.Right) {
//EXIF = 8
boundHeight = bounds.Height;
bounds.Height = bounds.Width;
bounds.Width = boundHeight;
transform = CGAffineTransform.MakeTranslation (imageSize.Height, 0);
transform.Rotate ((float)(Math.PI / 2.0));
} else {
throw new InvalidOperationException ("Invalid image orientation");
}
UIGraphics.BeginImageContext(bounds.Size);
CGContext context = UIGraphics.GetCurrentContext ();
if (orient == UIImageOrientation.Right || orient == UIImageOrientation.Left) {
context.ScaleCTM (-scaleRatio, scaleRatio);
context.TranslateCTM (-height, 0f);
} else {
context.ScaleCTM (scaleRatio, -scaleRatio);
context.TranslateCTM (0f, -height);
}
context.ConcatCTM(transform);
context.DrawImage (new RectangleF(0, 0, width, height), imgRef);
UIImage imageCopy = UIGraphics.GetImageFromCurrentImageContext ();
UIGraphics.EndImageContext ();
return imageCopy;
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我终于让这个工作了。这是一个包含代码的要点:
https://gist.github.com/890460
和我的博客文章关于它:
http:// /www.fastchicken.co.nz/2011/03/28/scaling-and-rotating-an-image-in-monotouch/
I finally got this to work. Here's a gist which has the code:
https://gist.github.com/890460
and my blog post about it:
http://www.fastchicken.co.nz/2011/03/28/scaling-and-rotating-an-image-in-monotouch/
在这里找到答案: CGContextDrawImage 颠倒绘制图像当传递 UIImage.CGImage 时:使用
UIImage.Draw()
而不是CGContext.DrawImage()
。生成的代码:这会生成尺寸、纵横比和方向正确的图像,但方向始终为“向上”。
Found an answer here: CGContextDrawImage draws image upside down when passed UIImage.CGImage : Use
UIImage.Draw()
rather thanCGContext.DrawImage()
. The resulting code:This produces an image of the right size, aspect ratio and orientation, but with the orientation always "up".
尝试通过 UIImageJPEGRepresentation 将 UIImage 转换为 NSData,因为 PNG 图像不会保存图像方向值。
Try to convert the UIImage to NSData through
UIImageJPEGRepresentation
as PNG image do not save your image orientation value.