1 /* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
2  *
3  * This library is open source and may be redistributed and/or modified under
4  * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
5  * (at your option) any later version.  The full license is in LICENSE file
6  * included with this distribution, and on the openscenegraph.org website.
7  *
8  * This library is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * OpenSceneGraph Public License for more details.
12 */
13 
14 #include "ExportHTML.h"
15 #include <osgDB/FileNameUtils>
16 #include <osgDB/WriteFile>
17 #include <sstream>
18 #include <iostream>
19 
20 template<typename A, typename B, typename C>
createString(const A & a,const B & b,const C & c)21 std::string createString(const A& a, const B& b, const C& c)
22 {
23     std::ostringstream hos;
24     hos << a << b << c;
25     return hos.str();
26 }
27 
28 template<typename A, typename B, typename C, typename D>
createString(const A & a,const B & b,const C & c,const D & d)29 std::string createString(const A& a, const B& b, const C& c, const D& d)
30 {
31     std::ostringstream hos;
32     hos << a << b << c << d;
33     return hos.str();
34 }
35 
36 class SnapImageDrawCallback : public osg::Camera::DrawCallback
37 {
38 public:
39 
SnapImageDrawCallback()40     SnapImageDrawCallback():
41         _snapImageOnNextFrame(false)
42     {
43     }
44 
setFileName(const std::string & filename)45     void setFileName(const std::string& filename) { _filename = filename; }
getFileName() const46     const std::string& getFileName() const { return _filename; }
47 
setSnapImageOnNextFrame(bool flag)48     void setSnapImageOnNextFrame(bool flag) { _snapImageOnNextFrame = flag; }
getSnapImageOnNextFrame() const49     bool getSnapImageOnNextFrame() const { return _snapImageOnNextFrame; }
50 
operator ()(const osg::Camera & camera) const51     virtual void operator () (const osg::Camera& camera) const
52     {
53         if (!_snapImageOnNextFrame) return;
54 
55         int x = static_cast<int>(camera.getViewport()->x());
56         int y = static_cast<int>(camera.getViewport()->y());
57         unsigned int width = static_cast<unsigned int>(camera.getViewport()->width());
58         unsigned int height = static_cast<unsigned int>(camera.getViewport()->height());
59 
60         osg::ref_ptr<osg::Image> image = new osg::Image;
61         image->readPixels(x,y,width,height,
62                           GL_RGB,GL_UNSIGNED_BYTE);
63 
64         if (osgDB::writeImageFile(*image,_filename))
65         {
66             osg::notify(osg::NOTICE) << "Saved screen image to `"<<_filename<<"`"<< std::endl;
67         }
68 
69         _snapImageOnNextFrame = false;
70     }
71 
72 protected:
73 
74     std::string _filename;
75     mutable bool _snapImageOnNextFrame;
76 
77 
78 };
79 
createFileName(const std::string & basename,unsigned int page,const std::string & ext)80 std::string ExportHTML::createFileName(const std::string& basename, unsigned int page, const std::string& ext)
81 {
82     if (page==0) return basename+ext;
83     else return createString(basename,'_', page, ext);
84 }
85 
write(osgPresentation::SlideEventHandler * seh,osgViewer::Viewer & viewer,const std::string & filename)86 bool ExportHTML::write(osgPresentation::SlideEventHandler* seh, osgViewer::Viewer& viewer, const std::string& filename)
87 {
88     std::string image_basename;
89     std::string image_ext;
90     std::string html_basename;
91     std::string html_ext;
92 
93     std::string ext = osgDB::getFileExtension(filename);
94     if (ext=="html" || ext=="htm")
95     {
96         image_basename = osgDB::getNameLessExtension(filename);
97         image_ext = ".jpg";
98         html_basename = osgDB::getNameLessExtension(filename);
99         html_ext = std::string(".")+ext;
100     }
101     else
102     {
103         image_basename = osgDB::getNameLessExtension(filename);
104         image_ext = ".jpg";
105     }
106 
107     std::cout<<"Writing slides to "<<image_basename<<"_[slidenumber]"<<image_ext<<std::endl;
108 
109     osg::ref_ptr<SnapImageDrawCallback> sidc = new SnapImageDrawCallback;
110 
111     osgViewer::Viewer::Cameras cameras;
112     viewer.getCameras(cameras);
113 
114     for(osgViewer::Viewer::Cameras::iterator itr = cameras.begin();
115         itr != cameras.end();
116         ++itr)
117     {
118         (*itr)->setPostDrawCallback(sidc.get());
119     }
120 
121     std::string home_file = createFileName(html_basename, 0, html_ext);
122 
123     unsigned int i;
124     for(i=0; i<seh->getNumSlides(); ++i)
125     {
126         std::ostringstream os;
127         os << image_basename <<"_"<<i<<image_ext;
128 
129         sidc->setFileName(os.str());
130         sidc->setSnapImageOnNextFrame(true);
131 
132         if (!html_basename.empty())
133         {
134             std::string htmlFileName = createFileName(html_basename, i, html_ext);
135 
136             std::ofstream fout(htmlFileName.c_str());
137             if (fout)
138             {
139                 std::string previous_file = i>0 ? createFileName(html_basename,i-1,html_ext) : "";
140                 std::string next_file = i<seh->getNumSlides()-1 ? createFileName(html_basename,i+1,html_ext) : "";
141 
142                 std::cout<<"Writing html slides "<<htmlFileName<<std::endl;
143 
144                 fout<<"<html>"<<std::endl;
145                 fout<<"<table width=\"100%\">"<<std::endl;
146                 fout<<"<tr>"<<std::endl;
147                 if (!previous_file.empty())
148                 {
149                     fout<<"<td align=\"left\" width=\"33%\"><a href=\""<<osgDB::getSimpleFileName(previous_file)<<"\"> Previous </a></td>"<<std::endl;
150                 }
151                 else
152                 {
153                     fout<<"<td align=\"left\" width=\"33%\"></td>"<<std::endl;
154                 }
155                 if (i != 0)
156                 {
157                     fout<<"<td align=\"center\" width=\"33%\"><a href=\""<<osgDB::getSimpleFileName(home_file)<<"\"> Home </a></td>"<<std::endl;
158                 }
159                 else
160                 {
161                     fout<<"<td align=\"center\" width=\"33%\"></td>"<<std::endl;
162                 }
163                 if (!next_file.empty())
164                 {
165                     fout<<"<td align=\"right\" width=\"33%\"><a href=\""<<osgDB::getSimpleFileName(next_file)<<"\"> Next </a></td>"<<std::endl;
166                 }
167                 else
168                 {
169                     fout<<"<td align=\"right\" width=\"33%\"></td>"<<std::endl;
170                 }
171                 fout<<"</tr>"<<std::endl;
172                 fout<<"</table>"<<std::endl;
173                 fout<<"<img src=\""<<osgDB::getSimpleFileName(os.str())<<"\">"<<std::endl;
174                 fout<<"</html>"<<std::endl;
175             }
176             else
177             {
178                 std::cout<<"Could not open '"<<filename<<"' for writing."<<std::endl;
179             }
180         }
181         // wait for all cull and draw threads to complete.
182 
183         seh->selectSlide(i, osgPresentation::SlideEventHandler::LAST_POSITION);
184 
185         // fire off the cull and draw traversals of the scene.
186         viewer.frame();
187     }
188     return true;
189 }
190