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

Revision 9156, 7.8 kB (checked in by robert, 6 years ago)

Introduced new osgpdf example that use Cario + Poppler libraries to provide a means of rendering a pdf document to an osg::Image.

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