> For the complete documentation index, see [llms.txt](https://docs.facephi.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.facephi.com/docs.facephi-en/sdks/sdk-mobile/ios-sdk/modulos/subida-de-ficheros-y-gestion-de-qr.md).

# File upload and QR Code management - Capture

## Introduction

File upload and QR Code reading and generation are performed with the ***Capture Component***.

This component allows document upload by taking a photo with the device camera or from the gallery. Its main features are:

* Document upload via camera or gallery.
* QR Code reading.
* QR Code generation.

In the section of [Simplified Launch](/docs.facephi-en/sdks/sdk-mobile/ios-sdk/inicializacion/lanzamiento-simplificado.md) the necessary steps for the basic integration of the SDK are detailed. In this section, information is added for the launch of this component.

***

## Dependencies

To avoid conflicts and compatibility issues, if you want to install the component in a project that contains an old version of the Facephi libraries (Widgets), they must be completely removed before installing the components of the **SDKMobile**.

### **CocoaPods**

* Currently, Facephi libraries are distributed remotely through different dependency managers, in this case CocoaPods. The dependencies **required** that must have been installed beforehand (by adding them to the project's Podfile) are:

```swift
pod 'FPHISDKMainComponent', '~> $VERSION'
```

* To install the Capture component, the following entry must be included in the application's Podfile:

```swift
pod 'FPHISDKCaptureComponent', '~> $VERSION'
```

### **SPM**

* The mandatory dependencies that must have been installed previously are:

```swift
//HTTPS
https://github.com/facephi-clienters/SDK-SdkPackage-SPM.git
//SSH
git@github.com:facephi-clienters/SDK-SdkPackage-SPM.git
```

* To install the Selphid component, it must be included in the project's modules:

<pre class="language-swift"><code class="lang-swift"><strong>//HTTPS
</strong>https://github.com/facephi-clienters/SDK-CapturePackage-SPM.git
//SSH
git@github.com:facephi-clienters/SDK-CapturePackage-SPM.git
</code></pre>

**IMPORTANT: If FileUploaderController is being used via SPM. The resources and&#x20;*****assets*****&#x20;that the component needs require running a script in each build of the target.**

To make this process automatic, the script should be added in Target -> Build Phases -> + Run Script

```
set -euo pipefail
BUNDLE_PATH="${TARGET_BUILD_DIR}/FPHICaptureWidget-SPM_FPHICaptureWidget-SPM.bundle/compose-resources"
DESTINATION="${TARGET_BUILD_DIR}/${TARGET_NAME}.app/compose-resources"
if [ -d "$BUNDLE_PATH" ]; then
  rm -rf "$DESTINATION"
  mkdir -p "$DESTINATION"
  cp -R "$BUNDLE_PATH/" "$DESTINATION/"
  echo "Copied FPHICaptureWidget Compose resources to ${DESTINATION}"
else
  echo "FPHICaptureWidget Compose resources not found at ${BUNDLE_PATH}. If your app is not using FPHICaptureWidget Component anymore, delete the script from your Build Phases -> Run Script section"
  exit 1
fi

BUNDLE_PATH_DS="${TARGET_BUILD_DIR}/FPHIDesignSystemResources_FPHIDesignSystemResources.bundle/Resources/compose-resources"
DESTINATION="${TARGET_BUILD_DIR}/${TARGET_NAME}.app/compose-resources"
if [ -d "$BUNDLE_PATH_DS" ]; then
  cp -R "$BUNDLE_PATH_DS/" "$DESTINATION/"
  echo "Copied FPHIDesignSystemResources Compose resources to ${DESTINATION}"
else
  echo "FPHIDesignSystemResources Compose resources not found at ${BUNDLE_PATH_DS}. If your app is not using FacePhi Components anymore, delete the script from your Build Phases -> Run Script section"
  exit 1
fi
```

It is important to uncheck the option *For install builds only*.

**If the script is not added, a runtime crash will occur when FileUploaderController is launched.**

***

## Available controllers <a href="#id-3-controladores-disponibles" id="id-3-controladores-disponibles"></a>

| **Controller**         | **Description**                   |
| ---------------------- | --------------------------------- |
| FileUploaderController | Controller for document capture   |
| QrReaderController     | Controller for QR Code capture    |
| QrGeneratorController  | Controller for QR Code generation |

***

## Simplified Launch <a href="#id-4-lanzamiento-simplificado" id="id-4-lanzamiento-simplificado"></a>

Once the SDK has been started and a new operation has been created, the component can be launched. Any of its controllers can be used to execute its functionality.

Document capture launch:

```swift
let controller = FileUploaderController(data: fileUploaderConfigurationData, , output: { sdkResult in
        // Do whatever with the result
        ...
    }, viewController: viewController)
SDKController.shared.launch(controller: controller)
```

QR capture launch:

```swift
let controller = QrReaderController(data: qrReaderConfigurationData, , output: { sdkResult in
        // Do whatever with the result
        ...
    }, viewController: viewController)
SDKController.shared.launch(controller: controller)
```

QR generation launch:

```swift
let controller = QrGeneratorController(data: qrGeneratorConfigurationData, , output: { sdkResult in
        // Do whatever with the result
        ...
    }, viewController: viewController)
SDKController.shared.launch(controller: controller)
```

***

## Basic configuration <a href="#id-5-configuracion-basica" id="id-5-configuracion-basica"></a>

For the component capture and QR capture controllers, configuration can be generated with default parameters. For QR generation, the text to be used will be needed:

```
QrGeneratorConfiguration(source:"QR text")
```

***

## Result reception <a href="#id-6-recepcion-del-resultado" id="id-6-recepcion-del-resultado"></a>

The launch will return the information in SdkResult format.

* errorType
* finishStatus
* data

### Error handling <a href="#id-61-recepcion-de-errores" id="id-61-recepcion-de-errores"></a>

Errors will be returned as a 'CaptureError' object.

List of errors:

* CAP\_ACTIVITY\_RESULT\_MSG\_ERROR: The result returned by the activity is incorrect or does not contain the necessary information to continue.
* CAP\_APPLICATION\_CONTEXT\_ERROR: The required application context is null or invalid, preventing the capture module from being initialized correctly.
* CAP\_CAMERA\_ERROR: An internal error has occurred related to the device camera (failure to open, initialize, or capture).
* CAP\_CAMERA\_PERMISSION\_DENIED: The user has denied the permissions required to access the camera.
* CAP\_CANCEL\_BY\_USER: The user has manually canceled the capture process.
* CAP\_CANCEL\_LAUNCH: The process has been generally canceled by the SDK or by an external action.
* CAP\_COMPONENT\_LICENSE\_ERROR: The component License is invalid, has expired, or does not match the required configuration.
* CAP\_EMPTY\_LICENSE: The license string is empty or has not been provided.
* CAP\_FETCH\_DATA\_ERROR: An error occurred while obtaining or processing the data needed to execute the Flow. *(Includes additional information in the field `error`.)*
* CAP\_FLOW\_ERROR: An internal error occurred during the execution of the capture Flow. *(Includes additional information in the field `error`.)*
* CAP\_INITIALIZATION\_ERROR: Error initializing the necessary SDK components. *(Includes detailed information in the field `error`.)*
* CAP\_FILE\_UPLOADER\_CAPTURE\_ERROR: Error during the upload process of the files generated in the capture.
* CAP\_MANAGER\_NOT\_INITIALIZED: The managers required to execute the process have not been initialized correctly.
* CAP\_NO\_DATA\_ERROR: The required input data is null, nonexistent, or insufficient to continue the process.
* CAP\_OPERATION\_NOT\_CREATED: It was not possible to create or recover an active operation needed to continue. *(Includes detailed information in the field `error`.)*
* CAP\_QR\_CAPTURE\_ERROR: Error during QR code capture or reading.
* CAP\_QR\_GENERATION\_ERROR: Error generating the requested QR code.
* CAP\_TIMEOUT: The maximum allowed time has been reached in one of the phases of the process.
* CAP\_FLOW\_VIDEO\_RECORDING\_ERROR: Error during video recording within the established Flow.
* CAP\_FLOW\_TRACKING\_ERROR: Error while performing the Tracking necessary to complete the capture Flow.

### Reception of the successful result - *data* <a href="#id-62-recepcion-del-resultado-correcto-data" id="id-62-recepcion-del-resultado-correcto-data"></a>

#### **Reception of the document capture result**

In the SdkResult.Success part - *data*, we will have the class *FileUploaderResult*.

The fields returned in the result are as follows:

***capturedDocumentList***

List of captured files. They can be images or PDFs. The fields returned for each one are:

* mimeType
* timestampMillis
* content: FileContent -> determines whether it is an image or a PDF document. If it is an image, it is also indicated whether it was captured with the camera or from the gallery.

```
public enum FileContent {
    case uploaderImage(UploaderImage)
    case uploaderDocument(UploaderDocument)
    
    // MARK: - Nested types
    public struct UploaderImage {
        public let image: UIImage
        public let rotationDegrees: Int
        public let source: FileUploaderSource
    }
    
    public struct UploaderDocument {
        public let frontPageImage: UIImage?
        public let bytes: Data
    }
}

public enum FileUploaderSource: String {
    case CAMERA
    case GALLERY
}
```

For example, to read the first element of the array:

```
(..., output: { fileUploaderResult in
    guard fileUploaderResult.errorType == .NO_ERROR else {
        print("\(fileUploaderResult.errorType)")
        return
    }
    ...
    let firstElement = fileUploaderResult.data?.documentImages.first
    
    switch firstElement?.content {
    case .uploaderDocument(let doc):
        // Do something with the file
        break
    case .uploaderImage(let image):
        // Do something with the image
        break
    case .none:
        break
    }
})
```

#### **Reception of the QR capture result**

In the SdkResult.Success part - *data*, we will have the class *QrResult*.

The fields returned in the result are as follows:

***qrText***

Text obtained from the QR Code

#### **Reception of the QR generation result**

In the SdkResult.Success part - *data*, we will have an SdkImage with the created QR code.

***

## Advanced information <a href="#id-7-informacion-avanzada" id="id-7-informacion-avanzada"></a>

This section expands on the component information.

### Advanced component configuration <a href="#id-71-configuracion-avanzada-del-componente" id="id-71-configuracion-avanzada-del-componente"></a>

#### **Document capture configuration**

To launch the current component, an object *FileUploaderConfigurationData* must be created, which will be the configuration of the component controller.

Below are all the fields that are part of this class.

* `vibrationEnabled`: Indicates the activation of vibration when the Widget ends successfully.
* `extractionTimeout`: Sets the maximum time for which capture can be performed.
* `showDiagnostic`: Show diagnostic screens at the end of the process.
* `showPreviousTip`: Displays a screen before capture launch with information about the process to be carried out and a launch button.
* `maxScannedDocs`: Maximum number of documents that can be captured
* `allowGallery`: Gallery access is enabled for obtaining images or PDFs
* `onlyGalleryMode`: Opens the Flow directly in gallery mode, without showing camera capture. By default `true`.
* `maxGalleryImageSizeKb`: Maximum allowed size for images selected from the gallery, in KB. By default `2048`. If an image exceeds this limit, the component returns `CAP_IMAGE_TOO_LARGE`.

#### **QR capture configuration**

To launch the current component, an object *QrCaptureConfigurationData* must be created, which will be the configuration of the component controller.

Below are all the fields that are part of this class.

* `vibrationEnabled`: Indicates the activation of vibration when the Widget ends successfully.
* `extractionTimeout`: Sets the maximum time for which capture can be performed.
* `showDiagnostic`: Show diagnostic screens at the end of the process.
* `showPreviousTip`: Displays a screen before capture launch with information about the process to be carried out and a launch button.
* `showTutorial`: Indicates whether the component activates the tutorial screen. In this view, capture is explained intuitively.
* `cameraShape`: Allows choosing between a square and a round mask.

***

## Component Customization <a href="#id-8-personalizacion-del-componente" id="id-8-personalizacion-del-componente"></a>

Besides the changes that can be made at SDK level (which are explained in the document of *SDK Customization*), this specific component allows its interface to be modified.

### Texts <a href="#id-81-textos" id="id-81-textos"></a>

The texts can be customized by overwriting the value of the following keys in a **Localizable.strings**. The keys containing the suffix ***\_alt*** are the literals used in the accessibility labels needed for the functionality of ***VoiceOver***.

```xml
<resources>
    <!-- Previous Tip -->
    <string name="capture_component_qr_tip_title">Scan the QR Code</string>
    <string name="capture_component_qr_tip_message">&lt;b&gt; Focus &lt;/b&gt; the QR Code &lt;b&gt; inside the frame &lt;/b&gt;</string>
    <string name="capture_component_qr_tip_button">Start</string>
    <string name="capture_component_qr_tip_anim_desc">Animation of a mobile phone taking a photo of a QR Code. A frame appears on the phone screen. When the QR Code fits inside the frame, the application takes a photo.</string>
    <string name="capture_component_qr_tutorial_1_anim_desc">A QR Code is shown on a white background. The edges of the QR Code are not clearly distinguishable. Through an animation, the background changes color.</string>
    <string name="capture_component_qr_tutorial_2_anim_desc">A mobile phone takes a photo of a QR Code. The QR Code appears horizontally, and the phone is in vertical position. A frame appears on the phone screen. When the QR Code fits inside the frame, the application takes a photo.</string>
    <!-- Tutorial -->
    <string name="capture_component_qr_tutorial_1">Make sure the QR Code has &lt;b&gt; enough light &lt;/b&gt; and &lt;b&gt; there are no reflections &lt;/b&gt; or glare on the code.</string>
    <string name="capture_component_qr_tutorial_2">Fit the edges of the QR Code inside the frame.</string>
    <!-- Process -->
    <string name="capture_component_qr_camera_message">Keep the QR in the center</string>
    <string name="capture_component_button_message">Capture</string>
    <!-- Diagnostic -->
    <string name="capture_component_timeout_title">Time exceeded</string>
    <string name="capture_component_timeout_desc">We apologize. The capture could not be completed</string>
    <string name="capture_component_internal_error_title">There was a technical issue</string>
    <string name="capture_component_internal_error_desc">We apologize. The capture could not be completed</string>

    <!-- WIDGET -->
    <!-- Previous Tip -->
    <string name="capture_widget_tip_title">Scan documents</string>
    <string name="capture_widget_tip_message">Take a photo of the document, or upload an image.&lt;br&gt;&lt;br&gt; You can scan multiple documents before finishing.</string>
    <string name="capture_widget_tip_message_alt">Take a photo of the document, or upload an image. You can scan multiple documents before finishing.</string>
    <string name="capture_widget_tip_button">Start</string>
    <string name="capture_widget_tip_button_alt">Start document capture</string>
    <string name="capture_widget_tip_close_button_alt">Back</string>
    <string name="capture_widget_tip_info_button_alt">View tips</string>
    <string name="capture_widget_tip_anim_desc">Animation of a mobile phone taking a photo of a document. A frame appears on the phone screen. When the document fits inside the frame, the application takes a photo.</string>
    <!-- Camera -->
    <string name="capture_widget_document_camera_button_gallery">Gallery</string>
    <string name="capture_widget_document_camera_button_capture">Capture</string>
    <string name="capture_widget_document_camera_button_cancel">Cancel capture</string>
    <string name="capture_widget_document_camera_button_finish">Finish</string>
    <!-- Gallery -->
    <string name="capture_widget_gallery_images">Images</string>
    <string name="capture_widget_gallery_pdf">Select PDF</string>
    <string name="capture_widget_gallery_cancel">Cancel</string>
    <!-- Confirmation -->
    <string name="capture_widget_image_captured">Image captured</string>
    <string name="capture_widget_confirmation_message">Are all the details readable and clear?</string>
    <string name="capture_widget_confirmation_retry">NO, I WANT TO REPEAT THE PHOTOS</string>
    <string name="capture_widget_confirmation_continue">Yes, finish</string>
    <string name="capture_widget_confirmation_delete">Delete photo</string>
    <string name="capture_widget_confirmation_image_unavailable">Preview not available</string>
    <string name="capture_widget_confirmation_no_images">No captures available</string>
    <string name="capture_widget_confirmation_delete_dialog_title">Do you want to delete this document?</string>
    <string name="capture_widget_confirmation_delete_dialog_message">By deleting this document, you will not be able to recover it. You will need to take a new photo.</string>
    <string name="capture_widget_confirmation_delete_dialog_cancel">CANCEL</string>
    <string name="capture_widget_confirmation_delete_dialog_confirm">DELETE DOCUMENT</string>
    <!-- Diagnostic -->
    <string name="capture_widget_timeout_title">Time exceeded</string>
    <string name="capture_widget_timeout_desc">We apologize. The capture could not be completed</string>
    <string name="capture_widget_internal_error_title">There was a technical issue</string>
    <string name="capture_widget_internal_error_desc">We apologize. The capture could not be completed</string>

</resources>
```

In this way, if you want to modify, for example, the text “*Start*” of the key `capture_widget_tip_button` for the language **is**, you will have to go to the file **Localizable.strings** in the folder **es.lproj** if it exists (if not, it must be created) and there, add:

`"capture_widget_tip_button"="Start";`

If a message is not specified in the language file, it will be filled with the default message.

### Animations <a href="#id-82-animaciones" id="id-82-animaciones"></a>

If you want to modify the SDK animations (lottie), you must include the animations with the same name in the application's res/raw/ folder.

```
qr_anim_tip_1.json
qr_anim_tip_2.json
capture_anim_tip.json
```
