comparison OrthancServer/FromDcmtkBridge.cpp @ 682:efc4928be6fb

Recover pixel data for more transfer syntaxes (notably JPEG)
author Sebastien Jodogne <s.jodogne@gmail.com>
date Thu, 30 Jan 2014 15:05:14 +0100
parents 27acbc5985f5
children 2d0a347e8cfc
comparison
equal deleted inserted replaced
680:571583642ce2 682:efc4928be6fb
128 128
129 #include <boost/math/special_functions/round.hpp> 129 #include <boost/math/special_functions/round.hpp>
130 #include <glog/logging.h> 130 #include <glog/logging.h>
131 #include <dcmtk/dcmdata/dcostrmb.h> 131 #include <dcmtk/dcmdata/dcostrmb.h>
132 132
133
134 static const char* CONTENT_TYPE_OCTET_STREAM = "application/octet-stream";
135
136
137
133 namespace Orthanc 138 namespace Orthanc
134 { 139 {
135 void ParsedDicomFile::Setup(const char* buffer, size_t size) 140 void ParsedDicomFile::Setup(const char* buffer, size_t size)
136 { 141 {
137 DcmInputBufferStream is; 142 DcmInputBufferStream is;
212 217
213 output.AnswerJson(v); 218 output.AnswerJson(v);
214 } 219 }
215 220
216 221
217 static void AnswerPixelData(RestApiOutput& output, 222 static unsigned int GetPixelDataBlockCount(DcmPixelData& pixelData,
218 DcmPixelData& pixelData, 223 E_TransferSyntax transferSyntax)
219 E_TransferSyntax transferSyntax)
220 { 224 {
221 DcmPixelSequence* pixelSequence = NULL; 225 DcmPixelSequence* pixelSequence = NULL;
222 if (pixelData.getEncapsulatedRepresentation 226 if (pixelData.getEncapsulatedRepresentation
223 (transferSyntax, NULL, pixelSequence).good() && pixelSequence) 227 (transferSyntax, NULL, pixelSequence).good() && pixelSequence)
224 { 228 {
225 for (unsigned long i = 0; i < pixelSequence->card(); i++) 229 return pixelSequence->card();
226 { 230 }
227 DcmPixelItem* pixelItem = NULL; 231 else
228 if (pixelSequence->getItem(pixelItem, i).good() && pixelItem) 232 {
229 { 233 return 1;
230 Uint8* b = NULL;
231 if (pixelItem->getUint8Array(b).good() && b)
232 {
233 // JPEG-LS (lossless)
234 // http://gdcm.sourceforge.net/wiki/index.php/Tools/ffmpeg#JPEG_LS
235 // http://www.stat.columbia.edu/~jakulin/jpeg-ls/
236 // http://itohws03.ee.noda.sut.ac.jp/~matsuda/mrp/
237
238 printf("ITEM: %d %d\n", transferSyntax, pixelItem->getLength());
239 char buf[64];
240 sprintf(buf, "/tmp/toto-%06ld.jpg", i);
241 FILE* fp = fopen(buf, "wb");
242 fwrite(b, pixelItem->getLength(), 1, fp);
243 fclose(fp);
244 }
245 }
246 }
247 } 234 }
248 } 235 }
249 236
250 237
251 static void AnswerDicomField(RestApiOutput& output, 238 static void AnswerDicomField(RestApiOutput& output,
252 DcmElement& element, 239 DcmElement& element,
253 E_TransferSyntax transferSyntax) 240 E_TransferSyntax transferSyntax)
254 { 241 {
255 // This element is not a sequence. Test if it is pixel data.
256 if (element.getTag().getGTag() == DICOM_TAG_PIXEL_DATA.GetGroup() &&
257 element.getTag().getETag() == DICOM_TAG_PIXEL_DATA.GetElement())
258 {
259 try
260 {
261 DcmPixelData& pixelData = dynamic_cast<DcmPixelData&>(element);
262 AnswerPixelData(output, pixelData, transferSyntax);
263 //return;
264 }
265 catch (std::bad_cast&)
266 {
267 }
268 }
269
270
271 // This element is nor a sequence, neither a pixel-data 242 // This element is nor a sequence, neither a pixel-data
272 std::string buffer; 243 std::string buffer;
273 buffer.resize(65536); 244 buffer.resize(65536);
274 Uint32 length = element.getLength(transferSyntax); 245 Uint32 length = element.getLength(transferSyntax);
275 Uint32 offset = 0; 246 Uint32 offset = 0;
276 247
277 output.GetLowLevelOutput().SendOkHeader("application/octet-stream", true, length, NULL); 248 output.GetLowLevelOutput().SendOkHeader(CONTENT_TYPE_OCTET_STREAM, true, length, NULL);
278 249
279 while (offset < length) 250 while (offset < length)
280 { 251 {
281 Uint32 nbytes; 252 Uint32 nbytes;
282 if (length - offset < buffer.size()) 253 if (length - offset < buffer.size())
302 } 273 }
303 } 274 }
304 275
305 output.MarkLowLevelOutputDone(); 276 output.MarkLowLevelOutputDone();
306 } 277 }
278
279
280 static bool AnswerPixelData(RestApiOutput& output,
281 DcmItem& dicom,
282 E_TransferSyntax transferSyntax,
283 const std::string* blockUri)
284 {
285 DcmTag k(DICOM_TAG_PIXEL_DATA.GetGroup(),
286 DICOM_TAG_PIXEL_DATA.GetElement());
287
288 DcmElement *element = NULL;
289 if (!dicom.findAndGetElement(k, element).good() ||
290 element == NULL)
291 {
292 return false;
293 }
294
295 try
296 {
297 DcmPixelData& pixelData = dynamic_cast<DcmPixelData&>(*element);
298 if (blockUri == NULL)
299 {
300 // The user asks how many blocks are presents in this pixel data
301 unsigned int blocks = GetPixelDataBlockCount(pixelData, transferSyntax);
302
303 Json::Value result(Json::arrayValue);
304 for (unsigned int i = 0; i < blocks; i++)
305 {
306 result.append(boost::lexical_cast<std::string>(i));
307 }
308
309 output.AnswerJson(result);
310 return true;
311 }
312
313
314 unsigned int block = boost::lexical_cast<unsigned int>(*blockUri);
315
316 if (block < GetPixelDataBlockCount(pixelData, transferSyntax))
317 {
318 DcmPixelSequence* pixelSequence = NULL;
319 if (pixelData.getEncapsulatedRepresentation
320 (transferSyntax, NULL, pixelSequence).good() && pixelSequence)
321 {
322 // This is the case for JPEG transfer syntaxes
323 if (block < pixelSequence->card())
324 {
325 DcmPixelItem* pixelItem = NULL;
326 if (pixelSequence->getItem(pixelItem, block).good() && pixelItem)
327 {
328 if (pixelItem->getLength() == 0)
329 {
330 output.AnswerBuffer(NULL, 0, CONTENT_TYPE_OCTET_STREAM);
331 return true;
332 }
333
334 Uint8* buffer = NULL;
335 if (pixelItem->getUint8Array(buffer).good() && buffer)
336 {
337 output.AnswerBuffer(buffer, pixelItem->getLength(), CONTENT_TYPE_OCTET_STREAM);
338 return true;
339 }
340 }
341 }
342 }
343 else
344 {
345 // This is the case for raw, uncompressed image buffers
346 assert(*blockUri == "0");
347 AnswerDicomField(output, *element, transferSyntax);
348 }
349 }
350 }
351 catch (boost::bad_lexical_cast&)
352 {
353 // The URI entered by the user is not a number
354 }
355 catch (std::bad_cast&)
356 {
357 // This should never happen
358 }
359
360 return false;
361 }
362
363
307 364
308 static void SendPathValueForLeaf(RestApiOutput& output, 365 static void SendPathValueForLeaf(RestApiOutput& output,
309 const std::string& tag, 366 const std::string& tag,
310 DcmItem& dicom, 367 DcmItem& dicom,
311 E_TransferSyntax transferSyntax) 368 E_TransferSyntax transferSyntax)
334 391
335 void ParsedDicomFile::SendPathValue(RestApiOutput& output, 392 void ParsedDicomFile::SendPathValue(RestApiOutput& output,
336 const UriComponents& uri) 393 const UriComponents& uri)
337 { 394 {
338 DcmItem* dicom = file_->getDataset(); 395 DcmItem* dicom = file_->getDataset();
396 E_TransferSyntax transferSyntax = file_->getDataset()->getOriginalXfer();
397
398 // Special case: Accessing the pixel data
399 if (uri.size() == 1 ||
400 uri.size() == 2)
401 {
402 DcmTagKey tag;
403 ParseTagAndGroup(tag, uri[0]);
404
405 if (tag.getGroup() == DICOM_TAG_PIXEL_DATA.GetGroup() &&
406 tag.getElement() == DICOM_TAG_PIXEL_DATA.GetElement())
407 {
408 AnswerPixelData(output, *dicom, transferSyntax, uri.size() == 1 ? NULL : &uri[1]);
409 return;
410 }
411 }
339 412
340 // Go down in the tag hierarchy according to the URI 413 // Go down in the tag hierarchy according to the URI
341 for (size_t pos = 0; pos < uri.size() / 2; pos++) 414 for (size_t pos = 0; pos < uri.size() / 2; pos++)
342 { 415 {
343 size_t index; 416 size_t index;
367 { 440 {
368 SendPathValueForDictionary(output, *dicom); 441 SendPathValueForDictionary(output, *dicom);
369 } 442 }
370 else 443 else
371 { 444 {
372 SendPathValueForLeaf(output, uri.back(), *dicom, file_->getDataset()->getOriginalXfer()); 445 SendPathValueForLeaf(output, uri.back(), *dicom, transferSyntax);
373 } 446 }
374 } 447 }
375 448
376 449
377 450
758 void ParsedDicomFile::Answer(RestApiOutput& output) 831 void ParsedDicomFile::Answer(RestApiOutput& output)
759 { 832 {
760 std::string serialized; 833 std::string serialized;
761 if (FromDcmtkBridge::SaveToMemoryBuffer(serialized, file_->getDataset())) 834 if (FromDcmtkBridge::SaveToMemoryBuffer(serialized, file_->getDataset()))
762 { 835 {
763 output.AnswerBuffer(serialized, "application/octet-stream"); 836 output.AnswerBuffer(serialized, CONTENT_TYPE_OCTET_STREAM);
764 } 837 }
765 } 838 }
766 839
767 840
768 841