# FixBrokenJ2K.cxx

    /*=========================================================================

      Program: GDCM (Grassroots DICOM). A DICOM library
      Module:  $URL$

      Copyright (c) 2006-2009 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;
    }