comparison OrthancStone/Sources/Oracle/GetOrthancImageCommand.cpp @ 1512:244ad1e4e76a

reorganization of folders
author Sebastien Jodogne <s.jodogne@gmail.com>
date Tue, 07 Jul 2020 16:21:02 +0200
parents Framework/Oracle/GetOrthancImageCommand.cpp@30deba7bc8e2
children 85e117739eca
comparison
equal deleted inserted replaced
1511:9dfeee74c1e6 1512:244ad1e4e76a
1 /**
2 * Stone of Orthanc
3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
4 * Department, University Hospital of Liege, Belgium
5 * Copyright (C) 2017-2020 Osimis S.A., Belgium
6 *
7 * This program is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU Affero General Public License
9 * as published by the Free Software Foundation, either version 3 of
10 * the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Affero General Public License for more details.
16 *
17 * You should have received a copy of the GNU Affero General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 **/
20
21
22 #include "GetOrthancImageCommand.h"
23
24 #include <Images/JpegReader.h>
25 #include <Images/PamReader.h>
26 #include <Images/PngReader.h>
27 #include <OrthancException.h>
28 #include <Toolbox.h>
29
30 namespace OrthancStone
31 {
32 GetOrthancImageCommand::GetOrthancImageCommand() :
33 uri_("/"),
34 timeout_(600),
35 hasExpectedFormat_(false)
36 {
37 }
38
39
40 void GetOrthancImageCommand::SetExpectedPixelFormat(Orthanc::PixelFormat format)
41 {
42 hasExpectedFormat_ = true;
43 expectedFormat_ = format;
44 }
45
46
47 static std::string GetFormatSuffix(Orthanc::PixelFormat pixelFormat)
48 {
49 switch (pixelFormat)
50 {
51 case Orthanc::PixelFormat_RGB24:
52 return "preview";
53
54 case Orthanc::PixelFormat_Grayscale16:
55 return "image-uint16";
56
57 case Orthanc::PixelFormat_SignedGrayscale16:
58 return "image-int16";
59
60 default:
61 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
62 }
63 }
64
65
66 void GetOrthancImageCommand::SetInstanceUri(const std::string& instance,
67 Orthanc::PixelFormat pixelFormat)
68 {
69 uri_ = "/instances/" + instance + "/" + GetFormatSuffix(pixelFormat);
70 }
71
72
73 void GetOrthancImageCommand::SetFrameUri(const std::string& instance,
74 unsigned int frame,
75 Orthanc::PixelFormat pixelFormat)
76 {
77 uri_ = ("/instances/" + instance + "/frames/" +
78 boost::lexical_cast<std::string>(frame) + "/" + GetFormatSuffix(pixelFormat));
79 }
80
81
82 void GetOrthancImageCommand::ProcessHttpAnswer(boost::weak_ptr<IObserver> receiver,
83 IMessageEmitter& emitter,
84 const std::string& answer,
85 const HttpHeaders& answerHeaders) const
86 {
87 for (HttpHeaders::const_iterator it = answerHeaders.begin(); it != answerHeaders.end(); ++it)
88 {
89 std::string key = Orthanc::Toolbox::StripSpaces(it->first);
90 Orthanc::Toolbox::ToLowerCase(key);
91
92 if (key == "content-disposition" &&
93 it->second == "filename=\"unsupported.png\"")
94 {
95 throw Orthanc::OrthancException(Orthanc::ErrorCode_IncompatibleImageFormat,
96 "Orthanc cannot decode this image");
97 }
98 }
99
100 Orthanc::MimeType contentType = Orthanc::MimeType_Binary;
101
102 for (HttpHeaders::const_iterator it = answerHeaders.begin();
103 it != answerHeaders.end(); ++it)
104 {
105 std::string s;
106 Orthanc::Toolbox::ToLowerCase(s, it->first);
107
108 if (s == "content-type")
109 {
110 contentType = Orthanc::StringToMimeType(it->second);
111 break;
112 }
113 }
114
115 std::unique_ptr<Orthanc::ImageAccessor> image;
116
117 switch (contentType)
118 {
119 case Orthanc::MimeType_Png:
120 {
121 image.reset(new Orthanc::PngReader);
122 dynamic_cast<Orthanc::PngReader&>(*image).ReadFromMemory(answer);
123 break;
124 }
125
126 case Orthanc::MimeType_Pam:
127 {
128 #ifdef __EMSCRIPTEN__
129 // "true" means we ask the PamReader to make an extra copy so that
130 // the resulting Orthanc::ImageAccessor is aligned (as malloc is).
131 // Indeed, even though alignment is not required in Web Assembly,
132 // Emscripten seems to check it and bail out if addresses are "odd"
133 image.reset(new Orthanc::PamReader(true));
134 #else
135 // potentially unaligned, with is faster and consumes less heap memory
136 image.reset(new Orthanc::PamReader);
137 #endif
138 dynamic_cast<Orthanc::PamReader&>(*image).ReadFromMemory(answer);
139 break;
140 }
141
142 case Orthanc::MimeType_Jpeg:
143 {
144 image.reset(new Orthanc::JpegReader);
145 dynamic_cast<Orthanc::JpegReader&>(*image).ReadFromMemory(answer);
146 break;
147 }
148
149 default:
150 throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol,
151 "Unsupported HTTP Content-Type for an image: " +
152 std::string(Orthanc::EnumerationToString(contentType)));
153 }
154
155 if (hasExpectedFormat_)
156 {
157 if (expectedFormat_ == Orthanc::PixelFormat_SignedGrayscale16 &&
158 image->GetFormat() == Orthanc::PixelFormat_Grayscale16)
159 {
160 image->SetFormat(Orthanc::PixelFormat_SignedGrayscale16);
161 }
162
163 if (expectedFormat_ != image->GetFormat())
164 {
165 throw Orthanc::OrthancException(Orthanc::ErrorCode_IncompatibleImageFormat);
166 }
167 }
168
169 //{
170 // // DEBUG DISPLAY IMAGE PROPERTIES BGO 2020-04-11
171 // const Orthanc::ImageAccessor& source = *image;
172 // const void* sourceBuffer = source.GetConstBuffer();
173 // intptr_t sourceBufferInt = reinterpret_cast<intptr_t>(sourceBuffer);
174 // int sourceWidth = source.GetWidth();
175 // int sourceHeight = source.GetHeight();
176 // int sourcePitch = source.GetPitch();
177
178 // // TODO: turn error into trace below
179 // LOG(ERROR) << "GetOrthancImageCommand::ProcessHttpAnswer | source:"
180 // << " W = " << sourceWidth << " H = " << sourceHeight
181 // << " P = " << sourcePitch << " B = " << sourceBufferInt
182 // << " B % 4 == " << sourceBufferInt % 4;
183 //}
184
185
186 SuccessMessage message(*this, *image, contentType);
187 emitter.EmitMessage(receiver, message);
188 }
189 }