Mercurial > hg > orthanc-wsi
comparison Framework/Jpeg2000Reader.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 | 1e864138f0da |
children | 4eefa34657f0 |
comparison
equal
deleted
inserted
replaced
216:c35a3a0627b9 | 217:20bc074ec19a |
---|---|
23 #include "Jpeg2000Reader.h" | 23 #include "Jpeg2000Reader.h" |
24 | 24 |
25 #include "ImageToolbox.h" | 25 #include "ImageToolbox.h" |
26 | 26 |
27 #include <Compatibility.h> // For std::unique_ptr | 27 #include <Compatibility.h> // For std::unique_ptr |
28 #include <Images/ImageProcessing.h> | |
28 #include <OrthancException.h> | 29 #include <OrthancException.h> |
29 #include <SystemToolbox.h> | 30 #include <SystemToolbox.h> |
30 | 31 |
31 #include <cassert> | 32 #include <cassert> |
32 #include <string.h> | 33 #include <string.h> |
38 # define OPJ_CODEC_J2K CODEC_J2K | 39 # define OPJ_CODEC_J2K CODEC_J2K |
39 # define OPJ_CODEC_JP2 CODEC_JP2 | 40 # define OPJ_CODEC_JP2 CODEC_JP2 |
40 typedef opj_dinfo_t opj_codec_t; | 41 typedef opj_dinfo_t opj_codec_t; |
41 typedef opj_cio_t opj_stream_t; | 42 typedef opj_cio_t opj_stream_t; |
42 #elif ORTHANC_OPENJPEG_MAJOR_VERSION == 2 | 43 #elif ORTHANC_OPENJPEG_MAJOR_VERSION == 2 |
43 #else | 44 // OK, no need for compatibility macros |
44 #error Unsupported version of OpenJpeg | 45 #else |
46 # error Unsupported version of OpenJpeg | |
45 #endif | 47 #endif |
46 | 48 |
47 | 49 |
48 namespace OrthancWSI | 50 namespace OrthancWSI |
49 { | 51 { |
293 | 295 |
294 class OpenJpegImage | 296 class OpenJpegImage |
295 { | 297 { |
296 private: | 298 private: |
297 opj_image_t* image_; | 299 opj_image_t* image_; |
298 | 300 |
301 Orthanc::ImageAccessor* ExtractChannel(unsigned int channel) | |
302 { | |
303 const unsigned int width = image_->comps[channel].w; | |
304 const unsigned int height = image_->comps[channel].h; | |
305 | |
306 std::unique_ptr<Orthanc::ImageAccessor> target( | |
307 new Orthanc::Image(Orthanc::PixelFormat_Grayscale8, width, height, false)); | |
308 | |
309 const int32_t* q = image_->comps[channel].data; | |
310 assert(q != NULL); | |
311 | |
312 for (unsigned int y = 0; y < height; y++) | |
313 { | |
314 uint8_t *p = reinterpret_cast<uint8_t*>(target->GetRow(y)); | |
315 | |
316 for (unsigned int x = 0; x < width; x++, p++, q++) | |
317 { | |
318 *p = *q; | |
319 } | |
320 } | |
321 | |
322 return target.release(); | |
323 } | |
324 | |
299 void CopyChannel(Orthanc::ImageAccessor& target, | 325 void CopyChannel(Orthanc::ImageAccessor& target, |
300 unsigned int channel, | 326 unsigned int channel, |
301 unsigned int targetIncrement) | 327 unsigned int targetIncrement) |
302 { | 328 { |
303 int32_t* q = image_->comps[channel].data; | |
304 assert(q != NULL); | |
305 | |
306 const unsigned int width = target.GetWidth(); | 329 const unsigned int width = target.GetWidth(); |
307 const unsigned int height = target.GetHeight(); | 330 const unsigned int height = target.GetHeight(); |
308 | 331 |
309 for (unsigned int y = 0; y < height; y++) | 332 if (0 && // TODO |
310 { | 333 width == image_->comps[channel].w && |
311 uint8_t *p = reinterpret_cast<uint8_t*>(target.GetRow(y)) + channel; | 334 height == image_->comps[channel].h) |
312 | 335 { |
313 for (unsigned int x = 0; x < width; x++, p += targetIncrement) | 336 const int32_t* q = image_->comps[channel].data; |
314 { | 337 assert(q != NULL); |
315 *p = *q; | 338 |
316 q++; | 339 for (unsigned int y = 0; y < height; y++) |
317 } | 340 { |
318 } | 341 uint8_t *p = reinterpret_cast<uint8_t*>(target.GetRow(y)) + channel; |
342 | |
343 for (unsigned int x = 0; x < width; x++, p += targetIncrement) | |
344 { | |
345 *p = *q; | |
346 q++; | |
347 } | |
348 } | |
349 } | |
350 else | |
351 { | |
352 // This component is subsampled | |
353 std::unique_ptr<Orthanc::ImageAccessor> source(ExtractChannel(channel)); | |
354 Orthanc::Image resized(Orthanc::PixelFormat_Grayscale8, width, height, false); | |
355 Orthanc::ImageProcessing::Resize(resized, *source); | |
356 | |
357 assert(resized.GetWidth() == target.GetWidth() && | |
358 resized.GetHeight() == target.GetHeight() && | |
359 resized.GetFormat() == Orthanc::PixelFormat_Grayscale8 && | |
360 source->GetFormat() == Orthanc::PixelFormat_Grayscale8); | |
361 | |
362 for (unsigned int y = 0; y < height; y++) | |
363 { | |
364 const uint8_t *q = reinterpret_cast<const uint8_t*>(resized.GetConstRow(y)); | |
365 uint8_t *p = reinterpret_cast<uint8_t*>(target.GetRow(y)) + channel; | |
366 | |
367 for (unsigned int x = 0; x < width; x++, p += targetIncrement) | |
368 { | |
369 *p = *q; | |
370 q++; | |
371 } | |
372 } | |
373 } | |
319 } | 374 } |
320 | 375 |
321 public: | 376 public: |
322 OpenJpegImage(OpenJpegDecoder& decoder, | 377 OpenJpegImage(OpenJpegDecoder& decoder, |
323 OpenJpegInput& input) : | 378 OpenJpegInput& input) : |
373 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); | 428 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); |
374 } | 429 } |
375 | 430 |
376 for (unsigned int c = 0; c < static_cast<unsigned int>(image_->numcomps); c++) | 431 for (unsigned int c = 0; c < static_cast<unsigned int>(image_->numcomps); c++) |
377 { | 432 { |
378 if (image_->comps[c].dx != 1 || | 433 if (image_->comps[c].x0 != 0 || |
379 image_->comps[c].dy != 1 || | |
380 image_->comps[c].x0 != 0 || | |
381 image_->comps[c].y0 != 0 || | 434 image_->comps[c].y0 != 0 || |
382 image_->comps[c].w != image_->x1 || | 435 image_->comps[c].dx * image_->comps[c].w != image_->x1 || |
383 image_->comps[c].h != image_->y1 || | 436 image_->comps[c].dy * image_->comps[c].h != image_->y1 || |
384 image_->comps[c].prec != 8 || | 437 image_->comps[c].prec != 8 || |
385 image_->comps[c].sgnd != 0) | 438 image_->comps[c].sgnd != 0) |
386 { | 439 { |
387 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); | 440 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); |
388 } | 441 } |
427 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); | 480 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); |
428 } | 481 } |
429 | 482 |
430 return image.release(); | 483 return image.release(); |
431 } | 484 } |
432 | |
433 }; | 485 }; |
434 } | 486 } |
435 | 487 |
436 | 488 |
437 void Jpeg2000Reader::ReadFromMemory(const void* buffer, | 489 void Jpeg2000Reader::ReadFromMemory(const void* buffer, |
440 OpenJpegDecoder decoder(DetectFormatFromMemory(buffer, size)); | 492 OpenJpegDecoder decoder(DetectFormatFromMemory(buffer, size)); |
441 OpenJpegInput input(decoder, buffer, size); | 493 OpenJpegInput input(decoder, buffer, size); |
442 OpenJpegImage image(decoder, input); | 494 OpenJpegImage image(decoder, input); |
443 | 495 |
444 image_.reset(image.ProvideImage()); | 496 image_.reset(image.ProvideImage()); |
445 AssignReadOnly(image_->GetFormat(), | 497 AssignWritable(image_->GetFormat(), |
446 image_->GetWidth(), | 498 image_->GetWidth(), |
447 image_->GetHeight(), | 499 image_->GetHeight(), |
448 image_->GetPitch(), | 500 image_->GetPitch(), |
449 image_->GetConstBuffer()); | 501 image_->GetBuffer()); |
450 } | 502 } |
451 | 503 |
452 | 504 |
453 void Jpeg2000Reader::ReadFromMemory(const std::string& buffer) | 505 void Jpeg2000Reader::ReadFromMemory(const std::string& buffer) |
454 { | 506 { |