GDCM  2.0.18
FixJAIBugJPEGLS.cxx
/*=========================================================================

  Program: GDCM (Grassroots DICOM). A DICOM library

  Copyright (c) 2006-2011 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 <fstream>

#include "gdcmcharls/stdafx.h"
#include "gdcmcharls/interface.h"

/*
 * This small example should show how one can handle the famous JAI-JPEGLS bug
 * It will take in as invalid DICOM/JAI-JPEG-LS and write out as Explicit Little
 * Endian. One can use `gdcmconv --jpegls` to recompress properly
 *
 * References:
 * http://charls.codeplex.com/discussions/230307?ProjectName=charls
 * http://charls.codeplex.com/workitem/7297
 * http://www.dcm4che.org/jira/browse/DCM-442
 * http://www.dcm4che.org/jira/browse/DCMEE-1144
 * http://java.net/jira/browse/JAI_IMAGEIO_CORE-183
 *
 * Explanation of the issue:
 *
 * Seems, the error is in the calculation of the default values for thresholds T1,
 * T2, T3, in particular min(MAXVAL, 4095) is not applied in
 *
 * FACTOR = (min(MAXVAL, 4095) + 128)/256
 *
 * as specified in http://www.itu.int/rec/T-REC-T.87-199806-I/en .
 *
 */
int main(int argc, char *argv[])
{
  const char *filename = argv[1];
  const char *outfilename = argv[2];

  gdcm::ImageReader reader;
  reader.SetFileName( filename );
  reader.Read();

  gdcm::Image &image = reader.GetImage();
  //unsigned long len = image.GetBufferLength();
  const gdcm::DataElement & in =
    reader.GetFile().GetDataSet().GetDataElement( gdcm::Tag(0x7fe0,0x0010) );
  const gdcm::SequenceOfFragments *sf = in.GetSequenceOfFragments();
  if( !sf )
    {
    std::cerr << "No pixle data" << std::endl;
    return 1;
    }
  unsigned long totalLen = sf->ComputeByteLength();
  std::vector<char> vbuffer;
  vbuffer.resize( totalLen );
  char *buffer = &vbuffer[0];
    sf->GetBuffer(buffer, totalLen);

  JlsParamaters metadata;
  if (JpegLsReadHeader(buffer, totalLen, &metadata) != OK)
    {
    std::cerr << "Cant parse jpegls" << std::endl;
    return false;
    }

  std::cout << metadata.width << std::endl;
  std::cout << metadata.height << std::endl;
  std::cout << metadata.bitspersample << std::endl;

  gdcm::PixelFormat const & pf = image.GetPixelFormat();
  std::cout << pf << std::endl;

  // http://charls.codeplex.com/discussions/230307?ProjectName=charls
  unsigned char marker_lse_13[] = {
    0xFF, 0xF8, 0x00, 0x0D,
    0x01,
    0x1F, 0xFF,
    0x00, 0x22,  // T1 = 34
    0x00, 0x83,  // T2 = 131
    0x02, 0x24,  // T3 = 548
    0x00, 0x40
  };

  unsigned char marker_lse_14[] = {
    0xFF, 0xF8, 0x00, 0x0D,
    0x01,
    0x3F, 0xFF,
    0x00, 0x42, // T1 = 66
    0x01, 0x03, // T2 = 259
    0x04, 0x44, // T3 = 1092
    0x00, 0x40
  };

  unsigned char marker_lse_15[] = {
    0xFF, 0xF8, 0x00, 0x0D,
    0x01,
    0x7F, 0xFF,
    0x00, 0x82, // T1 = 130
    0x02, 0x03, // T2 = 515
    0x08, 0x84, // T3 = 2180
    0x00, 0x40
  };

  unsigned char marker_lse_16[] = {
    0xFF, 0xF8, 0x00, 0x0D,
    0x01,
    0xFF, 0xFF,
    0x01, 0x02, // T1 = 258
    0x04, 0x03, // T2 = 1027
    0x11, 0x04, // T3 = 4356
    0x00, 0x40
  };

  const unsigned char *marker_lse = NULL;
  switch( metadata.bitspersample )
    {
  case 13:
    marker_lse = marker_lse_13;
    break;
  case 14:
    marker_lse = marker_lse_14;
    break;
  case 15:
    marker_lse = marker_lse_15;
    break;
  case 16:
    marker_lse = marker_lse_16;
    break;
    }
  if( !marker_lse )
    {
    std::cerr << "Cant handle: " << metadata.bitspersample << std::endl;
    return 1;
    }

  // FIXME: One should recompute the value for 0x0F
  vbuffer.insert (vbuffer.begin() + 0x0F, marker_lse, marker_lse+15);

#if 0
  std::ofstream of( "/tmp/d.jls" );
  of.write( &vbuffer[0], vbuffer.size() );
  of.close();
#endif

  const char *pbyteCompressed = &vbuffer[0];
  unsigned int cbyteCompressed = vbuffer.size(); // updated legnth

  JlsParamaters params = {0};
  JpegLsReadHeader(pbyteCompressed, cbyteCompressed, &params);

  std::vector<BYTE> rgbyteOut;
  //rgbyteOut.resize( image.GetBufferLength() );
  rgbyteOut.resize(params.height *params.width * ((params.bitspersample + 7) / 8) * params.components);

  JLS_ERROR result =
    JpegLsDecode(&rgbyteOut[0], rgbyteOut.size(), pbyteCompressed, cbyteCompressed );
  if (result != OK)
    {
    std::cerr << "Could not patch JAI-JPEGLS" << std::endl;
    return 1;
    }

  gdcm::DataElement pixeldata( gdcm::Tag(0x7fe0,0x0010) );
  pixeldata.SetVR( gdcm::VR::OW );
  pixeldata.SetByteValue( (char*)&rgbyteOut[0], rgbyteOut.size() );

  // Add the pixel data element
  reader.GetFile().GetDataSet().Replace( pixeldata );
  reader.GetFile().GetHeader().SetDataSetTransferSyntax(
    gdcm::TransferSyntax::ExplicitVRLittleEndian);

  gdcm::Writer writer;
  writer.SetFileName( outfilename );
  writer.SetFile( reader.GetFile() );
  writer.Write();

  std::cout << "Success !" << std::endl;

  return 0;
}

Generated on Tue Dec 6 2011 20:36:24 for GDCM by doxygen 1.7.5.1
SourceForge.net Logo