南锋

南奔万里空,脱死锋镝余

cocosCreator导出web工程上传本地图片

在 Cocos Creator 导出的 Web 项目中实现手机或者电脑上传相册图片,可以使用 HTMLJavaScript 来实现文件选择功能,并将其与 Cocos Creator 项目进行集成。以下是大致的步骤:

1、在ts脚本中动态创建HTML元素(input文件选择器)

在ts脚本中动态创建HTML元素(input文件选择器,并添加事件)

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
private inputElement;

private creatorInput() {
this.inputElement = document.createElement('input');
this.inputElement.type = 'file';
this.inputElement.accept = 'image/*'; // 仅接受图片文件
this.inputElement.style.display = 'none'; // 隐藏 input
document.body.appendChild(this.inputElement);
this.inputElement.addEventListener('change', (event: Event) => {
const target = event.target as HTMLInputElement;
if (target.files && target.files.length > 0) {
const file = target.files[0];
this.handleFileUpload(file);
}
});
}
private handleFileUpload(file: File) {
const reader = new FileReader();
// 读取文件为 DataURL
reader.onload = (e) => {
const imageUrl = e.target?.result as string;
this.loadTextureInCocos(imgNode,imageUrl); // imgNode为图片显示的节点,即上传的图片会在这个节点渲染
};
reader.readAsDataURL(file);
}

private loadTextureInCocos(node: Node, imageUrl: string){
let image = new Image();
image.onload = () => {
let img = new ImageAsset(image)
let texture = new Texture2D();
texture.image = img; // 设置纹理的图片
let spriteFrame = new SpriteFrame();
spriteFrame.texture = texture;
node.getComponent(Sprite).spriteFrame = spriteFrame; // 直接设置精灵帧
node.getComponent(UITransform).setContentSize(width, hight); // 可选,自己设置图片尺寸
};
image.src = imageUrl;
}

2、创建上传图片按钮

1
2
3
private clickBtn(){
this.inputElement.click();
}

完成上面2步就可以实现图片上传功能了。

3、优化

上面方法是可行的,但是我这里使用的时候有几点优化
1、上传图片过大时,容易卡住
2、上传图片为长方形时,会显示不全
3、我这里要将长方形的图片只显示一个正方形,即截取中间一部分
优化方案:
1、上传图片的时候对图片大小进行限制
2、将上传的图片进行压缩
3、渲染图片时对图片进行尺寸修改(缩放和裁剪)

示例代码

我这里是将上传的图片首先按照长宽比进行一个正方形的裁剪,以短的那边作为边长。
然后对裁剪后的图片按照我给出的寸尺进行缩放,缩放到我想要的尺寸,再进行压缩,压缩后输出一个jpeg的base64的数据。

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
private inputElement;
private imageUrl;
private creatorInput() {
this.inputElement = document.createElement('input');
this.inputElement.type = 'file';
this.inputElement.accept = 'image/*'; // 仅接受图片文件
this.inputElement.style.display = 'none'; // 隐藏 input
document.body.appendChild(this.inputElement);
this.inputElement.addEventListener('change', (event: Event) => {
const target = event.target as HTMLInputElement;
if (target.files && target.files.length > 0) {
const file = target.files[0];
this.handleFileUpload(file);
}
});
}
private handleFileUpload(file: File) {
if (file.size > 1024 * 1024) { // 限制文件大小为 2MB
console.error('文件过大,无法上传');
return;
}
const reader = new FileReader();
// 读取文件为 DataURL
reader.onload = (e) => {
const imageUrl = e.target?.result as string;
Tool.compressImage(imageUrl, 126, 126).then((compressedImageUrl) => {
this.imageUrl = compressedImageUrl;
Tool.loadTextureInCocos(this.imgNode, compressedImageUrl, 126, 126);
});
};
reader.readAsDataURL(file);
}

private loadTextureInCocos(node: Node, imageUrl: string){
let image = new Image();
image.onload = () => {
let img = new ImageAsset(image)
let texture = new Texture2D();
texture.image = img; // 设置纹理的图片
let spriteFrame = new SpriteFrame();
spriteFrame.texture = texture;
node.getComponent(Sprite).spriteFrame = spriteFrame; // 直接设置精灵帧
node.getComponent(UITransform).setContentSize(width, hight); // 可选,自己设置图片尺寸
};
image.src = imageUrl;
}

public compressImage(url: string, targetWidth: number, targetHeight: number): Promise<string> {
return new Promise((resolve) => {
const img = new Image();
img.src = url;

img.onload = () => {
const width = img.width;
const height = img.height;

// 计算正方形的边长
const size = Math.min(width, height);

// 计算截取的正方形区域
const startX = (width - size) / 2; // 中心点
const startY = (height - size) / 2; // 中心点

// 创建画布来截取正方形
const canvas = document.createElement('canvas');
canvas.width = size;
canvas.height = size;

const ctx = canvas.getContext('2d');
ctx?.drawImage(img, startX, startY, size, size, 0, 0, size, size); // 截取并绘制正方形

// 创建一个新的画布以进行缩放
const scaledCanvas = document.createElement('canvas');
scaledCanvas.width = targetWidth;
scaledCanvas.height = targetHeight;
const scaledCtx = scaledCanvas.getContext('2d');

// 按比例缩放图像
scaledCtx?.drawImage(canvas, 0, 0, size, size, 0, 0, targetWidth, targetHeight);

// 输出压缩后的图片
resolve(scaledCanvas.toDataURL('image/jpeg', 0.5)); // 使用 JPEG 格式压缩
};
});
}
public loadTextureInCocos(node: Node, imageUrl: string, width, hight) {
let image = new Image();
image.onload = () => {
let img = new ImageAsset(image)
let texture = new Texture2D();
texture.image = img; // 设置纹理的图片
let spriteFrame = new SpriteFrame();
spriteFrame.texture = texture;
node.getComponent(Sprite).spriteFrame = spriteFrame; // 直接设置精灵帧
node.getComponent(UITransform).setContentSize(width, hight);
};
image.src = imageUrl;
}

private clickBtn(){
this.inputElement.click();
}

5、代码解读

文件选择事件:我们为文件选择器设置了 change 事件监听器,当用户选择图片时,会调用 handleFileUpload() 方法。

FileReader 读取图片``:FileReader 用来读取用户上传的图片,并将其转换为 Base64 数据 URL 格式。

6、注意事项

跨域问题:确保你的服务器支持 https,否则某些浏览器可能会限制上传功能的使用。
UI布局:上传按钮的位置可以根据你的游戏场景动态调整。
性能考虑:如果图片过大,可能会导致内存消耗过多,可以在上传前对图片进行压缩。

+