PageRenderTime 279ms CodeModel.GetById 100ms app.highlight 120ms RepoModel.GetById 41ms app.codeStats 12ms

/Source/System/Image/FileIO/OSGDATImageFileType.cpp

https://github.com/msteners/OpenSGDevMaster_Toolbox
C++ | 667 lines | 504 code | 73 blank | 90 comment | 50 complexity | 6b90ed3da19fad9391badee111e99414 MD5 | raw file
  1/*---------------------------------------------------------------------------*\
  2 *                                OpenSG                                     *
  3 *                                                                           *
  4 *                                                                           *
  5 *             Copyright (C) 2000-2002 by the OpenSG Forum                   *
  6 *                                                                           *
  7 *                            www.opensg.org                                 *
  8 *                                                                           *
  9 *   contact: dirk@opensg.org, gerrit.voss@vossg.org, jbehr@zgdv.de          *
 10 *                                                                           *
 11\*---------------------------------------------------------------------------*/
 12/*---------------------------------------------------------------------------*\
 13 *                                License                                    *
 14 *                                                                           *
 15 * This library is free software; you can redistribute it and/or modify it   *
 16 * under the terms of the GNU Library General Public License as published    *
 17 * by the Free Software Foundation, version 2.                               *
 18 *                                                                           *
 19 * This library is distributed in the hope that it will be useful, but       *
 20 * WITHOUT ANY WARRANTY; without even the implied warranty of                *
 21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU         *
 22 * Library General Public License for more details.                          *
 23 *                                                                           *
 24 * You should have received a copy of the GNU Library General Public         *
 25 * License along with this library; if not, write to the Free Software       *
 26 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.                 *
 27 *                                                                           *
 28\*---------------------------------------------------------------------------*/
 29/*---------------------------------------------------------------------------*\
 30 *                                Changes                                    *
 31 *                                                                           *
 32 *                                                                           *
 33 *                                                                           *
 34 *                                                                           *
 35 *                                                                           *
 36 *                                                                           *
 37\*---------------------------------------------------------------------------*/
 38
 39//-------------------------------
 40//      Includes
 41//-------------------------------
 42
 43#include <cstdlib>
 44#include <cstdio>
 45
 46#include "OSGConfig.h"
 47
 48#include <iostream>
 49#include <fstream>
 50
 51#include "OSGLog.h"
 52#include "OSGImageFileHandler.h"
 53#include "OSGPathHandler.h"
 54#include "OSGFileSystem.h"
 55#include "OSGZStream.h"
 56
 57#include "OSGDATImageFileType.h"
 58
 59OSG_USING_NAMESPACE
 60
 61/*! \class OSG::DATImageFileType
 62    \ingroup GrpSystemImage
 63
 64  Image File Type to read/write and store/restore Image objects as
 65  PNM/RAW data.
 66
 67  All the type specific code is included in the class. Does
 68  not depend on external libs.
 69
 70 */
 71
 72
 73// Static Class Varible implementations:
 74
 75static const Char8 *suffixArray[] =
 76{
 77    "dat"
 78};
 79
 80DATImageFileType DATImageFileType::_the("image/x-dat",
 81                                        suffixArray,
 82                                        sizeof(suffixArray) );
 83
 84std::map<std::string,
 85         DATImageFileType::KeyType   > DATImageFileType::_keyStrMap;
 86
 87std::map<std::string,
 88         DATImageFileType::FormatDesc> DATImageFileType::_formatStrMap;
 89
 90
 91
 92//-------------------------------------------------------------------------
 93
 94/*! Tries to fill the image object with the data read from
 95    the given fileName. Returns true on success.
 96 */
 97
 98bool DATImageFileType::read(      Image *image,
 99                            const Char8 *fileName)
100{
101    bool retCode = false;
102
103    std::ifstream inDat(fileName), inVolS;
104    std::istream *inVol;
105    std::string keyStr, objectFileName;
106    const UInt32 lineBufferSize = 1024;
107    Char8 *value, *keySepPos, lineBuffer[lineBufferSize];
108    const Char8 keySep = ':';
109    int fileOffset, keyL, valueL;
110    std::map<std::string, KeyType>::iterator keyI;
111    std::map<std::string, FormatDesc>::iterator formatI;
112    KeyType key;
113    Image::Type formatType;
114    UInt32 channel = 1;
115    UInt32 res[3];
116    UInt32 dataSize = 0;
117    Image::PixelFormat pixelFormat = Image::OSG_L_PF;
118    char *dataBuffer = 0;
119    bool needConversion = false;
120    // default endian type is big endian
121    bool big_endian = true;
122
123    res[0] = res[1] = res[2] = 0;
124    fileOffset = 0;
125    formatType = Image::OSG_INVALID_IMAGEDATATYPE;
126    dataSize = 0;
127    dataBuffer = 0;
128
129    initTypeMap();
130
131    // read the data file
132    for(lineBuffer[0] = 0;
133        inDat.getline(lineBuffer, lineBufferSize);
134        lineBuffer[0] = 0)
135    {
136        if((keySepPos = strchr(lineBuffer,keySep)))
137        {
138            keyL = keySepPos - lineBuffer;
139            keyStr.assign( lineBuffer, keyL );
140            keyI = _keyStrMap.find(keyStr);
141            key = ((keyI == _keyStrMap.end()) ? UNKNOWN_KT : keyI->second);
142            value = keySepPos + 1;
143
144            while (value && isspace(*value))
145                value++;
146
147            valueL = strlen(value);
148
149            while (isspace(value[valueL-1]))
150                value[--valueL] = 0;
151
152            switch (key)
153            {
154                case OBJECT_FILE_NAME_KT:
155                    objectFileName = value;
156                    image->setAttachmentField ( keyStr, value );
157                    break;
158                case CHANNEL_KT:
159                    sscanf ( value, "%d", &(channel) );
160                    image->setAttachmentField ( keyStr, value );
161                    break;
162                case RESOLUTION_KT:
163                    sscanf ( value, "%d %d %d",
164                             &(res[0]), &(res[1]), &(res[2]));
165                    image->setAttachmentField ( keyStr, value );
166                    break;
167                case FORMAT_KT:
168                    formatI = _formatStrMap.find(value);
169                    if (formatI != _formatStrMap.end())
170                    {
171                        formatType = formatI->second.type;
172                    }
173                    else
174                    {
175                        formatType = Image::OSG_INVALID_IMAGEDATATYPE;
176                    }
177                    image->setAttachmentField ( keyStr, value );
178                    break;
179                case ENDIAN_KT:
180                    if(!strcmp(value, "LITTLE"))
181                        big_endian = false;
182                    image->setAttachmentField ( keyStr, value );
183                    break;
184                case FILE_OFFSET_KT:
185                    sscanf ( value, "%d", &fileOffset );
186                    image->setAttachmentField ( keyStr, value );
187                    break;
188                case UNKNOWN_KT:
189                    FNOTICE (( "Uknown DAT file key: >%s<\n",
190                                 keyStr.c_str() ));
191                    image->setAttachmentField ( keyStr, value );
192                    break;
193                case SLICE_THICKNESS_KT:
194                default:
195                    image->setAttachmentField ( keyStr, value );
196                    break;
197            }
198        }
199        else
200        {
201            FINFO (("Skip DAT line\n"));
202        }
203    }
204
205    // set pixelformat
206    switch (channel) 
207    {
208        case 4:
209            pixelFormat = Image::OSG_RGBA_PF;
210            break;
211        case 3:
212            pixelFormat = Image::OSG_RGB_PF;
213            break;
214        case 2:
215            pixelFormat = Image::OSG_LA_PF;
216            break;
217        default:
218            pixelFormat = Image::OSG_L_PF;
219            break;
220    }
221
222    // check the setting and read the raw vol data
223    if (objectFileName.empty() == false)
224    {
225        if((res[0] > 0) && (res[1] > 0) && (res[2] > 0))
226        {
227            if(formatType != Image::OSG_INVALID_IMAGEDATATYPE)
228            {
229                inVolS.open(objectFileName.c_str(),
230                            std::ios::in | std::ios::binary);
231
232                if (inVolS.fail() && ImageFileHandler::the()->getPathHandler())
233                {
234                    // Try to find the file in the search path
235                    inVolS.clear(); // reset the error state
236
237                    PathHandler *ph =
238                        ImageFileHandler::the()->getPathHandler();
239
240                    inVolS.open(ph->findFile(objectFileName.c_str()).c_str(),
241                                std::ios::in | std::ios::binary );
242                }
243
244                if(inVolS.fail())
245                {
246                    // Maybe compressed and name not changed?
247                    std::string gzname = objectFileName + ".gz";
248
249                    inVolS.clear(); // reset the error state
250
251                    inVolS.open(gzname.c_str(),
252                                std::ios::in | std::ios::binary );
253
254                    if(inVolS.fail() &&
255                       ImageFileHandler::the()->getPathHandler())
256                    {
257                        // Try to find the file in the search path
258                        inVolS.clear(); // reset the error state
259
260                        PathHandler *ph =
261                            ImageFileHandler::the()->getPathHandler();
262
263                        inVolS.open(ph->findFile(gzname.c_str()).c_str(),
264                                    std::ios::in | std::ios::binary );
265                    }
266                }
267
268                if(inVolS.good())
269                {
270#ifdef OSG_WITH_ZLIB
271                    zip_istream *unzipper = NULL;
272#endif
273
274                    image->set(pixelFormat,
275                               res[0], res[1], res[2],
276                               1, 1, 0.0, 0,
277                               formatType);
278
279                    image->clear();
280
281                    dataSize = image->getSize();
282
283                    UInt32 fileDataSize = dataSize;
284
285                    if(isGZip(inVolS))
286                    {
287#ifdef OSG_WITH_ZLIB
288                        unzipper = new zip_istream(inVolS);
289                        inVol = unzipper;
290#else
291                        SFATAL << "Compressed streams are not supported! "
292                               << "Configure with --enable-png "
293                               << "--with-png=DIR options." << std::endl;
294#endif
295                    }
296                    else
297                    {
298                        inVol = &inVolS;
299
300                        // get length of the stream.
301                        inVol->seekg(0, std::ios::end);
302                        UInt64 length = inVol->tellg();
303                        inVol->seekg(0, std::ios::beg);
304
305                        if(length < dataSize - fileOffset)
306                        {
307                            // correct dataSize.
308                            fileDataSize = length;
309                            FWARNING (( "RAW file length to small!\n" ));
310                        }
311                        else if(length > dataSize - fileOffset)
312                        {
313                            FWARNING (( "RAW file length to big!\n" ));
314                        }
315                    }
316
317                    if(needConversion)
318                    {
319                        dataBuffer = new char [ dataSize ];
320                    }
321                    else
322                    {
323                        dataBuffer = 
324                            reinterpret_cast<char *>(image->editData());
325                    }
326
327                    if(fileOffset != 0)
328                        inVol->ignore (fileOffset);
329
330                    inVol->read ( dataBuffer, fileDataSize );
331
332#ifdef OSG_WITH_ZLIB
333                    if(unzipper != NULL)
334                        delete unzipper;
335#endif
336                }
337                else
338                {
339                    FWARNING (( "Can not open %s image data\n",
340                                objectFileName.c_str() ));
341                }
342            }
343            else
344            {
345                FWARNING (( "Invalid/Missing DAT Format\n" ));
346            }
347        }
348        else
349        {
350            FWARNING (( "Invalid/Missing DAT Resolution\n" ));
351        }
352    }
353    else
354    {
355        FWARNING (( "Invalid/Missing DAT ObjectFileName\n" ));
356    }
357
358    // check/reformat vol data
359    if (dataSize && dataBuffer)
360    {
361        // check host endian type
362        UInt16 word = 0x0001;
363        UInt8 *byte = reinterpret_cast<UInt8 *>(&word);
364        bool host_big_endian = byte[0] ? false : true;
365
366        if(big_endian != host_big_endian)
367            image->swapDataEndian();
368
369        if (needConversion)
370        {
371            FLOG (("DAT-Data convert not impl. yet !\n"));
372            {
373                switch (formatType)
374                {
375                    case Image::OSG_UINT8_IMAGEDATA:
376                        break;
377                    case Image::OSG_UINT16_IMAGEDATA:
378                        break;
379                    case Image::OSG_UINT32_IMAGEDATA:
380                        break;
381                    case Image::OSG_FLOAT32_IMAGEDATA:
382                        break;
383                    default:
384                        ;
385                }
386            }
387        }
388        else
389        {
390            retCode = true;
391        }
392    }
393
394
395    /* TODO
396       std::ifstream in(fileName);
397       Head head;
398       void *headData = (void*)(&head);
399       unsigned dataSize, headSize = sizeof(Head);
400
401       if ( in &&
402       in.read(static_cast<char *>(headData),
403       headSize) && head.netToHost() &&
404       image.set ( Image::PixelFormat(head.pixelFormat),
405       head.width, head.height, head.depth, head.mipmapCount,
406       head.frameCount, float(head.frameDelay) / 1000.0) &&
407       (dataSize = image.getSize()) &&
408       in.read((char *)(image.getData()), dataSize ))
409       retCode = true;
410       else
411       retCode = false;
412    */
413
414    return retCode;
415}
416
417//-------------------------------------------------------------------------
418/*! Tries to write the image object to the given fileName.
419    Returns true on success.
420*/
421bool DATImageFileType::write(const Image *image,
422                             const Char8 *fileName)
423{
424    initTypeMap();
425
426    // ok we write always in big endian.
427#if BYTE_ORDER == LITTLE_ENDIAN
428    Image *pSwapImage = const_cast<Image *>(&(*image));
429
430    pSwapImage->swapDataEndian();
431#endif
432
433    std::ofstream dat(fileName, std::ios::binary);
434
435    if(!dat)
436    {
437        SWARNING << "DATImageFileType::write : Can not open output stream "
438                 << "for file '"
439                 << fileName
440                 << "'!"
441                 << std::endl;
442
443        return false;
444    }
445
446    Real64 sT[3];
447    sT[0] = sT[1] = sT[2] = 1.0;
448
449    const std::string *attr = image->findAttachmentField("SliceThickness");
450
451    if(attr != NULL)
452        sscanf(attr->c_str(), "%lf %lf %lf", &sT[0], &sT[1], &sT[2]);
453
454    std::string format = "UCHAR";
455
456    for(std::map<std::string, FormatDesc>::iterator it = _formatStrMap.begin();
457        it != _formatStrMap.end();
458        ++it)
459    {
460        if((*it).second.type == image->getDataType())
461        {
462            format = (*it).first;
463            break;
464        }
465    }
466
467    std::string basename = fileName;
468    std::string::size_type i = basename.rfind(".");
469
470    if(i != std::string::npos)
471        basename = basename.substr(0, i);
472
473    basename += ".raw";
474
475    std::string name = basename;
476
477    i = name.rfind("/");
478
479    // on windows also a / is possible!
480#if defined(WIN32)
481    if(i == std::string::npos)
482        i = name.rfind("\\");
483#endif
484
485    if(i != std::string::npos)
486        name = name.substr(i+1);
487
488    dat << "ObjectFileName: " << name << "\n";
489    dat << "TaggedFileName: ---\n";
490    dat << "Resolution:     " << image->getWidth() << " " << image->getHeight()
491        << " "                << image->getDepth() << "\n";
492    dat << "SliceThickness: " << sT[0] << " " << sT[1] << " " << sT[2] << "\n";
493    dat << "Format:         " << format << "\n";
494    dat << "NbrTags:        0\n";
495    dat << "ObjectType:     TEXTURE_VOLUME_OBJECT\n";
496    dat << "ObjectModel:    DENSITY\n";
497    dat << "GridType:       EQUIDISTANT\n";
498
499    if(image->getBpp() > 1)
500      dat << "Channel: " << image->getBpp() << "\n";
501
502    dat.close();
503
504    std::ofstream raw(basename.c_str(), std::ios::binary);
505
506    if(!raw)
507    {
508        SWARNING << "DATImageFileType::write : Can not open output stream "
509                 << "for file '"
510                 << basename
511                 << "'!"
512                 << std::endl;
513
514        return false;
515    }
516
517    raw.write (reinterpret_cast<const char *>(image->getData()), 
518               image->getSize());
519    raw.close();
520
521    // restore to original endian
522#if BYTE_ORDER == LITTLE_ENDIAN
523    pSwapImage->swapDataEndian();
524#endif
525
526    /*
527    ofstream out(fileName);
528    Head head;
529    const void *headData = (void*)(&head);
530    unsigned dataSize = image.getSize(), headSize = sizeof(Head);
531
532    head.pixelFormat  = image.getPixelFormat();
533    head.width        = image.getWidth();
534    head.height       = image.getHeight();
535    head.depth        = image.getDepth();
536    head.mipmapCount  = image.getMipMapCount();
537    head.frameCount   = image.getFrameCount();
538    head.frameDelay   = short(image.getFrameDelay() * 1000.0);
539    head.hostToNet();
540
541    if ( out && out.write(static_cast<const char *>(headData), headSize) &&
542         dataSize &&
543             out.write((char *)(image.getData()), dataSize) )
544            retCode = true;
545    else
546        retCode = false;
547    */
548
549    return true;
550}
551
552
553//-------------------------------------------------------------------------
554/*! Tries to restore the image data from the given memblock.
555    Returns the amount of data read.
556*/
557
558UInt64 DATImageFileType::restoreData(      Image  *image,
559                                     const UChar8 *buffer,
560                                           Int32   OSG_CHECK_ARG(memSize))
561{
562    image->setData(buffer);
563
564    return image->getSize();
565}
566
567//-------------------------------------------------------------------------
568/*! Tries to store the image data to the given memblock.
569    Returns the amount of data written.
570*/
571
572UInt64 DATImageFileType::storeData(const Image  *image,
573                                         UChar8 *buffer,
574                                         Int32   OSG_CHECK_ARG(memSize))
575{
576          UInt32  dataSize = image->getSize();
577    const UChar8 *src      = image->getData();
578
579    if(dataSize && src && buffer)
580        memcpy( buffer, src, dataSize);
581
582    return dataSize;
583}
584
585
586//-------------------------------------------------------------------------
587/*! Constructor used for the singleton object
588 */
589
590DATImageFileType::DATImageFileType(const Char8  *mimeType,
591                                   const Char8  *suffixArray[],
592                                         UInt16  suffixByteCount) :
593    Inherited(mimeType,
594              suffixArray,
595              suffixByteCount)
596{
597}
598
599
600//-------------------------------------------------------------------------
601/*! Destructor
602 */
603
604DATImageFileType::~DATImageFileType(void)
605{
606}
607
608//-------------------------------------------------------------------------
609/*! Helper to initialize the type map;
610 */
611
612void DATImageFileType::initTypeMap(void)
613{
614    FormatDesc *desc;
615
616    if(_keyStrMap.empty())
617    {
618        _keyStrMap["ObjectFileName"]  = OBJECT_FILE_NAME_KT;
619        _keyStrMap["Resolution"]      = RESOLUTION_KT;
620        _keyStrMap["Channel"]         = CHANNEL_KT;
621        _keyStrMap["SliceThickness"]  = SLICE_THICKNESS_KT;
622        _keyStrMap["Format"]          = FORMAT_KT;
623        _keyStrMap["Endian"]          = ENDIAN_KT;
624        _keyStrMap["FileOffset"]      = FILE_OFFSET_KT;
625    }
626
627    if(_formatStrMap.empty())
628    {
629        desc = &(_formatStrMap["UCHAR"]);
630        desc->type = Image::OSG_UINT8_IMAGEDATA;
631        desc->bpv  = 1;
632        desc->pixelFormat = Image::OSG_L_PF;
633        desc->needConversion = false;
634
635        desc = &(_formatStrMap["USHORT"]);
636        desc->type = Image::OSG_UINT16_IMAGEDATA;
637        desc->bpv  = 2;
638        desc->pixelFormat = Image::OSG_L_PF;
639        desc->needConversion = false;
640
641        desc = &(_formatStrMap["UINT"]);
642        desc->type = Image::OSG_UINT32_IMAGEDATA;
643        desc->bpv  = 4; // TODO; is this right ?
644        desc->pixelFormat = Image::OSG_L_PF;
645        desc->needConversion = false;
646
647        desc = &(_formatStrMap["ULONG"]);
648        desc->type = Image::OSG_UINT32_IMAGEDATA;
649        desc->bpv  = 4;
650        desc->pixelFormat = Image::OSG_L_PF;
651        desc->needConversion = false;
652
653        desc = &(_formatStrMap["FLOAT"]);
654        desc->type = Image::OSG_FLOAT32_IMAGEDATA;
655        desc->bpv  = 4;
656        desc->pixelFormat = Image::OSG_L_PF;
657        desc->needConversion = false;
658
659        desc = &(_formatStrMap["DOUBLE"]);
660        // we have no OSG_FLOAT64_IMAGEDATA
661        desc->type = Image::OSG_FLOAT32_IMAGEDATA;
662        desc->bpv  = 8;
663        desc->pixelFormat = Image::OSG_L_PF;
664        desc->needConversion = false;
665    }
666}
667