Attached files purely add a mouse handler to the pdf plugin. This permits page changes using the mouse when keyboard input is inconvenient (based on scene graph usage context). Let me know if .tgz would be more convenient than individual files.
PdfReader
Description: Binary data
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1999-2008 Robert Osfield * * This software is open source and may be redistributed and/or modified under * the terms of the GNU General Public License (GPL) version 2.0. * The full license is in LICENSE.txt file included with this distribution,. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * include LICENSE.txt for more details. */
#include <osgDB/ReaderWriter>
#include <osgDB/FileNameUtils>
#include <osgDB/Registry>
#include <osgDB/FileUtils>
#include <osgWidget/PdfReader>
#include <osg/ImageUtils>
#include <cairo.h>
#include <poppler.h>
class CairoImage : public osg::Referenced
{
public:
CairoImage(osg::Image* image):
_image(image),
_surface(0),
_context(0) {}
void create(int width, int height)
{
if (_image->data() && width==_image->s() && height==_image->t())
{
return;
}
osg::notify(osg::NOTICE)<<"Create cario surface/context "<<width<<", "<<height<<std::endl;
// allocate the image data
_image->allocateImage(width, height, 1, GL_RGBA, GL_UNSIGNED_BYTE);
_image->setPixelFormat(GL_BGRA);
_image->setDataVariance(osg::Object::DYNAMIC);
_image->setOrigin(osg::Image::TOP_LEFT);
// create a cairo surface for this image data
_surface = cairo_image_surface_create_for_data(
_image->data(),
CAIRO_FORMAT_ARGB32,
width, height,
_image->getRowSizeInBytes());
// create a context for the surface
_context = cairo_create(_surface);
}
void destroy()
{
if (_surface) cairo_surface_destroy(_surface);
if (_context) cairo_destroy(_context);
}
int getWidth() { return _image->s(); }
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 ~CairoImage()
{
destroy();
}
osg::observer_ptr<osg::Image> _image;
cairo_surface_t* _surface;
cairo_t* _context;
};
class PopplerPdfImage : public osgWidget::PdfImage
{
public:
PopplerPdfImage():
_doc(0)
{
_cairoImage = new CairoImage(this);
}
virtual ~PopplerPdfImage()
{
_cairoImage = 0;
if (_doc)
{
g_object_unref(_doc);
}
}
PopplerDocument* _doc;
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;
}
#if defined(WIN32) && !defined(__CYGWIN__)
std::string uri = std::string("file:///") + foundFile;
#else
std::string uri = std::string("file:") + foundFile;
#endif
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 bool sendKeyEvent(int key, bool keyDown)
{
if (keyDown && key!=0)
{
if (key==_nextPageKeyEvent)
{
next();
return true;
}
else if (key==_previousPageKeyEvent)
{
previous();
return true;
}
}
return false;
}
virtual bool sendPointerEvent(int x, int y, int buttonMask)
{
if (!buttonMask || !_cairoImage || _previousButtonMask)
{
_previousButtonMask = buttonMask;
return false;
}
_previousButtonMask = buttonMask;
if (x > _cairoImage->getWidth() / 2)
{
osg::notify(osg::NOTICE)<<"PDF next"<<std::endl;
next();
} else
{
osg::notify(osg::NOTICE)<<"PDF prev"<<std::endl;
previous();
}
return true;
}
virtual 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);
_cairoImage->create((unsigned int)(w*2.0),(unsigned int)(h*2.0));
osg::clearImageToColor(this, _backgroundColor);
cairo_save(_cairoImage->getContext());
cairo_rectangle(_cairoImage->getContext(), 0.0, 0.0, double(s()), double(t()));
cairo_scale(_cairoImage->getContext(), double(s())/w, double(t())/h);
poppler_page_render(page, _cairoImage->getContext());
cairo_restore(_cairoImage->getContext());
dirty();
return true;
}
protected:
osg::ref_ptr<CairoImage> _cairoImage;
};
class ReaderWriterPDF : public osgDB::ReaderWriter
{
public:
ReaderWriterPDF()
{
supportsExtension("pdf","PDF plugin");
}
virtual const char* className() const { return "PDF plugin"; }
virtual osgDB::ReaderWriter::ReadResult readObject(const std::string& file, const osgDB::ReaderWriter::Options* options) const
{
return readImage(file,options);
}
virtual osgDB::ReaderWriter::ReadResult readImage(const std::string& fileName, const osgDB::ReaderWriter::Options* options) const
{
if (!osgDB::equalCaseInsensitive(osgDB::getFileExtension(fileName),"pdf"))
{
return osgDB::ReaderWriter::ReadResult::FILE_NOT_HANDLED;
}
std::string file = osgDB::findDataFile(fileName);
if (file.empty())
{
return osgDB::ReaderWriter::ReadResult::FILE_NOT_FOUND;
}
osg::ref_ptr<PopplerPdfImage> image = new PopplerPdfImage;
image->setDataVariance(osg::Object::DYNAMIC);
image->setOrigin(osg::Image::TOP_LEFT);
if (!image->open(file))
{
return "Could not open "+file;
}
return image.get();
}
virtual osgDB::ReaderWriter::ReadResult readNode(const std::string& fileName, const osgDB::ReaderWriter::Options* options) const
{
osgDB::ReaderWriter::ReadResult result = readImage(fileName, options);
if (!result.validImage()) return result;
osg::ref_ptr<osgWidget::PdfReader> pdfReader = new osgWidget::PdfReader();
if (pdfReader->assign(dynamic_cast<osgWidget::PdfImage*>(result.getImage())))
{
return pdfReader.release();
}
else
{
return osgDB::ReaderWriter::ReadResult::FILE_NOT_HANDLED;
}
}
};
// now register with Registry to instantiate the above
// reader/writer.
REGISTER_OSGPLUGIN(pdf, ReaderWriterPDF)
_______________________________________________ osg-submissions mailing list [email protected] http://lists.openscenegraph.org/listinfo.cgi/osg-submissions-openscenegraph.org
