]> Creatis software - gdcm.git/blob - Testing/TestAllReadCompareDicom.cxx
COMP: Could not find if ios::failure is defined in C++ or not..disabling on GNU system
[gdcm.git] / Testing / TestAllReadCompareDicom.cxx
1 /*=========================================================================
2                                                                                 
3   Program:   gdcm
4   Module:    $RCSfile: TestAllReadCompareDicom.cxx,v $
5   Language:  C++
6   Date:      $Date: 2005/04/15 21:46:06 $
7   Version:   $Revision: 1.36 $
8                                                                                 
9   Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de
10   l'Image). All rights reserved. See Doc/License.txt or
11   http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details.
12                                                                                 
13      This software is distributed WITHOUT ANY WARRANTY; without even
14      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15      PURPOSE.  See the above copyright notices for more information.
16                                                                                 
17 =========================================================================*/
18 #include "gdcmDirList.h"
19 #include "gdcmFile.h"
20 #include "gdcmFileHelper.h"
21
22 #include <iostream>
23 #include <fstream>
24
25 //Generated file:
26 #include "gdcmDataImages.h"
27
28 /**
29  * /brief   File Read/Writer specific for the TestAllReadCompareDicom test
30  * /remarks The Test file format is (only in little endian) :
31  *  - 4 bytes : 'gdcm'
32  *  - 4 bytes : size X
33  *  - 4 bytes : size Y
34  *  - 4 bytes : size Z
35  *  - 2 bytes : scalar size (8,16,32)
36  *  - 2 bytes : number of components per pixel (1,2,3)
37  *  - n bytes : datas
38  */
39 class TestFile
40 {
41 public:
42    TestFile(void);
43    ~TestFile(void);
44
45    bool IsReadable(void) {return readable;}
46    int GetXSize(void) {return sizeX;};
47    void SetXSize(int size) {sizeX = size;};
48    int GetYSize(void) {return sizeY;};
49    void SetYSize(int size) {sizeY = size;};
50    int GetZSize(void) {return sizeZ;};
51    void SetZSize(int size) {sizeZ = size;};
52    int GetScalarSize(void) {return scalarSize;};
53    void SetScalarSize(int size) {scalarSize = size;};
54    int GetNumberOfComponents(void) {return components;};
55    void SetNumberOfComponents(int size) {components = size;};
56
57    unsigned long GetDataSize(void) {return GetLineSize()*sizeY*sizeZ;}
58    uint8_t *GetData(void) {return data;}
59    void SetData(const uint8_t *newData);
60
61    void Load(const std::string &filename);
62    void Write(const std::string &filename);
63
64 private:
65    unsigned long GetLineSize(void) {return sizeX*scalarSize*components;}
66    int GetSwapCode(uint32_t tag);
67
68    void NewData(void);
69    void DeleteData(void);
70
71    void ReadFile(void);
72    bool ReadFileHeader(std::ifstream *fp);
73    bool ReadFileData(std::ifstream *fp);
74    void WriteFile(void);
75    bool WriteFileHeader(std::ofstream *fp);
76    bool WriteFileData(std::ofstream *fp);
77
78    uint8_t  ReadInt8 (std::ifstream *fp)
79 #ifndef __GNUC__
80  throw( std::ofstream::failure );
81 #else
82  ;
83 #endif
84    uint16_t ReadInt16(std::ifstream *fp)
85 #ifndef __GNUC__
86   throw( std::ios::failure );
87 #else
88  ;
89 #endif
90    uint32_t ReadInt32(std::ifstream *fp)
91 #ifndef __GNUC__
92   throw( std::ios::failure );
93 #else
94  ;
95 #endif
96    void WriteInt8 (std::ofstream *fp,uint8_t  value);
97    void WriteInt16(std::ofstream *fp,uint16_t value);
98    void WriteInt32(std::ofstream *fp,uint32_t value);
99
100    std::string fileName;
101    bool readable;
102
103    int sizeX;
104    int sizeY;
105    int sizeZ;
106    int scalarSize;
107    int components;
108    uint8_t *data;
109    int swapCode;
110
111    static const unsigned int HEADER_SIZE;
112 };
113
114 const unsigned int TestFile::HEADER_SIZE = 20;
115
116 TestFile::TestFile(void)
117 {
118    fileName = "";
119    readable=false;
120
121    sizeX = 0;
122    sizeY = 0;
123    sizeZ = 0;
124    scalarSize = 0;
125    components = 0;
126    data = NULL;
127
128    swapCode = 1234;
129 }
130
131 TestFile::~TestFile(void)
132 {
133    DeleteData();
134 }
135
136 void TestFile::SetData(const uint8_t *newData)
137 {
138    DeleteData();
139    NewData();
140    if( data )
141       memcpy(data,newData,GetDataSize());
142 }
143
144 void TestFile::Load(const std::string &filename)
145 {
146    fileName = filename;
147    ReadFile();
148 }
149
150 void TestFile::Write(const std::string &filename)
151 {
152    fileName = filename;
153    WriteFile();
154 }
155
156 int TestFile::GetSwapCode(uint32_t tag)
157 {
158    int swap = 0;
159    for(int i=0;i<4;i++)
160    {
161       switch(tag&0x000000FF)
162       {
163          case 'g':
164             swap += (i+1)*1000;
165             break;
166          case 'd':
167             swap += (i+1)*100;
168             break;
169          case 'c':
170             swap += (i+1)*10;
171             break;
172          case 'm':
173             swap += (i+1);
174             break;
175          default:
176             return 0;
177       }
178       tag >>= 8;
179    }
180    return swap;
181 }
182
183 void TestFile::NewData(void)
184 {
185    DeleteData();
186    if( GetDataSize() == 0 )
187       return;
188    data = new uint8_t[GetDataSize()];
189 }
190
191 void TestFile::DeleteData(void)
192 {
193    if( data )
194       delete[] data;
195    data = NULL;
196 }
197
198 void TestFile::ReadFile(void)
199 {
200    readable=true;
201    std::ifstream fp(fileName.c_str(),std::ios::in | std::ios::binary);
202
203    if(!fp)
204    {
205       readable=false;
206       return;
207    }
208
209    try
210    {
211       readable=ReadFileHeader(&fp);
212       if(!readable)
213       {
214          std::cout << "Problems when reading Header part" << std::endl;
215          fp.close();
216          return;
217       }
218
219       readable=ReadFileData(&fp);
220       if(!readable)
221       {
222          std::cout << "Problems when reading datas" << std::endl;
223          fp.close();
224          return;
225       }
226    }
227    catch(...)
228    {
229       readable=false;
230       fp.close();
231       return;
232    }
233
234    fp.close();
235 }
236
237 bool TestFile::ReadFileHeader(std::ifstream *fp)
238 {
239    uint32_t tag = ReadInt32(fp);
240    swapCode = GetSwapCode(tag);
241    if( swapCode == 0 )
242    {
243       std::cout << "TestFile: Bad tag - Must be 'gdcm'" << std::endl;
244       return(false);
245    }
246
247    sizeX = ReadInt32(fp); // Size X
248    sizeY = ReadInt32(fp); // Size Y
249    sizeZ = ReadInt32(fp); // Size Z
250    scalarSize = ReadInt16(fp)/8; // bits per scalar
251    components = ReadInt16(fp); // Number of components
252
253    return(true);
254 }
255
256 bool TestFile::ReadFileData(std::ifstream *fp)
257 {
258    DeleteData();
259
260    // Allocate datas
261    NewData();
262    if( !data )
263       return(false);
264
265    // Read datas
266    fp->read((char *)data,GetDataSize());
267
268    return(true);
269 }
270
271 void TestFile::WriteFile(void)
272 {
273    std::ofstream fp(fileName.c_str(),std::ios::out | std::ios::binary);
274
275    if(!fp)
276    {
277       readable=false;
278       return;
279    }
280
281    WriteFileHeader(&fp);
282    WriteFileData(&fp);
283
284    fp.close();
285 }
286
287 bool TestFile::WriteFileHeader(std::ofstream *fp)
288 {
289    WriteInt8(fp,'g'); // Bitmap tag - must be 'g'
290    WriteInt8(fp,'d'); // Bitmap tag - must be 'd'
291    WriteInt8(fp,'c'); // Bitmap tag - must be 'c'
292    WriteInt8(fp,'m'); // Bitmap tag - must be 'm'
293    WriteInt32(fp,sizeX); // Size X
294    WriteInt32(fp,sizeY); // Size Y
295    WriteInt32(fp,sizeZ); // Size Z
296    WriteInt16(fp,scalarSize*8); // bits per scalar
297    WriteInt16(fp,components); // number of components
298
299    return(true);
300 }
301
302 bool TestFile::WriteFileData(std::ofstream *fp)
303 {
304    fp->write((char *)data,GetDataSize());
305
306    return(true);
307 }
308
309 uint8_t  TestFile::ReadInt8 (std::ifstream *fp)
310 #ifndef __GNUC__
311    throw( std::ios::failure )
312 #endif
313 {
314    uint8_t g;
315    fp->read ((char*)&g, (size_t)1);
316 #ifndef __GNUC__
317    if ( fp->fail() )
318       throw std::ios::failure( "TestFile::ReadInt8() - file error." );
319    if( fp->eof() )
320       throw std::ios::failure( "TestFile::ReadInt8() - EOF." );
321 #endif
322    return g;
323 }
324
325 uint16_t TestFile::ReadInt16(std::ifstream *fp)
326 #ifndef __GNUC__
327    throw( std::ios::failure )
328 #endif
329 {
330    uint16_t g;
331    fp->read ((char*)&g, (size_t)2);
332 #ifndef __GNUC__
333    if ( fp->fail() )
334       throw std::ios::failure( "TestFile::ReadInt16() - file error." );
335    if( fp->eof() )
336       throw std::ios::failure( "TestFile::ReadInt16() - EOF." );
337 #endif
338
339 #if defined(GDCM_WORDS_BIGENDIAN)
340    g = ( g << 8 |  g >> 8  );
341 #endif
342    return g;
343 }
344
345 uint32_t TestFile::ReadInt32(std::ifstream *fp)
346 #ifndef __GNUC__
347    throw( std::ios::failure )
348 #endif
349 {
350    uint32_t g;
351    fp->read ((char*)&g, (size_t)4);
352 #ifndef __GNUC__
353    if ( fp->fail() )
354       throw std::ios::failure( "TestFile::ReadInt32() - file error." );
355    if( fp->eof() )
356       throw std::ios::failure( "TestFile::ReadInt32() - EOF." );
357 #endif
358
359 #if defined(GDCM_WORDS_BIGENDIAN)
360    g = (  (g<<24)               | ((g<<8)  & 0x00ff0000) | 
361        (  (g>>8)  & 0x0000ff00) |  (g>>24)               );
362 #endif
363    return g;
364 }
365
366 void TestFile::WriteInt8 (std::ofstream *fp,uint8_t value)
367 {
368    fp->write((char*)&value, (size_t)1);
369 }
370
371 void TestFile::WriteInt16(std::ofstream *fp,uint16_t value)
372 {
373 #if defined(GDCM_WORDS_BIGENDIAN)
374    value = ( value << 8 |  value >> 8  );
375 #endif
376    fp->write((char*)&value, (size_t)2);
377 }
378
379 void TestFile::WriteInt32(std::ofstream *fp,uint32_t value)
380 {
381 #if defined(GDCM_WORDS_BIGENDIAN)
382    value = (  (value<<24)               | ((value<<8)  & 0x00ff0000) | 
383            (  (value>>8)  & 0x0000ff00) |  (value>>24)               );
384 #endif
385    fp->write((char*)&value, (size_t)4);
386 }
387
388 int InternalTest(std::string const &filename, 
389                  std::string const &referenceFileName )
390 {
391       std::cout << "   Testing: " << filename << std::endl;
392       std::cout << "      ";
393
394       ////// Step 1:
395       std::cout << "1...";
396       gdcm::FileHelper *tested = new gdcm::FileHelper( filename );
397       if( !tested->GetFile()->IsReadable() )
398       {
399         std::cout << " Failed" << std::endl
400                    << "      Image not gdcm compatible:"
401                   << filename << std::endl;
402         delete tested;
403         return 1;
404       }
405
406       ////// Step 2:
407       ////// Check for existence of reference baseline dicom file:
408       std::cout << "2...";
409
410       TestFile *reference = new TestFile();
411       std::ifstream refFile(referenceFileName.c_str(),
412                             std::ios::binary|std::ios::in);
413       if(!refFile)
414       {
415          std::cout << " Failed" << std::endl
416                    << "      Image not found:"
417                    << referenceFileName << std::endl;
418          reference->SetXSize(tested->GetFile()->GetXSize());
419          reference->SetYSize(tested->GetFile()->GetYSize());
420          reference->SetZSize(tested->GetFile()->GetZSize());
421          reference->SetScalarSize(tested->GetFile()->GetPixelSize());
422          reference->SetNumberOfComponents(tested->GetFile()->GetNumberOfScalarComponents());
423          reference->SetData(tested->GetImageData());
424          reference->Write(referenceFileName);
425       }
426       else
427          refFile.close();
428
429       reference->Load(referenceFileName);
430       if(!reference->IsReadable())
431       {
432         std::cout << " Failed" << std::endl
433                    << "      Image not Testing compatible:"
434                   << filename << std::endl;
435          delete reference;
436          delete tested;
437          return 1;
438       }
439
440       ////// Step 3:
441       std::string PixelType = tested->GetFile()->GetPixelType();
442       std::cout << "3...";
443       int testedDataSize    = tested->GetImageDataSize();
444       uint8_t *testedImageData = tested->GetImageData();
445     
446       int    referenceDataSize = reference->GetDataSize();
447       uint8_t *referenceImageData = reference->GetData();
448
449       // Test the image size
450       if (tested->GetFile()->GetXSize() != reference->GetXSize() ||
451           tested->GetFile()->GetYSize() != reference->GetYSize() ||
452           tested->GetFile()->GetZSize() != reference->GetZSize())
453       {
454          std::cout << "Failed" << std::endl
455                    << "        Size differs: "
456                    << "X: " << tested->GetFile()->GetXSize() << " # " 
457                    << reference->GetXSize() << " | "
458                    << "Y: " << tested->GetFile()->GetYSize() << " # " 
459                    << reference->GetYSize() << " | "
460                    << "Z: " << tested->GetFile()->GetZSize() << " # " 
461                    << reference->GetZSize() << std::endl;
462          delete reference;
463          delete tested;
464          return 1;
465       }
466
467       // Test the pixel size
468       if (tested->GetFile()->GetPixelSize() != reference->GetScalarSize() ||
469           tested->GetFile()->GetNumberOfScalarComponents() != reference->GetNumberOfComponents())
470       {
471          std::cout << "Failed" << std::endl
472                    << "        Pixel size differs: " << std::endl
473                    << "        Scalar size: " << tested->GetFile()->GetPixelSize() << " # " 
474                    << reference->GetScalarSize() << std::endl
475                    << "        Number of scalar: " << tested->GetFile()->GetNumberOfScalarComponents() << " # " 
476                    << reference->GetNumberOfComponents() << std::endl;
477          delete reference;
478          delete tested;
479          return 1;
480       }
481
482       // Test the data size
483       if (testedDataSize != referenceDataSize)
484       {
485          std::cout << " Failed" << std::endl
486                    << "        pixel ("
487                    << PixelType
488                    <<") areas lengths differ: "
489                    << testedDataSize << " # " << referenceDataSize
490                    << std::endl
491                    << "        Image size: ("
492                    << tested->GetFile()->GetXSize() << ","
493                    << tested->GetFile()->GetYSize() << ","
494                    << tested->GetFile()->GetZSize() << ")"
495                    << std::endl;
496          delete tested;
497          delete reference;
498          return 1;
499       }
500
501       // Test the data content
502       if (int res = memcmp(testedImageData, referenceImageData,
503                            testedDataSize) != 0 )
504       {
505          (void)res;
506          std::cout << " Failed" << std::endl
507                    << "        pixel (" 
508                    << PixelType
509                    << ") differ (as expanded in memory)."
510                    << std::endl;
511          delete tested;
512          delete reference;
513          return 1;
514       }
515
516       //////////////// Clean up:
517       delete tested;
518       delete reference;
519
520       std::cout << "OK." << std::endl;
521       
522       return 0;
523 }
524
525 int TestAllReadCompareDicom(int argc, char *argv[]) 
526 {
527    if ( argc == 3 )
528    {
529       // The test is specified a specific filename, use it instead of looping
530       // over all images
531       const std::string input = argv[1];
532       const std::string reference = argv[2];
533       return InternalTest( input, reference );
534    }
535    else if ( argc > 3 || argc == 2 )
536    {
537       std::cerr << "   Usage: " << argv[0]
538                 << " (no arguments needed)." << std::endl;
539       std::cerr << "or   Usage: " << argv[0]
540                 << " filename.dcm reference.dcm" << std::endl;
541       return 1;
542    }
543    // else other cases:
544    
545    std::cout << "   Description (Test::TestAllReadCompareDicom): "
546              << std::endl;
547    std::cout << "   For all images in gdcmData (and not blacklisted in "
548                 "Test/CMakeLists.txt)"
549              << std::endl;
550    std::cout << "   apply the following to each filename.xxx: "
551              << std::endl;
552    std::cout << "   step 1: parse the image (as gdcmFile) and call"
553              << " IsReadable(). "
554              << std::endl;
555    std::cout << "   step 2: find in GDCM_DATA_ROOT/BaselineDicom/filename.dcm"
556              << std::endl
557              << "           (with format DICOM V3, explicit Value"
558              << "Representation)"
559              << std::endl;
560    std::cout << "   step 3a: when image NOT found on step 2, write "
561              << std::endl
562              << "            GDCM_DATA_ROOT/BaselineDicom/filename.dcm"
563              << std::endl
564              << "           (with format DICOM V3, explicit Value"
565              << "Representation)"
566              << std::endl;
567    std::cout << "   step 3b: when image found on step 2, and when IsReadable()"
568              << std::endl
569              << "            compare it (in memory with memcmp) with the"
570              << std::endl
571              << "            image we are testing (the one of step 1). "
572              << std::endl << std::endl;
573
574    int i = 0;
575    int result = 0;
576    while( gdcmDataImages[i] != 0 )
577    {
578       ////// Check for existence of reference baseline directory
579
580       std::string baseLineDir = GDCM_DATA_ROOT;
581       baseLineDir += "/BaselineDicom";
582
583       if( !gdcm::DirList::IsDirectory(baseLineDir) )
584       {
585          std::cerr << "   The reference baseline directory " << std::endl
586                    << "      "
587                    << baseLineDir << std::endl
588                    << "   couldn't be opened."
589                    << std::endl;
590          return 1;
591       }
592
593       ////// Step 1 (see above description):
594       std::string filename = GDCM_DATA_ROOT;
595       filename += "/";
596       filename += gdcmDataImages[i];
597       
598       baseLineDir += '/';
599       std::string referenceFileName = baseLineDir + gdcmDataImages[i++];
600       std::string::size_type slash_pos = referenceFileName.rfind( "." );
601       if( slash_pos != std::string::npos )
602       {
603          referenceFileName.replace( slash_pos + 1, 3, "tst" );
604       }
605
606       if( InternalTest( filename, referenceFileName ) != 0 )
607       {
608          result++;
609       }
610    }
611
612    return result;
613 }