Mercurial > hg > orthanc
comparison OrthancServer/OrthancRestApi/OrthancRestResources.cpp @ 1784:2dbf25006f88
".../preview" and ".../image-uint8" can return JPEG images if the HTTP Accept Header asks so
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Wed, 18 Nov 2015 09:56:34 +0100 |
parents | 5ad4e4d92ecb |
children | b530c3dfe2a6 |
comparison
equal
deleted
inserted
replaced
1783:dbb07eb1a2f3 | 1784:2dbf25006f88 |
---|---|
32 | 32 |
33 #include "../PrecompiledHeadersServer.h" | 33 #include "../PrecompiledHeadersServer.h" |
34 #include "OrthancRestApi.h" | 34 #include "OrthancRestApi.h" |
35 | 35 |
36 #include "../../Core/Logging.h" | 36 #include "../../Core/Logging.h" |
37 #include "../../Core/HttpServer/HttpContentNegociation.h" | |
37 #include "../ServerToolbox.h" | 38 #include "../ServerToolbox.h" |
38 #include "../FromDcmtkBridge.h" | 39 #include "../FromDcmtkBridge.h" |
39 #include "../ServerContext.h" | 40 #include "../ServerContext.h" |
40 #include "../SliceOrdering.h" | 41 #include "../SliceOrdering.h" |
41 | 42 |
257 call.GetOutput().AnswerJson(result); | 258 call.GetOutput().AnswerJson(result); |
258 } | 259 } |
259 } | 260 } |
260 | 261 |
261 | 262 |
262 static void AnswerImage(RestApiGetCall& call, | 263 namespace |
263 ParsedDicomFile& dicom, | 264 { |
264 unsigned int frame, | 265 class ImageToEncode |
265 ImageExtractionMode mode) | 266 { |
266 { | 267 private: |
267 typedef std::vector<std::string> MediaRanges; | 268 std::string format_; |
268 | 269 std::string encoded_; |
269 // Get the HTTP "Accept" header, if any | 270 ParsedDicomFile& dicom_; |
270 std::string accept = call.GetHttpHeader("accept", "*/*"); | 271 unsigned int frame_; |
271 | 272 ImageExtractionMode mode_; |
272 MediaRanges mediaRanges; | 273 |
273 Toolbox::TokenizeString(mediaRanges, accept, ','); | 274 public: |
274 | 275 ImageToEncode(ParsedDicomFile& dicom, |
275 for (MediaRanges::const_reverse_iterator it = mediaRanges.rbegin(); | 276 unsigned int frame, |
276 it != mediaRanges.rend(); ++it) | 277 ImageExtractionMode mode) : |
277 { | 278 dicom_(dicom), |
278 } | 279 frame_(frame), |
279 | 280 mode_(mode) |
280 throw OrthancException(ErrorCode_NotAcceptable); | 281 { |
281 | 282 } |
282 std::string image; | 283 |
283 dicom.ExtractPngImage(image, frame, mode); | 284 ParsedDicomFile& GetDicom() const |
284 call.GetOutput().AnswerBuffer(image, "image/png"); | 285 { |
286 return dicom_; | |
287 } | |
288 | |
289 unsigned int GetFrame() const | |
290 { | |
291 return frame_; | |
292 } | |
293 | |
294 ImageExtractionMode GetMode() const | |
295 { | |
296 return mode_; | |
297 } | |
298 | |
299 void SetFormat(const std::string& format) | |
300 { | |
301 format_ = format; | |
302 } | |
303 | |
304 std::string& GetTarget() | |
305 { | |
306 return encoded_; | |
307 } | |
308 | |
309 void Answer(RestApiOutput& output) | |
310 { | |
311 output.AnswerBuffer(encoded_, format_); | |
312 } | |
313 }; | |
314 | |
315 class EncodePng : public HttpContentNegociation::IHandler | |
316 { | |
317 private: | |
318 ImageToEncode& image_; | |
319 | |
320 public: | |
321 EncodePng(ImageToEncode& image) : image_(image) | |
322 { | |
323 } | |
324 | |
325 virtual void Handle(const std::string& type, | |
326 const std::string& subtype) | |
327 { | |
328 assert(type == "image"); | |
329 assert(subtype == "png"); | |
330 image_.GetDicom().ExtractPngImage(image_.GetTarget(), image_.GetFrame(), image_.GetMode()); | |
331 image_.SetFormat("image/png"); | |
332 } | |
333 }; | |
334 | |
335 class EncodeJpeg : public HttpContentNegociation::IHandler | |
336 { | |
337 private: | |
338 ImageToEncode& image_; | |
339 unsigned int quality_; | |
340 | |
341 public: | |
342 EncodeJpeg(ImageToEncode& image, | |
343 const RestApiGetCall& call) : | |
344 image_(image) | |
345 { | |
346 std::string v = call.GetArgument("quality", "90" /* default JPEG quality */); | |
347 bool ok = false; | |
348 | |
349 try | |
350 { | |
351 quality_ = boost::lexical_cast<unsigned int>(v); | |
352 ok = (quality_ >= 0 && quality_ <= 100); | |
353 } | |
354 catch (boost::bad_lexical_cast&) | |
355 { | |
356 } | |
357 | |
358 if (!ok) | |
359 { | |
360 LOG(ERROR) << "Bad quality for a JPEG encoding (must be a number between 0 and 100): " << v; | |
361 throw OrthancException(ErrorCode_BadRequest); | |
362 } | |
363 } | |
364 | |
365 virtual void Handle(const std::string& type, | |
366 const std::string& subtype) | |
367 { | |
368 assert(type == "image"); | |
369 assert(subtype == "jpeg"); | |
370 image_.GetDicom().ExtractJpegImage(image_.GetTarget(), image_.GetFrame(), image_.GetMode(), quality_); | |
371 image_.SetFormat("image/jpeg"); | |
372 } | |
373 }; | |
285 } | 374 } |
286 | 375 |
287 | 376 |
288 template <enum ImageExtractionMode mode> | 377 template <enum ImageExtractionMode mode> |
289 static void GetImage(RestApiGetCall& call) | 378 static void GetImage(RestApiGetCall& call) |
308 | 397 |
309 ParsedDicomFile dicom(dicomContent); | 398 ParsedDicomFile dicom(dicomContent); |
310 | 399 |
311 try | 400 try |
312 { | 401 { |
313 AnswerImage(call, dicom, frame, mode); | 402 ImageToEncode image(dicom, frame, mode); |
403 | |
404 HttpContentNegociation negociation; | |
405 EncodePng png(image); negociation.Register("image/png", png); | |
406 EncodeJpeg jpeg(image, call); negociation.Register("image/jpeg", jpeg); | |
407 | |
408 if (negociation.Apply(call.GetHttpHeaders())) | |
409 { | |
410 image.Answer(call.GetOutput()); | |
411 } | |
314 } | 412 } |
315 catch (OrthancException& e) | 413 catch (OrthancException& e) |
316 { | 414 { |
317 if (e.GetErrorCode() == ErrorCode_ParameterOutOfRange) | 415 if (e.GetErrorCode() == ErrorCode_ParameterOutOfRange) |
318 { | 416 { |