Mercurial > hg > orthanc
diff OrthancFramework/Sources/DicomParsing/Internals/DicomImageDecoder.cpp @ 4529:5774fe497ff2
fix decoding of images on big-endian architectures
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Wed, 24 Feb 2021 21:06:34 +0100 |
parents | d9473bd5ed43 |
children | 4cfd96732076 |
line wrap: on
line diff
--- a/OrthancFramework/Sources/DicomParsing/Internals/DicomImageDecoder.cpp Wed Feb 24 15:07:54 2021 +0100 +++ b/OrthancFramework/Sources/DicomParsing/Internals/DicomImageDecoder.cpp Wed Feb 24 21:06:34 2021 +0100 @@ -91,6 +91,7 @@ #include <dcmtk/dcmdata/dcrleccd.h> #include <dcmtk/dcmdata/dcrlecp.h> #include <dcmtk/dcmdata/dcrlerp.h> +#include <dcmtk/dcmdata/dcswap.h> #if ORTHANC_ENABLE_DCMTK_JPEG_LOSSLESS == 1 # include <dcmtk/dcmjpeg/djrplol.h> @@ -122,6 +123,7 @@ namespace Orthanc { + static const Endianness ENDIANNESS = Toolbox::DetectEndianness(); static const DicomTag DICOM_TAG_CONTENT(0x07a1, 0x100a); static const DicomTag DICOM_TAG_COMPRESSION_TYPE(0x07a1, 0x1011); @@ -556,7 +558,25 @@ info.GetWidth() * GetBytesPerPixel(sourceFormat), buffer + frame * frameSize); - ImageProcessing::Convert(*target, sourceImage); + switch (ENDIANNESS) + { + case Endianness_Little: + ImageProcessing::Convert(*target, sourceImage); + break; + + case Endianness_Big: + { + // We cannot do byte swapping directly on the constant DcmDataset + std::unique_ptr<ImageAccessor> copy(Image::Clone(sourceImage)); + ImageProcessing::SwapEndianness(*copy); + ImageProcessing::Convert(*target, *copy); + break; + } + + default: + throw OrthancException(ErrorCode_InternalError); + } + ImageProcessing::ShiftRight(*target, info.GetShift()); fastVersionSuccess = true; } @@ -660,6 +680,29 @@ } + static void UndoBigEndianSwapping(ImageAccessor& decoded) + { + if (ENDIANNESS == Endianness_Big && + decoded.GetFormat() == PixelFormat_Grayscale8) + { + /** + * Undo the call to "swapIfNecessary()" that is done in + * "dcmjpeg/libsrc/djcodecd.cc" and "dcmjpls/libsrc/djcodecd.cc" + * if "jpeg->bytesPerSample() == 1", presumably because DCMTK + * plans for DICOM-to-DICOM conversion + **/ + if (decoded.GetPitch() % 2 == 0) + { + swapBytes(decoded.GetBuffer(), decoded.GetPitch() * decoded.GetHeight(), sizeof(uint16_t)); + } + else + { + throw OrthancException(ErrorCode_InternalError, "Cannot swap the bytes of an image that has an odd width"); + } + } + } + + ImageAccessor* DicomImageDecoder::Decode(DcmDataset& dataset, unsigned int frame) { @@ -710,7 +753,9 @@ throw OrthancException(ErrorCode_InternalError); } - return ApplyCodec(*decoder, parameters, representationParameter, dataset, frame); + std::unique_ptr<ImageAccessor> result(ApplyCodec(*decoder, parameters, representationParameter, dataset, frame)); + UndoBigEndianSwapping(*result); // New in Orthanc 1.9.1 to decode on big-endian architectures + return result.release(); } #endif @@ -771,8 +816,10 @@ default: throw OrthancException(ErrorCode_InternalError); } - - return ApplyCodec(*decoder, parameters, representationParameter, dataset, frame); + + std::unique_ptr<ImageAccessor> result(ApplyCodec(*decoder, parameters, representationParameter, dataset, frame)); + UndoBigEndianSwapping(*result); // New in Orthanc 1.9.1 to decode on big-endian architectures + return result.release(); } #endif