基于java后端的 krpano 功能化


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

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


基于java后端的 krpano 功能化_第1张图片


**于是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文件夹


基于java后端的 krpano 功能化_第2张图片


![这里写图片描述](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下,发布即可访问,


基于java后端的 krpano 功能化_第3张图片




当然这是静态的,我们是要做成动态的网页。通过这两个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 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 map = new HashMap();
				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+"/";
%>




	${title }
	
	
	
	
	
	



来看看震撼的效果:


![这里写图片描述](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)

你可能感兴趣的:(krpano)