Nanfeng

Notes on software development, code, and curious ideas

Uploading and Cropping Local Images in a Cocos Creator Web Build

A Cocos Creator web build can use an HTML file input and JavaScript APIs to select images on desktop or mobile.

Create a hidden picker and read the selected file:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
private inputElement: HTMLInputElement;

private createInput() {
this.inputElement = document.createElement('input');
this.inputElement.type = 'file';
this.inputElement.accept = 'image/*';
this.inputElement.style.display = 'none';
document.body.appendChild(this.inputElement);
this.inputElement.addEventListener('change', event => {
const target = event.target as HTMLInputElement;
if (target.files?.length) this.handleFileUpload(target.files[0]);
});
}

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

Reject oversized files, convert the image to a data URL, then crop and compress it:

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
private handleFileUpload(file: File) {
if (file.size > 1024 * 1024) {
console.error('The file is too large');
return;
}
const reader = new FileReader();
reader.onload = event => {
const url = event.target?.result as string;
this.compressImage(url, 126, 126).then(result => {
this.loadTextureInCocos(this.imgNode, result, 126, 126);
});
};
reader.readAsDataURL(file);
}

public compressImage(url: string, targetWidth: number, targetHeight: number): Promise<string> {
return new Promise(resolve => {
const img = new Image();
img.src = url;
img.onload = () => {
const size = Math.min(img.width, img.height);
const startX = (img.width - size) / 2;
const startY = (img.height - size) / 2;
const canvas = document.createElement('canvas');
canvas.width = targetWidth;
canvas.height = targetHeight;
canvas.getContext('2d')?.drawImage(
img, startX, startY, size, size,
0, 0, targetWidth, targetHeight
);
resolve(canvas.toDataURL('image/jpeg', 0.5));
};
});
}

Create a Cocos texture and SpriteFrame:

1
2
3
4
5
6
7
8
9
10
11
12
public loadTextureInCocos(node: Node, imageUrl: string, width: number, height: number) {
const image = new Image();
image.onload = () => {
const texture = new Texture2D();
texture.image = new ImageAsset(image);
const frame = new SpriteFrame();
frame.texture = texture;
node.getComponent(Sprite).spriteFrame = frame;
node.getComponent(UITransform).setContentSize(width, height);
};
image.src = imageUrl;
}

Use HTTPS, remove the hidden DOM element when the component is destroyed, and keep memory usage in mind for large images.

+