Xamarin iOS配置AVCaptureSession实现与iOS系统相机一致的图片压缩效果
问题核心原因
- 冗余的重绘流程引入了alpha通道,导致位深从24位提升到32位,同时修改了默认DPI为96,额外增加了文件体积
- 自定义JPG转码逻辑效率低,未使用系统硬件编码能力,你当前代码中
AsJPEG(0f)存在逻辑异常(正常0为最大压缩等级,不会出现20MB体积,大概率是实际代码误写为1f,即最高质量等级) - AVCapturePhotoSettings未指定JPEG输出格式,默认输出未压缩的原始像素数据,自行软件转码的压缩比远低于系统硬件编码的压缩比
- 未对齐系统相机的默认配置,多余的画质选项拉高了输出体积
修复方案(Xamarin iOS)
1. 配置AVCapturePhotoOutput开启硬件JPEG编码
移除冗余的重绘、转码流程,直接使用系统硬件编码输出JPG,是体积对齐系统相机的最优方案:
// 初始化CaptureOutput时禁用RAW输出,仅保留JPEG编码能力 CaptureOutput = new AVCapturePhotoOutput(); CaptureSession.AddOutput(CaptureOutput);
2. 调整拍照参数,指定JPEG输出格式
var settings = AVCapturePhotoSettings.Create(); // 直接指定输出JPEG格式,调用系统硬件编码能力 settings.OutputFormat = new NSDictionary<NSString, NSObject>( AVVideo.CodecKey, AVVideoCodecType.Jpeg ); settings.FlashMode = AVCaptureFlashMode.Auto; // 对齐系统相机默认HDR配置 settings.AutoHDREnabled = true; settings.IsHighResolutionCaptureEnabled = false; return settings;
3. 直接从拍照回调获取系统编码后的JPG数据
在AVCapturePhotoCaptureDelegate的DidFinishProcessingPhoto回调中直接读取编码完成的数据,不需要自行处理UIImage:
public override void DidFinishProcessingPhoto(AVCapturePhotoOutput output, AVCapturePhoto photo, NSError error) { if (error != null) return; // 直接获取硬件编码的JPG数据,参数已经和系统相机对齐 NSData jpgData = photo.FileDataRepresentation; byte[] myByteArray = jpgData.ToArray(); // 直接保存即可 }
4. 特殊场景下自定义转码的修复方案
如果确实需要先处理UIImage再转码,按如下逻辑修改原有转码代码,移除alpha通道、对齐DPI参数:
public NSData OptimizedJpegFromImage(UIImage image, float quality = 0.7f) { // 转换为无alpha的24位RGB格式 using (var context = new CGBitmapContext(IntPtr.Zero, (nint)image.Size.Width, (nint)image.Size.Height, 8, 0, CGColorSpace.CreateDeviceRGB(), CGImageAlphaInfo.NoneSkipFirst)) { context.DrawImage(new CGRect(0, 0, image.Size.Width, image.Size.Height), image.CGImage); using (var noAlphaImage = UIImage.FromImage(context.ToImage())) { // 对齐系统相机72DPI配置 var options = new NSDictionary<NSString, NSObject>( CGImageProperties.DPIWidth, NSNumber.FromFloat(72), CGImageProperties.DPIHeight, NSNumber.FromFloat(72) ); // 压缩质量0.7~0.8和系统相机默认输出画质一致 return noAlphaImage.AsJPEG(quality, options); } } }
Swift参考代码
// 配置拍照输出 let photoOutput = AVCapturePhotoOutput() photoOutput.isRawCaptureEnabled = false captureSession.addOutput(photoOutput) // 配置拍照参数 let settings = AVCapturePhotoSettings() settings.outputFormat = [AVVideoCodecKey: AVVideoCodecType.jpeg] settings.flashMode = .auto settings.isAutoHDREnabled = true photoOutput.capturePhoto(with: settings, delegate: self) // 回调中直接读取编码完成的JPG数据 func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) { guard let jpgData = photo.fileDataRepresentation() else { return } // 直接保存即可 }
按上述方案修改后,输出的JPG位深为24位、DPI为72,相同场景下体积和系统相机输出的3MB左右基本一致,不需要调整原有AVCaptureSession的预设参数。
内容的提问来源于stack exchange,提问作者The Overrider
相关产品推荐
相关产品推荐

