本文仅供技术交流。
在前面的文章中:基于java后端的 krpano 功能化 已经实现在win平台将krpano功能化,这次我将krpano迁移至服务器:ubuntu 16.04 server。
以win的经验为基础,这里只需解决2个问题:
linux上krpano的安装与注册
在linux上,用java执行krpano命令
(1)linux上krpano的安装与注册
我以krpano-1.19-pr10为例,不必无官网下载,在这里下: http://pan.baidu.com/s/1bppkEbd 上传到服务器解压就可以了(里面有注册码)。可是,在生成全景图时,会有水印,怎么解决呢?在解压的文件夹里,有个叫Serial.txt文件,是一个注册码。只需要在服务器注册这个注册码就行了,每个用户都注册一遍。
我先把krpano-1.19-pr10上传到/opt目录下,unrar 解压,然后执行krpanotools register命令注册机器:
root@S189919:/opt/krpano-1.19-pr10Code registered.root@S189919:/opt/krpano-1.19-pr10exitwen@S189919:~$ cd /opt/krpano-1.19-pr10/wen@S189919:/opt/krpano-1.19-pr10$ /opt/krpano-1.19-pr10/krpanotools register FXsqTqaGNSZER5dSETEm+VzQEh9sWSa5DZMFsSmMxYV9GcXs8W3R8A/mWXrGNUceXvrihmh28hfRF1ivrW0HMzEychPvNiD8B/4/ZzDaUE9Rh6Ig22aKJGDbja1/kYIqmc/VKfItRE2RTSOIbIroxOtsz626NIpxWksAAifwhpNwuPXqDQpz2sRUMBzoPqZktpkItoSenN2mKd8Klfx7pOuB6CIK3e1CDXgyndqOt2mWybLZcU/wfJVAecfxk15ghiqrzaDsbqrdABDowg==Code registered.
这样,就会在用户的~/下生成一个.krpanolicense文件
有了krpanolicense,就不用担心会有水印和版权信息了。
(2)在linux上,用java执行krpano命令
因为java本身是跨平台的第一语言,所以选择java,就等于成功了一半。但在linux上,用java的runtime.exec与在win上的调用命令不同,文件路径也不同,这是最需要注意的!
以/opt/test/test.jpg的图片为例
krpano在linux执行的命令是:
/opt/krpano-1.19-pr10/krpanotools makepano -config=templates/vtour-normal.config /opt/test/test.jpg
而win是:
cmd /c start f:\\krpano\\krpano-1.19-pr10-postable\\krpanotools32.exe makepano -config=\\templates\\vtour-normal.config f:\\test\\test.jpg
linux的文件目录是”/ “,win是”\\”。
这是完整的krpano工具类:CmdBat
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 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 = "/opt/krpano-1.19-pr10/krpanotools makepano -config=templates/vtour-normal.config " + path + "/*.jpg"; Runtime runtime = Runtime.getRuntime(); String[] cmd = new String[]{"/bin/sh","-c", ex }; boolean b = true; Process p = null; try { p = runtime.exec(cmd); } 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); 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]); } updateElementValue(doc, title); deleteElement(doc); addElement(doc); updateAttributeColorValue(doc, "0x000000"); addMusicElement(doc,music); 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); } 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; fs.write(buffer, 0, byteread); } inStream.close(); } } catch (Exception e) { 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) { 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; 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; 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; 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; 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; 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; for (int i = 0; i < employees.getLength(); i++) { emp = (Element) employees.item(i); emp.setAttribute("design_bgcolor", newname); emp.setAttribute("design_bgalpha", "0.8"); } }}
- 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
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
- 199
- 200
- 201
- 202
- 203
- 204
- 205
- 206
- 207
- 208
- 209
- 210
- 211
- 212
- 213
- 214
- 215
- 216
- 217
- 218
- 219
- 220
- 221
- 222
- 223
- 224
- 225
- 226
- 227
- 228
- 229
- 230
- 231
- 232
- 233
- 234
- 235
- 236
- 237
- 238
- 239
- 240
- 241
- 242
- 243
- 244
- 245
- 246
- 247
- 248
- 249
- 250
- 251
- 252
- 253
- 254
- 255
- 256
- 257
- 258
- 259
- 260
- 261
- 262
- 263
- 264
- 265
- 266
- 267
- 268
- 269
- 270
- 271
- 272
- 273
- 274
- 275
- 276
- 277
- 278
- 279
- 280
- 281
- 282
- 283
- 284
- 285
- 286
- 287
- 288
- 289
- 290
- 291
- 292
- 293
- 294
- 295
- 296
- 297
- 298
- 299
- 300
- 301
- 302
- 303
- 304
- 305
- 306
- 307
- 308
- 309
- 310
- 311
- 312
- 313
- 314
- 315
- 316
- 317
- 318
- 319
- 320
- 321
- 322
- 323
- 324
- 325
- 326
- 327
- 328
- 329
- 330
- 331
- 332
- 333
- 334
- 335
- 336
- 337
- 338
- 339
- 340
- 341
- 342
- 343
- 344
- 345
- 346
- 347
- 348
- 349
- 350
- 351
- 352
- 353
- 354
- 355
- 356
- 357
- 358
- 359
- 360
- 361
- 362
- 363
- 364
- 365
- 366
- 367
- 368
- 369
- 370
- 371
- 372
- 373
- 374
- 375
- 376
- 377
- 378
- 379
- 380
- 381
- 382
- 383
- 384
- 385
- 386
- 387
- 388
- 389
- 390
- 391
- 392
- 393
- 394
- 395
- 396
- 397
- 398
- 399
- 400
- 401
- 402
- 403
- 404
- 405
至于如何调用CmdBat类,看具体的业务需求,我是先把全景图从前台传输到后台,存在uploadtemp目录中,再调用krpano处理全景图,在uploadtemp目录中生成一个图片id的文件夹,里面放vtour,然后把vtour里面的panos、tour.js、tour.xml、tour.swf 复制到tomcat统一存放全景目录vshow中,最后再把uploadtemp删除,页面只需要去vshow中根据图片id就可以访问到每个全景文件。跟在win上的一模一样。仔细研究CmdBat类,看懂了基本就可以用了,调用时很容易的。如果对java的io不太熟悉,看的吃力,多补补基础。
vshow:
图片id文件夹内部:
jsp页面,把title、图片id(uploadId )从后台传过来即可:
<%@ 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://serverIp:8080/K/vshow/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://serverIp:8080/K/vshow/tour.swf", xml:"http://serverIp:8080/K/vshow/${uploadId }/tour.xml", target:"pano", html5:"prefer", mobilescale:1.0, passQueryParameters:true}); </script></div></body></html>
- 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
看看最终自豪的效果:
后记:用服务器处理全景图是不现实的,只能做做开发,测试用,因为当并发量达到上k时,服务器必定hold不住,最理想的方法是让客户端(安卓、Ios)去切割全景图,把panos文件夹统一上传到第三方存储器或者业务服务器,业务服务器的功能应该是利用krpano去展示效果而已,而且krpano的版权,切割全景图也就没用了。现在切割符合krpano展示的全景图算法还在研究中,不久便可以投入使用!
转转自 http://blog.csdn.net/change_on/article/details/77879243