You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

开发相机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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 08:34:57