基于java后端的 krpano 功能化
来源:互联网 发布:淘宝关键词可以改吗 编辑:程序博客网 时间:2024/06/03 17:24
最近领导要求全景图的展示效果跟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
会先后生成一个叫vtour的文件夹,为了区分,我重命名为vtuor和vtour2,然后再来看看生成的两个vtour文件夹
在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命名的,生成后的结构如下:
这些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 value updateElementValue(doc, title); // delete element deleteElement(doc); // add new element addElement(doc); updateAttributeColorValue(doc, "0x000000"); addMusicElement(doc,music); // write the updated document to // file or console doc.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 employee for (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 employee for (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 employee for (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 employee for (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 employee for (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 employee for (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 block e.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 block e.printStackTrace(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.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>
来看看震撼的效果:
注意事项
1.java执行批处理用的是Runtime.getRuntime().exec(); 这里面全用字符串,利用krpanotools32去执行命令,每个文件夹的关系是\,这和原来的博客区分,原来是:-config=templates,我改为:-config=\templates
2.如果频繁的报删除文件,文件找不到的错,仔细看看临时存放路径有没有错,全景图路径有没有错
3.如果是上传在显示,注意时间,生成文件io操作的速度比跳转页面的速度慢很多,可能会出现页面跳转了,报找不到tour.js(404)错误,只要让执行生成全景文件的线程在跳转线程完成前即可
4.动态化的界面背景音乐不能播放,这个我也没琢磨出来
一定要仔细看路径!!很容易晕,如果有什么问题不解的,欢迎加我qq,个人主页有,要源码的加原来博客博主的微信(文章最后有大牛的联系方式:http://blog.csdn.net/u012084981/article/details/76382991)
- 基于java后端的 krpano 功能化
- krpano 功能化 -- linux 部署
- krpano 功能化 -- linux 部署
- 基于Krpano 的全景漫游系统的实现
- Krpano功能介绍-所有标签
- 如何使用java代码自动生成对应的krpano全景
- java的后端技术
- 后端实现点赞功能(java web)
- Krpano插件的使用
- krpano的调试
- 基于Bmob后端云实现APP,登录功能--binbinyang
- krpano
- KRPano
- 基于java实现发短信的功能
- 基于NodeJS的前后端分离
- 基于NodeJS的前后端分离
- 基于Ajax的前后端分离
- 基于 SSM框架的前后端分离
- POJ 2239 Selecting Courses(二分图最大匹配)
- struts2.5动态方法调用不能使用问题
- hibernate.validator.constraints.NotEmpty鏍¢獙璇锋眰鍙傛暟鎶ラ敊java.lang.NoClassDefFoundError- javax-el-Propert
- 计数排序详解:O(n)
- ORACLE闪回机制分析与研究应用
- 基于java后端的 krpano 功能化
- Android学习-Serializable、Parcelable序列化
- 如何利用Node.js 构建分布式集群
- 基于Android的Word在线预览
- 支付宝小程序简易教程分享给你!
- Android使用Google的apv查看pdf文件之源码的下载与编译
- 一个标准的JAVA枚举类
- 神经网络_多层感知机MLP_以mnist为例(tensorflow和keras实现)
- Ubuntu安装SublimeText3及配置MarkDown环境