/*========================================================================= Program: GDCM (Grassroots DICOM). A DICOM library Module: $URL$ Copyright (c) 2006-2010 Mathieu Malaterre All rights reserved. See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notice for more information. =========================================================================*/ #include "gdcmReader.h" #include "gdcmWriter.h" #include "gdcmImageReader.h" #include "gdcmSequenceOfFragments.h" #include "gdcmFile.h" // http://www.lost.in.ua/dicom/c.dcm // // -> BuggyJ2Kvvvua-fixed2-j2k.dcm /* * This program attemps to fix a broken J2K/DICOM: * It contains 2 bugs: * 1. The first 8 bytes seems to be random bytes: remove them * 2. YCC is set to 1, while image is grayscale need to set it back to 0 * * Ref: * It's a software from http://rentgenprom.ru/ , shipped with universal digital radiographic units * "ProScan-2000". The Ukrainian manufacturer developed own digital radiographic unit and it is * compatible with software from "ProScan-2000". */ int main(int argc, char *argv[]) { if( argc < 3 ) { std::cerr << argv[0] << " input.dcm output.dcm" << std::endl; return 1; } const char *filename = argv[1]; const char *outfilename = argv[2]; gdcm::Reader reader; reader.SetFileName( filename ); if( !reader.Read() ) { return 1; } gdcm::File &file = reader.GetFile(); const gdcm::DataElement &pixeldata = file.GetDataSet().GetDataElement( gdcm::Tag(0x7fe0,0x0010) ); const gdcm::SequenceOfFragments *sqf = pixeldata.GetSequenceOfFragments(); if( !sqf ) { return 1; } const gdcm::Fragment &frag = sqf->GetFragment(0); const gdcm::ByteValue *bv = frag.GetByteValue(); const char *ptr = bv->GetPointer(); size_t len = bv->GetLength(); const char sig[] = "\x00\x00\x00\x00\x6A\x70\x32\x63"; if( memcmp(ptr, sig, sizeof(sig) != 0 ) ) { std::cerr << "magic random signature not found" << std::endl; return 1; } // Apparently the flag to enable a color transform on 3 color components is set in // the COD marker. (YCC is byte[6] in the COD marker) // we need to disable this flag; const char *cod_marker = ptr + 0x35; /* 0x2d + 0x8 */ // FIXME if( cod_marker[0] == (char)0xff && cod_marker[1] == 0x52 ) { // found start of COD if( cod_marker[6+2] == 1 ) { // Change in place: *((char*)cod_marker + 6+2) = 0; // Prepare a new DataElement: gdcm::DataElement pixeldata( gdcm::Tag(0x7fe0,0x0010) ); pixeldata.SetVR( gdcm::VR::OB ); gdcm::SmartPointer<gdcm::SequenceOfFragments> sq = new gdcm::SequenceOfFragments; gdcm::Fragment frag; // remove 8 first bytes: frag.SetByteValue( ptr + 8, len - 8 ); sq->AddFragment( frag ); pixeldata.SetValue( *sq ); file.GetDataSet().Replace( pixeldata ); } else { return 1; } } else { std::cerr << "COD not found" << (int)cod_marker[0] << std::endl; return 1; } gdcm::Writer writer; writer.SetFile( reader.GetFile() ); writer.SetFileName( outfilename ); writer.CheckFileMetaInformationOff(); if( !writer.Write() ) { std::cerr << "Could not write" << std::endl; } // paranoid check: gdcm::ImageReader ireader; ireader.SetFileName( outfilename ); if( !ireader.Read() ) { std::cerr << "file written is still not valid, please report" << std::endl; return 1; } return 0; }