- メインページ
- モジュール
- ネームスペース
- データ構造
- ファイル

- ファイル一覧
- グローバル

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名前空間の始まり
81 _MIST_BEGIN
82
83
86
89
90
92 namespace dicom
93 {
95 enum compress_type
96 {
97 RAW,
98 JPEG,
99 JPEGLS,
100 JPEG2000,
101 RLE,
102 };
103
105 enum photometric_interpretation_type
106 {
107 UNKNOWNTYPE,
108 MONOCHROME1,
109 MONOCHROME2,
110 RGB,
111 PALETTE_COLOR,
112 YBR_FULL_422,
113 YBR_FULL,
114 };
115
117 inline dicom_uid_table & get_dicom_uid_table( )
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
795 ~dicom_element( )
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
906 dicom_tag_container( )
907 {
908 }
909 dicom_tag_container( const dicom_tag_container &dicm ) : base( dicm )
910 {
911 }
912 };
913
915 class dicom_image_info
916 {
917 public:
918 compress_type compression_type;
919 photometric_interpretation_type photometric_type;
920
921 unsigned short samples_per_pixel;
922 signed int number_of_frames;
923 unsigned short rows;
924 unsigned short cols;
925 double pixel_spacing_x;
926 double pixel_spacing_y;
927 double image_position_x;
928 double image_position_y;
929 double image_position_z;
930 double rescale_intercept;
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
974 class dicom_info : public dicom_image_info
975 {
976 public:
977 bool little_endian_encoding;
978 std::string study_instance_uid;
979 std::string series_instance_uid;
980 std::string study_id;
981 std::string patient_id;
982 int series_number;
983 int acquisition_number;
984 int instance_number;
985
986 public:
988 dicom_info( ) :
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 {
1242 info.photometric_type = MONOCHROME1;
1243 }
1244 else if( begin_with( photometric_interpretation, "MONOCHROME2" ) )
1245 {
1246 info.photometric_type = MONOCHROME2;
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 {
1254 info.photometric_type = PALETTE_COLOR;
1255 }
1256 else if( begin_with( photometric_interpretation, "YBR FULL 422" ) )
1257 {
1258 info.photometric_type = YBR_FULL_422;
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; // ビットマップ１行のバイト数
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