@unif/react-native-camera 1.0.10 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (101) hide show
  1. package/lib/commonjs/camera/Camera.js +40 -7
  2. package/lib/commonjs/camera/Camera.js.map +1 -1
  3. package/lib/commonjs/camera/footer/Footer.js +3 -2
  4. package/lib/commonjs/camera/footer/Footer.js.map +1 -1
  5. package/lib/commonjs/camera/preview/PreView.js +6 -2
  6. package/lib/commonjs/camera/preview/PreView.js.map +1 -1
  7. package/lib/commonjs/camera/preview/PreViewContainer.js +3 -2
  8. package/lib/commonjs/camera/preview/PreViewContainer.js.map +1 -1
  9. package/lib/commonjs/camera/preview/PreviewFooter.js +1 -1
  10. package/lib/commonjs/camera/preview/SinglePre.js +7 -7
  11. package/lib/commonjs/camera/preview/SinglePre.js.map +1 -1
  12. package/lib/commonjs/camera/setup/SetUp.js +6 -10
  13. package/lib/commonjs/camera/setup/SetUp.js.map +1 -1
  14. package/lib/commonjs/camera/watermark/Render.js +110 -0
  15. package/lib/commonjs/camera/watermark/Render.js.map +1 -0
  16. package/lib/commonjs/camera/watermark/ViewShotWatermark.js +88 -0
  17. package/lib/commonjs/camera/watermark/ViewShotWatermark.js.map +1 -0
  18. package/lib/commonjs/camera/watermark/index.js +21 -0
  19. package/lib/commonjs/camera/watermark/index.js.map +1 -0
  20. package/lib/commonjs/utils/common.js +3 -2
  21. package/lib/commonjs/utils/common.js.map +1 -1
  22. package/lib/commonjs/utils/index.js +22 -0
  23. package/lib/commonjs/utils/index.js.map +1 -1
  24. package/lib/commonjs/utils/interface.js +1 -1
  25. package/lib/commonjs/utils/render-item.js +3 -2
  26. package/lib/commonjs/utils/render-item.js.map +1 -1
  27. package/lib/commonjs/utils/util.js +23 -0
  28. package/lib/commonjs/utils/util.js.map +1 -0
  29. package/lib/commonjs/utils/watermark.js +43 -0
  30. package/lib/commonjs/utils/watermark.js.map +1 -0
  31. package/lib/module/camera/Camera.js +41 -7
  32. package/lib/module/camera/Camera.js.map +1 -1
  33. package/lib/module/camera/footer/Footer.js +4 -3
  34. package/lib/module/camera/footer/Footer.js.map +1 -1
  35. package/lib/module/camera/index.js +1 -1
  36. package/lib/module/camera/preview/PreView.js +6 -2
  37. package/lib/module/camera/preview/PreView.js.map +1 -1
  38. package/lib/module/camera/preview/PreViewContainer.js +3 -2
  39. package/lib/module/camera/preview/PreViewContainer.js.map +1 -1
  40. package/lib/module/camera/preview/PreviewFooter.js +1 -1
  41. package/lib/module/camera/preview/SinglePre.js +7 -7
  42. package/lib/module/camera/preview/SinglePre.js.map +1 -1
  43. package/lib/module/camera/setup/SetUp.js +6 -10
  44. package/lib/module/camera/setup/SetUp.js.map +1 -1
  45. package/lib/module/camera/watermark/Render.js +102 -0
  46. package/lib/module/camera/watermark/Render.js.map +1 -0
  47. package/lib/module/camera/watermark/ViewShotWatermark.js +78 -0
  48. package/lib/module/camera/watermark/ViewShotWatermark.js.map +1 -0
  49. package/lib/module/camera/watermark/index.js +13 -0
  50. package/lib/module/camera/watermark/index.js.map +1 -0
  51. package/lib/module/utils/common.js +2 -1
  52. package/lib/module/utils/common.js.map +1 -1
  53. package/lib/module/utils/index.js +3 -1
  54. package/lib/module/utils/index.js.map +1 -1
  55. package/lib/module/utils/interface.js +1 -1
  56. package/lib/module/utils/render-item.js +3 -2
  57. package/lib/module/utils/render-item.js.map +1 -1
  58. package/lib/module/utils/util.js +16 -0
  59. package/lib/module/utils/util.js.map +1 -0
  60. package/lib/module/utils/watermark.js +33 -0
  61. package/lib/module/utils/watermark.js.map +1 -0
  62. package/lib/typescript/src/camera/Camera.d.ts.map +1 -1
  63. package/lib/typescript/src/camera/footer/Footer.d.ts.map +1 -1
  64. package/lib/typescript/src/camera/preview/PreView.d.ts.map +1 -1
  65. package/lib/typescript/src/camera/preview/SinglePre.d.ts +2 -0
  66. package/lib/typescript/src/camera/preview/SinglePre.d.ts.map +1 -1
  67. package/lib/typescript/src/camera/watermark/Render.d.ts +26 -0
  68. package/lib/typescript/src/camera/watermark/Render.d.ts.map +1 -0
  69. package/lib/typescript/src/camera/watermark/ViewShotWatermark.d.ts +33 -0
  70. package/lib/typescript/src/camera/watermark/ViewShotWatermark.d.ts.map +1 -0
  71. package/lib/typescript/src/camera/watermark/index.d.ts +4 -0
  72. package/lib/typescript/src/camera/watermark/index.d.ts.map +1 -0
  73. package/lib/typescript/src/utils/common.d.ts +1 -0
  74. package/lib/typescript/src/utils/common.d.ts.map +1 -1
  75. package/lib/typescript/src/utils/index.d.ts +2 -0
  76. package/lib/typescript/src/utils/index.d.ts.map +1 -1
  77. package/lib/typescript/src/utils/interface.d.ts +10 -0
  78. package/lib/typescript/src/utils/interface.d.ts.map +1 -1
  79. package/lib/typescript/src/utils/render-item.d.ts.map +1 -1
  80. package/lib/typescript/src/utils/util.d.ts +2 -0
  81. package/lib/typescript/src/utils/util.d.ts.map +1 -0
  82. package/lib/typescript/src/utils/watermark.d.ts +11 -0
  83. package/lib/typescript/src/utils/watermark.d.ts.map +1 -0
  84. package/package.json +12 -5
  85. package/src/camera/Camera.tsx +144 -104
  86. package/src/camera/footer/Footer.tsx +3 -1
  87. package/src/camera/index.tsx +1 -1
  88. package/src/camera/preview/PreView.tsx +4 -2
  89. package/src/camera/preview/PreViewContainer.tsx +2 -1
  90. package/src/camera/preview/PreviewFooter.tsx +1 -1
  91. package/src/camera/preview/SinglePre.tsx +5 -10
  92. package/src/camera/setup/SetUp.tsx +4 -3
  93. package/src/camera/watermark/Render.tsx +128 -0
  94. package/src/camera/watermark/ViewShotWatermark.tsx +81 -0
  95. package/src/camera/watermark/index.tsx +12 -0
  96. package/src/utils/common.ts +3 -1
  97. package/src/utils/index.ts +3 -1
  98. package/src/utils/interface.ts +12 -1
  99. package/src/utils/render-item.tsx +3 -2
  100. package/src/utils/util.ts +15 -0
  101. package/src/utils/watermark.ts +45 -0
@@ -2,7 +2,7 @@
2
2
  * @Author: 刘利军
3
3
  * @Date: 2024-12-02 11:52:31
4
4
  * @LastEditors: 刘利军
5
- * @LastEditTime: 2024-12-23 10:46:40
5
+ * @LastEditTime: 2024-12-30 13:11:06
6
6
  * @Description:
7
7
  * @PageName:
8
8
  */
@@ -99,11 +99,11 @@ const SetUp: React.FC<{
99
99
  return (
100
100
  <>
101
101
  {openHeader && (
102
- <View style={{ ...styles.top, ...styles.header, top: insets.top + 10 }}>
102
+ <View style={[styles.top, styles.header, { top: insets.top + 10 }]}>
103
103
  {/* <Text style={styles.text}></Text> */}
104
104
  </View>
105
105
  )}
106
- <View style={{ ...styles.top, ...styles.tools }}>
106
+ <View style={[styles.top, styles.tools]}>
107
107
  <View style={styles.tool}>
108
108
  <TouchableOpacity
109
109
  style={styles.toolImg}
@@ -237,6 +237,7 @@ const styles = StyleSheet.create({
237
237
  ...StyleSheet.absoluteFillObject,
238
238
  marginHorizontal: 20,
239
239
  bottom: undefined,
240
+ zIndex: 9,
240
241
  },
241
242
  header: {
242
243
  display: 'flex',
@@ -0,0 +1,128 @@
1
+ import { Dimensions, Image, StyleSheet, View } from 'react-native';
2
+ import React, { useState } from 'react';
3
+ import {
4
+ getContentMeasure,
5
+ getMeasure,
6
+ lastPx,
7
+ type WatermarkType,
8
+ } from '../../utils';
9
+ import Canvas, { Image as CanvasImage } from 'react-native-canvas';
10
+
11
+ const Render: React.FC<{
12
+ data: WatermarkType;
13
+ zIndex?: number;
14
+ }> = ({ data, zIndex }) => {
15
+ const [waterBase64, setWaterBase64] = useState<string>();
16
+
17
+ const getMarkSize = async (width: number, height: number) => {
18
+ let defaultWidth = lastPx(120);
19
+ let defaultHeight = lastPx(64);
20
+ if (!data?.image) {
21
+ defaultWidth = width;
22
+ defaultHeight = height;
23
+ }
24
+ return [data?.width ?? defaultWidth, data?.height ?? defaultHeight];
25
+ };
26
+
27
+ const handleImageRect = async (canvas: Canvas) => {
28
+ const ctx = canvas.getContext('2d');
29
+ const {
30
+ image,
31
+ content = [],
32
+ rotate = data.image ? 0 : -22,
33
+ gap = [100, 100],
34
+ } = data;
35
+
36
+ const measure = await getContentMeasure(ctx, content);
37
+
38
+ const [markWidth, markHeight] = await getMarkSize(
39
+ measure.width,
40
+ measure.height
41
+ );
42
+ const x = lastPx(gap[0] as number);
43
+ const y = lastPx(gap[1] as number);
44
+
45
+ const width = lastPx(markWidth as number);
46
+ const height = lastPx(markHeight as number);
47
+ canvas.width = width + x;
48
+ canvas.height = height + y;
49
+
50
+ const angle = (Math.PI * rotate) / 180;
51
+ ctx.translate(canvas.width * 0.5, canvas.height * 0.5);
52
+ const setDataURL = async () => {
53
+ const imgBase64 = await canvas.toDataURL();
54
+ const base = imgBase64.replace(/^"|"$/g, '');
55
+ setWaterBase64(base.split(',')[1]);
56
+ };
57
+ if (image) {
58
+ const canvasImage = new CanvasImage(canvas);
59
+ canvasImage.crossOrigin = 'anonymous';
60
+ canvasImage.src = image;
61
+ canvasImage.width = width;
62
+ canvasImage.height = height;
63
+
64
+ ctx.rotate(angle);
65
+
66
+ canvasImage.addEventListener('load', async () => {
67
+ ctx.drawImage(
68
+ canvasImage,
69
+ -canvas.height / 2,
70
+ -canvas.width / 2,
71
+ width,
72
+ height
73
+ );
74
+ setDataURL();
75
+ });
76
+ } else {
77
+ if (content.length > 0) {
78
+ ctx.font = `${lastPx(22)}px Arial`;
79
+ ctx.textAlign = 'center';
80
+ ctx.rotate(angle);
81
+ for (let index = 0; index < content.length; index++) {
82
+ const element = content[index];
83
+ const metrics = await getMeasure(ctx, element as string);
84
+ ctx.fillText(element as string, 0, metrics.height * (index + 1));
85
+ }
86
+ setDataURL();
87
+ }
88
+ }
89
+ };
90
+ return (
91
+ <View style={[styles.container, { zIndex }]}>
92
+ <View style={styles.watermark}>
93
+ {waterBase64 ? (
94
+ <Image
95
+ resizeMode="repeat"
96
+ source={{ uri: `data:image/png;base64,${waterBase64}` }}
97
+ style={{
98
+ width: Dimensions.get('window').width,
99
+ height: Dimensions.get('window').height,
100
+ }}
101
+ />
102
+ ) : (
103
+ <Canvas
104
+ ref={(canvas: Canvas) => canvas && handleImageRect(canvas)}
105
+ style={styles.canvas}
106
+ />
107
+ )}
108
+ </View>
109
+ </View>
110
+ );
111
+ };
112
+
113
+ export default Render;
114
+
115
+ export const styles = StyleSheet.create({
116
+ container: {
117
+ ...StyleSheet.absoluteFillObject,
118
+ },
119
+ watermark: {
120
+ display: 'flex',
121
+ flexWrap: 'wrap',
122
+ flex: 1,
123
+ flexDirection: 'row',
124
+ },
125
+ canvas: {
126
+ display: 'none',
127
+ },
128
+ });
@@ -0,0 +1,81 @@
1
+ /*
2
+ * @Author: 刘利军
3
+ * @Date: 2024-12-25 16:56:42
4
+ * @LastEditors: 刘利军
5
+ * @LastEditTime: 2024-12-30 13:07:33
6
+ * @Description:
7
+ * @PageName:
8
+ */
9
+ import { Image, StyleSheet, Text, View } from 'react-native';
10
+ import React, { useRef } from 'react';
11
+ import ViewShot from 'react-native-view-shot';
12
+ import WaterMarkRender from './Render';
13
+ import {
14
+ formatUri,
15
+ MAX_ZINDEX,
16
+ pxToDpWidth,
17
+ type CustomPhotoFile,
18
+ type WatermarkType,
19
+ } from '../../utils';
20
+
21
+ const ViewShotWatermark: React.FC<{
22
+ data?: CustomPhotoFile;
23
+ watermark?: WatermarkType;
24
+ onChange: (photo: CustomPhotoFile) => void;
25
+ }> = ({ data, watermark, onChange }) => {
26
+ const viewShotRef = useRef<ViewShot>(null);
27
+ if (!data || !watermark) {
28
+ return null;
29
+ }
30
+
31
+ const autoSaveWatermark = async () => {
32
+ const img = await viewShotRef.current?.capture?.();
33
+ onChange({ ...data, path: img || data.path });
34
+ };
35
+ return (
36
+ <>
37
+ <ViewShot ref={viewShotRef} style={styles.container}>
38
+ <Image
39
+ source={{ uri: formatUri(data.path) }}
40
+ style={styles.container}
41
+ onLoadEnd={() => {
42
+ setTimeout(() => {
43
+ autoSaveWatermark();
44
+ }, 800);
45
+ }}
46
+ />
47
+ <WaterMarkRender data={watermark} zIndex={MAX_ZINDEX + 1} />
48
+ </ViewShot>
49
+ <View style={styles.footer}>
50
+ <Text style={styles.text}>生成中...</Text>
51
+ </View>
52
+ </>
53
+ );
54
+ };
55
+
56
+ export default ViewShotWatermark;
57
+
58
+ export const styles = StyleSheet.create({
59
+ container: {
60
+ flex: 1,
61
+ position: 'absolute',
62
+ left: 0,
63
+ right: 0,
64
+ top: 0,
65
+ bottom: 0,
66
+ backgroundColor: '#fff',
67
+ zIndex: MAX_ZINDEX,
68
+ },
69
+ footer: {
70
+ position: 'absolute',
71
+ left: 0,
72
+ right: 0,
73
+ bottom: 24,
74
+ zIndex: MAX_ZINDEX + 2,
75
+ },
76
+ text: {
77
+ color: '#fff',
78
+ textAlign: 'center',
79
+ fontSize: pxToDpWidth(32),
80
+ },
81
+ });
@@ -0,0 +1,12 @@
1
+ /*
2
+ * @Author: 刘利军
3
+ * @Date: 2024-12-25 11:01:20
4
+ * @LastEditors: 刘利军
5
+ * @LastEditTime: 2024-12-30 13:08:49
6
+ * @Description:
7
+ * @PageName:
8
+ */
9
+
10
+ import WaterMarkRender from './Render';
11
+ import ViewShotWatermark from './ViewShotWatermark';
12
+ export { WaterMarkRender, ViewShotWatermark };
@@ -2,7 +2,7 @@
2
2
  * @Author: 刘利军
3
3
  * @Date: 2024-01-11 14:53:09
4
4
  * @LastEditors: 刘利军
5
- * @LastEditTime: 2024-12-20 17:05:50
5
+ * @LastEditTime: 2024-12-25 17:43:07
6
6
  * @Description:
7
7
  * @PageName:
8
8
  */
@@ -26,6 +26,8 @@ export const MAX_ZOOM_FACTOR = 10;
26
26
  // Control Button like Flash
27
27
  export const CONTROL_BUTTON_SIZE = 44;
28
28
 
29
+ export const MAX_ZINDEX = 99999;
30
+
29
31
  // 相机拍照模式
30
32
  export const CameraModeList: CameraModeListItem[] = [
31
33
  { label: '连拍', value: 'continuous' },
@@ -2,7 +2,7 @@
2
2
  * @Author: 刘利军
3
3
  * @Date: 2024-01-11 14:53:09
4
4
  * @LastEditors: 刘利军
5
- * @LastEditTime: 2024-12-17 16:54:04
5
+ * @LastEditTime: 2024-12-25 17:48:42
6
6
  * @Description:
7
7
  * @PageName:
8
8
  */
@@ -10,3 +10,5 @@ export * from './common';
10
10
  export * from './render-item';
11
11
  export * from './px-to-dp';
12
12
  export * from './interface';
13
+ export * from './watermark';
14
+ export * from './util';
@@ -2,7 +2,7 @@
2
2
  * @Author: 刘利军
3
3
  * @Date: 2024-01-12 11:38:13
4
4
  * @LastEditors: 刘利军
5
- * @LastEditTime: 2024-12-23 11:27:11
5
+ * @LastEditTime: 2024-12-27 10:42:36
6
6
  * @Description:
7
7
  * @PageName:
8
8
  */
@@ -45,6 +45,7 @@ export type DataRetainedModeType = 'retain' | 'clear';
45
45
  export type CameraProps = {
46
46
  cameraMode: CameraModeType[];
47
47
  dataRetainedMode: DataRetainedModeType;
48
+ watermark?: WatermarkType;
48
49
  };
49
50
 
50
51
  export type CameraModeListItem = {
@@ -77,6 +78,7 @@ import type { PhotoFile } from 'react-native-vision-camera';
77
78
 
78
79
  export interface CustomPhotoFile extends PhotoFile {
79
80
  mode: CameraMode;
81
+ frontTime: number;
80
82
  }
81
83
 
82
84
  export interface ConfirmConfigProps {
@@ -88,3 +90,12 @@ export interface ConfirmRef {
88
90
  open: (config?: ConfirmConfigProps) => Promise<boolean>;
89
91
  close: () => void;
90
92
  }
93
+
94
+ export type WatermarkType = {
95
+ content?: string[];
96
+ image?: string;
97
+ gap?: number[]; // 水印之间距离
98
+ rotate?: number; // 水印旋转角度
99
+ width?: number;
100
+ height?: number;
101
+ };
@@ -2,7 +2,7 @@
2
2
  * @Author: 刘利军
3
3
  * @Date: 2024-12-17 16:02:49
4
4
  * @LastEditors: 刘利军
5
- * @LastEditTime: 2024-12-18 14:40:10
5
+ * @LastEditTime: 2024-12-25 17:50:26
6
6
  * @Description:
7
7
  * @PageName:
8
8
  */
@@ -11,6 +11,7 @@ import type { CarouselRenderItem } from 'react-native-reanimated-carousel';
11
11
  import { SlideItem } from '../components';
12
12
  import React from 'react';
13
13
  import type { PhotoFile } from 'react-native-vision-camera';
14
+ import { formatUri } from './util';
14
15
 
15
16
  interface Options {
16
17
  rounded?: boolean;
@@ -28,7 +29,7 @@ export const renderItem =
28
29
  return (
29
30
  <SlideItem
30
31
  key={index}
31
- source={{ uri: `file://${item.path}` }}
32
+ source={{ uri: formatUri(item.path) }}
32
33
  index={index}
33
34
  rounded={rounded}
34
35
  style={style}
@@ -0,0 +1,15 @@
1
+ /*
2
+ * @Author: 刘利军
3
+ * @Date: 2024-12-25 17:48:18
4
+ * @LastEditors: 刘利军
5
+ * @LastEditTime: 2024-12-25 17:48:44
6
+ * @Description:
7
+ * @PageName:
8
+ */
9
+ export const formatUri = (uri: string) => {
10
+ const startPath = 'file://';
11
+ if (uri.startsWith(startPath)) {
12
+ return uri;
13
+ }
14
+ return `${startPath}${uri}`;
15
+ };
@@ -0,0 +1,45 @@
1
+ /*
2
+ * @Author: 刘利军
3
+ * @Date: 2024-12-25 13:51:40
4
+ * @LastEditors: 刘利军
5
+ * @LastEditTime: 2024-12-25 13:53:40
6
+ * @Description:
7
+ * @PageName:
8
+ */
9
+ import { PixelRatio, Platform } from 'react-native';
10
+ import { pxToDpWidth } from './px-to-dp';
11
+ import type { CanvasRenderingContext2D } from 'react-native-canvas';
12
+
13
+ export const lastPx = (v: number) =>
14
+ pxToDpWidth(v) / (Platform.OS === 'ios' ? PixelRatio.get() : 1);
15
+
16
+ export const getMeasure = async (
17
+ ctx: CanvasRenderingContext2D,
18
+ content: string
19
+ ) => {
20
+ const metrics = await ctx.measureText(content);
21
+ return {
22
+ width: metrics.width,
23
+ height: metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent,
24
+ };
25
+ };
26
+
27
+ export const getContentMeasure = async (
28
+ ctx: CanvasRenderingContext2D,
29
+ content: string[]
30
+ ) => {
31
+ let sizes: number[][] = [];
32
+
33
+ for (let index = 0; index < content.length; index++) {
34
+ const element = content[index];
35
+ const metrics = await getMeasure(ctx, element as string);
36
+ sizes.push([metrics.width, metrics.height]);
37
+ }
38
+ const defaultWidth = Math.ceil(
39
+ Math.max(...sizes.map((size) => size[0] as number))
40
+ );
41
+ const defaultHeight =
42
+ Math.ceil(Math.max(...sizes.map((size) => size[1] as number))) *
43
+ content.length;
44
+ return { width: defaultWidth, height: defaultHeight };
45
+ };