comparison Plugins/Samples/GdcmDecoder/Plugin.cpp @ 3930:b99acc213937 transcoding

transcoder plugins and GDCM transcoding are working
author Sebastien Jodogne <s.jodogne@gmail.com>
date Thu, 14 May 2020 19:20:40 +0200
parents 7e33516965f8
children f67b48833a4f
comparison
equal deleted inserted replaced
3929:7dc5e7e0045d 3930:b99acc213937
22 #include "../../../Core/Compatibility.h" 22 #include "../../../Core/Compatibility.h"
23 #include "../../../Core/DicomFormat/DicomMap.h" 23 #include "../../../Core/DicomFormat/DicomMap.h"
24 #include "../../../Core/Toolbox.h" 24 #include "../../../Core/Toolbox.h"
25 #include "GdcmDecoderCache.h" 25 #include "GdcmDecoderCache.h"
26 26
27 #include <gdcmImageChangeTransferSyntax.h>
28 #include <gdcmImageReader.h>
29 #include <gdcmImageWriter.h>
30 #include <gdcmUIDGenerator.h>
31 #include <gdcmAttribute.h>
32
33
27 static OrthancPlugins::GdcmDecoderCache cache_; 34 static OrthancPlugins::GdcmDecoderCache cache_;
28 static bool restrictTransferSyntaxes_ = false; 35 static bool restrictTransferSyntaxes_ = false;
29 static std::set<std::string> enabledTransferSyntaxes_; 36 static std::set<std::string> enabledTransferSyntaxes_;
30 37
31 38
146 return OrthancPluginErrorCode_Plugin; 153 return OrthancPluginErrorCode_Plugin;
147 } 154 }
148 } 155 }
149 156
150 157
158 OrthancPluginErrorCode TranscoderCallback(
159 OrthancPluginMemoryBuffer* transcoded /* out */,
160 uint8_t* hasSopInstanceUidChanged /* out */,
161 const void* buffer,
162 uint64_t size,
163 const char* const* allowedSyntaxes,
164 uint32_t countSyntaxes,
165 uint8_t allowNewSopInstanceUid)
166 {
167 try
168 {
169 std::string dicom(reinterpret_cast<const char*>(buffer), size);
170 std::stringstream stream(dicom);
171
172 gdcm::ImageReader reader;
173 reader.SetStream(stream);
174 if (!reader.Read())
175 {
176 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat,
177 "GDCM cannot decode the image");
178 }
179
180 // First check that transcoding is mandatory
181 for (uint32_t i = 0; i < countSyntaxes; i++)
182 {
183 gdcm::TransferSyntax syntax(gdcm::TransferSyntax::GetTSType(allowedSyntaxes[i]));
184 if (syntax.IsValid() &&
185 reader.GetImage().GetTransferSyntax() == syntax)
186 {
187 // Same transfer syntax as in the source, return a copy of the
188 // source buffer
189 OrthancPlugins::MemoryBuffer orthancBuffer(buffer, size);
190 *transcoded = orthancBuffer.Release();
191 *hasSopInstanceUidChanged = false;
192 return OrthancPluginErrorCode_Success;
193 }
194 }
195
196 for (uint32_t i = 0; i < countSyntaxes; i++)
197 {
198 gdcm::TransferSyntax syntax(gdcm::TransferSyntax::GetTSType(allowedSyntaxes[i]));
199 if (syntax.IsValid())
200 {
201 gdcm::ImageChangeTransferSyntax change;
202 change.SetTransferSyntax(syntax);
203 change.SetInput(reader.GetImage());
204
205 if (change.Change())
206 {
207 if (syntax == gdcm::TransferSyntax::JPEGBaselineProcess1 ||
208 syntax == gdcm::TransferSyntax::JPEGExtendedProcess2_4 ||
209 syntax == gdcm::TransferSyntax::JPEGLSNearLossless ||
210 syntax == gdcm::TransferSyntax::JPEG2000 ||
211 syntax == gdcm::TransferSyntax::JPEG2000Part2)
212 {
213 // In the case of a lossy compression, generate new SOP instance UID
214 gdcm::UIDGenerator generator;
215 std::string uid = generator.Generate();
216 if (uid.size() == 0)
217 {
218 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError,
219 "GDCM cannot generate a UID");
220 }
221
222 gdcm::Attribute<0x0008,0x0018> sopInstanceUid;
223 sopInstanceUid.SetValue(uid);
224 reader.GetFile().GetDataSet().Replace(sopInstanceUid.GetAsDataElement());
225 *hasSopInstanceUidChanged = 1;
226 }
227 else
228 {
229 *hasSopInstanceUidChanged = 0;
230 }
231
232 // GDCM was able to change the transfer syntax, serialize it
233 // to the output buffer
234 gdcm::ImageWriter writer;
235 writer.SetImage(change.GetOutput());
236 writer.SetFile(reader.GetFile());
237
238 std::stringstream ss;
239 writer.SetStream(ss);
240 if (writer.Write())
241 {
242 std::string s = ss.str();
243 OrthancPlugins::MemoryBuffer orthancBuffer(s.empty() ? NULL : s.c_str(), s.size());
244 *transcoded = orthancBuffer.Release();
245
246 return OrthancPluginErrorCode_Success;
247 }
248 else
249 {
250 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError,
251 "GDCM cannot serialize the image");
252 }
253 }
254 }
255 }
256
257 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
258 }
259 catch (Orthanc::OrthancException& e)
260 {
261 LOG(INFO) << "Cannot transcode image using GDCM: " << e.What();
262 return OrthancPluginErrorCode_Plugin;
263 }
264 catch (std::runtime_error& e)
265 {
266 LOG(INFO) << "Cannot transcode image using GDCM: " << e.what();
267 return OrthancPluginErrorCode_Plugin;
268 }
269 catch (...)
270 {
271 LOG(INFO) << "Native exception while decoding image using GDCM";
272 return OrthancPluginErrorCode_Plugin;
273 }
274 }
275
151 276
152 /** 277 /**
153 * We force the redefinition of the "ORTHANC_PLUGINS_API" macro, that 278 * We force the redefinition of the "ORTHANC_PLUGINS_API" macro, that
154 * was left empty with gcc until Orthanc SDK 1.5.7 (no "default" 279 * was left empty with gcc until Orthanc SDK 1.5.7 (no "default"
155 * visibility). This causes the version script, if run from "Holy 280 * visibility). This causes the version script, if run from "Holy
174 static const char* const KEY_GDCM = "Gdcm"; 299 static const char* const KEY_GDCM = "Gdcm";
175 static const char* const KEY_ENABLE_GDCM = "EnableGdcm"; 300 static const char* const KEY_ENABLE_GDCM = "EnableGdcm";
176 static const char* const KEY_RESTRICT_TRANSFER_SYNTAXES = "RestrictTransferSyntaxes"; 301 static const char* const KEY_RESTRICT_TRANSFER_SYNTAXES = "RestrictTransferSyntaxes";
177 302
178 OrthancPlugins::SetGlobalContext(context); 303 OrthancPlugins::SetGlobalContext(context);
179 LOG(INFO) << "Initializing the advanced decoder of medical images using GDCM"; 304 Orthanc::Logging::Initialize(context);
180 305 LOG(INFO) << "Initializing the decoder/transcoder of medical images using GDCM";
181 306
182 /* Check the version of the Orthanc core */ 307 /* Check the version of the Orthanc core */
183 if (OrthancPluginCheckVersion(context) == 0) 308 if (!OrthancPlugins::CheckMinimalOrthancVersion(0, 9, 5))
184 { 309 {
185 char info[1024]; 310 LOG(ERROR) << "Your version of Orthanc (" << std::string(context->orthancVersion)
186 sprintf(info, "Your version of Orthanc (%s) must be above %d.%d.%d to run this plugin", 311 << ") must be above 0.9.5 to run this plugin";
187 context->orthancVersion,
188 ORTHANC_PLUGINS_MINIMAL_MAJOR_NUMBER,
189 ORTHANC_PLUGINS_MINIMAL_MINOR_NUMBER,
190 ORTHANC_PLUGINS_MINIMAL_REVISION_NUMBER);
191 OrthancPluginLogError(context, info);
192 return -1; 312 return -1;
193 } 313 }
194 314
195 OrthancPluginSetDescription(context, "Advanced decoder of medical images using GDCM."); 315 OrthancPluginSetDescription(context, "Decoder/transcoder of medical images using GDCM.");
196 316
197 OrthancPlugins::OrthancConfiguration global; 317 OrthancPlugins::OrthancConfiguration global;
198 318
199 bool enabled = true; 319 bool enabled = true;
200 320
218 } 338 }
219 339
220 if (enabled) 340 if (enabled)
221 { 341 {
222 OrthancPluginRegisterDecodeImageCallback(context, DecodeImageCallback); 342 OrthancPluginRegisterDecodeImageCallback(context, DecodeImageCallback);
343
344 if (OrthancPlugins::CheckMinimalOrthancVersion(1, 7, 0))
345 {
346 OrthancPluginRegisterTranscoderCallback(context, TranscoderCallback);
347 }
348 else
349 {
350 LOG(ERROR) << "Your version of Orthanc (" << std::string(context->orthancVersion)
351 << ") must be above 1.7.0 to benefit from transcoding";
352 }
223 } 353 }
224 else 354 else
225 { 355 {
226 LOG(WARNING) << "The advanced decoder of medical images using GDCM is disabled"; 356 LOG(WARNING) << "The decoder/transcoder of medical images using GDCM is disabled";
227 } 357 }
228 358
229 return 0; 359 return 0;
230 } 360 }
231 361
232 362
233 ORTHANC_PLUGINS_API void OrthancPluginFinalize() 363 ORTHANC_PLUGINS_API void OrthancPluginFinalize()
234 { 364 {
235 LOG(INFO) << "Finalizing the advanced decoder of medical images using GDCM"; 365 LOG(INFO) << "Finalizing the decoder/transcoder of medical images using GDCM";
236 } 366 }
237 367
238 368
239 ORTHANC_PLUGINS_API const char* OrthancPluginGetName() 369 ORTHANC_PLUGINS_API const char* OrthancPluginGetName()
240 { 370 {
241 return "gdcm-decoder"; 371 return "gdcm";
242 } 372 }
243 373
244 374
245 ORTHANC_PLUGINS_API const char* OrthancPluginGetVersion() 375 ORTHANC_PLUGINS_API const char* OrthancPluginGetVersion()
246 { 376 {