@react-native-ohos/react-native-image-crop-picker 0.40.4-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ COMMITTERS.md +9 -0
- package/.github/FUNDING.yml +1 -0
- package/CODE_OF_CONDUCT.md +0 -0
- package/CONTRIBUTING.md +68 -0
- package/ISSUE_TEMPLATE.md +34 -0
- package/LICENSE +21 -0
- package/OAT.xml +75 -0
- package/README.OpenSource +11 -0
- package/README.md +13 -0
- package/harmony/image_crop_picker/build-profile.json5 +8 -0
- package/harmony/image_crop_picker/hvigorfile.ts +1 -0
- package/harmony/image_crop_picker/index.ets +6 -0
- package/harmony/image_crop_picker/oh-package.json5 +10 -0
- package/harmony/image_crop_picker/src/main/cpp/CMakeLists.txt +9 -0
- package/harmony/image_crop_picker/src/main/cpp/ImageCropPickerPackage.h +19 -0
- package/harmony/image_crop_picker/src/main/cpp/generated/RNOH/generated/BaseReactNativeImageCropPickerPackage.h +66 -0
- package/harmony/image_crop_picker/src/main/cpp/generated/RNOH/generated/turbo_modules/ImageCropPicker.cpp +20 -0
- package/harmony/image_crop_picker/src/main/cpp/generated/RNOH/generated/turbo_modules/ImageCropPicker.h +16 -0
- package/harmony/image_crop_picker/src/main/ets/ImageCropPickerPackage.ts +28 -0
- package/harmony/image_crop_picker/src/main/ets/ImageCropPickerTurboModule.ts +1041 -0
- package/harmony/image_crop_picker/src/main/ets/Logger.ts +38 -0
- package/harmony/image_crop_picker/src/main/ets/generated/components/ts.ts +5 -0
- package/harmony/image_crop_picker/src/main/ets/generated/index.ets +5 -0
- package/harmony/image_crop_picker/src/main/ets/generated/ts.ts +6 -0
- package/harmony/image_crop_picker/src/main/ets/generated/turboModules/ImageCropPicker.ts +30 -0
- package/harmony/image_crop_picker/src/main/ets/generated/turboModules/ts.ts +5 -0
- package/harmony/image_crop_picker/src/main/ets/pages/ImageEditInfo.ets +862 -0
- package/harmony/image_crop_picker/src/main/ets/utils/Constants.ets +14 -0
- package/harmony/image_crop_picker/src/main/ets/utils/CropModel.ets +73 -0
- package/harmony/image_crop_picker/src/main/ets/utils/DecodeAndEncodeUtil.ets +54 -0
- package/harmony/image_crop_picker/src/main/ets/utils/EncodeUtil.ets +33 -0
- package/harmony/image_crop_picker/src/main/ets/utils/jul.ts +7 -0
- package/harmony/image_crop_picker/src/main/ets/utils/types.ets +94 -0
- package/harmony/image_crop_picker/src/main/ets/viewmodel/viewAndModel.ets +38 -0
- package/harmony/image_crop_picker/src/main/module.json5 +9 -0
- package/harmony/image_crop_picker/src/main/resources/base/element/string.json +20 -0
- package/harmony/image_crop_picker/src/main/resources/base/media/ic_anti_clockwise.png +0 -0
- package/harmony/image_crop_picker/src/main/resources/base/media/ic_clockwise.png +0 -0
- package/harmony/image_crop_picker/src/main/resources/base/media/ic_reset.png +0 -0
- package/harmony/image_crop_picker/src/main/resources/base/media/ic_save.png +0 -0
- package/harmony/image_crop_picker/src/main/resources/base/media/icon.png +0 -0
- package/harmony/image_crop_picker/src/main/resources/base/profile/main_pages.json +5 -0
- package/harmony/image_crop_picker/src/main/resources/en_US/element/string.json +8 -0
- package/harmony/image_crop_picker/src/main/resources/zh_CN/element/string.json +8 -0
- package/harmony/image_crop_picker/ts.ts +17 -0
- package/harmony/image_crop_picker.har +0 -0
- package/index.d.ts +512 -0
- package/js/NativeRNCImageCropPicker.ts +108 -0
- package/js/index.js +31 -0
- package/package.json +48 -0
- package/svg.svg +122 -0
|
@@ -0,0 +1,1041 @@
|
|
|
1
|
+
// Copyright (c) 2024 Huawei Device Co., Ltd. All rights reserved
|
|
2
|
+
// Use of this source code is governed by a MIT license that can be
|
|
3
|
+
// found in the LICENSE file.
|
|
4
|
+
|
|
5
|
+
import type { TurboModuleContext } from '@rnoh/react-native-openharmony/ts';
|
|
6
|
+
import { ImageCropPicker } from "./generated/turboModules/ImageCropPicker";
|
|
7
|
+
import { TurboModule } from '@rnoh/react-native-openharmony/ts'
|
|
8
|
+
import Logger from './Logger';
|
|
9
|
+
import type Want from '@ohos.app.ability.Want';
|
|
10
|
+
import image from '@ohos.multimedia.image';
|
|
11
|
+
import media from '@ohos.multimedia.media';
|
|
12
|
+
import util from '@ohos.util';
|
|
13
|
+
import uri from '@ohos.uri';
|
|
14
|
+
import picker from '@ohos.multimedia.cameraPicker';
|
|
15
|
+
import photoAccessHelper from '@ohos.file.photoAccessHelper';
|
|
16
|
+
import camera from '@ohos.multimedia.camera';
|
|
17
|
+
import { BusinessError } from '@ohos.base';
|
|
18
|
+
import fs, { Filter } from '@ohos.file.fs';
|
|
19
|
+
import { JSON } from '@kit.ArkTS';
|
|
20
|
+
import abilityAccessCtrl, { Permissions } from '@ohos.abilityAccessCtrl';
|
|
21
|
+
import { PermissionRequestResult } from '@ohos.abilityAccessCtrl';
|
|
22
|
+
|
|
23
|
+
import { window } from '@kit.ArkUI';
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
export type MediaType = 'photo' | 'video' | 'any';
|
|
27
|
+
|
|
28
|
+
export type OrderType = 'asc' | 'desc' | 'none';
|
|
29
|
+
|
|
30
|
+
export type ErrorCode = 'camera_unavailable' | 'permission' | 'others';
|
|
31
|
+
|
|
32
|
+
const MaxNumber = 5;
|
|
33
|
+
const MinNumber = 1;
|
|
34
|
+
const ImageQuality = 1;
|
|
35
|
+
const TAG: string = 'ImageCropPickerTurboModule';
|
|
36
|
+
const WANT_PARAM_URI_SELECT_SINGLE: string = 'singleselect';
|
|
37
|
+
const WANT_PARAM_URI_SELECT_MULTIPLE: string = 'multipleselect';
|
|
38
|
+
const ENTER_GALLERY_ACTION: string = "ohos.want.action.photoPicker";
|
|
39
|
+
const filePrefix = 'file://'
|
|
40
|
+
const atManager = abilityAccessCtrl.createAtManager();
|
|
41
|
+
const MINIMUM_VALUE = 1;
|
|
42
|
+
|
|
43
|
+
let avMetadataExtractor: media.AVMetadataExtractor;
|
|
44
|
+
|
|
45
|
+
export type SmartAlbums = | 'Regular' | 'SyncedEvent' | 'SyncedFaces';
|
|
46
|
+
|
|
47
|
+
export type CompressVideoPresets = | 'LowQuality' | 'MediumQuality' | 'HighestQuality' | 'Passthrough';
|
|
48
|
+
|
|
49
|
+
export type CropperOptions = ImageOptions & {
|
|
50
|
+
path: string;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export type Options = AnyOptions | VideoOptions | ImageOptions;
|
|
54
|
+
|
|
55
|
+
export type AnyOptions = Omit<ImageOptions, 'mediaType'> & Omit<VideoOptions, 'mediaType'> & {
|
|
56
|
+
mediaType?: 'any';
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
export type VideoOptions = CommonOptions & {
|
|
60
|
+
mediaType: 'video';
|
|
61
|
+
compressVideoPreset?: CompressVideoPresets;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
export type ImageOptions = CommonOptions & {
|
|
65
|
+
mediaType: MediaType;
|
|
66
|
+
width?: number;
|
|
67
|
+
height?: number;
|
|
68
|
+
includeBase64?: boolean;
|
|
69
|
+
includeExif?: boolean;
|
|
70
|
+
forceJpg?: boolean;
|
|
71
|
+
cropping?: boolean;
|
|
72
|
+
avoidEmptySpaceAroundImage?: boolean;
|
|
73
|
+
cropperActiveWidgetColor?: string;
|
|
74
|
+
cropperStatusBarColor?: string;
|
|
75
|
+
cropperToolbarColor?: string;
|
|
76
|
+
cropperToolbarWidgetColor?: string;
|
|
77
|
+
cropperToolbarTitle?: string;
|
|
78
|
+
freeStyleCropEnabled?: boolean;
|
|
79
|
+
cropperTintColor?: string;
|
|
80
|
+
cropperCircleOverlay?: boolean;
|
|
81
|
+
cropperCancelText?: string;
|
|
82
|
+
cropperCancelColor?: string;
|
|
83
|
+
cropperChooseText?: string;
|
|
84
|
+
cropperChooseColor?: string;
|
|
85
|
+
cropperRotateButtonsHidden?: boolean
|
|
86
|
+
showCropGuidelines?: boolean;
|
|
87
|
+
showCropFrame?: boolean;
|
|
88
|
+
enableRotationGesture?: boolean;
|
|
89
|
+
disableCropperColorSetters?: boolean;
|
|
90
|
+
compressImageMaxWidth?: number;
|
|
91
|
+
compressImageMaxHeight?: number;
|
|
92
|
+
compressImageQuality?: number;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export interface CommonOptions {
|
|
96
|
+
multiple?: boolean;
|
|
97
|
+
minFiles?: number;
|
|
98
|
+
maxFiles?: number;
|
|
99
|
+
waitAnimationEnd?: boolean;
|
|
100
|
+
smartAlbums?: SmartAlbums[];
|
|
101
|
+
useFrontCamera?: boolean;
|
|
102
|
+
loadingLabelText?: string;
|
|
103
|
+
showsSelectedCount?: boolean;
|
|
104
|
+
sortOrder?: 'none' | 'asc' | 'desc';
|
|
105
|
+
hideBottomControls?: boolean;
|
|
106
|
+
compressImageQuality?: number;
|
|
107
|
+
mediaType: MediaType;
|
|
108
|
+
width?: number;
|
|
109
|
+
height?: number;
|
|
110
|
+
includeBase64?: boolean;
|
|
111
|
+
includeExif?: boolean;
|
|
112
|
+
forceJpg?: boolean;
|
|
113
|
+
cropping?: boolean;
|
|
114
|
+
avoidEmptySpaceAroundImage?: boolean;
|
|
115
|
+
cropperActiveWidgetColor?: string;
|
|
116
|
+
cropperStatusBarColor?: string;
|
|
117
|
+
cropperToolbarColor?: string;
|
|
118
|
+
cropperToolbarWidgetColor?: string;
|
|
119
|
+
cropperToolbarTitle?: string;
|
|
120
|
+
freeStyleCropEnabled?: boolean;
|
|
121
|
+
cropperTintColor?: string;
|
|
122
|
+
cropperCircleOverlay?: boolean;
|
|
123
|
+
cropperCancelText?: string;
|
|
124
|
+
cropperCancelColor?: string;
|
|
125
|
+
cropperChooseText?: string;
|
|
126
|
+
cropperChooseColor?: string;
|
|
127
|
+
cropperRotateButtonsHidden?: boolean
|
|
128
|
+
showCropGuidelines?: boolean;
|
|
129
|
+
showCropFrame?: boolean;
|
|
130
|
+
enableRotationGesture?: boolean;
|
|
131
|
+
disableCropperColorSetters?: boolean;
|
|
132
|
+
compressImageMaxWidth?: number;
|
|
133
|
+
compressImageMaxHeight?: number;
|
|
134
|
+
writeTempFile?: boolean;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export interface Image extends ImageVideoCommon {
|
|
138
|
+
data?: string | null;
|
|
139
|
+
cropRect?: CropRect | null;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export interface Video extends ImageVideoCommon {
|
|
143
|
+
duration: number | null;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export interface CropRect {
|
|
147
|
+
x: number;
|
|
148
|
+
y: number;
|
|
149
|
+
width: number;
|
|
150
|
+
height: number;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export interface ImageOrVideo {
|
|
154
|
+
data?: string | null;
|
|
155
|
+
width?: number | null;
|
|
156
|
+
height?: number | null;
|
|
157
|
+
size?: number | null;
|
|
158
|
+
cropRect?: CropRect | null;
|
|
159
|
+
filename?: string | null;
|
|
160
|
+
path?: string | null;
|
|
161
|
+
exif?: Exif | null;
|
|
162
|
+
mime?: string | null;
|
|
163
|
+
sourceURL?: string | null;
|
|
164
|
+
creationDate?: string | null;
|
|
165
|
+
modificationDate?: string | null;
|
|
166
|
+
localIdentifier?: string | null;
|
|
167
|
+
duration?: string | null;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export interface ImageVideoCommon {
|
|
171
|
+
path: string;
|
|
172
|
+
size: number;
|
|
173
|
+
width: number;
|
|
174
|
+
height: number;
|
|
175
|
+
mime: string;
|
|
176
|
+
exif?: Exif;
|
|
177
|
+
localIdentifier?: string;
|
|
178
|
+
sourceURL?: string;
|
|
179
|
+
filename?: string;
|
|
180
|
+
creationDate?: string;
|
|
181
|
+
modificationDate?: string;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
export interface Exif {
|
|
185
|
+
BitsPerSample?: string;
|
|
186
|
+
Orientation?: string;
|
|
187
|
+
ImageLength?: string;
|
|
188
|
+
ImageWidth?: string;
|
|
189
|
+
GPSLatitude?: string;
|
|
190
|
+
GPSLongitude?: string;
|
|
191
|
+
GPSLatitudeRef?: string;
|
|
192
|
+
GPSLongitudeRef?: string;
|
|
193
|
+
DateTimeOriginal?: string;
|
|
194
|
+
ExposureTime?: string;
|
|
195
|
+
SceneType?: string;
|
|
196
|
+
ISOSpeedRatings?: string;
|
|
197
|
+
FNumber?: string;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
export class FilePath {
|
|
201
|
+
path?: string;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
export interface VideoImageInfo {
|
|
205
|
+
data?: string | null;
|
|
206
|
+
width?: number | null;
|
|
207
|
+
height?: number | null;
|
|
208
|
+
size?: number | null;
|
|
209
|
+
cropRect?: CropRect | null;
|
|
210
|
+
filename?: string | null;
|
|
211
|
+
path?: string | null;
|
|
212
|
+
exif?: Exif | null;
|
|
213
|
+
mime?: string | null;
|
|
214
|
+
sourceURL?: string | null;
|
|
215
|
+
creationDate?: number | null;
|
|
216
|
+
modificationDate?: number | null;
|
|
217
|
+
localIdentifier?: string | null;
|
|
218
|
+
duration?: string | null;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
export interface FilePathResult {
|
|
222
|
+
result?: FilePath[];
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
export class AbilityResult {
|
|
226
|
+
resultCode: number;
|
|
227
|
+
want?: Want;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
export class ImageCropPickerTurboModule extends TurboModule implements ImageCropPicker.Spec {
|
|
231
|
+
constructor(protected ctx: TurboModuleContext) {
|
|
232
|
+
super(ctx);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
isNullOrUndefined(value: any): boolean {
|
|
236
|
+
return value === null || value === undefined || value === '';
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
async openPicker(options?: Options): Promise<Video[] | Video | ImageOrVideo[] | ImageOrVideo | Image[] | Image> {
|
|
240
|
+
Logger.info(`${TAG} into openPicker request ${JSON.stringify(options)}`);
|
|
241
|
+
let cropping = this.isNullOrUndefined(options?.cropping) ? false : options?.cropping;
|
|
242
|
+
let minFiles = this.isNullOrUndefined(options?.minFiles) ? MinNumber : options.minFiles;
|
|
243
|
+
let maxFiles = this.isNullOrUndefined(options?.maxFiles) ? MaxNumber : options.maxFiles;
|
|
244
|
+
let isShowSerialNum = this.isNullOrUndefined(options?.showsSelectedCount) ? true : options?.showsSelectedCount;
|
|
245
|
+
if (options.multiple && minFiles > maxFiles) {
|
|
246
|
+
return new Promise(async (res, rej) => {
|
|
247
|
+
rej('minFiles is error')
|
|
248
|
+
})
|
|
249
|
+
}
|
|
250
|
+
let quality = options.compressImageQuality;
|
|
251
|
+
if (!this.isNullOrUndefined(quality) && !(quality >= 0 && quality <= 1)) {
|
|
252
|
+
return new Promise(async (res, rej) => {
|
|
253
|
+
rej('quality is error')
|
|
254
|
+
})
|
|
255
|
+
}
|
|
256
|
+
let multiple = this.isNullOrUndefined(options.multiple) ? false : options.multiple;
|
|
257
|
+
let mediaType = options.mediaType == 'photo' ? photoAccessHelper.PhotoViewMIMETypes.IMAGE_TYPE
|
|
258
|
+
: (options.mediaType == 'video' ? photoAccessHelper.PhotoViewMIMETypes.VIDEO_TYPE : photoAccessHelper.PhotoViewMIMETypes.IMAGE_VIDEO_TYPE);
|
|
259
|
+
|
|
260
|
+
let writeTempFile = this.isNullOrUndefined(options.writeTempFile) ? true : options.writeTempFile;
|
|
261
|
+
let qualityNumber = this.isNullOrUndefined(options.compressImageQuality) ? ImageQuality : options.compressImageQuality;
|
|
262
|
+
let forceJpg = this.isNullOrUndefined(options.forceJpg) ? false : options.forceJpg;
|
|
263
|
+
try {
|
|
264
|
+
let photoSelectOptions = new photoAccessHelper.PhotoSelectOptions();
|
|
265
|
+
photoSelectOptions.MIMEType = mediaType;
|
|
266
|
+
photoSelectOptions.maxSelectNumber = multiple ? maxFiles : 1;
|
|
267
|
+
photoSelectOptions.isSearchSupported = false;
|
|
268
|
+
let photoPicker = new photoAccessHelper.PhotoViewPicker();
|
|
269
|
+
let result: photoAccessHelper.PhotoSelectResult = await photoPicker.select(photoSelectOptions);
|
|
270
|
+
let sourceFilePaths: Array<string> = result.photoUris as Array<string>;
|
|
271
|
+
if (sourceFilePaths.length < MINIMUM_VALUE) {
|
|
272
|
+
return new Promise(async (res, rej) => {
|
|
273
|
+
rej('sourceFilePaths is empty')
|
|
274
|
+
})
|
|
275
|
+
}
|
|
276
|
+
let tempFilePaths = null;
|
|
277
|
+
Logger.info(`${TAG} into openPicker tempFilePaths ${JSON.stringify(sourceFilePaths)}`);
|
|
278
|
+
if (qualityNumber !== 1 || forceJpg) {
|
|
279
|
+
Logger.info(`${TAG} qualityNumber = ${qualityNumber} forceJpg = ${forceJpg}`);
|
|
280
|
+
tempFilePaths = await this.compressPictures(qualityNumber * 100, forceJpg, sourceFilePaths);
|
|
281
|
+
} else {
|
|
282
|
+
tempFilePaths = writeTempFile ? this.getTempFilePaths(sourceFilePaths) : null;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
let tempFilePath = null;
|
|
286
|
+
const isImg = tempFilePaths ? this.isImage(tempFilePaths[0]) : false;
|
|
287
|
+
if (!multiple && isImg && cropping) {
|
|
288
|
+
const imgCropPath = await this.intoCropper(tempFilePaths[0], options);
|
|
289
|
+
if (!this.isNullOrUndefined(imgCropPath)) {
|
|
290
|
+
tempFilePath = imgCropPath;
|
|
291
|
+
Logger.info(`${TAG} into openCamera imgCropPath = ${imgCropPath}`);
|
|
292
|
+
}
|
|
293
|
+
let exifInfo;
|
|
294
|
+
if (options?.includeExif) {
|
|
295
|
+
try {
|
|
296
|
+
let exifFile = fs.openSync(tempFilePath, fs.OpenMode.READ_ONLY);
|
|
297
|
+
let exifImageIS = image.createImageSource(exifFile.fd);
|
|
298
|
+
exifInfo = await this.getImageExif(exifImageIS);
|
|
299
|
+
} catch (err) {
|
|
300
|
+
Logger.error(`${TAG} into getPickerResult err : ${JSON.stringify(err)}`);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
let imgResult: Image = {
|
|
304
|
+
data: null,
|
|
305
|
+
cropRect: null,
|
|
306
|
+
path: null,
|
|
307
|
+
size: 0,
|
|
308
|
+
width: 0,
|
|
309
|
+
height: 0,
|
|
310
|
+
mime: '',
|
|
311
|
+
exif: null,
|
|
312
|
+
localIdentifier: '',
|
|
313
|
+
sourceURL: '',
|
|
314
|
+
filename: '',
|
|
315
|
+
creationDate: null,
|
|
316
|
+
modificationDate: null
|
|
317
|
+
};
|
|
318
|
+
await this.getFileInfo(options?.includeBase64, tempFilePath, null, exifInfo).then((imageInfo) => {
|
|
319
|
+
imgResult.path = filePrefix + imgCropPath;
|
|
320
|
+
imgResult.exif = imageInfo.exif;
|
|
321
|
+
imgResult.data = imageInfo.data;
|
|
322
|
+
imgResult.size = imageInfo.size;
|
|
323
|
+
imgResult.width = imageInfo.width;
|
|
324
|
+
imgResult.height = imageInfo.height;
|
|
325
|
+
imgResult.filename = imageInfo.filename;
|
|
326
|
+
imgResult.mime = imageInfo.mime;
|
|
327
|
+
imgResult.localIdentifier = imageInfo.localIdentifier;
|
|
328
|
+
imgResult.cropRect = imageInfo.cropRect;
|
|
329
|
+
imgResult.creationDate = imageInfo.creationDate + '';
|
|
330
|
+
imgResult.modificationDate = imageInfo.modificationDate + '';
|
|
331
|
+
})
|
|
332
|
+
return imgResult;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
return this.getPickerResult(options, sourceFilePaths, tempFilePaths);
|
|
336
|
+
} catch (error) {
|
|
337
|
+
Logger.error(`${TAG} PhotoViewPicker failed err: ${JSON.stringify(error)}`);
|
|
338
|
+
return new Promise(async (res, rej) => {
|
|
339
|
+
rej('PhotoViewPicker is failed')
|
|
340
|
+
})
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
getTempFilePaths(images: Array<string>): Array<string> {
|
|
345
|
+
let resultImages: Array<string> = new Array<string>();
|
|
346
|
+
Logger.info(`${TAG} getTempFilePaths images = ${images}`);
|
|
347
|
+
for (let srcPath of images) {
|
|
348
|
+
Logger.info(`${TAG} getTempFilePaths img srcPath = ${srcPath}`);
|
|
349
|
+
let i = srcPath.lastIndexOf('.');
|
|
350
|
+
let imageType = '';
|
|
351
|
+
if (i != -1) {
|
|
352
|
+
imageType = srcPath.substring(i + 1);
|
|
353
|
+
Logger.info(`${TAG} getTempFilePaths img imageType = ${imageType}`);
|
|
354
|
+
}
|
|
355
|
+
let file = fs.openSync(srcPath, fs.OpenMode.CREATE);
|
|
356
|
+
let dstPath = this.ctx.uiAbilityContext.tempDir + '/rn_image_crop_picker_lib_temp_' + util.generateRandomUUID(true) + '.' + imageType;
|
|
357
|
+
try {
|
|
358
|
+
fs.copyFileSync(file.fd, dstPath, 0);
|
|
359
|
+
resultImages.push(dstPath);
|
|
360
|
+
Logger.info(`${TAG} getTempFilePaths suc dstPath = ${dstPath}`);
|
|
361
|
+
} catch (err) {
|
|
362
|
+
Logger.info(`${TAG}, getTempFilePaths fail err = ${JSON.stringify(err)}`);
|
|
363
|
+
}
|
|
364
|
+
fs.closeSync(file);
|
|
365
|
+
}
|
|
366
|
+
return resultImages;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
async getPickerResult(options: Options, sourceFilePaths: Array<string>, tempFilePaths: Array<string>): Promise<ImageOrVideo[] | ImageOrVideo> {
|
|
370
|
+
Logger.info(`${TAG}, into openPickerResult :`);
|
|
371
|
+
let resultsList: ImageOrVideo[] = [];
|
|
372
|
+
let includeExif = this.isNullOrUndefined(options?.includeExif) ? false : options?.includeExif;
|
|
373
|
+
let images = this.isNullOrUndefined(tempFilePaths) ? sourceFilePaths : tempFilePaths;
|
|
374
|
+
Logger.info(`${TAG} into openPickerResult : images = ${images}`);
|
|
375
|
+
let includeBase64 = this.isNullOrUndefined(options.includeBase64) ? false : options.includeBase64;
|
|
376
|
+
let results;
|
|
377
|
+
for (let j = 0; j < images.length; j++) {
|
|
378
|
+
results = {
|
|
379
|
+
duration: null,
|
|
380
|
+
data: null,
|
|
381
|
+
cropRect: null,
|
|
382
|
+
path: null,
|
|
383
|
+
size: 0,
|
|
384
|
+
width: 0,
|
|
385
|
+
height: 0,
|
|
386
|
+
mime: '',
|
|
387
|
+
exif: null,
|
|
388
|
+
localIdentifier: '',
|
|
389
|
+
sourceURL: '',
|
|
390
|
+
filename: '',
|
|
391
|
+
creationDate: null,
|
|
392
|
+
modificationDate: null
|
|
393
|
+
};
|
|
394
|
+
let value = images[j];
|
|
395
|
+
if (this.isNullOrUndefined(value)) {
|
|
396
|
+
return;
|
|
397
|
+
}
|
|
398
|
+
let imageType;
|
|
399
|
+
let i = value.lastIndexOf('/')
|
|
400
|
+
let fileName = value.substring(i + 1)
|
|
401
|
+
i = value.lastIndexOf('.')
|
|
402
|
+
if (i != -1) {
|
|
403
|
+
imageType = value.substring(i + 1)
|
|
404
|
+
}
|
|
405
|
+
results.sourceURL = sourceFilePaths[j];
|
|
406
|
+
results.filename = fileName;
|
|
407
|
+
let exifInfo;
|
|
408
|
+
// /\.(jpeg)$/i.test(sourceFilePaths[j])
|
|
409
|
+
if (includeExif) {
|
|
410
|
+
try {
|
|
411
|
+
let exifFile = fs.openSync(sourceFilePaths[j], fs.OpenMode.READ_ONLY);
|
|
412
|
+
let exifImageIS = image.createImageSource(exifFile.fd);
|
|
413
|
+
exifInfo = await this.getImageExif(exifImageIS);
|
|
414
|
+
} catch (err) {
|
|
415
|
+
Logger.error(`${TAG} into getPickerResult err : ${JSON.stringify(err)}`);
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
results.exif = exifInfo;
|
|
419
|
+
let file = fs.openSync(value, fs.OpenMode.READ_ONLY)
|
|
420
|
+
Logger.info(`${TAG} into openSync : file.fd = ${file.fd} file.path = ${file.path} file.name = ${file.name}`);
|
|
421
|
+
let stat = fs.statSync(file.fd);
|
|
422
|
+
let length = stat.size;
|
|
423
|
+
results.size = length;
|
|
424
|
+
results.creationDate = stat.ctime + '';
|
|
425
|
+
results.modificationDate = stat.mtime + '';
|
|
426
|
+
results.path = this.isNullOrUndefined(tempFilePaths) ? null : filePrefix + value;
|
|
427
|
+
if (this.isImage(value)) {
|
|
428
|
+
results.data = includeBase64 ? this.imageToBase64(value) : null;
|
|
429
|
+
results.mime = 'image/' + imageType;
|
|
430
|
+
Logger.info(`${TAG} into openPickerResult value : ${value}`);
|
|
431
|
+
let imageIS = image.createImageSource(file.fd)
|
|
432
|
+
let imagePM = await imageIS.createPixelMap()
|
|
433
|
+
Logger.info(`${TAG} end createImageSource : imageIS = ${imageIS} imagePM = ${imagePM}`);
|
|
434
|
+
let imgInfo = await imagePM.getImageInfo();
|
|
435
|
+
results.height = imgInfo.size.height;
|
|
436
|
+
results.width = imgInfo.size.width;
|
|
437
|
+
imagePM.release().then(() => {
|
|
438
|
+
imagePM = undefined;
|
|
439
|
+
})
|
|
440
|
+
imageIS.release().then(() => {
|
|
441
|
+
imageIS = undefined;
|
|
442
|
+
})
|
|
443
|
+
results.duration = null;
|
|
444
|
+
} else {
|
|
445
|
+
Logger.info(`${TAG} into getPickerResult video start`);
|
|
446
|
+
results.data = null;
|
|
447
|
+
results.mime = 'video/' + imageType;
|
|
448
|
+
let url = 'fd://' + file.fd;
|
|
449
|
+
Logger.info(`${TAG} start avPlayer url = ${url}`);
|
|
450
|
+
avMetadataExtractor = await media.createAVMetadataExtractor();
|
|
451
|
+
avMetadataExtractor.fdSrc = { fd: file.fd, offset: 0, length: length };
|
|
452
|
+
try {
|
|
453
|
+
const res = await avMetadataExtractor.fetchMetadata();
|
|
454
|
+
results.duration = res.duration;
|
|
455
|
+
results.width = Number(res.videoWidth);
|
|
456
|
+
results.height = Number(res.videoHeight);
|
|
457
|
+
} catch (error) {
|
|
458
|
+
Logger.error(`${TAG} get video info suc error = ${JSON.stringify(error)}`);
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
resultsList.push(results);
|
|
462
|
+
fs.closeSync(file);
|
|
463
|
+
}
|
|
464
|
+
return options.multiple ? resultsList : results;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
async openCamera(options?: Options): Promise<Video[] | Video | ImageOrVideo[] | ImageOrVideo | Image[] | Image> {
|
|
468
|
+
Logger.info(`${TAG} into openCamera request = ${JSON.stringify(options)}`);
|
|
469
|
+
let cropping = this.isNullOrUndefined(options?.cropping) ? false : options?.cropping;
|
|
470
|
+
let quality = options.compressImageQuality;
|
|
471
|
+
if (!this.isNullOrUndefined(quality) && !(quality >= 0 && quality <= 1)) {
|
|
472
|
+
return new Promise(async (res, rej) => {
|
|
473
|
+
rej('quality is error')
|
|
474
|
+
})
|
|
475
|
+
}
|
|
476
|
+
let isImg = false;
|
|
477
|
+
let imgResult: Image = {
|
|
478
|
+
data: null,
|
|
479
|
+
cropRect: null,
|
|
480
|
+
path: null,
|
|
481
|
+
size: 0,
|
|
482
|
+
width: 0,
|
|
483
|
+
height: 0,
|
|
484
|
+
mime: '',
|
|
485
|
+
exif: null,
|
|
486
|
+
localIdentifier: '',
|
|
487
|
+
sourceURL: '',
|
|
488
|
+
filename: '',
|
|
489
|
+
creationDate: null,
|
|
490
|
+
modificationDate: null
|
|
491
|
+
};
|
|
492
|
+
let videoResult: Video = {
|
|
493
|
+
duration: null,
|
|
494
|
+
path: null,
|
|
495
|
+
size: 0,
|
|
496
|
+
width: 0,
|
|
497
|
+
height: 0,
|
|
498
|
+
mime: '',
|
|
499
|
+
exif: null,
|
|
500
|
+
localIdentifier: '',
|
|
501
|
+
sourceURL: '',
|
|
502
|
+
filename: '',
|
|
503
|
+
creationDate: null,
|
|
504
|
+
modificationDate: null
|
|
505
|
+
};
|
|
506
|
+
let useFrontCamera = this.isNullOrUndefined(options.useFrontCamera) ? false : options.useFrontCamera;
|
|
507
|
+
let writeTempFile = this.isNullOrUndefined(options?.writeTempFile) ? true : options?.writeTempFile;
|
|
508
|
+
let includeBase64 = this.isNullOrUndefined(options.includeBase64) ? false : options.includeBase64;
|
|
509
|
+
let qualityNumber = this.isNullOrUndefined(options.compressImageQuality) ? ImageQuality : options.compressImageQuality;
|
|
510
|
+
let forceJpg = this.isNullOrUndefined(options.forceJpg) ? false : options.forceJpg;
|
|
511
|
+
let mediaType = options.mediaType == 'photo' ? [picker.PickerMediaType.PHOTO] : (options.mediaType == 'video'
|
|
512
|
+
? [picker.PickerMediaType.VIDEO] : [picker.PickerMediaType.PHOTO, picker.PickerMediaType.VIDEO]);
|
|
513
|
+
return new Promise(async (res, rej) => {
|
|
514
|
+
try {
|
|
515
|
+
let mContext = await this.ctx.uiAbilityContext;
|
|
516
|
+
let pickerProfile: picker.PickerProfile = {
|
|
517
|
+
cameraPosition: useFrontCamera ? camera.CameraPosition.CAMERA_POSITION_FRONT : camera.CameraPosition.CAMERA_POSITION_BACK,
|
|
518
|
+
};
|
|
519
|
+
let pickerResult: picker.PickerResult = await picker.pick(mContext, mediaType, pickerProfile);
|
|
520
|
+
Logger.info(`${TAG} into openCamera results = ${JSON.stringify(pickerResult)}`);
|
|
521
|
+
let imgOrVideoPath = pickerResult.resultUri;
|
|
522
|
+
isImg = this.isImage(imgOrVideoPath);
|
|
523
|
+
if (isImg) {
|
|
524
|
+
let file = fs.openSync(imgOrVideoPath, fs.OpenMode.READ_ONLY);
|
|
525
|
+
try {
|
|
526
|
+
let dstPath = this.ctx.uiAbilityContext.tempDir + '/rn_image_crop_picker_lib_temp_' + util.generateRandomUUID(true) + '.jpeg';
|
|
527
|
+
fs.copyFileSync(file.fd, dstPath, 0);
|
|
528
|
+
imgOrVideoPath = dstPath;
|
|
529
|
+
Logger.info(`${TAG} into openCamera suc dstPath = ${dstPath}`);
|
|
530
|
+
} catch (err) {
|
|
531
|
+
Logger.error(`${TAG} into openCamera fail err = ${JSON.stringify(err)}`);
|
|
532
|
+
}
|
|
533
|
+
fs.closeSync(file);
|
|
534
|
+
}
|
|
535
|
+
let tempFilePaths = null;
|
|
536
|
+
let sourceFilePaths: Array<string> = [imgOrVideoPath];
|
|
537
|
+
if (qualityNumber !== 1 || forceJpg) {
|
|
538
|
+
Logger.info(`${TAG} into openCamera qualityNumber = ${qualityNumber} forceJpg = ${forceJpg}`);
|
|
539
|
+
tempFilePaths = await this.compressPictures(qualityNumber * 100, forceJpg, sourceFilePaths);
|
|
540
|
+
} else {
|
|
541
|
+
tempFilePaths = writeTempFile ? this.getTempFilePaths(sourceFilePaths) : null;
|
|
542
|
+
}
|
|
543
|
+
let tempFilePath = this.isNullOrUndefined(tempFilePaths) ? null : tempFilePaths[0];
|
|
544
|
+
let includeExif = this.isNullOrUndefined(options?.includeExif) ? false : options?.includeExif;
|
|
545
|
+
if (isImg) {
|
|
546
|
+
let exifInfo;
|
|
547
|
+
// /\.(jpeg)$/i.test(imgOrVideoPath)
|
|
548
|
+
if (includeExif) {
|
|
549
|
+
try {
|
|
550
|
+
let exifFile = fs.openSync(imgOrVideoPath, fs.OpenMode.READ_ONLY);
|
|
551
|
+
let exifImageIS = image.createImageSource(exifFile.fd);
|
|
552
|
+
exifInfo = await this.getImageExif(exifImageIS);
|
|
553
|
+
} catch (err) {
|
|
554
|
+
Logger.error(`${TAG} into openCamera err = ${JSON.stringify(err)}`);
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
let imgCropPath = cropping ? await this.intoCropper(imgOrVideoPath, options) : '';
|
|
558
|
+
if (!this.isNullOrUndefined(imgCropPath)) {
|
|
559
|
+
tempFilePath = imgCropPath;
|
|
560
|
+
Logger.info(`${TAG} into openCamera imgCropPath = ${imgCropPath}`);
|
|
561
|
+
}
|
|
562
|
+
this.getFileInfo(includeBase64, imgOrVideoPath, tempFilePath, exifInfo).then((imageInfo) => {
|
|
563
|
+
imgResult.sourceURL = imgOrVideoPath;
|
|
564
|
+
imgResult.path = this.isNullOrUndefined(tempFilePath) ? filePrefix + imgOrVideoPath : filePrefix + tempFilePath;
|
|
565
|
+
imgResult.exif = imageInfo.exif;
|
|
566
|
+
imgResult.data = imageInfo.data;
|
|
567
|
+
imgResult.size = imageInfo.size;
|
|
568
|
+
imgResult.width = imageInfo.width;
|
|
569
|
+
imgResult.height = imageInfo.height;
|
|
570
|
+
imgResult.filename = imageInfo.filename;
|
|
571
|
+
imgResult.mime = imageInfo.mime;
|
|
572
|
+
imgResult.localIdentifier = imageInfo.localIdentifier;
|
|
573
|
+
imgResult.cropRect = imageInfo.cropRect;
|
|
574
|
+
imgResult.creationDate = imageInfo.creationDate + '';
|
|
575
|
+
imgResult.modificationDate = imageInfo.modificationDate + '';
|
|
576
|
+
res(imgResult);
|
|
577
|
+
})
|
|
578
|
+
} else {
|
|
579
|
+
this.getFileInfo(false, imgOrVideoPath, tempFilePath, null).then((imageInfo) => {
|
|
580
|
+
videoResult.sourceURL = imgOrVideoPath;
|
|
581
|
+
videoResult.path = this.isNullOrUndefined(tempFilePath) ? imgOrVideoPath : filePrefix + tempFilePath;
|
|
582
|
+
videoResult.exif = imageInfo.exif;
|
|
583
|
+
videoResult.size = imageInfo.size;
|
|
584
|
+
videoResult.width = imageInfo.width;
|
|
585
|
+
videoResult.height = imageInfo.height;
|
|
586
|
+
videoResult.filename = imageInfo.filename;
|
|
587
|
+
videoResult.mime = imageInfo.mime;
|
|
588
|
+
videoResult.localIdentifier = imageInfo.localIdentifier;
|
|
589
|
+
videoResult.creationDate = imageInfo.creationDate + '';
|
|
590
|
+
videoResult.modificationDate = imageInfo.modificationDate + '';
|
|
591
|
+
videoResult.duration = Number(imageInfo.duration);
|
|
592
|
+
res(videoResult);
|
|
593
|
+
})
|
|
594
|
+
}
|
|
595
|
+
} catch (error) {
|
|
596
|
+
let err = error as BusinessError;
|
|
597
|
+
rej(JSON.stringify(err));
|
|
598
|
+
}
|
|
599
|
+
})
|
|
600
|
+
};
|
|
601
|
+
|
|
602
|
+
imageToBase64(filePath: string): string {
|
|
603
|
+
Logger.info(`${TAG} into imageToBase64 filePath = ${filePath}`);
|
|
604
|
+
let uriPath = new uri.URI(filePath);
|
|
605
|
+
let dstPath = filePath;
|
|
606
|
+
if (uriPath.host === 'media') {
|
|
607
|
+
let i = filePath.lastIndexOf('.');
|
|
608
|
+
let imageType;
|
|
609
|
+
if (i != -1) {
|
|
610
|
+
imageType = filePath.substring(i + 1);
|
|
611
|
+
}
|
|
612
|
+
let file = fs.openSync(filePath, fs.OpenMode.CREATE);
|
|
613
|
+
try {
|
|
614
|
+
dstPath = this.ctx.uiAbilityContext.tempDir + '/rn_image_crop_picker_lib_temp_' + util.generateRandomUUID(true) + '.' + imageType;
|
|
615
|
+
fs.copyFileSync(file.fd, dstPath, 0);
|
|
616
|
+
Logger.info(`${TAG} into imageToBase64 suc dstPath = ${dstPath}`);
|
|
617
|
+
} catch (err) {
|
|
618
|
+
Logger.error(`${TAG} into imageToBase64 fail err = ${JSON.stringify(err)}`);
|
|
619
|
+
}
|
|
620
|
+
fs.closeSync(file);
|
|
621
|
+
}
|
|
622
|
+
let base64Data;
|
|
623
|
+
try {
|
|
624
|
+
let file = fs.openSync(dstPath, fs.OpenMode.READ_ONLY);
|
|
625
|
+
let stat = fs.lstatSync(dstPath);
|
|
626
|
+
Logger.info(`${TAG} into imageToBase64 stat.size = ${stat.size}`);
|
|
627
|
+
let buf = new ArrayBuffer(stat.size);
|
|
628
|
+
fs.readSync(file.fd, buf);
|
|
629
|
+
let unit8Array: Uint8Array = new Uint8Array(buf);
|
|
630
|
+
let base64Helper = new util.Base64Helper();
|
|
631
|
+
base64Data = base64Helper.encodeToStringSync(unit8Array, util.Type.BASIC);
|
|
632
|
+
fs.closeSync(file);
|
|
633
|
+
Logger.info(`${TAG} into imageToBase64 base64Data = ${base64Data}`);
|
|
634
|
+
} catch (err) {
|
|
635
|
+
Logger.error(`${TAG} into imageToBase64 err = ${JSON.stringify(err)}`);
|
|
636
|
+
}
|
|
637
|
+
return base64Data;
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
isImage(filePath: string): boolean {
|
|
641
|
+
Logger.info(`${TAG} into isImage fileName = ${filePath}`);
|
|
642
|
+
const imageExtensionsRegex = /\.(jpg|jpeg|png|gif|bmp|webp)$/i;
|
|
643
|
+
return imageExtensionsRegex.test(filePath);
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
async compressPictures(quality: number, forceJpg: boolean, sourceURL: Array<string>): Promise<Array<string>> {
|
|
647
|
+
Logger.info(`${TAG} into compressPictures sourceURL = ${sourceURL} quality = ${quality} forceJpg = ${forceJpg}`);
|
|
648
|
+
let imageType: string = 'jpg';
|
|
649
|
+
let resultImages: Array<string> = new Array<string>();
|
|
650
|
+
quality = (quality > 100) ? 100 : quality;
|
|
651
|
+
for (let srcPath of sourceURL) {
|
|
652
|
+
if (this.isImage(srcPath)) {
|
|
653
|
+
Logger.info(`${TAG} into compressPictures img srcPath = ${srcPath}`);
|
|
654
|
+
if (forceJpg) {
|
|
655
|
+
imageType = 'jpg'
|
|
656
|
+
} else {
|
|
657
|
+
let i = srcPath.lastIndexOf('.');
|
|
658
|
+
if (i != -1) {
|
|
659
|
+
imageType = srcPath.substring(i + 1);
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
Logger.info(`${TAG} into compressPictures imageType = ${imageType}`);
|
|
663
|
+
let files = fs.openSync(srcPath, fs.OpenMode.READ_ONLY)
|
|
664
|
+
let imageISs = image.createImageSource(files.fd);
|
|
665
|
+
let imagePMs = await imageISs.createPixelMap();
|
|
666
|
+
let imagePackerApi = await image.createImagePacker();
|
|
667
|
+
let options: image.PackingOption = {
|
|
668
|
+
format: 'image/jpeg',
|
|
669
|
+
quality: quality,
|
|
670
|
+
};
|
|
671
|
+
try {
|
|
672
|
+
let packerData = await imagePackerApi.packing(imagePMs, options);
|
|
673
|
+
Logger.info(`${TAG} into compressPictures data = ${JSON.stringify(packerData)}`);
|
|
674
|
+
let dstPath = this.ctx.uiAbilityContext.tempDir + '/rn_image_crop_picker_lib_temp_' + util.generateRandomUUID(true) + '.' + imageType;
|
|
675
|
+
let newFile = fs.openSync(dstPath, fs.OpenMode.CREATE | fs.OpenMode.READ_WRITE);
|
|
676
|
+
Logger.info(`${TAG} into compressPictures newFile id = ${newFile.fd}`);
|
|
677
|
+
const number = fs.writeSync(newFile.fd, packerData);
|
|
678
|
+
Logger.info(`${TAG} into compressPictures write data to file succeed size = ${number}`);
|
|
679
|
+
resultImages.push(dstPath);
|
|
680
|
+
fs.closeSync(files);
|
|
681
|
+
} catch (err) {
|
|
682
|
+
Logger.error(`${TAG} into compressPictures write data to file failed err = ${JSON.stringify(err)}`);
|
|
683
|
+
}
|
|
684
|
+
} else {
|
|
685
|
+
Logger.info(`${TAG} into compressPictures video srcPath = ${srcPath}`);
|
|
686
|
+
resultImages.push(srcPath);
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
return resultImages;
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
async getListFile(): Promise<FilePathResult> {
|
|
693
|
+
let filePathResult: FilePathResult = { result: [] };
|
|
694
|
+
let filesDir = this.ctx.uiAbilityContext.tempDir;
|
|
695
|
+
|
|
696
|
+
class ListFileOption {
|
|
697
|
+
public recursion: boolean = false;
|
|
698
|
+
public listNum: number = 0;
|
|
699
|
+
public filter: Filter = {};
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
let option = new ListFileOption();
|
|
703
|
+
option.filter.suffix = ['.jpg'];
|
|
704
|
+
option.filter.displayName = ['*'];
|
|
705
|
+
option.filter.fileSizeOver = 0;
|
|
706
|
+
option.filter.lastModifiedAfter = new Date(0).getTime();
|
|
707
|
+
Logger.info(`${TAG} into getListFile filesDir = ${filesDir}`);
|
|
708
|
+
let files = fs.listFileSync(filesDir, option);
|
|
709
|
+
for (let i = 0; i < files.length; i++) {
|
|
710
|
+
let listFilePath: FilePath = {}
|
|
711
|
+
listFilePath.path = files[i];
|
|
712
|
+
filePathResult.result.push(listFilePath);
|
|
713
|
+
}
|
|
714
|
+
Logger.info(`${TAG} into getListFile arrayList = ${JSON.stringify(filePathResult)}`);
|
|
715
|
+
return filePathResult;
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
async cleanSingle(path: string): Promise<void> {
|
|
719
|
+
Logger.info(`${TAG} into cleanSingle path = ${path}`);
|
|
720
|
+
let filePath = path.trim();
|
|
721
|
+
fs.access(filePath, (err) => {
|
|
722
|
+
if (err) {
|
|
723
|
+
Logger.info(`${TAG} cleanSingle access error data = ${err.data}`);
|
|
724
|
+
} else {
|
|
725
|
+
fs.unlink(filePath).then(() => {
|
|
726
|
+
Logger.info(`${TAG} cleanSingle file succeed`);
|
|
727
|
+
}).catch((err: BusinessError) => {
|
|
728
|
+
Logger.error(`${TAG} cleanSingle err = ${JSON.stringify(err)}`);
|
|
729
|
+
});
|
|
730
|
+
}
|
|
731
|
+
});
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
async clean(): Promise<void> {
|
|
735
|
+
let dirPath = this.ctx.uiAbilityContext.tempDir;
|
|
736
|
+
fs.rmdir(dirPath).then(() => {
|
|
737
|
+
Logger.info(`${TAG} clean rmdir succeed`);
|
|
738
|
+
}).catch((err: BusinessError) => {
|
|
739
|
+
Logger.error(`${TAG} clean rmdir err = ${JSON.stringify(err)}`);
|
|
740
|
+
});
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
async openCropper(options?: CropperOptions): Promise<Image> {
|
|
744
|
+
Logger.info(`${TAG} into openCropper = ${JSON.stringify(options)}`);
|
|
745
|
+
let path = options?.path;
|
|
746
|
+
if (this.isNullOrUndefined(path?.trim())) {
|
|
747
|
+
return new Promise(async (res, rej) => {
|
|
748
|
+
rej('path is empty')
|
|
749
|
+
})
|
|
750
|
+
}
|
|
751
|
+
let quality = options.compressImageQuality;
|
|
752
|
+
if (!this.isNullOrUndefined(quality) && !(quality >= 0 && quality <= 1)) {
|
|
753
|
+
return new Promise(async (res, rej) => {
|
|
754
|
+
rej('quality is error')
|
|
755
|
+
})
|
|
756
|
+
}
|
|
757
|
+
let result: Image = {
|
|
758
|
+
data: null,
|
|
759
|
+
cropRect: null,
|
|
760
|
+
path: null,
|
|
761
|
+
size: 0,
|
|
762
|
+
width: 0,
|
|
763
|
+
height: 0,
|
|
764
|
+
mime: '',
|
|
765
|
+
exif: null,
|
|
766
|
+
localIdentifier: '',
|
|
767
|
+
sourceURL: '',
|
|
768
|
+
filename: '',
|
|
769
|
+
creationDate: null,
|
|
770
|
+
modificationDate: null
|
|
771
|
+
};
|
|
772
|
+
let includeExif = this.isNullOrUndefined(options?.includeExif) ? false : options?.includeExif;
|
|
773
|
+
let writeTempFile = this.isNullOrUndefined(options?.writeTempFile) ? true : options?.writeTempFile;
|
|
774
|
+
let qualityNumber = this.isNullOrUndefined(options.compressImageQuality) ? ImageQuality : options.compressImageQuality;
|
|
775
|
+
let forceJpg = this.isNullOrUndefined(options.forceJpg) ? false : options.forceJpg;
|
|
776
|
+
let imgPath = await this.intoCropper(path, options);
|
|
777
|
+
Logger.info(`${TAG} into openCropper imgPath = ${imgPath}`);
|
|
778
|
+
if (this.isNullOrUndefined(imgPath)) {
|
|
779
|
+
return new Promise(async (res, rej) => {
|
|
780
|
+
rej('imgPath is null')
|
|
781
|
+
})
|
|
782
|
+
}
|
|
783
|
+
let tempFilePaths = null;
|
|
784
|
+
let sourceFilePaths: Array<string> = [imgPath];
|
|
785
|
+
if (qualityNumber !== 1 || forceJpg) {
|
|
786
|
+
Logger.info(`${TAG} into openCropper qualityNumber = ${qualityNumber} forceJpg = ${forceJpg}`);
|
|
787
|
+
tempFilePaths = await this.compressPictures(qualityNumber * 100, forceJpg, sourceFilePaths);
|
|
788
|
+
} else {
|
|
789
|
+
tempFilePaths = writeTempFile ? this.getTempFilePaths(sourceFilePaths) : null;
|
|
790
|
+
}
|
|
791
|
+
let tempFilePath = this.isNullOrUndefined(tempFilePaths) ? null : tempFilePaths[0];
|
|
792
|
+
let exifInfo;
|
|
793
|
+
// /\.(jpeg)$/i.test(path)
|
|
794
|
+
if (includeExif) {
|
|
795
|
+
try {
|
|
796
|
+
let exifFile = fs.openSync(path, fs.OpenMode.READ_ONLY);
|
|
797
|
+
let exifImageIS = image.createImageSource(exifFile.fd);
|
|
798
|
+
exifInfo = await this.getImageExif(exifImageIS);
|
|
799
|
+
} catch (err) {
|
|
800
|
+
Logger.error(`${TAG} into openCamera err = ${JSON.stringify(err)}`);
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
return new Promise(async (res, rej) => {
|
|
804
|
+
this.getFileInfo(options?.includeBase64, imgPath, tempFilePath, exifInfo).then((imageInfo) => {
|
|
805
|
+
result.path = this.isNullOrUndefined(tempFilePath) ? filePrefix + imgPath : filePrefix + tempFilePath;
|
|
806
|
+
result.exif = imageInfo.exif;
|
|
807
|
+
result.sourceURL = options?.path;
|
|
808
|
+
result.data = imageInfo.data;
|
|
809
|
+
result.size = imageInfo.size;
|
|
810
|
+
result.width = imageInfo.width;
|
|
811
|
+
result.height = imageInfo.height;
|
|
812
|
+
result.filename = imageInfo.filename;
|
|
813
|
+
result.mime = imageInfo.mime;
|
|
814
|
+
result.localIdentifier = imageInfo.localIdentifier;
|
|
815
|
+
result.cropRect = imageInfo.cropRect;
|
|
816
|
+
result.creationDate = imageInfo.creationDate + '';
|
|
817
|
+
result.modificationDate = imageInfo.modificationDate + '';
|
|
818
|
+
res(result);
|
|
819
|
+
})
|
|
820
|
+
})
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
async getFileInfo(includeBase64: boolean, filePath: string, compressOrTempFilePath: string, exifInfo: Exif): Promise<VideoImageInfo> {
|
|
824
|
+
let videoImageInfo: VideoImageInfo = { duration: null };
|
|
825
|
+
let imageType;
|
|
826
|
+
let i = this.isNullOrUndefined(compressOrTempFilePath) ? filePath.lastIndexOf('/') : compressOrTempFilePath.lastIndexOf('/')
|
|
827
|
+
let fileName = this.isNullOrUndefined(compressOrTempFilePath) ? filePath.substring(i + 1) : compressOrTempFilePath.substring(i + 1)
|
|
828
|
+
i = filePath.lastIndexOf('.')
|
|
829
|
+
if (i != -1) {
|
|
830
|
+
imageType = filePath.substring(i + 1)
|
|
831
|
+
}
|
|
832
|
+
videoImageInfo.path = this.isNullOrUndefined(compressOrTempFilePath) ? filePrefix + filePath : compressOrTempFilePath + filePath;
|
|
833
|
+
videoImageInfo.filename = fileName;
|
|
834
|
+
videoImageInfo.mime = 'image/' + imageType;
|
|
835
|
+
|
|
836
|
+
let file = fs.openSync(filePath, fs.OpenMode.READ_ONLY)
|
|
837
|
+
let stat = fs.statSync(file.fd);
|
|
838
|
+
let length = stat.size;
|
|
839
|
+
videoImageInfo.size = length;
|
|
840
|
+
videoImageInfo.creationDate = stat.ctime;
|
|
841
|
+
videoImageInfo.modificationDate = stat.mtime;
|
|
842
|
+
if (this.isImage(filePath)) {
|
|
843
|
+
let imageIS = image.createImageSource(file.fd)
|
|
844
|
+
let imagePM = await imageIS.createPixelMap()
|
|
845
|
+
let imgInfo = await imagePM.getImageInfo();
|
|
846
|
+
videoImageInfo.data = includeBase64 ? this.imageToBase64(compressOrTempFilePath || filePath) : null;
|
|
847
|
+
videoImageInfo.height = imgInfo.size.height;
|
|
848
|
+
videoImageInfo.width = imgInfo.size.width;
|
|
849
|
+
videoImageInfo.exif = exifInfo;
|
|
850
|
+
imagePM.release().then(() => {
|
|
851
|
+
imagePM = undefined;
|
|
852
|
+
})
|
|
853
|
+
imageIS.release().then(() => {
|
|
854
|
+
imageIS = undefined;
|
|
855
|
+
})
|
|
856
|
+
} else {
|
|
857
|
+
videoImageInfo.mime = 'video/' + imageType;
|
|
858
|
+
let url = 'fd://' + file.fd;
|
|
859
|
+
Logger.info(`${TAG} start avPlayer url = ${url}`);
|
|
860
|
+
avMetadataExtractor = await media.createAVMetadataExtractor();
|
|
861
|
+
avMetadataExtractor.fdSrc = { fd: file.fd, offset: 0, length: length };
|
|
862
|
+
try {
|
|
863
|
+
const res = await avMetadataExtractor.fetchMetadata();
|
|
864
|
+
videoImageInfo.duration = res.duration;
|
|
865
|
+
videoImageInfo.width = Number(res.videoWidth);
|
|
866
|
+
videoImageInfo.height = Number(res.videoHeight);
|
|
867
|
+
} catch (error) {
|
|
868
|
+
Logger.error(`${TAG} get video info suc error = ${JSON.stringify(error)}`);
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
videoImageInfo.cropRect = AppStorage.get('cropRect') as CropRect;
|
|
873
|
+
|
|
874
|
+
fs.close(file.fd);
|
|
875
|
+
return videoImageInfo;
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
async intoCropper(filePath: string, options?: Options | CropperOptions): Promise<string> {
|
|
879
|
+
Logger.info(`${TAG} into intoCropper : filePath = ${filePath}`);
|
|
880
|
+
let imagePath: string;
|
|
881
|
+
const bundleName = this.ctx.uiAbilityContext.abilityInfo.bundleName;
|
|
882
|
+
AppStorage.setOrCreate('filePath', filePath);
|
|
883
|
+
return new Promise((res, rej) => {
|
|
884
|
+
const initWidth: number = this.isNullOrUndefined(options?.width) ? 0 : options?.width;
|
|
885
|
+
const initHeight: number = this.isNullOrUndefined(options?.height) ? 0 : options?.height;
|
|
886
|
+
const enableRotationGesture: boolean = this.isNullOrUndefined(options?.enableRotationGesture) ? false : options?.enableRotationGesture;
|
|
887
|
+
const title: string = this.isNullOrUndefined(options?.cropperToolbarTitle) ? '编辑图片' : options?.cropperToolbarTitle;
|
|
888
|
+
const chooseText: string = this.isNullOrUndefined(options?.cropperChooseText) ? 'Choose' : options?.cropperChooseText;
|
|
889
|
+
const chooseTextColor: string = this.isNullOrUndefined(options?.cropperChooseColor) ? '#FFCC00' : options?.cropperChooseColor;
|
|
890
|
+
const cancelText: string = this.isNullOrUndefined(options?.cropperCancelText) ? 'Cancel' : options?.cropperCancelText;
|
|
891
|
+
const cancelTextColor: string = this.isNullOrUndefined(options?.cropperCancelColor) ? '#0000FF' : options?.cropperCancelColor;
|
|
892
|
+
const showCropGuidelines: boolean = this.isNullOrUndefined(options?.showCropGuidelines) ? true : options?.showCropGuidelines;
|
|
893
|
+
const showCropFrame: boolean = this.isNullOrUndefined(options?.showCropFrame) ? true : options?.showCropFrame;
|
|
894
|
+
const freeStyleCropEnabled: boolean = this.isNullOrUndefined(options?.freeStyleCropEnabled) ? false : options?.freeStyleCropEnabled;
|
|
895
|
+
const cropperRotate: string = options?.cropperRotateButtonsHidden + '';
|
|
896
|
+
AppStorage.setOrCreate('initWidth', initWidth);
|
|
897
|
+
AppStorage.setOrCreate('initHeight', initHeight);
|
|
898
|
+
AppStorage.setOrCreate('enableRotationGesture', enableRotationGesture);
|
|
899
|
+
AppStorage.setOrCreate('textTitle', title);
|
|
900
|
+
AppStorage.setOrCreate('chooseText', chooseText);
|
|
901
|
+
AppStorage.setOrCreate('chooseTextColor', chooseTextColor);
|
|
902
|
+
AppStorage.setOrCreate('cancelText', cancelText);
|
|
903
|
+
AppStorage.setOrCreate('cancelTextColor', cancelTextColor);
|
|
904
|
+
AppStorage.setOrCreate('cropperRotate', cropperRotate);
|
|
905
|
+
AppStorage.setOrCreate('showCropGuidelines', showCropGuidelines);
|
|
906
|
+
AppStorage.setOrCreate('showCropFrame', showCropFrame);
|
|
907
|
+
AppStorage.setOrCreate('freeStyleCropEnabled', freeStyleCropEnabled);
|
|
908
|
+
|
|
909
|
+
try {
|
|
910
|
+
let want: Want = {
|
|
911
|
+
"bundleName": bundleName,
|
|
912
|
+
"abilityName": "ImageEditAbility",
|
|
913
|
+
}
|
|
914
|
+
this.ctx.uiAbilityContext.startAbilityForResult(want, (error, data) => {
|
|
915
|
+
imagePath = AppStorage.get('cropImagePath') as string;
|
|
916
|
+
AppStorage.setOrCreate('cropImagePath', '')
|
|
917
|
+
Logger.info(`${TAG} into intoCropper startAbility suc imagePath = ${imagePath}`);
|
|
918
|
+
res(imagePath);
|
|
919
|
+
});
|
|
920
|
+
} catch (err) {
|
|
921
|
+
Logger.error(`${TAG} into intoCropper startAbility err = ${JSON.stringify(err)}`);
|
|
922
|
+
res('')
|
|
923
|
+
}
|
|
924
|
+
});
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
async getImageExif(imageSource: image.ImageSource): Promise<Exif> {
|
|
928
|
+
Logger.info(`${TAG} into getImageExif:`);
|
|
929
|
+
let bitsPerSample;
|
|
930
|
+
let orientation;
|
|
931
|
+
let imageLength;
|
|
932
|
+
let imageWidth;
|
|
933
|
+
let gpsLatitude;
|
|
934
|
+
let gpsLongitude;
|
|
935
|
+
let gpsLatitudeRef;
|
|
936
|
+
let gpsLongitudeRef;
|
|
937
|
+
let dateTimeOriginal;
|
|
938
|
+
let exposureTime;
|
|
939
|
+
let sceneType;
|
|
940
|
+
let isoSpeedRatings;
|
|
941
|
+
let fNumber;
|
|
942
|
+
try {
|
|
943
|
+
bitsPerSample = await imageSource.getImageProperty(image.PropertyKey.BITS_PER_SAMPLE);
|
|
944
|
+
} catch (err) {
|
|
945
|
+
Logger.info(`${TAG} into getImageExif bitsPerSample err = ${JSON.stringify(err)}`);
|
|
946
|
+
}
|
|
947
|
+
try {
|
|
948
|
+
orientation = await imageSource.getImageProperty(image.PropertyKey.ORIENTATION);
|
|
949
|
+
} catch (err) {
|
|
950
|
+
Logger.info(`${TAG} into getImageExif orientation err = ${JSON.stringify(err)}`);
|
|
951
|
+
}
|
|
952
|
+
try {
|
|
953
|
+
imageLength = await imageSource.getImageProperty(image.PropertyKey.IMAGE_LENGTH);
|
|
954
|
+
} catch (err) {
|
|
955
|
+
Logger.info(`${TAG} into getImageExif imageLength err = ${JSON.stringify(err)}`);
|
|
956
|
+
}
|
|
957
|
+
try {
|
|
958
|
+
imageWidth = await imageSource.getImageProperty(image.PropertyKey.IMAGE_WIDTH);
|
|
959
|
+
} catch (err) {
|
|
960
|
+
Logger.info(`${TAG} into getImageExif imageWidth err = ${JSON.stringify(err)}`);
|
|
961
|
+
}
|
|
962
|
+
try {
|
|
963
|
+
gpsLatitude = await imageSource.getImageProperty(image.PropertyKey.GPS_LATITUDE);
|
|
964
|
+
} catch (err) {
|
|
965
|
+
Logger.info(`${TAG} into getImageExif gpsLatitude err = ${JSON.stringify(err)}`);
|
|
966
|
+
}
|
|
967
|
+
try {
|
|
968
|
+
gpsLongitude = await imageSource.getImageProperty(image.PropertyKey.GPS_LONGITUDE);
|
|
969
|
+
} catch (err) {
|
|
970
|
+
Logger.info(`${TAG} into getImageExif gpsLongitude err = ${JSON.stringify(err)}`);
|
|
971
|
+
}
|
|
972
|
+
try {
|
|
973
|
+
gpsLatitudeRef = await imageSource.getImageProperty(image.PropertyKey.GPS_LATITUDE_REF);
|
|
974
|
+
} catch (err) {
|
|
975
|
+
Logger.info(`${TAG} into getImageExif gpsLatitudeRef err = ${JSON.stringify(err)}`);
|
|
976
|
+
}
|
|
977
|
+
try {
|
|
978
|
+
gpsLongitudeRef = await imageSource.getImageProperty(image.PropertyKey.GPS_LONGITUDE_REF);
|
|
979
|
+
} catch (err) {
|
|
980
|
+
Logger.info(`${TAG} into getImageExif gpsLongitudeRef err = ${JSON.stringify(err)}`);
|
|
981
|
+
}
|
|
982
|
+
try {
|
|
983
|
+
dateTimeOriginal = await imageSource.getImageProperty(image.PropertyKey.DATE_TIME_ORIGINAL);
|
|
984
|
+
} catch (err) {
|
|
985
|
+
Logger.info(`${TAG} into getImageExif dateTimeOriginal err = ${JSON.stringify(err)}`);
|
|
986
|
+
}
|
|
987
|
+
try {
|
|
988
|
+
exposureTime = await imageSource.getImageProperty(image.PropertyKey.EXPOSURE_TIME);
|
|
989
|
+
} catch (err) {
|
|
990
|
+
Logger.info(`${TAG} into getImageExif exposureTime err = ${JSON.stringify(err)}`);
|
|
991
|
+
}
|
|
992
|
+
try {
|
|
993
|
+
sceneType = await imageSource.getImageProperty(image.PropertyKey.SCENE_TYPE);
|
|
994
|
+
} catch (err) {
|
|
995
|
+
Logger.info(`${TAG} into getImageExif sceneType err = ${JSON.stringify(err)}`);
|
|
996
|
+
}
|
|
997
|
+
try {
|
|
998
|
+
isoSpeedRatings = await imageSource.getImageProperty(image.PropertyKey.ISO_SPEED_RATINGS);
|
|
999
|
+
} catch (err) {
|
|
1000
|
+
Logger.info(`${TAG} into getImageExif isoSpeedRatings err = ${JSON.stringify(err)}`);
|
|
1001
|
+
}
|
|
1002
|
+
try {
|
|
1003
|
+
fNumber = await imageSource.getImageProperty(image.PropertyKey.F_NUMBER);
|
|
1004
|
+
} catch (err) {
|
|
1005
|
+
Logger.info(`${TAG} into getImageExif fNumber err = ${JSON.stringify(err)}`);
|
|
1006
|
+
}
|
|
1007
|
+
return {
|
|
1008
|
+
BitsPerSample: bitsPerSample,
|
|
1009
|
+
Orientation: orientation,
|
|
1010
|
+
ImageLength: imageLength,
|
|
1011
|
+
ImageWidth: imageWidth,
|
|
1012
|
+
GPSLatitude: gpsLatitude,
|
|
1013
|
+
GPSLongitude: gpsLongitude,
|
|
1014
|
+
GPSLatitudeRef: gpsLatitudeRef,
|
|
1015
|
+
GPSLongitudeRef: gpsLongitudeRef,
|
|
1016
|
+
DateTimeOriginal: dateTimeOriginal,
|
|
1017
|
+
ExposureTime: exposureTime,
|
|
1018
|
+
SceneType: sceneType,
|
|
1019
|
+
ISOSpeedRatings: isoSpeedRatings,
|
|
1020
|
+
FNumber: fNumber,
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
grantPermission(): Promise<boolean> {
|
|
1025
|
+
Logger.info(`${TAG} into grantPermission:`);
|
|
1026
|
+
const permissions: Array<Permissions> = [
|
|
1027
|
+
'ohos.permission.READ_MEDIA',
|
|
1028
|
+
'ohos.permission.WRITE_MEDIA',
|
|
1029
|
+
'ohos.permission.MEDIA_LOCATION',
|
|
1030
|
+
];
|
|
1031
|
+
return new Promise((res, rej) => {
|
|
1032
|
+
atManager.requestPermissionsFromUser(this.ctx.uiAbilityContext, permissions)
|
|
1033
|
+
.then((data: PermissionRequestResult) => {
|
|
1034
|
+
res(data?.authResults[0] === 0)
|
|
1035
|
+
}).catch((err) => {
|
|
1036
|
+
res(false)
|
|
1037
|
+
Logger.info(`${TAG} grantPermission err = ${JSON.stringify(err)}`);
|
|
1038
|
+
})
|
|
1039
|
+
});
|
|
1040
|
+
}
|
|
1041
|
+
}
|