Mercurial > hg > orthanc-wsi
comparison ViewerPlugin/RawTile.cpp @ 260:35c241231af2 iiif
reorganization
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Mon, 10 Jul 2023 08:31:50 +0200 |
parents | |
children | c72fbdecdc38 |
comparison
equal
deleted
inserted
replaced
259:3e511f10896c | 260:35c241231af2 |
---|---|
1 /** | |
2 * Orthanc - A Lightweight, RESTful DICOM Store | |
3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics | |
4 * Department, University Hospital of Liege, Belgium | |
5 * Copyright (C) 2017-2023 Osimis S.A., Belgium | |
6 * Copyright (C) 2021-2023 Sebastien Jodogne, ICTEAM UCLouvain, Belgium | |
7 * | |
8 * This program is free software: you can redistribute it and/or | |
9 * modify it under the terms of the GNU Affero General Public License | |
10 * as published by the Free Software Foundation, either version 3 of | |
11 * the License, or (at your option) any later version. | |
12 * | |
13 * This program is distributed in the hope that it will be useful, but | |
14 * WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
16 * Affero General Public License for more details. | |
17 * | |
18 * You should have received a copy of the GNU Affero General Public License | |
19 * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
20 **/ | |
21 | |
22 | |
23 #include "../Framework/PrecompiledHeadersWSI.h" | |
24 #include "RawTile.h" | |
25 | |
26 #include "../Framework/ImageToolbox.h" | |
27 #include "../Framework/Jpeg2000Reader.h" | |
28 #include "../Resources/Orthanc/Plugins/OrthancPluginCppWrapper.h" | |
29 | |
30 #include <Compatibility.h> // For std::unique_ptr | |
31 #include <Images/JpegReader.h> | |
32 #include <Images/JpegWriter.h> | |
33 #include <Images/PngWriter.h> | |
34 #include <MultiThreading/Semaphore.h> | |
35 #include <OrthancException.h> | |
36 | |
37 | |
38 static std::unique_ptr<Orthanc::Semaphore> transcoderSemaphore_; | |
39 | |
40 Orthanc::ImageAccessor* RawTile::DecodeInternal() | |
41 { | |
42 switch (compression_) | |
43 { | |
44 case OrthancWSI::ImageCompression_Jpeg: | |
45 { | |
46 std::unique_ptr<Orthanc::JpegReader> decoded(new Orthanc::JpegReader); | |
47 decoded->ReadFromMemory(tile_); | |
48 return decoded.release(); | |
49 } | |
50 | |
51 case OrthancWSI::ImageCompression_Jpeg2000: | |
52 { | |
53 std::unique_ptr<OrthancWSI::Jpeg2000Reader> decoded(new OrthancWSI::Jpeg2000Reader); | |
54 decoded->ReadFromMemory(tile_); | |
55 | |
56 if (photometric_ == Orthanc::PhotometricInterpretation_YBR_ICT) | |
57 { | |
58 OrthancWSI::ImageToolbox::ConvertJpegYCbCrToRgb(*decoded); | |
59 } | |
60 | |
61 return decoded.release(); | |
62 } | |
63 | |
64 case OrthancWSI::ImageCompression_None: | |
65 { | |
66 unsigned int bpp = Orthanc::GetBytesPerPixel(format_); | |
67 if (bpp * tileWidth_ * tileHeight_ != tile_.size()) | |
68 { | |
69 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); | |
70 } | |
71 | |
72 std::unique_ptr<Orthanc::ImageAccessor> decoded(new Orthanc::ImageAccessor); | |
73 decoded->AssignReadOnly(format_, tileWidth_, tileHeight_, bpp * tileWidth_, tile_.c_str()); | |
74 | |
75 return decoded.release(); | |
76 } | |
77 | |
78 default: | |
79 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); | |
80 } | |
81 } | |
82 | |
83 | |
84 void RawTile::EncodeInternal(std::string& encoded, | |
85 const Orthanc::ImageAccessor& decoded, | |
86 Orthanc::MimeType transcodingType) | |
87 { | |
88 switch (transcodingType) | |
89 { | |
90 case Orthanc::MimeType_Png: | |
91 { | |
92 Orthanc::PngWriter writer; | |
93 Orthanc::IImageWriter::WriteToMemory(writer, encoded, decoded); | |
94 break; | |
95 } | |
96 | |
97 case Orthanc::MimeType_Jpeg: | |
98 { | |
99 Orthanc::JpegWriter writer; | |
100 Orthanc::IImageWriter::WriteToMemory(writer, encoded, decoded); | |
101 break; | |
102 } | |
103 | |
104 default: | |
105 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); | |
106 } | |
107 } | |
108 | |
109 | |
110 RawTile::RawTile(OrthancWSI::ITiledPyramid& pyramid, | |
111 unsigned int level, | |
112 unsigned int tileX, | |
113 unsigned int tileY) : | |
114 format_(pyramid.GetPixelFormat()), | |
115 tileWidth_(pyramid.GetTileWidth(level)), | |
116 tileHeight_(pyramid.GetTileHeight(level)), | |
117 photometric_(pyramid.GetPhotometricInterpretation()) | |
118 { | |
119 if (!pyramid.ReadRawTile(tile_, compression_, level, tileX, tileY)) | |
120 { | |
121 // Handling of missing tile (for sparse tiling): TODO parameter? | |
122 // AnswerSparseTile(output, tileWidth, tileHeight); return; | |
123 throw Orthanc::OrthancException(Orthanc::ErrorCode_UnknownResource); | |
124 } | |
125 } | |
126 | |
127 | |
128 void RawTile::Answer(OrthancPluginRestOutput* output, | |
129 Orthanc::MimeType transcodingType) | |
130 { | |
131 if (compression_ == OrthancWSI::ImageCompression_Jpeg) | |
132 { | |
133 // The tile is already a JPEG image. In such a case, we can | |
134 // serve it as such, because any Web browser can handle JPEG. | |
135 OrthancPluginAnswerBuffer(OrthancPlugins::GetGlobalContext(), output, tile_.c_str(), | |
136 tile_.size(), Orthanc::EnumerationToString(Orthanc::MimeType_Jpeg)); | |
137 } | |
138 else | |
139 { | |
140 // This is a lossless frame (coming from a JPEG2000 or an | |
141 // uncompressed DICOM instance), which is not a DICOM-JPEG | |
142 // instance. We need to decompress the raw tile, then transcode | |
143 // it to the PNG/JPEG, depending on the "transcodingType". | |
144 | |
145 std::string transcoded; | |
146 | |
147 { | |
148 // The semaphore is used to throttle the number of simultaneous computations | |
149 Orthanc::Semaphore::Locker locker(*transcoderSemaphore_); | |
150 | |
151 std::unique_ptr<Orthanc::ImageAccessor> decoded(DecodeInternal()); | |
152 EncodeInternal(transcoded, *decoded, transcodingType); | |
153 } | |
154 | |
155 OrthancPluginAnswerBuffer(OrthancPlugins::GetGlobalContext(), output, transcoded.c_str(), | |
156 transcoded.size(), Orthanc::EnumerationToString(transcodingType)); | |
157 } | |
158 } | |
159 | |
160 | |
161 Orthanc::ImageAccessor* RawTile::Decode() | |
162 { | |
163 Orthanc::Semaphore::Locker locker(*transcoderSemaphore_); | |
164 return DecodeInternal(); | |
165 } | |
166 | |
167 | |
168 void RawTile::Encode(std::string& encoded, | |
169 const Orthanc::ImageAccessor& decoded, | |
170 Orthanc::MimeType transcodingType) | |
171 { | |
172 Orthanc::Semaphore::Locker locker(*transcoderSemaphore_); | |
173 EncodeInternal(encoded, decoded, transcodingType); | |
174 } | |
175 | |
176 | |
177 void RawTile::InitializeTranscoderSemaphore(unsigned int maxThreads) | |
178 { | |
179 transcoderSemaphore_.reset(new Orthanc::Semaphore(maxThreads)); | |
180 } | |
181 | |
182 | |
183 void RawTile::FinalizeTranscoderSemaphore() | |
184 { | |
185 transcoderSemaphore_.reset(NULL); | |
186 } |