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

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

dicom.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__
34 #define __INCLUDE_MIST_DICOM__
35
36
37 #ifndef __INCLUDE_MIST_CONF_H__
38 #include "../config/mist_conf.h"
39 #endif
40
41 #ifndef __INCLUDE_MIST_H__
42 #include "../mist.h"
43 #endif
44
45 #ifndef __INCLUDE_MIST_ENDIAN__
46 #include "../config/endian.h"
47 #endif
48
49 #ifndef __INCLUDE_MIST_LIMITS__
50 #include "../limits.h"
51 #endif
52
53 // カラー画像の設定を読み込む
54 #ifndef __INCLUDE_MIST_COLOR_H__
55 #include "../config/color.h"
56 #endif
57
58 #ifndef __INCLUDE_MIST_DICOM_TAG__
59 #include "./dicom_tag.h"
60 #endif
61
62 #ifndef __INCLUDE_MIST_DICOM_INFO__
63 #include "./dicom_info.h"
64 #endif
65
66 #ifndef __INCLUDE_MIST_SINGLETON__
67 #include "../singleton.h"
68 #endif
69
70 // mist名前空間の始まり
71 _MIST_BEGIN
72
73
76
84
85
86 // 次のマクロを定義すると，コンソール上に読み込んだタグ情報を表示する
87 // #define __SHOW_DICOM_TAG__
88 // #define __SHOW_DICOM_UNKNOWN_TAG__
89 // #define __SHOW_DICOM_ZEROBYTE_TAG__
90 // #define __CHECK_TAG_FORMAT__
91
92 // 次のマクロを定義すると，認識不能なタグは排除する
93 // #define __EXCLUDE_DICOM_UNKNOWN_TAG__
94 // #define __EXCLUDE_DICOM_ZEROBYTE_TAG__
95
96
98 namespace dicom
99 {
109 inline unsigned char *check_dicom_file( unsigned char *p, unsigned char *e )
110 {
111 if( p == NULL || p + 4 >= e )
112 {
113 return( NULL );
114 }
115
116 char *dicm = reinterpret_cast< char * >( p ) + 128;
117 if( dicm[ 0 ] == 'D' && dicm[ 1 ] == 'I' && dicm[ 2 ] == 'C' && dicm[ 3 ] == 'M' )
118 {
119 if( p + 4 + 128 >= e )
120 {
121 return( NULL );
122 }
123 else
124 {
125 return( p + 128 + 4 );
126 }
127 }
128
129 // DICOM用のプリアンブルが存在しないため，先頭のポインタを返す
130 return( p );
131 }
132
133
142 inline bool is_sequence_separate_tag( const unsigned char *p, const unsigned char *e )
143 {
144 if( p + 4 > e )
145 {
146 return( false );
147 }
148 return( p[ 0 ] == 0xfe && p[ 1 ] == 0xff && p[ 2 ] == 0x00 && p[ 3 ] == 0xe0 );
149 }
150
159 inline bool is_sequence_element_end( const unsigned char *p, const unsigned char *e )
160 {
161 if( p + 8 > e )
162 {
163 return( false );
164 }
165 return( p[ 0 ] == 0xfe && p[ 1 ] == 0xff && p[ 2 ] == 0x0d && p[ 3 ] == 0xe0 && p[ 4 ] == 0x00 && p[ 5 ] == 0x00 && p[ 6 ] == 0x00 && p[ 7 ] == 0x00 );
166 }
167
176 inline bool is_sequence_tag_end( const unsigned char *p, const unsigned char *e )
177 {
178 if( p + 8 > e )
179 {
180 return( false );
181 }
182 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 );
183 }
184
185 template < bool _IS_SIGNED_ >
186 struct __check_num_bytes_function__
187 {
188 template < class T >
189 static ptrdiff_t check( const T &nbytes )
190 {
191 if( nbytes == type_limits< T >::maximum( ) )
192 {
193 return( -1 );
194 }
195 else
196 {
197 return( nbytes );
198 }
199 }
200 };
201
202 template < >
203 struct __check_num_bytes_function__< true >
204 {
205 template < class T >
206 static ptrdiff_t check( const T &nbytes )
207 {
208 return( nbytes );
209 }
210 };
211
212 template < class T >
213 inline ptrdiff_t __check_num_bytes__( const T &nbytes )
214 {
215 return( __check_num_bytes_function__< std::numeric_limits< T >::is_signed >::check( nbytes ) );
216 }
217
233 inline unsigned char *read_dicom_tag( unsigned char *p, unsigned char *e, dicom_tag &tag, difference_type &numBytes, bool from_little_endian = true )
234 {
235 if( p == NULL || p + 8 > e )
236 {
237 numBytes = -1;
238 return( e );
239 }
240
241 unsigned char *data = p;
242
243 unsigned short group = to_current_endian( byte_array< unsigned short >( data ), from_little_endian ).get_value( );
244 unsigned short element = to_current_endian( byte_array< unsigned short >( data + 2 ), from_little_endian ).get_value( );
245
246 data += 4;
247
248 char VR[ 3 ] = { static_cast< char >( data[ 0 ] ), static_cast< char >( data[ 1 ] ), '\0' };
249 dicom_vr vr = get_dicom_vr( VR );
250
251 difference_type num_bytes = 0;
252 const dicom_tag_table &dicom_table = singleton< dicom_tag_table >::get_instance( );
253 tag = dicom_table.get_tag( group, element, vr );
254
255 if( tag.tag != 0xffffffff )
256 {
257 //タグがテーブルに登録されている場合
258 if( tag.vr == vr )
259 {
260 // 明示的VR
261 switch( vr )
262 {
263 case OB:
264 case OW:
265 case UN:
266 case SQ:
267 case OF:
268 case UT:
269 data += 4;
270 num_bytes = __check_num_bytes__( to_current_endian( byte_array< unsigned int >( data ), from_little_endian ).get_value( ) );
271 break;
272
273 default:
274 num_bytes = __check_num_bytes__( to_current_endian( byte_array< unsigned short >( data + 2 ), from_little_endian ).get_value( ) );
275 break;
276 }
277 }
278 else if( vr != UNKNOWN )
279 {
280 // 明示的VRであるが，辞書と異なる場合
281 tag.vr = vr;
282 switch( vr )
283 {
284 case OB:
285 case OW:
286 case UN:
287 case SQ:
288 case OF:
289 case UT:
290 data += 4;
291 num_bytes = __check_num_bytes__( to_current_endian( byte_array< unsigned int >( data ), from_little_endian ).get_value( ) );
292 break;
293
294 default:
295 num_bytes = __check_num_bytes__( to_current_endian( byte_array< unsigned short >( data + 2 ), from_little_endian ).get_value( ) );
296 }
297 }
298 else
299 {
300 // 暗示的VR
301 num_bytes = __check_num_bytes__( to_current_endian( byte_array< unsigned int >( data ), from_little_endian ).get_value( ) );
302 }
303
304 numBytes = num_bytes;
305 return( reinterpret_cast< unsigned char * >( data + 4 ) );
306 }
307 else
308 {
309 //タグがテーブルに登録されていない場合はデータスキップ
310 switch( vr )
311 {
312 case AE:
313 case AS:
314 case AT:
315 case CS:
316 case DA:
317 case DS:
318 case DT:
319 case FL:
320 case FD:
321 case IS:
322 case LO:
323 case LT:
324 case PN:
325 case SH:
326 case SL:
327 case SS:
328 case ST:
329 case TM:
330 case UI:
331 case UL:
332 case US:
333 num_bytes = __check_num_bytes__( to_current_endian( byte_array< unsigned short >( data + 2 ), from_little_endian ).get_value( ) );
334 break;
335
336 case OB:
337 case OW:
338 case UN:
339 case SQ:
340 case OF:
341 case UT:
342 data += 4;
343 num_bytes = __check_num_bytes__( to_current_endian( byte_array< unsigned int >( data ), from_little_endian ).get_value( ) );
344 break;
345
346 default:
347 num_bytes = __check_num_bytes__( to_current_endian( byte_array< unsigned int >( data ), from_little_endian ).get_value( ) );
348 break;
349 }
350
351 #if defined( __SHOW_DICOM_ZEROBYTE_TAG__ ) && defined( __SHOW_DICOM_UNKNOWN_TAG__ )
352 printf( "( %04x, %04x, %s, % 8d ) = Unknown Tags!!\n", group, element, VR, num_bytes );
353 #endif
354 if( vr == SQ )
355 {
356 // 不明なタグだけどシーケンスタグということを確認
357 tag = dicom_tag( construct_dicom_tag( group, element ), SQ, -1, "UNKNOWN" );
358 numBytes = num_bytes;
359 return( data + 4 );
360 }
361 else if( data + 4 + 4 <= e && data[ 0 ] == 0xff && data[ 1 ] == 0xff && data[ 2 ] == 0xff && data[ 3 ] == 0xff && is_sequence_separate_tag( data + 4, e ) )
362 {
363 // 不明なタグだけどシーケンスタグの可能性がある場合ということを確認
364 tag = dicom_tag( construct_dicom_tag( group, element ), SQ, -1, "UNKNOWN" );
365 numBytes = num_bytes;
366 return( data + 4 );
367 }
368 else if( data + 4 + num_bytes <= e )
369 {
370 if( element == 0x0000 )
371 {
372 // Group Length タグ
373 char str[ 50 ];
374 sprintf( str, "Group %04d Length", group );
375 tag = dicom_tag( construct_dicom_tag( group, element ), UL, 1, str );
376 numBytes = num_bytes;
377 return( reinterpret_cast< unsigned char * >( data + 4 ) );
378 }
379 else
380 {
381 tag = dicom_tag( construct_dicom_tag( group, element ), vr, -1, "UNKNOWN" );
382 numBytes = num_bytes;
383 return( reinterpret_cast< unsigned char * >( data + 4 ) );
384 }
385 }
386 else
387 {
388 numBytes = -2;
389 return( p );
390 }
391 }
392 }
393
394
395
405 inline bool process_dicom_tag( const dicom_tag &tag, unsigned char *byte, difference_type num_bytes, bool from_little_endian = true )
406 {
407 switch( tag.vr )
408 {
409 case AE:
410 // Application Entity
411 // 「16バイト以下」
412 // 先頭と末尾にスペース（20H）を持つ可能性のある文字列
413 // 文字列の長さを偶数に保つために，末尾にスペースを挿入する必要あり
414 // スペースは特に意味なし
415 if( tag.vm != -1 && num_bytes > 16 * tag.vm )
416 {
417 return( false );
418 }
419 break;
420
421 case AS:
422 // 年齢を表す文字列
423 // 「4バイト固定」
424 // 文字列の書式は nnnD, nnnW, nnnM, nnnY のいずれか
425 // 使用可能な値は，0-9, D, W, M, Y のいずれか
426 // 　D: nnn → 日
427 // 　W: nnn → 週
428 // 　M: nnn → 月
429 // 　Y: nnn → 年
430 //
431 // 例： "018M" は生後18ヶ月を表す
432 if( tag.vm != -1 && ( num_bytes % 4 != 0 || (int)( num_bytes / 4 ) > tag.vm ) )
433 {
434 return( false );
435 }
436 break;
437
438 case AT:
439 // Attribute Tag
440 // 「4バイト固定」
441 // 2つの16ビット符号なし整数の並び
442 //
443 // 例： (0018,00FF) のタグは，4バイトの並びで表現され，エンディアンの違いにより以下のように符号化される
444 // リトルエンディアン転送構文 → 18H, 00H, FFH, 00H
445 // ビッグエンディアン転送構文 → 00H, 18H, 00H, FFH
446 if( tag.vm != -1 && ( num_bytes % 4 != 0 || (int)( num_bytes / 4 ) > tag.vm ) )
447 {
448 return( false );
449 }
450
451 if( _is_little_endian_( ) != from_little_endian )
452 {
453 for( long i = 0 ; i < num_bytes ; i += 4 )
454 {
455 unsigned char v0 = byte[ i + 0 ];
456 unsigned char v1 = byte[ i + 1 ];
457 unsigned char v2 = byte[ i + 2 ];
458 unsigned char v3 = byte[ i + 3 ];
459 byte[ i + 0 ] = v1;
460 byte[ i + 1 ] = v0;
461 byte[ i + 2 ] = v3;
462 byte[ i + 3 ] = v2;
463 }
464 }
465 break;
466
467 case CS:
468 // Code String
469 // 「16バイト以下」
470 // 先頭と末尾にスペース（20H）を持つ可能性のある文字列
471 // 文字列の長さを偶数に保つために，末尾にスペースを挿入する必要あり
472 // スペースは特に意味なし
473 // 大文字の A-Z, 0-9, アンダーバー（_）のみを使用可能．
474 if( tag.vm != -1 && num_bytes > 16 * tag.vm )
475 {
476 return( false );
477 }
478 break;
479
480 case DA:
481 // 日付を表す文字列
482 // 「8バイト固定」ただし，DICOM2.0では「10バイト固定」のためどちらも扱えるようにする必要あり
483 // yyyymmdd もしくは yyyy.mm.dd の書式で日付を符号化した文字列
484 // これは，yyyy 年 mm 月 dd 日を表す
485 // 0-9, ピリオド（.）のみを使用可能．
486 //
487 // 例：19930822 は 1993 年 8 月 22 日を表す
488 if( tag.vm != -1 && ( num_bytes % 8 != 0 || (int)( num_bytes / 8 ) > tag.vm ) && ( num_bytes % 10 != 0 || (int)( num_bytes / 10 ) > tag.vm ) )
489 {
490 return( false );
491 }
492 break;
493
494 case DS:
495 // 10進数を表す文字列
496 // 「16バイト以下」
497 // 固定小数点もしくは浮動小数点数を表現する文字列であり，先頭と末尾にスペース（20H）を持つ可能性のある文字列
498 // 固定小数点数の場合は 0-9 に加え，先頭に + もしくは -，さらに小数点を示す任意の . を含む
499 // 浮動小数点数は，ANSI X3.9 に従い，指数を示す E もしくは e を含む
500 // 文字列の長さを偶数に保つために，末尾にスペースを挿入する必要あり
501 if( tag.vm != -1 && num_bytes > 16 * tag.vm )
502 {
503 return( false );
504 }
505 break;
506
507 case DT:
508 // 日時を表す文字列
509 // 「26バイト以下」
510 // YYYYMMDDHHMMSS.FFFFFF&ZZZZ の書式に従って日時を表し，先頭と末尾にスペース（20H）を持つ可能性のある文字列
511 // これは，YYYY 年 MM 月 DD 日 HH 時 MM 分 SS.FFFFFF 秒（FFFFFFは病の小数部分）を表す
512 // また，& は + もしくは - のどちらかであり，ZZZZ は時間と分のオフセットを表す
513 // 文字列の長さを偶数に保つために，末尾にスペースを挿入する必要あり
514 if( tag.vm != -1 && num_bytes > 26 * tag.vm )
515 {
516 return( false );
517 }
518 break;
519
520 case FL:
521 // 単精度浮動小数
522 // 「4バイト固定」
523 if( tag.vm != -1 && ( num_bytes % 4 != 0 || (int)( num_bytes / 4 ) > tag.vm ) )
524 {
525 return( false );
526 }
527
528 {
529 byte_array< float > tmp = to_current_endian( byte_array< float >( byte ), from_little_endian );
530 byte[ 0 ] = tmp[ 0 ];
531 byte[ 1 ] = tmp[ 1 ];
532 byte[ 2 ] = tmp[ 2 ];
533 byte[ 3 ] = tmp[ 3 ];
534 }
535 break;
536
537 case FD:
538 // 倍精度浮動小数
539 // 「8バイト固定」
540 if( tag.vm != -1 && ( num_bytes % 8 != 0 || (int)( num_bytes / 8 ) > tag.vm ) )
541 {
542 return( false );
543 }
544
545 {
546 byte_array< double > tmp = to_current_endian( byte_array< double >( byte ), from_little_endian );
547 byte[ 0 ] = tmp[ 0 ];
548 byte[ 1 ] = tmp[ 1 ];
549 byte[ 2 ] = tmp[ 2 ];
550 byte[ 3 ] = tmp[ 3 ];
551 byte[ 4 ] = tmp[ 4 ];
552 byte[ 5 ] = tmp[ 5 ];
553 byte[ 6 ] = tmp[ 6 ];
554 byte[ 7 ] = tmp[ 7 ];
555 }
556 break;
557
558 case IS:
559 // 整数を表す文字列
560 // 「16バイト以下」
561 // 10 を底とする整数（10進数）を表わす文字列で，先頭に + もしくは - を含んでも良く，先頭と末尾にスペース（20H）を持つ可能性のある文字列
562 // 文字列の長さを偶数に保つために，末尾にスペースを挿入する必要あり
563 // -2^31 ≦ n ≦ (2^31-1) の範囲を表現することが可能．
564 if( tag.vm != -1 && num_bytes > 16 * tag.vm )
565 {
566 return( false );
567 }
568 break;
569
570 case LO:
571 // 長文字列
572 // 「64バイト以下」
573 // 先頭と末尾にスペース（20H）を持つ文字列
574 // 文字列の長さを偶数に保つために，末尾にスペースを挿入する必要あり
575 // 制御文字列は含まない
576 if( tag.vm != -1 && num_bytes > 64 * tag.vm )
577 {
578 return( false );
579 }
580 break;
581
582 case LT:
583 // 長テキスト文字列
584 // 「10240バイト以下」
585 // 末尾にスペース（20H）を持つ可能性のある文字列
586 // 文字列の長さを偶数に保つために，末尾にスペースを挿入する必要あり
587 // 制御文字コードを含む
588 if( tag.vm != -1 && num_bytes > 10240 * tag.vm )
589 {
590 return( false );
591 }
592 break;
593
594 case OB:
595 // バイト列
596 // 「無制限」
597 // 転送構文のエンディアン形式に依存しないデータ列
598 // バイト列の長さを偶数に保つために，末尾にNULL値（00H）で埋められる可能性あり
599 break;
600
601 case OF:
602 // 4バイト浮動小数のバイト列の並びワード列
603 // 「無制限」
604 // 転送構文のエンディアン形式に依存して，バイトの並びが変化するデータ列
605 if( _is_little_endian_( ) != from_little_endian )
606 {
607 for( long i = 0 ; i < num_bytes ; i += 4 )
608 {
609 unsigned char v1 = byte[ i + 0 ];
610 unsigned char v2 = byte[ i + 1 ];
611 unsigned char v3 = byte[ i + 2 ];
612 unsigned char v4 = byte[ i + 3 ];
613 byte[ i + 0 ] = v4;
614 byte[ i + 1 ] = v3;
615 byte[ i + 2 ] = v2;
616 byte[ i + 3 ] = v1;
617 }
618 }
619 break;
620
621 case OW:
622 // ワード列
623 // 「無制限」
624 // 転送構文のエンディアン形式に依存して，バイトの並びが変化するデータ列
625 if( _is_little_endian_( ) != from_little_endian )
626 {
627 for( long i = 0 ; i < num_bytes ; i += 2 )
628 {
629 unsigned char tmp = byte[ i ];
630 byte[ i ] = byte[ i + 1 ];
631 byte[ i + 1 ] = tmp;
632 }
633 }
634 break;
635
636 case PN:
637 // 患者名を表す文字列
638 // 「64バイト以下」
639 // 制御文字列を一切含まず，末尾にスペース（20H）を持つ可能性のある文字列
640 // 文字列の長さを偶数に保つために，末尾にスペースを挿入する必要あり
641 // 姓と名の区切りには，^ (5EH) が用いられる
642 if( tag.vm != -1 && num_bytes > 64 * tag.vm )
643 {
644 return( false );
645 }
646 break;
647
648 case SH:
649 // 短文字列
650 // 「16バイト以下」
651 // 先頭と末尾にスペース（20H）を持つ文字列
652 // 文字列の長さを偶数に保つために，末尾にスペースを挿入する必要あり
653 // 制御文字列は含まない
654 if( tag.vm != -1 && num_bytes > 16 * tag.vm )
655 {
656 return( false );
657 }
658 break;
659
660 case SL:
661 // 符号付き4バイト整数
662 // 「4バイト固定」
663 if( tag.vm != -1 && ( num_bytes % 4 != 0 || (int)( num_bytes / 4 ) > tag.vm ) )
664 {
665 return( false );
666 }
667
668 {
669 byte_array< signed int > tmp = to_current_endian( byte_array< signed int >( byte ), from_little_endian );
670 byte[ 0 ] = tmp[ 0 ];
671 byte[ 1 ] = tmp[ 1 ];
672 byte[ 2 ] = tmp[ 2 ];
673 byte[ 3 ] = tmp[ 3 ];
674 }
675 break;
676
677 case SQ:
678 // シーケンスを表すタグ
679 // 「無制限」
680 // DICOMタグのシーケンスを格納するタグ
681 break;
682
683 case SS:
684 // 符号付き2バイト整数
685 // 「2バイト固定」
686 if( tag.vm != -1 && ( num_bytes % 2 != 0 || (int)( num_bytes / 2 ) > tag.vm ) )
687 {
688 return( false );
689 }
690
691 {
692 byte_array< signed short > tmp = to_current_endian( byte_array< signed short >( byte ), from_little_endian );
693 byte[ 0 ] = tmp[ 0 ];
694 byte[ 1 ] = tmp[ 1 ];
695 }
696 break;
697
698 case ST:
699 // 短テキスト文字列
700 // 末尾にスペース（20H）を持つ可能性のある文字列
701 // 文字列の長さを偶数に保つために，末尾にスペースを挿入する必要あり
702 // 制御文字コードを含む
703 if( tag.vm != -1 && num_bytes > 1024 * tag.vm )
704 {
705 return( false );
706 }
707 break;
708
709 case TM:
710 // 時刻を表す文字列
711 // 「16バイト以下」
712 // hhmmss.frac の書式で時刻を符号化した文字列
713 // これは，hh 時 mm 分 ss 秒 (frac は1億分の1秒単位) を表す
714 // 24時間形式の時刻表記が用いられ，深夜24時は0時として扱われる
715 // 文字列の長さを偶数に保つために，末尾にスペースを挿入する必要あり
716 if( tag.vm != -1 && num_bytes > 16 * tag.vm )
717 {
718 return( false );
719 }
720 break;
721
722 case UI:
723 // UIDを表す文字列
724 // 「64バイト以下」
725 // 文字列の長さを偶数に保つために，末尾にNULL (00H) を挿入する必要あり
726 if( tag.vm != -1 && num_bytes > 64 * tag.vm )
727 {
728 return( false );
729 }
730 break;
731
732 case UL:
733 // 符号無し4バイト整数
734 // 「4バイト固定」
735 if( tag.vm != -1 && ( num_bytes % 4 != 0 || (int)( num_bytes / 4 ) > tag.vm ) )
736 {
737 return( false );
738 }
739
740 {
741 byte_array< unsigned int > tmp = to_current_endian( byte_array< unsigned int >( byte ), from_little_endian );
742 byte[ 0 ] = tmp[ 0 ];
743 byte[ 1 ] = tmp[ 1 ];
744 byte[ 2 ] = tmp[ 2 ];
745 byte[ 3 ] = tmp[ 3 ];
746 }
747 break;
748
749 case UN:
750 // 不明なタグ
751 break;
752
753 case US:
754 // 符号無し2バイト整数
755 // 「2バイト固定」
756 if( tag.vm != -1 && ( num_bytes % 2 != 0 || (int)( num_bytes / 2 ) > tag.vm ) )
757 {
758 return( false );
759 }
760
761 {
762 byte_array< unsigned short > tmp = to_current_endian( byte_array< unsigned short >( byte ), from_little_endian );
763 byte[ 0 ] = tmp[ 0 ];
764 byte[ 1 ] = tmp[ 1 ];
765 }
766 break;
767
768 case UT:
769 // 無制限のテキスト文字列
770 // 末尾にスペース（20H）を持つ可能性のある文字列
771 // 文字列の長さを偶数に保つために，末尾にスペースを挿入する必要あり
772 // 制御文字コードを含む
773 break;
774
775 default:
776 // VRがわかんないからとりあえず良しとする
777 break;
778 }
779
780 return( true );
781 }
782
783
796 inline unsigned char *process_dicom_tag( dicom_tag_container &dicm, unsigned char *pointer, unsigned char *end_pointer, bool from_little_endian = true, bool is_in_sequence_tag = false )
797 {
798 difference_type numBytes = 0;
799 dicom_tag tag;
800
801 pointer = read_dicom_tag( pointer, end_pointer, tag, numBytes, from_little_endian );
802
803 if( tag.vr == SQ )
804 {
805 unsigned char *sp = pointer;
806 if( numBytes != -1 && pointer + numBytes <= end_pointer )
807 {
808 pointer += numBytes;
809 }
810 else
811 {
812 unsigned char *ep = numBytes == -1 ? end_pointer : pointer + numBytes;
813 if( ep > end_pointer )
814 {
815 // 認識不能なシーケンスタグ発見
816 return( NULL );
817 }
818 while( pointer + 8 <= ep )
819 {
820 if( is_sequence_tag_end( pointer, end_pointer ) )
821 {
822 pointer += 8;
823 break;
824 }
825 else
826 {
827 if( !is_sequence_separate_tag( pointer, ep ) )
828 {
829 return( NULL );
830 }
831
832 pointer += 4;
833 numBytes = __check_num_bytes__( to_current_endian( byte_array< unsigned int >( pointer ), from_little_endian ).get_value( ) );
834 pointer += 4;
835
836 unsigned char *epp = numBytes == -1 ? ep : pointer + numBytes;
837 if( epp > ep )
838 {
839 return( NULL );
840 }
841
842 while( pointer + 8 <= epp )
843 {
844 if( is_sequence_element_end( pointer, ep ) )
845 {
846 pointer += 8;
847 break;
848 }
849 else
850 {
851 pointer = process_dicom_tag( dicm, pointer, ep, from_little_endian, true );
852 if( pointer == NULL )
853 {
854 return( NULL );
855 }
856 }
857 }
858 }
859 }
860 }
861
862 if( !is_in_sequence_tag )
863 {
864 dicom_tag_container::iterator ite;
865 ite = dicm.append( dicom_element( tag, sp, pointer - sp ) );
866
867 #ifdef __SHOW_DICOM_TAG__
868 if( ite != dicm.end( ) )
869 {
870 ite->second.show_tag( );
871 }
872 #endif
873 }
874 }
875 else if( numBytes < -1 )
876 {
877 return( NULL );
878 }
879 else if( numBytes == -1 )
880 {
881 // 圧縮がかかっている可能性があるのでチェック
882 dicom_tag_container::iterator ite;
883 switch( tag.vr )
884 {
885 case OB:
886 case OW:
887 {
888 unsigned char *p = pointer;
889 while( p + 8 <= end_pointer )
890 {
891 if( is_sequence_tag_end( p, end_pointer ) )
892 {
893 p += 8;
894 break;
895 }
896 else
897 {
898 if( !is_sequence_separate_tag( p, end_pointer ) )
899 {
900 return( NULL );
901 }
902
903 p += 4;
904 numBytes = __check_num_bytes__( to_current_endian( byte_array< unsigned int >( p ), from_little_endian ).get_value( ) );
905 p += 4 + numBytes;
906
907 if( numBytes < 0 || p > end_pointer )
908 {
909 return( NULL );
910 }
911 }
912 }
913 if( p <= end_pointer )
914 {
915 numBytes = p - pointer;
916 if( !is_in_sequence_tag )
917 {
918 ite = dicm.append( dicom_element( tag, pointer, numBytes ) );
919 }
920 pointer += 8;
921 }
922 else
923 {
924 // 圧縮シーケンスの終わりをうまく検出できなかった
925 return( NULL );
926 }
927 }
928 break;
929
930 default:
931 return( NULL );
932 }
933
934 pointer += numBytes;
935
936 #ifdef __SHOW_DICOM_TAG__
937 if( !is_in_sequence_tag && ite != dicm.end( ) )
938 {
939 ite->second.show_tag( );
940 }
941 #endif
942 }
943 else if( numBytes > 0 )
944 {
945 // 不適切なバイト数かどうかをチェックする
946 if( pointer + numBytes > end_pointer )
947 {
948 return( NULL );
949 }
950
951 #ifndef __CHECK_TAG_FORMAT__
952 if( !process_dicom_tag( tag, pointer, numBytes, from_little_endian ) )
953 {
954 // 規格に従っていないタグを発見したが，とりあえず無視しておく
955 std::cout << "Illegal DICOM tag is found!" << std::endl;
956 }
957 #else
958 if( !process_dicom_tag( tag, pointer, numBytes, from_little_endian ) )
959 {
960 // 処理することができないDICOMタグを発見したので終了する
961 return( NULL );
962 }
963 #endif
964 if( !is_in_sequence_tag )
965 {
966 dicom_tag_container::iterator ite;
967 ite = dicm.append( dicom_element( tag, pointer, numBytes ) );
968
969 #ifdef __SHOW_DICOM_TAG__
970 if( ite != dicm.end( ) )
971 {
972 ite->second.show_tag( );
973 }
974 #endif
975 }
976
977 pointer += numBytes;
978 }
979 else if( tag.vr != UNKNOWN && !is_in_sequence_tag )
980 {
981 // 不明なタグもリストに追加する
982 dicom_tag_container::iterator ite;
983 ite = dicm.append( dicom_element( tag, NULL, 0 ) );
984
985 #if defined( __SHOW_DICOM_ZEROBYTE_TAG__ ) && defined( __SHOW_DICOM_TAG__ )
986 if( ite != dicm.end( ) )
987 {
988 ite->second.show_tag( );
989 }
990 #endif
991 }
992
993 return( pointer );
994 }
995
996
1007 inline bool read_dicom_tags( dicom_tag_container &dicm, unsigned char *buff, size_type numBytes, bool is_little_endian = true )
1008 {
1009 unsigned char *pointer = buff;
1010 unsigned char *end_pointer = buff + numBytes;
1011
1012 // DICOMデータの先頭までポインタを移動
1013 pointer = check_dicom_file( pointer, end_pointer );
1014
1015 dicm.clear( );
1016
1017 unsigned char *group_end_pointer = NULL;
1018 bool ret = true, from_little_endian = is_little_endian, once = true;
1019 while( pointer < end_pointer )
1020 {
1021 pointer = process_dicom_tag( dicm, pointer, end_pointer, from_little_endian );
1022 if( pointer == NULL )
1023 {
1024 ret = false;
1025 break;
1026 }
1027
1028 if( group_end_pointer == NULL && dicm.contain( 0x0002, 0x0000 ) )
1029 {
1030 // エンディアンの判定に用いる範囲を決定する
1031 group_end_pointer = pointer + find_tag( dicm, 0x0002, 0x0000, static_cast< unsigned int >( 0 ) );
1032 }
1033
1034 if( group_end_pointer != NULL && once && dicm.contain( 0x0002, 0x0010 ) )
1035 {
1036 // 一度しか実行されないようにする
1037 once = false;
1038
1039 // エンディアンの形式を設定する
1040 from_little_endian = find_tag( dicm, 0x0002, 0x0010, "" ) != "1.2.840.10008.1.2.2";
1041
1042 // ビッグエンディアンの場合は，このブロックだけリトルエンディアンで処理する
1043 if( !from_little_endian )
1044 {
1045 while( pointer < group_end_pointer )
1046 {
1047 pointer = process_dicom_tag( dicm, pointer, group_end_pointer, true );
1048 if( pointer == NULL )
1049 {
1050 pointer = end_pointer;
1051 ret = false;
1052 break;
1053 }
1054 }
1055 }
1056 }
1057 }
1058
1059 #ifdef __SHOW_DICOM_TAG__
1060 printf( "\n\n\n" );
1061 #endif
1062
1063 return( ret );
1064 }
1065
1066
1075 inline bool read_dicom_tags( dicom_tag_container &dicm, const std::string &filename )
1076 {
1077 size_type filesize;
1078 FILE *fp;
1079 if( ( fp = fopen( filename.c_str( ), "rb" ) ) == NULL )
1080 {
1081 return( false );
1082 }
1083
1084 // ファイルサイズを取得
1085 fseek( fp, 0, SEEK_END );
1086 filesize = ftell( fp );
1087 fseek( fp, 0, SEEK_SET );
1088
1089 unsigned char *buff = new unsigned char[ filesize + 1 ];
1090 unsigned char *pointer = buff;
1091 size_type read_size = 0;
1092 while( feof( fp ) == 0 )
1093 {
1094 read_size = fread( pointer, sizeof( unsigned char ), 1024, fp );
1095 if( read_size < 1024 )
1096 {
1097 break;
1098 }
1099 pointer += read_size;
1100 }
1101
1102 fclose( fp );
1103
1104 bool ret = read_dicom_tags( dicm, buff, filesize, true );
1105
1106 delete [] buff;
1107
1108 #ifdef __SHOW_DICOM_TAG__
1109 printf( "\n\n\n" );
1110 #endif
1111
1112 // 適切なDICOMファイルかどうかをチェックする
1113 if( ret )
1114 {
1115 dicom_tag_container::iterator ite = dicm.begin( );
1116 for( ; ite != dicm.end( ) ; ++ite )
1117 {
1118 if( ite->second.comment != "UNKNOWN" )
1119 {
1120 return( true );
1121 }
1122 }
1123
1124 return( false );
1125 }
1126 else
1127 {
1128 return( false );
1129 }
1130 }
1131
1132
1146 inline bool write_dicom_tag_explicit_vr( unsigned short group, unsigned short element, dicom_vr vr, const unsigned char *data, size_t num_bytes, FILE *fp, bool to_little_endian = true )
1147 {
1148 unsigned char ZERO[] = { 0, 0, 0, 0 };
1149 unsigned char FFFF[] = { 0xff, 0xff, 0xff, 0xff };
1150
1151 switch( vr )
1152 {
1153 case OW:
1154 case OF:
1155 fwrite( from_current_endian( byte_array< unsigned short >( group ), to_little_endian ).get_bytes( ), 1, 2, fp );
1156 fwrite( from_current_endian( byte_array< unsigned short >( element ), to_little_endian ).get_bytes( ), 1, 2, fp );
1157 fwrite( get_dicom_vr( vr ).c_str( ), 1, 2, fp );
1158 fwrite( ZERO, 1, 2, fp );
1159
1160 // データがシーケンスになっているかを調べ，出力方法を切り替える
1161 if( num_bytes > 4 + 8 && is_sequence_separate_tag( data, data + num_bytes ) && is_sequence_tag_end( data + num_bytes - 8, data + num_bytes ) )
1162 {
1163 fwrite( FFFF, 1, 4, fp );
1164 }
1165 else
1166 {
1167 fwrite( from_current_endian( byte_array< unsigned int >( static_cast< unsigned int >( num_bytes ) ), to_little_endian ).get_bytes( ), 1, 4, fp );
1168 }
1169
1170 if( _is_little_endian_( ) == to_little_endian )
1171 {
1172 fwrite( data, 1, num_bytes, fp );
1173 }
1174 else
1175 {
1176 switch( vr )
1177 {
1178 case OW:
1179 if( num_bytes % 2 == 0 )
1180 {
1181 for( size_t i = 0 ; i < num_bytes ; i += 2 )
1182 {
1183 fwrite( from_current_endian( byte_array< unsigned short >( data + i ), to_little_endian ).get_bytes( ), 1, 2, fp );
1184 }
1185 }
1186 else
1187 {
1188 // データのバイト数がおかしい
1189 return( false );
1190 }
1191 break;
1192
1193 case OF:
1194 default:
1195 if( num_bytes % 4 == 0 )
1196 {
1197 for( size_t i = 0 ; i < num_bytes ; i += 4 )
1198 {
1199 fwrite( from_current_endian( byte_array< unsigned int >( data + i ), to_little_endian ).get_bytes( ), 1, 4, fp );
1200 }
1201 }
1202 else
1203 {
1204 // データのバイト数がおかしい
1205 return( false );
1206 }
1207 break;
1208 }
1209 }
1210 break;
1211
1212 case US:
1213 case SS:
1214 case AT:
1215 case UL:
1216 case SL:
1217 case FL:
1218 case FD:
1219 fwrite( from_current_endian( byte_array< unsigned short >( group ), to_little_endian ).get_bytes( ), 1, 2, fp );
1220 fwrite( from_current_endian( byte_array< unsigned short >( element ), to_little_endian ).get_bytes( ), 1, 2, fp );
1221 fwrite( get_dicom_vr( vr ).c_str( ), 1, 2, fp );
1222 fwrite( from_current_endian( byte_array< unsigned short >( static_cast< unsigned short >( num_bytes ) ), to_little_endian ).get_bytes( ), 1, 2, fp );
1223 if( _is_little_endian_( ) == to_little_endian )
1224 {
1225 fwrite( data, 1, num_bytes, fp );
1226 }
1227 else
1228 {
1229 switch( vr )
1230 {
1231 case US:
1232 case SS:
1233 case AT:
1234 if( num_bytes % 2 == 0 )
1235 {
1236 for( size_t i = 0 ; i < num_bytes ; i += 2 )
1237 {
1238 fwrite( from_current_endian( byte_array< unsigned short >( data + i ), to_little_endian ).get_bytes( ), 1, 2, fp );
1239 }
1240 }
1241 else
1242 {
1243 // データのバイト数がおかしい
1244 return( false );
1245 }
1246 break;
1247
1248 case UL:
1249 case SL:
1250 case FL:
1251 if( num_bytes % 4 == 0 )
1252 {
1253 for( size_t i = 0 ; i < num_bytes ; i += 4 )
1254 {
1255 fwrite( from_current_endian( byte_array< unsigned int >( data + i ), to_little_endian ).get_bytes( ), 1, 4, fp );
1256 }
1257 }
1258 else
1259 {
1260 // データのバイト数がおかしい
1261 return( false );
1262 }
1263 break;
1264
1265 case FD:
1266 default:
1267 if( num_bytes % 8 == 0 )
1268 {
1269 for( size_t i = 0 ; i < num_bytes ; i += 8 )
1270 {
1271 fwrite( from_current_endian( byte_array< double >( data + i ), to_little_endian ).get_bytes( ), 1, 8, fp );
1272 }
1273 }
1274 else
1275 {
1276 // データのバイト数がおかしい
1277 return( false );
1278 }
1279 break;
1280 }
1281 }
1282 break;
1283
1284 case OB:
1285 case UN:
1286 case UT:
1287 case SQ:
1288 fwrite( from_current_endian( byte_array< unsigned short >( group ), to_little_endian ).get_bytes( ), 1, 2, fp );
1289 fwrite( from_current_endian( byte_array< unsigned short >( element ), to_little_endian ).get_bytes( ), 1, 2, fp );
1290 fwrite( get_dicom_vr( vr ).c_str( ), 1, 2, fp );
1291 fwrite( ZERO, 1, 2, fp );
1292 // データがシーケンスになっているかを調べ，出力方法を切り替える
1293 if( num_bytes > 4 + 8 && is_sequence_separate_tag( data, data + num_bytes ) && is_sequence_tag_end( data + num_bytes - 8, data + num_bytes ) )
1294 {
1295 fwrite( FFFF, 1, 4, fp );
1296 fwrite( data, 1, num_bytes, fp );
1297 }
1298 else
1299 {
1300 fwrite( from_current_endian( byte_array< unsigned int >( static_cast< unsigned int >( num_bytes ) ), to_little_endian ).get_bytes( ), 1, 4, fp );
1301 fwrite( data, 1, num_bytes, fp );
1302 }
1303 break;
1304
1305 case UNKNOWN:
1306 fwrite( from_current_endian( byte_array< unsigned short >( group ), to_little_endian ).get_bytes( ), 1, 2, fp );
1307 fwrite( from_current_endian( byte_array< unsigned short >( element ), to_little_endian ).get_bytes( ), 1, 2, fp );
1308 fwrite( "UN", 1, 2, fp );
1309 fwrite( get_dicom_vr( vr ).c_str( ), 1, 2, fp );
1310 fwrite( from_current_endian( byte_array< unsigned int >( static_cast< unsigned int >( num_bytes ) ), to_little_endian ).get_bytes( ), 1, 4, fp );
1311 fwrite( data, 1, num_bytes, fp );
1312 break;
1313
1314 default:
1315 fwrite( from_current_endian( byte_array< unsigned short >( group ), to_little_endian ).get_bytes( ), 1, 2, fp );
1316 fwrite( from_current_endian( byte_array< unsigned short >( element ), to_little_endian ).get_bytes( ), 1, 2, fp );
1317 fwrite( get_dicom_vr( vr ).c_str( ), 1, 2, fp );
1318 fwrite( from_current_endian( byte_array< unsigned short >( static_cast< unsigned short >( num_bytes ) ), to_little_endian ).get_bytes( ), 1, 2, fp );
1319 fwrite( data, 1, num_bytes, fp );
1320 break;
1321 }
1322
1323 return( true );
1324 }
1325
1326
1327
1341 inline bool write_dicom_tag_implicit_vr( unsigned short group, unsigned short element, dicom_vr vr, const unsigned char *data, size_t num_bytes, FILE *fp, bool to_little_endian = true )
1342 {
1343 unsigned char FFFF[] = { 0xff, 0xff, 0xff, 0xff };
1344
1345 switch( vr )
1346 {
1347 case OB:
1348 case UN:
1349 case UT:
1350 case SQ:
1351 // データがシーケンスになっているかを調べ，出力方法を切り替える
1352 if( num_bytes > 4 + 8 && is_sequence_separate_tag( data, data + num_bytes ) && is_sequence_tag_end( data + num_bytes - 8, data + num_bytes ) )
1353 {
1354 fwrite( from_current_endian( byte_array< unsigned short >( group ), to_little_endian ).get_bytes( ), 1, 2, fp );
1355 fwrite( from_current_endian( byte_array< unsigned short >( element ), to_little_endian ).get_bytes( ), 1, 2, fp );
1356 fwrite( FFFF, 1, 4, fp );
1357 fwrite( data, 1, num_bytes, fp );
1358 }
1359 else
1360 {
1361 fwrite( from_current_endian( byte_array< unsigned short >( group ), to_little_endian ).get_bytes( ), 1, 2, fp );
1362 fwrite( from_current_endian( byte_array< unsigned short >( element ), to_little_endian ).get_bytes( ), 1, 2, fp );
1363 fwrite( from_current_endian( byte_array< unsigned int >( static_cast< unsigned int >( num_bytes ) ), to_little_endian ).get_bytes( ), 1, 4, fp );
1364 fwrite( data, 1, num_bytes, fp );
1365 }
1366 break;
1367
1368 default:
1369 fwrite( from_current_endian( byte_array< unsigned short >( group ), to_little_endian ).get_bytes( ), 1, 2, fp );
1370 fwrite( from_current_endian( byte_array< unsigned short >( element ), to_little_endian ).get_bytes( ), 1, 2, fp );
1371 fwrite( from_current_endian( byte_array< unsigned int >( static_cast< unsigned int >( num_bytes ) ), to_little_endian ).get_bytes( ), 1, 4, fp );
1372 fwrite( data, 1, num_bytes, fp );
1373 break;
1374 }
1375
1376 return( true );
1377 }
1378
1388 inline bool write_dicom_tag_explicit_vr( const dicom_element &e, FILE *fp, bool to_little_endian = true )
1389 {
1390 return( write_dicom_tag_explicit_vr( e.get_group( ), e.get_element( ), e.vr, e.data, e.num_bytes, fp, to_little_endian ) );
1391 }
1392
1402 inline bool write_dicom_tag_implicit_vr( const dicom_element &e, FILE *fp, bool to_little_endian = true )
1403 {
1404 return( write_dicom_tag_implicit_vr( e.get_group( ), e.get_element( ), e.vr, e.data, e.num_bytes, fp, to_little_endian ) );
1405 }
1406
1407
1415 inline size_t get_write_dicom_tag_size( const dicom_element &e, bool implicitVR )
1416 {
1417 if( implicitVR )
1418 {
1419 return( 8 + e.num_bytes );
1420 }
1421 else
1422 {
1423 size_t num_bytes = 0;
1424
1425 switch( e.vr )
1426 {
1427 case OW:
1428 case OF:
1429 case OB:
1430 case UN:
1431 case SQ:
1432 case UT:
1433 case UNKNOWN:
1434 num_bytes = 12 + e.num_bytes;
1435 break;
1436
1437 case US:
1438 case SS:
1439 case AT:
1440 case UL:
1441 case SL:
1442 case FL:
1443 case FD:
1444 default:
1445 num_bytes = 8 + e.num_bytes;
1446 break;
1447 }
1448
1449 return( num_bytes );
1450 }
1451 }
1452
1453
1459 inline void compute_group_length( dicom_tag_container &dicm, bool implicitVR )
1460 {
1461 std::map< unsigned short, size_t > group_length;
1462 dicom_tag_container::iterator ite;
1463 for( ite = dicm.begin( ) ; ite != dicm.end( ) ; ++ite )
1464 {
1465 const dicom_element &e = ite->second;
1466 if( e.enable )
1467 {
1468 unsigned short group = e.get_group( );
1469 unsigned short element = e.get_element( );
1470 // Group 0002 だけは Explicit VR Little Endian Transfer Syntax でエンコードする必要あり
1471 size_t num_bytes = get_write_dicom_tag_size( e, group == 0x0002 ? false : implicitVR );
1472
1473 if( element != 0x0000 )
1474 {
1475 // Group Length のタグはスキップする
1476 if( group_length.find( group ) != group_length.end( ) )
1477 {
1478 group_length[ group ] += num_bytes;
1479 }
1480 else
1481 {
1482 group_length[ group ] = num_bytes;
1483 }
1484 }
1485 }
1486 }
1487
1488 for( ite = dicm.begin( ) ; ite != dicm.end( ) ; ++ite )
1489 {
1490 dicom_element &e = ite->second;
1491 unsigned short group = e.get_group( );
1492 unsigned short element = e.get_element( );
1493
1494 if( element == 0x0000 )
1495 {
1496 // Group Length のタグにデータを設定する
1497 size_t num_bytes = group_length[ group ];
1498
1499 switch( e.num_bytes )
1500 {
1501 case 2:
1502 {
1503 byte_array< unsigned short > b( static_cast< unsigned short >( num_bytes ) );
1504 memcpy( e.data, b.get_bytes( ), e.num_bytes );
1505 }
1506 break;
1507
1508 case 4:
1509 default:
1510 {
1511 byte_array< unsigned int > b( static_cast< unsigned int >( num_bytes ) );
1512 memcpy( e.data, b.get_bytes( ), e.num_bytes );
1513 }
1514 break;
1515 }
1516 }
1517 }
1518 }
1519
1520
1529 inline bool write_dicom_tags( const dicom_tag_container &dicom, const std::string &filename )
1530 {
1531 FILE *fp;
1532 if( ( fp = fopen( filename.c_str( ), "wb" ) ) == NULL )
1533 {
1534 return( false );
1535 }
1536
1537 // DICOMのプリアンブルのタグが存在するかどうかを調べる
1538 bool hasPreamble = false;
1539 {
1540 unsigned short elements[] = { 0x0001, 0x0002, 0x0003, 0x0010, 0x0012, 0x0013, 0x0016, 0x0100, 0x0102 };
1541 size_t num = sizeof( elements ) / sizeof( unsigned short );
1542 for( size_t i = 0 ; i < num ; i++ )
1543 {
1544 if( dicom.contain( 0x0002, elements[ i ] ) )
1545 {
1546 // データが存在するのでプリアンブルを埋め込む
1547 hasPreamble = true;
1548 break;
1549 }
1550 }
1551 }
1552
1553 dicom_tag_container dicm( dicom );
1554 bool implicitVR = true;
1555
1556 if( hasPreamble )
1557 {
1558 // DICOMのヘッダ情報を書き込む
1559 unsigned char ZERO[ 128 ];
1560 unsigned char DICM[ 4 ];
1561 memset( ZERO, 0, sizeof( unsigned char ) * 128 );
1562 DICM[ 0 ] = 'D';
1563 DICM[ 1 ] = 'I';
1564 DICM[ 2 ] = 'C';
1565 DICM[ 3 ] = 'M';
1566 fwrite( ZERO, sizeof( unsigned char ), 128, fp );
1567 fwrite( DICM, sizeof( unsigned char ), 4, fp );
1568
1569
1570 // 明示的VRの指定がない場合は追加する
1571 if( !dicm.contain( 0x0002, 0x0010 ) )
1572 {
1573 // Transfer Syntax UID が存在しない場合は，「Implicit VR Little Endian」を指定する
1574 std::string syntax = "1.2.840.10008.1.2";
1575 dicm.append( dicom_element( 0x0002, 0x0010, reinterpret_cast< const unsigned char * >( syntax.c_str( ) ), syntax.length( ) ) );
1576 }
1577 else if( find_tag( dicm, 0x0002, 0x0010, "" ) == "1.2.840.10008.1.2.1" )
1578 {
1579 // 「Explicit VR Little Endian」が指定されている場合は，「Explicit VR Little Endian」に変更する
1580 implicitVR = false;
1581 }
1582 else if( find_tag( dicm, 0x0002, 0x0010, "" ) == "1.2.840.10008.1.2.2" )
1583 {
1584 // 「Implicit VR Big Endian」が指定されている場合は，「Explicit VR Little Endian」に変更する
1585 implicitVR = false;
1586 std::string syntax = "1.2.840.10008.1.2.1";
1587 dicm( 0x0002, 0x0010 ).copy( reinterpret_cast< const unsigned char * >( syntax.c_str( ) ), syntax.length( ) );
1588 }
1589 else if( get_compress_type( find_tag( dicm, 0x0002, 0x0010, "" ) ) != RAW )
1590 {
1591 // 圧縮されている場合は「Explicit VR Little Endian」に変更する
1592 implicitVR = false;
1593 }
1594
1595 // Group 0002 の長さが挿入されていない場合は挿入する
1596 if( !dicm.contain( 0x0002, 0x0000 ) )
1597 {
1598 byte_array< unsigned int > b( static_cast< unsigned int >( 0 ) );
1599 dicm.append( dicom_element( 0x0002, 0x0000, b.get_bytes( ), b.length( ) ) );
1600 }
1601 }
1602
1603 // DICOM のタグが使用に準拠するようにする
1604 dicm.update( );
1605
1606 // Group Length を正しく設定する
1607 compute_group_length( dicm, implicitVR );
1608
1609 // VRに応じて出力する
1610 dicom_tag_container::const_iterator ite = dicm.begin( );
1611 for( ; ite != dicm.end( ) ; ++ite )
1612 {
1613 if( ite->second.enable )
1614 {
1615 // Group 0002 だけは Explicit VR Little Endian Transfer Syntax でエンコードする必要あり
1616 if( implicitVR && ite->second.get_group( ) != 0x0002 )
1617 {
1618 write_dicom_tag_implicit_vr( ite->second, fp, true );
1619 }
1620 else
1621 {
1622 write_dicom_tag_explicit_vr( ite->second, fp, true );
1623 }
1624 }
1625 }
1626
1627 fclose( fp );
1628
1629 return( true );
1630 }
1631 }
1632
1633
1634
1635
1646 template < class T, class Allocator >
1647 bool read_dicom( array2< T, Allocator > &image, const std::string &filename )
1648 {
1649 typedef typename array2< T, Allocator >::value_type value_type;
1650 typedef typename array2< T, Allocator >::size_type size_type;
1651 typedef _pixel_converter_< T > pixel_converter;
1652 typedef typename pixel_converter::color_type color_type;
1653
1654 dicom::dicom_tag_container dicm;
1655 dicom::dicom_info info;
1656
1657 if( !dicom::read_dicom_tags( dicm, filename ) )
1658 {
1659 return( false );
1660 }
1661
1662 dicom::get_dicom_info( dicm, info );
1663
1664 double window_level = info.window_center;
1665 double window_width = info.window_width;
1666
1667 if( dicm.contain( 0x7fe0, 0x0010 ) )
1668 {
1669 switch( info.compression_type )
1670 {
1671 case dicom::JPEG:
1672 case dicom::JPEGLS:
1673 case dicom::JPEG2000:
1674 // 今のところ未サポート
1675 return( false );
1676
1677 default:
1678 break;
1679 }
1680
1681 dicom::dicom_element element = dicm( 0x7fe0, 0x0010 );
1682 if( !dicom::decode( element, info ) )
1683 {
1684 // 圧縮の解凍もしくはデータがおかしい
1685 return( false );
1686 }
1687
1688 image.resize( info.cols, info.rows );
1689 image.reso1( info.pixel_spacing_x );
1690 image.reso2( info.pixel_spacing_y );
1691
1692 switch( info.photometric_type )
1693 {
1694 case dicom::RGB:
1695 if( info.compression_type == dicom::RLE )
1696 {
1697 // RLEで圧縮する際は，色ごとに圧縮されるみたい
1698 for( size_type j = 0 ; j < image.height( ) ; j++ )
1699 {
1700 unsigned char *r = element.data + j * info.cols;
1701 unsigned char *g = element.data + j * info.cols + info.cols * info.rows;
1702 unsigned char *b = element.data + j * info.cols + info.cols * info.rows * 2;
1703 for( size_type i = 0 ; i < image.width( ) ; i++ )
1704 {
1705 image( i, j ) = pixel_converter::convert_to( r[ i ], g[ i ], b[ i ] );
1706 }
1707 }
1708 }
1709 else
1710 {
1711 for( size_type j = 0 ; j < image.height( ) ; j++ )
1712 {
1713 unsigned char *data = element.data + j * image.width( ) * 3;
1714 for( size_type i = 0 ; i < image.width( ) ; i++ )
1715 {
1716 size_type ii = i * 3;
1717 image( i, j ) = pixel_converter::convert_to( data[ ii + 2 ], data[ ii + 1 ], data[ ii + 0 ] );
1718 }
1719 }
1720 }
1721 break;
1722
1723 case dicom::PALETTE_COLOR:
1724 if( dicm.contain( 0x0028, 0x1201 ) && dicm.contain( 0x0028, 0x1202 ) && dicm.contain( 0x0028, 0x1203 ) )
1725 {
1726 const dicom::dicom_element &red = dicm( 0x0028, 0x1201 );
1727 const dicom::dicom_element &green = dicm( 0x0028, 0x1202 );
1728 const dicom::dicom_element &blue = dicm( 0x0028, 0x1203 );
1729
1730 const short *r = reinterpret_cast< const short * >( red.data );
1731 const short *g = reinterpret_cast< const short * >( green.data );
1732 const short *b = reinterpret_cast< const short * >( blue.data );
1733
1734 bool is_big_endian = false;
1735
1736 int max_value = ( 2 << info.bits_stored ) - 1;
1737 for( size_t i = 0 ; i < red.num_bytes / 2 ; i++ )
1738 {
1739 if( r[ i ] > max_value || g[ i ] > max_value || b[ i ] > max_value )
1740 {
1741 is_big_endian = true;
1742 break;
1743 }
1744 }
1745
1746 if( is_big_endian )
1747 {
1748 // パレットのデータは，必ずビッグエンディアンでインプリメントされている
1749 for( size_type j = 0 ; j < image.height( ) ; j++ )
1750 {
1751 unsigned char *data = element.data + j * image.width( );
1752 for( size_type i = 0 ; i < image.width( ) ; i++ )
1753 {
1754 unsigned char R = static_cast< unsigned char >( from_current_endian( byte_array< short >( r[ data[ i ] ] ), false ).get_value( ) );
1755 unsigned char G = static_cast< unsigned char >( from_current_endian( byte_array< short >( g[ data[ i ] ] ), false ).get_value( ) );
1756 unsigned char B = static_cast< unsigned char >( from_current_endian( byte_array< short >( b[ data[ i ] ] ), false ).get_value( ) );
1757 image( i, j ) = pixel_converter::convert_to( R, G, B );
1758 }
1759 }
1760 }
1761 else
1762 {
1763 // パレットのデータは，必ずビッグエンディアンでインプリメントされている
1764 for( size_type j = 0 ; j < image.height( ) ; j++ )
1765 {
1766 unsigned char *data = element.data + j * image.width( );
1767 for( size_type i = 0 ; i < image.width( ) ; i++ )
1768 {
1769 unsigned char R = static_cast< unsigned char >( r[ data[ i ] ] );
1770 unsigned char G = static_cast< unsigned char >( g[ data[ i ] ] );
1771 unsigned char B = static_cast< unsigned char >( b[ data[ i ] ] );
1772 image( i, j ) = pixel_converter::convert_to( R, G, B );
1773 }
1774 }
1775 }
1776 }
1777 break;
1778
1779 case dicom::MONOCHROME1:
1780 case dicom::MONOCHROME2:
1781 default:
1782 if( info.bits_allocated == 8 )
1783 {
1784 for( size_type j = 0 ; j < image.height( ) ; j++ )
1785 {
1786 unsigned char *data = element.data + j * image.width( );
1787 for( size_type i = 0 ; i < image.width( ) ; i++ )
1788 {
1789 image( i, j ) = data[ i ];
1790 }
1791 }
1792 }
1793 else if( info.bits_allocated == 16 )
1794 {
1795 // MONOCHROME1 では背景が白がデフォルト
1796 // MONOCHROME2 では背景が黒がデフォルト
1797 if( info.photometric_type == dicom::MONOCHROME1 )
1798 {
1799 window_width = -window_width;
1800 }
1801
1802 double offset = info.rescale_intercept;
1803 if( dicm.contain( 0x0028, 0x1050 ) && dicm.contain( 0x0028, 0x1051 ) && dicm( 0x0028, 0x1050 ).num_bytes > 0 && dicm( 0x0028, 0x1051 ).num_bytes > 0 )
1804 {
1805 const short *bytes = reinterpret_cast< const short * >( element.data );
1806 for( size_type j = 0 ; j < image.height( ) ; j++ )
1807 {
1808 const short *data = bytes + j * image.width( );
1809 for( size_type i = 0 ; i < image.width( ) ; i++ )
1810 {
1811 double pix = ( ( data[ i ] + offset - window_level ) / window_width + 0.5 ) * 255.0;
1812 pix = pix > 255.0 ? 255.0 : pix;
1813 pix = pix < 0.0 ? 0.0 : pix;
1814 image( i, j ) = static_cast< unsigned char >( pix );
1815 }
1816 }
1817 }
1818 else
1819 {
1820 // まず，描画に用いる範囲を決定する
1821 const unsigned short *bytes = reinterpret_cast< const unsigned short * >( element.data );
1822 double min = bytes[ 0 ], max = bytes[ 0 ];
1823 for( size_t l = 1 ; l < element.num_bytes / 2 ; l++ )
1824 {
1825 if( bytes[ l ] < min )
1826 {
1827 min = bytes[ l ];
1828 }
1829 else if( max < bytes[ l ] )
1830 {
1831 max = bytes[ l ];
1832 }
1833 }
1834
1835 double ww = max - min + 1;
1836 double wl = ( max + min ) / 2.0;
1837
1838 // MONOCHROME1 では背景が白がデフォルト
1839 // MONOCHROME2 では背景が黒がデフォルト
1840 if( info.photometric_type == dicom::MONOCHROME1 )
1841 {
1842 ww = -ww;
1843 }
1844
1845 for( size_type j = 0 ; j < image.height( ) ; j++ )
1846 {
1847 const unsigned short *data = bytes + j * image.width( );
1848 for( size_type i = 0 ; i < image.width( ) ; i++ )
1849 {
1850 double pix = ( ( data[ i ] - wl ) / ww + 0.5 ) * 255.0;
1851 pix = pix > 255.0 ? 255.0 : pix;
1852 pix = pix < 0.0 ? 0.0 : pix;
1853 image( i, j ) = static_cast< unsigned char >( pix );
1854 }
1855 }
1856 }
1857 }
1858 else
1859 {
1860 return( false );
1861 }
1862 break;
1863 }
1864 }
1865 else
1866 {
1867 return( false );
1868 }
1869
1870 return( true );
1871 }
1872
1873
1875 // DICOM画像入出力グループの終わり
1876
1878 // 画像入出力グループの終わり
1879
1880
1881 // mist名前空間の終わり
1882 _MIST_END
1883
1884
1885 #endif // __INCLUDE_MIST_DICOM__
1886