<commit_before>#include <osg/Image>
#include <osg/Geometry>
#include <osg/Texture2D>
#include <osg/io_utils>

#include <osgViewer/Viewer>
#include <osgViewer/ViewerEventHandlers>

#include <osgDB/ReadFile>

#include <cairo.h>
#include <poppler.h>

class CarioImage : public osg::Image
{
    public:
    
        CarioImage():
            _surface(0),
            _context(0) {}
            
        
        void create(unsigned int width, unsigned int height)
        {
            if (data() && width==s() && height==t()) return;

            osg::notify(osg::NOTICE)<<"Create cario surface/context "<<width<<", "<<height<<std::endl;

            // allocate the image data
            allocateImage(width, height, 1, GL_RGBA, GL_UNSIGNED_BYTE);
            setPixelFormat(GL_BGRA);
            setDataVariance(osg::Object::DYNAMIC);            
            setOrigin(osg::Image::TOP_LEFT);
            
            
            // create a cairo surface for this image data
            _surface = cairo_image_surface_create_for_data(
                    data(),
                    CAIRO_FORMAT_ARGB32, 
                    width, height, 
                    getRowSizeInBytes());
            
            // create a context for the surface
            _context = cairo_create(_surface);            
        }        
        
        void destroy()
        {
            if (_surface) cairo_surface_destroy(_surface);
	    if (_context) cairo_destroy(_context);
        }
        
        cairo_surface_t* getSurface() { return _surface; }
        const cairo_surface_t* getSurface() const { return _surface; }

        cairo_t* getContext() { return _context; }
        const cairo_t* getContext() const { return _context; }

    protected:
    
        virtual ~CarioImage()
        {
            destroy();
        }

        cairo_surface_t* _surface;
        cairo_t*         _context;
};

class PdfImage : public CarioImage
{
    public:
    
        PdfImage():
            _doc(0),
            _pageNum(0)
        {
        }
            
        virtual ~PdfImage()
        {
            if (_doc)
            {
        	g_object_unref(_doc);
            }
        }
    
        PopplerDocument* _doc;
        int _pageNum;
    
	int getNumOfPages() { return _doc ? poppler_document_get_n_pages(_doc) : 0; }

        bool open(const std::string& filename)
        {
            osg::notify(osg::NOTICE)<<"open("<<filename<<")"<<std::endl;

	    static bool gTypeInit = false;

	    if(!gTypeInit)
            {
		    g_type_init();

		    gTypeInit = true;
	    }

            PopplerDocument* doc = poppler_document_new_from_file(filename.c_str(), NULL, NULL);
            if (!doc) 
            {
                osg::notify(osg::NOTICE)<<" could not open("<<filename<<")"<<std::endl;

                return false;
            }
            
            if (_doc) 
            {
                g_object_unref(_doc);
            }
            
            _doc = doc;
            _pageNum = 0;
            
            setFileName(filename);

            osg::notify(osg::NOTICE)<<"getNumOfPages()=="<<getNumOfPages()<<std::endl;

            if (getNumOfPages()==0)
            {
                return false;
            }

            page(0);

            return true;
        }
        
        virtual void sendKeyEvent(int key, bool keyDown)
        {
            if (keyDown)
            {
                if (key=='n') next();
                else if (key=='p') previous();
            }
        }

 
        bool previous()
        {
            return page(_pageNum-1);
        }
        
        bool next()
        { 
             return page(_pageNum+1);
        }
        
        bool page(int pageNum)
        {
            if (!_doc) return false;
            
            if (pageNum<0 || pageNum>=getNumOfPages()) return false;

	    PopplerPage* page = poppler_document_get_page(_doc, pageNum);

	    if(!page) return false;
            
            _pageNum = pageNum;

            double w = 0.0f;
            double h = 0.0f;

            poppler_page_get_size(page, &w, &h);

            create((unsigned int)(w),(unsigned int)(h));

            double r = 1.0;
            double g = 1.0;
            double b = 1.0;
            double a = 1.0;
            
            cairo_save(_context);
            
                cairo_set_source_rgba(_context, r, g, b, a);
                cairo_rectangle(_context, 0.0, 0.0, w, h);
                cairo_fill(_context);

                poppler_page_render(page, getContext());
            
            cairo_restore(_context);

            dirty();

	}


};


osg::Node* createInteractiveQuad(const osg::Vec3& origin, osg::Vec3& widthAxis, osg::Vec3& heightAxis, 
                                 osg::Image* image)
{
    bool flip = image->getOrigin()==osg::Image::TOP_LEFT;

    osg::Geometry* pictureQuad = osg::createTexturedQuadGeometry(origin, widthAxis, heightAxis,
                                       0.0f, flip ? 1.0f : 0.0f , 1.0f, flip ? 0.0f : 1.0f);

    osg::Texture2D* texture = new osg::Texture2D(image);
    texture->setResizeNonPowerOfTwoHint(false);
    texture->setFilter(osg::Texture::MIN_FILTER,osg::Texture::LINEAR);
    texture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE);
    texture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE);
    
    pictureQuad->getOrCreateStateSet()->setTextureAttributeAndModes(0,
                texture,
                osg::StateAttribute::ON);
                
    pictureQuad->setEventCallback(new osgViewer::InteractiveImageHandler(image));

    osg::Geode* geode = new osg::Geode;<commit_msg>Improved filepath handling, and increased the image resolution for better rendering quality<commit_after>#include <osg/Image>
#include <osg/Geometry>
#include <osg/Texture2D>
#include <osg/io_utils>

#include <osgViewer/Viewer>
#include <osgViewer/ViewerEventHandlers>

#include <osgDB/FileUtils>
#include <osgDB/FileNameUtils>
#include <osgDB/ReadFile>

#include <cairo.h>
#include <poppler.h>

class CarioImage : public osg::Image
{
    public:
    
        CarioImage():
            _surface(0),
            _context(0) {}
            
        
        void create(unsigned int width, unsigned int height)
        {
            if (data() && width==s() && height==t()) return;

            osg::notify(osg::NOTICE)<<"Create cario surface/context "<<width<<", "<<height<<std::endl;

            // allocate the image data
            allocateImage(width, height, 1, GL_RGBA, GL_UNSIGNED_BYTE);
            setPixelFormat(GL_BGRA);
            setDataVariance(osg::Object::DYNAMIC);            
            setOrigin(osg::Image::TOP_LEFT);
            
            
            // create a cairo surface for this image data
            _surface = cairo_image_surface_create_for_data(
                    data(),
                    CAIRO_FORMAT_ARGB32, 
                    width, height, 
                    getRowSizeInBytes());
            
            // create a context for the surface
            _context = cairo_create(_surface);            
        }        
        
        void destroy()
        {
            if (_surface) cairo_surface_destroy(_surface);
	    if (_context) cairo_destroy(_context);
        }
        
        cairo_surface_t* getSurface() { return _surface; }
        const cairo_surface_t* getSurface() const { return _surface; }

        cairo_t* getContext() { return _context; }
        const cairo_t* getContext() const { return _context; }

    protected:
    
        virtual ~CarioImage()
        {
            destroy();
        }

        cairo_surface_t* _surface;
        cairo_t*         _context;
};

class PdfImage : public CarioImage
{
    public:
    
        PdfImage():
            _doc(0),
            _pageNum(0)
        {
        }
            
        virtual ~PdfImage()
        {
            if (_doc)
            {
        	g_object_unref(_doc);
            }
        }
    
        PopplerDocument* _doc;
        int _pageNum;
    
	int getNumOfPages() { return _doc ? poppler_document_get_n_pages(_doc) : 0; }

        bool open(const std::string& filename)
        {
            osg::notify(osg::NOTICE)<<"open("<<filename<<")"<<std::endl;
            
            std::string foundFile = osgDB::findDataFile(filename);
            if (foundFile.empty())
            {
                osg::notify(osg::NOTICE)<<"could not find filename="<<filename<<std::endl;
                return false;
            }
            
            osg::notify(osg::NOTICE)<<"foundFile = "<<foundFile<<std::endl;
            foundFile = osgDB::getRealPath(foundFile);
            osg::notify(osg::NOTICE)<<"foundFile = "<<foundFile<<std::endl;

	    static bool gTypeInit = false;

	    if(!gTypeInit)
            {
		g_type_init();

		gTypeInit = true;
	    }
            
            std::string uri = std::string("file:") + foundFile;

            PopplerDocument* doc = poppler_document_new_from_file(uri.c_str(), NULL, NULL);
            if (!doc) 
            {
                osg::notify(osg::NOTICE)<<" could not open("<<filename<<"), uri="<<uri<<std::endl;

                return false;
            }
            
            if (_doc) 
            {
                g_object_unref(_doc);
            }
            
            _doc = doc;
            _pageNum = 0;
            
            setFileName(filename);

            osg::notify(osg::NOTICE)<<"getNumOfPages()=="<<getNumOfPages()<<std::endl;

            if (getNumOfPages()==0)
            {
                return false;
            }

            page(0);

            return true;
        }
        
        virtual void sendKeyEvent(int key, bool keyDown)
        {
            if (keyDown)
            {
                if (key=='n') next();
                else if (key=='p') previous();
            }
        }

 
        bool previous()
        {
            return page(_pageNum-1);
        }
        
        bool next()
        { 
             return page(_pageNum+1);
        }
        
        bool page(int pageNum)
        {
            if (!_doc) return false;
            
            if (pageNum<0 || pageNum>=getNumOfPages()) return false;

	    PopplerPage* page = poppler_document_get_page(_doc, pageNum);

	    if(!page) return false;
            
            _pageNum = pageNum;

            double w = 0.0f;
            double h = 0.0f;

            poppler_page_get_size(page, &w, &h);

            create((unsigned int)(w*2.0),(unsigned int)(h*2.0));

            double r = 1.0;
            double g = 1.0;
            double b = 1.0;
            double a = 1.0;
            
            cairo_save(_context);
            
                cairo_set_source_rgba(_context, r, g, b, a);
                cairo_rectangle(_context, 0.0, 0.0, double(s()), double(t()));
                cairo_fill(_context);

                cairo_scale(_context, double(s())/w, double(t())/h);

                poppler_page_render(page, getContext());
            

            cairo_restore(_context);

            dirty();

	}


};


osg::Node* createInteractiveQuad(const osg::Vec3& origin, osg::Vec3& widthAxis, osg::Vec3& heightAxis, 
                                 osg::Image* image)
{
    bool flip = image->getOrigin()==osg::Image::TOP_LEFT;

    osg::Geometry* pictureQuad = osg::createTexturedQuadGeometry(origin, widthAxis, heightAxis,
                                       0.0f, flip ? 1.0f : 0.0f , 1.0f, flip ? 0.0f : 1.0f);

    osg::Texture2D* texture = new osg::Texture2D(image);
    texture->setResizeNonPowerOfTwoHint(false);
    texture->setFilter(osg::Texture::MIN_FILTER,osg::Texture::LINEAR);
    texture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE);
    texture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE);
    
    pictureQuad->getOrCreateStateSet()->setTextureAttributeAndModes(0,
                texture,
                osg::StateAttribute::ON);
                
    pictureQuad->setEventCallback(new osgViewer::InteractiveImageHandler(image));

    osg::Geode* geode = new osg::Geode;
{'fraction_non_alphanumeric': 0.11913000494315373, 'fraction_numerical': 0.008403361344537815, 'mean_word_length': 1.5954671798161215, 'pattern_counts': {'":': 0, '<': 109, '<?xml version=': 0, '>': 41, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4980342', 'n_tokens_mistral': 3766, 'n_tokens_neox': 3589, 'n_words': 655}