dicom_info.h
説明を見る。
1 //
2 // Copyright (c) 2003-2011, MIST Project, Nagoya University
3 // All rights reserved.
4 //
5 // Redistribution and use in source and binary forms, with or without modification,
6 // are permitted provided that the following conditions are met:
7 //
8 // 1. Redistributions of source code must retain the above copyright notice,
9 // this list of conditions and the following disclaimer.
10 //
11 // 2. Redistributions in binary form must reproduce the above copyright notice,
12 // this list of conditions and the following disclaimer in the documentation
13 // and/or other materials provided with the distribution.
14 //
15 // 3. Neither the name of the Nagoya University nor the names of its contributors
16 // may be used to endorse or promote products derived from this software
17 // without specific prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
20 // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
21 // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
22 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25 // IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
26 // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 //
28 
33 #ifndef __INCLUDE_MIST_DICOM_INFO__
34 #define __INCLUDE_MIST_DICOM_INFO__
35 
36 
37 #ifndef __INCLUDE_MIST_CONF_H__
38 #include "../config/mist_conf.h"
39 #endif
40 
41 #ifndef __INCLUDE_MIST_ENDIAN__
42 #include "../config/endian.h"
43 #endif
44 
45 #ifndef __INCLUDE_MIST_SINGLETON__
46 #include "../singleton.h"
47 #endif
48 
49 #ifndef __INCLUDE_MIST_DICOM_TAG__
50 #include "./dicom_tag.h"
51 #endif
52 
53 #include <iostream>
54 #include <map>
55 #include <string>
56 
57 
58 // 次のマクロを定義すると,JPEG圧縮されたDICOMのデコードが可能になる
59 // ただし,外部のJPEGライブラリを必要とするので注意
60 //#define __DECODE_JPEG_COMPRESSION__
61 
62 #ifdef __DECODE_JPEG_COMPRESSION__
63 
64 #if defined( __MIST_WINDOWS__ ) && __MIST_WINDOWS__ > 0
65 
66  #define XMD_H
67  #define HAVE_INT32 // JPEG用INT32型を持っている宣言
68  #define HAVE_BOOLEAN // JPEG用boolean型を持っている宣言
69 
70 #endif
71 
72 extern "C"
73 {
74  #include <jpeglib.h>
75 }
76 
77 #endif
78 
79 
80 // mist名前空間の始まり
82 
83 
86 
89 
90 
92 namespace dicom
93 {
96  {
97  RAW,
98  JPEG,
101  RLE,
102  };
103 
106  {
107  UNKNOWNTYPE,
110  RGB,
114  };
115 
118  {
119  static dicom_uid_table uid_table;
120  return( uid_table );
121  }
122 
124  inline dicom_uid get_uid( const std::string &uid )
125  {
126  dicom_uid_table &uid_table = get_dicom_uid_table( );
127  return( uid_table.get_uid( uid ) );
128  }
129 
131  inline bool is_dicom_class_uid( const std::string &uid )
132  {
133  const dicom_uid_table &uid_table = get_dicom_uid_table( );
134  return( uid_table.contain_uid( uid ) );
135  }
136 
137 
139  inline dicom_uid get_uid( const unsigned char *str, difference_type numBytes )
140  {
141  return( get_uid( std::string( reinterpret_cast< const char * >( str ), str[ numBytes - 1 ] == 0 ? numBytes - 1 : numBytes ) ) );
142  }
143 
144  inline size_t compute_need_bytes( const dicom_tag &tag, size_t max_bytes, size_t num_bytes, bool align_max_bytes )
145  {
146  size_t rest = num_bytes % max_bytes;
147 
148  if( rest > 0 && align_max_bytes )
149  {
150  num_bytes += max_bytes - rest;
151  }
152 
153  if( tag.vm != -1 && num_bytes > max_bytes * tag.vm )
154  {
155  num_bytes = max_bytes * tag.vm;
156  }
157 
158  return( num_bytes );
159  }
160 
161  inline size_t compute_need_bytes( const dicom_tag &tag, size_t num_bytes )
162  {
163  bool isEven = ( num_bytes % 2 ) == 0;
164 
165  switch( tag.vr )
166  {
167  case AE:
168  // Application Entity
169  // 「16バイト以下」
170  // 先頭と末尾にスペース(20H)を持つ可能性のある文字列
171  // 文字列の長さを偶数に保つために,末尾にスペースを挿入する必要あり
172  // スペースは特に意味なし
173  if( !isEven )
174  {
175  num_bytes++;
176  }
177 
178  num_bytes = compute_need_bytes( tag, 16, num_bytes, false );
179  break;
180 
181  case AS:
182  // 年齢を表す文字列
183  // 「4バイト固定」
184  // 文字列の書式は nnnD, nnnW, nnnM, nnnY のいずれか
185  // 使用可能な値は,0-9, D, W, M, Y のいずれか
186  //  D: nnn → 日
187  //  W: nnn → 週
188  //  M: nnn → 月
189  //  Y: nnn → 年
190  //
191  // 例: "018M" は生後18ヶ月を表す
192  num_bytes = compute_need_bytes( tag, 4, num_bytes, true );
193  break;
194 
195  case AT:
196  // Attribute Tag
197  // 「4バイト固定」
198  // 2つの16ビット符号なし整数の並び
199  //
200  // 例: (0018,00FF) のタグは,4バイトの並びで表現され,エンディアンの違いにより以下のように符号化される
201  // リトルエンディアン転送構文 → 18H, 00H, FFH, 00H
202  // ビッグエンディアン転送構文 → 00H, 18H, 00H, FFH
203  num_bytes = compute_need_bytes( tag, 4, num_bytes, true );
204  break;
205 
206  case CS:
207  // Code String
208  // 「16バイト以下」
209  // 先頭と末尾にスペース(20H)を持つ可能性のある文字列
210  // 文字列の長さを偶数に保つために,末尾にスペースを挿入する必要あり
211  // スペースは特に意味なし
212  // 大文字の A-Z, 0-9, アンダーバー(_)のみが利用可能.
213  if( !isEven )
214  {
215  num_bytes++;
216  }
217 
218  num_bytes = compute_need_bytes( tag, 16, num_bytes, false );
219  break;
220 
221  case DA:
222  // 日付を表す文字列
223  // 「8バイト固定」ただし,DICOM2.0では「10バイト固定」のためどちらも扱えるようにする必要あり
224  // yyyymmdd もしくは yyyy.mm.dd の書式で日付を符号化した文字列
225  // これは,yyyy 年 mm 月 dd 日を表す
226  // 0-9, ピリオド(.)のみが利用可能.
227  //
228  // 例:19930822 は 1993 年 8 月 22 日を表す
229  if( num_bytes != 8 && num_bytes != 10 )
230  {
231  num_bytes = compute_need_bytes( tag, 10, num_bytes, true );
232  }
233  break;
234 
235  case DS:
236  // 10進数を表す文字列
237  // 「16バイト以下」
238  // 固定小数点もしくは浮動小数点数を表現する文字列であり,先頭と末尾にスペース(20H)を持つ可能性のある文字列
239  // 固定小数点数の場合は 0-9 に加え,先頭に + もしくは -,さらに小数点を示す任意の . を含む
240  // 浮動小数点数は,ANSI X3.9 に従い,指数を示す E もしくは e を含む
241  // 文字列の長さを偶数に保つために,末尾にスペースを挿入する必要あり
242  if( !isEven )
243  {
244  num_bytes++;
245  }
246 
247  num_bytes = compute_need_bytes( tag, 16, num_bytes, false );
248  break;
249 
250  case DT:
251  // 日時を表す文字列
252  // 「26バイト以下」
253  // YYYYMMDDHHMMSS.FFFFFF&ZZZZ の書式に従って日時を表し,先頭と末尾にスペース(20H)を持つ可能性のある文字列
254  // これは,YYYY 年 MM 月 DD 日 HH 時 MM 分 SS.FFFFFF 秒(FFFFFFは病の小数部分)を表す
255  // また,& は + もしくは - のどちらかであり,ZZZZ は時間と分のオフセットを表す
256  // 文字列の長さを偶数に保つために,末尾にスペースを挿入する必要あり
257  if( !isEven )
258  {
259  num_bytes++;
260  }
261 
262  num_bytes = compute_need_bytes( tag, 26, num_bytes, false );
263  break;
264 
265  case FL:
266  // 単精度浮動小数
267  // 「4バイト固定」
268  num_bytes = compute_need_bytes( tag, 4, num_bytes, true );
269  break;
270 
271  case FD:
272  // 倍精度浮動小数
273  // 「8バイト固定」
274  num_bytes = compute_need_bytes( tag, 8, num_bytes, true );
275  break;
276 
277  case IS:
278  // 整数を表す文字列
279  // 「16バイト以下」
280  // 10 を底とする整数(10進数)を表わす文字列で,先頭に + もしくは - を含んでも良く,先頭と末尾にスペース(20H)を持つ可能性のある文字列
281  // 文字列の長さを偶数に保つために,末尾にスペースを挿入する必要あり
282  // -2^31 ≦ n ≦ (2^31-1) の範囲を表現することが可能.
283  if( !isEven )
284  {
285  num_bytes++;
286  }
287 
288  num_bytes = compute_need_bytes( tag, 16, num_bytes, false );
289  break;
290 
291  case LO:
292  // 長文字列
293  // 「64バイト以下」
294  // 先頭と末尾にスペース(20H)を持つ文字列
295  // 文字列の長さを偶数に保つために,末尾にスペースを挿入する必要あり
296  // 制御文字列は含まない
297  if( !isEven )
298  {
299  num_bytes++;
300  }
301 
302  num_bytes = compute_need_bytes( tag, 64, num_bytes, false );
303  break;
304 
305  case LT:
306  // 長テキスト文字列
307  // 「10240バイト以下」
308  // 末尾にスペース(20H)を持つ可能性のある文字列
309  // 文字列の長さを偶数に保つために,末尾にスペースを挿入する必要あり
310  // 制御文字コードを含む
311  if( !isEven )
312  {
313  num_bytes++;
314  }
315 
316  num_bytes = compute_need_bytes( tag, 10240, num_bytes, false );
317  break;
318 
319  case OB:
320  // バイト列
321  // 「無制限」
322  // 転送構文のエンディアン形式に依存しないデータ列
323  // バイト列の長さを偶数に保つために,末尾にNULL値(00H)で埋められる可能性あり
324  if( !isEven )
325  {
326  num_bytes++;
327  }
328  break;
329 
330  case OF:
331  // 4バイト浮動小数のバイト列の並びワード列
332  // 「無制限」
333  // 転送構文のエンディアン形式に依存して,バイトの並びが変化するデータ列
334  break;
335 
336  case OW:
337  // ワード列
338  // 「無制限」
339  // 転送構文のエンディアン形式に依存して,バイトの並びが変化するデータ列
340  break;
341 
342  case PN:
343  // 患者名を表す文字列
344  // 「64バイト以下」
345  // 制御文字列を一切含まず,末尾にスペース(20H)を持つ可能性のある文字列
346  // 文字列の長さを偶数に保つために,末尾にスペースを挿入する必要あり
347  // 姓と名の区切りには,^ (5EH) が用いられる
348  if( !isEven )
349  {
350  num_bytes++;
351  }
352 
353  num_bytes = compute_need_bytes( tag, 64, num_bytes, false );
354  break;
355 
356  case SH:
357  // 短文字列
358  // 「16バイト以下」
359  // 先頭と末尾にスペース(20H)を持つ文字列
360  // 文字列の長さを偶数に保つために,末尾にスペースを挿入する必要あり
361  // 制御文字列は含まない
362  if( !isEven )
363  {
364  num_bytes++;
365  }
366 
367  num_bytes = compute_need_bytes( tag, 16, num_bytes, false );
368  break;
369 
370  case SL:
371  // 符号付き4バイト整数
372  // 「4バイト固定」
373  num_bytes = compute_need_bytes( tag, 4, num_bytes, true );
374  break;
375 
376  case SQ:
377  // シーケンスを表すタグ
378  // 「無制限」
379  // DICOMタグのシーケンスを格納するタグ
380  break;
381 
382  case SS:
383  // 符号付き2バイト整数
384  // 「2バイト固定」
385  num_bytes = compute_need_bytes( tag, 2, num_bytes, true );
386  break;
387 
388  case ST:
389  // 短テキスト文字列
390  // 末尾にスペース(20H)を持つ可能性のある文字列
391  // 文字列の長さを偶数に保つために,末尾にスペースを挿入する必要あり
392  // 制御文字コードを含む
393  if( !isEven )
394  {
395  num_bytes++;
396  }
397 
398  num_bytes = compute_need_bytes( tag, 1024, num_bytes, false );
399  break;
400 
401  case TM:
402  // 時刻を表す文字列
403  // 「16バイト以下」
404  // hhmmss.frac の書式で時刻を符号化した文字列
405  // これは,hh 時 mm 分 ss 秒 (frac は1億分の1秒単位) を表す
406  // 24時間形式の時刻表記が用いられ,深夜24時は0時として扱われる
407  // 文字列の長さを偶数に保つために,末尾にスペースを挿入する必要あり
408  if( !isEven )
409  {
410  num_bytes++;
411  }
412 
413  num_bytes = compute_need_bytes( tag, 16, num_bytes, false );
414  break;
415 
416  case UI:
417  // UIDを表す文字列
418  // 「64バイト以下」
419  // 文字列の長さを偶数に保つために,末尾にNULL (00H) を挿入する必要あり
420  if( !isEven )
421  {
422  num_bytes++;
423  }
424 
425  num_bytes = compute_need_bytes( tag, 64, num_bytes, false );
426  break;
427 
428  case UL:
429  // 符号無し4バイト整数
430  // 「4バイト固定」
431  num_bytes = compute_need_bytes( tag, 4, num_bytes, true );
432  break;
433 
434  case UN:
435  // 不明なタグ
436  break;
437 
438  case US:
439  // 符号無し2バイト整数
440  // 「2バイト固定」
441  num_bytes = compute_need_bytes( tag, 2, num_bytes, true );
442  break;
443 
444  case UT:
445  // 無制限のテキスト文字列
446  // 末尾にスペース(20H)を持つ可能性のある文字列
447  // 文字列の長さを偶数に保つために,末尾にスペースを挿入する必要あり
448  // 制御文字コードを含む
449  if( !isEven )
450  {
451  num_bytes++;
452  }
453  break;
454 
455  default:
456  // VRがわかんないからとりあえず良しとする
457  break;
458  }
459 
460  return( num_bytes );
461  }
462 
463  inline void padding_bytes( const dicom_tag &tag, unsigned char *from, unsigned char *to )
464  {
465  switch( tag.vr )
466  {
467  case AE:
468  case CS:
469  case DS:
470  case DT:
471  case IS:
472  case LO:
473  case LT:
474  case PN:
475  case SH:
476  case ST:
477  case TM:
478  case UT:
479  while( from != to )
480  {
481  *from++ = 0x20;
482  }
483  break;
484 
485  case OB:
486  case UI:
487  while( from != to )
488  {
489  *from++ = 0x00;
490  }
491  break;
492 
493  default:
494  break;
495  }
496  }
497 
499  class dicom_element : public dicom_tag
500  {
501  private:
502  typedef dicom_tag base;
503 
504  public:
505  unsigned char *data;
506  size_type num_bytes;
507 
509  void create( const size_type nbytes )
510  {
511  if( num_bytes != nbytes )
512  {
513  release( );
514  }
515 
516  num_bytes = nbytes;
517 
518  if( num_bytes != 0 && data == NULL )
519  {
520  data = new unsigned char[ num_bytes + 1 ];
521  data[ num_bytes ] = '\0';
522  }
523  }
524 
525 
527  void copy( const unsigned char *p, const size_type nbytes )
528  {
529  create( nbytes );
530 
531  if( num_bytes != 0 )
532  {
533  memcpy( data, p, nbytes );
534  }
535  }
536 
538  void swap( dicom_element &dicm )
539  {
540  if( &dicm != this )
541  {
542  unsigned char *tmp = data;
543  data = dicm.data;
544  dicm.data = tmp;
545 
546  size_type nbytes = num_bytes;
547  num_bytes = dicm.num_bytes;
548  dicm.num_bytes = nbytes;
549  }
550  }
551 
552 
554  void update( )
555  {
556  size_type need_bytes = compute_need_bytes( *this, num_bytes );
557 
558  if( num_bytes != need_bytes && need_bytes > 0 )
559  {
560  size_t nbytes = num_bytes;
561  unsigned char *tmp = data;
562  data = NULL;
563  num_bytes = 0;
564 
565  create( need_bytes );
566 
567  // タグのデータが仕様で定められた長さを超えている
568  if( nbytes > need_bytes )
569  {
570  nbytes = need_bytes;
571  }
572 
573  memcpy( data, tmp, nbytes );
574  padding_bytes( *this, data + nbytes, data + num_bytes );
575 
576  delete [] tmp;
577  }
578  }
579 
580 
582  void release( )
583  {
584  delete [] data;
585  data = NULL;
586  num_bytes = 0;
587  }
588 
589 
591  bool operator <( const dicom_element &dicm ) const { return( base::operator <( dicm ) ); }
592 
593 
595  const dicom_element &operator =( const dicom_element &dicm )
596  {
597  if( &dicm != this )
598  {
599  base::operator =( dicm );
600  create( dicm.num_bytes );
601  memcpy( data, dicm.data, sizeof( unsigned char ) * num_bytes );
602  }
603  return( *this );
604  }
605 
606 
608  void modify( const std::string &value )
609  {
610  switch( vr )
611  {
612  case FL:
613  {
614  float val = ( float )atof( value.c_str( ) );
615  *this = dicom_element( get_group( ), get_element( ), reinterpret_cast< unsigned char * >( &val ), sizeof( float ) );
616  }
617  break;
618  case FD:
619  {
620  double val = atof( value.c_str( ) );
621  *this = dicom_element( get_group( ), get_element( ), reinterpret_cast< unsigned char * >( &val ), sizeof( double ) );
622  }
623  break;
624  case SL:
625  {
626  long val = atoi( value.c_str( ) );
627  *this = dicom_element( get_group( ), get_element( ), reinterpret_cast< unsigned char * >( &val ), sizeof( long ) );
628  }
629  break;
630  case SS:
631  {
632  short val = ( short )atoi( value.c_str( ) );
633  *this = dicom_element( get_group( ), get_element( ), reinterpret_cast< unsigned char * >( &val ), sizeof( short ) );
634  }
635  break;
636  case UL:
637  {
638  unsigned long val = atoi( value.c_str( ) );
639  *this = dicom_element( get_group( ), get_element( ), reinterpret_cast< unsigned char * >( &val ), sizeof( unsigned long ) );
640  }
641  break;
642  case US:
643  {
644  unsigned short val = ( unsigned short )atoi( value.c_str( ) );
645  *this = dicom_element( get_group( ), get_element( ), reinterpret_cast< unsigned char * >( &val ), sizeof( unsigned short ) );
646  }
647  break;
648 
649  default:
650  *this = dicom_element( get_group( ), get_element( ), reinterpret_cast< const unsigned char * >( value.c_str( ) ), value.size( ) );
651  break;
652  }
653  }
654 
655 
657  double to_double( ) const { return( ( vr == FD && num_bytes == 8 )? byte_array< double >( data ).get_value( ) : static_cast< double > ( atof( to_string( ).c_str( ) ) ) ); }
658 
660  float to_float( ) const { return( ( vr == FL && num_bytes == 4 )? byte_array< float >( data ).get_value( ) : static_cast< float > ( atof( to_string( ).c_str( ) ) ) ); }
661 
663  signed int to_int( ) const { return( ( vr == SL && num_bytes == 4 )? byte_array< signed int >( data ).get_value( ) : static_cast< signed int > ( atoi( to_string( ).c_str( ) ) ) ); }
664 
666  unsigned int to_uint( ) const { return( ( vr == UL && num_bytes == 4 )? byte_array< unsigned int >( data ).get_value( ) : static_cast< unsigned int > ( atoi( to_string( ).c_str( ) ) ) ); }
667 
669  signed short to_short( ) const { return( ( vr == SS && num_bytes == 2 )? byte_array< signed short >( data ).get_value( ) : static_cast< signed short > ( atoi( to_string( ).c_str( ) ) ) ); }
670 
672  unsigned short to_ushort( ) const { return( ( vr == US && num_bytes == 2 )? byte_array< unsigned short >( data ).get_value( ) : static_cast< unsigned short >( atoi( to_string( ).c_str( ) ) ) ); }
673 
675  std::string to_string( ) const
676  {
677  if( data != NULL && num_bytes > 0 )
678  {
679  static char buff[ 128 ];
680  switch( vr )
681  {
682  case FL:
683  sprintf( buff, "%f", byte_array< float >( data ).get_value( ) );
684  break;
685  case FD:
686  sprintf( buff, "%f", byte_array< double >( data ).get_value( ) );
687  break;
688  case SL:
689  sprintf( buff, "%d", byte_array< signed int >( data ).get_value( ) );
690  break;
691  case SS:
692  sprintf( buff, "%d", byte_array< signed short >( data ).get_value( ) );
693  break;
694  case UL:
695  sprintf( buff, "%d", byte_array< unsigned int >( data ).get_value( ) );
696  break;
697  case US:
698  sprintf( buff, "%d", byte_array< unsigned short >( data ).get_value( ) );
699  break;
700 
701  case OB:
702  case OW:
703  case SQ:
704  case UN:
705  return( "..." );
706  break;
707 
708  default:
709  return( std::string( reinterpret_cast< char * >( data ) ) );
710  break;
711  }
712  return( buff );
713  }
714  else
715  {
716  return( "empty" );
717  }
718  }
719 
721  void show_tag( ) const
722  {
723  if( data == NULL || num_bytes == 0 )
724  {
725  printf( "( %04x, %04x, %s, % 8d, %s ) = undefined!!\n", get_group( ), get_element( ), get_dicom_vr( vr ).c_str(), static_cast< unsigned int >( num_bytes ), comment.c_str() );
726  }
727  else if( vr == UI )
728  {
729  // DICOMのUIDを変換する
730  dicom_uid uid = get_uid( std::string( reinterpret_cast< char * >( data ), num_bytes ) );
731  printf( "( %04x, %04x, %s, % 8d, %s ) = %s\n", get_group( ), get_element( ), get_dicom_vr( vr ).c_str(), static_cast< unsigned int >( num_bytes ), comment.c_str(), uid.name.c_str( ) );
732  }
733  else
734  {
735  switch( vr )
736  {
737  case FL:
738  printf( "( %04x, %04x, %s, % 8d, %s ) = %f\n", get_group( ), get_element( ), get_dicom_vr( vr ).c_str(), static_cast< unsigned int >( num_bytes ), comment.c_str(), to_float( ) );
739  break;
740  case FD:
741  printf( "( %04x, %04x, %s, % 8d, %s ) = %f\n", get_group( ), get_element( ), get_dicom_vr( vr ).c_str(), static_cast< unsigned int >( num_bytes ), comment.c_str(), to_double( ) );
742  break;
743  case SL:
744  printf( "( %04x, %04x, %s, % 8d, %s ) = %d\n", get_group( ), get_element( ), get_dicom_vr( vr ).c_str(), static_cast< unsigned int >( num_bytes ), comment.c_str(), to_int( ) );
745  break;
746  case SS:
747  printf( "( %04x, %04x, %s, % 8d, %s ) = %d\n", get_group( ), get_element( ), get_dicom_vr( vr ).c_str(), static_cast< unsigned int >( num_bytes ), comment.c_str(), to_short( ) );
748  break;
749  case UL:
750  printf( "( %04x, %04x, %s, % 8d, %s ) = %d\n", get_group( ), get_element( ), get_dicom_vr( vr ).c_str(), static_cast< unsigned int >( num_bytes ), comment.c_str(), to_uint( ) );
751  break;
752  case US:
753  printf( "( %04x, %04x, %s, % 8d, %s ) = %d\n", get_group( ), get_element( ), get_dicom_vr( vr ).c_str(), static_cast< unsigned int >( num_bytes ), comment.c_str(), to_ushort( ) );
754  break;
755 
756  case OB:
757  case OW:
758  case SQ:
759  case UN:
760  printf( "( %04x, %04x, %s, % 8d, %s ) = ...\n", get_group( ), get_element( ), get_dicom_vr( vr ).c_str(), static_cast< unsigned int >( num_bytes ), comment.c_str() );
761  break;
762 
763  default:
764  printf( "( %04x, %04x, %s, % 8d, %s ) = %s\n", get_group( ), get_element( ), get_dicom_vr( vr ).c_str(), static_cast< unsigned int >( num_bytes ), comment.c_str(), reinterpret_cast< char * >( data ) );
765  break;
766  }
767  }
768  }
769 
771  dicom_element( ) : base( ), data( NULL ), num_bytes( 0 )
772  {
773  }
774 
776  dicom_element( const dicom_element &dicm ) : base( dicm ), data( NULL ), num_bytes( 0 )
777  {
778  copy( dicm.data, dicm.num_bytes );
779  }
780 
782  dicom_element( unsigned short group, unsigned short element, const unsigned char *d = NULL, size_type nbytes = 0 )
783  : base( singleton< dicom_tag_table >::get_instance( ).get_tag( group, element ) ), data( NULL ), num_bytes( 0 )
784  {
785  copy( d, nbytes );
786  }
787 
789  dicom_element( const dicom_tag &t, const unsigned char *d = NULL, size_type nbytes = 0 ) : base( t ), data( NULL ), num_bytes( 0 )
790  {
791  copy( d, nbytes );
792  }
793 
796  {
797  release( );
798  }
799  };
800 
801 
803  class dicom_tag_container : public std::map< unsigned int, dicom_element >
804  {
805  private:
806  typedef std::map< unsigned int, dicom_element > base;
807  typedef std::pair< unsigned int, dicom_element > element_pair;
808 
809  public:
810  typedef base::iterator iterator;
811  typedef base::const_iterator const_iterator;
812  typedef base::const_reference const_reference;
813  typedef base::reference reference;
814 
815  public:
817  dicom_element &operator ()( unsigned short group, unsigned short element ){ return( base::operator []( construct_dicom_tag( group, element ) ) ); }
818 
820  const dicom_element &operator ()( unsigned short group, unsigned short element ) const
821  {
822  const_iterator cite = find( group, element );
823  return( cite->second );
824  }
825 
826  public:
828  bool add( const dicom_element &element )
829  {
830  std::pair< iterator, bool > ite = base::insert( element_pair( element.tag, element ) );
831  return( ite.second );
832  }
833 
835  iterator append( const dicom_element &element )
836  {
837  std::pair< iterator, bool > ite = base::insert( element_pair( element.tag, element ) );
838  return( ite.first );
839  }
840 
842  void erase( const dicom_element &element )
843  {
844  base::erase( element.tag );
845  }
846 
848  void erase( const dicom_tag &tag )
849  {
850  base::erase( tag.tag );
851  }
852 
854  void erase( unsigned short group, unsigned short element )
855  {
856  base::erase( construct_dicom_tag( group, element ) );
857  }
858 
860  void remove( const dicom_element &element )
861  {
862  base::erase( element.tag );
863  }
864 
866  void remove( const dicom_tag &tag )
867  {
868  base::erase( tag.tag );
869  }
870 
872  void remove( unsigned short group, unsigned short element )
873  {
874  base::erase( construct_dicom_tag( group, element ) );
875  }
876 
877 
879  iterator find( unsigned short group, unsigned short element )
880  {
881  return( base::find( construct_dicom_tag( group, element ) ) );
882  }
883 
885  const_iterator find( unsigned short group, unsigned short element ) const
886  {
887  return( base::find( construct_dicom_tag( group, element ) ) );
888  }
889 
890 
892  bool contain( unsigned short group, unsigned short element ) const
893  {
894  return( find( group, element ) != base::end( ) );
895  }
896 
898  void update( )
899  {
900  for( iterator ite = base::begin( ) ; ite != base::end( ) ; ++ite )
901  {
902  ite->second.update( );
903  }
904  }
905 
907  {
908  }
909  dicom_tag_container( const dicom_tag_container &dicm ) : base( dicm )
910  {
911  }
912  };
913 
916  {
917  public:
920 
921  unsigned short samples_per_pixel;
922  signed int number_of_frames;
923  unsigned short rows;
924  unsigned short cols;
931  double rescale_slope;
932  unsigned short bits_allocated;
933  unsigned short bits_stored;
934  unsigned short high_bits;
935  unsigned short pixel_representation;
936  unsigned short planar_configuration;
937  double window_center;
938  double window_width;
939 
940  double KVP;
941  double mA;
942  double thickness;
943 
944  dicom_image_info( ) :
945  compression_type( RAW ),
946  photometric_type( UNKNOWNTYPE ),
947  samples_per_pixel( 1 ),
948  number_of_frames( 1 ),
949  rows( 0 ),
950  cols( 0 ),
951  pixel_spacing_x( 1.0 ),
952  pixel_spacing_y( 1.0 ),
953  image_position_x( 1.0 ),
954  image_position_y( 1.0 ),
955  image_position_z( 1.0 ),
956  rescale_intercept( 0.0 ),
957  rescale_slope( 1.0 ),
958  bits_allocated( 8 ),
959  bits_stored( 8 ),
960  high_bits( 7 ),
961  pixel_representation( 0 ),
962  planar_configuration( 0 ),
963  window_center( 128 ),
964  window_width( 256 ),
965  KVP( 0.0 ),
966  mA( 0.0 ),
967  thickness( 0.0 )
968  {
969  }
970  };
971 
972 
975  {
976  public:
978  std::string study_instance_uid;
979  std::string series_instance_uid;
980  std::string study_id;
981  std::string patient_id;
985 
986  public:
989  little_endian_encoding( true ),
990  study_instance_uid( "0" ),
991  series_instance_uid( "0" ),
992  study_id( "0" ),
993  patient_id( "0" ),
994  series_number( 0 ),
995  acquisition_number( 0 ),
996  instance_number( 0 )
997  {
998  }
999 
1001  dicom_info( const dicom_info &info ) :
1002  dicom_image_info( info ),
1003  little_endian_encoding( info.little_endian_encoding ),
1004  study_instance_uid( info.study_instance_uid ),
1005  series_instance_uid( info.series_instance_uid ),
1006  study_id( info.study_id ),
1007  patient_id( info.patient_id ),
1008  series_number( info.series_number ),
1009  acquisition_number( info.acquisition_number ),
1010  instance_number( info.instance_number )
1011  {
1012  }
1013 
1014 
1016  const dicom_info &operator =( const dicom_info &info )
1017  {
1018  if( &info != this )
1019  {
1020  dicom_image_info::operator =( info );
1021  little_endian_encoding = info.little_endian_encoding;
1022  study_instance_uid = info.study_instance_uid;
1023  series_instance_uid = info.series_instance_uid;
1024  study_id = info.study_id;
1025  patient_id = info.patient_id;
1026  series_number = info.series_number;
1027  acquisition_number = info.acquisition_number;
1028  instance_number = info.instance_number;
1029  }
1030  return( *this );
1031  }
1032  };
1033 
1034  typedef struct
1035  {
1036  const char *uid;
1037  compress_type type;
1038  } __dicom_compress_type__;
1039 
1040  inline std::string trim( const std::string &str )
1041  {
1042  std::string::difference_type sindx = 0;
1043  std::string::difference_type eindx = str.length( ) - 1;
1044 
1045  for( ; sindx <= eindx ; sindx++ )
1046  {
1047  if( str[ sindx ] != 0x20 )
1048  {
1049  break;
1050  }
1051  }
1052 
1053  for( ; sindx <= eindx ; eindx-- )
1054  {
1055  if( str[ eindx ] != 0x20 )
1056  {
1057  break;
1058  }
1059  }
1060 
1061  if( sindx <= eindx )
1062  {
1063  return( str.substr( sindx, eindx - sindx + 1 ) );
1064  }
1065  else
1066  {
1067  return( "" );
1068  }
1069  }
1070 
1072  inline compress_type get_compress_type( const std::string &uid )
1073  {
1074  static __dicom_compress_type__ compress_type_list[] = {
1075  { "1.2.840.10008.1.2.4.50", JPEG, }, // JPEG 基準(処理 1):非可逆 JPEG 8 ビット画像圧縮用デフォルト転送構文
1076  { "1.2.840.10008.1.2.4.51", JPEG, }, // JPEG 拡張(処理 2 & 4):非可逆 JPEG 12 ビット画像圧縮用デフォルト転送構文(処理4のみ)
1077  { "1.2.840.10008.1.2.4.52", JPEG, }, // JPEG 拡張(処理 3 & 5)
1078  { "1.2.840.10008.1.2.4.53", JPEG, }, // JPEG スペクトル選択,非階層(処理 6 & 8)
1079  { "1.2.840.10008.1.2.4.54", JPEG, }, // JPEG スペクトル選択,非階層(処理 7 & 9)
1080  { "1.2.840.10008.1.2.4.55", JPEG, }, // JPEG 全数列,非階層(処理 10 & 12)
1081  { "1.2.840.10008.1.2.4.56", JPEG, }, // JPEG 全数列,非階層(処理 11 & 13)
1082  { "1.2.840.10008.1.2.4.57", JPEGLS, }, // JPEG 可逆,非階層(処理 14)
1083  { "1.2.840.10008.1.2.4.58", JPEGLS, }, // JPEG 可逆,非階層(処理 15)
1084  { "1.2.840.10008.1.2.4.59", JPEG, }, // JPEG 拡張,階層(処理 16 & 18)
1085  { "1.2.840.10008.1.2.4.60", JPEG, }, // JPEG 拡張,階層(処理 17 & 19)
1086  { "1.2.840.10008.1.2.4.61", JPEG, }, // JPEG スペクトル選択,階層(処理 20 & 22)
1087  { "1.2.840.10008.1.2.4.62", JPEG, }, // JPEG スペクトル選択,階層(処理 21 & 23)
1088  { "1.2.840.10008.1.2.4.63", JPEG, }, // JPEG 全数列,階層(処理 24 & 26)
1089  { "1.2.840.10008.1.2.4.64", JPEG, }, // JPEG 全数列,階層(処理 25 & 27)
1090  { "1.2.840.10008.1.2.4.65", JPEGLS, }, // JPEG 可逆,階層(処理 28)
1091  { "1.2.840.10008.1.2.4.66", JPEGLS, }, // JPEG 可逆,階層(処理 29)
1092  { "1.2.840.10008.1.2.4.70", JPEGLS, }, // JPEG 可逆,非階層,一次予測(処理 14 [選択値 1]):可逆 JPEG 画像圧縮用デフォルト転送構文
1093  { "1.2.840.10008.1.2.4.80", JPEGLS, }, // JPEG-LS 可逆画像圧縮
1094  { "1.2.840.10008.1.2.4.81", JPEGLS, }, // JPEG-LS 非可逆(準可逆)画像圧縮
1095  { "1.2.840.10008.1.2.4.90", JPEG2000, }, // JPEG 2000 Image Compression (Lossless Only)
1096  { "1.2.840.10008.1.2.4.91", JPEG2000, }, // JPEG 2000 Image Compression
1097  { "1.2.840.10008.1.2.5", RLE, }, // Run Length Encoding
1098  { NULL, RAW, },
1099  };
1100 
1101  __dicom_compress_type__ *list = compress_type_list;
1102  while( list->uid != NULL )
1103  {
1104  if( uid == list->uid )
1105  {
1106  return( list->type );
1107  }
1108  list++;
1109  }
1110 
1111  return( RAW );
1112  }
1113 
1114 
1116  inline double find_tag( const dicom_tag_container &dicm, unsigned short group, unsigned short element, double default_value )
1117  {
1118  dicom_tag_container::const_iterator cite = dicm.find( group, element );
1119  return( cite == dicm.end( ) ? default_value : cite->second.to_double( ) );
1120  }
1121 
1123  inline float find_tag( const dicom_tag_container &dicm, unsigned short group, unsigned short element, float default_value )
1124  {
1125  dicom_tag_container::const_iterator cite = dicm.find( group, element );
1126  return( cite == dicm.end( ) ? default_value : cite->second.to_float( ) );
1127  }
1128 
1130  inline signed int find_tag( const dicom_tag_container &dicm, unsigned short group, unsigned short element, signed int default_value )
1131  {
1132  dicom_tag_container::const_iterator cite = dicm.find( group, element );
1133  return( cite == dicm.end( ) ? default_value : cite->second.to_int( ) );
1134  }
1135 
1137  inline unsigned int find_tag( const dicom_tag_container &dicm, unsigned short group, unsigned short element, unsigned int default_value )
1138  {
1139  dicom_tag_container::const_iterator cite = dicm.find( group, element );
1140  return( cite == dicm.end( ) ? default_value : cite->second.to_uint( ) );
1141  }
1142 
1144  inline signed short find_tag( const dicom_tag_container &dicm, unsigned short group, unsigned short element, signed short default_value )
1145  {
1146  dicom_tag_container::const_iterator cite = dicm.find( group, element );
1147  return( cite == dicm.end( ) ? default_value : cite->second.to_short( ) );
1148  }
1149 
1151  inline unsigned short find_tag( const dicom_tag_container &dicm, unsigned short group, unsigned short element, unsigned short default_value )
1152  {
1153  dicom_tag_container::const_iterator cite = dicm.find( group, element );
1154  return( cite == dicm.end( ) ? default_value : cite->second.to_ushort( ) );
1155  }
1156 
1158  inline std::string find_tag( const dicom_tag_container &dicm, unsigned short group, unsigned short element, const std::string &default_value )
1159  {
1160  dicom_tag_container::const_iterator cite = dicm.find( group, element );
1161  return( cite == dicm.end( ) ? default_value : cite->second.to_string( ) );
1162  }
1163 
1165  inline std::string find_tag( const dicom_tag_container &dicm, unsigned short group, unsigned short element, const char *default_value )
1166  {
1167  dicom_tag_container::const_iterator cite = dicm.find( group, element );
1168  return( cite == dicm.end( ) ? default_value : cite->second.to_string( ) );
1169  }
1170 
1171  inline bool begin_with( const std::string &str1, const std::string &str2 )
1172  {
1173  if( str1.size( ) < str2.size( ) )
1174  {
1175  return( false );
1176  }
1177 
1178  for( size_t i = 0 ; i < str2.size( ) ; i++ )
1179  {
1180  if( str1[ i ] != str2[ i ] )
1181  {
1182  return( false );
1183  }
1184  }
1185 
1186  return( true );
1187  }
1188 
1189  inline bool can_convert_to_number( const std::string &str )
1190  {
1191  size_t i = 0;
1192  for( i = 0 ; i < str.size( ) ; i++ )
1193  {
1194  std::string::value_type ch = str[ i ];
1195  if( ( '0' <= ch && ch <= '9' ) || ( '+' <= ch && ch <= '.' ) )
1196  {
1197  break;
1198  }
1199  else if( ch != ' ' )
1200  {
1201  return( false );
1202  }
1203  }
1204  for( ; i < str.size( ) ; i++ )
1205  {
1206  std::string::value_type ch = str[ i ];
1207  if( ch == ' ' )
1208  {
1209  break;
1210  }
1211  else if( !( ( '0' <= ch && ch <= '9' ) || ( '+' <= ch && ch <= '.' ) ) )
1212  {
1213  return( false );
1214  }
1215  }
1216  for( ; i < str.size( ) ; i++ )
1217  {
1218  std::string::value_type ch = str[ i ];
1219  if( ch != ' ' )
1220  {
1221  return( false );
1222  }
1223  }
1224  return( true );
1225  }
1226 
1228  inline bool get_dicom_info( const dicom_tag_container &dicm, dicom_info &info )
1229  {
1230  info.little_endian_encoding = find_tag( dicm, 0x0002, 0x0010, "" ) != "1.2.840.10008.1.2.2";
1231 
1232  info.compression_type = get_compress_type( find_tag( dicm, 0x0002, 0x0010, "" ) );
1233  info.samples_per_pixel = find_tag( dicm, 0x0028, 0x0002, info.samples_per_pixel );
1234  info.number_of_frames = find_tag( dicm, 0x0028, 0x0008, info.number_of_frames );
1235  info.rows = find_tag( dicm, 0x0028, 0x0010, info.rows ); // X軸方向の解像度
1236  info.cols = find_tag( dicm, 0x0028, 0x0011, info.cols ); // Y軸方向の解像度
1237 
1238  // 画素の表現方法
1239  std::string photometric_interpretation = find_tag( dicm, 0x0028, 0x0004, "" );
1240  if( begin_with( photometric_interpretation, "MONOCHROME1" ) )
1241  {
1243  }
1244  else if( begin_with( photometric_interpretation, "MONOCHROME2" ) )
1245  {
1247  }
1248  else if( begin_with( photometric_interpretation, "RGB" ) )
1249  {
1250  info.photometric_type = RGB;
1251  }
1252  else if( begin_with( photometric_interpretation, "PALETTE COLOR" ) )
1253  {
1255  }
1256  else if( begin_with( photometric_interpretation, "YBR FULL 422" ) )
1257  {
1259  }
1260  else if( begin_with( photometric_interpretation, "YBR FULL" ) )
1261  {
1262  info.photometric_type = YBR_FULL;
1263  }
1264 
1265 
1266  // 画像のXY方向の解像度
1267  std::string pixel_spacing = find_tag( dicm, 0x0028, 0x0030, "" );
1268  if( pixel_spacing != "" )
1269  {
1270  double resoX = 1.0, resoY = 1.0;
1271  sscanf( pixel_spacing.c_str( ), "%lf\\%lf", &resoX, &resoY );
1272  info.pixel_spacing_x = resoX;
1273  info.pixel_spacing_y = resoY;
1274  }
1275 
1276  // イメージポジションを取得
1277  std::string image_position = find_tag( dicm, 0x0020, 0x0032, "" );
1278  if( image_position != "" )
1279  {
1280  double posX = 0.0, posY = 0.0, posZ = 0.0;
1281  sscanf( image_position.c_str( ), "%lf\\%lf\\%lf", &posX, &posY, &posZ );
1282  info.image_position_x = posX;
1283  info.image_position_y = posY;
1284  info.image_position_z = posZ;
1285  }
1286  else
1287  {
1288  info.image_position_z = find_tag( dicm, 0x2020, 0x0010, ( short )0 );
1289  }
1290 
1291  // 管電圧を取得
1292  std::string kvp = find_tag( dicm, 0x0018, 0x0060, "" );
1293  if( kvp != "" )
1294  {
1295  info.KVP = atof( kvp.c_str( ) );
1296  }
1297 
1298  // 管電流を取得
1299  std::string mA = find_tag( dicm, 0x0018, 0x1151, "" );
1300  if( mA != "" )
1301  {
1302  info.mA = atoi( mA.c_str( ) );
1303  }
1304 
1305  // スライス厚を取得
1306  info.thickness = find_tag( dicm, 0x0018, 0x0050, info.thickness );
1307 
1308  // 画素に適用するオフセットを取得
1309  std::string rescale_intercept = find_tag( dicm, 0x0028, 0x1052, "" );
1310  if( rescale_intercept != "" && can_convert_to_number( rescale_intercept ) )
1311  {
1312  info.rescale_intercept = atof( rescale_intercept.c_str( ) );
1313  }
1314 
1315  // 画素に適用する傾きを取得
1316  std::string rescale_slope = find_tag( dicm, 0x0028, 0x1053, "" );
1317  if( rescale_slope != "" && can_convert_to_number( rescale_slope ) )
1318  {
1319  info.rescale_slope = atof( rescale_slope.c_str( ) );
1320  }
1321 
1322  // Window Centerを取得
1323  std::string window_center = find_tag( dicm, 0x0028, 0x1050, "" );
1324  if( window_center != "" && can_convert_to_number( window_center ) )
1325  {
1326  info.window_center = atof( window_center.c_str( ) );
1327  }
1328 
1329  // Window Widthを取得
1330  std::string window_width = find_tag( dicm, 0x0028, 0x1051, "" );
1331  if( window_width != "" && can_convert_to_number( window_width ) )
1332  {
1333  info.window_width = atof( window_width.c_str( ) );
1334  }
1335 
1336  info.bits_allocated = find_tag( dicm, 0x0028, 0x0100, info.bits_allocated );
1337  info.bits_stored = find_tag( dicm, 0x0028, 0x0101, info.bits_stored );
1338  info.high_bits = find_tag( dicm, 0x0028, 0x0102, info.high_bits );
1339  info.pixel_representation = find_tag( dicm, 0x0028, 0x0103, info.pixel_representation );
1340  info.planar_configuration = find_tag( dicm, 0x0028, 0x0006, info.planar_configuration );
1341 
1342  // データのシリーズを識別するデータを取得
1343  info.study_instance_uid = find_tag( dicm, 0x0020, 0x000D, info.study_instance_uid );
1344  info.series_instance_uid = find_tag( dicm, 0x0020, 0x000E, info.series_instance_uid );
1345  info.series_number = find_tag( dicm, 0x0020, 0x0011, info.series_number );
1346  info.acquisition_number = find_tag( dicm, 0x0020, 0x0012, info.acquisition_number );
1347  info.instance_number = find_tag( dicm, 0x0020, 0x0013, info.instance_number );
1348 
1349  info.study_id = find_tag( dicm, 0x0020, 0x0010, info.study_id );
1350  info.patient_id = find_tag( dicm, 0x0010, 0x0020, info.patient_id );
1351 
1352  return( true );
1353  }
1354 
1363  inline bool is_element_begin( const unsigned char *p, const unsigned char *e )
1364  {
1365  if( p + 4 > e )
1366  {
1367  return( false );
1368  }
1369  return( p[ 0 ] == 0xfe && p[ 1 ] == 0xff && p[ 2 ] == 0x00 && p[ 3 ] == 0xe0 );
1370  }
1371 
1380  inline bool is_element_end( const unsigned char *p, const unsigned char *e )
1381  {
1382  if( p + 8 > e )
1383  {
1384  return( false );
1385  }
1386  return( p[ 0 ] == 0xfe && p[ 1 ] == 0xff && p[ 2 ] == 0xdd && p[ 3 ] == 0xe0 && p[ 4 ] == 0x00 && p[ 5 ] == 0x00 && p[ 6 ] == 0x00 && p[ 7 ] == 0x00 );
1387  }
1388 
1389 
1400  inline unsigned char *decode_RLE( unsigned char *psrc, unsigned char *psrc_end, unsigned char *pdst, unsigned char *pdst_end, bool from_little_endian = true )
1401  {
1402  if( psrc + 64 >= psrc_end )
1403  {
1404  // RLE圧縮がかかっていません
1405  return( NULL );
1406  }
1407 
1408  // RLEのヘッダ情報を読み込む
1409  size_type number_of_segments = to_current_endian( byte_array< unsigned int >( psrc ), true ).get_value( );
1410  difference_type frame_offset[ 15 ] = {
1411  to_current_endian( byte_array< unsigned int >( psrc + 4 ), from_little_endian ).get_value( ),
1412  to_current_endian( byte_array< unsigned int >( psrc + 8 ), from_little_endian ).get_value( ),
1413  to_current_endian( byte_array< unsigned int >( psrc + 12 ), from_little_endian ).get_value( ),
1414  to_current_endian( byte_array< unsigned int >( psrc + 16 ), from_little_endian ).get_value( ),
1415  to_current_endian( byte_array< unsigned int >( psrc + 20 ), from_little_endian ).get_value( ),
1416  to_current_endian( byte_array< unsigned int >( psrc + 24 ), from_little_endian ).get_value( ),
1417  to_current_endian( byte_array< unsigned int >( psrc + 28 ), from_little_endian ).get_value( ),
1418  to_current_endian( byte_array< unsigned int >( psrc + 32 ), from_little_endian ).get_value( ),
1419  to_current_endian( byte_array< unsigned int >( psrc + 36 ), from_little_endian ).get_value( ),
1420  to_current_endian( byte_array< unsigned int >( psrc + 40 ), from_little_endian ).get_value( ),
1421  to_current_endian( byte_array< unsigned int >( psrc + 44 ), from_little_endian ).get_value( ),
1422  to_current_endian( byte_array< unsigned int >( psrc + 48 ), from_little_endian ).get_value( ),
1423  to_current_endian( byte_array< unsigned int >( psrc + 52 ), from_little_endian ).get_value( ),
1424  to_current_endian( byte_array< unsigned int >( psrc + 56 ), from_little_endian ).get_value( ),
1425  to_current_endian( byte_array< unsigned int >( psrc + 60 ), from_little_endian ).get_value( ),
1426  };
1427 
1428  if( frame_offset[ 0 ] != 64 )
1429  {
1430  frame_offset[ 0 ] = 64;
1431  }
1432 
1433  size_type n = 0;
1434  while( n < number_of_segments && psrc < psrc_end && pdst < pdst_end )
1435  {
1436  char *p = reinterpret_cast< char * >( psrc + frame_offset[ n ] );
1437  char *e = reinterpret_cast< char * >( n == number_of_segments - 1 ? psrc_end : psrc + frame_offset[ n + 1 ] );
1438  while( p < e && pdst < pdst_end )
1439  {
1440  difference_type num = *p++;
1441  if( 0 <= num && num <= 127 )
1442  {
1443  num = num + 1;
1444  if( p + num <= e && pdst + num <= pdst_end )
1445  {
1446  for( difference_type i = 0 ; i < num ; i++ )
1447  {
1448  pdst[ i ] = p[ i ];
1449  }
1450  }
1451  p += num;
1452  pdst += num;
1453  }
1454  else if( -127 <= num && num <= -1 )
1455  {
1456  num = 1 - num;
1457  if( p + 1 <= e && pdst + num <= pdst_end )
1458  {
1459  for( difference_type i = 0 ; i < num ; i++ )
1460  {
1461  pdst[ i ] = *p;
1462  }
1463  }
1464  p++;
1465  pdst += num;
1466  }
1467  }
1468  n++;
1469  }
1470 
1471  return( pdst );
1472  }
1473 
1474 #ifdef __DECODE_JPEG_COMPRESSION__
1475  static void JpegInitSource( j_decompress_ptr dinfo )
1476  {
1477  }
1478 
1479  static boolean JpegFillInputBuffer( j_decompress_ptr dinfo )
1480  {
1481  return TRUE;
1482  }
1483 
1484  static void JpegSkipInputData( j_decompress_ptr dinfo, long num_bytes )
1485  {
1486  jpeg_source_mgr &jpegSrcManager = *( dinfo->src );
1487  jpegSrcManager.next_input_byte += (size_t) num_bytes;
1488  jpegSrcManager.bytes_in_buffer -= (size_t) num_bytes;
1489  }
1490 
1491  static void JpegTermSource( j_decompress_ptr dinfo )
1492  {
1493  /* No work necessary here. */
1494  }
1495 #endif
1496 
1506  inline unsigned char *decode_JPEG( unsigned char *psrc, unsigned char *psrc_end, unsigned char *pdst, unsigned char *pdst_end )
1507  {
1508 #ifdef __DECODE_JPEG_COMPRESSION__
1509  difference_type compressedLen = psrc_end - psrc;
1510  if( compressedLen <= 0 )
1511  {
1512  return( NULL );
1513  }
1514 
1515  JDIMENSION i, j;
1516  JSAMPROW bitmap[1]; // ビットマップデータ配列へのポインター
1517  jpeg_decompress_struct dinfo; // JPEG解凍情報構造体
1518  jpeg_error_mgr jerr; // JPEGエラー処理用構造体
1519  int scanlen, c; // ビットマップ1行のバイト数
1520 
1521  dinfo.err = jpeg_std_error( &jerr );
1522  jpeg_create_decompress( &dinfo );
1523 
1524  jpeg_source_mgr jpegSrcManager;
1525  jpegSrcManager.init_source = JpegInitSource;
1526  jpegSrcManager.fill_input_buffer = JpegFillInputBuffer;
1527  jpegSrcManager.skip_input_data = JpegSkipInputData;
1528  jpegSrcManager.resync_to_restart = jpeg_resync_to_restart;
1529  jpegSrcManager.term_source = JpegTermSource;
1530  jpegSrcManager.next_input_byte = psrc;
1531  jpegSrcManager.bytes_in_buffer = compressedLen;
1532  dinfo.src = &jpegSrcManager;
1533 
1534  jpeg_read_header( &dinfo, TRUE );
1535 // dinfo.out_color_space = JCS_RGB;
1536 
1537  jpeg_start_decompress( &dinfo );
1538 
1539  scanlen = dinfo.output_width * dinfo.output_components;
1540 
1541  JSAMPLE *buffer = new JSAMPLE[ scanlen ];
1542  for( j = 0 ; j < dinfo.output_height ; j++ )
1543  {
1544  bitmap[ 0 ] = &buffer[ 0 ];
1545  if( dinfo.output_scanline < dinfo.output_height ) jpeg_read_scanlines( &dinfo, bitmap, 1 );
1546  for( i = 0 ; i < dinfo.output_width ; i++ )
1547  {
1548  for( c = 0 ; c < dinfo.output_components ; c++ )
1549  {
1550  *pdst++ = buffer[ i * dinfo.output_components + c ];
1551  }
1552  }
1553  }
1554 
1555  jpeg_finish_decompress(&dinfo);
1556  jpeg_destroy_decompress(&dinfo);
1557 
1558  return( pdst );
1559 #else
1560  return( NULL );
1561 #endif
1562  }
1563 
1564 
1575  inline bool decode( dicom_element &element, const dicom_info &info )
1576  {
1577  switch( info.compression_type )
1578  {
1579  case RAW:
1580  return( true );
1581 
1582 //#ifndef __DECODE_JPEG_COMPRESSION__
1583 // case JPEG:
1584 // case JPEGLS:
1585 // case JPEG2000:
1586 // // 今のところ未サポート
1587 // return( false );
1588 //#endif
1589 
1590  default:
1591  break;
1592  }
1593 
1594  if( element.num_bytes < 8 + 8 )
1595  {
1596  // 圧縮がかかっていません
1597  return( false );
1598  }
1599 
1600  unsigned char *pointer = element.data;
1601  unsigned char *end_pointer = element.data + element.num_bytes;
1602  difference_type num_bytes = element.num_bytes;
1603  difference_type frame_offset[ 16 ] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
1604  size_type number_of_fragments = 0;
1605 
1606  // ベーシックオフセットテーブルをスキップ
1607  if( !is_element_begin( pointer, end_pointer ) )
1608  {
1609  return( false );
1610  }
1611  pointer += 4;
1612  num_bytes = to_current_endian( byte_array< unsigned int >( pointer ), info.little_endian_encoding ).get_value( );
1613  pointer += 4;
1614  if( num_bytes > 0 )
1615  {
1616  // 各フレームへのポインタが発見されたので調査
1617  unsigned char *p = pointer;
1618  while( p < pointer + num_bytes && number_of_fragments < 16 )
1619  {
1620  frame_offset[ number_of_fragments++ ] = to_current_endian( byte_array< unsigned int >( p ), info.little_endian_encoding ).get_value( );
1621  p += 4;
1622  }
1623  }
1624  else
1625  {
1626  number_of_fragments = 1;
1627  }
1628  if( num_bytes < 0 )
1629  {
1630  return( false );
1631  }
1632  pointer += num_bytes;
1633  if( pointer > end_pointer )
1634  {
1635  return( false );
1636  }
1637 
1638  size_type dstBytes = info.rows * info.cols * info.number_of_frames * info.samples_per_pixel * info.bits_allocated / 8;
1639  unsigned char *buff = new unsigned char[ dstBytes + 1 ];
1640  unsigned char *dst_pointer = buff;
1641  unsigned char *p = pointer;
1642  bool ret = true;
1643 
1644  // ベーシックオフセットテーブルをスキップ
1645  size_type i = 0;
1646  while( dst_pointer < buff + dstBytes && i < number_of_fragments && ret )
1647  {
1648  p = pointer + frame_offset[ i ];
1649  if( !is_element_begin( p, end_pointer ) )
1650  {
1651  return( false );
1652  }
1653  p += 4;
1654  num_bytes = to_current_endian( byte_array< unsigned int >( p ), info.little_endian_encoding ).get_value( );
1655  p += 4;
1656 
1657  switch( info.compression_type )
1658  {
1659  case RLE:
1660  dst_pointer = decode_RLE( p, p + num_bytes, dst_pointer, buff + dstBytes, info.little_endian_encoding );
1661  if( dst_pointer == NULL )
1662  {
1663  ret = false;
1664  }
1665  break;
1666 
1667  case JPEG:
1668  case JPEGLS:
1669  case JPEG2000:
1670  memcpy( dst_pointer, p, num_bytes );
1671  dst_pointer += num_bytes;
1672  break;
1673 
1674  default:
1675  break;
1676  }
1677  i++;
1678  }
1679 
1680  if( ret )
1681  {
1682  element.copy( buff, dst_pointer - buff );
1683  }
1684 
1685  delete [] buff;
1686  return( ret );
1687  }
1688 
1689 }
1690 
1691 
1693 // DICOM画像入出力グループの終わり
1694 
1695 
1697 // 画像入出力グループの終わり
1698 
1699 
1700 // mist名前空間の終わり
1701 _MIST_END
1702 
1703 
1704 #endif // __INCLUDE_MIST_DICOM_INFO__
1705 

Generated on Wed Nov 12 2014 19:44:14 for MIST by doxygen 1.8.1.2