From 0683c1b5a8a7b3f91cfc87df95995e1910d6e075 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Tue, 23 Dec 2003 23:55:06 +0000 Subject: [PATCH] Added support for a photo archive. --- examples/osgphotoalbum/ImageReaderWriter.cpp | 16 +- examples/osgphotoalbum/ImageReaderWriter.h | 10 +- examples/osgphotoalbum/PhotoArchive.cpp | 329 +++++++++++++++++++ examples/osgphotoalbum/PhotoArchive.h | 96 ++++++ examples/osgphotoalbum/osgphotoalbum.cpp | 39 ++- 5 files changed, 479 insertions(+), 11 deletions(-) diff --git a/examples/osgphotoalbum/ImageReaderWriter.cpp b/examples/osgphotoalbum/ImageReaderWriter.cpp index 94699a51c..4cad18b83 100644 --- a/examples/osgphotoalbum/ImageReaderWriter.cpp +++ b/examples/osgphotoalbum/ImageReaderWriter.cpp @@ -70,6 +70,13 @@ std::string ImageReaderWriter::insertReference(const std::string& fileName, unsi osg::Image* ImageReaderWriter::readImage_Archive(DataReference& dr, float& s,float& t) { + for(PhotoArchiveList::iterator itr=_photoArchiveList.begin(); + itr!=_photoArchiveList.end(); + ++itr) + { + osg::Image* image = (*itr)->readImage(dr._fileName,dr._resolutionX,dr._resolutionY,s,t); + if (image) return image; + } return 0; } @@ -100,8 +107,6 @@ osg::Image* ImageReaderWriter::readImage_DynamicSampling(DataReference& dr, floa osgDB::ReaderWriter::ReadResult ImageReaderWriter::readNode(const std::string& fileName, const Options*) { - std::cout<<"Request to read paged image "< DataReferenceMap; + typedef std::map< std::string,DataReference > DataReferenceMap; + typedef std::vector< osg::ref_ptr > PhotoArchiveList; DataReferenceMap _dataReferences; - osg::ref_ptr _photoArchive; + PhotoArchiveList _photoArchiveList; }; diff --git a/examples/osgphotoalbum/PhotoArchive.cpp b/examples/osgphotoalbum/PhotoArchive.cpp index b7aac2ae6..b0c8da80c 100644 --- a/examples/osgphotoalbum/PhotoArchive.cpp +++ b/examples/osgphotoalbum/PhotoArchive.cpp @@ -12,3 +12,332 @@ #include "PhotoArchive.h" +#include +#include +#include +#include + +#include + + + +const std::string FILE_IDENTIFER("osgphotoalbum photo archive"); + +class GraphicsContext { + public: + GraphicsContext() + { + rs = new Producer::RenderSurface; + rs->setWindowRectangle(0,0,1,1); + rs->useBorder(false); + rs->useConfigEventThread(false); + rs->realize(); + std::cout<<"Realized window"< rs; +}; + +PhotoArchive::PhotoArchive(const std::string& filename) +{ + readPhotoIndex(filename); +} + +bool PhotoArchive::readPhotoIndex(const std::string& filename) +{ + std::ifstream in(filename.c_str()); + + char* fileIndentifier = new char [FILE_IDENTIFER.size()]; + in.read(fileIndentifier,FILE_IDENTIFER.size()); + if (FILE_IDENTIFER!=fileIndentifier) return false; + + unsigned int numPhotos; + in.read((char*)&numPhotos,sizeof(numPhotos)); + + _photoIndex.resize(numPhotos); + + in.read((char*)&_photoIndex.front(),sizeof(PhotoHeader)*numPhotos); + + // success record filename. + _archiveFileName = filename; + + return true; +} + +void PhotoArchive::getImageFileNameList(FileNameList& filenameList) +{ + for(PhotoIndexList::const_iterator itr=_photoIndex.begin(); + itr!=_photoIndex.end(); + ++itr) + { + filenameList.push_back(std::string(itr->filename)); + } + +} + +osg::Image* PhotoArchive::readImage(const std::string& filename, + unsigned int target_s, unsigned target_t, + float& original_s, float& original_t) +{ + for(PhotoIndexList::const_iterator itr=_photoIndex.begin(); + itr!=_photoIndex.end(); + ++itr) + { + if (filename==itr->filename) + { + const PhotoHeader& photoHeader = *itr; + + if (target_s <= photoHeader.thumbnail_s && + target_t <= photoHeader.thumbnail_t && + photoHeader.thumbnail_position != 0) + { + std::ifstream in(_archiveFileName.c_str(),std::ios::in | std::ios::binary); + + // find image + in.seekg(photoHeader.thumbnail_position); + + // read image header + ImageHeader imageHeader; + in.read((char*)&imageHeader,sizeof(ImageHeader)); + unsigned char* data = new unsigned char[imageHeader.size]; + in.read((char*)data,imageHeader.size); + + osg::Image* image = new osg::Image; + image->setImage(photoHeader.thumbnail_s,photoHeader.thumbnail_t,1, + imageHeader.pixelFormat,imageHeader.pixelFormat,imageHeader.type, + data,osg::Image::USE_NEW_DELETE); + + original_s = photoHeader.original_s; + original_t = photoHeader.original_t; + + return image; + } + + if (photoHeader.fullsize_s && + photoHeader.fullsize_t && + photoHeader.fullsize_position != 0) + { + std::ifstream in(_archiveFileName.c_str(),std::ios::in | std::ios::binary); + + // find image + in.seekg(photoHeader.fullsize_position); + + // read image header + ImageHeader imageHeader; + in.read((char*)&imageHeader,sizeof(ImageHeader)); + unsigned char* data = new unsigned char[imageHeader.size]; + in.read((char*)data,imageHeader.size); + + osg::Image* image = new osg::Image; + image->setImage(photoHeader.fullsize_s,photoHeader.fullsize_t,1, + imageHeader.pixelFormat,imageHeader.pixelFormat,imageHeader.type, + data,osg::Image::USE_NEW_DELETE); + + original_s = photoHeader.original_s; + original_t = photoHeader.original_t; + + return image; + } + + } + + } + return NULL; +} + +void PhotoArchive::buildArchive(const std::string& filename, const FileNameList& imageList, unsigned int thumbnailSize, unsigned int maximumSize, bool compressed) +{ + + PhotoIndexList photoIndex; + photoIndex.reserve(imageList.size()); + for(FileNameList::const_iterator fitr=imageList.begin(); + fitr!=imageList.end(); + ++fitr) + { + PhotoHeader header; + + // set name + strncpy(header.filename,fitr->c_str(),255); + header.filename[255]=0; + + header.thumbnail_s = thumbnailSize; + header.thumbnail_t = thumbnailSize; + header.thumbnail_position = 0; + + header.fullsize_s = thumbnailSize; + header.fullsize_t = thumbnailSize; + header.fullsize_position = 0; + + photoIndex.push_back(header); + + } + + std::cout<<"Building photo archive containing "< image = osgDB::readImageFile(photoHeader.filename); + + std::cout<<"done."<< std::endl; + + photoHeader.original_s = image->s(); + photoHeader.original_t = image->t(); + + { + + std::cout<<" creating thumbnail image..."; + // first need to rescale image to the require thumbnail size + unsigned int newTotalSize = + image->computeRowWidthInBytes(thumbnailSize,image->getPixelFormat(),image->getDataType(),image->getPacking())* + thumbnailSize; + + // need to sort out what size to really use... + unsigned char* newData = new unsigned char [newTotalSize]; + if (!newData) + { + // should we throw an exception??? Just return for time being. + osg::notify(osg::FATAL) << "Error scaleImage() did not succeed : out of memory."<getPacking()); + glPixelStorei(GL_UNPACK_ALIGNMENT,image->getPacking()); + + GLint status = gluScaleImage(image->getPixelFormat(), + image->s(), + image->t(), + image->getDataType(), + image->data(), + thumbnailSize, + thumbnailSize, + image->getDataType(), + newData); + + if (status!=0) + { + delete [] newData; + + osg::notify(osg::WARN) << "Error scaleImage() did not succeed : errorString = "<getInternalTextureFormat(); + imageHeader.pixelFormat = image->getPixelFormat(); + imageHeader.type = image->getDataType(); + imageHeader.size = newTotalSize; + + // write out image header and image data. + out.write((char*)&imageHeader,sizeof(ImageHeader)); + out.write((char*)newData,imageHeader.size); + + delete [] newData; + + std::cout<<"done."<< std::endl; + + } + + { + std::cout<<" creating fullsize image...";std::cout.flush(); + + + photoHeader.fullsize_s = osg::minimum((unsigned int)image->s(),maximumSize); + photoHeader.fullsize_t = osg::minimum((unsigned int)image->t(),maximumSize); + photoHeader.fullsize_position = (unsigned int)out.tellp(); + + // first need to rescale image to the require thumbnail size + unsigned int newTotalSize = + image->computeRowWidthInBytes(photoHeader.fullsize_s,image->getPixelFormat(),image->getDataType(),image->getPacking())* + photoHeader.fullsize_t; + + // need to sort out what size to really use... + unsigned char* newData = new unsigned char [newTotalSize]; + if (!newData) + { + // should we throw an exception??? Just return for time being. + osg::notify(osg::FATAL) << "Error scaleImage() did not succeed : out of memory."<getPacking()); + glPixelStorei(GL_UNPACK_ALIGNMENT,image->getPacking()); + + GLint status = gluScaleImage(image->getPixelFormat(), + image->s(), + image->t(), + image->getDataType(), + image->data(), + photoHeader.fullsize_s, + photoHeader.fullsize_t, + image->getDataType(), + newData); + + if (status!=0) + { + delete [] newData; + + osg::notify(osg::WARN) << "Error scaleImage() did not succeed : errorString = "<getInternalTextureFormat(); + imageHeader.pixelFormat = image->getPixelFormat(); + imageHeader.type = image->getDataType(); + imageHeader.size = newTotalSize; + + out.write((char*)&imageHeader,sizeof(ImageHeader)); + out.write((char*)newData,imageHeader.size); + //out.write((char*)image->data(),imageHeader.size); + + delete [] newData; + + std::cout<<"done."<< std::endl; + } + + } + + // rewrite photo index now it has the correct sizes set + out.seekp(startOfPhotoIndex); + out.write((char*)&photoIndex.front(),sizeof(PhotoHeader)*photoIndex.size()); + +} diff --git a/examples/osgphotoalbum/PhotoArchive.h b/examples/osgphotoalbum/PhotoArchive.h index 015e3b75c..8ad713d8a 100644 --- a/examples/osgphotoalbum/PhotoArchive.h +++ b/examples/osgphotoalbum/PhotoArchive.h @@ -1,3 +1,15 @@ +/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2003 Robert Osfield + * + * This application is open source and may be redistributed and/or modified under + * the terms of the GNU Public License (GPL) version 1.0 or + * (at your option) any later version. + * + * This library 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 + * OpenSceneGraph Public License for more details. +*/ + #ifndef PHOTOARCHIVE_H #define PHOTOARCHIVE_H @@ -5,6 +17,90 @@ class PhotoArchive : public osg::Referenced { +public: + + static PhotoArchive* open(const std::string& filename) + { + osg::ref_ptr archive = new PhotoArchive(filename); + if (!archive->empty()) return archive.release(); + else return 0; + } + + typedef std::vector FileNameList; + + bool empty() { return _photoIndex.empty(); } + + void getImageFileNameList(FileNameList& filenameList); + + static void buildArchive(const std::string& filename, const FileNameList& imageList, unsigned int thumbnailSize=256, unsigned int maximumSize=1024, bool compressed=true); + + osg::Image* readImage(const std::string& filename, + unsigned int target_s, unsigned target_t, + float& original_s, float& original_t); + + + +protected: + + PhotoArchive(const std::string& filename); + + virtual ~PhotoArchive() {} + + bool readPhotoIndex(const std::string& filename); + + struct PhotoHeader + { + PhotoHeader(): + original_s(0), + original_t(0), + thumbnail_s(0), + thumbnail_t(0), + thumbnail_position(0), + fullsize_s(0), + fullsize_t(0), + fullsize_position(0) + { + filename[0]='\0'; + } + + char filename[256]; + unsigned int original_s; + unsigned int original_t; + + unsigned int thumbnail_s; + unsigned int thumbnail_t; + unsigned int thumbnail_position; + + unsigned int fullsize_s; + unsigned int fullsize_t; + unsigned int fullsize_position; + }; + + + struct ImageHeader + { + ImageHeader(): + s(0), + t(0), + internalTextureformat(0), + pixelFormat(0), + type(0), + size(0) {} + + unsigned int s; + unsigned int t; + GLint internalTextureformat; + GLenum pixelFormat; + GLenum type; + unsigned int size; + }; + + + typedef std::vector PhotoIndexList; + + std::string _archiveFileName; + PhotoIndexList _photoIndex; + }; #endif diff --git a/examples/osgphotoalbum/osgphotoalbum.cpp b/examples/osgphotoalbum/osgphotoalbum.cpp index 58fc7427b..234d78264 100644 --- a/examples/osgphotoalbum/osgphotoalbum.cpp +++ b/examples/osgphotoalbum/osgphotoalbum.cpp @@ -18,6 +18,8 @@ #include +#include + #include #include @@ -447,7 +449,24 @@ Album::Album(osg::ArgumentParser& arguments, float width, float height) for(int pos=1;posaddPhotoArchive(photoArchive); + photoArchive->getImageFileNameList(fileList); + } + + } + else + { + fileList.push_back(arguments[pos]); + } + } } _radiusOfRings = 0.02; @@ -652,6 +671,7 @@ int main( int argc, char **argv ) arguments.getApplicationUsage()->addCommandLineOption("-d ","Time delay in sceonds between the display of successive image pairs when in auto advance mode."); arguments.getApplicationUsage()->addCommandLineOption("-a","Enter auto advance of image pairs on start up."); arguments.getApplicationUsage()->addCommandLineOption("-h or --help","Display this information"); + arguments.getApplicationUsage()->addCommandLineOption("--create ","Create an photo archive of specified files"); // construct the viewer. @@ -683,6 +703,9 @@ int main( int argc, char **argv ) return 1; } + std::string archiveName; + while (arguments.read("--create",archiveName)) {} + // any option left unread are converted into errors to write out later. arguments.reportRemainingOptionsAsUnrecognized(); @@ -700,6 +723,20 @@ int main( int argc, char **argv ) } + if (!archiveName.empty()) + { + // archive name set to create + PhotoArchive::FileNameList fileNameList; + for(int i=1;i