当前位置:   article > 正文

Krpano:打造全景漫游体验—全景开发(一)

krpano

前言

前面的文章主要基本介绍了krpano一些元素的用法,从这篇文章开始我们就进入全景开发的实战教学,从全景切图全景编辑最后到整个全景的预览,前端使用react框架+antd组件库+krpano,后端使用koa来实现一个类似720云全景的制作网站

image.png

image.png

之前的文章中都是通过MAKE VTOUR Droplet.exe应用程序来手动切图的,但是对于一个制作网站来说肯定是网站来帮用户实现切图,用户只需要上传全景图片,前端拿到图片再传给后端,通过后端来完成切图,所以步骤是-->用户选择图片切图-->客户端拿到图片后调用接口进行上传-->服务端实现切图-->切图完成

krpano实现切图demo

1.用户选择图片并调用接口上传

上传图片通过Upload组件上传,这里将官方文档的示例直接复制过来

<Upload {...props}>
  <Button type="primary">本地导入</Button>
</Upload>
const props: UploadProps = {
    name: 'panos',
    action: `${BASE_URL}/upload/panos`,
    headers: {
      authorization: localcache.getCacha('token')
    },
    showUploadList: false,
    multiple: true
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

2.实现切图

2.1如何实现切图

后端实现切图我们通过krpanotools.exe可执行文件执行命令行来切图,在我们从官网下来的包里就包含了这个文件

image.png

cmd执行一下krpanotools命令,可以看到这个应用程序提供好几个功能:

  1. makepano:制作基于模版的全景或漫游
  2. maketiles:制作或组合切片图像。可用于转换或重置尺寸
  3. makepreview:制作平滑的预览图
  4. spheretocube:球形或圆柱形全景图像转换为立方体
  5. cubetosphere:立方体全景图像转换回球形全景图像
  6. protect:生成自定义保护设置的viewer文件
  7. encrypt:加密文件
  8. testserver:测试服务
  9. register:授权码注册

详细文档建议查看官方文档

image.png

我们主要通过makepano命令来切图,这是官方的示例命令krpanotools makepano [-config=###] [OPTIONS] inputfiles …

config参数是切图所依赖的配置文件,默认是当前路径下的templates/vtour-multires.config文件,OPTIONS参数用于设置或覆盖配置文件的设定,inputfiles参数是全景图片的路径,可以是一个或者多个图片

在cmd中执行这个命令切图

image.png

切图完成后会在图片所在的文件夹下生成一个vtour文件夹

image.png

然后点击测试服务,发现可以正常预览

image.png

2.2配置文件的修改

切图后生成的vtour文件夹里有很多东西我们都是不需要的,我们只需要保存着切好图的panos文件夹和tour.xml,所以要根据需求来修改配置文件,打开vtour-multires.config这个文件,将对应的配置设为false或者注释掉,具体的配置说明可以查看官方文档

image.png

修改完后再执行一次切图,不再生成vtour文件夹了而是生成了切好图的文件夹和xml文件

image.png

image.png

2.3服务端实现切图

知道如何使用krpanotools.exe切图后,我们将krpanotools.exe和对应的配置文件放入项目中

image.png

然后开始设计/upload/panos这个接口,nodejs构建的服务端中我们可以使用child_process模块中的exec方法来执行命令

先将图片下载到本地,然后通过exec执行方法执行切图命令,切图完后通过xml-js这个库拿到生成的xml文件中的分辨率参数multires,之后将切好图的文件夹上传到oss,上传成功之后往数据库添加一条记录,并将结果返回给客户端,最后将本地生成的图片,文件夹和xml文件等都删除掉

/**
* 批量上传
* @param {*} localFolderPath // 文件路径
* @param {*} ossFolderPath // oss路径
*/
async uploadFolder(localFolderPath, ossFolderPath) {
    const files = fs.readdirSync(localFolderPath)
    for (const file of files) {
        const filePath = path.posix.join(localFolderPath, file)
        const ossPath = path.posix.join(ossFolderPath, file)
        if (fs.statSync(filePath).isDirectory()) {
            // 如果是文件夹,递归上传
            await this.uploadFolder(filePath, ossPath)
        } else {
            // 如果是文件,上传到 OSS
            try {
                await this.client.put(ossPath, filePath)
            } catch (error) {
                console.error('Failed to upload file ' + ossPath + ':', error)
            }
        }
    }
}


/**
 * 切图并上传到阿里云oss
 * @param {*} ctx
 * @param {*} next
 */
uploadPano = async (ctx, next) => {
    const files = ctx.request.files
    const { id } = ctx.user
    if (!files.length) return ctx.app.emit('error', { code: 400, message: '文件上传错误' }, ctx)
    try {
        // krpanotools.exe切图
        const execPromise = new Promise((resolve, reject) => {
            exec(
                'krpanotools makepano [-config=templates/vtour-multires.config] ' + files[0].path,
                (error, stdout, stderr) => {
                    if (error) {
                        reject('执行命令时发生错误:' + error)
                    } else {
                        resolve()
                    }
                }
            )
        })
        await execPromise
        // 全景参数
        const view_uuid = files[0].filename.split('.')[0]
        const name = files[0].originalname.split('.')[0]
        const xml_path = files[0].path.split('.')[0] + '.xml'
        const xmlData = fs.readFileSync(xml_path, {
            encoding: 'utf-8',
        })
        const xmltree = JSON.parse(xmljs.xml2json(xmlData, { compact: true, spaces: 4 }))
        const multires = xmltree.krpano.scene.image.cube._attributes.multires
        // 切图上传到oss
        await this.uploadFolder('uploads/' + view_uuid, '/panos/' + id + '/' + view_uuid)
        // 预览和文件夹的路径
        const path = '/panos/' + id + '/' + view_uuid
        const thumbUrl = '/panos/' + id + '/' + view_uuid + '/thumb.jpg'
        const data = {
            scene_id: view_uuid,
            path,
            thumbUrl,
            name,
            multires,
            albumid: id,
        }

        await fileService.addPanoMaterials(data)

        ctx.body = {
            code: 200,
            message: '上传成功',
            data,
        }
        // 删除本地文件夹,图片和xml文件
        fs.rmSync('uploads/' + view_uuid, { recursive: true })
        fs.unlinkSync(files[0].path)
        fs.unlinkSync(xml_path)
    } catch (error) {
        console.log(error.message)
        const message = error.sqlMessage ? error.sqlMessage : error.message ? error.message : 'error'
        return ctx.app.emit('error', { code: 500, message }, ctx)
    }
}

  • 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

a.gif

结尾

以上就是我对服务端实现切图的实现,如果还有更好的方式也欢迎大家一起分享交流,学习学习

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/672950
推荐阅读
相关标签