Mercurial > hg > orthanc
comparison 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 |
comparison
equal
deleted
inserted
replaced
799:777b6b694da6 | 800:ecedd89055db |
---|---|
85 #include "../Core/ImageFormats/PngWriter.h" | 85 #include "../Core/ImageFormats/PngWriter.h" |
86 #include "../Core/Uuid.h" | 86 #include "../Core/Uuid.h" |
87 #include "../Core/DicomFormat/DicomString.h" | 87 #include "../Core/DicomFormat/DicomString.h" |
88 #include "../Core/DicomFormat/DicomNullValue.h" | 88 #include "../Core/DicomFormat/DicomNullValue.h" |
89 #include "../Core/DicomFormat/DicomIntegerPixelAccessor.h" | 89 #include "../Core/DicomFormat/DicomIntegerPixelAccessor.h" |
90 #include "../Core/ImageFormats/PngReader.h" | |
90 | 91 |
91 #include <list> | 92 #include <list> |
92 #include <limits> | 93 #include <limits> |
93 | 94 |
94 #include <boost/lexical_cast.hpp> | 95 #include <boost/lexical_cast.hpp> |
1085 | 1086 |
1086 ParsedDicomFile* ParsedDicomFile::Clone() | 1087 ParsedDicomFile* ParsedDicomFile::Clone() |
1087 { | 1088 { |
1088 return new ParsedDicomFile(*this); | 1089 return new ParsedDicomFile(*this); |
1089 } | 1090 } |
1091 | |
1092 | |
1093 void ParsedDicomFile::EmbedImage(const std::string& dataUriScheme) | |
1094 { | |
1095 std::string mime, content; | |
1096 Toolbox::DecodeDataUriScheme(mime, content, dataUriScheme); | |
1097 | |
1098 std::string decoded = Toolbox::DecodeBase64(content); | |
1099 | |
1100 if (mime == "image/png") | |
1101 { | |
1102 PngReader reader; | |
1103 reader.ReadFromMemory(decoded); | |
1104 EmbedImage(reader); | |
1105 } | |
1106 else | |
1107 { | |
1108 throw OrthancException(ErrorCode_NotImplemented); | |
1109 } | |
1110 } | |
1111 | |
1112 | |
1113 void ParsedDicomFile::EmbedImage(const ImageAccessor& accessor) | |
1114 { | |
1115 if (accessor.GetFormat() != PixelFormat_Grayscale8 && | |
1116 accessor.GetFormat() != PixelFormat_Grayscale16 && | |
1117 accessor.GetFormat() != PixelFormat_RGB24 && | |
1118 accessor.GetFormat() != PixelFormat_RGBA32) | |
1119 { | |
1120 throw OrthancException(ErrorCode_NotImplemented); | |
1121 } | |
1122 | |
1123 if (accessor.GetFormat() == PixelFormat_RGBA32) | |
1124 { | |
1125 LOG(WARNING) << "Getting rid of the alpha channel when embedding a RGBA image inside DICOM"; | |
1126 } | |
1127 | |
1128 // http://dicomiseasy.blogspot.be/2012/08/chapter-12-pixel-data.html | |
1129 | |
1130 Remove(DICOM_TAG_PIXEL_DATA); | |
1131 Replace(DICOM_TAG_COLUMNS, boost::lexical_cast<std::string>(accessor.GetWidth())); | |
1132 Replace(DICOM_TAG_ROWS, boost::lexical_cast<std::string>(accessor.GetHeight())); | |
1133 Replace(DICOM_TAG_SAMPLES_PER_PIXEL, "1"); | |
1134 Replace(DICOM_TAG_NUMBER_OF_FRAMES, "1"); | |
1135 Replace(DICOM_TAG_PIXEL_REPRESENTATION, "0"); // Unsigned pixels | |
1136 Replace(DICOM_TAG_PLANAR_CONFIGURATION, "0"); // Color channels are interleaved | |
1137 Replace(DICOM_TAG_PHOTOMETRIC_INTERPRETATION, "MONOCHROME2"); | |
1138 Replace(DICOM_TAG_BITS_ALLOCATED, "8"); | |
1139 Replace(DICOM_TAG_BITS_STORED, "8"); | |
1140 Replace(DICOM_TAG_HIGH_BIT, "7"); | |
1141 | |
1142 unsigned int bytesPerPixel = 1; | |
1143 | |
1144 switch (accessor.GetFormat()) | |
1145 { | |
1146 case PixelFormat_RGB24: | |
1147 case PixelFormat_RGBA32: | |
1148 Replace(DICOM_TAG_PHOTOMETRIC_INTERPRETATION, "RGB"); | |
1149 Replace(DICOM_TAG_SAMPLES_PER_PIXEL, "3"); | |
1150 bytesPerPixel = 3; | |
1151 break; | |
1152 | |
1153 case PixelFormat_Grayscale8: | |
1154 break; | |
1155 | |
1156 case PixelFormat_Grayscale16: | |
1157 Replace(DICOM_TAG_BITS_ALLOCATED, "16"); | |
1158 Replace(DICOM_TAG_BITS_STORED, "16"); | |
1159 Replace(DICOM_TAG_HIGH_BIT, "15"); | |
1160 bytesPerPixel = 2; | |
1161 break; | |
1162 | |
1163 default: | |
1164 throw OrthancException(ErrorCode_NotImplemented); | |
1165 } | |
1166 | |
1167 DcmTag key(DICOM_TAG_PIXEL_DATA.GetGroup(), | |
1168 DICOM_TAG_PIXEL_DATA.GetElement()); | |
1169 | |
1170 std::auto_ptr<DcmPixelData> pixels(new DcmPixelData(key)); | |
1171 | |
1172 unsigned int pitch = accessor.GetWidth() * bytesPerPixel; | |
1173 Uint8* target = NULL; | |
1174 pixels->createUint8Array(accessor.GetHeight() * pitch, target); | |
1175 | |
1176 for (unsigned int y = 0; y < accessor.GetHeight(); y++) | |
1177 { | |
1178 switch (accessor.GetFormat()) | |
1179 { | |
1180 case PixelFormat_RGB24: | |
1181 case PixelFormat_Grayscale8: | |
1182 case PixelFormat_Grayscale16: | |
1183 case PixelFormat_SignedGrayscale16: | |
1184 { | |
1185 if (Toolbox::DetectEndianness() != Endianness_Little) | |
1186 { | |
1187 throw OrthancException(ErrorCode_NotImplemented); | |
1188 } | |
1189 | |
1190 memcpy(target, reinterpret_cast<const Uint8*>(accessor.GetConstRow(y)), pitch); | |
1191 target += pitch; | |
1192 break; | |
1193 } | |
1194 | |
1195 case PixelFormat_RGBA32: | |
1196 { | |
1197 // The alpha channel is not supported by the DICOM standard | |
1198 const Uint8* source = reinterpret_cast<const Uint8*>(accessor.GetConstRow(y)); | |
1199 for (unsigned int x = 0; x < accessor.GetWidth(); x++, target += 3, source += 4) | |
1200 { | |
1201 target[0] = source[0]; | |
1202 target[1] = source[1]; | |
1203 target[2] = source[2]; | |
1204 } | |
1205 | |
1206 break; | |
1207 } | |
1208 | |
1209 default: | |
1210 throw OrthancException(ErrorCode_NotImplemented); | |
1211 } | |
1212 } | |
1213 | |
1214 if (!pimpl_->file_->getDataset()->insert(pixels.release(), false, false).good()) | |
1215 { | |
1216 throw OrthancException(ErrorCode_InternalError); | |
1217 } | |
1218 } | |
1090 } | 1219 } |