GDCM 2.2.1

- Main Page
- Related Pages
- Namespaces
- Classes
- Files
- Examples

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 "gdcm_charls.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[])
{
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::FileMetaInformation::SetSourceApplicationEntityTitle( "FixJAIBugJPEGLS" );
gdcm::ImageReader reader;
reader.SetFileName( filename );
if( !reader.Read() )
{
return 1;
}
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 pixel data (or not encapsulated)" << std::endl;
return 1;
}
const unsigned int *dims = image.GetDimensions();
if ( sf->GetNumberOfFragments() != dims[2] )
{
std::cerr << "Unsupported" << std::endl;
return 1;
}
// unsigned long totalLen = sf->ComputeByteLength();
std::vector<BYTE> rgbyteOutall;
for(unsigned int i = 0; i < sf->GetNumberOfFragments(); ++i)
{
const gdcm::Fragment &frag = sf->GetFragment(i);
if( frag.IsEmpty() ) return 1;
const gdcm::ByteValue *bv = frag.GetByteValue();
if( !bv ) return 1;
unsigned long totalLen = bv->GetLength();
std::vector<char> vbuffer;
vbuffer.resize( totalLen );
char *buffer = &vbuffer[0];
bv->GetBuffer(buffer, totalLen);
const BYTE* pbyteCompressed0 = (const BYTE*)buffer;
while( totalLen > 0 && pbyteCompressed0[totalLen-1] != 0xd9 )
{
totalLen--;
}
#ifdef GDCM_USE_SYSTEM_CHARLS
JlsParameters metadata;
#else
JlsParamaters metadata;
#endif
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];
size_t cbyteCompressed = vbuffer.size(); // updated legnth
#ifdef GDCM_USE_SYSTEM_CHARLS
JlsParameters params;
#else
JlsParamaters params;
#endif
JpegLsReadHeader(pbyteCompressed, cbyteCompressed, &params);
std::vector<BYTE> rgbyteOut;
//rgbyteOut.resize( image.GetBufferLength() );
rgbyteOut.resize(params.height *params.width * ((params.bitspersample + 7)
/ 8) * params.components);
#ifdef GDCM_USE_SYSTEM_CHARLS
JLS_ERROR result =
JpegLsDecode(&rgbyteOut[0], rgbyteOut.size(), pbyteCompressed, cbyteCompressed, &params );
#else
JLS_ERROR result =
JpegLsDecode(&rgbyteOut[0], rgbyteOut.size(), pbyteCompressed, cbyteCompressed );
#endif
if (result != OK)
{
std::cerr << "Could not patch JAI-JPEGLS" << std::endl;
return 1;
}
rgbyteOutall.insert( rgbyteOutall.end(), rgbyteOut.begin(), rgbyteOut.end() );
}
gdcm::DataElement pixeldata( gdcm::Tag(0x7fe0,0x0010) );
pixeldata.SetVR( gdcm::VR::OW );
pixeldata.SetByteValue( (char*)&rgbyteOutall[0], (uint32_t)rgbyteOutall.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;
}