root/OpenSceneGraph/trunk/examples/osgpdf/osgpdf.cpp @ 9158

Revision 9158, 8.5 kB (checked in by robert, 6 years ago)

Improved filepath handling, and increased the image resolution for better rendering quality

Line 
1#include <osg/Image>
2#include <osg/Geometry>
3#include <osg/Texture2D>
4#include <osg/io_utils>
5
6#include <osgViewer/Viewer>
7#include <osgViewer/ViewerEventHandlers>
8
9#include <osgDB/FileUtils>
10#include <osgDB/FileNameUtils>
11#include <osgDB/ReadFile>
12
13#include <cairo.h>
14#include <poppler.h>
15
16class CarioImage : public osg::Image
17{
18    public:
19   
20        CarioImage():
21            _surface(0),
22            _context(0) {}
23           
24       
25        void create(unsigned int width, unsigned int height)
26        {
27            if (data() && width==s() && height==t()) return;
28
29            osg::notify(osg::NOTICE)<<"Create cario surface/context "<<width<<", "<<height<<std::endl;
30
31            // allocate the image data
32            allocateImage(width, height, 1, GL_RGBA, GL_UNSIGNED_BYTE);
33            setPixelFormat(GL_BGRA);
34            setDataVariance(osg::Object::DYNAMIC);           
35            setOrigin(osg::Image::TOP_LEFT);
36           
37           
38            // create a cairo surface for this image data
39            _surface = cairo_image_surface_create_for_data(
40                    data(),
41                    CAIRO_FORMAT_ARGB32,
42                    width, height,
43                    getRowSizeInBytes());
44           
45            // create a context for the surface
46            _context = cairo_create(_surface);           
47        }       
48       
49        void destroy()
50        {
51            if (_surface) cairo_surface_destroy(_surface);
52            if (_context) cairo_destroy(_context);
53        }
54       
55        cairo_surface_t* getSurface() { return _surface; }
56        const cairo_surface_t* getSurface() const { return _surface; }
57
58        cairo_t* getContext() { return _context; }
59        const cairo_t* getContext() const { return _context; }
60
61    protected:
62   
63        virtual ~CarioImage()
64        {
65            destroy();
66        }
67
68        cairo_surface_t* _surface;
69        cairo_t*         _context;
70};
71
72class PdfImage : public CarioImage
73{
74    public:
75   
76        PdfImage():
77            _doc(0),
78            _pageNum(0)
79        {
80        }
81           
82        virtual ~PdfImage()
83        {
84            if (_doc)
85            {
86                g_object_unref(_doc);
87            }
88        }
89   
90        PopplerDocument* _doc;
91        int _pageNum;
92   
93        int getNumOfPages() { return _doc ? poppler_document_get_n_pages(_doc) : 0; }
94
95        bool open(const std::string& filename)
96        {
97            osg::notify(osg::NOTICE)<<"open("<<filename<<")"<<std::endl;
98           
99            std::string foundFile = osgDB::findDataFile(filename);
100            if (foundFile.empty())
101            {
102                osg::notify(osg::NOTICE)<<"could not find filename="<<filename<<std::endl;
103                return false;
104            }
105           
106            osg::notify(osg::NOTICE)<<"foundFile = "<<foundFile<<std::endl;
107            foundFile = osgDB::getRealPath(foundFile);
108            osg::notify(osg::NOTICE)<<"foundFile = "<<foundFile<<std::endl;
109
110            static bool gTypeInit = false;
111
112            if(!gTypeInit)
113            {
114                g_type_init();
115
116                gTypeInit = true;
117            }
118           
119            std::string uri = std::string("file:") + foundFile;
120
121            PopplerDocument* doc = poppler_document_new_from_file(uri.c_str(), NULL, NULL);
122            if (!doc)
123            {
124                osg::notify(osg::NOTICE)<<" could not open("<<filename<<"), uri="<<uri<<std::endl;
125
126                return false;
127            }
128           
129            if (_doc)
130            {
131                g_object_unref(_doc);
132            }
133           
134            _doc = doc;
135            _pageNum = 0;
136           
137            setFileName(filename);
138
139            osg::notify(osg::NOTICE)<<"getNumOfPages()=="<<getNumOfPages()<<std::endl;
140
141            if (getNumOfPages()==0)
142            {
143                return false;
144            }
145
146            page(0);
147
148            return true;
149        }
150       
151        virtual void sendKeyEvent(int key, bool keyDown)
152        {
153            if (keyDown)
154            {
155                if (key=='n') next();
156                else if (key=='p') previous();
157            }
158        }
159
160 
161        bool previous()
162        {
163            return page(_pageNum-1);
164        }
165       
166        bool next()
167        {
168             return page(_pageNum+1);
169        }
170       
171        bool page(int pageNum)
172        {
173            if (!_doc) return false;
174           
175            if (pageNum<0 || pageNum>=getNumOfPages()) return false;
176
177            PopplerPage* page = poppler_document_get_page(_doc, pageNum);
178
179            if(!page) return false;
180           
181            _pageNum = pageNum;
182
183            double w = 0.0f;
184            double h = 0.0f;
185
186            poppler_page_get_size(page, &w, &h);
187
188            create((unsigned int)(w*2.0),(unsigned int)(h*2.0));
189
190            double r = 1.0;
191            double g = 1.0;
192            double b = 1.0;
193            double a = 1.0;
194           
195            cairo_save(_context);
196           
197                cairo_set_source_rgba(_context, r, g, b, a);
198                cairo_rectangle(_context, 0.0, 0.0, double(s()), double(t()));
199                cairo_fill(_context);
200
201                cairo_scale(_context, double(s())/w, double(t())/h);
202
203                poppler_page_render(page, getContext());
204           
205
206            cairo_restore(_context);
207
208            dirty();
209
210        }
211
212
213};
214
215
216osg::Node* createInteractiveQuad(const osg::Vec3& origin, osg::Vec3& widthAxis, osg::Vec3& heightAxis,
217                                 osg::Image* image)
218{
219    bool flip = image->getOrigin()==osg::Image::TOP_LEFT;
220
221    osg::Geometry* pictureQuad = osg::createTexturedQuadGeometry(origin, widthAxis, heightAxis,
222                                       0.0f, flip ? 1.0f : 0.0f , 1.0f, flip ? 0.0f : 1.0f);
223
224    osg::Texture2D* texture = new osg::Texture2D(image);
225    texture->setResizeNonPowerOfTwoHint(false);
226    texture->setFilter(osg::Texture::MIN_FILTER,osg::Texture::LINEAR);
227    texture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE);
228    texture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE);
229   
230    pictureQuad->getOrCreateStateSet()->setTextureAttributeAndModes(0,
231                texture,
232                osg::StateAttribute::ON);
233               
234    pictureQuad->setEventCallback(new osgViewer::InteractiveImageHandler(image));
235
236    osg::Geode* geode = new osg::Geode;
237    geode->addDrawable(pictureQuad);
238   
239    return geode;
240}
241
242class PageHandler : public osgGA::GUIEventHandler
243{
244    public:
245   
246        PageHandler() {}
247
248        bool handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter& aa)
249        {
250            if (ea.getHandled()) return false;
251
252            switch(ea.getEventType())
253            {
254                case(osgGA::GUIEventAdapter::KEYDOWN):
255                {
256                    if (ea.getKey()=='n')
257                    {
258                        osg::notify(osg::NOTICE)<<"Next page"<<std::endl;
259                        return true;
260                    }
261                    else
262                    if (ea.getKey()=='p')
263                    {
264                        osg::notify(osg::NOTICE)<<"Previous page"<<std::endl;
265                        return true;
266                    }
267                }
268
269                default:
270                    return false;
271            }
272            return false;
273        }
274};
275
276int main(int argc,char** argv)
277{
278
279    osg::ArgumentParser arguments(&argc, argv);
280    osgViewer::Viewer viewer(arguments);
281   
282    typedef std::list< osg::ref_ptr<osg::Image> > Images;
283    Images images;
284
285    for(int i=1; i<arguments.argc(); ++i)
286    {
287        if (!arguments.isOption(i))
288        {
289            osg::ref_ptr<PdfImage> pdfImage= new PdfImage;
290            if (pdfImage->open(arguments[i]))
291            {           
292                images.push_back(pdfImage.get());
293            }
294        }
295    }
296
297    bool xyPlane = false;
298
299    osg::Group* group = new osg::Group;
300
301    osg::Vec3 origin = osg::Vec3(0.0f,0.0f,0.0f);
302    for(Images::iterator itr = images.begin();
303        itr != images.end();
304        ++itr)
305    {
306        osg::Image* image = itr->get();
307        float width = 1.0;
308        float height = float(image->t())/float(image->s());
309        osg::Vec3 widthAxis = osg::Vec3(width,0.0f,0.0f);
310        osg::Vec3 heightAxis = xyPlane ? osg::Vec3(0.0f,height,0.0f) : osg::Vec3(0.0f,0.0f,height);
311        group->addChild(createInteractiveQuad(origin, widthAxis, heightAxis, image));
312       
313        origin += widthAxis*1.1f;
314    }
315   
316    viewer.setSceneData(group);
317
318    viewer.addEventHandler(new osgViewer::StatsHandler);
319   
320    //viewer.addEventHandler(new PageHandler);
321
322    return viewer.run();
323}
Note: See TracBrowser for help on using the browser.