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

Revision 12912, 12.1 kB (checked in by robert, 3 years ago)

Added support for using GL_UNPACK_ROW_LENGTH in conjunction with texture's + osg::Image via new RowLength?
parameter in osg::Image. To support this Image::setData(..) now has a new optional rowLength parameter which
defaults to 0, which provides the original behaviour, Image::setRowLength(int) and int Image::getRowLength() are also provided.

With the introduction of RowLength? support in osg::Image it is now possible to create a sub image where
the t size of the image are smaller than the row length, useful for when you have a large image on the CPU
and which to use a small portion of it on the GPU. However, when these sub images are created the data
within the image is no longer contiguous so data access can no longer assume that all the data is in
one block. The new method Image::isDataContiguous() enables the user to check whether the data is contiguous,
and if not one can either access the data row by row using Image::data(column,row,image) accessor, or use the
new Image::DataIterator? for stepping through each block on memory assocatied with the image.

To support the possibility of non contiguous osg::Image usage of image objects has had to be updated to
check DataContiguous? and handle the case or use access via the DataIerator? or by row by row. To achieve
this a relatively large number of files has had to be modified, in particular the texture classes and
image plugins that doing writing.

  • 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#include <osgDB/fstream>
25
26#include <osg/GraphicsContext>
27
28#include <iostream>
29#include <string.h>
30
31const std::string FILE_IDENTIFER("osgphotoalbum photo archive");
32
33PhotoArchive::PhotoArchive(const std::string& filename)
34{
35    readPhotoIndex(filename);
36}
37
38bool PhotoArchive::readPhotoIndex(const std::string& filename)
39{
40    osgDB::ifstream in(filename.c_str());
41   
42    char* fileIndentifier = new char [FILE_IDENTIFER.size()];
43    in.read(fileIndentifier,FILE_IDENTIFER.size());
44    if (FILE_IDENTIFER!=fileIndentifier)
45    {
46        delete [] fileIndentifier;
47        return false;
48    }
49    delete [] fileIndentifier;
50   
51    unsigned int numPhotos;
52    in.read((char*)&numPhotos,sizeof(numPhotos));
53
54    _photoIndex.resize(numPhotos);
55
56    in.read((char*)&_photoIndex.front(),sizeof(PhotoHeader)*numPhotos);
57   
58    // success record filename.
59    _archiveFileName = filename;
60   
61    return true;
62}
63
64void PhotoArchive::getImageFileNameList(FileNameList& filenameList)
65{
66    for(PhotoIndexList::const_iterator itr=_photoIndex.begin();
67        itr!=_photoIndex.end();
68        ++itr)
69    {
70        filenameList.push_back(std::string(itr->filename));
71    }
72                       
73}
74
75osg::Image* PhotoArchive::readImage(const std::string& filename,
76                                    unsigned int target_s, unsigned target_t,
77                                    float& original_s, float& original_t)
78{
79    for(PhotoIndexList::const_iterator itr=_photoIndex.begin();
80        itr!=_photoIndex.end();
81        ++itr)
82    {
83        if (filename==itr->filename)
84        {
85            const PhotoHeader& photoHeader = *itr;
86       
87            if  (target_s <= photoHeader.thumbnail_s &&
88                 target_t <= photoHeader.thumbnail_t &&
89                 photoHeader.thumbnail_position != 0)
90            {
91                osgDB::ifstream in(_archiveFileName.c_str(),std::ios::in | std::ios::binary);
92               
93                // find image
94                in.seekg(photoHeader.thumbnail_position);
95               
96                // read image header
97                ImageHeader imageHeader;
98                in.read((char*)&imageHeader,sizeof(ImageHeader));
99                unsigned char* data = new unsigned char[imageHeader.size];
100                in.read((char*)data,imageHeader.size);
101               
102                osg::Image* image = new osg::Image;
103                image->setImage(photoHeader.thumbnail_s,photoHeader.thumbnail_t,1,
104                                imageHeader.pixelFormat,imageHeader.pixelFormat,imageHeader.type,
105                                data,osg::Image::USE_NEW_DELETE);
106                               
107                original_s =  photoHeader.original_s;
108                original_t =  photoHeader.original_t;
109               
110                return image;
111            }
112                 
113            if  (photoHeader.fullsize_s &&
114                 photoHeader.fullsize_t &&
115                 photoHeader.fullsize_position != 0)
116            {
117                osgDB::ifstream in(_archiveFileName.c_str(),std::ios::in | std::ios::binary);
118               
119                // find image
120                in.seekg(photoHeader.fullsize_position);
121               
122                // read image header
123                ImageHeader imageHeader;
124                in.read((char*)&imageHeader,sizeof(ImageHeader));
125                unsigned char* data = new unsigned char[imageHeader.size];
126                in.read((char*)data,imageHeader.size);
127               
128                osg::Image* image = new osg::Image;
129                image->setImage(photoHeader.fullsize_s,photoHeader.fullsize_t,1,
130                                imageHeader.pixelFormat,imageHeader.pixelFormat,imageHeader.type,
131                                data,osg::Image::USE_NEW_DELETE);
132                               
133                original_s =  photoHeader.original_s;
134                original_t =  photoHeader.original_t;
135               
136                return image;
137           }
138
139       }
140
141    }
142    return NULL;
143}
144
145void PhotoArchive::buildArchive(const std::string& filename, const FileNameList& imageList, unsigned int thumbnailSize, unsigned int maximumSize, bool /*compressed*/)
146{
147
148    PhotoIndexList photoIndex;
149    photoIndex.reserve(imageList.size());
150    for(FileNameList::const_iterator fitr=imageList.begin();
151        fitr!=imageList.end();
152        ++fitr)
153    {
154        PhotoHeader header;
155       
156        // set name
157        strncpy(header.filename,fitr->c_str(),255);
158        header.filename[255]=0;
159       
160        header.thumbnail_s = thumbnailSize;
161        header.thumbnail_t = thumbnailSize;
162        header.thumbnail_position = 0;
163       
164        header.fullsize_s = thumbnailSize;
165        header.fullsize_t = thumbnailSize;
166        header.fullsize_position = 0;
167
168        photoIndex.push_back(header);
169       
170    }
171
172    std::cout<<"Building photo archive containing "<<photoIndex.size()<<" pictures"<<std::endl;
173
174    // open up the archive for writing to
175    osgDB::ofstream out(filename.c_str(), std::ios::out | std::ios::binary);
176
177    // write out file indentifier.
178    out.write(FILE_IDENTIFER.c_str(),FILE_IDENTIFER.size());
179
180    unsigned int numPhotos = photoIndex.size();
181    out.write((char*)&numPhotos,sizeof(unsigned int));
182
183    // write the photo index to ensure we can the correct amount of space
184    // available.
185    unsigned int startOfPhotoIndex = out.tellp();
186    out.write((char*)&photoIndex.front(),sizeof(PhotoHeader)*photoIndex.size());
187
188    unsigned int photoCount=1;   
189    for(PhotoIndexList::iterator pitr=photoIndex.begin();
190        pitr!=photoIndex.end();
191        ++pitr,++photoCount)
192    {
193        PhotoHeader& photoHeader = *pitr;
194       
195       
196        std::cout<<"Processing image "<<photoCount<<" of "<< photoIndex.size()<<" filename="<< photoHeader.filename << std::endl;
197        std::cout<<"    reading image...";std::cout.flush();
198       
199        osg::ref_ptr<osg::Image> image = osgDB::readImageFile(photoHeader.filename);
200       
201        std::cout<<"done."<< std::endl;
202       
203        photoHeader.original_s = image->s();
204        photoHeader.original_t = image->t();
205
206        {
207
208            std::cout<<"    creating thumbnail image...";
209            // first need to rescale image to the require thumbnail size
210            unsigned int newTotalSize =
211                image->computeRowWidthInBytes(thumbnailSize,image->getPixelFormat(),image->getDataType(),image->getPacking())*
212                thumbnailSize;
213
214            // need to sort out what size to really use...
215            unsigned char* newData = new unsigned char [newTotalSize];
216            if (!newData)
217            {
218                // should we throw an exception???  Just return for time being.
219                osg::notify(osg::FATAL) << "Error scaleImage() did not succeed : out of memory."<<newTotalSize<<std::endl;
220                return;
221            }
222
223            osg::PixelStorageModes psm;
224            psm.pack_alignment = image->getPacking();
225            psm.pack_row_length = image->getRowLength();
226            psm.unpack_alignment = image->getPacking();
227
228            GLint status = osg::gluScaleImage(&psm, image->getPixelFormat(),
229                image->s(),
230                image->t(),
231                image->getDataType(),
232                image->data(),
233                thumbnailSize,
234                thumbnailSize,
235                image->getDataType(),
236                newData);
237
238            if (status!=0)
239            {
240                delete [] newData;
241                osg::notify(osg::WARN) << "Error scaleImage() did not succeed : errorString = "<<osg::gluErrorString((GLenum)status)<<std::endl;
242                return;
243            }
244   
245            // now set up the photo header.
246            photoHeader.thumbnail_s = thumbnailSize;
247            photoHeader.thumbnail_t = thumbnailSize;
248            photoHeader.thumbnail_position = (unsigned int)out.tellp();
249
250            // set up image header
251            ImageHeader imageHeader;
252            imageHeader.s = thumbnailSize;
253            imageHeader.t = thumbnailSize;
254            imageHeader.internalTextureformat = image->getInternalTextureFormat();
255            imageHeader.pixelFormat = image->getPixelFormat();
256            imageHeader.type = image->getDataType();
257            imageHeader.size = newTotalSize;
258
259            // write out image header and image data.
260            out.write((char*)&imageHeader,sizeof(ImageHeader));
261            out.write((char*)newData,imageHeader.size);
262           
263            delete [] newData;
264
265            std::cout<<"done."<< std::endl;
266
267        }
268       
269        {
270            std::cout<<"    creating fullsize image...";std::cout.flush();
271
272
273            photoHeader.fullsize_s = osg::minimum((unsigned int)image->s(),maximumSize);
274            photoHeader.fullsize_t = osg::minimum((unsigned int)image->t(),maximumSize);
275            photoHeader.fullsize_position = (unsigned int)out.tellp();
276
277            // first need to rescale image to the require thumbnail size
278            unsigned int newTotalSize =
279                image->computeRowWidthInBytes(photoHeader.fullsize_s,image->getPixelFormat(),image->getDataType(),image->getPacking())*
280                photoHeader.fullsize_t;
281
282            // need to sort out what size to really use...
283            unsigned char* newData = new unsigned char [newTotalSize];
284            if (!newData)
285            {
286                // should we throw an exception???  Just return for time being.
287                osg::notify(osg::FATAL) << "Error scaleImage() did not succeed : out of memory."<<newTotalSize<<std::endl;
288                return;
289            }
290
291            osg::PixelStorageModes psm;
292            psm.pack_alignment = image->getPacking();
293            psm.pack_row_length = image->getRowLength();
294            psm.unpack_alignment = image->getPacking();
295
296            GLint status = osg::gluScaleImage(&psm, image->getPixelFormat(),
297                image->s(),
298                image->t(),
299                image->getDataType(),
300                image->data(),
301                photoHeader.fullsize_s,
302                photoHeader.fullsize_t,
303                image->getDataType(),
304                newData);
305
306            if (status!=0)
307            {
308                delete [] newData;
309                osg::notify(osg::WARN) << "Error scaleImage() did not succeed : errorString = "<<osg::gluErrorString((GLenum)status)<<std::endl;
310                return;
311            }
312
313            ImageHeader imageHeader;
314            imageHeader.s = photoHeader.fullsize_s;
315            imageHeader.t = photoHeader.fullsize_t;
316            imageHeader.internalTextureformat = image->getInternalTextureFormat();
317            imageHeader.pixelFormat = image->getPixelFormat();
318            imageHeader.type = image->getDataType();
319            imageHeader.size = newTotalSize;
320
321            out.write((char*)&imageHeader,sizeof(ImageHeader));
322            out.write((char*)newData,imageHeader.size);
323            //out.write((char*)image->data(),imageHeader.size);
324
325            delete [] newData;
326
327            std::cout<<"done."<< std::endl;
328        }
329       
330    }
331
332    // rewrite photo index now it has the correct sizes set
333    out.seekp(startOfPhotoIndex);
334    out.write((char*)&photoIndex.front(),sizeof(PhotoHeader)*photoIndex.size());
335
336}
Note: See TracBrowser for help on using the browser.