Mercurial > hg > orthanc
diff OrthancServer/ParsedDicomFile.cpp @ 800:ecedd89055db
generation of DICOM images from PNG files
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Tue, 06 May 2014 16:33:40 +0200 |
parents | 777b6b694da6 |
children | 8ce2f69436ca |
line wrap: on
line diff
--- a/OrthancServer/ParsedDicomFile.cpp Tue May 06 12:55:41 2014 +0200 +++ b/OrthancServer/ParsedDicomFile.cpp Tue May 06 16:33:40 2014 +0200 @@ -87,6 +87,7 @@ #include "../Core/DicomFormat/DicomString.h" #include "../Core/DicomFormat/DicomNullValue.h" #include "../Core/DicomFormat/DicomIntegerPixelAccessor.h" +#include "../Core/ImageFormats/PngReader.h" #include <list> #include <limits> @@ -1087,4 +1088,132 @@ { return new ParsedDicomFile(*this); } + + + void ParsedDicomFile::EmbedImage(const std::string& dataUriScheme) + { + std::string mime, content; + Toolbox::DecodeDataUriScheme(mime, content, dataUriScheme); + + std::string decoded = Toolbox::DecodeBase64(content); + + if (mime == "image/png") + { + PngReader reader; + reader.ReadFromMemory(decoded); + EmbedImage(reader); + } + else + { + throw OrthancException(ErrorCode_NotImplemented); + } + } + + + void ParsedDicomFile::EmbedImage(const ImageAccessor& accessor) + { + if (accessor.GetFormat() != PixelFormat_Grayscale8 && + accessor.GetFormat() != PixelFormat_Grayscale16 && + accessor.GetFormat() != PixelFormat_RGB24 && + accessor.GetFormat() != PixelFormat_RGBA32) + { + throw OrthancException(ErrorCode_NotImplemented); + } + + if (accessor.GetFormat() == PixelFormat_RGBA32) + { + LOG(WARNING) << "Getting rid of the alpha channel when embedding a RGBA image inside DICOM"; + } + + // http://dicomiseasy.blogspot.be/2012/08/chapter-12-pixel-data.html + + Remove(DICOM_TAG_PIXEL_DATA); + Replace(DICOM_TAG_COLUMNS, boost::lexical_cast<std::string>(accessor.GetWidth())); + Replace(DICOM_TAG_ROWS, boost::lexical_cast<std::string>(accessor.GetHeight())); + Replace(DICOM_TAG_SAMPLES_PER_PIXEL, "1"); + Replace(DICOM_TAG_NUMBER_OF_FRAMES, "1"); + Replace(DICOM_TAG_PIXEL_REPRESENTATION, "0"); // Unsigned pixels + Replace(DICOM_TAG_PLANAR_CONFIGURATION, "0"); // Color channels are interleaved + Replace(DICOM_TAG_PHOTOMETRIC_INTERPRETATION, "MONOCHROME2"); + Replace(DICOM_TAG_BITS_ALLOCATED, "8"); + Replace(DICOM_TAG_BITS_STORED, "8"); + Replace(DICOM_TAG_HIGH_BIT, "7"); + + unsigned int bytesPerPixel = 1; + + switch (accessor.GetFormat()) + { + case PixelFormat_RGB24: + case PixelFormat_RGBA32: + Replace(DICOM_TAG_PHOTOMETRIC_INTERPRETATION, "RGB"); + Replace(DICOM_TAG_SAMPLES_PER_PIXEL, "3"); + bytesPerPixel = 3; + break; + + case PixelFormat_Grayscale8: + break; + + case PixelFormat_Grayscale16: + Replace(DICOM_TAG_BITS_ALLOCATED, "16"); + Replace(DICOM_TAG_BITS_STORED, "16"); + Replace(DICOM_TAG_HIGH_BIT, "15"); + bytesPerPixel = 2; + break; + + default: + throw OrthancException(ErrorCode_NotImplemented); + } + + DcmTag key(DICOM_TAG_PIXEL_DATA.GetGroup(), + DICOM_TAG_PIXEL_DATA.GetElement()); + + std::auto_ptr<DcmPixelData> pixels(new DcmPixelData(key)); + + unsigned int pitch = accessor.GetWidth() * bytesPerPixel; + Uint8* target = NULL; + pixels->createUint8Array(accessor.GetHeight() * pitch, target); + + for (unsigned int y = 0; y < accessor.GetHeight(); y++) + { + switch (accessor.GetFormat()) + { + case PixelFormat_RGB24: + case PixelFormat_Grayscale8: + case PixelFormat_Grayscale16: + case PixelFormat_SignedGrayscale16: + { + if (Toolbox::DetectEndianness() != Endianness_Little) + { + throw OrthancException(ErrorCode_NotImplemented); + } + + memcpy(target, reinterpret_cast<const Uint8*>(accessor.GetConstRow(y)), pitch); + target += pitch; + break; + } + + case PixelFormat_RGBA32: + { + // The alpha channel is not supported by the DICOM standard + const Uint8* source = reinterpret_cast<const Uint8*>(accessor.GetConstRow(y)); + for (unsigned int x = 0; x < accessor.GetWidth(); x++, target += 3, source += 4) + { + target[0] = source[0]; + target[1] = source[1]; + target[2] = source[2]; + } + + break; + } + + default: + throw OrthancException(ErrorCode_NotImplemented); + } + } + + if (!pimpl_->file_->getDataset()->insert(pixels.release(), false, false).good()) + { + throw OrthancException(ErrorCode_InternalError); + } + } }