C# WPF使用SharpAvi转图片为AVI时视频画面旋转问题
图片转AVI视频画面旋转问题解决
将图片转为AVI视频后,生成的视频画面出现旋转,与原图方向不符:
原图:
生成视频中的画面:
问题原因
这种情况几乎都是因为图片的EXIF旋转信息未被处理。很多手机拍摄的图片会在EXIF元数据中记录旋转角度(比如竖拍图片会标记需旋转90度),但直接将图片转为System.Drawing.Bitmap时,BMP格式不支持保存EXIF信息,且现有代码未主动读取并应用该旋转角度,导致视频帧使用了原始像素数据——而视频播放器不会自动解析EXIF旋转,最终画面显示为旋转状态。
你的代码片段
var croppedImage = GetCroppedImageVideo(vidSize); System.Drawing.Bitmap bmp; bmp = BitmapFromSource(croppedImage); byte[] byteArray = BitmapToByteArray(bmp); stream.WriteFrame(true, byteArray, 0, byteArray.Length);
public static System.Drawing.Bitmap BitmapFromSource(CroppedBitmap bmp) { System.Drawing.Bitmap bitmap; using (var outStream = new MemoryStream()) { BitmapEncoder enc = new BmpBitmapEncoder(); enc.Frames.Add(BitmapFrame.Create(bmp)); enc.Save(outStream); bitmap = new System.Drawing.Bitmap(outStream); } return bitmap; }
public static byte[] BitmapToByteArray(System.Drawing.Bitmap bitmap) { BitmapData bmpdata = null; try { bmpdata = bitmap.LockBits(new System.Drawing.Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, bitmap.PixelFormat); int numbytes = bmpdata.Stride * bitmap.Height; byte[] bytedata = new byte[numbytes]; IntPtr ptr = bmpdata.Scan0; Marshal.Copy(ptr, bytedata, 0, numbytes); return bytedata; } finally { if (bmpdata != null) { bitmap.UnlockBits(bmpdata); } } }
解决方法
需要先读取原图的EXIF旋转角度,再将Bitmap旋转到正确方向后写入视频帧。
- 添加读取EXIF旋转角度的方法:
private static int GetExifRotationAngle(Image image) { // 274是EXIF标准中标记旋转角度的属性ID if (image.PropertyIdList.Contains(274)) { var rotationProp = image.GetPropertyItem(274); return rotationProp.Value[0]; } return 0; // 默认无旋转 }
- 添加Bitmap旋转方法:
private static System.Drawing.Bitmap RotateBitmap(System.Drawing.Bitmap bitmap, int rotationAngle) { switch (rotationAngle) { case 90: bitmap.RotateFlip(RotateFlipType.Rotate90FlipNone); break; case 180: bitmap.RotateFlip(RotateFlipType.Rotate180FlipNone); break; case 270: bitmap.RotateFlip(RotateFlipType.Rotate270FlipNone); break; } return new System.Drawing.Bitmap(bitmap); }
- 修改调用代码,加入旋转处理:
var croppedImage = GetCroppedImageVideo(vidSize); System.Drawing.Bitmap bmp; bmp = BitmapFromSource(croppedImage); // 读取并应用EXIF旋转 int rotationAngle = GetExifRotationAngle(bmp); if (rotationAngle != 0) { using (var tempBmp = bmp) { bmp = RotateBitmap(tempBmp, rotationAngle); } } byte[] byteArray = BitmapToByteArray(bmp); stream.WriteFrame(true, byteArray, 0, byteArray.Length); // 记得最后释放bmp资源 bmp.Dispose();
额外说明
如果GetCroppedImageVideo方法处理的是带EXIF信息的原图,也可以在生成CroppedBitmap前先处理旋转,避免后续转Bitmap时丢失信息。另外,视频的分辨率需要和旋转后的Bitmap尺寸匹配,否则可能出现拉伸或黑边问题。
内容的提问来源于stack exchange,提问作者Muhammad Arshad
相关产品推荐
相关产品推荐

