###**最近领导要求全景图的展示效果跟XX公司做的一样,仔细研究了一下XX公司的效果,发现用的是krpano,了解了krpano后,就要将krpano功能化,做成一个功能。很多全景公司采用krpano做,只要集成了一个krpano,效果也可以做的跟他们一样。难点是,krpano每生成处理一张全景图,都会生成很多个文件夹,怎么将它功能化?**

第一件想到的当然是百度!可是没找到有价值的情报。

**于是google,找到了一篇写的很好很好,但是在百度搜索搜不到的博客:http://blog.csdn.net/u012084981/article/details/76382991,博主也是一个很好的人,我向他要了源代码,自己研究,然后根据自己的见解写了这篇博客。**

先仔细观察krpano,可以发现,krpano生成的文件夹有一些是可以复用的,看下图,用鼠标将两张图tset.jpg和test2.jpg拖拽进krpano的MAKE VTOUR (NORMAL)droplet.bat

![这里写图片描述](https://img-blog.csdn.net/20170818164409858?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY2hhbmdlX29u/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)

会先后生成一个叫vtour的文件夹,为了区分,我重命名为vtuor和vtour2,然后再来看看生成的两个vtour文件夹

![这里写图片描述](https://img-blog.csdn.net/20170818164721434?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY2hhbmdlX29u/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)

在java web开发环境中,我们新建一个web project,将vtour文件夹拷贝到web root下,发布即可访问,

当然这是静态的,我们是要做成动态的网页。通过这两个vtour文件夹的对比(用Beyond Compare 4 软件对比),可以发现:

  • panos文件夹保存的是每张全景图生成的小图片,是动态变化的

  • plugins是各种效果的插件文件夹,是公有的

  • skin也是公有的

  • tour.html是一样的,是访问入口,也是公有的

  • tour.js是不一样的

  • tour.swf是不一样的

  • tour.xml是不一样的

    后面的tour_editor.html、tour_testingserver.exe、tour_testingserver_macos这几个是修改全景图的,显示时不会用到的,删掉了。

所以,只要保证tour.html能动态的读取到panos、tour.js、tour.swf、tour.xml就行了,用最笨的方法,在web root新建一个文件夹,专门处理krpano,就是vshow,将静态的文件夹拷进去,当用户每上传一张全景图时,先在临时文件夹为他生成全部文件,然后再将几个不一致的文件整合进一个文件夹,将该文件夹放在vshow里面,这个文件夹是动态的,每个用户都不一样,因此,我是用图片id命名的,生成后的结构如下:

![这里写图片描述](https://img-blog.csdn.net/20170818164906321?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY2hhbmdlX29u/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)

这些418、419、420…是动态的,每次访问不同的图片时,前台传给后台图片id即可,至于访问入口,可以把tour.html的内容拷进一个通用的jsp,只要在里面访问不同图片id的不同panos、tour.js、tour.swf、tour.xml就行。

下面的代码除了展示全景效果图外,还有背景音乐!给出核心代码:

CmdBat.java

package com.xforce.krpano.util;import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;public class CmdBat {/*public static void main(String[] args) {String dpath = "D:\\apache-tomcat-8.0.33\\webapps\\krpano\\vshow";String file = "353";String[] fn1 = {};String[] fn2 = {};String title = "yyyyyyyy";String temppath = "f:\\temp-room\\";String music = "vshow/backgroundmusic/default.mp3";try {setKrpano(dpath, file,temppath, fn1, fn2, title,music);} catch (InterruptedException e) {e.printStackTrace();System.out.println("上传失败");}}*/public static void setKrpano(final String dpath, final String file,final String temppath, final String[] fn1, final String[] fn2, final String title,final String music)throws InterruptedException {String path = temppath + file;File targetFile = new File(path);  if(!targetFile.exists()){  targetFile.mkdirs();  }  String ex = "krpanotools32.exe makepano -config=\\templates\\vtour-normal.config "+ path + "\\*.jpg";Runtime runtime = Runtime.getRuntime();boolean b = true;Process p = null;try {p = runtime.exec("cmd /c start f:\\krpano\\krpano-1.19-pr10-postable\\" + ex);} catch (Exception e) {b = false;}if (b) {final InputStream is1 = p.getInputStream();final InputStream is2 = p.getErrorStream();new Thread() {public void run() {BufferedReader br1 = new BufferedReader(new InputStreamReader(is1));try {String line1 = null;while ((line1 = br1.readLine()) != null) {if (line1 != null) {System.out.println("=AA==========line1======"+ line1);}}} catch (IOException e) {e.printStackTrace();} finally {try {is1.close();// 执行文件复制File f = new File(dpath + "\\" + file);f.mkdirs();// 创建目录// 复制文件boolean b1 = copyFile(temppath + file+ "\\vtour\\tour.js", dpath + "\\" + file+ "\\tour.js");if (b1) {boolean b2 = copyFile(temppath + file+ "\\vtour\\tour.swf", dpath + "\\"+ file + "\\tour.swf");if (b2) {boolean b3 = copyFile(temppath+ file + "\\vtour\\tour.xml", dpath+ "\\" + file + "\\tour.xml");if (b3) {// 复制文件夹boolean b4 = copyFolder(temppath + file+ "\\vtour\\panos",dpath + "\\" + file + "\\panos");if (b4) {// 删除临时生成文件delFolder(temppath + file);// 修改krpano文件内容String xmlPath = dpath + "\\"+ file + "\\tour.xml";File xmlFile = new File(xmlPath);DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();DocumentBuilder dBuilder;try {dBuilder = dbFactory.newDocumentBuilder();Document doc = dBuilder.parse(xmlFile);doc.getDocumentElement().normalize();for (int i = 0; i < fn1.length; i++) {updateAttributeValue(doc,fn1[i], fn2[i]);}// update Element valueupdateElementValue(doc, title);// delete elementdeleteElement(doc);// add new elementaddElement(doc);updateAttributeColorValue(doc,"0x000000");addMusicElement(doc,music);// write the updated document to// file or consoledoc.getDocumentElement().normalize();TransformerFactory transformerFactory = TransformerFactory.newInstance();Transformer transformer = transformerFactory.newTransformer();DOMSource source = new DOMSource(doc);StreamResult result = new StreamResult(new File(xmlPath));transformer.setOutputProperty(OutputKeys.INDENT,"yes");transformer.transform(source,result);//生成成功/*System.out.println("XML file updated successfully");*/} catch (Exception e1) {e1.printStackTrace();//生成失败}}}}}} catch (IOException e) {e.printStackTrace();}}}}.start();new Thread() {public void run() {BufferedReader br2 = new BufferedReader(new InputStreamReader(is2));try {String line2 = null;while ((line2 = br2.readLine()) != null) {if (line2 != null) {System.out.println("=AA==========line2======"+ line2);}}} catch (IOException e) {e.printStackTrace();} finally {try {is2.close();} catch (IOException e) {e.printStackTrace();}}}}.start();p.waitFor();p.destroy();} else {System.out.println("上传失败");}}/*** 复制单个文件* * @param oldPath*            String 原文件路径 如:c:/fqf.txt* @param newPath*            String 复制后路径 如:f:/fqf.txt* @return boolean*/public static boolean copyFile(String oldPath, String newPath) {try {int bytesum = 0;int byteread = 0;File oldfile = new File(oldPath);if (oldfile.exists()) { // 文件存在时InputStream inStream = new FileInputStream(oldPath); // 读入原文件FileOutputStream fs = new FileOutputStream(newPath);byte[] buffer = new byte[1444];int length;while ((byteread = inStream.read(buffer)) != -1) {bytesum += byteread; // 字节数 文件大小// System.out.println(bytesum);fs.write(buffer, 0, byteread);}inStream.close();}} catch (Exception e) {// System.out.println("复制单个文件操作出错");e.printStackTrace();return false;}return true;}/*** 复制整个文件夹内容* * @param oldPath*            String 原文件路径 如:c:/fqf* @param newPath*            String 复制后路径 如:f:/fqf/ff* @return boolean*/public static boolean copyFolder(String oldPath, String newPath) {try {(new File(newPath)).mkdirs(); // 如果文件夹不存在 则建立新文件夹File a = new File(oldPath);String[] file = a.list();File temp = null;for (int i = 0; i < file.length; i++) {if (oldPath.endsWith(File.separator)) {temp = new File(oldPath + file[i]);} else {temp = new File(oldPath + File.separator + file[i]);}if (temp.isFile()) {FileInputStream input = new FileInputStream(temp);FileOutputStream output = new FileOutputStream(newPath+ "/" + (temp.getName()).toString());byte[] b = new byte[1024 * 5];int len;while ((len = input.read(b)) != -1) {output.write(b, 0, len);}output.flush();output.close();input.close();}if (temp.isDirectory()) {// 如果是子文件夹copyFolder(oldPath + "/" + file[i], newPath + "/" + file[i]);}}} catch (Exception e) {// System.out.println("复制整个文件夹内容操作出错");e.printStackTrace();return false;}return true;}// 删除文件夹public static void delFolder(String folderPath) {try {delAllFile(folderPath); // 删除完里面所有内容String filePath = folderPath;filePath = filePath.toString();java.io.File myFilePath = new java.io.File(filePath);myFilePath.delete(); // 删除空文件夹} catch (Exception e) {e.printStackTrace();}}public static boolean delAllFile(String path) {boolean flag = false;File file = new File(path);if (!file.exists()) {return flag;}if (!file.isDirectory()) {return flag;}String[] tempList = file.list();File temp = null;for (int i = 0; i < tempList.length; i++) {if (path.endsWith(File.separator)) {temp = new File(path + tempList[i]);} else {temp = new File(path + File.separator + tempList[i]);}if (temp.isFile()) {temp.delete();}if (temp.isDirectory()) {delAllFile(path + "/" + tempList[i]);// 先删除文件夹里面的文件delFolder(path + "/" + tempList[i]);// 再删除空文件夹flag = true;}}return flag;}private static void addElement(Document doc) {NodeList employees = doc.getElementsByTagName("krpano");Element emp = null;// loop for each employeefor (int i = 0; i < employees.getLength(); i++) {emp = (Element) employees.item(i);Element vtourskin = doc.createElement("include");vtourskin.setAttribute("url", "../skin/vtourskin.xml");emp.appendChild(vtourskin);Element skinselect = doc.createElement("include");skinselect.setAttribute("url", "../skinselect.xml");emp.appendChild(skinselect);}}private static void addMusicElement(Document doc,String music) {NodeList employees = doc.getElementsByTagName("krpano");Element emp = null;// loop for each employeefor (int i = 0; i < employees.getLength(); i++) {emp = (Element) employees.item(i);Element musicEl = doc.createElement("action");musicEl.setAttribute("name", "bgsnd_action");musicEl.setAttribute("autorun", "onstart");musicEl.appendChild(doc.createTextNode("playsound(bgsnd, '"+music+"', 0);"));emp.appendChild(musicEl);}}private static void deleteElement(Document doc) {NodeList employees = doc.getElementsByTagName("krpano");Element emp = null;// loop for each employeefor (int i = 0; i < employees.getLength(); i++) {emp = (Element) employees.item(i);Node genderNode = emp.getElementsByTagName("include").item(0);emp.removeChild(genderNode);}}private static void updateElementValue(Document doc, String title) {NodeList employees = doc.getElementsByTagName("krpano");Element emp = null;// loop for each employeefor (int i = 0; i < employees.getLength(); i++) {emp = (Element) employees.item(i);emp.setAttribute("title", title);}}private static void updateAttributeValue(Document doc, String oldname,String newname) {NodeList employees = doc.getElementsByTagName("scene");Element emp = null;// loop for each employeefor (int i = 0; i < employees.getLength(); i++) {emp = (Element) employees.item(i);if (emp.getAttribute("title").equals(oldname)) {emp.setAttribute("title", newname);break;}}}private static void updateAttributeColorValue(Document doc, String newname) {NodeList employees = doc.getElementsByTagName("skin_settings");Element emp = null;// loop for each employeefor (int i = 0; i < employees.getLength(); i++) {emp = (Element) employees.item(i);emp.setAttribute("design_bgcolor", newname);emp.setAttribute("design_bgalpha", "0.8");}}
}

在控制层使用:ShareController.java

package com.xforce.krpano.controller;import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;import javax.servlet.http.HttpServletRequest;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;import com.xforce.krpano.model.Upload;
import com.xforce.krpano.service.ShareService;
import com.xforce.krpano.util.CmdBat;
import com.xforce.krpano.util.FileUpload;
import com.xforce.krpano.util.FileUtil;
import com.xforce.krpano.util.GreaterQiniuUtil;
import com.xforce.krpano.util.QiniuUtil;@Controller
@Scope("prototype")
public class ShareController {...//分享@RequestMapping("share")public ModelAndView share(Model model, HttpServletRequest request, @RequestParam(value = "file") MultipartFile file) {...//做处理String newGilePath = path + "\\"+ upload.getId() + "\\";FileUtil.moveFile(filePath, newGilePath);String dpath = request.getSession().getServletContext().getRealPath("vshow");String[] fn1 = {};String[] fn2 = {};String title = "xxxxx";String music = "vshow\\backgroundmusic\\default.mp3";String uploadId = upload.getId()+"";try {CmdBat.setKrpano(dpath, uploadId , path + "/", fn1, fn2, title,music);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}   try {Thread.sleep(4000);mv = new ModelAndView();Map<String, Object> map = new HashMap<String, Object>();map.put("uploadId", Integer.parseInt(uploadId));map.put("title",title);mv.addAllObjects(map);mv.setViewName("share");} catch (NumberFormatException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}return mv;}}

通用jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8" isELIgnored="false"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE html>
<html>
<head>
<base href="<%=basePath%>"><title>${title }</title><meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0" /><meta name="apple-mobile-web-app-capable" content="yes" /><meta name="apple-mobile-web-app-status-bar-style" content="black" /><meta http-equiv="Content-Type" content="text/html;charset=utf-8" /><meta http-equiv="x-ua-compatible" content="IE=edge" /><style>@-ms-viewport { width:device-width; }@media only screen and (min-device-width:800px) { html { overflow:hidden; } }html { height:100%; }body { height:100%; overflow:hidden; margin:0; padding:0; font-family:Arial, Helvetica, sans-serif; font-size:16px; color:#FFFFFF; background-color:#000000; }</style>
</head>
<body>
<div style="position: absolute;z-index: 1;margin-top: 10px;margin-left: 10px">
</div>
<script src="http://10.10.3.56:8080/K/vshow/${uploadId }/tour.js"></script>
<div id="pano" style="width:100%;height:100%;"><noscript><table style="width:100%;height:100%;"><tr style="vertical-align:middle;"><td><div style="text-align:center;">ERROR:<br/><br/>Javascript not activated<br/><br/></div></td></tr></table></noscript><script>var uploadId = "${uploadId}";embedpano({swf:"http://10.10.3.56:8080/K/vshow/${uploadId }/tour.swf", xml:"http://10.10.3.56:8080/K/vshow/${uploadId }/tour.xml", target:"pano", html5:"prefer", mobilescale:1.0, passQueryParameters:true});</script>
</div></body>
</html>

来看看震撼的效果:

![这里写图片描述](https://img-blog.csdn.net/20170818171712263?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY2hhbmdlX29u/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)

注意事项

  • 1.java执行批处理用的是Runtime.getRuntime().exec(); 这里面全用字符串,利用krpanotools32去执行命令,每个文件夹的关系是\,这和原来的博客区分,原来是:-config=templates,我改为:-config=\templates

  • 2.如果频繁的报删除文件,文件找不到的错,仔细看看临时存放路径有没有错,全景图路径有没有错

  • 3.如果是上传在显示,注意时间,生成文件io操作的速度比跳转页面的速度慢很多,可能会出现页面跳转了,报找不到tour.js(404)错误,只要让执行生成全景文件的线程在跳转线程完成前即可

  • 4.动态化的界面背景音乐不能播放,这个我也没琢磨出来

##一定要仔细看路径!!很容易晕,原来博客博主的文章:http://blog.csdn.net/u012084981/article/details/76382991)

基于java后端的 krpano 功能化相关推荐

  1. krpano功能化实现

    本人因为公司需求,需要做个VR全景功能,所以研究VR功能.在网上查询了一些资料以后发现krpano软件可以满足这个需求,果断学习之,如果大家有兴趣的话可以看下这些内容: krpano360,http: ...

  2. 【 malcolmcrum】基于Java后端与Typescript前端的代码自动生成

    Java 后端和 Typescript 前端虽然都是类型语言,但传统上这两个域上的类型之间存在脱节.本文推荐的这个工具让我们在一个地方修改一个方法或类,并立即在其他地方直接使用它,或者在我们误用它时在 ...

  3. java全自动生成krpano全景漫游

    之前有需求想把krpano功能化,让后台全自动生成,但是在网上并没有看到相关的帖子,于是我就对krpano研究了一天,总算给实现了,随着VR的发展,这项技术肯定会有更多的人学习,我就把我研究出来的解决 ...

  4. 功能化超小纳米Fe3O4/负载的超小四氧化三铁纳米金花

    核磁共振成像(MRI)技术中造影剂起到至关重要的作用.磁性纳米材料不仅具备良好的MR成像性能,而且更加安全稳定,已成为生物医学领域的研究重点.四氧化三铁(Fe3O4)纳米颗粒具有非常好的生物相容性和磁 ...

  5. java后端项目怎么实现图片预览_项目经验不重样!3个基于 SpringBoot 的图片识别处理系统送给你!...

    最近看了太多读者小伙伴的简历,发现各种商城/秒杀系统/在线教育系统真的是挺多的.推荐一下昨晚找的几个还不错的基于 Java 的图片识别处理系统. 中药图片拍照识别系统 项目地址:https://git ...

  6. 基于Java的Minecraft游戏后端自定义插件 的Java实践项目整理

    Minecraft_Plugin 1.项目概述 2.系统设计 3.功能模块成果展示 4.个人总结 1.项目概述 1.1 项目简介 小组准备编写一个具有武器战斗,道具收集.互动社交和任务悬赏四大系统的聚 ...

  7. 【JAVA程序设计】基于JAVA/SpringBoot技术的中小型企业采购招标系统(采购员功能、企业投标功能、专家评标功能),完善的招投标流程系统

    基于JAVA的中小型企业采购招标系统的设计与实现 项目获取 项目简介 开发环境 项目技术 项目功能 项目演示 项目获取 获取方式(点击下载):是云猿实战 项目经过多人测试运行,可以确保100%成功运行 ...

  8. Java后端实现人脸识别(基于虹软ArcSoft)

    问题引入 博主最近想实现一下基于Web应用的人脸识别登录功能,在网上查找了相关的博客示例之后并没有找到一篇能够彻底解决我问题的.通过自己阅读虹软(ArcSoft)的开放文档,以及示例代码,博主实现了简 ...

  9. java酒店的点评功能实现,基于JAVA的酒店管理系统

    <基于JAVA的酒店管理系统>由会员分享,可在线阅读,更多相关<基于JAVA的酒店管理系统(33页珍藏版)>请在人人文库网上搜索. 1.酒店管理系统主讲人:开发背景酒店业是一个 ...

最新文章

  1. centOS下调整swap
  2. Redis 性能问题分析
  3. 渗透知识-HTML基础
  4. c++re什么意思_玩转英语词汇--词汇积累策略之前缀re
  5. element 修改分页样式_如何给wordpress网站的文章列表,添加分页效果?可以通过2种方式...
  6. linux搜索文件内容含有星号,文本内容查找grep、文件查找find、正则匹配
  7. go将服务器图片响应给客户端,Go中来自客户端和服务器的RPC
  8. c++如何防止一个类被其他类继承?
  9. ssh 免密登录并用脚本群起服务
  10. VB讲课笔记09:过程
  11. 【重磅】世界首例无创脑机接口,无大脑电极植入操控机器臂与飞行器
  12. c语言 字符串不足用零代替,关于c语言的知识点不足的地方
  13. 动态网站Web开发用什么语言好?PHP、ASP还是ASP.NET
  14. 20200927:Java和Cpp中栈与队列的区别
  15. iMazing的付费功能与免费功能对比
  16. c#简易学生信息管理系统
  17. linux定时器无法重启pm2,在linux下开机启动pm2 不成功
  18. 《Unix网络编程》环境搭建
  19. 手机Linux安装rtl8187L,fedora 19编译安装rtl8187l驱动问题
  20. 2370. 最长理想子序列(每日一难phase2--day6)

热门文章

  1. 地图数据可视化库folium
  2. 7-41 哥尼斯堡的“七桥问题” (25 分)
  3. 服务器上的文件都变成只读了,[求助]Excel 文档都变成只读了,请问怎么恢复?/excle变成只读文件怎么办...
  4. 编写lisp程序解一元二次方程_vb解一元二次方程代码
  5. 华为荣耀手表GS3 评测怎么样
  6. 转专业计算机类面试自我介绍,转专业面试自我介绍
  7. [ linux ] vim 编辑器的三种模式介绍
  8. 数据安全建设中合规管理措施
  9. 企业微信自动添加手机好友工具
  10. 网易互娱2017实习生招聘游戏研发工程师在线笔试第二场(图像处理)