expo-image-picker 14.0.1 → 14.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/android/build.gradle +2 -2
- package/build/ImagePicker.d.ts +5 -3
- package/build/ImagePicker.d.ts.map +1 -1
- package/build/ImagePicker.js +5 -3
- package/build/ImagePicker.js.map +1 -1
- package/ios/ImagePickerOptions.swift +2 -0
- package/ios/MediaHandler.swift +47 -22
- package/package.json +2 -2
- package/src/ImagePicker.ts +5 -3
package/CHANGELOG.md
CHANGED
|
@@ -10,6 +10,12 @@
|
|
|
10
10
|
|
|
11
11
|
### 💡 Others
|
|
12
12
|
|
|
13
|
+
## 14.0.2 — 2022-11-21
|
|
14
|
+
|
|
15
|
+
### 🐛 Bug fixes
|
|
16
|
+
|
|
17
|
+
- Fix support for animated GIFs on iOS. ([#20034](https://github.com/expo/expo/pull/20034) by [@barthap](https://github.com/barthap))
|
|
18
|
+
|
|
13
19
|
## 14.0.1 — 2022-11-08
|
|
14
20
|
|
|
15
21
|
### 🐛 Bug fixes
|
package/android/build.gradle
CHANGED
|
@@ -3,7 +3,7 @@ apply plugin: 'kotlin-android'
|
|
|
3
3
|
apply plugin: 'maven-publish'
|
|
4
4
|
|
|
5
5
|
group = 'host.exp.exponent'
|
|
6
|
-
version = '14.0.
|
|
6
|
+
version = '14.0.2'
|
|
7
7
|
|
|
8
8
|
buildscript {
|
|
9
9
|
def expoModulesCorePlugin = new File(project(":expo-modules-core").projectDir.absolutePath, "ExpoModulesCorePlugin.gradle")
|
|
@@ -74,7 +74,7 @@ android {
|
|
|
74
74
|
minSdkVersion safeExtGet("minSdkVersion", 21)
|
|
75
75
|
targetSdkVersion safeExtGet("targetSdkVersion", 31)
|
|
76
76
|
versionCode 22
|
|
77
|
-
versionName "14.0.
|
|
77
|
+
versionName "14.0.2"
|
|
78
78
|
}
|
|
79
79
|
lintOptions {
|
|
80
80
|
abortOnError false
|
package/build/ImagePicker.d.ts
CHANGED
|
@@ -78,10 +78,12 @@ export declare function launchCameraAsync(options?: ImagePickerOptions): Promise
|
|
|
78
78
|
* Requires `Permissions.MEDIA_LIBRARY` on iOS 10 only. On mobile web, this must be called
|
|
79
79
|
* immediately in a user interaction like a button press, otherwise the browser will block the
|
|
80
80
|
* request without a warning.
|
|
81
|
-
*
|
|
82
|
-
*
|
|
81
|
+
*
|
|
82
|
+
* **Animated GIFs support:** On Android, if the selected image is an animated GIF, the result image will be an
|
|
83
|
+
* animated GIF too if and only if `quality` is explicitly set to `1.0` and `allowsEditing` is set to `false`.
|
|
83
84
|
* Otherwise compression and/or cropper will pick the first frame of the GIF and return it as the
|
|
84
|
-
* result (on Android the result will be a PNG
|
|
85
|
+
* result (on Android the result will be a PNG). On iOS, both quality and cropping are supported.
|
|
86
|
+
*
|
|
85
87
|
* > **Notes for Web:** The system UI can only be shown after user activation (e.g. a `Button` press).
|
|
86
88
|
* Therefore, calling `launchImageLibraryAsync` in `componentDidMount`, for example, will **not**
|
|
87
89
|
* work as intended. The `cancelled` event will not be returned in the browser due to platform
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ImagePicker.d.ts","sourceRoot":"","sources":["../src/ImagePicker.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,EAChB,oBAAoB,EACpB,qBAAqB,EACrB,kBAAkB,EAInB,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EACL,wBAAwB,EACxB,8BAA8B,EAC9B,iBAAiB,EACjB,gBAAgB,EAChB,sBAAsB,EACtB,gBAAgB,EAChB,kBAAkB,EAClB,iBAAiB,EACjB,uBAAuB,EACvB,SAAS,EACT,yBAAyB,EACzB,0BAA0B,EAC1B,sBAAsB,EACtB,kCAAkC,EAClC,8BAA8B,EAC/B,MAAM,qBAAqB,CAAC;AAsE7B;;;GAGG;AACH,wBAAsB,yBAAyB,IAAI,OAAO,CAAC,wBAAwB,CAAC,CAEnF;AAGD;;;;GAIG;AACH,wBAAsB,+BAA+B,CACnD,SAAS,GAAE,OAAe,GACzB,OAAO,CAAC,8BAA8B,CAAC,CAEzC;AAGD;;;;GAIG;AACH,wBAAsB,6BAA6B,IAAI,OAAO,CAAC,wBAAwB,CAAC,CAEvF;AAGD;;;;GAIG;AACH,wBAAsB,mCAAmC,CACvD,SAAS,GAAE,OAAe,GACzB,OAAO,CAAC,8BAA8B,CAAC,CAGzC;AAGD;;;;;;;;GAQG;AACH,eAAO,MAAM,0BAA0B;;wJAOrC,CAAC;AAGH;;;;;;;;GAQG;AACH,eAAO,MAAM,oBAAoB,4JAG/B,CAAC;AAGH;;;;;;;;;;GAUG;AACH,wBAAsB,qBAAqB,IAAI,OAAO,CACpD,CAAC,iBAAiB,GAAG,sBAAsB,CAAC,EAAE,CAC/C,CAKA;AAGD;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,iBAAiB,CACrC,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,iBAAiB,CAAC,CAM5B;AAGD
|
|
1
|
+
{"version":3,"file":"ImagePicker.d.ts","sourceRoot":"","sources":["../src/ImagePicker.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,EAChB,oBAAoB,EACpB,qBAAqB,EACrB,kBAAkB,EAInB,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EACL,wBAAwB,EACxB,8BAA8B,EAC9B,iBAAiB,EACjB,gBAAgB,EAChB,sBAAsB,EACtB,gBAAgB,EAChB,kBAAkB,EAClB,iBAAiB,EACjB,uBAAuB,EACvB,SAAS,EACT,yBAAyB,EACzB,0BAA0B,EAC1B,sBAAsB,EACtB,kCAAkC,EAClC,8BAA8B,EAC/B,MAAM,qBAAqB,CAAC;AAsE7B;;;GAGG;AACH,wBAAsB,yBAAyB,IAAI,OAAO,CAAC,wBAAwB,CAAC,CAEnF;AAGD;;;;GAIG;AACH,wBAAsB,+BAA+B,CACnD,SAAS,GAAE,OAAe,GACzB,OAAO,CAAC,8BAA8B,CAAC,CAEzC;AAGD;;;;GAIG;AACH,wBAAsB,6BAA6B,IAAI,OAAO,CAAC,wBAAwB,CAAC,CAEvF;AAGD;;;;GAIG;AACH,wBAAsB,mCAAmC,CACvD,SAAS,GAAE,OAAe,GACzB,OAAO,CAAC,8BAA8B,CAAC,CAGzC;AAGD;;;;;;;;GAQG;AACH,eAAO,MAAM,0BAA0B;;wJAOrC,CAAC;AAGH;;;;;;;;GAQG;AACH,eAAO,MAAM,oBAAoB,4JAG/B,CAAC;AAGH;;;;;;;;;;GAUG;AACH,wBAAsB,qBAAqB,IAAI,OAAO,CACpD,CAAC,iBAAiB,GAAG,sBAAsB,CAAC,EAAE,CAC/C,CAKA;AAGD;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,iBAAiB,CACrC,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,iBAAiB,CAAC,CAM5B;AAGD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,uBAAuB,CAC3C,OAAO,CAAC,EAAE,kBAAkB,GAC3B,OAAO,CAAC,iBAAiB,CAAC,CAa5B;AAED,OAAO,EACL,gBAAgB,EAChB,kBAAkB,EAClB,iBAAiB,EACjB,sBAAsB,EACtB,gBAAgB,EAChB,iBAAiB,EACjB,wBAAwB,EACxB,8BAA8B,EAC9B,gBAAgB,EAChB,oBAAoB,EACpB,qBAAqB,EACrB,kBAAkB,EAClB,SAAS,EAAE,aAAa;AACxB,yBAAyB,EAAE,aAAa;AACxC,0BAA0B,EAAE,aAAa;AACzC,sBAAsB,EACtB,uBAAuB,EAAE,aAAa;AACtC,kCAAkC,EAClC,8BAA8B,GAC/B,CAAC"}
|
package/build/ImagePicker.js
CHANGED
|
@@ -160,10 +160,12 @@ export async function launchCameraAsync(options = {}) {
|
|
|
160
160
|
* Requires `Permissions.MEDIA_LIBRARY` on iOS 10 only. On mobile web, this must be called
|
|
161
161
|
* immediately in a user interaction like a button press, otherwise the browser will block the
|
|
162
162
|
* request without a warning.
|
|
163
|
-
*
|
|
164
|
-
*
|
|
163
|
+
*
|
|
164
|
+
* **Animated GIFs support:** On Android, if the selected image is an animated GIF, the result image will be an
|
|
165
|
+
* animated GIF too if and only if `quality` is explicitly set to `1.0` and `allowsEditing` is set to `false`.
|
|
165
166
|
* Otherwise compression and/or cropper will pick the first frame of the GIF and return it as the
|
|
166
|
-
* result (on Android the result will be a PNG
|
|
167
|
+
* result (on Android the result will be a PNG). On iOS, both quality and cropping are supported.
|
|
168
|
+
*
|
|
167
169
|
* > **Notes for Web:** The system UI can only be shown after user activation (e.g. a `Button` press).
|
|
168
170
|
* Therefore, calling `launchImageLibraryAsync` in `componentDidMount`, for example, will **not**
|
|
169
171
|
* work as intended. The `cancelled` event will not be returned in the browser due to platform
|
package/build/ImagePicker.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ImagePicker.js","sourceRoot":"","sources":["../src/ImagePicker.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n PermissionStatus,\n PermissionExpiration,\n PermissionHookOptions,\n PermissionResponse,\n createPermissionHook,\n UnavailabilityError,\n CodedError,\n} from 'expo-modules-core';\n\nimport ExponentImagePicker from './ExponentImagePicker';\nimport {\n CameraPermissionResponse,\n MediaLibraryPermissionResponse,\n ImagePickerResult,\n ImagePickerAsset,\n ImagePickerErrorResult,\n MediaTypeOptions,\n ImagePickerOptions,\n VideoExportPreset,\n ExpandImagePickerResult,\n ImageInfo,\n ImagePickerMultipleResult,\n ImagePickerCancelledResult,\n OpenFileBrowserOptions,\n UIImagePickerControllerQualityType,\n UIImagePickerPresentationStyle,\n} from './ImagePicker.types';\n\nfunction validateOptions(options: ImagePickerOptions) {\n const { aspect, quality, videoMaxDuration } = options;\n\n if (aspect != null) {\n const [x, y] = aspect;\n\n if (x <= 0 || y <= 0) {\n throw new CodedError(\n 'ERR_INVALID_ARGUMENT',\n `Invalid aspect ratio values ${x}:${y}. Provide positive numbers.`\n );\n }\n }\n\n if (quality && (quality < 0 || quality > 1)) {\n throw new CodedError(\n 'ERR_INVALID_ARGUMENT',\n `Invalid 'quality' value ${quality}. Provide a value between 0 and 1.`\n );\n }\n\n if (videoMaxDuration && videoMaxDuration < 0) {\n throw new CodedError(\n 'ERR_INVALID_ARGUMENT',\n `Invalid 'videoMaxDuration' value ${videoMaxDuration}. Provide a non-negative number.`\n );\n }\n\n return options;\n}\n\nconst DEPRECATED_RESULT_KEYS = [\n 'uri',\n 'assetId',\n 'width',\n 'height',\n 'type',\n 'exif',\n 'base64',\n 'duration',\n 'fileName',\n 'fileSize',\n];\nfunction mergeDeprecatedResult(result: ImagePickerResult): ImagePickerResult {\n const firstAsset = result.assets?.[0];\n const deprecatedResult = {\n ...result,\n get cancelled() {\n console.warn(\n 'Key \"cancelled\" in the image picker result is deprecated and will be removed in SDK 48, use \"canceled\" instead'\n );\n return this.canceled;\n },\n };\n for (const key of DEPRECATED_RESULT_KEYS) {\n Object.defineProperty(deprecatedResult, key, {\n get() {\n console.warn(\n `Key \"${key}\" in the image picker result is deprecated and will be removed in SDK 48, you can access selected assets through the \"assets\" array instead`\n );\n return firstAsset?.[key];\n },\n });\n }\n return deprecatedResult;\n}\n\n// @needsAudit\n/**\n * Checks user's permissions for accessing camera.\n * @return A promise that fulfills with an object of type [CameraPermissionResponse](#camerapermissionresponse).\n */\nexport async function getCameraPermissionsAsync(): Promise<CameraPermissionResponse> {\n return ExponentImagePicker.getCameraPermissionsAsync();\n}\n\n// @needsAudit\n/**\n * Checks user's permissions for accessing photos.\n * @param writeOnly Whether to request write or read and write permissions. Defaults to `false`\n * @return A promise that fulfills with an object of type [MediaLibraryPermissionResponse](#medialibrarypermissionresponse).\n */\nexport async function getMediaLibraryPermissionsAsync(\n writeOnly: boolean = false\n): Promise<MediaLibraryPermissionResponse> {\n return ExponentImagePicker.getMediaLibraryPermissionsAsync(writeOnly);\n}\n\n// @needsAudit\n/**\n * Asks the user to grant permissions for accessing camera. This does nothing on web because the\n * browser camera is not used.\n * @return A promise that fulfills with an object of type [CameraPermissionResponse](#camerarollpermissionresponse).\n */\nexport async function requestCameraPermissionsAsync(): Promise<CameraPermissionResponse> {\n return ExponentImagePicker.requestCameraPermissionsAsync();\n}\n\n// @needsAudit\n/**\n * Asks the user to grant permissions for accessing user's photo. This method does nothing on web.\n * @param writeOnly Whether to request write or read and write permissions. Defaults to `false`\n * @return A promise that fulfills with an object of type [MediaLibraryPermissionResponse](#medialibrarypermissionresponse).\n */\nexport async function requestMediaLibraryPermissionsAsync(\n writeOnly: boolean = false\n): Promise<MediaLibraryPermissionResponse> {\n const imagePickerMethod = ExponentImagePicker.requestMediaLibraryPermissionsAsync;\n return imagePickerMethod(writeOnly);\n}\n\n// @needsAudit\n/**\n * Check or request permissions to access the media library.\n * This uses both `requestMediaLibraryPermissionsAsync` and `getMediaLibraryPermissionsAsync` to interact with the permissions.\n *\n * @example\n * ```ts\n * const [status, requestPermission] = ImagePicker.useMediaLibraryPermissions();\n * ```\n */\nexport const useMediaLibraryPermissions = createPermissionHook<\n MediaLibraryPermissionResponse,\n { writeOnly?: boolean }\n>({\n // TODO(cedric): permission requesters should have an options param or a different requester\n getMethod: (options) => getMediaLibraryPermissionsAsync(options?.writeOnly),\n requestMethod: (options) => requestMediaLibraryPermissionsAsync(options?.writeOnly),\n});\n\n// @needsAudit\n/**\n * Check or request permissions to access the camera.\n * This uses both `requestCameraPermissionsAsync` and `getCameraPermissionsAsync` to interact with the permissions.\n *\n * @example\n * ```ts\n * const [status, requestPermission] = ImagePicker.useCameraPermissions();\n * ```\n */\nexport const useCameraPermissions = createPermissionHook({\n getMethod: getCameraPermissionsAsync,\n requestMethod: requestCameraPermissionsAsync,\n});\n\n// @needsAudit\n/**\n * Android system sometimes kills the `MainActivity` after the `ImagePicker` finishes. When this\n * happens, we lost the data selected from the `ImagePicker`. However, you can retrieve the lost\n * data by calling `getPendingResultAsync`. You can test this functionality by turning on\n * `Don't keep activities` in the developer options.\n * @return\n * - **On Android:** a promise that resolves to an array of objects of exactly same type as in\n * `ImagePicker.launchImageLibraryAsync` or `ImagePicker.launchCameraAsync` if the `ImagePicker`\n * finished successfully. Otherwise, to the array of [`ImagePickerErrorResult`](#imagepickerimagepickererrorresult).\n * - **On other platforms:** an empty array.\n */\nexport async function getPendingResultAsync(): Promise<\n (ImagePickerResult | ImagePickerErrorResult)[]\n> {\n if (ExponentImagePicker.getPendingResultAsync) {\n return ExponentImagePicker.getPendingResultAsync();\n }\n return [];\n}\n\n// @needsAudit\n/**\n * Display the system UI for taking a photo with the camera. Requires `Permissions.CAMERA`.\n * On Android and iOS 10 `Permissions.CAMERA_ROLL` is also required. On mobile web, this must be\n * called immediately in a user interaction like a button press, otherwise the browser will block\n * the request without a warning.\n * > **Note:** Make sure that you handle `MainActivity` destruction on **Android**. See [ImagePicker.getPendingResultAsync](#imagepickergetpendingresultasync).\n * > **Notes for Web:** The system UI can only be shown after user activation (e.g. a `Button` press).\n * Therefore, calling `launchCameraAsync` in `componentDidMount`, for example, will **not** work as\n * intended. The `cancelled` event will not be returned in the browser due to platform restrictions\n * and inconsistencies across browsers.\n * @param options An `ImagePickerOptions` object.\n * @return A promise that resolves to an object with `canceled` and `assets` fields.\n * When the user canceled the action the `assets` is always `null`, otherwise it's an array of\n * the selected media assets which have a form of [`ImagePickerAsset`](#imagepickerasset).\n */\nexport async function launchCameraAsync(\n options: ImagePickerOptions = {}\n): Promise<ImagePickerResult> {\n if (!ExponentImagePicker.launchCameraAsync) {\n throw new UnavailabilityError('ImagePicker', 'launchCameraAsync');\n }\n const result = await ExponentImagePicker.launchCameraAsync(validateOptions(options));\n return mergeDeprecatedResult(result);\n}\n\n// @needsAudit\n/**\n * Display the system UI for choosing an image or a video from the phone's library.\n * Requires `Permissions.MEDIA_LIBRARY` on iOS 10 only. On mobile web, this must be called\n * immediately in a user interaction like a button press, otherwise the browser will block the\n * request without a warning.\n * **Animated GIFs support** If the selected image is an animated GIF, the result image will be an\n * animated GIF too if and only if `quality` is set to `undefined` and `allowsEditing` is set to `false`.\n * Otherwise compression and/or cropper will pick the first frame of the GIF and return it as the\n * result (on Android the result will be a PNG, on iOS — GIF).\n * > **Notes for Web:** The system UI can only be shown after user activation (e.g. a `Button` press).\n * Therefore, calling `launchImageLibraryAsync` in `componentDidMount`, for example, will **not**\n * work as intended. The `cancelled` event will not be returned in the browser due to platform\n * restrictions and inconsistencies across browsers.\n * @param options An object extended by [`ImagePickerOptions`](#imagepickeroptions).\n * @return A promise that resolves to an object with `canceled` and `assets` fields.\n * When the user canceled the action the `assets` is always `null`, otherwise it's an array of\n * the selected media assets which have a form of [`ImagePickerAsset`](#imagepickerasset).\n */\nexport async function launchImageLibraryAsync(\n options?: ImagePickerOptions\n): Promise<ImagePickerResult> {\n if (!ExponentImagePicker.launchImageLibraryAsync) {\n throw new UnavailabilityError('ImagePicker', 'launchImageLibraryAsync');\n }\n if (options?.allowsEditing && options.allowsMultipleSelection) {\n console.warn(\n '[expo-image-picker] `allowsEditing` is not supported when `allowsMultipleSelection` is enabled and will be ignored.' +\n \"Disable either 'allowsEditing' or 'allowsMultipleSelection' in 'launchImageLibraryAsync' \" +\n 'to fix this warning.'\n );\n }\n const result = await ExponentImagePicker.launchImageLibraryAsync(options ?? {});\n return mergeDeprecatedResult(result);\n}\n\nexport {\n MediaTypeOptions,\n ImagePickerOptions,\n ImagePickerResult,\n ImagePickerErrorResult,\n ImagePickerAsset,\n VideoExportPreset,\n CameraPermissionResponse,\n MediaLibraryPermissionResponse,\n PermissionStatus,\n PermissionExpiration,\n PermissionHookOptions,\n PermissionResponse,\n ImageInfo, // deprecated\n ImagePickerMultipleResult, // deprecated\n ImagePickerCancelledResult, // deprecated\n OpenFileBrowserOptions,\n ExpandImagePickerResult, // deprecated\n UIImagePickerControllerQualityType,\n UIImagePickerPresentationStyle,\n};\n"]}
|
|
1
|
+
{"version":3,"file":"ImagePicker.js","sourceRoot":"","sources":["../src/ImagePicker.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n PermissionStatus,\n PermissionExpiration,\n PermissionHookOptions,\n PermissionResponse,\n createPermissionHook,\n UnavailabilityError,\n CodedError,\n} from 'expo-modules-core';\n\nimport ExponentImagePicker from './ExponentImagePicker';\nimport {\n CameraPermissionResponse,\n MediaLibraryPermissionResponse,\n ImagePickerResult,\n ImagePickerAsset,\n ImagePickerErrorResult,\n MediaTypeOptions,\n ImagePickerOptions,\n VideoExportPreset,\n ExpandImagePickerResult,\n ImageInfo,\n ImagePickerMultipleResult,\n ImagePickerCancelledResult,\n OpenFileBrowserOptions,\n UIImagePickerControllerQualityType,\n UIImagePickerPresentationStyle,\n} from './ImagePicker.types';\n\nfunction validateOptions(options: ImagePickerOptions) {\n const { aspect, quality, videoMaxDuration } = options;\n\n if (aspect != null) {\n const [x, y] = aspect;\n\n if (x <= 0 || y <= 0) {\n throw new CodedError(\n 'ERR_INVALID_ARGUMENT',\n `Invalid aspect ratio values ${x}:${y}. Provide positive numbers.`\n );\n }\n }\n\n if (quality && (quality < 0 || quality > 1)) {\n throw new CodedError(\n 'ERR_INVALID_ARGUMENT',\n `Invalid 'quality' value ${quality}. Provide a value between 0 and 1.`\n );\n }\n\n if (videoMaxDuration && videoMaxDuration < 0) {\n throw new CodedError(\n 'ERR_INVALID_ARGUMENT',\n `Invalid 'videoMaxDuration' value ${videoMaxDuration}. Provide a non-negative number.`\n );\n }\n\n return options;\n}\n\nconst DEPRECATED_RESULT_KEYS = [\n 'uri',\n 'assetId',\n 'width',\n 'height',\n 'type',\n 'exif',\n 'base64',\n 'duration',\n 'fileName',\n 'fileSize',\n];\nfunction mergeDeprecatedResult(result: ImagePickerResult): ImagePickerResult {\n const firstAsset = result.assets?.[0];\n const deprecatedResult = {\n ...result,\n get cancelled() {\n console.warn(\n 'Key \"cancelled\" in the image picker result is deprecated and will be removed in SDK 48, use \"canceled\" instead'\n );\n return this.canceled;\n },\n };\n for (const key of DEPRECATED_RESULT_KEYS) {\n Object.defineProperty(deprecatedResult, key, {\n get() {\n console.warn(\n `Key \"${key}\" in the image picker result is deprecated and will be removed in SDK 48, you can access selected assets through the \"assets\" array instead`\n );\n return firstAsset?.[key];\n },\n });\n }\n return deprecatedResult;\n}\n\n// @needsAudit\n/**\n * Checks user's permissions for accessing camera.\n * @return A promise that fulfills with an object of type [CameraPermissionResponse](#camerapermissionresponse).\n */\nexport async function getCameraPermissionsAsync(): Promise<CameraPermissionResponse> {\n return ExponentImagePicker.getCameraPermissionsAsync();\n}\n\n// @needsAudit\n/**\n * Checks user's permissions for accessing photos.\n * @param writeOnly Whether to request write or read and write permissions. Defaults to `false`\n * @return A promise that fulfills with an object of type [MediaLibraryPermissionResponse](#medialibrarypermissionresponse).\n */\nexport async function getMediaLibraryPermissionsAsync(\n writeOnly: boolean = false\n): Promise<MediaLibraryPermissionResponse> {\n return ExponentImagePicker.getMediaLibraryPermissionsAsync(writeOnly);\n}\n\n// @needsAudit\n/**\n * Asks the user to grant permissions for accessing camera. This does nothing on web because the\n * browser camera is not used.\n * @return A promise that fulfills with an object of type [CameraPermissionResponse](#camerarollpermissionresponse).\n */\nexport async function requestCameraPermissionsAsync(): Promise<CameraPermissionResponse> {\n return ExponentImagePicker.requestCameraPermissionsAsync();\n}\n\n// @needsAudit\n/**\n * Asks the user to grant permissions for accessing user's photo. This method does nothing on web.\n * @param writeOnly Whether to request write or read and write permissions. Defaults to `false`\n * @return A promise that fulfills with an object of type [MediaLibraryPermissionResponse](#medialibrarypermissionresponse).\n */\nexport async function requestMediaLibraryPermissionsAsync(\n writeOnly: boolean = false\n): Promise<MediaLibraryPermissionResponse> {\n const imagePickerMethod = ExponentImagePicker.requestMediaLibraryPermissionsAsync;\n return imagePickerMethod(writeOnly);\n}\n\n// @needsAudit\n/**\n * Check or request permissions to access the media library.\n * This uses both `requestMediaLibraryPermissionsAsync` and `getMediaLibraryPermissionsAsync` to interact with the permissions.\n *\n * @example\n * ```ts\n * const [status, requestPermission] = ImagePicker.useMediaLibraryPermissions();\n * ```\n */\nexport const useMediaLibraryPermissions = createPermissionHook<\n MediaLibraryPermissionResponse,\n { writeOnly?: boolean }\n>({\n // TODO(cedric): permission requesters should have an options param or a different requester\n getMethod: (options) => getMediaLibraryPermissionsAsync(options?.writeOnly),\n requestMethod: (options) => requestMediaLibraryPermissionsAsync(options?.writeOnly),\n});\n\n// @needsAudit\n/**\n * Check or request permissions to access the camera.\n * This uses both `requestCameraPermissionsAsync` and `getCameraPermissionsAsync` to interact with the permissions.\n *\n * @example\n * ```ts\n * const [status, requestPermission] = ImagePicker.useCameraPermissions();\n * ```\n */\nexport const useCameraPermissions = createPermissionHook({\n getMethod: getCameraPermissionsAsync,\n requestMethod: requestCameraPermissionsAsync,\n});\n\n// @needsAudit\n/**\n * Android system sometimes kills the `MainActivity` after the `ImagePicker` finishes. When this\n * happens, we lost the data selected from the `ImagePicker`. However, you can retrieve the lost\n * data by calling `getPendingResultAsync`. You can test this functionality by turning on\n * `Don't keep activities` in the developer options.\n * @return\n * - **On Android:** a promise that resolves to an array of objects of exactly same type as in\n * `ImagePicker.launchImageLibraryAsync` or `ImagePicker.launchCameraAsync` if the `ImagePicker`\n * finished successfully. Otherwise, to the array of [`ImagePickerErrorResult`](#imagepickerimagepickererrorresult).\n * - **On other platforms:** an empty array.\n */\nexport async function getPendingResultAsync(): Promise<\n (ImagePickerResult | ImagePickerErrorResult)[]\n> {\n if (ExponentImagePicker.getPendingResultAsync) {\n return ExponentImagePicker.getPendingResultAsync();\n }\n return [];\n}\n\n// @needsAudit\n/**\n * Display the system UI for taking a photo with the camera. Requires `Permissions.CAMERA`.\n * On Android and iOS 10 `Permissions.CAMERA_ROLL` is also required. On mobile web, this must be\n * called immediately in a user interaction like a button press, otherwise the browser will block\n * the request without a warning.\n * > **Note:** Make sure that you handle `MainActivity` destruction on **Android**. See [ImagePicker.getPendingResultAsync](#imagepickergetpendingresultasync).\n * > **Notes for Web:** The system UI can only be shown after user activation (e.g. a `Button` press).\n * Therefore, calling `launchCameraAsync` in `componentDidMount`, for example, will **not** work as\n * intended. The `cancelled` event will not be returned in the browser due to platform restrictions\n * and inconsistencies across browsers.\n * @param options An `ImagePickerOptions` object.\n * @return A promise that resolves to an object with `canceled` and `assets` fields.\n * When the user canceled the action the `assets` is always `null`, otherwise it's an array of\n * the selected media assets which have a form of [`ImagePickerAsset`](#imagepickerasset).\n */\nexport async function launchCameraAsync(\n options: ImagePickerOptions = {}\n): Promise<ImagePickerResult> {\n if (!ExponentImagePicker.launchCameraAsync) {\n throw new UnavailabilityError('ImagePicker', 'launchCameraAsync');\n }\n const result = await ExponentImagePicker.launchCameraAsync(validateOptions(options));\n return mergeDeprecatedResult(result);\n}\n\n// @needsAudit\n/**\n * Display the system UI for choosing an image or a video from the phone's library.\n * Requires `Permissions.MEDIA_LIBRARY` on iOS 10 only. On mobile web, this must be called\n * immediately in a user interaction like a button press, otherwise the browser will block the\n * request without a warning.\n *\n * **Animated GIFs support:** On Android, if the selected image is an animated GIF, the result image will be an\n * animated GIF too if and only if `quality` is explicitly set to `1.0` and `allowsEditing` is set to `false`.\n * Otherwise compression and/or cropper will pick the first frame of the GIF and return it as the\n * result (on Android the result will be a PNG). On iOS, both quality and cropping are supported.\n *\n * > **Notes for Web:** The system UI can only be shown after user activation (e.g. a `Button` press).\n * Therefore, calling `launchImageLibraryAsync` in `componentDidMount`, for example, will **not**\n * work as intended. The `cancelled` event will not be returned in the browser due to platform\n * restrictions and inconsistencies across browsers.\n * @param options An object extended by [`ImagePickerOptions`](#imagepickeroptions).\n * @return A promise that resolves to an object with `canceled` and `assets` fields.\n * When the user canceled the action the `assets` is always `null`, otherwise it's an array of\n * the selected media assets which have a form of [`ImagePickerAsset`](#imagepickerasset).\n */\nexport async function launchImageLibraryAsync(\n options?: ImagePickerOptions\n): Promise<ImagePickerResult> {\n if (!ExponentImagePicker.launchImageLibraryAsync) {\n throw new UnavailabilityError('ImagePicker', 'launchImageLibraryAsync');\n }\n if (options?.allowsEditing && options.allowsMultipleSelection) {\n console.warn(\n '[expo-image-picker] `allowsEditing` is not supported when `allowsMultipleSelection` is enabled and will be ignored.' +\n \"Disable either 'allowsEditing' or 'allowsMultipleSelection' in 'launchImageLibraryAsync' \" +\n 'to fix this warning.'\n );\n }\n const result = await ExponentImagePicker.launchImageLibraryAsync(options ?? {});\n return mergeDeprecatedResult(result);\n}\n\nexport {\n MediaTypeOptions,\n ImagePickerOptions,\n ImagePickerResult,\n ImagePickerErrorResult,\n ImagePickerAsset,\n VideoExportPreset,\n CameraPermissionResponse,\n MediaLibraryPermissionResponse,\n PermissionStatus,\n PermissionExpiration,\n PermissionHookOptions,\n PermissionResponse,\n ImageInfo, // deprecated\n ImagePickerMultipleResult, // deprecated\n ImagePickerCancelledResult, // deprecated\n OpenFileBrowserOptions,\n ExpandImagePickerResult, // deprecated\n UIImagePickerControllerQualityType,\n UIImagePickerPresentationStyle,\n};\n"]}
|
package/ios/MediaHandler.swift
CHANGED
|
@@ -126,6 +126,7 @@ internal struct MediaHandler {
|
|
|
126
126
|
}
|
|
127
127
|
|
|
128
128
|
let (imageData, fileExtension) = try ImageUtils.readDataAndFileExtension(image: image,
|
|
129
|
+
rawData: rawData,
|
|
129
130
|
itemProvider: itemProvider,
|
|
130
131
|
options: self.options)
|
|
131
132
|
|
|
@@ -345,11 +346,17 @@ private struct ImageUtils {
|
|
|
345
346
|
return (nil, ".bmp")
|
|
346
347
|
|
|
347
348
|
case .some(let s) where s.contains("ext=GIF"):
|
|
349
|
+
var rawData: Data?
|
|
350
|
+
if let imgUrl = mediaInfo[.imageURL] as? URL {
|
|
351
|
+
rawData = try? Data(contentsOf: imgUrl)
|
|
352
|
+
}
|
|
353
|
+
let inputData = rawData ?? image.jpegData(compressionQuality: compressionQuality)
|
|
348
354
|
let metadata = mediaInfo[.mediaMetadata] as? [String: Any]
|
|
349
|
-
let
|
|
355
|
+
let cropRect = options.allowsEditing ? mediaInfo[.cropRect] as? CGRect : nil
|
|
356
|
+
let gifData = try processGifData(inputData: inputData,
|
|
350
357
|
compressionQuality: options.quality,
|
|
351
|
-
initialMetadata: metadata
|
|
352
|
-
|
|
358
|
+
initialMetadata: metadata,
|
|
359
|
+
cropRect: cropRect)
|
|
353
360
|
return (gifData, ".gif")
|
|
354
361
|
default:
|
|
355
362
|
let data = image.jpegData(compressionQuality: compressionQuality)
|
|
@@ -360,6 +367,7 @@ private struct ImageUtils {
|
|
|
360
367
|
@available(iOS 14, *)
|
|
361
368
|
static func readDataAndFileExtension(
|
|
362
369
|
image: UIImage,
|
|
370
|
+
rawData: Data,
|
|
363
371
|
itemProvider: NSItemProvider,
|
|
364
372
|
options: ImagePickerOptions
|
|
365
373
|
) throws -> (imageData: Data?, fileExtension: String) {
|
|
@@ -371,7 +379,7 @@ private struct ImageUtils {
|
|
|
371
379
|
let data = image.pngData()
|
|
372
380
|
return (data, ".png")
|
|
373
381
|
case UTType.gif.identifier:
|
|
374
|
-
let gifData = try
|
|
382
|
+
let gifData = try processGifData(inputData: rawData,
|
|
375
383
|
compressionQuality: options.quality,
|
|
376
384
|
initialMetadata: nil)
|
|
377
385
|
return (gifData, ".gif")
|
|
@@ -508,37 +516,54 @@ private struct ImageUtils {
|
|
|
508
516
|
return exif
|
|
509
517
|
}
|
|
510
518
|
|
|
511
|
-
static func
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
519
|
+
static func processGifData(
|
|
520
|
+
inputData: Data?,
|
|
521
|
+
compressionQuality quality: Double?,
|
|
522
|
+
initialMetadata: [String: Any]?,
|
|
523
|
+
cropRect: CGRect? = nil
|
|
524
|
+
) throws -> Data? {
|
|
525
|
+
// for uncropped, maximum quality image we can just pass through the raw data
|
|
526
|
+
if cropRect == nil,
|
|
527
|
+
quality == nil || (quality ?? -1) >= MAXIMUM_QUALITY {
|
|
528
|
+
return inputData
|
|
516
529
|
}
|
|
517
530
|
|
|
531
|
+
guard let sourceData = inputData,
|
|
532
|
+
let imageSource = CGImageSourceCreateWithData(sourceData as CFData, nil)
|
|
533
|
+
else {
|
|
534
|
+
throw FailedToReadImageException()
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
let gifProperties = CGImageSourceCopyProperties(imageSource, nil) as? [String: Any]
|
|
538
|
+
let frameCount = CGImageSourceGetCount(imageSource)
|
|
539
|
+
|
|
518
540
|
let destinationData = NSMutableData()
|
|
519
|
-
guard let imageDestination = CGImageDestinationCreateWithData(destinationData, kUTTypeGIF,
|
|
520
|
-
let cgImage = image.cgImage
|
|
541
|
+
guard let imageDestination = CGImageDestinationCreateWithData(destinationData, kUTTypeGIF, frameCount, nil)
|
|
521
542
|
else {
|
|
522
543
|
throw FailedToCreateGifException()
|
|
523
544
|
}
|
|
524
545
|
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
let cgImageSource = CGImageSourceCreateWithData(data as CFData, nil),
|
|
528
|
-
let properties = CGImageSourceCopyPropertiesAtIndex(cgImageSource, 0, nil) as? [String: Any] {
|
|
529
|
-
metadata = properties
|
|
530
|
-
}
|
|
546
|
+
let gifMetadata = initialMetadata ?? gifProperties
|
|
547
|
+
CGImageDestinationSetProperties(imageDestination, gifMetadata as CFDictionary?)
|
|
531
548
|
|
|
532
|
-
|
|
533
|
-
|
|
549
|
+
for frameIndex in 0 ..< frameCount {
|
|
550
|
+
guard var cgImage = CGImageSourceCreateImageAtIndex(imageSource, frameIndex, nil),
|
|
551
|
+
var frameProperties = CGImageSourceCopyPropertiesAtIndex(imageSource, frameIndex, nil) as? [String: Any]
|
|
552
|
+
else {
|
|
553
|
+
throw FailedToCreateGifException()
|
|
554
|
+
}
|
|
555
|
+
if cropRect != nil {
|
|
556
|
+
cgImage = cgImage.cropping(to: cropRect!)!
|
|
557
|
+
}
|
|
558
|
+
if quality != nil {
|
|
559
|
+
frameProperties[kCGImageDestinationLossyCompressionQuality as String] = quality
|
|
560
|
+
}
|
|
561
|
+
CGImageDestinationAddImage(imageDestination, cgImage, frameProperties as CFDictionary)
|
|
534
562
|
}
|
|
535
563
|
|
|
536
|
-
CGImageDestinationAddImage(imageDestination, cgImage, metadata as CFDictionary)
|
|
537
|
-
|
|
538
564
|
if !CGImageDestinationFinalize(imageDestination) {
|
|
539
565
|
throw FailedToExportGifException()
|
|
540
566
|
}
|
|
541
|
-
|
|
542
567
|
return destinationData as Data
|
|
543
568
|
}
|
|
544
569
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "expo-image-picker",
|
|
3
|
-
"version": "14.0.
|
|
3
|
+
"version": "14.0.2",
|
|
4
4
|
"description": "Provides access to the system's UI for selecting images and videos from the phone's library or taking a photo with the camera.",
|
|
5
5
|
"main": "build/ImagePicker.js",
|
|
6
6
|
"types": "build/ImagePicker.d.ts",
|
|
@@ -45,5 +45,5 @@
|
|
|
45
45
|
"peerDependencies": {
|
|
46
46
|
"expo": "*"
|
|
47
47
|
},
|
|
48
|
-
"gitHead": "
|
|
48
|
+
"gitHead": "7cc0ce2b21febcaf96e875d8a8aff10b320e1b5f"
|
|
49
49
|
}
|
package/src/ImagePicker.ts
CHANGED
|
@@ -225,10 +225,12 @@ export async function launchCameraAsync(
|
|
|
225
225
|
* Requires `Permissions.MEDIA_LIBRARY` on iOS 10 only. On mobile web, this must be called
|
|
226
226
|
* immediately in a user interaction like a button press, otherwise the browser will block the
|
|
227
227
|
* request without a warning.
|
|
228
|
-
*
|
|
229
|
-
*
|
|
228
|
+
*
|
|
229
|
+
* **Animated GIFs support:** On Android, if the selected image is an animated GIF, the result image will be an
|
|
230
|
+
* animated GIF too if and only if `quality` is explicitly set to `1.0` and `allowsEditing` is set to `false`.
|
|
230
231
|
* Otherwise compression and/or cropper will pick the first frame of the GIF and return it as the
|
|
231
|
-
* result (on Android the result will be a PNG
|
|
232
|
+
* result (on Android the result will be a PNG). On iOS, both quality and cropping are supported.
|
|
233
|
+
*
|
|
232
234
|
* > **Notes for Web:** The system UI can only be shown after user activation (e.g. a `Button` press).
|
|
233
235
|
* Therefore, calling `launchImageLibraryAsync` in `componentDidMount`, for example, will **not**
|
|
234
236
|
* work as intended. The `cancelled` event will not be returned in the browser due to platform
|