五一劳动节,首先祝所有的劳动者节日快乐,向奋战在劳动的抗疫战士致敬。本想出去走一走,无奈人太多,就不给景区增加负担。
之前有一些文章陆续进行了全景照片的处理说明。之前的文章链接,1、实战!使用pano2vr生成html5全景页面 2、基于Three.js的全景展示框架-TPano 3、全景自动切片技术-krpano初识。本次分享一个比较真实的全景处理案例,可以自动完成全景照片的切片及展示场景需求。
环境说明:
1、JDK8、MySQL5.7、SpringBoot、Hibernate、krpano-1.19-pr13、Thymeleaf、JQuery3.4.1、Bootstrap3.3.7
下面正式进入正题。
第一步、项目Pom.xml定义,如下代码所示:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.0.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>cn.com.scitc</groupId>
<artifactId>pano</artifactId>
<version>1</version>
<packaging>war</packaging>
<name>pano</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
第二步、安装krpano,具体步骤可参见krpano的官网或者网络教程。这里不进行赘述。在服务器上执行脚本命令行完成切片的功能。核心代码结构截图如下:
在controller中定义了所有的页面交互控制类。每个控制类根据命令已经大致可以猜到具体的用途。文中核心的转换逻辑写在PageController中,核心代码如下:
// 执行上传
@RequestMapping("/upload")
public String upload(@RequestParam("file") MultipartFile file, Model model) throws IOException {
//获取用户名
UserDetails userDetails = (UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
String name = userDetails.getUsername();
// 获取上传文件名
String filename = file.getOriginalFilename();
String fileName = filename.substring(0,filename.length() - 5);
// 定义上传文件保存路径
String path = filePath + "rotPhoto/" + name;
// 新建文件
File filepath = new File(path, filename);
// 判断路径是否存在,如果不存在就创建一个
if (!filepath.getParentFile().exists()) {
filepath.getParentFile().mkdirs();
}
try {
// 写入文件
file.transferTo(new File(path + File.separator + filename));
} catch (IOException e) {
e.printStackTrace();
}
// 将src路径发送至html页面
model.addAttribute("filename", "/images/rotPhoto/" + name + "\\" + filename);
String cmd;
String appction = "E:/krpano/krpano-1.19-pr13/krpanotools64.exe makepano -config=templates/vtour-normal.config D:/code/pano/src/main/resources/static/images/rotPhoto/";
cmd = appction + name + "/" + filename;
try {
Process process = Runtime.getRuntime().exec(cmd);
InputStream is = process.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String content = br.readLine();
while (content != null) {
System.out.println(content);
content = br.readLine();
}
} catch (IOException e) {
e.printStackTrace();
}
String[] wenname = new String[4];
String pathfile = "D:/code/pano/src/main/resources/static/images/rotPhoto/";
wenname[0] = pathfile + name + "/vtour/usergoods.html";
wenname[1] = pathfile + name + "/vtour/tour.swf";
wenname[2] = pathfile + name + "/vtour/tour_testingserver.exe";
wenname[3] = pathfile + name + "/vtour/tour_testingserver_macos";
for (int i = 0; i <wenname.length; i++){
File filethree = new File(wenname[i]);
filethree.delete();
}
// 删除生成的重复的文件包
String[] wennametwo = new String[2];
wennametwo[0] = pathfile + name + "/vtour/plugins";
wennametwo[1] = pathfile + name + "/vtour/skin";
for (int i = 0; i <wennametwo.length; i++){
File filefour = new File(wennametwo[i]);
DeleteFile deleteFile = new DeleteFile();
deleteFile.deleteFile(filefour);
}
try {
Pattern pattern = Pattern.compile("<include url=\"skin/vtourskin.xml\" />", Pattern.CASE_INSENSITIVE); // 要匹配的字段内容,正则表达式
Matcher matcher = pattern.matcher("");
List<String> lines = Files.readAllLines(Paths.get(pathfile + name + "/vtour/tour.xml")); // 读取文本文件
for (int i = 0; i < lines.size(); i++) {
matcher.reset(lines.get(i));
if (matcher.find()) { // 匹配正则表达式
lines.remove(i);
lines.add(i, "<include url=\"../../../../skin/vtourskin.xml\" />");
}
}
Files.write(Paths.get(pathfile + name + "/vtour/tour.xml"), lines);
} catch (IOException e) {
e.printStackTrace();
}
File oldFile = new File("D:/code/pano/src/main/resources/static/images/rotPhoto/" + name + "/vtour");
if(!oldFile.exists()){
oldFile.createNewFile();
}
String rootPath = oldFile.getParent();
File newFile = new File(rootPath + File.separator + fileName);
if (oldFile.renameTo(newFile)){
log.info("修改成功!");
}else{
log.info("修改失败");
}
return "upload";
}
后台接收前台上传的文件后,即开始进行全景切图。
第三步、全景图片展示核心代码如下:
@Controller
@RequestMapping("/")
public class HomeController {
private Log log = LogFactory.getLog(getClass());
@GetMapping("/include/navstyle")
public String navstyle(){
return "/include/navstyle";
}
@RequestMapping("/select")
private String select(Model model) {
UserDetails userDetails = (UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
String name = userDetails.getUsername();
File file = new File("D:/code/pano/src/main/resources/static/images/rotPhoto/" + name);
if (!file.exists()){
model.addAttribute("goods","/prompt");
}else {
model.addAttribute("goods","/goods");
}
if (!file.exists()){
model.addAttribute("works","/prompt");
}else {
model.addAttribute("works","/userwork");
}
return "select";
}
@RequestMapping("/include/nav")
private String nav() {
return "/include/nav";
}
@RequestMapping("/include/footer")
private String footer() {
return "/include/footer";
}
@RequestMapping("/prompt")
private String prompt() {
return "/prompt";
}
}
最后我们来看下展示的效果。
首页展示
万里长城展示
全景登录
全景处理
总结:本文介绍了一种基于krpano的全自动处理平台,可以自动发布全景实战案例。完整构建了完整的生命周期,从图片上传,到后台图片切片等,基本具备服务能力。但是本平台也存在一定的缺点,比如:页面UI不够美观、不兼容Linux平台、没有采用文件存储模式、图片处理没有异步化,系统容错性不好、krpano的工作路径是固定的,没有设置成动态路径,于此同时,还有一些bug需要调整。
不过总体来说,是一个很好的全景处理程序,提供了比较详细的处理逻辑。有兴趣的朋友可以在此基础之上进行二次开发和扩展,比如去弥补上述的一些缺陷也是未尝不可以的。最后分享开源地址:https://gitee.com/hszzz/pano.git,有需要的小伙伴可以自行下载。