独辟蹊径:逆推Krpano切图算法,实现在浏览器切多层级瓦片图( 四 )

analyzeImageLevel(panoWidth: number) {// 系数,瓦片图最高层级的尺寸 = 图片宽度 / 系数const coefficient = 3.125// 瓦片图最大尺寸const maxTileSize = 512// 瓦片图最小尺寸const minTileSize = 64// 调整层级的尺寸:控制 faceSize % 512 % 64 = 0function adjustLevelSize(inputLevelSize: number) {if (inputLevelSize % maxTileSize % minTileSize === 0) return inputLevelSizeconst lastTileSize = inputLevelSize % maxTileSize// 最后一行小于64则舍弃if (lastTileSize < minTileSize) {inputLevelSize -= lastTileSize} else {//最后一行瓦片的余数(对64取余)const minRemainder = lastTileSize % minTileSizeif (minRemainder !== 0) {inputLevelSize = inputLevelSize - (minTileSize - minRemainder)}}return inputLevelSize}function getLevelConfig(panoSize): ILevelConfig[] {let count = 1let levels = []const minFaceSize = 640const topLevelSize = panoSize / coefficient// 最高层levels.push({level: count,size: adjustLevelSize(topLevelSize)})getNextLevelConfig(topLevelSize)// 递归获取子层级function getNextLevelConfig(topLevelSize) {const levelstep = 2const nextLevelSize = topLevelSize / levelstepif (nextLevelSize + minTileSize >= minFaceSize) {count++levels.push({level: count,size: adjustLevelSize(nextLevelSize)})getNextLevelConfig(nextLevelSize)}}// 层级转为正常从小到大levels = levels.map((item, index) => {item.level = levels.length - indexreturn item})return levels}this.levelConfig = getLevelConfig(panoWidth)}8.利用canvas分割图片上面我们推算出了算法,得到了这样的数据:
// 层级数// 每一层级的分辨率let levelConfig = [{level: 1,size: 768,},{level: 2,size: 1600,},{level: 3,size: 3200,},]把一张图按照一定的规律风格成碎图,这很简单,不在这里详细展开,否则篇幅太长,可以去网上搜索或者我到时候单独写个文章 。
9.如何在生成目录结构和下载?大家在使用我的DEMO的时候可以发现,你传一张全景图上去,我可以在浏览器给你直接下载整个压缩包,并且里面已经分好层级和目录结构 。
如图所示 , 这是我在浏览器生成的:

独辟蹊径:逆推Krpano切图算法,实现在浏览器切多层级瓦片图

文章插图
01.JSZip
  • 这时候,我给大家推荐一个非常好用的浏览器压缩与解压工具JSZip,官方文档 。效率高,速度快,压缩2G以内的非常快,有一次我压缩3700张图片,每张1m,这是内存就爆满了 , 不过这种极限条件下一般遇不到,解决方法也很简单,分块上传 。
  • 他可以让我们很方便的去压缩文件上传到服务器,在前端压缩文件再传到后端的优势是可以极大减少请求数量,比如上传1000张需要1000个请求,压缩成一个文件仅需要一个请求,并且大文件上传速度比传碎文件速度快 。
  • 做这个demo遇到很多问题:
    • Mac上unix可执行文件压缩就再解压,就不是可执行文件了 , 因为在Mac中可执行文件其实就是可以使用普通文稿去生成,暂时无解;
    • 在vite构建工具中 , 如果文件放到了assets中,打包之后的文件会带上hash,导致场景无法预览 , 如果放在public中又无法使用import,巧妙的解决方法:把所有需要放在assets中的打包成一个压缩包,单独导入这个压缩包 , 再把它解压,最终合并到zip实例中去;
    • ...
02.file-saver下载的话 , 我也推荐一个好用的库,file-saver,源码链接 。下载文件其实很简单,但是如果有非常好用、稳定的库,那直接用就得了,不用自己写 。
在早期,关于文件的操作 , 我都是交给后端来处理,我调接口 。但现在不一样,这两个库给了我无限的想象空间,很多东西我可以在前端去组装去做,然后再统一给到后端 。
10.生成预览图 preview.jpg
前面最核心都做完了,这个小图片岂能难道我?果不其然?。。?
进入场景前会先加载预览图 , 等场景图片加载完后才显示原图,这样可以提升场景加载速度并且不会耗费太多资源 。
预览图如下 , 是一张分辨率为256x1536的长条图 。它生成的方式是立方体的六个面,按照「左、前、右、后、上、下」,自上而下拼接成 。
独辟蹊径:逆推Krpano切图算法,实现在浏览器切多层级瓦片图

文章插图
我就是这样去合成的,我测试的时候把场景image节点隐藏掉 , 仅加载预览图,发现没问题很完美 。
错就错在我是一个特别细心的人,如下图,我发现我合成的图片体积有221kb,而krpano才77kb,体积整整比它大了三倍啊 。这里面到底暗藏了什么玄机?

推荐阅读