react-native-compressor 1.6.4 → 1.7.1
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/LICENSE +1 -1
- package/README.md +41 -27
- package/android/build.gradle +95 -42
- package/android/gradle.properties +5 -0
- package/android/src/main/AndroidManifest.xml +0 -1
- package/android/src/main/AndroidManifestNew.xml +2 -0
- package/android/src/main/java/com/reactnativecompressor/CompressorModule.java +107 -43
- package/android/src/main/java/com/reactnativecompressor/CompressorPackage.java +47 -19
- package/android/src/main/java/com/reactnativecompressor/Image/ImageCompressor.java +28 -16
- package/android/src/main/java/com/reactnativecompressor/Image/utils/ImageCompressorOptions.java +5 -1
- package/android/src/main/java/com/reactnativecompressor/Utils/MediaCache.java +65 -0
- package/android/src/main/java/com/reactnativecompressor/Utils/Utils.java +162 -3
- package/android/src/main/java/com/reactnativecompressor/Video/VideoCompressorHelper.java +7 -4
- package/android/src/main/java/com/reactnativecompressor/Video/VideoModule.java +11 -22
- package/android/src/newarch/CompressorSpec.java +9 -0
- package/android/src/newarch/VideoCompressorSpec.java +9 -0
- package/android/src/oldarch/CompressorSpec.java +34 -0
- package/android/src/oldarch/VideoCompressorSpec.java +26 -0
- package/ios/Compressor-Bridging-Header.h +1 -0
- package/ios/Compressor.h +9 -1
- package/ios/Compressor.mm +427 -0
- package/ios/Compressor.xcodeproj/project.pbxproj +6 -36
- package/ios/Image/ImageCompressor.h +12 -7
- package/ios/Image/ImageCompressor.m +164 -67
- package/ios/Image/ImageCompressorOptions.h +1 -0
- package/ios/Image/ImageCompressorOptions.m +5 -1
- package/ios/Utils/Downloader.h +16 -0
- package/ios/Utils/Downloader.m +150 -0
- package/ios/Utils/MediaCache.h +11 -0
- package/ios/Utils/MediaCache.m +51 -0
- package/ios/Video/VideoCompressor.swift +14 -5
- package/lib/commonjs/Audio/index.js +13 -14
- package/lib/commonjs/Audio/index.js.map +1 -1
- package/lib/commonjs/Image/index.js +26 -7
- package/lib/commonjs/Image/index.js.map +1 -1
- package/lib/commonjs/Main.js +29 -0
- package/lib/commonjs/Main.js.map +1 -0
- package/lib/commonjs/Spec/NativeCompressor.js +10 -0
- package/lib/commonjs/Spec/NativeCompressor.js.map +1 -0
- package/lib/commonjs/Spec/NativeVideoCompressor.js +10 -0
- package/lib/commonjs/Spec/NativeVideoCompressor.js.map +1 -0
- package/lib/commonjs/Video/index.js +17 -25
- package/lib/commonjs/Video/index.js.map +1 -1
- package/lib/commonjs/expo-plugin/compressor.js +1 -4
- package/lib/commonjs/expo-plugin/compressor.js.map +1 -1
- package/lib/commonjs/index.js +21 -28
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/utils/index.js +32 -51
- package/lib/commonjs/utils/index.js.map +1 -1
- package/lib/module/Audio/index.js +13 -11
- package/lib/module/Audio/index.js.map +1 -1
- package/lib/module/Image/index.js +27 -6
- package/lib/module/Image/index.js.map +1 -1
- package/lib/module/Main.js +22 -0
- package/lib/module/Main.js.map +1 -0
- package/lib/module/Spec/NativeCompressor.js +3 -0
- package/lib/module/Spec/NativeCompressor.js.map +1 -0
- package/lib/module/Spec/NativeVideoCompressor.js +3 -0
- package/lib/module/Spec/NativeVideoCompressor.js.map +1 -0
- package/lib/module/Video/index.js +18 -19
- package/lib/module/Video/index.js.map +1 -1
- package/lib/module/expo-plugin/compressor.js +1 -3
- package/lib/module/expo-plugin/compressor.js.map +1 -1
- package/lib/module/index.js +8 -5
- package/lib/module/index.js.map +1 -1
- package/lib/module/utils/index.js +26 -34
- package/lib/module/utils/index.js.map +1 -1
- package/lib/typescript/Audio/index.d.ts +2 -1
- package/lib/typescript/Audio/index.d.ts.map +1 -0
- package/lib/typescript/Image/index.d.ts +11 -6
- package/lib/typescript/Image/index.d.ts.map +1 -0
- package/lib/typescript/Main.d.ts +4 -0
- package/lib/typescript/Main.d.ts.map +1 -0
- package/lib/typescript/Spec/NativeCompressor.d.ts +14 -0
- package/lib/typescript/Spec/NativeCompressor.d.ts.map +1 -0
- package/lib/typescript/Spec/NativeVideoCompressor.d.ts +13 -0
- package/lib/typescript/Spec/NativeVideoCompressor.d.ts.map +1 -0
- package/lib/typescript/Video/index.d.ts +5 -3
- package/lib/typescript/Video/index.d.ts.map +1 -0
- package/lib/typescript/expo-plugin/compressor.d.ts +2 -3
- package/lib/typescript/expo-plugin/compressor.d.ts.map +1 -0
- package/lib/typescript/index.d.ts +7 -3
- package/lib/typescript/index.d.ts.map +1 -0
- package/lib/typescript/utils/index.d.ts +6 -4
- package/lib/typescript/utils/index.d.ts.map +1 -0
- package/package.json +62 -38
- package/react-native-compressor.podspec +24 -1
- package/src/Audio/index.tsx +6 -4
- package/src/Image/index.tsx +38 -5
- package/src/Main.tsx +41 -0
- package/src/Spec/NativeCompressor.ts +15 -0
- package/src/Spec/NativeVideoCompressor.ts +14 -0
- package/src/Video/index.tsx +28 -11
- package/src/expo-plugin/compressor.ts +2 -1
- package/src/index.tsx +7 -2
- package/src/utils/index.tsx +11 -5
- package/android/.gradle/6.9/executionHistory/executionHistory.lock +0 -0
- package/android/.gradle/6.9/fileChanges/last-build.bin +0 -0
- package/android/.gradle/6.9/fileHashes/fileHashes.bin +0 -0
- package/android/.gradle/6.9/fileHashes/fileHashes.lock +0 -0
- package/android/.gradle/6.9/gc.properties +0 -0
- package/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
- package/android/.gradle/buildOutputCleanup/cache.properties +0 -2
- package/android/.gradle/checksums/checksums.lock +0 -0
- package/android/.gradle/checksums/md5-checksums.bin +0 -0
- package/android/.gradle/checksums/sha1-checksums.bin +0 -0
- package/android/.gradle/vcs-1/gc.properties +0 -0
- package/android/.idea/caches/build_file_checksums.ser +0 -0
- package/android/.idea/compiler.xml +0 -6
- package/android/.idea/gradle.xml +0 -20
- package/android/.idea/jarRepositories.xml +0 -45
- package/android/.idea/libraries/Gradle__androidx_annotation_annotation_1_1_0.xml +0 -13
- package/android/.idea/libraries/Gradle__androidx_appcompat_appcompat_1_0_2_aar.xml +0 -24
- package/android/.idea/libraries/Gradle__androidx_arch_core_core_common_2_0_0.xml +0 -11
- package/android/.idea/libraries/Gradle__androidx_arch_core_core_runtime_2_0_0_aar.xml +0 -19
- package/android/.idea/libraries/Gradle__androidx_asynclayoutinflater_asynclayoutinflater_1_0_0_aar.xml +0 -19
- package/android/.idea/libraries/Gradle__androidx_autofill_autofill_1_1_0_aar.xml +0 -16
- package/android/.idea/libraries/Gradle__androidx_collection_collection_1_0_0.xml +0 -11
- package/android/.idea/libraries/Gradle__androidx_coordinatorlayout_coordinatorlayout_1_0_0_aar.xml +0 -24
- package/android/.idea/libraries/Gradle__androidx_core_core_1_1_0_aar.xml +0 -16
- package/android/.idea/libraries/Gradle__androidx_cursoradapter_cursoradapter_1_0_0_aar.xml +0 -19
- package/android/.idea/libraries/Gradle__androidx_customview_customview_1_0_0_aar.xml +0 -19
- package/android/.idea/libraries/Gradle__androidx_documentfile_documentfile_1_0_0_aar.xml +0 -19
- package/android/.idea/libraries/Gradle__androidx_drawerlayout_drawerlayout_1_0_0_aar.xml +0 -24
- package/android/.idea/libraries/Gradle__androidx_fragment_fragment_1_0_0_aar.xml +0 -24
- package/android/.idea/libraries/Gradle__androidx_interpolator_interpolator_1_0_0_aar.xml +0 -19
- package/android/.idea/libraries/Gradle__androidx_legacy_legacy_support_core_ui_1_0_0_aar.xml +0 -19
- package/android/.idea/libraries/Gradle__androidx_legacy_legacy_support_core_utils_1_0_0_aar.xml +0 -19
- package/android/.idea/libraries/Gradle__androidx_lifecycle_lifecycle_common_2_0_0.xml +0 -11
- package/android/.idea/libraries/Gradle__androidx_lifecycle_lifecycle_livedata_2_0_0_aar.xml +0 -19
- package/android/.idea/libraries/Gradle__androidx_lifecycle_lifecycle_livedata_core_2_0_0_aar.xml +0 -19
- package/android/.idea/libraries/Gradle__androidx_lifecycle_lifecycle_runtime_2_0_0_aar.xml +0 -19
- package/android/.idea/libraries/Gradle__androidx_lifecycle_lifecycle_viewmodel_2_0_0_aar.xml +0 -19
- package/android/.idea/libraries/Gradle__androidx_loader_loader_1_0_0_aar.xml +0 -19
- package/android/.idea/libraries/Gradle__androidx_localbroadcastmanager_localbroadcastmanager_1_0_0_aar.xml +0 -19
- package/android/.idea/libraries/Gradle__androidx_print_print_1_0_0_aar.xml +0 -24
- package/android/.idea/libraries/Gradle__androidx_slidingpanelayout_slidingpanelayout_1_0_0_aar.xml +0 -19
- package/android/.idea/libraries/Gradle__androidx_swiperefreshlayout_swiperefreshlayout_1_0_0_aar.xml +0 -24
- package/android/.idea/libraries/Gradle__androidx_vectordrawable_vectordrawable_1_0_1_aar.xml +0 -19
- package/android/.idea/libraries/Gradle__androidx_vectordrawable_vectordrawable_animated_1_0_0_aar.xml +0 -19
- package/android/.idea/libraries/Gradle__androidx_versionedparcelable_versionedparcelable_1_1_0_aar.xml +0 -13
- package/android/.idea/libraries/Gradle__androidx_viewpager_viewpager_1_0_0_aar.xml +0 -19
- package/android/.idea/libraries/Gradle__com_facebook_fbjni_fbjni_java_only_0_2_2.xml +0 -13
- package/android/.idea/libraries/Gradle__com_facebook_fresco_drawee_2_5_0_aar.xml +0 -15
- package/android/.idea/libraries/Gradle__com_facebook_fresco_fbcore_2_5_0_aar.xml +0 -18
- package/android/.idea/libraries/Gradle__com_facebook_fresco_fresco_2_5_0_aar.xml +0 -18
- package/android/.idea/libraries/Gradle__com_facebook_fresco_imagepipeline_2_5_0_aar.xml +0 -18
- package/android/.idea/libraries/Gradle__com_facebook_fresco_imagepipeline_base_2_5_0_aar.xml +0 -18
- package/android/.idea/libraries/Gradle__com_facebook_fresco_imagepipeline_native_2_5_0_aar.xml +0 -15
- package/android/.idea/libraries/Gradle__com_facebook_fresco_imagepipeline_okhttp3_2_5_0_aar.xml +0 -15
- package/android/.idea/libraries/Gradle__com_facebook_fresco_memory_type_ashmem_2_5_0_aar.xml +0 -15
- package/android/.idea/libraries/Gradle__com_facebook_fresco_memory_type_java_2_5_0_aar.xml +0 -15
- package/android/.idea/libraries/Gradle__com_facebook_fresco_memory_type_native_2_5_0_aar.xml +0 -15
- package/android/.idea/libraries/Gradle__com_facebook_fresco_nativeimagefilters_2_5_0_aar.xml +0 -15
- package/android/.idea/libraries/Gradle__com_facebook_fresco_nativeimagetranscoder_2_5_0_aar.xml +0 -15
- package/android/.idea/libraries/Gradle__com_facebook_fresco_ui_common_2_5_0_aar.xml +0 -15
- package/android/.idea/libraries/Gradle__com_facebook_infer_annotation_infer_annotation_0_18_0.xml +0 -13
- package/android/.idea/libraries/Gradle__com_facebook_react_react_native_0_66_1_aar.xml +0 -14
- package/android/.idea/libraries/Gradle__com_facebook_soloader_annotation_0_10_1.xml +0 -13
- package/android/.idea/libraries/Gradle__com_facebook_soloader_nativeloader_0_10_1.xml +0 -13
- package/android/.idea/libraries/Gradle__com_facebook_soloader_soloader_0_10_1_aar.xml +0 -15
- package/android/.idea/libraries/Gradle__com_facebook_yoga_proguard_annotations_1_19_0.xml +0 -13
- package/android/.idea/libraries/Gradle__com_google_code_findbugs_jsr305_3_0_2.xml +0 -13
- package/android/.idea/libraries/Gradle__com_googlecode_mp4parser_isoparser_1_0_6.xml +0 -13
- package/android/.idea/libraries/Gradle__com_squareup_okhttp3_okhttp_4_9_1.xml +0 -13
- package/android/.idea/libraries/Gradle__com_squareup_okhttp3_okhttp_urlconnection_4_9_1.xml +0 -13
- package/android/.idea/libraries/Gradle__com_squareup_okio_okio_2_9_0.xml +0 -13
- package/android/.idea/libraries/Gradle__io_github_lizhangqu_coreprogress_1_0_2_aar.xml +0 -18
- package/android/.idea/libraries/Gradle__javax_inject_javax_inject_1.xml +0 -13
- package/android/.idea/libraries/Gradle__org_aspectj_aspectjrt_1_8_2.xml +0 -13
- package/android/.idea/libraries/Gradle__org_jetbrains_annotations_13_0.xml +0 -13
- package/android/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_annotations_jvm_1_3_72.xml +0 -13
- package/android/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_4_10.xml +0 -13
- package/android/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_common_1_4_10.xml +0 -13
- package/android/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_jdk7_1_4_10.xml +0 -13
- package/android/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_jdk8_1_4_10.xml +0 -13
- package/android/.idea/libraries/Gradle__org_jetbrains_kotlinx_kotlinx_coroutines_android_1_4_0.xml +0 -13
- package/android/.idea/libraries/Gradle__org_jetbrains_kotlinx_kotlinx_coroutines_core_jvm_1_4_0.xml +0 -13
- package/android/.idea/misc.xml +0 -9
- package/android/.idea/modules/android.iml +0 -138
- package/android/.idea/modules.xml +0 -8
- package/android/.idea/vcs.xml +0 -6
- package/android/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/android/gradle/wrapper/gradle-wrapper.properties +0 -5
- package/android/gradlew +0 -183
- package/android/gradlew.bat +0 -100
- package/android/local.properties +0 -8
- package/ios/Compressor.m +0 -351
- package/ios/Compressor.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +0 -8
- package/ios/Compressor.xcodeproj/project.xcworkspace/xcuserdata/apple.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
- package/ios/Compressor.xcodeproj/xcshareddata/xcschemes/Compressor.xcscheme +0 -67
- package/ios/Compressor.xcodeproj/xcuserdata/apple.xcuserdatad/xcschemes/xcschememanagement.plist +0 -22
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -5,18 +5,21 @@
|
|
|
5
5
|
|
|
6
6
|
<div align="center">
|
|
7
7
|
|
|
8
|
-
[](https://discord.gg/
|
|
8
|
+
[](https://discord.gg/6Wx8Em8KAN)
|
|
9
9
|
[](https://github.com/numandev1/react-native-compressor/stargazers)
|
|
10
10
|
[](https://www.npmjs.com/package/react-native-compressor)
|
|
11
11
|

|
|
12
12
|

|
|
13
|
+
[](http://makeapullrequest.com)
|
|
13
14
|
|
|
14
15
|
</div>
|
|
15
16
|
|
|
16
|
-
**REACT-NATIVE-COMPRESSOR** is a react-native package, which
|
|
17
|
+
**REACT-NATIVE-COMPRESSOR** is a react-native package, which helps us to Compress `Image`, `Video`, and `Audio` before uploading, same like **Whatsapp** without knowing the compression `algorithm`
|
|
17
18
|
|
|
18
19
|
<div align="center">
|
|
19
|
-
<img height="
|
|
20
|
+
<img height="90" src="/media/whatsapp_logo.png"/>
|
|
21
|
+
|
|
22
|
+
<img height="90" src="/media/compress_media.png"/>
|
|
20
23
|
<h2 align="center">🗜️Compress Image, Video, and Audio same like Whatsapp</h2>
|
|
21
24
|
</div>
|
|
22
25
|
|
|
@@ -76,19 +79,13 @@ We should use **react-native-compressor** instead of **FFmpeg** because **react-
|
|
|
76
79
|
|
|
77
80
|
## Installation
|
|
78
81
|
|
|
79
|
-
### React Native
|
|
80
|
-
|
|
81
|
-
#### For React Native<0.65
|
|
82
|
-
|
|
83
82
|
```sh
|
|
84
|
-
yarn add react-native-compressor
|
|
83
|
+
yarn add react-native-compressor
|
|
85
84
|
```
|
|
86
85
|
|
|
87
|
-
|
|
86
|
+
### [New Architecture (Turbo Module)](https://reactnative.dev/docs/new-architecture-intro) Supported
|
|
87
|
+
you can give feedback on [Discord channel](https://discord.gg/dtYzk8sp)
|
|
88
88
|
|
|
89
|
-
```sh
|
|
90
|
-
yarn add react-native-compressor
|
|
91
|
-
```
|
|
92
89
|
|
|
93
90
|
### Managed Expo
|
|
94
91
|
|
|
@@ -164,8 +161,12 @@ react-native link react-native-compressor
|
|
|
164
161
|
```js
|
|
165
162
|
import { Image } from 'react-native-compressor';
|
|
166
163
|
|
|
167
|
-
const result = await Image.compress('file://path_of_file/image.jpg'
|
|
168
|
-
|
|
164
|
+
const result = await Image.compress('file://path_of_file/image.jpg');
|
|
165
|
+
// OR
|
|
166
|
+
const result = await Image.compress('https://path_of_file/image.jpg',{
|
|
167
|
+
downloadProgress: (progress) => {
|
|
168
|
+
console.log('downloadProgress: ', progress);
|
|
169
|
+
}
|
|
169
170
|
});
|
|
170
171
|
```
|
|
171
172
|
|
|
@@ -177,6 +178,7 @@ const result = await Image.compress('file://path_of_file/image.jpg', {
|
|
|
177
178
|
import { Image } from 'react-native-compressor';
|
|
178
179
|
|
|
179
180
|
const result = await Image.compress('file://path_of_file/image.jpg', {
|
|
181
|
+
compressionMethod: 'manual',
|
|
180
182
|
maxWidth: 1000,
|
|
181
183
|
quality: 0.8,
|
|
182
184
|
});
|
|
@@ -191,15 +193,23 @@ import { Video } from 'react-native-compressor';
|
|
|
191
193
|
|
|
192
194
|
const result = await Video.compress(
|
|
193
195
|
'file://path_of_file/BigBuckBunny.mp4',
|
|
196
|
+
{},
|
|
197
|
+
(progress) => {
|
|
198
|
+
console.log('Compression Progress: ', progress);
|
|
199
|
+
}
|
|
200
|
+
);
|
|
201
|
+
|
|
202
|
+
//OR
|
|
203
|
+
|
|
204
|
+
const result = await Video.compress(
|
|
205
|
+
'https://example.com/video.mp4',
|
|
194
206
|
{
|
|
195
|
-
|
|
207
|
+
downloadProgress: (progress) => {
|
|
208
|
+
console.log('downloadProgress: ', progress);
|
|
209
|
+
}
|
|
196
210
|
},
|
|
197
211
|
(progress) => {
|
|
198
|
-
if (backgroundMode) {
|
|
199
212
|
console.log('Compression Progress: ', progress);
|
|
200
|
-
} else {
|
|
201
|
-
setCompressingProgress(progress);
|
|
202
|
-
}
|
|
203
213
|
}
|
|
204
214
|
);
|
|
205
215
|
```
|
|
@@ -213,13 +223,11 @@ import { Video } from 'react-native-compressor';
|
|
|
213
223
|
|
|
214
224
|
const result = await Video.compress(
|
|
215
225
|
'file://path_of_file/BigBuckBunny.mp4',
|
|
216
|
-
{
|
|
226
|
+
{
|
|
227
|
+
compressionMethod: 'manual',
|
|
228
|
+
},
|
|
217
229
|
(progress) => {
|
|
218
|
-
if (backgroundMode) {
|
|
219
230
|
console.log('Compression Progress: ', progress);
|
|
220
|
-
} else {
|
|
221
|
-
setCompressingProgress(progress);
|
|
222
|
-
}
|
|
223
231
|
}
|
|
224
232
|
);
|
|
225
233
|
```
|
|
@@ -292,10 +300,13 @@ const uploadResult = await backgroundUpload(
|
|
|
292
300
|
|
|
293
301
|
### CompressorOptions
|
|
294
302
|
|
|
295
|
-
- ###### `compressionMethod: compressionMethod` (default: "
|
|
303
|
+
- ###### `compressionMethod: compressionMethod` (default: "auto")
|
|
296
304
|
|
|
297
305
|
if you want to compress images like **whatsapp** then make this prop `auto`. Can be either `manual` or `auto`, defines the Compression Method.
|
|
298
306
|
|
|
307
|
+
- ##### `downloadProgress?: (progress: number) => void;`
|
|
308
|
+
it is callback, only trigger when we pass image url from server
|
|
309
|
+
|
|
299
310
|
- ###### `maxWidth: number` (default: 1280)
|
|
300
311
|
|
|
301
312
|
The maximum width boundary used as the main boundary in resizing a landscape image.
|
|
@@ -332,6 +343,9 @@ const uploadResult = await backgroundUpload(
|
|
|
332
343
|
|
|
333
344
|
if you want to compress videos like **whatsapp** then make this prop `auto`. Can be either `manual` or `auto`, defines the Compression Method.
|
|
334
345
|
|
|
346
|
+
- ##### `downloadProgress?: (progress: number) => void;`
|
|
347
|
+
it is callback, only trigger when we pass image url from server
|
|
348
|
+
|
|
335
349
|
- ###### `maxSize: number` (default: 640)
|
|
336
350
|
|
|
337
351
|
The maximum size can be height in case of portrait video or can be width in case of landscape video.
|
|
@@ -340,9 +354,9 @@ const uploadResult = await backgroundUpload(
|
|
|
340
354
|
|
|
341
355
|
bitrate of video which reduce or increase video size. if compressionMethod will auto then this prop will not work
|
|
342
356
|
|
|
343
|
-
- ###### `minimumFileSizeForCompress: number` (default:
|
|
357
|
+
- ###### `minimumFileSizeForCompress: number` (default: 0)
|
|
344
358
|
|
|
345
|
-
16
|
|
359
|
+
previously default was 16 but now it is 0 by default. 0 mean 0mb. This is an offset, which you can set for minimumFileSizeForCompress will allow this package to dont compress less than or equal to `minimumFileSizeForCompress` ref [#26](https://github.com/numandev1/react-native-compressor/issues/26)
|
|
346
360
|
|
|
347
361
|
- ###### `getCancellationId: function`
|
|
348
362
|
`getCancellationId` is a callback function that gives us compress video id, which can be used in `Video.cancelCompression` method to cancel the compression
|
package/android/build.gradle
CHANGED
|
@@ -1,62 +1,115 @@
|
|
|
1
1
|
buildscript {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
2
|
+
repositories {
|
|
3
|
+
google()
|
|
4
|
+
mavenCentral()
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
dependencies {
|
|
8
|
+
classpath "com.android.tools.build:gradle:7.2.1"
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
def isNewArchitectureEnabled() {
|
|
13
|
+
return rootProject.hasProperty("newArchEnabled") && rootProject.getProperty("newArchEnabled") == "true"
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
apply plugin: "com.android.library"
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def appProject = rootProject.allprojects.find { it.plugins.hasPlugin('com.android.application') }
|
|
20
|
+
|
|
21
|
+
if (isNewArchitectureEnabled()) {
|
|
22
|
+
apply plugin: "com.facebook.react"
|
|
12
23
|
}
|
|
13
24
|
|
|
14
|
-
|
|
25
|
+
def getExtOrDefault(name) {
|
|
26
|
+
return rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties["Compressor_" + name]
|
|
27
|
+
}
|
|
15
28
|
|
|
16
|
-
def
|
|
17
|
-
|
|
29
|
+
def getExtOrIntegerDefault(name) {
|
|
30
|
+
return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties["Compressor_" + name]).toInteger()
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
def supportsNamespace() {
|
|
34
|
+
def parsed = com.android.Version.ANDROID_GRADLE_PLUGIN_VERSION.tokenize('.')
|
|
35
|
+
def major = parsed[0].toInteger()
|
|
36
|
+
def minor = parsed[1].toInteger()
|
|
37
|
+
|
|
38
|
+
// Namespace support was added in 7.3.0
|
|
39
|
+
if (major == 7 && minor >= 3) {
|
|
40
|
+
return true
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return major >= 8
|
|
18
44
|
}
|
|
19
45
|
|
|
20
46
|
android {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
defaultConfig {
|
|
24
|
-
minSdkVersion safeExtGet('minSdkVersion', 16)
|
|
25
|
-
targetSdkVersion safeExtGet('targetSdkVersion', 29)
|
|
26
|
-
versionCode 1
|
|
27
|
-
versionName "1.0"
|
|
47
|
+
if (supportsNamespace()) {
|
|
48
|
+
namespace "com.reactnativecompressor"
|
|
28
49
|
|
|
50
|
+
sourceSets {
|
|
51
|
+
main {
|
|
52
|
+
manifest.srcFile "src/main/AndroidManifestNew.xml"
|
|
53
|
+
}
|
|
29
54
|
}
|
|
55
|
+
}
|
|
30
56
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
57
|
+
compileSdkVersion getExtOrIntegerDefault("compileSdkVersion")
|
|
58
|
+
|
|
59
|
+
defaultConfig {
|
|
60
|
+
minSdkVersion getExtOrIntegerDefault("minSdkVersion")
|
|
61
|
+
targetSdkVersion getExtOrIntegerDefault("targetSdkVersion")
|
|
62
|
+
buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()
|
|
63
|
+
}
|
|
64
|
+
buildTypes {
|
|
65
|
+
release {
|
|
66
|
+
minifyEnabled false
|
|
38
67
|
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
lintOptions {
|
|
71
|
+
disable "GradleCompatible"
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
compileOptions {
|
|
75
|
+
sourceCompatibility JavaVersion.VERSION_1_8
|
|
76
|
+
targetCompatibility JavaVersion.VERSION_1_8
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
sourceSets {
|
|
80
|
+
main {
|
|
81
|
+
if (isNewArchitectureEnabled()) {
|
|
82
|
+
java.srcDirs += [
|
|
83
|
+
"src/newarch",
|
|
84
|
+
// This is needed to build Kotlin project with NewArch enabled
|
|
85
|
+
"${project.buildDir}/generated/source/codegen/java"
|
|
86
|
+
]
|
|
87
|
+
} else {
|
|
88
|
+
java.srcDirs += ["src/oldarch"]
|
|
89
|
+
}
|
|
42
90
|
}
|
|
91
|
+
}
|
|
43
92
|
}
|
|
44
93
|
|
|
45
94
|
repositories {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
maven {
|
|
49
|
-
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
|
|
50
|
-
url("$rootDir/../node_modules/react-native/android")
|
|
51
|
-
}
|
|
52
|
-
mavenCentral()
|
|
53
|
-
maven { url "https://www.jitpack.io" }
|
|
95
|
+
mavenCentral()
|
|
96
|
+
google()
|
|
54
97
|
}
|
|
55
98
|
|
|
99
|
+
|
|
56
100
|
dependencies {
|
|
57
|
-
|
|
58
|
-
|
|
101
|
+
// For < 0.71, this will be from the local maven repo
|
|
102
|
+
// For > 0.71, this will be replaced by `com.facebook.react:react-android:$version` by react gradle plugin
|
|
103
|
+
//noinspection GradleDynamicVersion
|
|
104
|
+
implementation "com.facebook.react:react-native:+"
|
|
59
105
|
implementation 'io.github.lizhangqu:coreprogress:1.0.2'
|
|
60
|
-
implementation 'com.github.numandev1:VideoCompressor:
|
|
61
|
-
|
|
106
|
+
implementation 'com.github.numandev1:VideoCompressor:1a262bba37'
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (isNewArchitectureEnabled()) {
|
|
110
|
+
react {
|
|
111
|
+
jsRootDir = file("../src/")
|
|
112
|
+
libraryName = "Compressor"
|
|
113
|
+
codegenJavaPackageName = "com.reactnativecompressor"
|
|
114
|
+
}
|
|
62
115
|
}
|
|
@@ -1,67 +1,64 @@
|
|
|
1
1
|
package com.reactnativecompressor;
|
|
2
2
|
|
|
3
|
-
import android.media.MediaMetadataRetriever;
|
|
4
|
-
import android.net.Uri;
|
|
5
|
-
import android.os.Build;
|
|
6
|
-
import android.util.Log;
|
|
7
|
-
|
|
8
3
|
import androidx.annotation.NonNull;
|
|
9
|
-
import androidx.annotation.Nullable;
|
|
10
|
-
import androidx.annotation.RequiresApi;
|
|
11
4
|
|
|
12
|
-
import com.facebook.react.bridge.Arguments;
|
|
13
5
|
import com.facebook.react.bridge.Promise;
|
|
14
6
|
import com.facebook.react.bridge.ReactApplicationContext;
|
|
15
|
-
import com.facebook.react.bridge.ReactContext;
|
|
16
|
-
import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
|
17
7
|
import com.facebook.react.bridge.ReactMethod;
|
|
8
|
+
|
|
9
|
+
import androidx.annotation.RequiresApi;
|
|
10
|
+
|
|
11
|
+
import com.facebook.react.bridge.Arguments;
|
|
12
|
+
import com.facebook.react.bridge.ReactContext;
|
|
18
13
|
import com.facebook.react.bridge.ReadableMap;
|
|
19
14
|
import com.facebook.react.bridge.WritableMap;
|
|
20
|
-
import com.facebook.react.module.annotations.ReactModule;
|
|
21
|
-
import com.facebook.react.modules.core.DeviceEventManagerModule;
|
|
22
15
|
import com.reactnativecompressor.Image.ImageCompressor;
|
|
23
16
|
import com.reactnativecompressor.Image.utils.ImageCompressorOptions;
|
|
17
|
+
import com.reactnativecompressor.Utils.MediaCache;
|
|
24
18
|
import com.reactnativecompressor.Utils.Utils;
|
|
25
19
|
import com.reactnativecompressor.Video.VideoCompressorHelper;
|
|
20
|
+
import com.reactnativecompressor.CompressorSpec;
|
|
26
21
|
import static com.reactnativecompressor.Utils.Utils.generateCacheFilePath;
|
|
27
|
-
|
|
22
|
+
|
|
23
|
+
import android.content.ContentResolver;
|
|
24
|
+
import android.content.res.AssetFileDescriptor;
|
|
25
|
+
import android.database.Cursor;
|
|
26
|
+
import android.media.MediaMetadataRetriever;
|
|
27
|
+
import android.net.Uri;
|
|
28
|
+
import android.os.Build;
|
|
29
|
+
import android.provider.OpenableColumns;
|
|
30
|
+
import android.util.Log;
|
|
28
31
|
|
|
29
32
|
import com.reactnativecompressor.Audio.AudioCompressor;
|
|
30
33
|
|
|
31
34
|
import java.io.File;
|
|
35
|
+
import java.io.FileNotFoundException;
|
|
32
36
|
|
|
33
|
-
|
|
34
|
-
public
|
|
35
|
-
public static final String NAME = "Compressor";
|
|
37
|
+
public class CompressorModule extends CompressorSpec {
|
|
38
|
+
public static final String NAME = "Compressor";
|
|
36
39
|
private final ReactApplicationContext reactContext;
|
|
37
|
-
public CompressorModule(ReactApplicationContext reactContext) {
|
|
38
|
-
super(reactContext);
|
|
39
|
-
this.reactContext = reactContext;
|
|
40
|
-
}
|
|
41
40
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
}
|
|
41
|
+
public CompressorModule(ReactApplicationContext context) {
|
|
42
|
+
super(context);
|
|
43
|
+
this.reactContext = context;
|
|
44
|
+
}
|
|
47
45
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
|
|
53
|
-
.emit(eventName, params);
|
|
46
|
+
@Override
|
|
47
|
+
@NonNull
|
|
48
|
+
public String getName() {
|
|
49
|
+
return NAME;
|
|
54
50
|
}
|
|
55
51
|
|
|
56
|
-
|
|
52
|
+
//Image
|
|
57
53
|
@ReactMethod
|
|
58
54
|
public void image_compress(
|
|
59
55
|
String imagePath,
|
|
60
56
|
ReadableMap optionMap,
|
|
61
57
|
Promise promise) {
|
|
62
58
|
try {
|
|
63
|
-
imagePath=Utils.getRealPath(imagePath,reactContext);
|
|
64
59
|
final ImageCompressorOptions options = ImageCompressorOptions.fromMap(optionMap);
|
|
60
|
+
imagePath=Utils.getRealPath(imagePath,reactContext,options.uuid);
|
|
61
|
+
|
|
65
62
|
|
|
66
63
|
if(options.compressionMethod==ImageCompressorOptions.CompressionMethod.auto)
|
|
67
64
|
{
|
|
@@ -73,13 +70,14 @@ public class CompressorModule extends ReactContextBaseJavaModule {
|
|
|
73
70
|
String returnableResult=ImageCompressor.manualCompressImage(imagePath,options,reactContext);
|
|
74
71
|
promise.resolve(returnableResult);
|
|
75
72
|
}
|
|
73
|
+
MediaCache.removeCompletedImagePath(imagePath);
|
|
76
74
|
} catch (Exception ex) {
|
|
77
75
|
promise.reject(ex);
|
|
78
76
|
}
|
|
79
77
|
}
|
|
80
78
|
|
|
81
|
-
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
|
|
82
79
|
@ReactMethod
|
|
80
|
+
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
|
|
83
81
|
public void compress_audio(
|
|
84
82
|
String fileUrl,
|
|
85
83
|
ReadableMap optionMap,
|
|
@@ -104,15 +102,15 @@ public class CompressorModule extends ReactContextBaseJavaModule {
|
|
|
104
102
|
|
|
105
103
|
|
|
106
104
|
//General
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
105
|
+
@ReactMethod
|
|
106
|
+
public void generateFilePath(String extension, Promise promise) {
|
|
107
|
+
try {
|
|
108
|
+
final String outputUri =generateCacheFilePath(extension,reactContext);
|
|
109
|
+
promise.resolve(outputUri);
|
|
110
|
+
} catch (Exception e) {
|
|
111
|
+
promise.reject(e);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
116
114
|
|
|
117
115
|
@ReactMethod
|
|
118
116
|
public void getRealPath(String path,String type, Promise promise) {
|
|
@@ -153,4 +151,70 @@ public class CompressorModule extends ReactContextBaseJavaModule {
|
|
|
153
151
|
promise.reject(e);
|
|
154
152
|
}
|
|
155
153
|
}
|
|
154
|
+
@ReactMethod
|
|
155
|
+
public void getFileSize(String filePath, Promise promise)
|
|
156
|
+
{
|
|
157
|
+
if(filePath.startsWith("http://")||filePath.startsWith("https://"))
|
|
158
|
+
{
|
|
159
|
+
promise.resolve(Utils.getFileSizeFromURL(filePath));
|
|
160
|
+
}
|
|
161
|
+
else
|
|
162
|
+
{
|
|
163
|
+
filePath=Utils.getRealPath(filePath,reactContext);
|
|
164
|
+
Uri uri= Uri.parse(filePath);
|
|
165
|
+
ContentResolver contentResolver = reactContext.getContentResolver();
|
|
166
|
+
long fileSize = getLength(uri, contentResolver);
|
|
167
|
+
if (fileSize >= 0) {
|
|
168
|
+
promise.resolve(String.valueOf(fileSize));
|
|
169
|
+
} else {
|
|
170
|
+
promise.resolve("");
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
@ReactMethod
|
|
176
|
+
public void addListener(String eventName) {
|
|
177
|
+
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
@ReactMethod
|
|
181
|
+
public void removeListeners(double count) {
|
|
182
|
+
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
public static long getLength(Uri uri, ContentResolver contentResolver) {
|
|
186
|
+
AssetFileDescriptor assetFileDescriptor = null;
|
|
187
|
+
try {
|
|
188
|
+
assetFileDescriptor = contentResolver.openAssetFileDescriptor(uri, "r");
|
|
189
|
+
} catch (FileNotFoundException e) {
|
|
190
|
+
// Do nothing
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
long length = (assetFileDescriptor != null) ? assetFileDescriptor.getLength() : -1L;
|
|
194
|
+
if (length != -1L) {
|
|
195
|
+
return length;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
if (ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
|
|
199
|
+
Cursor cursor = contentResolver.query(uri, new String[]{OpenableColumns.SIZE}, null, null, null);
|
|
200
|
+
if (cursor != null) {
|
|
201
|
+
try {
|
|
202
|
+
int sizeIndex = cursor.getColumnIndex(OpenableColumns.SIZE);
|
|
203
|
+
if (sizeIndex != -1 && cursor.moveToFirst()) {
|
|
204
|
+
try {
|
|
205
|
+
return cursor.getLong(sizeIndex);
|
|
206
|
+
} catch (Throwable ignored) {
|
|
207
|
+
return -1L;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
} finally {
|
|
211
|
+
cursor.close();
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
return -1L;
|
|
215
|
+
} else {
|
|
216
|
+
return -1L;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
156
220
|
}
|
|
@@ -1,30 +1,58 @@
|
|
|
1
1
|
package com.reactnativecompressor;
|
|
2
2
|
|
|
3
|
-
import androidx.annotation.
|
|
3
|
+
import androidx.annotation.Nullable;
|
|
4
4
|
|
|
5
|
-
import com.facebook.react.ReactPackage;
|
|
6
5
|
import com.facebook.react.bridge.NativeModule;
|
|
7
6
|
import com.facebook.react.bridge.ReactApplicationContext;
|
|
8
|
-
import com.facebook.react.
|
|
7
|
+
import com.facebook.react.module.model.ReactModuleInfo;
|
|
8
|
+
import com.facebook.react.module.model.ReactModuleInfoProvider;
|
|
9
|
+
import com.facebook.react.TurboReactPackage;
|
|
10
|
+
import java.util.HashMap;
|
|
11
|
+
import java.util.Map;
|
|
9
12
|
import com.reactnativecompressor.Video.VideoModule;
|
|
10
13
|
|
|
11
|
-
|
|
12
|
-
import java.util.Collections;
|
|
13
|
-
import java.util.List;
|
|
14
|
+
public class CompressorPackage extends TurboReactPackage {
|
|
14
15
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
16
|
+
@Nullable
|
|
17
|
+
@Override
|
|
18
|
+
public NativeModule getModule(String name, ReactApplicationContext reactContext) {
|
|
19
|
+
if (name.equals(CompressorModule.NAME)) {
|
|
20
|
+
return new CompressorModule(reactContext);
|
|
21
|
+
} else if (name.equals(VideoModule.NAME)) {
|
|
22
|
+
return new VideoModule(reactContext);
|
|
23
|
+
} else {
|
|
24
|
+
return null;
|
|
23
25
|
}
|
|
26
|
+
}
|
|
24
27
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
@Override
|
|
29
|
+
public ReactModuleInfoProvider getReactModuleInfoProvider() {
|
|
30
|
+
return () -> {
|
|
31
|
+
final Map<String, ReactModuleInfo> moduleInfos = new HashMap<>();
|
|
32
|
+
boolean isTurboModule = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED;
|
|
33
|
+
moduleInfos.put(
|
|
34
|
+
CompressorModule.NAME,
|
|
35
|
+
new ReactModuleInfo(
|
|
36
|
+
CompressorModule.NAME,
|
|
37
|
+
CompressorModule.NAME,
|
|
38
|
+
false, // canOverrideExistingModule
|
|
39
|
+
false, // needsEagerInit
|
|
40
|
+
true, // hasConstants
|
|
41
|
+
false, // isCxxModule
|
|
42
|
+
isTurboModule // isTurboModule
|
|
43
|
+
));
|
|
44
|
+
moduleInfos.put(
|
|
45
|
+
VideoModule.NAME,
|
|
46
|
+
new ReactModuleInfo(
|
|
47
|
+
VideoModule.NAME,
|
|
48
|
+
VideoModule.NAME,
|
|
49
|
+
false, // canOverrideExistingModule
|
|
50
|
+
false, // needsEagerInit
|
|
51
|
+
true, // hasConstants
|
|
52
|
+
false, // isCxxModule
|
|
53
|
+
isTurboModule // isTurboModule
|
|
54
|
+
));
|
|
55
|
+
return moduleInfos;
|
|
56
|
+
};
|
|
57
|
+
}
|
|
30
58
|
}
|
|
@@ -201,22 +201,7 @@ public class ImageCompressor {
|
|
|
201
201
|
bmp.recycle();
|
|
202
202
|
}
|
|
203
203
|
|
|
204
|
-
|
|
205
|
-
try {
|
|
206
|
-
exif = new ExifInterface(imagePath);
|
|
207
|
-
int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 0);
|
|
208
|
-
Matrix matrix = new Matrix();
|
|
209
|
-
if (orientation == 6) {
|
|
210
|
-
matrix.postRotate(90);
|
|
211
|
-
} else if (orientation == 3) {
|
|
212
|
-
matrix.postRotate(180);
|
|
213
|
-
} else if (orientation == 8) {
|
|
214
|
-
matrix.postRotate(270);
|
|
215
|
-
}
|
|
216
|
-
scaledBitmap = Bitmap.createBitmap(scaledBitmap, 0, 0, scaledBitmap.getWidth(), scaledBitmap.getHeight(), matrix, true);
|
|
217
|
-
} catch (IOException e) {
|
|
218
|
-
e.printStackTrace();
|
|
219
|
-
}
|
|
204
|
+
scaledBitmap = correctImageOrientation(scaledBitmap, imagePath);
|
|
220
205
|
|
|
221
206
|
final ByteArrayOutputStream imageDataByteArrayOutputStream = ImageCompressor.compress(scaledBitmap, compressorOptions.output, compressorOptions.quality);
|
|
222
207
|
String returnableResult = ImageCompressor.encodeImage(imageDataByteArrayOutputStream,isBase64,compressorOptions.output.toString(),reactContext);
|
|
@@ -242,4 +227,31 @@ public class ImageCompressor {
|
|
|
242
227
|
|
|
243
228
|
return inSampleSize;
|
|
244
229
|
}
|
|
230
|
+
|
|
231
|
+
public static Bitmap correctImageOrientation(Bitmap bitmap, String imagePath) {
|
|
232
|
+
try {
|
|
233
|
+
ExifInterface exif = new ExifInterface(imagePath);
|
|
234
|
+
int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
|
|
235
|
+
Matrix matrix = new Matrix();
|
|
236
|
+
|
|
237
|
+
switch (orientation) {
|
|
238
|
+
case ExifInterface.ORIENTATION_ROTATE_90:
|
|
239
|
+
matrix.postRotate(90);
|
|
240
|
+
break;
|
|
241
|
+
case ExifInterface.ORIENTATION_ROTATE_180:
|
|
242
|
+
matrix.postRotate(180);
|
|
243
|
+
break;
|
|
244
|
+
case ExifInterface.ORIENTATION_ROTATE_270:
|
|
245
|
+
matrix.postRotate(270);
|
|
246
|
+
break;
|
|
247
|
+
default:
|
|
248
|
+
return bitmap; // No rotation needed
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
|
|
252
|
+
} catch (IOException e) {
|
|
253
|
+
e.printStackTrace();
|
|
254
|
+
return bitmap; // Return original bitmap if an error occurs
|
|
255
|
+
}
|
|
256
|
+
}
|
|
245
257
|
}
|