经过在角色区和造型区成功生成图片的历程之后,最后的任务就是在背景区通过文生图模型生成图片了。这次任务相对来说也是最简单的一步,因为它和之前的逻辑非常相似,只是在 Scratch 3 的背景区操作图片。

遇到的问题

在实现背景区生成图片时,我已经有了之前的角色和造型区开发的经验,因此这次遇到的挑战并不多。主要需要注意的是,背景的处理和造型类似,但需要确保它被设置为舞台的当前背景。

解决方法

这里同样使用了 TextGeneratedPic 方法来处理图片的生成。我们通过文生图模型获取到的图片 URL,然后调用 addBackdropToStage 方法将该图片设置为背景。

关键代码

1
2
3
4
5
async TextGeneratedPic(args, util) {
const imageUrl = this.imageUrl
const stage = this.runtime.getTargetForStage()
await this.addBackdropToStage(stage, imageUrl, util)
}

这段代码的作用是获取舞台对象 stage,并将图片 URL 传递给 addBackdropToStage 方法,以完成背景的设置。

背景的处理与添加

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
async addBackdropToStage(stage, imageUrl, util) {
try {
const response = await fetch(imageUrl)
const blob = await response.blob()
const imageBitmap = await createImageBitmap(blob)
const extractedContent = this.imageUrl.split('.png')[0]

const md5 = extractedContent

const canvas = document.createElement('canvas')
canvas.width = imageBitmap.width
canvas.height = imageBitmap.height
const context = canvas.getContext('2d')
context.drawImage(imageBitmap, 0, 0)

const pngDataUrl = canvas.toDataURL('image/png')
const base64Data = pngDataUrl.split(',')[1]

const binaryString = atob(base64Data)
const binaryLen = binaryString.length
const bytes = new Uint8Array(binaryLen)
for (let i = 0; i < binaryLen; i++) {
const ascii = binaryString.charCodeAt(i)
bytes[i] = ascii
}

const backdrop = {
asset: null,
md5: `${md5}.png`,
name: this.fileName + new Date().getTime(),
bitmapResolution: 2,
rotationCenterX: imageBitmap.width / 2,
rotationCenterY: imageBitmap.height / 2,
skinId: null,
dataFormat: 'png'
}

const storage = stage.runtime.storage
const asset = storage.createAsset(
AssetType.ImageBitmap,
'png',
bytes,
md5
)

backdrop.asset = asset
backdrop.assetId = asset.assetId

const skinId = await stage.runtime.renderer.createBitmapSkin(imageBitmap, backdrop.bitmapResolution)
backdrop.skinId = skinId

console.log(stage.sprite, 'stage.sprite')

stage.sprite.costumes.push(backdrop)
stage.setCostume(stage.sprite.costumes.length - 1)
this.runtime.emit("SAY", util.target, "say", '')
console.log('背景已成功添加并设置为当前背景')
} catch (error) {
console.error('添加背景时出错:', error)
}
}

代码解析

图片的加载与处理:与之前处理角色和造型时类似,我们通过 fetch 从 imageUrl 获取图片,并将其转换为 imageBitmap。通过 canvas 将图片绘制为 Base64,接着将 Base64 数据解析为二进制数据,构建背景的 backdrop 对象。

背景对象的创建:backdrop 对象包含了图片的 MD5 值、名称、分辨率等信息,并通过 Scratch 的存储机制创建了对应的图片资源 asset。

背景的设置:最终将背景对象添加到舞台的 costumes 列表中,并设置为当前背景。为了确保背景正确渲染,还调用了 setCostume 方法。

经验与收获

与之前在角色区和造型区生成图片相比,在背景区生成图片是整个任务的最后一步,也是最简单的一步。通过前面的开发经历,我对 Scratch 的渲染机制有了更深入的理解。在背景的设置过程中,主要工作依然是处理图片的格式,并确保它能够正确显示在舞台上。

这次开发也标志着我在通过文生图模型生成图片任务上的全部完成。从角色区、造型区到背景区,我成功实现了在 Scratch 3 中通过文生图生成的图片动态添加的功能。

生成中

已完成