1 /*=========================================================================
2 
3   Program: GDCM (Grassroots DICOM). A DICOM library
4 
5   Copyright (c) 2006-2011 Mathieu Malaterre
6   All rights reserved.
7   See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details.
8 
9      This software is distributed WITHOUT ANY WARRANTY; without even
10      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
11      PURPOSE.  See the above copyright notice for more information.
12 
13 =========================================================================*/
14 /*
15  * HISTORY:
16  * In GDCM 1.X the preferred term was 'ReWrite', however one author of GDCM dislike
17  * the term ReWrite since it is associated with the highly associated with the Rewrite
18  * notion in software programming where using reinvent the wheel and rewrite from scratch code
19  * the term convert was preferred
20  *
21  * Tools to conv. Goals being to 'purify' a DICOM file.
22  * For now it will do the minimum:
23  * - If Group Length is present, the length is guarantee to be correct
24  * - If Element with Group Tag 0x1, 0x3, 0x5 or 0x7 are present they are
25  *   simply discarded (not written).
26  * - Elements are written in alphabetical order
27  * - 32bits VR have the residue bytes sets to 0x0,0x0
28  * - Same goes from Item Length end delimiter, sets to 0x0,0x0
29  * - All buggy files (wrong length: GE, 13 and Siemens Leonardo) are fixed
30  * - All size are even (no odd length from gdcm 1.x)
31  *
32  * // \todo:
33  * // --preamble: clean preamble
34  * // --meta: clean meta (meta info version...)
35  * // --dicomV3 (use TS unless not supported)
36  * // --recompute group-length
37  * // --undefined sq
38  * // --explicit sq *
39  * \todo in a close future:
40  * - Set appropriate VR from DICOM dict
41  * - Rewrite PMS SQ into DICOM SQ
42  * - Rewrite Implicit SQ with defined length as undefined length
43  * - PixelData with `overlay` in unused bits should be cleanup
44  * - Any broken JPEG file (wrong bits) should be fixed
45  * - DicomObject bug should be fixed
46  * - Meta and Dataset should have a matching UID (more generally File Meta
47  *   should be correct (Explicit!) and consistent with DataSet)
48  * - User should be able to specify he wants Group Length (or remove them)
49  * - Media SOP should be correct (deduct from something else or set to
50  *   SOP Secondary if all else fail).
51  * - Padding character should be correct
52  *
53  * \todo distant future:
54  * - Later on, it should run through a Validator
55  *   which will make sure all field 1, 1C are present and those only
56  * - In a perfect world I should remove private tags and transform them into
57  *   public fields.
58  * - DA should be correct, PN should be correct (no space!)
59  * - Enumerated Value should be correct
60  */
61 /*
62  check-meta is ideal for image like:
63 
64   gdcmconv -C gdcmData/PICKER-16-MONO2-No_DicomV3_Preamble.dcm bla.dcm
65 */
66 #include "gdcmReader.h"
67 #include "gdcmFileDerivation.h"
68 #include "gdcmAnonymizer.h"
69 #include "gdcmVersion.h"
70 #include "gdcmPixmapReader.h"
71 #include "gdcmPixmapWriter.h"
72 #include "gdcmWriter.h"
73 #include "gdcmSystem.h"
74 #include "gdcmFileMetaInformation.h"
75 #include "gdcmDataSet.h"
76 #include "gdcmIconImageGenerator.h"
77 #include "gdcmAttribute.h"
78 #include "gdcmSequenceOfItems.h"
79 #include "gdcmUIDGenerator.h"
80 #include "gdcmImage.h"
81 #include "gdcmImageChangeTransferSyntax.h"
82 #include "gdcmImageApplyLookupTable.h"
83 #include "gdcmFileDecompressLookupTable.h"
84 #include "gdcmImageFragmentSplitter.h"
85 #include "gdcmImageChangePlanarConfiguration.h"
86 #include "gdcmImageChangePhotometricInterpretation.h"
87 #include "gdcmFileExplicitFilter.h"
88 #include "gdcmJPEG2000Codec.h"
89 #include "gdcmJPEGCodec.h"
90 #include "gdcmJPEGLSCodec.h"
91 #include "gdcmSequenceOfFragments.h"
92 
93 #include <string>
94 #include <iostream>
95 
96 #include <stdio.h>     /* for printf */
97 #include <stdlib.h>    /* for exit */
98 #include <getopt.h>
99 #include <string.h>
100 
101 struct SetSQToUndefined
102 {
operator ()SetSQToUndefined103   void operator() (gdcm::DataElement &de) {
104     de.SetVLToUndefined();
105   }
106 };
107 
PrintVersion()108 static void PrintVersion()
109 {
110   std::cout << "gdcmconv: gdcm " << gdcm::Version::GetVersion() << " ";
111   const char date[] = "$Date$";
112   std::cout << date << std::endl;
113 }
114 
PrintLossyWarning()115 static void PrintLossyWarning()
116 {
117   std::cout << "You have selected a lossy compression transfer syntax." << std::endl;
118   std::cout << "This will degrade the quality of your input image, and can." << std::endl;
119   std::cout << "impact professional interpretation of the image." << std::endl;
120   std::cout << "Do not use if you do not understand the risk." << std::endl;
121   std::cout << "WARNING: this mode is very experimental." << std::endl;
122 }
123 
PrintHelp()124 static void PrintHelp()
125 {
126   PrintVersion();
127   std::cout << "Usage: gdcmconv [OPTION] input.dcm output.dcm" << std::endl;
128   std::cout << "Convert a DICOM file into another DICOM file.\n";
129   std::cout << "Parameter (required):" << std::endl;
130   std::cout << "  -i --input      DICOM filename" << std::endl;
131   std::cout << "  -o --output     DICOM filename" << std::endl;
132   std::cout << "Options:" << std::endl;
133   std::cout << "  -X --explicit            Change Transfer Syntax to explicit." << std::endl;
134   std::cout << "  -M --implicit            Change Transfer Syntax to implicit." << std::endl;
135   std::cout << "  -U --use-dict            Use dict for VR (only public by default)." << std::endl;
136   std::cout << "     --with-private-dict   Use private dict for VR (advanced user only)." << std::endl;
137   std::cout << "  -C --check-meta          Check File Meta Information (advanced user only)." << std::endl;
138   std::cout << "     --root-uid            Root UID." << std::endl;
139   std::cout << "     --remove-gl           Remove group length (deprecated in DICOM 2008)." << std::endl;
140   std::cout << "     --remove-private-tags Remove private tags." << std::endl;
141   std::cout << "     --remove-retired      Remove retired tags." << std::endl;
142   std::cout << "Image only Options:" << std::endl;
143   std::cout << "  -l --apply-lut                      Apply LUT (non-standard, advanced user only)." << std::endl;
144   std::cout << "  -8 --apply-lut8                     Apply LUT/RGB8 (non-standard, advanced user only)." << std::endl;
145   std::cout << "     --decompress-lut                 Decompress LUT (linearize segmented LUT)." << std::endl;
146   std::cout << "  -P --photometric-interpretation %s  Change Photometric Interpretation (when possible)." << std::endl;
147   std::cout << "  -w --raw                            Decompress image." << std::endl;
148   std::cout << "  -d --deflated                       Compress using deflated (gzip)." << std::endl;
149   std::cout << "  -J --jpeg                           Compress image in jpeg." << std::endl;
150   std::cout << "  -K --j2k                            Compress image in j2k." << std::endl;
151   std::cout << "  -L --jpegls                         Compress image in jpeg-ls." << std::endl;
152   std::cout << "  -R --rle                            Compress image in rle (lossless only)." << std::endl;
153   std::cout << "  -F --force                          Force decompression/merging before recompression/splitting." << std::endl;
154   std::cout << "     --generate-icon                  Generate icon." << std::endl;
155   std::cout << "     --icon-minmax %d,%d              Min/Max value for icon." << std::endl;
156   std::cout << "     --icon-auto-minmax               Automatically compute best Min/Max values for icon." << std::endl;
157   std::cout << "     --compress-icon                  Decide whether icon follows main TransferSyntax or remains uncompressed." << std::endl;
158   std::cout << "     --planar-configuration [01]      Change planar configuration." << std::endl;
159   std::cout << "  -Y --lossy                          Use the lossy (if possible) compressor." << std::endl;
160   std::cout << "  -S --split %d                       Write 2D image with multiple fragments (using max size)" << std::endl;
161   std::cout << "General Options:" << std::endl;
162   std::cout << "  -V --verbose    more verbose (warning+error)." << std::endl;
163   std::cout << "  -W --warning    print warning info." << std::endl;
164   std::cout << "  -D --debug      print debug info." << std::endl;
165   std::cout << "  -E --error      print error info." << std::endl;
166   std::cout << "  -h --help       print help." << std::endl;
167   std::cout << "  -v --version    print version." << std::endl;
168   std::cout << "     --quiet      do not print to stdout." << std::endl;
169   std::cout << "JPEG Options:" << std::endl;
170   std::cout << "  -q --quality %*f           set quality." << std::endl;
171   std::cout << "JPEG-LS Options:" << std::endl;
172   std::cout << "  -e --allowed-error %*i             set allowed error." << std::endl;
173   std::cout << "J2K Options:" << std::endl;
174   std::cout << "  -r --rate    %*f           set rate." << std::endl;
175   std::cout << "  -q --quality %*f           set quality." << std::endl;
176   std::cout << "  -t --tile %d,%d            set tile size." << std::endl;
177   std::cout << "  -n --number-resolution %d  set number of resolution." << std::endl;
178   std::cout << "     --irreversible          set irreversible." << std::endl;
179   std::cout << "Special Options:" << std::endl;
180   std::cout << "  -I --ignore-errors   convert even if file is corrupted (advanced users only, see disclaimers)." << std::endl;
181   std::cout << "Env var:" << std::endl;
182   std::cout << "  GDCM_ROOT_UID Root UID" << std::endl;
183 /*
184  * Default behavior for root UID is:
185  * By default the GDCM one is used
186  * If GDCM_ROOT_UID is set, then use this one instead
187  * If --root-uid is explicitly set on the command line, it will override any other defined behavior
188  */
189 }
190 
191 template <typename T>
readvector(std::vector<T> & v,const char * str)192 static size_t readvector(std::vector<T> &v, const char *str)
193 {
194   if( !str ) return 0;
195   std::istringstream os( str );
196   T f;
197   while( os >> f )
198     {
199     v.push_back( f );
200     os.get(); //  == ","
201     }
202   return v.size();
203 }
204 
205 namespace gdcm
206 {
derives(File & file,const Pixmap & compressed_image)207 static bool derives( File & file, const Pixmap& compressed_image )
208 {
209 #if 1
210   DataSet &ds = file.GetDataSet();
211 
212   if( !ds.FindDataElement( Tag(0x0008,0x0016) )
213     || ds.GetDataElement( Tag(0x0008,0x0016) ).IsEmpty() )
214     {
215     return false;
216     }
217   if( !ds.FindDataElement( Tag(0x0008,0x0018) )
218     || ds.GetDataElement( Tag(0x0008,0x0018) ).IsEmpty() )
219     {
220     return false;
221     }
222   const DataElement &sopclassuid = ds.GetDataElement( Tag(0x0008,0x0016) );
223   const DataElement &sopinstanceuid = ds.GetDataElement( Tag(0x0008,0x0018) );
224   // Make sure that const char* pointer will be properly padded with \0 char:
225   std::string sopclassuid_str( sopclassuid.GetByteValue()->GetPointer(), sopclassuid.GetByteValue()->GetLength() );
226   std::string sopinstanceuid_str( sopinstanceuid.GetByteValue()->GetPointer(), sopinstanceuid.GetByteValue()->GetLength() );
227   ds.Remove( Tag(0x8,0x18) );
228 
229   FileDerivation fd;
230   fd.SetFile( file );
231   fd.AddReference( sopclassuid_str.c_str(), sopinstanceuid_str.c_str() );
232 
233   // CID 7202 Source Image Purposes of Reference
234   // {"DCM",121320,"Uncompressed predecessor"},
235   fd.SetPurposeOfReferenceCodeSequenceCodeValue( 121320 );
236 
237   // CID 7203 Image Derivation
238   // { "DCM",113040,"Lossy Compression" },
239   fd.SetDerivationCodeSequenceCodeValue( 113040 );
240   fd.SetDerivationDescription( "lossy conversion" );
241   if( !fd.Derive() )
242     {
243     std::cerr << "Sorry could not derive using input info" << std::endl;
244     return false;
245     }
246 
247 
248 #else
249 /*
250 (0008,2111) ST [Lossy compression with JPEG extended sequential 8 bit, IJG quality... # 102, 1 DerivationDescription
251 (0008,2112) SQ (Sequence with explicit length #=1)      # 188, 1 SourceImageSequence
252   (fffe,e000) na (Item with explicit length #=3)          # 180, 1 Item
253     (0008,1150) UI =UltrasoundImageStorage                  #  28, 1 ReferencedSOPClassUID
254     (0008,1155) UI [1.2.840.1136190195280574824680000700.3.0.1.19970424140438] #  58, 1 ReferencedSOPInstanceUID
255     (0040,a170) SQ (Sequence with explicit length #=1)      #  66, 1 PurposeOfReferenceCodeSequence
256       (fffe,e000) na (Item with explicit length #=3)          #  58, 1 Item
257         (0008,0100) SH [121320]                                 #   6, 1 CodeValue
258         (0008,0102) SH [DCM]                                    #   4, 1 CodingSchemeDesignator
259         (0008,0104) LO [Uncompressed predecessor]               #  24, 1 CodeMeaning
260       (fffe,e00d) na (ItemDelimitationItem for re-encoding)   #   0, 0 ItemDelimitationItem
261     (fffe,e0dd) na (SequenceDelimitationItem for re-encod.) #   0, 0 SequenceDelimitationItem
262   (fffe,e00d) na (ItemDelimitationItem for re-encoding)   #   0, 0 ItemDelimitationItem
263 (fffe,e0dd) na (SequenceDelimitationItem for re-encod.) #   0, 0 SequenceDelimitationItem
264 */
265     const Tag sisq(0x8,0x2112);
266     SequenceOfItems * sqi;
267       sqi = new SequenceOfItems;
268       DataElement de( sisq);
269       de.SetVR( VR::SQ );
270       de.SetValue( *sqi );
271       de.SetVLToUndefined();
272 
273   DataSet &ds = file.GetDataSet();
274       ds.Insert( de );
275 {
276     // (0008,0008) CS [ORIGINAL\SECONDARY]                     #  18, 2 ImageType
277     gdcm::Attribute<0x0008,0x0008> at3;
278     static const gdcm::CSComp values[] = {"DERIVED","SECONDARY"};
279     at3.SetValues( values, 2, true ); // true => copy data !
280     if( ds.FindDataElement( at3.GetTag() ) )
281       {
282       const gdcm::DataElement &de = ds.GetDataElement( at3.GetTag() );
283       at3.SetFromDataElement( de );
284       // Make sure that value #1 is at least 'DERIVED', so override in all cases:
285       at3.SetValue( 0, values[0] );
286       }
287     ds.Replace( at3.GetAsDataElement() );
288 
289 }
290 {
291     Attribute<0x0008,0x2111> at1;
292     at1.SetValue( "lossy conversion" );
293     ds.Replace( at1.GetAsDataElement() );
294 }
295 
296     sqi = (SequenceOfItems*)ds.GetDataElement( sisq ).GetSequenceOfItems();
297     sqi->SetLengthToUndefined();
298 
299     if( !sqi->GetNumberOfItems() )
300       {
301       Item item; //( Tag(0xfffe,0xe000) );
302       item.SetVLToUndefined();
303       sqi->AddItem( item );
304       }
305 
306     Item &item1 = sqi->GetItem(1);
307     DataSet &subds = item1.GetNestedDataSet();
308 /*
309     (0008,1150) UI =UltrasoundImageStorage                  #  28, 1 ReferencedSOPClassUID
310     (0008,1155) UI [1.2.840.1136190195280574824680000700.3.0.1.19970424140438] #  58, 1 ReferencedSOPInstanceUID
311 */
312 {
313     DataElement sopinstanceuid = ds.GetDataElement( Tag(0x0008,0x0016) );
314     sopinstanceuid.SetTag( Tag(0x8,0x1150 ) );
315     subds.Replace( sopinstanceuid );
316     DataElement sopclassuid = ds.GetDataElement( Tag(0x0008,0x0018) );
317     sopclassuid.SetTag( Tag(0x8,0x1155 ) );
318     subds.Replace( sopclassuid );
319     ds.Remove( Tag(0x8,0x18) );
320 }
321 
322     const Tag prcs(0x0040,0xa170);
323     if( !subds.FindDataElement( prcs) )
324       {
325       SequenceOfItems *sqi2 = new SequenceOfItems;
326       DataElement de( prcs );
327       de.SetVR( VR::SQ );
328       de.SetValue( *sqi2 );
329       de.SetVLToUndefined();
330       subds.Insert( de );
331       }
332 
333     sqi = (SequenceOfItems*)subds.GetDataElement( prcs ).GetSequenceOfItems();
334     sqi->SetLengthToUndefined();
335 
336     if( !sqi->GetNumberOfItems() )
337       {
338       Item item; //( Tag(0xfffe,0xe000) );
339       item.SetVLToUndefined();
340       sqi->AddItem( item );
341       }
342     Item &item2 = sqi->GetItem(1);
343     DataSet &subds2 = item2.GetNestedDataSet();
344 
345 /*
346         (0008,0100) SH [121320]                                 #   6, 1 CodeValue
347         (0008,0102) SH [DCM]                                    #   4, 1 CodingSchemeDesignator
348         (0008,0104) LO [Uncompressed predecessor]               #  24, 1 CodeMeaning
349 */
350 
351     Attribute<0x0008,0x0100> at1;
352     at1.SetValue( "121320" );
353     subds2.Replace( at1.GetAsDataElement() );
354     Attribute<0x0008,0x0102> at2;
355     at2.SetValue( "DCM" );
356     subds2.Replace( at2.GetAsDataElement() );
357     Attribute<0x0008,0x0104> at3;
358     at3.SetValue( "Uncompressed predecessor" );
359     subds2.Replace( at3.GetAsDataElement() );
360 
361 /*
362 (0008,9215) SQ (Sequence with explicit length #=1)      #  98, 1 DerivationCodeSequence
363   (fffe,e000) na (Item with explicit length #=3)          #  90, 1 Item
364     (0008,0100) SH [121327]                                 #   6, 1 CodeValue
365     (0008,0102) SH [DCM]                                    #   4, 1 CodingSchemeDesignator
366     (0008,0104) LO [Full fidelity image, uncompressed or lossless compressed] #  56, 1 CodeMeaning
367   (fffe,e00d) na (ItemDelimitationItem for re-encoding)   #   0, 0 ItemDelimitationItem
368 (fffe,e0dd) na (SequenceDelimitationItem for re-encod.) #   0, 0 SequenceDelimitationItem
369 */
370 {
371     const Tag sisq(0x8,0x9215);
372     SequenceOfItems * sqi;
373       sqi = new SequenceOfItems;
374       DataElement de( sisq );
375       de.SetVR( VR::SQ );
376       de.SetValue( *sqi );
377       de.SetVLToUndefined();
378       ds.Insert( de );
379     sqi = (SequenceOfItems*)ds.GetDataElement( sisq ).GetSequenceOfItems();
380     sqi->SetLengthToUndefined();
381 
382     if( !sqi->GetNumberOfItems() )
383       {
384       Item item; //( Tag(0xfffe,0xe000) );
385       item.SetVLToUndefined();
386       sqi->AddItem( item );
387       }
388 
389     Item &item1 = sqi->GetItem(1);
390     DataSet &subds3 = item1.GetNestedDataSet();
391 
392     Attribute<0x0008,0x0100> at1;
393     at1.SetValue( "121327" );
394     subds3.Replace( at1.GetAsDataElement() );
395     Attribute<0x0008,0x0102> at2;
396     at2.SetValue( "DCM" );
397     subds3.Replace( at2.GetAsDataElement() );
398     Attribute<0x0008,0x0104> at3;
399     at3.SetValue( "Full fidelity image, uncompressed or lossless compressed" );
400     subds3.Replace( at3.GetAsDataElement() );
401 }
402 #endif
403 
404 {
405   /*
406   (0028,2110) CS [01]                                     #   2, 1 LossyImageCompression
407   (0028,2112) DS [15.95]                                  #   6, 1 LossyImageCompressionRatio
408   (0028,2114) CS [ISO_10918_1]                            #  12, 1 LossyImageCompressionMethod
409    */
410   const DataElement & pixeldata = compressed_image.GetDataElement();
411   size_t len = pixeldata.GetSequenceOfFragments()->ComputeByteLength();
412   size_t reflen = compressed_image.GetBufferLength();
413   double ratio = (double)reflen / (double)len;
414   Attribute<0x0028,0x2110> at1;
415   at1.SetValue( "01" );
416   ds.Replace( at1.GetAsDataElement() );
417   Attribute<0x0028,0x2112> at2;
418   at2.SetValues( &ratio, 1);
419   ds.Replace( at2.GetAsDataElement() );
420   Attribute<0x0028,0x2114> at3;
421 
422   // ImageWriter will properly set attribute 0028,2114 (Lossy Image Compression Method)
423 }
424 
425 return true;
426 
427 }
428 } // end namespace gdcm
429 
main(int argc,char * argv[])430 int main (int argc, char *argv[])
431 {
432   int c;
433   //int digit_optind = 0;
434 
435   std::string filename;
436   std::string outfilename;
437   std::string root;
438   int explicitts = 0; // explicit is a reserved keyword
439   int implicit = 0;
440   int quiet = 0;
441   int lut = 0;
442   int lut8 = 0;
443   int decompress_lut = 0;
444   int raw = 0;
445   int deflated = 0;
446   int rootuid = 0;
447   int checkmeta = 0;
448   int jpeg = 0;
449   int jpegls = 0;
450   int j2k = 0;
451   int lossy = 0;
452   int split = 0;
453   int fragmentsize = 0;
454   int rle = 0;
455   int force = 0;
456   int planarconf = 0;
457   int planarconfval = 0;
458   double iconmin = 0;
459   double iconmax = 0;
460   int usedict = 0;
461   int compressicon = 0;
462   int generateicon = 0;
463   int iconminmax = 0;
464   int iconautominmax = 0;
465   int removegrouplength = 0;
466   int removeprivate = 0;
467   int removeretired = 0;
468   int photometricinterpretation = 0;
469   std::string photometricinterpretation_str;
470   int quality = 0;
471   int rate = 0;
472   int tile = 0;
473   int nres = 0;
474   int nresvalue = 6; // ??
475   std::vector<float> qualities;
476   std::vector<float> rates;
477   std::vector<unsigned int> tilesize;
478   int irreversible = 0;
479   int changeprivatetags = 0;
480 
481   int verbose = 0;
482   int warning = 0;
483   int debug = 0;
484   int error = 0;
485   int help = 0;
486   int version = 0;
487   int ignoreerrors = 0;
488   int jpeglserror = 0;
489   int jpeglserror_value = 0;
490 
491   while (true) {
492     //int this_option_optind = optind ? optind : 1;
493     int option_index = 0;
494     static struct option long_options[] = {
495         {"input", 1, nullptr, 0},
496         {"output", 1, nullptr, 0},
497         {"group-length", 1, nullptr, 0}, // valid / create / remove
498         {"preamble", 1, nullptr, 0}, // valid / create / remove
499         {"padding", 1, nullptr, 0}, // valid (\0 -> space) / optimize (at most 1 byte of padding)
500         {"vr", 1, nullptr, 0}, // valid
501         {"sop", 1, nullptr, 0}, // default to SC...
502         {"iod", 1, nullptr, 0}, // valid
503         {"meta", 1, nullptr, 0}, // valid / create / remove
504         {"dataset", 1, nullptr, 0}, // valid / create / remove?
505         {"sequence", 1, nullptr, 0}, // defined / undefined
506         {"deflate", 1, nullptr, 0}, // 1 - 9 / best = 9 / fast = 1
507         {"tag", 1, nullptr, 0}, // need to specify a tag xxxx,yyyy = value to override default
508         {"name", 1, nullptr, 0}, // same as tag but explicit use of name
509         {"root-uid", 1, &rootuid, 1}, // specific Root (not GDCM)
510         {"check-meta", 0, &checkmeta, 1}, // specific Root (not GDCM)
511 // Image specific options:
512         {"pixeldata", 1, nullptr, 0}, // valid
513         {"apply-lut", 0, &lut, 1}, // default (implicit VR, LE) / Explicit LE / Explicit BE
514         {"raw", 0, &raw, 1}, // default (implicit VR, LE) / Explicit LE / Explicit BE
515         {"deflated", 0, &deflated, 1}, // DeflatedExplicitVRLittleEndian
516         {"lossy", 0, &lossy, 1}, // Specify lossy comp
517         {"force", 0, &force, 1}, // force decompression even if target compression is identical
518         {"jpeg", 0, &jpeg, 1}, // JPEG lossy / lossless
519         {"jpegls", 0, &jpegls, 1}, // JPEG-LS: lossy / lossless
520         {"j2k", 0, &j2k, 1}, // J2K: lossy / lossless
521         {"rle", 0, &rle, 1}, // lossless !
522         {"mpeg2", 0, nullptr, 0}, // lossy !
523         {"jpip", 0, nullptr, 0}, // ??
524         {"split", 1, &split, 1}, // split fragments
525         {"planar-configuration", 1, &planarconf, 1}, // Planar Configuration
526         {"explicit", 0, &explicitts, 1}, //
527         {"implicit", 0, &implicit, 1}, //
528         {"use-dict", 0, &usedict, 1}, //
529         {"generate-icon", 0, &generateicon, 1}, //
530         {"icon-minmax", 1, &iconminmax, 1}, //
531         {"icon-auto-minmax", 0, &iconautominmax, 1}, //
532         {"compress-icon", 0, &compressicon, 1}, //
533         {"remove-gl", 0, &removegrouplength, 1}, //
534         {"remove-private-tags", 0, &removeprivate, 1}, //
535         {"remove-retired", 0, &removeretired, 1}, //
536         {"photometric-interpretation", 1, &photometricinterpretation, 1}, //
537         {"with-private-dict", 0, &changeprivatetags, 1}, //
538         {"decompress-lut", 0, &decompress_lut, 1}, // linearized segmented LUT
539         {"apply-lut8", 0, &lut8, 1},
540 // j2k :
541         {"rate", 1, &rate, 1}, //
542         {"quality", 1, &quality, 1}, // will also work for regular jpeg compressor
543         {"tile", 1, &tile, 1}, //
544         {"number-resolution", 1, &nres, 1}, //
545         {"irreversible", 0, &irreversible, 1}, //
546         {"allowed-error", 1, &jpeglserror, 1}, //
547 
548 // General options !
549         {"verbose", 0, &verbose, 1},
550         {"warning", 0, &warning, 1},
551         {"debug", 0, &debug, 1},
552         {"error", 0, &error, 1},
553         {"help", 0, &help, 1},
554         {"version", 0, &version, 1},
555         {"ignore-errors", 0, &ignoreerrors, 1},
556         {"quiet", 0, &quiet, 1},
557 
558         {nullptr, 0, nullptr, 0}
559     };
560 
561     c = getopt_long (argc, argv, "i:o:XMUCl8wdJKLRFYS:P:VWDEhvIr:q:t:n:e:",
562       long_options, &option_index);
563     if (c == -1)
564       {
565       break;
566       }
567 
568     switch (c)
569       {
570     case 0:
571         {
572         const char *s = long_options[option_index].name; (void)s;
573         //printf ("option %s", s);
574         if (optarg)
575           {
576           if( option_index == 0 ) /* input */
577             {
578             assert( strcmp(s, "input") == 0 );
579             assert( filename.empty() );
580             filename = optarg;
581             }
582           else if( option_index == 14 ) /* root-uid */
583             {
584             assert( strcmp(s, "root-uid") == 0 );
585             assert( root.empty() );
586             root = optarg;
587             }
588           else if( option_index == 28 ) /* split */
589             {
590             assert( strcmp(s, "split") == 0 );
591             fragmentsize = atoi(optarg);
592             }
593           else if( option_index == 29 ) /* planar conf*/
594             {
595             assert( strcmp(s, "planar-configuration") == 0 );
596             planarconfval = atoi(optarg);
597             }
598           else if( option_index == 34 ) /* icon minmax*/
599             {
600             assert( strcmp(s, "icon-minmax") == 0 );
601             std::stringstream ss;
602             ss.str( optarg );
603             ss >> iconmin;
604             char comma;
605             ss >> comma;
606             ss >> iconmax;
607             }
608           else if( option_index == 40 ) /* photometricinterpretation */
609             {
610             assert( strcmp(s, "photometric-interpretation") == 0 );
611             photometricinterpretation_str = optarg;
612             }
613           else if( option_index == 42 ) /* rate */
614             {
615             assert( strcmp(s, "rate") == 0 );
616             readvector(rates, optarg);
617             }
618           else if( option_index == 43 ) /* quality */
619             {
620             assert( strcmp(s, "quality") == 0 );
621             readvector(qualities, optarg);
622             }
623           else if( option_index == 44 ) /* tile */
624             {
625             assert( strcmp(s, "tile") == 0 );
626             size_t n = readvector(tilesize, optarg);
627             assert( n == 2 ); (void)n;
628             }
629           else if( option_index == 45 ) /* number of resolution */
630             {
631             assert( strcmp(s, "number-resolution") == 0 );
632             nresvalue = atoi(optarg);
633             }
634           else if( option_index == 47 ) /* JPEG-LS error */
635             {
636             assert( strcmp(s, "allowed-error") == 0 );
637             jpeglserror_value = atoi(optarg);
638             }
639           //printf (" with arg %s, index = %d", optarg, option_index);
640           }
641         //printf ("\n");
642         }
643       break;
644 
645     case 'i':
646       //printf ("option i with value '%s'\n", optarg);
647       assert( filename.empty() );
648       filename = optarg;
649       break;
650 
651     case 'o':
652       //printf ("option o with value '%s'\n", optarg);
653       assert( outfilename.empty() );
654       outfilename = optarg;
655       break;
656 
657     case 'X':
658       explicitts = 1;
659       break;
660 
661     case 'M':
662       implicit = 1;
663       break;
664 
665     case 'U':
666       usedict = 1;
667       break;
668 
669     case 'C':
670       checkmeta = 1;
671       break;
672 
673     // root-uid
674 
675     case 'l':
676       lut = 1;
677       break;
678 
679     case '8':
680       lut8 = 1;
681       break;
682 
683 
684     case 'w':
685       raw = 1;
686       break;
687 
688     case 'e':
689       jpeglserror = 1;
690       jpeglserror_value = atoi(optarg);
691       break;
692 
693     case 'd':
694       deflated = 1;
695       break;
696 
697     case 'J':
698       jpeg = 1;
699       break;
700 
701     case 'K':
702       j2k = 1;
703       break;
704 
705     case 'L':
706       jpegls = 1;
707       break;
708 
709     case 'R':
710       rle = 1;
711       break;
712 
713     case 'F':
714       force = 1;
715       break;
716 
717     case 'Y':
718       lossy = 1;
719       break;
720 
721     case 'S':
722       split = 1;
723       fragmentsize = atoi(optarg);
724       break;
725 
726     case 'P':
727       photometricinterpretation = 1;
728       photometricinterpretation_str = optarg;
729       break;
730 
731     case 'r':
732       rate = 1;
733       readvector(rates, optarg);
734       break;
735 
736     case 'q':
737       quality = 1;
738       readvector(qualities, optarg);
739       break;
740 
741     case 't':
742       tile = 1;
743       readvector(tilesize, optarg);
744       break;
745 
746     case 'n':
747       nres = 1;
748       nresvalue = atoi(optarg);
749       break;
750 
751     // General option
752     case 'V':
753       verbose = 1;
754       break;
755 
756     case 'W':
757       warning = 1;
758       break;
759 
760     case 'D':
761       debug = 1;
762       break;
763 
764     case 'E':
765       error = 1;
766       break;
767 
768     case 'h':
769       help = 1;
770       break;
771 
772     case 'v':
773       version = 1;
774       break;
775 
776     case 'I':
777       ignoreerrors = 1;
778       break;
779 
780     case '?':
781       break;
782 
783     default:
784       printf ("?? getopt returned character code 0%o ??\n", c);
785       }
786   }
787 
788   // For now only support one input / one output
789   if (optind < argc)
790     {
791     //printf ("non-option ARGV-elements: ");
792     std::vector<std::string> files;
793     while (optind < argc)
794       {
795       //printf ("%s\n", argv[optind++]);
796       files.emplace_back(argv[optind++] );
797       }
798     //printf ("\n");
799     if( files.size() == 2
800       && filename.empty()
801       && outfilename.empty()
802     )
803       {
804       filename = files[0];
805       outfilename = files[1];
806       }
807     else
808       {
809       PrintHelp();
810       return 1;
811       }
812     }
813 
814   if( version )
815     {
816     //std::cout << "version" << std::endl;
817     PrintVersion();
818     return 0;
819     }
820 
821   if( help )
822     {
823     //std::cout << "help" << std::endl;
824     PrintHelp();
825     return 0;
826     }
827 
828   if( filename.empty() )
829     {
830     //std::cerr << "Need input file (-i)\n";
831     PrintHelp();
832     return 1;
833     }
834   if( outfilename.empty() )
835     {
836     //std::cerr << "Need output file (-o)\n";
837     PrintHelp();
838     return 1;
839     }
840 
841   // Debug is a little too verbose
842   gdcm::Trace::SetDebug( (debug  > 0 ? true : false));
843   gdcm::Trace::SetWarning(  (warning  > 0 ? true : false));
844   gdcm::Trace::SetError(  (error  > 0 ? true : false));
845   // when verbose is true, make sure warning+error are turned on:
846   if( verbose )
847     {
848     gdcm::Trace::SetWarning( (verbose  > 0 ? true : false) );
849     gdcm::Trace::SetError( (verbose  > 0 ? true : false) );
850     }
851 
852   gdcm::FileMetaInformation::SetSourceApplicationEntityTitle( "gdcmconv" );
853   if( !rootuid )
854     {
855     // only read the env var is no explicit cmd line option
856     // maybe there is an env var defined... let's check
857     const char *rootuid_env = getenv("GDCM_ROOT_UID");
858     if( rootuid_env )
859       {
860       rootuid = 1;
861       root = rootuid_env;
862       }
863     }
864   if( rootuid )
865     {
866     // root is set either by the cmd line option or the env var
867     if( !gdcm::UIDGenerator::IsValid( root.c_str() ) )
868       {
869       std::cerr << "specified Root UID is not valid: " << root << std::endl;
870       return 1;
871       }
872     gdcm::UIDGenerator::SetRoot( root.c_str() );
873     }
874 
875   if( removegrouplength || removeprivate || removeretired )
876     {
877     gdcm::Reader reader;
878     reader.SetFileName( filename.c_str() );
879     if( !reader.Read() )
880       {
881       std::cerr << "Could not read: " << filename << std::endl;
882       return 1;
883       }
884     gdcm::MediaStorage ms;
885     ms.SetFromFile( reader.GetFile() );
886     if( ms == gdcm::MediaStorage::MediaStorageDirectoryStorage )
887       {
888       std::cerr << "Sorry DICOMDIR is not supported" << std::endl;
889       return 1;
890       }
891 
892     gdcm::Anonymizer ano;
893     ano.SetFile( reader.GetFile() );
894     if( removegrouplength )
895       {
896       if( !ano.RemoveGroupLength() )
897         {
898         std::cerr << "Could not remove group length" << std::endl;
899         }
900       }
901     if( removeretired )
902       {
903       if( !ano.RemoveRetired() )
904         {
905         std::cerr << "Could not remove retired tags" << std::endl;
906         }
907       }
908     if( removeprivate )
909       {
910       if( !ano.RemovePrivateTags() )
911         {
912         std::cerr << "Could not remove private tags" << std::endl;
913         }
914       }
915 
916     gdcm::Writer writer;
917     writer.SetFileName( outfilename.c_str() );
918     writer.SetFile( ano.GetFile() );
919     if( !writer.Write() )
920       {
921       std::cerr << "Failed to write: " << outfilename << std::endl;
922       return 1;
923       }
924 
925     return 0;
926     }
927 
928   // Handle here the general file (not required to be image)
929   if ( !raw && (explicitts || implicit || deflated) )
930     {
931     if( explicitts && implicit ) return 1; // guard
932     if( explicitts && deflated ) return 1; // guard
933     if( implicit && deflated ) return 1; // guard
934     gdcm::Reader reader;
935     reader.SetFileName( filename.c_str() );
936     if( !reader.Read() )
937       {
938       std::cerr << "Could not read: " << filename << std::endl;
939       return 1;
940       }
941     gdcm::MediaStorage ms;
942     ms.SetFromFile( reader.GetFile() );
943     if( ms == gdcm::MediaStorage::MediaStorageDirectoryStorage )
944       {
945       std::cerr << "Sorry DICOMDIR is not supported" << std::endl;
946       return 1;
947       }
948 
949     gdcm::Writer writer;
950     writer.SetFileName( outfilename.c_str() );
951     writer.SetFile( reader.GetFile() );
952     gdcm::File & file = writer.GetFile();
953     gdcm::FileMetaInformation &fmi = file.GetHeader();
954 
955     const gdcm::TransferSyntax &orits = fmi.GetDataSetTransferSyntax();
956     if( orits != gdcm::TransferSyntax::ExplicitVRLittleEndian
957       && orits != gdcm::TransferSyntax::ImplicitVRLittleEndian
958       && orits != gdcm::TransferSyntax::DeflatedExplicitVRLittleEndian )
959       {
960       std::cerr << "Sorry input Transfer Syntax not supported for this conversion: " << orits << std::endl;
961       return 1;
962       }
963 
964     gdcm::TransferSyntax ts = gdcm::TransferSyntax::ImplicitVRLittleEndian;
965     if( explicitts )
966       {
967       ts = gdcm::TransferSyntax::ExplicitVRLittleEndian;
968       }
969     else if( deflated )
970       {
971       ts = gdcm::TransferSyntax::DeflatedExplicitVRLittleEndian;
972       }
973     std::string tsuid = gdcm::TransferSyntax::GetTSString( ts );
974     if( tsuid.size() % 2 == 1 )
975       {
976       tsuid.push_back( 0 ); // 0 padding
977       }
978     gdcm::DataElement de( gdcm::Tag(0x0002,0x0010) );
979     de.SetByteValue( &tsuid[0], (uint32_t)tsuid.size() );
980     de.SetVR( gdcm::Attribute<0x0002, 0x0010>::GetVR() );
981     fmi.Clear();
982     fmi.Replace( de );
983 
984     fmi.SetDataSetTransferSyntax(ts);
985 
986     if( explicitts || deflated )
987       {
988       gdcm::FileExplicitFilter fef;
989       fef.SetChangePrivateTags( (changeprivatetags > 0 ? true: false));
990       fef.SetFile( reader.GetFile() );
991       if( !fef.Change() )
992         {
993         std::cerr << "Failed to change: " << filename << std::endl;
994         return 1;
995         }
996       }
997 
998     if( !writer.Write() )
999       {
1000       std::cerr << "Failed to write: " << outfilename << std::endl;
1001       return 1;
1002       }
1003 
1004     return 0;
1005     }
1006 
1007   // split fragments
1008   if( split )
1009     {
1010     gdcm::PixmapReader reader;
1011     reader.SetFileName( filename.c_str() );
1012     if( !reader.Read() )
1013       {
1014       std::cerr << "Could not read (pixmap): " << filename << std::endl;
1015       return 1;
1016       }
1017     const gdcm::Pixmap &image = reader.GetPixmap();
1018 
1019     gdcm::ImageFragmentSplitter splitter;
1020     splitter.SetInput( image );
1021     splitter.SetFragmentSizeMax( fragmentsize );
1022     splitter.SetForce( (force > 0 ? true: false));
1023     bool b = splitter.Split();
1024     if( !b )
1025       {
1026       std::cerr << "Could not split: " << filename << std::endl;
1027       return 1;
1028       }
1029     gdcm::PixmapWriter writer;
1030     writer.SetFileName( outfilename.c_str() );
1031     writer.SetFile( reader.GetFile() );
1032     writer.SetPixmap( splitter.PixmapToPixmapFilter::GetOutput() );
1033     if( !writer.Write() )
1034       {
1035       std::cerr << "Failed to write: " << outfilename << std::endl;
1036       return 1;
1037       }
1038     }
1039   else if( photometricinterpretation )
1040     {
1041     gdcm::PixmapReader reader;
1042     reader.SetFileName( filename.c_str() );
1043     if( !reader.Read() )
1044       {
1045       std::cerr << "Could not read (pixmap): " << filename << std::endl;
1046       return 1;
1047       }
1048     const gdcm::Pixmap &image = reader.GetPixmap();
1049 
1050     // Just in case:
1051     if( gdcm::PhotometricInterpretation::GetPIType(photometricinterpretation_str.c_str())
1052       == gdcm::PhotometricInterpretation::PI_END )
1053       {
1054       std::cerr << "Do not handle PhotometricInterpretation: " << photometricinterpretation_str << std::endl;
1055       return 1;
1056       }
1057     gdcm::PhotometricInterpretation pi (
1058       gdcm::PhotometricInterpretation::GetPIType(photometricinterpretation_str.c_str()) );
1059     gdcm::ImageChangePhotometricInterpretation pifilt;
1060     pifilt.SetInput( image );
1061     pifilt.SetPhotometricInterpretation( pi );
1062     bool b = pifilt.Change();
1063     if( !b )
1064       {
1065       std::cerr << "Could not apply PhotometricInterpretation: " << filename << std::endl;
1066       return 1;
1067       }
1068     gdcm::PixmapWriter writer;
1069     writer.SetFileName( outfilename.c_str() );
1070     writer.SetFile( reader.GetFile() );
1071     writer.SetPixmap( pifilt.PixmapToPixmapFilter::GetOutput() );
1072     if( !writer.Write() )
1073       {
1074       std::cerr << "Failed to write: " << outfilename << std::endl;
1075       return 1;
1076       }
1077     }
1078   else if( decompress_lut )
1079   {
1080     gdcm::PixmapReader reader;
1081     reader.SetFileName( filename.c_str() );
1082     if( !reader.Read() )
1083       {
1084       std::cerr << "Could not read (pixmap): " << filename << std::endl;
1085       return 1;
1086       }
1087     const gdcm::Pixmap &image = reader.GetPixmap();
1088 
1089     gdcm::FileDecompressLookupTable lutfilt;
1090     lutfilt.SetFile( reader.GetFile() );
1091     lutfilt.SetPixmap( image );
1092     bool b = lutfilt.Change();
1093     if( !b )
1094       {
1095       std::cerr << "Could not decompress LUT: " << filename << std::endl;
1096       return 1;
1097       }
1098     gdcm::PixmapWriter writer;
1099     writer.SetFileName( outfilename.c_str() );
1100     writer.SetFile( reader.GetFile() );
1101     writer.SetPixmap( lutfilt.GetPixmap() );
1102     if( !writer.Write() )
1103       {
1104       std::cerr << "Failed to write: " << outfilename << std::endl;
1105       return 1;
1106       }
1107   }
1108   else if( lut || lut8 )
1109     {
1110     gdcm::PixmapReader reader;
1111     reader.SetFileName( filename.c_str() );
1112     if( !reader.Read() )
1113       {
1114       std::cerr << "Could not read (pixmap): " << filename << std::endl;
1115       return 1;
1116       }
1117     const gdcm::Pixmap &image = reader.GetPixmap();
1118 
1119     gdcm::ImageApplyLookupTable lutfilt;
1120     lutfilt.SetInput( image );
1121     lutfilt.SetRGB8( lut8 != 0 );
1122     bool b = lutfilt.Apply();
1123     if( !b )
1124       {
1125       std::cerr << "Could not apply LUT: " << filename << std::endl;
1126       return 1;
1127       }
1128     gdcm::PixmapWriter writer;
1129     writer.SetFileName( outfilename.c_str() );
1130     writer.SetFile( reader.GetFile() );
1131     writer.SetPixmap( lutfilt.PixmapToPixmapFilter::GetOutput() );
1132     if( !writer.Write() )
1133       {
1134       std::cerr << "Failed to write: " << outfilename << std::endl;
1135       return 1;
1136       }
1137     }
1138   else if( jpeg || j2k || jpegls || rle || raw || force /*|| deflated*/ /*|| planarconf*/ )
1139     {
1140     gdcm::PixmapReader reader;
1141     reader.SetFileName( filename.c_str() );
1142     if( !reader.Read() )
1143       {
1144       std::cerr << "Could not read (pixmap): " << filename << std::endl;
1145       return 1;
1146       }
1147     gdcm::Pixmap &image = reader.GetPixmap();
1148     //const gdcm::IconImage &icon = image.GetIconImage();
1149     //if( !icon.IsEmpty() )
1150     //  {
1151     //  std::cerr << "Icons are not supported" << std::endl;
1152     //  return 1;
1153     //  }
1154     if( generateicon )
1155       {
1156       gdcm::IconImageGenerator iig;
1157       iig.SetPixmap( image );
1158       const unsigned int idims[2] = { 64, 64 };
1159       iig.SetOutputDimensions( idims );
1160       if( iconminmax )
1161         {
1162         iig.SetPixelMinMax( iconmin, iconmax );
1163         }
1164       iig.AutoPixelMinMax( iconautominmax ? true : false );
1165       bool b = iig.Generate();
1166       if( !b ) return 1;
1167       const gdcm::IconImage &icon = iig.GetIconImage();
1168       image.SetIconImage( icon );
1169       }
1170 
1171     gdcm::JPEG2000Codec j2kcodec;
1172     gdcm::JPEGCodec jpegcodec;
1173     gdcm::JPEGLSCodec jpeglscodec;
1174     gdcm::ImageChangeTransferSyntax change;
1175     change.SetForce( (force > 0 ? true: false));
1176     change.SetCompressIconImage( (compressicon > 0 ? true: false));
1177     if( jpeg )
1178       {
1179       if( lossy )
1180         {
1181         const gdcm::PixelFormat &pf = image.GetPixelFormat();
1182         if( pf.GetBitsAllocated() > 8 )
1183           change.SetTransferSyntax(gdcm::TransferSyntax::JPEGExtendedProcess2_4);
1184         else
1185           change.SetTransferSyntax( gdcm::TransferSyntax::JPEGBaselineProcess1 );
1186         jpegcodec.SetLossless( false );
1187         if( quality )
1188           {
1189           assert( qualities.size() == 1 );
1190           jpegcodec.SetQuality( static_cast<double>(qualities[0]) );
1191           }
1192         change.SetUserCodec( &jpegcodec );
1193         }
1194       else
1195         {
1196         change.SetTransferSyntax( gdcm::TransferSyntax::JPEGLosslessProcess14_1 );
1197         }
1198       }
1199     else if( jpegls )
1200       {
1201       if( lossy )
1202         {
1203         change.SetTransferSyntax( gdcm::TransferSyntax::JPEGLSNearLossless );
1204         jpeglscodec.SetLossless( false );
1205         if( jpeglserror )
1206           {
1207           jpeglscodec.SetLossyError( jpeglserror_value );
1208           }
1209         change.SetUserCodec( &jpeglscodec );
1210         }
1211       else
1212         {
1213         change.SetTransferSyntax( gdcm::TransferSyntax::JPEGLSLossless );
1214         }
1215       }
1216     else if( j2k )
1217       {
1218       if( lossy )
1219         {
1220         change.SetTransferSyntax( gdcm::TransferSyntax::JPEG2000 );
1221         if( rate )
1222           {
1223           int i = 0;
1224           for(std::vector<float>::const_iterator it = rates.begin(); it != rates.end(); ++it )
1225             {
1226             j2kcodec.SetRate(i++, static_cast<double>(*it) );
1227             }
1228           }
1229         if( quality )
1230           {
1231           int i = 0;
1232           for(std::vector<float>::const_iterator it = qualities.begin(); it != qualities.end(); ++it )
1233             {
1234             j2kcodec.SetQuality( i++, static_cast<double>(*it) );
1235             }
1236           }
1237         if( tile )
1238           {
1239           j2kcodec.SetTileSize( tilesize[0], tilesize[1] );
1240           }
1241         if( nres )
1242           {
1243           j2kcodec.SetNumberOfResolutions( nresvalue );
1244           }
1245         j2kcodec.SetReversible( !irreversible );
1246         change.SetUserCodec( &j2kcodec );
1247         }
1248       else
1249         {
1250         change.SetTransferSyntax( gdcm::TransferSyntax::JPEG2000Lossless );
1251         }
1252       }
1253     else if( raw )
1254       {
1255       if( lossy )
1256         {
1257         std::cerr << "no such thing as raw & lossy" << std::endl;
1258         return 1;
1259         }
1260       const gdcm::TransferSyntax &ts = image.GetTransferSyntax();
1261 #ifdef GDCM_WORDS_BIGENDIAN
1262 	(void)ts;
1263       change.SetTransferSyntax( gdcm::TransferSyntax::ExplicitVRBigEndian );
1264 #else
1265       if( ts.IsExplicit() )
1266         {
1267         change.SetTransferSyntax( gdcm::TransferSyntax::ExplicitVRLittleEndian );
1268         if( implicit )
1269           change.SetTransferSyntax( gdcm::TransferSyntax::ImplicitVRLittleEndian );
1270         }
1271       else
1272         {
1273         assert( ts.IsImplicit() );
1274         change.SetTransferSyntax( gdcm::TransferSyntax::ImplicitVRLittleEndian );
1275         if( explicitts )
1276         change.SetTransferSyntax( gdcm::TransferSyntax::ExplicitVRLittleEndian );
1277         }
1278 #endif
1279       }
1280     else if( rle )
1281       {
1282       if( lossy )
1283         {
1284         std::cerr << "no such thing as rle & lossy" << std::endl;
1285         return 1;
1286         }
1287       change.SetTransferSyntax( gdcm::TransferSyntax::RLELossless );
1288       }
1289     else if( deflated )
1290       {
1291       if( lossy )
1292         {
1293         std::cerr << "no such thing as deflated & lossy" << std::endl;
1294         return 1;
1295         }
1296       change.SetTransferSyntax( gdcm::TransferSyntax::DeflatedExplicitVRLittleEndian );
1297       }
1298     else if( force )
1299       {
1300       // If image is encapsulated it will check some attribute (col/row/pi/pf) and
1301       // some attributes...
1302       }
1303     else
1304       {
1305       std::cerr << "unhandled action" << std::endl;
1306       return 1;
1307       }
1308     if( raw && planarconf )
1309       {
1310       gdcm::ImageChangePlanarConfiguration icpc;
1311       icpc.SetPlanarConfiguration( planarconfval );
1312       icpc.SetInput( image );
1313       bool b = icpc.Change();
1314       if( !b )
1315         {
1316         std::cerr << "Could not change the Planar Configuration: " << filename << std::endl;
1317         return 1;
1318         }
1319       change.SetInput( icpc.PixmapToPixmapFilter::GetOutput() );
1320       }
1321     else
1322       {
1323       change.SetInput( image );
1324       }
1325     bool b = change.Change();
1326     if( !b )
1327       {
1328       std::cerr << "Could not change the Transfer Syntax: " << filename << std::endl;
1329       return 1;
1330       }
1331     if( lossy )
1332       {
1333       if(!quiet)
1334         PrintLossyWarning();
1335       if( !gdcm::derives( reader.GetFile(), change.PixmapToPixmapFilter::GetOutput() ) )
1336         {
1337         std::cerr << "Failed to derives: " << filename << std::endl;
1338         return 1;
1339         }
1340       }
1341     if( usedict /*ts.IsImplicit()*/ )
1342       {
1343       gdcm::FileExplicitFilter fef;
1344       fef.SetChangePrivateTags( (changeprivatetags > 0 ? true : false));
1345       fef.SetFile( reader.GetFile() );
1346       if(!fef.Change())
1347         {
1348         std::cerr << "Failed to change: " << filename << std::endl;
1349         return 1;
1350         }
1351       }
1352 
1353     gdcm::PixmapWriter writer;
1354     writer.SetFileName( outfilename.c_str() );
1355     writer.SetFile( reader.GetFile() );
1356     //writer.SetFile( fef.GetFile() );
1357 
1358     gdcm::File & file = writer.GetFile();
1359     gdcm::FileMetaInformation &fmi = file.GetHeader();
1360     fmi.Remove( gdcm::Tag(0x0002,0x0100) ); //  '   '    ' // PrivateInformationCreatorUID
1361     fmi.Remove( gdcm::Tag(0x0002,0x0102) ); //  '   '    ' // PrivateInformation
1362 
1363     const gdcm::Pixmap &pixout = change.PixmapToPixmapFilter::GetOutput();
1364     writer.SetPixmap( pixout );
1365     if( !writer.Write() )
1366       {
1367       std::cerr << "Failed to write: " << outfilename << std::endl;
1368       return 1;
1369       }
1370 
1371     }
1372   else if( raw && false )
1373     {
1374     gdcm::PixmapReader reader;
1375     reader.SetFileName( filename.c_str() );
1376     if( !reader.Read() )
1377       {
1378       std::cerr << "Could not read (pixmap): " << filename << std::endl;
1379       return 1;
1380       }
1381 
1382     const gdcm::Pixmap &ir = reader.GetPixmap();
1383 
1384     gdcm::Pixmap image( ir );
1385     const gdcm::TransferSyntax &ts = ir.GetTransferSyntax();
1386     if( ts.IsExplicit() )
1387       {
1388       image.SetTransferSyntax( gdcm::TransferSyntax::ExplicitVRLittleEndian );
1389       }
1390     else
1391       {
1392       assert( ts.IsImplicit() );
1393       image.SetTransferSyntax( gdcm::TransferSyntax::ImplicitVRLittleEndian );
1394       }
1395 
1396 /*
1397     image.SetNumberOfDimensions( ir.GetNumberOfDimensions() );
1398 
1399     const unsigned int *dims = ir.GetDimensions();
1400     image.SetDimension(0, dims[0] );
1401     image.SetDimension(1, dims[1] );
1402 
1403     const gdcm::PixelFormat &pixeltype = ir.GetPixelFormat();
1404     image.SetPixelFormat( pixeltype );
1405 
1406     const gdcm::PhotometricInterpretation &pi = ir.GetPhotometricInterpretation();
1407     image.SetPhotometricInterpretation( pi );
1408 */
1409 
1410     unsigned long len = ir.GetBufferLength();
1411     //assert( len = ir.GetBufferLength() );
1412     std::vector<char> buffer;
1413     buffer.resize(len); // black image
1414 
1415     ir.GetBuffer( &buffer[0] );
1416     gdcm::ByteValue *bv = new gdcm::ByteValue(buffer);
1417     gdcm::DataElement pixeldata( gdcm::Tag(0x7fe0,0x0010) );
1418     pixeldata.SetValue( *bv );
1419     image.SetDataElement( pixeldata );
1420 
1421     gdcm::PixmapWriter writer;
1422     writer.SetFile( reader.GetFile() );
1423     writer.SetPixmap( image );
1424     writer.SetFileName( outfilename.c_str() );
1425 
1426     if( !writer.Write() )
1427       {
1428       std::cerr << "could not write: " << outfilename << std::endl;
1429       return 1;
1430       }
1431     }
1432   else
1433     {
1434     gdcm::Reader reader;
1435     reader.SetFileName( filename.c_str() );
1436     if( !reader.Read() )
1437       {
1438       if( ignoreerrors )
1439         {
1440         std::cerr << "WARNING: an error was found during the reading of your DICOM file." << std::endl;
1441         std::cerr << "gdcmconv will still try to continue and rewrite your DICOM file." << std::endl;
1442         std::cerr << "There is absolutely no guarantee that your output file will be valid." << std::endl;
1443         }
1444       else
1445         {
1446         std::cerr << "Failed to read: " << filename << std::endl;
1447         return 1;
1448         }
1449       }
1450     gdcm::MediaStorage ms;
1451     ms.SetFromFile( reader.GetFile() );
1452     if( ms == gdcm::MediaStorage::MediaStorageDirectoryStorage )
1453       {
1454       std::cerr << "Sorry DICOMDIR is not supported" << std::endl;
1455       return 1;
1456       }
1457 
1458 #if 0
1459     // if preamble create:
1460     gdcm::File f(reader.GetFile());
1461     gdcm::Preamble p;
1462     p.Create();
1463     f.SetPreamble(p);
1464     gdcm::DataSet ds = reader.GetFile().GetDataSet();
1465     SetSQToUndefined undef;
1466     ds.ExecuteOperation(undef);
1467 
1468     gdcm::File f(reader.GetFile());
1469     f.SetDataSet(ds);
1470 #endif
1471 
1472 #if 0
1473     gdcm::DataSet& ds = reader.GetFile().GetDataSet();
1474     gdcm::DataElement de = ds.GetDataElement( gdcm::Tag(0x0010,0x0010) );
1475     const char patname[] = "John^Doe";
1476     de.SetByteValue(patname, strlen(patname));
1477     std::cout << de << std::endl;
1478 
1479     ds.Replace( de );
1480     std::cout << ds.GetDataElement( gdcm::Tag(0x0010,0x0010) ) << std::endl;
1481 #endif
1482 
1483     /*
1484     //(0020,0032) DS [-158.135803\-179.035797\-75.699997]     #  34, 3 ImagePositionPatient
1485     //(0020,0037) DS [1.000000\0.000000\0.000000\0.000000\1.000000\0.000000] #  54, 6 ImageOrientationPatient
1486     gdcm::Attribute<0x0020,0x0032> at = { -158.135803, -179.035797, -75.699997 };
1487     gdcm::DataElement ipp = at.GetAsDataElement();
1488     ds.Remove( at.GetTag() );
1489     ds.Remove( ipp.GetTag() );
1490     ds.Replace( ipp );
1491      */
1492 
1493     gdcm::Writer writer;
1494     writer.SetFileName( outfilename.c_str() );
1495     writer.SetCheckFileMetaInformation( (checkmeta > 0 ? true : false));
1496     //writer.SetFile( f );
1497     writer.SetFile( reader.GetFile() );
1498     if( !writer.Write() )
1499       {
1500       std::cerr << "Failed to write: " << outfilename << std::endl;
1501       // remove file to avoid any temptation
1502       if( filename != outfilename )
1503         {
1504         gdcm::System::RemoveFile( outfilename.c_str() );
1505         }
1506       else
1507         {
1508         std::cerr << "gdcmconv just corrupted: " << filename << " for you (data lost)." << std::endl;
1509         }
1510       return 1;
1511       }
1512     }
1513 
1514   return 0;
1515 }
1516