# HG changeset patch # User Sebastien Jodogne # Date 1357215591 -3600 # Node ID 760d0f32cb346544f90b444296df373974f89263 # Parent b83d85a85d69f3240cc50600acce93339d4f58ec PMSCT_RLE1 diff -r b83d85a85d69 -r 760d0f32cb34 Core/DicomFormat/DicomIntegerPixelAccessor.cpp --- a/Core/DicomFormat/DicomIntegerPixelAccessor.cpp Mon Dec 31 09:14:35 2012 +0100 +++ b/Core/DicomFormat/DicomIntegerPixelAccessor.cpp Thu Jan 03 13:19:51 2013 +0100 @@ -111,9 +111,9 @@ throw OrthancException(ErrorCode_NotImplemented); } - if (width_ * height_ * bitsAllocated / 8 * numberOfFrames_ != size) + if (width_ * height_ * bitsAllocated / 8 * numberOfFrames_ > size) { - throw OrthancException(ErrorCode_NotImplemented); + throw OrthancException(ErrorCode_BadFileFormat); } /*printf("%d %d %d %d %d %d %d %d\n", width_, height_, samplesPerPixel_, bitsAllocated, diff -r b83d85a85d69 -r 760d0f32cb34 NEWS --- a/NEWS Mon Dec 31 09:14:35 2012 +0100 +++ b/NEWS Thu Jan 03 13:19:51 2013 +0100 @@ -10,6 +10,7 @@ Minor changes ------------- +* Implementation of the PMSCT_RLE1 image decoding for Philips modalities * Support of private tags diff -r b83d85a85d69 -r 760d0f32cb34 OrthancServer/FromDcmtkBridge.cpp --- a/OrthancServer/FromDcmtkBridge.cpp Mon Dec 31 09:14:35 2012 +0100 +++ b/OrthancServer/FromDcmtkBridge.cpp Thu Jan 03 13:19:51 2013 +0100 @@ -1077,6 +1077,101 @@ } + static bool DecodePsmctRle1(std::string& output, + DcmDataset& dataset) + { + static const DicomTag tagContent(0x07a1, 0x100a); + static const DicomTag tagCompressionType(0x07a1, 0x1011); + + DcmElement* e; + char* c; + + // Check whether the DICOM instance contains an image encoded with + // the PMSCT_RLE1 scheme. + if (!dataset.findAndGetElement(ToDcmtkBridge::Convert(tagCompressionType), e).good() || + e == NULL || + !e->isaString() || + !e->getString(c).good() || + c == NULL || + strcmp("PMSCT_RLE1", c)) + { + return false; + } + + // OK, this is a custom RLE encoding from Philips. Get the pixel + // data from the appropriate private DICOM tag. + Uint8* pixData = NULL; + if (!dataset.findAndGetElement(ToDcmtkBridge::Convert(tagContent), e).good() || + e == NULL || + e->getUint8Array(pixData) != EC_Normal) + { + return false; + } + + // The "unsigned" below IS VERY IMPORTANT + const uint8_t* inbuffer = reinterpret_cast(pixData); + const size_t length = e->getLength(); + + /** + * The code below is an adaptation of a sample code for GDCM by + * Mathieu Malaterre (under a BSD license). + * http://gdcm.sourceforge.net/html/rle2img_8cxx-example.html + **/ + + // RLE pass + std::vector temp; + temp.reserve(length); + for (size_t i = 0; i < length; i++) + { + if (inbuffer[i] == 0xa5) + { + temp.push_back(inbuffer[i+2]); + for (uint8_t repeat = inbuffer[i + 1]; repeat != 0; repeat--) + { + temp.push_back(inbuffer[i+2]); + } + i += 2; + } + else + { + temp.push_back(inbuffer[i]); + } + } + + // Delta encoding pass + uint16_t delta = 0; + output.clear(); + output.reserve(temp.size()); + for (size_t i = 0; i < temp.size(); i++) + { + uint16_t value; + + if (temp[i] == 0x5a) + { + uint16_t v1 = temp[i + 1]; + uint16_t v2 = temp[i + 2]; + value = (v2 << 8) + v1; + i += 2; + } + else + { + value = delta + (int8_t) temp[i]; + } + + output.push_back(value & 0xff); + output.push_back(value >> 8); + delta = value; + } + + if (output.size() % 2) + { + output.resize(output.size() - 1); + } + + return true; + } + + void FromDcmtkBridge::ExtractPngImage(std::string& result, DcmDataset& dataset, unsigned int frame, @@ -1089,6 +1184,8 @@ DicomMap m; FromDcmtkBridge::Convert(m, dataset); + std::string privateContent; + DcmElement* e; if (dataset.findAndGetElement(ToDcmtkBridge::Convert(DICOM_TAG_PIXEL_DATA), e).good() && e != NULL) @@ -1100,6 +1197,15 @@ accessor->SetCurrentFrame(frame); } } + else if (DecodePsmctRle1(privateContent, dataset)) + { + LOG(INFO) << "The PMSCT_RLE1 decoding has succeeded"; + Uint8* pixData = NULL; + if (privateContent.size() > 0) + pixData = reinterpret_cast(&privateContent[0]); + accessor.reset(new DicomIntegerPixelAccessor(m, pixData, privateContent.size())); + accessor->SetCurrentFrame(frame); + } PixelFormat format; switch (mode) @@ -1266,7 +1372,7 @@ { DicomTag t = it->first; std::string s = it->second->AsString(); - printf("0x%04x 0x%04x (%s) [%s]\n", t.GetGroup(), t.GetElement(), GetName(t).c_str(), s.c_str()); + fprintf(fp, "0x%04x 0x%04x (%s) [%s]\n", t.GetGroup(), t.GetElement(), GetName(t).c_str(), s.c_str()); } }