Capture Reference
Add more functionality to your Lens camera on iOS
It is left to you as the developer of the app hosting LensSDK to provide all user interface affordances which will interact with the camera; capture button, flash on/off button, front/rear camera swap button, etc. As part of the initialization procedure, you pass a reference to a UIView
which will host the Lens Camera preview view.
Here's an overview of the additional features supported by the camera besides standard photo and video capture.
Camera Methods
Here is a helpful list of all the optional methods to be added in extension ViewController: LensCameraDelegate
.
Start recording video
lensCameraDidStartRecordingVideo()
Called when Lens starts recording video frames to disk. Use this to start a timer to show the user how long they've been recording.
Stop recording video
lensCameraDidStopRecordingVideo()
Called when Lens stops recording video frames to disk.
Generate a thumbnail
lensCameraDidGenerateVideoThumnail(fileName: String, image: UIImage, duration: TimeInterval?)
Called when Lens generates a thumbnail for the video file.
Parameter | Description |
---|---|
fileName | The name of the image file, which matches the video output file name |
image | A UIImage containing the thumbnail |
duration | The duration of the recorded video |
Recorded video completed signing
lensCameraDidGenerateTruepicVideo(_ url: URL)
Called when the recorded video data has completed C2PA processing.
Parameter | Description |
---|---|
url | The URL to which the recorded and signed video data was saved |
Recorded video failed to be signed
lensCameraDidGenerateUnsignedVideo(_ url: URL)
Called if signing of the recorded video fails C2PAProcessing.
Parameter | Description |
---|---|
url | The URL to which the unsigned recorded video data was saved |
New zoom factor
lensCameraChangedZoomFactor(_ zoomFactor: CGFloat?, error: Error?)
This method provides the new zoom factor, which can be used as an informational display for the user - 1X, 2X, 3X, etc.
Parameter | Description |
---|---|
zoomFactor | The new zoom factor |
Get focal point
lensCameraDidFocusOnPoint(_ point: CGPoint?, error: Error?)
Confirms the actual point within the camera's viewport that was used as the new focal point. Auto exposure metering is also applied to the new point.
New instance
lensCameraDidChangeTo(_ device: LensCaptureDevice?, error: Error?)
Provides a new instance of LensCaptureDevice upon successful change. This will be the same as LensCamera.CurrentDevice
, so there is no need to cache this value.
Get flash mode
lensCameraDidSetFlashMode(_ mode: LensCaptureDevice.FlashMode?, error: Error?
Provides the new flash mode that was selected.
Get manual focus area
lensCameraSubjectAreaDidChange()
If focus has been set manually, this method is called when subject area changes are detected, such as lighting changes, substantial movement, etc.
Audio methods
Like video, capturing audio through Lens is as simple as calling startAudioCapture
and stopAudioCapture
:
public func startAudioCapture
public func stopAudioCapture
If you intend to record audio, you should add the appropriate Privacy keys to your app's Info.plist
.
Key | Value (example) |
---|---|
Privacy - Microphone Usage Description | APPNAME will use the microphone when recording videos or audio. |
or
<key>NSMicrophoneUsageDescription</key>
<string>APPNAME will use the microphone when recording videos or audio.</string>
Lens notifies your delegate of certain lifecycle events once recording starts:
// Called when Lens starts recording audio.
func lensCameraDidStartRecordingAudio() {}
// Called multiple times a second with the instantaneous average power level in decibels per channel.
func lensCameraDidMeasureAudioLevels(_ levels: [Float]) {}
// Called when Lens stops recording audio.
func lensCameraDidStopRecordingAudio() {}
// Called when Lens signs the recorded audio file.
// - url: the final URL of the signed media
// - duration: the duration of the recording. To get the number of seconds, use duration.seconds
// - error: if an error was encountered during signing, it will be return here
func lensCameraDidGenerateSignedAudio(_ url: URL?, duration: CMTime?, error: Error?) {}
The delegate method lensCameraDidMeasureAudioLevels
can be used to display an audio meter in your app, useful to let the user know that audio is being picked up by the device's microphones. Multiple channels are supported.
The example code below normalizes the incoming levels and masks a UIImageView
with a fill percentage calculated from the levels. Note that in multi-channel situations, this code only operates on the first channel. You may want to modify this code to account for more than one channel.
func lensCameraDidMeasureAudioLevels(_ levels: [Float]) {
// Normalize the level to a value between 0 and 1
let normalizedLevel = min(max(levels[0], -60), 0) + 60
let fillPercentage: CGFloat = CGFloat(normalizedLevel / 60)
// Update the mask of the white microphone image view
let maskLayer = CALayer()
maskLayer.backgroundColor = UIColor.black.cgColor
let maskHeight = audioMeterFilledImageView.bounds.height * fillPercentage
maskLayer.frame = CGRect(x: 0, y: audioMeterFilledImageView.bounds.height - maskHeight, width: audioMeterFilledImageView.bounds.width, height: maskHeight)
DispatchQueue.main.async {
self.audioMeterFilledImageView.layer.mask = maskLayer
self.audioMeterFilledImageView.setNeedsDisplay()
}
}
Add Camera Controls
The following properties are available from lensCamera.sharedInstance.currentDevice
. The capabilities of the default capture device are encapsulated by the following:
public struct LensCaptureDevice {
// The value of this property is a BOOL indicating whether the receiver has a flash.
// The receiver's flashMode property can only be set when this property returns true.
public var hasFlash: Bool { get }
// Indicates whether the receiver's flash is currently available for use.
// The flash may become unavailable if, for example, the device overheats and needs to cool off.
public var isFlashAvailable: Bool { get }
// The value of this property is a Position indicating where the receiver's device
// is physically located on the system hardware.
public var position: LensCaptureDevice.Position { get }
// Indicates the mode of the flash on the receiver's device, if it has one.
public var flashMode: LensCaptureDevice.FlashMode { get }
// The value of this property is a BOOL indicating whether the receiver can zoom
public var canZoom: Bool { get }
// Controls zoom level of image outputs.
public var videoZoomFactor: CGFloat { get }
}
Zoom
To enable pinch-to-zoom, create a UIPinchGestureRecognizer
and add it to your cameraPreviewView
:
let zoom = UIPinchGestureRecognizer(target: self, action: #selector(handleZoom(_:)))
cameraPreviewView.addGestureRecognizer(zoom)
In your zoom handler, call LensCamera
's zoom(with:)
method, and pass the sender
property:
@objc private func handleZoom(_ sender: UIPinchGestureRecognizer) {
self.camera?.zoom(with: sender)
}
Implement the optional delegate method to be notified when the zoom factor changes so that you can update your user interface. This is always delivered on the main queue:
public protocol LensCameraDelegate: AnyObject {
// Called when LensCamera preview view changes zoom level.
func lensCameraDidChangeZoomLevel(_ zoom: CGFloat?, error: Error?)
}
Focus
To enable tap-to-focus, create a UITapGestureRecognizer
and add it to your cameraPreviewView
:
let tap = UITapGestureRecognizer(target: self, action: #selector(handleTapToFocus(_:)))
cameraPreviewView.addGestureRecognizer(tap)
In your tap handler, call LensCamera
's focus(with:)
method, and pass the sender
property:
@objc private func handleTapToFocus(_ sender: UITapGestureRecognizer) {
self.camera?.focus(with: sender)
}
This tells LensCamera
to set the device's focus point of interest, and to begin auto exposure for the selected point. You can use this method to add a focus reticle to the camera view. See the example integration code for more.
Implement the optional delegate method to be notified when LensCamera
focuses on the selected point, or when an error occurs during focus and exposure. This is always delivered on the main queue:
public protocol LensCameraDelegate: AnyObject {
// Called when the focus point of interest changes.
func lensCameraDidFocusOnPoint(_ point: CGFloat?, error: Error?)
}
If an error is returned, it will be of type LensCameraError.setFocusFailed
.
Enable flash
Flash availability depends on the current capture device's capabilities. lensFlashMode
can only be set to the values contained in supportedFlashModes
.
LensFlashMode
has three possible states:
public enum FlashMode: Int {
// Indicates that the flash should always be off. Default.
case off = 0
// Indicates that the flash should always be on.
case on = 1
// Indicates that the flash should be used automatically depending on light conditions.
case auto = 2
}
The current state of flash can be obtained or set with this property:
self.camera?.currentDevice?.flashMode
To cycle through the available flash modes, call:
self.camera?.toggleFlash()
Implement the optional delegate method to be notified when Lens changes the flash mode, or when an error occurs. This is always delivered on the main queue:
public protocol LensCameraDelegate: AnyObject {
func lensCameraDidSetFlashMode(_ mode: LensCaptureDevice.FlashMode?, error: Error?)
}
Switch cameras
You can add a control to your user interface to switch between front and back cameras. By default, the back camera is activated when the session is configured.
public enum Position: Int {
case unspecified = 0
case back = 1 // default
case front = 2
}
The currently selected position can be obtained via this property:
self.camera?.currentDevice?.devicePosition
To toggle between front and back devices, call:
self.camera?.changeCamera()
Implement the optional delegate method to be notified when Lens switches between back and front cameras, or when an error occurs. This is always delivered on the main queue:
public protocol LensCameraDelegate: AnyObject {
func lensCameraDidChangeTo(_ device: LensCaptureDevice?, error: Error?)
}
Location Accuracy
Your customer's location at the time they capture a photo or video is an important piece of provenance. The more accurately that location can be determined, the better. The device's location can be determined in a number of ways: directly from a GPS, or approximated by cell phone tower or WiFi network triangulation, and each have varying degrees of accuracy. Moving around, or going from outdoors to indoors can also affect accuracy. This variance is encoded as a radius of uncertainty about the device, measured in meters. The threshold is the maximum accuracy required to enable the camera. After that threshold is passed, the user may begin taking photos. Lens will continue to get a more accurate reading even after the threshold is passed, often down to 3-4m of accuracy. The user experience would be negatively affected if we prevented capture until that level of accuracy was achieved because it can take 30 seconds or more.
The default location accuracy used by Lens is 1500 meters, or approximately 1 mile. To lower this call the following on LensCamera
:
@discardableResult
public func setMaximumLocationAccuracy(_ newValue: Double) -> Bool
The range of valid values is from 3 to 1500 meters. If a value is set beyond these bounds, the function will return false
, otherwise true
is returned. Note that setting this value very low may increase the time it takes for Lens to get an accurate location reading, and enable the camera for capture.
Reduce accuracy
For cases where the accuracy requires a higher threshold, the 1500 meters limitation can be removed by setting the allowsImprecise
option to true
while configuring the LensCamera
session:
guard let camera = self.camera else { return }
camera.configureSession(previewView: cameraPreviewView, fillView: false, apiKey: apiKey, delegate: self, locationMode: .required, allowsImprecise: true)
Setting the allowsImprecise
value to true
will widen the threshold to 20,000 meters. The default value of allowsImprecise
is false
.
Make location optional
For camera use that does not require the location information. The SDK offers an optional
or none
setting. The default setting is required
if nothing has been specified.
public enum LensLocationMode: Int {
case required
case optional
case none
}
Setting the LensLocationMode
to optional
will allow the SDK to provide the Location data if the device's location permission is enabled by the user. If the location permission on the device is disabled, location information will not be provided.
guard let camera = self.camera else { return }
camera.configureSession(previewView: cameraPreviewView, fillView: false, apiKey: api_key, delegate: self, locationMode: LensLocationMode.optional)
Disabling location data from signing can be performed by setting LensLocationMode
to none
. This will disregard any location data during signing regardless of the location permission setting.
guard let camera = self.camera else { return }
camera.configureSession(previewView: cameraPreviewView, fillView: false, apiKey: api_key, delegate: self, locationMode: LensLocationMode.none)
Offline Capture
Lens offers out of the box support for capturing and signing photos and videos offline, which can be uploaded to your server or directly to the Lens API when the device regains connectivity. To learn more about the differences between online and offline capture, see Offline Capture.
Updated 3 months ago