开发相机APP实现Instagram式375x375正方形拍照求助
嘿,我之前也踩过这个坑!你已经把预览层改成正方形了,但拍摄出来的照片还是全屏尺寸,这是因为你只是调整了预览的显示区域,并没有对相机实际捕获的原始图像进行正方形裁剪和尺寸压缩。结合你的CameraViewController结构,给你一套能直接用的解决方案:
解决步骤&代码实现
1. 先搞清楚:预览层≠捕获图像
AVCaptureSession捕获的照片是相机传感器的原始分辨率(比如1920×1080、3840×2160等),你设置的正方形取景框只是把预览层的显示区域裁剪成了正方形,实际捕获的图像还是完整的全屏尺寸。所以我们需要在捕获后对图像做两步处理:裁剪成正方形 → 缩放到375×375。
2. 实现正方形裁剪逻辑
在你的CameraViewController里添加一个计算裁剪区域的方法,注意要适配图像的方向(相机捕获的图像默认是横屏的,竖屏拍摄时需要调整):
func squareCropRect(for image: UIImage) -> CGRect { let imageSize = image.size let cropLength = min(imageSize.width, imageSize.height) // 根据图像方向调整裁剪坐标(竖屏拍摄时图像是旋转90度的) var xOffset: CGFloat = 0 var yOffset: CGFloat = 0 switch image.imageOrientation { case .right, .leftMirrored, .rightMirrored, .left: // 竖屏时,图像的宽高实际是互换的 xOffset = (imageSize.height - cropLength) / 2 yOffset = (imageSize.width - cropLength) / 2 default: xOffset = (imageSize.width - cropLength) / 2 yOffset = (imageSize.height - cropLength) / 2 } return CGRect(x: xOffset, y: yOffset, width: cropLength, height: cropLength) }
3. 捕获照片后处理并保存
实现AVCapturePhotoCaptureDelegate的回调方法,在里面完成裁剪、缩放和保存:
extension CameraViewController: AVCapturePhotoCaptureDelegate { func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) { guard let imageData = photo.fileDataRepresentation(), let capturedImage = UIImage(data: imageData) else { print("获取照片失败: \(error?.localizedDescription ?? "未知错误")") return } // 步骤1:裁剪成正方形 let cropRect = squareCropRect(for: capturedImage) guard let croppedCGImage = capturedImage.cgImage?.cropping(to: cropRect) else { print("裁剪图像失败") return } let croppedImage = UIImage(cgImage: croppedCGImage, scale: capturedImage.scale, orientation: capturedImage.imageOrientation) // 步骤2:缩放到目标尺寸375×375 let targetSize = CGSize(width: 375, height: 375) UIGraphicsBeginImageContextWithOptions(targetSize, false, UIScreen.main.scale) croppedImage.draw(in: CGRect(origin: .zero, size: targetSize)) let resizedImage = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() // 步骤3:保存到相册 guard let finalImage = resizedImage else { return } UIImageWriteToSavedPhotosAlbum(finalImage, self, #selector(imageSaved(_:didFinishSavingWithError:contextInfo:)), nil) } @objc private func imageSaved(_ image: UIImage, didFinishSavingWithError error: Error?, contextInfo: UnsafeRawPointer) { if let error = error { print("照片保存失败:\(error.localizedDescription)") } else { print("375×375正方形照片已成功保存!") } } }
4. 优化小技巧
如果想减少裁剪损失,可以在配置AVCapturePhotoOutput时,优先选择接近1:1比例的分辨率:
func setupPhotoOutput() { let photoOutput = AVCapturePhotoOutput() guard self.captureSession.canAddOutput(photoOutput) else { return } // 优先选择接近正方形的分辨率 if let availableFormats = photoOutput.availablePhotoPixelFormatTypes as? [NSNumber] { let preferredFormat = availableFormats.first { format in let formatDesc = CMFormatDescriptionCreateWithMediaType(kCMMediaType_Video, format, nil)! let dimensions = CMVideoFormatDescriptionGetDimensions(formatDesc) // 宽高比接近1:1(差值小于500) return abs(dimensions.width - dimensions.height) < 500 } photoOutput.setPreferredPhotoPixelFormatType(preferredFormat ?? availableFormats.first!) } self.captureSession.addOutput(photoOutput) }
内容的提问来源于stack exchange,提问作者user9459145
相关产品推荐
相关产品推荐

