如何用纯JavaScript从spritesheet中提取指定精灵切片并返回base64
问题分析
你原有代码存在三个核心问题:
- 图片是异步加载资源,未等加载完成就执行裁剪逻辑,drawImage操作会失效,画布为空
- canvas变量定义在循环内部,循环结束后只能拿到最后一个tile的画布,无法匹配坐标获取对应tile
- 未设置图片跨域属性,画布会被浏览器标记为跨域污染,无法调用toDataURL导出base64
原生JS实现方案
以下是完整可运行的实现,预加载裁剪所有tile缓存后,可直接调用getTile(x, y)获取对应tile的base64编码:
// 雪碧图基础配置 const TILE_SIZE = 16; // 单个tile的实际尺寸 const TILE_GAP = 1; // 雪碧图上tile之间的间隔像素 const SPRITE_URL = 'https://cdn.glitch.me/b3505ee1-a321-48ea-baf5-d84841324af1%2Fd3b13ce6-f5ed-4122-9bd9-37f74d13d470.image.png?v=1634242985542'; const ROW_TOTAL = 8; // 雪碧图总行数 const COL_TOTAL = 20; // 雪碧图总列数 let tileCache = []; // 所有tile的base64缓存 let spriteLoaded = false; // 预加载雪碧图并裁剪所有tile存入缓存 function initSpriteSheet() { return new Promise((resolve, reject) => { const spriteImg = new Image(); // 处理跨域,避免画布被污染 spriteImg.crossOrigin = 'anonymous'; spriteImg.src = SPRITE_URL; spriteImg.onload = () => { for (let row = 0; row < ROW_TOTAL; row++) { tileCache[row] = []; for (let col = 0; col < COL_TOTAL; col++) { const canvas = document.createElement('canvas'); const ctx = canvas.getContext('2d'); canvas.width = TILE_SIZE; canvas.height = TILE_SIZE; // 计算裁剪起始位置,跳过1px间隔 const sourceX = col * (TILE_SIZE + TILE_GAP) + TILE_GAP; const sourceY = row * (TILE_SIZE + TILE_GAP) + TILE_GAP; ctx.drawImage(spriteImg, sourceX, sourceY, TILE_SIZE, TILE_SIZE, 0, 0, TILE_SIZE, TILE_SIZE); tileCache[row][col] = canvas.toDataURL('image/png'); } } spriteLoaded = true; resolve(); }; spriteImg.onerror = reject; }); } // 目标调用函数:getTile(横向坐标x, 纵向坐标y) 返回对应tile的base64 function getTile(x, y) { if (!spriteLoaded) throw new Error('雪碧图未加载完成,请等待初始化完成后调用'); if (x < 0 || x >= COL_TOTAL || y < 0 || y >= ROW_TOTAL) throw new Error('tile坐标超出范围'); return tileCache[y][x]; } // 使用示例 initSpriteSheet().then(() => { // 初始化完成后可任意调用getTile const knightBase64 = getTile(2, 1); // 测试:新窗口打开查看获取到的骑士图案 const testTab = window.open('about:blank'); testTab.document.write(`<img src="${knightBase64}" alt="骑士tile">`); });
注意说明
- 所有tile仅在初始化时裁剪一次,后续调用
getTile直接读取缓存,性能损耗极低 - 坐标规则和你要求的完全一致,
getTile(2,1)即可获取对应骑士图案的base64编码 - 如果你的业务场景不需要提前缓存所有tile,也可以修改为调用
getTile时实时裁剪,按需调整即可
内容的提问来源于stack exchange,提问作者qman101
相关产品推荐
相关产品推荐

