Mercurial > hg > orthanc
changeset 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 | 93a51d228d80 |
children | e40148c916b8 |
files | OrthancFramework/Sources/DicomParsing/Internals/DicomImageDecoder.cpp OrthancFramework/Sources/Images/ImageProcessing.cpp OrthancFramework/Sources/Images/ImageProcessing.h |
diffstat | 3 files changed, 120 insertions(+), 4 deletions(-) [+] |
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
--- a/OrthancFramework/Sources/Images/ImageProcessing.cpp Wed Feb 24 15:07:54 2021 +0100 +++ b/OrthancFramework/Sources/Images/ImageProcessing.cpp Wed Feb 24 21:06:34 2021 +0100 @@ -2636,4 +2636,71 @@ } } } + + + void ImageProcessing::SwapEndianness(ImageAccessor& image /* inplace */) + { + const unsigned int width = image.GetWidth(); + const unsigned int height = image.GetHeight(); + + switch (image.GetFormat()) + { + case PixelFormat_Grayscale8: + case PixelFormat_RGB24: + case PixelFormat_RGBA32: + case PixelFormat_BGRA32: + // No swapping required + break; + + case PixelFormat_Grayscale16: + case PixelFormat_SignedGrayscale16: + for (unsigned int y = 0; y < height; y++) + { + uint8_t* t = reinterpret_cast<uint8_t*>(image.GetRow(y)); + for (unsigned int x = 0; x < width; x++) + { + uint8_t a = t[0]; + t[0] = t[1]; + t[1] = a; + t += 2; + } + } + break; + + case PixelFormat_Grayscale32: + case PixelFormat_Float32: + for (unsigned int y = 0; y < height; y++) + { + uint8_t* t = reinterpret_cast<uint8_t*>(image.GetRow(y)); + for (unsigned int x = 0; x < width; x++) + { + uint8_t a = t[0]; + uint8_t b = t[1]; + t[0] = t[3]; + t[1] = t[2]; + t[2] = b; + t[3] = a; + t += 4; + } + } + break; + + case PixelFormat_RGB48: // uint16_t per channel + for (unsigned int y = 0; y < height; y++) + { + uint8_t* t = reinterpret_cast<uint8_t*>(image.GetRow(y)); + for (unsigned int x = 0; x < 3 * width; x++) + { + uint8_t a = t[0]; + t[0] = t[1]; + t[1] = a; + t += 2; + } + } + break; + + default: + throw OrthancException(ErrorCode_NotImplemented); + } + } }
--- a/OrthancFramework/Sources/Images/ImageProcessing.h Wed Feb 24 15:07:54 2021 +0100 +++ b/OrthancFramework/Sources/Images/ImageProcessing.h Wed Feb 24 21:06:34 2021 +0100 @@ -200,5 +200,7 @@ // https://en.wikipedia.org/wiki/YCbCr#JPEG_conversion static void ConvertJpegYCbCrToRgb(ImageAccessor& image /* inplace */); + + static void SwapEndianness(ImageAccessor& image /* inplace */); }; }