ImageUtils.ets
9.98 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
/*
* Copyright (c) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { resourceManager } from '@kit.LocalizationKit';
import { image } from '@kit.ImageKit';
import { ColorHsv, ColorRgb, ColorUtils } from './ColorUtils';
import { http } from '@kit.NetworkKit';
import { BusinessError } from '@kit.BasicServicesKit';
import ResponseCode from '@ohos.net.http';
const resourceMgs: resourceManager.ResourceManager = getContext(this).resourceManager;
const PIXEL_MAP_SIZE_WIDTH: number = 40;
const PIXEL_MAP_SIZE_HEIGHT: number = 40;
/**
* 图片转换为PixelMap对象
* @param icon 图片地址,模拟数据存放于rawfile文件夹中
* @returns 图片转换的PixelMap对象
*/
export async function image2PixelMap(icon: string): Promise<image.PixelMap> {
// 读取rawfile文件夹下的文件
const rawFileDescriptor: resourceManager.RawFileDescriptor = resourceMgs.getRawFdSync(icon);
const imageSource: image.ImageSource = image.createImageSource(rawFileDescriptor);
// 通过ImageSource对象创建PixelMap对象,使用BGRA_8888格式,由4个字节表示一个像素
const pixelMap: Promise<PixelMap> = imageSource.createPixelMap({
editable: false,
desiredPixelFormat: image.PixelMapFormat.BGRA_8888,
// 高性能知识点:经测试,将图片的宽和高设置为40像素时,既可以保证提取颜色的准确性,也可以保证计算颜色的速度。
desiredSize: { width: PIXEL_MAP_SIZE_WIDTH, height: PIXEL_MAP_SIZE_HEIGHT }
})
return pixelMap;
}
/**
* 通过http的request方法从网络下载图片资源
*/
// export async function getPicture() {
// const url:string='https://rmrbcmsonline.peopleapp.com/upload/image/202312/rmrb_86691703594454.png'
// http.createHttp()
// .request(url,
// (error: BusinessError, data: http.HttpResponse) => {
// // if (error) {
// // // 下载失败时弹窗提示检查网络,不执行后续逻辑
// // promptAction.showToast({
// // message: $r('app.string.image_request_fail'),
// // duration: 2000
// // })
// // return;
// // }
// // transcodePixelMap(data);
// // 判断网络获取到的资源是否为ArrayBuffer类型
// // if (data.result instanceof ArrayBuffer) {
// // this.imageBuffer = data.result as ArrayBuffer;
// // }
// if (ResponseCode.ResponseCode.OK === data.responseCode) {
// const imageData: ArrayBuffer = data.result as ArrayBuffer;
// // 通过ArrayBuffer创建图片源实例。
// const imageSource: image.ImageSource = image.createImageSource(imageData);
// return imageSource
// // const options: image.InitializationOptions = {
// // 'alphaType': 0, // 透明度
// // 'editable': false, // 是否可编辑
// // 'pixelFormat': 3, // 像素格式
// // 'scaleMode': 1, // 缩略值
// // 'size': { height: 100, width: 100 }
// // }; // 创建图片大小
//
// // 通过属性创建PixelMap
// // imageSource.createPixelMap(options).then((pixelMap: PixelMap) => {
// // // this.image = pixelMap;
// // });
// // imageNet2PixelMap(imageSource)
// }
// }
// )
// }
// 假设http和image是之前正确导入或定义的模块
export async function getPicture(imageUrl: string): Promise<image.ImageSource | undefined> {
// const url: string = 'https://rmrbcmsonline.peopleapp.com/upload/image/202312/rmrb_86691703594454.png';
const url: string = 'https://rmrbcmsonline.peopleapp.com/upload/image/201912/rmrb_24141576767688.png?x-oss-process=image/resize,w_550/quality,q_90/format,jpg';
return new Promise((resolve, reject) => {
http.createHttp().request(url, (error: BusinessError, data: http.HttpResponse) => {
if (error) {
// 处理错误情况,比如网络错误
console.error("Download error", error);
// 你可以选择reject(error)或者根据需要调整
reject(error);
return;
}
if (ResponseCode.ResponseCode.OK === data.responseCode) {
const imageData: ArrayBuffer = data.result as ArrayBuffer;
// 通过ArrayBuffer创建图片源实例
const imageSource: image.ImageSource = image.createImageSource(imageData);
resolve(imageSource); // 成功时解析Promise
} else {
// 处理其他响应码
reject(new Error('Invalid response code'));
}
});
});
}
/**
* 使用createPixelMap将ArrayBuffer类型的图片装换为PixelMap类型
* @param data:网络获取到的资源
*/
function transcodePixelMap(data: http.HttpResponse) {
if (ResponseCode.ResponseCode.OK === data.responseCode) {
const imageData: ArrayBuffer = data.result as ArrayBuffer;
// 通过ArrayBuffer创建图片源实例。
const imageSource: image.ImageSource = image.createImageSource(imageData);
// const options: image.InitializationOptions = {
// 'alphaType': 0, // 透明度
// 'editable': false, // 是否可编辑
// 'pixelFormat': 3, // 像素格式
// 'scaleMode': 1, // 缩略值
// 'size': { height: 100, width: 100 }
// }; // 创建图片大小
// 通过属性创建PixelMap
// imageSource.createPixelMap(options).then((pixelMap: PixelMap) => {
// // this.image = pixelMap;
// });
// imageNet2PixelMap(imageSource)
}
}
/**
* 图片转换为PixelMap对象
* @param icon 图片地址,模拟数据存放于rawfile文件夹中
* @returns 图片转换的PixelMap对象
*/
export async function imageNet2PixelMap(imageSource: image.ImageSource): Promise<image.PixelMap> {
// 读取rawfile文件夹下的文件
// const rawFileDescriptor: resourceManager.RawFileDescriptor = resourceMgs.getRawFdSync(icon);
// const imageSource: image.ImageSource = image.createImageSource(rawFileDescriptor);
// 通过ImageSource对象创建PixelMap对象,使用BGRA_8888格式,由4个字节表示一个像素
const pixelMap: Promise<PixelMap> = imageSource.createPixelMap({
editable: false,
desiredPixelFormat: image.PixelMapFormat.BGRA_8888,
// 高性能知识点:经测试,将图片的宽和高设置为40像素时,既可以保证提取颜色的准确性,也可以保证计算颜色的速度。
desiredSize: { width: PIXEL_MAP_SIZE_WIDTH, height: PIXEL_MAP_SIZE_HEIGHT }
})
return pixelMap;
}
/**
* 查找数组中出现次数最多的像素
* @param allPixels 像素数组
* @returns 出现次数最多的像素
*/
export function findMaxPixel(allPixels: number[]): number {
// 遍历数组,将像素放到一个Map中,key是像素值,value是该像素值出现的次数
const map: Map<number, number> = new Map();
allPixels.forEach((pixel: number) => {
if (map.has(pixel)) {
map.set(pixel, map.get(pixel)! + 1);
} else {
map.set(pixel, 1);
}
})
// 查找出现次数最多的像素
let maxPixel: number = 0;
let maxTimes: number = 0;
map.forEach((value: number, key: number) => {
if (value >= maxTimes) {
maxTimes = value;
maxPixel = key;
}
})
return maxPixel;
}
/**
* 修改HSV格式的颜色值,可根据业务需求或者UI设计自行修改S和V的值,此处只举例进行说明
* @param color HSV格式的颜色
*/
export function modifySVValue(color: ColorHsv): void {
if (color.hue > 0 && color.hue <= 60) {
color.saturation = 0.12;
color.value = 0.93;
} else if (color.hue > 60 && color.hue <= 190) {
color.saturation = 0.08;
color.value = 0.91;
} else if (color.hue > 190 && color.hue <= 270) {
color.saturation = 0.1;
color.value = 0.93;
} else {
color.saturation = 0.08;
color.value = 0.93;
}
}
/**
* 遍历所有像素,并放到一个数组中
* @param pixelMap 图片的PixelMap对象
* @returns 包含图片所有像素的数组
*/
export async function traverseAllPixel(pixelMap: image.PixelMap): Promise<number[]> {
// PixelMap对象使用BGRA_8888格式,由4个字节表示一个像素,并且宽和高都设置为40,所以此处ArrayBuffer的length就是40*40*4
const pixelArrayBuffer: ArrayBuffer = new ArrayBuffer(40 * 40 * 4);
// 将PixelMap对象读入ArrayBuffer中
await pixelMap.readPixelsToBuffer(pixelArrayBuffer);
const allPixels: number[] = [];
// ArrayBuffer是一个二进制的数组,无法直接读取内容,需要转换为整型数组才可以正常使用,此处使用Uint8Array(8 位无符号整型数组)
const unit8Pixels: Uint8Array = new Uint8Array(pixelArrayBuffer);
// 遍历unit8Pixels,取出每个像素的red、green、blue、alpha颜色值,放到一个ColorRgb对象中,然后将ColorRgb转换为数字,放入数组中
for (let i = 0; i < unit8Pixels.length; i += 4) {
// 如果是透明色,则不放入数组中,否则可能导致计算出来的出现次数最多的像素是透明色
if (unit8Pixels[i] === 0 && unit8Pixels[i+1] === 0 && unit8Pixels[i+2] === 0 && unit8Pixels[i+3] === 0) {
continue;
}
// BGRA_8888格式,B表示Blue,G表示Green,R表示Red,A表示透明度,此处根据顺序提取B、R、G、A
const rgb: ColorRgb = {
red: unit8Pixels[i+2],
green: unit8Pixels[i+1],
blue: unit8Pixels[i],
alpha: unit8Pixels[i+3]
}
// 高性能知识点:直接将ColorRgb放入数组或者Map中会影响计算出现次数最多的像素的速度,所以需要使用rgbToNumber方法转换为整数
allPixels.push(ColorUtils.rgbToNumber(rgb));
}
return allPixels;
}