comparison Framework/Inputs/OpenSlideLibrary.cpp @ 0:4a7a53257c7d

initial commit
author Sebastien Jodogne <s.jodogne@gmail.com>
date Sat, 22 Oct 2016 21:48:33 +0200
parents
children 7a88c614be04
comparison
equal deleted inserted replaced
-1:000000000000 0:4a7a53257c7d
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 *
6 * This program is free software: you can redistribute it and/or
7 * modify it under the terms of the GNU Affero General Public License
8 * as published by the Free Software Foundation, either version 3 of
9 * the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Affero General Public License for more details.
15 *
16 * You should have received a copy of the GNU Affero General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 **/
19
20
21 #include "OpenSlideLibrary.h"
22
23 #include "../Orthanc/Core/Logging.h"
24 #include "../Orthanc/Core/Images/Image.h"
25
26 namespace OrthancWSI
27 {
28 static std::auto_ptr<OpenSlideLibrary> globalLibrary_;
29
30
31 OpenSlideLibrary::OpenSlideLibrary(const std::string& path) :
32 library_(path)
33 {
34 close_ = (FunctionClose) library_.GetFunction("openslide_close");
35 getLevelCount_ = (FunctionGetLevelCount) library_.GetFunction("openslide_get_level_count");
36 getLevelDimensions_ = (FunctionGetLevelDimensions) library_.GetFunction("openslide_get_level_dimensions");
37 getLevelDownsample_ = (FunctionGetLevelDownsample) library_.GetFunction("openslide_get_level_downsample");
38 open_ = (FunctionOpen) library_.GetFunction("openslide_open");
39 readRegion_ = (FunctionReadRegion) library_.GetFunction("openslide_read_region");
40 }
41
42
43 OpenSlideLibrary::Image::Level::Level() :
44 width_(0),
45 height_(0),
46 downsample_(1)
47 {
48 }
49
50
51 OpenSlideLibrary::Image::Level::Level(int64_t width,
52 int64_t height,
53 double downsample) :
54 width_(static_cast<unsigned int>(width)),
55 height_(static_cast<unsigned int>(height)),
56 downsample_(downsample)
57 {
58 if (width < 0 ||
59 height < 0 ||
60 downsample <= 0)
61 {
62 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
63 }
64
65 if (static_cast<int64_t>(width_) != width ||
66 static_cast<int64_t>(height_) != height)
67 {
68 LOG(ERROR) << "The whole-slide image is too large";
69 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
70 }
71 }
72
73
74 void OpenSlideLibrary::Image::Initialize(const std::string& path)
75 {
76 handle_ = that_.open_(path.c_str());
77 if (handle_ == NULL)
78 {
79 LOG(ERROR) << "Cannot open an image with OpenSlide: " << path;
80 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
81 }
82
83 try
84 {
85 LOG(INFO) << "Opening an image with OpenSlide: " << path;
86
87 int32_t tmp = that_.getLevelCount_(handle_);
88 if (tmp <= 0)
89 {
90 LOG(ERROR) << "Image with no pyramid level";
91 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
92 }
93
94 levels_.resize(tmp);
95
96 for (int32_t level = 0; level < tmp; level++)
97 {
98 int64_t width, height;
99 that_.getLevelDimensions_(handle_, level, &width, &height);
100
101 double downsample = that_.getLevelDownsample_(handle_, level);
102
103 levels_[level] = Level(width, height, downsample);
104 }
105
106 for (size_t i = 1; i < levels_.size(); i++)
107 {
108 if (levels_[i].width_ >= levels_[i - 1].width_ ||
109 levels_[i].height_ >= levels_[i - 1].height_)
110 {
111 // This is not a pyramid with levels of decreasing sizes
112 // (level "0" must be the finest level)
113 LOG(ERROR) << "The pyramid does not have levels of strictly decreasing sizes";
114 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
115 }
116 }
117 }
118 catch (Orthanc::OrthancException&)
119 {
120 Close();
121 throw;
122 }
123 }
124
125
126 OpenSlideLibrary::Image::Image(OpenSlideLibrary& that,
127 const std::string& path) :
128 that_(that),
129 handle_(NULL)
130 {
131 Initialize(path);
132 }
133
134
135 OpenSlideLibrary::Image::Image(const std::string& path) :
136 that_(OpenSlideLibrary::GetInstance()),
137 handle_(NULL)
138 {
139 Initialize(path);
140 }
141
142
143 void OpenSlideLibrary::Image::Close()
144 {
145 if (handle_ != NULL)
146 {
147 that_.close_(handle_);
148 handle_ = NULL;
149 }
150 }
151
152
153 void OpenSlideLibrary::Image::CheckLevel(unsigned int level) const
154 {
155 if (level >= levels_.size())
156 {
157 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
158 }
159 }
160
161
162 double OpenSlideLibrary::Image::GetLevelDownsample(unsigned int level) const
163 {
164 CheckLevel(level);
165 return levels_[level].downsample_;
166 }
167
168
169 unsigned int OpenSlideLibrary::Image::GetLevelWidth(unsigned int level) const
170 {
171 CheckLevel(level);
172 return levels_[level].width_;
173 }
174
175
176 unsigned int OpenSlideLibrary::Image::GetLevelHeight(unsigned int level) const
177 {
178 CheckLevel(level);
179 return levels_[level].height_;
180 }
181
182
183 Orthanc::ImageAccessor* OpenSlideLibrary::Image::ReadRegion(unsigned int level,
184 uint64_t x,
185 uint64_t y,
186 unsigned int width,
187 unsigned int height)
188 {
189 CheckLevel(level);
190
191 // Create a new image, with minimal pitch so as to be compatible with OpenSlide API
192 std::auto_ptr<Orthanc::ImageAccessor> region(new Orthanc::Image(Orthanc::PixelFormat_RGBA32, width, height, true));
193
194 if (region->GetWidth() != 0 &&
195 region->GetHeight() != 0)
196 {
197 double zoom = levels_[level].downsample_;
198 x = static_cast<uint64_t>(zoom * static_cast<double>(x));
199 y = static_cast<uint64_t>(zoom * static_cast<double>(y));
200
201 that_.readRegion_(handle_, reinterpret_cast<uint32_t*>(region->GetBuffer()),
202 x, y, level, region->GetWidth(), region->GetHeight());
203 }
204
205 return region.release();
206 }
207
208
209 OpenSlideLibrary& OpenSlideLibrary::GetInstance()
210 {
211 if (globalLibrary_.get() == NULL)
212 {
213 LOG(ERROR) << "OpenSlide has not been initialized";
214 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
215 }
216 else
217 {
218 return *globalLibrary_;
219 }
220 }
221
222
223 void OpenSlideLibrary::Initialize(const std::string& path)
224 {
225 globalLibrary_.reset(new OpenSlideLibrary(path));
226 }
227
228
229 void OpenSlideLibrary::Finalize()
230 {
231 globalLibrary_.reset(NULL);
232 }
233 }