325 lines
8.5 KiB
C++
325 lines
8.5 KiB
C++
#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;
|
|
geode->addDrawable(pictureQuad);
|
|
|
|
return geode;
|
|
}
|
|
|
|
class PageHandler : public osgGA::GUIEventHandler
|
|
{
|
|
public:
|
|
|
|
PageHandler() {}
|
|
|
|
bool handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter& aa)
|
|
{
|
|
if (ea.getHandled()) return false;
|
|
|
|
switch(ea.getEventType())
|
|
{
|
|
case(osgGA::GUIEventAdapter::KEYDOWN):
|
|
{
|
|
if (ea.getKey()=='n')
|
|
{
|
|
osg::notify(osg::NOTICE)<<"Next page"<<std::endl;
|
|
return true;
|
|
}
|
|
else
|
|
if (ea.getKey()=='p')
|
|
{
|
|
osg::notify(osg::NOTICE)<<"Previous page"<<std::endl;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
default:
|
|
return false;
|
|
}
|
|
return false;
|
|
}
|
|
};
|
|
|
|
int main(int argc,char** argv)
|
|
{
|
|
|
|
osg::ArgumentParser arguments(&argc, argv);
|
|
osgViewer::Viewer viewer(arguments);
|
|
|
|
typedef std::list< osg::ref_ptr<osg::Image> > Images;
|
|
Images images;
|
|
|
|
for(int i=1; i<arguments.argc(); ++i)
|
|
{
|
|
if (!arguments.isOption(i))
|
|
{
|
|
osg::ref_ptr<PdfImage> pdfImage= new PdfImage;
|
|
if (pdfImage->open(arguments[i]))
|
|
{
|
|
images.push_back(pdfImage.get());
|
|
}
|
|
}
|
|
}
|
|
|
|
bool xyPlane = false;
|
|
|
|
osg::Group* group = new osg::Group;
|
|
|
|
osg::Vec3 origin = osg::Vec3(0.0f,0.0f,0.0f);
|
|
for(Images::iterator itr = images.begin();
|
|
itr != images.end();
|
|
++itr)
|
|
{
|
|
osg::Image* image = itr->get();
|
|
float width = 1.0;
|
|
float height = float(image->t())/float(image->s());
|
|
osg::Vec3 widthAxis = osg::Vec3(width,0.0f,0.0f);
|
|
osg::Vec3 heightAxis = xyPlane ? osg::Vec3(0.0f,height,0.0f) : osg::Vec3(0.0f,0.0f,height);
|
|
group->addChild(createInteractiveQuad(origin, widthAxis, heightAxis, image));
|
|
|
|
origin += widthAxis*1.1f;
|
|
}
|
|
|
|
viewer.setSceneData(group);
|
|
|
|
viewer.addEventHandler(new osgViewer::StatsHandler);
|
|
|
|
//viewer.addEventHandler(new PageHandler);
|
|
|
|
return viewer.run();
|
|
}
|
|
|