294 lines
7.9 KiB
C++
294 lines
7.9 KiB
C++
/* -*-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_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);
|
|
}
|
|
|
|
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_NOTICE<<"open("<<filename<<")"<<std::endl;
|
|
|
|
std::string foundFile = osgDB::findDataFile(filename);
|
|
if (foundFile.empty())
|
|
{
|
|
OSG_NOTICE<<"could not find filename="<<filename<<std::endl;
|
|
return false;
|
|
}
|
|
|
|
OSG_NOTICE<<"foundFile = "<<foundFile<<std::endl;
|
|
foundFile = osgDB::getRealPath(foundFile);
|
|
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_NOTICE<<" could not open("<<filename<<"), uri="<<uri<<std::endl;
|
|
|
|
return false;
|
|
}
|
|
|
|
if (_doc)
|
|
{
|
|
g_object_unref(_doc);
|
|
}
|
|
|
|
_doc = doc;
|
|
_pageNum = 0;
|
|
|
|
setFileName(filename);
|
|
|
|
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 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)
|
|
|