@tarojs/plugin-platform-harmony-ets 4.0.0-beta.111 → 4.0.0-beta.113
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/dist/apis/media/image/index.ts +207 -44
- package/dist/apis/utils/index.ts +18 -0
- package/dist/apis/utils/permissions.ts +6 -0
- package/dist/components-harmony-ets/utils/styles.ets +2 -0
- package/dist/runtime-ets/dom/stylesheet/type.ts +4 -4
- package/dist/runtime-utils.js +201 -49
- package/dist/runtime-utils.js.map +1 -1
- package/dist/runtime.js +201 -49
- package/dist/runtime.js.map +1 -1
- package/package.json +9 -9
- package/types/harmony.d.ts +1 -0
|
@@ -9,11 +9,15 @@
|
|
|
9
9
|
// ❌ wx.saveImageToPhotosAlbum(Object object) api 9+ HarmonyOS不支持
|
|
10
10
|
// ❌ wx.previewImage(Object object) api 9+ HarmonyOS不支持
|
|
11
11
|
|
|
12
|
+
import fs from '@ohos.file.fs'
|
|
12
13
|
import picker from '@ohos.file.picker'
|
|
13
14
|
import image from '@ohos.multimedia.image'
|
|
15
|
+
import { Current } from '@tarojs/runtime'
|
|
14
16
|
import { isNull } from '@tarojs/shared'
|
|
15
17
|
|
|
16
|
-
import {
|
|
18
|
+
import { getSystemInfoSync } from '../../base'
|
|
19
|
+
import { callAsyncFail, callAsyncSuccess, requestPermissions, temporarilyNotSupport, validateParams } from '../../utils'
|
|
20
|
+
import { IMAGE_PERMISSION } from '../../utils/permissions'
|
|
17
21
|
|
|
18
22
|
import type Taro from '@tarojs/taro/types'
|
|
19
23
|
|
|
@@ -22,12 +26,21 @@ interface IPackingOptionOHOS {
|
|
|
22
26
|
quality: number
|
|
23
27
|
}
|
|
24
28
|
|
|
29
|
+
interface IChooseImageData {
|
|
30
|
+
tempFilePaths?: string[]
|
|
31
|
+
|
|
32
|
+
tempFiles?: {
|
|
33
|
+
path: string
|
|
34
|
+
size: number
|
|
35
|
+
}[]
|
|
36
|
+
}
|
|
37
|
+
|
|
25
38
|
const getImageInfoSchema = {
|
|
26
|
-
|
|
39
|
+
src: 'String'
|
|
27
40
|
}
|
|
28
41
|
|
|
29
42
|
const compressImageSchema = {
|
|
30
|
-
|
|
43
|
+
src: 'String'
|
|
31
44
|
}
|
|
32
45
|
|
|
33
46
|
const chooseImageSchema = {
|
|
@@ -60,61 +73,211 @@ export const getImageInfo: typeof Taro.getImageInfo = function (options) {
|
|
|
60
73
|
})
|
|
61
74
|
}
|
|
62
75
|
|
|
76
|
+
|
|
77
|
+
class CompressedImageInfo {
|
|
78
|
+
imageUri = '' // 压缩后图片保存位置的uri
|
|
79
|
+
imageByteLength = 0 // 压缩后图片字节长度
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
async function saveImage(compressedImageData, compressedImageUri) {
|
|
83
|
+
const tempArr = compressedImageUri.split('/')
|
|
84
|
+
const name = tempArr[tempArr.length - 1]
|
|
85
|
+
const context = getContext(Current?.page)
|
|
86
|
+
const applicationContext = context.getApplicationContext()
|
|
87
|
+
const tempDir = applicationContext.tempDir
|
|
88
|
+
const filePath = `${tempDir}/${name}`
|
|
89
|
+
|
|
90
|
+
try {
|
|
91
|
+
const res = fs.accessSync(filePath)
|
|
92
|
+
if (res) {
|
|
93
|
+
// 如果图片afterCompressiona.jpeg已存在,则删除
|
|
94
|
+
fs.unlinkSync(filePath)
|
|
95
|
+
}
|
|
96
|
+
} catch (err) {
|
|
97
|
+
console.error(`[Taro] saveImage Error: AccessSync failed with error message: ${err.message}, error code: ${err.code}`)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// 知识点:保存图片。获取最终图片压缩数据compressedImageData,保存图片。
|
|
101
|
+
// 压缩图片数据写入文件
|
|
102
|
+
const file = fs.openSync(filePath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE)
|
|
103
|
+
fs.writeSync(file.fd, compressedImageData)
|
|
104
|
+
fs.closeSync(file)
|
|
105
|
+
|
|
106
|
+
// 获取压缩图片信息
|
|
107
|
+
const compressedImageInfo = new CompressedImageInfo()
|
|
108
|
+
compressedImageInfo.imageUri = filePath
|
|
109
|
+
compressedImageInfo.imageByteLength = compressedImageData.byteLength
|
|
110
|
+
|
|
111
|
+
return compressedImageInfo
|
|
112
|
+
}
|
|
113
|
+
|
|
63
114
|
export const compressImage: typeof Taro.compressImage = function (options) {
|
|
64
115
|
return new Promise((resolve, reject) => {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
116
|
+
requestPermissions(IMAGE_PERMISSION).then(() => {
|
|
117
|
+
try {
|
|
118
|
+
validateParams('compressImage', options, compressImageSchema)
|
|
119
|
+
} catch (error) {
|
|
120
|
+
const res = { errMsg: error.message }
|
|
121
|
+
return callAsyncFail(reject, res, options)
|
|
122
|
+
}
|
|
123
|
+
const { src, quality = 80, compressedWidth, compressedHeight } = options
|
|
124
|
+
const srcAfterCompress = src.includes('_after_compress') ? src : src.split('.').join('_after_compress.')
|
|
125
|
+
const file = fs.openSync(src, fs.OpenMode.READ_ONLY)
|
|
72
126
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
const createImageSourceError = { errMsg: 'compressImage fail: createImageSource has failed.' }
|
|
76
|
-
callAsyncFail(reject, createImageSourceError, options)
|
|
77
|
-
return
|
|
78
|
-
}
|
|
127
|
+
// const stat = fs.statSync(file.fd)
|
|
128
|
+
// console.log('[Taro] 压缩前图片的大小为:', stat.size)
|
|
79
129
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
130
|
+
const source = image.createImageSource(file.fd)
|
|
131
|
+
if (isNull(source)) {
|
|
132
|
+
const createImageSourceError = { errMsg: 'compressImage fail: createImageSource has failed.' }
|
|
133
|
+
callAsyncFail(reject, createImageSourceError, options)
|
|
134
|
+
return
|
|
135
|
+
}
|
|
85
136
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
137
|
+
const width = source.getImageInfoSync().size.width
|
|
138
|
+
const height = source.getImageInfoSync().size.height
|
|
139
|
+
let wantWidth = compressedWidth || compressedHeight || 0
|
|
140
|
+
let wantHeight = compressedHeight || compressedWidth || 0
|
|
141
|
+
|
|
142
|
+
if (width > wantWidth || height > wantHeight) {
|
|
143
|
+
const heightRatio = height / wantHeight
|
|
144
|
+
const widthRatio = width / wantWidth
|
|
145
|
+
const finalRatio = heightRatio < widthRatio ? heightRatio : widthRatio
|
|
146
|
+
|
|
147
|
+
wantWidth = Math.round(width / finalRatio)
|
|
148
|
+
wantHeight = Math.round(height / finalRatio)
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const decodingOptions = {
|
|
152
|
+
editable: true,
|
|
153
|
+
desiredPixelFormat: image.PixelMapFormat.RGBA_8888,
|
|
154
|
+
desiredSize: { width: wantWidth, height: wantHeight }
|
|
155
|
+
}
|
|
156
|
+
source.createPixelMap(decodingOptions, (error, pixelMap) => {
|
|
157
|
+
if (error !== undefined) {
|
|
158
|
+
fs.closeSync(file)
|
|
159
|
+
const res = { errMsg: error }
|
|
160
|
+
callAsyncFail(reject, res, options)
|
|
161
|
+
} else {
|
|
162
|
+
const packer = image.createImagePacker(file.fd)
|
|
163
|
+
if (isNull(packer)) {
|
|
164
|
+
fs.closeSync(file)
|
|
165
|
+
const createImagePackerError = { errMsg: 'compressImage fail: createImagePacker has failed.' }
|
|
166
|
+
callAsyncFail(reject, createImagePackerError, options)
|
|
167
|
+
return
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const isPNG = src.endsWith('.png')
|
|
171
|
+
const packingOptionsOHOS: IPackingOptionOHOS = {
|
|
172
|
+
format: isPNG ? 'image/png' : 'image/jpeg',
|
|
173
|
+
quality: quality
|
|
174
|
+
}
|
|
175
|
+
packer.packing(pixelMap, packingOptionsOHOS).then((value) => {
|
|
176
|
+
fs.closeSync(file)
|
|
177
|
+
saveImage(value, srcAfterCompress).then(result => {
|
|
178
|
+
callAsyncSuccess(resolve, { tempFilePath: result.imageUri }, options)
|
|
179
|
+
})
|
|
180
|
+
}).catch((error) => {
|
|
181
|
+
fs.closeSync(file)
|
|
182
|
+
callAsyncFail(reject, error, options)
|
|
183
|
+
})
|
|
184
|
+
}
|
|
185
|
+
})
|
|
186
|
+
}, (error: string) => {
|
|
187
|
+
const res = { errMsg: error }
|
|
188
|
+
return callAsyncFail(reject, res, options)
|
|
95
189
|
})
|
|
96
190
|
})
|
|
97
191
|
}
|
|
98
192
|
|
|
99
193
|
export const chooseImage: typeof Taro.chooseImage = function (options) {
|
|
100
194
|
return new Promise((resolve, reject) => {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
195
|
+
requestPermissions(IMAGE_PERMISSION).then(() => {
|
|
196
|
+
try {
|
|
197
|
+
validateParams('chooseImage', options, chooseImageSchema)
|
|
198
|
+
} catch (error) {
|
|
199
|
+
const res = { errMsg: error.message }
|
|
200
|
+
return callAsyncFail(reject, res, options)
|
|
201
|
+
}
|
|
107
202
|
|
|
108
|
-
|
|
109
|
-
|
|
203
|
+
const { count = 9 } = options
|
|
204
|
+
const photoViewPicker = new picker.PhotoViewPicker()
|
|
205
|
+
let sizeType = options.sizeType
|
|
110
206
|
|
|
111
|
-
|
|
112
|
-
|
|
207
|
+
if (!sizeType || !sizeType.length) {
|
|
208
|
+
sizeType = ['compressed', 'original']
|
|
209
|
+
}
|
|
113
210
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
211
|
+
photoSelectOptions.maxSelectNumber = count // 选择媒体文件的最大数目
|
|
212
|
+
photoSelectOptions.MIMEType = picker.PhotoViewMIMETypes.IMAGE_TYPE // 过滤选择媒体文件类型为IMAGE
|
|
213
|
+
|
|
214
|
+
photoViewPicker.select(photoSelectOptions).then((photoSelectResult) => {
|
|
215
|
+
const result: IChooseImageData = {}
|
|
216
|
+
const isOrigin = photoSelectResult.isOriginalPhoto
|
|
217
|
+
|
|
218
|
+
if (isOrigin) {
|
|
219
|
+
const tempFilePaths: string[] = []
|
|
220
|
+
const tempFiles = photoSelectResult.photoUris.map(uri => {
|
|
221
|
+
const file = fs.openSync(uri, fs.OpenMode.READ_ONLY)
|
|
222
|
+
const stat = fs.statSync(file.fd)
|
|
223
|
+
const size = stat.size
|
|
224
|
+
|
|
225
|
+
fs.closeSync(file)
|
|
226
|
+
tempFilePaths.push(uri)
|
|
227
|
+
|
|
228
|
+
return {
|
|
229
|
+
size,
|
|
230
|
+
path: uri,
|
|
231
|
+
}
|
|
232
|
+
})
|
|
233
|
+
|
|
234
|
+
result.tempFiles = tempFiles
|
|
235
|
+
result.tempFilePaths = tempFilePaths
|
|
236
|
+
|
|
237
|
+
callAsyncSuccess(resolve, result, options)
|
|
238
|
+
} else {
|
|
239
|
+
const actions: Promise<string>[] = photoSelectResult.photoUris.map(uri => {
|
|
240
|
+
return new Promise<string>(resolve => {
|
|
241
|
+
compressImage({
|
|
242
|
+
src: uri,
|
|
243
|
+
compressedWidth: getSystemInfoSync().screenWidth / 2,
|
|
244
|
+
compressedHeight: getSystemInfoSync().screenHeight / 2,
|
|
245
|
+
success: (compressResult) => {
|
|
246
|
+
resolve(compressResult.tempFilePath)
|
|
247
|
+
}
|
|
248
|
+
})
|
|
249
|
+
})
|
|
250
|
+
})
|
|
251
|
+
|
|
252
|
+
Promise.all(actions).then(tempFilePaths => {
|
|
253
|
+
const tempFiles = tempFilePaths.map(uri => {
|
|
254
|
+
const file = fs.openSync(uri, fs.OpenMode.READ_ONLY)
|
|
255
|
+
const stat = fs.statSync(file.fd)
|
|
256
|
+
const size: number = stat.size
|
|
257
|
+
|
|
258
|
+
fs.closeSync(file)
|
|
259
|
+
|
|
260
|
+
return {
|
|
261
|
+
size,
|
|
262
|
+
path: uri,
|
|
263
|
+
}
|
|
264
|
+
})
|
|
265
|
+
|
|
266
|
+
result.tempFilePaths = tempFilePaths
|
|
267
|
+
result.tempFiles = tempFiles
|
|
268
|
+
|
|
269
|
+
callAsyncSuccess(resolve, result, options)
|
|
270
|
+
}).catch(error => {
|
|
271
|
+
const res = { errMsg: error }
|
|
272
|
+
return callAsyncFail(reject, res, options)
|
|
273
|
+
})
|
|
274
|
+
}
|
|
275
|
+
}).catch((error) => {
|
|
276
|
+
callAsyncFail(reject, error, options)
|
|
277
|
+
})
|
|
278
|
+
}, (error: string) => {
|
|
279
|
+
const res = { errMsg: error }
|
|
280
|
+
return callAsyncFail(reject, res, options)
|
|
118
281
|
})
|
|
119
282
|
})
|
|
120
283
|
}
|
package/dist/apis/utils/index.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import abilityAccessCtrl from '@ohos.abilityAccessCtrl'
|
|
2
|
+
import { Current } from '@tarojs/runtime'
|
|
1
3
|
import { eventCenter } from '@tarojs/runtime/dist/runtime.esm'
|
|
2
4
|
|
|
3
5
|
import { ICallbackResult, MethodHandler } from './handler'
|
|
@@ -8,6 +10,22 @@ export * from './validate'
|
|
|
8
10
|
export { MethodHandler }
|
|
9
11
|
export { noop } from '@tarojs/shared'
|
|
10
12
|
|
|
13
|
+
export function requestPermissions (permissions: string[]) {
|
|
14
|
+
return new Promise<void>((resolve, reject) => {
|
|
15
|
+
const context = getContext(Current?.page)
|
|
16
|
+
const atManager = abilityAccessCtrl.createAtManager()
|
|
17
|
+
|
|
18
|
+
atManager.requestPermissionsFromUser(context, permissions, (err, _) => {
|
|
19
|
+
if (err) {
|
|
20
|
+
// eslint-disable-next-line prefer-promise-reject-errors
|
|
21
|
+
reject(`[Taro] 请求用户授权 ${permissions.join('、')} 失败:${JSON.stringify(err)}`)
|
|
22
|
+
} else {
|
|
23
|
+
resolve()
|
|
24
|
+
}
|
|
25
|
+
})
|
|
26
|
+
})
|
|
27
|
+
}
|
|
28
|
+
|
|
11
29
|
export function object2String (obj) {
|
|
12
30
|
let str = ''
|
|
13
31
|
for (const item in obj) {
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export const READ_IMAGEVIDEO_PERMISSIONS = 'ohos.permission.READ_IMAGEVIDEO'
|
|
2
|
+
export const READ_MEDIA_PERMISSIONS = 'ohos.permission.READ_MEDIA'
|
|
3
|
+
export const WRITE_MEDIA_PERMISSIONS = 'ohos.permission.WRITE_MEDIA'
|
|
4
|
+
export const MEDIA_LOCATION_PERMISSIONS = 'ohos.permission.MEDIA_LOCATION'
|
|
5
|
+
|
|
6
|
+
export const IMAGE_PERMISSION = [READ_IMAGEVIDEO_PERMISSIONS, READ_MEDIA_PERMISSIONS, WRITE_MEDIA_PERMISSIONS, MEDIA_LOCATION_PERMISSIONS]
|
|
@@ -38,10 +38,10 @@ export interface TaroStyleType {
|
|
|
38
38
|
|
|
39
39
|
// position
|
|
40
40
|
position?: 'relative' | 'absolute' | 'fixed'
|
|
41
|
-
top?:
|
|
42
|
-
left?:
|
|
43
|
-
bottom?:
|
|
44
|
-
right?:
|
|
41
|
+
top?: Dimension
|
|
42
|
+
left?: Dimension
|
|
43
|
+
bottom?: Dimension
|
|
44
|
+
right?: Dimension
|
|
45
45
|
|
|
46
46
|
// flex
|
|
47
47
|
flexBasis?: number | string
|
package/dist/runtime-utils.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { isFunction, isString, isArray, isObject, isNull, isNumber, isUndefined, queryToJson, PLATFORM_TYPE, singleQuote, internalComponents } from '@tarojs/shared';
|
|
2
2
|
import _display from '@ohos.display';
|
|
3
3
|
import { Current, window, eventSource, hooks, document as document$1, getPageScrollerOrNode, findChildNodeWithDFS, setNodeEventCallbackAndTriggerComponentUpdate, AREA_CHANGE_EVENT_NAME, disconnectEvent, VISIBLE_CHANGE_EVENT_NAME, getCurrentInstance } from '@tarojs/runtime';
|
|
4
|
+
import abilityAccessCtrl from '@ohos.abilityAccessCtrl';
|
|
4
5
|
import { eventCenter, Events, History } from '@tarojs/runtime/dist/runtime.esm';
|
|
5
6
|
import ConfigurationConstant from '@ohos.app.ability.ConfigurationConstant';
|
|
6
7
|
import deviceInfo from '@ohos.deviceInfo';
|
|
@@ -22,6 +23,7 @@ import app from '@system.app';
|
|
|
22
23
|
import file from '@system.file';
|
|
23
24
|
import geoLocationManager from '@ohos.geoLocationManager';
|
|
24
25
|
import mediaLibrary from '@ohos.multimedia.mediaLibrary';
|
|
26
|
+
import fs from '@ohos.file.fs';
|
|
25
27
|
import picker from '@ohos.file.picker';
|
|
26
28
|
import image from '@ohos.multimedia.image';
|
|
27
29
|
import request$1 from '@ohos.request';
|
|
@@ -174,6 +176,21 @@ const validateParams = function (name, params, schema) {
|
|
|
174
176
|
}
|
|
175
177
|
};
|
|
176
178
|
|
|
179
|
+
function requestPermissions(permissions) {
|
|
180
|
+
return new Promise((resolve, reject) => {
|
|
181
|
+
const context = getContext(Current === null || Current === void 0 ? void 0 : Current.page);
|
|
182
|
+
const atManager = abilityAccessCtrl.createAtManager();
|
|
183
|
+
atManager.requestPermissionsFromUser(context, permissions, (err, _) => {
|
|
184
|
+
if (err) {
|
|
185
|
+
// eslint-disable-next-line prefer-promise-reject-errors
|
|
186
|
+
reject(`[Taro] 请求用户授权 ${permissions.join('、')} 失败:${JSON.stringify(err)}`);
|
|
187
|
+
}
|
|
188
|
+
else {
|
|
189
|
+
resolve();
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
}
|
|
177
194
|
function object2String(obj) {
|
|
178
195
|
let str = '';
|
|
179
196
|
for (const item in obj) {
|
|
@@ -2262,20 +2279,20 @@ const chooseMedia = function (options) {
|
|
|
2262
2279
|
});
|
|
2263
2280
|
};
|
|
2264
2281
|
|
|
2282
|
+
const READ_IMAGEVIDEO_PERMISSIONS = 'ohos.permission.READ_IMAGEVIDEO';
|
|
2283
|
+
const READ_MEDIA_PERMISSIONS = 'ohos.permission.READ_MEDIA';
|
|
2284
|
+
const WRITE_MEDIA_PERMISSIONS = 'ohos.permission.WRITE_MEDIA';
|
|
2285
|
+
const MEDIA_LOCATION_PERMISSIONS = 'ohos.permission.MEDIA_LOCATION';
|
|
2286
|
+
const IMAGE_PERMISSION = [READ_IMAGEVIDEO_PERMISSIONS, READ_MEDIA_PERMISSIONS, WRITE_MEDIA_PERMISSIONS, MEDIA_LOCATION_PERMISSIONS];
|
|
2287
|
+
|
|
2265
2288
|
// HarmonyOS 图片模块首批接口从API version 7开始支持。
|
|
2266
2289
|
// HarmonyOS 文档链接:https://developer.harmonyos.com/cn/docs/documentation/doc-references/js-apis-image-0000001122977382
|
|
2267
2290
|
// WX 文档链接:https://developers.weixin.qq.com/miniprogram/dev/api/media/image/wx.saveImageToPhotosAlbum.html
|
|
2268
|
-
// ✅ wx.getImageInfo(Object object) API7以上支持
|
|
2269
|
-
// ✅ wx.compressImage(Object object) API7以上支持
|
|
2270
|
-
// ✅ wx.chooseImage(Object object)
|
|
2271
|
-
// ❌ wx.chooseMessageFile(Object object) HarmonyOS不支持
|
|
2272
|
-
// ❌ wx.saveImageToPhotosAlbum(Object object) api 9+ HarmonyOS不支持
|
|
2273
|
-
// ❌ wx.previewImage(Object object) api 9+ HarmonyOS不支持
|
|
2274
2291
|
const getImageInfoSchema = {
|
|
2275
|
-
|
|
2292
|
+
src: 'String'
|
|
2276
2293
|
};
|
|
2277
2294
|
const compressImageSchema = {
|
|
2278
|
-
|
|
2295
|
+
src: 'String'
|
|
2279
2296
|
};
|
|
2280
2297
|
const chooseImageSchema = {
|
|
2281
2298
|
count: 'Number'
|
|
@@ -2305,56 +2322,191 @@ const getImageInfo = function (options) {
|
|
|
2305
2322
|
});
|
|
2306
2323
|
});
|
|
2307
2324
|
};
|
|
2308
|
-
|
|
2309
|
-
|
|
2325
|
+
class CompressedImageInfo {
|
|
2326
|
+
constructor() {
|
|
2327
|
+
this.imageUri = ''; // 压缩后图片保存位置的uri
|
|
2328
|
+
this.imageByteLength = 0; // 压缩后图片字节长度
|
|
2329
|
+
}
|
|
2330
|
+
}
|
|
2331
|
+
function saveImage(compressedImageData, compressedImageUri) {
|
|
2332
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
2333
|
+
const tempArr = compressedImageUri.split('/');
|
|
2334
|
+
const name = tempArr[tempArr.length - 1];
|
|
2335
|
+
const context = getContext(Current === null || Current === void 0 ? void 0 : Current.page);
|
|
2336
|
+
const applicationContext = context.getApplicationContext();
|
|
2337
|
+
const tempDir = applicationContext.tempDir;
|
|
2338
|
+
const filePath = `${tempDir}/${name}`;
|
|
2310
2339
|
try {
|
|
2311
|
-
|
|
2340
|
+
const res = fs.accessSync(filePath);
|
|
2341
|
+
if (res) {
|
|
2342
|
+
// 如果图片afterCompressiona.jpeg已存在,则删除
|
|
2343
|
+
fs.unlinkSync(filePath);
|
|
2344
|
+
}
|
|
2312
2345
|
}
|
|
2313
|
-
catch (
|
|
2314
|
-
|
|
2346
|
+
catch (err) {
|
|
2347
|
+
console.error(`[Taro] saveImage Error: AccessSync failed with error message: ${err.message}, error code: ${err.code}`);
|
|
2348
|
+
}
|
|
2349
|
+
// 知识点:保存图片。获取最终图片压缩数据compressedImageData,保存图片。
|
|
2350
|
+
// 压缩图片数据写入文件
|
|
2351
|
+
const file = fs.openSync(filePath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
|
|
2352
|
+
fs.writeSync(file.fd, compressedImageData);
|
|
2353
|
+
fs.closeSync(file);
|
|
2354
|
+
// 获取压缩图片信息
|
|
2355
|
+
const compressedImageInfo = new CompressedImageInfo();
|
|
2356
|
+
compressedImageInfo.imageUri = filePath;
|
|
2357
|
+
compressedImageInfo.imageByteLength = compressedImageData.byteLength;
|
|
2358
|
+
return compressedImageInfo;
|
|
2359
|
+
});
|
|
2360
|
+
}
|
|
2361
|
+
const compressImage = function (options) {
|
|
2362
|
+
return new Promise((resolve, reject) => {
|
|
2363
|
+
requestPermissions(IMAGE_PERMISSION).then(() => {
|
|
2364
|
+
try {
|
|
2365
|
+
validateParams('compressImage', options, compressImageSchema);
|
|
2366
|
+
}
|
|
2367
|
+
catch (error) {
|
|
2368
|
+
const res = { errMsg: error.message };
|
|
2369
|
+
return callAsyncFail(reject, res, options);
|
|
2370
|
+
}
|
|
2371
|
+
const { src, quality = 80, compressedWidth, compressedHeight } = options;
|
|
2372
|
+
const srcAfterCompress = src.includes('_after_compress') ? src : src.split('.').join('_after_compress.');
|
|
2373
|
+
const file = fs.openSync(src, fs.OpenMode.READ_ONLY);
|
|
2374
|
+
// const stat = fs.statSync(file.fd)
|
|
2375
|
+
// console.log('[Taro] 压缩前图片的大小为:', stat.size)
|
|
2376
|
+
const source = image.createImageSource(file.fd);
|
|
2377
|
+
if (isNull(source)) {
|
|
2378
|
+
const createImageSourceError = { errMsg: 'compressImage fail: createImageSource has failed.' };
|
|
2379
|
+
callAsyncFail(reject, createImageSourceError, options);
|
|
2380
|
+
return;
|
|
2381
|
+
}
|
|
2382
|
+
const width = source.getImageInfoSync().size.width;
|
|
2383
|
+
const height = source.getImageInfoSync().size.height;
|
|
2384
|
+
let wantWidth = compressedWidth || compressedHeight || 0;
|
|
2385
|
+
let wantHeight = compressedHeight || compressedWidth || 0;
|
|
2386
|
+
if (width > wantWidth || height > wantHeight) {
|
|
2387
|
+
const heightRatio = height / wantHeight;
|
|
2388
|
+
const widthRatio = width / wantWidth;
|
|
2389
|
+
const finalRatio = heightRatio < widthRatio ? heightRatio : widthRatio;
|
|
2390
|
+
wantWidth = Math.round(width / finalRatio);
|
|
2391
|
+
wantHeight = Math.round(height / finalRatio);
|
|
2392
|
+
}
|
|
2393
|
+
const decodingOptions = {
|
|
2394
|
+
editable: true,
|
|
2395
|
+
desiredPixelFormat: image.PixelMapFormat.RGBA_8888,
|
|
2396
|
+
desiredSize: { width: wantWidth, height: wantHeight }
|
|
2397
|
+
};
|
|
2398
|
+
source.createPixelMap(decodingOptions, (error, pixelMap) => {
|
|
2399
|
+
if (error !== undefined) {
|
|
2400
|
+
fs.closeSync(file);
|
|
2401
|
+
const res = { errMsg: error };
|
|
2402
|
+
callAsyncFail(reject, res, options);
|
|
2403
|
+
}
|
|
2404
|
+
else {
|
|
2405
|
+
const packer = image.createImagePacker(file.fd);
|
|
2406
|
+
if (isNull(packer)) {
|
|
2407
|
+
fs.closeSync(file);
|
|
2408
|
+
const createImagePackerError = { errMsg: 'compressImage fail: createImagePacker has failed.' };
|
|
2409
|
+
callAsyncFail(reject, createImagePackerError, options);
|
|
2410
|
+
return;
|
|
2411
|
+
}
|
|
2412
|
+
const isPNG = src.endsWith('.png');
|
|
2413
|
+
const packingOptionsOHOS = {
|
|
2414
|
+
format: isPNG ? 'image/png' : 'image/jpeg',
|
|
2415
|
+
quality: quality
|
|
2416
|
+
};
|
|
2417
|
+
packer.packing(pixelMap, packingOptionsOHOS).then((value) => {
|
|
2418
|
+
fs.closeSync(file);
|
|
2419
|
+
saveImage(value, srcAfterCompress).then(result => {
|
|
2420
|
+
callAsyncSuccess(resolve, { tempFilePath: result.imageUri }, options);
|
|
2421
|
+
});
|
|
2422
|
+
}).catch((error) => {
|
|
2423
|
+
fs.closeSync(file);
|
|
2424
|
+
callAsyncFail(reject, error, options);
|
|
2425
|
+
});
|
|
2426
|
+
}
|
|
2427
|
+
});
|
|
2428
|
+
}, (error) => {
|
|
2429
|
+
const res = { errMsg: error };
|
|
2315
2430
|
return callAsyncFail(reject, res, options);
|
|
2316
|
-
}
|
|
2317
|
-
const { src, quality = 80 } = options;
|
|
2318
|
-
const source = image.createImageSource(src);
|
|
2319
|
-
if (isNull(source)) {
|
|
2320
|
-
const createImageSourceError = { errMsg: 'compressImage fail: createImageSource has failed.' };
|
|
2321
|
-
callAsyncFail(reject, createImageSourceError, options);
|
|
2322
|
-
return;
|
|
2323
|
-
}
|
|
2324
|
-
const packer = image.createImagePacker(src);
|
|
2325
|
-
if (isNull(packer)) {
|
|
2326
|
-
const createImagePackerError = { errMsg: 'compressImage fail: createImagePacker has failed.' };
|
|
2327
|
-
callAsyncFail(reject, createImagePackerError, options);
|
|
2328
|
-
}
|
|
2329
|
-
const packingOptionsOHOS = {
|
|
2330
|
-
// TODO:需要获取文件名后缀
|
|
2331
|
-
format: 'image/jpeg',
|
|
2332
|
-
quality: quality
|
|
2333
|
-
};
|
|
2334
|
-
packer.packing(source, packingOptionsOHOS).then((value) => {
|
|
2335
|
-
callAsyncSuccess(resolve, value, options);
|
|
2336
|
-
}).catch((error) => {
|
|
2337
|
-
callAsyncFail(reject, error, options);
|
|
2338
2431
|
});
|
|
2339
2432
|
});
|
|
2340
2433
|
};
|
|
2341
2434
|
const chooseImage = function (options) {
|
|
2342
2435
|
return new Promise((resolve, reject) => {
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2436
|
+
requestPermissions(IMAGE_PERMISSION).then(() => {
|
|
2437
|
+
try {
|
|
2438
|
+
validateParams('chooseImage', options, chooseImageSchema);
|
|
2439
|
+
}
|
|
2440
|
+
catch (error) {
|
|
2441
|
+
const res = { errMsg: error.message };
|
|
2442
|
+
return callAsyncFail(reject, res, options);
|
|
2443
|
+
}
|
|
2444
|
+
const { count = 9 } = options;
|
|
2445
|
+
const photoViewPicker = new picker.PhotoViewPicker();
|
|
2446
|
+
let sizeType = options.sizeType;
|
|
2447
|
+
if (!sizeType || !sizeType.length) {
|
|
2448
|
+
sizeType = ['compressed', 'original'];
|
|
2449
|
+
}
|
|
2450
|
+
photoSelectOptions.maxSelectNumber = count; // 选择媒体文件的最大数目
|
|
2451
|
+
photoSelectOptions.MIMEType = picker.PhotoViewMIMETypes.IMAGE_TYPE; // 过滤选择媒体文件类型为IMAGE
|
|
2452
|
+
photoViewPicker.select(photoSelectOptions).then((photoSelectResult) => {
|
|
2453
|
+
const result = {};
|
|
2454
|
+
const isOrigin = photoSelectResult.isOriginalPhoto;
|
|
2455
|
+
if (isOrigin) {
|
|
2456
|
+
const tempFilePaths = [];
|
|
2457
|
+
const tempFiles = photoSelectResult.photoUris.map(uri => {
|
|
2458
|
+
const file = fs.openSync(uri, fs.OpenMode.READ_ONLY);
|
|
2459
|
+
const stat = fs.statSync(file.fd);
|
|
2460
|
+
const size = stat.size;
|
|
2461
|
+
fs.closeSync(file);
|
|
2462
|
+
tempFilePaths.push(uri);
|
|
2463
|
+
return {
|
|
2464
|
+
size,
|
|
2465
|
+
path: uri,
|
|
2466
|
+
};
|
|
2467
|
+
});
|
|
2468
|
+
result.tempFiles = tempFiles;
|
|
2469
|
+
result.tempFilePaths = tempFilePaths;
|
|
2470
|
+
callAsyncSuccess(resolve, result, options);
|
|
2471
|
+
}
|
|
2472
|
+
else {
|
|
2473
|
+
const actions = photoSelectResult.photoUris.map(uri => {
|
|
2474
|
+
return new Promise(resolve => {
|
|
2475
|
+
compressImage({
|
|
2476
|
+
src: uri,
|
|
2477
|
+
compressedWidth: getSystemInfoSync().screenWidth / 2,
|
|
2478
|
+
compressedHeight: getSystemInfoSync().screenHeight / 2,
|
|
2479
|
+
success: (compressResult) => {
|
|
2480
|
+
resolve(compressResult.tempFilePath);
|
|
2481
|
+
}
|
|
2482
|
+
});
|
|
2483
|
+
});
|
|
2484
|
+
});
|
|
2485
|
+
Promise.all(actions).then(tempFilePaths => {
|
|
2486
|
+
const tempFiles = tempFilePaths.map(uri => {
|
|
2487
|
+
const file = fs.openSync(uri, fs.OpenMode.READ_ONLY);
|
|
2488
|
+
const stat = fs.statSync(file.fd);
|
|
2489
|
+
const size = stat.size;
|
|
2490
|
+
fs.closeSync(file);
|
|
2491
|
+
return {
|
|
2492
|
+
size,
|
|
2493
|
+
path: uri,
|
|
2494
|
+
};
|
|
2495
|
+
});
|
|
2496
|
+
result.tempFilePaths = tempFilePaths;
|
|
2497
|
+
result.tempFiles = tempFiles;
|
|
2498
|
+
callAsyncSuccess(resolve, result, options);
|
|
2499
|
+
}).catch(error => {
|
|
2500
|
+
const res = { errMsg: error };
|
|
2501
|
+
return callAsyncFail(reject, res, options);
|
|
2502
|
+
});
|
|
2503
|
+
}
|
|
2504
|
+
}).catch((error) => {
|
|
2505
|
+
callAsyncFail(reject, error, options);
|
|
2506
|
+
});
|
|
2507
|
+
}, (error) => {
|
|
2508
|
+
const res = { errMsg: error };
|
|
2348
2509
|
return callAsyncFail(reject, res, options);
|
|
2349
|
-
}
|
|
2350
|
-
const { count = 9 } = options;
|
|
2351
|
-
const photoViewPicker = new picker.PhotoViewPicker();
|
|
2352
|
-
photoSelectOptions.maxSelectNumber = count; // 选择媒体文件的最大数目
|
|
2353
|
-
photoSelectOptions.MIMEType = picker.PhotoViewMIMETypes.IMAGE_TYPE; // 过滤选择媒体文件类型为IMAGE
|
|
2354
|
-
photoViewPicker.select(photoSelectOptions).then((photoSelectResult) => {
|
|
2355
|
-
callAsyncSuccess(resolve, { tempFilePaths: photoSelectResult.photoUris }, options);
|
|
2356
|
-
}).catch((error) => {
|
|
2357
|
-
callAsyncFail(reject, error, options);
|
|
2358
2510
|
});
|
|
2359
2511
|
});
|
|
2360
2512
|
};
|