comparison ViewerPlugin/Plugin.cpp @ 260:35c241231af2 iiif

reorganization
author Sebastien Jodogne <s.jodogne@gmail.com>
date Mon, 10 Jul 2023 08:31:50 +0200
parents 3e511f10896c
children c72fbdecdc38
comparison
equal deleted inserted replaced
259:3e511f10896c 260:35c241231af2
20 **/ 20 **/
21 21
22 22
23 #include "../Framework/PrecompiledHeadersWSI.h" 23 #include "../Framework/PrecompiledHeadersWSI.h"
24 24
25 #include "../Framework/ImageToolbox.h"
26 #include "../Framework/Jpeg2000Reader.h"
27 #include "DicomPyramidCache.h" 25 #include "DicomPyramidCache.h"
28 #include "OrthancPluginConnection.h" 26 #include "OrthancPluginConnection.h"
27 #include "RawTile.h"
29 28
30 #include <Compatibility.h> // For std::unique_ptr 29 #include <Compatibility.h> // For std::unique_ptr
31 #include <Logging.h> 30 #include <Logging.h>
31 #include <Images/Image.h>
32 #include <Images/ImageProcessing.h> 32 #include <Images/ImageProcessing.h>
33 #include <Images/JpegReader.h>
34 #include <Images/JpegWriter.h>
35 #include <Images/PngWriter.h>
36 #include <MultiThreading/Semaphore.h>
37 #include <OrthancException.h> 33 #include <OrthancException.h>
38 #include <SystemToolbox.h> 34 #include <SystemToolbox.h>
39 35
40 #include "../Resources/Orthanc/Plugins/OrthancPluginCppWrapper.h" 36 #include "../Resources/Orthanc/Plugins/OrthancPluginCppWrapper.h"
41 37
43 39
44 #include <cassert> 40 #include <cassert>
45 #include <boost/regex.hpp> 41 #include <boost/regex.hpp>
46 #include <boost/math/special_functions/round.hpp> 42 #include <boost/math/special_functions/round.hpp>
47 43
48 std::unique_ptr<OrthancWSI::OrthancPluginConnection> orthanc_; 44 static std::unique_ptr<OrthancWSI::OrthancPluginConnection> orthanc_;
49 std::unique_ptr<OrthancWSI::DicomPyramidCache> cache_; 45 static std::unique_ptr<OrthancWSI::DicomPyramidCache> cache_;
50 std::unique_ptr<Orthanc::Semaphore> transcoderSemaphore_; 46 static std::string publicIIIFUrl_;
51 static std::string publicIIIFUrl_;
52 47
53 static void AnswerSparseTile(OrthancPluginRestOutput* output, 48 static void AnswerSparseTile(OrthancPluginRestOutput* output,
54 unsigned int tileWidth, 49 unsigned int tileWidth,
55 unsigned int tileHeight) 50 unsigned int tileHeight)
56 { 51 {
136 std::string s = result.toStyledString(); 131 std::string s = result.toStyledString();
137 OrthancPluginAnswerBuffer(OrthancPlugins::GetGlobalContext(), output, s.c_str(), s.size(), "application/json"); 132 OrthancPluginAnswerBuffer(OrthancPlugins::GetGlobalContext(), output, s.c_str(), s.size(), "application/json");
138 } 133 }
139 134
140 135
141 class RawTile : public boost::noncopyable
142 {
143 private:
144 Orthanc::PixelFormat format_;
145 unsigned int tileWidth_;
146 unsigned int tileHeight_;
147 Orthanc::PhotometricInterpretation photometric_;
148 std::string tile_;
149 OrthancWSI::ImageCompression compression_;
150
151 Orthanc::ImageAccessor* DecodeInternal()
152 {
153 switch (compression_)
154 {
155 case OrthancWSI::ImageCompression_Jpeg:
156 {
157 std::unique_ptr<Orthanc::JpegReader> decoded(new Orthanc::JpegReader);
158 decoded->ReadFromMemory(tile_);
159 return decoded.release();
160 }
161
162 case OrthancWSI::ImageCompression_Jpeg2000:
163 {
164 std::unique_ptr<OrthancWSI::Jpeg2000Reader> decoded(new OrthancWSI::Jpeg2000Reader);
165 decoded->ReadFromMemory(tile_);
166
167 if (photometric_ == Orthanc::PhotometricInterpretation_YBR_ICT)
168 {
169 OrthancWSI::ImageToolbox::ConvertJpegYCbCrToRgb(*decoded);
170 }
171
172 return decoded.release();
173 }
174
175 case OrthancWSI::ImageCompression_None:
176 {
177 unsigned int bpp = Orthanc::GetBytesPerPixel(format_);
178 if (bpp * tileWidth_ * tileHeight_ != tile_.size())
179 {
180 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
181 }
182
183 std::unique_ptr<Orthanc::ImageAccessor> decoded(new Orthanc::ImageAccessor);
184 decoded->AssignReadOnly(format_, tileWidth_, tileHeight_, bpp * tileWidth_, tile_.c_str());
185
186 return decoded.release();
187 }
188
189 default:
190 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
191 }
192 }
193
194 static void EncodeInternal(std::string& encoded,
195 const Orthanc::ImageAccessor& decoded,
196 Orthanc::MimeType transcodingType)
197 {
198 switch (transcodingType)
199 {
200 case Orthanc::MimeType_Png:
201 {
202 Orthanc::PngWriter writer;
203 Orthanc::IImageWriter::WriteToMemory(writer, encoded, decoded);
204 break;
205 }
206
207 case Orthanc::MimeType_Jpeg:
208 {
209 Orthanc::JpegWriter writer;
210 Orthanc::IImageWriter::WriteToMemory(writer, encoded, decoded);
211 break;
212 }
213
214 default:
215 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
216 }
217 }
218
219
220 public:
221 RawTile(OrthancWSI::ITiledPyramid& pyramid,
222 unsigned int level,
223 unsigned int tileX,
224 unsigned int tileY) :
225 format_(pyramid.GetPixelFormat()),
226 tileWidth_(pyramid.GetTileWidth(level)),
227 tileHeight_(pyramid.GetTileHeight(level)),
228 photometric_(pyramid.GetPhotometricInterpretation())
229 {
230 if (!pyramid.ReadRawTile(tile_, compression_, level, tileX, tileY))
231 {
232 // Handling of missing tile (for sparse tiling): TODO parameter?
233 // AnswerSparseTile(output, tileWidth, tileHeight); return;
234 throw Orthanc::OrthancException(Orthanc::ErrorCode_UnknownResource);
235 }
236 }
237
238 void Answer(OrthancPluginRestOutput* output,
239 Orthanc::MimeType transcodingType)
240 {
241 if (compression_ == OrthancWSI::ImageCompression_Jpeg)
242 {
243 // The tile is already a JPEG image. In such a case, we can
244 // serve it as such, because any Web browser can handle JPEG.
245 OrthancPluginAnswerBuffer(OrthancPlugins::GetGlobalContext(), output, tile_.c_str(),
246 tile_.size(), Orthanc::EnumerationToString(Orthanc::MimeType_Jpeg));
247 }
248 else
249 {
250 // This is a lossless frame (coming from a JPEG2000 or an
251 // uncompressed DICOM instance), which is not a DICOM-JPEG
252 // instance. We need to decompress the raw tile, then transcode
253 // it to the PNG/JPEG, depending on the "transcodingType".
254
255 std::string transcoded;
256
257 {
258 // The semaphore is used to throttle the number of simultaneous computations
259 Orthanc::Semaphore::Locker locker(*transcoderSemaphore_);
260
261 std::unique_ptr<Orthanc::ImageAccessor> decoded(DecodeInternal());
262 EncodeInternal(transcoded, *decoded, transcodingType);
263 }
264
265 OrthancPluginAnswerBuffer(OrthancPlugins::GetGlobalContext(), output, transcoded.c_str(),
266 transcoded.size(), Orthanc::EnumerationToString(transcodingType));
267 }
268 }
269
270 Orthanc::ImageAccessor* Decode()
271 {
272 Orthanc::Semaphore::Locker locker(*transcoderSemaphore_);
273 return DecodeInternal();
274 }
275
276 static void Encode(std::string& encoded,
277 const Orthanc::ImageAccessor& decoded,
278 Orthanc::MimeType transcodingType)
279 {
280 Orthanc::Semaphore::Locker locker(*transcoderSemaphore_);
281 EncodeInternal(encoded, decoded, transcodingType);
282 }
283 };
284
285
286 void ServeTile(OrthancPluginRestOutput* output, 136 void ServeTile(OrthancPluginRestOutput* output,
287 const char* url, 137 const char* url,
288 const OrthancPluginHttpRequest* request) 138 const OrthancPluginHttpRequest* request)
289 { 139 {
290 std::string seriesId(request->groups[0]); 140 std::string seriesId(request->groups[0]);
795 645
796 // Limit the number of PNG transcoders to the number of available 646 // Limit the number of PNG transcoders to the number of available
797 // hardware threads (e.g. number of CPUs or cores or 647 // hardware threads (e.g. number of CPUs or cores or
798 // hyperthreading units) 648 // hyperthreading units)
799 unsigned int threads = Orthanc::SystemToolbox::GetHardwareConcurrency(); 649 unsigned int threads = Orthanc::SystemToolbox::GetHardwareConcurrency();
800 transcoderSemaphore_.reset(new Orthanc::Semaphore(threads)); 650 RawTile::InitializeTranscoderSemaphore(threads);
801 651
802 char info[1024]; 652 char info[1024];
803 sprintf(info, "The whole-slide imaging plugin will use at most %u threads to transcode the tiles", threads); 653 sprintf(info, "The whole-slide imaging plugin will use at most %u threads to transcode the tiles", threads);
804 OrthancPluginLogWarning(OrthancPlugins::GetGlobalContext(), info); 654 OrthancPluginLogWarning(OrthancPlugins::GetGlobalContext(), info);
805 655
843 693
844 ORTHANC_PLUGINS_API void OrthancPluginFinalize() 694 ORTHANC_PLUGINS_API void OrthancPluginFinalize()
845 { 695 {
846 cache_.reset(NULL); 696 cache_.reset(NULL);
847 orthanc_.reset(NULL); 697 orthanc_.reset(NULL);
848 transcoderSemaphore_.reset(NULL); 698 RawTile::FinalizeTranscoderSemaphore();
849 } 699 }
850 700
851 701
852 ORTHANC_PLUGINS_API const char* OrthancPluginGetName() 702 ORTHANC_PLUGINS_API const char* OrthancPluginGetName()
853 { 703 {