root/OpenSceneGraph/trunk/examples/osgphotoalbum/PhotoArchive.cpp @ 6941

Revision 6941, 13.1 kB (checked in by robert, 7 years ago)

From Martin Lavery and Robert Osfield, Updated examples to use a variation of the MIT License

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/* OpenSceneGraph example, osgphotoalbum.
2*
3*  Permission is hereby granted, free of charge, to any person obtaining a copy
4*  of this software and associated documentation files (the "Software"), to deal
5*  in the Software without restriction, including without limitation the rights
6*  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7*  copies of the Software, and to permit persons to whom the Software is
8*  furnished to do so, subject to the following conditions:
9*
10*  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
11*  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
12*  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
13*  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
14*  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
15*  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
16*  THE SOFTWARE.
17*/
18
19#include "PhotoArchive.h"
20
21#include <osg/GLU>
22#include <osg/Notify>
23#include <osgDB/ReadFile>
24
25#include <osg/GraphicsContext>
26
27#include <fstream>
28#include <iostream>
29
30
31
32const std::string FILE_IDENTIFER("osgphotoalbum photo archive");
33
34class MyGraphicsContext {
35    public:
36        MyGraphicsContext()
37        {
38            osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits;
39            traits->x = 0;
40            traits->y = 0;
41            traits->width = 1;
42            traits->height = 1;
43            traits->windowDecoration = false;
44            traits->doubleBuffer = false;
45            traits->sharedContext = 0;
46            traits->pbuffer = true;
47
48            _gc = osg::GraphicsContext::createGraphicsContext(traits.get());
49
50            if (!_gc)
51            {
52                osg::notify(osg::NOTICE)<<"Failed to create pbuffer, failing back to normal graphics window."<<std::endl;
53               
54                traits->pbuffer = false;
55                _gc = osg::GraphicsContext::createGraphicsContext(traits.get());
56            }
57
58            if (_gc.valid())
59           
60           
61            {
62                _gc->realize();
63                _gc->makeCurrent();
64                std::cout<<"Realized window"<<std::endl;
65            }
66        }
67       
68        bool valid() const { return _gc.valid() && _gc->isRealized(); }
69       
70    private:
71        osg::ref_ptr<osg::GraphicsContext> _gc;
72};
73
74PhotoArchive::PhotoArchive(const std::string& filename)
75{
76    readPhotoIndex(filename);
77}
78
79bool PhotoArchive::readPhotoIndex(const std::string& filename)
80{
81    std::ifstream in(filename.c_str());
82   
83    char* fileIndentifier = new char [FILE_IDENTIFER.size()];
84    in.read(fileIndentifier,FILE_IDENTIFER.size());
85    if (FILE_IDENTIFER!=fileIndentifier) return false;
86   
87    unsigned int numPhotos;
88    in.read((char*)&numPhotos,sizeof(numPhotos));
89
90    _photoIndex.resize(numPhotos);
91
92    in.read((char*)&_photoIndex.front(),sizeof(PhotoHeader)*numPhotos);
93   
94    // success record filename.
95    _archiveFileName = filename;
96   
97    return true;
98}
99
100void PhotoArchive::getImageFileNameList(FileNameList& filenameList)
101{
102    for(PhotoIndexList::const_iterator itr=_photoIndex.begin();
103        itr!=_photoIndex.end();
104        ++itr)
105    {
106        filenameList.push_back(std::string(itr->filename));
107    }
108                       
109}
110
111osg::Image* PhotoArchive::readImage(const std::string& filename,
112                                    unsigned int target_s, unsigned target_t,
113                                    float& original_s, float& original_t)
114{
115    for(PhotoIndexList::const_iterator itr=_photoIndex.begin();
116        itr!=_photoIndex.end();
117        ++itr)
118    {
119        if (filename==itr->filename)
120        {
121            const PhotoHeader& photoHeader = *itr;
122       
123            if  (target_s <= photoHeader.thumbnail_s &&
124                 target_t <= photoHeader.thumbnail_t &&
125                 photoHeader.thumbnail_position != 0)
126            {
127                std::ifstream in(_archiveFileName.c_str(),std::ios::in | std::ios::binary);
128               
129                // find image
130                in.seekg(photoHeader.thumbnail_position);
131               
132                // read image header
133                ImageHeader imageHeader;
134                in.read((char*)&imageHeader,sizeof(ImageHeader));
135                unsigned char* data = new unsigned char[imageHeader.size];
136                in.read((char*)data,imageHeader.size);
137               
138                osg::Image* image = new osg::Image;
139                image->setImage(photoHeader.thumbnail_s,photoHeader.thumbnail_t,1,
140                                imageHeader.pixelFormat,imageHeader.pixelFormat,imageHeader.type,
141                                data,osg::Image::USE_NEW_DELETE);
142                               
143                original_s =  photoHeader.original_s;
144                original_t =  photoHeader.original_t;
145               
146                return image;
147            }
148                 
149            if  (photoHeader.fullsize_s &&
150                 photoHeader.fullsize_t &&
151                 photoHeader.fullsize_position != 0)
152            {
153                std::ifstream in(_archiveFileName.c_str(),std::ios::in | std::ios::binary);
154               
155                // find image
156                in.seekg(photoHeader.fullsize_position);
157               
158                // read image header
159                ImageHeader imageHeader;
160                in.read((char*)&imageHeader,sizeof(ImageHeader));
161                unsigned char* data = new unsigned char[imageHeader.size];
162                in.read((char*)data,imageHeader.size);
163               
164                osg::Image* image = new osg::Image;
165                image->setImage(photoHeader.fullsize_s,photoHeader.fullsize_t,1,
166                                imageHeader.pixelFormat,imageHeader.pixelFormat,imageHeader.type,
167                                data,osg::Image::USE_NEW_DELETE);
168                               
169                original_s =  photoHeader.original_s;
170                original_t =  photoHeader.original_t;
171               
172                return image;
173           }
174
175       }
176
177    }
178    return NULL;
179}
180
181void PhotoArchive::buildArchive(const std::string& filename, const FileNameList& imageList, unsigned int thumbnailSize, unsigned int maximumSize, bool /*compressed*/)
182{
183
184    PhotoIndexList photoIndex;
185    photoIndex.reserve(imageList.size());
186    for(FileNameList::const_iterator fitr=imageList.begin();
187        fitr!=imageList.end();
188        ++fitr)
189    {
190        PhotoHeader header;
191       
192        // set name
193        strncpy(header.filename,fitr->c_str(),255);
194        header.filename[255]=0;
195       
196        header.thumbnail_s = thumbnailSize;
197        header.thumbnail_t = thumbnailSize;
198        header.thumbnail_position = 0;
199       
200        header.fullsize_s = thumbnailSize;
201        header.fullsize_t = thumbnailSize;
202        header.fullsize_position = 0;
203
204        photoIndex.push_back(header);
205       
206    }
207
208    std::cout<<"Building photo archive containing "<<photoIndex.size()<<" pictures"<<std::endl;
209
210    // create a graphics context so we can do data operations
211    MyGraphicsContext context;
212
213    // open up the archive for writing to   
214    std::ofstream out(filename.c_str(), std::ios::out | std::ios::binary);
215
216    // write out file indentifier.
217    out.write(FILE_IDENTIFER.c_str(),FILE_IDENTIFER.size());
218
219    unsigned int numPhotos = photoIndex.size();
220    out.write((char*)&numPhotos,sizeof(unsigned int));
221
222    // write the photo index to ensure we can the correct amount of space
223    // available.
224    unsigned int startOfPhotoIndex = out.tellp();
225    out.write((char*)&photoIndex.front(),sizeof(PhotoHeader)*photoIndex.size());
226
227    unsigned int photoCount=1;   
228    for(PhotoIndexList::iterator pitr=photoIndex.begin();
229        pitr!=photoIndex.end();
230        ++pitr,++photoCount)
231    {
232        PhotoHeader& photoHeader = *pitr;
233       
234       
235        std::cout<<"Processing image "<<photoCount<<" of "<< photoIndex.size()<<" filename="<< photoHeader.filename << std::endl;
236        std::cout<<"    reading image...";std::cout.flush();
237       
238        osg::ref_ptr<osg::Image> image = osgDB::readImageFile(photoHeader.filename);
239       
240        std::cout<<"done."<< std::endl;
241       
242        photoHeader.original_s = image->s();
243        photoHeader.original_t = image->t();
244
245        {
246
247            std::cout<<"    creating thumbnail image...";
248            // first need to rescale image to the require thumbnail size
249            unsigned int newTotalSize =
250                image->computeRowWidthInBytes(thumbnailSize,image->getPixelFormat(),image->getDataType(),image->getPacking())*
251                thumbnailSize;
252
253            // need to sort out what size to really use...
254            unsigned char* newData = new unsigned char [newTotalSize];
255            if (!newData)
256            {
257                // should we throw an exception???  Just return for time being.
258                osg::notify(osg::FATAL) << "Error scaleImage() did not succeed : out of memory."<<newTotalSize<<std::endl;
259                return;
260            }
261
262            glPixelStorei(GL_PACK_ALIGNMENT,image->getPacking());
263            glPixelStorei(GL_UNPACK_ALIGNMENT,image->getPacking());
264
265            GLint status = gluScaleImage(image->getPixelFormat(),
266                image->s(),
267                image->t(),
268                image->getDataType(),
269                image->data(),
270                thumbnailSize,
271                thumbnailSize,
272                image->getDataType(),
273                newData);
274
275            if (status!=0)
276            {
277               delete [] newData;
278
279                osg::notify(osg::WARN) << "Error scaleImage() did not succeed : errorString = "<<gluErrorString((GLenum)status)<<std::endl;
280            }
281   
282            // now set up the photo header.
283            photoHeader.thumbnail_s = thumbnailSize;
284            photoHeader.thumbnail_t = thumbnailSize;
285            photoHeader.thumbnail_position = (unsigned int)out.tellp();
286
287            // set up image header
288            ImageHeader imageHeader;
289            imageHeader.s = thumbnailSize;
290            imageHeader.t = thumbnailSize;
291            imageHeader.internalTextureformat = image->getInternalTextureFormat();
292            imageHeader.pixelFormat = image->getPixelFormat();
293            imageHeader.type = image->getDataType();
294            imageHeader.size = newTotalSize;
295
296            // write out image header and image data.
297            out.write((char*)&imageHeader,sizeof(ImageHeader));
298            out.write((char*)newData,imageHeader.size);
299           
300            delete [] newData;
301
302            std::cout<<"done."<< std::endl;
303
304        }
305       
306        {
307            std::cout<<"    creating fullsize image...";std::cout.flush();
308
309
310            photoHeader.fullsize_s = osg::minimum((unsigned int)image->s(),maximumSize);
311            photoHeader.fullsize_t = osg::minimum((unsigned int)image->t(),maximumSize);
312            photoHeader.fullsize_position = (unsigned int)out.tellp();
313
314            // first need to rescale image to the require thumbnail size
315            unsigned int newTotalSize =
316                image->computeRowWidthInBytes(photoHeader.fullsize_s,image->getPixelFormat(),image->getDataType(),image->getPacking())*
317                photoHeader.fullsize_t;
318
319            // need to sort out what size to really use...
320            unsigned char* newData = new unsigned char [newTotalSize];
321            if (!newData)
322            {
323                // should we throw an exception???  Just return for time being.
324                osg::notify(osg::FATAL) << "Error scaleImage() did not succeed : out of memory."<<newTotalSize<<std::endl;
325                return;
326            }
327
328            glPixelStorei(GL_PACK_ALIGNMENT,image->getPacking());
329            glPixelStorei(GL_UNPACK_ALIGNMENT,image->getPacking());
330
331            GLint status = gluScaleImage(image->getPixelFormat(),
332                image->s(),
333                image->t(),
334                image->getDataType(),
335                image->data(),
336                photoHeader.fullsize_s,
337                photoHeader.fullsize_t,
338                image->getDataType(),
339                newData);
340
341            if (status!=0)
342            {
343               delete [] newData;
344
345                osg::notify(osg::WARN) << "Error scaleImage() did not succeed : errorString = "<<gluErrorString((GLenum)status)<<std::endl;
346            }
347
348            ImageHeader imageHeader;
349            imageHeader.s = photoHeader.fullsize_s;
350            imageHeader.t = photoHeader.fullsize_t;
351            imageHeader.internalTextureformat = image->getInternalTextureFormat();
352            imageHeader.pixelFormat = image->getPixelFormat();
353            imageHeader.type = image->getDataType();
354            imageHeader.size = newTotalSize;
355
356            out.write((char*)&imageHeader,sizeof(ImageHeader));
357            out.write((char*)newData,imageHeader.size);
358            //out.write((char*)image->data(),imageHeader.size);
359
360            delete [] newData;
361
362            std::cout<<"done."<< std::endl;
363        }
364       
365    }
366
367    // rewrite photo index now it has the correct sizes set
368    out.seekp(startOfPhotoIndex);
369    out.write((char*)&photoIndex.front(),sizeof(PhotoHeader)*photoIndex.size());
370
371}
Note: See TracBrowser for help on using the browser.