├── .github └── FUNDING.yml ├── .gitignore ├── .npmignore ├── AwesomeExample ├── .bundle │ └── config ├── .eslintrc.js ├── .gitignore ├── .prettierrc.js ├── .watchmanconfig ├── App.tsx ├── Gemfile ├── Gemfile.lock ├── README.md ├── __tests__ │ └── App.test.tsx ├── android │ ├── app │ │ ├── build.gradle │ │ ├── debug.keystore │ │ ├── proguard-rules.pro │ │ └── src │ │ │ ├── debug │ │ │ └── AndroidManifest.xml │ │ │ └── main │ │ │ ├── AndroidManifest.xml │ │ │ ├── java │ │ │ └── com │ │ │ │ └── awesomeexample │ │ │ │ ├── MainActivity.kt │ │ │ │ └── MainApplication.kt │ │ │ └── res │ │ │ ├── drawable │ │ │ └── rn_edit_text_material.xml │ │ │ ├── mipmap-hdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-mdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxxhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ └── values │ │ │ ├── strings.xml │ │ │ └── styles.xml │ ├── build.gradle │ ├── gradle.properties │ ├── gradle │ │ └── wrapper │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ ├── gradlew │ ├── gradlew.bat │ └── settings.gradle ├── app.json ├── babel.config.js ├── index.js ├── ios │ ├── .xcode.env │ ├── AwesomeExample.xcodeproj │ │ ├── project.pbxproj │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ └── AwesomeExample.xcscheme │ ├── AwesomeExample.xcworkspace │ │ └── contents.xcworkspacedata │ ├── AwesomeExample │ │ ├── AppDelegate.swift │ │ ├── Images.xcassets │ │ │ ├── AppIcon.appiconset │ │ │ │ └── Contents.json │ │ │ └── Contents.json │ │ ├── Info.plist │ │ ├── LaunchScreen.storyboard │ │ └── PrivacyInfo.xcprivacy │ ├── Podfile │ └── Podfile.lock ├── jest.config.js ├── metro.config.js ├── package ├── package.json ├── tsconfig.json └── yarn.lock ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE.md ├── LICENSE ├── README.md ├── RNImageCropPicker.podspec ├── android ├── android.iml ├── build.gradle ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── src │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── reactnative │ │ │ └── ivpusic │ │ │ └── imagepicker │ │ │ ├── Compression.java │ │ │ ├── ExifExtractor.java │ │ │ ├── GeoDegree.java │ │ │ ├── ImageCropPicker.java │ │ │ ├── IvpusicImagePickerFileProvider.java │ │ │ ├── PickerPackage.java │ │ │ ├── RealPathUtil.java │ │ │ └── ResultCollector.java │ └── res │ │ └── xml │ │ └── ivpusic_imagepicker_provider_paths.xml │ ├── newArch │ └── java │ │ └── com │ │ └── reactnative │ │ └── ivpusic │ │ └── imagepicker │ │ └── PickerModule.java │ ├── oldArch │ └── java │ │ └── com │ │ └── reactnative │ │ └── ivpusic │ │ └── imagepicker │ │ └── PickerModule.java │ └── test │ └── test.iml ├── images ├── ios_circular_crop.png ├── ios_multiple_pick_v2.png ├── ios_normal_crop.png └── ios_single_pick_v2.png ├── index.d.ts ├── index.js ├── ios ├── ImageCropPickerSDK │ └── QBImagePicker.framework │ │ ├── Headers │ │ ├── QBImagePicker.h │ │ └── QBImagePickerController.h │ │ ├── Info.plist │ │ ├── Modules │ │ └── module.modulemap │ │ ├── QBImagePicker │ │ ├── QBImagePicker.storyboardc │ │ ├── Info.plist │ │ ├── QBAlbumsNavigationController.nib │ │ ├── QBAlbumsViewController.nib │ │ ├── QBAssetsViewController.nib │ │ ├── QL5-wR-LYt-view-66K-TS-Yoc.nib │ │ └── QiH-NZ-ZGN-view-sD2-zK-ryo.nib │ │ ├── _CodeSignature │ │ └── CodeResources │ │ ├── de.lproj │ │ └── QBImagePicker.strings │ │ ├── en.lproj │ │ └── QBImagePicker.strings │ │ ├── es.lproj │ │ └── QBImagePicker.strings │ │ ├── ja.lproj │ │ └── QBImagePicker.strings │ │ ├── pl.lproj │ │ └── QBImagePicker.strings │ │ └── zh-Hans.lproj │ │ └── QBImagePicker.strings ├── PrivacyInfo.xcprivacy ├── QBImagePicker │ ├── .gitignore │ ├── LICENSE │ ├── QBImagePicker.xcodeproj │ │ ├── project.pbxproj │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ └── QBImagePicker.xcscheme │ ├── QBImagePicker │ │ ├── Info.plist │ │ ├── QBAlbumCell.h │ │ ├── QBAlbumCell.m │ │ ├── QBAlbumsViewController.h │ │ ├── QBAlbumsViewController.m │ │ ├── QBAssetCell.h │ │ ├── QBAssetCell.m │ │ ├── QBAssetsViewController.h │ │ ├── QBAssetsViewController.m │ │ ├── QBCheckmarkView.h │ │ ├── QBCheckmarkView.m │ │ ├── QBImagePicker.h │ │ ├── QBImagePicker.storyboard │ │ ├── QBImagePickerController.h │ │ ├── QBImagePickerController.m │ │ ├── QBSlomoIconView.h │ │ ├── QBSlomoIconView.m │ │ ├── QBVideoIconView.h │ │ ├── QBVideoIconView.m │ │ ├── QBVideoIndicatorView.h │ │ ├── QBVideoIndicatorView.m │ │ ├── da.lproj │ │ │ └── QBImagePicker.strings │ │ ├── de.lproj │ │ │ └── QBImagePicker.strings │ │ ├── en.lproj │ │ │ └── QBImagePicker.strings │ │ ├── es.lproj │ │ │ └── QBImagePicker.strings │ │ ├── fi.lproj │ │ │ └── QBImagePicker.strings │ │ ├── fr.lproj │ │ │ └── QBImagePicker.strings │ │ ├── it.lproj │ │ │ └── QBImagePicker.strings │ │ ├── ja.lproj │ │ │ └── QBImagePicker.strings │ │ ├── ko.lproj │ │ │ └── QBImagePicker.strings │ │ ├── nb.lproj │ │ │ └── QBImagePicker.strings │ │ ├── nl.lproj │ │ │ └── QBImagePicker.strings │ │ ├── pl.lproj │ │ │ └── QBImagePicker.strings │ │ ├── pt.lproj │ │ │ └── QBImagePicker.strings │ │ ├── ro.lproj │ │ │ └── QBImagePicker.strings │ │ ├── ru.lproj │ │ │ └── QBImagePicker.strings │ │ ├── sv.lproj │ │ │ └── QBImagePicker.strings │ │ ├── tr.lproj │ │ │ └── QBImagePicker.strings │ │ ├── uk.lproj │ │ │ └── QBImagePicker.strings │ │ ├── vi.lproj │ │ │ └── QBImagePicker.strings │ │ ├── zh-Hans.lproj │ │ │ └── QBImagePicker.strings │ │ └── zh-Hant.lproj │ │ │ └── QBImagePicker.strings │ └── QBImagePickerController.podspec ├── imageCropPicker.xcodeproj │ └── project.pbxproj └── src │ ├── Compression.h │ ├── Compression.m │ ├── ImageCropPicker.h │ ├── ImageCropPicker.mm │ ├── UIImage+Extension.h │ ├── UIImage+Extension.m │ ├── UIImage+Resize.h │ └── UIImage+Resize.m ├── package.json ├── src └── NativeImageCropPicker.ts ├── svg.svg └── yarn.lock /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | open_collective: react-native-image-crop-picker -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | # 3 | .DS_Store 4 | 5 | # android studio 6 | *.iml 7 | .idea 8 | .gradle 9 | build/ 10 | 11 | # Xcode 12 | # 13 | build/ 14 | *.pbxuser 15 | !default.pbxuser 16 | *.mode1v3 17 | !default.mode1v3 18 | *.mode2v3 19 | !default.mode2v3 20 | *.perspectivev3 21 | !default.perspectivev3 22 | xcuserdata 23 | *.xccheckout 24 | *.moved-aside 25 | DerivedData 26 | *.hmap 27 | *.ipa 28 | *.xcuserstate 29 | project.xcworkspace 30 | 31 | # Android/IJ 32 | # 33 | .idea 34 | .gradle 35 | local.properties 36 | 37 | # node.js 38 | # 39 | node_modules/ 40 | npm-debug.log 41 | 42 | # BUCK 43 | buck-out/ 44 | \.buckd/ 45 | android/app/libs 46 | android/keystores/debug.keystore 47 | pods 48 | .vscode 49 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .git 2 | example 3 | node_modules 4 | build 5 | images 6 | 7 | # android studio 8 | *.iml 9 | .idea 10 | .gradle 11 | build/ -------------------------------------------------------------------------------- /AwesomeExample/.bundle/config: -------------------------------------------------------------------------------- 1 | BUNDLE_PATH: "vendor/bundle" 2 | BUNDLE_FORCE_RUBY_PLATFORM: 1 3 | -------------------------------------------------------------------------------- /AwesomeExample/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | extends: '@react-native', 4 | }; 5 | -------------------------------------------------------------------------------- /AwesomeExample/.gitignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | # 3 | .DS_Store 4 | 5 | # Xcode 6 | # 7 | build/ 8 | *.pbxuser 9 | !default.pbxuser 10 | *.mode1v3 11 | !default.mode1v3 12 | *.mode2v3 13 | !default.mode2v3 14 | *.perspectivev3 15 | !default.perspectivev3 16 | xcuserdata 17 | *.xccheckout 18 | *.moved-aside 19 | DerivedData 20 | *.hmap 21 | *.ipa 22 | *.xcuserstate 23 | **/.xcode.env.local 24 | 25 | # Android/IntelliJ 26 | # 27 | build/ 28 | .idea 29 | .gradle 30 | local.properties 31 | *.iml 32 | *.hprof 33 | .cxx/ 34 | *.keystore 35 | !debug.keystore 36 | .kotlin/ 37 | 38 | # node.js 39 | # 40 | node_modules/ 41 | npm-debug.log 42 | yarn-error.log 43 | 44 | # fastlane 45 | # 46 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 47 | # screenshots whenever they are needed. 48 | # For more information about the recommended setup visit: 49 | # https://docs.fastlane.tools/best-practices/source-control/ 50 | 51 | **/fastlane/report.xml 52 | **/fastlane/Preview.html 53 | **/fastlane/screenshots 54 | **/fastlane/test_output 55 | 56 | # Bundle artifact 57 | *.jsbundle 58 | 59 | # Ruby / CocoaPods 60 | **/Pods/ 61 | /vendor/bundle/ 62 | 63 | # Temporary files created by Metro to check the health of the file watcher 64 | .metro-health-check* 65 | 66 | # testing 67 | /coverage 68 | 69 | # Yarn 70 | .yarn/* 71 | !.yarn/patches 72 | !.yarn/plugins 73 | !.yarn/releases 74 | !.yarn/sdks 75 | !.yarn/versions 76 | -------------------------------------------------------------------------------- /AwesomeExample/.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | arrowParens: 'avoid', 3 | bracketSameLine: true, 4 | bracketSpacing: false, 5 | singleQuote: true, 6 | trailingComma: 'all', 7 | }; 8 | -------------------------------------------------------------------------------- /AwesomeExample/.watchmanconfig: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /AwesomeExample/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # You may use http://rbenv.org/ or https://rvm.io/ to install and use this version 4 | ruby ">= 2.6.10" 5 | 6 | # Exclude problematic versions of cocoapods and activesupport that causes build failures. 7 | gem 'cocoapods', '>= 1.13', '!= 1.15.0', '!= 1.15.1' 8 | gem 'activesupport', '>= 6.1.7.5', '!= 7.1.0' 9 | gem 'xcodeproj', '< 1.26.0' 10 | gem 'concurrent-ruby', '< 1.3.4' 11 | 12 | # Ruby 3.4.0 has removed some libraries from the standard library. 13 | gem 'bigdecimal' 14 | gem 'logger' 15 | gem 'benchmark' 16 | gem 'mutex_m' 17 | -------------------------------------------------------------------------------- /AwesomeExample/Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | CFPropertyList (3.0.7) 5 | base64 6 | nkf 7 | rexml 8 | activesupport (7.2.2.1) 9 | base64 10 | benchmark (>= 0.3) 11 | bigdecimal 12 | concurrent-ruby (~> 1.0, >= 1.3.1) 13 | connection_pool (>= 2.2.5) 14 | drb 15 | i18n (>= 1.6, < 2) 16 | logger (>= 1.4.2) 17 | minitest (>= 5.1) 18 | securerandom (>= 0.3) 19 | tzinfo (~> 2.0, >= 2.0.5) 20 | addressable (2.8.7) 21 | public_suffix (>= 2.0.2, < 7.0) 22 | algoliasearch (1.27.5) 23 | httpclient (~> 2.8, >= 2.8.3) 24 | json (>= 1.5.1) 25 | atomos (0.1.3) 26 | base64 (0.2.0) 27 | benchmark (0.4.0) 28 | bigdecimal (3.1.9) 29 | claide (1.1.0) 30 | cocoapods (1.15.2) 31 | addressable (~> 2.8) 32 | claide (>= 1.0.2, < 2.0) 33 | cocoapods-core (= 1.15.2) 34 | cocoapods-deintegrate (>= 1.0.3, < 2.0) 35 | cocoapods-downloader (>= 2.1, < 3.0) 36 | cocoapods-plugins (>= 1.0.0, < 2.0) 37 | cocoapods-search (>= 1.0.0, < 2.0) 38 | cocoapods-trunk (>= 1.6.0, < 2.0) 39 | cocoapods-try (>= 1.1.0, < 2.0) 40 | colored2 (~> 3.1) 41 | escape (~> 0.0.4) 42 | fourflusher (>= 2.3.0, < 3.0) 43 | gh_inspector (~> 1.0) 44 | molinillo (~> 0.8.0) 45 | nap (~> 1.0) 46 | ruby-macho (>= 2.3.0, < 3.0) 47 | xcodeproj (>= 1.23.0, < 2.0) 48 | cocoapods-core (1.15.2) 49 | activesupport (>= 5.0, < 8) 50 | addressable (~> 2.8) 51 | algoliasearch (~> 1.0) 52 | concurrent-ruby (~> 1.1) 53 | fuzzy_match (~> 2.0.4) 54 | nap (~> 1.0) 55 | netrc (~> 0.11) 56 | public_suffix (~> 4.0) 57 | typhoeus (~> 1.0) 58 | cocoapods-deintegrate (1.0.5) 59 | cocoapods-downloader (2.1) 60 | cocoapods-plugins (1.0.0) 61 | nap 62 | cocoapods-search (1.0.1) 63 | cocoapods-trunk (1.6.0) 64 | nap (>= 0.8, < 2.0) 65 | netrc (~> 0.11) 66 | cocoapods-try (1.2.0) 67 | colored2 (3.1.2) 68 | concurrent-ruby (1.3.3) 69 | connection_pool (2.5.3) 70 | drb (2.2.3) 71 | escape (0.0.4) 72 | ethon (0.16.0) 73 | ffi (>= 1.15.0) 74 | ffi (1.17.2) 75 | fourflusher (2.3.1) 76 | fuzzy_match (2.0.4) 77 | gh_inspector (1.1.3) 78 | httpclient (2.9.0) 79 | mutex_m 80 | i18n (1.14.7) 81 | concurrent-ruby (~> 1.0) 82 | json (2.12.2) 83 | logger (1.7.0) 84 | minitest (5.25.5) 85 | molinillo (0.8.0) 86 | mutex_m (0.3.0) 87 | nanaimo (0.3.0) 88 | nap (1.1.0) 89 | netrc (0.11.0) 90 | nkf (0.2.0) 91 | public_suffix (4.0.7) 92 | rexml (3.4.1) 93 | ruby-macho (2.5.1) 94 | securerandom (0.4.1) 95 | typhoeus (1.4.1) 96 | ethon (>= 0.9.0) 97 | tzinfo (2.0.6) 98 | concurrent-ruby (~> 1.0) 99 | xcodeproj (1.25.1) 100 | CFPropertyList (>= 2.3.3, < 4.0) 101 | atomos (~> 0.1.3) 102 | claide (>= 1.0.2, < 2.0) 103 | colored2 (~> 3.1) 104 | nanaimo (~> 0.3.0) 105 | rexml (>= 3.3.6, < 4.0) 106 | 107 | PLATFORMS 108 | ruby 109 | 110 | DEPENDENCIES 111 | activesupport (>= 6.1.7.5, != 7.1.0) 112 | benchmark 113 | bigdecimal 114 | cocoapods (>= 1.13, != 1.15.1, != 1.15.0) 115 | concurrent-ruby (< 1.3.4) 116 | logger 117 | mutex_m 118 | xcodeproj (< 1.26.0) 119 | 120 | RUBY VERSION 121 | ruby 3.4.4p34 122 | 123 | BUNDLED WITH 124 | 2.6.9 125 | -------------------------------------------------------------------------------- /AwesomeExample/README.md: -------------------------------------------------------------------------------- 1 | This is a new [**React Native**](https://reactnative.dev) project, bootstrapped using [`@react-native-community/cli`](https://github.com/react-native-community/cli). 2 | 3 | # Getting Started 4 | 5 | > **Note**: Make sure you have completed the [Set Up Your Environment](https://reactnative.dev/docs/set-up-your-environment) guide before proceeding. 6 | 7 | ## Step 1: Start Metro 8 | 9 | First, you will need to run **Metro**, the JavaScript build tool for React Native. 10 | 11 | To start the Metro dev server, run the following command from the root of your React Native project: 12 | 13 | ```sh 14 | # Using npm 15 | npm start 16 | 17 | # OR using Yarn 18 | yarn start 19 | ``` 20 | 21 | ## Step 2: Build and run your app 22 | 23 | With Metro running, open a new terminal window/pane from the root of your React Native project, and use one of the following commands to build and run your Android or iOS app: 24 | 25 | ### Android 26 | 27 | ```sh 28 | # Using npm 29 | npm run android 30 | 31 | # OR using Yarn 32 | yarn android 33 | ``` 34 | 35 | ### iOS 36 | 37 | For iOS, remember to install CocoaPods dependencies (this only needs to be run on first clone or after updating native deps). 38 | 39 | The first time you create a new project, run the Ruby bundler to install CocoaPods itself: 40 | 41 | ```sh 42 | bundle install 43 | ``` 44 | 45 | Then, and every time you update your native dependencies, run: 46 | 47 | ```sh 48 | bundle exec pod install 49 | ``` 50 | 51 | For more information, please visit [CocoaPods Getting Started guide](https://guides.cocoapods.org/using/getting-started.html). 52 | 53 | ```sh 54 | # Using npm 55 | npm run ios 56 | 57 | # OR using Yarn 58 | yarn ios 59 | ``` 60 | 61 | If everything is set up correctly, you should see your new app running in the Android Emulator, iOS Simulator, or your connected device. 62 | 63 | This is one way to run your app — you can also build it directly from Android Studio or Xcode. 64 | 65 | ## Step 3: Modify your app 66 | 67 | Now that you have successfully run the app, let's make changes! 68 | 69 | Open `App.tsx` in your text editor of choice and make some changes. When you save, your app will automatically update and reflect these changes — this is powered by [Fast Refresh](https://reactnative.dev/docs/fast-refresh). 70 | 71 | When you want to forcefully reload, for example to reset the state of your app, you can perform a full reload: 72 | 73 | - **Android**: Press the R key twice or select **"Reload"** from the **Dev Menu**, accessed via Ctrl + M (Windows/Linux) or Cmd ⌘ + M (macOS). 74 | - **iOS**: Press R in iOS Simulator. 75 | 76 | ## Congratulations! :tada: 77 | 78 | You've successfully run and modified your React Native App. :partying_face: 79 | 80 | ### Now what? 81 | 82 | - If you want to add this new React Native code to an existing application, check out the [Integration guide](https://reactnative.dev/docs/integration-with-existing-apps). 83 | - If you're curious to learn more about React Native, check out the [docs](https://reactnative.dev/docs/getting-started). 84 | 85 | # Troubleshooting 86 | 87 | If you're having issues getting the above steps to work, see the [Troubleshooting](https://reactnative.dev/docs/troubleshooting) page. 88 | 89 | # Learn More 90 | 91 | To learn more about React Native, take a look at the following resources: 92 | 93 | - [React Native Website](https://reactnative.dev) - learn more about React Native. 94 | - [Getting Started](https://reactnative.dev/docs/environment-setup) - an **overview** of React Native and how setup your environment. 95 | - [Learn the Basics](https://reactnative.dev/docs/getting-started) - a **guided tour** of the React Native **basics**. 96 | - [Blog](https://reactnative.dev/blog) - read the latest official React Native **Blog** posts. 97 | - [`@facebook/react-native`](https://github.com/facebook/react-native) - the Open Source; GitHub **repository** for React Native. 98 | -------------------------------------------------------------------------------- /AwesomeExample/__tests__/App.test.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @format 3 | */ 4 | 5 | import React from 'react'; 6 | import ReactTestRenderer from 'react-test-renderer'; 7 | import App from '../App'; 8 | 9 | test('renders correctly', async () => { 10 | await ReactTestRenderer.act(() => { 11 | ReactTestRenderer.create(); 12 | }); 13 | }); 14 | -------------------------------------------------------------------------------- /AwesomeExample/android/app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: "com.android.application" 2 | apply plugin: "org.jetbrains.kotlin.android" 3 | apply plugin: "com.facebook.react" 4 | 5 | /** 6 | * This is the configuration block to customize your React Native Android app. 7 | * By default you don't need to apply any configuration, just uncomment the lines you need. 8 | */ 9 | react { 10 | /* Folders */ 11 | // The root of your project, i.e. where "package.json" lives. Default is '../..' 12 | // root = file("../../") 13 | // The folder where the react-native NPM package is. Default is ../../node_modules/react-native 14 | // reactNativeDir = file("../../node_modules/react-native") 15 | // The folder where the react-native Codegen package is. Default is ../../node_modules/@react-native/codegen 16 | // codegenDir = file("../../node_modules/@react-native/codegen") 17 | // The cli.js file which is the React Native CLI entrypoint. Default is ../../node_modules/react-native/cli.js 18 | // cliFile = file("../../node_modules/react-native/cli.js") 19 | 20 | /* Variants */ 21 | // The list of variants to that are debuggable. For those we're going to 22 | // skip the bundling of the JS bundle and the assets. By default is just 'debug'. 23 | // If you add flavors like lite, prod, etc. you'll have to list your debuggableVariants. 24 | // debuggableVariants = ["liteDebug", "prodDebug"] 25 | 26 | /* Bundling */ 27 | // A list containing the node command and its flags. Default is just 'node'. 28 | // nodeExecutableAndArgs = ["node"] 29 | // 30 | // The command to run when bundling. By default is 'bundle' 31 | // bundleCommand = "ram-bundle" 32 | // 33 | // The path to the CLI configuration file. Default is empty. 34 | // bundleConfig = file(../rn-cli.config.js) 35 | // 36 | // The name of the generated asset file containing your JS bundle 37 | // bundleAssetName = "MyApplication.android.bundle" 38 | // 39 | // The entry file for bundle generation. Default is 'index.android.js' or 'index.js' 40 | // entryFile = file("../js/MyApplication.android.js") 41 | // 42 | // A list of extra flags to pass to the 'bundle' commands. 43 | // See https://github.com/react-native-community/cli/blob/main/docs/commands.md#bundle 44 | // extraPackagerArgs = [] 45 | 46 | /* Hermes Commands */ 47 | // The hermes compiler command to run. By default it is 'hermesc' 48 | // hermesCommand = "$rootDir/my-custom-hermesc/bin/hermesc" 49 | // 50 | // The list of flags to pass to the Hermes compiler. By default is "-O", "-output-source-map" 51 | // hermesFlags = ["-O", "-output-source-map"] 52 | 53 | /* Autolinking */ 54 | autolinkLibrariesWithApp() 55 | } 56 | 57 | /** 58 | * Set this to true to Run Proguard on Release builds to minify the Java bytecode. 59 | */ 60 | def enableProguardInReleaseBuilds = false 61 | 62 | /** 63 | * The preferred build flavor of JavaScriptCore (JSC) 64 | * 65 | * For example, to use the international variant, you can use: 66 | * `def jscFlavor = io.github.react-native-community:jsc-android-intl:2026004.+` 67 | * 68 | * The international variant includes ICU i18n library and necessary data 69 | * allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that 70 | * give correct results when using with locales other than en-US. Note that 71 | * this variant is about 6MiB larger per architecture than default. 72 | */ 73 | def jscFlavor = 'io.github.react-native-community:jsc-android:2026004.+' 74 | 75 | android { 76 | ndkVersion rootProject.ext.ndkVersion 77 | buildToolsVersion rootProject.ext.buildToolsVersion 78 | compileSdk rootProject.ext.compileSdkVersion 79 | 80 | namespace "com.awesomeexample" 81 | defaultConfig { 82 | applicationId "com.awesomeexample" 83 | minSdkVersion rootProject.ext.minSdkVersion 84 | targetSdkVersion rootProject.ext.targetSdkVersion 85 | versionCode 1 86 | versionName "1.0" 87 | } 88 | signingConfigs { 89 | debug { 90 | storeFile file('debug.keystore') 91 | storePassword 'android' 92 | keyAlias 'androiddebugkey' 93 | keyPassword 'android' 94 | } 95 | } 96 | buildTypes { 97 | debug { 98 | signingConfig signingConfigs.debug 99 | } 100 | release { 101 | // Caution! In production, you need to generate your own keystore file. 102 | // see https://reactnative.dev/docs/signed-apk-android. 103 | signingConfig signingConfigs.debug 104 | minifyEnabled enableProguardInReleaseBuilds 105 | proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" 106 | } 107 | } 108 | } 109 | 110 | dependencies { 111 | // The version of react-native is set by the React Native Gradle Plugin 112 | implementation("com.facebook.react:react-android") 113 | 114 | if (hermesEnabled.toBoolean()) { 115 | implementation("com.facebook.react:hermes-android") 116 | } else { 117 | implementation jscFlavor 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /AwesomeExample/android/app/debug.keystore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivpusic/react-native-image-crop-picker/748898a3d8ee1af82a333780f1f9bb6c62439d28/AwesomeExample/android/app/debug.keystore -------------------------------------------------------------------------------- /AwesomeExample/android/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | -------------------------------------------------------------------------------- /AwesomeExample/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 10 | -------------------------------------------------------------------------------- /AwesomeExample/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | 10 | 18 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /AwesomeExample/android/app/src/main/java/com/awesomeexample/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.awesomeexample 2 | 3 | import com.facebook.react.ReactActivity 4 | import com.facebook.react.ReactActivityDelegate 5 | import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.fabricEnabled 6 | import com.facebook.react.defaults.DefaultReactActivityDelegate 7 | 8 | class MainActivity : ReactActivity() { 9 | 10 | /** 11 | * Returns the name of the main component registered from JavaScript. This is used to schedule 12 | * rendering of the component. 13 | */ 14 | override fun getMainComponentName(): String = "AwesomeExample" 15 | 16 | /** 17 | * Returns the instance of the [ReactActivityDelegate]. We use [DefaultReactActivityDelegate] 18 | * which allows you to enable New Architecture with a single boolean flags [fabricEnabled] 19 | */ 20 | override fun createReactActivityDelegate(): ReactActivityDelegate = 21 | DefaultReactActivityDelegate(this, mainComponentName, fabricEnabled) 22 | } 23 | -------------------------------------------------------------------------------- /AwesomeExample/android/app/src/main/java/com/awesomeexample/MainApplication.kt: -------------------------------------------------------------------------------- 1 | package com.awesomeexample 2 | 3 | import android.app.Application 4 | import com.facebook.react.PackageList 5 | import com.facebook.react.ReactApplication 6 | import com.facebook.react.ReactHost 7 | import com.facebook.react.ReactNativeHost 8 | import com.facebook.react.ReactPackage 9 | import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.load 10 | import com.facebook.react.defaults.DefaultReactHost.getDefaultReactHost 11 | import com.facebook.react.defaults.DefaultReactNativeHost 12 | import com.facebook.react.soloader.OpenSourceMergedSoMapping 13 | import com.facebook.soloader.SoLoader 14 | 15 | class MainApplication : Application(), ReactApplication { 16 | 17 | override val reactNativeHost: ReactNativeHost = 18 | object : DefaultReactNativeHost(this) { 19 | override fun getPackages(): List = 20 | PackageList(this).packages.apply { 21 | // Packages that cannot be autolinked yet can be added manually here, for example: 22 | // add(MyReactNativePackage()) 23 | } 24 | 25 | override fun getJSMainModuleName(): String = "index" 26 | 27 | override fun getUseDeveloperSupport(): Boolean = BuildConfig.DEBUG 28 | 29 | override val isNewArchEnabled: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED 30 | override val isHermesEnabled: Boolean = BuildConfig.IS_HERMES_ENABLED 31 | } 32 | 33 | override val reactHost: ReactHost 34 | get() = getDefaultReactHost(applicationContext, reactNativeHost) 35 | 36 | override fun onCreate() { 37 | super.onCreate() 38 | SoLoader.init(this, OpenSourceMergedSoMapping) 39 | if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) { 40 | // If you opted-in for the New Architecture, we load the native entry point for this app. 41 | load() 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /AwesomeExample/android/app/src/main/res/drawable/rn_edit_text_material.xml: -------------------------------------------------------------------------------- 1 | 2 | 16 | 22 | 23 | 24 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /AwesomeExample/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivpusic/react-native-image-crop-picker/748898a3d8ee1af82a333780f1f9bb6c62439d28/AwesomeExample/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /AwesomeExample/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivpusic/react-native-image-crop-picker/748898a3d8ee1af82a333780f1f9bb6c62439d28/AwesomeExample/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /AwesomeExample/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivpusic/react-native-image-crop-picker/748898a3d8ee1af82a333780f1f9bb6c62439d28/AwesomeExample/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /AwesomeExample/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivpusic/react-native-image-crop-picker/748898a3d8ee1af82a333780f1f9bb6c62439d28/AwesomeExample/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /AwesomeExample/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivpusic/react-native-image-crop-picker/748898a3d8ee1af82a333780f1f9bb6c62439d28/AwesomeExample/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /AwesomeExample/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivpusic/react-native-image-crop-picker/748898a3d8ee1af82a333780f1f9bb6c62439d28/AwesomeExample/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /AwesomeExample/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivpusic/react-native-image-crop-picker/748898a3d8ee1af82a333780f1f9bb6c62439d28/AwesomeExample/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /AwesomeExample/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivpusic/react-native-image-crop-picker/748898a3d8ee1af82a333780f1f9bb6c62439d28/AwesomeExample/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /AwesomeExample/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivpusic/react-native-image-crop-picker/748898a3d8ee1af82a333780f1f9bb6c62439d28/AwesomeExample/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /AwesomeExample/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivpusic/react-native-image-crop-picker/748898a3d8ee1af82a333780f1f9bb6c62439d28/AwesomeExample/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /AwesomeExample/android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | AwesomeExample 3 | 4 | -------------------------------------------------------------------------------- /AwesomeExample/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /AwesomeExample/android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext { 3 | buildToolsVersion = "35.0.0" 4 | minSdkVersion = 24 5 | compileSdkVersion = 35 6 | targetSdkVersion = 35 7 | ndkVersion = "27.1.12297006" 8 | kotlinVersion = "2.0.21" 9 | } 10 | repositories { 11 | google() 12 | mavenCentral() 13 | } 14 | dependencies { 15 | classpath("com.android.tools.build:gradle") 16 | classpath("com.facebook.react:react-native-gradle-plugin") 17 | classpath("org.jetbrains.kotlin:kotlin-gradle-plugin") 18 | } 19 | } 20 | 21 | apply plugin: "com.facebook.react.rootproject" 22 | -------------------------------------------------------------------------------- /AwesomeExample/android/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx512m -XX:MaxMetaspaceSize=256m 13 | org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true 19 | 20 | # AndroidX package structure to make it clearer which packages are bundled with the 21 | # Android operating system, and which are packaged with your app's APK 22 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 23 | android.useAndroidX=true 24 | 25 | # Use this property to specify which architecture you want to build. 26 | # You can also override it from the CLI using 27 | # ./gradlew -PreactNativeArchitectures=x86_64 28 | reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64 29 | 30 | # Use this property to enable support to the new architecture. 31 | # This will allow you to use TurboModules and the Fabric render in 32 | # your application. You should enable this flag either if you want 33 | # to write custom TurboModules/Fabric components OR use libraries that 34 | # are providing them. 35 | newArchEnabled=true 36 | 37 | # Use this property to enable or disable the Hermes JS engine. 38 | # If set to false, you will be using JSC instead. 39 | hermesEnabled=true 40 | -------------------------------------------------------------------------------- /AwesomeExample/android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivpusic/react-native-image-crop-picker/748898a3d8ee1af82a333780f1f9bb6c62439d28/AwesomeExample/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /AwesomeExample/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /AwesomeExample/android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | @rem SPDX-License-Identifier: Apache-2.0 17 | @rem 18 | 19 | @if "%DEBUG%"=="" @echo off 20 | @rem ########################################################################## 21 | @rem 22 | @rem Gradle startup script for Windows 23 | @rem 24 | @rem ########################################################################## 25 | 26 | @rem Set local scope for the variables with windows NT shell 27 | if "%OS%"=="Windows_NT" setlocal 28 | 29 | set DIRNAME=%~dp0 30 | if "%DIRNAME%"=="" set DIRNAME=. 31 | @rem This is normally unused 32 | set APP_BASE_NAME=%~n0 33 | set APP_HOME=%DIRNAME% 34 | 35 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 36 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 37 | 38 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 39 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 40 | 41 | @rem Find java.exe 42 | if defined JAVA_HOME goto findJavaFromJavaHome 43 | 44 | set JAVA_EXE=java.exe 45 | %JAVA_EXE% -version >NUL 2>&1 46 | if %ERRORLEVEL% equ 0 goto execute 47 | 48 | echo. 1>&2 49 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 50 | echo. 1>&2 51 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 52 | echo location of your Java installation. 1>&2 53 | 54 | goto fail 55 | 56 | :findJavaFromJavaHome 57 | set JAVA_HOME=%JAVA_HOME:"=% 58 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 59 | 60 | if exist "%JAVA_EXE%" goto execute 61 | 62 | echo. 1>&2 63 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 64 | echo. 1>&2 65 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 66 | echo location of your Java installation. 1>&2 67 | 68 | goto fail 69 | 70 | :execute 71 | @rem Setup the command line 72 | 73 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 74 | 75 | 76 | @rem Execute Gradle 77 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 78 | 79 | :end 80 | @rem End local scope for the variables with windows NT shell 81 | if %ERRORLEVEL% equ 0 goto mainEnd 82 | 83 | :fail 84 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 85 | rem the _cmd.exe /c_ return code! 86 | set EXIT_CODE=%ERRORLEVEL% 87 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 88 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 89 | exit /b %EXIT_CODE% 90 | 91 | :mainEnd 92 | if "%OS%"=="Windows_NT" endlocal 93 | 94 | :omega 95 | -------------------------------------------------------------------------------- /AwesomeExample/android/settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { includeBuild("../node_modules/@react-native/gradle-plugin") } 2 | plugins { id("com.facebook.react.settings") } 3 | extensions.configure(com.facebook.react.ReactSettingsExtension){ ex -> ex.autolinkLibrariesFromCommand() } 4 | rootProject.name = 'AwesomeExample' 5 | include ':app' 6 | includeBuild('../node_modules/@react-native/gradle-plugin') 7 | -------------------------------------------------------------------------------- /AwesomeExample/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "AwesomeExample", 3 | "displayName": "AwesomeExample" 4 | } 5 | -------------------------------------------------------------------------------- /AwesomeExample/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: ['module:@react-native/babel-preset'], 3 | }; 4 | -------------------------------------------------------------------------------- /AwesomeExample/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @format 3 | */ 4 | 5 | import {AppRegistry} from 'react-native'; 6 | import App from './App'; 7 | import {name as appName} from './app.json'; 8 | 9 | AppRegistry.registerComponent(appName, () => App); 10 | -------------------------------------------------------------------------------- /AwesomeExample/ios/.xcode.env: -------------------------------------------------------------------------------- 1 | # This `.xcode.env` file is versioned and is used to source the environment 2 | # used when running script phases inside Xcode. 3 | # To customize your local environment, you can create an `.xcode.env.local` 4 | # file that is not versioned. 5 | 6 | # NODE_BINARY variable contains the PATH to the node executable. 7 | # 8 | # Customize the NODE_BINARY variable here. 9 | # For example, to use nvm with brew, add the following line 10 | # . "$(brew --prefix nvm)/nvm.sh" --no-use 11 | export NODE_BINARY=$(command -v node) 12 | -------------------------------------------------------------------------------- /AwesomeExample/ios/AwesomeExample.xcodeproj/xcshareddata/xcschemes/AwesomeExample.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 53 | 55 | 61 | 62 | 63 | 64 | 70 | 72 | 78 | 79 | 80 | 81 | 83 | 84 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /AwesomeExample/ios/AwesomeExample.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /AwesomeExample/ios/AwesomeExample/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import React 3 | import React_RCTAppDelegate 4 | import ReactAppDependencyProvider 5 | 6 | @main 7 | class AppDelegate: UIResponder, UIApplicationDelegate { 8 | var window: UIWindow? 9 | 10 | var reactNativeDelegate: ReactNativeDelegate? 11 | var reactNativeFactory: RCTReactNativeFactory? 12 | 13 | func application( 14 | _ application: UIApplication, 15 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil 16 | ) -> Bool { 17 | let delegate = ReactNativeDelegate() 18 | let factory = RCTReactNativeFactory(delegate: delegate) 19 | delegate.dependencyProvider = RCTAppDependencyProvider() 20 | 21 | reactNativeDelegate = delegate 22 | reactNativeFactory = factory 23 | 24 | window = UIWindow(frame: UIScreen.main.bounds) 25 | 26 | factory.startReactNative( 27 | withModuleName: "AwesomeExample", 28 | in: window, 29 | launchOptions: launchOptions 30 | ) 31 | 32 | return true 33 | } 34 | } 35 | 36 | class ReactNativeDelegate: RCTDefaultReactNativeFactoryDelegate { 37 | override func sourceURL(for bridge: RCTBridge) -> URL? { 38 | self.bundleURL() 39 | } 40 | 41 | override func bundleURL() -> URL? { 42 | #if DEBUG 43 | RCTBundleURLProvider.sharedSettings().jsBundleURL(forBundleRoot: "index") 44 | #else 45 | Bundle.main.url(forResource: "main", withExtension: "jsbundle") 46 | #endif 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /AwesomeExample/ios/AwesomeExample/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "scale" : "2x", 6 | "size" : "20x20" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "scale" : "3x", 11 | "size" : "20x20" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "scale" : "2x", 16 | "size" : "29x29" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "scale" : "3x", 21 | "size" : "29x29" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "scale" : "2x", 26 | "size" : "40x40" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "scale" : "3x", 31 | "size" : "40x40" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "scale" : "2x", 36 | "size" : "60x60" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "scale" : "3x", 41 | "size" : "60x60" 42 | }, 43 | { 44 | "idiom" : "ios-marketing", 45 | "scale" : "1x", 46 | "size" : "1024x1024" 47 | } 48 | ], 49 | "info" : { 50 | "author" : "xcode", 51 | "version" : 1 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /AwesomeExample/ios/AwesomeExample/Images.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /AwesomeExample/ios/AwesomeExample/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | AwesomeExample 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | NSPhotoLibraryUsageDescription 20 | Photo Library Access Warning 21 | NSCameraUsageDescription 22 | Camera usage description 23 | NSMicrophoneUsageDescription 24 | This app requires to access your microphone to record video with your voice send via chat 25 | CFBundleShortVersionString 26 | $(MARKETING_VERSION) 27 | CFBundleSignature 28 | ???? 29 | CFBundleVersion 30 | $(CURRENT_PROJECT_VERSION) 31 | LSRequiresIPhoneOS 32 | 33 | NSAppTransportSecurity 34 | 35 | 36 | NSAllowsArbitraryLoads 37 | 38 | NSAllowsLocalNetworking 39 | 40 | 41 | NSLocationWhenInUseUsageDescription 42 | 43 | UILaunchStoryboardName 44 | LaunchScreen 45 | UIRequiredDeviceCapabilities 46 | 47 | arm64 48 | 49 | UISupportedInterfaceOrientations 50 | 51 | UIInterfaceOrientationPortrait 52 | UIInterfaceOrientationLandscapeLeft 53 | UIInterfaceOrientationLandscapeRight 54 | 55 | UIViewControllerBasedStatusBarAppearance 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /AwesomeExample/ios/AwesomeExample/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 24 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /AwesomeExample/ios/AwesomeExample/PrivacyInfo.xcprivacy: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSPrivacyAccessedAPITypes 6 | 7 | 8 | NSPrivacyAccessedAPIType 9 | NSPrivacyAccessedAPICategoryFileTimestamp 10 | NSPrivacyAccessedAPITypeReasons 11 | 12 | 3B52.1 13 | C617.1 14 | 15 | 16 | 17 | NSPrivacyAccessedAPIType 18 | NSPrivacyAccessedAPICategoryUserDefaults 19 | NSPrivacyAccessedAPITypeReasons 20 | 21 | CA92.1 22 | 23 | 24 | 25 | NSPrivacyAccessedAPIType 26 | NSPrivacyAccessedAPICategorySystemBootTime 27 | NSPrivacyAccessedAPITypeReasons 28 | 29 | 35F9.1 30 | 31 | 32 | 33 | NSPrivacyCollectedDataTypes 34 | 35 | NSPrivacyTracking 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /AwesomeExample/ios/Podfile: -------------------------------------------------------------------------------- 1 | # Resolve react_native_pods.rb with node to allow for hoisting 2 | require Pod::Executable.execute_command('node', ['-p', 3 | 'require.resolve( 4 | "react-native/scripts/react_native_pods.rb", 5 | {paths: [process.argv[1]]}, 6 | )', __dir__]).strip 7 | 8 | platform :ios, min_ios_version_supported 9 | prepare_react_native_project! 10 | 11 | linkage = ENV['USE_FRAMEWORKS'] 12 | if linkage != nil 13 | Pod::UI.puts "Configuring Pod with #{linkage}ally linked Frameworks".green 14 | use_frameworks! :linkage => linkage.to_sym 15 | end 16 | 17 | target 'AwesomeExample' do 18 | config = use_native_modules! 19 | 20 | use_react_native!( 21 | :path => config[:reactNativePath], 22 | # An absolute path to your application root. 23 | :app_path => "#{Pod::Config.instance.installation_root}/.." 24 | ) 25 | 26 | post_install do |installer| 27 | # https://github.com/facebook/react-native/blob/main/packages/react-native/scripts/react_native_pods.rb#L197-L202 28 | react_native_post_install( 29 | installer, 30 | config[:reactNativePath], 31 | :mac_catalyst_enabled => false, 32 | # :ccache_enabled => true 33 | ) 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /AwesomeExample/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | preset: 'react-native', 3 | }; 4 | -------------------------------------------------------------------------------- /AwesomeExample/metro.config.js: -------------------------------------------------------------------------------- 1 | const {getDefaultConfig, mergeConfig} = require('@react-native/metro-config'); 2 | 3 | /** 4 | * Metro configuration 5 | * https://reactnative.dev/docs/metro 6 | * 7 | * @type {import('@react-native/metro-config').MetroConfig} 8 | */ 9 | const config = {}; 10 | 11 | module.exports = mergeConfig(getDefaultConfig(__dirname), config); 12 | -------------------------------------------------------------------------------- /AwesomeExample/package: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivpusic/react-native-image-crop-picker/748898a3d8ee1af82a333780f1f9bb6c62439d28/AwesomeExample/package -------------------------------------------------------------------------------- /AwesomeExample/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "AwesomeExample", 3 | "version": "0.0.1", 4 | "private": true, 5 | "scripts": { 6 | "android": "react-native run-android", 7 | "ios": "react-native run-ios", 8 | "lint": "eslint .", 9 | "start": "react-native start", 10 | "test": "jest" 11 | }, 12 | "dependencies": { 13 | "react": "19.0.0", 14 | "react-native": "0.79.2", 15 | "react-native-image-crop-picker": "../", 16 | "react-native-video": "^6.14.1" 17 | }, 18 | "devDependencies": { 19 | "@babel/core": "^7.25.2", 20 | "@babel/preset-env": "^7.25.3", 21 | "@babel/runtime": "^7.25.0", 22 | "@react-native-community/cli": "18.0.0", 23 | "@react-native-community/cli-platform-android": "18.0.0", 24 | "@react-native-community/cli-platform-ios": "18.0.0", 25 | "@react-native/babel-preset": "0.79.2", 26 | "@react-native/eslint-config": "0.79.2", 27 | "@react-native/metro-config": "0.79.2", 28 | "@react-native/typescript-config": "0.79.2", 29 | "@types/jest": "^29.5.13", 30 | "@types/react": "^19.0.0", 31 | "@types/react-test-renderer": "^19.0.0", 32 | "eslint": "^8.19.0", 33 | "jest": "^29.6.3", 34 | "prettier": "2.8.8", 35 | "react-test-renderer": "19.0.0", 36 | "typescript": "5.0.4" 37 | }, 38 | "engines": { 39 | "node": ">=18" 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /AwesomeExample/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@react-native/typescript-config/tsconfig.json" 3 | } 4 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. 6 | 7 | ## Our Standards 8 | 9 | Examples of behavior that contributes to creating a positive environment include: 10 | 11 | * Using welcoming and inclusive language 12 | * Being respectful of differing viewpoints and experiences 13 | * Gracefully accepting constructive criticism 14 | * Focusing on what is best for the community 15 | * Showing empathy towards other community members 16 | 17 | Examples of unacceptable behavior by participants include: 18 | 19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances 20 | * Trolling, insulting/derogatory comments, and personal or political attacks 21 | * Public or private harassment 22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission 23 | * Other conduct which could reasonably be considered inappropriate in a professional setting 24 | 25 | ## Our Responsibilities 26 | 27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. 28 | 29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. 30 | 31 | ## Scope 32 | 33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. 34 | 35 | ## Enforcement 36 | 37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at pusic007@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. 38 | 39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. 40 | 41 | ## Attribution 42 | 43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] 44 | 45 | [homepage]: http://contributor-covenant.org 46 | [version]: http://contributor-covenant.org/version/1/4/ 47 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contribute 2 | 3 | ## Introduction 4 | 5 | First, thank you for considering contributing to react-native-image-crop-picker! It's people like you that make the open source community such a great community! 😊 6 | 7 | We welcome any type of contribution, not only code. You can help with 8 | - **QA**: file bug reports, the more details you can give the better (e.g. screenshots with the console open) 9 | - **Marketing**: writing blog posts, howto's, printing stickers, ... 10 | - **Community**: presenting the project at meetups, organizing a dedicated meetup for the local community, ... 11 | - **Code**: take a look at the [open issues](https://github.com/ivpusic/react-native-image-crop-picker/issues). Even if you can't write code, commenting on them, showing that you care about a given 12 | matters. It helps us triage them. 13 | - **Money**: we welcome financial contributions in full transparency on our [open collective](https://opencollective.com/react-native-image-crop-picker). 14 | 15 | ## Your First Contribution 16 | 17 | Working on your first Pull Request? You can learn how from this *free* series, [How to Contribute to an Open Source Project on GitHub](https://egghead.io/series/how-to-contribute-to-an-open-source-project-on-github). 18 | 19 | ## Submitting code 20 | 21 | Any code change should be submitted as a pull request. The description should explain what the code does and give steps to execute it. The pull request should also contain tests. 22 | 23 | ## Code review process 24 | 25 | The bigger the pull request, the longer it will take to review and merge. Try to break down large pull requests in smaller chunks that are easier to review and merge. 26 | It is also always helpful to have some context for your pull request. What was the purpose? Why does it matter to you? 27 | 28 | ## Financial contributions 29 | 30 | We also welcome financial contributions in full transparency on our [open collective](https://opencollective.com/react-native-image-crop-picker). 31 | Anyone can file an expense. If the expense makes sense for the development of the community, it will be "merged" in the ledger of our open collective by the core contributors and the person who filed the expense will be reimbursed. 32 | 33 | ## Questions 34 | 35 | If you have any questions, create an [issue](https://github.com/ivpusic/react-native-image-crop-picker/issues) (protip: do a quick search first to see if someone else didn't ask the same question before!). 36 | You can also reach us at hello@react-native-image-crop-picker.opencollective.com. 37 | 38 | ## Credits 39 | 40 | ### Contributors 41 | 42 | Thank you to all the people who have already contributed to react-native-image-crop-picker! 43 | 44 | 45 | 46 | ### Backers 47 | 48 | Thank you to all our backers! [[Become a backer](https://opencollective.com/react-native-image-crop-picker#backer)] 49 | 50 | 51 | 52 | 53 | ### Sponsors 54 | 55 | Thank you to all our sponsors! (please ask your company to also support this open source project by [becoming a sponsor](https://opencollective.com/react-native-image-crop-picker#sponsor)) 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### Version 2 | Tell us which versions you are using: 3 | 4 | - react-native-image-crop-picker v0.?.? 5 | - react-native v0.?.? 6 | 7 | ### Platform 8 | Tell us to which platform this issue is related 9 | 10 | - iOS 11 | - Android 12 | 13 | ### Expected behaviour 14 | 15 | 16 | 17 | ### Actual behaviour 18 | 19 | 20 | 21 | ### Steps to reproduce 22 | 23 | 1. 24 | 25 | 2. 26 | 27 | 3. 28 | 29 | ### Attachments 30 | 31 | // stacktrace or any other useful debug info 32 | 33 | Love react-native-image-crop-picker? Please consider supporting our collective: 34 | 👉 https://opencollective.com/react-native-image-crop-picker/donate 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Ivan Pusic 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /RNImageCropPicker.podspec: -------------------------------------------------------------------------------- 1 | package = JSON.parse(File.read(File.join(__dir__, "package.json"))) 2 | 3 | Pod::Spec.new do |s| 4 | s.name = "RNImageCropPicker" 5 | s.version = package['version'] 6 | s.summary = package["description"] 7 | s.requires_arc = true 8 | s.license = 'MIT' 9 | s.homepage = 'n/a' 10 | s.authors = { "ivpusic" => "" } 11 | s.source = { :git => "https://github.com/ivpusic/react-native-image-crop-picker", :tag => "v#{s.version}"} 12 | s.source_files = 'ios/src/*.{h,m,mm}' 13 | s.platform = :ios, "8.0" 14 | s.dependency 'React-Core' 15 | s.dependency 'React-RCTImage' 16 | s.dependency 'TOCropViewController', '~> 2.7.4' 17 | s.resource_bundles = { 18 | 'RNImageCropPickerPrivacyInfo' => ['ios/PrivacyInfo.xcprivacy'], 19 | } 20 | 21 | s.subspec 'QBImagePickerController' do |qb| 22 | qb.name = "QBImagePickerController" 23 | qb.source_files = "ios/QBImagePicker/QBImagePicker/*.{h,m}" 24 | qb.exclude_files = "ios/QBImagePicker/QBImagePicker/QBImagePicker.h" 25 | qb.resource_bundles = { "QBImagePicker" => "ios/QBImagePicker/QBImagePicker/*.{lproj,storyboard}" } 26 | qb.requires_arc = true 27 | qb.frameworks = "Photos", "PhotosUI" 28 | end 29 | 30 | install_modules_dependencies(s) 31 | end 32 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | import com.android.Version 2 | 3 | apply plugin: 'com.android.library' 4 | 5 | def safeExtGet(prop, fallback) { 6 | rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback 7 | } 8 | 9 | def isNewArchitectureEnabled() { 10 | return project.hasProperty("newArchEnabled") && project.newArchEnabled == "true" 11 | } 12 | 13 | def resolveReactNativeDirectory() { 14 | def reactNativeLocation = safeExtGet("REACT_NATIVE_NODE_MODULES_DIR", null) 15 | if (reactNativeLocation != null) { 16 | return file(reactNativeLocation) 17 | } 18 | 19 | def reactNativeFromProjectNodeModules = file("${rootProject.projectDir}/../node_modules/react-native") 20 | if (reactNativeFromProjectNodeModules.exists()) { 21 | return reactNativeFromProjectNodeModules 22 | } 23 | 24 | def reactNativeFromNodeModulesWithPicker = file("${projectDir}/../../react-native") 25 | if (reactNativeFromNodeModulesWithPicker.exists()) { 26 | return reactNativeFromNodeModulesWithPicker 27 | } 28 | 29 | throw new Exception( 30 | "[react-native-picker] Unable to resolve react-native location in " + 31 | "node_modules. You should add project extension property (in app/build.gradle) " + 32 | "`REACT_NATIVE_NODE_MODULES_DIR` with path to react-native." 33 | ) 34 | } 35 | 36 | def getReactNativeMinorVersion() { 37 | def REACT_NATIVE_DIR = resolveReactNativeDirectory() 38 | 39 | def reactProperties = new Properties() 40 | file("$REACT_NATIVE_DIR/ReactAndroid/gradle.properties").withInputStream { reactProperties.load(it) } 41 | 42 | def REACT_NATIVE_VERSION = reactProperties.getProperty("VERSION_NAME") 43 | def REACT_NATIVE_MINOR_VERSION = REACT_NATIVE_VERSION.startsWith("0.0.0-") ? 1000 : REACT_NATIVE_VERSION.split("\\.")[1].toInteger() 44 | 45 | return REACT_NATIVE_MINOR_VERSION 46 | } 47 | 48 | 49 | if (isNewArchitectureEnabled()) { 50 | apply plugin: "com.facebook.react" 51 | } 52 | 53 | android { 54 | compileSdk safeExtGet('compileSdkVersion', 34) 55 | 56 | def agpVersion = Version.ANDROID_GRADLE_PLUGIN_VERSION 57 | // Check AGP version for backward compatibility reasons 58 | if (agpVersion.tokenize('.')[0].toInteger() >= 7) { 59 | namespace = "com.reactnative.ivpusic.imagepicker" 60 | } 61 | 62 | defaultConfig { 63 | minSdkVersion safeExtGet('minSdkVersion', 23) 64 | targetSdkVersion safeExtGet('targetSdkVersion', 34) 65 | versionCode 1 66 | buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString() 67 | } 68 | lintOptions { 69 | abortOnError false 70 | } 71 | 72 | sourceSets.main { 73 | java { 74 | if (isNewArchitectureEnabled()) { 75 | srcDirs += [ 76 | "src/newArch/java", 77 | ] 78 | } else { 79 | srcDirs += [ 80 | "src/oldArch/java", 81 | ] 82 | } 83 | } 84 | } 85 | } 86 | 87 | repositories { 88 | maven { 89 | url "$projectDir/../node_modules/react-native/android" 90 | } 91 | google() 92 | mavenCentral() 93 | } 94 | dependencies { 95 | if (isNewArchitectureEnabled() && getReactNativeMinorVersion() < 71) { 96 | implementation project(":ReactAndroid") 97 | } else { 98 | implementation 'com.facebook.react:react-native:+' 99 | } 100 | implementation "com.facebook.react:react-native:${safeExtGet('reactNativeVersion', '+')}" 101 | implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0' 102 | implementation 'com.github.yalantis:ucrop:2.2.10' 103 | implementation 'androidx.activity:activity:1.10.1' 104 | implementation "androidx.core:core:1.16.0" 105 | implementation 'androidx.exifinterface:exifinterface:1.4.1' 106 | } 107 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivpusic/react-native-image-crop-picker/748898a3d8ee1af82a333780f1f9bb6c62439d28/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /android/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /android/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 12 | 13 | 14 | 15 | 20 | 23 | 24 | 25 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /android/src/main/java/com/reactnative/ivpusic/imagepicker/Compression.java: -------------------------------------------------------------------------------- 1 | package com.reactnative.ivpusic.imagepicker; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.graphics.Bitmap; 6 | import android.graphics.BitmapFactory; 7 | import android.media.ExifInterface; 8 | import android.os.Environment; 9 | import android.util.Log; 10 | import android.util.Pair; 11 | 12 | import com.facebook.react.bridge.Promise; 13 | import com.facebook.react.bridge.ReadableMap; 14 | 15 | import java.io.BufferedOutputStream; 16 | import java.io.File; 17 | import java.io.FileOutputStream; 18 | import java.io.IOException; 19 | import java.io.OutputStream; 20 | import java.util.Arrays; 21 | import java.util.List; 22 | import java.util.UUID; 23 | 24 | /** 25 | * Created by ipusic on 12/27/16. 26 | */ 27 | 28 | class Compression { 29 | 30 | File resize( 31 | Context context, 32 | String originalImagePath, 33 | int originalWidth, 34 | int originalHeight, 35 | int maxWidth, 36 | int maxHeight, 37 | int quality 38 | ) throws IOException,OutOfMemoryError { 39 | Pair targetDimensions = 40 | this.calculateTargetDimensions(originalWidth, originalHeight, maxWidth, maxHeight); 41 | 42 | int targetWidth = targetDimensions.first; 43 | int targetHeight = targetDimensions.second; 44 | 45 | Bitmap bitmap = null; 46 | if (originalWidth <= maxWidth && originalHeight <= maxHeight) { 47 | bitmap = BitmapFactory.decodeFile(originalImagePath); 48 | } else { 49 | BitmapFactory.Options options = new BitmapFactory.Options(); 50 | options.inSampleSize = calculateInSampleSize(originalWidth, originalHeight, targetWidth, targetHeight); 51 | bitmap = BitmapFactory.decodeFile(originalImagePath, options); 52 | } 53 | 54 | // Use original image exif orientation data to preserve image orientation for the resized bitmap 55 | ExifInterface originalExif = new ExifInterface(originalImagePath); 56 | String originalOrientation = originalExif.getAttribute(ExifInterface.TAG_ORIENTATION); 57 | 58 | bitmap = Bitmap.createScaledBitmap(bitmap, targetWidth, targetHeight, true); 59 | 60 | File imageDirectory = context.getExternalFilesDir(Environment.DIRECTORY_PICTURES); 61 | 62 | if (!imageDirectory.exists()) { 63 | Log.d("image-crop-picker", "Pictures Directory is not existing. Will create this directory."); 64 | imageDirectory.mkdirs(); 65 | } 66 | 67 | File resizeImageFile = new File(imageDirectory, UUID.randomUUID() + ".jpg"); 68 | 69 | OutputStream os = new BufferedOutputStream(new FileOutputStream(resizeImageFile)); 70 | bitmap.compress(Bitmap.CompressFormat.JPEG, quality, os); 71 | 72 | // Don't set unnecessary exif attribute 73 | if (shouldSetOrientation(originalOrientation)) { 74 | ExifInterface exif = new ExifInterface(resizeImageFile.getAbsolutePath()); 75 | exif.setAttribute(ExifInterface.TAG_ORIENTATION, originalOrientation); 76 | exif.saveAttributes(); 77 | } 78 | 79 | os.close(); 80 | bitmap.recycle(); 81 | 82 | return resizeImageFile; 83 | } 84 | 85 | private int calculateInSampleSize(int originalWidth, int originalHeight, int requestedWidth, int requestedHeight) { 86 | int inSampleSize = 1; 87 | 88 | if (originalWidth > requestedWidth || originalHeight > requestedHeight) { 89 | final int halfWidth = originalWidth / 2; 90 | final int halfHeight = originalHeight / 2; 91 | 92 | // Calculate the largest inSampleSize value that is a power of 2 and keeps both 93 | // height and width larger than the requested height and width. 94 | while ((halfWidth / inSampleSize) >= requestedWidth 95 | && (halfHeight / inSampleSize) >= requestedHeight) { 96 | inSampleSize *= 2; 97 | } 98 | } 99 | 100 | return inSampleSize; 101 | } 102 | 103 | private boolean shouldSetOrientation(String orientation) { 104 | return !orientation.equals(String.valueOf(ExifInterface.ORIENTATION_NORMAL)) 105 | && !orientation.equals(String.valueOf(ExifInterface.ORIENTATION_UNDEFINED)); 106 | } 107 | 108 | File compressImage(final Context context, final ReadableMap options, final String originalImagePath, final BitmapFactory.Options bitmapOptions) throws IOException,OutOfMemoryError { 109 | Integer maxWidth = options.hasKey("compressImageMaxWidth") ? options.getInt("compressImageMaxWidth") : null; 110 | Integer maxHeight = options.hasKey("compressImageMaxHeight") ? options.getInt("compressImageMaxHeight") : null; 111 | Double quality = options.hasKey("compressImageQuality") ? options.getDouble("compressImageQuality") : null; 112 | 113 | boolean isLossLess = (quality == null || quality == 1.0); 114 | boolean useOriginalWidth = (maxWidth == null || maxWidth >= bitmapOptions.outWidth); 115 | boolean useOriginalHeight = (maxHeight == null || maxHeight >= bitmapOptions.outHeight); 116 | 117 | List knownMimes = Arrays.asList("image/jpeg", "image/jpg", "image/png", "image/gif", "image/tiff"); 118 | boolean isKnownMimeType = (bitmapOptions.outMimeType != null && knownMimes.contains(bitmapOptions.outMimeType.toLowerCase())); 119 | 120 | if (isLossLess && useOriginalWidth && useOriginalHeight && isKnownMimeType) { 121 | Log.d("image-crop-picker", "Skipping image compression"); 122 | return new File(originalImagePath); 123 | } 124 | 125 | Log.d("image-crop-picker", "Image compression activated"); 126 | 127 | // compression quality 128 | int targetQuality = quality != null ? (int) (quality * 100) : 100; 129 | Log.d("image-crop-picker", "Compressing image with quality " + targetQuality); 130 | 131 | if (maxWidth == null) maxWidth = bitmapOptions.outWidth; 132 | if (maxHeight == null) maxHeight = bitmapOptions.outHeight; 133 | 134 | return resize(context, originalImagePath, bitmapOptions.outWidth, bitmapOptions.outHeight, maxWidth, maxHeight, targetQuality); 135 | } 136 | 137 | private Pair calculateTargetDimensions(int currentWidth, int currentHeight, int maxWidth, int maxHeight) { 138 | int width = currentWidth; 139 | int height = currentHeight; 140 | 141 | if (width > maxWidth) { 142 | float ratio = ((float) maxWidth / width); 143 | height = (int) (height * ratio); 144 | width = maxWidth; 145 | } 146 | 147 | if (height > maxHeight) { 148 | float ratio = ((float) maxHeight / height); 149 | width = (int) (width * ratio); 150 | height = maxHeight; 151 | } 152 | 153 | return Pair.create(width, height); 154 | } 155 | 156 | synchronized void compressVideo(final Activity activity, final ReadableMap options, final String originalVideo, final String compressedVideo, final Promise promise) { 157 | // todo: video compression 158 | // failed attempt 1: ffmpeg => slow and licensing issues 159 | promise.resolve(originalVideo); 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /android/src/main/java/com/reactnative/ivpusic/imagepicker/ExifExtractor.java: -------------------------------------------------------------------------------- 1 | package com.reactnative.ivpusic.imagepicker; 2 | 3 | import android.media.ExifInterface; 4 | import android.os.Build; 5 | 6 | import com.facebook.react.bridge.WritableMap; 7 | import com.facebook.react.bridge.WritableNativeMap; 8 | 9 | import java.io.IOException; 10 | import java.util.ArrayList; 11 | import java.util.Arrays; 12 | import java.util.List; 13 | 14 | import static android.media.ExifInterface.*; 15 | 16 | class ExifExtractor { 17 | 18 | static WritableMap extract(String path) throws IOException { 19 | WritableMap exifData = new WritableNativeMap(); 20 | 21 | List attributes = getBasicAttributes(); 22 | 23 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 24 | attributes.addAll(getLevel23Attributes()); 25 | } 26 | 27 | ExifInterface exif = new ExifInterface(path); 28 | 29 | try { 30 | GeoDegree geoDegree = new GeoDegree(exif); 31 | if (geoDegree.getLatitude() != null && geoDegree.getLongitude() != null) { 32 | exifData.putDouble("Latitude", geoDegree.getLatitude()); 33 | exifData.putDouble("Longitude", geoDegree.getLongitude()); 34 | } 35 | } catch (Exception e) { 36 | e.printStackTrace(); 37 | } 38 | 39 | for (String attribute : attributes) { 40 | String value = exif.getAttribute(attribute); 41 | exifData.putString(attribute, value); 42 | } 43 | 44 | return exifData; 45 | } 46 | 47 | private static List getBasicAttributes() { 48 | return new ArrayList<>(Arrays.asList( 49 | TAG_APERTURE, 50 | TAG_DATETIME, 51 | TAG_EXPOSURE_TIME, 52 | TAG_FLASH, 53 | TAG_FOCAL_LENGTH, 54 | TAG_GPS_ALTITUDE, 55 | TAG_GPS_ALTITUDE_REF, 56 | TAG_GPS_DATESTAMP, 57 | TAG_GPS_LATITUDE, 58 | TAG_GPS_LATITUDE_REF, 59 | TAG_GPS_LONGITUDE, 60 | TAG_GPS_LONGITUDE_REF, 61 | TAG_GPS_PROCESSING_METHOD, 62 | TAG_GPS_TIMESTAMP, 63 | TAG_IMAGE_LENGTH, 64 | TAG_IMAGE_WIDTH, 65 | TAG_ISO, 66 | TAG_MAKE, 67 | TAG_MODEL, 68 | TAG_ORIENTATION, 69 | TAG_WHITE_BALANCE 70 | )); 71 | } 72 | 73 | private static List getLevel23Attributes() { 74 | return new ArrayList<>(Arrays.asList( 75 | TAG_DATETIME_DIGITIZED, 76 | TAG_SUBSEC_TIME, 77 | TAG_SUBSEC_TIME_DIG, 78 | TAG_SUBSEC_TIME_ORIG 79 | )); 80 | } 81 | } -------------------------------------------------------------------------------- /android/src/main/java/com/reactnative/ivpusic/imagepicker/GeoDegree.java: -------------------------------------------------------------------------------- 1 | package com.reactnative.ivpusic.imagepicker; 2 | 3 | import android.media.ExifInterface; 4 | 5 | public class GeoDegree { 6 | Float latitude; 7 | Float longitude; 8 | 9 | public GeoDegree(ExifInterface exif) { 10 | String attrLATITUDE = exif.getAttribute(ExifInterface.TAG_GPS_LATITUDE); 11 | String attrLATITUDE_REF = exif.getAttribute(ExifInterface.TAG_GPS_LATITUDE_REF); 12 | String attrLONGITUDE = exif.getAttribute(ExifInterface.TAG_GPS_LONGITUDE); 13 | String attrLONGITUDE_REF = exif.getAttribute(ExifInterface.TAG_GPS_LONGITUDE_REF); 14 | 15 | if ((attrLATITUDE != null) 16 | && (attrLATITUDE_REF != null) 17 | && (attrLONGITUDE != null) 18 | && (attrLONGITUDE_REF != null)) { 19 | 20 | if (attrLATITUDE_REF.equals("N")) { 21 | latitude = convertToDegree(attrLATITUDE); 22 | } else { 23 | latitude = 0 - convertToDegree(attrLATITUDE); 24 | } 25 | 26 | if (attrLONGITUDE_REF.equals("E")) { 27 | longitude = convertToDegree(attrLONGITUDE); 28 | } else { 29 | longitude = 0 - convertToDegree(attrLONGITUDE); 30 | } 31 | } 32 | } 33 | 34 | private Float convertToDegree(String stringDMS) { 35 | Float result = null; 36 | String[] DMS = stringDMS.split(",", 3); 37 | 38 | String[] stringD = DMS[0].split("/", 2); 39 | Double D0 = Double.valueOf(stringD[0]); 40 | Double D1 = Double.valueOf(stringD[1]); 41 | double FloatD = D0 / D1; 42 | 43 | String[] stringM = DMS[1].split("/", 2); 44 | Double M0 = Double.valueOf(stringM[0]); 45 | Double M1 = Double.valueOf(stringM[1]); 46 | double FloatM = M0 / M1; 47 | 48 | String[] stringS = DMS[2].split("/", 2); 49 | Double S0 = Double.valueOf(stringS[0]); 50 | Double S1 = Double.valueOf(stringS[1]); 51 | double FloatS = S0 / S1; 52 | 53 | result = (float) (FloatD + (FloatM / 60) + (FloatS / 3600)); 54 | 55 | return result; 56 | } 57 | 58 | public Float getLatitude() { 59 | return latitude; 60 | } 61 | 62 | public Float getLongitude() { 63 | return longitude; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /android/src/main/java/com/reactnative/ivpusic/imagepicker/IvpusicImagePickerFileProvider.java: -------------------------------------------------------------------------------- 1 | package com.reactnative.ivpusic.imagepicker; 2 | 3 | import androidx.core.content.FileProvider; 4 | 5 | /** 6 | * A custom {@code FileProvider} prevents manifest {@code } name collisions. 7 | */ 8 | public class IvpusicImagePickerFileProvider extends FileProvider { 9 | } -------------------------------------------------------------------------------- /android/src/main/java/com/reactnative/ivpusic/imagepicker/PickerPackage.java: -------------------------------------------------------------------------------- 1 | package com.reactnative.ivpusic.imagepicker; 2 | 3 | import androidx.annotation.NonNull; 4 | import androidx.annotation.Nullable; 5 | 6 | import com.facebook.react.ReactPackage; 7 | import com.facebook.react.TurboReactPackage; 8 | import com.facebook.react.bridge.JavaScriptModule; 9 | import com.facebook.react.bridge.NativeModule; 10 | import com.facebook.react.bridge.ReactApplicationContext; 11 | import com.facebook.react.module.model.ReactModuleInfo; 12 | import com.facebook.react.module.model.ReactModuleInfoProvider; 13 | import com.facebook.react.uimanager.ViewManager; 14 | 15 | import java.util.ArrayList; 16 | import java.util.Collections; 17 | import java.util.HashMap; 18 | import java.util.List; 19 | import java.util.Map; 20 | 21 | import javax.annotation.Nonnull; 22 | 23 | /** 24 | * Created by ipusic on 5/16/16. 25 | */ 26 | public class PickerPackage extends TurboReactPackage { 27 | @Override 28 | @Nonnull 29 | public List createNativeModules(@Nonnull ReactApplicationContext reactContext) { 30 | List modules = new ArrayList<>(); 31 | modules.add(new PickerModule(reactContext)); 32 | return modules; 33 | } 34 | 35 | @Nullable 36 | @Override 37 | public NativeModule getModule(@NonNull String name, @NonNull ReactApplicationContext reactContext) { 38 | if (name.equals(ImageCropPicker.NAME)) { 39 | return new PickerModule(reactContext); 40 | } else { 41 | return null; 42 | } 43 | } 44 | 45 | @Override 46 | public ReactModuleInfoProvider getReactModuleInfoProvider() { 47 | return () -> { 48 | final Map moduleInfos = new HashMap<>(); 49 | boolean isTurboModule = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED; 50 | moduleInfos.put( 51 | ImageCropPicker.NAME, 52 | new ReactModuleInfo( 53 | ImageCropPicker.NAME, 54 | ImageCropPicker.NAME, 55 | false, 56 | false, 57 | false, 58 | isTurboModule 59 | )); 60 | return moduleInfos; 61 | }; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /android/src/main/java/com/reactnative/ivpusic/imagepicker/RealPathUtil.java: -------------------------------------------------------------------------------- 1 | package com.reactnative.ivpusic.imagepicker; 2 | 3 | import android.annotation.TargetApi; 4 | import android.content.ContentUris; 5 | import android.content.Context; 6 | import android.database.Cursor; 7 | import android.net.Uri; 8 | import android.os.Build; 9 | import android.os.Environment; 10 | import android.provider.DocumentsContract; 11 | import android.provider.MediaStore; 12 | 13 | import java.io.File; 14 | import java.io.FileOutputStream; 15 | import java.io.IOException; 16 | import java.io.InputStream; 17 | 18 | class RealPathUtil { 19 | @TargetApi(Build.VERSION_CODES.KITKAT) 20 | static String getRealPathFromURI(final Context context, final Uri uri) throws IOException { 21 | 22 | final boolean isKitKat = Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT; 23 | 24 | // DocumentProvider 25 | if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) { 26 | // ExternalStorageProvider 27 | if (isExternalStorageDocument(uri)) { 28 | final String docId = DocumentsContract.getDocumentId(uri); 29 | final String[] split = docId.split(":"); 30 | final String type = split[0]; 31 | 32 | if ("primary".equalsIgnoreCase(type)) { 33 | return Environment.getExternalStorageDirectory() + "/" + split[1]; 34 | } else { 35 | final int splitIndex = docId.indexOf(':', 1); 36 | final String tag = docId.substring(0, splitIndex); 37 | final String path = docId.substring(splitIndex + 1); 38 | 39 | String nonPrimaryVolume = getPathToNonPrimaryVolume(context, tag); 40 | if (nonPrimaryVolume != null) { 41 | String result = nonPrimaryVolume + "/" + path; 42 | File file = new File(result); 43 | if (file.exists() && file.canRead()) { 44 | return result; 45 | } 46 | return null; 47 | } 48 | } 49 | } 50 | // DownloadsProvider 51 | else if (isDownloadsDocument(uri)) { 52 | final String id = DocumentsContract.getDocumentId(uri); 53 | final Uri contentUri = ContentUris.withAppendedId( 54 | Uri.parse("content://downloads/public_downloads"), Long.valueOf(id)); 55 | 56 | return getDataColumn(context, contentUri, null, null); 57 | } 58 | // MediaProvider 59 | else if (isMediaDocument(uri)) { 60 | final String docId = DocumentsContract.getDocumentId(uri); 61 | final String[] split = docId.split(":"); 62 | final String type = split[0]; 63 | 64 | Uri contentUri = null; 65 | if ("image".equals(type)) { 66 | contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; 67 | } else if ("video".equals(type)) { 68 | contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI; 69 | } else if ("audio".equals(type)) { 70 | contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI; 71 | } 72 | 73 | final String selection = "_id=?"; 74 | final String[] selectionArgs = new String[] { 75 | split[1] 76 | }; 77 | 78 | return getDataColumn(context, contentUri, selection, selectionArgs); 79 | } 80 | } 81 | // MediaStore (and general) 82 | else if ("content".equalsIgnoreCase(uri.getScheme())) { 83 | // Return the remote address 84 | if (isGooglePhotosUri(uri)) 85 | return uri.getLastPathSegment(); 86 | return getDataColumn(context, uri, null, null); 87 | } 88 | // File 89 | else if ("file".equalsIgnoreCase(uri.getScheme())) { 90 | return uri.getPath(); 91 | } 92 | 93 | return null; 94 | } 95 | 96 | /** 97 | * If an image/video has been selected from a cloud storage, this method 98 | * should be call to download the file in the cache folder. 99 | * 100 | * @param context The context 101 | * @param fileName donwloaded file's name 102 | * @param uri file's URI 103 | * @return file that has been written 104 | */ 105 | private static File writeToFile(Context context, String fileName, Uri uri) { 106 | String tmpDir = context.getCacheDir() + "/react-native-image-crop-picker"; 107 | Boolean created = new File(tmpDir).mkdir(); 108 | fileName = fileName.substring(fileName.lastIndexOf('/') + 1); 109 | File path = new File(tmpDir); 110 | File file = new File(path, fileName); 111 | try { 112 | FileOutputStream oos = new FileOutputStream(file); 113 | byte[] buf = new byte[8192]; 114 | InputStream is = context.getContentResolver().openInputStream(uri); 115 | int c = 0; 116 | while ((c = is.read(buf, 0, buf.length)) > 0) { 117 | oos.write(buf, 0, c); 118 | oos.flush(); 119 | } 120 | oos.close(); 121 | is.close(); 122 | } catch (Exception e) { 123 | e.printStackTrace(); 124 | } 125 | return file; 126 | } 127 | 128 | /** 129 | * Get the value of the data column for this Uri. This is useful for 130 | * MediaStore Uris, and other file-based ContentProviders. 131 | * 132 | * @param context The context. 133 | * @param uri The Uri to query. 134 | * @param selection (Optional) Filter used in the query. 135 | * @param selectionArgs (Optional) Selection arguments used in the query. 136 | * @return The value of the _data column, which is typically a file path. 137 | */ 138 | private static String getDataColumn(Context context, Uri uri, String selection, 139 | String[] selectionArgs) { 140 | 141 | Cursor cursor = null; 142 | final String[] projection = { 143 | MediaStore.MediaColumns.DATA, 144 | MediaStore.MediaColumns.DISPLAY_NAME, 145 | }; 146 | 147 | try { 148 | cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, 149 | null); 150 | if (cursor != null && cursor.moveToFirst()) { 151 | // Fall back to writing to file if _data column does not exist 152 | final int index = cursor.getColumnIndex(MediaStore.MediaColumns.DATA); 153 | String path = index > -1 ? cursor.getString(index) : null; 154 | if (path != null) { 155 | return cursor.getString(index); 156 | } else { 157 | final int indexDisplayName = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DISPLAY_NAME); 158 | String fileName = cursor.getString(indexDisplayName); 159 | File fileWritten = writeToFile(context, fileName, uri); 160 | return fileWritten.getAbsolutePath(); 161 | } 162 | } 163 | } finally { 164 | if (cursor != null) 165 | cursor.close(); 166 | } 167 | return null; 168 | } 169 | 170 | 171 | /** 172 | * @param uri The Uri to check. 173 | * @return Whether the Uri authority is ExternalStorageProvider. 174 | */ 175 | private static boolean isExternalStorageDocument(Uri uri) { 176 | return "com.android.externalstorage.documents".equals(uri.getAuthority()); 177 | } 178 | 179 | /** 180 | * @param uri The Uri to check. 181 | * @return Whether the Uri authority is DownloadsProvider. 182 | */ 183 | private static boolean isDownloadsDocument(Uri uri) { 184 | return "com.android.providers.downloads.documents".equals(uri.getAuthority()); 185 | } 186 | 187 | /** 188 | * @param uri The Uri to check. 189 | * @return Whether the Uri authority is MediaProvider. 190 | */ 191 | private static boolean isMediaDocument(Uri uri) { 192 | return "com.android.providers.media.documents".equals(uri.getAuthority()); 193 | } 194 | 195 | /** 196 | * @param uri The Uri to check. 197 | * @return Whether the Uri authority is Google Photos. 198 | */ 199 | private static boolean isGooglePhotosUri(Uri uri) { 200 | return "com.google.android.apps.photos.content".equals(uri.getAuthority()); 201 | } 202 | 203 | @TargetApi(Build.VERSION_CODES.KITKAT) 204 | private static String getPathToNonPrimaryVolume(Context context, String tag) { 205 | File[] volumes = context.getExternalCacheDirs(); 206 | if (volumes != null) { 207 | for (File volume : volumes) { 208 | if (volume != null) { 209 | String path = volume.getAbsolutePath(); 210 | if (path != null) { 211 | int index = path.indexOf(tag); 212 | if (index != -1) { 213 | return path.substring(0, index) + tag; 214 | } 215 | } 216 | } 217 | } 218 | } 219 | return null; 220 | } 221 | 222 | } 223 | -------------------------------------------------------------------------------- /android/src/main/java/com/reactnative/ivpusic/imagepicker/ResultCollector.java: -------------------------------------------------------------------------------- 1 | package com.reactnative.ivpusic.imagepicker; 2 | 3 | import android.util.Log; 4 | 5 | import com.facebook.react.bridge.Promise; 6 | import com.facebook.react.bridge.WritableArray; 7 | import com.facebook.react.bridge.WritableMap; 8 | import com.facebook.react.bridge.WritableNativeArray; 9 | 10 | import java.util.concurrent.atomic.AtomicInteger; 11 | 12 | /** 13 | * Created by ipusic on 12/28/16. 14 | */ 15 | 16 | class ResultCollector { 17 | private Promise promise; 18 | private int waitCount; 19 | private boolean multiple; 20 | private AtomicInteger waitCounter; 21 | private WritableArray arrayResult; 22 | private boolean resultSent; 23 | 24 | synchronized void setup(Promise promise, boolean multiple) { 25 | this.promise = promise; 26 | this.multiple = multiple; 27 | 28 | this.resultSent = false; 29 | this.waitCount = 0; 30 | this.waitCounter = new AtomicInteger(0); 31 | 32 | if (multiple) { 33 | this.arrayResult = new WritableNativeArray(); 34 | } 35 | } 36 | 37 | // if user has provided "multiple" option, we will wait for X number of result to come, 38 | // and also return result as an array 39 | synchronized void setWaitCount(int waitCount) { 40 | this.waitCount = waitCount; 41 | this.waitCounter = new AtomicInteger(0); 42 | } 43 | 44 | synchronized private boolean isRequestValid() { 45 | if (resultSent) { 46 | Log.w("image-crop-picker", "Skipping result, already sent..."); 47 | return false; 48 | } 49 | 50 | if (promise == null) { 51 | Log.w("image-crop-picker", "Trying to notify success but promise is not set"); 52 | return false; 53 | } 54 | 55 | return true; 56 | } 57 | 58 | synchronized void notifySuccess(WritableMap result) { 59 | if (!isRequestValid()) { 60 | return; 61 | } 62 | 63 | if (multiple) { 64 | arrayResult.pushMap(result); 65 | int currentCount = waitCounter.addAndGet(1); 66 | 67 | if (currentCount == waitCount) { 68 | promise.resolve(arrayResult); 69 | resultSent = true; 70 | } 71 | } else { 72 | promise.resolve(result); 73 | resultSent = true; 74 | } 75 | } 76 | 77 | synchronized void notifyProblem(String code, String message) { 78 | if (!isRequestValid()) { 79 | return; 80 | } 81 | 82 | Log.e("image-crop-picker", "Promise rejected. " + message); 83 | promise.reject(code, message); 84 | resultSent = true; 85 | } 86 | 87 | synchronized void notifyProblem(String code, Throwable throwable) { 88 | if (!isRequestValid()) { 89 | return; 90 | } 91 | 92 | Log.e("image-crop-picker", "Promise rejected. " + throwable.getMessage()); 93 | promise.reject(code, throwable); 94 | resultSent = true; 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /android/src/main/res/xml/ivpusic_imagepicker_provider_paths.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /android/src/newArch/java/com/reactnative/ivpusic/imagepicker/PickerModule.java: -------------------------------------------------------------------------------- 1 | package com.reactnative.ivpusic.imagepicker; 2 | 3 | import com.facebook.react.bridge.Promise; 4 | import com.facebook.react.bridge.ReactApplicationContext; 5 | import com.facebook.react.bridge.ReactMethod; 6 | import com.facebook.react.bridge.ReadableMap; 7 | import com.facebook.react.module.annotations.ReactModule; 8 | 9 | @ReactModule(name = ImageCropPicker.NAME) 10 | public class PickerModule extends NativeImageCropPickerSpec { 11 | private final ImageCropPicker picker; 12 | 13 | public PickerModule(ReactApplicationContext reactContext) { 14 | super(reactContext); 15 | picker = new ImageCropPicker(reactContext); 16 | } 17 | 18 | @Override 19 | public void openPicker(ReadableMap options, Promise promise) { 20 | picker.openPicker(options, promise); 21 | } 22 | 23 | @Override 24 | public void openCamera(ReadableMap options, Promise promise) { 25 | picker.openCamera(options, promise); 26 | } 27 | 28 | @Override 29 | public void openCropper(ReadableMap options, Promise promise) { 30 | picker.openCropper(options, promise); 31 | } 32 | 33 | @Override 34 | public void clean(Promise promise) { 35 | picker.clean(promise); 36 | } 37 | 38 | @Override 39 | public void cleanSingle(String path, Promise promise) { 40 | picker.cleanSingle(path, promise); 41 | } 42 | } -------------------------------------------------------------------------------- /android/src/oldArch/java/com/reactnative/ivpusic/imagepicker/PickerModule.java: -------------------------------------------------------------------------------- 1 | package com.reactnative.ivpusic.imagepicker; 2 | 3 | import androidx.annotation.NonNull; 4 | 5 | import com.facebook.react.bridge.Promise; 6 | import com.facebook.react.bridge.ReactApplicationContext; 7 | import com.facebook.react.bridge.ReactContextBaseJavaModule; 8 | import com.facebook.react.bridge.ReactMethod; 9 | import com.facebook.react.bridge.ReadableMap; 10 | 11 | public class PickerModule extends ReactContextBaseJavaModule { 12 | private final ImageCropPicker picker; 13 | 14 | public PickerModule(ReactApplicationContext reactContext) { 15 | super(reactContext); 16 | picker = new ImageCropPicker(reactContext); 17 | } 18 | 19 | @NonNull 20 | @Override 21 | public String getName() { 22 | return ImageCropPicker.NAME; 23 | } 24 | 25 | @ReactMethod 26 | public void openPicker(ReadableMap options, Promise promise) { 27 | picker.openPicker(options, promise); 28 | } 29 | 30 | @ReactMethod 31 | public void openCamera(ReadableMap options, Promise promise) { 32 | picker.openCamera(options, promise); 33 | } 34 | 35 | @ReactMethod 36 | public void openCropper(ReadableMap options, Promise promise) { 37 | picker.openCropper(options, promise); 38 | } 39 | 40 | @ReactMethod 41 | public void clean(Promise promise) { 42 | picker.clean(promise); 43 | } 44 | 45 | @ReactMethod 46 | public void cleanSingle(String path, Promise promise) { 47 | picker.cleanSingle(path, promise); 48 | } 49 | } -------------------------------------------------------------------------------- /android/src/test/test.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /images/ios_circular_crop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivpusic/react-native-image-crop-picker/748898a3d8ee1af82a333780f1f9bb6c62439d28/images/ios_circular_crop.png -------------------------------------------------------------------------------- /images/ios_multiple_pick_v2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivpusic/react-native-image-crop-picker/748898a3d8ee1af82a333780f1f9bb6c62439d28/images/ios_multiple_pick_v2.png -------------------------------------------------------------------------------- /images/ios_normal_crop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivpusic/react-native-image-crop-picker/748898a3d8ee1af82a333780f1f9bb6c62439d28/images/ios_normal_crop.png -------------------------------------------------------------------------------- /images/ios_single_pick_v2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivpusic/react-native-image-crop-picker/748898a3d8ee1af82a333780f1f9bb6c62439d28/images/ios_single_pick_v2.png -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | import ImageCropPicker from "./src/NativeImageCropPicker"; 2 | 3 | export default ImageCropPicker; 4 | export const openPicker = ImageCropPicker.openPicker; 5 | export const openCamera = ImageCropPicker.openCamera; 6 | export const openCropper = ImageCropPicker.openCropper; 7 | export const clean = ImageCropPicker.clean; 8 | export const cleanSingle = ImageCropPicker.cleanSingle; 9 | -------------------------------------------------------------------------------- /ios/ImageCropPickerSDK/QBImagePicker.framework/Headers/QBImagePicker.h: -------------------------------------------------------------------------------- 1 | // 2 | // QBImagePicker.h 3 | // QBImagePicker 4 | // 5 | // Created by Katsuma Tanaka on 2015/04/03. 6 | // Copyright (c) 2015 Katsuma Tanaka. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for QBImagePicker. 12 | FOUNDATION_EXPORT double QBImagePickerVersionNumber; 13 | 14 | //! Project version string for QBImagePicker. 15 | FOUNDATION_EXPORT const unsigned char QBImagePickerVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | #import 19 | -------------------------------------------------------------------------------- /ios/ImageCropPickerSDK/QBImagePicker.framework/Headers/QBImagePickerController.h: -------------------------------------------------------------------------------- 1 | // 2 | // QBImagePickerController.h 3 | // QBImagePicker 4 | // 5 | // Created by Katsuma Tanaka on 2015/04/03. 6 | // Copyright (c) 2015 Katsuma Tanaka. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @class QBImagePickerController; 13 | 14 | @protocol QBImagePickerControllerDelegate 15 | 16 | @optional 17 | - (void)qb_imagePickerController:(QBImagePickerController *)imagePickerController didFinishPickingAssets:(NSArray *)assets; 18 | - (void)qb_imagePickerControllerDidCancel:(QBImagePickerController *)imagePickerController; 19 | 20 | - (BOOL)qb_imagePickerController:(QBImagePickerController *)imagePickerController shouldSelectAsset:(PHAsset *)asset; 21 | - (void)qb_imagePickerController:(QBImagePickerController *)imagePickerController didSelectAsset:(PHAsset *)asset; 22 | - (void)qb_imagePickerController:(QBImagePickerController *)imagePickerController didDeselectAsset:(PHAsset *)asset; 23 | 24 | @end 25 | 26 | typedef NS_ENUM(NSUInteger, QBImagePickerMediaType) { 27 | QBImagePickerMediaTypeAny = 0, 28 | QBImagePickerMediaTypeImage, 29 | QBImagePickerMediaTypeVideo 30 | }; 31 | 32 | @interface QBImagePickerController : UIViewController 33 | 34 | @property (nonatomic, weak) id delegate; 35 | 36 | @property (nonatomic, strong, readonly) NSMutableOrderedSet *selectedAssets; 37 | 38 | @property (nonatomic, copy) NSArray *assetCollectionSubtypes; 39 | @property (nonatomic, assign) QBImagePickerMediaType mediaType; 40 | 41 | @property (nonatomic, assign) BOOL allowsMultipleSelection; 42 | @property (nonatomic, assign) NSUInteger minimumNumberOfSelection; 43 | @property (nonatomic, assign) NSUInteger maximumNumberOfSelection; 44 | 45 | @property (nonatomic, copy) NSString *prompt; 46 | @property (nonatomic, assign) BOOL showsNumberOfSelectedAssets; 47 | 48 | @property (nonatomic, assign) NSUInteger numberOfColumnsInPortrait; 49 | @property (nonatomic, assign) NSUInteger numberOfColumnsInLandscape; 50 | 51 | @end 52 | -------------------------------------------------------------------------------- /ios/ImageCropPickerSDK/QBImagePicker.framework/Info.plist: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivpusic/react-native-image-crop-picker/748898a3d8ee1af82a333780f1f9bb6c62439d28/ios/ImageCropPickerSDK/QBImagePicker.framework/Info.plist -------------------------------------------------------------------------------- /ios/ImageCropPickerSDK/QBImagePicker.framework/Modules/module.modulemap: -------------------------------------------------------------------------------- 1 | framework module QBImagePicker { 2 | umbrella header "QBImagePicker.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /ios/ImageCropPickerSDK/QBImagePicker.framework/QBImagePicker: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivpusic/react-native-image-crop-picker/748898a3d8ee1af82a333780f1f9bb6c62439d28/ios/ImageCropPickerSDK/QBImagePicker.framework/QBImagePicker -------------------------------------------------------------------------------- /ios/ImageCropPickerSDK/QBImagePicker.framework/QBImagePicker.storyboardc/Info.plist: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivpusic/react-native-image-crop-picker/748898a3d8ee1af82a333780f1f9bb6c62439d28/ios/ImageCropPickerSDK/QBImagePicker.framework/QBImagePicker.storyboardc/Info.plist -------------------------------------------------------------------------------- /ios/ImageCropPickerSDK/QBImagePicker.framework/QBImagePicker.storyboardc/QBAlbumsNavigationController.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivpusic/react-native-image-crop-picker/748898a3d8ee1af82a333780f1f9bb6c62439d28/ios/ImageCropPickerSDK/QBImagePicker.framework/QBImagePicker.storyboardc/QBAlbumsNavigationController.nib -------------------------------------------------------------------------------- /ios/ImageCropPickerSDK/QBImagePicker.framework/QBImagePicker.storyboardc/QBAlbumsViewController.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivpusic/react-native-image-crop-picker/748898a3d8ee1af82a333780f1f9bb6c62439d28/ios/ImageCropPickerSDK/QBImagePicker.framework/QBImagePicker.storyboardc/QBAlbumsViewController.nib -------------------------------------------------------------------------------- /ios/ImageCropPickerSDK/QBImagePicker.framework/QBImagePicker.storyboardc/QBAssetsViewController.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivpusic/react-native-image-crop-picker/748898a3d8ee1af82a333780f1f9bb6c62439d28/ios/ImageCropPickerSDK/QBImagePicker.framework/QBImagePicker.storyboardc/QBAssetsViewController.nib -------------------------------------------------------------------------------- /ios/ImageCropPickerSDK/QBImagePicker.framework/QBImagePicker.storyboardc/QL5-wR-LYt-view-66K-TS-Yoc.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivpusic/react-native-image-crop-picker/748898a3d8ee1af82a333780f1f9bb6c62439d28/ios/ImageCropPickerSDK/QBImagePicker.framework/QBImagePicker.storyboardc/QL5-wR-LYt-view-66K-TS-Yoc.nib -------------------------------------------------------------------------------- /ios/ImageCropPickerSDK/QBImagePicker.framework/QBImagePicker.storyboardc/QiH-NZ-ZGN-view-sD2-zK-ryo.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivpusic/react-native-image-crop-picker/748898a3d8ee1af82a333780f1f9bb6c62439d28/ios/ImageCropPickerSDK/QBImagePicker.framework/QBImagePicker.storyboardc/QiH-NZ-ZGN-view-sD2-zK-ryo.nib -------------------------------------------------------------------------------- /ios/ImageCropPickerSDK/QBImagePicker.framework/_CodeSignature/CodeResources: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | files 6 | 7 | Headers/QBImagePicker.h 8 | 9 | wIb/otiZ7bd2vyPJQF6JEeoqhqo= 10 | 11 | Headers/QBImagePickerController.h 12 | 13 | Pj/03SZs3R39/KDJC/Sw28hOcV4= 14 | 15 | Info.plist 16 | 17 | IcCz/8UZ07kkFONGwju3BBUrdSA= 18 | 19 | Modules/module.modulemap 20 | 21 | b8XazA/6z0jSXdJ08gOuLFgiplM= 22 | 23 | QBImagePicker.storyboardc/Info.plist 24 | 25 | iwZHbHPu3m3FYRI+FCDLbHeFs44= 26 | 27 | QBImagePicker.storyboardc/QBAlbumsNavigationController.nib 28 | 29 | 5MCnX6u0y0SAVdmtiddUomh9GyY= 30 | 31 | QBImagePicker.storyboardc/QBAlbumsViewController.nib 32 | 33 | pY80pANgQzeIQuYM9GWFeoXUSxQ= 34 | 35 | QBImagePicker.storyboardc/QBAssetsViewController.nib 36 | 37 | 7+OaszKW0bhc6RotWxC0o0SijKw= 38 | 39 | QBImagePicker.storyboardc/QL5-wR-LYt-view-66K-TS-Yoc.nib 40 | 41 | 0xNFW/713RpJkWqwnLEP8bUWcuI= 42 | 43 | QBImagePicker.storyboardc/QiH-NZ-ZGN-view-sD2-zK-ryo.nib 44 | 45 | Fj2aIfr+Es6yrxOSQzP/3Uhvvvs= 46 | 47 | de.lproj/QBImagePicker.strings 48 | 49 | hash 50 | 51 | aEwah75TRZyK1k7zsKbitGOHsEE= 52 | 53 | optional 54 | 55 | 56 | en.lproj/QBImagePicker.strings 57 | 58 | hash 59 | 60 | /bN8mAXwM04zgDQj19s7yTHxKQs= 61 | 62 | optional 63 | 64 | 65 | es.lproj/QBImagePicker.strings 66 | 67 | hash 68 | 69 | 3E8xykBQDKx9XRx4cigrfFeoUwo= 70 | 71 | optional 72 | 73 | 74 | ja.lproj/QBImagePicker.strings 75 | 76 | hash 77 | 78 | 7j4cVfYmTo9Yfo4fA9g4AvzTLhw= 79 | 80 | optional 81 | 82 | 83 | pl.lproj/QBImagePicker.strings 84 | 85 | hash 86 | 87 | LfadkhKMCL8TGzZnnEP7Pbsb0I4= 88 | 89 | optional 90 | 91 | 92 | zh-Hans.lproj/QBImagePicker.strings 93 | 94 | hash 95 | 96 | 0F5a3/dLVWvW3skcaXrrOpnhPv0= 97 | 98 | optional 99 | 100 | 101 | 102 | files2 103 | 104 | Headers/QBImagePicker.h 105 | 106 | hash 107 | 108 | wIb/otiZ7bd2vyPJQF6JEeoqhqo= 109 | 110 | hash2 111 | 112 | Fh9fdGZCY2P54hZbKvAZwwcML6IHufU9QAmHXrcmAMI= 113 | 114 | 115 | Headers/QBImagePickerController.h 116 | 117 | hash 118 | 119 | Pj/03SZs3R39/KDJC/Sw28hOcV4= 120 | 121 | hash2 122 | 123 | WcCD5/uhcGaZMLBPYHrRY/JkiB7BPQZqn5rkufhmY8c= 124 | 125 | 126 | Modules/module.modulemap 127 | 128 | hash 129 | 130 | b8XazA/6z0jSXdJ08gOuLFgiplM= 131 | 132 | hash2 133 | 134 | t0ZEP5nTTzs177dyaKMwGF/sZUJu1h9MPbMCcGQ7acw= 135 | 136 | 137 | QBImagePicker.storyboardc/Info.plist 138 | 139 | hash 140 | 141 | iwZHbHPu3m3FYRI+FCDLbHeFs44= 142 | 143 | hash2 144 | 145 | gyFhkTx7M92K1jKJpSG0Yl9R+mQfrd/YtnmTaP54ukY= 146 | 147 | 148 | QBImagePicker.storyboardc/QBAlbumsNavigationController.nib 149 | 150 | hash 151 | 152 | 5MCnX6u0y0SAVdmtiddUomh9GyY= 153 | 154 | hash2 155 | 156 | SLNRGZnuwERXFNcJLu1791ZVDMDsNnnk49Xb01ZjoZo= 157 | 158 | 159 | QBImagePicker.storyboardc/QBAlbumsViewController.nib 160 | 161 | hash 162 | 163 | pY80pANgQzeIQuYM9GWFeoXUSxQ= 164 | 165 | hash2 166 | 167 | KiZiF6NMbTf2YFOEQs4U1Yef9CSUk8GUiApZAjwtnOM= 168 | 169 | 170 | QBImagePicker.storyboardc/QBAssetsViewController.nib 171 | 172 | hash 173 | 174 | 7+OaszKW0bhc6RotWxC0o0SijKw= 175 | 176 | hash2 177 | 178 | PLJdoPEFJT4ItZgiMWCnK0GDoCTxbI/2wAwBBb8l3wM= 179 | 180 | 181 | QBImagePicker.storyboardc/QL5-wR-LYt-view-66K-TS-Yoc.nib 182 | 183 | hash 184 | 185 | 0xNFW/713RpJkWqwnLEP8bUWcuI= 186 | 187 | hash2 188 | 189 | ey42W/ZWm6W0Eea8Q4i9o79eTvpujgSK8HU9PTkbS/4= 190 | 191 | 192 | QBImagePicker.storyboardc/QiH-NZ-ZGN-view-sD2-zK-ryo.nib 193 | 194 | hash 195 | 196 | Fj2aIfr+Es6yrxOSQzP/3Uhvvvs= 197 | 198 | hash2 199 | 200 | 0iH5b4oLNN+sXyFq/BdGICtJzSnj4ll873t0puG4aqM= 201 | 202 | 203 | de.lproj/QBImagePicker.strings 204 | 205 | hash 206 | 207 | aEwah75TRZyK1k7zsKbitGOHsEE= 208 | 209 | hash2 210 | 211 | 5NH6glXlP7txoHgxKL83/BqWApGAb0poqKByJ1yo+9c= 212 | 213 | optional 214 | 215 | 216 | en.lproj/QBImagePicker.strings 217 | 218 | hash 219 | 220 | /bN8mAXwM04zgDQj19s7yTHxKQs= 221 | 222 | hash2 223 | 224 | xZGH0lOWeKlYEMMZNToG0j+vQVTgUTNoydCOJBG+Kjs= 225 | 226 | optional 227 | 228 | 229 | es.lproj/QBImagePicker.strings 230 | 231 | hash 232 | 233 | 3E8xykBQDKx9XRx4cigrfFeoUwo= 234 | 235 | hash2 236 | 237 | T0LWvjKc9Wmuxznj7gCFXRNeGYuFiF92kDcjOVI/WPo= 238 | 239 | optional 240 | 241 | 242 | ja.lproj/QBImagePicker.strings 243 | 244 | hash 245 | 246 | 7j4cVfYmTo9Yfo4fA9g4AvzTLhw= 247 | 248 | hash2 249 | 250 | jxfNgX8MVlO7C53RGOjJwPc1dcSj9DxTyWW8N37BkaE= 251 | 252 | optional 253 | 254 | 255 | pl.lproj/QBImagePicker.strings 256 | 257 | hash 258 | 259 | LfadkhKMCL8TGzZnnEP7Pbsb0I4= 260 | 261 | hash2 262 | 263 | BQCDVBKWaLio8bCJuurR2oc3ENu7K8c6N9ECEh98owU= 264 | 265 | optional 266 | 267 | 268 | zh-Hans.lproj/QBImagePicker.strings 269 | 270 | hash 271 | 272 | 0F5a3/dLVWvW3skcaXrrOpnhPv0= 273 | 274 | hash2 275 | 276 | smMz2/UyQzPo54Zq6lLJj+H42kPbfO4Bfy0iP1jCyf8= 277 | 278 | optional 279 | 280 | 281 | 282 | rules 283 | 284 | ^ 285 | 286 | ^.*\.lproj/ 287 | 288 | optional 289 | 290 | weight 291 | 1000 292 | 293 | ^.*\.lproj/locversion.plist$ 294 | 295 | omit 296 | 297 | weight 298 | 1100 299 | 300 | ^version.plist$ 301 | 302 | 303 | rules2 304 | 305 | .*\.dSYM($|/) 306 | 307 | weight 308 | 11 309 | 310 | ^ 311 | 312 | weight 313 | 20 314 | 315 | ^(.*/)?\.DS_Store$ 316 | 317 | omit 318 | 319 | weight 320 | 2000 321 | 322 | ^(Frameworks|SharedFrameworks|PlugIns|Plug-ins|XPCServices|Helpers|MacOS|Library/(Automator|Spotlight|LoginItems))/ 323 | 324 | nested 325 | 326 | weight 327 | 10 328 | 329 | ^.* 330 | 331 | ^.*\.lproj/ 332 | 333 | optional 334 | 335 | weight 336 | 1000 337 | 338 | ^.*\.lproj/locversion.plist$ 339 | 340 | omit 341 | 342 | weight 343 | 1100 344 | 345 | ^Info\.plist$ 346 | 347 | omit 348 | 349 | weight 350 | 20 351 | 352 | ^PkgInfo$ 353 | 354 | omit 355 | 356 | weight 357 | 20 358 | 359 | ^[^/]+$ 360 | 361 | nested 362 | 363 | weight 364 | 10 365 | 366 | ^embedded\.provisionprofile$ 367 | 368 | weight 369 | 20 370 | 371 | ^version\.plist$ 372 | 373 | weight 374 | 20 375 | 376 | 377 | 378 | 379 | -------------------------------------------------------------------------------- /ios/ImageCropPickerSDK/QBImagePicker.framework/de.lproj/QBImagePicker.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivpusic/react-native-image-crop-picker/748898a3d8ee1af82a333780f1f9bb6c62439d28/ios/ImageCropPickerSDK/QBImagePicker.framework/de.lproj/QBImagePicker.strings -------------------------------------------------------------------------------- /ios/ImageCropPickerSDK/QBImagePicker.framework/en.lproj/QBImagePicker.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivpusic/react-native-image-crop-picker/748898a3d8ee1af82a333780f1f9bb6c62439d28/ios/ImageCropPickerSDK/QBImagePicker.framework/en.lproj/QBImagePicker.strings -------------------------------------------------------------------------------- /ios/ImageCropPickerSDK/QBImagePicker.framework/es.lproj/QBImagePicker.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivpusic/react-native-image-crop-picker/748898a3d8ee1af82a333780f1f9bb6c62439d28/ios/ImageCropPickerSDK/QBImagePicker.framework/es.lproj/QBImagePicker.strings -------------------------------------------------------------------------------- /ios/ImageCropPickerSDK/QBImagePicker.framework/ja.lproj/QBImagePicker.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivpusic/react-native-image-crop-picker/748898a3d8ee1af82a333780f1f9bb6c62439d28/ios/ImageCropPickerSDK/QBImagePicker.framework/ja.lproj/QBImagePicker.strings -------------------------------------------------------------------------------- /ios/ImageCropPickerSDK/QBImagePicker.framework/pl.lproj/QBImagePicker.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivpusic/react-native-image-crop-picker/748898a3d8ee1af82a333780f1f9bb6c62439d28/ios/ImageCropPickerSDK/QBImagePicker.framework/pl.lproj/QBImagePicker.strings -------------------------------------------------------------------------------- /ios/ImageCropPickerSDK/QBImagePicker.framework/zh-Hans.lproj/QBImagePicker.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivpusic/react-native-image-crop-picker/748898a3d8ee1af82a333780f1f9bb6c62439d28/ios/ImageCropPickerSDK/QBImagePicker.framework/zh-Hans.lproj/QBImagePicker.strings -------------------------------------------------------------------------------- /ios/PrivacyInfo.xcprivacy: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSPrivacyAccessedAPITypes 6 | 7 | 8 | NSPrivacyAccessedAPITypeReasons 9 | 10 | 3B52.1 11 | 12 | NSPrivacyAccessedAPIType 13 | NSPrivacyAccessedAPICategoryFileTimestamp 14 | 15 | 16 | NSPrivacyCollectedDataTypes 17 | 18 | 19 | NSPrivacyCollectedDataType 20 | NSPrivacyCollectedDataTypePhotosorVideos 21 | NSPrivacyCollectedDataTypeLinked 22 | 23 | NSPrivacyCollectedDataTypeTracking 24 | 25 | NSPrivacyCollectedDataTypePurposes 26 | 27 | NSPrivacyCollectedDataTypePurposeAppFunctionality 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /ios/QBImagePicker/.gitignore: -------------------------------------------------------------------------------- 1 | # Created by https://www.gitignore.io 2 | 3 | ### OSX ### 4 | .DS_Store 5 | .AppleDouble 6 | .LSOverride 7 | 8 | # Icon must end with two \r 9 | Icon 10 | 11 | # Thumbnails 12 | ._* 13 | 14 | # Files that might appear in the root of a volume 15 | .DocumentRevisions-V100 16 | .fseventsd 17 | .Spotlight-V100 18 | .TemporaryItems 19 | .Trashes 20 | .VolumeIcon.icns 21 | 22 | # Directories potentially created on remote AFP share 23 | .AppleDB 24 | .AppleDesktop 25 | Network Trash Folder 26 | Temporary Items 27 | .apdisk 28 | 29 | 30 | ### Xcode ### 31 | build/ 32 | *.pbxuser 33 | !default.pbxuser 34 | *.mode1v3 35 | !default.mode1v3 36 | *.mode2v3 37 | !default.mode2v3 38 | *.perspectivev3 39 | !default.perspectivev3 40 | xcuserdata 41 | *.xccheckout 42 | *.moved-aside 43 | DerivedData 44 | *.xcuserstate 45 | 46 | 47 | ### Objective-C ### 48 | # Xcode 49 | # 50 | build/ 51 | *.pbxuser 52 | !default.pbxuser 53 | *.mode1v3 54 | !default.mode1v3 55 | *.mode2v3 56 | !default.mode2v3 57 | *.perspectivev3 58 | !default.perspectivev3 59 | xcuserdata 60 | *.xccheckout 61 | *.moved-aside 62 | DerivedData 63 | *.hmap 64 | *.ipa 65 | *.xcuserstate 66 | 67 | # CocoaPods 68 | # 69 | # We recommend against adding the Pods directory to your .gitignore. However 70 | # you should judge for yourself, the pros and cons are mentioned at: 71 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control 72 | # 73 | # Pods/ 74 | 75 | # Carthage 76 | # 77 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 78 | # Carthage/Checkouts 79 | 80 | Carthage/Build 81 | -------------------------------------------------------------------------------- /ios/QBImagePicker/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 Katsuma Tanaka 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /ios/QBImagePicker/QBImagePicker.xcodeproj/xcshareddata/xcschemes/QBImagePicker.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 38 | 39 | 44 | 45 | 47 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 65 | 66 | 67 | 68 | 78 | 79 | 85 | 86 | 87 | 88 | 89 | 90 | 96 | 97 | 103 | 104 | 105 | 106 | 108 | 109 | 112 | 113 | 114 | -------------------------------------------------------------------------------- /ios/QBImagePicker/QBImagePicker/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 3.4.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /ios/QBImagePicker/QBImagePicker/QBAlbumCell.h: -------------------------------------------------------------------------------- 1 | // 2 | // QBAlbumCell.h 3 | // QBImagePicker 4 | // 5 | // Created by Katsuma Tanaka on 2015/04/03. 6 | // Copyright (c) 2015 Katsuma Tanaka. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface QBAlbumCell : UITableViewCell 12 | 13 | @property (weak, nonatomic) IBOutlet UIImageView *imageView1; 14 | @property (weak, nonatomic) IBOutlet UIImageView *imageView2; 15 | @property (weak, nonatomic) IBOutlet UIImageView *imageView3; 16 | @property (weak, nonatomic) IBOutlet UILabel *titleLabel; 17 | @property (weak, nonatomic) IBOutlet UILabel *countLabel; 18 | 19 | @property (nonatomic, assign) CGFloat borderWidth; 20 | 21 | @end 22 | -------------------------------------------------------------------------------- /ios/QBImagePicker/QBImagePicker/QBAlbumCell.m: -------------------------------------------------------------------------------- 1 | // 2 | // QBAlbumCell.m 3 | // QBImagePicker 4 | // 5 | // Created by Katsuma Tanaka on 2015/04/03. 6 | // Copyright (c) 2015 Katsuma Tanaka. All rights reserved. 7 | // 8 | 9 | #import "QBAlbumCell.h" 10 | 11 | @implementation QBAlbumCell 12 | 13 | - (void)setBorderWidth:(CGFloat)borderWidth 14 | { 15 | _borderWidth = borderWidth; 16 | 17 | self.imageView1.layer.borderColor = [[UIColor whiteColor] CGColor]; 18 | self.imageView1.layer.borderWidth = borderWidth; 19 | 20 | self.imageView2.layer.borderColor = [[UIColor whiteColor] CGColor]; 21 | self.imageView2.layer.borderWidth = borderWidth; 22 | 23 | self.imageView3.layer.borderColor = [[UIColor whiteColor] CGColor]; 24 | self.imageView3.layer.borderWidth = borderWidth; 25 | } 26 | 27 | @end 28 | -------------------------------------------------------------------------------- /ios/QBImagePicker/QBImagePicker/QBAlbumsViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // QBAlbumsViewController.h 3 | // QBImagePicker 4 | // 5 | // Created by Katsuma Tanaka on 2015/04/03. 6 | // Copyright (c) 2015 Katsuma Tanaka. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class QBImagePickerController; 12 | 13 | @interface QBAlbumsViewController : UITableViewController 14 | 15 | @property (nonatomic, weak) QBImagePickerController *imagePickerController; 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /ios/QBImagePicker/QBImagePicker/QBAssetCell.h: -------------------------------------------------------------------------------- 1 | // 2 | // QBAssetCell.h 3 | // QBImagePicker 4 | // 5 | // Created by Katsuma Tanaka on 2015/04/03. 6 | // Copyright (c) 2015 Katsuma Tanaka. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class QBVideoIndicatorView; 12 | 13 | @interface QBAssetCell : UICollectionViewCell 14 | 15 | @property (weak, nonatomic) IBOutlet UIImageView *imageView; 16 | @property (weak, nonatomic) IBOutlet QBVideoIndicatorView *videoIndicatorView; 17 | 18 | @property (nonatomic, assign) BOOL showsOverlayViewWhenSelected; 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /ios/QBImagePicker/QBImagePicker/QBAssetCell.m: -------------------------------------------------------------------------------- 1 | // 2 | // QBAssetCell.m 3 | // QBImagePicker 4 | // 5 | // Created by Katsuma Tanaka on 2015/04/03. 6 | // Copyright (c) 2015 Katsuma Tanaka. All rights reserved. 7 | // 8 | 9 | #import "QBAssetCell.h" 10 | 11 | @interface QBAssetCell () 12 | 13 | @property (weak, nonatomic) IBOutlet UIView *overlayView; 14 | 15 | @end 16 | 17 | @implementation QBAssetCell 18 | 19 | - (void)setSelected:(BOOL)selected 20 | { 21 | [super setSelected:selected]; 22 | 23 | // Show/hide overlay view 24 | self.overlayView.hidden = !(selected && self.showsOverlayViewWhenSelected); 25 | } 26 | 27 | @end 28 | -------------------------------------------------------------------------------- /ios/QBImagePicker/QBImagePicker/QBAssetsViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // QBAssetsViewController.h 3 | // QBImagePicker 4 | // 5 | // Created by Katsuma Tanaka on 2015/04/03. 6 | // Copyright (c) 2015 Katsuma Tanaka. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class QBImagePickerController; 12 | @class PHAssetCollection; 13 | 14 | @interface QBAssetsViewController : UICollectionViewController 15 | 16 | @property (nonatomic, weak) QBImagePickerController *imagePickerController; 17 | @property (nonatomic, strong) PHAssetCollection *assetCollection; 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /ios/QBImagePicker/QBImagePicker/QBCheckmarkView.h: -------------------------------------------------------------------------------- 1 | // 2 | // QBCheckmarkView.h 3 | // QBImagePicker 4 | // 5 | // Created by Katsuma Tanaka on 2015/04/03. 6 | // Copyright (c) 2015 Katsuma Tanaka. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | IB_DESIGNABLE 12 | @interface QBCheckmarkView : UIView 13 | 14 | @property (nonatomic, assign) IBInspectable CGFloat borderWidth; 15 | @property (nonatomic, assign) IBInspectable CGFloat checkmarkLineWidth; 16 | 17 | @property (nonatomic, strong) IBInspectable UIColor *borderColor; 18 | @property (nonatomic, strong) IBInspectable UIColor *bodyColor; 19 | @property (nonatomic, strong) IBInspectable UIColor *checkmarkColor; 20 | 21 | @end 22 | -------------------------------------------------------------------------------- /ios/QBImagePicker/QBImagePicker/QBCheckmarkView.m: -------------------------------------------------------------------------------- 1 | // 2 | // QBCheckmarkView.m 3 | // QBImagePicker 4 | // 5 | // Created by Katsuma Tanaka on 2015/04/03. 6 | // Copyright (c) 2015 Katsuma Tanaka. All rights reserved. 7 | // 8 | 9 | #import "QBCheckmarkView.h" 10 | 11 | @implementation QBCheckmarkView 12 | 13 | - (void)awakeFromNib 14 | { 15 | [super awakeFromNib]; 16 | 17 | // Set default values 18 | self.borderWidth = 1.0; 19 | self.checkmarkLineWidth = 1.2; 20 | 21 | self.borderColor = [UIColor whiteColor]; 22 | self.bodyColor = [UIColor colorWithRed:(20.0 / 255.0) green:(111.0 / 255.0) blue:(223.0 / 255.0) alpha:1.0]; 23 | self.checkmarkColor = [UIColor whiteColor]; 24 | 25 | // Set shadow 26 | self.layer.shadowColor = [[UIColor grayColor] CGColor]; 27 | self.layer.shadowOffset = CGSizeMake(0, 0); 28 | self.layer.shadowOpacity = 0.6; 29 | self.layer.shadowRadius = 2.0; 30 | } 31 | 32 | - (void)drawRect:(CGRect)rect 33 | { 34 | // Border 35 | [self.borderColor setFill]; 36 | [[UIBezierPath bezierPathWithOvalInRect:self.bounds] fill]; 37 | 38 | // Body 39 | [self.bodyColor setFill]; 40 | [[UIBezierPath bezierPathWithOvalInRect:CGRectInset(self.bounds, self.borderWidth, self.borderWidth)] fill]; 41 | 42 | // Checkmark 43 | UIBezierPath *checkmarkPath = [UIBezierPath bezierPath]; 44 | checkmarkPath.lineWidth = self.checkmarkLineWidth; 45 | 46 | [checkmarkPath moveToPoint:CGPointMake(CGRectGetWidth(self.bounds) * (6.0 / 24.0), CGRectGetHeight(self.bounds) * (12.0 / 24.0))]; 47 | [checkmarkPath addLineToPoint:CGPointMake(CGRectGetWidth(self.bounds) * (10.0 / 24.0), CGRectGetHeight(self.bounds) * (16.0 / 24.0))]; 48 | [checkmarkPath addLineToPoint:CGPointMake(CGRectGetWidth(self.bounds) * (18.0 / 24.0), CGRectGetHeight(self.bounds) * (8.0 / 24.0))]; 49 | 50 | [self.checkmarkColor setStroke]; 51 | [checkmarkPath stroke]; 52 | } 53 | 54 | @end 55 | -------------------------------------------------------------------------------- /ios/QBImagePicker/QBImagePicker/QBImagePicker.h: -------------------------------------------------------------------------------- 1 | // 2 | // QBImagePicker.h 3 | // QBImagePicker 4 | // 5 | // Created by Katsuma Tanaka on 2015/04/03. 6 | // Copyright (c) 2015 Katsuma Tanaka. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for QBImagePicker. 12 | FOUNDATION_EXPORT double QBImagePickerVersionNumber; 13 | 14 | //! Project version string for QBImagePicker. 15 | FOUNDATION_EXPORT const unsigned char QBImagePickerVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | #import 19 | -------------------------------------------------------------------------------- /ios/QBImagePicker/QBImagePicker/QBImagePickerController.h: -------------------------------------------------------------------------------- 1 | // 2 | // QBImagePickerController.h 3 | // QBImagePicker 4 | // 5 | // Created by Katsuma Tanaka on 2015/04/03. 6 | // Copyright (c) 2015 Katsuma Tanaka. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @class QBImagePickerController; 13 | 14 | @protocol QBImagePickerControllerDelegate 15 | 16 | @optional 17 | - (void)qb_imagePickerController:(QBImagePickerController *)imagePickerController didFinishPickingAssets:(NSArray *)assets; 18 | - (void)qb_imagePickerControllerDidCancel:(QBImagePickerController *)imagePickerController; 19 | 20 | - (BOOL)qb_imagePickerController:(QBImagePickerController *)imagePickerController shouldSelectAsset:(PHAsset *)asset; 21 | - (void)qb_imagePickerController:(QBImagePickerController *)imagePickerController didSelectAsset:(PHAsset *)asset; 22 | - (void)qb_imagePickerController:(QBImagePickerController *)imagePickerController didDeselectAsset:(PHAsset *)asset; 23 | 24 | @end 25 | 26 | typedef NS_ENUM(NSUInteger, QBImagePickerMediaType) { 27 | QBImagePickerMediaTypeAny = 0, 28 | QBImagePickerMediaTypeImage, 29 | QBImagePickerMediaTypeVideo 30 | }; 31 | 32 | @interface QBImagePickerController : UIViewController 33 | 34 | @property (nonatomic, weak) id delegate; 35 | 36 | @property (nonatomic, strong, readonly) NSMutableOrderedSet *selectedAssets; 37 | 38 | @property (nonatomic, copy) NSArray *assetCollectionSubtypes; 39 | @property (nonatomic, assign) QBImagePickerMediaType mediaType; 40 | 41 | @property (nonatomic, assign) BOOL allowsMultipleSelection; 42 | @property (nonatomic, assign) NSUInteger minimumNumberOfSelection; 43 | @property (nonatomic, assign) NSUInteger maximumNumberOfSelection; 44 | @property (nonatomic, strong) NSString* sortOrder; 45 | 46 | @property (nonatomic, copy) NSString *prompt; 47 | @property (nonatomic, assign) BOOL showsNumberOfSelectedAssets; 48 | 49 | @property (nonatomic, assign) NSUInteger numberOfColumnsInPortrait; 50 | @property (nonatomic, assign) NSUInteger numberOfColumnsInLandscape; 51 | 52 | @end 53 | -------------------------------------------------------------------------------- /ios/QBImagePicker/QBImagePicker/QBImagePickerController.m: -------------------------------------------------------------------------------- 1 | // 2 | // QBImagePickerController.m 3 | // QBImagePicker 4 | // 5 | // Created by Katsuma Tanaka on 2015/04/03. 6 | // Copyright (c) 2015 Katsuma Tanaka. All rights reserved. 7 | // 8 | 9 | #import "QBImagePickerController.h" 10 | #import 11 | 12 | // ViewControllers 13 | #import "QBAlbumsViewController.h" 14 | 15 | @interface QBImagePickerController () 16 | 17 | @property (nonatomic, strong) UINavigationController *albumsNavigationController; 18 | 19 | @property (nonatomic, strong) NSBundle *assetBundle; 20 | 21 | @end 22 | 23 | @implementation QBImagePickerController 24 | 25 | - (instancetype)init 26 | { 27 | self = [super init]; 28 | 29 | if (self) { 30 | // Set default values 31 | self.assetCollectionSubtypes = @[ 32 | @(PHAssetCollectionSubtypeSmartAlbumUserLibrary), 33 | @(PHAssetCollectionSubtypeAlbumMyPhotoStream), 34 | @(PHAssetCollectionSubtypeSmartAlbumPanoramas), 35 | @(PHAssetCollectionSubtypeSmartAlbumVideos), 36 | @(PHAssetCollectionSubtypeSmartAlbumBursts) 37 | ]; 38 | self.minimumNumberOfSelection = 1; 39 | self.numberOfColumnsInPortrait = 4; 40 | self.numberOfColumnsInLandscape = 7; 41 | 42 | _selectedAssets = [NSMutableOrderedSet orderedSet]; 43 | 44 | // Get asset bundle 45 | self.assetBundle = [NSBundle bundleForClass:[self class]]; 46 | NSString *bundlePath = [self.assetBundle pathForResource:@"QBImagePicker" ofType:@"bundle"]; 47 | if (bundlePath) { 48 | self.assetBundle = [NSBundle bundleWithPath:bundlePath]; 49 | } 50 | 51 | [self setUpAlbumsViewController]; 52 | 53 | // Set instance 54 | QBAlbumsViewController *albumsViewController = (QBAlbumsViewController *)self.albumsNavigationController.topViewController; 55 | albumsViewController.imagePickerController = self; 56 | } 57 | 58 | return self; 59 | } 60 | 61 | - (void)setUpAlbumsViewController 62 | { 63 | // Add QBAlbumsViewController as a child 64 | UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"QBImagePicker" bundle:self.assetBundle]; 65 | UINavigationController *navigationController = [storyboard instantiateViewControllerWithIdentifier:@"QBAlbumsNavigationController"]; 66 | 67 | [self addChildViewController:navigationController]; 68 | 69 | navigationController.view.frame = self.view.bounds; 70 | [self.view addSubview:navigationController.view]; 71 | 72 | [navigationController didMoveToParentViewController:self]; 73 | 74 | self.albumsNavigationController = navigationController; 75 | } 76 | 77 | @end 78 | -------------------------------------------------------------------------------- /ios/QBImagePicker/QBImagePicker/QBSlomoIconView.h: -------------------------------------------------------------------------------- 1 | // 2 | // QBSlomoIconView.h 3 | // QBImagePicker 4 | // 5 | // Created by Julien Chaumond on 22/04/2015. 6 | // Copyright (c) 2015 Katsuma Tanaka. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | IB_DESIGNABLE 12 | @interface QBSlomoIconView : UIView 13 | 14 | @property (nonatomic, strong) IBInspectable UIColor *iconColor; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /ios/QBImagePicker/QBImagePicker/QBSlomoIconView.m: -------------------------------------------------------------------------------- 1 | // 2 | // QBSlomoIconView.m 3 | // QBImagePicker 4 | // 5 | // Created by Julien Chaumond on 22/04/2015. 6 | // Copyright (c) 2015 Katsuma Tanaka. All rights reserved. 7 | // 8 | 9 | #import "QBSlomoIconView.h" 10 | 11 | @implementation QBSlomoIconView 12 | 13 | - (void)awakeFromNib 14 | { 15 | [super awakeFromNib]; 16 | 17 | // Set default values 18 | self.iconColor = [UIColor whiteColor]; 19 | } 20 | 21 | - (void)drawRect:(CGRect)rect 22 | { 23 | [self.iconColor setStroke]; 24 | 25 | CGFloat width = 2.2; 26 | CGRect insetRect = CGRectInset(rect, width / 2, width / 2); 27 | 28 | // Draw dashed circle 29 | UIBezierPath* circlePath = [UIBezierPath bezierPathWithOvalInRect:insetRect]; 30 | circlePath.lineWidth = width; 31 | CGFloat ovalPattern[] = {0.75, 0.75}; 32 | [circlePath setLineDash:ovalPattern count:2 phase:0]; 33 | [circlePath stroke]; 34 | } 35 | 36 | @end 37 | -------------------------------------------------------------------------------- /ios/QBImagePicker/QBImagePicker/QBVideoIconView.h: -------------------------------------------------------------------------------- 1 | // 2 | // QBVideoIconView.h 3 | // QBImagePicker 4 | // 5 | // Created by Katsuma Tanaka on 2015/04/04. 6 | // Copyright (c) 2015 Katsuma Tanaka. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | IB_DESIGNABLE 12 | @interface QBVideoIconView : UIView 13 | 14 | @property (nonatomic, strong) IBInspectable UIColor *iconColor; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /ios/QBImagePicker/QBImagePicker/QBVideoIconView.m: -------------------------------------------------------------------------------- 1 | // 2 | // QBVideoIconView.m 3 | // QBImagePicker 4 | // 5 | // Created by Katsuma Tanaka on 2015/04/04. 6 | // Copyright (c) 2015 Katsuma Tanaka. All rights reserved. 7 | // 8 | 9 | #import "QBVideoIconView.h" 10 | 11 | @implementation QBVideoIconView 12 | 13 | - (void)awakeFromNib 14 | { 15 | [super awakeFromNib]; 16 | 17 | // Set default values 18 | self.iconColor = [UIColor whiteColor]; 19 | } 20 | 21 | - (void)drawRect:(CGRect)rect 22 | { 23 | [self.iconColor setFill]; 24 | 25 | // Draw triangle 26 | UIBezierPath *trianglePath = [UIBezierPath bezierPath]; 27 | [trianglePath moveToPoint:CGPointMake(CGRectGetMaxX(self.bounds), CGRectGetMinY(self.bounds))]; 28 | [trianglePath addLineToPoint:CGPointMake(CGRectGetMaxX(self.bounds), CGRectGetMaxY(self.bounds))]; 29 | [trianglePath addLineToPoint:CGPointMake(CGRectGetMaxX(self.bounds) - CGRectGetMidY(self.bounds), CGRectGetMidY(self.bounds))]; 30 | [trianglePath closePath]; 31 | [trianglePath fill]; 32 | 33 | // Draw rounded square 34 | UIBezierPath *squarePath = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(CGRectGetMinX(self.bounds), CGRectGetMinY(self.bounds), CGRectGetWidth(self.bounds) - CGRectGetMidY(self.bounds) - 1.0, CGRectGetHeight(self.bounds)) cornerRadius:2.0]; 35 | [squarePath fill]; 36 | } 37 | 38 | @end 39 | -------------------------------------------------------------------------------- /ios/QBImagePicker/QBImagePicker/QBVideoIndicatorView.h: -------------------------------------------------------------------------------- 1 | // 2 | // QBVideoIndicatorView.h 3 | // QBImagePicker 4 | // 5 | // Created by Katsuma Tanaka on 2015/04/04. 6 | // Copyright (c) 2015 Katsuma Tanaka. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "QBVideoIconView.h" 12 | #import "QBSlomoIconView.h" 13 | 14 | @interface QBVideoIndicatorView : UIView 15 | 16 | @property (nonatomic, weak) IBOutlet UILabel *timeLabel; 17 | @property (nonatomic, weak) IBOutlet QBVideoIconView *videoIcon; 18 | @property (nonatomic, weak) IBOutlet QBSlomoIconView *slomoIcon; 19 | 20 | 21 | @end 22 | -------------------------------------------------------------------------------- /ios/QBImagePicker/QBImagePicker/QBVideoIndicatorView.m: -------------------------------------------------------------------------------- 1 | // 2 | // QBVideoIndicatorView.m 3 | // QBImagePicker 4 | // 5 | // Created by Katsuma Tanaka on 2015/04/04. 6 | // Copyright (c) 2015 Katsuma Tanaka. All rights reserved. 7 | // 8 | 9 | #import "QBVideoIndicatorView.h" 10 | 11 | @implementation QBVideoIndicatorView 12 | 13 | - (void)awakeFromNib 14 | { 15 | [super awakeFromNib]; 16 | 17 | // Add gradient layer 18 | CAGradientLayer *gradientLayer = [CAGradientLayer layer]; 19 | gradientLayer.frame = self.bounds; 20 | gradientLayer.colors = @[ 21 | (__bridge id)[[UIColor clearColor] CGColor], 22 | (__bridge id)[[UIColor blackColor] CGColor] 23 | ]; 24 | 25 | [self.layer insertSublayer:gradientLayer atIndex:0]; 26 | } 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /ios/QBImagePicker/QBImagePicker/da.lproj/QBImagePicker.strings: -------------------------------------------------------------------------------- 1 | /* 2 | QBImagePicker.strings 3 | QBImagePicker 4 | */ 5 | 6 | "albums.title" = "Billeder"; 7 | 8 | "assets.footer.photo" = "%ld Billede"; 9 | "assets.footer.photos" = "%ld Billeder"; 10 | "assets.footer.video" = "%ld Video"; 11 | "assets.footer.videos" = "%ld Videoer"; 12 | "assets.footer.photo-and-video" = "%ld Billede, %ld Video"; 13 | "assets.footer.photos-and-video" = "%ld Billeder, %ld Video"; 14 | "assets.footer.photo-and-videos" = "%ld Billede, %ld Videoer"; 15 | "assets.footer.photos-and-videos" = "%ld Billeder, %ld Videoer"; 16 | 17 | "assets.toolbar.item-selected" = "%ld Valgt objekt"; 18 | "assets.toolbar.items-selected" = "%ld Udvalgte genstande"; 19 | 20 | "permission.help" = "Du har givet adgang til et begrænset antal udvalgte billeder og videoer."; 21 | "permission.manage" = "HÅNDTERE"; 22 | "permission.title" = "For at få adgang til alle dine billeder i appen skal du give adgang til hele dit bibliotek i din enheds indstillinger."; 23 | "permission.choose_more" = "Vælg flere billeder"; 24 | "permission.change_settings" = "Ændre indstillinger"; 25 | "permission.cancel" = "Annuller"; 26 | -------------------------------------------------------------------------------- /ios/QBImagePicker/QBImagePicker/de.lproj/QBImagePicker.strings: -------------------------------------------------------------------------------- 1 | /* 2 | QBImagePicker.strings 3 | QBImagePicker 4 | 5 | Created by Katsuma Tanaka on 2015/04/03. 6 | Copyright (c) 2015 Katsuma Tanaka. All rights reserved. 7 | */ 8 | 9 | "albums.title" = "Fotos"; 10 | 11 | "assets.footer.photo" = "%ld Foto"; 12 | "assets.footer.photos" = "%ld Fotos"; 13 | "assets.footer.video" = "%ld Video"; 14 | "assets.footer.videos" = "%ld Videos"; 15 | "assets.footer.photo-and-video" = "%ld Foto, %ld Video"; 16 | "assets.footer.photos-and-video" = "%ld Fotos, %ld Video"; 17 | "assets.footer.photo-and-videos" = "%ld Foto, %ld Videos"; 18 | "assets.footer.photos-and-videos" = "%ld Fotos, %ld Videos"; 19 | 20 | "assets.toolbar.item-selected" = "%ld Element ausgewählt"; 21 | "assets.toolbar.items-selected" = "%ld Elemente ausgewählt"; 22 | 23 | "permission.help" = "Sie haben einer begrenzten Anzahl ausgewählter Fotos und Videos die Erlaubnis erteilt."; 24 | "permission.manage" = "VERWALTEN"; 25 | "permission.title" = "Um auf alle Ihre Fotos in der App zuzugreifen, geben Sie in den Geräteeinstellungen Zugriff auf Ihre vollständige Bibliothek."; 26 | "permission.choose_more" = "Weitere Fotos auswählen"; 27 | "permission.change_settings" = "Einstellungen ändern"; 28 | "permission.cancel" = "Abbrechen"; 29 | -------------------------------------------------------------------------------- /ios/QBImagePicker/QBImagePicker/en.lproj/QBImagePicker.strings: -------------------------------------------------------------------------------- 1 | /* 2 | QBImagePicker.strings 3 | QBImagePicker 4 | 5 | Created by Katsuma Tanaka on 2015/04/03. 6 | Copyright (c) 2015 Katsuma Tanaka. All rights reserved. 7 | */ 8 | 9 | "albums.title" = "Photos"; 10 | 11 | "assets.footer.photo" = "%ld Photo"; 12 | "assets.footer.photos" = "%ld Photos"; 13 | "assets.footer.video" = "%ld Video"; 14 | "assets.footer.videos" = "%ld Videos"; 15 | "assets.footer.photo-and-video" = "%ld Photo, %ld Video"; 16 | "assets.footer.photos-and-video" = "%ld Photos, %ld Video"; 17 | "assets.footer.photo-and-videos" = "%ld Photo, %ld Videos"; 18 | "assets.footer.photos-and-videos" = "%ld Photos, %ld Videos"; 19 | 20 | "assets.toolbar.item-selected" = "%ld Item Selected"; 21 | "assets.toolbar.items-selected" = "%ld Items Selected"; 22 | 23 | "permission.help" = "You have given permission to a limited number of selected photos and videos."; 24 | "permission.manage" = "MANAGE"; 25 | "permission.title" = "To access all your photos in the app, give access to your full library in the device settings."; 26 | "permission.choose_more" = "Select More Photos"; 27 | "permission.change_settings" = "Change Settings"; 28 | "permission.cancel" = "Cancel"; 29 | -------------------------------------------------------------------------------- /ios/QBImagePicker/QBImagePicker/es.lproj/QBImagePicker.strings: -------------------------------------------------------------------------------- 1 | /* 2 | QBImagePicker.strings 3 | QBImagePicker 4 | 5 | Created by Katsuma Tanaka on 2015/04/03. 6 | Copyright (c) 2015 Katsuma Tanaka. All rights reserved. 7 | */ 8 | 9 | "albums.title" = "Fotos"; 10 | 11 | "assets.footer.photo" = "%ld Foto"; 12 | "assets.footer.photos" = "%ld Fotos"; 13 | "assets.footer.video" = "%ld Video"; 14 | "assets.footer.videos" = "%ld Videos"; 15 | "assets.footer.photo-and-video" = "%ld Foto, %ld Video"; 16 | "assets.footer.photos-and-video" = "%ld Fotos, %ld Video"; 17 | "assets.footer.photo-and-videos" = "%ld Foto, %ld Videos"; 18 | "assets.footer.photos-and-videos" = "%ld Fotos, %ld Videos"; 19 | 20 | "assets.toolbar.item-selected" = "%ld items seleccionados"; 21 | "assets.toolbar.items-selected" = "%ld items seleccionados"; 22 | 23 | "permission.help" = "Ha otorgado permiso a un número limitado de fotos y videos seleccionados."; 24 | "permission.manage" = "ADMINISTRAR"; 25 | "permission.title" = "Para acceder a todas sus fotos en la aplicación, dé acceso a su biblioteca completa en la configuración del dispositivo."; 26 | "permission.choose_more" = "Seleccionar más fotos"; 27 | "permission.change_settings" = "Cambiar configuración"; 28 | "permission.cancel" = "Cancelar"; 29 | -------------------------------------------------------------------------------- /ios/QBImagePicker/QBImagePicker/fi.lproj/QBImagePicker.strings: -------------------------------------------------------------------------------- 1 | /* 2 | QBImagePicker.strings 3 | QBImagePicker 4 | */ 5 | 6 | "albums.title" = "Kuvia"; 7 | 8 | "assets.footer.photo" = "%ld Kuva"; 9 | "assets.footer.photos" = "%ld Kuvia"; 10 | "assets.footer.video" = "%ld Video"; 11 | "assets.footer.videos" = "%ld Videoita"; 12 | "assets.footer.photo-and-video" = "%ld Kuva, %ld Video"; 13 | "assets.footer.photos-and-video" = "%ld Kuvia, %ld Video"; 14 | "assets.footer.photo-and-videos" = "%ld Kuva, %ld Videoita"; 15 | "assets.footer.photos-and-videos" = "%ld Kuvia, %ld Videoita"; 16 | 17 | "assets.toolbar.item-selected" = "%ld Valittu objekti"; 18 | "assets.toolbar.items-selected" = "%ld Valitut kohteet"; 19 | 20 | "permission.help" = "Olet myöntänyt pääsyn rajoitettuun määrään valittuja kuvia ja videoita."; 21 | "permission.manage" = "KÄSITTELE"; 22 | "permission.title" = "Jos haluat käyttää kaikkia sovelluksessa olevia kuviasi, anna käyttöoikeus koko kirjastoosi laitteesi asetuksista."; 23 | "permission.choose_more" = "Valitse lisää kuvia"; 24 | "permission.change_settings" = "Vaihda asetuksia"; 25 | "permission.cancel" = "Peruuttaa"; 26 | -------------------------------------------------------------------------------- /ios/QBImagePicker/QBImagePicker/fr.lproj/QBImagePicker.strings: -------------------------------------------------------------------------------- 1 | /* 2 | QBImagePicker.strings 3 | QBImagePicker 4 | 5 | Created by Gareth McCall on 2018/01/17. 6 | MIT License - Copyright (c) 2018 Ivan Pusic, et al 7 | */ 8 | 9 | "albums.title" = "Photos"; 10 | 11 | "assets.footer.photo" = "%ld Photo"; 12 | "assets.footer.photos" = "%ld Photos"; 13 | "assets.footer.video" = "%ld Vidéo"; 14 | "assets.footer.videos" = "%ld Vidéos"; 15 | "assets.footer.photo-and-video" = "%ld Photo, %ld Vidéo"; 16 | "assets.footer.photos-and-video" = "%ld Photos, %ld Vidéo"; 17 | "assets.footer.photo-and-videos" = "%ld Photo, %ld Vidéos"; 18 | "assets.footer.photos-and-videos" = "%ld Photos, %ld Vidéos"; 19 | 20 | "assets.toolbar.item-selected" = "%ld Élément Sélectionné"; 21 | "assets.toolbar.items-selected" = "%ld Éléments Sélectionnés"; 22 | 23 | "permission.help" = "Vous avez autorisé un nombre limité de photos et de vidéos sélectionnées."; 24 | "permission.manage" = "GÉRER"; 25 | "permission.title" = "Pour accéder à toutes vos photos dans l'application, donnez accès à votre bibliothèque complète dans les paramètres de l'appareil."; 26 | "permission.choose_more" = "Sélectionner plus de photos" ; 27 | "permission.change_settings" = "Modifier les paramètres" ; 28 | "permission.cancel" = "Annuler" ; 29 | -------------------------------------------------------------------------------- /ios/QBImagePicker/QBImagePicker/it.lproj/QBImagePicker.strings: -------------------------------------------------------------------------------- 1 | /* 2 | QBImagePicker.strings 3 | QBImagePicker 4 | 5 | Created by Seungyeob Song on 2020/11/10. 6 | Copyright (c) 2020 Seungyeob Song. All rights reserved. 7 | */ 8 | 9 | "albums.title" = "Foto"; 10 | 11 | "assets.footer.photo" = "%ld Foto"; 12 | "assets.footer.photos" = "%ld Foto"; 13 | "assets.footer.video" = "%ld Video"; 14 | "assets.footer.videos" = "%ld Video"; 15 | "assets.footer.photo-and-video" = "%ld Foto, %ld Video"; 16 | "assets.footer.photos-and-video" = "%ld Foto, %ld Video"; 17 | "assets.footer.photo-and-videos" = "%ld Foto, %ld Video"; 18 | "assets.footer.photos-and-videos" = "%ld Foto, %ld Video"; 19 | 20 | "assets.toolbar.item-selected" = "%ld Elemento Selezionato"; 21 | "assets.toolbar.items-selected" = "%ld Elementi Selezionati"; 22 | 23 | "permission.help" = "Hai autorizzato un numero limitato di foto e video selezionati."; 24 | "permission.manage" = "GESTISCI"; 25 | "permission.title" = "Per accedere a tutte le tue foto nell'app, concedi l'accesso alla tua libreria completa nelle impostazioni del dispositivo."; 26 | "permission.choose_more" = "Seleziona altre foto"; 27 | "permission.change_settings" = "Cambia impostazioni"; 28 | "permission.cancel" = "Annulla"; 29 | -------------------------------------------------------------------------------- /ios/QBImagePicker/QBImagePicker/ja.lproj/QBImagePicker.strings: -------------------------------------------------------------------------------- 1 | /* 2 | QBImagePicker.strings 3 | QBImagePicker 4 | 5 | Created by Katsuma Tanaka on 2015/04/03. 6 | Copyright (c) 2015 Katsuma Tanaka. All rights reserved. 7 | */ 8 | 9 | "albums.title" = "アルバム"; 10 | 11 | "assets.footer.photo" = "写真: %ld枚"; 12 | "assets.footer.photos" = "写真: %ld枚"; 13 | "assets.footer.video" = "ビデオ: %ld本"; 14 | "assets.footer.videos" = "ビデオ: %ld本"; 15 | "assets.footer.photo-and-video" = "写真: %ld枚、ビデオ%ld本"; 16 | "assets.footer.photos-and-video" = "写真: %ld枚、ビデオ%ld本"; 17 | "assets.footer.photo-and-videos" = "写真: %ld枚、ビデオ%ld本"; 18 | "assets.footer.photos-and-videos" = "写真: %ld枚、ビデオ%ld本"; 19 | 20 | "assets.toolbar.item-selected" = "%ld 項目を選択中"; 21 | "assets.toolbar.items-selected" = "%ld 項目を選択中"; 22 | 23 | "permission.help" = "選択した限られた数の写真とビデオに許可を与えました。"; 24 | "permission.manage" = "管理"; 25 | "permission.title" = "アプリ内のすべての写真にアクセスするには、デバイス設定でライブラリ全体へのアクセスを許可します。"; 26 | "permission.choose_more" = "写真をもっと選択"; 27 | "permission.change_settings" = "設定の変更"; 28 | "permission.cancel" = "キャンセル"; 29 | -------------------------------------------------------------------------------- /ios/QBImagePicker/QBImagePicker/ko.lproj/QBImagePicker.strings: -------------------------------------------------------------------------------- 1 | /* 2 | QBImagePicker.strings 3 | QBImagePicker 4 | 5 | Created by Katsuma Tanaka on 2015/04/03. 6 | Copyright (c) 2015 Katsuma Tanaka. All rights reserved. 7 | */ 8 | 9 | "albums.title" = "사진"; 10 | 11 | "assets.footer.photo" = "%ld 사진"; 12 | "assets.footer.photos" = "%ld 사진"; 13 | "assets.footer.video" = "%ld 비디오"; 14 | "assets.footer.videos" = "%ld 비디오"; 15 | "assets.footer.photo-and-video" = "%ld 사진, %ld 비디오"; 16 | "assets.footer.photos-and-video" = "%ld 사진, %ld 비디오"; 17 | "assets.footer.photo-and-videos" = "%ld 사진, %ld 비디오"; 18 | "assets.footer.photos-and-videos" = "%ld 사진, %ld 비디오"; 19 | 20 | "assets.toolbar.item-selected" = "%ld 선택된 아이템"; 21 | "assets.toolbar.items-selected" = "%ld 선택된 아이템"; 22 | 23 | "permission.help" = "선택한 사진 및 비디오의 제한된 수에 대한 권한을 부여했습니다."; 24 | "permission.manage" = "관리"; 25 | "permission.title" = "앱에 있는 모든 사진에 접근하려면 기기 설정에서 전체 보관함에 접근 권한을 부여하십시오."; 26 | "permission.choose_more" = "추가 사진 선택"; 27 | "permission.change_settings" = "설정 변경"; 28 | "permission.cancel" = "취소"; 29 | -------------------------------------------------------------------------------- /ios/QBImagePicker/QBImagePicker/nb.lproj/QBImagePicker.strings: -------------------------------------------------------------------------------- 1 | /* 2 | QBImagePicker.strings 3 | QBImagePicker 4 | 5 | Created by Katsuma Tanaka on 2015/04/03. 6 | Copyright (c) 2015 Katsuma Tanaka. All rights reserved. 7 | */ 8 | 9 | "albums.title" = "Bilder"; 10 | 11 | "assets.footer.photo" = "%ld bilde"; 12 | "assets.footer.photos" = "%ld bilder"; 13 | "assets.footer.video" = "%ld video"; 14 | "assets.footer.videos" = "%ld videoer"; 15 | "assets.footer.photo-and-video" = "%ld bilde, %ld video"; 16 | "assets.footer.photos-and-video" = "%ld bilder, %ld video"; 17 | "assets.footer.photo-and-videos" = "%ld bilde, %ld videoer"; 18 | "assets.footer.photos-and-videos" = "%ld bilder, %ld videoer"; 19 | 20 | "assets.toolbar.item-selected" = "%ld objekt valgt"; 21 | "assets.toolbar.items-selected" = "%ld objekter valgt"; 22 | 23 | "permission.help" = "Du har gitt tilgang til et begrenset utvalg av bilder og videoer."; 24 | "permission.manage" = "ENDRE"; 25 | "permission.title" = "For å gi tilgang til alle bildene dine i appen, må du gi full tilgang til biblioteket fra enhetsinnstillingene."; 26 | "permission.choose_more" = "Velg flere bilder"; 27 | "permission.change_settings" = "Endre innstillinger"; 28 | "permission.cancel" = "Avbryt"; 29 | -------------------------------------------------------------------------------- /ios/QBImagePicker/QBImagePicker/nl.lproj/QBImagePicker.strings: -------------------------------------------------------------------------------- 1 | /* 2 | QBImagePicker.strings 3 | QBImagePicker 4 | 5 | Created by Marijn Hosten on 2023/04/18. 6 | */ 7 | 8 | "albums.title" = "Fotos"; 9 | 10 | "assets.footer.photo" = "%ld Foto"; 11 | "assets.footer.photos" = "%ld Fotos"; 12 | "assets.footer.video" = "%ld Video"; 13 | "assets.footer.videos" = "%ld Videos"; 14 | "assets.footer.photo-and-video" = "%ld Foto, %ld Video"; 15 | "assets.footer.photos-and-video" = "%ld Fotos, %ld Video"; 16 | "assets.footer.photo-and-videos" = "%ld Foto, %ld Videos"; 17 | "assets.footer.photos-and-videos" = "%ld Fotos, %ld Videos"; 18 | 19 | "assets.toolbar.item-selected" = "%ld Item Geselecteerd"; 20 | "assets.toolbar.items-selected" = "%ld Items Geselecteerd"; 21 | 22 | "permission.help" = "U heeft toestemming gegeven om een gelimiteerd aantal fotos en videos te gebruiken."; 23 | "permission.manage" = "BEHEER"; 24 | "permission.title" = "Om toegang te hebben tot alle fotos moet u toestemming geven in de instellingen van uw toestel."; 25 | "permission.choose_more" = "Kies Meer Fotos"; 26 | "permission.change_settings" = "Wijzig Instellingen"; 27 | "permission.cancel" = "Annuleer"; 28 | -------------------------------------------------------------------------------- /ios/QBImagePicker/QBImagePicker/pl.lproj/QBImagePicker.strings: -------------------------------------------------------------------------------- 1 | /* 2 | QBImagePicker.strings 3 | QBImagePicker 4 | 5 | Created by Katsuma Tanaka on 2015/04/03. 6 | Copyright (c) 2015 Katsuma Tanaka. All rights reserved. 7 | */ 8 | 9 | "albums.title" = "Zdjęcia"; 10 | 11 | "assets.footer.photo" = "%ld zdjęcie"; 12 | "assets.footer.photos" = "Zdjęć: %ld"; 13 | "assets.footer.video" = "%ld wideo"; 14 | "assets.footer.videos" = "Wideo: %ld"; 15 | "assets.footer.photo-and-video" = "%ld zdjęcie, %ld wideo"; 16 | "assets.footer.photos-and-video" = "Zdjęć: %ld, %ld wideo"; 17 | "assets.footer.photo-and-videos" = "%ld zdjęcie, %ld wideo"; 18 | "assets.footer.photos-and-videos" = "Zdjęć: %ld, %ld wideo"; 19 | 20 | "assets.toolbar.item-selected" = "%ld zaznaczona rzecz"; 21 | "assets.toolbar.items-selected" = "Zaznaczonych rzeczy: %ld"; 22 | 23 | "permission.help" = "Zezwolono na ograniczoną liczbę wybranych zdjęć i filmów."; 24 | "permission.manage" = "ZARZĄDZAJ"; 25 | "permission.title" = "Aby uzyskać dostęp do wszystkich swoich zdjęć w aplikacji, zezwól na dostęp do pełnej biblioteki w ustawieniach urządzenia."; 26 | "permission.choose_more" = "Wybierz więcej zdjęć"; 27 | "permission.change_settings" = "Zmień ustawienia"; 28 | "permission.cancel" = "Anuluj"; 29 | -------------------------------------------------------------------------------- /ios/QBImagePicker/QBImagePicker/pt.lproj/QBImagePicker.strings: -------------------------------------------------------------------------------- 1 | /* 2 | QBImagePicker.strings 3 | QBImagePicker 4 | 5 | Created by Seungyeob Song on 2020/11/10. 6 | Copyright (c) 2020 Seungyeob Song. All rights reserved. 7 | */ 8 | 9 | "albums.title" = "Fotos"; 10 | 11 | "assets.footer.photo" = "%ld Foto"; 12 | "assets.footer.photos" = "%ld Fotos"; 13 | "assets.footer.video" = "%ld Vídeo"; 14 | "assets.footer.videos" = "%ld Vídeos"; 15 | "assets.footer.photo-and-video" = "%ld Foto, %ld Vídeo"; 16 | "assets.footer.photos-and-video" = "%ld Fotos, %ld Vídeo"; 17 | "assets.footer.photo-and-videos" = "%ld Foto, %ld Vídeos"; 18 | "assets.footer.photos-and-videos" = "%ld Fotos, %ld Vídeos"; 19 | 20 | "assets.toolbar.item-selected" = "%ld Item Selecionado"; 21 | "assets.toolbar.items-selected" = "%ld Itens Selecionados"; 22 | 23 | "permission.help" = "Você deu permissão a um número limitado de fotos e vídeos selecionados."; 24 | "permission.manage" = "GERENCIAR"; 25 | "permission.title" = "Para acessar todas as suas fotos no aplicativo, dê acesso à sua biblioteca completa nas configurações do dispositivo."; 26 | "permission.choose_more" = "Selecionar mais fotos"; 27 | "permission.change_settings" = "Alterar configurações"; 28 | "permission.cancel" = "Cancelar"; 29 | -------------------------------------------------------------------------------- /ios/QBImagePicker/QBImagePicker/ro.lproj/QBImagePicker.strings: -------------------------------------------------------------------------------- 1 | /* 2 | QBImagePicker.strings 3 | QBImagePicker 4 | 5 | Created by Anton Cojocaru on 2021/05/28. 6 | Copyright (c) 2021 Anton Cojocaru. All rights reserved. 7 | */ 8 | 9 | "albums.title" = "Poze"; 10 | 11 | "assets.footer.photo" = "%ld Poză"; 12 | "assets.footer.photos" = "%ld Poze"; 13 | "assets.footer.video" = "%ld Clip"; 14 | "assets.footer.videos" = "%ld Clipuri"; 15 | "assets.footer.photo-and-video" = "%ld Poză, %ld Clip"; 16 | "assets.footer.photos-and-video" = "%ld Poze, %ld Clip"; 17 | "assets.footer.photo-and-videos" = "%ld Poză, %ld Clipuri"; 18 | "assets.footer.photos-and-videos" = "%ld Poze, %ld Clipuri"; 19 | 20 | "assets.toolbar.item-selected" = "%ld Element Selectat"; 21 | "assets.toolbar.items-selected" = "%ld Elemente Selectate"; 22 | 23 | "permission.help" = "Ați acordat permisiunea unui număr limitat de fotografii și videoclipuri selectate."; 24 | "permission.manage" = "GESTIONARE"; 25 | "permission.title" = "Pentru a vă accesa toate fotografiile din aplicație, acordați acces la biblioteca completă în setările dispozitivului."; 26 | "permission.choose_more" = "Selectați mai multe fotografii"; 27 | "permission.change_settings" = "Schimbați setările"; 28 | "permission.cancel" = "Anulați"; 29 | -------------------------------------------------------------------------------- /ios/QBImagePicker/QBImagePicker/ru.lproj/QBImagePicker.strings: -------------------------------------------------------------------------------- 1 | /* 2 | QBImagePicker.strings 3 | QBImagePicker 4 | 5 | Created by Yaroslav Bunyaev on 2020/10/04. 6 | Copyright (c) 2020 Yaroslav Bunyaev. All rights reserved. 7 | */ 8 | 9 | "albums.title" = "Фотографии"; 10 | 11 | "assets.footer.photo" = "%ld Фото"; 12 | "assets.footer.photos" = "%ld Фото"; 13 | "assets.footer.video" = "%ld Видео"; 14 | "assets.footer.videos" = "%ld Видео"; 15 | "assets.footer.photo-and-video" = "%ld Фото, %ld Видео"; 16 | "assets.footer.photos-and-video" = "%ld Фото, %ld Видео"; 17 | "assets.footer.photo-and-videos" = "%ld Фото, %ld Видео"; 18 | "assets.footer.photos-and-videos" = "%ld Фото, %ld Видео"; 19 | 20 | "assets.toolbar.item-selected" = "%ld Элемент выбран"; 21 | "assets.toolbar.items-selected" = "%ld Элементы выбраны"; 22 | 23 | "permission.help" = "Вы дали разрешение на ограниченное количество выбранных фотографий и видео."; 24 | "permission.manage" = "УПРАВЛЕНИЕ"; 25 | "permission.title" = "Чтобы получить доступ ко всем своим фотографиям в приложении, предоставьте доступ к полной библиотеке в настройках устройства."; 26 | "permission.choose_more" = "Выбрать больше фотографий"; 27 | "permission.change_settings" = "Изменить настройки"; 28 | "permission.cancel" = "Отменить"; 29 | -------------------------------------------------------------------------------- /ios/QBImagePicker/QBImagePicker/sv.lproj/QBImagePicker.strings: -------------------------------------------------------------------------------- 1 | /* 2 | QBImagePicker.strings 3 | QBImagePicker 4 | 5 | Created by Marina Skripnik on 2021/10/07. 6 | Copyright (c) 2021 Marina Skripnik. All rights reserved. 7 | */ 8 | 9 | "albums.title" = "Bilder"; 10 | 11 | "assets.footer.photo" = "%ld Bild"; 12 | "assets.footer.photos" = "%ld Bilder"; 13 | "assets.footer.video" = "%ld Video"; 14 | "assets.footer.videos" = "%ld Videor"; 15 | "assets.footer.photo-and-video" = "%ld Bild, %ld Video"; 16 | "assets.footer.photos-and-video" = "%ld Bilder, %ld Video"; 17 | "assets.footer.photo-and-videos" = "%ld Bild, %ld Videor"; 18 | "assets.footer.photos-and-videos" = "%ld Bilder, %ld Videor"; 19 | 20 | "assets.toolbar.item-selected" = "%ld Markerad Objekt"; 21 | "assets.toolbar.items-selected" = "%ld Markerade Objekt"; 22 | 23 | "permission.help" = "Du har gett åtkomst till ett begränsat antal utvalda bilder och videor."; 24 | "permission.manage" = "HANTERA"; 25 | "permission.title" = "För att komma åt alla dina foton i appen, ge åtkomst till ditt fulla bibliotek i enhetens inställningar."; 26 | "permission.choose_more" = "Välj fler foton"; 27 | "permission.change_settings" = "Ändra inställningar"; 28 | "permission.cancel" = "Avbryt"; 29 | -------------------------------------------------------------------------------- /ios/QBImagePicker/QBImagePicker/tr.lproj/QBImagePicker.strings: -------------------------------------------------------------------------------- 1 | /* 2 | QBImagePicker.strings 3 | QBImagePicker 4 | 5 | Created by Katsuma Tanaka on 2015/04/03. 6 | Copyright (c) 2015 Katsuma Tanaka. All rights reserved. 7 | */ 8 | 9 | "albums.title" = "Fotoğraflar"; 10 | 11 | "assets.footer.photo" = "%ld Fotoğraf"; 12 | "assets.footer.photos" = "%ld Fotoğraf"; 13 | "assets.footer.video" = "%ld Video"; 14 | "assets.footer.videos" = "%ld Video"; 15 | "assets.footer.photo-and-video" = "%ld Fotoğraf, %ld Video"; 16 | "assets.footer.photos-and-video" = "%ld Fotoğraf, %ld Video"; 17 | "assets.footer.photo-and-videos" = "%ld Fotoğraf, %ld Video"; 18 | "assets.footer.photos-and-videos" = "%ld Fotoğraf, %ld Video"; 19 | 20 | "assets.toolbar.item-selected" = "%ld Adet Seçildi"; 21 | "assets.toolbar.items-selected" = "%ld Adet Seçildi"; 22 | 23 | "permission.help" = "Sınırlı sayıda seçili fotoğraf ve videoya izin verdiniz."; 24 | "permission.manage" = "YÖNET"; 25 | "permission.title" = "Uygulamadaki tüm fotoğraflarınıza erişmek için cihaz ayarlarından tam kitaplığınıza erişim izni verin."; 26 | "permission.choose_more" = "Daha Fazla Fotoğraf Seç"; 27 | "permission.change_settings" = "Ayarları Değiştir"; 28 | "permission.cancel" = "İptal"; 29 | -------------------------------------------------------------------------------- /ios/QBImagePicker/QBImagePicker/uk.lproj/QBImagePicker.strings: -------------------------------------------------------------------------------- 1 | /* 2 | QBImagePicker.strings 3 | QBImagePicker 4 | 5 | Created by Marina Skripnik on 2021/10/07. 6 | Copyright (c) 2021 Marina Skripnik. All rights reserved. 7 | */ 8 | 9 | "albums.title" = "Фотографії"; 10 | 11 | "assets.footer.photo" = "%ld Фото"; 12 | "assets.footer.photos" = "%ld Фото"; 13 | "assets.footer.video" = "%ld Відео"; 14 | "assets.footer.videos" = "%ld Відео"; 15 | "assets.footer.photo-and-video" = "%ld Фото, %ld Відео"; 16 | "assets.footer.photos-and-video" = "%ld Фото, %ld Відео"; 17 | "assets.footer.photo-and-videos" = "%ld Фото, %ld Відео"; 18 | "assets.footer.photos-and-videos" = "%ld Фото, %ld Відео"; 19 | 20 | "assets.toolbar.item-selected" = "Вибрано %ld Елемент"; 21 | "assets.toolbar.items-selected" = "Вибрано %ld Елементи"; 22 | 23 | "permission.help" = "Ви дали дозвіл на обмежену кількість вибраних фотографій і відео."; 24 | "permission.manage" = "КЕРУВАТИ"; 25 | "permission.title" = "Щоб отримати доступ до всіх своїх фотографій у програмі, надайте доступ до повної бібліотеки в налаштуваннях пристрою."; 26 | "permission.choose_more" = "Вибрати більше фотографій"; 27 | "permission.change_settings" = "Змінити налаштування"; 28 | "permission.cancel" = "Скасувати"; 29 | -------------------------------------------------------------------------------- /ios/QBImagePicker/QBImagePicker/vi.lproj/QBImagePicker.strings: -------------------------------------------------------------------------------- 1 | /* 2 | QBImagePicker.strings 3 | QBImagePicker 4 | 5 | Created by Pham Ngoc Thach on 2022/08/26. 6 | Copyright (c) 2022 Pham Ngoc Thach. All rights reserved. 7 | */ 8 | 9 | "albums.title" = "Ảnh"; 10 | 11 | "assets.footer.photo" = "%ld Ảnh"; 12 | "assets.footer.photos" = "%ld Ảnh"; 13 | "assets.footer.video" = "%ld Video"; 14 | "assets.footer.videos" = "%ld Video"; 15 | "assets.footer.photo-and-video" = "%ld Ảnh, %ld Video"; 16 | "assets.footer.photos-and-video" = "%ld Ảnh, %ld Video"; 17 | "assets.footer.photo-and-videos" = "%ld Ảnh, %ld Video"; 18 | "assets.footer.photos-and-videos" = "%ld Ảnh, %ld Video"; 19 | 20 | "assets.toolbar.item-selected" = "Đã chọn %ld mục"; 21 | "assets.toolbar.items-selected" = "Đã chọn %ld mục"; 22 | 23 | "permission.help" = "Bạn đã cấp quyền truy cập vào số lượng ảnh và video có hạn."; 24 | "permission.manage" = "QUẢN LÝ"; 25 | "permission.title" = "Để truy cập tất cả ảnh trong ứng dụng, hãy cấp quyền truy cập vào toàn bộ thư viện của bạn trong cài đặt thiết bị."; 26 | "permission.choose_more" = "Chọn Nhiều Ảnh"; 27 | "permission.change_settings" = "Đổi Cài đặt"; 28 | "permission.cancel" = "Hủy bỏ"; -------------------------------------------------------------------------------- /ios/QBImagePicker/QBImagePicker/zh-Hans.lproj/QBImagePicker.strings: -------------------------------------------------------------------------------- 1 | /* 2 | QBImagePicker.strings 3 | QBImagePicker 4 | 5 | Created by Katsuma Tanaka on 2015/04/03. 6 | Copyright (c) 2015 Katsuma Tanaka. All rights reserved. 7 | */ 8 | 9 | "albums.title" = "照片"; 10 | 11 | "assets.footer.photo" = "共%ld张照片"; 12 | "assets.footer.photos" = "共%ld张照片"; 13 | "assets.footer.video" = "共%ld个视频"; 14 | "assets.footer.videos" = "共%ld个视频"; 15 | "assets.footer.photo-and-video" = "共%ld 张照片, %ld 个视频"; 16 | "assets.footer.photos-and-video" = "共%ld 张照片, %ld 个视频"; 17 | "assets.footer.photo-and-videos" = "共%ld 张照片, %ld 个视频"; 18 | "assets.footer.photos-and-videos" = "共%ld 张照片, %ld 个视频"; 19 | 20 | "assets.toolbar.item-selected" = "选择了%ld项"; 21 | "assets.toolbar.items-selected" = "选择了%ld项"; 22 | 23 | "permission.help" = "您已授予有限数量的选定照片和视频的权限。"; 24 | "permission.manage" = "管理"; 25 | "permission.title" = "要访问您在应用程序中的所有照片,请在设备设置中授予访问您的完整图库的权限。"; 26 | "permission.choose_more" = "选择更多照片"; 27 | "permission.change_settings" = "更改设置"; 28 | "permission.cancel" = "取消"; 29 | -------------------------------------------------------------------------------- /ios/QBImagePicker/QBImagePicker/zh-Hant.lproj/QBImagePicker.strings: -------------------------------------------------------------------------------- 1 | /* 2 | QBImagePicker.strings 3 | QBImagePicker 4 | 5 | Created by Seungyeob Song on 2020/11/10. 6 | Copyright (c) 2020 Seungyeob Song. All rights reserved. 7 | */ 8 | 9 | "albums.title" = "照片"; 10 | 11 | "assets.footer.photo" = "共%ld張照片"; 12 | "assets.footer.photos" = "共%ld張照片"; 13 | "assets.footer.video" = "共%ld個視頻"; 14 | "assets.footer.videos" = "共%ld個視頻"; 15 | "assets.footer.photo-and-video" = "共%ld 張照片, %ld 個視頻"; 16 | "assets.footer.photos-and-video" = "共%ld 張照片, %ld 個視頻"; 17 | "assets.footer.photo-and-videos" = "共%ld 張照片, %ld 個視頻"; 18 | "assets.footer.photos-and-videos" = "共%ld 張照片, %ld 個視頻"; 19 | 20 | "assets.toolbar.item-selected" = "選擇了%ld項"; 21 | "assets.toolbar.items-selected" = "選擇了%ld項"; 22 | 23 | "permission.help" = "您已授予有限數量的選定照片和視頻的權限。"; 24 | "permission.manage" = "管理"; 25 | "permission.title" = "要訪問您在應用程序中的所有照片,請在設備設置中授予訪問您的完整圖庫的權限。"; 26 | "permission.choose_more" = "選擇更多照片"; 27 | "permission.change_settings" = "更改設置"; 28 | "permission.cancel" = "取消"; 29 | -------------------------------------------------------------------------------- /ios/QBImagePicker/QBImagePickerController.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "QBImagePickerController" 3 | s.version = "3.4.0" 4 | s.summary = "A clone of UIImagePickerController with multiple selection support." 5 | s.homepage = "https://github.com/questbeat/QBImagePicker" 6 | s.license = "MIT" 7 | s.author = { "questbeat" => "questbeat@gmail.com" } 8 | s.source = { :git => "https://github.com/questbeat/QBImagePicker.git", :tag => s.version.to_s } 9 | s.social_media_url = "https://twitter.com/questbeat" 10 | s.source_files = "QBImagePicker/*.{h,m}" 11 | s.exclude_files = "QBImagePicker/QBImagePicker.h" 12 | s.resource_bundles = { "QBImagePicker" => "QBImagePicker/*.{lproj,storyboard}" } 13 | s.platform = :ios, "8.0" 14 | s.requires_arc = true 15 | s.frameworks = "Photos" 16 | end 17 | -------------------------------------------------------------------------------- /ios/src/Compression.h: -------------------------------------------------------------------------------- 1 | // 2 | // Compression.h 3 | // imageCropPicker 4 | // 5 | // Created by Ivan Pusic on 12/24/16. 6 | // Copyright © 2016 Ivan Pusic. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | #import 12 | 13 | @interface ImageResult : NSObject 14 | 15 | @property NSData *data; 16 | @property NSNumber *width; 17 | @property NSNumber *height; 18 | @property NSString *mime; 19 | @property UIImage *image; 20 | 21 | @end 22 | 23 | @interface VideoResult : NSObject 24 | 25 | @end 26 | 27 | @interface Compression : NSObject 28 | 29 | - (ImageResult*) compressImage:(UIImage*)image withOptions:(NSDictionary*)options; 30 | - (void)compressVideo:(NSURL*)inputURL 31 | outputURL:(NSURL*)outputURL 32 | withOptions:(NSDictionary*)options 33 | handler:(void (^)(AVAssetExportSession*))handler; 34 | 35 | @property NSDictionary *exportPresets; 36 | 37 | @end 38 | -------------------------------------------------------------------------------- /ios/src/Compression.m: -------------------------------------------------------------------------------- 1 | // 2 | // Compression.m 3 | // imageCropPicker 4 | // 5 | // Created by Ivan Pusic on 12/24/16. 6 | // Copyright © 2016 Ivan Pusic. All rights reserved. 7 | // 8 | 9 | #import "Compression.h" 10 | 11 | @implementation Compression 12 | 13 | - (instancetype)init { 14 | NSMutableDictionary *dic = [[NSMutableDictionary alloc] initWithDictionary:@{ 15 | @"640x480": AVAssetExportPreset640x480, 16 | @"960x540": AVAssetExportPreset960x540, 17 | @"1280x720": AVAssetExportPreset1280x720, 18 | @"1920x1080": AVAssetExportPreset1920x1080, 19 | @"LowQuality": AVAssetExportPresetLowQuality, 20 | @"MediumQuality": AVAssetExportPresetMediumQuality, 21 | @"HighestQuality": AVAssetExportPresetHighestQuality, 22 | @"Passthrough": AVAssetExportPresetPassthrough, 23 | }]; 24 | 25 | if (@available(iOS 9.0, *)) { 26 | [dic addEntriesFromDictionary:@{@"3840x2160": AVAssetExportPreset3840x2160}]; 27 | } else { 28 | // Fallback on earlier versions 29 | } 30 | 31 | self.exportPresets = dic; 32 | 33 | return self; 34 | } 35 | 36 | - (ImageResult*) compressImageDimensions:(UIImage*)image 37 | compressImageMaxWidth:(CGFloat)maxWidth 38 | compressImageMaxHeight:(CGFloat)maxHeight 39 | intoResult:(ImageResult*)result { 40 | 41 | CGFloat oldWidth = image.size.width; 42 | CGFloat oldHeight = image.size.height; 43 | 44 | CGFloat widthScale = maxWidth / oldWidth; 45 | CGFloat heightScale = maxHeight / oldHeight; 46 | CGFloat scaleFactor = MIN(widthScale, heightScale); 47 | 48 | CGFloat newWidth = oldWidth * scaleFactor; 49 | CGFloat newHeight = oldHeight * scaleFactor; 50 | 51 | CGSize newSize = CGSizeMake(newWidth, newHeight); 52 | 53 | UIGraphicsImageRendererFormat *format = [[UIGraphicsImageRendererFormat alloc] init]; 54 | format.scale = image.scale; 55 | 56 | UIGraphicsImageRenderer *renderer = [[UIGraphicsImageRenderer alloc] initWithSize:newSize format:format]; 57 | UIImage *resizedImage = [renderer imageWithActions:^(UIGraphicsImageRendererContext * _Nonnull rendererContext) { 58 | [image drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)]; 59 | }]; 60 | 61 | result.width = @(newWidth); 62 | result.height = @(newHeight); 63 | result.image = resizedImage; 64 | 65 | return result; 66 | } 67 | 68 | - (ImageResult*) compressImage:(UIImage*)image 69 | withOptions:(NSDictionary*)options { 70 | 71 | ImageResult *result = [[ImageResult alloc] init]; 72 | result.width = @(image.size.width); 73 | result.height = @(image.size.height); 74 | result.image = image; 75 | result.mime = @"image/jpeg"; 76 | 77 | NSNumber *compressImageMaxWidth = [options valueForKey:@"compressImageMaxWidth"]; 78 | NSNumber *compressImageMaxHeight = [options valueForKey:@"compressImageMaxHeight"]; 79 | 80 | // determine if it is necessary to resize image 81 | BOOL shouldResizeWidth = (compressImageMaxWidth != nil && [compressImageMaxWidth floatValue] < image.size.width); 82 | BOOL shouldResizeHeight = (compressImageMaxHeight != nil && [compressImageMaxHeight floatValue] < image.size.height); 83 | 84 | if (shouldResizeWidth || shouldResizeHeight) { 85 | CGFloat maxWidth = compressImageMaxWidth != nil ? [compressImageMaxWidth floatValue] : image.size.width; 86 | CGFloat maxHeight = compressImageMaxHeight != nil ? [compressImageMaxHeight floatValue] : image.size.height; 87 | 88 | [self compressImageDimensions:image 89 | compressImageMaxWidth:maxWidth 90 | compressImageMaxHeight:maxHeight 91 | intoResult:result]; 92 | } 93 | 94 | // parse desired image quality 95 | NSNumber *compressQuality = [options valueForKey:@"compressImageQuality"]; 96 | if (compressQuality == nil) { 97 | compressQuality = [NSNumber numberWithFloat:0.8]; 98 | } 99 | 100 | // convert image to jpeg representation 101 | result.data = UIImageJPEGRepresentation(result.image, [compressQuality floatValue]); 102 | 103 | return result; 104 | } 105 | 106 | - (void)compressVideo:(NSURL*)inputURL 107 | outputURL:(NSURL*)outputURL 108 | withOptions:(NSDictionary*)options 109 | handler:(void (^)(AVAssetExportSession*))handler { 110 | 111 | NSString *presetKey = [options valueForKey:@"compressVideoPreset"]; 112 | if (presetKey == nil) { 113 | presetKey = @"MediumQuality"; 114 | } 115 | 116 | NSString *preset = [self.exportPresets valueForKey:presetKey]; 117 | if (preset == nil) { 118 | preset = AVAssetExportPresetMediumQuality; 119 | } 120 | 121 | [[NSFileManager defaultManager] removeItemAtURL:outputURL error:nil]; 122 | AVURLAsset *asset = [AVURLAsset URLAssetWithURL:inputURL options:nil]; 123 | AVAssetExportSession *exportSession = [[AVAssetExportSession alloc] initWithAsset:asset presetName:preset]; 124 | exportSession.shouldOptimizeForNetworkUse = YES; 125 | exportSession.outputURL = outputURL; 126 | exportSession.outputFileType = AVFileTypeMPEG4; 127 | 128 | [exportSession exportAsynchronouslyWithCompletionHandler:^(void) { 129 | handler(exportSession); 130 | }]; 131 | } 132 | 133 | @end 134 | -------------------------------------------------------------------------------- /ios/src/ImageCropPicker.h: -------------------------------------------------------------------------------- 1 | // 2 | // ImageManager.h 3 | // 4 | // Created by Ivan Pusic on 5/4/16. 5 | // Copyright © 2016 Facebook. All rights reserved. 6 | // 7 | 8 | #ifndef RN_IMAGE_CROP_PICKER_h 9 | #define RN_IMAGE_CROP_PICKER_h 10 | 11 | #import 12 | 13 | #if __has_include() 14 | #import 15 | #import 16 | #import 17 | #import 18 | #import 19 | #else 20 | #import "RCTBridgeModule.h" 21 | #import "RCTImageURLLoader.h" 22 | #import "RCTImageShadowView.h" 23 | #import "RCTImageView.h" 24 | #import "RCTImageLoaderProtocol.h" 25 | #endif 26 | 27 | #ifdef RCT_NEW_ARCH_ENABLED 28 | #import 29 | #endif 30 | 31 | #if __has_include("QBImagePicker.h") 32 | #import "QBImagePicker.h" 33 | #elif __has_include() 34 | #import 35 | #elif __has_include("QBImagePickerController.h") // local QBImagePickerController subspec 36 | #import "QBImagePickerController.h" 37 | #else 38 | #import "QBImagePicker/QBImagePicker.h" 39 | #endif 40 | 41 | 42 | #import 43 | 44 | #import "UIImage+Resize.h" 45 | #import "UIImage+Extension.h" 46 | #import "Compression.h" 47 | #import 48 | 49 | @interface ImageCropPicker : NSObject< 50 | UIImagePickerControllerDelegate, 51 | UINavigationControllerDelegate, 52 | RCTBridgeModule, 53 | QBImagePickerControllerDelegate, 54 | TOCropViewControllerDelegate> 55 | 56 | typedef enum selectionMode { 57 | CAMERA, 58 | CROPPING, 59 | PICKER 60 | } SelectionMode; 61 | 62 | @property (nonatomic, strong) NSMutableDictionary *croppingFile; 63 | @property (nonatomic, strong) NSDictionary *defaultOptions; 64 | @property (nonatomic, strong) Compression *compression; 65 | @property (nonatomic, retain) NSMutableDictionary *options; 66 | @property (nonatomic, strong) RCTPromiseResolveBlock resolve; 67 | @property (nonatomic, strong) RCTPromiseRejectBlock reject; 68 | @property SelectionMode currentSelectionMode; 69 | 70 | @end 71 | 72 | #endif 73 | -------------------------------------------------------------------------------- /ios/src/UIImage+Extension.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIImage+Extension.h 3 | // Pods 4 | // 5 | // Created by Ivan Pusic on 09/05/2020. 6 | // 7 | 8 | #ifndef UIImage_Extension_h 9 | #define UIImage_Extension_h 10 | 11 | #import 12 | 13 | @interface UIImage (fixOrientation) 14 | 15 | - (UIImage *)fixOrientation; 16 | 17 | @end 18 | 19 | #endif /* UIImage_Extension_h */ 20 | -------------------------------------------------------------------------------- /ios/src/UIImage+Extension.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIImage+Extension.m 3 | // DoubleConversion 4 | // 5 | // Created by Ivan Pusic on 09/05/2020. 6 | // 7 | 8 | #import "UIImage+Extension.h" 9 | 10 | @implementation UIImage (fixOrientation) 11 | 12 | - (UIImage *)fixOrientation 13 | { 14 | // No-op if the orientation is already correct. 15 | if (self.imageOrientation == UIImageOrientationUp) { 16 | return self; 17 | } 18 | 19 | // We need to calculate the proper transformation to make the image upright. 20 | // We do it in 2 steps: Rotate if Left/Right/Down, and then flip if Mirrored. 21 | CGAffineTransform transform = CGAffineTransformIdentity; 22 | 23 | switch (self.imageOrientation) { 24 | case UIImageOrientationDown: 25 | case UIImageOrientationDownMirrored: 26 | transform = CGAffineTransformTranslate(transform, self.size.width, self.size.height); 27 | transform = CGAffineTransformRotate(transform, M_PI); 28 | break; 29 | 30 | case UIImageOrientationLeft: 31 | case UIImageOrientationLeftMirrored: 32 | transform = CGAffineTransformTranslate(transform, self.size.width, 0); 33 | transform = CGAffineTransformRotate(transform, M_PI_2); 34 | break; 35 | 36 | case UIImageOrientationRight: 37 | case UIImageOrientationRightMirrored: 38 | transform = CGAffineTransformTranslate(transform, 0, self.size.height); 39 | transform = CGAffineTransformRotate(transform, -M_PI_2); 40 | break; 41 | case UIImageOrientationUp: 42 | case UIImageOrientationUpMirrored: 43 | break; 44 | } 45 | 46 | switch (self.imageOrientation) { 47 | case UIImageOrientationUpMirrored: 48 | case UIImageOrientationDownMirrored: 49 | transform = CGAffineTransformTranslate(transform, self.size.width, 0); 50 | transform = CGAffineTransformScale(transform, -1, 1); 51 | break; 52 | 53 | case UIImageOrientationLeftMirrored: 54 | case UIImageOrientationRightMirrored: 55 | transform = CGAffineTransformTranslate(transform, self.size.height, 0); 56 | transform = CGAffineTransformScale(transform, -1, 1); 57 | break; 58 | case UIImageOrientationUp: 59 | case UIImageOrientationDown: 60 | case UIImageOrientationLeft: 61 | case UIImageOrientationRight: 62 | break; 63 | } 64 | 65 | // Now we draw the underlying CGImage into a new context, applying the transform 66 | // calculated above. 67 | CGContextRef ctx = CGBitmapContextCreate(NULL, self.size.width, self.size.height, 68 | CGImageGetBitsPerComponent(self.CGImage), 0, 69 | CGImageGetColorSpace(self.CGImage), 70 | CGImageGetBitmapInfo(self.CGImage)); 71 | CGContextConcatCTM(ctx, transform); 72 | switch (self.imageOrientation) { 73 | case UIImageOrientationLeft: 74 | case UIImageOrientationLeftMirrored: 75 | case UIImageOrientationRight: 76 | case UIImageOrientationRightMirrored: 77 | CGContextDrawImage(ctx, CGRectMake(0, 0, self.size.height, self.size.width), self.CGImage); 78 | break; 79 | 80 | default: 81 | CGContextDrawImage(ctx, CGRectMake(0, 0, self.size.width, self.size.height), self.CGImage); 82 | break; 83 | } 84 | 85 | // And now we just create a new UIImage from the drawing context. 86 | CGImageRef cgimg = CGBitmapContextCreateImage(ctx); 87 | UIImage *img = [UIImage imageWithCGImage:cgimg]; 88 | CGContextRelease(ctx); 89 | CGImageRelease(cgimg); 90 | 91 | return img; 92 | } 93 | 94 | @end 95 | -------------------------------------------------------------------------------- /ios/src/UIImage+Resize.h: -------------------------------------------------------------------------------- 1 | /*********************************************************************************** 2 | * 3 | * Copyright (c) 2010 Olivier Halligon 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | * 23 | *********************************************************************************** 24 | * 25 | * Any comment or suggestion welcome. Referencing this project in your AboutBox is appreciated. 26 | * Please tell me if you use this class so we can cross-reference our projects. 27 | * 28 | ***********************************************************************************/ 29 | 30 | 31 | #import 32 | #import 33 | 34 | @interface UIImage(ResizeCategory) 35 | -(UIImage*)resizedImageToSize:(CGSize)dstSize; 36 | -(UIImage*)resizedImageToFitInSize:(CGSize)boundingSize scaleIfSmaller:(BOOL)scale; 37 | @end 38 | -------------------------------------------------------------------------------- /ios/src/UIImage+Resize.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIImage+Resize.m 3 | // 4 | // Created by Olivier Halligon on 12/08/09. 5 | // Copyright 2009 AliSoftware. All rights reserved. 6 | // 7 | 8 | #import "UIImage+Resize.h" 9 | 10 | @implementation UIImage (ResizeCategory) 11 | 12 | -(UIImage*)resizedImageToSize:(CGSize)dstSize 13 | { 14 | CGImageRef imgRef = self.CGImage; 15 | // the below values are regardless of orientation : for UIImages from Camera, width>height (landscape) 16 | CGSize srcSize = CGSizeMake(CGImageGetWidth(imgRef), CGImageGetHeight(imgRef)); // not equivalent to self.size (which is dependant on the imageOrientation)! 17 | 18 | /* Don't resize if we already meet the required destination size. */ 19 | if (CGSizeEqualToSize(srcSize, dstSize)) { 20 | return self; 21 | } 22 | 23 | CGFloat scaleRatio = dstSize.width / srcSize.width; 24 | UIImageOrientation orient = self.imageOrientation; 25 | CGAffineTransform transform = CGAffineTransformIdentity; 26 | switch(orient) { 27 | 28 | case UIImageOrientationUp: //EXIF = 1 29 | transform = CGAffineTransformIdentity; 30 | break; 31 | 32 | case UIImageOrientationUpMirrored: //EXIF = 2 33 | transform = CGAffineTransformMakeTranslation(srcSize.width, 0.0); 34 | transform = CGAffineTransformScale(transform, -1.0, 1.0); 35 | break; 36 | 37 | case UIImageOrientationDown: //EXIF = 3 38 | transform = CGAffineTransformMakeTranslation(srcSize.width, srcSize.height); 39 | transform = CGAffineTransformRotate(transform, M_PI); 40 | break; 41 | 42 | case UIImageOrientationDownMirrored: //EXIF = 4 43 | transform = CGAffineTransformMakeTranslation(0.0, srcSize.height); 44 | transform = CGAffineTransformScale(transform, 1.0, -1.0); 45 | break; 46 | 47 | case UIImageOrientationLeftMirrored: //EXIF = 5 48 | dstSize = CGSizeMake(dstSize.height, dstSize.width); 49 | transform = CGAffineTransformMakeTranslation(srcSize.height, srcSize.width); 50 | transform = CGAffineTransformScale(transform, -1.0, 1.0); 51 | transform = CGAffineTransformRotate(transform, 3.0 * M_PI_2); 52 | break; 53 | 54 | case UIImageOrientationLeft: //EXIF = 6 55 | dstSize = CGSizeMake(dstSize.height, dstSize.width); 56 | transform = CGAffineTransformMakeTranslation(0.0, srcSize.width); 57 | transform = CGAffineTransformRotate(transform, 3.0 * M_PI_2); 58 | break; 59 | 60 | case UIImageOrientationRightMirrored: //EXIF = 7 61 | dstSize = CGSizeMake(dstSize.height, dstSize.width); 62 | transform = CGAffineTransformMakeScale(-1.0, 1.0); 63 | transform = CGAffineTransformRotate(transform, M_PI_2); 64 | break; 65 | 66 | case UIImageOrientationRight: //EXIF = 8 67 | dstSize = CGSizeMake(dstSize.height, dstSize.width); 68 | transform = CGAffineTransformMakeTranslation(srcSize.height, 0.0); 69 | transform = CGAffineTransformRotate(transform, M_PI_2); 70 | break; 71 | 72 | default: 73 | [NSException raise:NSInternalInconsistencyException format:@"Invalid image orientation"]; 74 | 75 | } 76 | 77 | ///////////////////////////////////////////////////////////////////////////// 78 | // The actual resize: draw the image on a new context, applying a transform matrix 79 | UIGraphicsBeginImageContextWithOptions(dstSize, NO, self.scale); 80 | 81 | CGContextRef context = UIGraphicsGetCurrentContext(); 82 | 83 | if (!context) { 84 | return nil; 85 | } 86 | 87 | if (orient == UIImageOrientationRight || orient == UIImageOrientationLeft) { 88 | CGContextScaleCTM(context, -scaleRatio, scaleRatio); 89 | CGContextTranslateCTM(context, -srcSize.height, 0); 90 | } else { 91 | CGContextScaleCTM(context, scaleRatio, -scaleRatio); 92 | CGContextTranslateCTM(context, 0, -srcSize.height); 93 | } 94 | 95 | CGContextConcatCTM(context, transform); 96 | 97 | // we use srcSize (and not dstSize) as the size to specify is in user space (and we use the CTM to apply a scaleRatio) 98 | CGContextDrawImage(UIGraphicsGetCurrentContext(), CGRectMake(0, 0, srcSize.width, srcSize.height), imgRef); 99 | UIImage* resizedImage = UIGraphicsGetImageFromCurrentImageContext(); 100 | UIGraphicsEndImageContext(); 101 | 102 | return resizedImage; 103 | } 104 | 105 | 106 | 107 | ///////////////////////////////////////////////////////////////////////////// 108 | 109 | 110 | 111 | -(UIImage*)resizedImageToFitInSize:(CGSize)boundingSize scaleIfSmaller:(BOOL)scale 112 | { 113 | // get the image size (independant of imageOrientation) 114 | CGImageRef imgRef = self.CGImage; 115 | CGSize srcSize = CGSizeMake(CGImageGetWidth(imgRef), CGImageGetHeight(imgRef)); // not equivalent to self.size (which depends on the imageOrientation)! 116 | 117 | // adjust boundingSize to make it independant on imageOrientation too for farther computations 118 | UIImageOrientation orient = self.imageOrientation; 119 | switch (orient) { 120 | case UIImageOrientationLeft: 121 | case UIImageOrientationRight: 122 | case UIImageOrientationLeftMirrored: 123 | case UIImageOrientationRightMirrored: 124 | boundingSize = CGSizeMake(boundingSize.height, boundingSize.width); 125 | break; 126 | default: 127 | // NOP 128 | break; 129 | } 130 | 131 | // Compute the target CGRect in order to keep aspect-ratio 132 | CGSize dstSize; 133 | 134 | if ( !scale && (srcSize.width < boundingSize.width) && (srcSize.height < boundingSize.height) ) { 135 | //NSLog(@"Image is smaller, and we asked not to scale it in this case (scaleIfSmaller:NO)"); 136 | dstSize = srcSize; // no resize (we could directly return 'self' here, but we draw the image anyway to take image orientation into account) 137 | } else { 138 | CGFloat wRatio = boundingSize.width / srcSize.width; 139 | CGFloat hRatio = boundingSize.height / srcSize.height; 140 | 141 | if (wRatio < hRatio) { 142 | //NSLog(@"Width imposed, Height scaled ; ratio = %f",wRatio); 143 | dstSize = CGSizeMake(boundingSize.width, floorf(srcSize.height * wRatio)); 144 | } else { 145 | //NSLog(@"Height imposed, Width scaled ; ratio = %f",hRatio); 146 | dstSize = CGSizeMake(floorf(srcSize.width * hRatio), boundingSize.height); 147 | } 148 | } 149 | 150 | return [self resizedImageToSize:dstSize]; 151 | } 152 | 153 | @end 154 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-native-image-crop-picker", 3 | "version": "0.50.1", 4 | "description": "Select single or multiple images, with cropping option", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "prepublish": "rm -rf android/build" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/ivpusic/react-native-image-crop-picker.git" 13 | }, 14 | "keywords": [ 15 | "react", 16 | "native", 17 | "react-native", 18 | "image", 19 | "picker", 20 | "crop", 21 | "cropping", 22 | "multiple", 23 | "camera" 24 | ], 25 | "author": "Ivan Pusic", 26 | "license": "MIT", 27 | "bugs": { 28 | "url": "https://github.com/ivpusic/react-native-image-crop-picker/issues" 29 | }, 30 | "homepage": "https://github.com/ivpusic/react-native-image-crop-picker#readme", 31 | "peerDependencies": { 32 | "react": "*", 33 | "react-native": "*" 34 | }, 35 | "codegenConfig": { 36 | "name": "RNCImageCropPickerSpec", 37 | "type": "modules", 38 | "jsSrcsDir": "src", 39 | "android": { 40 | "javaPackageName": "com.reactnative.ivpusic.imagepicker" 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/NativeImageCropPicker.ts: -------------------------------------------------------------------------------- 1 | import { TurboModule, TurboModuleRegistry } from "react-native"; 2 | 3 | export type PickerResponse = { 4 | path: string; 5 | localIdentifier?: string; 6 | sourceURL?: string; 7 | filename?: string; 8 | width: number; 9 | height: number; 10 | mime: string; 11 | size: number; 12 | duration?: number; 13 | data?: string; 14 | exif?: { 15 | [key: string]: string; 16 | }; 17 | cropRect?: { 18 | width: number; 19 | height: number; 20 | x: number; 21 | y: number; 22 | }; 23 | creationDate?: string; 24 | modificationDate?: string; 25 | }; 26 | 27 | export type PickerOptions = { 28 | mediaType?: string; 29 | multiple?: boolean; 30 | includeBase64?: boolean; 31 | includeExif?: boolean; 32 | cropping?: boolean; 33 | width?: number; 34 | height?: number; 35 | cropperActiveWidgetColor?: string; 36 | cropperStatusBarColor?: string; 37 | cropperToolbarColor?: string; 38 | cropperToolbarTitle?: string; 39 | cropperToolbarWidgetColor?: string; 40 | cropperCircleOverlay?: boolean; 41 | freeStyleCropEnabled?: boolean; 42 | showCropGuidelines?: boolean; 43 | showCropFrame?: boolean; 44 | hideBottomControls?: boolean; 45 | enableRotationGesture?: boolean; 46 | disableCropperColorSetters?: boolean; 47 | useFrontCamera?: boolean; 48 | }; 49 | 50 | export interface Spec extends TurboModule { 51 | openPicker(options: PickerOptions): Promise; 52 | openCamera(options: PickerOptions): Promise; 53 | openCropper(options: PickerOptions): Promise; 54 | clean(): Promise; 55 | cleanSingle(path: string): Promise; 56 | } 57 | 58 | export default TurboModuleRegistry.getEnforcing( 59 | "RNCImageCropPicker" 60 | ) as Spec; 61 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | --------------------------------------------------------------------------------