AVCam:构建相机应用——在PreviewView上方绘制网格:如何获取捕获图像边界以适配GridView尺寸
Got it, let's figure out how to get the exact bounds you need so your GridView perfectly overlays the captured image in AVCam. Depending on whether you want to match the full-resolution captured photo or just the on-screen preview frame, here are two solid approaches:
1. Get bounds for the full-resolution captured photo
If you need your grid to align with the actual photo that gets saved (not just the scaled preview on screen), you can pull the dimensions directly from the AVCapturePhoto object once a capture completes, or pre-fetch the output's default resolution.
Option 1: Fetch dimensions during capture callback
When the photo finishes processing, extract the resolution from the AVCapturePhoto instance:
func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) { guard error == nil else { // Handle error case return } // Get the full resolution of the captured photo let imageDimensions = photo.resolution.dimensions let imageSize = CGSize(width: CGFloat(imageDimensions.width), height: CGFloat(imageDimensions.height)) // Adjust GridView size to match (account for aspect ratio if scaling to fit the screen) let aspectRatio = imageSize.width / imageSize.height let targetWidth = previewView.frame.width let targetHeight = targetWidth / aspectRatio // Update your GridView's frame or constraints gridView.frame = CGRect(x: 0, y: 0, width: targetWidth, height: targetHeight) }
Option 2: Pre-fetch default output resolution
You can also get the expected resolution upfront during your AVCaptureSession setup:
if let photoOutput = captureSession.outputs.first as? AVCapturePhotoOutput { if let previewFormat = photoOutput.previewPhotoFormat as? [String: Any], let width = previewFormat[kCVPixelBufferWidthKey as String] as? Int, let height = previewFormat[kCVPixelBufferHeightKey as String] as? Int { let defaultCaptureSize = CGSize(width: width, height: height) // Use this size to pre-configure your GridView's initial layout } }
2. Get bounds for the on-screen preview frame
If you just need the grid to cover exactly what the user sees in the PreviewView (ignoring the full photo resolution), use the AVCaptureVideoPreviewLayer to calculate the visible video rect. This accounts for aspect ratio differences between the camera's output and the screen.
// Assuming your PreviewView has a reference to its AVCaptureVideoPreviewLayer guard let previewLayer = previewView.previewLayer else { return } // Convert the preview layer's bounds to the actual video content rect let videoRect = previewLayer.metadataOutputRectConverted(fromLayerRect: previewLayer.bounds) let visibleVideoFrame = previewLayer.layerRectConverted(fromMetadataOutputRect: videoRect) // Set your GridView's frame to match this visible area gridView.frame = visibleVideoFrame
Handle screen rotations
Don't forget to update the GridView's frame when the device rotates. Add this to your view controller:
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { super.viewWillTransition(to: size, with: coordinator) coordinator.animate(alongsideTransition: { _ in self.updateGridViewFrame() }) } private func updateGridViewFrame() { guard let previewLayer = previewView.previewLayer else { return } let videoRect = previewLayer.metadataOutputRectConverted(fromLayerRect: previewLayer.bounds) let visibleVideoFrame = previewLayer.layerRectConverted(fromMetadataOutputRect: videoRect) gridView.frame = visibleVideoFrame }
Quick notes
- Make sure your GridView's
contentModematches the PreviewView's (like.scaleAspectFitor.scaleAspectFill) to avoid stretching the grid. - If you're using Auto Layout instead of frame-based layout, adjust your width/height constraints using the calculated size instead of setting
framedirectly.
内容的提问来源于stack exchange,提问作者chiarotto.alessandro

