Compare commits

...

429 Commits

Author SHA1 Message Date
Marcos Rodriguez Vélez
3e04f6156d
Update RNCamera.m 2020-11-15 00:01:11 -05:00
Marcos Rodriguez Vélez
c307142c9d Add If/endif for Catalyst 2020-11-13 23:49:37 -05:00
Marcos Rodriguez Vélez
3467454fcf Add If/EndIf for Catalyst 2020-11-13 23:49:37 -05:00
Felippe Rodrigo Puhle
42388be530
Merge pull request #3005 from doranteseduardo/master
Fixed documentation URL
2020-10-20 17:06:53 -03:00
Eduardo Dorantes
4b65edfe84 Fixed documentation URL 2020-10-19 21:18:59 -05:00
Sibelius Seraphini
d973dbaab6
improve 2020-10-14 10:15:37 -03:00
Sibelius Seraphini
b01531189a
Looking for Maintainers 2020-10-14 10:15:14 -03:00
semantic-release-bot
819ba0d526 chore(release): 3.40.0 [skip ci]
# [3.40.0](https://github.com/react-native-community/react-native-camera/compare/v3.39.1...v3.40.0) (2020-09-18)

### Features

* **ios:** Optimize invertColors / fix memory leak ([#2955](https://github.com/react-native-community/react-native-camera/issues/2955)) ([43f2a0f](43f2a0f774)), closes [#2904](https://github.com/react-native-community/react-native-camera/issues/2904) [#2950](https://github.com/react-native-community/react-native-camera/issues/2950)
2020-09-18 14:43:23 +00:00
stanleykerr
43f2a0f774
feat(ios): Optimize invertColors / fix memory leak (#2955)
Releases the CGImage that was created in order to populate the UIImage's CGImage property. This probably relates to #2904 and possibly #2950.
2020-09-18 11:41:27 -03:00
dependabot[bot]
90ec544cd2
chore(deps): bump logkitty in /examples/advanced/advanced (#2976)
Bumps [logkitty](https://github.com/zamotany/logkitty) from 0.6.1 to 0.7.1.
- [Release notes](https://github.com/zamotany/logkitty/releases)
- [Commits](https://github.com/zamotany/logkitty/compare/v0.6.1...v0.7.1)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-09-18 07:55:25 -03:00
semantic-release-bot
5c1187ed42 chore(release): 3.39.1 [skip ci]
## [3.39.1](https://github.com/react-native-community/react-native-camera/compare/v3.39.0...v3.39.1) (2020-09-17)

### Bug Fixes

* Xcode 12 compatibility ([#2975](https://github.com/react-native-community/react-native-camera/issues/2975)) ([1e7152e](1e7152e179))
2020-09-17 15:10:17 +00:00
Radek Czemerys
1e7152e179
fix: Xcode 12 compatibility (#2975) 2020-09-17 12:07:03 -03:00
semantic-release-bot
d5e74c05ed chore(release): 3.39.0 [skip ci]
# [3.39.0](https://github.com/react-native-community/react-native-camera/compare/v3.38.0...v3.39.0) (2020-09-08)

### Features

* **upgrade:** upgrade deps ([#2967](https://github.com/react-native-community/react-native-camera/issues/2967)) ([1d876ef](1d876ef5eb))
2020-09-08 17:30:32 +00:00
dependabot[bot]
bde54e0559
chore(deps): bump handlebars in /examples/advanced/advanced (#2968)
Bumps [handlebars](https://github.com/wycats/handlebars.js) from 4.5.2 to 4.7.6.
- [Release notes](https://github.com/wycats/handlebars.js/releases)
- [Changelog](https://github.com/handlebars-lang/handlebars.js/blob/master/release-notes.md)
- [Commits](https://github.com/wycats/handlebars.js/compare/v4.5.2...v4.7.6)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-09-08 14:28:42 -03:00
Sibelius Seraphini
1d876ef5eb
feat(upgrade): upgrade deps (#2967)
* feat(upgrade): upgrade deps

* feat(key): add missing debug keystore
2020-09-08 14:28:20 -03:00
dependabot[bot]
a6a7a9be1b
chore(deps): bump decompress from 4.2.0 to 4.2.1 in /website (#2962)
Bumps [decompress](https://github.com/kevva/decompress) from 4.2.0 to 4.2.1.
- [Release notes](https://github.com/kevva/decompress/releases)
- [Commits](https://github.com/kevva/decompress/compare/v4.2.0...v4.2.1)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-09-08 09:49:23 -03:00
dependabot[bot]
27dbe43ad3
chore(deps): bump @hapi/hoek in /examples/advanced/advanced (#2965)
Bumps [@hapi/hoek](https://github.com/hapijs/hoek) from 8.5.0 to 8.5.1.
- [Release notes](https://github.com/hapijs/hoek/releases)
- [Commits](https://github.com/hapijs/hoek/compare/v8.5.0...v8.5.1)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-09-08 09:49:11 -03:00
semantic-release-bot
641ae7525c chore(release): 3.38.0 [skip ci]
# [3.38.0](https://github.com/react-native-community/react-native-camera/compare/v3.37.0...v3.38.0) (2020-09-02)

### Features

* **windows:** updates for RNW 0.63 ([#2960](https://github.com/react-native-community/react-native-camera/issues/2960)) ([b990a24](https://github.com/react-native-community/react-native-camera/commit/b990a24)), closes [#2942](https://github.com/react-native-community/react-native-camera/issues/2942) [#2944](https://github.com/react-native-community/react-native-camera/issues/2944)
2020-09-02 01:26:22 +00:00
Jon Thysell
b990a2465c
feat(windows): updates for RNW 0.63 (#2960)
Build:
* Updated huycn.zxingcpp.winrt to v1.1.0, enables ARM64 build on RNW >=
  0.61
* Updated ReactNativeCameraCPP.sln with RNW 0.63 dependencies
* Added ReactNativeCameraCPP62.sln for building against RNW 0.62
* Cleaned up ReactNativeCameraCPP61.sln for building against RNW 0.61

ReactNativeCamera RNCamera component:
* Passing unspecified maxDuration to recordAsync no longer stops
  recording immediately

Documentation:
* Updated installation docs for RNW 0.63 auto-linking

Closes #2942, #2944
2020-09-01 22:24:04 -03:00
semantic-release-bot
f4f6352392 chore(release): 3.37.0 [skip ci]
# [3.37.0](https://github.com/react-native-community/react-native-camera/compare/v3.36.0...v3.37.0) (2020-08-21)

### Bug Fixes

* **android:** Fix camera parameters getting lost on setting focus. ([#2946](https://github.com/react-native-community/react-native-camera/issues/2946)) ([4763777](https://github.com/react-native-community/react-native-camera/commit/4763777))

### Features

* **android:** Document `pictureSize` and make sure Camera1 implementation uses it appropriately. ([#2945](https://github.com/react-native-community/react-native-camera/issues/2945)) ([628c416](https://github.com/react-native-community/react-native-camera/commit/628c416))
* **ios:** Reset cached exposure limits to avoid a crash. ([#2948](https://github.com/react-native-community/react-native-camera/issues/2948)) ([7109ac7](https://github.com/react-native-community/react-native-camera/commit/7109ac7))
2020-08-21 11:22:07 +00:00
cristianoccazinsp
7109ac7ab1
feat(ios): Reset cached exposure limits to avoid a crash. (#2948)
Add exception handling to exposure updates just in case.

Co-authored-by: Cristiano Coelho <cristianocca@hotmail.com>
2020-08-21 08:19:21 -03:00
cristianoccazinsp
47637774a1
fix(android): Fix camera parameters getting lost on setting focus. (#2946)
* Fix camera parameters getting lost on setting focus.

* merge error

Co-authored-by: Cristiano Coelho <cristianocca@hotmail.com>
2020-08-21 08:18:55 -03:00
cristianoccazinsp
628c4162e1
feat(android): Document pictureSize and make sure Camera1 implementation uses it appropriately. (#2945)
Co-authored-by: Cristiano Coelho <cristianocca@hotmail.com>
2020-08-21 08:18:34 -03:00
semantic-release-bot
d7092048ff chore(release): 3.36.0 [skip ci]
# [3.36.0](https://github.com/react-native-community/react-native-camera/compare/v3.35.0...v3.36.0) (2020-08-11)

### Features

* **windows:** added barcode scanning support ([#2930](https://github.com/react-native-community/react-native-camera/issues/2930)) ([2782a24](https://github.com/react-native-community/react-native-camera/commit/2782a24)), closes [#2830](https://github.com/react-native-community/react-native-camera/issues/2830)
2020-08-11 18:59:08 +00:00
dependabot[bot]
5a3af65773
chore(deps): bump prismjs from 1.16.0 to 1.21.0 in /website (#2939)
Bumps [prismjs](https://github.com/PrismJS/prism) from 1.16.0 to 1.21.0.
- [Release notes](https://github.com/PrismJS/prism/releases)
- [Changelog](https://github.com/PrismJS/prism/blob/master/CHANGELOG.md)
- [Commits](https://github.com/PrismJS/prism/compare/v1.16.0...v1.21.0)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-08-11 15:57:16 -03:00
Jon Thysell
2782a24d25
feat(windows): added barcode scanning support (#2930)
Build:
* Fixed issue with edit and continue debug symbols
* Fixed ReactNativeCameraCPP61 builds
* Added dependency on huycn.zxingcpp.winrt for barcode support

ReactNativeCameraCPP RNCamera component:
* Added onBarCodeRead event support
* Added barCodeScannerEnabled property support
* Added barCodeTypes property support
* Added barCodeReadIntervalMS property to alter how often the scan
  occurs when enabled

ReactNativeCameraCPP RNCamera module:
* Added BarCodeType constants

Other:
* Fixed intermittent issue with thread marshalling
* Re-ran clang formatting

Closes #2830
2020-08-11 15:57:00 -03:00
semantic-release-bot
bec91a4b5a chore(release): 3.35.0 [skip ci]
# [3.35.0](https://github.com/react-native-community/react-native-camera/compare/v3.34.0...v3.35.0) (2020-07-23)

### Features

* **android:** use FOCUS_MODE_MACRO if FOCUS_MODE_CONTINOUS_PICTURE is not available and device is scanning ([#2912](https://github.com/react-native-community/react-native-camera/issues/2912)) ([20c62fb](https://github.com/react-native-community/react-native-camera/commit/20c62fb))
2020-07-23 17:07:52 +00:00
SimonErm
20c62fb972
feat(android): use FOCUS_MODE_MACRO if FOCUS_MODE_CONTINOUS_PICTURE is not available and device is scanning (#2912)
Co-authored-by: sermler <s.ermler@evosec.de>
2020-07-23 14:06:29 -03:00
semantic-release-bot
5a27a361fd chore(release): 3.34.0 [skip ci]
# [3.34.0](https://github.com/react-native-community/react-native-camera/compare/v3.33.0...v3.34.0) (2020-07-23)

### Features

* **android:** onBarCodeRead should also send raw photo bytes, fixed [#2786](https://github.com/react-native-community/react-native-camera/issues/2786) ([#2923](https://github.com/react-native-community/react-native-camera/issues/2923)) ([0df72c3](https://github.com/react-native-community/react-native-camera/commit/0df72c3))
2020-07-23 17:06:08 +00:00
Hendy Irawan
0df72c3114
feat(android): onBarCodeRead should also send raw photo bytes, fixed #2786 (#2923)
* feat: onBarCodeRead should also send raw photo bytes, fixed #2786

* docs: documentation to explain feature #2786
2020-07-23 14:04:18 -03:00
semantic-release-bot
c3159aa374 chore(release): 3.33.0 [skip ci]
# [3.33.0](https://github.com/react-native-community/react-native-camera/compare/v3.32.0...v3.33.0) (2020-07-21)

### Features

* **android:** Added pause and resume recording ([#2911](https://github.com/react-native-community/react-native-camera/issues/2911)) ([360a5b0](https://github.com/react-native-community/react-native-camera/commit/360a5b0))
2020-07-21 21:36:27 +00:00
Pradeep S Asundi
360a5b0ce2
feat(android): Added pause and resume recording (#2911)
* Added pause and resume recording functionality for android version 24 onwards

* Added pause and resume recording functions to Camera1.java

Co-authored-by: Pradeep Asundi <pradeep@asundi.in>
2020-07-21 18:32:33 -03:00
semantic-release-bot
951fcbd397 chore(release): 3.32.0 [skip ci]
# [3.32.0](https://github.com/react-native-community/react-native-camera/compare/v3.31.1...v3.32.0) (2020-07-17)

### Features

* **windows:** updated for react-native-windows 0.62 ([#2882](https://github.com/react-native-community/react-native-camera/issues/2882)) ([93e6581](https://github.com/react-native-community/react-native-camera/commit/93e6581))
2020-07-17 15:05:43 +00:00
dependabot[bot]
0d90e84848
chore(deps): bump lodash from 4.17.15 to 4.17.19 in /examples/tests (#2902)
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.15 to 4.17.19.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.15...4.17.19)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-07-17 12:00:46 -03:00
dependabot[bot]
e78242b038
chore(deps): bump lodash from 4.17.15 to 4.17.19 in /examples/mlkit (#2900)
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.15 to 4.17.19.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.15...4.17.19)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-07-17 12:00:20 -03:00
dependabot[bot]
2d7985a46f
chore(deps): bump lodash in /examples/advanced/advanced (#2903)
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.15 to 4.17.19.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.15...4.17.19)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-07-17 11:59:49 -03:00
dependabot[bot]
f3d6d7db19
chore(deps): bump lodash from 4.17.14 to 4.17.19 in /examples/basic (#2899)
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.14 to 4.17.19.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.14...4.17.19)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-07-17 11:59:34 -03:00
Jon Thysell
93e6581cde
feat(windows): updated for react-native-windows 0.62 (#2882)
Build:
* Updated ReactNativeCameraCPP projects to use the new RNW lib props/targets provided in 0.62 for easier upgrades
* Added new ReactNativeCameraCPP solution and readme with instructions for building locally
* Added ReactNativeCameraCPP61 solution and project to maintain 0.61 support

ReactNativeCameraCPP RNCamera component:
* Added properties: defaultVideoQuality, mirrorVideo, autoFocus, whiteBalance, cameraId
* Removed deprecated properties: torchMode
* Expanded Type constant (front/back) to include other Windows types (Unknown, Top, Bottom, Left, Right)

ReactNativeCamperaCPP RNCamera module:
* Cleaned up async error handling:
    * Uncaught exceptions no longer crash the app, instead returning the error via the promise reject as expected
    * Passed in options and promises are now properly captured so as to not get deleted before async operations are completed
* Fixed issue when passed in option values are doubles instead of integers
* Moved all possible processing off of the UI thread
* Fixed device enumeration by id/type to support non-integrated cameras
* Piped out CaptureTarget constants for "target" option (memory, disk, cameraRoll, temp)
* Added BarCodeType constant stubs
* Added FaceDetection constants stubs
* Added VideoCodec constants for "codec" option (H264, HEVC, WMV)
* takePicture:
    * Added options: target, quality, doNotSave, base64, width, mirrorImage, exif, writeExif
    * Added result properties: width, height, base64, exif
    * Fixed issue where EXIF data was being stripped from photos
* record:
    * Added options: target, mute, quality, maxDuration, videoBitrate, codec
    * Added result properties: codec
* stopRecording: Added implementation
* isRecording: Added implementation
* pausePreview: Added implementation
* resumePreview: Added implementation
* getCameraIds: Added implementation
2020-07-17 11:59:20 -03:00
dependabot[bot]
d62da5f092
chore(deps): bump lodash from 4.17.14 to 4.17.19 in /website (#2901)
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.14 to 4.17.19.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.14...4.17.19)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-07-17 08:38:47 -03:00
semantic-release-bot
a1ba2252b2 chore(release): 3.31.1 [skip ci]
## [3.31.1](https://github.com/react-native-community/react-native-camera/compare/v3.31.0...v3.31.1) (2020-07-13)

### Bug Fixes

* Fix (iOS) Fixed RNCameraManager.m ([#2895](https://github.com/react-native-community/react-native-camera/issues/2895)) ([7c796bf](https://github.com/react-native-community/react-native-camera/commit/7c796bf))
2020-07-13 11:26:29 +00:00
Marcel Lasaj
7c796bf0fd
fix: Fix (iOS) Fixed RNCameraManager.m (#2895)
- Camera Manager now also asks for permission when the description texts for camera and audio permission are localized
2020-07-13 08:25:03 -03:00
dependabot[bot]
bd4a7014a9
chore(deps): bump npm from 6.13.4 to 6.14.6 (#2891)
Bumps [npm](https://github.com/npm/cli) from 6.13.4 to 6.14.6.
- [Release notes](https://github.com/npm/cli/releases)
- [Changelog](https://github.com/npm/cli/blob/latest/CHANGELOG.md)
- [Commits](https://github.com/npm/cli/compare/v6.13.4...v6.14.6)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-07-07 18:30:20 -03:00
semantic-release-bot
e1462ea169 chore(release): 3.31.0 [skip ci]
# [3.31.0](https://github.com/react-native-community/react-native-camera/compare/v3.30.0...v3.31.0) (2020-06-30)

### Features

* **ios:** Remove artificial throttling of barcode scanning ([#2884](https://github.com/react-native-community/react-native-camera/issues/2884)) ([9675813](https://github.com/react-native-community/react-native-camera/commit/9675813))
2020-06-30 13:58:08 +00:00
Manish Kumar
9675813b7f
feat(ios): Remove artificial throttling of barcode scanning (#2884) 2020-06-30 10:55:38 -03:00
semantic-release-bot
7706ccbea7 chore(release): 3.30.0 [skip ci]
# [3.30.0](https://github.com/react-native-community/react-native-camera/compare/v3.29.0...v3.30.0) (2020-06-10)

### Features

* **ios:** enhanced advanced example project ([134173f](https://github.com/react-native-community/react-native-camera/commit/134173f)), closes [#2774](https://github.com/react-native-community/react-native-camera/issues/2774)
2020-06-10 21:41:15 +00:00
Renato Benkendorf
b738f41a7e
Merge pull request #2865 from rfischer/feat/advanced-example-whitebalance
Enhanced advanced example project
2020-06-10 18:39:30 -03:00
Mateus Andrade
0c78f0341d
docs: Merge pull request #2868 from luism3861/fix-scroll-links-api-page
fix scroll links in API Docs website
2020-06-10 15:00:06 -03:00
luism3861
6f433267d6 fix scroll links Api page in website docs 2020-06-10 12:44:42 -05:00
René Fischer
e11918ccf7 refactor: removed duplicated check for custom white balance 2020-06-10 09:26:01 +02:00
René Fischer
bb774ead9b
Update examples/advanced/advanced/src/screens/Camera.js
Co-authored-by: Renato Benkendorf <51369951+renatobenks@users.noreply.github.com>
2020-06-10 09:15:15 +02:00
René Fischer
945e97a042
Update examples/advanced/advanced/src/screens/Camera.js
Co-authored-by: Renato Benkendorf <51369951+renatobenks@users.noreply.github.com>
2020-06-10 09:15:01 +02:00
René Fischer
042880a584
Update examples/advanced/advanced/src/screens/Camera.js
Co-authored-by: Renato Benkendorf <51369951+renatobenks@users.noreply.github.com>
2020-06-10 09:13:52 +02:00
semantic-release-bot
3ba989edba chore(release): 3.29.0 [skip ci]
# [3.29.0](https://github.com/react-native-community/react-native-camera/compare/v3.28.0...v3.29.0) (2020-06-09)

### Bug Fixes

* **ios:** fixed app crash on barcode detection without FirebaseMLVision ([#2866](https://github.com/react-native-community/react-native-camera/issues/2866)) ([263b34e](https://github.com/react-native-community/react-native-camera/commit/263b34e))

### Features

* **ios:** Return the image containing barcodes (iOS only) ([#2864](https://github.com/react-native-community/react-native-camera/issues/2864)) ([dcbbbf4](https://github.com/react-native-community/react-native-camera/commit/dcbbbf4))
2020-06-09 13:20:21 +00:00
René Fischer
263b34e520
fix(ios): fixed app crash on barcode detection without FirebaseMLVision (#2866)
Update the mode of the barcode detector only if it is a real detector.
Otherwise, the app will crash due to '-[BarcodeDetectorManagerMlkit setMode:queue:]:  unrecognized selector sent to instance'.

Co-authored-by: René Fischer <rene.fischer@zollsoft.de>
2020-06-09 10:18:07 -03:00
Manish Kumar
dcbbbf453a
feat(ios): Return the image containing barcodes (iOS only) (#2864)
* Return the image containing barcodes

* Update RNCamera.md

Co-authored-by: Manish Kumar <mkumar@acvauctions.com>
2020-06-09 09:14:48 -03:00
René Fischer
134173f938 feat(ios): enhanced advanced example project
- added the custom white balance feature (#2774) to the advanced example project
2020-06-09 09:15:51 +02:00
Renato Benkendorf
c434051f0f
Merge pull request #2861 from manishkumar03/master
fix: Correct the way GoogleBarcodeDetectionMode is exposed in props
2020-06-05 23:26:39 -03:00
Manish Kumar
ac76480d7d Update RNCameraManager.m
Make iOS invocation in sync with Android
2020-06-05 16:34:06 -04:00
Mateus Andrade
26393332dd
Merge pull request #2858 from react-native-community/dependabot/npm_and_yarn/website/websocket-extensions-0.1.4 [skip ci]
chore(deps): bump websocket-extensions from 0.1.3 to 0.1.4 in /website
2020-06-05 14:39:56 -03:00
dependabot[bot]
485d098091
chore(deps): bump websocket-extensions from 0.1.3 to 0.1.4 in /website
Bumps [websocket-extensions](https://github.com/faye/websocket-extensions-node) from 0.1.3 to 0.1.4.
- [Release notes](https://github.com/faye/websocket-extensions-node/releases)
- [Changelog](https://github.com/faye/websocket-extensions-node/blob/master/CHANGELOG.md)
- [Commits](https://github.com/faye/websocket-extensions-node/compare/0.1.3...0.1.4)

Signed-off-by: dependabot[bot] <support@github.com>
2020-06-05 16:41:19 +00:00
semantic-release-bot
f5e68266dd chore(release): 3.28.0 [skip ci]
# [3.28.0](https://github.com/react-native-community/react-native-camera/compare/v3.27.1...v3.28.0) (2020-06-05)

### Bug Fixes

* merge cleanup ([815cb08](https://github.com/react-native-community/react-native-camera/commit/815cb08))

### Features

* **ios:** added customWhiteBalance to docs ([910c69a](https://github.com/react-native-community/react-native-camera/commit/910c69a))
* **ios:** added CustomWhiteBalance type ([9e9e12b](https://github.com/react-native-community/react-native-camera/commit/9e9e12b))
* **ios:** check if white balance mode locked is supported ([f4965cf](https://github.com/react-native-community/react-native-camera/commit/f4965cf))
* **ios:** check min/max gain values ([3a91036](https://github.com/react-native-community/react-native-camera/commit/3a91036))
* **ios:** customize white balance ([8c2100d](https://github.com/react-native-community/react-native-camera/commit/8c2100d))
* **ios:** fixed linter warning ([090f739](https://github.com/react-native-community/react-native-camera/commit/090f739))
* **ios:** refactoring ([68953bc](https://github.com/react-native-community/react-native-camera/commit/68953bc))
2020-06-05 16:39:51 +00:00
Renato Benkendorf
cec79269ee
Merge pull request #2774 from rfischer/feat/advanced-camera-settings
Adding Custom White Balance to IOS camera settings
2020-06-05 13:38:24 -03:00
semantic-release-bot
8c9d1e8f6d chore(release): 3.27.1 [skip ci]
## [3.27.1](https://github.com/react-native-community/react-native-camera/compare/v3.27.0...v3.27.1) (2020-06-05)

### Bug Fixes

* **googlevision barcode mode:** exposes correctly the barcode mode uses ([633322e](https://github.com/react-native-community/react-native-camera/commit/633322e))
* **mlkit example:** fixes the bad uses of googlevision barcode mode ([2071236](https://github.com/react-native-community/react-native-camera/commit/2071236))
2020-06-05 12:42:28 +00:00
Renato Benkendorf
a416a75aa8
Merge pull request #2856 from react-native-community/fix/googlevision-barcode-mode-mlkit-example
fix: (googlevision barcode mode)
2020-06-05 09:40:48 -03:00
Renato Benkendorf
633322e1e2 fix(googlevision barcode mode): exposes correctly the barcode mode uses 2020-06-05 02:27:02 -03:00
Renato Benkendorf
20712367d8 fix(mlkit example): fixes the bad uses of googlevision barcode mode 2020-06-05 02:23:17 -03:00
semantic-release-bot
250d98c306 chore(release): 3.27.0 [skip ci]
# [3.27.0](https://github.com/react-native-community/react-native-camera/compare/v3.26.0...v3.27.0) (2020-06-04)

### Features

* **ios:** Add ability to scan inverted-color barcodes on iOS using Google Vision ([#2851](https://github.com/react-native-community/react-native-camera/issues/2851)) ([fa61fce](https://github.com/react-native-community/react-native-camera/commit/fa61fce))
2020-06-04 15:19:35 +00:00
Manish Kumar
fa61fce613
feat(ios): Add ability to scan inverted-color barcodes on iOS using Google Vision (#2851)
* Add required plumbing for supporiting inverted colors

* Update package.json

* Update package.json

* Update RNCamera.js

* Update package.json

* Update RNCameraManager.m

* Read barcode detection mode

* Update package.json

* Declare invertImageData as a property

* Access the property correctly

* Refer to the property correctly

* Update RNCamera.m

* Update RNCamera.md

* Set default scan mode to Alternate

* Update package.json

* Set the default barcode detection mode to normal

* Update package.json

* Make the property type consistent

* Update RNCamera.h

* Update package.json

* Rename variables for readability

* Update package.json

* Add barcode mode usage

* Revert version update

Co-authored-by: Manish Kumar <mkumar@acvauctions.com>
2020-06-04 12:17:51 -03:00
Renato Benkendorf
ee88b38e22
Merge pull request #2749 from react-native-community/dependabot/npm_and_yarn/acorn-5.7.4
chore(deps): bump acorn from 5.7.1 to 5.7.4
2020-06-04 02:03:00 -03:00
Renato Benkendorf
9463bbc77a
Merge pull request #2746 from react-native-community/dependabot/npm_and_yarn/examples/advanced/advanced/acorn-5.7.4
chore(deps): bump acorn from 5.7.3 to 5.7.4 in /examples/advanced/advanced
2020-06-04 02:01:45 -03:00
Renato Benkendorf
ffed4359ab
Merge pull request #2744 from react-native-community/dependabot/npm_and_yarn/examples/mlkit/acorn-5.7.4
chore(deps): bump acorn from 5.7.3 to 5.7.4 in /examples/mlkit
2020-06-04 01:59:53 -03:00
dependabot[bot]
9478d158d0
chore(deps): bump acorn in /examples/advanced/advanced
Bumps [acorn](https://github.com/acornjs/acorn) from 5.7.3 to 5.7.4.
- [Release notes](https://github.com/acornjs/acorn/releases)
- [Commits](https://github.com/acornjs/acorn/compare/5.7.3...5.7.4)

Signed-off-by: dependabot[bot] <support@github.com>
2020-06-04 04:51:06 +00:00
dependabot[bot]
de1d7762eb
chore(deps): bump acorn from 5.7.3 to 5.7.4 in /examples/mlkit
Bumps [acorn](https://github.com/acornjs/acorn) from 5.7.3 to 5.7.4.
- [Release notes](https://github.com/acornjs/acorn/releases)
- [Commits](https://github.com/acornjs/acorn/compare/5.7.3...5.7.4)

Signed-off-by: dependabot[bot] <support@github.com>
2020-06-04 04:50:59 +00:00
dependabot[bot]
b130991527
chore(deps): bump acorn from 5.7.1 to 5.7.4
Bumps [acorn](https://github.com/acornjs/acorn) from 5.7.1 to 5.7.4.
- [Release notes](https://github.com/acornjs/acorn/releases)
- [Commits](https://github.com/acornjs/acorn/compare/5.7.1...5.7.4)

Signed-off-by: dependabot[bot] <support@github.com>
2020-06-04 04:50:58 +00:00
Renato Benkendorf
0f4107e729
Merge pull request #2743 from react-native-community/dependabot/npm_and_yarn/examples/basic/acorn-5.7.4
chore(deps): bump acorn from 5.7.3 to 5.7.4 in /examples/basic
2020-06-04 01:50:01 -03:00
René Fischer
815cb08d0b fix: merge cleanup 2020-05-25 09:38:11 +02:00
René Fischer
95201574c0 Merge branch 'master' into feat/advanced-camera-settings
# Conflicts:
#	ios/RN/RNCamera.m
#	ios/RNCamera.xcodeproj/project.pbxproj
2020-05-25 09:37:13 +02:00
semantic-release-bot
e55893bf4b chore(release): 3.26.0 [skip ci]
# [3.26.0](https://github.com/react-native-community/react-native-camera/compare/v3.25.0...v3.26.0) (2020-05-14)

### Features

* **android:** expose an ability to change the frames per second  ([#2834](https://github.com/react-native-community/react-native-camera/issues/2834)) ([04e6f06](https://github.com/react-native-community/react-native-camera/commit/04e6f06))
2020-05-14 11:48:57 +00:00
fabriziobertoglio1987
04e6f0674c
feat(android): expose an ability to change the frames per second (#2834)
* feat(android): expose an ability to change the frames per second

adding ability to change the video recording
frame per second using [MediaRecorder.setVideoFrameRate][1].

[1]: https://developer.android.com/reference/android/media/MediaRecorder#setVideoFrameRate(int)

* feat(android): adding getSupportedPreviewFpsRange

adding getSupportedPreviewFpsRange method to retrieve
supported android devices frame rates for recording.

* feat(android): updating docs

* feat(android): fix api docs type

* feat(android): adding typescript promise type

* feat(android): log message for Camera2

* feat(android): iOS error if method invoked

Triggering error if android only method getSupportedPreviewFpsRange is invoked on iOS.

* feat(android): expose an ability to change the frames per second

adding ability to change the video recording
frame per second using [MediaRecorder.setVideoFrameRate][1].

[1]: https://developer.android.com/reference/android/media/MediaRecorder#setVideoFrameRate(int)

* feat(android): adding getSupportedPreviewFpsRange

adding getSupportedPreviewFpsRange method to retrieve
supported android devices frame rates for recording.

* feat(android): updating docs

* feat(android): fix api docs type

* feat(android): adding typescript promise type

* feat(android): log message for Camera2

* feat(android): iOS error if method invoked

Triggering error if android only method getSupportedPreviewFpsRange is invoked on iOS.
2020-05-14 08:47:16 -03:00
semantic-release-bot
0641fc1755 chore(release): 3.25.0 [skip ci]
# [3.25.0](https://github.com/react-native-community/react-native-camera/compare/v3.24.2...v3.25.0) (2020-05-12)

### Features

* **touch:** Feature/add on tap events ([#2827](https://github.com/react-native-community/react-native-camera/issues/2827)) ([dc4f657](https://github.com/react-native-community/react-native-camera/commit/dc4f657))
2020-05-12 20:58:22 +00:00
SimonErm
dc4f65702f
feat(touch): Feature/add on tap events (#2827)
* add TouchEvent on android

* add GestureHandler to detect touches on android

* add property to enable touchDetector on android

* add onTouch event to ios

* add GestureRecognizer to ios

* add onTouch property and js setup

* add missing semicolons

* fix literal notation

* add missing ":"

* fix copy-paste error (wrong var-name)

* pass the native event to the onTouch callback

* replace : with ;

* add onTouch type defs

* add documentation for onTouch property

* scale postion before emitting since the event coordinates are raw pixels

* migrate advanced example to native pinch zoom and onTouch

* split onTouch property into onTap and onDoubleTap
2020-05-12 17:56:42 -03:00
semantic-release-bot
b6f9bb3b97 chore(release): 3.24.2 [skip ci]
## [3.24.2](https://github.com/react-native-community/react-native-camera/compare/v3.24.1...v3.24.2) (2020-05-11)

### Bug Fixes

* adding downloadDependencies task to android projects ([d496438](https://github.com/react-native-community/react-native-camera/commit/d496438))
2020-05-11 13:06:15 +00:00
Mateus Andrade
970248c1a6
ci: Merge pull request #2831 from MateusAndrade/ci-react-native-orb
CI: refactoring CircleCI config to use react-native-orb + split workflows
2020-05-11 10:04:27 -03:00
MateusAndrade
d49643813b fix: adding downloadDependencies task to android projects 2020-05-10 23:30:17 -03:00
MateusAndrade
802b56d88c ci: changing circle to use rn-orb 2020-05-10 23:17:29 -03:00
semantic-release-bot
2f57436c08 chore(release): 3.24.1 [skip ci]
## [3.24.1](https://github.com/react-native-community/react-native-camera/compare/v3.24.0...v3.24.1) (2020-05-05)

### Bug Fixes

* **ios:** add missing semicolon in RNCamera.m ([#2823](https://github.com/react-native-community/react-native-camera/issues/2823)) ([a5b55fa](https://github.com/react-native-community/react-native-camera/commit/a5b55fa))
2020-05-05 20:41:29 +00:00
Jose G
a5b55fa608
fix(ios): add missing semicolon in RNCamera.m (#2823) 2020-05-05 17:36:24 -03:00
semantic-release-bot
611fd9e5d1 chore(release): 3.24.0 [skip ci]
# [3.24.0](https://github.com/react-native-community/react-native-camera/compare/v3.23.1...v3.24.0) (2020-05-05)

### Bug Fixes

* **ios:** instance-method-conflict warning ([#2817](https://github.com/react-native-community/react-native-camera/issues/2817)) ([e02890c](https://github.com/react-native-community/react-native-camera/commit/e02890c))

### Features

* **android:** Update Gradle Wrapper and plugin, fix files ([#2818](https://github.com/react-native-community/react-native-camera/issues/2818)) ([ce79135](https://github.com/react-native-community/react-native-camera/commit/ce79135))
* **zoom:** Feature/add native zoom ([#2815](https://github.com/react-native-community/react-native-camera/issues/2815)) ([5b32936](https://github.com/react-native-community/react-native-camera/commit/5b32936))
2020-05-05 19:07:43 +00:00
Frieder Bluemle
ce791350a4
feat(android): Update Gradle Wrapper and plugin, fix files (#2818)
* Update yarn.lock

* Remove executable bit from non-executable files

* Update Gradle Wrapper to 5.6.4

* Update Android Gradle plugin to 3.6.3
2020-05-05 16:01:20 -03:00
Nick Hodapp
e02890c41a
fix(ios): instance-method-conflict warning (#2817) 2020-05-05 16:00:29 -03:00
SimonErm
5b32936f00
feat(zoom): Feature/add native zoom (#2815)
* add native zoom on android

* add native zoom on ios

* add useNativeZoom property

* extract compution of maxZoomFactor to a method

* use optional maxZoomFactor for native zoom

* add useNativeZoom Property to typescript declaration

* add doc entry for useNativeZoom
2020-05-05 15:59:56 -03:00
Di Da
ec84aa9d6b
Merge pull request #2802 from kaiguo/windows-fix
Windows fixes for 0.61 update
2020-05-04 11:38:56 -07:00
Kai Guo
77c0d0f751 Windows fixes 2020-04-23 10:39:28 -07:00
Kevin Sullivan
48a3a4dfd8
Merge pull request #2797 from wolverineks/master
remove unused files, fix broken tests
2020-04-18 10:14:28 -07:00
Kevin Sullivan
868d0fb828 test: fix broken tests 2020-04-18 10:00:38 -07:00
Kevin Sullivan
7b3c542b14 chore: remove unused files 2020-04-18 07:13:04 -07:00
Kevin Sullivan
3e94912fec
test: add more on-device tests (#2795) 2020-04-18 09:52:33 -03:00
semantic-release-bot
cc9a271781 chore(release): 3.23.1 [skip ci]
## [3.23.1](https://github.com/react-native-community/react-native-camera/compare/v3.23.0...v3.23.1) (2020-04-15)

### Bug Fixes

* **types:** updated types as per RN 0.62 version of [@types](https://github.com/types)/react-native ([#2794](https://github.com/react-native-community/react-native-camera/issues/2794)) ([45308c1](https://github.com/react-native-community/react-native-camera/commit/45308c1))
2020-04-15 14:18:17 +00:00
Brent Kelly
45308c1bae
fix(types): updated types as per RN 0.62 version of @types/react-native (#2794)
* fix(types): updated types as per RN 0.62 version of @types/react-native

* chore(cr): reverting version back to 3.23.0
2020-04-15 11:12:01 -03:00
semantic-release-bot
56cfa4739a chore(release): 3.23.0 [skip ci]
# [3.23.0](https://github.com/react-native-community/react-native-camera/compare/v3.22.1...v3.23.0) (2020-04-14)

### Features

* **test:** add on-device tests ([#2792](https://github.com/react-native-community/react-native-camera/issues/2792)) ([cb79f53](https://github.com/react-native-community/react-native-camera/commit/cb79f53))
2020-04-14 23:08:19 +00:00
Kevin Sullivan
cb79f53adc
feat(test): add on-device tests (#2792)
* test: add on-device tests

* test: add photos/videos tests
2020-04-14 20:02:17 -03:00
semantic-release-bot
296045e299 chore(release): 3.22.1 [skip ci]
## [3.22.1](https://github.com/react-native-community/react-native-camera/compare/v3.22.0...v3.22.1) (2020-04-08)

### Bug Fixes

* **android:** Fix Android Camera1 race condition crash ([#2781](https://github.com/react-native-community/react-native-camera/issues/2781)) ([85b951c](https://github.com/react-native-community/react-native-camera/commit/85b951c))
* **android:** Fix image path on Android, and add iOS implementation. ([#2782](https://github.com/react-native-community/react-native-camera/issues/2782)) ([baf6f9f](https://github.com/react-native-community/react-native-camera/commit/baf6f9f))
2020-04-08 20:57:06 +00:00
cristianoccazinsp
baf6f9fd52
fix(android): Fix image path on Android, and add iOS implementation. (#2782)
Co-authored-by: Cristiano Coelho <cristianocca@hotmail.com>
2020-04-08 17:51:48 -03:00
cristianoccazinsp
85b951ced1
fix(android): Fix Android Camera1 race condition crash (#2781)
* add synchronized to take pictures callback in case camera was already stopped.

This will also prevent a possible null camera object.

* use our mCamera variable instead of the one received in the callback so we know if it has been disposed.

Co-authored-by: Cristiano Coelho <cristianocca@hotmail.com>
2020-04-08 17:51:27 -03:00
semantic-release-bot
bfe04aaec8 chore(release): 3.22.0 [skip ci]
# [3.22.0](https://github.com/react-native-community/react-native-camera/compare/v3.21.0...v3.22.0) (2020-04-05)

### Features

* **android:** Accept path while taking picture in android ([#2769](https://github.com/react-native-community/react-native-camera/issues/2769)) ([3ee43d4](https://github.com/react-native-community/react-native-camera/commit/3ee43d4))
* **example:** Fix basic example bugs ([#2751](https://github.com/react-native-community/react-native-camera/issues/2751)) ([9c18c25](https://github.com/react-native-community/react-native-camera/commit/9c18c25))
2020-04-05 14:57:56 +00:00
fabriziobertoglio1987
9c18c25f19
feat(example): Fix basic example bugs (#2751)
* feat(example): adding sound permissions to android example

* feat(example): fix basic example runtime error
2020-04-05 11:53:51 -03:00
AsminBudha
3ee43d4acd
feat(android): Accept path while taking picture in android (#2769)
* Accept path while taking picture in android

* docs(context): change readme to add path option while taking picture
2020-04-05 11:53:03 -03:00
René Fischer
d59f5a099d refactor: lock and unlock device
Added a method to lock a capture device, apply settings via a block, and unlock the device at the end.
2020-04-04 16:04:07 +02:00
René Fischer
68953bcb14 feat(ios): refactoring
- merged whiteBalance and customWhiteBalance properties into one
- separate methods for custom and normal white balance modes
2020-04-02 17:29:37 +02:00
René Fischer
090f7390db feat(ios): fixed linter warning 2020-04-01 18:28:06 +02:00
René Fischer
910c69a30a feat(ios): added customWhiteBalance to docs 2020-04-01 17:54:53 +02:00
Mateus Andrade
e7ed948841
Merge pull request #2768 from cristianoccazinsp/android-crash-camerainfo
Crash fix when getCameraInfo fails
2020-03-26 15:14:27 -03:00
Cristiano Coelho
0111237eeb Crash fix when getCameraInfo fails 2020-03-26 14:43:14 -03:00
Mateus Andrade
d1e3d66a69
Merge pull request #2765 from tribou/tracked-text-feature-type
Fix TrackedTextFeature TS type
2020-03-26 08:52:43 -03:00
René Fischer
9e9e12b05a feat(ios): added CustomWhiteBalance type 2020-03-25 14:48:19 +01:00
Aaron Tribou
86e8053160
Fix TrackedTextFeature TS type 2020-03-24 21:13:23 -05:00
René Fischer
3a9103694d feat(ios): check min/max gain values 2020-03-23 12:38:28 +01:00
René Fischer
f4965cfc3d feat(ios): check if white balance mode locked is supported 2020-03-23 12:38:07 +01:00
semantic-release-bot
e9af04afbc chore(release): 3.21.0 [skip ci]
# [3.21.0](https://github.com/react-native-community/react-native-camera/compare/v3.20.0...v3.21.0) (2020-03-20)

### Features

* **example:** fix circleci error ([1f29ffb](https://github.com/react-native-community/react-native-camera/commit/1f29ffb))
2020-03-20 19:58:22 +00:00
Mateus Andrade
353eecec59
Merge pull request #2757 from fabriziobertoglio1987/fix/circle-ci-node-crash
node process crushing circleci
2020-03-20 16:52:53 -03:00
fabriziobertoglio1987
1f29ffb023 feat(example): fix circleci error 2020-03-20 19:29:52 +01:00
René Fischer
8c2100dd63 feat(ios): customize white balance
added possibility to customize white balance settings (temperature, tint, rgb gains offset)
2020-03-20 16:35:13 +01:00
semantic-release-bot
4c54bd5f2f chore(release): 3.20.0 [skip ci]
# [3.20.0](https://github.com/react-native-community/react-native-camera/compare/v3.19.2...v3.20.0) (2020-03-19)

### Features

* **example:** remove rectOfInterest example ([8e4d36a](https://github.com/react-native-community/react-native-camera/commit/8e4d36a))
2020-03-19 18:49:01 +00:00
Mateus Andrade
f11136a119
Merge pull request #2755 from fabriziobertoglio1987/fix/delete-additional-examples
remove rectOfInterest example
2020-03-19 15:44:08 -03:00
fabriziobertoglio1987
8e4d36aa14 feat(example): remove rectOfInterest example 2020-03-19 19:05:58 +01:00
semantic-release-bot
d477f4c53c chore(release): 3.19.2 [skip ci]
## [3.19.2](https://github.com/react-native-community/react-native-camera/compare/v3.19.1...v3.19.2) (2020-03-16)

### Bug Fixes

* **android:** fix empty popup ([407295b](https://github.com/react-native-community/react-native-camera/commit/407295b))
2020-03-16 16:43:54 +00:00
Mateus Andrade
0afc608eb0
Merge pull request #2748 from cristianoccazinsp/fix-android-shutter-sound
Fix android shutter sound
2020-03-16 13:39:11 -03:00
Cristiano Coelho
18d9347dfa improve camera2 to camera1 fallback on legacy devices. 2020-03-14 15:46:58 -03:00
Cristiano Coelho
0911852b53 Use same method to play sounds for consistency and so it works across multiple devices. 2020-03-14 13:43:11 -03:00
Cristiano Coelho
1f895481c9 move shutter sound to right location 2020-03-14 12:46:24 -03:00
Cristiano Coelho
4c757447cb prevent duplicated start calls (#2521) 2020-03-14 12:35:38 -03:00
Cristiano Coelho
886a3bb758 Fixes for Camera1 and Camera2 shutter sound.
Shutter sound should now be consistent with the `playSoundOnCapture` prop. Additionally, it should happen on successful capture as opposed to camera capture start (consistent with iOS and any camera app)

Lastly, added missing props to the docs.
2020-03-14 12:16:22 -03:00
dependabot[bot]
9f2796decf
chore(deps): bump acorn from 5.7.3 to 5.7.4 in /examples/basic
Bumps [acorn](https://github.com/acornjs/acorn) from 5.7.3 to 5.7.4.
- [Release notes](https://github.com/acornjs/acorn/releases)
- [Commits](https://github.com/acornjs/acorn/compare/5.7.3...5.7.4)

Signed-off-by: dependabot[bot] <support@github.com>
2020-03-14 03:55:45 +00:00
Mateus Andrade
fb2105c7cc
Merge pull request #2740 from lihroff/master
fix(android): fix empty popup
2020-03-13 10:07:10 -03:00
Mateus Andrade
43a7323f83
Merge pull request #2719 from bqwang91/master
Android - Limiting Scanning Area using rectOfInterest
2020-03-13 09:39:55 -03:00
TommY Lee
407295bc47 fix(android): fix empty popup
fix empty popup when not set android*PermissionOptions props.
2020-03-13 18:21:56 +08:00
Mateus Andrade
944c304b88
Merge pull request #2737 from stvdrsch/master
Typo
2020-03-12 12:40:28 -03:00
Steven Vanderschaeve
745e8de8c3
Typo
coordiate instead of coordinate
2020-03-12 14:44:27 +01:00
semantic-release-bot
38c5197023 chore(release): 3.19.1 [skip ci]
## [3.19.1](https://github.com/react-native-community/react-native-camera/compare/v3.19.0...v3.19.1) (2020-03-11)

### Bug Fixes

* **android:** fix bug Duplicate module rn ([4522841](https://github.com/react-native-community/react-native-camera/commit/4522841))
2020-03-11 16:40:29 +00:00
Di Da
4a1cfa5c2a
Merge pull request #2723 from ddalp/master
Add Cpp/WinRT camera module support for React Native Windows
2020-03-11 09:36:26 -07:00
Mateus Andrade
e76faaec41
Merge pull request #2735 from fabriziobertoglio1987/fix/basic-example-rn-cli-config
Fix Duplicate module rn
2020-03-10 19:38:17 -03:00
Di Da
7c7124df1c Move ReactCameraConstants under a class and fix typo 2020-03-10 09:44:42 -07:00
fabriziobertoglio1987
4522841f8a fix(android): fix bug Duplicate module rn
fixing bug Duplicate module react-native
when running the mlkit and basic examples

1) adding metro.config.js to examples/basic and
examples/mlkit

2) adding new RegExp in blacklist to ignore the
advanced/node_modules/react-native/.* files
2020-03-10 10:12:11 +01:00
Di Da
51a492782e Address PR comments 2020-03-09 10:53:26 -07:00
Di Da
72f2dc9f6d Add Cpp/WinRT camera module support for React Native Windows 2020-03-03 10:41:00 -08:00
James Wang
583507f223 update cam view height 2020-02-29 20:33:17 +11:00
James Wang
3f801ee11c add example 2020-02-29 17:42:35 +11:00
semantic-release-bot
ea0e9e68e7 chore(release): 3.19.0 [skip ci]
# [3.19.0](https://github.com/react-native-community/react-native-camera/compare/v3.18.0...v3.19.0) (2020-02-27)

### Features

* **ios:** Expose an ability to change the frames per second via an fps option in record. ([#2711](https://github.com/react-native-community/react-native-camera/issues/2711)) ([d60d201](https://github.com/react-native-community/react-native-camera/commit/d60d201))
2020-02-27 17:52:07 +00:00
cinjon
d60d201eb2
feat(ios): Expose an ability to change the frames per second via an fps option in record. (#2711) 2020-02-27 14:47:45 -03:00
James Wang
398ac120fc fix typo 2020-02-27 14:01:53 +11:00
James Wang
3f66aa5aeb update RNcamera readme 2020-02-27 13:59:19 +11:00
James Wang
802ce479ff add types 2020-02-27 13:52:57 +11:00
James Wang
6cc8fefc6f add aupport for limiting scan area for Android 2020-02-27 13:50:32 +11:00
semantic-release-bot
adae4a294d chore(release): 3.18.0 [skip ci]
# [3.18.0](https://github.com/react-native-community/react-native-camera/compare/v3.17.0...v3.18.0) (2020-02-14)

### Features

* **android:** stop/release camera in non-UI thread ([#2685](https://github.com/react-native-community/react-native-camera/issues/2685)) ([ba0e427](https://github.com/react-native-community/react-native-camera/commit/ba0e427))
2020-02-14 02:26:08 +00:00
cristianoccazinsp
c7e92b29c8
feature(record): On recording start and end events (#2702)
* This update tries to improve audio recording interruptions on iOS due to phone calls or background music.

- Use a more generic event to handle session interruptions. This removes the need to listen to foreground/background events, and stopping the session this way was actually redundant/wrong (see https://forums.developer.apple.com/thread/61406). This also makes session stopping detection more reliable (calls, suspension due to a call or notification, etc., which would previously not set the recording interrupted flag on every case)

From the above docs: "No, incorrect. You _never_ need to stop your capture session. The capture session automatically stops itself when your app goes to the background and resumes itself when you come back to the foreground."

- Allow for `captureAudio` updates to also update the audio connections internally so the prop can be correctly updated on the fly without remounting.

- add onAudioInterrupted and onAudioConnected events so the UI can handle scenarios where audio is wanted but not available. This should also help in keeping the preview active even if audio is interrupted and we have captureAudio={true}. Lastly, it can be used to detect if we can record audio or not due to the dummy implementation of the audio permission on iOS always returning true.

- check, activate, and release audio sessions (if captureAudio) so we can detect early if audio is available before attempting to connect the input. This will also allow us to detect if we can record even if there was already a call before opening the camera.

- use proper observer for session error instead of of the strong self block. No benefit, but makes code more readable and allows access to instance variables

- getDeviceOrientationWithBlock might fire more than once under some circumstances, ending up taking a picture or video twice. Add a lock and additional check to prevent this.

* no need for change check,

* do not resume audio if we were hinted not to (e.g., music playback happening)

* Move heavy work to a dedicated background thread. Improves camera initial loading and resumes from background.

Details:

- Use a HandlerThread to delegate heavy tasks to background. The thread is managed by the view, and passed down to the implementation in case it also needs to use it. The view will fire start calls and other possibly heavy operations in this thread to avoid ANRs. Some code sent to this thread:
    - start calls: start is extremely heavy and will cause ANRs on some devices, especially when coming back from background
    - Camera1: some preset changes fire a stop/start sequence. These will now happen in the background thread
    - take picture and start recording (from view class) will also start in this thread

- Add some extra null checks

- View was not properly cleaning up itself on destroy (host destroy event was never fired)

* Fix for a possible crash when changing devices and changing focus. If the new device resets the focus, "defocusing" might not be possible if the new device does not support auto focus. For this reason, we need to do a different cleanup on the focus and exposed flags and events.

* start session here also on session queue.

* check for session running before trying to record or capture.
This should fix a possible race condition where both the session start call happens at the same time as the record call

* set preview orientation also in session queue

* no need to set orientation on constructor, and set it on session queue to prevent race conditions

* move device init and checks also to session queue. This prevents possible double initializations.

* catch possible errors when starting camera preview. This might still randomly fail on some devices for some reason.

* delay capture in progress until we have resumed/paused preview.

* do not crash the app if set texture setup failed

* more synchronized checks to prevent crashes due to concurrent camera updates

* remove unused imports

* Handle audio interruption in session queue. This prevents the session isRunning flag from getting corrupted due to concurrent updates to the session.

* Fix possible crash when attempting to retrieve camera parameters.

* Preserve exif/metadata on photo capture. Add a few comments to each step of the capture process

* orientation must be fixed before mirroring

* x/y dimensions are redundantly updated (storing the image sets them automatically). However, orientation must be reset on any image change since the final stored image is automatically rotated when it is modified in place.

* revert mirrorImage order, has to be first since forceUpOrientation adjusts the image afterwards.

* Minor change: also implement `onPictureTaken` for iOS in case anyone needs the early event.

* - Improve Android code so skipProcessing is not needed, the code is more in line with iOS, and is "fast" by default. This means that skipProcessing is no longer needed (nor used), and adding additional options will "slow down" the capture as expected, rather than having always a lot of processing. This shouldn't be a breaking change.

- document the writeExif option, and implement it for iOS as well.

* This is a fix for events possibly being fired not on the main thread, which could cause the whole app to freeze.

* Fire events on the right thread. No need to use UI thread, and fix the still works

* Release CF object which could cause a memleak

* Fix Objects.equals that is only available after API 19

* allow for audio session to be kept even after unmounts

* readme typo

* readme typo

* Make camera ready events to fire also on camera/device change to be consistent with Android. Fire unmount error when session or device fails to start.

* update example app to properly use camera ready event

* Make camera ready events to fire also on camera/device change to be consistent with Android. Fire unmount error when session or device fails to start. Update advanced example app to use camera ready event instead.

* Android crash fixes. Make sure no unsupported aspect ratio is used, and do not crash when there are no cameras available.

* stop/release camera in non-UI thread so we prevent ANRs and UI freezing.

Some phones may take up to a second to release the camera and preview.

* move codec, max duration, and max file size settings to the session queue.

This might prevent a race condition when changing presets/quality.

* android crash fix

* Add onRecordingStart and onRecordingEnd events

* fix for surface destroy and resume events.

* add missing types

* fix for surface destroy and resume events.

* add missing types

Co-authored-by: Cristiano Coelho <cristianocca@hotmail.com>
2020-02-13 23:21:59 -03:00
cristianoccazinsp
ba0e427304
feat(android): stop/release camera in non-UI thread (#2685)
* stop/release camera in non-UI thread so we prevent ANRs and UI freezing.

Some phones may take up to a second to release the camera and preview.

* fix for surface destroy and resume events.

Co-authored-by: Cristiano Coelho <cristianocca@hotmail.com>
2020-02-13 18:02:39 -03:00
semantic-release-bot
c683076a48 chore(release): 3.17.0 [skip ci]
# [3.17.0](https://github.com/react-native-community/react-native-camera/compare/v3.16.0...v3.17.0) (2020-02-05)

### Bug Fixes

* **record:** android crash fix ([#2697](https://github.com/react-native-community/react-native-camera/issues/2697)) ([7c2572d](https://github.com/react-native-community/react-native-camera/commit/7c2572d))

### Features

* **codec:** move codec, max duration, and max file size settings to the session queue. ([#2694](https://github.com/react-native-community/react-native-camera/issues/2694)) ([9b4af8e](https://github.com/react-native-community/react-native-camera/commit/9b4af8e))
2020-02-05 15:53:24 +00:00
cristianoccazinsp
7c2572dc7a
fix(record): android crash fix (#2697)
Co-authored-by: Cristiano Coelho <cristianocca@hotmail.com>
2020-02-05 12:46:02 -03:00
cristianoccazinsp
9b4af8e649
feat(codec): move codec, max duration, and max file size settings to the session queue. (#2694)
This might prevent a race condition when changing presets/quality.

Co-authored-by: Cristiano Coelho <cristianocca@hotmail.com>
2020-02-05 12:45:42 -03:00
semantic-release-bot
7806f840cf chore(release): 3.16.0 [skip ci]
# [3.16.0](https://github.com/react-native-community/react-native-camera/compare/v3.15.1...v3.16.0) (2020-01-27)

### Bug Fixes

* **android:** crash fix for android sdk < 18 ([#2674](https://github.com/react-native-community/react-native-camera/issues/2674)) ([dea3371](https://github.com/react-native-community/react-native-camera/commit/dea3371))

### Features

* **RNCameraManager:** expose videoStabilizationMode from native ([#2681](https://github.com/react-native-community/react-native-camera/issues/2681)) ([cd4c8f2](https://github.com/react-native-community/react-native-camera/commit/cd4c8f2))
2020-01-27 20:18:11 +00:00
Simon Stern
8761fe0a2b
Merge pull request #2684 from jackiewung/patch-1
add pictureSize type to RNCameraProps
2020-01-27 15:12:05 -05:00
Jackie Wung
ea05b1449d
add pictureSize type 2020-01-23 14:38:49 -08:00
mauriciopf
cd4c8f24e3 feat(RNCameraManager): expose videoStabilizationMode from native (#2681)
* fix(RNCameraManager) expose videoStabilizationMode from native

* refactor(types): add videoStabilization to the module declaration
2020-01-22 14:42:20 -03:00
cristianoccazinsp
dea33716aa fix(android): crash fix for android sdk < 18 (#2674)
Co-authored-by: Cristiano Coelho <cristianocca@hotmail.com>
2020-01-13 14:41:29 -03:00
semantic-release-bot
b57538827c chore(release): 3.15.1 [skip ci]
## [3.15.1](https://github.com/react-native-community/react-native-camera/compare/v3.15.0...v3.15.1) (2019-12-31)

### Bug Fixes

* **android:** android  crash fixes. Make sure no unsupported aspect ratio is used, and do not crash when there are no cameras available. ([#2662](https://github.com/react-native-community/react-native-camera/issues/2662)) ([db7b9e4](https://github.com/react-native-community/react-native-camera/commit/db7b9e4))
2019-12-31 15:35:49 +00:00
cristianoccazinsp
db7b9e4a98 fix(android): android crash fixes. Make sure no unsupported aspect ratio is used, and do not crash when there are no cameras available. (#2662) 2019-12-31 12:30:01 -03:00
Simon Stern
d84127f310
Merge pull request #2650 from kant/patch-1
Semantic issue on line 50
2019-12-28 14:44:16 -05:00
Simon Stern
acfa7bd18b
Merge pull request #2657 from react-native-community/docs/api
Docs: Added several properties to docs and organized the reference with an index
2019-12-28 14:43:36 -05:00
Simon Stern
5de4bc54df
Merge pull request #2659 from react-native-community/dependabot/npm_and_yarn/handlebars-4.5.3
chore(deps): bump handlebars from 4.1.2 to 4.5.3
2019-12-28 14:04:38 -05:00
dependabot[bot]
1fa0441144
chore(deps): bump handlebars from 4.1.2 to 4.5.3
Bumps [handlebars](https://github.com/wycats/handlebars.js) from 4.1.2 to 4.5.3.
- [Release notes](https://github.com/wycats/handlebars.js/releases)
- [Changelog](https://github.com/wycats/handlebars.js/blob/master/release-notes.md)
- [Commits](https://github.com/wycats/handlebars.js/compare/v4.1.2...v4.5.3)

Signed-off-by: dependabot[bot] <support@github.com>
2019-12-28 17:54:22 +00:00
Mateus Andrade
2788b9d0d9
Merge pull request #2658 from react-native-community/dependabot/npm_and_yarn/examples/basic/handlebars-4.5.3
chore(deps): bump handlebars from 4.1.2 to 4.5.3 in /examples/basic
2019-12-28 14:53:39 -03:00
dependabot[bot]
fc387c271a
chore(deps): bump handlebars from 4.1.2 to 4.5.3 in /examples/basic
Bumps [handlebars](https://github.com/wycats/handlebars.js) from 4.1.2 to 4.5.3.
- [Release notes](https://github.com/wycats/handlebars.js/releases)
- [Changelog](https://github.com/wycats/handlebars.js/blob/master/release-notes.md)
- [Commits](https://github.com/wycats/handlebars.js/compare/v4.1.2...v4.5.3)

Signed-off-by: dependabot[bot] <support@github.com>
2019-12-28 01:38:45 +00:00
Mateus Andrade
e2748428b7
Merge pull request #2651 from kant/patch-2
Fixed typo on line 91
2019-12-26 17:43:15 -03:00
Mateus Andrade
84cf1df7aa
Merge pull request #2655 from MateusAndrade/fix-ci-build
Fix ci build
2019-12-26 17:15:20 -03:00
MateusAndrade
81fcbcc885 ci: adding clean to gradlew scripts 2019-12-26 16:56:50 -03:00
Mateus Andrade
ae687d047c
Merge pull request #8 from react-native-community/master
update fork
2019-12-26 16:51:43 -03:00
simistern
2cde2e76a6 Docs: Added several properties and collected the methods into an index 2019-12-25 16:00:52 -05:00
Darío Hereñú
2bb2540766
Fixed typo on line 91 2019-12-25 02:30:25 -03:00
Darío Hereñú
e7aa6a3a1a
Semantic issue on line 50 2019-12-25 02:24:40 -03:00
dependabot[bot]
44661fc5d3 chore(deps): bump npm from 6.4.1 to 6.13.4 (#2643)
Bumps [npm](https://github.com/npm/cli) from 6.4.1 to 6.13.4.
- [Release notes](https://github.com/npm/cli/releases)
- [Changelog](https://github.com/npm/cli/blob/latest/CHANGELOG.md)
- [Commits](https://github.com/npm/cli/compare/v6.4.1...v6.13.4)

Signed-off-by: dependabot[bot] <support@github.com>
2019-12-13 15:07:23 -03:00
semantic-release-bot
c235435b4f chore(release): 3.15.0 [skip ci]
# [3.15.0](https://github.com/react-native-community/react-native-camera/compare/v3.14.0...v3.15.0) (2019-12-13)

### Features

* **ios:** Make camera ready events to fire also on camera/device change to be consistent with Android. Fire unmount error when session or device fails to start. Update advanced example app to use camera ready event instead. ([#2642](https://github.com/react-native-community/react-native-camera/issues/2642)) ([7abf3f7](https://github.com/react-native-community/react-native-camera/commit/7abf3f7))
2019-12-13 17:55:53 +00:00
cristianoccazinsp
7abf3f78cb feat(ios): Make camera ready events to fire also on camera/device change to be consistent with Android. Fire unmount error when session or device fails to start. Update advanced example app to use camera ready event instead. (#2642) 2019-12-13 14:51:50 -03:00
semantic-release-bot
0745fb90f0 chore(release): 3.14.0 [skip ci]
# [3.14.0](https://github.com/react-native-community/react-native-camera/compare/v3.13.1...v3.14.0) (2019-12-10)

### Bug Fixes

* **android:** Fix Objects.equals that is only available after API 19 ([#2635](https://github.com/react-native-community/react-native-camera/issues/2635)) ([8c6a26f](https://github.com/react-native-community/react-native-camera/commit/8c6a26f))
* **example:** fixes and updates in mlkit example ([#2618](https://github.com/react-native-community/react-native-camera/issues/2618)) ([72c5624](https://github.com/react-native-community/react-native-camera/commit/72c5624))
* **ts:** fixed incorrect type definition file path ([#2622](https://github.com/react-native-community/react-native-camera/issues/2622)) ([047bbea](https://github.com/react-native-community/react-native-camera/commit/047bbea))

### Features

* **android:** Load Android Gradle Plugin conditionally ([#2623](https://github.com/react-native-community/react-native-camera/issues/2623)) ([d8cf6c9](https://github.com/react-native-community/react-native-camera/commit/d8cf6c9))
* **android:** restore state when useCamera2api is enabled ([#2603](https://github.com/react-native-community/react-native-camera/issues/2603)) ([1f8b863](https://github.com/react-native-community/react-native-camera/commit/1f8b863))
* **docs:** update onBarCodeRead on Android and add additional SubView library ([#2616](https://github.com/react-native-community/react-native-camera/issues/2616)) ([fe84811](https://github.com/react-native-community/react-native-camera/commit/fe84811))
* **iOS:** allow for audio session to be kept ([#2636](https://github.com/react-native-community/react-native-camera/issues/2636)) ([fe5d11d](https://github.com/react-native-community/react-native-camera/commit/fe5d11d))
2019-12-10 14:07:04 +00:00
cristianoccazinsp
fe5d11d12f feat(iOS): allow for audio session to be kept (#2636)
* allow for audio session to be kept even after unmounts

* readme typo
2019-12-10 11:02:45 -03:00
cristianoccazinsp
8c6a26f289 fix(android): Fix Objects.equals that is only available after API 19 (#2635) 2019-12-10 11:02:16 -03:00
SaeedZhiany
047bbeab56 fix(ts): fixed incorrect type definition file path (#2622) 2019-12-03 16:10:26 -03:00
SaeedZhiany
d8cf6c9c10 feat(android): Load Android Gradle Plugin conditionally (#2623) 2019-12-03 16:09:23 -03:00
Märt Lõhmus
1f8b863947 feat(android): restore state when useCamera2api is enabled (#2603) 2019-12-02 09:28:13 -03:00
Chau Tran
fe8481158f feat(docs): update onBarCodeRead on Android and add additional SubView library (#2616) 2019-12-02 09:27:17 -03:00
Stanimir
72c5624dd3 fix(example): fixes and updates in mlkit example (#2618) 2019-12-02 09:24:12 -03:00
semantic-release-bot
0af8ea9756 chore(release): 3.13.1 [skip ci]
## [3.13.1](https://github.com/react-native-community/react-native-camera/compare/v3.13.0...v3.13.1) (2019-12-01)

### Bug Fixes

* **android:** barcode option passing to mlkit for Android ([#2614](https://github.com/react-native-community/react-native-camera/issues/2614)) ([32355f4](https://github.com/react-native-community/react-native-camera/commit/32355f4))
2019-12-01 23:56:03 +00:00
Kyle Johnson
32355f4779 fix(android): barcode option passing to mlkit for Android (#2614)
* pass barcode options to mlkit

* rm doubled FORMAT_ALL_FORMATS
2019-12-01 20:50:57 -03:00
semantic-release-bot
c728529563 chore(release): 3.13.0 [skip ci]
# [3.13.0](https://github.com/react-native-community/react-native-camera/compare/v3.12.0...v3.13.0) (2019-11-29)

### Features

* **types:** Add "URL" to Barcode types & export additional TS types ([#2613](https://github.com/react-native-community/react-native-camera/issues/2613)) ([3f1334c](https://github.com/react-native-community/react-native-camera/commit/3f1334c))
2019-11-29 22:04:16 +00:00
Kyle Johnson
3f1334c5e0 feat(types): Add "URL" to Barcode types & export additional TS types (#2613)
* Add "URL" to flow types

* add "URL" to barcodes & export additional TS types

* add optional format to flow

* add optionl format prop to TS
2019-11-29 19:00:10 -03:00
semantic-release-bot
ecb20719d0 chore(release): 3.12.0 [skip ci]
# [3.12.0](https://github.com/react-native-community/react-native-camera/compare/v3.11.1...v3.12.0) (2019-11-29)

### Bug Fixes

* **ios:** camera is not detecting any faces ([#2611](https://github.com/react-native-community/react-native-camera/issues/2611)) ([b3d0ebe](https://github.com/react-native-community/react-native-camera/commit/b3d0ebe))

### Features

* **docs:** Feature/simplify installtion ([#2606](https://github.com/react-native-community/react-native-camera/issues/2606)) ([a39e8a8](https://github.com/react-native-community/react-native-camera/commit/a39e8a8))
2019-11-29 21:18:30 +00:00
mieszko4
a39e8a87f8 feat(docs): Feature/simplify installtion (#2606)
* docs: split installation into 2 main sections, simplify required steps

* doc: structure Additional installation steps

* docs: Hide firebase additional android steps

* docs: Highlight code snippets, add link to Windows
2019-11-29 18:14:31 -03:00
annakoro
b3d0ebe649 fix(ios): camera is not detecting any faces (#2611) 2019-11-29 11:02:25 -03:00
Chau Tran
168b3eec8b fix onBarcodeRead (#2604) 2019-11-24 12:30:30 -03:00
mieszko4
e47ffb5e50 Add required steps for android when using rn60 (#2602) 2019-11-22 11:00:13 -03:00
semantic-release-bot
36ba510f39 chore(release): 3.11.1 [skip ci]
## [3.11.1](https://github.com/react-native-community/react-native-camera/compare/v3.11.0...v3.11.1) (2019-11-20)

### Bug Fixes

* **mlkit:** implement proper RNFaceDetectorModuleMLKit if FirebaseMLVision is una… ([#2599](https://github.com/react-native-community/react-native-camera/issues/2599)) ([e35cc2d](https://github.com/react-native-community/react-native-camera/commit/e35cc2d))
2019-11-20 10:13:46 +00:00
Moritz
e35cc2dfd3 fix(mlkit): implement proper RNFaceDetectorModuleMLKit if FirebaseMLVision is una… (#2599)
* implement proper RNFaceDetectorModuleMLKit if FirebaseMLVision is unavailable

* fix constants
2019-11-20 07:09:34 -03:00
semantic-release-bot
92525f2c69 chore(release): 3.11.0 [skip ci]
# [3.11.0](https://github.com/react-native-community/react-native-camera/compare/v3.10.0...v3.11.0) (2019-11-20)

### Features

* **exif:** Implement writeExif for iOS, Android improvements ([#2577](https://github.com/react-native-community/react-native-camera/issues/2577)) ([aa22fd1](https://github.com/react-native-community/react-native-camera/commit/aa22fd1))
2019-11-20 03:26:12 +00:00
cristianoccazinsp
aa22fd1fff feat(exif): Implement writeExif for iOS, Android improvements (#2577)
* - Improve Android code so skipProcessing is not needed, the code is more in line with iOS, and is "fast" by default. This means that skipProcessing is no longer needed (nor used), and adding additional options will "slow down" the capture as expected, rather than having always a lot of processing. This shouldn't be a breaking change.

- document the writeExif option, and implement it for iOS as well.

* Release CF object which could cause a memleak
2019-11-20 00:22:08 -03:00
semantic-release-bot
7fa631f32d chore(release): 3.10.0 [skip ci]
# [3.10.0](https://github.com/react-native-community/react-native-camera/compare/v3.9.0...v3.10.0) (2019-11-20)

### Bug Fixes

* **android:** fix possible crash when attempting to retrieve camera parameters. ([#2570](https://github.com/react-native-community/react-native-camera/issues/2570)) ([be8a08c](https://github.com/react-native-community/react-native-camera/commit/be8a08c))
* **android:** Possible ANR due to events not fired on the main thread ([#2591](https://github.com/react-native-community/react-native-camera/issues/2591)) ([ad9d084](https://github.com/react-native-community/react-native-camera/commit/ad9d084))

### Features

* **docs:** update example readme and ios splash screen text ([#2589](https://github.com/react-native-community/react-native-camera/issues/2589)) ([cd0ca06](https://github.com/react-native-community/react-native-camera/commit/cd0ca06))
* **docs:** update react-navigation doc ([#2574](https://github.com/react-native-community/react-native-camera/issues/2574)) ([81563d7](https://github.com/react-native-community/react-native-camera/commit/81563d7))
* **example:** New example app using RN 0.61, native-base, and react-navigation. ([#2588](https://github.com/react-native-community/react-native-camera/issues/2588)) ([9c6fcea](https://github.com/react-native-community/react-native-camera/commit/9c6fcea))
* **ios:** Handle audio interruption in session queue. This prevents the session isRunning flag from getting corrupted due to concurrent updates to the session. ([#2567](https://github.com/react-native-community/react-native-camera/issues/2567)) ([ffbd805](https://github.com/react-native-community/react-native-camera/commit/ffbd805))
* **ios:** Preserve exif/metadata on photo capture. ([#2573](https://github.com/react-native-community/react-native-camera/issues/2573)) ([fabacb4](https://github.com/react-native-community/react-native-camera/commit/fabacb4))
* **npm:** ignore docs and publish 3.11.0 ([7c1284f](https://github.com/react-native-community/react-native-camera/commit/7c1284f))
* **npm:** ignore website when publishing to npm, manual bump ([aa0e2a9](https://github.com/react-native-community/react-native-camera/commit/aa0e2a9))
* **ts:** Update index.d.ts ([#2590](https://github.com/react-native-community/react-native-camera/issues/2590)) ([eece04a](https://github.com/react-native-community/react-native-camera/commit/eece04a))
2019-11-20 02:44:42 +00:00
Sibelius Seraphini
7c1284f73f
feat(npm): ignore docs and publish 3.11.0 2019-11-19 23:39:46 -03:00
Sibelius Seraphini
aa0e2a9baf
feat(npm): ignore website when publishing to npm, manual bump 2019-11-19 23:33:15 -03:00
cristianoccazinsp
cd0ca062e8 feat(docs): update example readme and ios splash screen text (#2589) 2019-11-18 09:53:26 -03:00
maderesponsively
eece04a66c feat(ts): Update index.d.ts (#2590)
Added missing googleVisionBarcodeMode prop
2019-11-18 09:53:06 -03:00
cristianoccazinsp
ad9d0840fd fix(android): Possible ANR due to events not fired on the main thread (#2591)
* This is a fix for events possibly being fired not on the main thread, which could cause the whole app to freeze.

* Fire events on the right thread. No need to use UI thread, and fix the still works
2019-11-18 09:52:35 -03:00
cristianoccazinsp
9c6fcea43e feat(example): New example app using RN 0.61, native-base, and react-navigation. (#2588)
Includes a camera screen with support for the right dimensions, aspect ratio, flash, tap to focus, pinch to zoom, flash, and multi camera support.
2019-11-15 11:15:19 -03:00
cristianoccazinsp
ffbd805bcf feat(ios): Handle audio interruption in session queue. This prevents the session isRunning flag from getting corrupted due to concurrent updates to the session. (#2567) 2019-11-11 11:42:58 -03:00
cristianoccazinsp
be8a08ce9c fix(android): fix possible crash when attempting to retrieve camera parameters. (#2570) 2019-11-11 11:30:06 -03:00
cristianoccazinsp
fabacb4e93 feat(ios): Preserve exif/metadata on photo capture. (#2573)
* Preserve exif/metadata on photo capture. Add a few comments to each step of the capture process

* orientation must be fixed before mirroring

* x/y dimensions are redundantly updated (storing the image sets them automatically). However, orientation must be reset on any image change since the final stored image is automatically rotated when it is modified in place.

* revert mirrorImage order, has to be first since forceUpOrientation adjusts the image afterwards.

* Minor change: also implement `onPictureTaken` for iOS in case anyone needs the early event.
2019-11-11 11:29:16 -03:00
Theodore Sevvos
81563d7a0b feat(docs): update react-navigation doc (#2574) 2019-11-11 11:28:41 -03:00
Sibelius Seraphini
cc3016fe43
doc(tidelift): add security section on readme
[skip ci]
2019-11-08 16:16:54 -03:00
semantic-release-bot
4eb67c7b63 chore(release): 3.9.0 [skip ci]
# [3.9.0](https://github.com/react-native-community/react-native-camera/compare/v3.8.0...v3.9.0) (2019-11-04)

### Bug Fixes

* **ios:** Fix for a possible crash when changing devices and changing focus. If the new device resets the focus, "defocusing" might not be possible if the new device does not support auto focus. For this reason, we need to do a different cleanup on the focus and exposed flags and events. ([#2557](https://github.com/react-native-community/react-native-camera/issues/2557)) ([8f4601b](https://github.com/react-native-community/react-native-camera/commit/8f4601b))

### Features

* **android:** Android ui thread ([#2560](https://github.com/react-native-community/react-native-camera/issues/2560)) ([87774dd](https://github.com/react-native-community/react-native-camera/commit/87774dd))
* **Ios:** handle audio interruptions ([#2565](https://github.com/react-native-community/react-native-camera/issues/2565)) ([59dfdb6](https://github.com/react-native-community/react-native-camera/commit/59dfdb6))
2019-11-04 21:46:50 +00:00
cristianoccazinsp
59dfdb649a feat(Ios): handle audio interruptions (#2565)
* This update tries to improve audio recording interruptions on iOS due to phone calls or background music.

- Use a more generic event to handle session interruptions. This removes the need to listen to foreground/background events, and stopping the session this way was actually redundant/wrong (see https://forums.developer.apple.com/thread/61406). This also makes session stopping detection more reliable (calls, suspension due to a call or notification, etc., which would previously not set the recording interrupted flag on every case)

From the above docs: "No, incorrect. You _never_ need to stop your capture session. The capture session automatically stops itself when your app goes to the background and resumes itself when you come back to the foreground."

- Allow for `captureAudio` updates to also update the audio connections internally so the prop can be correctly updated on the fly without remounting.

- add onAudioInterrupted and onAudioConnected events so the UI can handle scenarios where audio is wanted but not available. This should also help in keeping the preview active even if audio is interrupted and we have captureAudio={true}. Lastly, it can be used to detect if we can record audio or not due to the dummy implementation of the audio permission on iOS always returning true.

- check, activate, and release audio sessions (if captureAudio) so we can detect early if audio is available before attempting to connect the input. This will also allow us to detect if we can record even if there was already a call before opening the camera.

- use proper observer for session error instead of of the strong self block. No benefit, but makes code more readable and allows access to instance variables

- getDeviceOrientationWithBlock might fire more than once under some circumstances, ending up taking a picture or video twice. Add a lock and additional check to prevent this.

* no need for change check,

* do not resume audio if we were hinted not to (e.g., music playback happening)

* start session here also on session queue.

* check for session running before trying to record or capture.
This should fix a possible race condition where both the session start call happens at the same time as the record call

* no need to set orientation on constructor, and set it on session queue to prevent race conditions

* move device init and checks also to session queue. This prevents possible double initializations.
2019-11-04 18:39:37 -03:00
cristianoccazinsp
8f4601b3b0 fix(ios): Fix for a possible crash when changing devices and changing focus. If the new device resets the focus, "defocusing" might not be possible if the new device does not support auto focus. For this reason, we need to do a different cleanup on the focus and exposed flags and events. (#2557) 2019-11-04 17:42:28 -03:00
cristianoccazinsp
87774dd370 feat(android): Android ui thread (#2560)
* Move heavy work to a dedicated background thread. Improves camera initial loading and resumes from background.

Details:

- Use a HandlerThread to delegate heavy tasks to background. The thread is managed by the view, and passed down to the implementation in case it also needs to use it. The view will fire start calls and other possibly heavy operations in this thread to avoid ANRs. Some code sent to this thread:
    - start calls: start is extremely heavy and will cause ANRs on some devices, especially when coming back from background
    - Camera1: some preset changes fire a stop/start sequence. These will now happen in the background thread
    - take picture and start recording (from view class) will also start in this thread

- Add some extra null checks

- View was not properly cleaning up itself on destroy (host destroy event was never fired)

* catch possible errors when starting camera preview. This might still randomly fail on some devices for some reason.

* delay capture in progress until we have resumed/paused preview.

* do not crash the app if set texture setup failed

* more synchronized checks to prevent crashes due to concurrent camera updates

* remove unused imports
2019-11-04 14:53:42 -03:00
semantic-release-bot
0158ebfd39 chore(release): 3.8.0 [skip ci]
# [3.8.0](https://github.com/react-native-community/react-native-camera/compare/v3.7.2...v3.8.0) (2019-10-19)

### Bug Fixes

* **ios:** Honor captureAudio flag by not requesting audio input if set to false. ([#2542](https://github.com/react-native-community/react-native-camera/issues/2542)) ([db8ce26](https://github.com/react-native-community/react-native-camera/commit/db8ce26))

### Features

* **android:** support null object of androidPermissionOptions to avoid request window ([#2551](https://github.com/react-native-community/react-native-camera/issues/2551)) ([20e0486](https://github.com/react-native-community/react-native-camera/commit/20e0486))
* **ci:** CircleCI Fix & Optimizations ([#2550](https://github.com/react-native-community/react-native-camera/issues/2550)) ([4705834](https://github.com/react-native-community/react-native-camera/commit/4705834))
* **readme:** improve tidelift ([28e8ad5](https://github.com/react-native-community/react-native-camera/commit/28e8ad5))
* **torch:** Torch fixes for iOS and a few nil checks. ([#2543](https://github.com/react-native-community/react-native-camera/issues/2543)) ([7abc7c2](https://github.com/react-native-community/react-native-camera/commit/7abc7c2))
2019-10-19 02:12:02 +00:00
Sibelius Seraphini
255e19e77a
doc(tidelift): add tidelift for enterprise 2019-10-18 23:07:24 -03:00
Symous
20e04863c7 feat(android): support null object of androidPermissionOptions to avoid request window (#2551) 2019-10-18 08:44:38 -03:00
Michael Thanh
4705834f08 feat(ci): CircleCI Fix & Optimizations (#2550)
* fix(docs-ci): restore builds and add gradle caching

* fix(ci-docs): comment config out to test key changes

* fix(docs-ci): fix gradle caching keys

* fix(docs-ci): fixed another typo in gradle cache key

* fix(docs-ci): separate yarn and gradle steps for app

* fix(docs-ci): experiment w/ jvm RAM and remove 2nd yarn

* fix(docs-ci): add yarn install statement back in

* fix(docs-ci): move gradle cache restore earlier

* fix(docs-ci): add deploy steps and job back in [skip ci]

* fix(docs-ci): change gradle cache keys to use multiple files

* fix(docs-ci): add artifacting to job

* fix(deploy-ci): add deploy steps and job back in [skip ci]
2019-10-18 08:42:21 -03:00
Sibelius Seraphini
28e8ad5734
feat(readme): improve tidelift 2019-10-16 18:12:11 -03:00
cristianoccazinsp
7abc7c2e01 feat(torch): Torch fixes for iOS and a few nil checks. (#2543)
* Torch fixes for iOS and a few nil checks.

- Torch turned on by default should work as expected (turned on after mounting and camera type switch)
- Torch maintained when video recording starts (it will flicked if preset has to change)
- Torch resumed when app comes back from background (it is disabled on session pause)

* Fix Torch mode while recording for Android as well.
2019-10-16 18:09:07 -03:00
cristianoccazinsp
db8ce264bf fix(ios): Honor captureAudio flag by not requesting audio input if set to false. (#2542)
Further improve video stopping after the slight delay was added so the stop operation works even if video didn't start yet.
2019-10-16 06:50:59 -03:00
semantic-release-bot
b74d31f4ca chore(release): 3.7.2 [skip ci]
## [3.7.2](https://github.com/react-native-community/react-native-camera/compare/v3.7.1...v3.7.2) (2019-10-14)

### Bug Fixes

* **ios:** Remove flickering due to audio input ([#2539](https://github.com/react-native-community/react-native-camera/issues/2539)) ([127da64](https://github.com/react-native-community/react-native-camera/commit/127da64))
2019-10-14 13:41:45 +00:00
cristianoccazinsp
127da64382 fix(ios): Remove flickering due to audio input (#2539)
* Use connection for muting instead of adding/removing outputs to reduce/remove flickering while recording.

* Add a tiny delay before recording starts to prevent the first frame of the video from being underexposed/black.
2019-10-14 10:37:39 -03:00
cristianoccazinsp
6b7d7f4a64 feature(ios): Ios exposure poi (#2514)
* feat: autoexposure on point of interest and defocus on subject change

* Impelement cameraIds for iOS, and various iOS bug fixes.

Summary:

- Implement getCameraIds and cameraId property to manually select a camera device.

- Fix the internal preset being used to properly use a photo and video preset, and check for invalid presets on camera switch.
    - This fixes a bug that would happen after recording. After a recording is complete, the camera preset was set to 4k permanently, and attempting to select any camera that does not support that preset would result in an totally unusable camera. Now, the "Photo" preset is the default which should be the highest quality option for photos, and the previously used "High" preset will be used as video default if no value is provided.
    - This also adds proper support to setting the undocumented "pictureSize" property. Setting this property will change the default photo quality to be that one.

- Minor cleanup to the camera initialization so the same code is not called as many times redundantly (start session / device happening multiple times)
    - The reduced redundant calls to start session and session updates should make the camera startup slightly faster.

- Fix for warnings issued due to misuse of the "isRecording" property. This property was defined as both as a property and a method and was both getting set manually and retrieved with a function. It should now consistently only be retrieved with a function based on the real recording status. Should have no behaivour change, but removes a pesky warning.

- Fix an issue related to the camera getting stuck after a background resume by removing the use of the queue for those two events.

- Fixes a wrong event unsubscription (UIDeviceOrientationDidChangeNotification to UIApplicationDidChangeStatusBarOrientationNotification) from a previous change. Also move event subscriptions to superview changes for consistency and so they are not used/consumed if not needed. After testing, the View of RNCamera is instantiated twice (for some reason I couldn't find) but used only once. RN keeps a reference to the view in memory even after the camera is destroyed, resulting in these events getting fired and handled all the time during the app's lifetime.

* add maxZoom property to iOS.

Android: Not needed as of now. Also, zoom multiplier behaves different on Android and can't be used with the same value as iOS.

* add auto exposure option.
This branch is temporary from the other changes until the proper changes from https://github.com/react-native-community/react-native-camera/pull/2423/files are merged.

* allow for expose POI to also be cleared

* Add ultra-wide lense support. Requires XCode with SDK for iOS 13

* check that video capture device is ready before capturing, fix for string cameraId assignment

* add missing ios 13 camera types and exposure check.

* remove duplicates from camera id list, return its type on IOS, handle WB crash on unsupported devices.

* Do not return virtual devices (we can't really use them with the library), update zoom and flash on preset change so they are maintained while recording/restoring.

* remove redundant duplicates check, add SDK macro check for ultra wide lenses, remove virtual cameras from query

* Add more info about deviceType and iOS camera IDs behaviour.
2019-10-10 12:01:16 -03:00
semantic-release-bot
ae390037ff chore(release): 3.7.1 [skip ci]
## [3.7.1](https://github.com/react-native-community/react-native-camera/compare/v3.7.0...v3.7.1) (2019-10-09)

### Bug Fixes

* **android:** Add synchronized checks on some code that might cause issues if called concurrently. ([#2526](https://github.com/react-native-community/react-native-camera/issues/2526)) ([686ed2b](https://github.com/react-native-community/react-native-camera/commit/686ed2b))
2019-10-09 14:41:17 +00:00
cristianoccazinsp
686ed2bea8 fix(android): Add synchronized checks on some code that might cause issues if called concurrently. (#2526)
Add try catch on setDisplayOrientation

Should improve issues from https://github.com/react-native-community/react-native-camera/issues/2525
2019-10-09 11:37:00 -03:00
semantic-release-bot
dd6c5a4e38 chore(release): 3.7.0 [skip ci]
# [3.7.0](https://github.com/react-native-community/react-native-camera/compare/v3.6.0...v3.7.0) (2019-10-08)

### Features

* **ios:** Add cameraId feature to iOS and various bug fixes ([#2510](https://github.com/react-native-community/react-native-camera/issues/2510)) ([58f3b3e](https://github.com/react-native-community/react-native-camera/commit/58f3b3e))
2019-10-08 15:30:13 +00:00
cristianoccazinsp
58f3b3edbd feat(ios): Add cameraId feature to iOS and various bug fixes (#2510)
* Impelement cameraIds for iOS, and various iOS bug fixes.

Summary:

- Implement getCameraIds and cameraId property to manually select a camera device.

- Fix the internal preset being used to properly use a photo and video preset, and check for invalid presets on camera switch.
    - This fixes a bug that would happen after recording. After a recording is complete, the camera preset was set to 4k permanently, and attempting to select any camera that does not support that preset would result in an totally unusable camera. Now, the "Photo" preset is the default which should be the highest quality option for photos, and the previously used "High" preset will be used as video default if no value is provided.
    - This also adds proper support to setting the undocumented "pictureSize" property. Setting this property will change the default photo quality to be that one.

- Minor cleanup to the camera initialization so the same code is not called as many times redundantly (start session / device happening multiple times)
    - The reduced redundant calls to start session and session updates should make the camera startup slightly faster.

- Fix for warnings issued due to misuse of the "isRecording" property. This property was defined as both as a property and a method and was both getting set manually and retrieved with a function. It should now consistently only be retrieved with a function based on the real recording status. Should have no behaivour change, but removes a pesky warning.

- Fix an issue related to the camera getting stuck after a background resume by removing the use of the queue for those two events.

- Fixes a wrong event unsubscription (UIDeviceOrientationDidChangeNotification to UIApplicationDidChangeStatusBarOrientationNotification) from a previous change. Also move event subscriptions to superview changes for consistency and so they are not used/consumed if not needed. After testing, the View of RNCamera is instantiated twice (for some reason I couldn't find) but used only once. RN keeps a reference to the view in memory even after the camera is destroyed, resulting in these events getting fired and handled all the time during the app's lifetime.

* add maxZoom property to iOS.

Android: Not needed as of now. Also, zoom multiplier behaves different on Android and can't be used with the same value as iOS.
2019-10-08 12:24:21 -03:00
Mateus Andrade
18c00efd75
Merge pull request #2516 from ErickMaeda/patch-1
Add Info.plist format on README.md
2019-10-01 19:46:02 -03:00
Erick Maeda Lopes
68c3e3bdf8
Add Info.plist format on README.md 2019-10-01 21:33:02 +01:00
semantic-release-bot
e533d50572 chore(release): 3.6.0 [skip ci]
# [3.6.0](https://github.com/react-native-community/react-native-camera/compare/v3.5.0...v3.6.0) (2019-09-24)

### Features

* **android:** Support to enumerate and select Camera devices ([#2492](https://github.com/react-native-community/react-native-camera/issues/2492)) ([612cb65](https://github.com/react-native-community/react-native-camera/commit/612cb65))
2019-09-24 13:51:56 +00:00
cristianoccazinsp
612cb65f2a feat(android): Support to enumerate and select Camera devices (#2492)
* Android only: Support to enumerate Camera devices and to select from one of them.

* No need to have the camera in running state if querying for IDs.

* Silly bug, not using string compare. Also, do not run any camera code if the actual camera doesn't change.

* Crash fix when focus coordinates are set to null/undefined not being handled. Notes about not supported flash/focus

* If a camera is not found, set the first available camera just like Camera2 does.

* missing semicolon

* Fixes to Camera2 API:

- First change is related to camera selection by ID. Some more code was required to correctly set the facing flag and characteristics
- Second change fixes a previous issue (unrelated to the PR) that was causing the preview of the camera to look upside down on rotated devices. Device rotation should not affect the display (nor set it). Device rotation should however be used for the final image (and not screen rotation). Some code was borrowed from Camera1.
2019-09-24 10:47:23 -03:00
semantic-release-bot
200c7e136c chore(release): 3.5.0 [skip ci]
# [3.5.0](https://github.com/react-native-community/react-native-camera/compare/v3.4.0...v3.5.0) (2019-09-24)

### Bug Fixes

* **android:** Update Camera1 to not crash on invalid ratio ([#2501](https://github.com/react-native-community/react-native-camera/issues/2501)) ([702f608](https://github.com/react-native-community/react-native-camera/commit/702f608))

### Features

* **ios:** videoBitrate option for iOS ([#2504](https://github.com/react-native-community/react-native-camera/issues/2504)) ([38a5ffb](https://github.com/react-native-community/react-native-camera/commit/38a5ffb))
2019-09-24 12:37:33 +00:00
cristianoccazinsp
702f60862e fix(android): Update Camera1 to not crash on invalid ratio (#2501)
Setting a property ends up with an unhandled exception that cannot be caught easily by RN. This should also make the behaviour consistent with camera startup and Camera2.
2019-09-24 09:32:47 -03:00
Nathan Heinrich
38a5ffb2eb feat(ios): videoBitrate option for iOS (#2504)
* Update RNCamera.m

Add videoBitrate option for ios, setting video bitrate requires a codec to be set

* Update API documentation

* Update documentation

* Update typings
2019-09-24 09:32:22 -03:00
Rock Hu
0026b46c74 Fix jitpack.io maven link (#2497) 2019-09-23 13:43:21 -03:00
Simon Stern
204da4fa80
Merge pull request #2495 from cristianoccazinsp/patch-1
Use a more appropriate orientation change event
2019-09-19 21:36:14 -04:00
cristianoccazinsp
653714991b
Use a more appropriate orientation change event
Since the code relies on the status bar orientation, it makes sense to use UIApplicationDidChangeStatusBarOrientationNotification instead. This should fix some issues where the orientation value of the status bar has not been updated when the event is received.
2019-09-19 17:49:25 -03:00
semantic-release-bot
17293f73cc chore(release): 3.4.0 [skip ci]
# [3.4.0](https://github.com/react-native-community/react-native-camera/compare/v3.3.3...v3.4.0) (2019-09-09)

### Features

* **android:** Improve Android Camera1 error and concurrency handling. ([#2471](https://github.com/react-native-community/react-native-camera/issues/2471)) ([a20eb06](https://github.com/react-native-community/react-native-camera/commit/a20eb06))
2019-09-09 12:21:04 +00:00
cristianoccazinsp
a20eb06139 feat(android): Improve Android Camera1 error and concurrency handling. (#2471)
These changes include the following:
- use atomic boolean for capturing photo flag just like video
- add more exception catching and checks
- raise error instead of failing silently if can't capture photo - improve error handling here
- synchronize stop to avoid race conditions and crashes
- delay params updates (surface) if capturing or recording to avoid bugs
- do not allow video or photo capture if already doing video or photo
2019-09-09 09:15:41 -03:00
Mateus Andrade
add1c0c01f
Merge pull request #2474 from luancurti/chore/upgrade-gradle-version
Upgrade gradle version
2019-09-09 00:11:00 -03:00
luancurti
1d6a2ef945 chore(gradle): upgrade gradle version 2019-09-08 22:01:50 -03:00
semantic-release-bot
6e14c0b245 chore(release): 3.3.3 [skip ci]
## [3.3.3](https://github.com/react-native-community/react-native-camera/compare/v3.3.2...v3.3.3) (2019-09-05)

### Bug Fixes

* **android:** Fix app freeze on app/host pause on Android. Fix is quite simple, recording has to be stopped before the camera preview. ([#2467](https://github.com/react-native-community/react-native-camera/issues/2467)) ([57bf513](https://github.com/react-native-community/react-native-camera/commit/57bf513))
2019-09-05 21:04:25 +00:00
cristianoccazinsp
57bf513d5b fix(android): Fix app freeze on app/host pause on Android. Fix is quite simple, recording has to be stopped before the camera preview. (#2467)
Fix taken from: https://stackoverflow.com/questions/8914454/mediarecorder-stop-hanging-with-android-4-0-ics/18876200

TODO: Review Camera2 implementation since it might have the same issue.
2019-09-05 17:59:57 -03:00
semantic-release-bot
654f1b221f chore(release): 3.3.2 [skip ci]
## [3.3.2](https://github.com/react-native-community/react-native-camera/compare/v3.3.1...v3.3.2) (2019-09-02)

### Bug Fixes

* **android:** Add an additional error check to avoid crashes on Android. This fix comes from testing on multiple devices, where for some unknown reason the decode process fails and returns null and the app crashes immediately due to a null pointer exception. This attempts to handle this issue more gracefully. ([#2446](https://github.com/react-native-community/react-native-camera/issues/2446)) ([497e4a2](https://github.com/react-native-community/react-native-camera/commit/497e4a2))
2019-09-02 18:35:47 +00:00
cristianoccazinsp
497e4a21d8 fix(android): Add an additional error check to avoid crashes on Android. This fix comes from testing on multiple devices, where for some unknown reason the decode process fails and returns null and the app crashes immediately due to a null pointer exception. This attempts to handle this issue more gracefully. (#2446) 2019-09-02 15:29:17 -03:00
semantic-release-bot
ea935bd4c2 chore(release): 3.3.1 [skip ci]
## [3.3.1](https://github.com/react-native-community/react-native-camera/compare/v3.3.0...v3.3.1) (2019-09-02)

### Bug Fixes

* **android:** android-mlkit barcode bounds are inaccurate ([#2462](https://github.com/react-native-community/react-native-camera/issues/2462)) ([0323eaa](https://github.com/react-native-community/react-native-camera/commit/0323eaa))
2019-09-02 12:47:41 +00:00
joshslark
0323eaa47b fix(android): android-mlkit barcode bounds are inaccurate (#2462) 2019-09-02 09:42:59 -03:00
Simon Stern
07781ffbc4
Merge pull request #2459 from react-native-community/dependabot/npm_and_yarn/website/mixin-deep-1.3.2
chore(deps): bump mixin-deep from 1.3.1 to 1.3.2 in /website
2019-08-30 12:27:14 -04:00
dependabot[bot]
c4549d934a
chore(deps): bump mixin-deep from 1.3.1 to 1.3.2 in /website
Bumps [mixin-deep](https://github.com/jonschlinkert/mixin-deep) from 1.3.1 to 1.3.2.
- [Release notes](https://github.com/jonschlinkert/mixin-deep/releases)
- [Commits](https://github.com/jonschlinkert/mixin-deep/compare/1.3.1...1.3.2)

Signed-off-by: dependabot[bot] <support@github.com>
2019-08-30 14:49:10 +00:00
Simon Stern
186d512f83
Merge pull request #2447 from react-native-community/dependabot/npm_and_yarn/eslint-utils-1.4.2
chore(deps): bump eslint-utils from 1.3.1 to 1.4.2
2019-08-30 10:49:00 -04:00
Simon Stern
c4d86218a5
Merge pull request #2452 from react-native-community/dependabot/npm_and_yarn/examples/basic/mixin-deep-1.3.2
chore(deps): bump mixin-deep from 1.3.1 to 1.3.2 in /examples/basic
2019-08-30 10:48:28 -04:00
Simon Stern
481e7d91ac
Merge pull request #2453 from react-native-community/dependabot/npm_and_yarn/mixin-deep-1.3.2
chore(deps): bump mixin-deep from 1.3.1 to 1.3.2
2019-08-30 10:48:06 -04:00
Simon Stern
9080bc8173
Merge pull request #2454 from react-native-community/dependabot/npm_and_yarn/examples/mlkit/mixin-deep-1.3.2
chore(deps): bump mixin-deep from 1.3.1 to 1.3.2 in /examples/mlkit
2019-08-30 10:47:42 -04:00
dependabot[bot]
368f2d0860
chore(deps): bump mixin-deep from 1.3.1 to 1.3.2 in /examples/mlkit
Bumps [mixin-deep](https://github.com/jonschlinkert/mixin-deep) from 1.3.1 to 1.3.2.
- [Release notes](https://github.com/jonschlinkert/mixin-deep/releases)
- [Commits](https://github.com/jonschlinkert/mixin-deep/compare/1.3.1...1.3.2)

Signed-off-by: dependabot[bot] <support@github.com>
2019-08-29 01:07:43 +00:00
dependabot[bot]
9c534b09e8
chore(deps): bump mixin-deep from 1.3.1 to 1.3.2
Bumps [mixin-deep](https://github.com/jonschlinkert/mixin-deep) from 1.3.1 to 1.3.2.
- [Release notes](https://github.com/jonschlinkert/mixin-deep/releases)
- [Commits](https://github.com/jonschlinkert/mixin-deep/compare/1.3.1...1.3.2)

Signed-off-by: dependabot[bot] <support@github.com>
2019-08-29 01:06:29 +00:00
dependabot[bot]
7a3c8a1a11
chore(deps): bump mixin-deep from 1.3.1 to 1.3.2 in /examples/basic
Bumps [mixin-deep](https://github.com/jonschlinkert/mixin-deep) from 1.3.1 to 1.3.2.
- [Release notes](https://github.com/jonschlinkert/mixin-deep/releases)
- [Commits](https://github.com/jonschlinkert/mixin-deep/compare/1.3.1...1.3.2)

Signed-off-by: dependabot[bot] <support@github.com>
2019-08-29 00:53:49 +00:00
Mateus Andrade
6d7e6e4d9c
Merge pull request #2448 from jaideepghosh/master
fix(docs):Add CAMERA permission for Android.
2019-08-28 09:00:55 -03:00
Jaideep Ghosh
1530b883b9
fix:Add CAMERA permission for Android. 2019-08-28 16:35:13 +05:30
dependabot[bot]
56c824e0e3
chore(deps): bump eslint-utils from 1.3.1 to 1.4.2
Bumps [eslint-utils](https://github.com/mysticatea/eslint-utils) from 1.3.1 to 1.4.2.
- [Release notes](https://github.com/mysticatea/eslint-utils/releases)
- [Commits](https://github.com/mysticatea/eslint-utils/compare/v1.3.1...v1.4.2)

Signed-off-by: dependabot[bot] <support@github.com>
2019-08-26 20:38:02 +00:00
semantic-release-bot
c62be1e99a chore(release): 3.3.0 [skip ci]
# [3.3.0](https://github.com/react-native-community/react-native-camera/compare/v3.2.1...v3.3.0) (2019-08-22)

### Features

* **android:** Add exposure (brightness) support for iOS and standardize exposure value ([#2419](https://github.com/react-native-community/react-native-camera/issues/2419)) ([ccd6f0b](https://github.com/react-native-community/react-native-camera/commit/ccd6f0b))
2019-08-22 18:43:41 +00:00
Dominik Schwarz
ccd6f0b57c feat(android): Add exposure (brightness) support for iOS and standardize exposure value (#2419)
* Use standardized exposure value between 0 and 1

* Add iOS native exposure control

* Delete logging

* Add documentation + spell fixes

* Update RNCamera.m

* Remove reset of exposure after tap-to-focus
2019-08-22 15:38:53 -03:00
semantic-release-bot
70c8cbdb12 chore(release): 3.2.1 [skip ci]
## [3.2.1](https://github.com/react-native-community/react-native-camera/compare/v3.2.0...v3.2.1) (2019-08-22)

### Bug Fixes

* **ios:** for issue [#2434](https://github.com/react-native-community/react-native-camera/issues/2434) ([#2439](https://github.com/react-native-community/react-native-camera/issues/2439)) ([c9402b2](https://github.com/react-native-community/react-native-camera/commit/c9402b2))
2019-08-22 14:53:20 +00:00
Zayin Krige
c9402b2ddd fix(ios): for issue #2434 (#2439)
When VCARD doesnt contain ALL name fields, app crashes because it is trying to insert nil values into dictionary. This provides blank strings for nil values in vcard
2019-08-22 11:48:56 -03:00
semantic-release-bot
8c93ebd7aa chore(release): 3.2.0 [skip ci]
# [3.2.0](https://github.com/react-native-community/react-native-camera/compare/v3.1.2...v3.2.0) (2019-08-21)

### Features

* **ios:** rectOfInterest ([#1852](https://github.com/react-native-community/react-native-camera/issues/1852)) ([b47b80d](https://github.com/react-native-community/react-native-camera/commit/b47b80d))
2019-08-21 07:45:42 +00:00
chubakueno
b47b80d5a4 feat(ios): rectOfInterest (#1852) 2019-08-21 04:40:24 -03:00
semantic-release-bot
b90c58b794 chore(release): 3.1.2 [skip ci]
## [3.1.2](https://github.com/react-native-community/react-native-camera/compare/v3.1.1...v3.1.2) (2019-08-17)

### Bug Fixes

* **android:** This update does two things in order to fix [#2420](https://github.com/react-native-community/react-native-camera/issues/2420) and [#2421](https://github.com/react-native-community/react-native-camera/issues/2421). ([#2427](https://github.com/react-native-community/react-native-camera/issues/2427)) ([3407533](https://github.com/react-native-community/react-native-camera/commit/3407533))
2019-08-17 21:55:08 +00:00
cristianoccazinsp
3407533108 fix(android): This update does two things in order to fix #2420 and #2421. (#2427)
First, it updates the take picture call to capture right away instead of trying to focus again. This will match closer to what the native camera does, and also what the Camera2 does.

Secondly, it removes all calls to resetFocus after capturing and after a given timeout. This was causing issues when using autoFocusPointOfInterest, and it really didn't make sense to use an internal timeout to reset the focus. If anything, the user should do this from the JS side. A new method could also be exposed to do this.

Lastly, it adds some error catching logic to the autoFocus call. There was a chance on some devices that calling autoFocus while the device is capturing a photo that it would fail.

Tested on Google Pixel 2 (Android 9), Motorola G5 (Android 8), Samsung Grand Prime (Android 5?), and LG20 (android 6?). No issues so far.
2019-08-17 18:40:37 -03:00
semantic-release-bot
54e7dc1fee chore(release): 3.1.1 [skip ci]
## [3.1.1](https://github.com/react-native-community/react-native-camera/compare/v3.1.0...v3.1.1) (2019-08-08)

### Bug Fixes

* **ios:** wrap captureStillImageAsynchronouslyFromConnection with try/catch ([#2056](https://github.com/react-native-community/react-native-camera/issues/2056)) ([adac26f](https://github.com/react-native-community/react-native-camera/commit/adac26f))
2019-08-08 17:36:42 +00:00
Ruslan Bekenev
adac26f5cf fix(ios): wrap captureStillImageAsynchronouslyFromConnection with try/catch (#2056)
* wrap captureStillImageAsynchronouslyFromConnection with try/catch

the diff may look pretty big but the only change made here is
try/catch block added for captureStillImageAsynchronouslyFromConnection
call.
For some reason, this method may throw an exception saying about
inconsistent state.

* make sure null in cameraHandle isn't passed to Native code
2019-08-08 14:32:38 -03:00
semantic-release-bot
90225a96f0 chore(release): 3.1.0 [skip ci]
# [3.1.0](https://github.com/react-native-community/react-native-camera/compare/v3.0.2...v3.1.0) (2019-08-07)

### Features

* **android:** get format for android ([#2410](https://github.com/react-native-community/react-native-camera/issues/2410)) ([efb6b90](https://github.com/react-native-community/react-native-camera/commit/efb6b90))
2019-08-07 20:58:26 +00:00
TVMD
efb6b90036 feat(android): get format for android (#2410) 2019-08-07 17:54:10 -03:00
semantic-release-bot
1724ec3952 chore(release): 3.0.2 [skip ci]
## [3.0.2](https://github.com/react-native-community/react-native-camera/compare/v3.0.1...v3.0.2) (2019-08-07)

### Bug Fixes

* **android:** use initial exposure value ([#2418](https://github.com/react-native-community/react-native-camera/issues/2418)) ([c93e92f](https://github.com/react-native-community/react-native-camera/commit/c93e92f))
2019-08-07 20:53:12 +00:00
Dominik Schwarz
c93e92f602 fix(android): use initial exposure value (#2418) 2019-08-07 17:47:43 -03:00
dependabot[bot]
75d093d69d chore(deps): bump merge from 1.2.0 to 1.2.1 in /examples/basic (#2407)
Bumps [merge](https://github.com/yeikos/js.merge) from 1.2.0 to 1.2.1.
- [Release notes](https://github.com/yeikos/js.merge/releases)
- [Commits](https://github.com/yeikos/js.merge/compare/v1.2.0...v1.2.1)

Signed-off-by: dependabot[bot] <support@github.com>
2019-08-07 17:47:17 -03:00
dependabot[bot]
0f0d429c98 chore(deps): bump js-yaml from 3.10.0 to 3.13.1 (#2408)
Bumps [js-yaml](https://github.com/nodeca/js-yaml) from 3.10.0 to 3.13.1.
- [Release notes](https://github.com/nodeca/js-yaml/releases)
- [Changelog](https://github.com/nodeca/js-yaml/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nodeca/js-yaml/compare/3.10.0...3.13.1)

Signed-off-by: dependabot[bot] <support@github.com>
2019-08-07 17:47:08 -03:00
dependabot[bot]
14fa646a93 chore(deps): bump morgan from 1.9.0 to 1.9.1 (#2406)
Bumps [morgan](https://github.com/expressjs/morgan) from 1.9.0 to 1.9.1.
- [Release notes](https://github.com/expressjs/morgan/releases)
- [Changelog](https://github.com/expressjs/morgan/blob/master/HISTORY.md)
- [Commits](https://github.com/expressjs/morgan/compare/1.9.0...1.9.1)

Signed-off-by: dependabot[bot] <support@github.com>
2019-08-07 17:40:10 -03:00
dependabot[bot]
eef42fdf93 chore(deps): bump handlebars from 4.1.0 to 4.1.2 in /examples/mlkit (#2405)
Bumps [handlebars](https://github.com/wycats/handlebars.js) from 4.1.0 to 4.1.2.
- [Release notes](https://github.com/wycats/handlebars.js/releases)
- [Changelog](https://github.com/wycats/handlebars.js/blob/master/release-notes.md)
- [Commits](https://github.com/wycats/handlebars.js/compare/v4.1.0...v4.1.2)

Signed-off-by: dependabot[bot] <support@github.com>
2019-08-07 17:39:50 -03:00
dependabot[bot]
9b3db84898 chore(deps): bump js-yaml from 3.12.1 to 3.13.1 in /examples/mlkit (#2404)
Bumps [js-yaml](https://github.com/nodeca/js-yaml) from 3.12.1 to 3.13.1.
- [Release notes](https://github.com/nodeca/js-yaml/releases)
- [Changelog](https://github.com/nodeca/js-yaml/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nodeca/js-yaml/compare/3.12.1...3.13.1)

Signed-off-by: dependabot[bot] <support@github.com>
2019-08-07 17:39:38 -03:00
dependabot[bot]
1bf291753c chore(deps): bump js-yaml from 3.12.0 to 3.13.1 in /examples/basic (#2403)
Bumps [js-yaml](https://github.com/nodeca/js-yaml) from 3.12.0 to 3.13.1.
- [Release notes](https://github.com/nodeca/js-yaml/releases)
- [Changelog](https://github.com/nodeca/js-yaml/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nodeca/js-yaml/compare/3.12.0...3.13.1)

Signed-off-by: dependabot[bot] <support@github.com>
2019-08-07 17:39:27 -03:00
Simon Stern
3682aace2f
Merge pull request #2409 from react-native-community/dependabot/npm_and_yarn/fstream-1.0.12
chore(deps): bump fstream from 1.0.11 to 1.0.12
2019-08-07 15:10:04 -04:00
dependabot[bot]
f8abad88ad
chore(deps): bump fstream from 1.0.11 to 1.0.12
Bumps [fstream](https://github.com/npm/fstream) from 1.0.11 to 1.0.12.
- [Release notes](https://github.com/npm/fstream/releases)
- [Commits](https://github.com/npm/fstream/compare/v1.0.11...v1.0.12)

Signed-off-by: dependabot[bot] <support@github.com>
2019-08-02 14:21:09 +00:00
semantic-release-bot
919cda2a15 chore(release): 3.0.1 [skip ci]
## [3.0.1](https://github.com/react-native-community/react-native-camera/compare/v3.0.0...v3.0.1) (2019-08-02)

### Bug Fixes

* **android:** prevent crash when using Camera2 with autoFocusPointOfInterest ([#2401](https://github.com/react-native-community/react-native-camera/issues/2401)) ([3786223](https://github.com/react-native-community/react-native-camera/commit/3786223))
* **android:** Support writing custom Exif tags to modified image file ([#2402](https://github.com/react-native-community/react-native-camera/issues/2402)) ([c748b4e](https://github.com/react-native-community/react-native-camera/commit/c748b4e))
* **exif:** writing EXIF data with correct data type ([#2396](https://github.com/react-native-community/react-native-camera/issues/2396)) ([66e99d8](https://github.com/react-native-community/react-native-camera/commit/66e99d8))
* App name shouldn't be equal to the registered application ([#2393](https://github.com/react-native-community/react-native-camera/issues/2393)) ([a01187d](https://github.com/react-native-community/react-native-camera/commit/a01187d))
2019-08-02 14:19:36 +00:00
Tadas Talaikis
a01187d0b6 fix: App name shouldn't be equal to the registered application (#2393) 2019-08-02 11:10:23 -03:00
Valentin
c748b4eccc fix(android): Support writing custom Exif tags to modified image file (#2402) 2019-08-02 11:10:10 -03:00
Hanno Fellmann
66e99d8027 fix(exif): writing EXIF data with correct data type (#2396) 2019-08-02 11:09:50 -03:00
Valentin
3786223db2 fix(android): prevent crash when using Camera2 with autoFocusPointOfInterest (#2401) 2019-08-02 11:08:38 -03:00
semantic-release-bot
c90d86b122 chore(release): 3.0.0 [skip ci]
# [3.0.0](https://github.com/react-native-community/react-native-camera/compare/v2.11.1...v3.0.0) (2019-07-19)

### Features

* **docs:** add docs link on readme and also publish v3 to support ([2f6f8e6](https://github.com/react-native-community/react-native-camera/commit/2f6f8e6))

### BREAKING CHANGES

* **docs:** support androidX for react-native >= 60
2019-07-19 12:31:33 +00:00
Sibelius Seraphini
2f6f8e6cce
feat(docs): add docs link on readme and also publish v3 to support
androidX

BREAKING CHANGE: support androidX for react-native >= 60
2019-07-19 09:26:15 -03:00
Mateus Andrade
ce5311cb86
Merge pull request #2328 from xaphod/bugfix/ios-crash-on-error
Fix two crashes on iOS where error leads to runSession being called b…
2019-07-16 09:31:24 -03:00
dependabot[bot]
2a4dcf3dfb chore(deps): bump lodash.template from 4.4.0 to 4.5.0 (#2368)
Bumps [lodash.template](https://github.com/lodash/lodash) from 4.4.0 to 4.5.0.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.4.0...4.5.0)

Signed-off-by: dependabot[bot] <support@github.com>
2019-07-14 16:09:18 -03:00
dependabot[bot]
96481137fa chore(deps): bump lodash from 4.17.11 to 4.17.14 in /examples/basic (#2369)
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.11 to 4.17.14.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.11...4.17.14)

Signed-off-by: dependabot[bot] <support@github.com>
2019-07-14 16:09:08 -03:00
dependabot[bot]
4813cf3722 chore(deps): bump lodash from 4.17.11 to 4.17.14 in /examples/mlkit (#2370)
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.11 to 4.17.14.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.11...4.17.14)

Signed-off-by: dependabot[bot] <support@github.com>
2019-07-14 16:09:00 -03:00
dependabot[bot]
0d4f9fa732 chore(deps): bump lodash from 4.17.11 to 4.17.14 in /website (#2373)
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.11 to 4.17.14.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.11...4.17.14)

Signed-off-by: dependabot[bot] <support@github.com>
2019-07-14 16:08:52 -03:00
dependabot[bot]
c3f371a2fe chore(deps): bump lodash.merge from 4.6.1 to 4.6.2 in /website (#2367)
Bumps [lodash.merge](https://github.com/lodash/lodash) from 4.6.1 to 4.6.2.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/commits)

Signed-off-by: dependabot[bot] <support@github.com>
2019-07-14 16:08:44 -03:00
Laurin Quast
409d2a9eea break(androidX): upgrading to sdk 28 and androidx (#2068) (#2306)
* upgrading to sdk 28 and androidx

* revert attempt to fix build

* fixing build

* build version fix

* updating example app

* manifest update

* using stable release, instead of beta

* androidx migration doc

* migration doc update

* follow on androidx upgrade after rebase
2019-07-14 16:08:03 -03:00
semantic-release-bot
7699f5262f chore(release): 2.11.1 [skip ci]
## [2.11.1](https://github.com/react-native-community/react-native-camera/compare/v2.11.0...v2.11.1) (2019-07-09)

### Bug Fixes

* LinkingLibrariesWindows.md link ([#2365](https://github.com/react-native-community/react-native-camera/issues/2365)) ([00e9c32](https://github.com/react-native-community/react-native-camera/commit/00e9c32))
2019-07-09 20:44:44 +00:00
Rıdvan Altun
00e9c32453 fix: LinkingLibrariesWindows.md link (#2365) 2019-07-09 17:40:01 -03:00
Mateus Andrade
e6469bb630
Merge pull request #2332 from MateusAndrade/chore/androind-permission-example
Chore - setting androidCameraPermissionOptions to examples
2019-06-29 23:58:42 -03:00
Mateus Andrade
2facf5c71c
Merge pull request #2339 from canozinci/canozinci-patch-1
Update RNCamera.m to fix video quality mismatch while recording multiple videos
2019-06-25 13:53:14 -03:00
Can Ozinci
de88f74788
Update RNCamera.m 2019-06-25 17:27:06 +03:00
MateusAndrade
a12198b8b7 chore(camera-access): permission android Mlkit 2019-06-22 15:28:18 -03:00
MateusAndrade
1cd20cdacb chore(camera-access): change prop to androidCameraPermissionOptions 2019-06-22 15:22:44 -03:00
Mateus Andrade
4075cdf0b0
Update README.md 2019-06-22 15:13:11 -03:00
Mateus Andrade
9b99e66e1c
Update README.md 2019-06-21 23:34:02 -03:00
Mateus Andrade
cb73ffdf68
Merge pull request #7 from react-native-community/master
merge
2019-06-21 23:33:41 -03:00
Tim Carr
7ea241fa78 Fix two crashes on iOS where error leads to runSession being called before commitConfiguration 2019-06-21 15:48:51 -04:00
Andrew Chaa
a77b64cf5b Updating README with RN Camera instruction for iOS simulator (#2326)
* Update README.md

* Update README.md
2019-06-21 10:10:59 -03:00
semantic-release-bot
47ab6b3d0c chore(release): 2.11.0 [skip ci]
# [2.11.0](https://github.com/react-native-community/react-native-camera/compare/v2.10.2...v2.11.0) (2019-06-20)

### Bug Fixes

* **docs-ci:** setting GH_TOKEN_DOCS to deploy docs ([b891b1a](https://github.com/react-native-community/react-native-camera/commit/b891b1a))

### Features

* **funding:** add FUNDING.yml [skip ci] ([3e715b1](https://github.com/react-native-community/react-native-camera/commit/3e715b1))
2019-06-20 01:09:39 +00:00
Mateus Andrade
d5d849cb6d
Merge pull request #2322 from castillobgr/fix-onStatusChange-type
Fixes type of the onStatusChange callback in types/index.d.ts
2019-06-19 22:05:48 -03:00
David Castillo
85b6431353
Fixes type of the onStatusChange callback in types/index.d.ts
Currently, the `onStatusChange` has a type of 
```ts
onStatusChange?(event: {
    cameraStatus: CameraStatus;
    recordAudioPermissionStatus: keyof RecordAudioPermissionStatus;
  }): void
```
Which makes it very inconvenient to use with Typescript, having to set the `cameraStatus` field to `any` in the passed function:
```ts
const handleStatusChange = (event: {cameraStatus: any}) => {
    if (event.cameraStatus === 'NOT_AUTHORIZED') {
    }
  }
```
By changing it to
```ts
onStatusChange?(event: {
    cameraStatus: keyof CameraStatus;
    recordAudioPermissionStatus: keyof RecordAudioPermissionStatus;
  }): void
```
we're able to compare the new status against the intended type, autocomplete, and discard the `any`:
```ts

  const handleStatusChange = (event: {cameraStatus: keyof CameraStatus}) => {
    if (event.cameraStatus === 'NOT_AUTHORIZED') {
      onUnauthorized()
    }
  }
```
2019-06-19 12:53:44 -05:00
Mateus Andrade
117c2a5dcd
Merge pull request #6 from react-native-community/master
merge
2019-06-17 23:15:03 -03:00
Sibelius Seraphini
3e715b1535
feat(funding): add FUNDING.yml [skip ci] 2019-06-13 15:13:56 -03:00
Mateus Andrade
4fe18a5511
Merge pull request #2314 from MateusAndrade/hotfix/setting-gh-token-doc
Hotfix/setting gh token doc
2019-06-12 22:39:50 -03:00
MateusAndrade
b891b1a245 fix(docs-ci): setting GH_TOKEN_DOCS to deploy docs 2019-06-12 22:38:11 -03:00
Mateus Andrade
4d01c8e113
Merge pull request #5 from react-native-community/master
merge
2019-06-12 22:32:46 -03:00
semantic-release-bot
663b119552 chore(release): 2.10.2 [skip ci]
## [2.10.2](https://github.com/react-native-community/react-native-camera/compare/v2.10.1...v2.10.2) (2019-06-13)

### Bug Fixes

* **gh-user:** adding gh-user to deploy with docsaurus ([01d491d](https://github.com/react-native-community/react-native-camera/commit/01d491d))
2019-06-13 01:29:33 +00:00
Mateus Andrade
51b83e02fe
Merge pull request #2313 from MateusAndrade/hotfix/deploy-docs-ci
Hotfix/deploy docs ci
2019-06-12 22:24:12 -03:00
MateusAndrade
01d491d3ff fix(gh-user): adding gh-user to deploy with docsaurus 2019-06-12 22:21:44 -03:00
Mateus Andrade
363f513ed8
Merge pull request #4 from react-native-community/master
merge
2019-06-12 22:20:14 -03:00
Ronaldo Lima
f649e7a1fb
Merge pull request #2307 from MateusAndrade/feature/docsaurus-build
deploy docs based on master changes
2019-06-12 22:57:57 +02:00
Elphas Tori
729aa5d57e Missing AppRegistry Import (#2308)
Added missing AppRegistry in FaCC example
2019-06-10 09:23:30 -03:00
Mateus Andrade
d06963a273
Fix $GH_EMAIL 2019-06-09 11:58:33 -03:00
MateusAndrade
7c016f742b
Setting docs deploy only when master is changed 2019-06-08 22:02:03 -03:00
MateusAndrade
6655864bd5
Setting PR username to update docs 2019-06-08 22:00:08 -03:00
MateusAndrade
13b2366eb9
Testing GIT_USER docusaurus 2019-06-08 21:42:52 -03:00
MateusAndrade
0d496befa8
Removing filter to master to test docs deploy 2019-06-08 21:37:20 -03:00
MateusAndrade
06966e496e
Setting filter to deploy docs only when master is updated 2019-06-08 21:35:31 -03:00
MateusAndrade
8d187028da
chore(docs) setting a label to start to test ci deploy on pages 2019-06-08 21:34:33 -03:00
MateusAndrade
aea6c67e29
Defining ci envs 2019-06-08 21:23:54 -03:00
MateusAndrade
cd3cb26234
removing ci check 2019-06-08 21:05:03 -03:00
MateusAndrade
cba1451f58
Setting deploy-docs 2019-06-08 20:58:44 -03:00
MateusAndrade
3eb9e5ab26
Setting build to build-app 2019-06-08 20:56:33 -03:00
MateusAndrade
59d3fb7dfc
Setting deploy docs to run only when rc is deploying. Also, setting the config to yml 2019-06-08 20:52:02 -03:00
MateusAndrade
9ce4fb5aa1 removing require build to deploy docs 2019-06-08 20:40:13 -03:00
MateusAndrade
83b0456fb7
Applying a require on deploy docs 2019-06-08 20:24:29 -03:00
MateusAndrade
1644f753b3
Fixing yml circleci 2019-06-08 20:09:44 -03:00
MateusAndrade
1f06fd3557
Adding circleci config to deploy docs 2019-06-08 17:22:08 -03:00
MateusAndrade
efa10a4bc7
Setting circle ci config to deploy docs 2019-06-08 16:51:03 -03:00
semantic-release-bot
765daf400e chore(release): 2.10.1 [skip ci]
## [2.10.1](https://github.com/react-native-community/react-native-camera/compare/v2.10.0...v2.10.1) (2019-06-06)

### Bug Fixes

* revert breaking change upgrading to sdk 28 and androidx ([72a8d7f](https://github.com/react-native-community/react-native-camera/commit/72a8d7f))
2019-06-06 19:05:54 +00:00
Laurin Quast
72a8d7f34c
fix: revert breaking change upgrading to sdk 28 and androidx
This reverts commit e2a895ad1c.
2019-06-06 21:00:59 +02:00
dependabot[bot]
aeda5781e4 chore(deps): bump handlebars from 4.0.12 to 4.1.2 in /examples/basic (#2303)
Bumps [handlebars](https://github.com/wycats/handlebars.js) from 4.0.12 to 4.1.2.
- [Release notes](https://github.com/wycats/handlebars.js/releases)
- [Changelog](https://github.com/wycats/handlebars.js/blob/master/release-notes.md)
- [Commits](https://github.com/wycats/handlebars.js/compare/v4.0.12...v4.1.2)

Signed-off-by: dependabot[bot] <support@github.com>
2019-06-06 12:12:49 +02:00
dependabot[bot]
0b46954021 chore(deps): bump handlebars from 4.0.12 to 4.1.2 (#2304)
Bumps [handlebars](https://github.com/wycats/handlebars.js) from 4.0.12 to 4.1.2.
- [Release notes](https://github.com/wycats/handlebars.js/releases)
- [Changelog](https://github.com/wycats/handlebars.js/blob/master/release-notes.md)
- [Commits](https://github.com/wycats/handlebars.js/compare/v4.0.12...v4.1.2)

Signed-off-by: dependabot[bot] <support@github.com>
2019-06-06 12:12:27 +02:00
MateusAndrade
826edc323d
Setting gh pages url 2019-06-05 22:22:44 -03:00
MateusAndrade
3471436e54
Setting react-native-community info to gh pages 2019-06-05 22:09:24 -03:00
Mateus Andrade
99a4ed6a4c
Merge pull request #3 from react-native-community/master
update fork
2019-06-03 21:30:02 -03:00
semantic-release-bot
3c0db72f04 chore(release): 2.10.0 [skip ci]
# [2.10.0](https://github.com/react-native-community/react-native-camera/compare/v2.9.0...v2.10.0) (2019-06-02)

### Features

* **androidX:** upgrading to sdk 28 and androidx ([#2068](https://github.com/react-native-community/react-native-camera/issues/2068)) ([e2a895a](https://github.com/react-native-community/react-native-camera/commit/e2a895a))
* **docs:** Add docusaurus ([#2293](https://github.com/react-native-community/react-native-camera/issues/2293)) ([54b0332](https://github.com/react-native-community/react-native-camera/commit/54b0332))
2019-06-02 19:26:20 +00:00
Antonio Grass
1897633966 fix setParameters error (#2288)
* add try catch runtime in setParameters

* fix add log

* fix log names
2019-06-02 16:21:59 -03:00
Greg Alexander
e2a895ad1c feat(androidX): upgrading to sdk 28 and androidx (#2068)
* upgrading to sdk 28 and androidx

* revert attempt to fix build

* fixing build

* build version fix

* updating example app

* manifest update

* using stable release, instead of beta

* androidx migration doc

* migration doc update

* follow on androidx upgrade after rebase
2019-06-02 16:20:57 -03:00
Ronaldo Lima
54b03328b1 feat(docs): Add docusaurus (#2293)
* initial bootstrap on documentation

* Add EXPO_USAGE and MIgrating page

* add all pages

* add sponsors section to index

* theme

* configs

* clipboard button

* remove blog from docker

* start API.md

* minor updates
2019-06-02 16:20:35 -03:00
Mateus Andrade
6b4f8498a5
Merge pull request #2 from react-native-community/master
update fork
2019-05-31 16:25:06 -03:00
Mateus Andrade
5da10c9962
Merge pull request #2289 from MateusAndrade/feature/adding-stale-bot
Feature/adding stale bot
2019-05-31 15:39:30 -03:00
MateusAndrade
7c6e80c1c4
Adding a stale.yml handling issues older than 60 days and closing this issues after 7 days. 2019-05-29 21:51:50 -03:00
Mateus Andrade
49c0688292
Merge pull request #1 from react-native-community/master
updating fork
2019-05-29 21:45:54 -03:00
Arturo Mantinetti
493db170d2 Update AndroidManifest.xml (#2283)
Fix could not connect to development server and camera permission
2019-05-26 16:51:17 -03:00
Alan Kenyon
e609edc9a6 added node_modules (#2282) 2019-05-26 16:41:03 -03:00
semantic-release-bot
c70850ae35 chore(release): 2.9.0 [skip ci]
# [2.9.0](https://github.com/react-native-community/react-native-camera/compare/v2.8.0...v2.9.0) (2019-05-15)

### Features

* **android:** added image details to payload ([#2269](https://github.com/react-native-community/react-native-camera/issues/2269)) ([481594c](https://github.com/react-native-community/react-native-camera/commit/481594c))
* **android:** write Exif tags to modified image file ([#2263](https://github.com/react-native-community/react-native-camera/issues/2263)) ([8ad809e](https://github.com/react-native-community/react-native-camera/commit/8ad809e))
2019-05-15 12:14:22 +00:00
Valentin
8ad809ee88 feat(android): write Exif tags to modified image file (#2263) 2019-05-15 09:10:03 -03:00
psk200
481594c4c6 feat(android): added image details to payload (#2269) 2019-05-15 09:09:46 -03:00
semantic-release-bot
482fa7ced4 chore(release): 2.8.0 [skip ci]
# [2.8.0](https://github.com/react-native-community/react-native-camera/compare/v2.7.0...v2.8.0) (2019-05-13)

### Features

* **android:** Adding case 270 degrees to getFirebaseRotation method, according to FIrebase specs. ([#2264](https://github.com/react-native-community/react-native-camera/issues/2264)) ([60cc4cc](https://github.com/react-native-community/react-native-camera/commit/60cc4cc))
2019-05-13 17:21:10 +00:00
Andre Seiji
60cc4ccf56 feat(android): Adding case 270 degrees to getFirebaseRotation method, according to FIrebase specs. (#2264) 2019-05-13 14:16:26 -03:00
semantic-release-bot
045941fa3d chore(release): 2.7.0 [skip ci]
# [2.7.0](https://github.com/react-native-community/react-native-camera/compare/v2.6.0...v2.7.0) (2019-05-09)

### Features

* **android:** front camera face detect ([#2257](https://github.com/react-native-community/react-native-camera/issues/2257)) ([a6b619c](https://github.com/react-native-community/react-native-camera/commit/a6b619c))
2019-05-09 15:27:13 +00:00
Telmen
a6b619cb73 feat(android): front camera face detect (#2257) 2019-05-09 12:22:22 -03:00
Mateus Andrade
31830fe568
Merge pull request #2245 from Noitidart/patch-2
Add prop of autoFocusPointOfInterest
2019-04-29 15:25:10 -03:00
Noitidart
1d8465b555
Add prop of autoFocusPointOfInterest 2019-04-29 11:06:16 -07:00
Mateus Andrade
225209e8ac
Merge pull request #2238 from zoontek/fix-mlkit-dup-files
Ignore duplicate META files
2019-04-26 14:12:07 -03:00
Mathieu Acthernoene
2e529183c8 Ignore duplicate META files 2019-04-26 17:59:18 +02:00
Mateus Andrade
cf64014f87
Merge pull request #2236 from itsjgf/master
[Typescript] Add androidCameraPermissionOptions & androidRecordAudioPermissionOptions types
2019-04-26 09:56:42 -03:00
João Marins
61e82d5e0d
Merge pull request #2237 from ScottSmudger/patch-1
Typo in README
2019-04-26 09:48:43 -03:00
Scott Smith
3bcb32b11b
Typo in README
Text Recognition is used twice, should be Barcode Recognition
2019-04-26 13:38:50 +01:00
Jose Grana
b7cd9fe9b1 chore(typescript): add androidCameraPermissionOptions & androidRecordAudioPermissionOptions types 2019-04-26 11:30:02 +02:00
Noitidart
617b632bf9 Extend interface with _cameraRef and _cameraHandle (#2225) 2019-04-24 11:42:21 -03:00
Mark Oates
5a3841a618 Update Camera.js console warning spelling (#2218) 2019-04-18 21:43:10 -03:00
Mark Oates
4992572e81 Update spelling (#2217)
Some people search for "deprecated" and it was misspelled in the doc.
2019-04-18 13:21:04 -03:00
semantic-release-bot
150d0dfdec chore(release): 2.6.0 [skip ci]
# [2.6.0](https://github.com/react-native-community/react-native-camera/compare/v2.5.1...v2.6.0) (2019-04-18)

### Features

* **camera:** remove deprecated RCTCamera, fix [#1890](https://github.com/react-native-community/react-native-camera/issues/1890) ([#2215](https://github.com/react-native-community/react-native-camera/issues/2215)) ([c76a963](https://github.com/react-native-community/react-native-camera/commit/c76a963))
2019-04-18 01:59:11 +00:00
Sibelius Seraphini
c76a963026
feat(camera): remove deprecated RCTCamera, fix #1890 (#2215) 2019-04-17 22:54:48 -03:00
semantic-release-bot
0a0430aab3 chore(release): 2.5.1 [skip ci]
## [2.5.1](https://github.com/react-native-community/react-native-camera/compare/v2.5.0...v2.5.1) (2019-04-18)

### Bug Fixes

* **ts:** Update index.d.ts ([#2214](https://github.com/react-native-community/react-native-camera/issues/2214)) ([0957b5f](https://github.com/react-native-community/react-native-camera/commit/0957b5f))
2019-04-18 01:50:09 +00:00
Lerte Smith
0957b5fb4b fix(ts): Update index.d.ts (#2214) 2019-04-17 22:45:32 -03:00
semantic-release-bot
c8f25a8be7 chore(release): 2.5.0 [skip ci]
# [2.5.0](https://github.com/react-native-community/react-native-camera/compare/v2.4.0...v2.5.0) (2019-04-16)

### Features

* **mlkit:** add mlkit barcode detection ios ([#2209](https://github.com/react-native-community/react-native-camera/issues/2209)) ([1b9fb63](https://github.com/react-native-community/react-native-camera/commit/1b9fb63))
2019-04-16 18:38:35 +00:00
Daniil Ovoshchnikov
1b9fb63e56 feat(mlkit): add mlkit barcode detection ios (#2209)
extend barcode type cases for android
2019-04-16 15:33:46 -03:00
semantic-release-bot
028736b7c7 chore(release): 2.4.0 [skip ci]
# [2.4.0](https://github.com/react-native-community/react-native-camera/compare/v2.3.0...v2.4.0) (2019-04-14)

### Bug Fixes

* **ios:** [iOS] Video Interrupted on incoming call fix ([#2207](https://github.com/react-native-community/react-native-camera/issues/2207)) ([8cc3ca2](https://github.com/react-native-community/react-native-camera/commit/8cc3ca2))

### Features

* **android:** support for Rationale ([#2110](https://github.com/react-native-community/react-native-camera/issues/2110)) ([#2206](https://github.com/react-native-community/react-native-camera/issues/2206)) ([e564648](https://github.com/react-native-community/react-native-camera/commit/e564648))
2019-04-14 11:53:31 +00:00
Sankaran Kaliappan
8cc3ca2898 fix(ios): [iOS] Video Interrupted on incoming call fix (#2207)
* [iOS] Video Interrupted on incoming call fix

* Update index.d.ts
2019-04-14 08:47:12 -03:00
Kacper Kula
e564648b7c feat(android): support for Rationale (#2110) (#2206)
depracate permissionDialogTitle and permissionDialogMessage
add new props: androidCameraPermissionOptions and androidRecordAudioPermissionOptions
add functionality: when depracated parameters are provided, they are used instead of new ones (and the warning message is set).
2019-04-14 08:46:30 -03:00
semantic-release-bot
1a164fa537 chore(release): 2.3.0 [skip ci]
# [2.3.0](https://github.com/react-native-community/react-native-camera/compare/v2.2.2...v2.3.0) (2019-04-11)

### Bug Fixes

* **android:** picture sizes not updated when ratio changed ([#2204](https://github.com/react-native-community/react-native-camera/issues/2204)) ([24df865](https://github.com/react-native-community/react-native-camera/commit/24df865))

### Features

* **ios:** migrate face detection to mlkit ([#2193](https://github.com/react-native-community/react-native-camera/issues/2193)) ([025e7d9](https://github.com/react-native-community/react-native-camera/commit/025e7d9))
2019-04-11 12:16:06 +00:00
hushicai
24df865ee2 fix(android): picture sizes not updated when ratio changed (#2204) 2019-04-11 09:11:25 -03:00
Daniil Ovoshchnikov
025e7d97a4 feat(ios): migrate face detection to mlkit (#2193)
add face detection using mlkit
add enable tracking prop
cleanup android set tracking methods
remove old face detection
fix basic example not building on ios
2019-04-11 09:10:19 -03:00
semantic-release-bot
ac81c763e5 chore(release): 2.2.2 [skip ci]
## [2.2.2](https://github.com/react-native-community/react-native-camera/compare/v2.2.1...v2.2.2) (2019-04-07)

### Bug Fixes

* **android:** replace assertion with a null check ([#2194](https://github.com/react-native-community/react-native-camera/issues/2194)) ([47469e7](https://github.com/react-native-community/react-native-camera/commit/47469e7))
2019-04-07 17:38:21 +00:00
Burakhan Özyol
1ae330b3ea Updated Readme (#2180)
Fixed apostrophe sign error
2019-04-07 14:34:05 -03:00
Leeroy Brun
c2734547ed Fix incorrect heading in README (#2188) [skip ci]
It was misleading because I was looking for the Android manual install steps, but "Face Detection or Text Recognition Steps" was the same size as "Manual install" so it was like the Android manual install steps were non-existent.
2019-04-07 14:33:32 -03:00
Daniil Ovoshchnikov
47469e7305 fix(android): replace assertion with a null check (#2194)
some android cleanup
2019-04-07 14:33:09 -03:00
semantic-release-bot
b6a85d9f72 chore(release): 2.2.1 [skip ci]
## [2.2.1](https://github.com/react-native-community/react-native-camera/compare/v2.2.0...v2.2.1) (2019-04-03)

### Bug Fixes

* **android:** do not change camera rotation while video is being recorded ([#2187](https://github.com/react-native-community/react-native-camera/issues/2187)) ([963c249](https://github.com/react-native-community/react-native-camera/commit/963c249))
2019-04-03 13:25:32 +00:00
Jose G
963c249399 fix(android): do not change camera rotation while video is being recorded (#2187) 2019-04-03 10:20:02 -03:00
semantic-release-bot
1168ac95a7 chore(release): 2.2.0 [skip ci]
# [2.2.0](https://github.com/react-native-community/react-native-camera/compare/v2.1.1...v2.2.0) (2019-03-30)

### Features

* **android:** autoFocusPointOfInterest, Camera & Camera2 ([#1974](https://github.com/react-native-community/react-native-camera/issues/1974)) ([7bb9a12](https://github.com/react-native-community/react-native-camera/commit/7bb9a12))
2019-03-30 20:50:44 +00:00
Craig Tuttle
7bb9a1205c feat(android): autoFocusPointOfInterest, Camera & Camera2 (#1974)
* Android autoFocusPointOfInterest, Camera & Camera2

* updated example with touch to focus
2019-03-30 17:45:44 -03:00
Marius Reimer
d8922ac90e Upgrade to React Native 0.59.1 (#2162)
* Upgrade to React Native 0.59.1

* Fix CI

* Fix CI

* Fix CI

* Fix CI

* Fix CI

* Fix CI

* Fix CI

* Fix CI

* Fix CI
2019-03-28 18:08:43 -03:00
semantic-release-bot
08fce2ac1a chore(release): 2.1.1 [skip ci]
## [2.1.1](https://github.com/react-native-community/react-native-camera/compare/v2.1.0...v2.1.1) (2019-03-26)

### Bug Fixes

* **android:** support inverted qrcode for RCTCamera ([#2167](https://github.com/react-native-community/react-native-camera/issues/2167)) ([07f55ae](https://github.com/react-native-community/react-native-camera/commit/07f55ae))
2019-03-26 12:00:38 +00:00
Yori Zhao
07f55ae102 fix(android): support inverted qrcode for RCTCamera (#2167) 2019-03-26 08:56:44 -03:00
semantic-release-bot
7571099abc chore(release): 2.1.0 [skip ci]
# [2.1.0](https://github.com/react-native-community/react-native-camera/compare/v2.0.2...v2.1.0) (2019-03-25)

### Features

* **exposure:** adjustment support in Camera1(Camera API) ([#2163](https://github.com/react-native-community/react-native-camera/issues/2163)) ([ca35ac6](https://github.com/react-native-community/react-native-camera/commit/ca35ac6))
2019-03-25 14:34:15 +00:00
Neha Gupta
ca35ac609d feat(exposure): adjustment support in Camera1(Camera API) (#2163) 2019-03-25 11:30:08 -03:00
semantic-release-bot
ffe5b3744c chore(release): 2.0.2 [skip ci]
## [2.0.2](https://github.com/react-native-community/react-native-camera/compare/v2.0.1...v2.0.2) (2019-03-20)

### Bug Fixes

* **android:** Android build error ([#2152](https://github.com/react-native-community/react-native-camera/issues/2152)) ([d648582](https://github.com/react-native-community/react-native-camera/commit/d648582))
* **ios:** add application will enter foreground listener [iOS] ([#2158](https://github.com/react-native-community/react-native-camera/issues/2158)) ([773d5e8](https://github.com/react-native-community/react-native-camera/commit/773d5e8))
2019-03-20 14:50:11 +00:00
Daniil Ovoshchnikov
773d5e88ba fix(ios): add application will enter foreground listener [iOS] (#2158) 2019-03-20 11:46:03 -03:00
Daniil Ovoshchnikov
d6485828fd fix(android): Android build error (#2152)
add link to version2 migration in main readme
2019-03-20 11:45:49 -03:00
Tushar Gupta
cc5ae2a26e Update migrationV2.md (#2159)
Just a tiny fix for peeps who will be copy-pasting! :)
2019-03-20 11:45:30 -03:00
semantic-release-bot
f8269bf681 chore(release): 2.0.1 [skip ci]
## [2.0.1](https://github.com/react-native-community/react-native-camera/compare/v2.0.0...v2.0.1) (2019-03-14)

### Bug Fixes

* **barcode:** iniBarcodeReader ([#2145](https://github.com/react-native-community/react-native-camera/issues/2145)) ([e46b857](https://github.com/react-native-community/react-native-camera/commit/e46b857))
2019-03-14 14:44:09 +00:00
NIkita Belobrov
e46b8573f8 fix(barcode): iniBarcodeReader (#2145) 2019-03-14 11:40:46 -03:00
Daniil Ovoshchnikov
4ea35e33bb add version 2.x migration guide (#2143) 2019-03-14 09:53:01 -03:00
semantic-release-bot
d6a7c625d6 chore(release): 2.0.0 [skip ci]
# [2.0.0](https://github.com/react-native-community/react-native-camera/compare/v1.13.1...v2.0.0) (2019-03-11)

### Features

* **mlkit:** Migrate Face, Barcode and Text Recognition to Firebase MLKit (iOS - text, Android - all) ([#2075](https://github.com/react-native-community/react-native-camera/issues/2075)) ([0ab570a](https://github.com/react-native-community/react-native-camera/commit/0ab570a))

### BREAKING CHANGES

* **mlkit:** We migrated to MLKit instead of Google Mobile Vision
2019-03-11 11:59:49 +00:00
Daniil Ovoshchnikov
0ab570a636 feat(mlkit): Migrate Face, Barcode and Text Recognition to Firebase MLKit (iOS - text, Android - all) (#2075)
* switch to firebase mlkit for text recognition

* migrate android to MLKit

migrate Text detection android to MLKit
update gradle of example app
Update build.gradle
separate gms vision facedetector to general flavor

migrate faceDetector to mlkit and fix incorrect bounds due to padding

migrate barCode detector to mlkit
update android instructions in readme
safe face implementation move gms to generalImplementation

* add mlkit example

setup android of mlkit example

setup ios of mlkit example
fix typo in readme
update example project readme

* amend mlkit migration to include raw data

add barcode detection in basic and mlkit examples

* fix duplicate bridgeDidBackground method

BREAKING CHANGE: We migrated to MLKit instead of Google Mobile Vision
2019-03-11 08:56:24 -03:00
Marius Reimer
1a89d7981a Feature: isRecordingInterrupted video promise property (#2007)
* feat(rn-camera): add isRecordingInterrupted return property

* docs(rn-camera): added isRecordingInterrupted description

* Merge branch 'master' into feat-isRecordingInterrupted
2019-03-10 14:51:51 -03:00
Shashank Kushwah
9d56a21ddc [Android] Expose barcode bounds and source dimension from google vision barcode scanner (#2095)
* added react-navigation

* added barcode scanner example

* exposed barcode bounds and source dimensions in google vision barcode

* updated typescript types for google vision barcode
2019-03-09 11:41:15 -03:00
Sergey
aded9a4c4e [Android] Expose rawValue from google vision barcode scanner (#2087)
* Expose rawValue from google vision barcode scanner

* Rename rawValue to rawData
2019-03-09 11:40:01 -03:00
semantic-release-bot
fb9c4b5ac0 chore(release): 1.13.1 [skip ci]
## [1.13.1](https://github.com/react-native-community/react-native-camera/compare/v1.13.0...v1.13.1) (2019-03-08)

### Bug Fixes

* only call requestRecordPermission in debug mode ([#2119](https://github.com/react-native-community/react-native-camera/issues/2119)) ([959327e](https://github.com/react-native-community/react-native-camera/commit/959327e))
2019-03-08 21:27:32 +00:00
Laurin Quast
959327e99b fix: only call requestRecordPermission in debug mode (#2119) 2019-03-08 18:24:28 -03:00
semantic-release-bot
06ddd6f7b9 chore(release): 1.13.0 [skip ci]
# [1.13.0](https://github.com/react-native-community/react-native-camera/compare/v1.12.0...v1.13.0) (2019-03-08)

### Bug Fixes

* introduce refreshAuthorizationStatus method ([#2014](https://github.com/react-native-community/react-native-camera/issues/2014)) ([04ea06a](https://github.com/react-native-community/react-native-camera/commit/04ea06a))

### Features

* **android:** support inverted qrcode ([#2135](https://github.com/react-native-community/react-native-camera/issues/2135)) ([e2cdad5](https://github.com/react-native-community/react-native-camera/commit/e2cdad5))
* **docs:** added barcode-mask link ([#2128](https://github.com/react-native-community/react-native-camera/issues/2128)) [skip ci] ([3f70e46](https://github.com/react-native-community/react-native-camera/commit/3f70e46))
2019-03-08 14:21:58 +00:00
Yori Zhao
e2cdad56a7 feat(android): support inverted qrcode (#2135) 2019-03-08 11:19:05 -03:00
Dariusz Górak
04ea06a17d fix: introduce refreshAuthorizationStatus method (#2014) 2019-03-08 11:18:39 -03:00
Gustavo Barbosa
53b8e6206b chore(docs): Remove extra [ from Tidelift badge (#2126) [skip ci] 2019-02-28 23:55:35 -03:00
Shahnawaz Ali Kausar
3f70e46aa2 feat(docs): added barcode-mask link (#2128) [skip ci] 2019-02-28 22:07:34 -03:00
semantic-release-bot
1a5be4b301 chore(release): 1.12.0 [skip ci]
# [1.12.0](https://github.com/react-native-community/react-native-camera/compare/v1.11.2...v1.12.0) (2019-02-20)

### Features

* **android:** allow specifying a different google vision version via gradle properties ([#2112](https://github.com/react-native-community/react-native-camera/issues/2112)) ([1009c4e](https://github.com/react-native-community/react-native-camera/commit/1009c4e))
2019-02-20 13:30:21 +00:00
Jose G
1009c4ed79 feat(android): allow specifying a different google vision version via gradle properties (#2112) 2019-02-20 14:27:04 +01:00
semantic-release-bot
7598bc556e chore(release): 1.11.2 [skip ci]
## [1.11.2](https://github.com/react-native-community/react-native-camera/compare/v1.11.1...v1.11.2) (2019-02-19)

### Bug Fixes

* **windows:** update min sdk version ([#2117](https://github.com/react-native-community/react-native-camera/issues/2117)) ([634a06f](https://github.com/react-native-community/react-native-camera/commit/634a06f))
2019-02-19 15:28:38 +00:00
Mikalai Shchakatsikhin
634a06f585 fix(windows): update min sdk version (#2117) 2019-02-19 16:22:03 +01:00
João Marins
68a9df2c29
Update README.md 2019-02-18 23:48:35 -03:00
Laurin Quast
0ef031b958
docs(q-a): add how to save video/image to camera roll (#2115) 2019-02-18 12:44:58 +01:00
480 changed files with 76967 additions and 11421 deletions

103
.circleci/config.yml Normal file
View File

@ -0,0 +1,103 @@
version: 2.1
orbs:
react-native: react-native-community/react-native@4.4.0
commands:
checkout-attach-workspace:
description: "Checkout and attach workspace"
steps:
- checkout
- attach_workspace:
at: .
jobs:
install:
executor: react-native/linux_js
steps:
- checkout-attach-workspace
- react-native/yarn_install
- persist_to_workspace:
root: .
paths:
- node_modules
lint:
executor: react-native/linux_android
steps:
- checkout-attach-workspace
- run:
name: Lint
command: yarn lint
build-app:
executor: react-native/linux_android
steps:
- checkout-attach-workspace
- run:
name: Run Checks
command: |
cd android
chmod +x ./gradlew && ./gradlew check
- store_artifacts:
path: android/build/reports
- run:
name: Run Yarn to Generate react.gradle
command: cd examples/basic/android && yarn
- react-native/android_build:
project_path: ./examples/basic/android
deploy-docs:
executor: react-native/linux_js
steps:
- checkout-attach-workspace
- run:
name: Deploying to GitHub Pages
command: |
git config --global user.email "${GH_EMAIL}@users.noreply.github.com"
git config --global user.name "${GH_NAME}"
echo "machine github.com login $GH_NAME password $GH_TOKEN_DOCS" > ~/.netrc
cd website && yarn install && GIT_USER=${GH_NAME} yarn run publish-gh-pages
publish-version:
executor: react-native/linux_js
steps:
- checkout-attach-workspace
- run:
name: Run semantic-release
command: yarn ci:publish
workflows:
version: 2
develop:
jobs:
- install:
filters:
branches:
ignore: master
- lint:
requires:
- install
- build-app:
requires:
- install
release:
jobs:
- install:
filters:
branches:
only: master
- deploy-docs:
requires:
- install
- publish-version:
requires:
- install

2
.dockerignore Normal file
View File

@ -0,0 +1,2 @@
*/node_modules
*.log

1
.eslintIgnore Normal file
View File

@ -0,0 +1 @@
tests

4
.github/FUNDING.yml vendored Normal file
View File

@ -0,0 +1,4 @@
patreon: # Replace with a single Patreon username
open_collective: react-native-camera
tidelift: npm/react-native-camera
custom: # Replace with a single custom sponsorship URL

View File

@ -1,42 +1,43 @@
---
name: Bug report
about: Create a report to help us improve
---
# Bug Report
**To Do First**
- [ ] Did you try latest release?
- [ ] Did you try master?
- [ ] Did you look for existing matching issues?
**Related Modules**
<!--Comment in the related ones-->
<!--RNCamera-->
<!--FaceDetector-->
<!--RCTCamera(deprecated)-->
**Platforms**
<!--Comment in the related ones-->
<!--Android-->
<!--iOS-->
**Versions**
<!--Please add the used versions/branches or leave blank and comment in the optionals if used-->
- Android:
- iOS:
- react-native-camera:
- react-native:
- react:
<!---react-navigation:-->
<!---react-navigation:-->
**Description/Current Behaviour**
<!--place your bug description below-->
**Expected Behaviour**
<!--place your expected behaviour below-->
**Steps to Reproduce**
<!--describe how to produce the error below-->
<!--**Does it work with Expo Camera?**-->
@ -44,7 +45,8 @@ about: Create a report to help us improve
You should open an issue there as well, so we can cooperate in a solution.-->
**Additionals**
<!--place screenshots/suggestions and other additional infos below-->
> Love react-native-camera? Please consider supporting our collective: 👉 https://opencollective.com/react-native-camera/donate
> Love react-native-camera? Please consider supporting our collective: 👉 https://opencollective.com/react-native-camera/donate
> Want this issue to be resolved faster? Please consider adding a bounty to it https://issuehunt.io/repos/33218414

45
.github/stale.yml vendored Normal file
View File

@ -0,0 +1,45 @@
# Configuration for probot-stale based on: https://github.com/facebook/react-native/blob/master/.github/stale.yml
# Number of days of inactivity before an Issue or Pull Request becomes stale
daysUntilStale: 60
# Number of days of inactivity before an Issue or Pull Request with the stale label is closed.
daysUntilClose: 7
# Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable
exemptLabels:
- pinned
- security
- For Discussion
- semantic-release
- Needs revision
# Set to true to ignore issues in a project (defaults to false)
exemptProjects: false
# Set to true to ignore issues in a milestone (defaults to false)
exemptMilestones: false
# Set to true to ignore issues with an assignee (defaults to false)
exemptAssignees: false
# Label to use when marking as stale
staleLabel: stale
# Comment to post when marking as stale. Set to `false` to disable
markComment: >
This issue has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs. Thank you
for your contributions. You may also mark this issue as a "discussion" and i
will leave this open.
# Comment to post when closing a stale Issue or Pull Request.
closeComment: >
Closing this issue after a prolonged period of inactivity. Fell free to reopen
this issue, if this still affecting you.
# Limit the number of actions per hour, from 1-30. Default is 30
limitPerRun: 30
# Limit to only `issues` or `pulls`
only: issues

8
.gitignore vendored
View File

@ -45,4 +45,10 @@ android/keystores/debug.keystore
package-json.lock
# vscode
.vscode
.vscode
examples/mlkit/android/app/google-services.json
examples/mlkit/ios/Pods
examples/mlkit/ios/mlkit/GoogleService-Info.plist
!debug.keystore
/ios/Pods/

View File

@ -3,3 +3,5 @@
circle.yml
commitlint.config.js
/android/build
/website
/docs

10
Dockerfile Normal file
View File

@ -0,0 +1,10 @@
FROM node:8.11.4
WORKDIR /app/website
EXPOSE 3000 35729
COPY ./docs /app/docs
COPY ./website /app/website
RUN yarn install
CMD ["yarn", "start"]

348
README.md
View File

@ -1,13 +1,28 @@
# React Native Camera [![Backers on Open Collective](https://opencollective.com/react-native-camera/backers/badge.svg)](#backers) [![Sponsors on Open Collective](https://opencollective.com/react-native-camera/sponsors/badge.svg)](#sponsors) [![npm version](https://badge.fury.io/js/react-native-camera.svg)](http://badge.fury.io/js/react-native-camera) [![npm downloads](https://img.shields.io/npm/dm/react-native-camera.svg)](https://www.npmjs.com/package/react-native-camera)
[Looking for Maintainers](https://github.com/react-native-community/react-native-camera/issues/3000)
We are looking for maintainers for this package, or to deprecated this in favor of expo-camera, it nobody want to maintain this
## Docs
Follow our docs here [https://react-native-camera.github.io/react-native-camera/](https://react-native-camera.github.io/react-native-camera/)
## Sponsors
If you use this library on your commercial/personal projects, you can help us by funding the work on specific issues that you choose by using IssueHunt.io!
This gives you the power to prioritize our work and support the project contributors. Moreover it'll guarantee the project will be updated and maintained in the long run.
[![issuehunt-image](https://github.com/BoostIO/issuehunt-materials/blob/master/issuehunt-badge@1x.png?raw=true)](https://issuehunt.io/repos/33218414)
[![issuehunt-image](https://issuehunt.io/static/embed/issuehunt-button-v1.svg)](https://issuehunt.io/repos/33218414)
## react-native-camera for enterprise
Available as part of the Tidelift Subscription
The maintainers of react-native-camera and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source dependencies you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use. [Learn more.](https://tidelift.com/subscription/pkg/npm-react-native-camera?utm_source=npm-react-native-camera&utm_medium=referral&utm_campaign=enterprise&utm_term=repo)
## Open Collective
You can also fund this project using open collective
### Backers
@ -45,7 +60,6 @@ Support us with a monthly donation and help us continue our activities. [[Become
<a href="https://opencollective.com/react-native-camera/backer/28/website" target="_blank"><img src="https://opencollective.com/react-native-camera/backer/28/avatar.svg"></a>
<a href="https://opencollective.com/react-native-camera/backer/29/website" target="_blank"><img src="https://opencollective.com/react-native-camera/backer/29/avatar.svg"></a>
### Sponsors
Become a sponsor and get your logo on our README on Github with a link to your site. [[Become a sponsor](https://opencollective.com/react-native-camera#sponsor)]
@ -61,7 +75,6 @@ Become a sponsor and get your logo on our README on Github with a link to your s
<a href="https://opencollective.com/react-native-camera/sponsor/8/website" target="_blank"><img src="https://opencollective.com/react-native-camera/sponsor/8/avatar.svg"></a>
<a href="https://opencollective.com/react-native-camera/sponsor/9/website" target="_blank"><img src="https://opencollective.com/react-native-camera/sponsor/9/avatar.svg"></a>
The comprehensive camera module for React Native.
Supports:
@ -72,11 +85,6 @@ Supports:
- barcode scanning
- text recognition (optional installation for iOS using CocoaPods)
## Tidelift
[Get supported react-native-camera with the Tidelift Subscription](https://tidelift.com/subscription/pkg/npm-react-native-camera?utm_source=npm-react-native-camera&utm_medium=referral&utm_campaign=readme)
[![tidelift](https://tidelift.com/badges/github/react-native-community/react-native-camera)
### Example import
```jsx
@ -91,8 +99,8 @@ We recommend using the releases from npm, however if you need some features that
**npm**: `npm install --save react-native-camera@git+https://git@github.com/react-native-community/react-native-camera.git`
### Contributing
- Pull Requests are welcome, if you open a pull request we will do our best to get to it in a timely manner
- Pull Request Reviews are even more welcome! we need help testing, reviewing, and updating open PRs
- If you are interested in contributing more actively, please contact me (same username on Twitter, Facebook, etc.) Thanks!
@ -100,11 +108,17 @@ We recommend using the releases from npm, however if you need some features that
- If you want to help us coding, join Expo slack https://slack.expo.io/, so we can chat over there. (#react-native-camera)
##### Permissions
To use the camera on Android you must ask for camera permission:
To use the camera,
1) On Android you must ask for camera permission:
```java
<uses-permission android:name="android.permission.CAMERA" />
```
To enable `video recording` feature you have to add the following code to the `AndroidManifest.xml`:
```java
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
@ -113,315 +127,23 @@ To enable `video recording` feature you have to add the following code to the `A
![5j2jduk](https://cloud.githubusercontent.com/assets/2302315/22190752/6bc6ccd0-e0da-11e6-8e2f-6f22a3567a57.gif)
## Migrating from RCTCamera to RNCamera
2) On iOS, you must update Info.plist with a usage description for camera
See this [doc](./docs/migration.md)
### RNCamera Docs
[RNCamera](./docs/RNCamera.md)
### Docs old RCTCamera
[RCTCamera](./docs/RCTCamera.md)
## Getting started
### Requirements
1. JDK >= 1.7 (if you run on 1.6 you will get an error on "_cameras = new HashMap<>();")
2. With iOS 10 and higher you need to add the "Privacy - Camera Usage Description" key to the Info.plist of your project. This should be found in 'your_project/ios/your_project/Info.plist'. Add the following code:
```
```xml
...
<key>NSCameraUsageDescription</key>
<string>Your message to user when the camera is accessed for the first time</string>
<!-- Include this only if you are planning to use the camera roll -->
<key>NSPhotoLibraryUsageDescription</key>
<string>Your message to user when the photo library is accessed for the first time</string>
<!-- Include this only if you are planning to use the microphone for video recording -->
<key>NSMicrophoneUsageDescription</key>
<string>Your message to user when the microphone is accessed for the first time</string>
```
3. On Android, you require `buildToolsVersion` of `25.0.2+`. _This should easily and automatically be downloaded by Android Studio's SDK Manager._
4. On iOS 11 and later you need to add `NSPhotoLibraryAddUsageDescription` key to the Info.plist. This key lets you describe the reason your app seeks write-only access to the users photo library. Info.plist can be found in 'your_project/ios/your_project/Info.plist'. Add the following code:
```
<!-- Include this only if you are planning to use the camera roll -->
<key>NSPhotoLibraryAddUsageDescription</key>
<string>Your message to user when the photo library is accessed for the first time</string>
```
### Mostly automatic install with react-native
1. `npm install react-native-camera --save`
2. `react-native link react-native-camera`
*To install it with Windows, see manual install below*
### Mostly automatic install with CocoaPods
1. `npm install react-native-camera --save`
2. Add the plugin dependency to your Podfile, pointing at the path where NPM installed it:
```obj-c
pod 'react-native-camera', path: '../node_modules/react-native-camera'
```
3. Run `pod install`
*Note:* You might need to adjust your Podfile following the example below:
```ruby
target 'yourTargetName' do
# See http://facebook.github.io/react-native/docs/integration-with-existing-apps.html#configuring-cocoapods-dependencies
pod 'React', :path => '../node_modules/react-native', :subspecs => [
'Core',
'CxxBridge', # Include this for RN >= 0.47
'DevSupport', # Include this to enable In-App Devmenu if RN >= 0.43
'RCTText',
'RCTNetwork',
'RCTWebSocket', # Needed for debugging
'RCTAnimation', # Needed for FlatList and animations running on native UI thread
# Add any other subspecs you want to use in your project
]
# Explicitly include Yoga if you are using RN >= 0.42.0
pod 'yoga', :path => '../node_modules/react-native/ReactCommon/yoga'
# Third party deps podspec link
pod 'react-native-camera', path: '../node_modules/react-native-camera'
end
post_install do |installer|
installer.pods_project.targets.each do |target|
if target.name == "React"
target.remove_from_project
end
end
end
```
### Manual install
#### iOS
1. `npm install react-native-camera --save`
2. In XCode, in the project navigator, right click `Libraries``Add Files to [your project's name]`
3. Go to `node_modules``react-native-camera` and add `RNCamera.xcodeproj`
4. Expand the `RNCamera.xcodeproj``Products` folder
5. In XCode, in the project navigator, select your project. Add `libRNCamera.a` to your project's `Build Phases``Link Binary With Libraries`
6. Click `RNCamera.xcodeproj` in the project navigator and go the `Build Settings` tab. Make sure 'All' is toggled on (instead of 'Basic'). In the `Search Paths` section, look for `Header Search Paths` and make sure it contains both `$(SRCROOT)/../../react-native/React` and `$(SRCROOT)/../../../React` - mark both as `recursive`.
### Face Detection or Text Recognition Steps
Face Detection/Text Recognition are optional on iOS. If you want them, you are going to need to install Google Mobile Vision frameworks in your project, as mentioned in the next section.
##### No Face Detection steps
If you do not need it and do not want to install the GMV frameworks, open your app xcode project, on the Project Navigator, expand the RNCamera project, right click on the FaceDetector folder and delete it (move to trash, if you want). If you keep that folder and do not follow the GMV installation steps, your project will not compile.
If you want to make this automatic, you can add a postinstall script to your app `package.json`. Inside the `postinstall_project` there is a xcode project ready with the folder removed (we opened xcode, removed the folder from the project and copied the resulting project file). The post install script is:
```
#!/bin/bash
echo "Creating project without FaceDetector"
if [ -e node_modules/react-native-camera/ios/FaceDetector ] ; then
rm -rf node_modules/react-native-camera/ios/FaceDetector
fi
cp node_modules/react-native-camera/postinstall_project/projectWithoutFaceDetection.pbxproj node_modules/react-native-camera/ios/RNCamera.xcodeproj/project.pbxproj
```
And add something like this to the `scripts` section in your `package.json`:
*Note:* The face detection/text recognition code is excluded by default for the **CocoaPods** installation.
```
"postinstall": "./scripts/post.sh",
```
##### Installing GMV frameworks
GMV (Google Mobile Vision) is used for Face detection/Text recognition by the iOS RNCamera. You have to link the google frameworks to your project to successfully compile the RNCamera project.
###### CocoaPods Path (The only option for Text Recognition)
Modify the dependency towards `react-native-camera` in your
`Podfile`, from
```
pod 'react-native-camera', path: '../node_modules/react-native-camera'
```
to (for Face Detection)
```
pod 'react-native-camera', path: '../node_modules/react-native-camera', subspecs: [
'FaceDetector'
]
```
or to (for Text Recognition)
```
pod 'react-native-camera', path: '../node_modules/react-native-camera', subspecs: [
'TextDetector'
]
```
*Note:* Text recognition is available only via CocoaPods Path. If you have issues with duplicate symbols you will need to enable dead code stripping option in your Xcode (Target > Build Settings > search for "Dead code stripping") see: https://github.com/firebase/quickstart-ios/issues/487#issuecomment-415313053.
###### Non-CocoaPods Path
1. Download:
Google Symbol Utilities: https://www.gstatic.com/cpdc/dbffca986f6337f8-GoogleSymbolUtilities-1.1.1.tar.gz
Google Utilities: https://dl.google.com/dl/cpdc/978f81964b50a7c0/GoogleUtilities-1.3.2.tar.gz
Google Mobile Vision: https://dl.google.com/dl/cpdc/df83c97cbca53eaf/GoogleMobileVision-1.1.0.tar.gz
Google network Utilities: https://dl.google.com/dl/cpdc/54fd7b7ef8fd3edc/GoogleNetworkingUtilities-1.2.2.tar.gz
Google Interchange Utilities: https://dl.google.com/dl/cpdc/1a7f7ba905b2c029/GoogleInterchangeUtilities-1.2.2.tar.gz
2. Extract everything to one folder. Delete "BarcodeDetector" and "copy" folders from Google Mobile Vision.
3. Open XCode, right click on your project and choose "New Group". Rename the new folder to "Frameworks". Right click on "Frameworks" and select "add files to 'YOUR_PROJECT'". Select all content from the folder of step 2, click on Options. Select "Copy items if needed", leave "Create groups" selected and choose all your targets on the "Add to targets" section. Then, click on "Add".
4. On your target -> Build Phases -> Link Binary with Libraries -> add AddressBook.framework
5. On your target -> Build Settings -> Other Linker Flags -> add -lz, -ObjC and -lc++
6. To force indexing and prevent errors, restart xcode and reopen your project again before compiling.
#### Android
1. `npm install react-native-camera --save`
2. Open up `android/app/src/main/java/[...]/MainApplication.java`
- Add `import org.reactnative.camera.RNCameraPackage;` to the imports at the top of the file
- Add `new RNCameraPackage()` to the list returned by the `getPackages()` method. Add a comma to the previous item if there's already something there.
3. Append the following lines to `android/settings.gradle`:
```gradle
include ':react-native-camera'
project(':react-native-camera').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-camera/android')
```
4. Insert the following lines inside the dependencies block in `android/app/build.gradle`:
```gradle
compile (project(':react-native-camera')) {
exclude group: "com.google.android.gms"
compile 'com.android.support:exifinterface:25.+'
compile ('com.google.android.gms:play-services-vision:12.0.1') {
force = true
}
}
```
> You may need to use different exifinterface versions, e.g. `27.+` instead of `25.+`.
5. Declare the permissions in your Android Manifest (required for `video recording` feature)
```java
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
```
6. Add jitpack to android/build.gradle
```gradle
allprojects {
repositories {
maven { url "https://jitpack.io" }
maven { url "https://maven.google.com" }
}
}
```
The current Android library defaults to the below values for the Google SDK and Libraries,
```gradle
def DEFAULT_COMPILE_SDK_VERSION = 26
def DEFAULT_BUILD_TOOLS_VERSION = "26.0.2"
def DEFAULT_TARGET_SDK_VERSION = 26
def DEFAULT_GOOGLE_PLAY_SERVICES_VERSION = "12.0.1"
def DEFAULT_SUPPORT_LIBRARY_VERSION = "27.1.0"
```
You can override this settings by adding a Project-wide gradle configuration properties for
use by all modules in your ReactNative project by adding the below to `android/build.gradle`
file,
```gradle
buildscript {...}
allprojects {...}
/**
* Project-wide gradle configuration properties for use by all modules
*/
ext {
compileSdkVersion = 26
targetSdkVersion = 26
buildToolsVersion = "26.0.2"
googlePlayServicesVersion = "12.0.1"
supportLibVersion = "27.1.0"
}
```
The above settings in the ReactNative project over-rides the values present in the `react-native-camera`
module. For your reference below is the `android/build.gradle` file of the module.
```gradle
buildscript {
<string>Your own description of the purpose</string>
...
def DEFAULT_COMPILE_SDK_VERSION = 26
def DEFAULT_BUILD_TOOLS_VERSION = "26.0.2"
def DEFAULT_TARGET_SDK_VERSION = 26
def DEFAULT_GOOGLE_PLAY_SERVICES_VERSION = "12.0.1"
def DEFAULT_SUPPORT_LIBRARY_VERSION = "27.1.0"
android {
compileSdkVersion rootProject.hasProperty('compileSdkVersion') ? rootProject.compileSdkVersion : DEFAULT_COMPILE_SDK_VERSION
buildToolsVersion rootProject.hasProperty('buildToolsVersion') ? rootProject.buildToolsVersion : DEFAULT_BUILD_TOOLS_VERSION
defaultConfig {
minSdkVersion 16
targetSdkVersion rootProject.hasProperty('targetSdkVersion') ? rootProject.targetSdkVersion : DEFAULT_TARGET_SDK_VERSION
versionCode 1
versionName "1.0.0"
}
lintOptions {
abortOnError false
warning 'InvalidPackage'
}
}
...
dependencies {
def googlePlayServicesVersion = rootProject.hasProperty('googlePlayServicesVersion') ? rootProject.googlePlayServicesVersion : DEFAULT_GOOGLE_PLAY_SERVICES_VERSION
def supportLibVersion = rootProject.hasProperty('supportLibVersion') ? rootProject.supportLibVersion : DEFAULT_SUPPORT_LIBRARY_VERSION
compile 'com.facebook.react:react-native:+'
compile "com.google.zxing:core:3.2.1"
compile "com.drewnoakes:metadata-extractor:2.9.1"
compile 'com.google.android.gms:play-services-vision:$googlePlayServicesVersion'
compile 'com.android.support:exifinterface:$supportLibVersion'
compile 'com.github.react-native-community:cameraview:cc47bb28ed2fc54a8c56a4ce9ce53edd1f0af3a5'
}
```
For more information on installation, please refer to [installation requirements](./docs/installation.md#requirements).
#### Windows
1. `npm install react-native-camera --save`
2. Link the library as described here: [react-native-windows / LinkingLibrariesWindows.md](https://github.com/Microsoft/react-native-windows/blob/master/docs/LinkingLibrariesWindows.md)
For the last step of this guide, you have to add the following things to your `MainReactNativeHost.cs`:
- in the import section at the very top: `using RNCamera;`
- in `protected override List<IReactPackage> Packages => new List<IReactPackage>` add a new line with `new RNCameraPackage()`
3. Add the capabilities (permissions) for the webcam and microphone as described here: [docs.microsoft / audio-video-camera](https://docs.microsoft.com/en-us/windows/uwp/audio-video-camera/simple-camera-preview-access#add-capability-declarations-to-the-app-manifest)
4. Use `RCTCamera` (RNCamera is not supported yet) like described above
For general introduction, please take a look into this [RNCamera](./docs/RNCamera.md).
Follow the [Q & A](./docs/QA.md) section if you are having compilation issues.
## Security contact information
## Usage
To report a security vulnerability, please use the
### RNCamera
[Tidelift security contact](https://tidelift.com/security).
Take a look into this [documentation](./docs/RNCamera.md).
### RCTCamera
Since `1.0.0`, RCTCamera is deprecated, but if you want to use it, you can see its [documentation](./docs/RCTCamera.md).
------------
Thanks to Brent Vatne (@brentvatne) for the `react-native-video` module which provided me with a great example of how to set up this module.
Tidelift will coordinate the fix and disclosure.

View File

@ -3,41 +3,59 @@ def safeExtGet(prop, fallback) {
}
buildscript {
repositories {
google()
maven {
url 'https://maven.google.com'
// The Android Gradle plugin is only required when opening the android folder stand-alone.
// This avoids unnecessary downloads and potential conflicts when the library is included as a
// module dependency in an application project.
if (project == rootProject) {
repositories {
google()
jcenter()
}
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.0.1'
dependencies {
//noinspection GradleDependency
classpath("com.android.tools.build:gradle:3.6.3")
}
}
}
apply plugin: 'com.android.library'
android {
compileSdkVersion safeExtGet('compileSdkVersion', 26)
buildToolsVersion safeExtGet('buildToolsVersion', '26.0.2')
compileSdkVersion safeExtGet('compileSdkVersion', 28)
buildToolsVersion safeExtGet('buildToolsVersion', '28.0.3')
defaultConfig {
minSdkVersion safeExtGet('minSdkVersion', 16)
targetSdkVersion safeExtGet('targetSdkVersion', 26)
targetSdkVersion safeExtGet('targetSdkVersion', 28)
}
flavorDimensions "react-native-camera"
productFlavors {
general {
dimension "react-native-camera"
}
mlkit {
dimension "react-native-camera"
}
}
lintOptions {
abortOnError false
warning 'InvalidPackage'
}
packagingOptions {
exclude 'META-INF/androidx.exifinterface_exifinterface.version'
exclude 'META-INF/proguard/androidx-annotations.pro'
}
}
repositories {
google()
jcenter()
mavenCentral()
maven {
url 'https://maven.google.com'
}
maven { url "https://jitpack.io" }
maven {
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
@ -46,12 +64,16 @@ repositories {
}
dependencies {
compileOnly 'com.facebook.react:react-native:+'
compileOnly 'com.facebook.infer.annotation:infer-annotation:+'
implementation "com.google.zxing:core:3.3.0"
implementation "com.drewnoakes:metadata-extractor:2.9.1"
implementation "com.google.android.gms:play-services-vision:${safeExtGet('googlePlayServicesVersion', '15.0.2')}"
implementation "com.android.support:exifinterface:${safeExtGet('supportLibVersion', '27.1.0')}"
implementation "com.android.support:support-annotations:${safeExtGet('supportLibVersion', '27.1.0')}"
implementation "com.android.support:support-v4:${safeExtGet('supportLibVersion', '27.1.0')}"
def googlePlayServicesVisionVersion = safeExtGet('googlePlayServicesVisionVersion', safeExtGet('googlePlayServicesVersion', '17.0.2'))
//noinspection GradleDynamicVersion
implementation 'com.facebook.react:react-native:+' // From node_modules
implementation "com.google.zxing:core:3.3.3"
implementation "com.drewnoakes:metadata-extractor:2.11.0"
generalImplementation "com.google.android.gms:play-services-vision:$googlePlayServicesVisionVersion"
implementation "androidx.exifinterface:exifinterface:1.0.0"
implementation "androidx.annotation:annotation:1.0.0"
implementation "androidx.legacy:legacy-support-v4:1.0.0"
mlkitImplementation "com.google.firebase:firebase-ml-vision:${safeExtGet('firebase-ml-vision', '19.0.3')}"
mlkitImplementation "com.google.firebase:firebase-ml-vision-face-model:${safeExtGet('firebase-ml-vision-face-model', '17.0.2')}"
}

View File

@ -0,0 +1,2 @@
android.enableJetifier=true
android.useAndroidX=true

Binary file not shown.

View File

@ -1,6 +1,5 @@
#Sun Dec 31 13:43:56 BRST 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip

120
android/gradlew vendored
View File

@ -1,4 +1,20 @@
#!/usr/bin/env bash
#!/usr/bin/env sh
#
# Copyright 2015 the original author or authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
##############################################################################
##
@ -6,42 +22,6 @@
##
##############################################################################
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn ( ) {
echo "$*"
}
die ( ) {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
esac
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
@ -60,6 +40,46 @@ cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn () {
echo "$*"
}
die () {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@ -85,7 +105,7 @@ location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
@ -105,8 +125,8 @@ if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
# For Cygwin or MSYS, switch paths to Windows format before running java
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
@ -150,11 +170,19 @@ if $cygwin ; then
esac
fi
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
JVM_OPTS=("$@")
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
APP_ARGS=$(save "$@")
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
fi
exec "$JAVACMD" "$@"

30
android/gradlew.bat vendored
View File

@ -1,3 +1,19 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@ -8,14 +24,14 @@
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
@ -46,10 +62,9 @@ echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windowz variants
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args
:win9xME_args
@rem Slurp the command line arguments.
@ -60,11 +75,6 @@ set _SKIP=2
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
goto execute
:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
set CMD_LINE_ARGS=%$
:execute
@rem Setup the command line

View File

@ -12,6 +12,7 @@ public class RNBarcodeDetector {
public static int NORMAL_MODE = 0;
public static int ALTERNATE_MODE = 1;
public static int INVERTED_MODE = 2;
public static int ALL_FORMATS = Barcode.ALL_FORMATS;
private BarcodeDetector mBarcodeDetector = null;
private ImageDimensions mPreviousDimensions;

View File

@ -0,0 +1,127 @@
package org.reactnative.camera.tasks;
import android.graphics.Rect;
import android.util.SparseArray;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.WritableArray;
import com.facebook.react.bridge.WritableMap;
import com.google.android.gms.vision.barcode.Barcode;
import org.reactnative.barcodedetector.BarcodeFormatUtils;
import org.reactnative.camera.utils.ImageDimensions;
import org.reactnative.frame.RNFrame;
import org.reactnative.frame.RNFrameFactory;
import org.reactnative.barcodedetector.RNBarcodeDetector;
public class BarcodeDetectorAsyncTask extends android.os.AsyncTask<Void, Void, SparseArray<Barcode>> {
private byte[] mImageData;
private int mWidth;
private int mHeight;
private int mRotation;
private RNBarcodeDetector mBarcodeDetector;
private BarcodeDetectorAsyncTaskDelegate mDelegate;
private double mScaleX;
private double mScaleY;
private ImageDimensions mImageDimensions;
private int mPaddingLeft;
private int mPaddingTop;
public BarcodeDetectorAsyncTask(
BarcodeDetectorAsyncTaskDelegate delegate,
RNBarcodeDetector barcodeDetector,
byte[] imageData,
int width,
int height,
int rotation,
float density,
int facing,
int viewWidth,
int viewHeight,
int viewPaddingLeft,
int viewPaddingTop) {
mImageData = imageData;
mWidth = width;
mHeight = height;
mRotation = rotation;
mDelegate = delegate;
mBarcodeDetector = barcodeDetector;
mImageDimensions = new ImageDimensions(width, height, rotation, facing);
mScaleX = (double) (viewWidth) / (mImageDimensions.getWidth() * density);
mScaleY = (double) (viewHeight) / (mImageDimensions.getHeight() * density);
mPaddingLeft = viewPaddingLeft;
mPaddingTop = viewPaddingTop;
}
@Override
protected SparseArray<Barcode> doInBackground(Void... ignored) {
if (isCancelled() || mDelegate == null || mBarcodeDetector == null || !mBarcodeDetector.isOperational()) {
return null;
}
RNFrame frame = RNFrameFactory.buildFrame(mImageData, mWidth, mHeight, mRotation);
return mBarcodeDetector.detect(frame);
}
@Override
protected void onPostExecute(SparseArray<Barcode> barcodes) {
super.onPostExecute(barcodes);
if (barcodes == null) {
mDelegate.onBarcodeDetectionError(mBarcodeDetector);
} else {
if (barcodes.size() > 0) {
mDelegate.onBarcodesDetected(serializeEventData(barcodes), mWidth, mHeight, mImageData);
}
mDelegate.onBarcodeDetectingTaskCompleted();
}
}
private WritableArray serializeEventData(SparseArray<Barcode> barcodes) {
WritableArray barcodesList = Arguments.createArray();
for (int i = 0; i < barcodes.size(); i++) {
Barcode barcode = barcodes.valueAt(i);
WritableMap serializedBarcode = Arguments.createMap();
serializedBarcode.putString("data", barcode.displayValue);
serializedBarcode.putString("rawData", barcode.rawValue);
serializedBarcode.putString("type", BarcodeFormatUtils.get(barcode.format));
serializedBarcode.putMap("bounds", processBounds(barcode.getBoundingBox()));
barcodesList.pushMap(serializedBarcode);
}
return barcodesList;
}
private WritableMap processBounds(Rect frame) {
WritableMap origin = Arguments.createMap();
int x = frame.left;
int y = frame.top;
if (frame.left < mWidth / 2) {
x = x + mPaddingLeft / 2;
} else if (frame.left > mWidth /2) {
x = x - mPaddingLeft / 2;
}
if (frame.top < mHeight / 2) {
y = y + mPaddingTop / 2;
} else if (frame.top > mHeight / 2) {
y = y - mPaddingTop / 2;
}
origin.putDouble("x", x * mScaleX);
origin.putDouble("y", y * mScaleY);
WritableMap size = Arguments.createMap();
size.putDouble("width", frame.width() * mScaleX);
size.putDouble("height", frame.height() * mScaleY);
WritableMap bounds = Arguments.createMap();
bounds.putMap("origin", origin);
bounds.putMap("size", size);
return bounds;
}
}

View File

@ -0,0 +1,97 @@
package org.reactnative.camera.tasks;
import android.util.SparseArray;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.WritableArray;
import com.facebook.react.bridge.WritableMap;
import com.google.android.cameraview.CameraView;
import com.google.android.gms.vision.face.Face;
import org.reactnative.camera.utils.ImageDimensions;
import org.reactnative.facedetector.FaceDetectorUtils;
import org.reactnative.frame.RNFrame;
import org.reactnative.frame.RNFrameFactory;
import org.reactnative.facedetector.RNFaceDetector;
public class FaceDetectorAsyncTask extends android.os.AsyncTask<Void, Void, SparseArray<Face>> {
private byte[] mImageData;
private int mWidth;
private int mHeight;
private int mRotation;
private RNFaceDetector mFaceDetector;
private FaceDetectorAsyncTaskDelegate mDelegate;
private ImageDimensions mImageDimensions;
private double mScaleX;
private double mScaleY;
private int mPaddingLeft;
private int mPaddingTop;
public FaceDetectorAsyncTask(
FaceDetectorAsyncTaskDelegate delegate,
RNFaceDetector faceDetector,
byte[] imageData,
int width,
int height,
int rotation,
float density,
int facing,
int viewWidth,
int viewHeight,
int viewPaddingLeft,
int viewPaddingTop
) {
mImageData = imageData;
mWidth = width;
mHeight = height;
mRotation = rotation;
mDelegate = delegate;
mFaceDetector = faceDetector;
mImageDimensions = new ImageDimensions(width, height, rotation, facing);
mScaleX = (double) (viewWidth) / (mImageDimensions.getWidth() * density);
mScaleY = (double) (viewHeight) / (mImageDimensions.getHeight() * density);
mPaddingLeft = viewPaddingLeft;
mPaddingTop = viewPaddingTop;
}
@Override
protected SparseArray<Face> doInBackground(Void... ignored) {
if (isCancelled() || mDelegate == null || mFaceDetector == null || !mFaceDetector.isOperational()) {
return null;
}
RNFrame frame = RNFrameFactory.buildFrame(mImageData, mWidth, mHeight, mRotation);
return mFaceDetector.detect(frame);
}
@Override
protected void onPostExecute(SparseArray<Face> faces) {
super.onPostExecute(faces);
if (faces == null) {
mDelegate.onFaceDetectionError(mFaceDetector);
} else {
if (faces.size() > 0) {
mDelegate.onFacesDetected(serializeEventData(faces));
}
mDelegate.onFaceDetectingTaskCompleted();
}
}
private WritableArray serializeEventData(SparseArray<Face> faces) {
WritableArray facesList = Arguments.createArray();
for(int i = 0; i < faces.size(); i++) {
Face face = faces.valueAt(i);
WritableMap serializedFace = FaceDetectorUtils.serializeFace(face, mScaleX, mScaleY, mWidth, mHeight, mPaddingLeft, mPaddingTop);
if (mImageDimensions.getFacing() == CameraView.FACING_FRONT) {
serializedFace = FaceDetectorUtils.rotateFaceX(serializedFace, mImageDimensions.getWidth(), mScaleX);
} else {
serializedFace = FaceDetectorUtils.changeAnglesDirection(serializedFace);
}
facesList.pushMap(serializedFace);
}
return facesList;
}
}

View File

@ -0,0 +1,178 @@
package org.reactnative.camera.tasks;
import android.util.SparseArray;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.WritableArray;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.uimanager.ThemedReactContext;
import com.google.android.cameraview.CameraView;
import com.google.android.gms.vision.text.Line;
import com.google.android.gms.vision.text.Text;
import com.google.android.gms.vision.text.TextBlock;
import com.google.android.gms.vision.text.TextRecognizer;
import org.reactnative.camera.utils.ImageDimensions;
import org.reactnative.facedetector.FaceDetectorUtils;
import org.reactnative.frame.RNFrame;
import org.reactnative.frame.RNFrameFactory;
public class TextRecognizerAsyncTask extends android.os.AsyncTask<Void, Void, SparseArray<TextBlock>> {
private TextRecognizerAsyncTaskDelegate mDelegate;
private ThemedReactContext mThemedReactContext;
private TextRecognizer mTextRecognizer;
private byte[] mImageData;
private int mWidth;
private int mHeight;
private int mRotation;
private ImageDimensions mImageDimensions;
private double mScaleX;
private double mScaleY;
private int mPaddingLeft;
private int mPaddingTop;
public TextRecognizerAsyncTask(
TextRecognizerAsyncTaskDelegate delegate,
ThemedReactContext themedReactContext,
byte[] imageData,
int width,
int height,
int rotation,
float density,
int facing,
int viewWidth,
int viewHeight,
int viewPaddingLeft,
int viewPaddingTop
) {
mDelegate = delegate;
mThemedReactContext = themedReactContext;
mImageData = imageData;
mWidth = width;
mHeight = height;
mRotation = rotation;
mImageDimensions = new ImageDimensions(width, height, rotation, facing);
mScaleX = (double) (viewWidth) / (mImageDimensions.getWidth() * density);
mScaleY = (double) (viewHeight) / (mImageDimensions.getHeight() * density);
mPaddingLeft = viewPaddingLeft;
mPaddingTop = viewPaddingTop;
}
@Override
protected SparseArray<TextBlock> doInBackground(Void... ignored) {
if (isCancelled() || mDelegate == null) {
return null;
}
mTextRecognizer = new TextRecognizer.Builder(mThemedReactContext).build();
RNFrame frame = RNFrameFactory.buildFrame(mImageData, mWidth, mHeight, mRotation);
return mTextRecognizer.detect(frame.getFrame());
}
@Override
protected void onPostExecute(SparseArray<TextBlock> textBlocks) {
super.onPostExecute(textBlocks);
if (mTextRecognizer != null) {
mTextRecognizer.release();
}
if (textBlocks != null) {
WritableArray textBlocksList = Arguments.createArray();
for (int i = 0; i < textBlocks.size(); ++i) {
TextBlock textBlock = textBlocks.valueAt(i);
WritableMap serializedTextBlock = serializeText(textBlock);
if (mImageDimensions.getFacing() == CameraView.FACING_FRONT) {
serializedTextBlock = rotateTextX(serializedTextBlock);
}
textBlocksList.pushMap(serializedTextBlock);
}
mDelegate.onTextRecognized(textBlocksList);
}
mDelegate.onTextRecognizerTaskCompleted();
}
private WritableMap serializeText(Text text) {
WritableMap encodedText = Arguments.createMap();
WritableArray components = Arguments.createArray();
for (Text component : text.getComponents()) {
components.pushMap(serializeText(component));
}
encodedText.putArray("components", components);
encodedText.putString("value", text.getValue());
int x = text.getBoundingBox().left;
int y = text.getBoundingBox().top;
if (text.getBoundingBox().left < mWidth / 2) {
x = x + mPaddingLeft / 2;
} else if (text.getBoundingBox().left > mWidth /2) {
x = x - mPaddingLeft / 2;
}
if (text.getBoundingBox().height() < mHeight / 2) {
y = y + mPaddingTop / 2;
} else if (text.getBoundingBox().height() > mHeight / 2) {
y = y - mPaddingTop / 2;
}
WritableMap origin = Arguments.createMap();
origin.putDouble("x", x * this.mScaleX);
origin.putDouble("y", y * this.mScaleY);
WritableMap size = Arguments.createMap();
size.putDouble("width", text.getBoundingBox().width() * this.mScaleX);
size.putDouble("height", text.getBoundingBox().height() * this.mScaleY);
WritableMap bounds = Arguments.createMap();
bounds.putMap("origin", origin);
bounds.putMap("size", size);
encodedText.putMap("bounds", bounds);
String type_;
if (text instanceof TextBlock) {
type_ = "block";
} else if (text instanceof Line) {
type_ = "line";
} else /*if (text instanceof Element)*/ {
type_ = "element";
}
encodedText.putString("type", type_);
return encodedText;
}
private WritableMap rotateTextX(WritableMap text) {
ReadableMap faceBounds = text.getMap("bounds");
ReadableMap oldOrigin = faceBounds.getMap("origin");
WritableMap mirroredOrigin = FaceDetectorUtils.positionMirroredHorizontally(
oldOrigin, mImageDimensions.getWidth(), mScaleX);
double translateX = -faceBounds.getMap("size").getDouble("width");
WritableMap translatedMirroredOrigin = FaceDetectorUtils.positionTranslatedHorizontally(mirroredOrigin, translateX);
WritableMap newBounds = Arguments.createMap();
newBounds.merge(faceBounds);
newBounds.putMap("origin", translatedMirroredOrigin);
text.putMap("bounds", newBounds);
ReadableArray oldComponents = text.getArray("components");
WritableArray newComponents = Arguments.createArray();
for (int i = 0; i < oldComponents.size(); ++i) {
WritableMap component = Arguments.createMap();
component.merge(oldComponents.getMap(i));
rotateTextX(component);
newComponents.pushMap(component);
}
text.putArray("components", newComponents);
return text;
}
}

View File

@ -18,10 +18,10 @@ public class FaceDetectorUtils {
};
public static WritableMap serializeFace(Face face) {
return serializeFace(face, 1, 1);
return serializeFace(face, 1, 1, 0, 0, 0, 0);
}
public static WritableMap serializeFace(Face face, double scaleX, double scaleY) {
public static WritableMap serializeFace(Face face, double scaleX, double scaleY, int width, int height, int paddingLeft, int paddingTop) {
WritableMap encodedFace = Arguments.createMap();
encodedFace.putInt("faceID", face.getId());
@ -39,12 +39,25 @@ public class FaceDetectorUtils {
}
for(Landmark landmark : face.getLandmarks()) {
encodedFace.putMap(landmarkNames[landmark.getType()], mapFromPoint(landmark.getPosition(), scaleX, scaleY));
encodedFace.putMap(landmarkNames[landmark.getType()], mapFromPoint(landmark.getPosition(), scaleX, scaleY, width, height, paddingLeft, paddingTop));
}
WritableMap origin = Arguments.createMap();
origin.putDouble("x", face.getPosition().x * scaleX);
origin.putDouble("y", face.getPosition().y * scaleY);
Float x = face.getPosition().x;
Float y = face.getPosition().y;
if (face.getPosition().x < width / 2) {
x = x + paddingLeft / 2;
} else if (face.getPosition().x > width / 2) {
x = x - paddingLeft / 2;
}
if (face.getPosition().y < height / 2) {
y = y + paddingTop / 2;
} else if (face.getPosition().y > height / 2) {
y = y - paddingTop / 2;
}
origin.putDouble("x", x * scaleX);
origin.putDouble("y", y * scaleY);
WritableMap size = Arguments.createMap();
size.putDouble("width", face.getWidth() * scaleX);
@ -91,8 +104,21 @@ public class FaceDetectorUtils {
return face;
}
public static WritableMap mapFromPoint(PointF point, double scaleX, double scaleY) {
public static WritableMap mapFromPoint(PointF point, double scaleX, double scaleY, int width, int height, int paddingLeft, int paddingTop) {
WritableMap map = Arguments.createMap();
Float x = point.x;
Float y = point.y;
if (point.x < width / 2) {
x = (x + paddingLeft / 2);
} else if (point.x > width / 2) {
x = (x - paddingLeft / 2);
}
if (point.y < height / 2) {
y = (y + paddingTop / 2);
} else if (point.y > height / 2) {
y = (y - paddingTop / 2);
}
map.putDouble("x", point.x * scaleX);
map.putDouble("y", point.y * scaleY);
return map;

View File

@ -88,11 +88,6 @@ public class RNFaceDetector {
}
}
public void setTrackingEnabled(boolean tracking) {
release();
mBuilder.setTrackingEnabled(tracking);
}
public void release() {
releaseFaceDetector();
mPreviousDimensions = null;

View File

@ -3,7 +3,7 @@ package org.reactnative.facedetector.tasks;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.support.media.ExifInterface;
import androidx.exifinterface.media.ExifInterface;
import android.net.Uri;
import android.os.AsyncTask;
import android.util.Log;
@ -131,7 +131,7 @@ public class FileFaceDetectionAsyncTask extends AsyncTask<Void, Void, SparseArra
private static RNFaceDetector detectorForOptions(ReadableMap options, Context context) {
RNFaceDetector detector = new RNFaceDetector(context);
detector.setTrackingEnabled(false);
detector.setTracking(false);
if(options.hasKey(MODE_OPTION_KEY)) {
detector.setMode(options.getInt(MODE_OPTION_KEY));

View File

@ -18,8 +18,8 @@ package com.google.android.cameraview;
import android.os.Parcel;
import android.os.Parcelable;
import android.support.annotation.NonNull;
import android.support.v4.util.SparseArrayCompat;
import androidx.annotation.NonNull;
import androidx.collection.SparseArrayCompat;
/**
* Immutable class for describing proportional relationship between width and height.

View File

@ -26,20 +26,25 @@ import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CameraMetadata;
import android.hardware.camera2.CaptureFailure;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.CaptureResult;
import android.hardware.camera2.TotalCaptureResult;
import android.hardware.camera2.params.MeteringRectangle;
import android.hardware.camera2.params.StreamConfigurationMap;
import android.media.CamcorderProfile;
import android.media.Image;
import android.media.ImageReader;
import android.media.MediaRecorder;
import android.support.annotation.NonNull;
import android.media.MediaActionSound;
import androidx.annotation.NonNull;
import android.util.Log;
import android.util.SparseIntArray;
import android.view.Surface;
import android.os.Handler;
import android.os.Looper;
import android.os.Build;
import com.facebook.react.bridge.ReadableMap;
@ -47,10 +52,17 @@ import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import java.util.SortedSet;
import org.reactnative.camera.utils.ObjectUtils;
@SuppressWarnings("MissingPermission")
@TargetApi(21)
class Camera2 extends CameraViewImpl implements MediaRecorder.OnInfoListener, MediaRecorder.OnErrorListener {
@ -74,6 +86,10 @@ class Camera2 extends CameraViewImpl implements MediaRecorder.OnInfoListener, Me
*/
private static final int MAX_PREVIEW_HEIGHT = 1080;
private static final int FOCUS_AREA_SIZE_DEFAULT = 300;
private static final int FOCUS_METERING_AREA_WEIGHT_DEFAULT = 1000;
private final CameraManager mCameraManager;
private final CameraDevice.StateCallback mCameraDeviceCallback
@ -192,11 +208,14 @@ class Camera2 extends CameraViewImpl implements MediaRecorder.OnInfoListener, Me
private String mCameraId;
private String _mCameraId;
private CameraCharacteristics mCameraCharacteristics;
CameraDevice mCamera;
MediaActionSound sound = new MediaActionSound();
CameraCaptureSession mCaptureSession;
CaptureRequest.Builder mPreviewRequestBuilder;
@ -231,6 +250,8 @@ class Camera2 extends CameraViewImpl implements MediaRecorder.OnInfoListener, Me
private int mFlash;
private float mExposure;
private int mCameraOrientation;
private int mDisplayOrientation;
@ -245,12 +266,14 @@ class Camera2 extends CameraViewImpl implements MediaRecorder.OnInfoListener, Me
private boolean mIsScanning;
private Boolean mPlaySoundOnCapture = false;
private Surface mPreviewSurface;
private Rect mInitialCropRegion;
Camera2(Callback callback, PreviewImpl preview, Context context) {
super(callback, preview);
Camera2(Callback callback, PreviewImpl preview, Context context, Handler bgHandler) {
super(callback, preview, bgHandler);
mCameraManager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
mCameraManager.registerAvailabilityCallback(new CameraManager.AvailabilityCallback() {
@Override
@ -283,6 +306,7 @@ class Camera2 extends CameraViewImpl implements MediaRecorder.OnInfoListener, Me
boolean start() {
if (!chooseCameraIdByFacing()) {
mAspectRatio = mInitialRatio;
mCallback.onMountError();
return false;
}
collectCameraInfo();
@ -321,6 +345,8 @@ class Camera2 extends CameraViewImpl implements MediaRecorder.OnInfoListener, Me
mMediaRecorder = null;
if (mIsRecording) {
mCallback.onRecordingEnd();
// @TODO: implement videoOrientation and deviceOrientation calculation
mCallback.onVideoRecorded(mVideoPath, 0, 0);
mIsRecording = false;
@ -350,11 +376,65 @@ class Camera2 extends CameraViewImpl implements MediaRecorder.OnInfoListener, Me
return mFacing;
}
@Override
public ArrayList<int[]> getSupportedPreviewFpsRange() {
Log.e("CAMERA_2:: ", "getSupportedPreviewFpsRange is not currently supported for Camera2");
ArrayList<int[]> validValues = new ArrayList<int[]>();
return validValues;
}
@Override
void setCameraId(String id) {
if(!ObjectUtils.equals(_mCameraId, id)){
_mCameraId = id;
// only update if our camera ID actually changes
// from what we currently have.
// Passing null will always yield true
if(!ObjectUtils.equals(_mCameraId, mCameraId)){
// this will call chooseCameraIdByFacing
if (isCameraOpened()) {
stop();
start();
}
}
}
}
@Override
String getCameraId() {
return _mCameraId;
}
@Override
Set<AspectRatio> getSupportedAspectRatios() {
return mPreviewSizes.ratios();
}
@Override
List<Properties> getCameraIds() {
try{
List<Properties> ids = new ArrayList<>();
String[] cameraIds = mCameraManager.getCameraIdList();
for (String id : cameraIds) {
Properties p = new Properties();
CameraCharacteristics characteristics = mCameraManager.getCameraCharacteristics(id);
Integer internal = characteristics.get(CameraCharacteristics.LENS_FACING);
p.put("id", id);
p.put("type", String.valueOf(internal == CameraCharacteristics.LENS_FACING_FRONT ? Constants.FACING_FRONT : Constants.FACING_BACK));
ids.add(p);
}
return ids;
}
catch (CameraAccessException e) {
throw new RuntimeException("Failed to get a list of camera ids", e);
}
}
@Override
SortedSet<Size> getAvailablePictureSizes(AspectRatio ratio) {
return mPictureSizes.sizes(ratio);
@ -375,7 +455,7 @@ class Camera2 extends CameraViewImpl implements MediaRecorder.OnInfoListener, Me
mStillImageReader.close();
}
if (size == null) {
if (mAspectRatio == null) {
if (mAspectRatio == null || mPictureSize == null) {
return;
}
mPictureSizes.sizes(mAspectRatio).last();
@ -467,6 +547,17 @@ class Camera2 extends CameraViewImpl implements MediaRecorder.OnInfoListener, Me
return mFlash;
}
@Override
float getExposureCompensation() {
return mExposure;
}
@Override
void setExposureCompensation(float exposure) {
Log.e("CAMERA_2:: ", "Adjusting exposure is not currently supported for Camera2");
}
@Override
void takePicture(ReadableMap options) {
mCaptureCallback.setOptions(options);
@ -479,7 +570,7 @@ class Camera2 extends CameraViewImpl implements MediaRecorder.OnInfoListener, Me
}
@Override
boolean record(String path, int maxDuration, int maxFileSize, boolean recordAudio, CamcorderProfile profile, int orientation) {
boolean record(String path, int maxDuration, int maxFileSize, boolean recordAudio, CamcorderProfile profile, int orientation, int fps) {
if (!mIsRecording) {
setUpMediaRecorder(path, maxDuration, maxFileSize, recordAudio, profile);
try {
@ -502,6 +593,11 @@ class Camera2 extends CameraViewImpl implements MediaRecorder.OnInfoListener, Me
mSessionCallback, null);
mMediaRecorder.start();
mIsRecording = true;
// @TODO: implement videoOrientation and deviceOrientation calculation
// same TODO as onVideoRecorded
mCallback.onRecordingStart(mVideoPath, 0, 0);
return true;
} catch (CameraAccessException | IOException e) {
e.printStackTrace();
@ -524,6 +620,16 @@ class Camera2 extends CameraViewImpl implements MediaRecorder.OnInfoListener, Me
}
}
@Override
void pauseRecording() {
pauseMediaRecorder();
}
@Override
void resumeRecording() {
resumeMediaRecorder();
}
@Override
public void setFocusDepth(float value) {
if (mFocusDepth == value) {
@ -593,6 +699,16 @@ class Camera2 extends CameraViewImpl implements MediaRecorder.OnInfoListener, Me
return mWhiteBalance;
}
@Override
void setPlaySoundOnCapture(boolean playSoundOnCapture) {
mPlaySoundOnCapture = playSoundOnCapture;
}
@Override
public boolean getPlaySoundOnCapture(){
return mPlaySoundOnCapture;
}
@Override
void setScanning(boolean isScanning) {
if (mIsScanning == isScanning) {
@ -631,7 +747,34 @@ class Camera2 extends CameraViewImpl implements MediaRecorder.OnInfoListener, Me
@Override
void setDeviceOrientation(int deviceOrientation) {
mDeviceOrientation = deviceOrientation;
mPreview.setDisplayOrientation(mDeviceOrientation);
//mPreview.setDisplayOrientation(deviceOrientation); // this is not needed and messes up the display orientation
}
// This is a helper method to query Camera2 legacy status so we don't need
// to instantiate and set all its props in order to check if it is legacy or not
// and then fallback to Camera1. This way, legacy devices can fall back to Camera1 right away
// This method makes sure all cameras are not legacy, so further checks are not needed.
public static boolean isLegacy(Context context){
try{
CameraManager manager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
String[] ids = manager.getCameraIdList();
for (String id : ids) {
CameraCharacteristics characteristics = manager.getCameraCharacteristics(id);
Integer level = characteristics.get(
CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
if (level == null ||
level == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY) {
Log.w(TAG, "Camera2 can only run in legacy mode and should not be used.");
return true;
}
}
return false;
}
catch(CameraAccessException ex){
Log.e(TAG, "Failed to check camera legacy status, returning true.", ex);
return true;
}
}
/**
@ -640,55 +783,79 @@ class Camera2 extends CameraViewImpl implements MediaRecorder.OnInfoListener, Me
* {@link #mFacing}.</p>
*/
private boolean chooseCameraIdByFacing() {
try {
int internalFacing = INTERNAL_FACINGS.get(mFacing);
final String[] ids = mCameraManager.getCameraIdList();
if (ids.length == 0) { // No camera
throw new RuntimeException("No camera available.");
}
for (String id : ids) {
CameraCharacteristics characteristics = mCameraManager.getCameraCharacteristics(id);
Integer level = characteristics.get(
CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
if (level == null ||
level == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY) {
continue;
if(_mCameraId == null){
try {
int internalFacing = INTERNAL_FACINGS.get(mFacing);
final String[] ids = mCameraManager.getCameraIdList();
if (ids.length == 0) { // No camera
Log.e(TAG, "No cameras available.");
return false;
}
Integer internal = characteristics.get(CameraCharacteristics.LENS_FACING);
for (String id : ids) {
CameraCharacteristics characteristics = mCameraManager.getCameraCharacteristics(id);
Integer internal = characteristics.get(CameraCharacteristics.LENS_FACING);
if (internal == null) {
Log.e(TAG, "Unexpected state: LENS_FACING null");
continue;
}
if (internal == internalFacing) {
mCameraId = id;
mCameraCharacteristics = characteristics;
return true;
}
}
// Not found
mCameraId = ids[0];
mCameraCharacteristics = mCameraManager.getCameraCharacteristics(mCameraId);
Integer internal = mCameraCharacteristics.get(CameraCharacteristics.LENS_FACING);
if (internal == null) {
throw new NullPointerException("Unexpected state: LENS_FACING null");
Log.e(TAG, "Unexpected state: LENS_FACING null");
return false;
}
if (internal == internalFacing) {
mCameraId = id;
mCameraCharacteristics = characteristics;
return true;
for (int i = 0, count = INTERNAL_FACINGS.size(); i < count; i++) {
if (INTERNAL_FACINGS.valueAt(i) == internal) {
mFacing = INTERNAL_FACINGS.keyAt(i);
return true;
}
}
}
// Not found
mCameraId = ids[0];
mCameraCharacteristics = mCameraManager.getCameraCharacteristics(mCameraId);
Integer level = mCameraCharacteristics.get(
CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
if (level == null ||
level == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY) {
// The operation can reach here when the only camera device is an external one.
// We treat it as facing back.
mFacing = Constants.FACING_BACK;
return true;
} catch (CameraAccessException e) {
Log.e(TAG, "Failed to get a list of camera devices", e);
return false;
}
Integer internal = mCameraCharacteristics.get(CameraCharacteristics.LENS_FACING);
if (internal == null) {
throw new NullPointerException("Unexpected state: LENS_FACING null");
}
for (int i = 0, count = INTERNAL_FACINGS.size(); i < count; i++) {
if (INTERNAL_FACINGS.valueAt(i) == internal) {
mFacing = INTERNAL_FACINGS.keyAt(i);
return true;
}
else{
try{
// need to set the mCameraCharacteristics variable as above and also do the same checks
// for legacy hardware
mCameraCharacteristics = mCameraManager.getCameraCharacteristics(_mCameraId);
// set our facing variable so orientation also works as expected
Integer internal = mCameraCharacteristics.get(CameraCharacteristics.LENS_FACING);
if (internal == null) {
Log.e(TAG, "Unexpected state: LENS_FACING null");
return false;
}
for (int i = 0, count = INTERNAL_FACINGS.size(); i < count; i++) {
if (INTERNAL_FACINGS.valueAt(i) == internal) {
mFacing = INTERNAL_FACINGS.keyAt(i);
break;
}
}
mCameraId = _mCameraId;
return true;
}
catch(Exception e){
Log.e(TAG, "Failed to get camera characteristics", e);
return false;
}
// The operation can reach here when the only camera device is an external one.
// We treat it as facing back.
mFacing = Constants.FACING_BACK;
return true;
} catch (CameraAccessException e) {
throw new RuntimeException("Failed to get a list of camera devices", e);
}
}
@ -788,6 +955,7 @@ class Camera2 extends CameraViewImpl implements MediaRecorder.OnInfoListener, Me
mCamera.createCaptureSession(Arrays.asList(surface, mStillImageReader.getSurface(),
mScanImageReader.getSurface()), mSessionCallback, null);
} catch (CameraAccessException e) {
Log.e(TAG, "Failed to start capture session", e);
mCallback.onMountError();
}
}
@ -1023,6 +1191,89 @@ class Camera2 extends CameraViewImpl implements MediaRecorder.OnInfoListener, Me
}
}
/**
* Auto focus on input coordinates
*/
// Much credit - https://gist.github.com/royshil/8c760c2485257c85a11cafd958548482
void setFocusArea(float x, float y) {
if (mCaptureSession == null) {
return;
}
CameraCaptureSession.CaptureCallback captureCallbackHandler = new CameraCaptureSession.CaptureCallback() {
@Override
public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) {
super.onCaptureCompleted(session, request, result);
if (request.getTag() == "FOCUS_TAG") {
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, null);
try {
mCaptureSession.setRepeatingRequest(mPreviewRequestBuilder.build(), null, null);
} catch (CameraAccessException e) {
Log.e(TAG, "Failed to manual focus.", e);
}
}
}
@Override
public void onCaptureFailed(CameraCaptureSession session, CaptureRequest request, CaptureFailure failure) {
super.onCaptureFailed(session, request, failure);
Log.e(TAG, "Manual AF failure: " + failure);
}
};
try {
mCaptureSession.stopRepeating();
} catch (CameraAccessException e) {
Log.e(TAG, "Failed to manual focus.", e);
}
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_CANCEL);
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_OFF);
try {
mCaptureSession.capture(mPreviewRequestBuilder.build(), captureCallbackHandler, null);
} catch (CameraAccessException e) {
Log.e(TAG, "Failed to manual focus.", e);
}
if (isMeteringAreaAFSupported()) {
MeteringRectangle focusAreaTouch = calculateFocusArea(x, y);
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_REGIONS, new MeteringRectangle[]{focusAreaTouch});
}
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_AUTO);
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_START);
mPreviewRequestBuilder.setTag("FOCUS_TAG");
try {
mCaptureSession.capture(mPreviewRequestBuilder.build(), captureCallbackHandler, null);
} catch (CameraAccessException e) {
Log.e(TAG, "Failed to manual focus.", e);
}
}
private boolean isMeteringAreaAFSupported() {
return mCameraCharacteristics.get(CameraCharacteristics.CONTROL_MAX_REGIONS_AF) >= 1;
}
private MeteringRectangle calculateFocusArea(float x, float y) {
final Rect sensorArraySize = mCameraCharacteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE);
// Current iOS spec has a requirement on sensor orientation that doesn't change, spec followed here.
final int xCoordinate = (int)(y * (float)sensorArraySize.height());
final int yCoordinate = (int)(x * (float)sensorArraySize.width());
final int halfTouchWidth = 150; //TODO: this doesn't represent actual touch size in pixel. Values range in [3, 10]...
final int halfTouchHeight = 150;
MeteringRectangle focusAreaTouch = new MeteringRectangle(Math.max(yCoordinate - halfTouchWidth, 0),
Math.max(xCoordinate - halfTouchHeight, 0),
halfTouchWidth * 2,
halfTouchHeight * 2,
MeteringRectangle.METERING_WEIGHT_MAX - 1);
return focusAreaTouch;
}
/**
* Captures a still picture.
*/
@ -1064,6 +1315,13 @@ class Camera2 extends CameraViewImpl implements MediaRecorder.OnInfoListener, Me
break;
}
captureRequestBuilder.set(CaptureRequest.JPEG_ORIENTATION, getOutputRotation());
if(mCaptureCallback.getOptions().hasKey("quality")){
int quality = (int) (mCaptureCallback.getOptions().getDouble("quality") * 100);
captureRequestBuilder.set(CaptureRequest.JPEG_QUALITY, (byte)quality);
}
captureRequestBuilder.set(CaptureRequest.SCALER_CROP_REGION, mPreviewRequestBuilder.get(CaptureRequest.SCALER_CROP_REGION));
// Stop preview and capture a still picture.
mCaptureSession.stopRepeating();
@ -1077,6 +1335,9 @@ class Camera2 extends CameraViewImpl implements MediaRecorder.OnInfoListener, Me
&& !mCaptureCallback.getOptions().getBoolean("pauseAfterCapture")) {
unlockFocus();
}
if (mPlaySoundOnCapture) {
sound.play(MediaActionSound.SHUTTER_CLICK);
}
}
}, null);
} catch (CameraAccessException e) {
@ -1087,9 +1348,25 @@ class Camera2 extends CameraViewImpl implements MediaRecorder.OnInfoListener, Me
private int getOutputRotation() {
@SuppressWarnings("ConstantConditions")
int sensorOrientation = mCameraCharacteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
return (sensorOrientation +
mDisplayOrientation * (mFacing == Constants.FACING_FRONT ? 1 : -1) +
360) % 360;
// updated and copied from Camera1
if (mFacing == Constants.FACING_BACK) {
return (sensorOrientation + mDeviceOrientation) % 360;
} else {
final int landscapeFlip = isLandscape(mDeviceOrientation) ? 180 : 0;
return (sensorOrientation + mDeviceOrientation + landscapeFlip) % 360;
}
}
/**
* Test if the supplied orientation is in landscape.
*
* @param orientationDegrees Orientation in degrees (0,90,180,270)
* @return True if in landscape, false if portrait
*/
private boolean isLandscape(int orientationDegrees) {
return (orientationDegrees == Constants.LANDSCAPE_90 ||
orientationDegrees == Constants.LANDSCAPE_270);
}
private void setUpMediaRecorder(String path, int maxDuration, int maxFileSize, boolean recordAudio, CamcorderProfile profile) {
@ -1150,6 +1427,8 @@ class Camera2 extends CameraViewImpl implements MediaRecorder.OnInfoListener, Me
mMediaRecorder.release();
mMediaRecorder = null;
mCallback.onRecordingEnd();
if (mVideoPath == null || !new File(mVideoPath).exists()) {
// @TODO: implement videoOrientation and deviceOrientation calculation
mCallback.onVideoRecorded(null, 0 , 0);
@ -1160,6 +1439,18 @@ class Camera2 extends CameraViewImpl implements MediaRecorder.OnInfoListener, Me
mVideoPath = null;
}
private void pauseMediaRecorder() {
if (Build.VERSION.SDK_INT >= 24) {
mMediaRecorder.pause();
}
}
private void resumeMediaRecorder() {
if (Build.VERSION.SDK_INT >= 24) {
mMediaRecorder.resume();
}
}
/**
* Unlocks the auto-focus and restart camera preview. This is supposed to be called after
* capturing a still picture.

View File

@ -20,13 +20,14 @@ import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.ImageFormat;
import android.hardware.camera2.params.StreamConfigurationMap;
import android.os.Handler;
@TargetApi(23)
class Camera2Api23 extends Camera2 {
Camera2Api23(Callback callback, PreviewImpl preview, Context context) {
super(callback, preview, context);
Camera2Api23(Callback callback, PreviewImpl preview, Context context, Handler bgHandler) {
super(callback, preview, context, bgHandler);
}
@Override

View File

@ -18,17 +18,22 @@ package com.google.android.cameraview;
import android.app.Activity;
import android.content.Context;
import android.graphics.Rect;
import android.hardware.Camera;
import android.media.CamcorderProfile;
import android.os.Build;
import android.os.HandlerThread;
import android.os.Handler;
import android.os.Parcel;
import android.os.Parcelable;
import android.support.annotation.IntDef;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.os.ParcelableCompat;
import android.support.v4.os.ParcelableCompatCreatorCallbacks;
import android.support.v4.view.ViewCompat;
import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.os.ParcelableCompat;
import androidx.core.os.ParcelableCompatCreatorCallbacks;
import androidx.core.view.ViewCompat;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.FrameLayout;
import android.graphics.SurfaceTexture;
@ -38,6 +43,8 @@ import com.facebook.react.bridge.ReadableMap;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import java.util.SortedSet;
@ -86,6 +93,10 @@ public class CameraView extends FrameLayout {
private final DisplayOrientationDetector mDisplayOrientationDetector;
protected HandlerThread mBgThread;
protected Handler mBgHandler;
public CameraView(Context context, boolean fallbackToOldApi) {
this(context, null, fallbackToOldApi);
}
@ -97,6 +108,13 @@ public class CameraView extends FrameLayout {
@SuppressWarnings("WrongConstant")
public CameraView(Context context, AttributeSet attrs, int defStyleAttr, boolean fallbackToOldApi) {
super(context, attrs, defStyleAttr);
// bg hanadler for non UI heavy work
mBgThread = new HandlerThread("RNCamera-Handler-Thread");
mBgThread.start();
mBgHandler = new Handler(mBgThread.getLooper());
if (isInEditMode()){
mCallbacks = null;
mDisplayOrientationDetector = null;
@ -108,12 +126,12 @@ public class CameraView extends FrameLayout {
// Internal setup
final PreviewImpl preview = createPreviewImpl(context);
mCallbacks = new CallbackBridge();
if (fallbackToOldApi || Build.VERSION.SDK_INT < 21) {
mImpl = new Camera1(mCallbacks, preview);
if (fallbackToOldApi || Build.VERSION.SDK_INT < 21 || Camera2.isLegacy(context)) {
mImpl = new Camera1(mCallbacks, preview, mBgHandler);
} else if (Build.VERSION.SDK_INT < 23) {
mImpl = new Camera2(mCallbacks, preview, context);
mImpl = new Camera2(mCallbacks, preview, context, mBgHandler);
} else {
mImpl = new Camera2Api23(mCallbacks, preview, context);
mImpl = new Camera2Api23(mCallbacks, preview, context, mBgHandler);
}
// Display orientation detector
@ -126,6 +144,19 @@ public class CameraView extends FrameLayout {
};
}
public void cleanup(){
if(mBgThread != null){
if(Build.VERSION.SDK_INT < 18){
mBgThread.quit();
}
else{
mBgThread.quitSafely();
}
mBgThread = null;
}
}
@NonNull
private PreviewImpl createPreviewImpl(Context context) {
PreviewImpl preview;
@ -217,12 +248,15 @@ public class CameraView extends FrameLayout {
protected Parcelable onSaveInstanceState() {
SavedState state = new SavedState(super.onSaveInstanceState());
state.facing = getFacing();
state.cameraId = getCameraId();
state.ratio = getAspectRatio();
state.autoFocus = getAutoFocus();
state.flash = getFlash();
state.exposure = getExposureCompensation();
state.focusDepth = getFocusDepth();
state.zoom = getZoom();
state.whiteBalance = getWhiteBalance();
state.playSoundOnCapture = getPlaySoundOnCapture();
state.scanning = getScanning();
state.pictureSize = getPictureSize();
return state;
@ -237,12 +271,15 @@ public class CameraView extends FrameLayout {
SavedState ss = (SavedState) state;
super.onRestoreInstanceState(ss.getSuperState());
setFacing(ss.facing);
setCameraId(ss.cameraId);
setAspectRatio(ss.ratio);
setAutoFocus(ss.autoFocus);
setFlash(ss.flash);
setExposureCompensation(ss.exposure);
setFocusDepth(ss.focusDepth);
setZoom(ss.zoom);
setWhiteBalance(ss.whiteBalance);
setPlaySoundOnCapture(ss.playSoundOnCapture);
setScanning(ss.scanning);
setPictureSize(ss.pictureSize);
}
@ -255,15 +292,17 @@ public class CameraView extends FrameLayout {
boolean wasOpened = isCameraOpened();
Parcelable state = onSaveInstanceState();
if (useCamera2) {
if (useCamera2 && !Camera2.isLegacy(mContext)) {
if (wasOpened) {
stop();
}
if (Build.VERSION.SDK_INT < 23) {
mImpl = new Camera2(mCallbacks, mImpl.mPreview, mContext);
mImpl = new Camera2(mCallbacks, mImpl.mPreview, mContext, mBgHandler);
} else {
mImpl = new Camera2Api23(mCallbacks, mImpl.mPreview, mContext);
mImpl = new Camera2Api23(mCallbacks, mImpl.mPreview, mContext, mBgHandler);
}
onRestoreInstanceState(state);
} else {
if (mImpl instanceof Camera1) {
return;
@ -272,9 +311,11 @@ public class CameraView extends FrameLayout {
if (wasOpened) {
stop();
}
mImpl = new Camera1(mCallbacks, mImpl.mPreview);
mImpl = new Camera1(mCallbacks, mImpl.mPreview, mBgHandler);
}
if(wasOpened){
start();
}
start();
}
/**
@ -282,17 +323,20 @@ public class CameraView extends FrameLayout {
* {@link Activity#onResume()}.
*/
public void start() {
if (!mImpl.start()) {
if (mImpl.getView() != null) {
this.removeView(mImpl.getView());
}
//store the state and restore this state after fall back to Camera1
Parcelable state=onSaveInstanceState();
// Camera2 uses legacy hardware layer; fall back to Camera1
mImpl = new Camera1(mCallbacks, createPreviewImpl(getContext()));
onRestoreInstanceState(state);
mImpl.start();
}
mImpl.start();
// this fallback is no longer needed and was too buggy/slow
// if (!mImpl.start()) {
// if (mImpl.getView() != null) {
// this.removeView(mImpl.getView());
// }
// //store the state and restore this state after fall back to Camera1
// Parcelable state = onSaveInstanceState();
// // Camera2 uses legacy hardware layer; fall back to Camera1
// mImpl = new Camera1(mCallbacks, createPreviewImpl(getContext()), mBgHandler);
// onRestoreInstanceState(state);
// mImpl.start();
// }
}
/**
@ -379,6 +423,24 @@ public class CameraView extends FrameLayout {
return mImpl.getFacing();
}
/**
* Chooses camera by its camera iD
*
* @param id The camera ID
*/
public void setCameraId(String id) {
mImpl.setCameraId(id);
}
/**
* Gets the currently set camera ID
*
* @return The camera facing.
*/
public String getCameraId() {
return mImpl.getCameraId();
}
/**
* Gets all the aspect ratios supported by the current camera.
*/
@ -386,6 +448,13 @@ public class CameraView extends FrameLayout {
return mImpl.getSupportedAspectRatios();
}
/**
* Gets all the camera IDs supported by the phone as a String
*/
public List<Properties> getCameraIds() {
return mImpl.getCameraIds();
}
/**
* Sets the aspect ratio of camera.
*
@ -406,7 +475,7 @@ public class CameraView extends FrameLayout {
public AspectRatio getAspectRatio() {
return mImpl.getAspectRatio();
}
/**
* Gets all the picture sizes for particular ratio supported by the current camera.
*
@ -415,7 +484,7 @@ public class CameraView extends FrameLayout {
public SortedSet<Size> getAvailablePictureSizes(@NonNull AspectRatio ratio) {
return mImpl.getAvailablePictureSizes(ratio);
}
/**
* Sets the size of taken pictures.
*
@ -424,7 +493,7 @@ public class CameraView extends FrameLayout {
public void setPictureSize(@NonNull Size size) {
mImpl.setPictureSize(size);
}
/**
* Gets the size of pictures that will be taken.
*/
@ -462,6 +531,10 @@ public class CameraView extends FrameLayout {
mImpl.setFlash(flash);
}
public ArrayList<int[]> getSupportedPreviewFpsRange() {
return mImpl.getSupportedPreviewFpsRange();
}
/**
* Gets the current flash mode.
*
@ -473,6 +546,15 @@ public class CameraView extends FrameLayout {
return mImpl.getFlash();
}
public void setExposureCompensation(float exposure) {
mImpl.setExposureCompensation(exposure);
}
public float getExposureCompensation() {
return mImpl.getExposureCompensation();
}
/**
* Gets the camera orientation relative to the devices native orientation.
*
@ -482,6 +564,16 @@ public class CameraView extends FrameLayout {
return mImpl.getCameraOrientation();
}
/**
* Sets the auto focus point.
*
* @param x sets the x coordinate for camera auto focus
* @param y sets the y coordinate for camera auto focus
*/
public void setAutoFocusPointOfInterest(float x, float y) {
mImpl.setFocusArea(x, y);
}
public void setFocusDepth(float value) {
mImpl.setFocusDepth(value);
}
@ -504,6 +596,14 @@ public class CameraView extends FrameLayout {
return mImpl.getWhiteBalance();
}
public void setPlaySoundOnCapture(boolean playSoundOnCapture) {
mImpl.setPlaySoundOnCapture(playSoundOnCapture);
}
public boolean getPlaySoundOnCapture() {
return mImpl.getPlaySoundOnCapture();
}
public void setScanning(boolean isScanning) { mImpl.setScanning(isScanning);}
public boolean getScanning() { return mImpl.getScanning(); }
@ -523,20 +623,30 @@ public class CameraView extends FrameLayout {
* @param maxDuration Maximum duration of the recording, in seconds.
* @param maxFileSize Maximum recording file size, in bytes.
* @param profile Quality profile of the recording.
*
* fires {@link Callback#onRecordingStart(CameraView, String, int, int)} and {@link Callback#onRecordingEnd(CameraView)}.
*/
public boolean record(String path, int maxDuration, int maxFileSize,
boolean recordAudio, CamcorderProfile profile, int orientation) {
return mImpl.record(path, maxDuration, maxFileSize, recordAudio, profile, orientation);
boolean recordAudio, CamcorderProfile profile, int orientation, int fps) {
return mImpl.record(path, maxDuration, maxFileSize, recordAudio, profile, orientation, fps);
}
public void stopRecording() {
mImpl.stopRecording();
}
public void pauseRecording() {
mImpl.pauseRecording();
}
public void resumeRecording() {
mImpl.resumeRecording();
}
public void resumePreview() {
mImpl.resumePreview();
}
public void pausePreview() {
mImpl.pausePreview();
}
@ -591,6 +701,20 @@ public class CameraView extends FrameLayout {
}
}
@Override
public void onRecordingStart(String path, int videoOrientation, int deviceOrientation) {
for (Callback callback : mCallbacks) {
callback.onRecordingStart(CameraView.this, path, videoOrientation, deviceOrientation);
}
}
@Override
public void onRecordingEnd() {
for (Callback callback : mCallbacks) {
callback.onRecordingEnd(CameraView.this);
}
}
@Override
public void onVideoRecorded(String path, int videoOrientation, int deviceOrientation) {
for (Callback callback : mCallbacks) {
@ -622,6 +746,8 @@ public class CameraView extends FrameLayout {
@Facing
int facing;
String cameraId;
AspectRatio ratio;
boolean autoFocus;
@ -629,26 +755,33 @@ public class CameraView extends FrameLayout {
@Flash
int flash;
float exposure;
float focusDepth;
float zoom;
int whiteBalance;
boolean playSoundOnCapture;
boolean scanning;
Size pictureSize;
@SuppressWarnings("WrongConstant")
public SavedState(Parcel source, ClassLoader loader) {
super(source);
facing = source.readInt();
cameraId = source.readString();
ratio = source.readParcelable(loader);
autoFocus = source.readByte() != 0;
flash = source.readInt();
exposure = source.readFloat();
focusDepth = source.readFloat();
zoom = source.readFloat();
whiteBalance = source.readInt();
playSoundOnCapture = source.readByte() != 0;
scanning = source.readByte() != 0;
pictureSize = source.readParcelable(loader);
}
@ -661,12 +794,15 @@ public class CameraView extends FrameLayout {
public void writeToParcel(Parcel out, int flags) {
super.writeToParcel(out, flags);
out.writeInt(facing);
out.writeString(cameraId);
out.writeParcelable(ratio, 0);
out.writeByte((byte) (autoFocus ? 1 : 0));
out.writeInt(flash);
out.writeFloat(exposure);
out.writeFloat(focusDepth);
out.writeFloat(zoom);
out.writeInt(whiteBalance);
out.writeByte((byte) (playSoundOnCapture ? 1 : 0));
out.writeByte((byte) (scanning ? 1 : 0));
out.writeParcelable(pictureSize, flags);
}
@ -699,16 +835,14 @@ public class CameraView extends FrameLayout {
*
* @param cameraView The associated {@link CameraView}.
*/
public void onCameraOpened(CameraView cameraView) {
}
public void onCameraOpened(CameraView cameraView) {}
/**
* Called when camera is closed.
*
* @param cameraView The associated {@link CameraView}.
*/
public void onCameraClosed(CameraView cameraView) {
}
public void onCameraClosed(CameraView cameraView) {}
/**
* Called when a picture is taken.
@ -716,8 +850,23 @@ public class CameraView extends FrameLayout {
* @param cameraView The associated {@link CameraView}.
* @param data JPEG data.
*/
public void onPictureTaken(CameraView cameraView, byte[] data, int deviceOrientation) {
}
public void onPictureTaken(CameraView cameraView, byte[] data, int deviceOrientation) {}
/**
* Called when a video recording starts
*
* @param cameraView The associated {@link CameraView}.
* @param path Path to recoredd video file.
*/
public void onRecordingStart(CameraView cameraView, String path, int videoOrientation, int deviceOrientation) {}
/**
* Called when a video recording ends, but before video is saved/processed.
*
* @param cameraView The associated {@link CameraView}.
* @param path Path to recoredd video file.
*/
public void onRecordingEnd(CameraView cameraView){}
/**
* Called when a video is recorded.
@ -725,11 +874,9 @@ public class CameraView extends FrameLayout {
* @param cameraView The associated {@link CameraView}.
* @param path Path to recoredd video file.
*/
public void onVideoRecorded(CameraView cameraView, String path, int videoOrientation, int deviceOrientation) {
}
public void onVideoRecorded(CameraView cameraView, String path, int videoOrientation, int deviceOrientation) {}
public void onFramePreview(CameraView cameraView, byte[] data, int width, int height, int orientation) {
}
public void onFramePreview(CameraView cameraView, byte[] data, int width, int height, int orientation) {}
public void onMountError(CameraView cameraView) {}
}

View File

@ -19,21 +19,33 @@ package com.google.android.cameraview;
import android.media.CamcorderProfile;
import android.view.View;
import android.graphics.SurfaceTexture;
import android.os.Handler;
import com.facebook.react.bridge.ReadableMap;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import java.util.SortedSet;
abstract class CameraViewImpl {
protected final Callback mCallback;
protected final PreviewImpl mPreview;
CameraViewImpl(Callback callback, PreviewImpl preview) {
// Background handler that the implementation an use to run heavy tasks in background
// in a thread/looper provided by the view.
// Most calls should not require this since the view will already schedule it
// on the bg thread. However, the implementation might need to do some heavy work
// by itself.
protected final Handler mBgHandler;
CameraViewImpl(Callback callback, PreviewImpl preview, Handler bgHandler) {
mCallback = callback;
mPreview = preview;
mBgHandler = bgHandler;
}
View getView() {
@ -50,15 +62,21 @@ abstract class CameraViewImpl {
abstract boolean isCameraOpened();
abstract void setFacing(int facing);
abstract int getFacing();
abstract void setCameraId(String id);
abstract String getCameraId();
abstract Set<AspectRatio> getSupportedAspectRatios();
abstract List<Properties> getCameraIds();
abstract SortedSet<Size> getAvailablePictureSizes(AspectRatio ratio);
abstract void setPictureSize(Size size);
abstract Size getPictureSize();
/**
@ -76,19 +94,29 @@ abstract class CameraViewImpl {
abstract int getFlash();
abstract void setExposureCompensation(float exposure);
abstract float getExposureCompensation();
abstract void takePicture(ReadableMap options);
abstract boolean record(String path, int maxDuration, int maxFileSize,
boolean recordAudio, CamcorderProfile profile, int orientation);
boolean recordAudio, CamcorderProfile profile, int orientation, int fps);
abstract void stopRecording();
abstract void pauseRecording();
abstract void resumeRecording();
abstract int getCameraOrientation();
abstract void setDisplayOrientation(int displayOrientation);
abstract void setDeviceOrientation(int deviceOrientation);
abstract void setFocusArea(float x, float y);
abstract void setFocusDepth(float value);
abstract float getFocusDepth();
@ -97,16 +125,22 @@ abstract class CameraViewImpl {
abstract float getZoom();
abstract public ArrayList<int[]> getSupportedPreviewFpsRange();
abstract void setWhiteBalance(int whiteBalance);
abstract int getWhiteBalance();
abstract void setPlaySoundOnCapture(boolean playSoundOnCapture);
abstract boolean getPlaySoundOnCapture();
abstract void setScanning(boolean isScanning);
abstract boolean getScanning();
abstract public void resumePreview();
abstract public void pausePreview();
abstract public void setPreviewTexture(SurfaceTexture surfaceTexture);
@ -123,6 +157,10 @@ abstract class CameraViewImpl {
void onVideoRecorded(String path, int videoOrientation, int deviceOrientation);
void onRecordingStart(String path, int videoOrientation, int deviceOrientation);
void onRecordingEnd();
void onFramePreview(byte[] data, int width, int height, int orientation);
void onMountError();

View File

@ -18,7 +18,7 @@ package com.google.android.cameraview;
import android.os.Parcel;
import android.os.Parcelable;
import android.support.annotation.NonNull;
import androidx.annotation.NonNull;
/**
* Immutable class for describing width and height dimensions in pixels.

View File

@ -16,7 +16,7 @@
package com.google.android.cameraview;
import android.support.v4.util.ArrayMap;
import androidx.collection.ArrayMap;
import java.util.Set;
import java.util.SortedSet;

View File

@ -17,7 +17,7 @@
package com.google.android.cameraview;
import android.content.Context;
import android.support.v4.view.ViewCompat;
import androidx.core.view.ViewCompat;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

View File

@ -3,7 +3,7 @@ package com.lwansbrough.RCTCamera;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.support.media.ExifInterface;
import androidx.exifinterface.media.ExifInterface;
import android.util.Base64;
import android.util.Log;

View File

@ -221,7 +221,12 @@ public class RCTCamera {
// this hint can help reduce the time it takes to start recording.
Camera.Parameters parameters = camera.getParameters();
parameters.setRecordingHint(captureMode == RCTCameraModule.RCT_CAMERA_CAPTURE_MODE_VIDEO);
camera.setParameters(parameters);
try{
camera.setParameters(parameters);
}
catch(RuntimeException e ) {
Log.e("RCTCamera", "setParameters failed", e);
}
}
public void setCaptureQuality(int cameraType, String captureQuality) {
@ -260,7 +265,12 @@ public class RCTCamera {
if (pictureSize != null) {
parameters.setPictureSize(pictureSize.width, pictureSize.height);
try{
camera.setParameters(parameters);
}
catch(RuntimeException e ) {
Log.e("RCTCamera", "setParameters failed", e);
}
}
}
@ -332,7 +342,12 @@ public class RCTCamera {
List<String> flashModes = parameters.getSupportedFlashModes();
if (flashModes != null && flashModes.contains(value)) {
parameters.setFlashMode(value);
camera.setParameters(parameters);
try{
camera.setParameters(parameters);
}
catch(RuntimeException e ) {
Log.e("RCTCamera", "setParameters failed", e);
}
}
}
@ -358,7 +373,12 @@ public class RCTCamera {
List<String> flashModes = parameters.getSupportedFlashModes();
if (flashModes != null && flashModes.contains(value)) {
parameters.setFlashMode(value);
try{
camera.setParameters(parameters);
}
catch(RuntimeException e ) {
Log.e("RCTCamera", "setParameters failed", e);
}
}
}
@ -373,7 +393,12 @@ public class RCTCamera {
if (parameters.isZoomSupported()) {
if (zoom >=0 && zoom < maxZoom) {
parameters.setZoom(zoom);
camera.setParameters(parameters);
try{
camera.setParameters(parameters);
}
catch(RuntimeException e ) {
Log.e("RCTCamera", "setParameters failed", e);
}
}
}
}

View File

@ -734,7 +734,12 @@ public class RCTCameraModule extends ReactContextBaseJavaModule
if (parameters.isZoomSupported()) {
if (zoom >=0 && zoom < maxZoom) {
parameters.setZoom(zoom);
camera.setParameters(parameters);
try{
camera.setParameters(parameters);
}
catch(RuntimeException e ) {
Log.e("RCTCameraModule", "setParameters failed", e);
}
}
}
}

View File

@ -13,6 +13,7 @@ import android.hardware.Camera;
import android.view.MotionEvent;
import android.view.TextureView;
import android.os.AsyncTask;
import android.util.Log;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.ReactContext;
@ -133,7 +134,7 @@ class RCTCameraViewFinder extends TextureView implements TextureView.SurfaceText
public void setZoom(int zoom) {
RCTCamera.getInstance().setZoom(_cameraType, zoom);
}
}
public void startPreview() {
if (_surfaceTexture != null) {
@ -188,7 +189,12 @@ class RCTCameraViewFinder extends TextureView implements TextureView.SurfaceText
);
parameters.setPictureSize(optimalPictureSize.width, optimalPictureSize.height);
_camera.setParameters(parameters);
try{
_camera.setParameters(parameters);
}
catch(RuntimeException e ) {
Log.e("RCTCameraViewFinder", "setParameters failed", e);
}
_camera.setPreviewTexture(_surfaceTexture);
_camera.startPreview();
// clear window background if needed
@ -332,11 +338,16 @@ class RCTCameraViewFinder extends TextureView implements TextureView.SurfaceText
this.imageData = imageData;
}
private Result getBarcode(int width, int height) {
private Result getBarcode(int width, int height, boolean inverse) {
try{
PlanarYUVLuminanceSource source = new PlanarYUVLuminanceSource(imageData, width, height, 0, 0, width, height, false);
BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
return _multiFormatReader.decodeWithState(bitmap);
PlanarYUVLuminanceSource source = new PlanarYUVLuminanceSource(imageData, width, height, 0, 0, width, height, false);
BinaryBitmap bitmap;
if (inverse) {
bitmap = new BinaryBitmap(new HybridBinarizer(source.invert()));
} else {
bitmap = new BinaryBitmap(new HybridBinarizer(source));
}
return _multiFormatReader.decodeWithState(bitmap);
} catch (Throwable t) {
// meh
} finally {
@ -350,15 +361,25 @@ class RCTCameraViewFinder extends TextureView implements TextureView.SurfaceText
int width = size.width;
int height = size.height;
Result result = getBarcode(width, height);
if (result != null)
return result;
Result result = getBarcode(width, height, false);
if (result != null) {
return result;
}
// inverse
result = getBarcode(width, height, true);
if (result != null) {
return result;
}
// rotate
rotateImage(width, height);
width = size.height;
height = size.width;
result = getBarcode(width, height, false);
if (result != null) {
return result;
}
return getBarcode(width, height, true);
return getBarcode(width, height);
}
private void rotateImage(int width, int height) {
@ -401,7 +422,7 @@ class RCTCameraViewFinder extends TextureView implements TextureView.SurfaceText
resultPoints.pushMap(newPoint);
}
}
event.putArray("bounds", resultPoints);
event.putString("data", result.getText());
event.putString("type", result.getBarcodeFormat().toString());
@ -461,7 +482,12 @@ class RCTCameraViewFinder extends TextureView implements TextureView.SurfaceText
}
mFingerSpacing = newDist;
params.setZoom(zoom);
_camera.setParameters(params);
try{
_camera.setParameters(params);
}
catch(RuntimeException e ) {
Log.e("RCTCameraViewFinder", "setParameters failed", e);
}
}
/**
@ -507,7 +533,12 @@ class RCTCameraViewFinder extends TextureView implements TextureView.SurfaceText
}
// Set parameters before starting auto-focus.
_camera.setParameters(params);
try{
_camera.setParameters(params);
}
catch(RuntimeException e ) {
Log.e("RCTCameraViewFinder", "setParameters failed", e);
}
// Start auto-focus now that focus area has been set. If successful, then can cancel
// it afterwards. Wrap in try-catch to avoid crashing on merely autoFocus fails.
@ -532,4 +563,4 @@ class RCTCameraViewFinder extends TextureView implements TextureView.SurfaceText
float y = event.getY(0) - event.getY(1);
return (float) Math.sqrt(x * x + y * y);
}
}
}

View File

@ -1,8 +1,7 @@
package com.lwansbrough.RCTCamera;
import android.support.annotation.Nullable;
import androidx.annotation.Nullable;
import com.facebook.infer.annotation.Assertions;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.common.MapBuilder;
import com.facebook.react.uimanager.*;
@ -39,7 +38,9 @@ public class RCTCameraViewManager extends ViewGroupManager<RCTCameraView> {
@Override
public void receiveCommand(RCTCameraView view, int commandType, @Nullable ReadableArray args) {
Assertions.assertNotNull(view);
if (view == null) {
throw new AssertionError();
}
switch (commandType) {
case COMMAND_STOP_PREVIEW: {
view.stopPreview();

View File

@ -20,12 +20,16 @@ import com.google.android.cameraview.Size;
import javax.annotation.Nullable;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Properties;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import java.util.Set;
import java.util.SortedSet;
public class CameraModule extends ReactContextBaseJavaModule {
private static final String TAG = "CameraModule";
@ -208,7 +212,7 @@ public class CameraModule extends ReactContextBaseJavaModule {
}
});
}
@ReactMethod
public void pausePreview(final int viewTag) {
final ReactApplicationContext context = getReactApplicationContext();
@ -217,7 +221,7 @@ public class CameraModule extends ReactContextBaseJavaModule {
@Override
public void execute(NativeViewHierarchyManager nativeViewHierarchyManager) {
final RNCameraView cameraView;
try {
cameraView = (RNCameraView) nativeViewHierarchyManager.resolveView(viewTag);
if (cameraView.isCameraOpened()) {
@ -229,7 +233,7 @@ public class CameraModule extends ReactContextBaseJavaModule {
}
});
}
@ReactMethod
public void resumePreview(final int viewTag) {
final ReactApplicationContext context = getReactApplicationContext();
@ -238,7 +242,7 @@ public class CameraModule extends ReactContextBaseJavaModule {
@Override
public void execute(NativeViewHierarchyManager nativeViewHierarchyManager) {
final RNCameraView cameraView;
try {
cameraView = (RNCameraView) nativeViewHierarchyManager.resolveView(viewTag);
if (cameraView.isCameraOpened()) {
@ -261,14 +265,15 @@ public class CameraModule extends ReactContextBaseJavaModule {
public void execute(NativeViewHierarchyManager nativeViewHierarchyManager) {
RNCameraView cameraView = (RNCameraView) nativeViewHierarchyManager.resolveView(viewTag);
try {
if (cameraView.isCameraOpened()) {
cameraView.takePicture(options, promise, cacheDirectory);
} else {
promise.reject("E_CAMERA_UNAVAILABLE", "Camera is not running");
}
} catch (Exception e) {
promise.reject("E_CAMERA_BAD_VIEWTAG", "takePictureAsync: Expected a Camera component");
}
if (cameraView.isCameraOpened()) {
cameraView.takePicture(options, promise, cacheDirectory);
} else {
promise.reject("E_CAMERA_UNAVAILABLE", "Camera is not running");
}
}
catch (Exception e) {
promise.reject("E_TAKE_PICTURE_FAILED", e.getMessage());
}
}
});
}
@ -319,6 +324,48 @@ public class CameraModule extends ReactContextBaseJavaModule {
});
}
@ReactMethod
public void pauseRecording(final int viewTag) {
final ReactApplicationContext context = getReactApplicationContext();
UIManagerModule uiManager = context.getNativeModule(UIManagerModule.class);
uiManager.addUIBlock(new UIBlock() {
@Override
public void execute(NativeViewHierarchyManager nativeViewHierarchyManager) {
final RNCameraView cameraView;
try {
cameraView = (RNCameraView) nativeViewHierarchyManager.resolveView(viewTag);
if (cameraView.isCameraOpened()) {
cameraView.pauseRecording();
}
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
@ReactMethod
public void resumeRecording(final int viewTag) {
final ReactApplicationContext context = getReactApplicationContext();
UIManagerModule uiManager = context.getNativeModule(UIManagerModule.class);
uiManager.addUIBlock(new UIBlock() {
@Override
public void execute(NativeViewHierarchyManager nativeViewHierarchyManager) {
final RNCameraView cameraView;
try {
cameraView = (RNCameraView) nativeViewHierarchyManager.resolveView(viewTag);
if (cameraView.isCameraOpened()) {
cameraView.resumeRecording();
}
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
@ReactMethod
public void getSupportedRatios(final int viewTag, final Promise promise) {
final ReactApplicationContext context = getReactApplicationContext();
@ -345,49 +392,104 @@ public class CameraModule extends ReactContextBaseJavaModule {
}
});
}
@ReactMethod
public void getAvailablePictureSizes(final String ratio, final int viewTag, final Promise promise) {
final ReactApplicationContext context = getReactApplicationContext();
UIManagerModule uiManager = context.getNativeModule(UIManagerModule.class);
uiManager.addUIBlock(new UIBlock() {
@Override
public void execute(NativeViewHierarchyManager nativeViewHierarchyManager) {
final RNCameraView cameraView;
try {
cameraView = (RNCameraView) nativeViewHierarchyManager.resolveView(viewTag);
WritableArray result = Arguments.createArray();
if (cameraView.isCameraOpened()) {
SortedSet<Size> sizes = cameraView.getAvailablePictureSizes(AspectRatio.parse(ratio));
for (Size size : sizes) {
result.pushString(size.toString());
}
promise.resolve(result);
} else {
promise.reject("E_CAMERA_UNAVAILABLE", "Camera is not running");
}
} catch (Exception e) {
promise.reject("E_CAMERA_BAD_VIEWTAG", "getAvailablePictureSizesAsync: Expected a Camera component");
}
}
});
}
@ReactMethod
public void checkIfRecordAudioPermissionsAreDefined(final Promise promise) {
try {
PackageInfo info = getCurrentActivity().getPackageManager().getPackageInfo(getReactApplicationContext().getPackageName(), PackageManager.GET_PERMISSIONS);
if (info.requestedPermissions != null) {
for (String p : info.requestedPermissions) {
if (p.equals(Manifest.permission.RECORD_AUDIO)) {
promise.resolve(true);
return;
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
promise.resolve(false);
}
@ReactMethod
public void getCameraIds(final int viewTag, final Promise promise) {
final ReactApplicationContext context = getReactApplicationContext();
UIManagerModule uiManager = context.getNativeModule(UIManagerModule.class);
uiManager.addUIBlock(new UIBlock() {
@Override
public void execute(NativeViewHierarchyManager nativeViewHierarchyManager) {
final RNCameraView cameraView;
try {
cameraView = (RNCameraView) nativeViewHierarchyManager.resolveView(viewTag);
WritableArray result = Arguments.createArray();
List<Properties> ids = cameraView.getCameraIds();
for (Properties p : ids) {
WritableMap m = new WritableNativeMap();
m.putString("id", p.getProperty("id"));
m.putInt("type", Integer.valueOf(p.getProperty("type")));
result.pushMap(m);
}
promise.resolve(result);
} catch (Exception e) {
e.printStackTrace();
promise.reject("E_CAMERA_FAILED", e.getMessage());
}
}
});
}
@ReactMethod
public void getAvailablePictureSizes(final String ratio, final int viewTag, final Promise promise) {
final ReactApplicationContext context = getReactApplicationContext();
UIManagerModule uiManager = context.getNativeModule(UIManagerModule.class);
uiManager.addUIBlock(new UIBlock() {
@Override
public void execute(NativeViewHierarchyManager nativeViewHierarchyManager) {
final RNCameraView cameraView;
try {
cameraView = (RNCameraView) nativeViewHierarchyManager.resolveView(viewTag);
WritableArray result = Arguments.createArray();
if (cameraView.isCameraOpened()) {
SortedSet<Size> sizes = cameraView.getAvailablePictureSizes(AspectRatio.parse(ratio));
for (Size size : sizes) {
result.pushString(size.toString());
}
promise.resolve(result);
} else {
promise.reject("E_CAMERA_UNAVAILABLE", "Camera is not running");
}
} catch (Exception e) {
promise.reject("E_CAMERA_BAD_VIEWTAG", "getAvailablePictureSizesAsync: Expected a Camera component");
}
}
});
}
@ReactMethod
public void checkIfRecordAudioPermissionsAreDefined(final Promise promise) {
try {
PackageInfo info = getCurrentActivity().getPackageManager().getPackageInfo(getReactApplicationContext().getPackageName(), PackageManager.GET_PERMISSIONS);
if (info.requestedPermissions != null) {
for (String p : info.requestedPermissions) {
if (p.equals(Manifest.permission.RECORD_AUDIO)) {
promise.resolve(true);
return;
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
promise.resolve(false);
}
@ReactMethod
public void getSupportedPreviewFpsRange(final int viewTag, final Promise promise) {
final ReactApplicationContext context = getReactApplicationContext();
UIManagerModule uiManager = context.getNativeModule(UIManagerModule.class);
uiManager.addUIBlock(new UIBlock() {
@Override
public void execute(NativeViewHierarchyManager nativeViewHierarchyManager) {
final RNCameraView cameraView;
try {
cameraView = (RNCameraView) nativeViewHierarchyManager.resolveView(viewTag);
WritableArray result = Arguments.createArray();
ArrayList<int[]> ranges = cameraView.getSupportedPreviewFpsRange();
for (int[] range : ranges) {
WritableMap m = new WritableNativeMap();
m.putInt("MAXIMUM_FPS", range[0]);
m.putInt("MINIMUM_FPS", range[1]);
result.pushMap(m);
}
promise.resolve(result);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}

View File

@ -1,7 +1,8 @@
package org.reactnative.camera;
import android.support.annotation.Nullable;
import androidx.annotation.Nullable;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.common.MapBuilder;
import com.facebook.react.uimanager.ThemedReactContext;
import com.facebook.react.uimanager.ViewGroupManager;
@ -24,7 +25,11 @@ public class CameraViewManager extends ViewGroupManager<RNCameraView> {
EVENT_ON_BARCODE_DETECTION_ERROR("onGoogleVisionBarcodeDetectionError"),
EVENT_ON_TEXT_RECOGNIZED("onTextRecognized"),
EVENT_ON_PICTURE_TAKEN("onPictureTaken"),
EVENT_ON_PICTURE_SAVED("onPictureSaved");
EVENT_ON_PICTURE_SAVED("onPictureSaved"),
EVENT_ON_RECORDING_START("onRecordingStart"),
EVENT_ON_RECORDING_END("onRecordingEnd"),
EVENT_ON_TOUCH("onTouch");
private final String mName;
@ -42,7 +47,7 @@ public class CameraViewManager extends ViewGroupManager<RNCameraView> {
@Override
public void onDropViewInstance(RNCameraView view) {
view.stop();
view.onHostDestroy();
super.onDropViewInstance(view);
}
@ -72,6 +77,11 @@ public class CameraViewManager extends ViewGroupManager<RNCameraView> {
view.setFacing(type);
}
@ReactProp(name = "cameraId")
public void setCameraId(RNCameraView view, String id) {
view.setCameraId(id);
}
@ReactProp(name = "ratio")
public void setRatio(RNCameraView view, String ratio) {
view.setAspectRatio(AspectRatio.parse(ratio));
@ -82,6 +92,11 @@ public class CameraViewManager extends ViewGroupManager<RNCameraView> {
view.setFlash(torchMode);
}
@ReactProp(name = "exposure")
public void setExposureCompensation(RNCameraView view, float exposure){
view.setExposureCompensation(exposure);
}
@ReactProp(name = "autoFocus")
public void setAutoFocus(RNCameraView view, boolean autoFocus) {
view.setAutoFocus(autoFocus);
@ -92,11 +107,24 @@ public class CameraViewManager extends ViewGroupManager<RNCameraView> {
view.setFocusDepth(depth);
}
@ReactProp(name = "autoFocusPointOfInterest")
public void setAutoFocusPointOfInterest(RNCameraView view, ReadableMap coordinates) {
if(coordinates != null){
float x = (float) coordinates.getDouble("x");
float y = (float) coordinates.getDouble("y");
view.setAutoFocusPointOfInterest(x, y);
}
}
@ReactProp(name = "zoom")
public void setZoom(RNCameraView view, float zoom) {
view.setZoom(zoom);
}
@ReactProp(name = "useNativeZoom")
public void setUseNativeZoom(RNCameraView view, boolean useNativeZoom) {
view.setUseNativeZoom(useNativeZoom);
}
@ReactProp(name = "whiteBalance")
public void setWhiteBalance(RNCameraView view, int whiteBalance) {
view.setWhiteBalance(whiteBalance);
@ -107,6 +135,11 @@ public class CameraViewManager extends ViewGroupManager<RNCameraView> {
view.setPictureSize(size.equals("None") ? null : Size.parse(size));
}
@ReactProp(name = "playSoundOnCapture")
public void setPlaySoundOnCapture(RNCameraView view, boolean playSoundOnCapture) {
view.setPlaySoundOnCapture(playSoundOnCapture);
}
@ReactProp(name = "barCodeTypes")
public void setBarCodeTypes(RNCameraView view, ReadableArray barCodeTypes) {
if (barCodeTypes == null) {
@ -119,6 +152,11 @@ public class CameraViewManager extends ViewGroupManager<RNCameraView> {
view.setBarCodeTypes(result);
}
@ReactProp(name = "detectedImageInEvent")
public void setDetectedImageInEvent(RNCameraView view, boolean detectedImageInEvent) {
view.setDetectedImageInEvent(detectedImageInEvent);
}
@ReactProp(name = "barCodeScannerEnabled")
public void setBarCodeScanning(RNCameraView view, boolean barCodeScannerEnabled) {
view.setShouldScanBarCodes(barCodeScannerEnabled);
@ -129,9 +167,9 @@ public class CameraViewManager extends ViewGroupManager<RNCameraView> {
view.setUsingCamera2Api(useCamera2Api);
}
@ReactProp(name = "playSoundOnCapture")
public void setPlaySoundOnCapture(RNCameraView view, boolean playSoundOnCapture) {
view.setPlaySoundOnCapture(playSoundOnCapture);
@ReactProp(name = "touchDetectorEnabled")
public void setTouchDetectorEnabled(RNCameraView view, boolean touchDetectorEnabled) {
view.setShouldDetectTouches(touchDetectorEnabled);
}
@ReactProp(name = "faceDetectorEnabled")
@ -154,6 +192,11 @@ public class CameraViewManager extends ViewGroupManager<RNCameraView> {
view.setFaceDetectionClassifications(classifications);
}
@ReactProp(name = "trackingEnabled")
public void setTracking(RNCameraView view, boolean trackingEnabled) {
view.setTracking(trackingEnabled);
}
@ReactProp(name = "googleVisionBarcodeDetectorEnabled")
public void setGoogleVisionBarcodeDetecting(RNCameraView view, boolean googleBarcodeDetectorEnabled) {
view.setShouldGoogleDetectBarcodes(googleBarcodeDetectorEnabled);
@ -173,4 +216,26 @@ public class CameraViewManager extends ViewGroupManager<RNCameraView> {
public void setTextRecognizing(RNCameraView view, boolean textRecognizerEnabled) {
view.setShouldRecognizeText(textRecognizerEnabled);
}
/**---limit scan area addition---**/
@ReactProp(name = "rectOfInterest")
public void setRectOfInterest(RNCameraView view, ReadableMap coordinates) {
if(coordinates != null){
float x = (float) coordinates.getDouble("x");
float y = (float) coordinates.getDouble("y");
float width = (float) coordinates.getDouble("width");
float height = (float) coordinates.getDouble("height");
view.setRectOfInterest(x, y, width, height);
}
}
@ReactProp(name = "cameraViewDimensions")
public void setCameraViewDimensions(RNCameraView view, ReadableMap dimensions) {
if(dimensions != null){
int cameraViewWidth = (int) dimensions.getDouble("width");
int cameraViewHeight = (int) dimensions.getDouble("height");
view.setCameraViewDimensions(cameraViewWidth, cameraViewHeight);
}
}
/**---limit scan area addition---**/
}

View File

@ -3,31 +3,35 @@ package org.reactnative.camera;
import android.Manifest;
import android.annotation.SuppressLint;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.ImageFormat;
import android.graphics.Rect;
import android.graphics.YuvImage;
import android.media.CamcorderProfile;
import android.media.MediaActionSound;
import android.os.Build;
import android.support.v4.content.ContextCompat;
import android.util.SparseArray;
import androidx.core.content.ContextCompat;
import android.util.DisplayMetrics;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;
import android.os.AsyncTask;
import com.facebook.react.bridge.*;
import com.facebook.react.uimanager.ThemedReactContext;
import com.google.android.cameraview.CameraView;
import com.google.android.gms.vision.barcode.Barcode;
import com.google.android.gms.vision.face.Face;
import com.google.android.gms.vision.text.TextBlock;
import com.google.android.gms.vision.text.TextRecognizer;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.DecodeHintType;
import com.google.zxing.MultiFormatReader;
import com.google.zxing.Result;
import org.reactnative.barcodedetector.RNBarcodeDetector;
import org.reactnative.camera.tasks.*;
import org.reactnative.camera.utils.ImageDimensions;
import org.reactnative.camera.utils.RNFileUtils;
import org.reactnative.facedetector.RNFaceDetector;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.util.*;
@ -42,11 +46,18 @@ public class RNCameraView extends CameraView implements LifecycleEventListener,
private Map<Promise, File> mPictureTakenDirectories = new ConcurrentHashMap<>();
private Promise mVideoRecordedPromise;
private List<String> mBarCodeTypes = null;
private Boolean mPlaySoundOnCapture = false;
private boolean mDetectedImageInEvent = false;
private ScaleGestureDetector mScaleGestureDetector;
private GestureDetector mGestureDetector;
private boolean mIsPaused = false;
private boolean mIsNew = true;
private boolean invertImageData = false;
private Boolean mIsRecording = false;
private Boolean mIsRecordingInterrupted = false;
private boolean mUseNativeZoom=false;
// Concurrency lock for scanners to avoid flooding the runtime
public volatile boolean barCodeScannerTaskLock = false;
@ -58,16 +69,28 @@ public class RNCameraView extends CameraView implements LifecycleEventListener,
private MultiFormatReader mMultiFormatReader;
private RNFaceDetector mFaceDetector;
private RNBarcodeDetector mGoogleBarcodeDetector;
private TextRecognizer mTextRecognizer;
private boolean mShouldDetectFaces = false;
private boolean mShouldGoogleDetectBarcodes = false;
private boolean mShouldScanBarCodes = false;
private boolean mShouldRecognizeText = false;
private boolean mShouldDetectTouches = false;
private int mFaceDetectorMode = RNFaceDetector.FAST_MODE;
private int mFaceDetectionLandmarks = RNFaceDetector.NO_LANDMARKS;
private int mFaceDetectionClassifications = RNFaceDetector.NO_CLASSIFICATIONS;
private int mGoogleVisionBarCodeType = Barcode.ALL_FORMATS;
private int mGoogleVisionBarCodeType = RNBarcodeDetector.ALL_FORMATS;
private int mGoogleVisionBarCodeMode = RNBarcodeDetector.NORMAL_MODE;
private boolean mTrackingEnabled = true;
private int mPaddingX;
private int mPaddingY;
// Limit Android Scan Area
private boolean mLimitScanArea = false;
private float mScanAreaX = 0.0f;
private float mScanAreaY = 0.0f;
private float mScanAreaWidth = 0.0f;
private float mScanAreaHeight = 0.0f;
private int mCameraViewWidth = 0;
private int mCameraViewHeight = 0;
public RNCameraView(ThemedReactContext themedReactContext) {
super(themedReactContext, true);
@ -103,11 +126,26 @@ public class RNCameraView extends CameraView implements LifecycleEventListener,
RNCameraViewHelper.emitPictureTakenEvent(cameraView);
}
@Override
public void onRecordingStart(CameraView cameraView, String path, int videoOrientation, int deviceOrientation) {
WritableMap result = Arguments.createMap();
result.putInt("videoOrientation", videoOrientation);
result.putInt("deviceOrientation", deviceOrientation);
result.putString("uri", RNFileUtils.uriFromFile(new File(path)).toString());
RNCameraViewHelper.emitRecordingStartEvent(cameraView, result);
}
@Override
public void onRecordingEnd(CameraView cameraView) {
RNCameraViewHelper.emitRecordingEndEvent(cameraView);
}
@Override
public void onVideoRecorded(CameraView cameraView, String path, int videoOrientation, int deviceOrientation) {
if (mVideoRecordedPromise != null) {
if (path != null) {
WritableMap result = Arguments.createMap();
result.putBoolean("isRecordingInterrupted", mIsRecordingInterrupted);
result.putInt("videoOrientation", videoOrientation);
result.putInt("deviceOrientation", deviceOrientation);
result.putString("uri", RNFileUtils.uriFromFile(new File(path)).toString());
@ -115,6 +153,8 @@ public class RNCameraView extends CameraView implements LifecycleEventListener,
} else {
mVideoRecordedPromise.reject("E_RECORDING", "Couldn't stop recording - there is none in progress");
}
mIsRecording = false;
mIsRecordingInterrupted = false;
mVideoRecordedPromise = null;
}
}
@ -137,13 +177,13 @@ public class RNCameraView extends CameraView implements LifecycleEventListener,
if (willCallBarCodeTask) {
barCodeScannerTaskLock = true;
BarCodeScannerAsyncTaskDelegate delegate = (BarCodeScannerAsyncTaskDelegate) cameraView;
new BarCodeScannerAsyncTask(delegate, mMultiFormatReader, data, width, height).execute();
new BarCodeScannerAsyncTask(delegate, mMultiFormatReader, data, width, height, mLimitScanArea, mScanAreaX, mScanAreaY, mScanAreaWidth, mScanAreaHeight, mCameraViewWidth, mCameraViewHeight, getAspectRatio().toFloat()).execute();
}
if (willCallFaceTask) {
faceDetectorTaskLock = true;
FaceDetectorAsyncTaskDelegate delegate = (FaceDetectorAsyncTaskDelegate) cameraView;
new FaceDetectorAsyncTask(delegate, mFaceDetector, data, width, height, correctRotation).execute();
new FaceDetectorAsyncTask(delegate, mFaceDetector, data, width, height, correctRotation, getResources().getDisplayMetrics().density, getFacing(), getWidth(), getHeight(), mPaddingX, mPaddingY).execute();
}
if (willCallGoogleBarcodeTask) {
@ -161,13 +201,15 @@ public class RNCameraView extends CameraView implements LifecycleEventListener,
}
}
BarcodeDetectorAsyncTaskDelegate delegate = (BarcodeDetectorAsyncTaskDelegate) cameraView;
new BarcodeDetectorAsyncTask(delegate, mGoogleBarcodeDetector, data, width, height, correctRotation).execute();
new BarcodeDetectorAsyncTask(delegate, mGoogleBarcodeDetector, data, width, height,
correctRotation, getResources().getDisplayMetrics().density, getFacing(),
getWidth(), getHeight(), mPaddingX, mPaddingY).execute();
}
if (willCallTextTask) {
textRecognizerTaskLock = true;
TextRecognizerAsyncTaskDelegate delegate = (TextRecognizerAsyncTaskDelegate) cameraView;
new TextRecognizerAsyncTask(delegate, mTextRecognizer, data, width, height, correctRotation).execute();
new TextRecognizerAsyncTask(delegate, mThemedReactContext, data, width, height, correctRotation, getResources().getDisplayMetrics().density, getFacing(), getWidth(), getHeight(), mPaddingX, mPaddingY).execute();
}
}
});
@ -205,6 +247,8 @@ public class RNCameraView extends CameraView implements LifecycleEventListener,
}
int paddingX = (int) ((width - correctWidth) / 2);
int paddingY = (int) ((height - correctHeight) / 2);
mPaddingX = paddingX;
mPaddingY = paddingY;
preview.layout(paddingX, paddingY, correctWidth + paddingX, correctHeight + paddingY);
}
@ -219,26 +263,29 @@ public class RNCameraView extends CameraView implements LifecycleEventListener,
initBarcodeReader();
}
public void setPlaySoundOnCapture(Boolean playSoundOnCapture) {
mPlaySoundOnCapture = playSoundOnCapture;
public void setDetectedImageInEvent(boolean detectedImageInEvent) {
this.mDetectedImageInEvent = detectedImageInEvent;
}
public void takePicture(ReadableMap options, final Promise promise, File cacheDirectory) {
mPictureTakenPromises.add(promise);
mPictureTakenOptions.put(promise, options);
mPictureTakenDirectories.put(promise, cacheDirectory);
if (mPlaySoundOnCapture) {
MediaActionSound sound = new MediaActionSound();
sound.play(MediaActionSound.SHUTTER_CLICK);
}
try {
super.takePicture(options);
} catch (Exception e) {
mPictureTakenPromises.remove(promise);
mPictureTakenOptions.remove(promise);
mPictureTakenDirectories.remove(promise);
throw e;
}
public void takePicture(final ReadableMap options, final Promise promise, final File cacheDirectory) {
mBgHandler.post(new Runnable() {
@Override
public void run() {
mPictureTakenPromises.add(promise);
mPictureTakenOptions.put(promise, options);
mPictureTakenDirectories.put(promise, cacheDirectory);
try {
RNCameraView.super.takePicture(options);
} catch (Exception e) {
mPictureTakenPromises.remove(promise);
mPictureTakenOptions.remove(promise);
mPictureTakenDirectories.remove(promise);
promise.reject("E_TAKE_PICTURE_FAILED", e.getMessage());
}
}
});
}
@Override
@ -246,38 +293,45 @@ public class RNCameraView extends CameraView implements LifecycleEventListener,
RNCameraViewHelper.emitPictureSavedEvent(this, response);
}
public void record(ReadableMap options, final Promise promise, File cacheDirectory) {
try {
String path = options.hasKey("path") ? options.getString("path") : RNFileUtils.getOutputFilePath(cacheDirectory, ".mp4");
int maxDuration = options.hasKey("maxDuration") ? options.getInt("maxDuration") : -1;
int maxFileSize = options.hasKey("maxFileSize") ? options.getInt("maxFileSize") : -1;
public void record(final ReadableMap options, final Promise promise, final File cacheDirectory) {
mBgHandler.post(new Runnable() {
@Override
public void run() {
try {
String path = options.hasKey("path") ? options.getString("path") : RNFileUtils.getOutputFilePath(cacheDirectory, ".mp4");
int maxDuration = options.hasKey("maxDuration") ? options.getInt("maxDuration") : -1;
int maxFileSize = options.hasKey("maxFileSize") ? options.getInt("maxFileSize") : -1;
int fps = options.hasKey("fps") ? options.getInt("fps") : -1;
CamcorderProfile profile = CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH);
if (options.hasKey("quality")) {
profile = RNCameraViewHelper.getCamcorderProfile(options.getInt("quality"));
}
if (options.hasKey("videoBitrate")) {
profile.videoBitRate = options.getInt("videoBitrate");
}
CamcorderProfile profile = CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH);
if (options.hasKey("quality")) {
profile = RNCameraViewHelper.getCamcorderProfile(options.getInt("quality"));
}
if (options.hasKey("videoBitrate")) {
profile.videoBitRate = options.getInt("videoBitrate");
}
boolean recordAudio = true;
if (options.hasKey("mute")) {
recordAudio = !options.getBoolean("mute");
}
boolean recordAudio = true;
if (options.hasKey("mute")) {
recordAudio = !options.getBoolean("mute");
}
int orientation = Constants.ORIENTATION_AUTO;
if (options.hasKey("orientation")) {
orientation = options.getInt("orientation");
}
int orientation = Constants.ORIENTATION_AUTO;
if (options.hasKey("orientation")) {
orientation = options.getInt("orientation");
}
if (super.record(path, maxDuration * 1000, maxFileSize, recordAudio, profile, orientation)) {
mVideoRecordedPromise = promise;
} else {
promise.reject("E_RECORDING_FAILED", "Starting video recording failed. Another recording might be in progress.");
if (RNCameraView.super.record(path, maxDuration * 1000, maxFileSize, recordAudio, profile, orientation, fps)) {
mIsRecording = true;
mVideoRecordedPromise = promise;
} else {
promise.reject("E_RECORDING_FAILED", "Starting video recording failed. Another recording might be in progress.");
}
} catch (IOException e) {
promise.reject("E_RECORDING_FAILED", "Starting video recording failed - could not create video file.");
}
}
} catch (IOException e) {
promise.reject("E_RECORDING_FAILED", "Starting video recording failed - could not create video file.");
}
});
}
/**
@ -294,7 +348,7 @@ public class RNCameraView extends CameraView implements LifecycleEventListener,
for (String code : mBarCodeTypes) {
String formatString = (String) CameraModule.VALID_BARCODE_TYPES.get(code);
if (formatString != null) {
decodeFormats.add(BarcodeFormat.valueOf(code));
decodeFormats.add(BarcodeFormat.valueOf(formatString));
}
}
}
@ -311,13 +365,28 @@ public class RNCameraView extends CameraView implements LifecycleEventListener,
setScanning(mShouldDetectFaces || mShouldGoogleDetectBarcodes || mShouldScanBarCodes || mShouldRecognizeText);
}
public void onBarCodeRead(Result barCode, int width, int height) {
public void onBarCodeRead(Result barCode, int width, int height, byte[] imageData) {
String barCodeType = barCode.getBarcodeFormat().toString();
if (!mShouldScanBarCodes || !mBarCodeTypes.contains(barCodeType)) {
return;
}
RNCameraViewHelper.emitBarCodeReadEvent(this, barCode, width, height);
final byte[] compressedImage;
if (mDetectedImageInEvent) {
try {
// https://stackoverflow.com/a/32793908/122441
final YuvImage yuvImage = new YuvImage(imageData, ImageFormat.NV21, width, height, null);
final ByteArrayOutputStream imageStream = new ByteArrayOutputStream();
yuvImage.compressToJpeg(new Rect(0, 0, width, height), 100, imageStream);
compressedImage = imageStream.toByteArray();
} catch (Exception e) {
throw new RuntimeException(String.format("Error decoding imageData from NV21 format (%d bytes)", imageData.length), e);
}
} else {
compressedImage = null;
}
RNCameraViewHelper.emitBarCodeReadEvent(this, barCode, width, height, compressedImage);
}
public void onBarCodeScanningTaskCompleted() {
@ -327,6 +396,49 @@ public class RNCameraView extends CameraView implements LifecycleEventListener,
}
}
// Limit Scan Area
public void setRectOfInterest(float x, float y, float width, float height) {
this.mLimitScanArea = true;
this.mScanAreaX = x;
this.mScanAreaY = y;
this.mScanAreaWidth = width;
this.mScanAreaHeight = height;
}
public void setCameraViewDimensions(int width, int height) {
this.mCameraViewWidth = width;
this.mCameraViewHeight = height;
}
public void setShouldDetectTouches(boolean shouldDetectTouches) {
if(!mShouldDetectTouches && shouldDetectTouches){
mGestureDetector=new GestureDetector(mThemedReactContext,onGestureListener);
}else{
mGestureDetector=null;
}
this.mShouldDetectTouches = shouldDetectTouches;
}
public void setUseNativeZoom(boolean useNativeZoom){
if(!mUseNativeZoom && useNativeZoom){
mScaleGestureDetector = new ScaleGestureDetector(mThemedReactContext,onScaleGestureListener);
}else{
mScaleGestureDetector=null;
}
mUseNativeZoom=useNativeZoom;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if(mUseNativeZoom) {
mScaleGestureDetector.onTouchEvent(event);
}
if(mShouldDetectTouches){
mGestureDetector.onTouchEvent(event);
}
return true;
}
/**
* Initial setup of the face detector
*/
@ -335,7 +447,7 @@ public class RNCameraView extends CameraView implements LifecycleEventListener,
mFaceDetector.setMode(mFaceDetectorMode);
mFaceDetector.setLandmarkType(mFaceDetectionLandmarks);
mFaceDetector.setClassificationType(mFaceDetectionClassifications);
mFaceDetector.setTracking(true);
mFaceDetector.setTracking(mTrackingEnabled);
}
public void setFaceDetectionLandmarks(int landmarks) {
@ -359,6 +471,13 @@ public class RNCameraView extends CameraView implements LifecycleEventListener,
}
}
public void setTracking(boolean trackingEnabled) {
mTrackingEnabled = trackingEnabled;
if (mFaceDetector != null) {
mFaceDetector.setTracking(trackingEnabled);
}
}
public void setShouldDetectFaces(boolean shouldDetectFaces) {
if (shouldDetectFaces && mFaceDetector == null) {
setupFaceDetector();
@ -367,23 +486,12 @@ public class RNCameraView extends CameraView implements LifecycleEventListener,
setScanning(mShouldDetectFaces || mShouldGoogleDetectBarcodes || mShouldScanBarCodes || mShouldRecognizeText);
}
public void setShouldGoogleDetectBarcodes(boolean shouldDetectBarcodes) {
if (shouldDetectBarcodes && mGoogleBarcodeDetector == null) {
setupBarcodeDetector();
}
this.mShouldGoogleDetectBarcodes = shouldDetectBarcodes;
setScanning(mShouldDetectFaces || mShouldGoogleDetectBarcodes || mShouldScanBarCodes || mShouldRecognizeText);
}
public void onFacesDetected(SparseArray<Face> facesReported, int sourceWidth, int sourceHeight, int sourceRotation) {
public void onFacesDetected(WritableArray data) {
if (!mShouldDetectFaces) {
return;
}
SparseArray<Face> facesDetected = facesReported == null ? new SparseArray<Face>() : facesReported;
ImageDimensions dimensions = new ImageDimensions(sourceWidth, sourceHeight, sourceRotation, getFacing());
RNCameraViewHelper.emitFacesDetectedEvent(this, facesDetected, dimensions);
RNCameraViewHelper.emitFacesDetectedEvent(this, data);
}
public void onFaceDetectionError(RNFaceDetector faceDetector) {
@ -407,11 +515,12 @@ public class RNCameraView extends CameraView implements LifecycleEventListener,
mGoogleBarcodeDetector.setBarcodeType(mGoogleVisionBarCodeType);
}
/**
* Initial setup of the text recongizer
*/
private void setupTextRecongnizer() {
mTextRecognizer = new TextRecognizer.Builder(mThemedReactContext).build();
public void setShouldGoogleDetectBarcodes(boolean shouldDetectBarcodes) {
if (shouldDetectBarcodes && mGoogleBarcodeDetector == null) {
setupBarcodeDetector();
}
this.mShouldGoogleDetectBarcodes = shouldDetectBarcodes;
setScanning(mShouldDetectFaces || mShouldGoogleDetectBarcodes || mShouldScanBarCodes || mShouldRecognizeText);
}
public void setGoogleVisionBarcodeType(int barcodeType) {
@ -425,14 +534,28 @@ public class RNCameraView extends CameraView implements LifecycleEventListener,
mGoogleVisionBarCodeMode = barcodeMode;
}
public void onBarcodesDetected(SparseArray<Barcode> barcodesReported, int sourceWidth, int sourceHeight, int sourceRotation) {
public void onBarcodesDetected(WritableArray barcodesDetected, int width, int height, byte[] imageData) {
if (!mShouldGoogleDetectBarcodes) {
return;
}
SparseArray<Barcode> barcodesDetected = barcodesReported == null ? new SparseArray<Barcode>() : barcodesReported;
// See discussion in https://github.com/react-native-community/react-native-camera/issues/2786
final byte[] compressedImage;
if (mDetectedImageInEvent) {
try {
// https://stackoverflow.com/a/32793908/122441
final YuvImage yuvImage = new YuvImage(imageData, ImageFormat.NV21, width, height, null);
final ByteArrayOutputStream imageStream = new ByteArrayOutputStream();
yuvImage.compressToJpeg(new Rect(0, 0, width, height), 100, imageStream);
compressedImage = imageStream.toByteArray();
} catch (Exception e) {
throw new RuntimeException(String.format("Error decoding imageData from NV21 format (%d bytes)", imageData.length), e);
}
} else {
compressedImage = null;
}
RNCameraViewHelper.emitBarcodesDetectedEvent(this, barcodesDetected);
RNCameraViewHelper.emitBarcodesDetectedEvent(this, barcodesDetected, compressedImage);
}
public void onBarcodeDetectionError(RNBarcodeDetector barcodeDetector) {
@ -448,24 +571,22 @@ public class RNCameraView extends CameraView implements LifecycleEventListener,
googleBarcodeDetectorTaskLock = false;
}
/**
*
* Text recognition
*/
public void setShouldRecognizeText(boolean shouldRecognizeText) {
if (shouldRecognizeText && mTextRecognizer == null) {
setupTextRecongnizer();
}
this.mShouldRecognizeText = shouldRecognizeText;
setScanning(mShouldDetectFaces || mShouldGoogleDetectBarcodes || mShouldScanBarCodes || mShouldRecognizeText);
}
@Override
public void onTextRecognized(SparseArray<TextBlock> textBlocks, int sourceWidth, int sourceHeight, int sourceRotation) {
public void onTextRecognized(WritableArray serializedData) {
if (!mShouldRecognizeText) {
return;
}
SparseArray<TextBlock> textBlocksDetected = textBlocks == null ? new SparseArray<TextBlock>() : textBlocks;
ImageDimensions dimensions = new ImageDimensions(sourceWidth, sourceHeight, sourceRotation, getFacing());
RNCameraViewHelper.emitTextRecognizedEvent(this, textBlocksDetected, dimensions);
RNCameraViewHelper.emitTextRecognizedEvent(this, serializedData);
}
@Override
@ -473,14 +594,23 @@ public class RNCameraView extends CameraView implements LifecycleEventListener,
textRecognizerTaskLock = false;
}
/**
*
* End Text Recognition */
@Override
public void onHostResume() {
if (hasCameraPermissions()) {
if ((mIsPaused && !isCameraOpened()) || mIsNew) {
mIsPaused = false;
mIsNew = false;
start();
}
mBgHandler.post(new Runnable() {
@Override
public void run() {
if ((mIsPaused && !isCameraOpened()) || mIsNew) {
mIsPaused = false;
mIsNew = false;
start();
}
}
});
} else {
RNCameraViewHelper.emitMountErrorEvent(this, "Camera permissions not granted - component could not be rendered.");
}
@ -488,6 +618,9 @@ public class RNCameraView extends CameraView implements LifecycleEventListener,
@Override
public void onHostPause() {
if (mIsRecording) {
mIsRecordingInterrupted = true;
}
if (!mIsPaused && isCameraOpened()) {
mIsPaused = true;
stop();
@ -502,12 +635,29 @@ public class RNCameraView extends CameraView implements LifecycleEventListener,
if (mGoogleBarcodeDetector != null) {
mGoogleBarcodeDetector.release();
}
if (mTextRecognizer != null) {
mTextRecognizer.release();
}
mMultiFormatReader = null;
stop();
mThemedReactContext.removeLifecycleEventListener(this);
// camera release can be quite expensive. Run in on bg handler
// and cleanup last once everything has finished
mBgHandler.post(new Runnable() {
@Override
public void run() {
stop();
cleanup();
}
});
}
private void onZoom(float scale){
float currentZoom=getZoom();
float nextZoom=currentZoom+(scale-1.0f);
if(nextZoom > currentZoom){
setZoom(Math.min(nextZoom,1.0f));
}else{
setZoom(Math.max(nextZoom,0.0f));
}
}
private boolean hasCameraPermissions() {
@ -518,4 +668,43 @@ public class RNCameraView extends CameraView implements LifecycleEventListener,
return true;
}
}
private int scalePosition(float raw){
Resources resources = getResources();
Configuration config = resources.getConfiguration();
DisplayMetrics dm = resources.getDisplayMetrics();
return (int)(raw/ dm.density);
}
private GestureDetector.SimpleOnGestureListener onGestureListener = new GestureDetector.SimpleOnGestureListener(){
@Override
public boolean onSingleTapUp(MotionEvent e) {
RNCameraViewHelper.emitTouchEvent(RNCameraView.this,false,scalePosition(e.getX()),scalePosition(e.getY()));
return true;
}
@Override
public boolean onDoubleTap(MotionEvent e) {
RNCameraViewHelper.emitTouchEvent(RNCameraView.this,true,scalePosition(e.getX()),scalePosition(e.getY()));
return true;
}
};
private ScaleGestureDetector.OnScaleGestureListener onScaleGestureListener = new ScaleGestureDetector.OnScaleGestureListener() {
@Override
public boolean onScale(ScaleGestureDetector scaleGestureDetector) {
onZoom(scaleGestureDetector.getScaleFactor());
return true;
}
@Override
public boolean onScaleBegin(ScaleGestureDetector scaleGestureDetector) {
onZoom(scaleGestureDetector.getScaleFactor());
return true;
}
@Override
public void onScaleEnd(ScaleGestureDetector scaleGestureDetector) {
}
};
}

View File

@ -6,20 +6,17 @@ import android.graphics.Color;
import android.graphics.Paint;
import android.media.CamcorderProfile;
import android.os.Build;
import android.support.media.ExifInterface;
import android.util.SparseArray;
import androidx.exifinterface.media.ExifInterface;
import android.view.ViewGroup;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.bridge.WritableArray;
import com.facebook.react.uimanager.UIManagerModule;
import com.google.android.cameraview.CameraView;
import com.google.android.gms.vision.barcode.Barcode;
import com.google.android.gms.vision.face.Face;
import com.google.android.gms.vision.text.TextBlock;
import com.google.zxing.Result;
import org.reactnative.camera.events.*;
import org.reactnative.camera.utils.ImageDimensions;
import org.reactnative.barcodedetector.RNBarcodeDetector;
import org.reactnative.facedetector.RNFaceDetector;
@ -159,131 +156,196 @@ public class RNCameraViewHelper {
{"int", ExifInterface.TAG_RW2_SENSOR_TOP_BORDER},
{"int", ExifInterface.TAG_RW2_ISO},
};
// Run all events on native modules queue thread since they might be fired
// from other non RN threads.
// Mount error event
public static void emitMountErrorEvent(ViewGroup view, String error) {
CameraMountErrorEvent event = CameraMountErrorEvent.obtain(view.getId(), error);
ReactContext reactContext = (ReactContext) view.getContext();
reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher().dispatchEvent(event);
public static void emitMountErrorEvent(final ViewGroup view, final String error) {
final ReactContext reactContext = (ReactContext) view.getContext();
reactContext.runOnNativeModulesQueueThread(new Runnable() {
@Override
public void run() {
CameraMountErrorEvent event = CameraMountErrorEvent.obtain(view.getId(), error);
reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher().dispatchEvent(event);
}
});
}
// Camera ready event
public static void emitCameraReadyEvent(ViewGroup view) {
CameraReadyEvent event = CameraReadyEvent.obtain(view.getId());
ReactContext reactContext = (ReactContext) view.getContext();
reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher().dispatchEvent(event);
public static void emitCameraReadyEvent(final ViewGroup view) {
final ReactContext reactContext = (ReactContext) view.getContext();
reactContext.runOnNativeModulesQueueThread(new Runnable() {
@Override
public void run() {
CameraReadyEvent event = CameraReadyEvent.obtain(view.getId());
reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher().dispatchEvent(event);
}
});
}
// Picture saved event
public static void emitPictureSavedEvent(ViewGroup view, WritableMap response) {
PictureSavedEvent event = PictureSavedEvent.obtain(view.getId(), response);
ReactContext reactContext = (ReactContext) view.getContext();
reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher().dispatchEvent(event);
public static void emitPictureSavedEvent(final ViewGroup view, final WritableMap response) {
final ReactContext reactContext = (ReactContext) view.getContext();
reactContext.runOnNativeModulesQueueThread(new Runnable() {
@Override
public void run() {
PictureSavedEvent event = PictureSavedEvent.obtain(view.getId(), response);
reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher().dispatchEvent(event);
}
});
}
// Picture taken event
public static void emitPictureTakenEvent(ViewGroup view) {
PictureTakenEvent event = PictureTakenEvent.obtain(view.getId());
ReactContext reactContext = (ReactContext) view.getContext();
reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher().dispatchEvent(event);
public static void emitPictureTakenEvent(final ViewGroup view) {
final ReactContext reactContext = (ReactContext) view.getContext();
reactContext.runOnNativeModulesQueueThread(new Runnable() {
@Override
public void run() {
PictureTakenEvent event = PictureTakenEvent.obtain(view.getId());
reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher().dispatchEvent(event);
}
});
}
// video recording start/end events
public static void emitRecordingStartEvent(final ViewGroup view, final WritableMap response) {
final ReactContext reactContext = (ReactContext) view.getContext();
reactContext.runOnNativeModulesQueueThread(new Runnable() {
@Override
public void run() {
RecordingStartEvent event = RecordingStartEvent.obtain(view.getId(), response);
reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher().dispatchEvent(event);
}
});
}
public static void emitRecordingEndEvent(final ViewGroup view) {
final ReactContext reactContext = (ReactContext) view.getContext();
reactContext.runOnNativeModulesQueueThread(new Runnable() {
@Override
public void run() {
RecordingEndEvent event = RecordingEndEvent.obtain(view.getId());
reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher().dispatchEvent(event);
}
});
}
// Touch event
public static void emitTouchEvent(final ViewGroup view, final boolean isDoubleTap, final int x, final int y) {
final ReactContext reactContext = (ReactContext) view.getContext();
reactContext.runOnNativeModulesQueueThread(new Runnable() {
@Override
public void run() {
TouchEvent event = TouchEvent.obtain(view.getId(), isDoubleTap, x, y);
reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher().dispatchEvent(event);
}
});
}
// Face detection events
public static void emitFacesDetectedEvent(
ViewGroup view,
SparseArray<Face> faces,
ImageDimensions dimensions
) {
float density = view.getResources().getDisplayMetrics().density;
public static void emitFacesDetectedEvent(final ViewGroup view, final WritableArray data) {
double scaleX = (double) view.getWidth() / (dimensions.getWidth() * density);
double scaleY = (double) view.getHeight() / (dimensions.getHeight() * density);
FacesDetectedEvent event = FacesDetectedEvent.obtain(
view.getId(),
faces,
dimensions,
scaleX,
scaleY
);
ReactContext reactContext = (ReactContext) view.getContext();
reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher().dispatchEvent(event);
final ReactContext reactContext = (ReactContext) view.getContext();
reactContext.runOnNativeModulesQueueThread(new Runnable() {
@Override
public void run() {
FacesDetectedEvent event = FacesDetectedEvent.obtain(view.getId(), data);
reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher().dispatchEvent(event);
}
});
}
public static void emitFaceDetectionErrorEvent(ViewGroup view, RNFaceDetector faceDetector) {
FaceDetectionErrorEvent event = FaceDetectionErrorEvent.obtain(view.getId(), faceDetector);
ReactContext reactContext = (ReactContext) view.getContext();
reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher().dispatchEvent(event);
public static void emitFaceDetectionErrorEvent(final ViewGroup view, final RNFaceDetector faceDetector) {
final ReactContext reactContext = (ReactContext) view.getContext();
reactContext.runOnNativeModulesQueueThread(new Runnable() {
@Override
public void run() {
FaceDetectionErrorEvent event = FaceDetectionErrorEvent.obtain(view.getId(), faceDetector);
reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher().dispatchEvent(event);
}
});
}
// Barcode detection events
public static void emitBarcodesDetectedEvent(
ViewGroup view,
SparseArray<Barcode> barcodes
) {
BarcodesDetectedEvent event = BarcodesDetectedEvent.obtain(
view.getId(),
barcodes
);
public static void emitBarcodesDetectedEvent(final ViewGroup view, final WritableArray barcodes, final byte[] compressedImage) {
ReactContext reactContext = (ReactContext) view.getContext();
reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher().dispatchEvent(event);
final ReactContext reactContext = (ReactContext) view.getContext();
reactContext.runOnNativeModulesQueueThread(new Runnable() {
@Override
public void run() {
BarcodesDetectedEvent event = BarcodesDetectedEvent.obtain(view.getId(), barcodes, compressedImage);
reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher().dispatchEvent(event);
}
});
}
public static void emitBarcodeDetectionErrorEvent(ViewGroup view, RNBarcodeDetector barcodeDetector) {
BarcodeDetectionErrorEvent event = BarcodeDetectionErrorEvent.obtain(view.getId(), barcodeDetector);
ReactContext reactContext = (ReactContext) view.getContext();
reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher().dispatchEvent(event);
public static void emitBarcodeDetectionErrorEvent(final ViewGroup view, final RNBarcodeDetector barcodeDetector) {
final ReactContext reactContext = (ReactContext) view.getContext();
reactContext.runOnNativeModulesQueueThread(new Runnable() {
@Override
public void run() {
BarcodeDetectionErrorEvent event = BarcodeDetectionErrorEvent.obtain(view.getId(), barcodeDetector);
reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher().dispatchEvent(event);
}
});
}
// Bar code read event
public static void emitBarCodeReadEvent(ViewGroup view, Result barCode, int width, int height) {
BarCodeReadEvent event = BarCodeReadEvent.obtain(view.getId(), barCode, width, height);
ReactContext reactContext = (ReactContext) view.getContext();
reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher().dispatchEvent(event);
public static void emitBarCodeReadEvent(final ViewGroup view, final Result barCode, final int width, final int height, final byte[] compressedImage) {
final ReactContext reactContext = (ReactContext) view.getContext();
reactContext.runOnNativeModulesQueueThread(new Runnable() {
@Override
public void run() {
BarCodeReadEvent event = BarCodeReadEvent.obtain(view.getId(), barCode, width, height, compressedImage);
reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher().dispatchEvent(event);
}
});
}
// Text recognition event
public static void emitTextRecognizedEvent(
ViewGroup view,
SparseArray<TextBlock> textBlocks,
ImageDimensions dimensions) {
float density = view.getResources().getDisplayMetrics().density;
double scaleX = (double) view.getWidth() / (dimensions.getWidth() * density);
double scaleY = (double) view.getHeight() / (dimensions.getHeight() * density);
TextRecognizedEvent event = TextRecognizedEvent.obtain(
view.getId(),
textBlocks,
dimensions,
scaleX,
scaleY
);
ReactContext reactContext = (ReactContext) view.getContext();
reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher().dispatchEvent(event);
public static void emitTextRecognizedEvent(final ViewGroup view, final WritableArray data) {
final ReactContext reactContext = (ReactContext) view.getContext();
reactContext.runOnNativeModulesQueueThread(new Runnable() {
@Override
public void run() {
TextRecognizedEvent event = TextRecognizedEvent.obtain(view.getId(), data);
reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher().dispatchEvent(event);
}
});
}
// Utilities
public static int getCorrectCameraRotation(int rotation, int facing, int cameraOrientation) {
if (facing == CameraView.FACING_FRONT) {
return (360 - (cameraOrientation + rotation) % 360) % 360;
// Tested the below line and there's no need to do the mirror calculation
return (cameraOrientation + rotation) % 360;
} else {
final int landscapeFlip = rotationIsLandscape(rotation) ? 180 : 0;
return (cameraOrientation - rotation + landscapeFlip) % 360;
}
}
private static boolean rotationIsLandscape(int rotation) {
return (rotation == Constants.LANDSCAPE_90 ||
rotation == Constants.LANDSCAPE_270);
@ -306,7 +368,7 @@ public class RNCameraViewHelper {
}
return CamcorderProfile.QUALITY_HIGH;
}
public static CamcorderProfile getCamcorderProfile(int quality) {
CamcorderProfile profile = CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH);
int camcorderQuality = getCamcorderProfileQualityFromCameraModuleConstant(quality);
@ -349,6 +411,48 @@ public class RNCameraViewHelper {
return exifMap;
}
public static void setExifData(ExifInterface exifInterface, ReadableMap exifMap) {
for (String[] tagInfo : exifTags) {
String name = tagInfo[1];
if (exifMap.hasKey(name)) {
String type = tagInfo[0];
switch (type) {
case "string":
exifInterface.setAttribute(name, exifMap.getString(name));
break;
case "int":
exifInterface.setAttribute(name, Integer.toString(exifMap.getInt(name)));
exifMap.getInt(name);
break;
case "double":
exifInterface.setAttribute(name, Double.toString(exifMap.getDouble(name)));
exifMap.getDouble(name);
break;
}
}
}
if (exifMap.hasKey(ExifInterface.TAG_GPS_LATITUDE) && exifMap.hasKey(ExifInterface.TAG_GPS_LONGITUDE)) {
exifInterface.setLatLong(exifMap.getDouble(ExifInterface.TAG_GPS_LATITUDE),
exifMap.getDouble(ExifInterface.TAG_GPS_LONGITUDE));
}
if(exifMap.hasKey(ExifInterface.TAG_GPS_ALTITUDE)){
exifInterface.setAltitude(exifMap.getDouble(ExifInterface.TAG_GPS_ALTITUDE));
}
}
// clears exif values in place
public static void clearExifData(ExifInterface exifInterface) {
for (String[] tagInfo : exifTags) {
exifInterface.setAttribute(tagInfo[1], null);
}
// these are not part of our tag list, remove by hand
exifInterface.setAttribute(ExifInterface.TAG_GPS_LATITUDE, null);
exifInterface.setAttribute(ExifInterface.TAG_GPS_LONGITUDE, null);
exifInterface.setAttribute(ExifInterface.TAG_GPS_ALTITUDE, null);
}
public static Bitmap generateSimulatorPhoto(int width, int height) {
Bitmap fakePhoto = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(fakePhoto);

View File

@ -1,6 +1,8 @@
package org.reactnative.camera.events;
import android.support.v4.util.Pools;
import android.util.Base64;
import androidx.core.util.Pools;
import org.reactnative.camera.CameraViewManager;
import com.facebook.react.bridge.Arguments;
@ -11,7 +13,6 @@ import com.facebook.react.uimanager.events.RCTEventEmitter;
import com.google.zxing.Result;
import com.google.zxing.ResultPoint;
import java.util.Date;
import java.util.Formatter;
public class BarCodeReadEvent extends Event<BarCodeReadEvent> {
@ -21,23 +22,25 @@ public class BarCodeReadEvent extends Event<BarCodeReadEvent> {
private Result mBarCode;
private int mWidth;
private int mHeight;
private byte[] mCompressedImage;
private BarCodeReadEvent() {}
public static BarCodeReadEvent obtain(int viewTag, Result barCode, int width, int height) {
public static BarCodeReadEvent obtain(int viewTag, Result barCode, int width, int height, byte[] compressedImage) {
BarCodeReadEvent event = EVENTS_POOL.acquire();
if (event == null) {
event = new BarCodeReadEvent();
}
event.init(viewTag, barCode, width, height);
event.init(viewTag, barCode, width, height, compressedImage);
return event;
}
private void init(int viewTag, Result barCode, int width, int height) {
private void init(int viewTag, Result barCode, int width, int height, byte[] compressedImage) {
super.init(viewTag);
mBarCode = barCode;
mWidth = width;
mHeight = height;
mCompressedImage = compressedImage;
}
/**
@ -96,6 +99,9 @@ public class BarCodeReadEvent extends Event<BarCodeReadEvent> {
eventOrigin.putInt("height", mHeight);
eventOrigin.putInt("width", mWidth);
event.putMap("bounds", eventOrigin);
if (mCompressedImage != null) {
event.putString("image", Base64.encodeToString(mCompressedImage, Base64.NO_WRAP));
}
return event;
}
}

View File

@ -1,6 +1,6 @@
package org.reactnative.camera.events;
import android.support.v4.util.Pools;
import androidx.core.util.Pools;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.uimanager.events.Event;

View File

@ -1,44 +1,46 @@
package org.reactnative.camera.events;
import android.support.v4.util.Pools;
import android.util.SparseArray;
import android.util.Base64;
import androidx.core.util.Pools;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.WritableArray;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.uimanager.events.Event;
import com.facebook.react.uimanager.events.RCTEventEmitter;
import com.google.android.gms.vision.barcode.Barcode;
import org.reactnative.camera.CameraViewManager;
import org.reactnative.barcodedetector.BarcodeFormatUtils;
public class BarcodesDetectedEvent extends Event<BarcodesDetectedEvent> {
private static final Pools.SynchronizedPool<BarcodesDetectedEvent> EVENTS_POOL =
new Pools.SynchronizedPool<>(3);
private SparseArray<Barcode> mBarcodes;
private WritableArray mBarcodes;
private byte[] mCompressedImage;
private BarcodesDetectedEvent() {
}
public static BarcodesDetectedEvent obtain(
int viewTag,
SparseArray<Barcode> barcodes
) {
int viewTag,
WritableArray barcodes,
byte[] compressedImage) {
BarcodesDetectedEvent event = EVENTS_POOL.acquire();
if (event == null) {
event = new BarcodesDetectedEvent();
}
event.init(viewTag, barcodes);
event.init(viewTag, barcodes, compressedImage);
return event;
}
private void init(
int viewTag,
SparseArray<Barcode> barcodes
) {
int viewTag,
WritableArray barcodes,
byte[] compressedImage) {
super.init(viewTag);
mBarcodes = barcodes;
mCompressedImage = compressedImage;
}
/**
@ -66,20 +68,13 @@ public class BarcodesDetectedEvent extends Event<BarcodesDetectedEvent> {
}
private WritableMap serializeEventData() {
WritableArray barcodesList = Arguments.createArray();
for (int i = 0; i < mBarcodes.size(); i++) {
Barcode barcode = mBarcodes.valueAt(i);
WritableMap serializedBarcode = Arguments.createMap();
serializedBarcode.putString("data", barcode.displayValue);
serializedBarcode.putString("type", BarcodeFormatUtils.get(barcode.format));
barcodesList.pushMap(serializedBarcode);
}
WritableMap event = Arguments.createMap();
event.putString("type", "barcode");
event.putArray("barcodes", barcodesList);
event.putArray("barcodes", mBarcodes);
event.putInt("target", getViewTag());
if (mCompressedImage != null) {
event.putString("image", Base64.encodeToString(mCompressedImage, Base64.NO_WRAP));
}
return event;
}
}

View File

@ -1,6 +1,6 @@
package org.reactnative.camera.events;
import android.support.v4.util.Pools;
import androidx.core.util.Pools;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.uimanager.events.Event;

View File

@ -1,6 +1,6 @@
package org.reactnative.camera.events;
import android.support.v4.util.Pools;
import androidx.core.util.Pools;
import org.reactnative.camera.CameraViewManager;
import com.facebook.react.bridge.Arguments;
@ -8,8 +8,6 @@ import com.facebook.react.bridge.WritableMap;
import com.facebook.react.uimanager.events.Event;
import com.facebook.react.uimanager.events.RCTEventEmitter;
import java.util.Date;
public class CameraReadyEvent extends Event<CameraReadyEvent> {
private static final Pools.SynchronizedPool<CameraReadyEvent> EVENTS_POOL = new Pools.SynchronizedPool<>(3);
private CameraReadyEvent() {}

View File

@ -1,6 +1,6 @@
package org.reactnative.camera.events;
import android.support.v4.util.Pools;
import androidx.core.util.Pools;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.uimanager.events.Event;

View File

@ -1,57 +1,34 @@
package org.reactnative.camera.events;
import android.support.v4.util.Pools;
import android.util.SparseArray;
import androidx.core.util.Pools;
import org.reactnative.camera.CameraViewManager;
import org.reactnative.camera.utils.ImageDimensions;
import org.reactnative.facedetector.FaceDetectorUtils;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.WritableArray;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.uimanager.events.Event;
import com.facebook.react.uimanager.events.RCTEventEmitter;
import com.google.android.cameraview.CameraView;
import com.google.android.gms.vision.face.Face;
public class FacesDetectedEvent extends Event<FacesDetectedEvent> {
private static final Pools.SynchronizedPool<FacesDetectedEvent> EVENTS_POOL =
new Pools.SynchronizedPool<>(3);
private double mScaleX;
private double mScaleY;
private SparseArray<Face> mFaces;
private ImageDimensions mImageDimensions;
private WritableArray mData;
private FacesDetectedEvent() {}
public static FacesDetectedEvent obtain(
int viewTag,
SparseArray<Face> faces,
ImageDimensions dimensions,
double scaleX,
double scaleY
) {
public static FacesDetectedEvent obtain(int viewTag, WritableArray data) {
FacesDetectedEvent event = EVENTS_POOL.acquire();
if (event == null) {
event = new FacesDetectedEvent();
}
event.init(viewTag, faces, dimensions, scaleX, scaleY);
event.init(viewTag, data);
return event;
}
private void init(
int viewTag,
SparseArray<Face> faces,
ImageDimensions dimensions,
double scaleX,
double scaleY
) {
private void init(int viewTag, WritableArray data) {
super.init(viewTag);
mFaces = faces;
mImageDimensions = dimensions;
mScaleX = scaleX;
mScaleY = scaleY;
mData = data;
}
/**
@ -61,11 +38,11 @@ public class FacesDetectedEvent extends Event<FacesDetectedEvent> {
*/
@Override
public short getCoalescingKey() {
if (mFaces.size() > Short.MAX_VALUE) {
if (mData.size() > Short.MAX_VALUE) {
return Short.MAX_VALUE;
}
return (short) mFaces.size();
return (short) mData.size();
}
@Override
@ -79,22 +56,9 @@ public class FacesDetectedEvent extends Event<FacesDetectedEvent> {
}
private WritableMap serializeEventData() {
WritableArray facesList = Arguments.createArray();
for(int i = 0; i < mFaces.size(); i++) {
Face face = mFaces.valueAt(i);
WritableMap serializedFace = FaceDetectorUtils.serializeFace(face, mScaleX, mScaleY);
if (mImageDimensions.getFacing() == CameraView.FACING_FRONT) {
serializedFace = FaceDetectorUtils.rotateFaceX(serializedFace, mImageDimensions.getWidth(), mScaleX);
} else {
serializedFace = FaceDetectorUtils.changeAnglesDirection(serializedFace);
}
facesList.pushMap(serializedFace);
}
WritableMap event = Arguments.createMap();
event.putString("type", "face");
event.putArray("faces", facesList);
event.putArray("faces", mData);
event.putInt("target", getViewTag());
return event;
}

View File

@ -1,6 +1,6 @@
package org.reactnative.camera.events;
import android.support.v4.util.Pools;
import androidx.core.util.Pools;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.uimanager.events.Event;

View File

@ -1,6 +1,6 @@
package org.reactnative.camera.events;
import android.support.v4.util.Pools;
import androidx.core.util.Pools;
import org.reactnative.camera.CameraViewManager;
import com.facebook.react.bridge.Arguments;
@ -8,8 +8,6 @@ import com.facebook.react.bridge.WritableMap;
import com.facebook.react.uimanager.events.Event;
import com.facebook.react.uimanager.events.RCTEventEmitter;
import java.util.Date;
public class PictureTakenEvent extends Event<PictureTakenEvent> {
private static final Pools.SynchronizedPool<PictureTakenEvent> EVENTS_POOL = new Pools.SynchronizedPool<>(3);
private PictureTakenEvent() {}

View File

@ -0,0 +1,42 @@
package org.reactnative.camera.events;
import androidx.core.util.Pools;
import org.reactnative.camera.CameraViewManager;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.uimanager.events.Event;
import com.facebook.react.uimanager.events.RCTEventEmitter;
public class RecordingEndEvent extends Event<RecordingEndEvent> {
private static final Pools.SynchronizedPool<RecordingEndEvent> EVENTS_POOL = new Pools.SynchronizedPool<>(3);
private RecordingEndEvent() {}
public static RecordingEndEvent obtain(int viewTag) {
RecordingEndEvent event = EVENTS_POOL.acquire();
if (event == null) {
event = new RecordingEndEvent();
}
event.init(viewTag);
return event;
}
@Override
public short getCoalescingKey() {
return 0;
}
@Override
public String getEventName() {
return CameraViewManager.Events.EVENT_ON_RECORDING_END.toString();
}
@Override
public void dispatch(RCTEventEmitter rctEventEmitter) {
rctEventEmitter.receiveEvent(getViewTag(), getEventName(), serializeEventData());
}
private WritableMap serializeEventData() {
return Arguments.createMap();
}
}

View File

@ -0,0 +1,46 @@
package org.reactnative.camera.events;
import androidx.core.util.Pools;
import org.reactnative.camera.CameraViewManager;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.uimanager.events.Event;
import com.facebook.react.uimanager.events.RCTEventEmitter;
public class RecordingStartEvent extends Event<RecordingStartEvent> {
private static final Pools.SynchronizedPool<RecordingStartEvent> EVENTS_POOL = new Pools.SynchronizedPool<>(3);
private RecordingStartEvent() {}
private WritableMap mResponse;
public static RecordingStartEvent obtain(int viewTag, WritableMap response) {
RecordingStartEvent event = EVENTS_POOL.acquire();
if (event == null) {
event = new RecordingStartEvent();
}
event.init(viewTag, response);
return event;
}
private void init(int viewTag, WritableMap response) {
super.init(viewTag);
mResponse = response;
}
// @Override
// public short getCoalescingKey() {
// int hashCode = mResponse.getString("uri").hashCode() % Short.MAX_VALUE;
// return (short) hashCode;
// }
@Override
public String getEventName() {
return CameraViewManager.Events.EVENT_ON_RECORDING_START.toString();
}
@Override
public void dispatch(RCTEventEmitter rctEventEmitter) {
rctEventEmitter.receiveEvent(getViewTag(), getEventName(), mResponse);
}
}

View File

@ -1,22 +1,14 @@
package org.reactnative.camera.events;
import android.support.v4.util.Pools;
import android.util.SparseArray;
import androidx.core.util.Pools;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.WritableArray;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.uimanager.events.Event;
import com.facebook.react.uimanager.events.RCTEventEmitter;
import com.google.android.cameraview.CameraView;
import com.google.android.gms.vision.text.Line;
import com.google.android.gms.vision.text.Text;
import com.google.android.gms.vision.text.TextBlock;
import org.reactnative.camera.CameraViewManager;
import org.reactnative.camera.utils.ImageDimensions;
import org.reactnative.facedetector.FaceDetectorUtils;
public class TextRecognizedEvent extends Event<TextRecognizedEvent> {
@ -24,39 +16,22 @@ public class TextRecognizedEvent extends Event<TextRecognizedEvent> {
private static final Pools.SynchronizedPool<TextRecognizedEvent> EVENTS_POOL =
new Pools.SynchronizedPool<>(3);
private double mScaleX;
private double mScaleY;
private SparseArray<TextBlock> mTextBlocks;
private ImageDimensions mImageDimensions;
private WritableArray mData;
private TextRecognizedEvent() {}
public static TextRecognizedEvent obtain(
int viewTag,
SparseArray<TextBlock> textBlocks,
ImageDimensions dimensions,
double scaleX,
double scaleY) {
public static TextRecognizedEvent obtain(int viewTag, WritableArray data) {
TextRecognizedEvent event = EVENTS_POOL.acquire();
if (event == null) {
event = new TextRecognizedEvent();
}
event.init(viewTag, textBlocks, dimensions, scaleX, scaleY);
event.init(viewTag, data);
return event;
}
private void init(
int viewTag,
SparseArray<TextBlock> textBlocks,
ImageDimensions dimensions,
double scaleX,
double scaleY) {
private void init(int viewTag, WritableArray data) {
super.init(viewTag);
mTextBlocks = textBlocks;
mImageDimensions = dimensions;
mScaleX = scaleX;
mScaleY = scaleY;
mData = data;
}
@Override
@ -66,92 +41,14 @@ public class TextRecognizedEvent extends Event<TextRecognizedEvent> {
@Override
public void dispatch(RCTEventEmitter rctEventEmitter) {
rctEventEmitter.receiveEvent(getViewTag(), getEventName(), serializeEventData());
rctEventEmitter.receiveEvent(getViewTag(), getEventName(), createEvent());
}
private WritableMap serializeEventData() {
WritableArray textBlocksList = Arguments.createArray();
for (int i = 0; i < mTextBlocks.size(); ++i) {
TextBlock textBlock = mTextBlocks.valueAt(i);
WritableMap serializedTextBlock = serializeText(textBlock);
if (mImageDimensions.getFacing() == CameraView.FACING_FRONT) {
serializedTextBlock = rotateTextX(serializedTextBlock);
}
textBlocksList.pushMap(serializedTextBlock);
}
private WritableMap createEvent() {
WritableMap event = Arguments.createMap();
event.putString("type", "textBlock");
event.putArray("textBlocks", textBlocksList);
event.putArray("textBlocks", mData);
event.putInt("target", getViewTag());
return event;
}
private WritableMap serializeText(Text text) {
WritableMap encodedText = Arguments.createMap();
WritableArray components = Arguments.createArray();
for (Text component : text.getComponents()) {
components.pushMap(serializeText(component));
}
encodedText.putArray("components", components);
encodedText.putString("value", text.getValue());
WritableMap origin = Arguments.createMap();
origin.putDouble("x", text.getBoundingBox().left * this.mScaleX);
origin.putDouble("y", text.getBoundingBox().top * this.mScaleY);
WritableMap size = Arguments.createMap();
size.putDouble("width", text.getBoundingBox().width() * this.mScaleX);
size.putDouble("height", text.getBoundingBox().height() * this.mScaleY);
WritableMap bounds = Arguments.createMap();
bounds.putMap("origin", origin);
bounds.putMap("size", size);
encodedText.putMap("bounds", bounds);
String type_;
if (text instanceof TextBlock) {
type_ = "block";
} else if (text instanceof Line) {
type_ = "line";
} else /*if (text instanceof Element)*/ {
type_ = "element";
}
encodedText.putString("type", type_);
return encodedText;
}
private WritableMap rotateTextX(WritableMap text) {
ReadableMap faceBounds = text.getMap("bounds");
ReadableMap oldOrigin = faceBounds.getMap("origin");
WritableMap mirroredOrigin = FaceDetectorUtils.positionMirroredHorizontally(
oldOrigin, mImageDimensions.getWidth(), mScaleX);
double translateX = -faceBounds.getMap("size").getDouble("width");
WritableMap translatedMirroredOrigin = FaceDetectorUtils.positionTranslatedHorizontally(mirroredOrigin, translateX);
WritableMap newBounds = Arguments.createMap();
newBounds.merge(faceBounds);
newBounds.putMap("origin", translatedMirroredOrigin);
text.putMap("bounds", newBounds);
ReadableArray oldComponents = text.getArray("components");
WritableArray newComponents = Arguments.createArray();
for (int i = 0; i < oldComponents.size(); ++i) {
WritableMap component = Arguments.createMap();
component.merge(oldComponents.getMap(i));
rotateTextX(component);
newComponents.pushMap(component);
}
text.putArray("components", newComponents);
return text;
}
}

View File

@ -0,0 +1,69 @@
package org.reactnative.camera.events;
import androidx.core.util.Pools;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.uimanager.events.Event;
import com.facebook.react.uimanager.events.RCTEventEmitter;
import org.reactnative.camera.CameraViewManager;
public class TouchEvent extends Event<TouchEvent> {
private static final Pools.SynchronizedPool<TouchEvent> EVENTS_POOL =
new Pools.SynchronizedPool<>(3);
private int mX;
private int mY;
private boolean mIsDoubleTap;
private TouchEvent() {}
public static TouchEvent obtain(int viewTag, boolean isDoubleTap, int x, int y) {
TouchEvent event = EVENTS_POOL.acquire();
if (event == null) {
event = new TouchEvent();
}
event.init(viewTag, isDoubleTap, x, y);
return event;
}
private void init(int viewTag, boolean isDoubleTap, int x, int y) {
super.init(viewTag);
mX = x;
mY = y;
mIsDoubleTap=isDoubleTap;
}
@Override
public short getCoalescingKey() {
return 0;
}
@Override
public String getEventName() {
return CameraViewManager.Events.EVENT_ON_TOUCH.toString();
}
@Override
public void dispatch(RCTEventEmitter rctEventEmitter) {
rctEventEmitter.receiveEvent(getViewTag(), getEventName(), serializeEventData());
}
private WritableMap serializeEventData() {
WritableMap event = Arguments.createMap();
event.putInt("target", getViewTag());
WritableMap touchOrigin = Arguments.createMap();
touchOrigin.putInt("x", mX);
touchOrigin.putInt("y",mY);
event.putBoolean("isDoubleTap", mIsDoubleTap);
event.putMap("touchOrigin", touchOrigin);
return event;
}
}

View File

@ -13,6 +13,14 @@ public class BarCodeScannerAsyncTask extends android.os.AsyncTask<Void, Void, Re
private int mHeight;
private BarCodeScannerAsyncTaskDelegate mDelegate;
private final MultiFormatReader mMultiFormatReader;
private boolean mLimitScanArea;
private float mScanAreaX;
private float mScanAreaY;
private float mScanAreaWidth;
private float mScanAreaHeight;
private int mCameraViewWidth;
private int mCameraViewHeight;
private float mRatio;
// note(sjchmiela): From my short research it's ok to ignore rotation of the image.
public BarCodeScannerAsyncTask(
@ -20,13 +28,29 @@ public class BarCodeScannerAsyncTask extends android.os.AsyncTask<Void, Void, Re
MultiFormatReader multiFormatReader,
byte[] imageData,
int width,
int height
int height,
boolean limitScanArea,
float scanAreaX,
float scanAreaY,
float scanAreaWidth,
float scanAreaHeight,
int cameraViewWidth,
int cameraViewHeight,
float ratio
) {
mImageData = imageData;
mWidth = width;
mHeight = height;
mDelegate = delegate;
mMultiFormatReader = multiFormatReader;
mLimitScanArea = limitScanArea;
mScanAreaX = scanAreaX;
mScanAreaY = scanAreaY;
mScanAreaWidth = scanAreaWidth;
mScanAreaHeight = scanAreaHeight;
mCameraViewWidth = cameraViewWidth;
mCameraViewHeight = cameraViewHeight;
mRatio = ratio;
}
@Override
@ -36,16 +60,74 @@ public class BarCodeScannerAsyncTask extends android.os.AsyncTask<Void, Void, Re
}
Result result = null;
/**
* mCameraViewWidth and mCameraViewHeight are obtained from portait orientation
* mWidth and mHeight are measured with landscape orientation with Home button to the right
* adjustedCamViewWidth is the adjusted width from the Aspect ratio setting
*/
int adjustedCamViewWidth = (int) (mCameraViewHeight / mRatio);
float adjustedScanY = (((adjustedCamViewWidth - mCameraViewWidth) / 2) + (mScanAreaY * mCameraViewWidth)) / adjustedCamViewWidth;
int left = (int) (mScanAreaX * mWidth);
int top = (int) (adjustedScanY * mHeight);
int scanWidth = (int) (mScanAreaWidth * mWidth);
int scanHeight = (int) (((mScanAreaHeight * mCameraViewWidth) / adjustedCamViewWidth) * mHeight);
try {
BinaryBitmap bitmap = generateBitmapFromImageData(mImageData, mWidth, mHeight);
BinaryBitmap bitmap = generateBitmapFromImageData(
mImageData,
mWidth,
mHeight,
false,
left,
top,
scanWidth,
scanHeight
);
result = mMultiFormatReader.decodeWithState(bitmap);
} catch (NotFoundException e) {
BinaryBitmap bitmap = generateBitmapFromImageData(rotateImage(mImageData,mWidth, mHeight), mHeight, mWidth);
BinaryBitmap bitmap = generateBitmapFromImageData(
rotateImage(mImageData,mWidth, mHeight),
mHeight,
mWidth,
false,
mHeight - scanHeight - top,
left,
scanHeight,
scanWidth
);
try {
result = mMultiFormatReader.decodeWithState(bitmap);
} catch (NotFoundException e1) {
//no barcode Found
BinaryBitmap invertedBitmap = generateBitmapFromImageData(
mImageData,
mWidth,
mHeight,
true,
mWidth - scanWidth - left,
mHeight - scanHeight - top,
scanWidth,
scanHeight
);
try {
result = mMultiFormatReader.decodeWithState(invertedBitmap);
} catch (NotFoundException e2) {
BinaryBitmap invertedRotatedBitmap = generateBitmapFromImageData(
rotateImage(mImageData,mWidth, mHeight),
mHeight,
mWidth,
true,
top,
mWidth - scanWidth - left,
scanHeight,
scanWidth
);
try {
result = mMultiFormatReader.decodeWithState(invertedRotatedBitmap);
} catch (NotFoundException e3) {
//no barcode Found
}
}
}
} catch (Throwable t) {
t.printStackTrace();
@ -66,13 +148,26 @@ public class BarCodeScannerAsyncTask extends android.os.AsyncTask<Void, Void, Re
protected void onPostExecute(Result result) {
super.onPostExecute(result);
if (result != null) {
mDelegate.onBarCodeRead(result, mWidth, mHeight);
mDelegate.onBarCodeRead(result, mWidth, mHeight, mImageData);
}
mDelegate.onBarCodeScanningTaskCompleted();
}
private BinaryBitmap generateBitmapFromImageData(byte[] imageData, int width, int height) {
PlanarYUVLuminanceSource source = new PlanarYUVLuminanceSource(
private BinaryBitmap generateBitmapFromImageData(byte[] imageData, int width, int height, boolean inverse, int left, int top, int sWidth, int sHeight) {
PlanarYUVLuminanceSource source;
if (mLimitScanArea) {
source = new PlanarYUVLuminanceSource(
imageData, // byte[] yuvData
width, // int dataWidth
height, // int dataHeight
left, // int left
top, // int top
sWidth, // int width
sHeight, // int height
false // boolean reverseHorizontal
);
} else {
source = new PlanarYUVLuminanceSource(
imageData, // byte[] yuvData
width, // int dataWidth
height, // int dataHeight
@ -81,7 +176,12 @@ public class BarCodeScannerAsyncTask extends android.os.AsyncTask<Void, Void, Re
width, // int width
height, // int height
false // boolean reverseHorizontal
);
return new BinaryBitmap(new HybridBinarizer(source));
);
}
if (inverse) {
return new BinaryBitmap(new HybridBinarizer(source.invert()));
} else {
return new BinaryBitmap(new HybridBinarizer(source));
}
}
}

View File

@ -3,6 +3,6 @@ package org.reactnative.camera.tasks;
import com.google.zxing.Result;
public interface BarCodeScannerAsyncTaskDelegate {
void onBarCodeRead(Result barCode, int width, int height);
void onBarCodeRead(Result barCode, int width, int height, byte[] imageData);
void onBarCodeScanningTaskCompleted();
}

View File

@ -1,57 +0,0 @@
package org.reactnative.camera.tasks;
import android.util.SparseArray;
import com.google.android.gms.vision.barcode.Barcode;
import org.reactnative.frame.RNFrame;
import org.reactnative.frame.RNFrameFactory;
import org.reactnative.barcodedetector.RNBarcodeDetector;
public class BarcodeDetectorAsyncTask extends android.os.AsyncTask<Void, Void, SparseArray<Barcode>> {
private byte[] mImageData;
private int mWidth;
private int mHeight;
private int mRotation;
private RNBarcodeDetector mBarcodeDetector;
private BarcodeDetectorAsyncTaskDelegate mDelegate;
public BarcodeDetectorAsyncTask(
BarcodeDetectorAsyncTaskDelegate delegate,
RNBarcodeDetector barcodeDetector,
byte[] imageData,
int width,
int height,
int rotation
) {
mImageData = imageData;
mWidth = width;
mHeight = height;
mRotation = rotation;
mDelegate = delegate;
mBarcodeDetector = barcodeDetector;
}
@Override
protected SparseArray<Barcode> doInBackground(Void... ignored) {
if (isCancelled() || mDelegate == null || mBarcodeDetector == null || !mBarcodeDetector.isOperational()) {
return null;
}
RNFrame frame = RNFrameFactory.buildFrame(mImageData, mWidth, mHeight, mRotation);
return mBarcodeDetector.detect(frame);
}
@Override
protected void onPostExecute(SparseArray<Barcode> barcodes) {
super.onPostExecute(barcodes);
if (barcodes == null) {
mDelegate.onBarcodeDetectionError(mBarcodeDetector);
} else {
if (barcodes.size() > 0) {
mDelegate.onBarcodesDetected(barcodes, mWidth, mHeight, mRotation);
}
mDelegate.onBarcodeDetectingTaskCompleted();
}
}
}

View File

@ -1,12 +1,11 @@
package org.reactnative.camera.tasks;
import android.util.SparseArray;
import com.google.android.gms.vision.barcode.Barcode;
import com.facebook.react.bridge.WritableArray;
import org.reactnative.barcodedetector.RNBarcodeDetector;
public interface BarcodeDetectorAsyncTaskDelegate {
void onBarcodesDetected(SparseArray<Barcode> barcodes, int sourceWidth, int sourceHeight, int sourceRotation);
void onBarcodesDetected(WritableArray barcodes, int width, int height, byte[] imageData);
void onBarcodeDetectionError(RNBarcodeDetector barcodeDetector);

View File

@ -1,56 +0,0 @@
package org.reactnative.camera.tasks;
import android.util.SparseArray;
import com.google.android.gms.vision.face.Face;
import org.reactnative.frame.RNFrame;
import org.reactnative.frame.RNFrameFactory;
import org.reactnative.facedetector.RNFaceDetector;
public class FaceDetectorAsyncTask extends android.os.AsyncTask<Void, Void, SparseArray<Face>> {
private byte[] mImageData;
private int mWidth;
private int mHeight;
private int mRotation;
private RNFaceDetector mFaceDetector;
private FaceDetectorAsyncTaskDelegate mDelegate;
public FaceDetectorAsyncTask(
FaceDetectorAsyncTaskDelegate delegate,
RNFaceDetector faceDetector,
byte[] imageData,
int width,
int height,
int rotation
) {
mImageData = imageData;
mWidth = width;
mHeight = height;
mRotation = rotation;
mDelegate = delegate;
mFaceDetector = faceDetector;
}
@Override
protected SparseArray<Face> doInBackground(Void... ignored) {
if (isCancelled() || mDelegate == null || mFaceDetector == null || !mFaceDetector.isOperational()) {
return null;
}
RNFrame frame = RNFrameFactory.buildFrame(mImageData, mWidth, mHeight, mRotation);
return mFaceDetector.detect(frame);
}
@Override
protected void onPostExecute(SparseArray<Face> faces) {
super.onPostExecute(faces);
if (faces == null) {
mDelegate.onFaceDetectionError(mFaceDetector);
} else {
if (faces.size() > 0) {
mDelegate.onFacesDetected(faces, mWidth, mHeight, mRotation);
}
mDelegate.onFaceDetectingTaskCompleted();
}
}
}

View File

@ -1,12 +1,11 @@
package org.reactnative.camera.tasks;
import android.util.SparseArray;
import org.reactnative.facedetector.RNFaceDetector;
import com.google.android.gms.vision.face.Face;
import com.facebook.react.bridge.WritableArray;
public interface FaceDetectorAsyncTaskDelegate {
void onFacesDetected(SparseArray<Face> face, int sourceWidth, int sourceHeight, int sourceRotation);
void onFacesDetected(WritableArray faces);
void onFaceDetectionError(RNFaceDetector faceDetector);
void onFaceDetectingTaskCompleted();
}

View File

@ -6,7 +6,7 @@ import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.net.Uri;
import android.os.AsyncTask;
import android.support.media.ExifInterface;
import androidx.exifinterface.media.ExifInterface;
import android.util.Base64;
import org.reactnative.camera.RNCameraViewHelper;
@ -15,6 +15,7 @@ import org.reactnative.camera.utils.RNFileUtils;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.ReadableType;
import com.facebook.react.bridge.WritableMap;
import java.io.ByteArrayInputStream;
@ -26,10 +27,10 @@ import java.io.IOException;
public class ResolveTakenPictureAsyncTask extends AsyncTask<Void, Void, WritableMap> {
private static final String ERROR_TAG = "E_TAKING_PICTURE_FAILED";
private Promise mPromise;
private Bitmap mBitmap;
private byte[] mImageData;
private ReadableMap mOptions;
private File mCacheDirectory;
private Bitmap mBitmap;
private int mDeviceOrientation;
private PictureSavedDelegate mPictureSavedDelegate;
@ -46,108 +47,222 @@ public class ResolveTakenPictureAsyncTask extends AsyncTask<Void, Void, Writable
return (int) (mOptions.getDouble("quality") * 100);
}
// loads bitmap only if necessary
private void loadBitmap() throws IOException {
if(mBitmap == null){
mBitmap = BitmapFactory.decodeByteArray(mImageData, 0, mImageData.length);
}
if(mBitmap == null){
throw new IOException("Failed to decode Image Bitmap");
}
}
@Override
protected WritableMap doInBackground(Void... voids) {
WritableMap response = Arguments.createMap();
ByteArrayInputStream inputStream = null;
ExifInterface exifInterface = null;
WritableMap exifData = null;
ReadableMap exifExtraData = null;
boolean orientationChanged = false;
response.putInt("deviceOrientation", mDeviceOrientation);
response.putInt("pictureOrientation", mOptions.hasKey("orientation") ? mOptions.getInt("orientation") : mDeviceOrientation);
if (mOptions.hasKey("skipProcessing")) {
try {
// Prepare file output
File imageFile = new File(RNFileUtils.getOutputFilePath(mCacheDirectory, ".jpg"));
imageFile.createNewFile();
FileOutputStream fOut = new FileOutputStream(imageFile);
// Save byte array (it is already a JPEG)
fOut.write(mImageData);
try{
// this replaces the skipProcessing flag, we will process only if needed, and in
// an orderly manner, so that skipProcessing is the default behaviour if no options are given
// and this behaves more like the iOS version.
// We will load all data lazily only when needed.
// Return file system URI
String fileUri = Uri.fromFile(imageFile).toString();
response.putString("uri", fileUri);
// this should not incurr in any overhead if not read/used
inputStream = new ByteArrayInputStream(mImageData);
} catch (Resources.NotFoundException e) {
mPromise.reject(ERROR_TAG, "Documents directory of the app could not be found.", e);
e.printStackTrace();
} catch (IOException e) {
mPromise.reject(ERROR_TAG, "An unknown I/O exception has occurred.", e);
e.printStackTrace();
// Rotate the bitmap to the proper orientation if requested
if(mOptions.hasKey("fixOrientation") && mOptions.getBoolean("fixOrientation")){
exifInterface = new ExifInterface(inputStream);
// Get orientation of the image from mImageData via inputStream
int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED);
if(orientation != ExifInterface.ORIENTATION_UNDEFINED){
loadBitmap();
mBitmap = rotateBitmap(mBitmap, getImageRotation(orientation));
orientationChanged = true;
}
}
return response;
}
if (mOptions.hasKey("width")) {
loadBitmap();
mBitmap = resizeBitmap(mBitmap, mOptions.getInt("width"));
}
// we need the stream only for photos from a device
if (mBitmap == null) {
mBitmap = BitmapFactory.decodeByteArray(mImageData, 0, mImageData.length);
inputStream = new ByteArrayInputStream(mImageData);
}
if (mOptions.hasKey("mirrorImage") && mOptions.getBoolean("mirrorImage")) {
loadBitmap();
mBitmap = flipHorizontally(mBitmap);
}
try {
if (inputStream != null) {
ExifInterface exifInterface = new ExifInterface(inputStream);
// Get orientation of the image from mImageData via inputStream
int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION,
ExifInterface.ORIENTATION_UNDEFINED);
// Rotate the bitmap to the proper orientation if needed
if (mOptions.hasKey("fixOrientation") && mOptions.getBoolean("fixOrientation") && orientation != ExifInterface.ORIENTATION_UNDEFINED) {
mBitmap = rotateBitmap(mBitmap, getImageRotation(orientation));
// EXIF code - we will adjust exif info later if we manipulated the bitmap
boolean writeExifToResponse = mOptions.hasKey("exif") && mOptions.getBoolean("exif");
// default to true if not provided so it is consistent with iOS and with what happens if no
// processing is done and the image is saved as is.
boolean writeExifToFile = true;
if (mOptions.hasKey("writeExif")) {
switch (mOptions.getType("writeExif")) {
case Boolean:
writeExifToFile = mOptions.getBoolean("writeExif");
break;
case Map:
exifExtraData = mOptions.getMap("writeExif");
writeExifToFile = true;
break;
}
}
// Read Exif data if needed
if (writeExifToResponse || writeExifToFile) {
// if we manipulated the image, or need to add extra data, or need to add it to the response,
// then we need to load the actual exif data.
// Otherwise we can just use w/e exif data we have right now in our byte array
if(mBitmap != null || exifExtraData != null || writeExifToResponse){
if(exifInterface == null){
exifInterface = new ExifInterface(inputStream);
}
exifData = RNCameraViewHelper.getExifData(exifInterface);
if(exifExtraData != null){
exifData.merge(exifExtraData);
}
}
if (mOptions.hasKey("width")) {
mBitmap = resizeBitmap(mBitmap, mOptions.getInt("width"));
}
// if we did anything to the bitmap, adjust exif
if(mBitmap != null){
exifData.putInt("width", mBitmap.getWidth());
exifData.putInt("height", mBitmap.getHeight());
if (mOptions.hasKey("mirrorImage") && mOptions.getBoolean("mirrorImage")) {
mBitmap = flipHorizontally(mBitmap);
if(orientationChanged){
exifData.putInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
}
}
// Write Exif data to the response if requested
if (mOptions.hasKey("exif") && mOptions.getBoolean("exif")) {
WritableMap exifData = RNCameraViewHelper.getExifData(exifInterface);
if (writeExifToResponse) {
response.putMap("exif", exifData);
}
}
// Upon rotating, write the image's dimensions to the response
response.putInt("width", mBitmap.getWidth());
response.putInt("height", mBitmap.getHeight());
// Cache compressed image in imageStream
ByteArrayOutputStream imageStream = new ByteArrayOutputStream();
mBitmap.compress(Bitmap.CompressFormat.JPEG, getQuality(), imageStream);
// Write compressed image to file in cache directory unless otherwise specified
if (!mOptions.hasKey("doNotSave") || !mOptions.getBoolean("doNotSave")) {
String filePath = writeStreamToFile(imageStream);
File imageFile = new File(filePath);
String fileUri = Uri.fromFile(imageFile).toString();
response.putString("uri", fileUri);
// final processing
// Based on whether or not we loaded the full bitmap into memory, final processing differs
if(mBitmap == null){
// set response dimensions. If we haven't read our bitmap, get it efficiently
// without loading the actual bitmap into memory
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeByteArray(mImageData, 0, mImageData.length, options);
if(options != null){
response.putInt("width", options.outWidth);
response.putInt("height", options.outHeight);
}
// save to file if requested
if (!mOptions.hasKey("doNotSave") || !mOptions.getBoolean("doNotSave")) {
// Prepare file output
File imageFile = new File(getImagePath());
imageFile.createNewFile();
FileOutputStream fOut = new FileOutputStream(imageFile);
// Save byte array (it is already a JPEG)
fOut.write(mImageData);
fOut.flush();
fOut.close();
// update exif data if needed.
// Since we didn't modify the image, we only update if we have extra exif info
if (writeExifToFile && exifExtraData != null) {
ExifInterface fileExifInterface = new ExifInterface(imageFile.getAbsolutePath());
RNCameraViewHelper.setExifData(fileExifInterface, exifExtraData);
fileExifInterface.saveAttributes();
}
else if (!writeExifToFile){
// if we were requested to NOT store exif, we actually need to
// clear the exif tags
ExifInterface fileExifInterface = new ExifInterface(imageFile.getAbsolutePath());
RNCameraViewHelper.clearExifData(fileExifInterface);
fileExifInterface.saveAttributes();
}
// else: exif is unmodified, no need to update anything
// Return file system URI
String fileUri = Uri.fromFile(imageFile).toString();
response.putString("uri", fileUri);
}
if (mOptions.hasKey("base64") && mOptions.getBoolean("base64")) {
response.putString("base64", Base64.encodeToString(mImageData, Base64.NO_WRAP));
}
}
else{
// Write base64-encoded image to the response if requested
if (mOptions.hasKey("base64") && mOptions.getBoolean("base64")) {
response.putString("base64", Base64.encodeToString(imageStream.toByteArray(), Base64.NO_WRAP));
}
// get response dimensions right from the bitmap if we have it
response.putInt("width", mBitmap.getWidth());
response.putInt("height", mBitmap.getHeight());
// Cache compressed image in imageStream
ByteArrayOutputStream imageStream = new ByteArrayOutputStream();
mBitmap.compress(Bitmap.CompressFormat.JPEG, getQuality(), imageStream);
// Write compressed image to file in cache directory unless otherwise specified
if (!mOptions.hasKey("doNotSave") || !mOptions.getBoolean("doNotSave")) {
String filePath = writeStreamToFile(imageStream);
// since we lost any exif data on bitmap creation, we only need
// to add it if requested
if (writeExifToFile && exifData != null) {
ExifInterface fileExifInterface = new ExifInterface(filePath);
RNCameraViewHelper.setExifData(fileExifInterface, exifData);
fileExifInterface.saveAttributes();
}
File imageFile = new File(filePath);
String fileUri = Uri.fromFile(imageFile).toString();
response.putString("uri", fileUri);
}
// Write base64-encoded image to the response if requested
if (mOptions.hasKey("base64") && mOptions.getBoolean("base64")) {
response.putString("base64", Base64.encodeToString(imageStream.toByteArray(), Base64.NO_WRAP));
}
// Cleanup
imageStream.close();
if (inputStream != null) {
inputStream.close();
inputStream = null;
}
return response;
} catch (Resources.NotFoundException e) {
}
catch (Resources.NotFoundException e) {
mPromise.reject(ERROR_TAG, "Documents directory of the app could not be found.", e);
e.printStackTrace();
} catch (IOException e) {
}
catch (IOException e) {
mPromise.reject(ERROR_TAG, "An unknown I/O exception has occurred.", e);
e.printStackTrace();
} finally {
}
finally {
try {
if (inputStream != null) {
inputStream.close();
@ -157,7 +272,6 @@ public class ResolveTakenPictureAsyncTask extends AsyncTask<Void, Void, Writable
}
}
// An exception had to occur, promise has already been rejected. Do not try to resolve it again.
return null;
}
@ -199,13 +313,20 @@ public class ResolveTakenPictureAsyncTask extends AsyncTask<Void, Void, Writable
return rotationDegrees;
}
private String getImagePath() throws IOException{
if(mOptions.hasKey("path")){
return mOptions.getString("path");
}
return RNFileUtils.getOutputFilePath(mCacheDirectory, ".jpg");
}
private String writeStreamToFile(ByteArrayOutputStream inputStream) throws IOException {
String outputPath = null;
IOException exception = null;
FileOutputStream outputStream = null;
try {
outputPath = RNFileUtils.getOutputFilePath(mCacheDirectory, ".jpg");
outputPath = getImagePath();
outputStream = new FileOutputStream(outputPath);
inputStream.writeTo(outputStream);
} catch (IOException e) {

View File

@ -1,55 +0,0 @@
package org.reactnative.camera.tasks;
import android.util.SparseArray;
import com.google.android.gms.vision.text.TextBlock;
import com.google.android.gms.vision.text.TextRecognizer;
import org.reactnative.frame.RNFrame;
import org.reactnative.frame.RNFrameFactory;
public class TextRecognizerAsyncTask extends android.os.AsyncTask<Void, Void, SparseArray<TextBlock>> {
private TextRecognizerAsyncTaskDelegate mDelegate;
private TextRecognizer mTextRecognizer;
private byte[] mImageData;
private int mWidth;
private int mHeight;
private int mRotation;
public TextRecognizerAsyncTask(
TextRecognizerAsyncTaskDelegate delegate,
TextRecognizer textRecognizer,
byte[] imageData,
int width,
int height,
int rotation
) {
mDelegate = delegate;
mTextRecognizer = textRecognizer;
mImageData = imageData;
mWidth = width;
mHeight = height;
mRotation = rotation;
}
@Override
protected SparseArray<TextBlock> doInBackground(Void... ignored) {
if (isCancelled() || mDelegate == null || mTextRecognizer == null || !mTextRecognizer.isOperational()) {
return null;
}
RNFrame frame = RNFrameFactory.buildFrame(mImageData, mWidth, mHeight, mRotation);
return mTextRecognizer.detect(frame.getFrame());
}
@Override
protected void onPostExecute(SparseArray<TextBlock> textBlocks) {
super.onPostExecute(textBlocks);
if (textBlocks != null) {
mDelegate.onTextRecognized(textBlocks, mWidth, mHeight, mRotation);
}
mDelegate.onTextRecognizerTaskCompleted();
}
}

View File

@ -1,10 +1,8 @@
package org.reactnative.camera.tasks;
import android.util.SparseArray;
import com.google.android.gms.vision.text.TextBlock;
import com.facebook.react.bridge.WritableArray;
public interface TextRecognizerAsyncTaskDelegate {
void onTextRecognized(SparseArray<TextBlock> textBlocks, int sourceWidth, int sourceHeight, int sourceRotation);
void onTextRecognized(WritableArray serializedData);
void onTextRecognizerTaskCompleted();
}

View File

@ -0,0 +1,15 @@
package org.reactnative.camera.utils;
public class ObjectUtils {
/*
* Replacement for Objects.equals that is only available after Android API 19
*/
public static boolean equals(Object o1, Object o2) {
if (o1 == null && o2 == null) return true;
if (o1 == null) return false;
return o1.equals(o2);
}
}

View File

@ -0,0 +1,95 @@
package org.reactnative.barcodedetector;
import android.util.SparseArray;
import com.google.firebase.ml.vision.barcode.FirebaseVisionBarcode;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public class BarcodeFormatUtils {
public static final SparseArray<String> FORMATS;
public static final Map<String, Integer> REVERSE_FORMATS;
public static final SparseArray<String> TYPES;
public static final Map<String, Integer> REVERSE_TYPES;
private static final int UNKNOWN_FORMAT_INT = FirebaseVisionBarcode.FORMAT_UNKNOWN;
private static final String UNKNOWN_TYPE_STRING = "UNKNOWN_TYPE";
private static final String UNKNOWN_FORMAT_STRING = "UNKNOWN_FORMAT";
static {
// Initialize integer to string map
SparseArray<String> map = new SparseArray<>();
map.put(FirebaseVisionBarcode.FORMAT_CODE_128, "CODE_128");
map.put(FirebaseVisionBarcode.FORMAT_CODE_39, "CODE_39");
map.put(FirebaseVisionBarcode.FORMAT_CODE_93, "CODE_93");
map.put(FirebaseVisionBarcode.FORMAT_CODABAR, "CODABAR");
map.put(FirebaseVisionBarcode.FORMAT_DATA_MATRIX, "DATA_MATRIX");
map.put(FirebaseVisionBarcode.FORMAT_EAN_13, "EAN_13");
map.put(FirebaseVisionBarcode.FORMAT_EAN_8, "EAN_8");
map.put(FirebaseVisionBarcode.FORMAT_ITF, "ITF");
map.put(FirebaseVisionBarcode.FORMAT_QR_CODE, "QR_CODE");
map.put(FirebaseVisionBarcode.FORMAT_UPC_A, "UPC_A");
map.put(FirebaseVisionBarcode.FORMAT_UPC_E, "UPC_E");
map.put(FirebaseVisionBarcode.FORMAT_PDF417, "PDF417");
map.put(FirebaseVisionBarcode.FORMAT_AZTEC, "AZTEC");
map.put(FirebaseVisionBarcode.FORMAT_ALL_FORMATS, "ALL");
map.put(FirebaseVisionBarcode.FORMAT_UPC_A, "UPC_A");
map.put(-1, "None");
FORMATS = map;
// Initialize string to integer map
Map<String, Integer> rmap = new HashMap<>();
for (int i = 0; i < map.size(); i++) {
rmap.put(map.valueAt(i), map.keyAt(i));
}
REVERSE_FORMATS = Collections.unmodifiableMap(rmap);
}
static {
// Initialize integer to string map
SparseArray<String> map = new SparseArray<>();
map.put(FirebaseVisionBarcode.TYPE_CALENDAR_EVENT, "CALENDAR_EVENT");
map.put(FirebaseVisionBarcode.TYPE_CONTACT_INFO, "CONTACT_INFO");
map.put(FirebaseVisionBarcode.TYPE_DRIVER_LICENSE, "DRIVER_LICENSE");
map.put(FirebaseVisionBarcode.TYPE_EMAIL, "EMAIL");
map.put(FirebaseVisionBarcode.TYPE_GEO, "GEO");
map.put(FirebaseVisionBarcode.TYPE_ISBN, "ISBN");
map.put(FirebaseVisionBarcode.TYPE_PHONE, "PHONE");
map.put(FirebaseVisionBarcode.TYPE_PRODUCT, "PRODUCT");
map.put(FirebaseVisionBarcode.TYPE_SMS, "SMS");
map.put(FirebaseVisionBarcode.TYPE_TEXT, "TEXT");
map.put(FirebaseVisionBarcode.TYPE_URL, "URL");
map.put(FirebaseVisionBarcode.TYPE_WIFI, "WIFI");
map.put(-1, "None");
TYPES = map;
// Initialize string to integer map
Map<String, Integer> rmap = new HashMap<>();
for (int i = 0; i < map.size(); i++) {
rmap.put(map.valueAt(i), map.keyAt(i));
}
REVERSE_TYPES = Collections.unmodifiableMap(rmap);
}
public static String get(int format) {
return TYPES.get(format, UNKNOWN_TYPE_STRING);
}
public static String getFormat(int format) {
return FORMATS.get(format, UNKNOWN_FORMAT_STRING);
}
public static int get(String format) {
if (REVERSE_FORMATS.containsKey(format)) {
return REVERSE_FORMATS.get(format);
}
return UNKNOWN_FORMAT_INT;
}
}

View File

@ -0,0 +1,67 @@
package org.reactnative.barcodedetector;
import android.content.Context;
import android.util.Log;
import com.google.firebase.ml.vision.FirebaseVision;
import com.google.firebase.ml.vision.barcode.FirebaseVisionBarcode;
import com.google.firebase.ml.vision.barcode.FirebaseVisionBarcodeDetector;
import com.google.firebase.ml.vision.barcode.FirebaseVisionBarcodeDetectorOptions;
public class RNBarcodeDetector {
public static int NORMAL_MODE = 0;
public static int ALTERNATE_MODE = 1;
public static int INVERTED_MODE = 2;
public static int ALL_FORMATS = FirebaseVisionBarcode.FORMAT_ALL_FORMATS;
private FirebaseVisionBarcodeDetector mBarcodeDetector = null;
private FirebaseVisionBarcodeDetectorOptions.Builder mBuilder;
private int mBarcodeType = FirebaseVisionBarcode.FORMAT_ALL_FORMATS;
public RNBarcodeDetector(Context context) {
mBuilder = new FirebaseVisionBarcodeDetectorOptions.Builder().setBarcodeFormats(mBarcodeType);
}
public boolean isOperational() {
// Legacy api from GMV
return true;
}
public FirebaseVisionBarcodeDetector getDetector() {
if (mBarcodeDetector == null) {
createBarcodeDetector();
}
return mBarcodeDetector;
}
public void setBarcodeType(int barcodeType) {
if (barcodeType != mBarcodeType) {
release();
mBuilder.setBarcodeFormats(barcodeType);
mBarcodeType = barcodeType;
}
}
public void release() {
if (mBarcodeDetector != null) {
try {
mBarcodeDetector.close();
} catch (Exception e) {
Log.e("RNCamera", "Attempt to close BarcodeDetector failed");
}
mBarcodeDetector = null;
}
}
private void createBarcodeDetector() {
FirebaseVisionBarcodeDetectorOptions options = mBuilder.build();
mBarcodeDetector = FirebaseVision.getInstance()
.getVisionBarcodeDetector(options);
}
}

View File

@ -0,0 +1,354 @@
package org.reactnative.camera.tasks;
//import android.graphics.Point;
import android.graphics.Rect;
import android.util.Log;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.WritableArray;
import com.facebook.react.bridge.WritableMap;
import com.google.android.gms.tasks.OnFailureListener;
import com.google.android.gms.tasks.OnSuccessListener;
import com.google.firebase.ml.vision.barcode.FirebaseVisionBarcode;
import com.google.firebase.ml.vision.barcode.FirebaseVisionBarcodeDetector;
import com.google.firebase.ml.vision.common.FirebaseVisionImage;
import com.google.firebase.ml.vision.common.FirebaseVisionImageMetadata;
import org.reactnative.barcodedetector.BarcodeFormatUtils;
import org.reactnative.barcodedetector.RNBarcodeDetector;
import org.reactnative.camera.utils.ImageDimensions;
import java.util.List;
public class BarcodeDetectorAsyncTask extends android.os.AsyncTask<Void, Void, Void> {
private byte[] mImageData;
private int mWidth;
private int mHeight;
private int mRotation;
private RNBarcodeDetector mBarcodeDetector;
private BarcodeDetectorAsyncTaskDelegate mDelegate;
private double mScaleX;
private double mScaleY;
private ImageDimensions mImageDimensions;
private int mPaddingLeft;
private int mPaddingTop;
private String TAG = "RNCamera";
public BarcodeDetectorAsyncTask(
BarcodeDetectorAsyncTaskDelegate delegate,
RNBarcodeDetector barcodeDetector,
byte[] imageData,
int width,
int height,
int rotation,
float density,
int facing,
int viewWidth,
int viewHeight,
int viewPaddingLeft,
int viewPaddingTop
) {
mImageData = imageData;
mWidth = width;
mHeight = height;
mRotation = rotation;
mDelegate = delegate;
mBarcodeDetector = barcodeDetector;
mImageDimensions = new ImageDimensions(width, height, rotation, facing);
mScaleX = (double) (viewWidth) / (mImageDimensions.getWidth() * density);
mScaleY = 1 / density;
mPaddingLeft = viewPaddingLeft;
mPaddingTop = viewPaddingTop;
}
@Override
protected Void doInBackground(Void... ignored) {
if (isCancelled() || mDelegate == null || mBarcodeDetector == null) {
return null;
}
final FirebaseVisionImageMetadata metadata = new FirebaseVisionImageMetadata.Builder()
.setWidth(mWidth)
.setHeight(mHeight)
.setFormat(FirebaseVisionImageMetadata.IMAGE_FORMAT_YV12)
.setRotation(getFirebaseRotation())
.build();
FirebaseVisionImage image = FirebaseVisionImage.fromByteArray(mImageData, metadata);
FirebaseVisionBarcodeDetector barcode = mBarcodeDetector.getDetector();
barcode.detectInImage(image)
.addOnSuccessListener(new OnSuccessListener<List<FirebaseVisionBarcode>>() {
@Override
public void onSuccess(List<FirebaseVisionBarcode> barcodes) {
WritableArray serializedBarcodes = serializeEventData(barcodes);
mDelegate.onBarcodesDetected(serializedBarcodes, mWidth, mHeight, mImageData);
mDelegate.onBarcodeDetectingTaskCompleted();
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
Log.e(TAG, "Text recognition task failed" + e);
mDelegate.onBarcodeDetectingTaskCompleted();
}
});
return null;
}
private int getFirebaseRotation(){
int result;
switch (mRotation) {
case 0:
result = FirebaseVisionImageMetadata.ROTATION_0;
break;
case 90:
result = FirebaseVisionImageMetadata.ROTATION_90;
break;
case 180:
result = FirebaseVisionImageMetadata.ROTATION_180;
break;
case -90:
result = FirebaseVisionImageMetadata.ROTATION_270;
break;
default:
result = FirebaseVisionImageMetadata.ROTATION_0;
Log.e(TAG, "Bad rotation value: " + mRotation);
}
return result;
}
private WritableArray serializeEventData(List<FirebaseVisionBarcode> barcodes) {
WritableArray barcodesList = Arguments.createArray();
for (FirebaseVisionBarcode barcode: barcodes) {
// TODO implement position and data from all barcode types
Rect bounds = barcode.getBoundingBox();
// Point[] corners = barcode.getCornerPoints();
String rawValue = barcode.getRawValue();
int valueType = barcode.getValueType();
int valueFormat = barcode.getFormat();
WritableMap serializedBarcode = Arguments.createMap();
switch (valueType) {
case FirebaseVisionBarcode.TYPE_WIFI:
String ssid = barcode.getWifi().getSsid();
String password = barcode.getWifi().getPassword();
int type = barcode.getWifi().getEncryptionType();
String typeString = "UNKNOWN";
switch (type) {
case FirebaseVisionBarcode.WiFi.TYPE_OPEN:
typeString = "Open";
break;
case FirebaseVisionBarcode.WiFi.TYPE_WEP:
typeString = "WEP";
break;
case FirebaseVisionBarcode.WiFi.TYPE_WPA:
typeString = "WPA";
break;
}
serializedBarcode.putString("encryptionType", typeString);
serializedBarcode.putString("password", password);
serializedBarcode.putString("ssid", ssid);
break;
case FirebaseVisionBarcode.TYPE_URL:
String title = barcode.getUrl().getTitle();
String url = barcode.getUrl().getUrl();
serializedBarcode.putString("url", url);
serializedBarcode.putString("title", title);
break;
case FirebaseVisionBarcode.TYPE_SMS:
String message = barcode.getSms().getMessage();
String phoneNumber = barcode.getSms().getPhoneNumber();
serializedBarcode.putString("message", message);
serializedBarcode.putString("title", phoneNumber);
break;
case FirebaseVisionBarcode.TYPE_PHONE:
String number = barcode.getPhone().getNumber();
int typePhone = barcode.getPhone().getType();
serializedBarcode.putString("number", number);
String typeStringPhone = getPhoneType(typePhone);
serializedBarcode.putString("phoneType", typeStringPhone);
break;
case FirebaseVisionBarcode.TYPE_CALENDAR_EVENT:
serializedBarcode.putString("description", barcode.getCalendarEvent().getDescription());
serializedBarcode.putString("location", barcode.getCalendarEvent().getLocation());
serializedBarcode.putString("organizer", barcode.getCalendarEvent().getOrganizer());
serializedBarcode.putString("status", barcode.getCalendarEvent().getStatus());
serializedBarcode.putString("summary", barcode.getCalendarEvent().getSummary());
FirebaseVisionBarcode.CalendarDateTime start = barcode.getCalendarEvent().getStart();
FirebaseVisionBarcode.CalendarDateTime end = barcode.getCalendarEvent().getEnd();
if (start != null) {
serializedBarcode.putString("start", start.getRawValue());
}
if (end != null) {
serializedBarcode.putString("end", start.getRawValue());
}
break;
case FirebaseVisionBarcode.TYPE_DRIVER_LICENSE:
serializedBarcode.putString("addressCity", barcode.getDriverLicense().getAddressCity());
serializedBarcode.putString("addressState", barcode.getDriverLicense().getAddressState());
serializedBarcode.putString("addressStreet", barcode.getDriverLicense().getAddressStreet());
serializedBarcode.putString("addressZip", barcode.getDriverLicense().getAddressZip());
serializedBarcode.putString("birthDate", barcode.getDriverLicense().getBirthDate());
serializedBarcode.putString("documentType", barcode.getDriverLicense().getDocumentType());
serializedBarcode.putString("expiryDate", barcode.getDriverLicense().getExpiryDate());
serializedBarcode.putString("firstName", barcode.getDriverLicense().getFirstName());
serializedBarcode.putString("middleName", barcode.getDriverLicense().getMiddleName());
serializedBarcode.putString("lastName", barcode.getDriverLicense().getLastName());
serializedBarcode.putString("gender", barcode.getDriverLicense().getGender());
serializedBarcode.putString("issueDate", barcode.getDriverLicense().getIssueDate());
serializedBarcode.putString("issuingCountry", barcode.getDriverLicense().getIssuingCountry());
serializedBarcode.putString("licenseNumber", barcode.getDriverLicense().getLicenseNumber());
break;
case FirebaseVisionBarcode.TYPE_GEO:
serializedBarcode.putDouble("latitude", barcode.getGeoPoint().getLat());
serializedBarcode.putDouble("longitude", barcode.getGeoPoint().getLng());
break;
case FirebaseVisionBarcode.TYPE_CONTACT_INFO:
serializedBarcode.putString("organization", barcode.getContactInfo().getOrganization());
serializedBarcode.putString("title", barcode.getContactInfo().getTitle());
FirebaseVisionBarcode.PersonName name = barcode.getContactInfo().getName();
if (name != null) {
serializedBarcode.putString("firstName", name.getFirst());
serializedBarcode.putString("lastName", name.getLast());
serializedBarcode.putString("middleName", name.getMiddle());
serializedBarcode.putString("formattedName", name.getFormattedName());
serializedBarcode.putString("prefix", name.getPrefix());
serializedBarcode.putString("pronunciation", name.getPronunciation());
serializedBarcode.putString("suffix", name.getSuffix());
}
List<FirebaseVisionBarcode.Phone> phones = barcode.getContactInfo().getPhones();
WritableArray phonesList = Arguments.createArray();
for (FirebaseVisionBarcode.Phone phone : phones) {
WritableMap phoneObject = Arguments.createMap();
phoneObject.putString("number", phone.getNumber());
phoneObject.putString("phoneType", getPhoneType(phone.getType()));
phonesList.pushMap(phoneObject);
}
serializedBarcode.putArray("phones", phonesList);
List<FirebaseVisionBarcode.Address> addresses = barcode.getContactInfo().getAddresses();
WritableArray addressesList = Arguments.createArray();
for (FirebaseVisionBarcode.Address address : addresses) {
WritableMap addressesData = Arguments.createMap();
WritableArray addressesLinesList = Arguments.createArray();
String[] addressesLines = address.getAddressLines();
for (String line : addressesLines) {
addressesLinesList.pushString(line);
}
addressesData.putArray("addressLines", addressesLinesList);
int addressType = address.getType();
String addressTypeString = "UNKNOWN";
switch(addressType) {
case FirebaseVisionBarcode.Address.TYPE_WORK:
addressTypeString = "Work";
break;
case FirebaseVisionBarcode.Address.TYPE_HOME:
addressTypeString = "Home";
break;
}
addressesData.putString("addressType", addressTypeString);
addressesList.pushMap(addressesData);
}
serializedBarcode.putArray("addresses", addressesList);
List<FirebaseVisionBarcode.Email> emails = barcode.getContactInfo().getEmails();
WritableArray emailsList = Arguments.createArray();
for (FirebaseVisionBarcode.Email email : emails) {
WritableMap emailData = processEmail(email);
emailsList.pushMap(emailData);
}
serializedBarcode.putArray("emails", emailsList);
String[] urls = barcode.getContactInfo().getUrls();
WritableArray urlsList = Arguments.createArray();
for (String urlContact : urls) {
urlsList.pushString(urlContact);
}
serializedBarcode.putArray("urls", urlsList);
break;
case FirebaseVisionBarcode.TYPE_EMAIL:
WritableMap emailData = processEmail(barcode.getEmail());
serializedBarcode.putMap("email", emailData);
break;
}
serializedBarcode.putString("data", barcode.getDisplayValue());
serializedBarcode.putString("dataRaw", rawValue);
serializedBarcode.putString("type", BarcodeFormatUtils.get(valueType));
serializedBarcode.putString("format", BarcodeFormatUtils.getFormat(valueFormat));
serializedBarcode.putMap("bounds", processBounds(bounds));
barcodesList.pushMap(serializedBarcode);
}
return barcodesList;
}
private WritableMap processEmail(FirebaseVisionBarcode.Email email) {
WritableMap emailData = Arguments.createMap();
emailData.putString("address", email.getAddress());
emailData.putString("body", email.getBody());
emailData.putString("subject", email.getSubject());
int emailType = email.getType();
String emailTypeString = "UNKNOWN";
switch (emailType) {
case FirebaseVisionBarcode.Email.TYPE_WORK:
emailTypeString = "Work";
break;
case FirebaseVisionBarcode.Email.TYPE_HOME:
emailTypeString = "Home";
break;
}
emailData.putString("emailType", emailTypeString);
return emailData;
}
private String getPhoneType(int typePhone) {
String typeStringPhone = "UNKNOWN";
switch(typePhone) {
case FirebaseVisionBarcode.Phone.TYPE_WORK:
typeStringPhone = "Work";
break;
case FirebaseVisionBarcode.Phone.TYPE_HOME:
typeStringPhone = "Home";
break;
case FirebaseVisionBarcode.Phone.TYPE_FAX:
typeStringPhone = "Fax";
break;
case FirebaseVisionBarcode.Phone.TYPE_MOBILE:
typeStringPhone = "Mobile";
break;
}
return typeStringPhone;
}
private WritableMap processBounds(Rect frame) {
WritableMap origin = Arguments.createMap();
int x = frame.left;
int y = frame.top;
if (frame.left < mWidth / 2) {
x = x + mPaddingLeft / 2;
} else if (frame.left > mWidth /2) {
x = x - mPaddingLeft / 2;
}
y = y + mPaddingTop;
origin.putDouble("x", x * mScaleX);
origin.putDouble("y", y * mScaleY);
WritableMap size = Arguments.createMap();
size.putDouble("width", frame.width() * mScaleX);
size.putDouble("height", frame.height() * mScaleY);
WritableMap bounds = Arguments.createMap();
bounds.putMap("origin", origin);
bounds.putMap("size", size);
return bounds;
}
}

View File

@ -0,0 +1,139 @@
package org.reactnative.camera.tasks;
import android.util.Log;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.WritableArray;
import com.facebook.react.bridge.WritableMap;
import com.google.android.cameraview.CameraView;
import com.google.android.gms.tasks.OnFailureListener;
import com.google.android.gms.tasks.OnSuccessListener;
import com.google.firebase.ml.vision.common.FirebaseVisionImage;
import com.google.firebase.ml.vision.common.FirebaseVisionImageMetadata;
import com.google.firebase.ml.vision.face.FirebaseVisionFace;
import com.google.firebase.ml.vision.face.FirebaseVisionFaceDetector;
import org.reactnative.camera.utils.ImageDimensions;
import org.reactnative.facedetector.FaceDetectorUtils;
import org.reactnative.facedetector.RNFaceDetector;
import java.util.List;
public class FaceDetectorAsyncTask extends android.os.AsyncTask<Void, Void, Void> {
private byte[] mImageData;
private int mWidth;
private int mHeight;
private int mRotation;
private RNFaceDetector mFaceDetector;
private FaceDetectorAsyncTaskDelegate mDelegate;
private double mScaleX;
private double mScaleY;
private ImageDimensions mImageDimensions;
private int mPaddingLeft;
private int mPaddingTop;
private String TAG = "RNCamera";
public FaceDetectorAsyncTask(
FaceDetectorAsyncTaskDelegate delegate,
RNFaceDetector faceDetector,
byte[] imageData,
int width,
int height,
int rotation,
float density,
int facing,
int viewWidth,
int viewHeight,
int viewPaddingLeft,
int viewPaddingTop
) {
mImageData = imageData;
mWidth = width;
mHeight = height;
mRotation = rotation;
mDelegate = delegate;
mFaceDetector = faceDetector;
mImageDimensions = new ImageDimensions(width, height, rotation, facing);
mScaleX = (double) (viewWidth) / (mImageDimensions.getWidth() * density);
mScaleY = (double) (viewHeight) / (mImageDimensions.getHeight() * density);
mPaddingLeft = viewPaddingLeft;
mPaddingTop = viewPaddingTop;
}
@Override
protected Void doInBackground(Void... ignored) {
if (isCancelled() || mDelegate == null || mFaceDetector == null) {
return null;
}
FirebaseVisionImageMetadata metadata = new FirebaseVisionImageMetadata.Builder()
.setWidth(mWidth)
.setHeight(mHeight)
.setFormat(FirebaseVisionImageMetadata.IMAGE_FORMAT_YV12)
.setRotation(getFirebaseRotation())
.build();
FirebaseVisionImage image = FirebaseVisionImage.fromByteArray(mImageData, metadata);
FirebaseVisionFaceDetector detector = mFaceDetector.getDetector();
detector.detectInImage(image)
.addOnSuccessListener(
new OnSuccessListener<List<FirebaseVisionFace>>() {
@Override
public void onSuccess(List<FirebaseVisionFace> faces) {
WritableArray facesList = serializeEventData(faces);
mDelegate.onFacesDetected(facesList);
mDelegate.onFaceDetectingTaskCompleted();
}
})
.addOnFailureListener(
new OnFailureListener() {
@Override
public void onFailure(Exception e) {
Log.e(TAG, "Text recognition task failed" + e);
mDelegate.onFaceDetectingTaskCompleted();
}
});
return null;
}
private int getFirebaseRotation(){
int result;
switch (mRotation) {
case 0:
result = FirebaseVisionImageMetadata.ROTATION_0;
break;
case 90:
result = FirebaseVisionImageMetadata.ROTATION_90;
break;
case 180:
result = FirebaseVisionImageMetadata.ROTATION_180;
break;
case 270:
result = FirebaseVisionImageMetadata.ROTATION_270;
break;
case -90:
result = FirebaseVisionImageMetadata.ROTATION_270;
break;
default:
result = FirebaseVisionImageMetadata.ROTATION_0;
Log.e(TAG, "Bad rotation value: " + mRotation);
}
return result;
}
private WritableArray serializeEventData(List<FirebaseVisionFace> faces) {
WritableArray facesList = Arguments.createArray();
for (FirebaseVisionFace face : faces) {
WritableMap serializedFace = FaceDetectorUtils.serializeFace(face, mScaleX, mScaleY, mWidth, mHeight, mPaddingLeft, mPaddingTop);
if (mImageDimensions.getFacing() == CameraView.FACING_FRONT) {
serializedFace = FaceDetectorUtils.rotateFaceX(serializedFace, mImageDimensions.getWidth(), mScaleX);
} else {
serializedFace = FaceDetectorUtils.changeAnglesDirection(serializedFace);
}
facesList.pushMap(serializedFace);
}
return facesList;
}
}

View File

@ -0,0 +1,267 @@
package org.reactnative.camera.tasks;
import android.graphics.Rect;
import android.util.Log;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.WritableArray;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.uimanager.ThemedReactContext;
import com.google.android.cameraview.CameraView;
import com.google.android.gms.tasks.OnFailureListener;
import com.google.android.gms.tasks.OnSuccessListener;
import com.google.firebase.ml.vision.FirebaseVision;
import com.google.firebase.ml.vision.common.FirebaseVisionImage;
import com.google.firebase.ml.vision.common.FirebaseVisionImageMetadata;
import com.google.firebase.ml.vision.text.FirebaseVisionText;
import com.google.firebase.ml.vision.text.FirebaseVisionTextRecognizer;
import org.reactnative.camera.utils.ImageDimensions;
import java.util.List;
public class TextRecognizerAsyncTask extends android.os.AsyncTask<Void, Void, Void> {
private TextRecognizerAsyncTaskDelegate mDelegate;
private ThemedReactContext mThemedReactContext;
private byte[] mImageData;
private int mWidth;
private int mHeight;
private int mRotation;
private double mScaleX;
private double mScaleY;
private ImageDimensions mImageDimensions;
private int mPaddingLeft;
private int mPaddingTop;
private String TAG = "RNCamera";
public TextRecognizerAsyncTask(
TextRecognizerAsyncTaskDelegate delegate,
ThemedReactContext themedReactContext,
byte[] imageData,
int width,
int height,
int rotation,
float density,
int facing,
int viewWidth,
int viewHeight,
int viewPaddingLeft,
int viewPaddingTop
) {
mDelegate = delegate;
mImageData = imageData;
mWidth = width;
mHeight = height;
mRotation = rotation;
mImageDimensions = new ImageDimensions(width, height, rotation, facing);
mScaleX = (double) (viewWidth) / (mImageDimensions.getWidth() * density);
mScaleY = (double) (viewHeight) / (mImageDimensions.getHeight() * density);
mPaddingLeft = viewPaddingLeft;
mPaddingTop = viewPaddingTop;
}
@Override
protected Void doInBackground(Void... ignored) {
if (isCancelled() || mDelegate == null) {
return null;
}
FirebaseVisionImageMetadata metadata = new FirebaseVisionImageMetadata.Builder()
.setWidth(mWidth)
.setHeight(mHeight)
.setFormat(FirebaseVisionImageMetadata.IMAGE_FORMAT_YV12)
.setRotation(getFirebaseRotation())
.build();
FirebaseVisionTextRecognizer detector = FirebaseVision.getInstance().getOnDeviceTextRecognizer();
FirebaseVisionImage image = FirebaseVisionImage.fromByteArray(mImageData, metadata);
detector.processImage(image)
.addOnSuccessListener(new OnSuccessListener<FirebaseVisionText>() {
@Override
public void onSuccess(FirebaseVisionText firebaseVisionText) {
List<FirebaseVisionText.TextBlock> textBlocks = firebaseVisionText.getTextBlocks();
WritableArray serializedData = serializeEventData(textBlocks);
mDelegate.onTextRecognized(serializedData);
mDelegate.onTextRecognizerTaskCompleted();
}
})
.addOnFailureListener(
new OnFailureListener() {
@Override
public void onFailure(Exception e) {
Log.e(TAG, "Text recognition task failed" + e);
mDelegate.onTextRecognizerTaskCompleted();
}
});
return null;
}
private int getFirebaseRotation(){
int result;
switch (mRotation) {
case 0:
result = FirebaseVisionImageMetadata.ROTATION_0;
break;
case 90:
result = FirebaseVisionImageMetadata.ROTATION_90;
break;
case 180:
result = FirebaseVisionImageMetadata.ROTATION_180;
break;
case -90:
result = FirebaseVisionImageMetadata.ROTATION_270;
break;
default:
result = FirebaseVisionImageMetadata.ROTATION_0;
Log.e(TAG, "Bad rotation value: " + mRotation);
}
return result;
}
private WritableArray serializeEventData(List<FirebaseVisionText.TextBlock> textBlocks) {
WritableArray textBlocksList = Arguments.createArray();
for (FirebaseVisionText.TextBlock block: textBlocks) {
WritableMap serializedTextBlock = serializeBloc(block);
if (mImageDimensions.getFacing() == CameraView.FACING_FRONT) {
serializedTextBlock = rotateTextX(serializedTextBlock);
}
textBlocksList.pushMap(serializedTextBlock);
}
return textBlocksList;
}
private WritableMap serializeBloc(FirebaseVisionText.TextBlock block) {
WritableMap encodedText = Arguments.createMap();
WritableArray lines = Arguments.createArray();
for (FirebaseVisionText.Line line : block.getLines()) {
lines.pushMap(serializeLine(line));
}
encodedText.putArray("components", lines);
encodedText.putString("value", block.getText());
WritableMap bounds = processBounds(block.getBoundingBox());
encodedText.putMap("bounds", bounds);
encodedText.putString("type", "block");
return encodedText;
}
private WritableMap serializeLine(FirebaseVisionText.Line line) {
WritableMap encodedText = Arguments.createMap();
WritableArray lines = Arguments.createArray();
for (FirebaseVisionText.Element element : line.getElements()) {
lines.pushMap(serializeElement(element));
}
encodedText.putArray("components", lines);
encodedText.putString("value", line.getText());
WritableMap bounds = processBounds(line.getBoundingBox());
encodedText.putMap("bounds", bounds);
encodedText.putString("type", "line");
return encodedText;
}
private WritableMap serializeElement(FirebaseVisionText.Element element) {
WritableMap encodedText = Arguments.createMap();
encodedText.putString("value", element.getText());
WritableMap bounds = processBounds(element.getBoundingBox());
encodedText.putMap("bounds", bounds);
encodedText.putString("type", "element");
return encodedText;
}
private WritableMap processBounds(Rect frame) {
WritableMap origin = Arguments.createMap();
int x = frame.left;
int y = frame.top;
if (frame.left < mWidth / 2) {
x = x + mPaddingLeft / 2;
} else if (frame.left > mWidth /2) {
x = x - mPaddingLeft / 2;
}
if (frame.top < mHeight / 2) {
y = y + mPaddingTop / 2;
} else if (frame.top > mHeight / 2) {
y = y - mPaddingTop / 2;
}
origin.putDouble("x", x * mScaleX);
origin.putDouble("y", y * mScaleY);
WritableMap size = Arguments.createMap();
size.putDouble("width", frame.width() * mScaleX);
size.putDouble("height", frame.height() * mScaleY);
WritableMap bounds = Arguments.createMap();
bounds.putMap("origin", origin);
bounds.putMap("size", size);
return bounds;
}
private WritableMap rotateTextX(WritableMap text) {
ReadableMap faceBounds = text.getMap("bounds");
ReadableMap oldOrigin = faceBounds.getMap("origin");
WritableMap mirroredOrigin = positionMirroredHorizontally(
oldOrigin, mImageDimensions.getWidth(), mScaleX);
double translateX = -faceBounds.getMap("size").getDouble("width");
WritableMap translatedMirroredOrigin = positionTranslatedHorizontally(mirroredOrigin, translateX);
WritableMap newBounds = Arguments.createMap();
newBounds.merge(faceBounds);
newBounds.putMap("origin", translatedMirroredOrigin);
text.putMap("bounds", newBounds);
ReadableArray oldComponents = text.getArray("components");
WritableArray newComponents = Arguments.createArray();
for (int i = 0; i < oldComponents.size(); ++i) {
WritableMap component = Arguments.createMap();
component.merge(oldComponents.getMap(i));
rotateTextX(component);
newComponents.pushMap(component);
}
text.putArray("components", newComponents);
return text;
}
public static WritableMap positionTranslatedHorizontally(ReadableMap position, double translateX) {
WritableMap newPosition = Arguments.createMap();
newPosition.merge(position);
newPosition.putDouble("x", position.getDouble("x") + translateX);
return newPosition;
}
public static WritableMap positionMirroredHorizontally(ReadableMap position, int containerWidth, double scaleX) {
WritableMap newPosition = Arguments.createMap();
newPosition.merge(position);
newPosition.putDouble("x", valueMirroredHorizontally(position.getDouble("x"), containerWidth, scaleX));
return newPosition;
}
public static double valueMirroredHorizontally(double elementX, int containerWidth, double scaleX) {
double originalX = elementX / scaleX;
double mirroredX = containerWidth - originalX;
return mirroredX * scaleX;
}
}

View File

@ -0,0 +1,74 @@
package org.reactnative.facedetector;
import org.reactnative.facedetector.tasks.FileFaceDetectionAsyncTask;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReadableMap;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import javax.annotation.Nullable;
public class FaceDetectorModule extends ReactContextBaseJavaModule {
private static final String TAG = "RNFaceDetector";
// private ScopedContext mScopedContext;
private static ReactApplicationContext mScopedContext;
public FaceDetectorModule(ReactApplicationContext reactContext) {
super(reactContext);
mScopedContext = reactContext;
}
@Override
public String getName() {
return TAG;
}
@Nullable
@Override
public Map<String, Object> getConstants() {
return Collections.unmodifiableMap(new HashMap<String, Object>() {
{
put("Mode", getFaceDetectionModeConstants());
put("Landmarks", getFaceDetectionLandmarksConstants());
put("Classifications", getFaceDetectionClassificationsConstants());
}
private Map<String, Object> getFaceDetectionModeConstants() {
return Collections.unmodifiableMap(new HashMap<String, Object>() {
{
put("fast", RNFaceDetector.FAST_MODE);
put("accurate", RNFaceDetector.ACCURATE_MODE);
}
});
}
private Map<String, Object> getFaceDetectionClassificationsConstants() {
return Collections.unmodifiableMap(new HashMap<String, Object>() {
{
put("all", RNFaceDetector.ALL_CLASSIFICATIONS);
put("none", RNFaceDetector.NO_CLASSIFICATIONS);
}
});
}
private Map<String, Object> getFaceDetectionLandmarksConstants() {
return Collections.unmodifiableMap(new HashMap<String, Object>() {
{
put("all", RNFaceDetector.ALL_LANDMARKS);
put("none", RNFaceDetector.NO_LANDMARKS);
}
});
}
});
}
@ReactMethod
public void detectFaces(ReadableMap options, final Promise promise) {
new FileFaceDetectionAsyncTask(mScopedContext, options, promise).execute();
}
}

View File

@ -0,0 +1,166 @@
package org.reactnative.facedetector;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.WritableMap;
import com.google.firebase.ml.vision.common.FirebaseVisionPoint;
import com.google.firebase.ml.vision.face.FirebaseVisionFace;
import com.google.firebase.ml.vision.face.FirebaseVisionFaceLandmark;
public class FaceDetectorUtils {
private static final String[] landmarkNames = {
"bottomMouthPosition", "leftCheekPosition", "leftEarPosition",
"leftEyePosition", "leftMouthPosition", "noseBasePosition", "rightCheekPosition",
"rightEarPosition", "rightEyePosition", "rightMouthPosition"
};
public static WritableMap serializeFace(FirebaseVisionFace face) {
return serializeFace(face, 1, 1, 0, 0, 0, 0);
}
public static WritableMap serializeFace(FirebaseVisionFace face, double scaleX, double scaleY, int width, int height, int paddingLeft, int paddingTop) {
WritableMap encodedFace = Arguments.createMap();
int id = 0;
// If face tracking was enabled:
if (face.getTrackingId() != FirebaseVisionFace.INVALID_ID) {
id = face.getTrackingId();
}
encodedFace.putInt("faceID", id);
encodedFace.putDouble("rollAngle", face.getHeadEulerAngleZ());
encodedFace.putDouble("yawAngle", face.getHeadEulerAngleY());
// If classification was enabled:
if (face.getSmilingProbability() != FirebaseVisionFace.UNCOMPUTED_PROBABILITY) {
encodedFace.putDouble("smilingProbability", face.getSmilingProbability());
}
if (face.getLeftEyeOpenProbability() != FirebaseVisionFace.UNCOMPUTED_PROBABILITY) {
encodedFace.putDouble("leftEyeOpenProbability", face.getLeftEyeOpenProbability());
}
if (face.getRightEyeOpenProbability() != FirebaseVisionFace.UNCOMPUTED_PROBABILITY) {
encodedFace.putDouble("rightEyeOpenProbability", face.getRightEyeOpenProbability());
}
int[] landmarks = {
FirebaseVisionFaceLandmark.MOUTH_BOTTOM,
FirebaseVisionFaceLandmark.LEFT_CHEEK,
FirebaseVisionFaceLandmark.LEFT_EAR,
FirebaseVisionFaceLandmark.LEFT_EYE,
FirebaseVisionFaceLandmark.MOUTH_LEFT,
FirebaseVisionFaceLandmark.NOSE_BASE,
FirebaseVisionFaceLandmark.RIGHT_CHEEK,
FirebaseVisionFaceLandmark.RIGHT_EAR,
FirebaseVisionFaceLandmark.RIGHT_EYE,
FirebaseVisionFaceLandmark.MOUTH_RIGHT};
for (int i = 0; i < landmarks.length; ++i) {
FirebaseVisionFaceLandmark landmark = face.getLandmark(landmarks[i]);
if (landmark != null) {
encodedFace.putMap(landmarkNames[i], mapFromPoint(landmark.getPosition(), scaleX, scaleY, width, height, paddingLeft, paddingTop));
}
}
WritableMap origin = Arguments.createMap();
Float x = face.getBoundingBox().exactCenterX() - (face.getBoundingBox().width() / 2 );
Float y = face.getBoundingBox().exactCenterY() - (face.getBoundingBox().height() / 2);
if (face.getBoundingBox().exactCenterX() < width / 2) {
x = x + paddingLeft / 2;
} else if (face.getBoundingBox().exactCenterX() > width / 2) {
x = x - paddingLeft / 2;
}
if (face.getBoundingBox().exactCenterY() < height / 2) {
y = y + paddingTop / 2;
} else if (face.getBoundingBox().exactCenterY() > height / 2) {
y = y - paddingTop / 2;
}
origin.putDouble("x", x * scaleX);
origin.putDouble("y", y * scaleY);
WritableMap size = Arguments.createMap();
size.putDouble("width", face.getBoundingBox().width() * scaleX);
size.putDouble("height", face.getBoundingBox().height() * scaleY);
WritableMap bounds = Arguments.createMap();
bounds.putMap("origin", origin);
bounds.putMap("size", size);
encodedFace.putMap("bounds", bounds);
return encodedFace;
}
public static WritableMap rotateFaceX(WritableMap face, int sourceWidth, double scaleX) {
ReadableMap faceBounds = face.getMap("bounds");
ReadableMap oldOrigin = faceBounds.getMap("origin");
WritableMap mirroredOrigin = positionMirroredHorizontally(oldOrigin, sourceWidth, scaleX);
double translateX = -faceBounds.getMap("size").getDouble("width");
WritableMap translatedMirroredOrigin = positionTranslatedHorizontally(mirroredOrigin, translateX);
WritableMap newBounds = Arguments.createMap();
newBounds.merge(faceBounds);
newBounds.putMap("origin", translatedMirroredOrigin);
for (String landmarkName : landmarkNames) {
ReadableMap landmark = face.hasKey(landmarkName) ? face.getMap(landmarkName) : null;
if (landmark != null) {
WritableMap mirroredPosition = positionMirroredHorizontally(landmark, sourceWidth, scaleX);
face.putMap(landmarkName, mirroredPosition);
}
}
face.putMap("bounds", newBounds);
return face;
}
public static WritableMap changeAnglesDirection(WritableMap face) {
face.putDouble("rollAngle", (-face.getDouble("rollAngle") + 360) % 360);
face.putDouble("yawAngle", (-face.getDouble("yawAngle") + 360) % 360);
return face;
}
public static WritableMap mapFromPoint(FirebaseVisionPoint point, double scaleX, double scaleY, int width, int height, int paddingLeft, int paddingTop) {
WritableMap map = Arguments.createMap();
Float x = point.getX();
Float y = point.getY();
if (point.getX() < width / 2) {
x = (x + paddingLeft / 2);
} else if (point.getX() > width / 2) {
x = (x - paddingLeft / 2);
}
if (point.getY() < height / 2) {
y = (y + paddingTop / 2);
} else if (point.getY() > height / 2) {
y = (y - paddingTop / 2);
}
map.putDouble("x", x * scaleX);
map.putDouble("y", y * scaleY);
return map;
}
public static WritableMap positionTranslatedHorizontally(ReadableMap position, double translateX) {
WritableMap newPosition = Arguments.createMap();
newPosition.merge(position);
newPosition.putDouble("x", position.getDouble("x") + translateX);
return newPosition;
}
public static WritableMap positionMirroredHorizontally(ReadableMap position, int containerWidth, double scaleX) {
WritableMap newPosition = Arguments.createMap();
newPosition.merge(position);
newPosition.putDouble("x", valueMirroredHorizontally(position.getDouble("x"), containerWidth, scaleX));
return newPosition;
}
public static double valueMirroredHorizontally(double elementX, int containerWidth, double scaleX) {
double originalX = elementX / scaleX;
double mirroredX = containerWidth - originalX;
return mirroredX * scaleX;
}
}

View File

@ -0,0 +1,97 @@
package org.reactnative.facedetector;
import android.content.Context;
import android.util.Log;
import com.google.firebase.ml.vision.FirebaseVision;
import com.google.firebase.ml.vision.face.FirebaseVisionFaceDetector;
import com.google.firebase.ml.vision.face.FirebaseVisionFaceDetectorOptions;
public class RNFaceDetector {
public static int ALL_CLASSIFICATIONS = FirebaseVisionFaceDetectorOptions.ALL_CLASSIFICATIONS;
public static int NO_CLASSIFICATIONS = FirebaseVisionFaceDetectorOptions.NO_CLASSIFICATIONS;
public static int ALL_LANDMARKS = FirebaseVisionFaceDetectorOptions.ALL_LANDMARKS;
public static int NO_LANDMARKS = FirebaseVisionFaceDetectorOptions.NO_LANDMARKS;
public static int ACCURATE_MODE = FirebaseVisionFaceDetectorOptions.ACCURATE;
public static int FAST_MODE = FirebaseVisionFaceDetectorOptions.FAST;
// TODO contours detection is possible for MLKit-based face detector, implement this feature
public static int ALL_CONTOURS = FirebaseVisionFaceDetectorOptions.ALL_CONTOURS;
public static int NO_CONTOURS = FirebaseVisionFaceDetectorOptions.NO_CONTOURS;
private FirebaseVisionFaceDetector mFaceDetector = null;
private FirebaseVisionFaceDetectorOptions.Builder mBuilder;
private int mClassificationType = NO_CLASSIFICATIONS;
private int mLandmarkType = NO_LANDMARKS;
private float mMinFaceSize = 0.15f;
private int mMode = FAST_MODE;
public RNFaceDetector(Context context) {
mBuilder = new FirebaseVisionFaceDetectorOptions.Builder()
.setPerformanceMode(mMode)
.setLandmarkMode(mLandmarkType)
.setClassificationMode(mClassificationType)
.setMinFaceSize(mMinFaceSize);
}
public boolean isOperational() {
// Legacy api from GMV
return true;
}
public FirebaseVisionFaceDetector getDetector() {
if (mFaceDetector == null) {
createFaceDetector();
}
return mFaceDetector;
}
public void setClassificationType(int classificationType) {
if (classificationType != mClassificationType) {
release();
mBuilder.setClassificationMode(classificationType);
mClassificationType = classificationType;
}
}
public void setLandmarkType(int landmarkType) {
if (landmarkType != mLandmarkType) {
release();
mBuilder.setLandmarkMode(landmarkType);
mLandmarkType = landmarkType;
}
}
public void setMode(int mode) {
if (mode != mMode) {
release();
mBuilder.setPerformanceMode(mode);
mMode = mode;
}
}
public void setTracking(boolean tracking) {
release();
if (tracking) {
mBuilder.enableTracking();
}
}
public void release() {
if (mFaceDetector != null) {
try {
mFaceDetector.close();
} catch (Exception e) {
Log.e("RNCamera", "Attempt to close FaceDetector failed");
}
mFaceDetector = null;
}
}
private void createFaceDetector() {
FirebaseVisionFaceDetectorOptions options = mBuilder.build();
mFaceDetector = FirebaseVision.getInstance().getVisionFaceDetector(options);
}
}

View File

@ -0,0 +1,167 @@
package org.reactnative.facedetector.tasks;
import android.content.Context;
import androidx.exifinterface.media.ExifInterface;
import android.net.Uri;
import android.os.AsyncTask;
import android.util.Log;
import org.reactnative.facedetector.RNFaceDetector;
import org.reactnative.facedetector.FaceDetectorUtils;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.WritableArray;
import com.facebook.react.bridge.WritableMap;
import com.google.android.gms.tasks.OnFailureListener;
import com.google.android.gms.tasks.OnSuccessListener;
import com.google.firebase.ml.vision.common.FirebaseVisionImage;
import com.google.firebase.ml.vision.face.FirebaseVisionFace;
import com.google.firebase.ml.vision.face.FirebaseVisionFaceDetector;
import java.io.File;
import java.io.IOException;
import java.util.List;
public class FileFaceDetectionAsyncTask extends AsyncTask<Void, Void, Void> {
private static final String ERROR_TAG = "E_FACE_DETECTION_FAILED";
private static final String MODE_OPTION_KEY = "mode";
private static final String DETECT_LANDMARKS_OPTION_KEY = "detectLandmarks";
private static final String RUN_CLASSIFICATIONS_OPTION_KEY = "runClassifications";
private String mUri;
private String mPath;
private Promise mPromise;
private int mWidth = 0;
private int mHeight = 0;
private Context mContext;
private ReadableMap mOptions;
private int mOrientation = ExifInterface.ORIENTATION_UNDEFINED;
private RNFaceDetector mRNFaceDetector;
public FileFaceDetectionAsyncTask(Context context, ReadableMap options, Promise promise) {
mUri = options.getString("uri");
mPromise = promise;
mOptions = options;
mContext = context;
}
@Override
protected void onPreExecute() {
if (mUri == null) {
mPromise.reject(ERROR_TAG, "You have to provide an URI of an image.");
cancel(true);
return;
}
Uri uri = Uri.parse(mUri);
mPath = uri.getPath();
if (mPath == null) {
mPromise.reject(ERROR_TAG, "Invalid URI provided: `" + mUri + "`.");
cancel(true);
return;
}
// We have to check if the requested image is in a directory safely accessible by our app.
boolean fileIsInSafeDirectories =
mPath.startsWith(mContext.getCacheDir().getPath()) || mPath.startsWith(mContext.getFilesDir().getPath());
if (!fileIsInSafeDirectories) {
mPromise.reject(ERROR_TAG, "The image has to be in the local app's directories.");
cancel(true);
return;
}
if(!new File(mPath).exists()) {
mPromise.reject(ERROR_TAG, "The file does not exist. Given path: `" + mPath + "`.");
cancel(true);
}
}
@Override
protected Void doInBackground(Void... voids) {
if (isCancelled()) {
return null;
}
mRNFaceDetector = detectorForOptions(mOptions, mContext);
try {
ExifInterface exif = new ExifInterface(mPath);
mOrientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED);
} catch (IOException e) {
Log.e(ERROR_TAG, "Reading orientation from file `" + mPath + "` failed.", e);
}
try {
FirebaseVisionImage image = FirebaseVisionImage.fromFilePath(mContext, Uri.parse(mUri));
FirebaseVisionFaceDetector detector = mRNFaceDetector.getDetector();
detector.detectInImage(image)
.addOnSuccessListener(
new OnSuccessListener<List<FirebaseVisionFace>>() {
@Override
public void onSuccess(List<FirebaseVisionFace> faces) {
serializeEventData(faces);
}
})
.addOnFailureListener(
new OnFailureListener() {
@Override
public void onFailure(Exception e) {
Log.e(ERROR_TAG, "Text recognition task failed", e);
mPromise.reject(ERROR_TAG, "Text recognition task failed", e);
}
});
} catch (IOException e) {
e.printStackTrace();
Log.e(ERROR_TAG, "Creating Firebase Image from uri" + mUri + "failed", e);
mPromise.reject(ERROR_TAG, "Creating Firebase Image from uri" + mUri + "failed", e);
}
return null;
}
private void serializeEventData(List<FirebaseVisionFace> faces) {
WritableMap result = Arguments.createMap();
WritableArray facesArray = Arguments.createArray();
for(FirebaseVisionFace face : faces) {
WritableMap encodedFace = FaceDetectorUtils.serializeFace(face);
encodedFace.putDouble("yawAngle", (-encodedFace.getDouble("yawAngle") + 360) % 360);
encodedFace.putDouble("rollAngle", (-encodedFace.getDouble("rollAngle") + 360) % 360);
facesArray.pushMap(encodedFace);
}
result.putArray("faces", facesArray);
WritableMap image = Arguments.createMap();
image.putInt("width", mWidth);
image.putInt("height", mHeight);
image.putInt("orientation", mOrientation);
image.putString("uri", mUri);
result.putMap("image", image);
mRNFaceDetector.release();
mPromise.resolve(result);
}
private static RNFaceDetector detectorForOptions(ReadableMap options, Context context) {
RNFaceDetector detector = new RNFaceDetector(context);
detector.setTracking(false);
if(options.hasKey(MODE_OPTION_KEY)) {
detector.setMode(options.getInt(MODE_OPTION_KEY));
}
if(options.hasKey(RUN_CLASSIFICATIONS_OPTION_KEY)) {
detector.setClassificationType(options.getInt(RUN_CLASSIFICATIONS_OPTION_KEY));
}
if(options.hasKey(DETECT_LANDMARKS_OPTION_KEY)) {
detector.setLandmarkType(options.getInt(DETECT_LANDMARKS_OPTION_KEY));
}
return detector;
}
}

View File

@ -1,48 +0,0 @@
version: 2
executorType: docker
jobs:
build:
resource_class: large
environment:
- GRADLE_OPTS: '-Dorg.gradle.jvmargs="-Xmx2048m -XX:+HeapDumpOnOutOfMemoryError"'
- REACT_NATIVE_MAX_WORKERS: 2
- ANDROID_BUILD_TOOLS_VERSION: '26.0.2'
working_directory: ~/app
docker:
- image: entria/react-native-android:0.1.82
steps:
- checkout
- restore_cache:
keys:
- v1-npm-{{ .Branch }}-{{ checksum "yarn.lock" }}
- v1-npm
- run:
name: Install Dependencies
command: yarn install --ignore-engines
- run:
name: Lint
command: yarn lint
- run:
name: Run Checks
command: |
cd android
chmod +x ./gradlew && ./gradlew check
- run:
name: Build Sample App
command: |
cd examples/basic/android
yarn
chmod +x ./gradlew && ./gradlew build
- deploy:
command: |
if [ "${CIRCLE_BRANCH}" == "master" ]; then
yarn ci:publish
fi
- save_cache:
key: v1-npm
paths:
- node_modules/
- save_cache:
key: v1-npm-{{ .Branch }}-{{ checksum "yarn.lock" }}
paths:
- node_modules/

17
docker-compose.yml Normal file
View File

@ -0,0 +1,17 @@
version: "3"
services:
docusaurus:
build: .
ports:
- 3000:3000
- 35729:35729
volumes:
- ./docs:/app/docs
- ./website/core:/app/website/core
- ./website/i18n:/app/website/i18n
- ./website/pages:/app/website/pages
- ./website/static:/app/website/static
- ./website/sidebars.json:/app/website/sidebars.json
- ./website/siteConfig.js:/app/website/siteConfig.js
working_dir: /app/website

408
docs/API.md Normal file
View File

@ -0,0 +1,408 @@
---
id: api
title: Work in progress
---
## Props Index
[**wip**]
- [`zoom`](API.md#zoom)
- [`maxZoom`](API.md#maxzoom)
- [`type`](API.md#type)
- [`cameraId`](API.md#cameraid)
- [`flashMode`](API.md#flashmode)
- [`exposure`](API.md#exposure)
- [`whiteBalance`](API.md#whiteBalance)
- [`autoFocus`](API.md#autoFocus)
- [`ratio`](API.md#ratio)
- [`pictureSize`](API.md#pictureSize)
- [`focusDepth`](API.md#focusDepth)
- [`onMountError`](API.md#onMountError)
- [`onCameraReady`](API.md#onCameraReady)
## Methods Index
- [`takePictureAsync`](API.md#takepictureasync)
- [`recordAsync`](API.md#recordasync)
- [`refreshAuthorizationStatus`](API.md#refreshauthorizationstatus)
- [`stopRecording`](API.md#stoprecording)
- [`pausePreview`](API.md#pausepreview)
- [`resumePreview`](API.md#resumepreview)
- [`getAvailablePictureSizes`](API.md#getavailablepicturesizes)
- [`getSupportedRatiosAsync`](API.md#getsupportedratiosasync-android-only)
- [`isRecording`](API.md#isrecording-ios-only)
- [`getSupportedPreviewFpsRange`](API.md#getsupportedpreviewfpsrange-android-only)
## Props
---
### `zoom`
This property specifies the zoom value of the camera. Ranges from 0 to 1. Default to 0.
| Type | Default Value |
| ------ | ------------- |
| number | 0 |
---
### `maxZoom`
The maximum zoom value of the camera. Defaults to 0.
| Type | Default Value |
| ------ | ------------- |
| number | 0 |
---
### `type`
This property defines which camera on the phone the component is using.
Possible values:
- `front`
- `back`
| Type | Default Value |
| ------ | ------------- |
| number | 'back' |
---
### `cameraId`
For selecting from multiple cameras on Android devices. See [2492](https://github.com/react-native-community/react-native-camera/pull/2492) for more info. Can be retrieved with `getCameraIds()`
| Type | Default Value | Platform |
| ------ | ------------- | -------- |
| String | `null` | Android |
---
### `flashMode`
Determines the state of the camera flash. Has the following possible states.
```off: '1',
on: 'auto',
auto: 'torch',
torch: 'off'
```
| Type | Default Value |
| ------ | ------------- |
| object | `{ off: 1 }` |
### `ratio`
A string representing the camera ratio in the format 'height:width'. Default is `"4:3"`.
Use `getSupportedRatiosAsync` method to get ratio strings supported by your camera on Android.
| Type | Default Value |
| ------ | ------------- |
| string | `4:3` |
### `pictureSize`
This prop has a different behaviour for Android and iOS and should rarely be set.
For Android, this prop attempts to control the camera sensor capture resolution, similar to how `ratio` behaves. This is useful for cases where a low resolution image is required, and makes further resizing less intensive on the device's memory. The list of possible values can be requested with `getAvailablePictureSizes`, and the value should be set in the format of `<width>x<height>`. Internally, the native code will attempt to get the best suited resolution for the given `pictureSize` value if the provided value is invalid, and will default to the highest resolution available.
For iOS, this prop controls the internal camera preset value and should rarely be changed. However, this value can be set to setup the sensor to match the video recording's quality in order to prevent flickering. The list of valid values can be gathered from https://developer.apple.com/documentation/avfoundation/avcapturesessionpreset and can also be requested with `getAvailablePictureSizes`.
| Type | Default Value |
| ------ | ------------- |
| string | `None` |
## Methods
## takePictureAsync()
Returns a promise with TakePictureResponse.
### Method type
```ts
takePictureAsync(options?: TakePictureOptions): Promise<TakePictureResponse>;
```
```ts
interface TakePictureOptions {
quality?: number;
orientation?: keyof Orientation | OrientationNumber;
base64?: boolean;
exif?: boolean;
width?: number;
mirrorImage?: boolean;
doNotSave?: boolean;
pauseAfterCapture?: boolean;
writeExif?: boolean | { [name: string]: any };
/** Android only */
fixOrientation?: boolean;
/** iOS only */
forceUpOrientation?: boolean;
}
interface TakePictureResponse {
width: number;
height: number;
uri: string;
base64?: string;
exif?: { [name: string]: any };
pictureOrientation: number;
deviceOrientation: number;
}
```
### Usage example
```js
takePicture = async () => {
if (this.camera) {
const data = await this.camera.takePictureAsync();
console.warn('takePictureResponse ', data);
}
};
```
---
## recordAsync()
Returns a promise with RecordResponse.
### Method type
```ts
recordAsync(options?: RecordOptions): Promise<RecordResponse>;
```
```ts
interface RecordOptions {
quality?: keyof VideoQuality;
orientation?: keyof Orientation | OrientationNumber;
maxDuration?: number;
maxFileSize?: number;
mute?: boolean;
mirrorVideo?: boolean;
path?: string;
videoBitrate?: number;
fps?: number;
/** iOS only */
codec?: keyof VideoCodec | VideoCodec[keyof VideoCodec];
}
interface RecordResponse {
/** Path to the video saved on your app's cache directory. */
uri: string;
videoOrientation: number;
deviceOrientation: number;
isRecordingInterrupted: boolean;
/** iOS only */
codec: VideoCodec[keyof VideoCodec];
}
```
### Usage example
```js
takeVideo = async () => {
if (this.camera) {
try {
const promise = this.camera.recordAsync(this.state.recordOptions);
if (promise) {
this.setState({ isRecording: true });
const data = await promise;
this.setState({ isRecording: false });
console.warn('takeVideo', data);
}
} catch (e) {
console.error(e);
}
}
};
```
---
## refreshAuthorizationStatus()
Allows to make RNCamera check Permissions again and set status accordingly.
Making it possible to refresh status of RNCamera after user initially rejected the permissions.
### Method type
```ts
refreshAuthorizationStatus(): Promise<void>;
```
### Usage example
```js
/* -> {
} */
```
---
## stopRecording()
Should be called after recordAsync() to make the promise be fulfilled and get the video uri.
### Method type
```ts
stopRecording(): void;
```
### Usage example
```js
stopRecording(): void;
/* -> {
} */
```
---
## pausePreview()
Pauses the preview. The preview can be resumed again by using resumePreview().
### Method type
```ts
pausePreview(): void;
```
### Usage example
```js
/* -> {
} */
```
---
## resumePreview()
Resumes the preview after pausePreview() has been called.
### Method type
```ts
resumePreview(): void;
```
### Usage example
```js
/* -> {
} */
```
---
## getAvailablePictureSizes()
Returns a promise with getAvailablePictureSizes.
### Method type
```ts
getAvailablePictureSizes(): Promise<string[]>;
```
### Usage example
```js
/* -> {
} */
```
---
## getSupportedRatiosAsync() - Android only
Android only. Returns a promise. The promise will be fulfilled with an object with an array containing strings with all camera aspect ratios supported by the device.
### Method type
```ts
getSupportedRatiosAsync(): Promise<string[]>;
```
### Usage example
```js
/* -> {
} */
```
---
## isRecording() - iOS only
iOS only. Returns a promise. The promise will be fulfilled with a boolean indicating if currently recording is started or stopped.
### Method type
```ts
isRecording(): Promise<boolean>;
```
### Usage example
```js
const isRecording = await isRecording();
/* -> {
isRecording = true
} */
```
- [`getSupportedPreviewFpsRange`](API.md#getSupportedPreviewFpsRange`)
## getSupportedPreviewFpsRange - Android only
Android only. Returns a promise. The promise will be fulfilled with a json object including the fps ranges available for those devices ([android docs](<https://developer.android.com/reference/android/hardware/Camera.Parameters#getSupportedPreviewFpsRange()>))
### Method type
```ts
getSupportedPreviewFpsRange(): Promise<[{MINIMUM_FPS: string, MAXIMUM_FPS: string}]>;
```
### Usage example
```js
const previewRange = await this.camera.getSupportedPreviewFpsRange();
/* -> [
{
MINIMUM_FPS: "15000",
MAXIMUM_FPS: "15000"
},
{
MINIMUM_FPS: "20000",
MAXIMUM_FPS: "20000"
}
] */
```
---

101
docs/AndroidXMigration.md Normal file
View File

@ -0,0 +1,101 @@
# AndroidX Migration
AndroidX is the replacement for Google Support Libraries. It is the open-source project that the Android team uses to
develop, test, package, version and release libraries within Jetpack. Moving forward, all new Android development
will be in AndroidX, the Support Libraries are depreciated.
> AndroidX is a major improvement to the original Android Support Library. Like the Support Library, AndroidX ships separately from the Android OS and provides backwards-compatibility across Android releases. AndroidX fully replaces the Support Library by providing feature parity and new libraries.
See: https://developer.android.com/jetpack/androidx/
## Migration via Android studio
You can follow the instructions [here](https://developer.android.com/jetpack/androidx/migrate) to migrate you existing
project.
## Manual
#### Update the android section `android/app/build.gradle` to
```
android {
compileSdkVersion 28
buildToolsVersion "28.0.3"
defaultConfig {
...
minSdkVersion 16
targetSdkVersion 28
}
...
```
If you have any `dependencies {` that are using the old Google Support Libraries, you'll need to update them
to use the androidx version. Can check the full migration list [here](https://developer.android.com/jetpack/androidx/migrate).
#### Update `android/app/src/main/AndroidManifest.xml`
remove
```xml
<uses-sdk android:minSdkVersion="16" android:targetSdkVersion="26" />
```
#### Update `android/build.gradle`
```
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.2.1'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
mavenLocal()
google()
jcenter()
maven { url "https://jitpack.io" }
maven {
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
url "$rootDir/../node_modules/react-native/android"
}
}
}
ext {
compileSdkVersion = 28
buildToolsVersion = '28.0.3'
}
subprojects { subproject ->
afterEvaluate{
if((subproject.plugins.hasPlugin('android') || subproject.plugins.hasPlugin('android-library'))) {
android {
compileSdkVersion rootProject.ext.compileSdkVersion
buildToolsVersion rootProject.ext.buildToolsVersion
}
}
}
}
```
#### Update `android/gradle.properties`
add
```
android.enableJetifier = true;
android.useAndroidX = true;
```
#### Update `android/gradle/wrapper/gradle-wrapper.properties`
make sure your gradle `distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip`

11
docs/Contributing.md Normal file
View File

@ -0,0 +1,11 @@
---
id: contributing
title: Contributing
sidebar_label: Contributing
---
- Pull Requests are welcome, if you open a pull request we will do our best to get to it in a timely manner
- Pull Request Reviews are even more welcome! we need help testing, reviewing, and updating open PRs
- If you are interested in contributing more actively, please contact me (same username on Twitter, Facebook, etc.) Thanks!
- We are now on [Open Collective](https://opencollective.com/react-native-camera#sponsor)! Contributions are appreciated and will be used to fund core contributors. [more details](#open-collective)
- If you want to help us coding, join Expo slack https://slack.expo.io/, so we can chat over there. (#react-native-camera)

View File

@ -1,4 +1,8 @@
# Upgrade gradle for Android projects
---
id: GradleUpgradeGuide
title: Upgrade gradle for Android projects
sidebar_label: Gradle Upgrade Guide
---
To integrate react-native-camera into your own react native project and make it work for Android, you need to edit the following files in the `android` folder under your project folder:

View File

@ -1,11 +1,16 @@
## Q & A
---
id: qa
title: Q & A
sidebar_label: Q & A
---
- [meta-data android 26](#meta-data-android-26)
- [Manifest merger failed](#when-i-try-to-build-my-project-i-get-following-error)
- [How can I resize captured images?](#how-can-i-resize-captured-images)
- [How can I get thumbnails for my video?](#how-can-i-get-thumbnails-for-my-video)
- [How can I save my video/image to the camera roll?](#hoc-can-i-save-my-video-image-to-the-camera-roll)
#### meta-data android 26
## meta-data android 26
```
AndroidManifest.xml:25:13-35 Error:
@ -39,7 +44,7 @@ Add this to your AndroidManifest.xml:
---
#### When I try to build my project, I get following error:
## When I try to build my project, I get following error:
```
Execution failed for task ':app:processDebugManifest'.
@ -48,7 +53,7 @@ Execution failed for task ':app:processDebugManifest'.
Suggestion: add 'tools:replace="android:value"' to <meta-data> element at AndroidManifest.xml:23:9-25:38 to override.
```
#### As the error message hints `com.android.support:exifinterface:26.0.2` is already found in `com.android.support:support-v4:26.0.1`
## As the error message hints `com.android.support:exifinterface:26.0.2` is already found in `com.android.support:support-v4:26.0.1`
To fix this issue, modify your project's `android/app/build.gradle` as follows:
@ -75,25 +80,25 @@ dependencies {
---
#### How can I resize captured images?
## How can I resize captured images?
Currently, `RNCamera` does not allow for specifying the desired resolution of the captured image, nor does it natively expose any functionality to resize images.
One way to achieve this (without any additional dependencies )is using [react-native.ImageEditor.cropImage](https://facebook.github.io/react-native/docs/imageeditor.html#cropimage).
One way to achieve this (without any additional dependencies ) is using [react-native.ImageEditor.cropImage](https://facebook.github.io/react-native/docs/imageeditor.html#cropimage).
The strategy is:
1. Capture an image using `RNCamera`, which uses the device's max resolution.
2. Use `react-native.ImageEditor.cropImage()` to crop the image using the image's native size as the crop size (thus maintaiing the original image), and the desired new size as the `displaySize` attribute (thus resizing the image).
1. Capture an image using `RNCamera`, which uses the device's max resolution.
2. Use `react-native.ImageEditor.cropImage()` to crop the image using the image's native size as the crop size (thus maintaining the original image), and the desired new size as the `displaySize` attribute (thus resizing the image).
```javascript
import React, { Component } from 'react';
import React, { PureComponent } from 'react';
import { Button, ImageEditor } from 'react-native';
import { RNCamera } from 'react-native-camera';
class CameraComponent extends Component {
class CameraComponent extends PureComponent {
// ...
capturePicture = function () {
capturePicture = () => {
if (this.camera) {
// 1) Capture the image using RNCamera API
this.camera.takePictureAsync(options)
@ -137,6 +142,11 @@ class CameraComponent extends Component {
```
#### How can I get thumbnails for my video
## How can I get thumbnails for my video
We recommend using the library [`react-native-thumbnail`](https://github.com/phuochau/react-native-thumbnail) for generating thumbnails of your video files.
## How can I save my video/image to the camera roll?
You can use the [`CameraRoll` Module](https://facebook.github.io/react-native/docs/cameraroll.htm).
You must follow the setup instructions in the `react-native` documentation, since `CameraRoll` module needs to be linked first.

View File

@ -1,398 +0,0 @@
# RCTCamera
As of 1.0.0 release, RCTCamera is deprecated. Please use RNCamera for the latest fixes and improvements.
## Usage
All you need is to `import` `Camera` from the `react-native-camera` module and then use the
`<Camera/>` tag.
```javascript
'use strict';
import React, { Component } from 'react';
import { AppRegistry, Dimensions, StyleSheet, Text, TouchableHighlight, View } from 'react-native';
import Camera from 'react-native-camera';
class BadInstagramCloneApp extends Component {
_requestPermissions = async () => {
if (Platform.OS === 'android') {
const result = await PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.CAMERA)
return result === PermissionsAndroid.RESULTS.GRANTED || result === true
}
return true
}
_takePicture = async () => {
if (this.camera) {
const options = { quality: 0.5, base64: true }
const data = await this.camera.takePictureAsync(options)
console.log(data.uri)
}
}
_onBarCodeRead = (e) => {
console.log(`Barcode Found! Type: ${e.type}\nData: ${e.data}`)
}
componentDidMount = () => {
({ _, status }) => {
if (status !== 'PERMISSION_GRANTED') {
this._requestPermissions()
}
}
}
render() {
return (
<View style={styles.container}>
<Camera
ref={(ref) => {
this.camera = ref;
}}
onBarCodeRead={(e) => this._onBarCodeRead(e)}
style={styles.preview}>
<Text style={styles.capture} onPress={() => this._takePicture()}>[CAPTURE]</Text>
</Camera>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'column',
backgroundColor: 'black'
},
preview: {
flex: 1,
justifyContent: 'flex-end',
alignItems: 'center'
},
capture: {
flex: 0,
backgroundColor: '#fff',
borderRadius: 5,
padding: 15,
paddingHorizontal: 20,
alignSelf: 'center',
margin: 20
}
});
AppRegistry.registerComponent('BadInstagramCloneApp', () => BadInstagramCloneApp);
```
## Properties
#### `aspect`
Values: `Camera.constants.Aspect.fit` or `"fit"`, `Camera.constants.Aspect.fill` or `"fill"` (default), `Camera.constants.Aspect.stretch` or `"stretch"`
The `aspect` property allows you to define how your viewfinder renders the camera's view. For instance, if you have a square viewfinder and you want to fill it entirely, you have two options: `"fill"`, where the aspect ratio of the camera's view is preserved by cropping the view or `"stretch"`, where the aspect ratio is skewed in order to fit the entire image inside the viewfinder. The other option is `"fit"`, which ensures the camera's entire view fits inside your viewfinder without altering the aspect ratio.
#### `cropToPreview`
Values: `true` or `false` (default)
Will crop the captured image to match the content that is displayed in the preview view. Works on both `Android` and `iOS`. Will be ignored if `captureMode` is other then `Camera.constants.CaptureMode.still`.
#### `iOS` `captureAudio`
Values: `true` (Boolean), `false` (default)
_Applies to video capture mode only._ Specifies whether or not audio should be captured with the video.
#### `captureMode`
Values: `Camera.constants.CaptureMode.still` (default), `Camera.constants.CaptureMode.video`
The type of capture that will be performed by the camera - either a still image or video.
#### `captureTarget`
Values: `Camera.constants.CaptureTarget.cameraRoll` (default), `Camera.constants.CaptureTarget.disk`, `Camera.constants.CaptureTarget.temp`, ~~`Camera.constants.CaptureTarget.memory`~~ (deprecated),
This property allows you to specify the target output of the captured image data. The disk output has been shown to improve capture response time, so that is the recommended value. When using the deprecated memory output, the image binary is sent back as a base64-encoded string.
#### `captureQuality`
Values: `Camera.constants.CaptureQuality.high` or `"high"` (default), `Camera.constants.CaptureQuality.medium` or `"medium"`, `Camera.constants.CaptureQuality.low` or `"low"`, `Camera.constants.CaptureQuality.photo` or `"photo"`, `Camera.constants.CaptureQuality["1080p"]` or `"1080p"`, `Camera.constants.CaptureQuality["720p"]` or `"720p"`, `Camera.constants.CaptureQuality["480p"]` or `"480p"`.
This property allows you to specify the quality output of the captured image or video. By default the quality is set to high.
When choosing more-specific quality settings (1080p, 720p, 480p), note that each platform and device supports different valid picture/video sizes, and actual resolution within each of these quality settings might differ. There should not be too much variance (if any) for iOS; 1080p should give 1920x1080, 720p should give 1280x720, and 480p should give 640x480 (note that iOS 480p therefore is NOT the typical 16:9 HD aspect ratio, and the typically-HD camera preview screen may differ greatly in aspect from what you actually record!!). For Android, expect more variance: on most Androids, 1080p _should_ give 1920x1080 and 720p _should_ give 1280x720; however, 480p will at "best" be 853x480 (16:9 HD aspect ratio), but falls back/down to 800x480, 720x480, or "worse", depending on what is closest-but-less-than 853x480 and available on the actual device. If your application requires knowledge of the precise resolution of the output image/video, you might consider manually determine the actual resolution itself after capture has completed (particularly for 480p on Android).
#### `type`
Values: `Camera.constants.Type.front` or `"front"`, `Camera.constants.Type.back` or `"back"` (default)
Use the `type` property to specify which camera to use.
#### `orientation`
Values:
`Camera.constants.Orientation.auto` or `"auto"` (default),
`Camera.constants.Orientation.landscapeLeft` or `"landscapeLeft"`, `Camera.constants.Orientation.landscapeRight` or `"landscapeRight"`, `Camera.constants.Orientation.portrait` or `"portrait"`, `Camera.constants.Orientation.portraitUpsideDown` or `"portraitUpsideDown"`
The `orientation` property allows you to specify the current orientation of the phone to ensure the viewfinder is "the right way up."
#### `Android` `playSoundOnCapture`
Values: `true` (default) or `false`
This property allows you to specify whether a shutter sound is played on capture. It is currently android only, pending [a reasonable mute implementation](http://stackoverflow.com/questions/4401232/avfoundation-how-to-turn-off-the-shutter-sound-when-capturestillimageasynchrono) in iOS.
#### `onBarCodeRead`
Will call the specified method when a barcode is detected in the camera's view.
Event contains `data` (the data in the barcode) and `bounds` (the rectangle which outlines the barcode.)
The following barcode types can be recognised:
- `aztec`
- `code128`
- `code39`
- `code39mod43`
- `code93`
- `ean13` (`iOS` converts `upca` barcodes to `ean13` by adding a leading 0)
- `ean8`
- `pdf417`
- `qr`
- `upce`
- `interleaved2of5` (when available)
- `itf14` (when available)
- `datamatrix` (when available)
The barcode type is provided in the `data` object.
#### `barCodeTypes`
An array of barcode types to search for. Defaults to all types listed above. No effect if `onBarCodeRead` is undefined.
Example: `<Camera barCodeTypes={[Camera.constants.BarCodeType.qr]} />`
#### `flashMode`
Values:
`Camera.constants.FlashMode.on`,
`Camera.constants.FlashMode.off`,
`Camera.constants.FlashMode.auto`
Use the `flashMode` property to specify the camera flash mode.
#### `torchMode`
Values:
`Camera.constants.TorchMode.on`,
`Camera.constants.TorchMode.off`,
`Camera.constants.TorchMode.auto`
Use the `torchMode` property to specify the camera torch mode.
#### `onFocusChanged: Event { nativeEvent: { touchPoint: { x, y } }`
iOS: Called when a touch focus gesture has been made.
By default, `onFocusChanged` is not defined and tap-to-focus is disabled.
Android: This callback is not yet implemented. However, Android will
automatically do tap-to-focus if the device supports auto-focus; there is
currently no way to manage this from javascript.
To get autofocus/tap to focus functionalities working correctly in android
make sure that the proper permissions are set in your `AndroidManifest.xml`:
```java
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
```
#### `iOS` `defaultOnFocusComponent`
Values:
`true` (default)
`false`
If `defaultOnFocusComponent` set to false, default internal implementation of visual feedback for tap-to-focus gesture will be disabled.
#### `iOS` `onZoomChanged: Event { nativeEvent: { velocity, zoomFactor } }`
iOS: Called when focus has changed.
By default, `onZoomChanged` is not defined and pinch-to-zoom is disabled.
Android: This callback is not yet implemented. However, Android will
automatically handle pinch-to-zoom; there is currently no way to manage this
from javascript.
#### `iOS` `keepAwake`
If set to `true`, the device will not sleep while the camera preview is visible. This mimics the behavior of the default camera app, which keeps the device awake while open.
#### `Android` `clearWindowBackground`
Values:
`true`
`false` (default)
If you encounter performance issue while using a window background drawable (typically defined in theme to emulate splashscreen behavior), set this to true to automatically clear window background once camera is started.
#### `Android` `permissionDialogTitle`
Starting on android M individual permissions must be granted for certain services, the camera is one of them, you can use this to change the title of the dialog prompt requesting permissions.
#### `Android` `permissionDialogMessage`
Starting on android M individual permissions must be granted for certain services, the camera is one of them, you can use this to change the content of the dialog prompt requesting permissions.
#### `notAuthorizedView`
By default a `Camera not authorized` message will be displayed when access to the camera has been denied, if set displays the passed react element instead of the default one.
#### `pendingAuthorizationView`
By default a <ActivityIndicator> will be displayed while the component is waiting for the user to grant/deny access to the camera, if set displays the passed react element instead of the default one.
#### `pendingAuthorizationView`
#### `mirrorImage`
If set to `true`, the image returned will be mirrored.
#### `mirrorVideo`
If set to `true`, the video returned will be mirrored.
#### `fixOrientation` (_deprecated_)
If set to `true`, the image returned will be rotated to the _right way up_. WARNING: It uses a significant amount of memory and my cause your application to crash if the device cannot provide enough RAM to perform the rotation.
(_If you find that you need to use this option because your images are incorrectly oriented by default,
could please submit a PR and include the make model of the device. We believe that it's not
required functionality any more and would like to remove it._)
## Component instance methods
You can access component methods by adding a `ref` (ie. `ref="camera"`) prop to your `<Camera>` element, then you can use `this.refs.camera.capture(cb)`, etc. inside your component.
#### `capture([options]): Promise`
Captures data from the camera. What is captured is based on the `captureMode` and `captureTarget` props. `captureMode` tells the camera whether you want a still image or video. `captureTarget` allows you to specify how you want the data to be captured and sent back to you. See `captureTarget` under Properties to see the available values.
Supported options:
- `audio` (See `captureAudio` under Properties)
- `mode` (See `captureMode` under Properties)
- `target` (See `captureTarget` under Properties)
- `metadata` This is metadata to be added to the captured image.
- `metadata.location` This is the object returned from `navigator.geolocation.getCurrentPosition()` (React Native's geolocation polyfill). It will add GPS metadata to the image.
- `rotation` This will rotate the image by the number of degrees specified.
- `jpegQuality` (integer between 1 and 100) This property is used to compress the output jpeg file with 100% meaning no jpeg compression will be applied.
- `totalSeconds` This will limit video length by number of seconds specified. Only works in video capture mode.
The promise will be fulfilled with an object with some of the following properties:
- `data`: Returns a base64-encoded string with the capture data (only returned with the deprecated `Camera.constants.CaptureTarget.memory`)
- `path`: Returns the path of the captured image or video file on disk
- `width`: (not yet implemented for Android video) returns the image or video file's frame width (taking image orientation into account)
- `height`: (not yet implemented for Android video) returns the image or video file's frame height (taking image orientation into account)
- `duration`: (currently iOS video only) video file duration
- `size`: (currently iOS video only) video file size (in bytes)
#### `iOS` `getFOV(): Promise`
Returns the camera's current field of view.
#### `hasFlash(): Promise`
Returns whether or not the camera has flash capabilities.
#### `stopCapture()`
Ends the current capture session for video captures. Only applies when the current `captureMode` is `video`.
#### `stopPreview()`
Stops the camera preview from running, and natively will make the current capture session pause.
#### `startPreview()`
Starts the camera preview again if previously stopped.
## Component static methods
#### `iOS` `Camera.checkDeviceAuthorizationStatus(): Promise`
Exposes the native API for checking if the device has authorized access to the camera (camera and microphone permissions). Can be used to call before loading the Camera component to ensure proper UX. The promise will be fulfilled with `true` or `false` depending on whether the device is authorized. Note, [as of iOS 10](https://developer.apple.com/library/content/documentation/AudioVideo/Conceptual/PhotoCaptureGuide/#//apple_ref/doc/uid/TP40017511-CH1-DontLinkElementID_3), you will need to add `NSCameraUsageDescription` and `NSMicrophoneUsageDescription` to your XCode project's Info.plist file or you might experience a crash.
#### `iOS` `Camera.checkVideoAuthorizationStatus(): Promise`
The same as `Camera.checkDeviceAuthorizationStatus()` but only checks the camera permission. Note, as of iOS 10, you will need to add `NSCameraUsageDescription` to your XCode project's Info.plist file or you might experience a crash.
#### `iOS` `Camera.checkAudioAuthorizationStatus(): Promise`
The same as `Camera.checkDeviceAuthorizationStatus()` but only checks the microphone permission. Note, as of iOS 10, you will need to add `NSMicrophoneUsageDescription` to your XCode project's Info.plist file or you might experience a crash.
## Subviews
This component supports subviews, so if you wish to use the camera view as a background or if you want to layout buttons/images/etc. inside the camera then you can do that.
## Example
To see more of the `RCTCamera` in action, you can check out the source in [Example](https://github.com/lwansbrough/react-native-camera/tree/master/Example) folder.
## Open Collective
We are just beginning a funding campaign for react-native-camera. Contributions are greatly appreciated. When we gain more than \$250 we will begin distributing funds to core maintainers in a fully transparent manner. Feedback for this process is welcomed, we will continue to evolve the strategy as we grow and learn more.
### Backers
Support us with a monthly donation and help us continue our activities. [[Become a backer](https://opencollective.com/react-native-camera#backer)]
<a href="https://opencollective.com/react-native-camera/backer/0/website" target="_blank"><img src="https://opencollective.com/react-native-camera/backer/0/avatar.svg"></a>
<a href="https://opencollective.com/react-native-camera/backer/1/website" target="_blank"><img src="https://opencollective.com/react-native-camera/backer/1/avatar.svg"></a>
<a href="https://opencollective.com/react-native-camera/backer/2/website" target="_blank"><img src="https://opencollective.com/react-native-camera/backer/2/avatar.svg"></a>
<a href="https://opencollective.com/react-native-camera/backer/3/website" target="_blank"><img src="https://opencollective.com/react-native-camera/backer/3/avatar.svg"></a>
<a href="https://opencollective.com/react-native-camera/backer/4/website" target="_blank"><img src="https://opencollective.com/react-native-camera/backer/4/avatar.svg"></a>
<a href="https://opencollective.com/react-native-camera/backer/5/website" target="_blank"><img src="https://opencollective.com/react-native-camera/backer/5/avatar.svg"></a>
<a href="https://opencollective.com/react-native-camera/backer/6/website" target="_blank"><img src="https://opencollective.com/react-native-camera/backer/6/avatar.svg"></a>
<a href="https://opencollective.com/react-native-camera/backer/7/website" target="_blank"><img src="https://opencollective.com/react-native-camera/backer/7/avatar.svg"></a>
<a href="https://opencollective.com/react-native-camera/backer/8/website" target="_blank"><img src="https://opencollective.com/react-native-camera/backer/8/avatar.svg"></a>
<a href="https://opencollective.com/react-native-camera/backer/9/website" target="_blank"><img src="https://opencollective.com/react-native-camera/backer/9/avatar.svg"></a>
<a href="https://opencollective.com/react-native-camera/backer/10/website" target="_blank"><img src="https://opencollective.com/react-native-camera/backer/10/avatar.svg"></a>
<a href="https://opencollective.com/react-native-camera/backer/11/website" target="_blank"><img src="https://opencollective.com/react-native-camera/backer/11/avatar.svg"></a>
<a href="https://opencollective.com/react-native-camera/backer/12/website" target="_blank"><img src="https://opencollective.com/react-native-camera/backer/12/avatar.svg"></a>
<a href="https://opencollective.com/react-native-camera/backer/13/website" target="_blank"><img src="https://opencollective.com/react-native-camera/backer/13/avatar.svg"></a>
<a href="https://opencollective.com/react-native-camera/backer/14/website" target="_blank"><img src="https://opencollective.com/react-native-camera/backer/14/avatar.svg"></a>
<a href="https://opencollective.com/react-native-camera/backer/15/website" target="_blank"><img src="https://opencollective.com/react-native-camera/backer/15/avatar.svg"></a>
<a href="https://opencollective.com/react-native-camera/backer/16/website" target="_blank"><img src="https://opencollective.com/react-native-camera/backer/16/avatar.svg"></a>
<a href="https://opencollective.com/react-native-camera/backer/17/website" target="_blank"><img src="https://opencollective.com/react-native-camera/backer/17/avatar.svg"></a>
<a href="https://opencollective.com/react-native-camera/backer/18/website" target="_blank"><img src="https://opencollective.com/react-native-camera/backer/18/avatar.svg"></a>
<a href="https://opencollective.com/react-native-camera/backer/19/website" target="_blank"><img src="https://opencollective.com/react-native-camera/backer/19/avatar.svg"></a>
<a href="https://opencollective.com/react-native-camera/backer/20/website" target="_blank"><img src="https://opencollective.com/react-native-camera/backer/20/avatar.svg"></a>
<a href="https://opencollective.com/react-native-camera/backer/21/website" target="_blank"><img src="https://opencollective.com/react-native-camera/backer/21/avatar.svg"></a>
<a href="https://opencollective.com/react-native-camera/backer/22/website" target="_blank"><img src="https://opencollective.com/react-native-camera/backer/22/avatar.svg"></a>
<a href="https://opencollective.com/react-native-camera/backer/23/website" target="_blank"><img src="https://opencollective.com/react-native-camera/backer/23/avatar.svg"></a>
<a href="https://opencollective.com/react-native-camera/backer/24/website" target="_blank"><img src="https://opencollective.com/react-native-camera/backer/24/avatar.svg"></a>
<a href="https://opencollective.com/react-native-camera/backer/25/website" target="_blank"><img src="https://opencollective.com/react-native-camera/backer/25/avatar.svg"></a>
<a href="https://opencollective.com/react-native-camera/backer/26/website" target="_blank"><img src="https://opencollective.com/react-native-camera/backer/26/avatar.svg"></a>
<a href="https://opencollective.com/react-native-camera/backer/27/website" target="_blank"><img src="https://opencollective.com/react-native-camera/backer/27/avatar.svg"></a>
<a href="https://opencollective.com/react-native-camera/backer/28/website" target="_blank"><img src="https://opencollective.com/react-native-camera/backer/28/avatar.svg"></a>
<a href="https://opencollective.com/react-native-camera/backer/29/website" target="_blank"><img src="https://opencollective.com/react-native-camera/backer/29/avatar.svg"></a>
### Sponsors
Become a sponsor and get your logo on our README on Github with a link to your site. [[Become a sponsor](https://opencollective.com/react-native-camera#sponsor)]
<a href="https://opencollective.com/react-native-camera/sponsor/0/website" target="_blank"><img src="https://opencollective.com/react-native-camera/sponsor/0/avatar.svg"></a>
<a href="https://opencollective.com/react-native-camera/sponsor/1/website" target="_blank"><img src="https://opencollective.com/react-native-camera/sponsor/1/avatar.svg"></a>
<a href="https://opencollective.com/react-native-camera/sponsor/2/website" target="_blank"><img src="https://opencollective.com/react-native-camera/sponsor/2/avatar.svg"></a>
<a href="https://opencollective.com/react-native-camera/sponsor/3/website" target="_blank"><img src="https://opencollective.com/react-native-camera/sponsor/3/avatar.svg"></a>
<a href="https://opencollective.com/react-native-camera/sponsor/4/website" target="_blank"><img src="https://opencollective.com/react-native-camera/sponsor/4/avatar.svg"></a>
<a href="https://opencollective.com/react-native-camera/sponsor/5/website" target="_blank"><img src="https://opencollective.com/react-native-camera/sponsor/5/avatar.svg"></a>
<a href="https://opencollective.com/react-native-camera/sponsor/6/website" target="_blank"><img src="https://opencollective.com/react-native-camera/sponsor/6/avatar.svg"></a>
<a href="https://opencollective.com/react-native-camera/sponsor/7/website" target="_blank"><img src="https://opencollective.com/react-native-camera/sponsor/7/avatar.svg"></a>
<a href="https://opencollective.com/react-native-camera/sponsor/8/website" target="_blank"><img src="https://opencollective.com/react-native-camera/sponsor/8/avatar.svg"></a>
<a href="https://opencollective.com/react-native-camera/sponsor/9/website" target="_blank"><img src="https://opencollective.com/react-native-camera/sponsor/9/avatar.svg"></a>
---
Thanks to Brent Vatne (@brentvatne) for the `react-native-video` module which provided me with a great example of how to set up this module.

View File

@ -1,4 +1,8 @@
# RNCamera
---
id: rncamera
title: RNCamera
sidebar_label: RNCamera
---
## Usage
@ -7,11 +11,11 @@ All you need is to `import` `{ RNCamera }` from the `react-native-camera` module
```javascript
'use strict';
import React, { Component } from 'react';
import React, { PureComponent } from 'react';
import { AppRegistry, StyleSheet, Text, TouchableOpacity, View } from 'react-native';
import { RNCamera } from 'react-native-camera';
class BadInstagramCloneApp extends Component {
class ExampleApp extends PureComponent {
render() {
return (
<View style={styles.container}>
@ -22,8 +26,18 @@ class BadInstagramCloneApp extends Component {
style={styles.preview}
type={RNCamera.Constants.Type.back}
flashMode={RNCamera.Constants.FlashMode.on}
permissionDialogTitle={'Permission to use camera'}
permissionDialogMessage={'We need your permission to use your camera phone'}
androidCameraPermissionOptions={{
title: 'Permission to use camera',
message: 'We need your permission to use your camera',
buttonPositive: 'Ok',
buttonNegative: 'Cancel',
}}
androidRecordAudioPermissionOptions={{
title: 'Permission to use audio recording',
message: 'We need your permission to use your audio',
buttonPositive: 'Ok',
buttonNegative: 'Cancel',
}}
onGoogleVisionBarcodesDetected={({ barcodes }) => {
console.log(barcodes);
}}
@ -37,7 +51,7 @@ class BadInstagramCloneApp extends Component {
);
}
takePicture = async function() {
takePicture = async () => {
if (this.camera) {
const options = { quality: 0.5, base64: true };
const data = await this.camera.takePictureAsync(options);
@ -68,7 +82,7 @@ const styles = StyleSheet.create({
},
});
AppRegistry.registerComponent('BadInstagramCloneApp', () => BadInstagramCloneApp);
AppRegistry.registerComponent('App', () => ExampleApp);
```
## FaCC (Function as Child Components)
@ -77,8 +91,8 @@ AppRegistry.registerComponent('BadInstagramCloneApp', () => BadInstagramCloneApp
```javascript
'use strict';
import React, { Component } from 'react';
import { StyleSheet, Text, TouchableOpacity, View } from 'react-native';
import React, { PureComponent } from 'react';
import { AppRegistry, StyleSheet, Text, TouchableOpacity, View } from 'react-native';
import { RNCamera } from 'react-native-camera';
const PendingView = () => (
@ -94,7 +108,7 @@ const PendingView = () => (
</View>
);
class App extends Component {
class ExampleApp extends PureComponent {
render() {
return (
<View style={styles.container}>
@ -102,8 +116,18 @@ class App extends Component {
style={styles.preview}
type={RNCamera.Constants.Type.back}
flashMode={RNCamera.Constants.FlashMode.on}
permissionDialogTitle={'Permission to use camera'}
permissionDialogMessage={'We need your permission to use your camera phone'}
androidCameraPermissionOptions={{
title: 'Permission to use camera',
message: 'We need your permission to use your camera',
buttonPositive: 'Ok',
buttonNegative: 'Cancel',
}}
androidRecordAudioPermissionOptions={{
title: 'Permission to use audio recording',
message: 'We need your permission to use your audio',
buttonPositive: 'Ok',
buttonNegative: 'Cancel',
}}
>
{({ camera, status, recordAudioPermissionStatus }) => {
if (status !== 'READY') return <PendingView />;
@ -150,20 +174,20 @@ const styles = StyleSheet.create({
},
});
AppRegistry.registerComponent('BadInstagramCloneApp', () => App);
AppRegistry.registerComponent('App', () => ExampleApp);
```
#### `camera`
### `camera`
_It's the RNCamera's reference_
#### `status`
### `status`
One of `RNCamera.Constants.CameraStatus`
'READY' | 'PENDING_AUTHORIZATION' | 'NOT_AUTHORIZED'
#### `recordAudioPermissionStatus`
### `recordAudioPermissionStatus`
One of `RNCamera.Constants.RecordAudioPermissionStatus`.
@ -171,7 +195,7 @@ One of `RNCamera.Constants.RecordAudioPermissionStatus`.
## Properties
#### `autoFocus`
### `autoFocus`
Values: `RNCamera.Constants.AutoFocus.on` (default) or `RNCamera.Constants.AutoFocus.off`
@ -179,22 +203,40 @@ Most cameras have a Auto Focus feature. It adjusts your camera lens position aut
Use the `autoFocus` property to specify the auto focus setting of your camera. `RNCamera.Constants.AutoFocus.on` turns it ON, `RNCamera.Constants.AutoFocus.off` turns it OFF.
#### `iOS` `autoFocusPointOfInterest`
### `autoFocusPointOfInterest`
Values: Object `{ x: 0.5, y: 0.5 }`.
Values (iOS): Object `{ x: 0.5, y: 0.5, autoExposure }`.
Setting this property causes the auto focus feature of the camera to attempt to focus on the part of the image at this coordiate.
Setting this property causes the auto focus feature of the camera to attempt to focus on the part of the image at this coordinate.
Coordinates values are measured as floats from `0` to `1.0`. `{ x: 0, y: 0 }` will focus on the top left of the image, `{ x: 1, y: 1 }` will be the bottom right. Values are based on landscape mode with the home button on the right—this applies even if the device is in portrait mode.
#### `captureAudio`
On iOS, focusing will not change the exposure automatically unless autoExposure is also set to true.
Hint:
for portrait orientation, apply 90° clockwise rotation + translation: [Example](https://gist.github.com/Craigtut/6632a9ac7cfff55e74fb561862bc4edb)
### iOS `onSubjectAreaChanged`
iOS only.
if autoFocusPointOfInterest is set, this event will be fired when a substancial change is detected with the following object: `{ nativeEvent: { prevPoint: { x: number; y: number; } } }`
### `captureAudio`
Values: boolean `true` (default) | `false`
Specifies if audio recording permissions should be requested.
Make sure to follow README instructions for audio recording permissions [here](../README.md).
Make sure to follow README instructions for audio recording permissions [here](README.md).
#### `flashMode`
### iOS `keepAudioSession`
Values: boolean `true` | `false` (false)
(iOS Only) When the camera is unmounted, it will release any audio session it acquired (if `captureAudio=true`) so other media can continue playing. However, this might not be always desirable (e.g., if video is played afterwards) and can be disabled by setting it to `true`. Setting this to `true`, means your app will not release the audio session. Note: other apps might still "steal" the audio session from your app.
### `flashMode`
Values: `RNCamera.Constants.FlashMode.off` (default), `RNCamera.Constants.FlashMode.on`, `RNCamera.Constants.FlashMode.auto` or `RNCamera.Constants.FlashMode.torch`.
@ -208,25 +250,33 @@ Specifies the flash mode of your camera.
`RNCamera.Constants.FlashMode.torch` turns on torch mode, meaning the flash light will be turned on all the time (even before taking photo) just like a flashlight.
#### `focusDepth`
### `focusDepth`
Value: float from `0` to `1.0`
Manually set camera focus. Only works with `autoFocus` off. The value 0 is minimum focus depth, 1 is maximum focus depth. For a medium focus depth, for example, you could use 0.5.
#### `Android` `ratio`
### `Android` `ratio`
A string representing the camera ratio in the format 'height:width'. Default is `"4:3"`.
Use `getSupportedRatiosAsync` method to get ratio strings supported by your camera on Android.
#### `type`
### `type`
Values: `RNCamera.Constants.Type.front` or `RNCamera.Constants.Type.back` (default)
Use the `type` property to specify which camera to use.
#### `whiteBalance`
### `Android` `cameraId`
Overrides the `type` property and uses the camera given by cameraId. Use `getCameraIds` to get the list of available IDs.
A common use case for this is to provide a "switch camera" button that loops through all available cameras.
Note: Variables such as flash might need to be resetted due to the camera not reporting an error when those values are not supported.
### `whiteBalance`
Values: `RNCamera.Constants.WhiteBalance.sunny`, `RNCamera.Constants.WhiteBalance.cloudy`, `RNCamera.Constants.WhiteBalance.shadow`, `RNCamera.Constants.WhiteBalance.incandescent`, `RNCamera.Constants.WhiteBalance.fluorescent` or `RNCamera.Constants.WhiteBalance.auto` (default)
@ -236,28 +286,76 @@ The idea is that you select the appropriate white balance setting for the type o
Use the `whiteBalance` property to specify which white balance setting the camera should use.
#### `zoom`
On iOS it's also possible to specify custom temperature, tint and rgb offset values instead of using one of the presets (auto, sunny, ...):
Value: Object (e.g. `{temperature: 4000, tint: -10.0, redGainOffset: 0.0, greenGainOffset: 0.0, blueGainOffset: 0.0}`)
The rgb offset values are applied to the calculated device specific white balance gains for the given temperature and tint values.
### `exposure`
Value: float from `0` to `1.0`, or `-1` (default) for auto.
Sets the camera's exposure value.
### `useNativeZoom`
Boolean to turn on native pinch to zoom. Works with the `maxZoom` property on iOS.
Warning: The Android Touch-Event-System causes childviews to catch the touch events. Therefore avoid using screenfilling touchables inside of the cameraview.
### `zoom`
Value: float from `0` to `1.0`
Specifies the zoom of your camera. The value 0 is no zoom, 1 is maximum zoom. For a medium zoom, for example, you could pass `0.5`.
#### `Android` `permissionDialogTitle`
### `iOS` `maxZoom`
iOS Only.
Value: optional float greater than `1.0` used to enforce a maximum zoom value on the camera. Setting a value to less than `1` (default) will make the camera use its own max zoom property.
Specifies the max zoom value used in zoom calculations. This is specifically useful for iOS where it reports arbitrary high values and using a 0 to 1 value as the zoom factor is not appropriate.
### `Android` `permissionDialogTitle` - Deprecated
Starting on android M individual permissions must be granted for certain services, the camera is one of them, you can use this to change the title of the dialog prompt requesting permissions.
#### `Android` `permissionDialogMessage`
### `Android` `permissionDialogMessage` - Deprecated
Starting on android M individual permissions must be granted for certain services, the camera is one of them, you can use this to change the content of the dialog prompt requesting permissions.
#### `notAuthorizedView`
### `Android` `androidRecordAudioPermissionOptions`
Configuration options for permissions request for recording audio. It will be passed as `rationale` parameter to [`PermissionsAndroid.request`](https://facebook.github.io/react-native/docs/permissionsandroid#request). This replaces and deprecates old `permissionDialogTitle` and `permissionDialogMessage` parameters.
### `Android` `androidCameraPermissionOptions`
Configuration options for permissions request for camera. It will be passed as `rationale` parameter to [`PermissionsAndroid.request`](https://facebook.github.io/react-native/docs/permissionsandroid#request). This replaces and deprecates old `permissionDialogTitle` and `permissionDialogMessage` parameters.
### `notAuthorizedView`
By default a `Camera not authorized` message will be displayed when access to the camera has been denied, if set displays the passed react element instead of the default one.
#### `pendingAuthorizationView`
### `pendingAuthorizationView`
By default a <ActivityIndicator> will be displayed while the component is waiting for the user to grant/deny access to the camera, if set displays the passed react element instead of the default one.
#### `rectOfInterest`
An `{x: , y:, width:, height: }` object which defines the rect of interst as normalized coordinates from `(0,0)` top left corner to `(1,1)` bottom right corner.
Note: Must also provide cameraViewDimensions prop for Android device
### `Android` `cameraViewDimensions`
An `{width:, height: }` object which defines the width and height of the cameraView. This prop is used to adjust the effect of Aspect Raio for rectOfInterest area on Android
### `Android` `playSoundOnCapture`
Boolean to turn on or off the camera's shutter sound (default false). Note that in some countries, the shutter sound cannot be turned off.
### `iOS` `videoStabilizationMode`
The video stabilization mode used for a video recording. The possible values are:
@ -269,7 +367,7 @@ The video stabilization mode used for a video recording. The possible values are
You can read more about each stabilization type here: https://developer.apple.com/documentation/avfoundation/avcapturevideostabilizationmode
### `iOS` `defaultVideoQuality`
### `defaultVideoQuality`
This option specifies the quality of the video to be taken. The possible values are:
@ -295,17 +393,25 @@ This option specifies the quality of the video to be taken. The possible values
If nothing is passed the device's highest camera quality will be used as default.
Note: This solve the flicker video recording issue for iOS
### `pictureSize`
This prop has a different behaviour for Android and iOS and should rarely be set.
For Android, this prop attempts to control the camera sensor capture resolution, similar to how `ratio` behaves. This is useful for cases where a low resolution image is required, and makes further resizing less intensive on the device's memory. The list of possible values can be requested with `getAvailablePictureSizes`, and the value should be set in the format of `<width>x<height>`. Internally, the native code will attempt to get the best suited resolution for the given `pictureSize` value if the provided value is invalid, and will default to the highest resolution available.
For iOS, this prop controls the internal camera preset value and should rarely be changed. However, this value can be set to setup the sensor to match the video recording's quality in order to prevent flickering. The list of valid values can be gathered from https://developer.apple.com/documentation/avfoundation/avcapturesessionpreset and can also be requested with `getAvailablePictureSizes`.
### Native Event callbacks props
#### `onCameraReady`
### `onCameraReady`
Function to be called when native code emit onCameraReady event, when camera is ready.
Function to be called when native code emit onCameraReady event, when camera is ready. This event will also fire when changing cameras (by `type` or `cameraId`).
#### `onMountError`
### `onMountError`
Function to be called when native code emit onMountError event, when there is a problem mounting the camera.
#### `onStatusChange`
### `onStatusChange`
Function to be called when native code emits status changes in relation to authorization changes.
@ -314,13 +420,51 @@ Event contains the following fields:
- `cameraStatus` - one of the [CameraStatus](#status) values
- `recordAudioPermissionStatus` - one of the [RecordAudioPermissionStatus](#recordAudioPermissionStatus) values
#### `Android` `onPictureTaken`
### `iOS` `onAudioInterrupted`
Function to be called when native code emit onPictureTaken event, when camera has taken a picture.
iOS only. Function to be called when the camera audio session is interrupted or fails to start for any reason (e.g., in use or not authorized). For example, this might happen due to another app taking exclusive control over the microphone (e.g., a phone call) if `captureAudio={true}`. When this happens, any active audio input will be temporarily disabled and cause a flicker on the preview screen. This will fire any time an attempt to connect the audio device fails. Use this to update your UI to indicate that audio recording is not currently possible.
### `iOS` `onAudioConnected`
iOS only. Function to be called when the camera audio session is connected. This will be fired the first time the camera is mounted with `captureAudio={true}`, and any time the audio device connection is established. Note that this event might not always fire after an interruption due to iOS' behavior. For example, if the audio was already interrupted before the camera was mounted, this event will only fire once a recording is attempted.
### `onPictureTaken`
Function to be called when native code emit onPictureTaken event, when camera has taken a picture, but before all extra processing happens. This can be useful to allow the UI to take other pictures while the processing of the current picture is still taking place.
### `onRecordingStart`
Function to be called when native code actually starts video recording. Note that video recording might take a few miliseconds to setup depending on the camera settings and hardware features. Use this event to detect when video is actually being recorded.
Event will contain the following fields:
- `uri` - Video file URI, as returned by `recordAsync`
- `videoOrientation` - Video orientation, as returned by `recordAsync`
- `deviceOrientation` - Video orientation, as returned by `recordAsync`
### `onRecordingEnd`
Function to be called when native code stops recording video, but before all video processing takes place. This event will only fire after a successful video recording, and it will not fire if video recording fails (use the error returned from `recordAsync` instead).
### `onTap`
Function to be called when a touch within the camera view is recognized.
The function is also called on the first touch of double tap.
Event will contain the following fields:
- `x`
- `y`
### `onDoubleTap`
Function to be called when a double touch within the camera view is recognized.
Event will contain the following fields:
- `x`
- `y`
### Bar Code Related props
#### `onBarCodeRead`
### `onBarCodeRead`
Will call the specified method when a barcode is detected in the camera's view.
@ -328,6 +472,7 @@ Event contains the following fields
- `data` - a textual representation of the barcode, if available
- `rawData` - The raw data encoded in the barcode, if available
- `uri`: (iOS only) string representing the path to the image saved on your app's cache directory. Applicable only for `onGoogleVisionBarcodesDetected`.
- `type` - the type of the barcode detected
- `bounds` -
@ -344,18 +489,24 @@ Event contains the following fields
}
}
- onAndroid:
- onAndroid: the `ResultPoint[]` (`bounds.origin`) is returned for scanned barcode origins. The number of `ResultPoint` returned depends on the type of Barcode.
bounds:[{x:string,y:string}]
- on Android it just returns resultPoints:
- for barcodes:
bounds: {
width: number;
height: number;
origin: Array<{x: number, y: number}>
}
bounds[0].x : left side of barcode.
bounds[1].x : right side of barcode
- counting for QRcodes:
1. **PDF417**: 8 ResultPoint, laid out as follow:
0 --- 4 ------ 6 --- 2
| ////////////////// |
1 --- 5 ------ 7 --- 3
1 2
0
2. **QR**: 4 ResultPoint, laid out as follow:
2 ------ 3
| //////
| //////
1 ------ 0
The following barcode types can be recognised:
@ -373,38 +524,61 @@ The following barcode types can be recognised:
- `itf14` (when available)
- `datamatrix` (when available)
#### `barCodeTypes`
### `barCodeTypes`
An array of barcode types to search for. Defaults to all types listed above. No effect if `onBarCodeRead` is undefined.
Example: `<RNCamera barCodeTypes={[RNCamera.Constants.BarCodeType.qr]} />`
#### `Android` `onGoogleVisionBarcodesDetected`
### `onGoogleVisionBarcodesDetected`
Like `onBarCodeRead`, but we will use Google Play Service Vision to scan barcodes, which is pretty fast on Android. Note: If you already set `onBarCodeRead`, this will be invalid.
Like `onBarCodeRead`, but using Firebase MLKit to scan barcodes. More info can be found [here](https://firebase.google.com/docs/ml-kit/read-barcodes) Note: If you already set `onBarCodeRead`, this will be invalid.
#### `Android` `googleVisionBarcodeType`
### `googleVisionBarcodeType`
Like `barCodeTypes`, but applies to the Google Play Service Vision barcode detector.
Like `barCodeTypes`, but applies to the Firebase MLKit barcode detector.
Example: `<RNCamera googleVisionBarcodeType={RNCamera.Constants.GoogleVisionBarcodeDetection.BarcodeType.DATA_MATRIX} />`
Available settings:
#### `Android` `googleVisionBarcodeMode`
- CODE_128
- CODE_39
- CODE_93
- CODABAR
- EAN_13
- EAN_8
- ITF
- UPC_A
- UPC_E
- QR_CODE
- PDF417
- AZTEC
- DATA_MATRIX
- ALL
### `googleVisionBarcodeMode`
Change the mode in order to scan "inverted" barcodes. You can either change it to `alternate`, which will inverted the image data every second screen and be able to read both normal and inverted barcodes, or `inverted`, which will only read inverted barcodes. Default is `normal`, which only reads "normal" barcodes. Note: this property only applies to the Google Vision barcode detector.
Example: `<RNCamera googleVisionBarcodeMode={RNCamera.Constants.GoogleVisionBarcodeDetection.BarcodeMode.ALTERNATE} />`
### `detectedImageInEvent`
When `detectedImageInEvent` is `false` (default), `onBarCodeRead` / `onBarcodesDetected` only gives metadata, but not the image (bytes/base64) itself.
When `detectedImageInEvent` is `true`, `onBarCodeRead` / `onGoogleVisionBarcodesDetected` will fill the `image` field inside the object given to the callback handler.
It contains raw image bytes in JPEG format (quality 100) as Base64-encoded string.
### Face Detection Related props
RNCamera uses the Google Mobile Vision frameworks for Face Detection, you can read more info about it [here](https://developers.google.com/android/reference/com/google/android/gms/vision/face/FaceDetector).
RNCamera uses the Firebase MLKit for Face Detection, you can read more about it [here](https://firebase.google.com/docs/ml-kit/detect-faces).
#### `onFacesDetected`
### `onFacesDetected`
Method to be called when face is detected. Receives a Faces Detected Event object. The interesting value of this object is the `faces` value, which is an array with objects of the [Face](https://developers.google.com/android/reference/com/google/android/gms/vision/face/Face) properties.
Method to be called when face is detected. Receives a Faces Detected Event object. The interesting value of this object is the `faces` value, which is an array of Face objects. You can find more details about the possible values of these objects [here](https://firebase.google.com/docs/ml-kit/face-detection-concepts)
#### `onFaceDetectionError`
### `onFaceDetectionError`
Method to be called if there was an Face Detection Error, receives an object with the `isOperational` property set to `false` if Face Detector is NOT operational and `true`if it is.
#### `faceDetectionMode`
### `faceDetectionMode`
Values: `RNCamera.Constants.FaceDetection.Mode.fast` (default) or `RNCamera.Constants.FaceDetection.Mode.accurate`
@ -412,13 +586,13 @@ Specifies the face detection mode of the Face Detection API.
Use `RNCamera.Constants.FaceDetection.Mode.accurate` if you want slower but more accurate results.
#### `faceDetectionLandmarks`
### `faceDetectionLandmarks`
Values: `RNCamera.Constants.FaceDetection.Landmarks.all` or `RNCamera.Constants.FaceDetection.Landmarks.none` (default)
A landmark is a point of interest within a face. The left eye, right eye, and nose base are all examples of landmarks. The Face API provides the ability to find landmarks on a detected face.
#### `faceDetectionClassifications`
### `faceDetectionClassifications`
Values: `RNCamera.Constants.FaceDetection.Classifications.all` or `RNCamera.Constants.FaceDetection.Classifications.none` (default)
@ -426,17 +600,17 @@ Classification is determining whether a certain facial characteristic is present
### Text Recognition Related props
RNCamera uses the Google Mobile Vision frameworks for Text Recognition, you can read more info about it [here](https://developers.google.com/vision/android/text-overview).
RNCamera uses the Firebase MLKit for Text Recognition, you can read more info about it [here](https://firebase.google.com/docs/ml-kit/recognize-text).
#### `onTextRecognized`
### `onTextRecognized`
Method to be called when text is detected. Receives a Text Recognized Event object. The interesting value of this object is the `textBlocks` value, which is an array with objects of the [TextBlock](https://developers.google.com/android/reference/com/google/android/gms/vision/text/TextBlock) properties.
Method to be called when text is detected. Receives a Text Recognized Event object. The interesting value of this object is the `textBlocks` value, which is an array of TextBlock objects.
## Component instance methods
#### `takePictureAsync([options]): Promise`
### `takePictureAsync([options]): Promise`
Takes a picture, saves in your app's cache directory and returns a promise.
Takes a picture, saves in your app's cache directory and returns a promise. Note: additional image processing, such as mirror, orientation, and width, can be significantly slow on Android.
Supported options:
@ -448,20 +622,30 @@ Supported options:
- `mirrorImage` (boolean true or false). Use this with `true` if you want the resulting rendered picture to be mirrored (inverted in the vertical axis). If no value is specified `mirrorImage:false` is used.
- `writeExif`: (boolean or object, defaults to true). Setting this to a boolean indicates if the image exif should be preserved after capture, or removed. Setting it to an object, merges any data with the final exif output. This is useful, for example, to add GPS metadata (note that GPS info is correctly transalted from double values to the EXIF format, so there's no need to read the EXIF protocol).
```js
writeExif = {
GPSLatitude: latitude,
GPSLongitude: longitude,
GPSAltitude: altitude,
};
```
- `exif` (boolean true or false) Use this with `true` if you want a exif data map of the picture taken on the return data of your promise. If no value is specified `exif:false` is used.
- `fixOrientation` (android only, boolean true or false) Use this with `true` if you want to fix incorrect image orientation (can take up to 5 seconds on some devices). Do not provide this if you only need EXIF based orientation.
- `forceUpOrientation` (iOS only, boolean true or false). This property allows to force portrait orientation based on actual data instead of exif data.
- `skipProcessing` (android only, boolean). This property skips all image processing on android, this makes taking photos super fast, but you loose some of the information, width, height and the ability to do some processing on the image (base64, width, quality, mirrorImage, exif, etc)
- `doNotSave` (boolean true or false). Use this with `true` if you do not want the picture to be saved as a file to cache. If no value is specified `doNotSave:false` is used. If you only need the base64 for the image, you can use this with `base64:true` and avoid having to save the file.
- `pauseAfterCapture` (boolean true or false). If true, pause the preview layer immediately after capturing the image. You will need to call `cameraRef.resumePreview()` before using the camera again. If no value is specified `pauseAfterCapture:false` is used.
- `orientation` (string or number). Specifies the orientation that us used for taking the picture. Possible values: `"portrait"`, `"portraitUpsideDown"`, `"landscapeLeft"` or `"landscapeRight"`.
- `path` (file path on disk). Specifies the path on disk to save picture to.
The promise will be fulfilled with an object with some of the following properties:
- `width`: returns the image's width (taking image orientation into account)
@ -472,7 +656,7 @@ The promise will be fulfilled with an object with some of the following properti
- `pictureOrientation`: (number) the orientation of the picture
- `deviceOrientation`: (number) the orientation of the device
#### `recordAsync([options]): Promise`
### `recordAsync([options]): Promise`
Records a video, saves it in your app's cache directory and returns a promise when stopRecording is called or either maxDuration or maxFileSize specified are reached.
@ -499,8 +683,9 @@ Supported options:
- `ios` Specifies capture settings suitable for CIF quality (352x288 pixel) video output.
- `android` Not supported.
- `videoBitrate`. (int greater than 0) This option specifies a desired video bitrate. For example, 5\*1000\*1000 would be 5Mbps.
- `ios` Not supported.
- `videoBitrate`. (int greater than 0) This option specifies a desired video bitrate. For example, 5\*1000\*1000 would be 5Mbps.
- `ios` Supported however requires that the codec key is also set.
- `android` Supported.
- `orientation` (string or number). Specifies the orientation that us used for recording the video. Possible values: `"portrait"`, `"portraitUpsideDown"`, `"landscapeLeft"` or `"landscapeRight"`.
@ -537,23 +722,44 @@ The promise will be fulfilled with an object with some of the following properti
- `iOS` `codec`: the codec of the recorded video. One of `RNCamera.Constants.VideoCodec`
#### `stopRecording: void`
- `isRecordingInterrupted`: (boolean) whether the app has been minimized while recording
### `refreshAuthorizationStatus: Promise<void>`
Allows to make RNCamera check Permissions again and set status accordingly.
Making it possible to refresh status of RNCamera after user initially rejected the permissions.
### `stopRecording: void`
Should be called after recordAsync() to make the promise be fulfilled and get the video uri.
#### `pausePreview: void`
### `pausePreview: void`
Pauses the preview. The preview can be resumed again by using resumePreview().
#### `resumePreview: void`
### `resumePreview: void`
Resumes the preview after pausePreview() has been called.
#### `Android` `getSupportedRatiosAsync(): Promise`
### `Android` `getSupportedRatiosAsync(): Promise`
Android only. Returns a promise. The promise will be fulfilled with an object with an array containing strings with all camera aspect ratios supported by the device.
#### `iOS` `isRecording(): Promise<boolean>`
### `getCameraIdsAsync(): Promise`
Returns a promise. The promise will be fulfilled with an array containing objects with all camera IDs and type supported by the device.
The promise will be fulfilled with an array containing objects with some of the following properties:
- `id`: (string) the ID of the camera.
- `type`: One of `RNCamera.Constants.Type.front` | `RNCamera.Constants.Type.back`
- `deviceType`: iOS 10+ only. Returns the internal device string type used by the OS. Useful to identify camera types (e.g., wide). Constants match iOS' string values: `AVCaptureDeviceTypeBuiltInWideAngleCamera`, `AVCaptureDeviceTypeBuiltInTelephotoCamera`, `AVCaptureDeviceTypeBuiltInUltraWideCamera`. More info can be found at <a href="https://developer.apple.com/documentation/avfoundation/avcapturedevicetypebuiltinultrawidecamera" target="_blank">Apple Docs</a>
Note: iOS also allows for virtual cameras (e.g., a camera made of multiple cameras). However, only physical non-virtual cameras are returned by this method since advanced features (such as depth maps or auto switching on camera zoom) are not supported.
### `iOS` `isRecording(): Promise<boolean>`
iOS only. Returns a promise. The promise will be fulfilled with a boolean indicating if currently recording is started or stopped.
@ -561,14 +767,31 @@ iOS only. Returns a promise. The promise will be fulfilled with a boolean indica
This component supports subviews, so if you wish to use the camera view as a background or if you want to layout buttons/images/etc. inside the camera then you can do that.
**Example subview:**
### react-native-barcode-mask
A Barcode and QR code UI mask which can be use to render a scanning layout on camera with customizable styling.
Read more about [react-native-barcode-mask](https://github.com/shahnawaz/react-native-barcode-mask) here.
### @nartc/react-native-barcode-mask
A rewritten version of `react-native-barcode-mask` using `Hooks` and `Reanimated`. If you're already using `react-native-reanimated` (`react-navigation` dependency) then you might benefit from this rewritten component.
- Customizable
- Provide custom hook to "scan barcode within finder area"
Read more about it here [@nartc/react-native-barcode-mask](https://github.com/nartc/react-native-barcode-mask)
## Testing
To learn about how to test components which uses `RNCamera` check its [documentation about testing](./tests.md).
## Example
## Examples
To see more of the `RNCamera` in action you can check out the [RNCamera examples directory](https://github.com/react-native-community/react-native-camera/tree/master/examples).
Firebase MLKit-base features (such as Text, Face and Barcode detection) can be found in the [mlkit](https://github.com/react-native-community/react-native-camera/tree/master/examples/mlkit) example.
## Open Collective

View File

@ -1,4 +1,8 @@
# Recipes
---
id: recipes
title: Recipes
sidebar_label: Recipes
---
The idea is to provide a list of useful snippets, links and resources to be used together with react-native-camera
@ -18,9 +22,9 @@ const { shouldFaceDetect } = this.state;
Passing `null` to `onFaceDetected`, `onGoogleVisionBarcodesDetected`, `onTextRecognized`, `onBarCodeRead` automatically turns off the correspondent detector.
### Events continue if screen is mounted but not on top of stack
## Events continue if screen is mounted but not on top of stack
Lets say you use Face Detection, you take a picture and then takes the user to another screen to see that picture. Meanwhile, RNCamera is still mounted on the previous screen. `onFaceDetected` will still be called if you do not prevent it. For example (using [`react-navigation`](https://github.com/react-navigation/react-navigation):
Lets say you use Face Detection, you take a picture and then takes the user to another screen to see that picture. Meanwhile, RNCamera is still mounted on the previous screen. `onFaceDetected` will still be called if you do not prevent it. For example (using [`react-navigation`](https://github.com/react-navigation/react-navigation)):
```
const takePictureAndShow = () => {
@ -43,7 +47,7 @@ const { navigation } = this.props;
## Sending the image to a server
A good way is to get the base64 string representation of your image. You can get it from RNCamera by passing the `base64: true` option lto `takePictureAsync` like:
A good way is to get the base64 string representation of your image. You can get it from RNCamera by passing the `base64: true` option to `takePictureAsync` like:
```
if (this.camera) {
@ -81,9 +85,9 @@ Use this package https://github.com/phuochau/react-native-thumbnail
Because of different project requirements there is no gesture zoom (like pinch zoom or slide-up zoom) implemented in this package. All implementation should be done in user-land.
However we have some recipies for common zoom behaviours. If you implemented your own solution feel free to add it to the list!
However we have some recipes for common zoom behaviours. If you implemented your own solution feel free to add it to the list!
### SlideUp Zoom
## SlideUp Zoom
```js
import React, { Component } from 'react';

56
docs/Tidelift.md Normal file
View File

@ -0,0 +1,56 @@
---
id: Tidelift
title: React-Native-Camera for Enterprise
---
## React-Native-Camera for Enterprise
### Available as part of the Tidelift Subscription
**Tidelift** is working with the maintainers of **React-Native-Camera** and thousands of other open source projects to deliver
commercial support and maintenance for the open source dependencies you use to build your applications.
Save time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use.
[LEARN MORE](https://tidelift.com/subscription/pkg/npm-react-native-camera?utm_source=npm-react-native-camera&utm_medium=referral&utm_campaign=enterprise)
[REQUEST A DEMO](https://tidelift.com/subscription/request-a-demo?utm_source=npm-react-native-camera&utm_medium=referral&utm_campaign=enterprise)
### Enterprise-ready open source software - managed for you
The Tidelift Subscription is a managed open source subscription for application dependencies covering millions
of open source projects across JavaScript, Python, Java, PHP, Ruby, .NET, and more.
Your subscription includes:
* **Security updates**<br />
Tidelifts security response team coordinates patches for new breaking security vulnerabilities and alerts
immediately through a private channel, so your software supply chain is always secure.
* **Licensing verification and indemnification**<br />
Tidelift verifies license information to enable easy policy enforcement and adds intellectual property
indemnification to cover creators and users in case something goes wrong. You always have a 100% up-to-date
bill of materials for your dependencies to share with your legal team, customers, or partners.
* **Maintenance and code improvement**<br />
Tidelift ensures the software you rely on keeps working as long as you need it to work.
Your managed dependencies are actively maintained and we recruit additional maintainers where required.
* **Package selection and version guidance**<br />
We help you choose the best open source packages from the start—and then guide you through updates to stay on
the best releases as new issues arise.
* **Roadmap input**<br />
Take a seat at the table with the creators behind the software you use. Tidelifts participating maintainers
earn more income as their software is used by more subscribers, so theyre interested in knowing what you need.
* **Tooling and cloud integration**<br />
Tidelift works with GitHub, GitLab, BitBucket, and more.
We support every cloud platform (and other deployment targets, too).
The end result? All of the capabilities you expect from commercial-grade software, for the full breadth
of open source you use. That means less time grappling with esoteric open source trivia, and more
time building your own applications—and your business.
[LEARN MORE](https://tidelift.com/subscription/pkg/npm-react-native-camera?utm_source=npm-react-native-camera&utm_medium=referral&utm_campaign=enterprise)
[REQUEST A DEMO](https://tidelift.com/subscription/request-a-demo?utm_source=npm-react-native-camera&utm_medium=referral&utm_campaign=enterprise)

View File

@ -1,4 +1,8 @@
# [Expo](https://expo.io/) Usage
---
id: expo_usage
title: Expo Usage
sidebar_label: Expo Usage
---
RNCamera of react-native-camera is heavily based on Expo camera module. Thanks @aalices and Expo for the great work.

468
docs/installation.md Normal file
View File

@ -0,0 +1,468 @@
---
id: installation
title: Installation
---
This document is split into two main sections:
1. Required installation steps for basic usage of `react-native-camera`
2. Additional installation steps for usage of Face Detection/Text Recognition/BarCode with [MLKit](https://developers.google.com/ml-kit)
# Required installation steps
_These steps assume installation for iOS/Android. To install it with Windows, see [Windows](#windows) below_
## Mostly automatic install with autolinking (RN > 0.60)
1. `npm install react-native-camera --save`
2. Run `cd ios && pod install && cd ..`
## Mostly automatic install with react-native link (RN < 0.60)
1. `npm install react-native-camera --save`
2. `react-native link react-native-camera`
## Manual install - iOS (not recommended)
1. `npm install react-native-camera --save`
2. In XCode, in the project navigator, right click `Libraries``Add Files to [your project's name]`
3. Go to `node_modules``react-native-camera` and add `RNCamera.xcodeproj`
4. Expand the `RNCamera.xcodeproj``Products` folder
5. In XCode, in the project navigator, select your project. Add `libRNCamera.a` to your project's `Build Phases``Link Binary With Libraries`
6. Click `RNCamera.xcodeproj` in the project navigator and go the `Build Settings` tab. Make sure 'All' is toggled on (instead of 'Basic'). In the `Search Paths` section, look for `Header Search Paths` and make sure it contains both `$(SRCROOT)/../../react-native/React` and `$(SRCROOT)/../../../React` - mark both as `recursive`.
## Manual install - Android (not recommended)
1. `npm install react-native-camera --save`
2. Open up `android/app/src/main/java/[...]/MainApplication.java`
- Add `import org.reactnative.camera.RNCameraPackage;` to the imports at the top of the file
- Add `new RNCameraPackage()` to the list returned by the `getPackages()` method. Add a comma to the previous item if there's already something there.
3. Append the following lines to `android/settings.gradle`:
```gradle
include ':react-native-camera'
project(':react-native-camera').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-camera/android')
```
4. Insert the following lines in `android/app/build.gradle` inside the dependencies block:
```gradle
implementation project(':react-native-camera')
```
## iOS - other required steps
Add permissions with usage descriptions to your app `Info.plist`:
```xml
<!-- Required with iOS 10 and higher -->
<key>NSCameraUsageDescription</key>
<string>Your message to user when the camera is accessed for the first time</string>
<!-- Required with iOS 11 and higher: include this only if you are planning to use the camera roll -->
<key>NSPhotoLibraryAddUsageDescription</key>
<string>Your message to user when the photo library is accessed for the first time</string>
<!-- Include this only if you are planning to use the camera roll -->
<key>NSPhotoLibraryUsageDescription</key>
<string>Your message to user when the photo library is accessed for the first time</string>
<!-- Include this only if you are planning to use the microphone for video recording -->
<key>NSMicrophoneUsageDescription</key>
<string>Your message to user when the microphone is accessed for the first time</string>
```
<details>
<summary>Additional information in case of problems</summary>
You might need to adjust your Podfile following the example below:
```ruby
target 'yourTargetName' do
# See http://facebook.github.io/react-native/docs/integration-with-existing-apps.html#configuring-cocoapods-dependencies
pod 'React', :path => '../node_modules/react-native', :subspecs => [
'Core',
'CxxBridge', # Include this for RN >= 0.47
'DevSupport', # Include this to enable In-App Devmenu if RN >= 0.43
'RCTText',
'RCTNetwork',
'RCTWebSocket', # Needed for debugging
'RCTAnimation', # Needed for FlatList and animations running on native UI thread
# Add any other subspecs you want to use in your project
]
# Explicitly include Yoga if you are using RN >= 0.42.0
pod 'yoga', :path => '../node_modules/react-native/ReactCommon/yoga'
# Third party deps podspec link
pod 'react-native-camera', path: '../node_modules/react-native-camera'
end
post_install do |installer|
installer.pods_project.targets.each do |target|
if target.name == "React"
target.remove_from_project
end
end
end
```
</details>
## Android - other required steps
Add permissions to your app `android/app/src/main/AndroidManifest.xml` file:
```xml
<!-- Required -->
<uses-permission android:name="android.permission.CAMERA" />
<!-- Include this only if you are planning to use the camera roll -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- Include this only if you are planning to use the microphone for video recording -->
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
```
Insert the following lines in `android/app/build.gradle`:
```gradle
android {
...
defaultConfig {
...
missingDimensionStrategy 'react-native-camera', 'general' // <--- insert this line
}
}
```
<details>
<summary>Additional information in case of problems</summary>
1. Make sure you use `JDK >= 1.7` and your `buildToolsVersion >= 25.0.2`
2. Make sure you have jitpack added in `android/build.gradle`
```gradle
allprojects {
repositories {
maven { url "https://www.jitpack.io" }
maven { url "https://maven.google.com" }
}
}
```
</details>
# Additional installation steps
Follow these optional steps if you want to use Face Detection/Text Recognition/BarCode with [MLKit](https://developers.google.com/ml-kit).
You will need to set-up Firebase project for your app (detailed steps below).
_Note:_ Installing [react-native-firebase](https://github.com/invertase/react-native-firebase) package is NOT necessary.
## iOS
If you want any of these optional features, you will need to use CocoaPods.
### Modifying Podfile
Add dependency towards `react-native-camera` in your `Podfile` with `subspecs` using one of the following:
- For Face Detection:
```ruby
pod 'react-native-camera', path: '../node_modules/react-native-camera', subspecs: [
'FaceDetectorMLKit'
]
```
- For Text Recognition:
```ruby
pod 'react-native-camera', path: '../node_modules/react-native-camera', subspecs: [
'TextDetector'
]
```
- For BarCode Recognition:
```ruby
pod 'react-native-camera', path: '../node_modules/react-native-camera', subspecs: [
'BarcodeDetectorMLKit'
]
```
- For all possible detections:
```ruby
pod 'react-native-camera', path: '../node_modules/react-native-camera', subspecs: [
'TextDetector',
'FaceDetectorMLKit',
'BarcodeDetectorMLKit'
]
```
Then run `cd ios && pod install && cd ..`
### Setting up Firebase
Text/Face recognition for iOS uses Firebase MLKit which requires setting up Firebase project for your app.
If you have not already added Firebase to your app, please follow the steps described in [getting started guide](https://firebase.google.com/docs/ios/setup).
In short, you would need to
1. Register your app in Firebase console.
2. Download `GoogleService-Info.plist` and add it to your project
3. Add `pod 'Firebase/Core'` to your podfile
4. In your `AppDelegate.m` file add the following lines:
```objective-c
#import <Firebase.h> // <--- add this
...
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[FIRApp configure]; // <--- add this
...
}
```
<details>
<summary>Additional information in case of problems</summary>
- If you have issues with duplicate symbols you will need to enable dead code stripping option in your Xcode (Target > Build Settings > search for "Dead code stripping") [see here](https://github.com/firebase/quickstart-ios/issues/487#issuecomment-415313053).
- If you are using `pod Firebase/Core` with a version set below 5.13 you might want to add `pod 'GoogleAppMeasurement', '~> 5.3.0'` to your podfile
</details>
## Android
### Modifying build.gradle
Modify the following lines in `android/app/build.gradle`:
```gradle
android {
...
defaultConfig {
...
missingDimensionStrategy 'react-native-camera', 'mlkit' // <--- replace general with mlkit
}
}
```
### Setting up Firebase
Using Firebase MLKit requires seting up Firebase project for your app. If you have not already added Firebase to your app, please follow the steps described in [getting started guide](https://firebase.google.com/docs/android/setup).
In short, you would need to
1. Register your app in Firebase console.
2. Download google-services.json and place it in `android/app/`
3. Add the folowing to project level `build.gradle`:
```gradle
buildscript {
dependencies {
// Add this line
classpath 'com.google.gms:google-services:4.0.1' // <--- you might want to use different version
}
}
```
4. add to the bottom of `android/app/build.gradle` file
```gradle
apply plugin: 'com.google.gms.google-services'
```
5. Configure your app to automatically download the ML model to the device after your app is installed from the Play Store. If you do not enable install-time model downloads, the model will be downloaded the first time you run the on-device detector. Requests you make before the download has completed will produce no results.
```xml
<application ...>
...
<meta-data
android:name="com.google.firebase.ml.vision.DEPENDENCIES"
android:value="ocr, face" /> <!-- choose models that you will use -->
</application>
```
<details>
<summary>Additional information in case of problems</summary>
The current Android library defaults to the below values for the Google SDK and Libraries,
```gradle
def DEFAULT_COMPILE_SDK_VERSION = 26
def DEFAULT_BUILD_TOOLS_VERSION = "26.0.2"
def DEFAULT_TARGET_SDK_VERSION = 26
def DEFAULT_GOOGLE_PLAY_SERVICES_VERSION = "12.0.1"
def DEFAULT_SUPPORT_LIBRARY_VERSION = "27.1.0"
```
You can override this settings by adding a Project-wide gradle configuration properties for
use by all modules in your ReactNative project by adding the below to `android/build.gradle`
file,
```gradle
buildscript {...}
allprojects {...}
/**
* Project-wide gradle configuration properties for use by all modules
*/
ext {
compileSdkVersion = 26
targetSdkVersion = 26
buildToolsVersion = "26.0.2"
googlePlayServicesVersion = "12.0.1"
googlePlayServicesVisionVersion = "15.0.2"
supportLibVersion = "27.1.0"
}
```
The above settings in the ReactNative project over-rides the values present in the `react-native-camera`
module. For your reference below is the `android/build.gradle` file of the module.
```gradle
def safeExtGet(prop, fallback) {
rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
}
buildscript {
repositories {
google()
maven {
url 'https://maven.google.com'
}
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.3.1'
}
}
apply plugin: 'com.android.library'
android {
compileSdkVersion safeExtGet('compileSdkVersion', 28)
buildToolsVersion safeExtGet('buildToolsVersion', '28.0.3')
defaultConfig {
minSdkVersion safeExtGet('minSdkVersion', 16)
targetSdkVersion safeExtGet('targetSdkVersion', 28)
}
flavorDimensions "react-native-camera"
productFlavors {
general {
dimension "react-native-camera"
}
mlkit {
dimension "react-native-camera"
}
}
sourceSets {
main {
java.srcDirs = ['src/main/java']
}
general {
java.srcDirs = ['src/general/java']
}
mlkit {
java.srcDirs = ['src/mlkit/java']
}
}
lintOptions {
abortOnError false
warning 'InvalidPackage'
}
}
repositories {
google()
jcenter()
maven {
url 'https://maven.google.com'
}
maven { url "https://jitpack.io" }
maven {
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
url "$rootDir/../node_modules/react-native/android"
}
}
dependencies {
def googlePlayServicesVisionVersion = safeExtGet('googlePlayServicesVisionVersion', safeExtGet('googlePlayServicesVersion', '17.0.2'))
implementation 'com.facebook.react:react-native:+'
implementation "com.google.zxing:core:3.3.3"
implementation "com.drewnoakes:metadata-extractor:2.11.0"
generalImplementation "com.google.android.gms:play-services-vision:$googlePlayServicesVisionVersion"
implementation "com.android.support:exifinterface:${safeExtGet('supportLibVersion', '28.0.0')}"
implementation "com.android.support:support-annotations:${safeExtGet('supportLibVersion', '28.0.0')}"
implementation "com.android.support:support-v4:${safeExtGet('supportLibVersion', '28.0.0')}"
mlkitImplementation "com.google.firebase:firebase-ml-vision:${safeExtGet('firebase-ml-vision', '19.0.3')}"
mlkitImplementation "com.google.firebase:firebase-ml-vision-face-model:${safeExtGet('firebase-ml-vision-face-model', '17.0.2')}"
}
```
If you are using a version of `googlePlayServicesVersion` that does not have `play-services-vision`, you can specify a different version of `play-services-vision` by adding `googlePlayServicesVisionVersion` to the project-wide properties
```gradle
ext {
compileSdkVersion = 26
targetSdkVersion = 26
buildToolsVersion = "26.0.2"
googlePlayServicesVersion = "16.0.1"
googlePlayServicesVisionVersion = "15.0.2"
supportLibVersion = "27.1.0"
}
```
</details>
# Windows
## Mostly automatic install with autolinking (RNW >= 0.63)
1. `npm install react-native-camera --save`
2. See [Additional steps - Windows](#additional-steps-windows) below
## Manual install - Windows (RNW 0.62)
1. `npm install react-native-camera --save`
2. Link the library as described below:
1. Add the _ReactNativeCameraCPP_ project to your solution (eg. `windows\yourapp.sln`)
1. Open your solution in Visual Studio 2019
2. Right-click Solution icon in Solution Explorer > Add > Existing Project...
3. Select `node_modules\react-native-camera\windows\ReactNativeCameraCPP\ReactNativeCameraCPP.vcxproj`
2. Add a reference to _ReactNativeCameraCPP_ to your main application project (eg. `windows\yourapp\yourapp.vcxproj`)
1. Open your solution in Visual Studio 2019
2. Right-click main application project > Add > Reference...
3. Check _ReactNativeCameraCPP_ from Solution Projects
3. Modify files below to add the package providers to your main application project
1. `pch.h`
1. Add `#include "winrt/ReactNativeCameraCPP.h"`
2. `App.cpp`
1. Add `PackageProviders().Append(winrt::ReactNativeCameraCPP::ReactPackageProvider());` before `InitializeComponent();`
4. See [Additional steps - Windows](#additional-steps-windows) below
## Manual install - Windows (RNW 0.61)
Follow [Manual install - Windows (RNW 0.62)](#manual-install-windows-rnw-062) above, but for step 2 substitute _ReactNativeCameraCPP61_ for _ReactNativeCameraCPP_.
## Additional steps - Windows
You need to declare that your app wants to access the camera:
1. Add the capabilities (permissions) for the webcam and microphone as described here: [Add capability declarations to the app manifest](https://docs.microsoft.com/en-us/windows/uwp/audio-video-camera/simple-camera-preview-access#add-capability-declarations-to-the-app-manifest)
2. If you plan on capturing images to the Pictures Library, or videos to the Videos Library, be sure to enable those capabilities too
Follow the [Q & A](QA.md) section if you are having compilation issues.

View File

@ -1,4 +1,8 @@
# Migrating from RCTCamera to RNCamera
---
id: migration
title: Migrating from RCTCamera to RNCamera
sidebar_label: Migrating from RCTCamera to RNCamera
---
## Project Integration

109
docs/migrationV2.md Normal file
View File

@ -0,0 +1,109 @@
---
id: migrationv2
title: Migrating from version 1.x to 2.x
sidebar_label: Migrating from version 1.x to 2.x
---
Version 2.x of react-native-camera moves to using Firebase MLKit for advanced features such as text/face recognition. Users can now opt into useing MLKit in their app by choosing a certain flavor of the library (Android) or selecting a desired podspec (iOS). This allows users who do not need Firebase MLKit-based features to not be forced to set up a Firebase project.
## Required steps
### a. No advanced features/ opt into using deprecated Google Mobile Vision
#### Android
Please insert the following line in `android/app/build.gradle` inside defaultConfig block:
```gradle
android {
...
defaultConfig {
...
missingDimensionStrategy 'react-native-camera', 'general' <-- insert this line
}
}
```
#### iOS
No additional steps required
### b. Text/Face/Barcode detection using Firebase MLKit
#### Android
1. Please insert the following line in `android/app/build.gradle`, inside defaultConfig block:
```gradle
android {
...
defaultConfig {
...
missingDimensionStrategy 'react-native-camera', 'mlkit' <-- insert this line
}
}
```
2. The use of Firebase MLKit requires seting up Firebase project for your app. If you have not already added Firebase to your app, please follow the steps described in [getting started guide](https://firebase.google.com/docs/android/setup).
In short, you would need to
- Register your app in Firebase console.
- Download google-services.json and place it in `android/app/`
- add the folowing to project level build.gradle:
```gradle
buildscript {
dependencies {
// Add this line
classpath 'com.google.gms:google-services:4.0.1' <-- you might want to use different version
}
}
```
- add to the bottom of `android/app/build.gradle` file the following:
```gradle
apply plugin: 'com.google.gms.google-services'
```
3. Configure your app to automatically download the ML model to the device after your app is installed from the Play Store. If you do not enable install-time model downloads, the model will be downloaded the first time you run the on-device detector. Requests you make before the download has completed will produce no results.
```xml
<application ...>
...
<meta-data
android:name="com.google.firebase.ml.vision.DEPENDENCIES"
android:value="ocr" />
<!-- To use multiple models, list all needed models: android:value="ocr, face, barcode" -->
</application>
```
#### iOS
1. The use of Firebase MLKit requires setting up Firebase project for your app.
If you have not already added Firebase to your app, please follow the steps described in [getting started guide](https://firebase.google.com/docs/ios/setup).
In short, you would need to
- Register your app in Firebase console.
- Download `GoogleService-Info.plist` and add it to your project
- Add `pod 'Firebase/Core'` to your Podfile
- In your `AppDelegate.m` file add the following lines:
```objective-c
#import <Firebase.h> // <--- add this
...
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[FIRApp configure]; // <--- add this
...
}
```
2. Check that you have selected a correct podspec in your Podfile, e.g. if you want to use Text Recognition, your Podfile should contain the following:
```
pod 'react-native-camera', path: '../node_modules/react-native-camera', subspecs: [
'TextDetector'
]
```

View File

@ -1,28 +1,28 @@
# react-navigation
---
id: react-navigation
title: React Navigation
sidebar_label: React Navigation
---
React-navigation does not unmount components when switching between tabs. So when you leave and return back to the screen with the camera component it will just be black view. So a good solution is to use `componentDidMount` and added two listeners `willFocus` and `willBlur` to help you mount and unmount the views.
React-navigation does not unmount components when switching between tabs. So when you leave and return back to the screen with the camera component it will just be black view. So a good solution is to use `withNavigationFocus`, which is a higher order component, and wrap it around your component. Then, you can have access to `isFocused` from `props`.
```jsx
componentDidMount() {
const { navigation } = this.props;
navigation.addListener('willFocus', () =>
this.setState({ focusedScreen: true })
);
navigation.addListener('willBlur', () =>
this.setState({ focusedScreen: false })
);
}
import { withNavigationFocus } from 'react-navigation'
render() {
const { hasCameraPermission, focusedScreen } = this.state;
if (hasCameraPermission === null) {
return <View />;
} else if (hasCameraPermission === false) {
return <Text>No access to camera</Text>;
} else if (focusedScreen){
return (this.cameraView());
} else {
return <View />;
}
const { isFocused } = this.props
const { hasCameraPermission } = this.state;
if (hasCameraPermission === null) {
return <View />;
} else if (hasCameraPermission === false) {
return <Text>No access to camera</Text>;
} else if (isFocused){
return (this.cameraView());
} else {
return <View />;
}
}
export default withNavigationFocus(YourComponent)
```

View File

@ -1,5 +1,8 @@
# Testing
---
id: tests
title: Testing
sidebar_label: Testing
---
## Jest
To test a component which use RNCamera, you need to create a react-native-camera.js file inside your **mocks** folder on the root of your project with the following content:

4
examples/advanced/.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
# OSX
#
.DS_Store
.vscode

View File

@ -0,0 +1,6 @@
[android]
target = Google Inc.:Google APIs:23
[maven_repositories]
central = https://repo1.maven.org/maven2

View File

@ -0,0 +1,4 @@
module.exports = {
root: true,
extends: '@react-native-community',
};

View File

@ -0,0 +1,75 @@
[ignore]
; We fork some components by platform
.*/*[.]android.js
; Ignore "BUCK" generated dirs
<PROJECT_ROOT>/\.buckd/
; Ignore polyfills
node_modules/react-native/Libraries/polyfills/.*
; These should not be required directly
; require from fbjs/lib instead: require('fbjs/lib/warning')
node_modules/warning/.*
; Flow doesn't support platforms
.*/Libraries/Utilities/LoadingView.js
[untyped]
.*/node_modules/@react-native-community/cli/.*/.*
[include]
[libs]
node_modules/react-native/Libraries/react-native/react-native-interface.js
node_modules/react-native/flow/
[options]
emoji=true
esproposal.optional_chaining=enable
esproposal.nullish_coalescing=enable
module.file_ext=.js
module.file_ext=.json
module.file_ext=.ios.js
munge_underscores=true
module.name_mapper='^react-native$' -> '<PROJECT_ROOT>/node_modules/react-native/Libraries/react-native/react-native-implementation'
module.name_mapper='^react-native/\(.*\)$' -> '<PROJECT_ROOT>/node_modules/react-native/\1'
module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> '<PROJECT_ROOT>/node_modules/react-native/Libraries/Image/RelativeImageStub'
suppress_type=$FlowIssue
suppress_type=$FlowFixMe
suppress_type=$FlowFixMeProps
suppress_type=$FlowFixMeState
suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(<VERSION>\\)? *\\(site=[a-z,_]*react_native\\(_ios\\)?_\\(oss\\|fb\\)[a-z,_]*\\)?)\\)
suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(<VERSION>\\)? *\\(site=[a-z,_]*react_native\\(_ios\\)?_\\(oss\\|fb\\)[a-z,_]*\\)?)\\)?:? #[0-9]+
suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError
[lints]
sketchy-null-number=warn
sketchy-null-mixed=warn
sketchy-number=warn
untyped-type-import=warn
nonstrict-import=warn
deprecated-type=warn
unsafe-getters-setters=warn
inexact-spread=warn
unnecessary-invariant=warn
signature-verification-failure=warn
deprecated-utility=error
[strict]
deprecated-type
nonstrict-import
sketchy-null
unclear-type
unsafe-getters-setters
untyped-import
untyped-type-import
[version]
^0.105.0

View File

@ -0,0 +1 @@
*.pbxproj -text

59
examples/advanced/advanced/.gitignore vendored Normal file
View File

@ -0,0 +1,59 @@
# OSX
#
.DS_Store
# Xcode
#
build/
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
xcuserdata
*.xccheckout
*.moved-aside
DerivedData
*.hmap
*.ipa
*.xcuserstate
# Android/IntelliJ
#
build/
.idea
.gradle
local.properties
*.iml
# node.js
#
node_modules/
npm-debug.log
yarn-error.log
# BUCK
buck-out/
\.buckd/
*.keystore
!debug.keystore
# fastlane
#
# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
# screenshots whenever they are needed.
# For more information about the recommended setup visit:
# https://docs.fastlane.tools/best-practices/source-control/
*/fastlane/report.xml
*/fastlane/Preview.html
*/fastlane/screenshots
# Bundle artifact
*.jsbundle
# CocoaPods
/ios/Pods/

View File

@ -0,0 +1,6 @@
module.exports = {
bracketSpacing: false,
jsxBracketSameLine: true,
singleQuote: true,
trailingComma: 'all',
};

View File

@ -0,0 +1 @@
{}

Some files were not shown because too many files have changed in this diff Show More