|
| 1 | +/** |
| 2 | + * Sample React Native App |
| 3 | + * https://github.com/facebook/react-native |
| 4 | + * |
| 5 | + * @format |
| 6 | + */ |
| 7 | + |
| 8 | +import React, {Component} from 'react'; |
| 9 | +import { |
| 10 | + Alert, |
| 11 | + Image, |
| 12 | + ScrollView, |
| 13 | + StyleSheet, |
| 14 | + Text, |
| 15 | + TouchableOpacity, |
| 16 | + View, |
| 17 | +} from 'react-native'; |
| 18 | +import ImagePicker from 'react-native-image-crop-picker'; |
| 19 | +import Video from 'react-native-video'; |
| 20 | + |
| 21 | +const styles = StyleSheet.create({ |
| 22 | + container: { |
| 23 | + flex: 1, |
| 24 | + justifyContent: 'center', |
| 25 | + alignItems: 'center', |
| 26 | + }, |
| 27 | + button: { |
| 28 | + backgroundColor: 'blue', |
| 29 | + marginBottom: 10, |
| 30 | + }, |
| 31 | + text: { |
| 32 | + color: 'white', |
| 33 | + fontSize: 20, |
| 34 | + textAlign: 'center', |
| 35 | + }, |
| 36 | +}); |
| 37 | + |
| 38 | +interface ImageState { |
| 39 | + uri: string; |
| 40 | + width: number; |
| 41 | + height: number; |
| 42 | + mime: string; |
| 43 | +} |
| 44 | + |
| 45 | +interface AppState { |
| 46 | + image: ImageState | null; |
| 47 | + images: ImageState[] | null; |
| 48 | +} |
| 49 | + |
| 50 | +export default class App extends Component<{}, AppState> { |
| 51 | + constructor(props: {}) { |
| 52 | + super(props); |
| 53 | + this.state = { |
| 54 | + image: null, |
| 55 | + images: null, |
| 56 | + }; |
| 57 | + } |
| 58 | + |
| 59 | + pickSingleWithCamera( |
| 60 | + cropping: boolean, |
| 61 | + mediaType: 'photo' | 'video' = 'photo', |
| 62 | + ) { |
| 63 | + ImagePicker.openCamera({ |
| 64 | + cropping: cropping, |
| 65 | + width: 500, |
| 66 | + height: 500, |
| 67 | + includeExif: true, |
| 68 | + mediaType, |
| 69 | + }) |
| 70 | + .then(image => { |
| 71 | + this.setState({ |
| 72 | + image: { |
| 73 | + uri: image.path, |
| 74 | + width: image.width, |
| 75 | + height: image.height, |
| 76 | + mime: image.mime, |
| 77 | + }, |
| 78 | + images: null, |
| 79 | + }); |
| 80 | + }) |
| 81 | + .catch(e => Alert.alert('Error', e.message)); |
| 82 | + } |
| 83 | + |
| 84 | + pickSingleBase64(cropit: boolean) { |
| 85 | + ImagePicker.openPicker({ |
| 86 | + width: 300, |
| 87 | + height: 300, |
| 88 | + cropping: cropit, |
| 89 | + includeBase64: true, |
| 90 | + includeExif: true, |
| 91 | + }) |
| 92 | + .then(image => { |
| 93 | + console.log('received base64 image'); |
| 94 | + this.setState({ |
| 95 | + image: { |
| 96 | + uri: `data:${image.mime};base64,` + (image as any).data, |
| 97 | + width: image.width, |
| 98 | + height: image.height, |
| 99 | + mime: image.mime, |
| 100 | + }, |
| 101 | + images: null, |
| 102 | + }); |
| 103 | + }) |
| 104 | + .catch(e => Alert.alert('Error', e.message)); |
| 105 | + } |
| 106 | + |
| 107 | + cleanupImages() { |
| 108 | + ImagePicker.clean() |
| 109 | + .then(() => { |
| 110 | + console.log('removed tmp images from tmp directory'); |
| 111 | + }) |
| 112 | + .catch(e => { |
| 113 | + Alert.alert('Error', e.message); |
| 114 | + }); |
| 115 | + } |
| 116 | + |
| 117 | + cleanupSingleImage() { |
| 118 | + let image = |
| 119 | + this.state.image || |
| 120 | + (this.state.images && this.state.images.length |
| 121 | + ? this.state.images[0] |
| 122 | + : null); |
| 123 | + console.log('will cleanup image', image); |
| 124 | + |
| 125 | + ImagePicker.cleanSingle(image?.uri || '') |
| 126 | + .then(() => { |
| 127 | + console.log(`removed tmp image ${image?.uri} from tmp directory`); |
| 128 | + }) |
| 129 | + .catch(e => { |
| 130 | + Alert.alert('Error', e.message); |
| 131 | + }); |
| 132 | + } |
| 133 | + |
| 134 | + cropLast() { |
| 135 | + if (!this.state.image) { |
| 136 | + return Alert.alert( |
| 137 | + 'No image', |
| 138 | + 'Before open cropping only, please select image', |
| 139 | + ); |
| 140 | + } |
| 141 | + |
| 142 | + ImagePicker.openCropper({ |
| 143 | + path: this.state.image.uri, |
| 144 | + width: 200, |
| 145 | + height: 200, |
| 146 | + mediaType: 'photo', |
| 147 | + }) |
| 148 | + .then(image => { |
| 149 | + console.log('received cropped image', image); |
| 150 | + this.setState({ |
| 151 | + image: { |
| 152 | + uri: image.path, |
| 153 | + width: image.width, |
| 154 | + height: image.height, |
| 155 | + mime: image.mime, |
| 156 | + }, |
| 157 | + images: null, |
| 158 | + }); |
| 159 | + }) |
| 160 | + .catch(e => { |
| 161 | + console.log(e); |
| 162 | + Alert.alert('Error', e.message); |
| 163 | + }); |
| 164 | + } |
| 165 | + |
| 166 | + pickSingle(cropit: boolean, circular: boolean = false) { |
| 167 | + ImagePicker.openPicker({ |
| 168 | + width: 500, |
| 169 | + height: 500, |
| 170 | + cropping: cropit, |
| 171 | + cropperCircleOverlay: circular, |
| 172 | + sortOrder: 'none', |
| 173 | + compressImageMaxWidth: 1000, |
| 174 | + compressImageMaxHeight: 1000, |
| 175 | + compressImageQuality: 1, |
| 176 | + compressVideoPreset: 'MediumQuality', |
| 177 | + includeExif: true, |
| 178 | + cropperStatusBarColor: 'white', |
| 179 | + cropperToolbarColor: 'white', |
| 180 | + cropperActiveWidgetColor: 'white', |
| 181 | + cropperToolbarWidgetColor: '#3498DB', |
| 182 | + }) |
| 183 | + .then(image => { |
| 184 | + console.log('received image', image); |
| 185 | + this.setState({ |
| 186 | + image: { |
| 187 | + uri: image.path, |
| 188 | + width: image.width, |
| 189 | + height: image.height, |
| 190 | + mime: image.mime, |
| 191 | + }, |
| 192 | + images: null, |
| 193 | + }); |
| 194 | + }) |
| 195 | + .catch(e => { |
| 196 | + console.log(e); |
| 197 | + Alert.alert('Error', e.message); |
| 198 | + }); |
| 199 | + } |
| 200 | + |
| 201 | + pickMultiple() { |
| 202 | + ImagePicker.openPicker({ |
| 203 | + multiple: true, |
| 204 | + waitAnimationEnd: false, |
| 205 | + sortOrder: 'desc', |
| 206 | + includeExif: true, |
| 207 | + forceJpg: true, |
| 208 | + }) |
| 209 | + .then(images => { |
| 210 | + this.setState({ |
| 211 | + image: null, |
| 212 | + images: images.map(i => { |
| 213 | + console.log('received image', i); |
| 214 | + return { |
| 215 | + uri: i.path, |
| 216 | + width: i.width, |
| 217 | + height: i.height, |
| 218 | + mime: i.mime, |
| 219 | + }; |
| 220 | + }), |
| 221 | + }); |
| 222 | + }) |
| 223 | + .catch(e => Alert.alert('Error', e.message)); |
| 224 | + } |
| 225 | + |
| 226 | + scaledHeight(oldW: number, oldH: number, newW: number) { |
| 227 | + return (oldH / oldW) * newW; |
| 228 | + } |
| 229 | + |
| 230 | + renderVideo(video: ImageState) { |
| 231 | + console.log('rendering video'); |
| 232 | + return ( |
| 233 | + <View style={{height: 300, width: 300}}> |
| 234 | + <Video |
| 235 | + source={{uri: video.uri, type: video.mime}} |
| 236 | + style={{position: 'absolute', top: 0, left: 0, bottom: 0, right: 0}} |
| 237 | + rate={1} |
| 238 | + paused={false} |
| 239 | + volume={1} |
| 240 | + muted={false} |
| 241 | + resizeMode={'cover'} |
| 242 | + onError={e => console.log(e)} |
| 243 | + onLoad={load => console.log(load)} |
| 244 | + repeat={true} |
| 245 | + /> |
| 246 | + </View> |
| 247 | + ); |
| 248 | + } |
| 249 | + |
| 250 | + renderImage(image: ImageState) { |
| 251 | + return ( |
| 252 | + <Image |
| 253 | + style={{width: 300, height: 300, resizeMode: 'contain'}} |
| 254 | + source={image} |
| 255 | + /> |
| 256 | + ); |
| 257 | + } |
| 258 | + |
| 259 | + renderAsset(image: ImageState) { |
| 260 | + if (image.mime && image.mime.toLowerCase().indexOf('video/') !== -1) { |
| 261 | + return this.renderVideo(image); |
| 262 | + } |
| 263 | + |
| 264 | + return this.renderImage(image); |
| 265 | + } |
| 266 | + |
| 267 | + render() { |
| 268 | + return ( |
| 269 | + <View style={styles.container}> |
| 270 | + <ScrollView> |
| 271 | + {this.state.image ? this.renderAsset(this.state.image) : null} |
| 272 | + {this.state.images |
| 273 | + ? this.state.images.map(i => ( |
| 274 | + <View key={i.uri}>{this.renderAsset(i)}</View> |
| 275 | + )) |
| 276 | + : null} |
| 277 | + </ScrollView> |
| 278 | + |
| 279 | + <TouchableOpacity |
| 280 | + onPress={() => this.pickSingleWithCamera(false)} |
| 281 | + style={styles.button}> |
| 282 | + <Text style={styles.text}>Select Single Image With Camera</Text> |
| 283 | + </TouchableOpacity> |
| 284 | + <TouchableOpacity |
| 285 | + onPress={() => this.pickSingleWithCamera(false, 'video')} |
| 286 | + style={styles.button}> |
| 287 | + <Text style={styles.text}>Select Single Video With Camera</Text> |
| 288 | + </TouchableOpacity> |
| 289 | + <TouchableOpacity |
| 290 | + onPress={() => this.pickSingleWithCamera(true)} |
| 291 | + style={styles.button}> |
| 292 | + <Text style={styles.text}> |
| 293 | + Select Single With Camera With Cropping |
| 294 | + </Text> |
| 295 | + </TouchableOpacity> |
| 296 | + <TouchableOpacity |
| 297 | + onPress={() => this.pickSingle(false)} |
| 298 | + style={styles.button}> |
| 299 | + <Text style={styles.text}>Select Single</Text> |
| 300 | + </TouchableOpacity> |
| 301 | + <TouchableOpacity onPress={() => this.cropLast()} style={styles.button}> |
| 302 | + <Text style={styles.text}>Crop Last Selected Image</Text> |
| 303 | + </TouchableOpacity> |
| 304 | + <TouchableOpacity |
| 305 | + onPress={() => this.pickSingleBase64(false)} |
| 306 | + style={styles.button}> |
| 307 | + <Text style={styles.text}>Select Single Returning Base64</Text> |
| 308 | + </TouchableOpacity> |
| 309 | + <TouchableOpacity |
| 310 | + onPress={() => this.pickSingle(true)} |
| 311 | + style={styles.button}> |
| 312 | + <Text style={styles.text}>Select Single With Cropping</Text> |
| 313 | + </TouchableOpacity> |
| 314 | + <TouchableOpacity |
| 315 | + onPress={() => this.pickSingle(true, true)} |
| 316 | + style={styles.button}> |
| 317 | + <Text style={styles.text}>Select Single With Circular Cropping</Text> |
| 318 | + </TouchableOpacity> |
| 319 | + <TouchableOpacity |
| 320 | + onPress={this.pickMultiple.bind(this)} |
| 321 | + style={styles.button}> |
| 322 | + <Text style={styles.text}>Select Multiple</Text> |
| 323 | + </TouchableOpacity> |
| 324 | + <TouchableOpacity |
| 325 | + onPress={this.cleanupImages.bind(this)} |
| 326 | + style={styles.button}> |
| 327 | + <Text style={styles.text}>Cleanup All Images</Text> |
| 328 | + </TouchableOpacity> |
| 329 | + <TouchableOpacity |
| 330 | + onPress={this.cleanupSingleImage.bind(this)} |
| 331 | + style={styles.button}> |
| 332 | + <Text style={styles.text}>Cleanup Single Image</Text> |
| 333 | + </TouchableOpacity> |
| 334 | + </View> |
| 335 | + ); |
| 336 | + } |
| 337 | +} |
0 commit comments