comparison Framework/Inputs/DicomPyramidInstance.cpp @ 217:20bc074ec19a

Viewer can display DICOM pyramids whose tile sizes vary across levels
author Sebastien Jodogne <s.jodogne@gmail.com>
date Tue, 12 Jan 2021 14:24:18 +0100
parents c35a3a0627b9
children ef3f8c5126a4
comparison
equal deleted inserted replaced
216:c35a3a0627b9 217:20bc074ec19a
26 #include "../../Resources/Orthanc/Stone/DicomDatasetReader.h" 26 #include "../../Resources/Orthanc/Stone/DicomDatasetReader.h"
27 #include "../../Resources/Orthanc/Stone/FullOrthancDataset.h" 27 #include "../../Resources/Orthanc/Stone/FullOrthancDataset.h"
28 28
29 #include <Logging.h> 29 #include <Logging.h>
30 #include <OrthancException.h> 30 #include <OrthancException.h>
31 #include <SerializationToolbox.h>
31 #include <Toolbox.h> 32 #include <Toolbox.h>
32 33
33 #include <cassert> 34 #include <cassert>
34 35
35 #define SERIALIZED_METADATA "4200" 36 #define SERIALIZED_METADATA "4201" // Was "4200" if versions <= 0.7 of this plugin
36 37
37 38
38 namespace OrthancWSI 39 namespace OrthancWSI
39 { 40 {
40 static const Orthanc::DicomTag DICOM_TAG_COLUMN_POSITION_IN_TOTAL_IMAGE_PIXEL_MATRIX(0x0048, 0x021e); 41 static const Orthanc::DicomTag DICOM_TAG_COLUMN_POSITION_IN_TOTAL_IMAGE_PIXEL_MATRIX(0x0048, 0x021e);
83 { 84 {
84 using namespace OrthancStone; 85 using namespace OrthancStone;
85 86
86 std::string p = Orthanc::Toolbox::StripSpaces 87 std::string p = Orthanc::Toolbox::StripSpaces
87 (reader.GetMandatoryStringValue(OrthancStone::DicomPath(Orthanc::DICOM_TAG_PHOTOMETRIC_INTERPRETATION))); 88 (reader.GetMandatoryStringValue(OrthancStone::DicomPath(Orthanc::DICOM_TAG_PHOTOMETRIC_INTERPRETATION)));
88 89
89 photometric = Orthanc::StringToPhotometricInterpretation(p.c_str()); 90 photometric = Orthanc::StringToPhotometricInterpretation(p.c_str());
90 91
91 if (photometric == Orthanc::PhotometricInterpretation_Palette) 92 if (photometric == Orthanc::PhotometricInterpretation_Palette)
92 { 93 {
93 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented, 94 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented,
258 259
259 DicomPyramidInstance::DicomPyramidInstance(OrthancStone::IOrthancConnection& orthanc, 260 DicomPyramidInstance::DicomPyramidInstance(OrthancStone::IOrthancConnection& orthanc,
260 const std::string& instanceId, 261 const std::string& instanceId,
261 bool useCache) : 262 bool useCache) :
262 instanceId_(instanceId), 263 instanceId_(instanceId),
263 hasCompression_(false) 264 hasCompression_(false),
265 compression_(ImageCompression_None) // Dummy initialization for serialization
264 { 266 {
265 if (useCache) 267 if (useCache)
266 { 268 {
267 try 269 try
268 { 270 {
269 // Try and deserialized the cached information about this instance 271 // Try and deserialized the cached information about this instance
270 std::string serialized; 272 std::string serialized;
271 orthanc.RestApiGet(serialized, "/instances/" + instanceId + "/metadata/" + SERIALIZED_METADATA); 273 orthanc.RestApiGet(serialized, "/instances/" + instanceId + "/metadata/" + SERIALIZED_METADATA);
274 std::cout << serialized;
272 Deserialize(serialized); 275 Deserialize(serialized);
273 return; // Success 276 return; // Success
274 } 277 }
275 catch (Orthanc::OrthancException&) 278 catch (Orthanc::OrthancException&)
276 { 279 {
302 { 305 {
303 assert(frame < frames_.size()); 306 assert(frame < frames_.size());
304 return frames_[frame].second; 307 return frames_[frame].second;
305 } 308 }
306 309
310
311
312 static const char* const HAS_COMPRESSION = "HasCompression";
313 static const char* const IMAGE_COMPRESSION = "ImageCompression";
314 static const char* const PIXEL_FORMAT = "PixelFormat";
315 static const char* const FRAMES = "Frames";
316 static const char* const TILE_WIDTH = "TileWidth";
317 static const char* const TILE_HEIGHT = "TileHeight";
318 static const char* const TOTAL_WIDTH = "TotalWidth";
319 static const char* const TOTAL_HEIGHT = "TotalHeight";
320 static const char* const PHOTOMETRIC_INTERPRETATION = "PhotometricInterpretation";
321
307 322
308 void DicomPyramidInstance::Serialize(std::string& result) const 323 void DicomPyramidInstance::Serialize(std::string& result) const
309 { 324 {
310 Json::Value frames = Json::arrayValue; 325 Json::Value frames = Json::arrayValue;
311 for (size_t i = 0; i < frames_.size(); i++) 326 for (size_t i = 0; i < frames_.size(); i++)
312 { 327 {
313 Json::Value frame = Json::arrayValue; 328 Json::Value frame = Json::arrayValue;
314 frame.append(frames_[i].first); 329 frame.append(frames_[i].first);
315 frame.append(frames_[i].second); 330 frame.append(frames_[i].second);
316
317 frames.append(frame); 331 frames.append(frame);
318 } 332 }
319 333
334 Json::Value content = Json::objectValue;
335 content[FRAMES] = frames;
336
337 // "instanceId_" is set by the constructor
338
339 content[HAS_COMPRESSION] = hasCompression_;
340 content[IMAGE_COMPRESSION] = static_cast<int>(compression_);
341 content[PIXEL_FORMAT] = static_cast<int>(format_);
342 content[TILE_WIDTH] = tileWidth_;
343 content[TILE_HEIGHT] = tileHeight_;
344 content[TOTAL_WIDTH] = totalWidth_;
345 content[TOTAL_HEIGHT] = totalHeight_;
346 content[PHOTOMETRIC_INTERPRETATION] = Orthanc::EnumerationToString(photometric_);
347
348 Orthanc::Toolbox::WriteFastJson(result, content);
349 }
350
351
352 void DicomPyramidInstance::Deserialize(const std::string& s)
353 {
320 Json::Value content; 354 Json::Value content;
321 content["Frames"] = frames; 355 Orthanc::Toolbox::ReadJson(content, s);
322 content["TileHeight"] = tileHeight_;
323 content["TileWidth"] = tileWidth_;
324 content["TotalHeight"] = totalHeight_;
325 content["TotalWidth"] = totalWidth_;
326
327 switch (format_)
328 {
329 case Orthanc::PixelFormat_RGB24:
330 content["PixelFormat"] = 0;
331 break;
332
333 case Orthanc::PixelFormat_Grayscale8:
334 content["PixelFormat"] = 1;
335 break;
336
337 default:
338 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
339 }
340
341 Orthanc::Toolbox::WriteFastJson(result, content);
342 }
343
344
345 void DicomPyramidInstance::Deserialize(const std::string& s)
346 {
347 hasCompression_ = false;
348
349 Json::Value content;
350 OrthancStone::IOrthancConnection::ParseJson(content, s);
351 356
352 if (content.type() != Json::objectValue || 357 if (content.type() != Json::objectValue ||
353 !content.isMember("Frames") || 358 !content.isMember(FRAMES) ||
354 !content.isMember("PixelFormat") || 359 content[FRAMES].type() != Json::arrayValue)
355 !content.isMember("TileHeight") ||
356 !content.isMember("TileWidth") ||
357 !content.isMember("TotalHeight") ||
358 !content.isMember("TotalWidth") ||
359 content["Frames"].type() != Json::arrayValue ||
360 content["PixelFormat"].type() != Json::intValue ||
361 content["TileHeight"].type() != Json::intValue ||
362 content["TileWidth"].type() != Json::intValue ||
363 content["TotalHeight"].type() != Json::intValue ||
364 content["TotalWidth"].type() != Json::intValue ||
365 content["TileHeight"].asInt() < 0 ||
366 content["TileWidth"].asInt() < 0 ||
367 content["TotalHeight"].asInt() < 0 ||
368 content["TotalWidth"].asInt() < 0)
369 { 360 {
370 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); 361 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
371 } 362 }
372 363
373 switch (content["PixelFormat"].asInt()) 364 hasCompression_ = Orthanc::SerializationToolbox::ReadBoolean(content, HAS_COMPRESSION);
374 { 365 compression_ = static_cast<ImageCompression>(Orthanc::SerializationToolbox::ReadInteger(content, IMAGE_COMPRESSION));
375 case 0: 366 format_ = static_cast<Orthanc::PixelFormat>(Orthanc::SerializationToolbox::ReadInteger(content, PIXEL_FORMAT));
376 format_ = Orthanc::PixelFormat_RGB24; 367 tileWidth_ = Orthanc::SerializationToolbox::ReadUnsignedInteger(content, TILE_WIDTH);
377 break; 368 tileHeight_ = Orthanc::SerializationToolbox::ReadUnsignedInteger(content, TILE_HEIGHT);
378 369 totalWidth_ = Orthanc::SerializationToolbox::ReadUnsignedInteger(content, TOTAL_WIDTH);
379 case 1: 370 totalHeight_ = Orthanc::SerializationToolbox::ReadUnsignedInteger(content, TOTAL_HEIGHT);
380 format_ = Orthanc::PixelFormat_Grayscale8; 371
381 break; 372 std::string p = Orthanc::SerializationToolbox::ReadString(content, PHOTOMETRIC_INTERPRETATION);
382 373 photometric_ = Orthanc::StringToPhotometricInterpretation(p.c_str());
383 default: 374
384 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); 375 const Json::Value f = content[FRAMES];
385 }
386
387 hasCompression_ = false;
388 tileHeight_ = static_cast<unsigned int>(content["TileHeight"].asInt());
389 tileWidth_ = static_cast<unsigned int>(content["TileWidth"].asInt());
390 totalHeight_ = static_cast<unsigned int>(content["TotalHeight"].asInt());
391 totalWidth_ = static_cast<unsigned int>(content["TotalWidth"].asInt());
392
393 const Json::Value f = content["Frames"];
394 frames_.resize(f.size()); 376 frames_.resize(f.size());
395 377
396 for (Json::Value::ArrayIndex i = 0; i < f.size(); i++) 378 for (Json::Value::ArrayIndex i = 0; i < f.size(); i++)
397 { 379 {
398 if (f[i].type() != Json::arrayValue || 380 if (f[i].type() != Json::arrayValue ||