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 }