TPCCLIB
Loading...
Searching...
No Matches
tpcdcm.h File Reference

Header file for libtpcdcm. More...

#include "tpcclibConfig.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "tpcextensions.h"
#include "tpcift.h"
#include "tpcfileutil.h"
#include "tpcisotope.h"

Go to the source code of this file.

Data Structures

struct  DCMTAG
struct  DCMITEM
struct  DCMFILE
struct  DCMMATRIX
struct  DCMML

Enumerations

enum  dcmtruid {
  DCM_TRUID_UNKNOWN , DCM_TRUID_LEI , DCM_TRUID_LEE , DCM_TRUID_LEED ,
  DCM_TRUID_BEE , DCM_TRUID_JPEG50 , DCM_TRUID_JPEG51 , DCM_TRUID_JPEG70 ,
  DCM_TRUID_JPEG80 , DCM_TRUID_JPEG81 , DCM_TRUID_JPEG90 , DCM_TRUID_JPEG91 ,
  DCM_TRUID_JPEG92 , DCM_TRUID_JPEG93 , DCM_TRUID_MPEG100 , DCM_TRUID_MPEG102 ,
  DCM_TRUID_MPEG103 , DCM_TRUID_RLE , DCM_TRUID_RFC , DCM_TRUID_XML ,
  DCM_TRUID_INVALID
}
enum  dcmvr {
  DCM_VR_AE , DCM_VR_AS , DCM_VR_AT , DCM_VR_CS ,
  DCM_VR_DA , DCM_VR_DS , DCM_VR_DT , DCM_VR_FL ,
  DCM_VR_FD , DCM_VR_IS , DCM_VR_LO , DCM_VR_LT ,
  DCM_VR_OB , DCM_VR_OD , DCM_VR_OF , DCM_VR_OL ,
  DCM_VR_OW , DCM_VR_PN , DCM_VR_SH , DCM_VR_SL ,
  DCM_VR_SQ , DCM_VR_SS , DCM_VR_ST , DCM_VR_TM ,
  DCM_VR_UC , DCM_VR_UI , DCM_VR_UL , DCM_VR_UN ,
  DCM_VR_UR , DCM_VR_US , DCM_VR_UT , DCM_VR_INVALID
}

Functions

void dcmfileInit (DCMFILE *d)
void dcmitemFree (DCMITEM *d)
void dcmfileFree (DCMFILE *d)
unsigned short int dcmfileMaxDepth (DCMFILE *df)
unsigned short int dcmitemMaxDepth (DCMITEM *d)
unsigned short int dcmitemParentNr (DCMITEM *d)
char * dcmValueString (DCMITEM *d)
long int dcmitemGetInt (DCMITEM *d)
double dcmitemGetReal (DCMITEM *d)
DCMITEMdcmFindTag (DCMITEM *d, const short int omit, DCMTAG *tag, const int verbose)
void dcmitemPrint (DCMITEM *d)
void dcmTagSet (DCMTAG *tag, unsigned short int group, unsigned short int element)
int dcmAddItem (DCMFILE *dcm, DCMITEM *d, short int aschild, DCMTAG tag, dcmvr vr, unsigned int vl, char *rd, const int verbose)
DCMITEMdcmFindDownTag (DCMITEM *d, const short int omit, DCMTAG *tag, const int verbose)
int dcmTagIntRange (DCMITEM *d, DCMTAG *tag, int *mi, int *ma, const int verbose)
dcmtruid dcmTrUID (const char *s)
char * dcmTrUIDDescr (dcmtruid id)
char * dcmTrUIDString (dcmtruid id)
unsigned int dcmSOPIdentify (const char *s)
char * dcmSOPName (unsigned int i)
char * dcmSOPUID (unsigned int i)
char * dcmSOPUIDName (const char *s)
unsigned char dcmVRReserved (dcmvr id)
dcmvr dcmVRId (const char *s)
char * dcmVRName (dcmvr id)
size_t dcmVRVLength (dcmvr id)
char * dcmVRDescr (dcmvr id)
char * dcmDA2intl (const char *orig, char *intl)
char * dcmTM2intl (const char *orig, char *intl)
char * dcmDT2intl (const char *orig, char *intl)
unsigned int dcmDictSize ()
int dcmDictIndexTag (unsigned int i, unsigned short int *group, unsigned short int *element)
char * dcmDictIndexVR (unsigned int i)
char * dcmDictIndexType (unsigned int i)
char * dcmDictIndexDescr (unsigned int i)
unsigned int dcmDictFindTag (DCMTAG *tag)
int dcmSameImage (const DCMFILE *d1, const DCMFILE *d2, const int verbose)
int dcmFileList (const char *filename, IFT *ift, TPCSTATUS *status)
 List DICOM files belonging to one image.
int dcmFileRemove (const char *filename, TPCSTATUS *status)
 Remove DICOM files belonging to one image.
int dcmVerifyMagic (const char *filename, FILE *fp)
dcmtruid dcmReadTransferSyntaxUID (FILE *fp)
int dcmReadFileTag (FILE *fp, DCMTAG *tag)
int dcmWriteFileTag (FILE *fp, DCMTAG *tag)
int dcmWriteFileSQDelimItem (FILE *fp)
int dcmWriteFileSQItemDelimTag (FILE *fp)
dcmvr dcmReadFileVR (FILE *fp, char *vrstr)
unsigned int dcmReadFileVL (FILE *fp, unsigned int n)
int dcmReadFileVRVL (FILE *fp, dcmvr *vr, unsigned int *vl, unsigned int *n)
int dcmWriteFileVRVL (FILE *fp, dcmvr vr, unsigned int vl, unsigned int *n)
int dcmFileReadNextElement (DCMFILE *dcm, DCMITEM *prev_item, DCMITEM *parent_item, const short int sub, const short int headerOnly, int verbose)
int dcmFileRead (const char *filename, DCMFILE *dcm, const short int headerOnly, TPCSTATUS *status)
int dcmFileWrite (const char *filename, DCMFILE *dcm, TPCSTATUS *status)
int dcmImgIsotope (DCMFILE *d, isotope *isot, decaycorrection *dc, const int verbose)
int dcmImgPos (DCMFILE *d, double *imgpos, const int verbose)
int dcmImgDim (DCMFILE *d, unsigned short int *imgdim, const int verbose)
int dcmImgPxlsize (DCMFILE *d, double *pxlsize, const int verbose)
int dcmImgOrient (DCMFILE *d, double *iop, const int verbose)
int dcmImgXform (double *iop, double *xyzMM, double *imgPos, double *xform, const int verbose)
int dcmXformToQuatern (double *xform, double *quatern, double *qoffset, const int verbose)
void dcmmatrixInit (DCMMATRIX *m)
void dcmmatrixFree (DCMMATRIX *m)
void dcmmlInit (DCMML *d)
void dcmmlFree (DCMML *d)
int dcmmlAllocate (DCMML *d, int mNr)
int dcmMListRead (IFT *ift, DCMML *ml, TPCSTATUS *status)
int dcmmlSortByPlane (DCMML *d, TPCSTATUS *status)

Detailed Description

Header file for libtpcdcm.

Header file for library libtpcdcm.

Author
Vesa Oikonen

Definition in file tpcdcm.h.

Enumeration Type Documentation

◆ dcmtruid

enum dcmtruid

DICOM Transfer Syntax UID.

In case of implicit VR, elements do NOT contain VR ! Reference: DICOM PS3.5 2017a chapter 10.

Items must be the same and in the same order as the dcm_truid list in dcmuid.c.

Enumerator
DCM_TRUID_UNKNOWN 

Unknown Transfer Syntax UID.

DCM_TRUID_LEI 

Little Endian Implicit VR (DICOM default).

DCM_TRUID_LEE 

Little Endian Explicit VR.

DCM_TRUID_LEED 

Little Endian Explicit Deflated VR.

DCM_TRUID_BEE 

Big Endian Explicit VR (retired).

DCM_TRUID_JPEG50 

Lossy JPEG 8-bit compression.

DCM_TRUID_JPEG51 

Lossy JPEG 12-bit compression.

DCM_TRUID_JPEG70 

Lossless JPEG.

DCM_TRUID_JPEG80 

Lossless JPEG-LS.

DCM_TRUID_JPEG81 

Lossy JPEG-LS.

DCM_TRUID_JPEG90 

Lossless JPEG 2000.

DCM_TRUID_JPEG91 

JPEG 2000.

DCM_TRUID_JPEG92 

Lossless multicomponent JPEG 2000.

DCM_TRUID_JPEG93 

Multicomponent JPEG 2000.

DCM_TRUID_MPEG100 

MPEG-2.

DCM_TRUID_MPEG102 

MPEG-4.

DCM_TRUID_MPEG103 

MPEG-4 BD-compatible.

DCM_TRUID_RLE 

Lossless RLE.

DCM_TRUID_RFC 

RFC 2557.

DCM_TRUID_XML 

XML encoding.

DCM_TRUID_INVALID 

Invalid Transfer Syntax UID.

Definition at line 57 of file tpcdcm.h.

57 {
79} dcmtruid;
dcmtruid
Definition tpcdcm.h:57
@ DCM_TRUID_LEI
Little Endian Implicit VR (DICOM default).
Definition tpcdcm.h:59
@ DCM_TRUID_JPEG81
Lossy JPEG-LS.
Definition tpcdcm.h:67
@ DCM_TRUID_JPEG93
Multicomponent JPEG 2000.
Definition tpcdcm.h:71
@ DCM_TRUID_MPEG100
MPEG-2.
Definition tpcdcm.h:72
@ DCM_TRUID_JPEG92
Lossless multicomponent JPEG 2000.
Definition tpcdcm.h:70
@ DCM_TRUID_JPEG91
JPEG 2000.
Definition tpcdcm.h:69
@ DCM_TRUID_JPEG70
Lossless JPEG.
Definition tpcdcm.h:65
@ DCM_TRUID_XML
XML encoding.
Definition tpcdcm.h:77
@ DCM_TRUID_INVALID
Invalid Transfer Syntax UID.
Definition tpcdcm.h:78
@ DCM_TRUID_MPEG103
MPEG-4 BD-compatible.
Definition tpcdcm.h:74
@ DCM_TRUID_RFC
RFC 2557.
Definition tpcdcm.h:76
@ DCM_TRUID_JPEG80
Lossless JPEG-LS.
Definition tpcdcm.h:66
@ DCM_TRUID_UNKNOWN
Unknown Transfer Syntax UID.
Definition tpcdcm.h:58
@ DCM_TRUID_LEED
Little Endian Explicit Deflated VR.
Definition tpcdcm.h:61
@ DCM_TRUID_BEE
Big Endian Explicit VR (retired).
Definition tpcdcm.h:62
@ DCM_TRUID_JPEG51
Lossy JPEG 12-bit compression.
Definition tpcdcm.h:64
@ DCM_TRUID_RLE
Lossless RLE.
Definition tpcdcm.h:75
@ DCM_TRUID_LEE
Little Endian Explicit VR.
Definition tpcdcm.h:60
@ DCM_TRUID_JPEG90
Lossless JPEG 2000.
Definition tpcdcm.h:68
@ DCM_TRUID_JPEG50
Lossy JPEG 8-bit compression.
Definition tpcdcm.h:63
@ DCM_TRUID_MPEG102
MPEG-4.
Definition tpcdcm.h:73

◆ dcmvr

enum dcmvr

DICOM value representation (VR).

Reference: DICOM PS3.5 2017a chapter 6.2.

Items must be the same and in the same order as the dcm_vr list in dcmvr.c.

Enumerator
DCM_VR_AE 

DICOM application entity, max 16 bytes.

DCM_VR_AS 

DICOM age string, 4 bytes fixed.

DCM_VR_AT 

DICOM attribute tag, 4 bytes fixed.

DCM_VR_CS 

DICOM code (control) string, max 16 bytes.

DCM_VR_DA 

DICOM date in format YYYYMMDD, 8 bytes fixed.

Note
In old standard 10 bytes fixed, in format YYYY.MM.DD
DCM_VR_DS 

DICOM decimal string, max 16 bytes.

DCM_VR_DT 

DICOM date time, max 26 bytes.

DCM_VR_FL 

DICOM floating point single precision, 4 bytes fixed.

DCM_VR_FD 

DICOM floating point double precision, 8 bytes fixed.

DCM_VR_IS 

DICOM integer string, max 12 bytes.

DCM_VR_LO 

DICOM long string, max 64 chars.

DCM_VR_LT 

DICOM long text, max 10240 chars.

DCM_VR_OB 

DICOM other byte string, even bytes, endian insensitive.

DCM_VR_OD 

DICOM other double (64-bit) stream, endian sensitive.

DCM_VR_OF 

DICOM other float (32-bit) stream, endian sensitive.

DCM_VR_OL 

DICOM other long (32-bit) stream, endian sensitive.

DCM_VR_OW 

DICOM other word (16-bit) stream, even bytes, endian sensitive.

DCM_VR_PN 

DICOM person name, max 64 chars per component group.

DCM_VR_SH 

DICOM short string, max 16 chars.

DCM_VR_SL 

DICOM signed long (32-bit integer), 4 bytes fixed.

DCM_VR_SQ 

DICOM sequence of zero or more elements (used for nested data).

DCM_VR_SS 

DICOM signed short (16-bit integer), 2 bytes fixed.

DCM_VR_ST 

DICOM short text, max 1024 chars.

DCM_VR_TM 

DICOM time HHMMSS.FFFFFF, max 14 bytes.

Note
In old standard 16 bytes max.
DCM_VR_UC 

DICOM unlimited characters.

DCM_VR_UI 

DICOM unique identifier (UID), max 64 bytes.

DCM_VR_UL 

DICOM unsigned long (32-bit) integer, 4 bytes fixed.

DCM_VR_UN 

DICOM unknown, any valid length of another VR.

DCM_VR_UR 

DICOM URI or URL, string of characters.

DCM_VR_US 

DICOM unsigned short (16-bit) integer, 2 bytes fixed.

DCM_VR_UT 

DICOM unlimited text, character string.

DCM_VR_INVALID 

Invalid DICOM value representation.

Definition at line 91 of file tpcdcm.h.

91 {
92 DCM_VR_AE,
93 DCM_VR_AS,
94 DCM_VR_AT,
95 DCM_VR_CS,
96 DCM_VR_DA,
97 DCM_VR_DS,
98 DCM_VR_DT,
99 DCM_VR_FL,
100 DCM_VR_FD,
101 DCM_VR_IS,
102 DCM_VR_LO,
103 DCM_VR_LT,
104 DCM_VR_OB,
105 DCM_VR_OD,
106 DCM_VR_OF,
107 DCM_VR_OL,
108 DCM_VR_OW,
109 DCM_VR_PN,
110 DCM_VR_SH,
111 DCM_VR_SL,
112 DCM_VR_SQ,
113 DCM_VR_SS,
114 DCM_VR_ST,
115 DCM_VR_TM,
116 DCM_VR_UC,
117 DCM_VR_UI,
118 DCM_VR_UL,
119 DCM_VR_UN,
120 DCM_VR_UR,
121 DCM_VR_US,
122 DCM_VR_UT,
124} dcmvr;
dcmvr
Definition tpcdcm.h:91
@ DCM_VR_INVALID
Invalid DICOM value representation.
Definition tpcdcm.h:123
@ DCM_VR_DT
DICOM date time, max 26 bytes.
Definition tpcdcm.h:98
@ DCM_VR_UI
DICOM unique identifier (UID), max 64 bytes.
Definition tpcdcm.h:117
@ DCM_VR_FD
DICOM floating point double precision, 8 bytes fixed.
Definition tpcdcm.h:100
@ DCM_VR_UC
DICOM unlimited characters.
Definition tpcdcm.h:116
@ DCM_VR_PN
DICOM person name, max 64 chars per component group.
Definition tpcdcm.h:109
@ DCM_VR_CS
DICOM code (control) string, max 16 bytes.
Definition tpcdcm.h:95
@ DCM_VR_SS
DICOM signed short (16-bit integer), 2 bytes fixed.
Definition tpcdcm.h:113
@ DCM_VR_SH
DICOM short string, max 16 chars.
Definition tpcdcm.h:110
@ DCM_VR_OF
DICOM other float (32-bit) stream, endian sensitive.
Definition tpcdcm.h:106
@ DCM_VR_UT
DICOM unlimited text, character string.
Definition tpcdcm.h:122
@ DCM_VR_US
DICOM unsigned short (16-bit) integer, 2 bytes fixed.
Definition tpcdcm.h:121
@ DCM_VR_TM
DICOM time HHMMSS.FFFFFF, max 14 bytes.
Definition tpcdcm.h:115
@ DCM_VR_OB
DICOM other byte string, even bytes, endian insensitive.
Definition tpcdcm.h:104
@ DCM_VR_AS
DICOM age string, 4 bytes fixed.
Definition tpcdcm.h:93
@ DCM_VR_ST
DICOM short text, max 1024 chars.
Definition tpcdcm.h:114
@ DCM_VR_AT
DICOM attribute tag, 4 bytes fixed.
Definition tpcdcm.h:94
@ DCM_VR_LT
DICOM long text, max 10240 chars.
Definition tpcdcm.h:103
@ DCM_VR_DA
DICOM date in format YYYYMMDD, 8 bytes fixed.
Definition tpcdcm.h:96
@ DCM_VR_UL
DICOM unsigned long (32-bit) integer, 4 bytes fixed.
Definition tpcdcm.h:118
@ DCM_VR_UN
DICOM unknown, any valid length of another VR.
Definition tpcdcm.h:119
@ DCM_VR_DS
DICOM decimal string, max 16 bytes.
Definition tpcdcm.h:97
@ DCM_VR_OW
DICOM other word (16-bit) stream, even bytes, endian sensitive.
Definition tpcdcm.h:108
@ DCM_VR_IS
DICOM integer string, max 12 bytes.
Definition tpcdcm.h:101
@ DCM_VR_AE
DICOM application entity, max 16 bytes.
Definition tpcdcm.h:92
@ DCM_VR_UR
DICOM URI or URL, string of characters.
Definition tpcdcm.h:120
@ DCM_VR_LO
DICOM long string, max 64 chars.
Definition tpcdcm.h:102
@ DCM_VR_SQ
DICOM sequence of zero or more elements (used for nested data).
Definition tpcdcm.h:112
@ DCM_VR_FL
DICOM floating point single precision, 4 bytes fixed.
Definition tpcdcm.h:99
@ DCM_VR_SL
DICOM signed long (32-bit integer), 4 bytes fixed.
Definition tpcdcm.h:111
@ DCM_VR_OL
DICOM other long (32-bit) stream, endian sensitive.
Definition tpcdcm.h:107
@ DCM_VR_OD
DICOM other double (64-bit) stream, endian sensitive.
Definition tpcdcm.h:105

Function Documentation

◆ dcmAddItem()

int dcmAddItem ( DCMFILE * dcm,
DCMITEM * d,
short int aschild,
DCMTAG tag,
dcmvr vr,
unsigned int vl,
char * rd,
const int verbose )

Add an item to DCMFILE data struct.

See also
dcmfileInit, dcmfileFree
Returns
0 if successful, otherwise >0.
Parameters
dcmPointer to DCMFILE.
dPointer to a previous item in DCMFILE, into which to link this item; enter NULL to add as next item to the highest level.
aschildAdd as child; 1=yes, 0=no.
tagTag
vrVR
vlVL; enter 0xFFFFFFFF to use VR's default length.
rdPointer to the item value as byte array
verboseVerbose level; if zero, then nothing is printed to stderr or stdout.

Definition at line 501 of file dcmdata.c.

519 {
520 if(verbose>0) {
521 printf("%s(dcm, (%04X,%04X))", __func__, tag.group, tag.element);
522 if(d==NULL) printf(", null"); else printf(", ptr");
523 printf(", %d, %s, 0x%08X, rd", aschild, dcmVRName(vr), vl);
524 printf(")\n");
525 }
526 if(dcm==NULL) return(1);
527 if(vr==DCM_VR_INVALID) return(2);
528
529 /* Check that caller has not given previous item pointer when there are none in DCMFILE */
530 if(d!=NULL && dcm->item==NULL) return(3);
531 /* Check that caller has not given previous item pointer that already has child */
532 if(d!=NULL && aschild && d->child_item!=NULL) return(4);
533
534 /* Check whether we currently support the Transfer UID */
535 if(dcm->truid!=DCM_TRUID_LEE) return(5);
536
537 /* Allocate memory for the new element; do not free it here, since it will be part of
538 DCMFILE struct. */
539 if(verbose>1) printf(" allocating memory for the item\n");
540 DCMITEM *item=(DCMITEM*)malloc(sizeof(DCMITEM));
541 if(item==NULL) return(11);
542 item->next_item=item->child_item=(DCMITEM*)NULL;
543 item->fp=dcm->fp; item->truid=dcm->truid;
544 item->rd=(char*)NULL;
545
546 /* Set item tag, VR, and VL */
547 if(verbose>1) printf(" setting item contents\n");
548 item->tag.group=tag.group;
549 item->tag.element=tag.element;
550 item->vr=vr;
551 item->vl=vl;
552 /* Allocate memory for item value */
553 size_t s;
554 if(vl==0xFFFFFFFF) s=dcmVRVLength(vr); else s=vl;
555 if(s>0) {
556 if(item->vl==0xFFFFFFFF) item->vl=(unsigned int)s;
557 if(verbose>1) printf(" allocating %u bytes for the item value\n", (unsigned int)s);
558 item->rd=(char*)calloc(s, sizeof(char));
559 if(item->rd==NULL) {free(item); return(21);}
560 } else {
561 if(verbose>1) printf("zero size for item value\n");
562 if(rd==NULL) {
563 if(verbose>1) printf("... which is ok since value is empty, too.\n");
564 } else {
565 if(verbose>0) printf("... which is not ok because we have value to store.\n");
566 if(item->rd==NULL) {free(item); return(22);}
567 }
568 }
569 /* Copy the item value */
570 if(rd!=NULL && s>0) {
571 if(verbose>1) printf(" copying the item value\n");
572 /* Special treatment for strings, because those tend to be shorter than told */
573 if(vr==DCM_VR_LO || vr==DCM_VR_LT || vr==DCM_VR_PN || vr==DCM_VR_SH || vr==DCM_VR_UI || vr==DCM_VR_UR)
574 {
575 unsigned int len=strnlen(rd, s);
576 if(len<s) strlcpy(item->rd, rd, s);
577 else memcpy(item->rd, rd, s);
578 } else if(vr==DCM_VR_DS || vr==DCM_VR_IS)
579 {
580 unsigned int len=strnlen(rd, s);
581 if(len<s) strlcpy(item->rd, rd, s);
582 else memcpy(item->rd, rd, s);
583 } else {
584 memcpy(item->rd, rd, s);
585 }
586 }
587
588
589 /* If we have the item to link to, then do the linking */
590 if(verbose>1) printf(" link the item.\n");
591 if(d!=NULL) {
592 if(aschild) {
593 d->child_item=item;
594 item->parent_item=d;
595 item->prev_item=(DCMITEM*)NULL;
596 } else if(d->next_item==NULL) {
597 d->next_item=item;
598 item->prev_item=d;
599 item->parent_item=d->parent_item;
600 } else {
601 /* find the last item in the list */
602 DCMITEM *ip=d; while(ip->next_item!=NULL) ip=ip->next_item;
603 ip->next_item=item;
604 item->prev_item=ip;
605 item->parent_item=ip->parent_item;
606 }
607 } else if(dcm->item==NULL) {
608 /* This is truly the first item ever */
609 dcm->item=item;
610 item->prev_item=item->parent_item=(DCMITEM*)NULL;
611 } else {
612 /* Caller lets us find the item to link to */
613 DCMITEM *ip=dcm->item; while(ip->next_item!=NULL) ip=ip->next_item;
614 ip->next_item=item;
615 item->prev_item=ip;
616 item->parent_item=ip->parent_item;
617 }
618
619 if(verbose>2) dcmitemPrint(item);
620
621 if(verbose>1) printf(" all done.\n");
622 return(0);
623}
void dcmitemPrint(DCMITEM *d)
Definition dcmdata.c:467
size_t dcmVRVLength(dcmvr id)
Definition dcmvr.c:144
char * dcmVRName(dcmvr id)
Definition dcmvr.c:126
size_t strnlen(const char *s, size_t n)
Definition stringext.c:566
size_t strlcpy(char *dst, const char *src, size_t dstsize)
Definition stringext.c:632
dcmtruid truid
Definition tpcdcm.h:162
DCMITEM * item
Definition tpcdcm.h:164
FILE * fp
Definition tpcdcm.h:160
dcmtruid truid
Definition tpcdcm.h:135
dcmvr vr
Definition tpcdcm.h:139
struct DCMITEM * child_item
Definition tpcdcm.h:143
struct DCMITEM * next_item
Definition tpcdcm.h:147
unsigned int vl
Definition tpcdcm.h:141
FILE * fp
Definition tpcdcm.h:131
char * rd
Definition tpcdcm.h:152
struct DCMITEM * prev_item
Definition tpcdcm.h:149
struct DCMITEM * parent_item
Definition tpcdcm.h:145
DCMTAG tag
Definition tpcdcm.h:137
unsigned short int element
Definition tpcdcm.h:44
unsigned short int group
Definition tpcdcm.h:42

Referenced by imgWriteDICOM().

◆ dcmDA2intl()

char * dcmDA2intl ( const char * orig,
char * intl )

Convert DICOM date 'DA' to international format YYYY-MM-DD.

Returns
Returns pointer to the date string, or NULL in case of an error.
Parameters
origPointer to original DICOM string.
intlPointer to string where date in international format will be written; must be allocated for at least 11 characters.

Definition at line 179 of file dcmvr.c.

185 {
186 if(orig==NULL || intl==NULL) return(NULL);
187 if(strnlen(orig, 10)<8) return(NULL);
188 if(isdigit(orig[4])) { // modern format YYYYMMDD
189 sprintf(intl, "%4.4s-%2.2s-%2.2s", orig, orig+4, orig+6);
190 } else { // old format YYYY.MM.DD
191 sprintf(intl, "%4.4s-%2.2s-%2.2s", orig, orig+5, orig+8);
192 }
193 if(strDateValid(intl)) {intl[0]=(char)0; return(NULL);}
194 return(intl);
195}
int strDateValid(const char *str)
Definition datetime.c:155

Referenced by dcmMListRead().

◆ dcmDictFindTag()

unsigned int dcmDictFindTag ( DCMTAG * tag)

Get the dictionary index for given tag.

Returns
If tag is found, returns its dictionary index; otherwise returns the length of the dictionary.
See also
dcmDictSize, dcmDictIndexTag, dcmDictIndexVR, dcmDictIndexType, dcmDictIndexDescr
Parameters
tagPointer to DICOM tag.

Definition at line 2820 of file dcmdictionary.c.

2823 {
2824 unsigned int i, n=dcmDictSize();
2825 if(tag==NULL) return(n);
2826 for(i=0; i<n; i++)
2827 if(tag->group==dcmdict[i].group && tag->element==dcmdict[i].element) break;
2828 return(i);
2829}
unsigned int dcmDictSize()

Referenced by dcmFileReadNextElement().

◆ dcmDictIndexDescr()

char * dcmDictIndexDescr ( unsigned int i)

Get the DICOM tag description, based on given dictionary index.

Returns
Returns pointer to description string, which is 'Unknown' if index equals dictionary length, or NULL in case of an error.
See also
dcmDictSize, dcmDictIndexTag, dcmDictFindTag
Parameters
iDictionary index [0..n-1].

Definition at line 2780 of file dcmdictionary.c.

2783 {
2784 if(i>dcmDictSize()) return(char*)NULL;
2785 else return(dcmdict[i].descr);
2786}

Referenced by dcmFileReadNextElement().

◆ dcmDictIndexTag()

int dcmDictIndexTag ( unsigned int i,
unsigned short int * group,
unsigned short int * element )

Get the DICOM tag group and element, based on given dictionary index.

Returns
Returns 0 when successful, 1 if invalid index.
See also
dcmDictSize, dcmDictIndexVR, dcmDictIndexType, dcmDictIndexDescr, dcmDictFindTag
Parameters
iDictionary index [0..n-1].
groupPointer to tag group; enter NULL if not needed.
elementPointer to tag element; enter NULL if not needed.

Definition at line 2744 of file dcmdictionary.c.

2751 {
2752 if(group!=NULL) *group=0;
2753 if(element!=NULL) *element=0;
2754 if(i>=dcmDictSize()) return(1);
2755 if(group!=NULL) *group=dcmdict[i].group;
2756 if(element!=NULL) *element=dcmdict[i].element;
2757 return(0);
2758}

◆ dcmDictIndexType()

char * dcmDictIndexType ( unsigned int i)

Get the DICOM Tag Type, based on given dictionary index.

Tag Type is a NULL terminated string.

  • 1: mandatory.
  • 1C: mandatory only under certain conditions.
  • 2: required to exist, but can have a null value.
  • 2C: required to exist only under certain conditions.
  • 3: optional.

Reference: DICOM PS3.3

Returns
Returns pointer to the tag type string, or NULL in case of an error.
See also
dcmDictSize, dcmDictIndexTag, dcmDictFindTag
Parameters
iDictionary index [0..n-1].

Definition at line 2804 of file dcmdictionary.c.

2807 {
2808 if(i>=dcmDictSize()) return(char*)NULL;
2809 else return(dcmdict[i].type);
2810}

◆ dcmDictIndexVR()

char * dcmDictIndexVR ( unsigned int i)

Get the DICOM tag VR string, based on given dictionary index.

Returns
Returns pointer to VR string, or NULL in case of an error.
See also
dcmDictSize, dcmDictIndexTag, dcmDictFindTag

Definition at line 2766 of file dcmdictionary.c.

2768 {
2769 if(i>=dcmDictSize()) return(char*)NULL;
2770 else return(dcmdict[i].vr);
2771}

Referenced by dcmFileReadNextElement().

◆ dcmDictSize()

unsigned int dcmDictSize ( )

Get the size of DICOM dictionary.

Returns
Returns the size of the dictionary.

Definition at line 2730 of file dcmdictionary.c.

2731{
2732 unsigned int n=1;
2733 while(dcmdict[n].group<0xFFFF && dcmdict[n].element<0xFFFF) n++;
2734 return(n);
2735}

Referenced by dcmDictFindTag(), dcmDictIndexDescr(), dcmDictIndexTag(), dcmDictIndexType(), and dcmDictIndexVR().

◆ dcmDT2intl()

char * dcmDT2intl ( const char * orig,
char * intl )

Convert DICOM datetime 'DT' to international format YYYY-MM-DD hh:mm:ss.

Returns
Returns pointer to the time string, or NULL in case of an error.
Parameters
origPointer to original DICOM string. Should be in format YYYYMMDDhhmmss.FFFFFF+hhmm
intlPointer to string where date and time in international format will be written; must be allocated for at least 20 characters.

Definition at line 225 of file dcmvr.c.

232 {
233 if(orig==NULL || intl==NULL) return(NULL);
234 if(strnlen(orig, 26)<14) return(NULL);
235 sprintf(intl, "%4.4s-%2.2s-%2.2s %2.2s:%2.2s:%2.2s",
236 orig, orig+4, orig+6, orig+8, orig+10, orig+12);
237 if(strDateTimeValid(intl, NULL)) {intl[0]=(char)0; return(NULL);}
238 return(intl);
239}
int strDateTimeValid(const char *str, char *intdate)
Definition datetime.c:308

Referenced by dcmMListRead(), and imgReadDICOM().

◆ dcmfileFree()

void dcmfileFree ( DCMFILE * d)

Free memory allocated for DCMFILE data. All contents are destroyed.

Precondition
Before first use initialize the struct with dcmfileInit().
See also
dcmfileInit
Author
Vesa Oikonen
Parameters
dPointer to DCMFILE.

Definition at line 67 of file dcmdata.c.

70 {
71 if(d==NULL) return;
72 dcmitemFree(d->item);
73 dcmfileInit(d);
74}
void dcmfileInit(DCMFILE *d)
Definition dcmdata.c:22
void dcmitemFree(DCMITEM *d)
Definition dcmdata.c:39

Referenced by dcmFileList(), dcmFileRead(), dcmMListRead(), imgReadDICOM(), and imgWriteDICOM().

◆ dcmfileInit()

void dcmfileInit ( DCMFILE * d)

Initiate the DCMFILE struct before any use.

See also
dcmfileFree
Parameters
dPointer to DCMFILE.

Definition at line 22 of file dcmdata.c.

25 {
26 if(d==NULL) return;
27 d->filename[0]=(char)0;
28 d->fp=(FILE*)NULL;
30 d->item=(DCMITEM*)NULL;
31}
char filename[FILENAME_MAX]
Definition tpcdcm.h:158

Referenced by dcmfileFree(), dcmFileList(), dcmMListRead(), imgReadDICOM(), and imgWriteDICOM().

◆ dcmFileList()

int dcmFileList ( const char * filename,
IFT * ift,
TPCSTATUS * status )

List DICOM files belonging to one image.

User can give DICOM image as a folder containing image file(s), or as a name of one of the files of the image. This function lists the files (with paths) belonging to the same image.

See also
dcmFileRemove, dcmSameImage
Returns
Code tpcerror, TPCERROR_OK (0) when successful.
Parameters
filenamePointer to the name of DICOM directory or file.
iftPointer to initiated IFT structure, into which file names will be stored; any previous contents will be deleted.
statusPointer to status data; enter NULL if not needed.

Definition at line 123 of file dcmfile.c.

131 {
132 int verbose=0; if(status!=NULL) verbose=status->verbose;
133 if(filename==NULL || strnlen(filename, 10)<1 || ift==NULL) {
134 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_FAIL);
135 return TPCERROR_FAIL;
136 }
137 if(verbose>1) printf("%s('%s', ...)\n", __func__, filename);
138
139 /* Make the list */
140 unsigned short int fileNr=0;
141 if(pathExist(filename)) {
142 /* We got a directory */
143 if(verbose>2) printf("%s is a directory\n", filename);
144 /* List all files in it */
145 iftFree(ift);
146 fileNr=pathFileList(filename, ift);
147 if(fileNr==0) {
148 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_NO_FILE);
149 return(TPCERROR_NO_FILE);
150 }
151 /* Remove files that are not DICOM */
152 int i=ift->keyNr-1;
153 do {
154 if(!dcmVerifyMagic(ift->item[i].value, NULL)) iftDelete(ift, i);
155 i--;
156 } while(i>=0);
157 fileNr=ift->keyNr; if(verbose>3) printf("fileNr := %d\n", fileNr);
158 if(fileNr==0) {
159 iftFree(ift);
160 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_UNSUPPORTED);
161 return(TPCERROR_UNSUPPORTED);
162 }
163 /* Check that all remaining files belong to the same image */
164 DCMFILE dcm1; dcmfileInit(&dcm1);
165 i=0; int ret;
166 ret=dcmFileRead(ift->item[i].value, &dcm1, 1, status);
167 if(ret!=TPCERROR_OK) {iftFree(ift); return(ret);}
168 DCMFILE dcm2; dcmfileInit(&dcm2);
169 for(i=1; i<ift->keyNr; i++) {
170 ret=dcmFileRead(ift->item[i].value, &dcm2, 1, NULL /*status*/);
171 if(ret!=TPCERROR_OK) {
172 iftFree(ift); dcmfileFree(&dcm1);
173 statusSet(status, __func__, __FILE__, __LINE__, ret);
174 return(ret);
175 }
176 if(!dcmSameImage(&dcm1, &dcm2, verbose-10)) {
177 dcmfileFree(&dcm2); iftFree(ift);
178 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_INCOMPATIBLE_DATA);
180 }
181 dcmfileFree(&dcm2);
182 }
183 dcmfileFree(&dcm1);
184 } else if(fileExist(filename)) {
185 /* We got a file */
186 if(verbose>2) printf("%s is a file\n", filename);
187 /* Verify that it is DICOM */
188 if(!dcmVerifyMagic(filename, NULL)) {
189 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_UNSUPPORTED);
190 return(TPCERROR_UNSUPPORTED);
191 }
192 if(verbose>2) {printf("... and DICOM\n"); fflush(stdout);}
193 /* Read the specified file */
194 DCMFILE dcm1; dcmfileInit(&dcm1);
195 int ret;
196 ret=dcmFileRead(filename, &dcm1, 1, status);
197 if(ret!=TPCERROR_OK) {iftFree(ift); return(ret);}
198 /* Check whether Per-frame Functional Groups Sequence is set */
199 DCMTAG tag; dcmTagSet(&tag, 0x5200, 0x9230);
200 if(dcmFindTag(dcm1.item, 0, &tag, 0)!=NULL) {
201 dcmfileFree(&dcm1);
202 if(verbose>1)
203 printf("Per-frame Functional Groups Sequence is available: assuming single-file.\n");
204 iftFree(ift); fileNr=1;
205 iftPut(ift, "", filename, 0, NULL);
206 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_OK);
207 return(TPCERROR_OK);
208 }
209
210 /* Since there is no RELIABLE way to tell how many files make up the whole
211 image, we have to list files in the same path */
212 char *pathname=strdup(filename); filenameRmFile(pathname);
213 if(verbose>3) printf("%s is its path\n", pathname);
214 iftFree(ift);
215 fileNr=pathFileList(pathname, ift); free(pathname);
216 if(verbose>3) printf("fileNr := %d\n", fileNr);
217 if(fileNr==0) {
218 iftFree(ift);
219 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_INVALID_FILENAME);
221 }
222 /* Remove files that are not DICOM */
223 int i=ift->keyNr-1;
224 do {
225 if(!dcmVerifyMagic(ift->item[i].value, NULL)) iftDelete(ift, i);
226 i--;
227 } while(i>=0);
228 fileNr=ift->keyNr; if(verbose>3) printf("fileNr := %d\n", fileNr);
229 if(fileNr==0) {
230 iftFree(ift);
231 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_UNSUPPORTED);
232 return(TPCERROR_UNSUPPORTED);
233 }
234 /* Remove files that do not belong to the same series as the specified file */
235 DCMFILE dcm2; dcmfileInit(&dcm2);
236 i=ift->keyNr-1;
237 do {
238 ret=dcmFileRead(ift->item[i].value, &dcm2, 1, NULL /*status*/);
239 if(ret!=TPCERROR_OK || !dcmSameImage(&dcm1, &dcm2, verbose-10)) {
240 if(verbose>5) {printf(" not same, removing from list\n"); fflush(stdout);}
241 iftDelete(ift, i);
242 }
243 dcmfileFree(&dcm2);
244 i--;
245 } while(i>=0);
246 dcmfileFree(&dcm1);
247 fileNr=ift->keyNr; if(verbose>3) printf("fileNr := %d\n", fileNr);
248 if(fileNr==0) {
249 iftFree(ift);
250 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_UNSUPPORTED);
251 return(TPCERROR_UNSUPPORTED);
252 }
253 } else {
254 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_NO_FILE);
255 return(TPCERROR_NO_FILE);
256 }
257
258 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_OK);
259 return(TPCERROR_OK);
260}
void dcmTagSet(DCMTAG *tag, unsigned short int group, unsigned short int element)
Definition dcmdata.c:483
DCMITEM * dcmFindTag(DCMITEM *d, const short int omit, DCMTAG *tag, const int verbose)
Definition dcmdata.c:375
void dcmfileFree(DCMFILE *d)
Definition dcmdata.c:67
int dcmSameImage(const DCMFILE *d1, const DCMFILE *d2, const int verbose)
Definition dcmfile.c:24
int dcmFileRead(const char *filename, DCMFILE *dcm, const short int headerOnly, TPCSTATUS *status)
Definition dcmio.c:768
int dcmVerifyMagic(const char *filename, FILE *fp)
Definition dcmio.c:25
void filenameRmFile(char *s)
Definition filename.c:44
unsigned short int pathFileList(const char *pathname, IFT *ift)
Definition filexist.c:83
int fileExist(const char *filename)
Definition filexist.c:17
void iftFree(IFT *ift)
Definition ift.c:37
int iftPut(IFT *ift, const char *key, const char *value, char comment, TPCSTATUS *status)
Definition ift.c:63
int iftDelete(IFT *ift, int index)
Definition ift.c:206
int pathExist(const char *pathname)
Definition pathexist.c:17
void statusSet(TPCSTATUS *s, const char *func, const char *srcfile, int srcline, tpcerror error)
Definition statusmsg.c:142
char * strdup(const char *s)
Definition stringext.c:185
char * value
Definition tpcift.h:37
IFT_ITEM * item
Definition tpcift.h:57
int keyNr
Definition tpcift.h:47
int verbose
Verbose level, used by statusPrint() etc.
@ TPCERROR_NO_FILE
File does not exist.
@ TPCERROR_FAIL
General error.
@ TPCERROR_UNSUPPORTED
Unsupported file type.
@ TPCERROR_OK
No error.
@ TPCERROR_INVALID_FILENAME
Invalid file name.
@ TPCERROR_INCOMPATIBLE_DATA
Incompatible data.

Referenced by dcmFileRemove(), and imgRead().

◆ dcmfileMaxDepth()

unsigned short int dcmfileMaxDepth ( DCMFILE * df)

Get the maximum depth of DCMFILE items tree.

Returns
Returns the number of item levels under specified DCMFILE, or zero in case of an error or if there are no items.
See also
dcmitemParentNr, dcmitemMaxDepth
Parameters
dfPointer to DCMFILE item.

Definition at line 102 of file dcmdata.c.

105 {
106 if(df==NULL || df->item==NULL) return(0);
107 unsigned short int m=0, n=0;
108 DCMITEM *sd=df->item;
109 while(sd!=NULL) { // go through all sisters
110 n=dcmitemMaxDepth(sd); if(n>m) m=n;
111 sd=sd->next_item;
112 }
113 return(m+1);
114}
unsigned short int dcmitemMaxDepth(DCMITEM *d)
Definition dcmdata.c:83

◆ dcmFileRead()

int dcmFileRead ( const char * filename,
DCMFILE * dcm,
const short int headerOnly,
TPCSTATUS * status )

Read a single DICOM file.

See also
dcmVerifyMagic, dcmfileInit, dcmfileFree, dcmReadTransferSyntaxUID, dcmFileWrite, dcmFileList
Returns
Code tpcerror, TPCERROR_OK (0) when successful.
Parameters
filenamePointer to filename.
dcmPointer to initiated data structure.
headerOnlyRead only header (1), or read both header and pixel data (0).
statusPointer to status data; enter NULL if not needed.

Definition at line 768 of file dcmio.c.

777 {
778 int verbose=0; if(status!=NULL) verbose=status->verbose;
779 if(filename==NULL || strnlen(filename, 10)<1 || dcm==NULL) {
780 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_FAIL);
781 return TPCERROR_FAIL;
782 }
783 if(verbose>1) printf("%s('%s', %d)\n", __func__, filename, headerOnly);
784
785 /* Delete any previous data */
786 dcmfileFree(dcm);
787
788 /* Open the file */
789 strlcpy(dcm->filename, filename, FILENAME_MAX);
790 dcm->fp=fopen(dcm->filename, "rb");
791 if(dcm->fp==NULL) {
792 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_CANNOT_OPEN);
794 }
795
796 /* Check the magic number and move file pointer to the end of it */
797 if(verbose>2) printf("checking DICOM magic number\n");
798 if(dcmVerifyMagic(NULL, dcm->fp)!=1) {
799 fclose(dcm->fp);
800 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_INVALID_FORMAT);
802 }
803
804 /* Get the Transfer Syntax UID */
805 if(verbose>2) printf("checking Transfer Syntax UID\n");
807 if(dcm->truid==DCM_TRUID_INVALID) { // not found
808 fclose(dcm->fp);
809 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_INVALID_FORMAT);
811 }
812 if(verbose>0) { // print the UID
813 printf("Transfer Syntax UID := %s\n", dcmTrUIDDescr(dcm->truid));
814 fflush(stdout);
815 }
816
817 /* Check whether we currently support the Transfer UID */
818 switch(dcm->truid) {
819 case DCM_TRUID_LEE:
820 case DCM_TRUID_LEI: // actually not supported yet
821 break;
822 default:
823 fclose(dcm->fp);
824 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_UNSUPPORTED);
826 }
827
828 /* Read DICOM file elements */
829 int ret=TPCERROR_OK;
830 do {
831 // note that the next function may need to call itself,
832 // therefore counting loops here would not be useful.
833 ret=dcmFileReadNextElement(dcm, NULL, NULL, 0, headerOnly, verbose-10);
834 } while(ret==TPCERROR_OK && !feof(dcm->fp));
835 fclose(dcm->fp);
836 /* TPCERROR_NO_KEY means that no (more) tag was found;
837 other codes still mean that something bad happened. */
838 if(ret==TPCERROR_NO_KEY) {
839 if(verbose>1) printf(" eof\n");
840 ret=TPCERROR_OK;
841 }
842 statusSet(status, __func__, __FILE__, __LINE__, ret);
843 return(ret);
844}
dcmtruid dcmReadTransferSyntaxUID(FILE *fp)
Definition dcmio.c:73
int dcmFileReadNextElement(DCMFILE *dcm, DCMITEM *prev_item, DCMITEM *parent_item, const short int sub, const short int headerOnly, int verbose)
Definition dcmio.c:409
char * dcmTrUIDDescr(dcmtruid id)
Definition dcmuid.c:87
@ TPCERROR_INVALID_FORMAT
Invalid file format.
@ TPCERROR_CANNOT_OPEN
Cannot open file.
@ TPCERROR_NO_KEY
Key not found.

Referenced by dcmFileList(), dcmMListRead(), and imgReadDICOM().

◆ dcmFileReadNextElement()

int dcmFileReadNextElement ( DCMFILE * dcm,
DCMITEM * prev_item,
DCMITEM * parent_item,
const short int sub,
const short int headerOnly,
int verbose )

Read an element from DICOM file, and add it to the given linked list. This function will be called recursively in case of sequential items.

Returns
Code tpcerror, TPCERROR_OK (0) when successful, TPCERROR_NO_KEY when no more elements could be read.
See also
dcmFileRead
Parameters
dcmPointer to DCMFILE struct; must be initiated before first call.
prev_itemPointer to previous element; NULL if none exists (yet).
parent_itemPointer to parent element; NULL if none exists (yet).
subAdd as next element (0) or as child element.
headerOnlyRead only header (1), or read both header and pixel data (0).
verboseVerbose level; if zero, then nothing is printed to stderr or stdout.

Definition at line 409 of file dcmio.c.

422 {
423 if(verbose>0) printf("%s(DCMFILE*, DCMITEM*, DCMITEM*, %d, %d)\n", __func__, sub, headerOnly);
424 if(dcm==NULL || dcm->fp==NULL) return(TPCERROR_FAIL);
425 if(sub!=0 && parent_item==NULL) return(TPCERROR_FAIL);
426 if(feof(dcm->fp)) return(TPCERROR_NO_KEY);
427
428 /* Check whether we currently support the Transfer UID */
429 switch(dcm->truid) {
430 case DCM_TRUID_LEE:
431 break;
432 case DCM_TRUID_LEI: // actually not supported yet
433 break;
434 default:
435 return(TPCERROR_UNSUPPORTED);
436 }
437
438 if(verbose>10) {
439 if(dcm->item==NULL) printf(" will add first element\n");
440 else if(sub==0) printf(" will add next element\n");
441 else printf(" will add sub-element\n");
442 }
443
444 /* Is this a child to a sequence element? */
445 int sq_child=0;
446 if(parent_item!=NULL && parent_item->vr==DCM_VR_SQ) {sq_child=1;}
447 if(verbose>10 && sq_child!=0) printf(" we're a child to a sequence element\n");
448
449 /* Allocate memory for the new element */
450 DCMITEM *item=(DCMITEM*)malloc(sizeof(DCMITEM));
451 if(item==NULL) return(TPCERROR_OUT_OF_MEMORY);
452 item->prev_item=prev_item;
453 item->parent_item=parent_item;
454 item->next_item=item->child_item=(DCMITEM*)NULL;
455 item->fp=dcm->fp; item->truid=dcm->truid;
456 item->rd=(char*)NULL;
457
458 /* Save current file position (should be the start of element) */
459 if(fgetpos(dcm->fp, &item->pos)) {
460 free(item); return(TPCERROR_CANNOT_READ);
461 }
462
463 /* Read the tag (2x2 bytes) */
464 if(verbose>10) {
465 long long int tagpos=ftello(dcm->fp);
466 printf(" reading tag at %lld\n", tagpos);
467 }
468 if(dcmReadFileTag(dcm->fp, &item->tag)) {
469 if(verbose>1 && !feof(dcm->fp)) printf(" error in reading the tag.\n");
470 free(item);
471 if(feof(dcm->fp)) return(TPCERROR_NO_KEY);
472 return(TPCERROR_CANNOT_READ);
473 }
474
475 if(verbose>2) {
476 printf(" tag(%04x,%04x) with %u parents\n",
477 item->tag.group, item->tag.element, dcmitemParentNr(item));
478 }
479
480 /* If child, then check for item delimitation tag (although it should not be here) */
481 if(dcmitemParentNr(item)>0 && item->tag.group==0xFFFE && item->tag.element==0xE00D) {
482 if(verbose>10)
483 printf(" item delimitation tag(%04x,%04x) found, reading VL\n",
484 item->tag.group, item->tag.element);
485 unsigned long int vl=dcmReadFileVL(dcm->fp, 4);
486 if(verbose>1) printf(" item delimitation tag VL := %lu (0x%08lx)\n", vl, vl);
487 if(vl!=0) {
488 if(verbose>1) printf(" error: VL should have been 0\n");
490 }
491 return(TPCERROR_OK);
492 }
493
494
495 /* Read value representation and length (VR and VL, 2x2 or 2x4 bytes) */
496 if(item->tag.group==0x0002 || dcm->truid==DCM_TRUID_LEE) {
497 // Group 0x0002 is always DCM_TRUID_LEE, the other groups are specified by
498 // the Transfer Syntax UID
499 if(verbose>10) printf(" reading VR and VL\n");
500 int ret;
501 unsigned int n;
502 ret=dcmReadFileVRVL(dcm->fp, &item->vr, &item->vl, &n);
503 if(ret!=TPCERROR_OK) {
504 if(verbose>1) printf(" invalid VR or VL\n");
505 free(item); return(ret);
506 }
507 if(verbose>1) {
508 printf(" VR := %s (%s)\n", dcmVRName(item->vr), dcmVRDescr(item->vr));
509 printf(" VL := %u (0x%08x) (%d bytes field)\n", item->vl, item->vl, n/2);
510 fflush(stdout);
511 }
512 } else if(dcm->truid==DCM_TRUID_LEI) {
513 if(verbose>10) printf(" set VR based on the tag\n");
514 unsigned int i=dcmDictFindTag(&item->tag);
515 item->vr=dcmVRId(dcmDictIndexVR(i));
516 if(item->vr!=DCM_VR_INVALID) {
517 if(verbose>1) {
518 printf(" VR := %s (%s)\n", dcmVRName(item->vr), dcmVRDescr(item->vr));
519 fflush(stdout);
520 }
521 } else {
522 if(verbose>1) printf(" VR not known for tag(%04x,%04x)\n",
523 item->tag.group, item->tag.element);
524 }
525 if(verbose>10) printf(" reading VL\n");
526 item->vl=dcmReadFileVL(dcm->fp, 4);
527 if(verbose>1) {
528 printf(" VL := %u (0x%08x)\n", item->vl, item->vl);
529 fflush(stdout);
530 }
531 }
532
533 /* Read value field, and add the current element to the list */
534 if(item->vr==DCM_VR_SQ) {
535 if(ftello(dcm->fp)<0) return(TPCERROR_INVALID_FORMAT);
536 unsigned long long int sqPos=(unsigned long int)ftello(dcm->fp);
537 if(verbose>10) {printf(" sequence... at %llu\n", sqPos); fflush(stdout);}
538 unsigned long int sqContentLength=item->vl;
539 if(verbose>12) printf(" sequence contents length is %lu\n", sqContentLength);
540 /* File position is now at the start of first item in the sequence */
541 int ret;
542 /* If parent has no previous child, then define this as its child */
543 if(sq_child!=0 && parent_item->child_item==NULL) {
544 parent_item->child_item=item;
545 } else {
546 /* else, add SQ sequence itself as next element to the list, and later
547 add each sequence item as child to it */
548 if(prev_item==NULL) {
549 if(dcm->item==NULL) { // truly the first item
550 dcm->item=item;
551 } else { // search for the previous one
552 DCMITEM *ip; ip=dcm->item;
553 while(ip->next_item!=NULL) ip=ip->next_item;
554 ip->next_item=item; item->prev_item=ip;
555 }
556 } else {
557 prev_item->next_item=item; item->prev_item=prev_item;
558 }
559 }
560 /* Read the first item tag and length, but there is no VR to read this time */
561 if(verbose>10) {
562 long long int tagpos=ftello(dcm->fp);
563 printf(" reading first item tag at %lld\n", tagpos);
564 }
565 DCMTAG itemtag;
566 ret=dcmReadFileTag(dcm->fp, &itemtag);
567 if(ret!=0) {
568 if(verbose>1) printf(" error %d in reading the tag.\n", ret);
569 return(TPCERROR_CANNOT_READ);
570 }
571 if(verbose>1) printf(" item tag(%04x,%04x)\n", itemtag.group, itemtag.element);
572 /* It is common that sequence is empty; check it first */
573 if(itemtag.group==0xFFFE && (itemtag.element==0xE0DD || itemtag.element==0xE00D)) {
574 /* yes; then read also the 4 byte LV, which should be zero */
575 if(verbose>10)
576 printf(" sequence delimitation item tag(%04x,%04x) found, reading VL\n",
577 itemtag.group, itemtag.element);
578 unsigned long int vl=dcmReadFileVL(dcm->fp, 4);
579 if(verbose>1) printf(" item tag VL := %lu (0x%08lx)\n", vl, vl);
580 if(vl!=0) {
581 if(verbose>1) printf(" error: VL should have been 0\n");
583 }
584 if(verbose>3) printf(" ending sequence before it really started.\n");
585 return(TPCERROR_OK);
586 }
587 /* If sequence actually contains something, the Item tag must be 0xFFFE,0xE000 */
588 if(itemtag.group!=0xFFFE || itemtag.element!=0xE000) {
589 if(verbose>1) printf(" invalid sequence item tag(%04x,%04x)\n", itemtag.group, itemtag.element);
590 return(TPCERROR_INVALID_FORMAT); //return(TPCERROR_OK);
591 }
592 /* Read past the VL of this item (always 4 bytes) */
593 unsigned long int itemvl=dcmReadFileVL(dcm->fp, 4);
594 if(verbose>3) {printf(" item_VL := %lu (0x%08lx)\n", itemvl, itemvl);}
595 if(ftello(dcm->fp)<0) return(TPCERROR_INVALID_FORMAT);
596 unsigned long int sqItemPos=(unsigned long int)ftell(dcm->fp);
597 /* Check if that is all of this sequence (probably Siemens) */
598 if((sqItemPos-sqPos)>=sqContentLength) {
599 if(verbose>3) printf(" ending sequence since it was found to be empty.\n");
600 return(TPCERROR_OK);
601 }
602 if(verbose>12) printf(" sequence content start position at %ld\n", sqItemPos);
603 /* Read the first item value as its own element, adding it as child to SQ */
604 ret=dcmFileReadNextElement(dcm, NULL, item, 1, headerOnly, verbose-1);
605 if(ret!=TPCERROR_OK) {
606 if(verbose>1) printf(" error in reading the first item value dataset\n");
607 return(ret);
608 }
609 /* Now we continue reading more items, until we reach Sequence Delimitation Item */
610 while(!feof(dcm->fp)) {
611 /* Do not read pass the length of the sequence data */
612 if(ftello(dcm->fp)<0) return(TPCERROR_INVALID_FORMAT);
613 unsigned long long int cPos=(unsigned long long int)ftello(dcm->fp);
614 if(sqContentLength>0 && (cPos-sqPos)>=sqContentLength) {
615 if(verbose>3) printf(" we reached the end of sequence VL %lu\n", sqContentLength);
616 /* set fake sequence delimitation tag */
617 itemtag.group=0xFFFE; itemtag.element=0xE0DD;
618 break;
619 }
620 if(verbose>10) {
621 long long int tagpos=ftello(dcm->fp);
622 printf(" reading next sequence item tag at %lld, %lld after start\n", tagpos, tagpos-sqItemPos);
623 }
624 if(dcmReadFileTag(dcm->fp, &itemtag)) return(TPCERROR_CANNOT_READ);
625 if(verbose>1) printf(" next item tag(%04x,%04x)\n", itemtag.group, itemtag.element);
626 itemvl=dcmReadFileVL(dcm->fp, 4); // delimitation tag has this too
627 if(verbose>3) {printf(" item_VL := %lu (0x%08lx)\n", itemvl, itemvl);}
628 /* Check if we got sequence delimitation tag */
629 if(itemtag.group==0xFFFE && itemtag.element==0xE0DD)
630 {
631 if(verbose>3) printf(" we got sequence delimitation tag\n");
632 break;
633 }
634 /* Check if we got item delimitation tag from the previous item */
635 if(itemtag.group==0xFFFE && itemtag.element==0xE00D)
636 {
637 if(verbose>3) printf(" we got item delimitation tag\n");
638 if(itemvl!=0) {
639 if(verbose>1) printf(" error: VL should have been 0\n");
641 }
642 continue;
643 }
644 /* Otherwise this should be sequence item tag */
645 if(itemtag.group!=0xFFFE || itemtag.element!=0xE000) {
646 if(verbose>3) printf(" not sequence item tag, move file position back 2x4 bytes\n");
647 fseeko(dcm->fp, -8, SEEK_CUR); //return(TPCERROR_INVALID_VALUE);
648 }
649 /* Read the item value as its own element, adding it to the SQ child list */
650 DCMITEM *child=item->child_item;
651 if(child==NULL) {
652 if(verbose>1) printf(" error had happened in adding the child element\n");
653 return(TPCERROR_UNSUPPORTED);
654 }
655 while(child->next_item!=NULL) child=child->next_item;
656 ret=dcmFileReadNextElement(dcm, child, item, 0, headerOnly, verbose-1);
657 if(ret!=TPCERROR_OK) {
658 if(verbose>1) printf(" error in reading item value dataset\n");
659 return(ret);
660 }
661 }
662 /* Check that loop really stopped at sequence delimitation item */
663 /* 0xE00D means the end of item, 0xE0DD the end of sequence. */
664 if(itemtag.group!=0xFFFE || itemtag.element!=0xE0DD) {
665 if(verbose>1)
666 printf(" invalid sequence delimitation item tag(%04x,%04x)\n", itemtag.group, itemtag.element);
667 return(TPCERROR_UNSUPPORTED);
668 }
669 /* Done. Do not free item! */
670 if(verbose>10) {printf(" end of sequence.\n"); fflush(stdout);} //return(TPCERROR_OK);
671 } else if(item->vl!=0xFFFFFFFF) {
672 if(verbose>10) {printf(" reading value of %u bytes...\n", item->vl); fflush(stdout);}
673 char *buf=NULL;
674 if(item->vl>0) {
675 buf=(char*)calloc(item->vl+1, sizeof(char));
676 if(buf==NULL) {free(item); return(TPCERROR_OUT_OF_MEMORY);}
677 if(fread(buf, 1, item->vl, item->fp)!=item->vl) {
678 free(item); free(buf); return(TPCERROR_NO_VALUE);
679 }
680 /* Do not store pixel data, if that was the request */
681 if(headerOnly!=0 &&
682 ((item->tag.group==0x7FE0 && item->tag.element>0) || item->tag.group==0x7FE1))
683 {
684 if(verbose>5) {printf(" ...not storing pixel data\n"); fflush(stdout);}
685 free(buf); buf=(char*)NULL;
686 } else {
687 item->rd=buf;
688 }
689 } else if(verbose>4) {
690 printf(" VL=0\n");
691 }
692 /* Add to list */
693 if(sub==0) {
694 if(prev_item==NULL) {
695 if(dcm->item==NULL) { // truly the first item
696 dcm->item=item;
697 } else { // search for the previous one
698 DCMITEM *ip; ip=dcm->item;
699 while(ip->next_item!=NULL) ip=ip->next_item;
700 ip->next_item=item; item->prev_item=ip;
701 }
702 } else {
703 prev_item->next_item=item; item->prev_item=prev_item;
704 }
705 } else { // add as child
706 parent_item->child_item=item; item->parent_item=parent_item;
707 }
708 /* Print tag and its value */
709 if(verbose>1) {
710 char *tagval=dcmValueString(item);
711 printf(" (%04x,%04x) %s := %s\n", item->tag.group, item->tag.element,
712 dcmDictIndexDescr(dcmDictFindTag(&item->tag)), tagval);
713 free(tagval);
714 }
715 /* Done. Do no free item or buf! */
716 return(TPCERROR_OK);
717
718 } else { // VL=0xFFFFFFFF
719 size_t s=dcmVRVLength(item->vr);
720 if(s==0) {
721 if(verbose>0) printf(" Unknown VL!!\n");
722 free(item);
723 return(TPCERROR_INVALID_VALUE); //return(TPCERROR_OK);
724 }
725 if(verbose>4) printf(" VR_based_VL=%u\n", (unsigned int)s);
726 char *buf=(char*)calloc(s+1, sizeof(char));
727 if(buf==NULL) {free(item); return(TPCERROR_OUT_OF_MEMORY);}
728 if(fread(buf, 1, s, item->fp)!=s) {
729 free(item); free(buf); return(TPCERROR_NO_VALUE);
730 }
731 item->rd=buf;
732 /* Add to list */
733 if(sub==0) {
734 if(prev_item==NULL) {
735 if(dcm->item==NULL) { // truly the first item
736 dcm->item=item;
737 } else { // search for the previous one
738 DCMITEM *ip; ip=dcm->item;
739 while(ip->next_item!=NULL) ip=ip->next_item;
740 ip->next_item=item; item->prev_item=ip;
741 }
742 } else {
743 prev_item->next_item=item; item->prev_item=prev_item;
744 }
745 } else { // add as child
746 parent_item->child_item=item; item->parent_item=parent_item;
747 }
748 /* Print tag and its value */
749 if(verbose>1) {
750 char *tagval=dcmValueString(item);
751 printf(" (%04x,%04x) %s := %s\n", item->tag.group, item->tag.element,
752 dcmDictIndexDescr(dcmDictFindTag(&item->tag)), tagval);
753 free(tagval);
754 }
755 /* Done. Do no free item or buf! */
756 return(TPCERROR_OK);
757 }
758
759 return(TPCERROR_OK);
760}
unsigned short int dcmitemParentNr(DCMITEM *d)
Definition dcmdata.c:122
char * dcmValueString(DCMITEM *d)
Definition dcmdata.c:141
char * dcmDictIndexVR(unsigned int i)
char * dcmDictIndexDescr(unsigned int i)
unsigned int dcmDictFindTag(DCMTAG *tag)
int dcmReadFileTag(FILE *fp, DCMTAG *tag)
Definition dcmio.c:135
int dcmReadFileVRVL(FILE *fp, dcmvr *vr, unsigned int *vl, unsigned int *n)
Definition dcmio.c:306
unsigned int dcmReadFileVL(FILE *fp, unsigned int n)
Definition dcmio.c:274
dcmvr dcmVRId(const char *s)
Definition dcmvr.c:103
char * dcmVRDescr(dcmvr id)
Definition dcmvr.c:162
fpos_t pos
Definition tpcdcm.h:133
@ TPCERROR_INVALID_VALUE
Invalid value.
@ TPCERROR_NO_VALUE
Value not found.
@ TPCERROR_OUT_OF_MEMORY
Cannot allocate memory.
@ TPCERROR_CANNOT_READ
Cannot read file.

Referenced by dcmFileRead(), and dcmFileReadNextElement().

◆ dcmFileRemove()

int dcmFileRemove ( const char * filename,
TPCSTATUS * status )

Remove DICOM files belonging to one image.

User can give DICOM image as a folder containing image file(s), or as a name of one of the files of the image.

See also
dcmFileList, dcmSameImage, pathRemoveFiles, dcmFileWrite
Returns
Code tpcerror, TPCERROR_OK (0) when successful.
Parameters
filenamePointer to the name of DICOM directory or file.
statusPointer to status data; enter NULL if not needed.

Definition at line 270 of file dcmfile.c.

275 {
276 int verbose=0; if(status!=NULL) verbose=status->verbose;
277 if(filename==NULL || strnlen(filename, 10)<1) {
278 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_FAIL);
279 return TPCERROR_FAIL;
280 }
281 if(verbose>1) printf("%s('%s', ...)\n", __func__, filename);
282
283 /* List files belonging to the image */
284 IFT ift; iftInit(&ift);
285 int ret=dcmFileList(filename, &ift, status);
286 if(ret!=TPCERROR_OK) {iftFree(&ift); return(ret);}
287
288 /* Remove the files */
289 for(int i=0; i<ift.keyNr; i++) {
290 if(remove(ift.item[i].value)) {
291 iftFree(&ift);
292 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_CANNOT_DELETE);
294 }
295 }
296 iftFree(&ift);
297
298 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_OK);
299 return(TPCERROR_OK);
300}
int dcmFileList(const char *filename, IFT *ift, TPCSTATUS *status)
List DICOM files belonging to one image.
Definition dcmfile.c:123
void iftInit(IFT *ift)
Definition ift.c:21
Definition tpcift.h:43
@ TPCERROR_CANNOT_DELETE
Cannot delete.

Referenced by imgWriteDICOM().

◆ dcmFileWrite()

int dcmFileWrite ( const char * filename,
DCMFILE * dcm,
TPCSTATUS * status )

Write a single DICOM file.

See also
dcmFileRead, dcmfileInit, dcmfileFree, dcmFileRemove
Returns
Code tpcerror, TPCERROR_OK (0) when successful.
Parameters
filenamePointer to file name.
dcmPointer to DICOM data to be written.
statusPointer to status data; enter NULL if not needed.

Definition at line 852 of file dcmio.c.

859 {
860 int verbose=0; if(status!=NULL) verbose=status->verbose;
861 if(filename==NULL || strnlen(filename, 10)<1 || dcm==NULL) {
862 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_FAIL);
863 return TPCERROR_FAIL;
864 }
865 if(verbose>1) {printf("%s('%s')\n", __func__, filename); fflush(stdout);}
866
867 /* Check for the data */
868 if(dcm->item==NULL) {
869 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_NO_DATA);
870 return TPCERROR_NO_DATA;
871 }
872
873 /* Check whether we currently support the Transfer UID */
874 if(dcm->truid!=DCM_TRUID_LEE) { // Little endian explicit
875 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_UNSUPPORTED);
877 }
878
879
880 /* Open the file */
881 if(verbose>1) printf("opening the file for writing\n");
882 FILE *fp;
883 fp=fopen(filename, "wb");
884 if(fp==NULL) {
885 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_CANNOT_WRITE);
887 }
888
889 /* Write preamble (just 128 zeroes) and magic number */
890 {
891 if(verbose>1) printf("writing preamble\n");
892 char buf1[128], buf2[5];
893 for(int i=0; i<128; i++) buf1[i]=(char)0;
894 strcpy(buf2, "DICM");
895 if(fwrite(buf1, 128, 1, fp)<1 || fwrite(buf2, 4, 1, fp)<1) {
896 fclose(fp); statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_CANNOT_WRITE);
898 }
899 }
900
901
902 /* Write the contents */
903 if(verbose>1) printf("writing DICOM contents\n");
904 int ret=0;
905 DCMITEM *iptr;
906 DCMITEM *d1=dcm->item;
907 while(d1!=NULL) {
908 if(verbose>2) {dcmitemPrint(d1);}
909 /* Write */
910 iptr=d1;
911 {
912 size_t n;
913 /* Write tag */
914 if(dcmWriteFileTag(fp, &iptr->tag)!=TPCERROR_OK) {ret=1; break;}
915 /* Write VR and VL */
916 if(dcmWriteFileVRVL(fp, iptr->vr, iptr->vl, NULL)!=TPCERROR_OK) {ret=2; break;}
917 /* Write value, unless zero length, or SQ, in which case written later */
918 if(iptr->vl>0 && iptr->vr!=DCM_VR_SQ) {
919 size_t len;
920 if(iptr->vl==0xFFFFFFFF) {
921 len=dcmVRVLength(iptr->vr);
922 if(verbose>30) printf(" value_len1 := %u\n", (unsigned int)len);
923 n=fwrite(iptr->rd, dcmVRVLength(iptr->vr), 1, fp);
924 } else {
925 len=iptr->vl;
926 if(verbose>30) printf(" value_len3 := %u\n", (unsigned int)len);
927 n=fwrite(iptr->rd, iptr->vl, 1, fp);
928 }
929 if(verbose>30) printf(" value_len := %u\n", (unsigned int)len);
930 if(n!=1) {ret=4; break;}
931 } else if(iptr->vr==DCM_VR_SQ && d1->child_item==NULL) {
932 if(verbose>1) printf("SQ, but no contents to write!\n");
933 /* Write Sequence Delimitation Item */
934 if(dcmWriteFileSQDelimItem(fp)!=TPCERROR_OK) {ret=6; break;}
935 }
936 }
937
938 /* If this element (SQ) has children, then write those */
939 /* Data Elements with a group of 0000, 0002 and 0006 shall not be present within Sequence Items,
940 but that is not verified here */
941 if(d1->child_item!=NULL) {
942 DCMITEM *d2=d1->child_item;
943 unsigned int d2counter=0;
944 while(d2!=NULL) {
945 if(verbose>2) {printf(" "); dcmitemPrint(d2);}
946
947 /* Write */
948 iptr=d2;
949
950 /* First, write Item tag (FFFE,E000) */
951 if(d2counter==0) {
952 DCMTAG tag; tag.group=0xFFFE; tag.element=0xE000;
953 if(dcmWriteFileTag(fp, &tag)!=TPCERROR_OK) {ret=11; break;}
954 }
955 /* Write item length; write 0xFFFFFFFF for now, correct later when known */
956 fpos_t d2ilpos; // position for item length
957 unsigned int d2il=0; // item length
958 if(d2counter==0) {
959 if(fgetpos(fp, &d2ilpos)) {ret=12; break;} // save position for writing later
960 unsigned int ibuf;
961 ibuf=0xFFFFFFFF;
962 if(fwrite(&ibuf, 4, 1, fp)!=1) {ret=13; break;}
963 }
964 d2counter++;
965
966 /* Write item value data set */
967 {
968 /* Write tag */
969 if(dcmWriteFileTag(fp, &iptr->tag)!=TPCERROR_OK) {ret=14; break;}
970 d2il+=4;
971 /* Write VR and VL */
972 unsigned int s;
973 if(dcmWriteFileVRVL(fp, iptr->vr, iptr->vl, &s)!=TPCERROR_OK) {ret=15; break;}
974 d2il+=s;
975 /* Write value, unless zero length, or SQ, in which case written later */
976 if(iptr->vl>0 && iptr->vr!=DCM_VR_SQ) {
977 size_t len, n;
978 if(iptr->vl==0xFFFFFFFF) {
979 len=dcmVRVLength(iptr->vr);
980 if(verbose>30) printf(" value_len1 := %u\n", (unsigned int)len);
981 n=fwrite(iptr->rd, dcmVRVLength(iptr->vr), 1, fp);
982 d2il+=len;
983 } else {
984 len=iptr->vl;
985 if(verbose>30) printf(" value_len3 := %u\n", (unsigned int)len);
986 n=fwrite(iptr->rd, iptr->vl, 1, fp);
987 d2il+=iptr->vl;
988 }
989 if(verbose>30) printf(" value_len := %u\n", (unsigned int)len);
990 if(n!=1) {ret=17; break;}
991 } else if(iptr->vr==DCM_VR_SQ && iptr->child_item==NULL) {
992 if(verbose>1) printf("SQ, but no contents to write!\n");
993 /* Write Sequence Delimitation Item */
994 if(dcmWriteFileSQDelimItem(fp)!=TPCERROR_OK) {ret=19; break;}
995 }
996 }
997
998 /* If this element has children, then write those */
999 if(d2->child_item!=NULL) {
1000 DCMITEM *d3=d2->child_item;
1001 unsigned int d3counter=0;
1002 while(d3!=NULL) {
1003 if(verbose>2) {printf(" "); dcmitemPrint(d3);}
1004
1005 /* Write */
1006 iptr=d3;
1007 if(iptr->vr==DCM_VR_SQ) {d3=d3->next_item; continue;} // for now do not write SQs
1008
1009 /* First, write Item tag (FFFE,E000) */
1010 if(d3counter==0) {
1011 DCMTAG tag; tag.group=0xFFFE; tag.element=0xE000;
1012 if(dcmWriteFileTag(fp, &tag)!=TPCERROR_OK) {ret=31; break;}
1013 d2il+=4;
1014 }
1015 /* Write item length; write 0xFFFFFFFF for now, correct later when known */
1016 fpos_t d3ilpos; // position for item length
1017 unsigned int d3il=0; // item length
1018 if(d3counter==0) {
1019 unsigned int ibuf;
1020 if(fgetpos(fp, &d3ilpos)) {ret=32; break;} // save position for writing later
1021 ibuf=0xFFFFFFFF;
1022 if(fwrite(&ibuf, 4, 1, fp)!=1) {ret=33; break;}
1023 d2il+=4;
1024 }
1025 d3counter++;
1026
1027 /* Write item value data set */
1028 {
1029 /* Write tag */
1030 if(dcmWriteFileTag(fp, &iptr->tag)!=TPCERROR_OK) {ret=34; break;}
1031 d3il+=4; d2il+=4;
1032 /* Write VR and VL */
1033 unsigned int s;
1034 if(dcmWriteFileVRVL(fp, iptr->vr, iptr->vl, &s)!=TPCERROR_OK) {ret=35; break;}
1035 d3il+=s; d2il+=s;
1036 /* Write value, unless zero length, or SQ, in which case written later */
1037 if(iptr->vl>0 && iptr->vr!=DCM_VR_SQ) {
1038 size_t len, n;
1039 if(iptr->vl==0xFFFFFFFF) {
1040 len=dcmVRVLength(iptr->vr);
1041 if(verbose>30) printf(" value_len1 := %u\n", (unsigned int)len);
1042 n=fwrite(iptr->rd, dcmVRVLength(iptr->vr), 1, fp);
1043 d3il+=len; d2il+=len;
1044 } else {
1045 len=iptr->vl;
1046 if(verbose>30) printf(" value_len3 := %u\n", (unsigned int)len);
1047 n=fwrite(iptr->rd, iptr->vl, 1, fp);
1048 d3il+=iptr->vl; d2il+=iptr->vl;
1049 }
1050 if(verbose>30) printf(" value_len := %u\n", (unsigned int)len);
1051 if(n!=1) {ret=37; break;}
1052 } else if(iptr->vr==DCM_VR_SQ && iptr->child_item==NULL) {
1053 if(verbose>1) printf("SQ, but no contents to write!\n");
1054 /* Write Sequence Delimitation Item */
1055 if(dcmWriteFileSQDelimItem(fp)!=TPCERROR_OK) {ret=39; break;}
1056 d2il+=8;
1057 }
1058 }
1059
1060 /* If this element has children, then write those */
1061 if(d3->child_item!=NULL) {
1062 //DCMITEM *d4=d3->child_item;
1063 if(verbose>0) fprintf(stderr, "Warning: 4th level items not written.\n");
1064 }
1065
1066 /* now that we known the length, write it to the saved position */
1067 if(0) {
1068 fpos_t opos; // current position to return to
1069 if(fgetpos(fp, &opos)) {ret=40; break;}
1070 fsetpos(fp, &d3ilpos); // go to the position for item length
1071 char buf[4];
1072 memcpy(buf, &d3il, 4);
1073 if(!endianLittle()) swabip(buf, 4);
1074 if(fwrite(&buf, 4, 1, fp)!=1) {ret=41; break;}
1075 fsetpos(fp, &opos); // back to the position where we were
1076 }
1077
1078 d3=d3->next_item;
1079 }
1080 if(ret!=0) break;
1081
1082 /* Write Item Delimitation Tag */
1083 if(dcmWriteFileSQItemDelimTag(fp)!=0) {ret=21; break;}
1084 /* End of the sequence - write Sequence Delimitation Item */
1085 if(dcmWriteFileSQDelimItem(fp)!=TPCERROR_OK) {ret=21; break;}
1086
1087 }
1088
1089
1090 /* now that we known the length, write it to the saved position */
1091 if(0) {
1092 fpos_t opos; // current position to return to
1093 if(fgetpos(fp, &opos)) {ret=18; break;}
1094 fsetpos(fp, &d2ilpos); // go to the position for item length
1095 char buf[4];
1096 memcpy(buf, &d2il, 4);
1097 if(!endianLittle()) swabip(buf, 4);
1098 if(fwrite(&buf, 4, 1, fp)!=1) {ret=19; break;}
1099 fsetpos(fp, &opos); // back to the position where we were
1100 }
1101
1102 d2=d2->next_item;
1103 }
1104 if(ret!=0) break;
1105
1106 /* Write Item Delimitation Tag */
1107 if(dcmWriteFileSQItemDelimTag(fp)!=0) {ret=21; break;}
1108 /* End of the sequence - write Sequence Delimitation Item */
1109 if(dcmWriteFileSQDelimItem(fp)!=TPCERROR_OK) {ret=21; break;}
1110
1111 }
1112
1113 d1=d1->next_item;
1114 } // next
1115 if(ret!=0) {
1116 if(verbose>0) fprintf(stderr, " ret := %d\n", ret);
1117 fclose(fp);
1118 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_CANNOT_WRITE);
1119 return TPCERROR_CANNOT_WRITE;
1120 }
1121
1122
1123 fclose(fp);
1124
1125 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_OK);
1126 return(TPCERROR_OK);
1127}
int dcmWriteFileVRVL(FILE *fp, dcmvr vr, unsigned int vl, unsigned int *n)
Definition dcmio.c:366
int dcmWriteFileSQItemDelimTag(FILE *fp)
Definition dcmio.c:216
int dcmWriteFileTag(FILE *fp, DCMTAG *tag)
Definition dcmio.c:165
int dcmWriteFileSQDelimItem(FILE *fp)
Definition dcmio.c:191
void swabip(void *buf, int size)
Definition endian.c:115
int endianLittle()
Definition endian.c:53
@ TPCERROR_NO_DATA
File contains no data.
@ TPCERROR_CANNOT_WRITE
Cannot write file.

Referenced by imgWriteDICOM().

◆ dcmFindDownTag()

DCMITEM * dcmFindDownTag ( DCMITEM * d,
const short int omit,
DCMTAG * tag,
const int verbose )

Search for specified tag in DCMITEM data tree, but only downward.

Returns
Returns pointer to next item with the tag, or NULL if not found.
Parameters
dPointer to current DICOM item.
omitOmit this item from the search.
tagPointer to the DICOM tag that is searched for.
verboseVerbose level; if zero, then nothing is printed to stderr or stdout.

Definition at line 428 of file dcmdata.c.

437 {
438 if(d==NULL || tag==NULL) return(NULL);
439 if(verbose>0) printf("%s((%04X,%04X),%d)\n", __func__, tag->group, tag->element, omit);
440 DCMITEM *iptr;
441 if(omit==0) iptr=d; else iptr=d->next_item;
442 while(iptr!=NULL) {
443 if(verbose>2)
444 printf(" checking tag(%04X,%04X)...\n", iptr->tag.group, iptr->tag.element);
445 if(iptr->tag.group==tag->group && iptr->tag.element==tag->element) {
446 if(verbose>2) printf(" found!\n");
447 break;
448 }
449 /* Check if this item has children */
450 if(iptr->child_item!=NULL) {
451 if(verbose>2) printf(" going to search inside children...\n");
452 DCMITEM *rptr=dcmFindDownTag(iptr->child_item, 0, tag, verbose);
453 if(rptr!=NULL) return(rptr);
454 if(verbose>3) printf(" nothing found in any of the children\n");
455 }
456 iptr=iptr->next_item;
457 }
458 /* Stop if we found tag */
459 if(iptr!=NULL) return(iptr);
460 /* Stop anyway */
461 return(NULL);
462}
DCMITEM * dcmFindDownTag(DCMITEM *d, const short int omit, DCMTAG *tag, const int verbose)
Definition dcmdata.c:428

Referenced by dcmFindDownTag(), dcmFindTag(), dcmImgIsotope(), dcmImgPos(), dcmImgPxlsize(), dcmMListRead(), and imgReadDICOM().

◆ dcmFindTag()

DCMITEM * dcmFindTag ( DCMITEM * d,
const short int omit,
DCMTAG * tag,
const int verbose )

Search for specified tag in DCMITEM data tree, from left to right, down and up.

Returns
Returns pointer to next item with the tag, or NULL if not found.
Parameters
dPointer to current DICOM item.
omitOmit this item from the search.
tagPointer to the DICOM tag that is searched for.
verboseVerbose level; if zero, then nothing is printed to stderr or stdout.

Definition at line 375 of file dcmdata.c.

384 {
385 if(d==NULL || tag==NULL) return(NULL);
386 if(verbose>0) printf("%s((%04X,%04X),%d)\n", __func__, tag->group, tag->element, omit);
387 DCMITEM *iptr;
388 if(omit==0) iptr=d; else iptr=d->next_item;
389 while(iptr!=NULL) {
390 if(verbose>2)
391 printf(" checking tag(%04X,%04X)...\n", iptr->tag.group, iptr->tag.element);
392 if(iptr->tag.group==tag->group && iptr->tag.element==tag->element) {
393 if(verbose>2) printf(" found!\n");
394 break;
395 }
396 /* Check if this item has children */
397 if(iptr->child_item!=NULL) {
398 if(verbose>2) printf(" going to search inside children...\n");
399 DCMITEM *rptr=dcmFindDownTag(iptr->child_item, 0, tag, verbose);
400 if(rptr!=NULL) return(rptr);
401 if(verbose>3) printf(" nothing found in any of the children\n");
402 }
403 iptr=iptr->next_item;
404 }
405 /* Stop if we found tag */
406 if(iptr!=NULL) return(iptr);
407 /* Stop if we do not have parent */
408 if(d->parent_item==NULL) return(NULL);
409 /* Search from the parent, but not including the parent */
410 if(verbose>2) printf(" going to search the parents sister...\n");
411 return(dcmFindTag(d->parent_item, 1, tag, verbose));
412
413#if(0)
414 if(d->parent_item==NULL) return(NULL);
415
416 /* Search from the parent */
417 if(verbose>2) printf(" going to search inside parent...\n");
418 return(dcmFindTag(d->parent_item, 1, tag, verbose));
419#endif
420}

Referenced by dcmFileList(), dcmFindTag(), dcmImgDim(), dcmImgIsotope(), dcmImgOrient(), dcmImgPos(), dcmImgPxlsize(), dcmMListRead(), dcmSameImage(), dcmTagIntRange(), and imgReadDICOM().

◆ dcmImgDim()

int dcmImgDim ( DCMFILE * d,
unsigned short int * imgdim,
const int verbose )

Get DICOM image dimensions.

See also
dcmImgOrient, dcmImgPxlsize
Returns
0 if successful, otherwise >0.
Parameters
dPointer to DCMFILE.
imgdimPointer to imgdim array of x, y, z, and frame numbers, to be filled here.
verboseVerbose level; if zero, then nothing is printed to stderr or stdout.

Definition at line 232 of file dcmimage.c.

239 {
240 if(verbose>0) {printf("%s(dcmfile, imgdim)\n", __func__); fflush(stdout);}
241 if(d==NULL || d->item==NULL || imgdim==NULL) return(1);
242 for(int i=0; i<4; i++) imgdim[i]=0;
243
244 DCMTAG tag; DCMITEM *iptr;
245
246 /* Get image row number (dimy) */
247 dcmTagSet(&tag, 0x0028, 0x0010);
248 iptr=dcmFindTag(d->item, 0, &tag, 0);
249 if(iptr==NULL) {
250 if(verbose>0) {fprintf(stderr, "Error: cannot find matrix row number.\n"); fflush(stderr);}
251 return(11);
252 }
253 imgdim[1]=(unsigned short int)dcmitemGetInt(iptr);
254
255 /* Get image column number (dimx) */
256 dcmTagSet(&tag, 0x0028, 0x0011);
257 iptr=dcmFindTag(d->item, 0, &tag, 0);
258 if(iptr==NULL) {
259 if(verbose>0) {fprintf(stderr, "Error: cannot find matrix column number.\n"); fflush(stderr);}
260 return(21);
261 }
262 imgdim[0]=(unsigned short int)dcmitemGetInt(iptr);
263
264 /* Get image plane/slice number (dimz) */
265 int a, b;
266 if(verbose>1) {printf("trying to read plane number as 'Number of Slices'\n"); fflush(stdout);}
267 dcmTagSet(&tag, 0x0054, 0x0081);
268 iptr=dcmFindTag(d->item, 0, &tag, 0);
269 if(iptr!=NULL) {
270 imgdim[2]=(unsigned short int)dcmitemGetInt(iptr);
271 if(verbose>2) printf("planeNr := %u\n", imgdim[2]);
272 } else {
273 if(verbose>1) {printf("trying to read plane number from 'In Stack Position Number'\n"); fflush(stdout);}
274 dcmTagSet(&tag, 0x0020, 0x9057);
275 if(dcmTagIntRange(d->item, &tag, &a, &b, verbose-100)==0) {
276 imgdim[2]=(unsigned short int)b;
277 if(verbose>2) printf("planeNr := %u\n", imgdim[2]);
278 } else {
279 if(verbose>1) {printf("trying to read plane number from 'Dimension Index Values'\n"); fflush(stdout);}
280 dcmTagSet(&tag, 0x0020, 0x9157);
281 if(dcmTagIntRange(d->item, &tag, &a, &b, verbose-1)==0) {
282 imgdim[2]=(unsigned short int)b;
283 if(verbose>2) printf("planeNr := %u\n", imgdim[2]);
284 } else {
285 if(verbose>0) {fprintf(stderr, "Warning: cannot find plane number.\n"); fflush(stderr);}
286 imgdim[2]=1;
287 }
288 }
289 }
290
291
292 /* Get frame number */
293 if(verbose>1) {printf("trying to get frame number from 'Temporal position index'\n"); fflush(stdout);}
294 dcmTagSet(&tag, 0x0020, 0x9128);
295 if(dcmTagIntRange(d->item, &tag, &a, &b, verbose-100)==0) {
296 imgdim[3]=(unsigned short int)b;
297 if(verbose>2) printf("frameNr := %u\n", imgdim[3]);
298 } else {
299 if(verbose>1) {printf("trying to get frame number from 'Number of Time Slices'\n"); fflush(stdout);}
300 dcmTagSet(&tag, 0x0054, 0x0101);
301 iptr=dcmFindTag(d->item, 0, &tag, 0);
302 if(iptr!=NULL) {
303 imgdim[3]=(unsigned short int)dcmitemGetInt(iptr);
304 if(verbose>2) printf("frameNr := %u\n", imgdim[3]);
305 } else {
306 if(verbose>0) {fprintf(stderr, "Warning: cannot find frame number.\n"); fflush(stderr);}
307 imgdim[3]=1;
308 }
309 }
310
311 return(0);
312}
long int dcmitemGetInt(DCMITEM *d)
Definition dcmdata.c:295
int dcmTagIntRange(DCMITEM *d, DCMTAG *tag, int *mi, int *ma, const int verbose)
Definition dcmdata.c:631

Referenced by imgReadDICOM().

◆ dcmImgIsotope()

int dcmImgIsotope ( DCMFILE * d,
isotope * isot,
decaycorrection * dc,
const int verbose )

Get isotope and status of decaycorrection from DICOM.

See also
isotopeName, lambdaFromIsotope, decayCorrectionFactorFromisotope,
Returns
0 if successful, otherwise >0.
Parameters
dPointer to DCMFILE.
isotPointer to isotope code, to be set here; enter NULL if not needed.
dcPointer to status of decaycorrection.
verboseVerbose level; if zero, then nothing is printed to stderr or stdout.

Definition at line 24 of file dcmimage.c.

33 {
34 if(verbose>0) {printf("%s(dcmfile, *isotope, *decaycorrection)\n", __func__); fflush(stdout);}
35 if(isot!=NULL) *isot=ISOTOPE_UNKNOWN;
36 if(dc!=NULL) *dc=DECAY_UNKNOWN;
37 if(d==NULL || d->item==NULL) return(1);
38
39
40 DCMTAG tag; DCMITEM *iptr, *jptr;
41
42 /* Get the status of decay correction */
43 if(dc!=NULL) {
44 if(verbose>1) {printf("trying to find 'Decay Correction' tag\n"); fflush(stdout);}
45 dcmTagSet(&tag, 0x0054, 0x1102); iptr=dcmFindTag(d->item, 0, &tag, 0);
46 if(iptr!=NULL) {
47 char *buf=dcmValueString(iptr);
48 if(verbose>12) printf("Decay Correction := '%s'\n", buf);
49 if(strcasestr(buf, "NONE")!=NULL) *dc=DECAY_NOTCORRECTED;
50 else if(strcasestr(buf, "START")!=NULL) *dc=DECAY_CORRECTED_START;
51 else if(strcasestr(buf, "ADMIN")!=NULL) *dc=DECAY_CORRECTED_ADMIN;
52 free(buf);
53 } else {
54 if(verbose>1) {printf(" not found\ntrying to find 'Decay Corrected' tag\n"); fflush(stdout);}
55 dcmTagSet(&tag, 0x0018, 0x9758); iptr=dcmFindTag(d->item, 0, &tag, 0);
56 if(iptr!=NULL) {
57 char *buf=dcmValueString(iptr);
58 if(verbose>12) printf("Decay Correction := '%s'\n", buf);
59 if(strcasestr(buf, "YES")!=NULL) *dc=DECAY_CORRECTED;
60 else if(strcasestr(buf, "NO")!=NULL) *dc=DECAY_NOTCORRECTED;
61 free(buf);
62 } else if(verbose>1) {printf(" not found.\n"); fflush(stdout);}
63 }
64 if(verbose>0 && *dc==DECAY_UNKNOWN) {
65 fprintf(stderr, "Warning: status of decay correction not found.\n");
66 fflush(stdout);
67 }
68 if(verbose>11) printf("decayCorrection := %s\n", decayDescr(*dc));
69 }
70
71 if(isot==NULL) return(0);
72
73 /* Get the radioisotope */
74 if(verbose>1) {printf("trying to find Radiopharmaceutical Information Sequence\n"); fflush(stdout);}
75 dcmTagSet(&tag, 0x0054, 0x0016); iptr=dcmFindTag(d->item, 0, &tag, 0);
76 if(iptr!=NULL) {
77 if(verbose>1) {printf(" found.\n"); fflush(stdout);}
78 iptr=iptr->child_item;
79 } else {
80 if(verbose>1) {printf(" not found.\n"); fflush(stdout);}
81 iptr=d->item;
82 }
83 if(verbose>1) {printf("trying to find Radionuclide Code Sequence\n"); fflush(stdout);}
84 dcmTagSet(&tag, 0x0054, 0x0300); jptr=dcmFindTag(iptr, 0, &tag, 0);
85 if(jptr!=NULL) {
86 if(verbose>1) {printf(" found.\n"); fflush(stdout);}
87 if(verbose>1) {printf("trying to find Code Meaning\n"); fflush(stdout);}
88 dcmTagSet(&tag, 0x0008, 0x0104); jptr=dcmFindDownTag(jptr, 0, &tag, 0);
89 if(jptr!=NULL) {
90 char *buf=dcmValueString(jptr);
91 if(verbose>12) {printf("Code Meaning := '%s'\n", buf); fflush(stdout);}
92 *isot=isotopeIdentify(buf);
93 free(buf);
94 if(verbose>11) {printf("isotope := %s\n", isotopeName(*isot)); fflush(stdout);}
95 } else if(verbose>1) {printf(" not found.\n"); fflush(stdout);}
96 } else {
97 if(verbose>1) {printf(" not found.\n"); fflush(stdout);}
98 }
99 if(*isot==ISOTOPE_UNKNOWN) {
100 if(verbose>1) {printf("trying to find Radionuclide Half Life\n"); fflush(stdout);}
101 dcmTagSet(&tag, 0x0018, 0x1075); jptr=dcmFindTag(iptr, 0, &tag, 0);
102 if(jptr!=NULL) {
103 char *buf=dcmValueString(jptr); strCleanSpaces(buf);
104 if(verbose>12) {printf("Radionuclide Half Life := '%s'\n", buf); fflush(stdout);}
105 double hl=atofVerified(buf);
106 *isot=isotopeIdentifyHalflife(hl/60.0);
107 free(buf);
108 if(verbose>11) {printf("isotope := %s\n", isotopeName(*isot)); fflush(stdout);}
109 } else if(verbose>1) {printf(" not found.\n"); fflush(stdout);}
110 }
111
112 return(0);
113}
char * decayDescr(decaycorrection d)
Definition decay.c:32
double atofVerified(const char *s)
Definition decpoint.c:75
char * isotopeName(int isotope_code)
Definition isotope.c:101
int isotopeIdentifyHalflife(double halflife)
Definition isotope.c:121
int isotopeIdentify(const char *isotope)
Definition isotope.c:145
int strCleanSpaces(char *s)
Definition stringext.c:300
char * strcasestr(const char *haystack, const char *needle)
Definition stringext.c:155
@ DECAY_UNKNOWN
Not known; usually assumed that data is corrected.
Definition tpcisotope.h:79
@ DECAY_CORRECTED_ADMIN
Data is corrected for physical decay to radioligand administration time.
Definition tpcisotope.h:83
@ DECAY_NOTCORRECTED
Data is not corrected for physical decay.
Definition tpcisotope.h:80
@ DECAY_CORRECTED
Data is corrected for physical decay.
Definition tpcisotope.h:81
@ DECAY_CORRECTED_START
Data is corrected for physical decay to scan start time.
Definition tpcisotope.h:82
@ ISOTOPE_UNKNOWN
Unknown.
Definition tpcisotope.h:51

Referenced by imgReadDICOM().

◆ dcmImgOrient()

int dcmImgOrient ( DCMFILE * d,
double * iop,
const int verbose )

Get DICOM image orientation (Patient).

See also
dcmImgPos, dcmImgDim, dcmImgPxlsize, dcmImgXform, dcmXformToQuatern
Returns
0 if successful, otherwise >0.
Parameters
dPointer to DCMFILE.
iopPointer to iop array of six values, to be filled here.
verboseVerbose level; if zero, then nothing is printed to stderr or stdout.

Definition at line 387 of file dcmimage.c.

394 {
395 if(verbose>0) {printf("%s(dcmfile, iop)\n", __func__); fflush(stdout);}
396 if(d==NULL || d->item==NULL || iop==NULL) return(1);
397 for(int i=0; i<6; i++) iop[i]=nan("");
398
399 DCMTAG tag; DCMITEM *iptr;
400
401 if(verbose>1) {printf("reading Image Orientation (Patient)\n"); fflush(stdout);}
402 dcmTagSet(&tag, 0x0020, 0x0037);
403 iptr=dcmFindTag(d->item, 0, &tag, 0);
404 if(iptr==NULL) {
405 if(verbose>0) {fprintf(stderr, "Error: no Image Orientation (Patient)\n"); fflush(stderr);}
406 return(11);
407 }
408 char *buf=dcmValueString(iptr);
409 if(verbose>2) printf(" image_orientation := '%s'\n", buf);
410 int n=sscanf(buf, "%lf\\%lf\\%lf\\%lf\\%lf\\%lf", &iop[0], &iop[1], &iop[2],
411 &iop[3], &iop[4], &iop[5]);
412 free(buf);
413 if(n!=6) {
414 if(verbose>0) {fprintf(stderr, "Error: invalid Image Orientation (Patient)\n"); fflush(stderr);}
415 return(12);
416 }
417
418 return(0);
419}

Referenced by imgReadDICOM().

◆ dcmImgPos()

int dcmImgPos ( DCMFILE * d,
double * imgpos,
const int verbose )

Get DICOM Image Position (Patient).

See also
dcmImgOrient, dcmImgDim, dcmImgPxlsize, dcmImgXform, dcmXformToQuatern
Returns
0 if successful, otherwise >0.
Parameters
dPointer to DCMFILE.
imgposPointer to imgpos array of x, y, and z coordinates of the upper left hand corner (centre of the first voxel) of the image, in mm, to be filled here.
verboseVerbose level; if zero, then nothing is printed to stderr or stdout.

Definition at line 121 of file dcmimage.c.

129 {
130 if(verbose>0) {printf("%s(dcmfile, imgpos)\n", __func__); fflush(stdout);}
131 if(d==NULL || d->item==NULL || imgpos==NULL) return(1);
132 for(int i=0; i<3; i++) imgpos[i]=nan("");
133
134 DCMTAG tag; DCMITEM *iptr, *jptr;
135
136 if(verbose>1) {printf("trying to find Per Frame Functional Groups Sequence\n"); fflush(stdout);}
137 dcmTagSet(&tag, 0x5200, 0x9230); // Per Frame Functional Groups Sequence
138 iptr=dcmFindTag(d->item, 0, &tag, 0);
139 if(iptr!=NULL) {
140 if(verbose>1) {printf(" found.\n"); fflush(stdout);}
141
142 /* search for Frame Content Sequences until we find one with position number 1 */
143 int posnr=0; dcmTagSet(&tag, 0x0020, 0x9111);
144 jptr=dcmFindDownTag(iptr->child_item, 0, &tag, 0);
145 while(jptr!=NULL) {
146 /* Get In Stack Position Number */
147 DCMITEM *kptr; DCMTAG spostag; dcmTagSet(&spostag, 0x0020, 0x9057);
148 kptr=dcmFindDownTag(jptr->child_item, 0, &spostag, 0);
149 if(kptr!=NULL) {
150 posnr=dcmitemGetInt(kptr); if(verbose>3) printf(" posnr=%d\n", posnr);
151 if(posnr==1) break; // found stack position number 1
152 }
153 jptr=dcmFindDownTag(jptr->next_item, 0, &tag, 0);
154 }
155 /* If stack position 1 was found, then get plane position sequence */
156 if(posnr==1 && jptr!=NULL) {
157 dcmTagSet(&tag, 0x0020, 0x9113);
158 jptr=dcmFindDownTag(jptr->next_item, 0, &tag, 0);
159 if(jptr!=NULL) {
160 /* Get Image Position (Patient) under it */
161 DCMITEM *kptr; DCMTAG ipostag; dcmTagSet(&ipostag, 0x0020, 0x0032);
162 kptr=dcmFindDownTag(jptr->child_item, 0, &ipostag, 0);
163 if(kptr!=NULL) {
164 char *buf=dcmValueString(kptr);
165 if(verbose>4) printf(" image_position := '%s'\n", buf);
166 int n=sscanf(buf, "%lf\\%lf\\%lf", &imgpos[0], &imgpos[1], &imgpos[2]);
167 free(buf);
168 if(n!=3) {
169 if(verbose>0) fprintf(stderr, "Error: invalid Image Position (Patient)\n");
170 return(131);
171 }
172 } else {
173 if(verbose>0) fprintf(stderr, "Error: no Image Position (Patient)\n");
174 return(121);
175 }
176 } else {
177 if(verbose>0) fprintf(stderr, "Error: no Plane Position Sequence\n");
178 return(111);
179 }
180 } else {
181 if(verbose>0) {fprintf(stderr, "Error: stack position 1 not found.\n"); fflush(stderr);}
182 return(101);
183 }
184 return(0);
185 }
186 if(verbose>1) {printf(" not found.\n"); fflush(stdout);}
187
188 if(verbose>1) {printf("find the smallest Instance (image) Number\n"); fflush(stdout);}
189 dcmTagSet(&tag, 0x0020, 0x0013);
190 iptr=dcmFindTag(d->item, 0, &tag, 0);
191 if(iptr==NULL) {
192 if(verbose>0) {fprintf(stderr, "Error: Instance (image) Number not found.\n"); fflush(stderr);}
193 return(201);
194 }
195 int mininr=dcmitemGetInt(iptr); if(verbose>5) printf(" inr=%d\n", mininr);
196 jptr=iptr;
197 while(jptr!=NULL) {
198 jptr=dcmFindDownTag(jptr->next_item, 0, &tag, 0);
199 if(jptr==NULL) break;
200 int inr=dcmitemGetInt(jptr); if(verbose>5) printf(" inr=%d\n", inr);
201 if(inr<mininr) {mininr=inr; iptr=jptr;}
202 }
203 if(verbose>2) {printf(" smallest Instance (image) Number: %d\n", mininr); fflush(stdout);}
204
205 /* Get Image Position (Patient) after the smallest Instance Number */
206 dcmTagSet(&tag, 0x0020, 0x0032);
207 jptr=dcmFindDownTag(iptr, 0, &tag, 0);
208 if(jptr==NULL) {
209 if(verbose>0) fprintf(stderr, "Error: no Image Position (Patient)\n");
210 return(211);
211 } else {
212 char *buf=dcmValueString(jptr);
213 if(verbose>2) printf(" image_position := '%s'\n", buf);
214 int n=sscanf(buf, "%lf\\%lf\\%lf", &imgpos[0], &imgpos[1], &imgpos[2]);
215 free(buf);
216 if(n!=3) {
217 if(verbose>0) fprintf(stderr, "Error: invalid Image Position (Patient)\n");
218 return(212);
219 }
220 }
221
222 return(0);
223}

Referenced by imgReadDICOM().

◆ dcmImgPxlsize()

int dcmImgPxlsize ( DCMFILE * d,
double * pxlsize,
const int verbose )

Get DICOM Image voxel size.

See also
dcmImgDim, dcmImgOrient
Returns
0 if successful, otherwise >0.
Parameters
dPointer to DCMFILE.
pxlsizePointer to pxlsize array of x, y, and z sizes of image pixel, or actually, mm distance between neighbour voxel centres in x, y, and z directions.
verboseVerbose level; if zero, then nothing is printed to stderr or stdout.

Definition at line 320 of file dcmimage.c.

329 {
330 if(verbose>0) {printf("%s(dcmfile, pxlsize)\n", __func__); fflush(stdout);}
331 if(d==NULL || d->item==NULL || pxlsize==NULL) return(1);
332 for(int i=0; i<3; i++) pxlsize[i]=nan("");
333
334 DCMTAG tag; DCMITEM *iptr, *jptr, *kptr;
335
336 if(verbose>1) {printf("trying to find Pixel Measures Sequence\n"); fflush(stdout);}
337 dcmTagSet(&tag, 0x0028, 0x9110);
338 iptr=dcmFindTag(d->item, 0, &tag, 0);
339 if(iptr==NULL) {
340 kptr=d->item; // search from root
341 if(verbose>3) {fprintf(stdout, "Note: missing Pixel Measures Sequence.\n"); fflush(stdout);}
342 } else {
343 kptr=iptr->child_item; // search under this sequence
344 }
345 dcmTagSet(&tag, 0x0018, 0x0050);
346 jptr=dcmFindDownTag(kptr, 0, &tag, 0);
347 if(jptr==NULL) {
348 if(verbose>0) {fprintf(stderr, "Error: missing Slice Thickness.\n"); fflush(stderr);}
349 return(11);
350 }
351 pxlsize[2]=dcmitemGetReal(jptr);
352
353 if(verbose>1) {printf("trying to find Spacing Between Slices\n"); fflush(stdout);}
354 dcmTagSet(&tag, 0x0018, 0x0088);
355 jptr=dcmFindDownTag(kptr, 0, &tag, 0);
356 if(jptr==NULL) {
357 if(verbose>1) {fprintf(stderr, "Warning: missing Spacing Between Slices.\n"); fflush(stderr);}
358 } else {
359 double v=dcmitemGetReal(jptr);
360 if(v>pxlsize[2]) pxlsize[2]=v;
361 }
362
363 if(verbose>1) {printf("trying to find Pixel Spacing/Size\n"); fflush(stdout);}
364 dcmTagSet(&tag, 0x0028, 0x0030);
365 jptr=dcmFindDownTag(kptr, 0, &tag, 0);
366 if(jptr==NULL) {
367 if(verbose>0) {fprintf(stderr, "Error: missing Pixel Spacing/Size.\n"); fflush(stderr);}
368 return(21);
369 }
370 char *buf=dcmValueString(jptr);
371 int n=sscanf(buf, "%lf\\%lf", &pxlsize[1], &pxlsize[0]);
372 free(buf);
373 if(n!=2) {
374 if(verbose>0) {fprintf(stderr, "Error: invalid Pixel Spacing/Size\n"); fflush(stderr);}
375 return(22);
376 }
377
378 return(0);
379}
double dcmitemGetReal(DCMITEM *d)
Definition dcmdata.c:331

Referenced by imgReadDICOM().

◆ dcmImgXform()

int dcmImgXform ( double * iop,
double * xyzMM,
double * imgPos,
double * xform,
const int verbose )

Calculate xform matrix from DICOM header information.

Based on dcm2niix xform_mat(), which is based on dicm2nii. Last vector xform[3][0..4] is not yet computed.

See also
dcmImgOrient, dcmImgPxlsize, dcmImgPos, dcmImgDim
Returns
0 if successful, otherwise >0.
Parameters
iopArray of 6 Image Orientation (Patient) parameters.
xyzMMArray of 3 voxel sizes in mm (x, y, z).
imgPosArray of 3 Image Position (Patient) parameters.
xformPointer to xform 4x4 matrix stored as an array of 16 doubles, to be filled here.
verboseVerbose level; if zero, then nothing is printed to stderr or stdout.

Definition at line 431 of file dcmimage.c.

442 {
443 if(verbose>0) {printf("%s(iop[], xyzMM[], imgPos[], xform)\n", __func__); fflush(stdout);}
444 if(iop==NULL || xyzMM==NULL || imgPos==NULL || xform==NULL) return(1);
445 for(int i=0; i<16; i++) xform[i]=nan("");
446
447
448 double readV[3], phaseV[3];
449 readV[0]=iop[0]; readV[1]=iop[1]; readV[2]=iop[2];
450 phaseV[0]=iop[3]; phaseV[1]=iop[4]; phaseV[2]=iop[5];
451 if(verbose>3) {
452 printf("readV := %g", readV[0]); for(int i=1; i<3; i++) printf(", %g", readV[i]);
453 printf("\n");
454 printf("phaseV := %g", phaseV[0]); for(int i=1; i<3; i++) printf(", %g", phaseV[i]);
455 printf("\n");
456 }
457
458 /* Cross-product of vectors */
459 double sliceV[3];
460 sliceV[0]= readV[1]*phaseV[2] - phaseV[1]*readV[2];
461 sliceV[1]=-readV[0]*phaseV[2] + phaseV[0]*readV[2];
462 sliceV[2]= readV[0]*phaseV[1] - phaseV[0]*readV[1];
463 if(verbose>3) {
464 printf("sliceV := %g", sliceV[0]); for(int i=1; i<3; i++) printf(", %g", sliceV[i]);
465 printf("\n");
466 }
467
468 /* Copy vectors into a 3x3 matrix */
469 double rM[3][3];
470 for(int i=0; i<3; i++) rM[0][i]=readV[i];
471 for(int i=0; i<3; i++) rM[1][i]=phaseV[i];
472 for(int i=0; i<3; i++) rM[2][i]=sliceV[i];
473 /* Transpose the matrix */
474 {
475 double tM[3][3];
476 for(int i=0; i<3; i++) for(int j=0; j<3; j++) tM[i][j]=rM[i][j];
477 for(int i=0; i<3; i++) for(int j=0; j<3; j++) rM[i][j]=tM[j][i];
478 }
479 if(verbose>3) {
480 printf("rM :=\t%g", rM[0][0]);
481 for(int i=1; i<3; i++) printf("\t%g", rM[0][i]);
482 printf("\n");
483 for(int i=0; i<3; i++) printf("\t%g", rM[1][i]);
484 printf("\n");
485 for(int i=0; i<3; i++) printf("\t%g", rM[2][i]);
486 printf("\n");
487 }
488 /* Max (left-over) indices */
489 unsigned short int xyz[3];
490 xyz[0]=0;
491 if(fabs(rM[1][0])>fabs(rM[0][0]) && fabs(rM[1][0])>fabs(rM[2][0])) xyz[0]=1;
492 else if(fabs(rM[2][0])>fabs(rM[0][0]) && fabs(rM[1][0])>fabs(rM[1][0])) xyz[0]=2;
493 if(xyz[0]==0) {if(fabs(rM[2][1])>fabs(rM[1][1])) xyz[1]=2; else xyz[1]=1;}
494 else if(xyz[0]==1) {if(fabs(rM[2][1])>fabs(rM[0][1])) xyz[1]=2; else xyz[1]=0;}
495 else {if(fabs(rM[1][1])>fabs(rM[0][1])) xyz[1]=1; else xyz[1]=0;}
496 xyz[2]=3-xyz[0]-xyz[1];
497 if(verbose>3) {
498 printf("xyz := %u", xyz[0]); for(int i=1; i<3; i++) printf(", %u", xyz[i]);
499 printf("\n(0, 1, 2 for Sag/Cor/Tra slice)\n");
500 }
501 double cosSL=rM[xyz[2]][2];
502 if(verbose>3) {printf("cosSL := %g\n", cosSL); fflush(stdout);}
503
504 /* Multiply matrix with voxel sizes */
505 if(verbose>3) {
506 printf("xyzMM := %g", xyzMM[0]); for(int i=1; i<3; i++) printf(", %g", xyzMM[i]);
507 printf("\n");
508 }
509 {
510 double tM[3][3], sM[3][3];
511 for(int i=0; i<3; i++) for(int j=0; j<3; j++) tM[i][j]=rM[i][j];
512 for(int i=0; i<3; i++) for(int j=0; j<3; j++) sM[i][j]=0.0;
513 sM[0][0]=xyzMM[0]; sM[1][1]=xyzMM[1]; sM[2][2]=xyzMM[2];
514 for(int i=0; i<3; i++)
515 for(int j=0; j<3; j++)
516 rM[i][j]= tM[i][0]*sM[0][j] + tM[i][1]*sM[1][j] + tM[i][2]*sM[2][j];
517 }
518
519 /* Fill most part of xform */
520 for(int i=0; i<3; i++)
521 for(int j=0; j<3; j++)
522 xform[j+4*i]=rM[i][j];
523 for(int i=0; i<3; i++)
524 xform[3+4*i]=imgPos[i];
525
526 /* Slice normalization vector not yet done */
527
528 return(0);
529}

Referenced by imgReadDICOM().

◆ dcmitemFree()

void dcmitemFree ( DCMITEM * d)

Recursively free memory allocated for DCMITEM items and their children items.

See also
dcmfileFree
Author
Vesa Oikonen
Parameters
dPointer to DCMITEM.

Definition at line 39 of file dcmdata.c.

42 {
43 if(d==NULL) return;
44 /* find the last item in the list */
45 DCMITEM *ip=d; while(ip->next_item!=NULL) ip=ip->next_item;
46 while(ip!=NULL) {
47 /* Free items child and their children */
48 if(ip->child_item!=NULL) dcmitemFree(ip->child_item);
49 /* Free this item and move to previous item */
50 if(ip->prev_item!=NULL) {
51 ip=ip->prev_item;
52 free(ip->next_item->rd); free(ip->next_item);
53 ip->next_item=NULL;
54 } else {
55 free(ip->rd); free(ip); ip=NULL;
56 }
57 }
58}

Referenced by dcmfileFree(), and dcmitemFree().

◆ dcmitemGetInt()

long int dcmitemGetInt ( DCMITEM * d)

Read integer value from given DICOM item.

VR must be either UL, US, SL, SS, or IS; otherwise 0 is returned.

Returns
Returns the value as long int, in order to cope with originally unsigned integers.
See also
dcmitemGetInt, dcmValueString, dcmFindTag
Parameters
dPointer to item.

Definition at line 295 of file dcmdata.c.

298 {
299 if(d==NULL || d->rd==NULL) return(0);
300 long int li=0;
301 if(d->vr==DCM_VR_UL) { // unsigned 32-bit int
302 unsigned int i;
303 memcpy(&i, d->rd, 4); if(!endianLittle()) swap(&i, &i, 4);
304 li=(long int)i;
305 } else if(d->vr==DCM_VR_US) { // unsigned 16-bit int
306 unsigned short int i;
307 memcpy(&i, d->rd, 2); if(!endianLittle()) swap(&i, &i, 2);
308 li=(long int)i;
309 } else if(d->vr==DCM_VR_SL) { // signed 32-bit int
310 int i;
311 memcpy(&i, d->rd, 4); if(!endianLittle()) swap(&i, &i, 4);
312 li=(long int)i;
313 } else if(d->vr==DCM_VR_SS) { // signed 16-bit int
314 short int i;
315 memcpy(&i, d->rd, 2); if(!endianLittle()) swap(&i, &i, 2);
316 li=(long int)i;
317 } else if(d->vr==DCM_VR_IS) { // integer string
318 li=atol(d->rd);
319 }
320 return(li);
321}
void swap(void *from, void *to, int size)
Definition endian.c:69

Referenced by dcmImgDim(), dcmImgPos(), dcmMListRead(), dcmSameImage(), dcmTagIntRange(), and imgReadDICOM().

◆ dcmitemGetReal()

double dcmitemGetReal ( DCMITEM * d)

Read floating point value from given DICOM item.

VR must be either FL, FD, DS, UL, US, SL, SS, or IS; otherwise 0 is returned.

Returns
Returns the value as double.
See also
dcmitemGetInt, dcmValueString, dcmFindTag
Parameters
dPointer to item.

Definition at line 331 of file dcmdata.c.

334 {
335 if(d==NULL || d->rd==NULL) return(0);
336 double r=0.0;
337 if(d->vr==DCM_VR_FL) { // 32-bit float
338 float f;
339 memcpy(&f, d->rd, 4); if(!endianLittle()) swap(&f, &f, 4);
340 r=(double)f;
341 } else if(d->vr==DCM_VR_FD) { // 64-bit double
342 double f;
343 memcpy(&f, d->rd, 8); if(!endianLittle()) swap(&f, &f, 8);
344 r=f;
345 } else if(d->vr==DCM_VR_DS) { // decimal string
346 r=atof(d->rd);
347 } else if(d->vr==DCM_VR_UL) { // unsigned 32-bit int
348 unsigned int i;
349 memcpy(&i, d->rd, 4); if(!endianLittle()) swap(&i, &i, 4);
350 r=(double)i;
351 } else if(d->vr==DCM_VR_US) { // unsigned 16-bit int
352 unsigned short int i;
353 memcpy(&i, d->rd, 2); if(!endianLittle()) swap(&i, &i, 2);
354 r=(double)i;
355 } else if(d->vr==DCM_VR_SL) { // signed 32-bit int
356 int i;
357 memcpy(&i, d->rd, 4); if(!endianLittle()) swap(&i, &i, 4);
358 r=(double)i;
359 } else if(d->vr==DCM_VR_SS) { // signed 16-bit int
360 short int i;
361 memcpy(&i, d->rd, 2); if(!endianLittle()) swap(&i, &i, 2);
362 r=(double)i;
363 } else if(d->vr==DCM_VR_IS) { // integer string
364 r=(double)atol(d->rd);
365 }
366 return(r);
367}

Referenced by dcmImgPxlsize(), dcmMListRead(), and imgReadDICOM().

◆ dcmitemMaxDepth()

unsigned short int dcmitemMaxDepth ( DCMITEM * d)

Get the maximum depth of DCMITEM tree.

Returns
Returns the number of levels under specified item, not including given item itself.
See also
dcmitemParentNr, dcmfileMaxDepth
Parameters
dPointer to DCMITEM item.

Definition at line 83 of file dcmdata.c.

86 {
87 if(d==NULL || d->child_item==NULL) return(0);
88 unsigned short int m=0, n=0;
89 DCMITEM *cd=d->child_item;
90 /* go through all children */
91 while(cd!=NULL) {
92 n=dcmitemMaxDepth(cd); if(n>m) m=n;
93 cd=cd->next_item;
94 }
95 return(m+1);
96}

Referenced by dcmfileMaxDepth(), and dcmitemMaxDepth().

◆ dcmitemParentNr()

unsigned short int dcmitemParentNr ( DCMITEM * d)

Check how deep in DCMITEM tree this item is.

Returns
Returns the number of parents this item has.
See also
dcmitemMaxDepth, dcmfileMaxDepth
Parameters
dPointer to DCMITEM.

Definition at line 122 of file dcmdata.c.

125 {
126 if(d==NULL) return(0);
127 unsigned short int n=0;
128 DCMITEM *pd=d->parent_item;
129 while(pd!=NULL) {n++; pd=pd->parent_item;}
130 return(n);
131}

Referenced by dcmFileReadNextElement().

◆ dcmitemPrint()

void dcmitemPrint ( DCMITEM * d)

Print contents of given DICOM item into stdout.

Parameters
dPointer to item.

Definition at line 467 of file dcmdata.c.

470 {
471 if(d==NULL) {printf("(null)\n"); fflush(stdout); return;}
472 printf("tag(%04X,%04X)", d->tag.group, d->tag.element); fflush(stdout);
473 printf(" VR=%s", dcmVRName(d->vr)); fflush(stdout);
474 if(d->vl==0xFFFFFFFF) printf(" VL=%08X", d->vl); else printf(" VL=%u", d->vl);
475 fflush(stdout);
476 char *buf=dcmValueString(d); printf(" '%s'", buf); free(buf);
477 printf("\n"); fflush(stdout);
478}

Referenced by dcmAddItem(), dcmFileWrite(), dcmMListRead(), and imgReadDICOM().

◆ dcmmatrixFree()

void dcmmatrixFree ( DCMMATRIX * m)

Free memory allocated for DCMMATRIX data. All contents are destroyed.

Precondition
Before first use initialize the struct with dcmmatrixInit().
See also
dcmmatrixInit
Author
Vesa Oikonen
Parameters
mPointer to DCMMATRIX.

Definition at line 40 of file dcmmatrix.c.

43 {
44 if(m==NULL) return;
45 if(m->filename!=NULL) free(m->filename);
47}
void dcmmatrixInit(DCMMATRIX *m)
Definition dcmmatrix.c:22
char * filename
Definition tpcdcm.h:175

Referenced by dcmmlFree().

◆ dcmmatrixInit()

void dcmmatrixInit ( DCMMATRIX * m)

Initiate the DCMMATRIX struct before any use.

See also
dcmmatrixFree
Parameters
mPointer to DCMMATRIX.

Definition at line 22 of file dcmmatrix.c.

25 {
26 if(m==NULL) return;
27 m->filename=NULL;
28 m->acqDate[0]=m->acqTime[0]=(char)0;
29 m->frame=m->plane=0;
30 m->frameStart=m->frameDur=0.0;
31}
double frameDur
Definition tpcdcm.h:188
unsigned int plane
Definition tpcdcm.h:184
double frameStart
Definition tpcdcm.h:186
char acqTime[16]
Definition tpcdcm.h:179
char acqDate[16]
Definition tpcdcm.h:177
unsigned int frame
Definition tpcdcm.h:182

Referenced by dcmmatrixFree(), and dcmmlAllocate().

◆ dcmmlAllocate()

int dcmmlAllocate ( DCMML * d,
int mNr )

Allocate more memory for DCMML data. Previous contents are preserved.

Returns
Returns TPCERROR status.
See also
dcmmlInit, dcmmlFree
Parameters
dPointer to initiated and possibly previously allocated DCMML struct data; any old contens are preserved.
mNrNr of additional matrices to allocate; if struct contains unused space for requested number already, then nothing is done.

Definition at line 89 of file dcmmatrix.c.

96 {
97 if(d==NULL) return TPCERROR_FAIL;
98 /* Check if there is enough space already */
99 unsigned int newNr, addNr;
100 newNr=d->nr+mNr;
101 if(d->anr>=newNr) return TPCERROR_OK;
102 addNr=newNr-d->anr;
103
104 /* (Re)allocate memory. */
105 DCMMATRIX *mptr;
106 mptr=(DCMMATRIX*)realloc(d->m, sizeof(DCMMATRIX)*newNr);
107 if(mptr==NULL) return TPCERROR_OUT_OF_MEMORY;
108 d->m=mptr;
109 mptr=d->m+d->anr; for(unsigned int i=0; i<addNr; i++) dcmmatrixInit(mptr++);
110 d->anr=newNr;
111 return TPCERROR_OK;
112}
DCMMATRIX * m
Definition tpcdcm.h:198
unsigned int anr
Definition tpcdcm.h:196
unsigned int nr
Definition tpcdcm.h:194

Referenced by dcmMListRead().

◆ dcmmlFree()

void dcmmlFree ( DCMML * d)

Free memory allocated for DCMML data. All contents are destroyed.

Precondition
Before first use initialize the struct with dcmmlInit().
See also
dcmmlInit
Author
Vesa Oikonen
Parameters
dPointer to DCMML.

Definition at line 70 of file dcmmatrix.c.

73 {
74 if(d==NULL) return;
75 if(d->m!=NULL) {
76 for(unsigned int i=0; i<d->anr; i++) dcmmatrixFree(d->m+i);
77 free(d->m);
78 }
79 dcmmlInit(d);
80}
void dcmmlInit(DCMML *d)
Definition dcmmatrix.c:54
void dcmmatrixFree(DCMMATRIX *m)
Definition dcmmatrix.c:40

Referenced by dcmMListRead().

◆ dcmmlInit()

void dcmmlInit ( DCMML * d)

Initiate the DCMML struct before any use.

See also
dcmmlFree
Parameters
dPointer to DCMMLIST.

Definition at line 54 of file dcmmatrix.c.

57 {
58 if(d==NULL) return;
59 d->nr=d->anr=0;
60 d->m=(DCMMATRIX*)NULL;
61}

Referenced by dcmmlFree().

◆ dcmMListRead()

int dcmMListRead ( IFT * ift,
DCMML * ml,
TPCSTATUS * status )

Read DICOM image matrix list.

See also
dcmFileList, dcmmlInit
Returns
Code tpcerror, TPCERROR_OK (0) when successful.
Parameters
iftPointer to IFT structure containing file names constituting a DICOM image.
mlPointer to initiated DICOM matrix list.
statusPointer to status data; enter NULL if not needed.

Definition at line 120 of file dcmmatrix.c.

127 {
128 int verbose=0; if(status!=NULL) verbose=status->verbose;
129 if(verbose>1) printf("%s()\n", __func__);
130 if(ift==NULL || ml==NULL) {
131 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_FAIL);
132 return TPCERROR_FAIL;
133 }
134 if(ift->keyNr<1) {
135 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_NO_DATA);
136 return TPCERROR_NO_DATA;
137 }
138
139 /* Delete any previous data */
140 dcmmlFree(ml);
141
142 /*
143 * Read the first file in list
144 */
145 int fi=0, ret=TPCERROR_OK;
146 DCMFILE dcm; dcmfileInit(&dcm);
147 ret=dcmFileRead(ift->item[fi].value, &dcm, 1, status);
148 if(ret!=TPCERROR_OK) {dcmfileFree(&dcm); return(ret);}
149
150 /* Read some information common to the whole image */
151 DCMTAG tag;
152 DCMITEM *iptr;
153
154 /* Get and check the Image Type */
155 int dynamic=0; // 0=no, 1=yes
156 tag.group=0x0008; tag.element=0x0008;
157 iptr=dcmFindTag(dcm.item, 0, &tag, 0);
158 if(iptr==NULL) {
159 ret=TPCERROR_NO_KEY; statusSet(status, __func__, __FILE__, __LINE__, ret);
160 dcmfileFree(&dcm); return(ret);
161 }
162 /* Check if dynamic; see DICOM 3.3 C.7.6.16.2.2.6
163 https://dicom.nema.org/MEDICAL/dicom/current/output/chtml/part03/sect_C.7.6.16.2.html
164 */
165 {
166 char *buf=dcmValueString(iptr);
167 if(verbose>2) printf("imageType := %s\n", buf);
168 if(strcasestr(buf, "DYNAMIC")!=NULL) dynamic=1; else dynamic=0;
169 free(buf);
170 }
171 if(verbose>1) {printf("dynamic := %d\n", dynamic); fflush(stdout);}
172
173 /* Check whether Per-frame Functional Groups Sequence is set */
174 int multiframe=0; // 0=no, 1=yes
175 tag.group=0x5200; tag.element=0x9230;
176 iptr=dcmFindTag(dcm.item, 0, &tag, 0);
177 if(iptr!=NULL) {
178 if(verbose>1) fprintf(stderr, "Notice: Per-frame Functional Groups Sequence is available.\n");
179 multiframe=1;
180 }
181
182
183 if(multiframe) { /* Multi-frame file */
184
185 /* Get the number of frames and planes */
186 if(verbose>1) {printf("reading frame and slice number\n"); fflush(stdout);}
187 unsigned short int frameNr=0;
188 /* Get frame number from 'Temporal position index' */
189 tag.group=0x0020; tag.element=0x9128;
190 int a, b;
191 if(dcmTagIntRange(dcm.item, &tag, &a, &b, verbose-100)==0) frameNr=b;
192 if(verbose>1) printf("frameNr := %u\n", frameNr);
193 unsigned short int sliceNr=0;
194 /* Get plane number from 'In Stack Position Number' */
195 tag.group=0x0020; tag.element=0x9057;
196 if(dcmTagIntRange(dcm.item, &tag, &a, &b, verbose-100)==0) sliceNr=b;
197 else {
198 /* Get plane number from 'Dimension Index Values' */
199 tag.group=0x0020; tag.element=0x9157;
200 if(dcmTagIntRange(dcm.item, &tag, &a, &b, verbose-1)==0) sliceNr=b;
201 }
202 if(verbose>1) printf("sliceNr := %u\n", sliceNr);
203 if(frameNr<=0 || sliceNr<=0) {
204 if(verbose>0) fprintf(stderr, "Error: cannot find frame/slice number.\n");
205 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_NO_KEY);
206 dcmfileFree(&dcm); return(TPCERROR_NO_KEY);
207 }
208
209 /* Get Decay Correction */
210 short unsigned int decayCorrection=0; // 0=NO, 1=YES
211 tag.group=0x0018; tag.element=0x9758;
212 iptr=dcmFindTag(dcm.item, 0, &tag, 0);
213 if(iptr!=NULL) {
214 char *buf=dcmValueString(iptr);
215 if(verbose>2) printf("Decay Correction := '%s'\n", buf);
216 if(strcasestr(buf, "YES")!=NULL) decayCorrection=1;
217 free(buf);
218 }
219 if(verbose>1) printf("decayCorrection := %d\n", decayCorrection);
220
221 /* If decay is corrected, read time of decay correction; otherwise read start time */
222 char zeroDateTime[32]; zeroDateTime[0]=(char)0;
223 if(decayCorrection==0) {
224 /* Get Acquisition DateTime */
225 tag.group=0x0008; tag.element=0x002A;
226 iptr=dcmFindTag(dcm.item, 0, &tag, 0);
227 if(iptr!=NULL) dcmDT2intl(iptr->rd, zeroDateTime);
228 } else {
229 tag.group=0x0018; tag.element=0x9701;
230 iptr=dcmFindTag(dcm.item, 0, &tag, 0);
231 if(iptr!=NULL) dcmDT2intl(iptr->rd, zeroDateTime);
232 }
233 if(!zeroDateTime[0]) {
234 if(verbose>0) fprintf(stderr, "Error: missing Acquisition Date and Time.\n");
235 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_NO_KEY);
236 dcmfileFree(&dcm); return(TPCERROR_NO_KEY);
237 }
238 if(verbose>4) printf("zeroDateTime := %s\n", zeroDateTime);
239
240 /* Initially allocate for frameNr x sliceNr matrices */
241 ret=dcmmlAllocate(ml, sliceNr*frameNr);
242 if(ret!=TPCERROR_OK) {
243 statusSet(status, __func__, __FILE__, __LINE__, ret);
244 dcmfileFree(&dcm); return ret;
245 }
246
247 /*
248 * Get the information from one matrix at a time
249 */
250 /* Find Per Frame Functional Groups Sequence */
251 tag.group=0x5200; tag.element=0x9230;
252 iptr=dcmFindTag(dcm.item, 0, &tag, 0);
253 if(iptr==NULL) {
254 if(verbose>0) {
255 fprintf(stderr, "Error: cannot find Per Frame Functional Groups Sequence.\n");
256 fflush(stderr);
257 }
258 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_NO_KEY);
259 dcmmlFree(ml); dcmfileFree(&dcm); return(TPCERROR_NO_KEY);
260 }
261 /* Loop through all Frame Content Sequences under it */
262 tag.group=0x0020; tag.element=0x9111;
263 DCMTAG tagstart; tagstart.group=0x0018; tagstart.element=0x9074;
264 DCMTAG tagdur; tagdur.group=0x0018; tagdur.element=0x9220;
265 DCMTAG tagfr; tagfr.group=0x0020; tagfr.element=0x9128;
266 DCMITEM *fptr=iptr->child_item;
267 while(fptr!=NULL) {
268 /* Find Frame Content Sequence */
269 iptr=dcmFindDownTag(fptr, 0, &tag, 0); if(iptr==NULL) break; // not an error!
270 if(verbose>10) printf(" found Frame Content Sequence\n");
271 /* Check that we have room */
272 if(ml->nr>=ml->anr) {
273 ret=dcmmlAllocate(ml, 100);
274 if(ret!=TPCERROR_OK) break;
275 }
276 /* Set file name */
277 ml->m[ml->nr].filename=strdup(ift->item[0].value);
278 /* Find Temporal Position Index */
279 DCMITEM *jptr;
280 jptr=dcmFindDownTag(iptr->child_item, 0, &tagfr, 0);
281 if(jptr==NULL) {
282 if(verbose>0) {printf("cannot find Temporal Position Index.\n"); fflush(stdout);}
283 ret=TPCERROR_NO_KEY; break;
284 }
285 if(verbose>20) dcmitemPrint(jptr);
286 ml->m[ml->nr].frame=(unsigned int)dcmitemGetInt(jptr);
287 //unsigned short int frameIndex=(unsigned short int)(dcmitemGetInt(jptr)-1);
288 /* Find slice index */
289 DCMTAG tagpl; tagpl.group=0x0020; tagpl.element=0x9057;
290 jptr=dcmFindDownTag(iptr->child_item, 0, &tagpl, 0);
291 if(jptr==NULL) {
292 tagpl.group=0x0020; tagpl.element=0x9157;
293 jptr=dcmFindDownTag(iptr->child_item, 0, &tagpl, 0);
294 }
295 if(jptr==NULL) {
296 if(verbose>0) {printf("cannot find Slice Index.\n"); fflush(stdout);}
297 ret=TPCERROR_NO_KEY; break;
298 }
299 if(verbose>20) dcmitemPrint(jptr);
300 ml->m[ml->nr].plane=(unsigned int)dcmitemGetInt(jptr);
301 /* Find Frame Acquisition DateTime */
302 jptr=dcmFindDownTag(iptr->child_item, 0, &tagstart, 0);
303 char facqDateTime[32]; facqDateTime[0]=(char)0;
304 if(jptr!=NULL) dcmDT2intl(jptr->rd, facqDateTime);
305 if(!facqDateTime[0]) {
306 if(verbose>0) {printf("cannot find Frame Acquisition DateTime.\n"); fflush(stdout);}
307 ret=TPCERROR_NO_KEY; break;
308 }
309 if(verbose>20) printf("facqDateTime := %s\n", facqDateTime);
310 strlcpy(ml->m[ml->nr].acqDate, facqDateTime, 11);
311 if(strlen(facqDateTime)>17) strlcpy(ml->m[ml->nr].acqTime, facqDateTime+11, 9);
312 /* Calculate the Frame start time */
313 ml->m[ml->nr].frameStart=strDateTimeDifference(facqDateTime, zeroDateTime);
314 /* Find Frame Acquisition Duration */
315 jptr=dcmFindDownTag(iptr->child_item, 0, &tagdur, 0);
316 if(jptr!=NULL) ml->m[ml->nr].frameDur=0.001*dcmitemGetReal(jptr);
317
318 /* prepare for the next matrix */
319 fptr=iptr->next_item;
320 ml->nr++;
321 }
322
323 dcmfileFree(&dcm);
324 if(ret!=TPCERROR_OK) {
325 statusSet(status, __func__, __FILE__, __LINE__, ret);
326 dcmmlFree(ml);
327 return(ret);
328 }
329
330 } else { /* Single-frame files */
331
332 /* Get the number of frames (time slices) */
333 unsigned short int frameNr=0;
334 tag.group=0x0054; tag.element=0x0101;
335 iptr=dcmFindTag(dcm.item, 0, &tag, 0);
336 if(iptr!=NULL) {
337 frameNr=(unsigned short int)dcmitemGetInt(iptr);
338 } else {
339 if(dynamic!=0) { // error, if dynamic
340 ret=TPCERROR_NO_KEY; statusSet(status, __func__, __FILE__, __LINE__, ret);
341 dcmfileFree(&dcm); return(ret);
342 } else { // assume 1, if static or whole-body
343 frameNr=1;
344 }
345 }
346 if(verbose>1) printf("frameNr := %u\n", frameNr);
347
348 /* Get the number of slices (needed to understand image index) */
349 unsigned short int sliceNr=0;
350 tag.group=0x0054; tag.element=0x0081;
351 iptr=dcmFindTag(dcm.item, 0, &tag, 0);
352 if(iptr==NULL) {
353 ret=TPCERROR_NO_KEY; statusSet(status, __func__, __FILE__, __LINE__, ret);
354 dcmfileFree(&dcm); return(ret);
355 }
356 sliceNr=(unsigned short int)dcmitemGetInt(iptr);
357 if(verbose>1) printf("sliceNr := %u\n", sliceNr);
358
359 /* Get Decay correction type */
360 short unsigned int decayCorrection=0; // 0=NONE, 1=START, 2=ADMIN
361 tag.group=0x0054; tag.element=0x1102;
362 iptr=dcmFindTag(dcm.item, 0, &tag, 0);
363 if(iptr!=NULL) {
364 char *buf=dcmValueString(iptr);
365 if(verbose>2) printf("Decay Correction := %s\n", buf);
366 if(strcasecmp(buf, "NONE")==0) decayCorrection=0;
367 else if(strcasecmp(buf, "START")==0) decayCorrection=1;
368 else if(strcasecmp(buf, "ADMIN")==0) decayCorrection=2;
369 free(buf);
370 }
371
372 /* If decay is corrected to tracer administration time, the we must read it */
373 char injDateTime[32]; injDateTime[0]=(char)0;
374 if(decayCorrection==2) {
375 /* Get the Tracer Start DateTime */
376 tag.group=0x0018; tag.element=0x1078;
377 iptr=dcmFindTag(dcm.item, 0, &tag, 0);
378 if(iptr!=NULL) {
379 if(dcmDT2intl(iptr->rd, injDateTime)==NULL) iptr=NULL;
380 }
381 /* If not successful, the try other tags */
382 if(iptr==NULL) {
383 char s1[16], s2[16];
384 /* Get the Tracer Start Time */
385 tag.group=0x0018; tag.element=0x1072;
386 iptr=dcmFindTag(dcm.item, 0, &tag, 0);
387 if(iptr!=NULL) {
388 /* Get the Series Date */
389 tag.group=0x0008; tag.element=0x0021;
390 DCMITEM *jptr=dcmFindTag(dcm.item, 0, &tag, 0);
391 if(jptr!=NULL) {
392 if(dcmDA2intl(jptr->rd, s1)!=NULL && dcmTM2intl(iptr->rd, s2)!=NULL)
393 sprintf(injDateTime, "%s %s", s1, s2);
394 }
395 }
396 }
397 if(injDateTime[0] && verbose>3) printf("injection_time := %s\n", injDateTime);
398 }
399
400 /* Get the Series DateTime
401 https://dicom.nema.org/MEDICAL/dicom/current/output/chtml/part03/sect_C.8.9.html#figure_C.8.9.1.1.11-1a
402 */
403 char seriesDateTime[32]; seriesDateTime[0]=(char)0;
404 tag.group=0x0008; tag.element=0x0021;
405 iptr=dcmFindTag(dcm.item, 0, &tag, 0);
406 if(iptr!=NULL) {
407 tag.group=0x0008; tag.element=0x0031;
408 DCMITEM *jptr=dcmFindTag(dcm.item, 0, &tag, 0);
409 if(jptr!=NULL) {
410 char s1[16], s2[16];
411 if(dcmDA2intl(iptr->rd, s1)!=NULL && dcmTM2intl(jptr->rd, s2)!=NULL)
412 sprintf(seriesDateTime, "%s %s", s1, s2);
413 }
414 }
415 if(seriesDateTime[0] && verbose>3) printf("seriesDateTime := %s\n", seriesDateTime);
416
417
418 /* Initially allocate for frameNr x sliceNr matrices */
419 ret=dcmmlAllocate(ml, sliceNr*frameNr);
420 if(ret!=TPCERROR_OK) {
421 statusSet(status, __func__, __FILE__, __LINE__, ret);
422 dcmfileFree(&dcm); return ret;
423 }
424
425
426 /*
427 * Get the information from one file at a time
428 */
429 //char startDateTime[32]; startDateTime[0]=(char)0;
430 //int fi=0, beds=0;
431 do {
432
433 /* Get the Image Index; DICOM PS3.3 C.8.9.4.1.9 */
434 unsigned short int imageIndex=0;
435 tag.group=0x0054; tag.element=0x1330;
436 iptr=dcmFindTag(dcm.item, 0, &tag, 0);
437 if(iptr==NULL) {ret=TPCERROR_NO_KEY; break;}
438 imageIndex=(unsigned short int)dcmitemGetInt(iptr);
439 /* Calculate the current frame and slice (index starting from 0) */
440 unsigned short int frameIndex, sliceIndex;
441 {
442 div_t meh=div(imageIndex-1, sliceNr);
443 frameIndex=meh.quot;
444 sliceIndex=meh.rem;
445 }
446 /* Set file name, plane, and frame into matrix list */
447 if(ml->nr>=ml->anr) {
448 ret=dcmmlAllocate(ml, 100);
449 if(ret!=TPCERROR_OK) break;
450 }
451 ml->m[ml->nr].filename=strdup(ift->item[fi].value);
452 ml->m[ml->nr].plane=1+sliceIndex;
453 ml->m[ml->nr].frame=1+frameIndex;
454
455 /* Get acquisition date and time */
456 char acqDateTime[32]; acqDateTime[0]=(char)0;
457 /* Try first Acquisition Datetime */
458 tag.group=0x0008; tag.element=0x002A;
459 iptr=dcmFindTag(dcm.item, 0, &tag, 0);
460 if(iptr!=NULL) dcmDT2intl(iptr->rd, acqDateTime);
461 /* If that did not work, try Acquisition Date and Time */
462 if(!acqDateTime[0]) {
463 tag.group=0x0008; tag.element=0x0022;
464 iptr=dcmFindTag(dcm.item, 0, &tag, 0);
465 if(iptr!=NULL) {
466 tag.group=0x0008; tag.element=0x0032;
467 DCMITEM *jptr=dcmFindTag(dcm.item, 0, &tag, 0);
468 if(jptr!=NULL) {
469 char s1[16], s2[16];
470 if(dcmDA2intl(iptr->rd, s1)!=NULL && dcmTM2intl(jptr->rd, s2)!=NULL)
471 sprintf(acqDateTime, "%s %s", s1, s2);
472 }
473 }
474 }
475 if(acqDateTime[0]) {
476 strlcpy(ml->m[ml->nr].acqDate, acqDateTime, 11);
477 if(strlen(acqDateTime)>17) strlcpy(ml->m[ml->nr].acqTime, acqDateTime+11, 9);
478 }
479
480 /* Calculate the Frame start time, if possible */
481 if(acqDateTime[0]) {
482 double t1=nan("");
483 if(decayCorrection==2 && injDateTime[0]) {
484 /* Injection time is the reference time */
485 t1=strDateTimeDifference(acqDateTime, injDateTime);
486 ml->m[ml->nr].frameStart=t1;
487 } else if(seriesDateTime[0]) {
488 /* Use series time, for now */
489 t1=strDateTimeDifference(acqDateTime, seriesDateTime);
490 ml->m[ml->nr].frameStart=t1;
491 }
492 }
493
494 /* Get Actual Frame Duration */
495 tag.group=0x0018; tag.element=0x1242;
496 iptr=dcmFindTag(dcm.item, 0, &tag, 0);
497 if(iptr!=NULL) ml->m[ml->nr].frameDur=0.001*dcmitemGetReal(iptr);
498
499
500 /* Done with this file */
501 ml->nr++;
502 dcmfileFree(&dcm);
503
504 /* Read the next file in list */
505 fi++; if(fi>=ift->keyNr) {ret=TPCERROR_OK; break;}
506 ret=dcmFileRead(ift->item[fi].value, &dcm, 1, status);
507 if(ret!=TPCERROR_OK) break;
508
509 } while(1);
510 dcmfileFree(&dcm);
511 if(ret!=TPCERROR_OK) {
512 statusSet(status, __func__, __FILE__, __LINE__, ret);
513 dcmmlFree(ml);
514 return(ret);
515 }
516 }
517
518
519 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_OK);
520 return(TPCERROR_OK);
521}
double strDateTimeDifference(const char *dt1, const char *dt0)
Definition datetime.c:519
void dcmmlFree(DCMML *d)
Definition dcmmatrix.c:70
int dcmmlAllocate(DCMML *d, int mNr)
Definition dcmmatrix.c:89
char * dcmDT2intl(const char *orig, char *intl)
Definition dcmvr.c:225
char * dcmDA2intl(const char *orig, char *intl)
Definition dcmvr.c:179
char * dcmTM2intl(const char *orig, char *intl)
Definition dcmvr.c:202

◆ dcmmlSortByPlane()

int dcmmlSortByPlane ( DCMML * d,
TPCSTATUS * status )

Sort matrices in DCMML (DICOM matrix list) struct by plane (slice) number.

Returns
enum tpcerror (TPCERROR_OK when successful).
Author
Vesa Oikonen
Parameters
dPointer to DCMML struct
statusPointer to status data; enter NULL if not needed

Definition at line 540 of file dcmmatrix.c.

545 {
546 int verbose=0; if(status!=NULL) verbose=status->verbose;
547 if(verbose>0) printf("%s()\n", __func__);
548 /* Check that required data exists */
549 if(d==NULL) {
550 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_NO_DATA);
551 return TPCERROR_NO_DATA;
552 }
553 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_OK);
554 if(d->nr<2) return TPCERROR_OK;
555 qsort(d->m, d->nr, sizeof(DCMMATRIX), dcmmlQSortPlane);
556 return TPCERROR_OK;
557}

◆ dcmReadFileTag()

int dcmReadFileTag ( FILE * fp,
DCMTAG * tag )

Read DICOM tag from current file position.

Note
Tag validity is not verified here; error may be caused by end-of-file. Alternatively, read may seem to be successful, but tag contents are file padding symbols (0xFFFC).
See also
dcmReadFile, dcmReadFileElement
Returns
Returns 0 when successful, otherwise >0.
Author
Vesa Oikonen
Parameters
fpFile pointer, positioned at the start of the element (and tag).
tagPointer to DICOM tag struct; enter NULL if you just need to move file position over the tag.

Definition at line 135 of file dcmio.c.

141 {
142 if(tag!=NULL) {tag->group=tag->element=0xFFFC;} // padding
143 if(fp==NULL || feof(fp)) return(1);
144 unsigned short int buf[2];
145 size_t n=fread(&buf, 2, 2, fp);
146 if(n!=2) return(2+n);
147 if(tag!=NULL) {
148 tag->group=buf[0];
149 tag->element=buf[1];
150 if(!endianLittle()) { // tag is by default little endian
151 swap(&tag->group, &tag->group, 2);
152 swap(&tag->element, &tag->element, 2);
153 }
154 }
155 return(0);
156}

Referenced by dcmFileReadNextElement(), and dcmReadTransferSyntaxUID().

◆ dcmReadFileVL()

unsigned int dcmReadFileVL ( FILE * fp,
unsigned int n )

Read DICOM value length (2 or 4 bytes, depending on VR) from current file position.

See also
dcmReadFileTag, dcmReadFileVR, dcmReadFileElement
Returns
Returns the value length.
Author
Vesa Oikonen
Parameters
fpFile pointer, positioned at the VL start.
nNumber of bytes (2 or 4) in the VL representation.

Definition at line 274 of file dcmio.c.

279 {
280 unsigned int vl=0;
281 if(fp==NULL || (n!=2 && n!=4)) return(vl);
282
283 /* Read 2 or 4 bytes */
284 if(n==2) {
285 unsigned short int si;
286 if(fread(&si, 2, 1, fp)!=1) return(vl);
287 if(!endianLittle()) swap(&si, &si, 2);
288 vl=si;
289 } else if(n==4) {
290 unsigned int li;
291 if(fread(&li, 4, 1, fp)!=1) return(vl);
292 if(!endianLittle()) swap(&li, &li, 4);
293 vl=li;
294 }
295 return(vl);
296}

Referenced by dcmFileReadNextElement(), and dcmReadTransferSyntaxUID().

◆ dcmReadFileVR()

dcmvr dcmReadFileVR ( FILE * fp,
char * vrstr )

Read DICOM value representation (2 or 4 bytes) from current file position.

See also
dcmReadFileTag, dcmReadFileElement
Returns
Returns the enumerated VR number, DCM_VR_INVALID in case of an error.
Author
Vesa Oikonen
Parameters
fpFile pointer, positioned at the VR start.
vrstrPointer for VR string, allocated for at least 3 characters to have space for the trailing null; enter NULL if not needed.

Definition at line 237 of file dcmio.c.

243 {
244 if(vrstr!=NULL) vrstr[0]=(char)0;
245 if(fp==NULL) return(DCM_VR_INVALID);
246
247 /* Read the first two bytes */
248 char buf[3];
249 if(fread(&buf, 1, 2, fp)!=2) return(DCM_VR_INVALID);
250 buf[2]=(char)0;
251
252 /* Identify the VR */
253 dcmvr lvr=dcmVRId(buf);
254 if(vrstr!=NULL) {
255 if(lvr!=DCM_VR_INVALID) strcpy(vrstr, dcmVRName(lvr));
256 else strcpy(vrstr, buf);
257 }
258
259 /* If this VR has extra 2 byte reserved space, then
260 we need to read but do not use the next 2 bytes. */
261 if(dcmVRReserved(lvr)!=0) {
262 if(fread(&buf, 1, 2, fp)!=2) return(DCM_VR_INVALID);
263 }
264 return(lvr);
265}
unsigned char dcmVRReserved(dcmvr id)
Definition dcmvr.c:85

Referenced by dcmReadTransferSyntaxUID().

◆ dcmReadFileVRVL()

int dcmReadFileVRVL ( FILE * fp,
dcmvr * vr,
unsigned int * vl,
unsigned int * n )

Read DICOM Value Representation (VR, 2 or 4 bytes) and Value Length (VL, 2 or 4 bytes) from current file position.

See also
dcmReadFileVR, dcmReadFileVL, dcmReadFileTag, dcmReadFileElement, dcmWriteFileVRVL
Returns
Code tpcerror, TPCERROR_OK (0) when successful.
Author
Vesa Oikonen
Parameters
fpFile pointer, positioned at the VR start.
vrPointer for enumerated VR value; enter NULL if not needed (file pointer moved anyway).
vlPointer for VL; enter NULL if not needed (file pointer moved anyway).
nPointer for number of bytes read from file; enter NULL if not needed.

Definition at line 306 of file dcmio.c.

315 {
316 if(vr!=NULL) *vr=DCM_VR_INVALID;
317 if(vl!=NULL) *vl=0;
318 if(n!=NULL) *n=0;
319 if(fp==NULL) return(TPCERROR_FAIL);
320
321 /* Read the first two bytes */
322 char buf[3];
323 if(fread(&buf, 1, 2, fp)!=2) return(TPCERROR_CANNOT_READ); else if(n!=NULL) *n+=2;
324 buf[2]=(char)0;
325
326 /* Identify the VR */
327 dcmvr lvr=dcmVRId(buf);
328 if(vr!=NULL) *vr=lvr;
329 if(lvr==DCM_VR_INVALID) return(TPCERROR_UNSUPPORTED);
330
331 /* If this VR has extra 2 byte reserved space, then
332 we need to read but do not use the next 2 bytes. */
333 unsigned int bsize=2+dcmVRReserved(lvr);
334 if(bsize==4) {
335 if(fread(&buf, 1, 2, fp)!=2) return(TPCERROR_CANNOT_READ);
336 if(n!=NULL) *n+=2;
337 }
338
339 /* Read VL from the next 2 or 4 bytes */
340 unsigned int lvl=0;
341 if(bsize==2) {
342 unsigned short int si;
343 if(fread(&si, 2, 1, fp)!=1) return(TPCERROR_CANNOT_READ);
344 if(!endianLittle()) swap(&si, &si, 2);
345 lvl=si;
346 } else {
347 unsigned int li;
348 if(fread(&li, 4, 1, fp)!=1) return(TPCERROR_CANNOT_READ);
349 if(!endianLittle()) swap(&li, &li, 4);
350 lvl=li;
351 }
352 if(n!=NULL) *n+=bsize;
353 if(vl!=NULL) *vl=lvl;
354
355 return(TPCERROR_OK);
356}

Referenced by dcmFileReadNextElement().

◆ dcmReadTransferSyntaxUID()

dcmtruid dcmReadTransferSyntaxUID ( FILE * fp)

Read and identify the DICOM Transfer Syntax UID.

Returns
Returns the enumerated UID, or DCM_TRUID_INVALID.
See also
dcmVerifyMagic
Parameters
fpPointer to DICOM file opened in binary format, and positioned right after the Magic number. Position will be returned to this position.

Definition at line 73 of file dcmio.c.

78 {
79 if(fp==NULL || feof(fp)) return(DCM_TRUID_INVALID);
80 /* Save original file position */
81 fpos_t opos;
82 if(fgetpos(fp, &opos)) return(DCM_TRUID_INVALID);
83 /* Read file until we find DICOM tag 0x0002,0x0010 */
84 DCMTAG tag;
85 int tag_found=0;
86 while(!tag_found && !feof(fp)) {
87 //printf("reading tag\n");
88 if(dcmReadFileTag(fp, &tag)) break;
89 //printf(" -> (%04x,%04x)\n", tag.group, tag.element);
90 if(tag.group==0x0002 && tag.element==0x0010) {tag_found=1; break;}
91 /* not the tag that we want, so just go through this item */
92 //printf("reading vr etc\n");
93 dcmvr vr=dcmReadFileVR(fp, NULL);
94 //printf("-> %s\n", dcmVRName(vr));
95 unsigned int vl=0;
96 if(dcmVRReserved(vr)==0) vl=dcmReadFileVL(fp, 2);
97 else vl=dcmReadFileVL(fp, 4);
98 //printf("reserved=%d\n", dcmVRReserved(vr));
99 if(vr==DCM_VR_SQ) break;
100 //printf("huuh\n");
101 if(vl==0xFFFFFFFF) break;
102 char buf[vl+1];
103 //printf("read buf length %d\n", vl);
104 if(fread(buf, 1, vl, fp)!=vl) break;
105 } // get next tag
106 //printf("end of loop\n");
107 if(!tag_found) {fsetpos(fp, &opos); return(DCM_TRUID_INVALID);}
108 /* Read the UID */
109 //printf("reading vr\n");
110 if(dcmReadFileVR(fp, NULL)!=DCM_VR_UI) {
111 fsetpos(fp, &opos); return(DCM_TRUID_INVALID);
112 }
113 //printf("reading vl\n");
114 unsigned int vl=dcmReadFileVL(fp, 2);
115 if(vl==0 || vl==0xFFFFFFFF) {fsetpos(fp, &opos); return(DCM_TRUID_INVALID);}
116 char uid[vl+1];
117 //printf("reading uid\n");
118 if(fread(uid, 1, vl, fp)!=vl) {fsetpos(fp, &opos); return(DCM_TRUID_INVALID);}
119 /* Return file position to the original */
120 fsetpos(fp, &opos);
121 /* Identify the UID */
122 return(dcmTrUID(uid));
123}
dcmvr dcmReadFileVR(FILE *fp, char *vrstr)
Definition dcmio.c:237
dcmtruid dcmTrUID(const char *s)
Definition dcmuid.c:66

Referenced by dcmFileRead().

◆ dcmSameImage()

int dcmSameImage ( const DCMFILE * d1,
const DCMFILE * d2,
const int verbose )

Check that two DICOM files belong to the same image.

Defaults to yes, if the needed tags are missing.

See also
dcmFileList, dcmVerifyMagic
Returns
Returns 1 if they are part of the same image, 0 if not.
Parameters
d1Pointer to the first DICOM file data (pixel data not necessary).
d2Pointer to the second DICOM file data (pixel data not necessary).
verboseVerbose level; if zero, then nothing is printed to stderr or stdout.

Definition at line 24 of file dcmfile.c.

31 {
32 if(verbose>0) printf("%s()\n", __func__);
33 if(d1==NULL || d2==NULL) return(0);
34
35 DCMTAG tag;
36 DCMITEM *iptr;
37
38 /* Check the similarity of Series Instance UID */
39 char siuid1[64], siuid2[64];
40 siuid1[0]=siuid2[0]=(char)0;
41 dcmTagSet(&tag, 0x0020, 0x000E);
42 iptr=dcmFindTag(d1->item, 0, &tag, 0);
43 if(iptr!=NULL) strlcpy(siuid1, iptr->rd, 64);
44 iptr=dcmFindTag(d2->item, 0, &tag, 0);
45 if(iptr!=NULL) strlcpy(siuid2, iptr->rd, 64);
46 if(verbose>1) {
47 printf("Series Instance UID [1] := %s\n", siuid1);
48 printf("Series Instance UID [2] := %s\n", siuid2);
49 }
50 if(strcmp(siuid1, siuid2)) return(0);
51
52 /* Check the similarity of Study ID */
53 char sid1[16], sid2[16];
54 sid1[0]=sid2[0]=(char)0;
55 dcmTagSet(&tag, 0x0020, 0x0010);
56 iptr=dcmFindTag(d1->item, 0, &tag, 0);
57 if(iptr!=NULL) strlcpy(sid1, iptr->rd, 16);
58 iptr=dcmFindTag(d2->item, 0, &tag, 0);
59 if(iptr!=NULL) strlcpy(sid2, iptr->rd, 16);
60 if(verbose>1) {
61 printf("Study ID [1] := %s\n", sid1);
62 printf("Study ID [2] := %s\n", sid2);
63 }
64 if(strcmp(sid1, sid2)) return(0);
65
66 /* Check the series number */
67 char snr1[12], snr2[12];
68 snr1[0]=snr2[0]=(char)0;
69 dcmTagSet(&tag, 0x0020, 0x0011);
70 iptr=dcmFindTag(d1->item, 0, &tag, 0);
71 if(iptr!=NULL) strlcpy(snr1, iptr->rd, 12);
72 iptr=dcmFindTag(d2->item, 0, &tag, 0);
73 if(iptr!=NULL) strlcpy(snr2, iptr->rd, 12);
74 if(verbose>1) {
75 printf("Series Number [1] := %s\n", snr1);
76 printf("Series Number [2] := %s\n", snr2);
77 }
78 if(strcmp(snr1, snr2)) return(0);
79
80 /* The rest of checks should not be necessary... */
81 if(verbose>2) {printf(" ... still looks the same...\n"); fflush(stdout);}
82
83 /* Check the number of frames (time slices) */
84 unsigned short int frameNr1=0, frameNr2=0;
85 dcmTagSet(&tag, 0x0054, 0x0101);
86 iptr=dcmFindTag(d1->item, 0, &tag, 0);
87 if(iptr!=NULL) frameNr1=(unsigned short int)dcmitemGetInt(iptr);
88 iptr=dcmFindTag(d2->item, 0, &tag, 0);
89 if(iptr!=NULL) frameNr2=(unsigned short int)dcmitemGetInt(iptr);
90 if(verbose>1) {
91 printf("frameNr [1] := %u\n", frameNr1);
92 printf("frameNr [2] := %u\n", frameNr2);
93 }
94 if(frameNr1!=frameNr2) return(0);
95 if(verbose>2) {printf(" ... still looks the same...\n"); fflush(stdout);}
96
97 /* Check the number of slices */
98 unsigned short int sliceNr1=0, sliceNr2=0;
99 dcmTagSet(&tag, 0x0054, 0x0081);
100 iptr=dcmFindTag(d1->item, 0, &tag, 0);
101 if(iptr!=NULL) sliceNr1=(unsigned short int)dcmitemGetInt(iptr);
102 iptr=dcmFindTag(d2->item, 0, &tag, 0);
103 if(iptr!=NULL) sliceNr2=(unsigned short int)dcmitemGetInt(iptr);
104 if(verbose>1) {
105 printf("sliceNr [1] := %u\n", sliceNr1);
106 printf("sliceNr [2] := %u\n", sliceNr2);
107 }
108 if(sliceNr1!=sliceNr2) return(0);
109
110 if(verbose>2) {printf(" ... the same.\n"); fflush(stdout);}
111 return(1);
112}

Referenced by dcmFileList().

◆ dcmSOPIdentify()

unsigned int dcmSOPIdentify ( const char * s)

Identify the DICOM SOP UID.

Returns
Returns the SOP UID list index.
See also
dcmSOPName, dcmSOPUID
Parameters
sSOP UID string.

Definition at line 62 of file dcmsop.c.

65 {
66 if(s==NULL || strnlen(s, 3)<3) return(0);
67
68 /* Identify the SOP UID */
69 unsigned int i=0;
70 while(strcmp(dcm_sop[i].uid, "unknown")!=0) {
71 if(strcmp(dcm_sop[i].uid, s)==0) return(i);
72 i++;
73 }
74 return(i);
75}

◆ dcmSOPName()

char * dcmSOPName ( unsigned int i)

Get the DICOM SOP UID Name.

Returns
Returns pointer to the SOP Name string.
See also
dcmSOPIdentify, dcmSOPUID
Parameters
iSOP UID list index.

Definition at line 83 of file dcmsop.c.

86 {
87 unsigned int j=0;
88 while(strcmp(dcm_sop[j].uid, "unknown")!=0) {
89 if(i==j) return(dcm_sop[j].name);
90 j++;
91 }
92 return(dcm_sop[j].name);
93}

◆ dcmSOPUID()

char * dcmSOPUID ( unsigned int i)

Get the DICOM SOP UID.

Returns
Returns pointer to the UID string.
See also
dcmSOPIdentify, dcmSOPName
Parameters
iSOP UID list index.

Definition at line 101 of file dcmsop.c.

104 {
105 unsigned int j=0;
106 while(strcmp(dcm_sop[j].uid, "unknown")!=0) {
107 if(i==j) return(dcm_sop[j].uid);
108 j++;
109 }
110 return(dcm_sop[j].uid);
111}

◆ dcmSOPUIDName()

char * dcmSOPUIDName ( const char * s)

Get the name of DICOM SOP UID.

Returns
Returns pointer to the SOP UID name string.
See also
dcmSOPName, dcmSOPUID
Parameters
sSOP UID string.

Definition at line 119 of file dcmsop.c.

122 {
123 if(s==NULL || strnlen(s, 3)<3) return(dcm_sop[0].name);
124
125 /* Identify the SOP UID */
126 unsigned int i=0;
127 while(strcmp(dcm_sop[i].uid, "unknown")!=0) {
128 if(strcmp(dcm_sop[i].uid, s)==0) return(dcm_sop[i].name);
129 i++;
130 }
131 return(dcm_sop[i].name);
132}

◆ dcmTagIntRange()

int dcmTagIntRange ( DCMITEM * d,
DCMTAG * tag,
int * mi,
int * ma,
const int verbose )

Search the range of integer values for specified tag in DCMITEM data tree.

Returns
0 if successful, otherwise >0.
Parameters
dPointer to top DICOM item.
tagPointer to the DICOM tag that is searched for.
miPointer to int where min value is written; NULL if not needed.
maPointer to int where max value is written; NULL if not needed.
verboseVerbose level; if zero, then nothing is printed to stderr or stdout.

Definition at line 631 of file dcmdata.c.

642 {
643 if(d==NULL || tag==NULL) return(1);
644 if(verbose>0) printf("%s(%04X,%04X)\n", __func__, tag->group, tag->element);
645
646 /* Find the first occurrence of tag */
647 DCMITEM *iptr=dcmFindTag(d, 0, tag, 0);
648 if(iptr==NULL) {
649 if(verbose>1) printf(" tag not found.\n");
650 return(2);
651 }
652 int iv=dcmitemGetInt(iptr); if(verbose>2) printf(" value := %d\n", iv);
653 int mini=iv;
654 int maxi=iv;
655 /* Find the rest of occurrences */
656 while(iptr!=NULL) {
657 iptr=dcmFindTag(iptr, 1, tag, 0);
658 if(iptr!=NULL) {
659 iv=dcmitemGetInt(iptr); if(verbose>2) printf(" value := %d\n", iv);
660 if(iv>maxi) maxi=iv; else if(iv<mini) mini=iv;
661 }
662 }
663 if(verbose>1) {
664 printf(" minimum_value := %d\n", mini);
665 printf(" maximum_value := %d\n", maxi);
666 }
667 if(mi!=NULL) *mi=mini;
668 if(ma!=NULL) *ma=maxi;
669 return(0);
670}

Referenced by dcmImgDim(), and dcmMListRead().

◆ dcmTagSet()

void dcmTagSet ( DCMTAG * tag,
unsigned short int group,
unsigned short int element )

Set DICOM Tag group and element.

Parameters
tagPointer to Tag to set.
groupTag Group
elementTag Element

Definition at line 483 of file dcmdata.c.

490 {
491 tag->group=group;
492 tag->element=element;
493}

Referenced by dcmFileList(), dcmImgDim(), dcmImgIsotope(), dcmImgOrient(), dcmImgPos(), dcmImgPxlsize(), dcmSameImage(), imgReadDICOM(), and imgWriteDICOM().

◆ dcmTM2intl()

char * dcmTM2intl ( const char * orig,
char * intl )

Convert DICOM time 'TM' to international format hh:mm:ss.

Returns
Returns pointer to the time string, or NULL in case of an error.
Parameters
origPointer to original DICOM string.
intlPointer to string where time in international format will be written; must be allocated for at least 9 characters.

Definition at line 202 of file dcmvr.c.

208 {
209 if(orig==NULL || intl==NULL) return(NULL);
210 if(strnlen(orig, 14)<6) return(NULL);
211 if(isdigit(orig[2])) { // modern format hhmmss.fract
212 sprintf(intl, "%2.2s:%2.2s:%2.2s", orig, orig+2, orig+4);
213 } else { // old format hh.mm.ss
214 sprintf(intl, "%2.2s:%2.2s:%2.2s", orig, orig+3, orig+6);
215 }
216 if(strTimeValid(intl)) {intl[0]=(char)0; return(NULL);}
217 return(intl);
218}
int strTimeValid(const char *str)
Definition datetime.c:284

Referenced by dcmMListRead().

◆ dcmTrUID()

dcmtruid dcmTrUID ( const char * s)

Identify the DICOM Transfer Syntax UID.

Returns
Returns the enumerated id.
See also
dcmTrUIDDescr
Parameters
sUID string.

Definition at line 66 of file dcmuid.c.

69 {
70 if(s==NULL || strnlen(s, 5)<5) return(DCM_TRUID_INVALID);
71
72 /* Identify the UID */
73 unsigned short int i=1; // 1 because 0 is unknown
74 while(dcm_truid[i].id!=DCM_TRUID_INVALID) {
75 if(strcmp(dcm_truid[i].uid, s)==0) return(dcm_truid[i].id);
76 i++;
77 }
78 return(DCM_TRUID_UNKNOWN);
79}

Referenced by dcmReadTransferSyntaxUID().

◆ dcmTrUIDDescr()

char * dcmTrUIDDescr ( dcmtruid id)

Get the DICOM Transfer Syntax UID description.

Returns
Returns pointer to the description string.
See also
dcmTrUID
Parameters
idTransfer Syntax UID id (DCM_TRUID_LEI, ...).

Definition at line 87 of file dcmuid.c.

90 {
91 unsigned short int i=0;
92 while(dcm_truid[i].id!=DCM_TRUID_INVALID) {
93 if(id==dcm_truid[i].id) return(dcm_truid[i].descr);
94 i++;
95 }
96 return(dcm_truid[DCM_TRUID_INVALID].descr);
97}

Referenced by dcmFileRead().

◆ dcmTrUIDString()

char * dcmTrUIDString ( dcmtruid id)

Get the DICOM Transfer Syntax UID string.

Returns
Returns pointer to the description string.
See also
dcmTrUID
Parameters
idTransfer Syntax UID id (DCM_TRUID_LEI, ...).

Definition at line 105 of file dcmuid.c.

108 {
109 unsigned short int i=0;
110 while(dcm_truid[i].id!=DCM_TRUID_INVALID) {
111 if(id==dcm_truid[i].id) return(dcm_truid[i].uid);
112 i++;
113 }
114 return(dcm_truid[DCM_TRUID_INVALID].uid);
115}

Referenced by imgWriteDICOM().

◆ dcmValueString()

char * dcmValueString ( DCMITEM * d)

Pre-process the DICOM element value into format suitable for printing.

Note
Use only for printing information for the user.
Returns
Returns pointer to locally allocated null-terminated string.
Postcondition
Free the pointer after use.
See also
dcmitemGetInt, dcmitemGetReal, dcmFindTag

Attribute tag

Float

Double

Unsigned 32-bit int

Unsigned 16-bit int

Signed 32-bit int

Signed 16-bit int

Parameters
dPointer to item containing the value to print.

Definition at line 141 of file dcmdata.c.

144 {
145 if(d==NULL) return((char*)NULL);
146
147 /* For sequence, return string 'na' */
148 if(d->vr==DCM_VR_SQ) {
149 char *s=malloc(3); strcpy(s, "na"); // do not write char *s="na";
150 return(s);
151 }
152
153 /* If there is no value, then return string 'empty', or
154 'na', if value just was not stored (pixel data) */
155 if(d->vl==0) {
156 char *s=malloc(6); strcpy(s, "empty");
157 return(s);
158 } else if(d->rd==NULL) {
159 char *s=malloc(3); strcpy(s, "na");
160 return(s);
161 }
162
163 unsigned int len;
164 if(d->vl==0xFFFFFFFF) len=(unsigned int)dcmVRVLength(d->vr); else len=d->vl;
165
166 /* String values */
167 if(d->vr==DCM_VR_CS || d->vr==DCM_VR_DS || d->vr==DCM_VR_IS ||
168 d->vr==DCM_VR_LO || d->vr==DCM_VR_LT || d->vr==DCM_VR_PN ||
169 d->vr==DCM_VR_SH || d->vr==DCM_VR_ST)
170 {
171 char *s=malloc(len+1);
172 memcpy(s, d->rd, len); s[len]=(char)0;
173 return(s);
174 }
175
176 /* More string values */
177 if(d->vr==DCM_VR_AS || d->vr==DCM_VR_PN ||
178 d->vr==DCM_VR_DA || d->vr==DCM_VR_DT || d->vr==DCM_VR_TM ||
179 d->vr==DCM_VR_UT || d->vr==DCM_VR_AE ||
180 d->vr==DCM_VR_UI || d->vr==DCM_VR_UR)
181 {
182 char *s=malloc(len+1);
183 memcpy(s, d->rd, len); s[len]=(char)0;
184 return(s);
185 }
186
188 if(d->vr==DCM_VR_AT) {
189 DCMTAG tag;
190 memcpy(&tag.group, d->rd, 2);
191 memcpy(&tag.element, d->rd+2, 2);
192 if(!endianLittle()) {
193 swap(&tag.group, &tag.group, 2);
194 swap(&tag.element, &tag.element, 2);
195 }
196 char *s=malloc(14);
197 sprintf(s, "0x%04x,0x%04x", tag.group, tag.element);
198 return(s);
199 }
200
202 if(d->vr==DCM_VR_FL) {
203 float f;
204 memcpy(&f, d->rd, 4);
205 if(!endianLittle()) swap(&f, &f, 4);
206 char *s=malloc(16);
207 sprintf(s, "%g", f);
208 return(s);
209 }
210
212 if(d->vr==DCM_VR_FD) {
213 char *s=malloc(32);
214 /*if(d->vl==2) {
215 printf("\nFD VL=%d\n", d->vl);
216 float f;
217 memcpy(&f, d->rd+4, 4);
218 if(!endianLittle()) swap(&f, &f, 4);
219 sprintf(s, "%g", f);
220 } else {
221 double f;
222 memcpy(&f, d->rd, 8);
223 if(!endianLittle()) swap(&f, &f, 8);
224 sprintf(s, "%g", f);
225 }
226 */
227 double f;
228 memcpy(&f, d->rd, 8);
229 if(!endianLittle()) swap(&f, &f, 8);
230 sprintf(s, "%g", f);
231 return(s);
232 }
233
235 if(d->vr==DCM_VR_UL) {
236 unsigned int i;
237 memcpy(&i, d->rd, 4);
238 if(!endianLittle()) swap(&i, &i, 4);
239 char *s=malloc(16);
240 sprintf(s, "%u", i);
241 return(s);
242 }
243
245 if(d->vr==DCM_VR_US) {
246 unsigned short int i;
247 memcpy(&i, d->rd, 2);
248 if(!endianLittle()) swap(&i, &i, 2);
249 char *s=malloc(8);
250 sprintf(s, "%u", i);
251 return(s);
252 }
253
255 if(d->vr==DCM_VR_SL) {
256 int i;
257 memcpy(&i, d->rd, 4);
258 if(!endianLittle()) swap(&i, &i, 4);
259 char *s=malloc(16);
260 sprintf(s, "%d", i);
261 return(s);
262 }
263
265 if(d->vr==DCM_VR_SS) {
266 short int i;
267 memcpy(&i, d->rd, 2);
268 if(!endianLittle()) swap(&i, &i, 2);
269 char *s=malloc(8);
270 sprintf(s, "%d", i);
271 return(s);
272 }
273
274/* Not (yet) printed:
275 DCM_VR_OB, ///< DICOM other byte string, even bytes, endian insensitive.
276 DCM_VR_OD, ///< DICOM other double (64-bit) stream, endian sensitive.
277 DCM_VR_OF, ///< DICOM other float (32-bit) stream, endian sensitive.
278 DCM_VR_OL, ///< DICOM other long (32-bit) stream, endian sensitive.
279 DCM_VR_OW, ///< DICOM other word (16-bit) stream, even bytes, endian sensitive.
280 DCM_VR_UC, ///< DICOM unlimited characters.
281 DCM_VR_UN, ///< DICOM unknown, any valid length of another VR.
282 DCM_VR_INVALID ///< Invalid DICOM value representation.
283*/
284 char *s=malloc(3); strcpy(s, "na"); // do not write char *s="na";
285 return(s);
286}

Referenced by dcmFileReadNextElement(), dcmImgIsotope(), dcmImgOrient(), dcmImgPos(), dcmImgPxlsize(), dcmitemPrint(), dcmMListRead(), and imgReadDICOM().

◆ dcmVerifyMagic()

int dcmVerifyMagic ( const char * filename,
FILE * fp )

Verify that given file (either file name or file pointer) appears to be DICOM file, based on the magic number.

See also
dcmReadFile, dcmReadTransferSyntaxUID
Returns
Returns 1 if DICOM magic number can be found, or 0 if not.
Author
Vesa Oikonen
Parameters
filenameName of file to open and to verify for the magic number; enter NULL to use the file pointer (next argument) instead.
fpFile pointer of file to check, opened with fp=fopen(filename, "rb"); enter NULL to open file (previous argument) locally. Previously opened file pointer is first rewound to start; if DICOM magic number is found, then file pointer is left to the end of magic number, and if not, it is rewound to the file start.

Definition at line 25 of file dcmio.c.

36 {
37 FILE *lfp;
38
39 if(filename==NULL && fp==NULL) return(0);
40 if(fp!=NULL) {
41 lfp=fp; rewind(lfp);
42 } else {
43 lfp=fopen(filename, "rb");
44 }
45 if(lfp==NULL) return(0);
46
47 /* Skip the first 128 bytes */
48 if(fseek(lfp, 128, SEEK_SET)) {if(fp==NULL) fclose(lfp); return(0);}
49
50 /* Read the next 4 bytes as characters */
51 char buf[5];
52 size_t n=fread(&buf, 1, 4, lfp);
53 buf[4]=(char)0;
54 //if(fp==NULL) fclose(lfp); else rewind(lfp);
55 if(n!=(size_t)4) {rewind(lfp); return(0);}
56
57 /* Check the magic number */
58 if(strncmp(buf, "DICM", 4)==0) {
59 if(fp==NULL) fclose(lfp);
60 return(1);
61 } else {
62 if(fp==NULL) fclose(lfp); else rewind(lfp);
63 return(0);
64 }
65}

Referenced by dcmFileList(), dcmFileRead(), and imgRead().

◆ dcmVRDescr()

char * dcmVRDescr ( dcmvr id)

Get the DICOM VR description.

Returns
Returns pointer to the description string.
See also
dcmIdentifyVR
Parameters
idVR id (DCM_VR_AE, ...).

Definition at line 162 of file dcmvr.c.

165 {
166 unsigned short int i=0;
167 while(dcm_vr[i].vr!=DCM_VR_INVALID) {
168 if(id==dcm_vr[i].vr) return(dcm_vr[i].descr);
169 i++;
170 }
171 return(dcm_vr[DCM_VR_INVALID].descr);
172}

Referenced by dcmFileReadNextElement().

◆ dcmVRId()

dcmvr dcmVRId ( const char * s)

Identify the DICOM VR based on the two-character long string.

Returns
Returns the VR id.
See also
dcmVRName
Parameters
sVR string. Two first characters are used. String does not need to be null-terminated.

Definition at line 103 of file dcmvr.c.

107 {
108 if(s==NULL) return(DCM_VR_INVALID);
109 char buf[3]; buf[0]=s[0]; buf[1]=s[1]; buf[2]=(char)0;
110
111 /* Identify the VR */
112 unsigned short int i=0;
113 while(dcm_vr[i].vr!=DCM_VR_INVALID) {
114 if(strncmp(dcm_vr[i].name, buf, 2)==0) return(dcm_vr[i].vr);
115 i++;
116 }
117 return(DCM_VR_INVALID);
118}

Referenced by dcmFileReadNextElement(), dcmReadFileVR(), and dcmReadFileVRVL().

◆ dcmVRName()

char * dcmVRName ( dcmvr id)

Get the DICOM VR name.

Returns
Returns pointer to the name string.
See also
dcmIdentifyVR
Parameters
idVR id (DCM_VR_AE, ...).

Definition at line 126 of file dcmvr.c.

129 {
130 unsigned short int i=0;
131 while(dcm_vr[i].vr!=DCM_VR_INVALID) {
132 if(id==dcm_vr[i].vr) return(dcm_vr[i].name);
133 i++;
134 }
135 return(dcm_vr[DCM_VR_INVALID].name);
136}

Referenced by dcmAddItem(), dcmFileReadNextElement(), dcmitemPrint(), dcmReadFileVR(), and dcmWriteFileVRVL().

◆ dcmVRReserved()

unsigned char dcmVRReserved ( dcmvr id)

Is the explicit VR (2 bytes) followed by reserved 2 bytes? If yes, then the following Value Length is also given as 32-byte integer, if no, then as 16-bit integer.

Returns
Returns 0, if not, and 2, if it is.
Parameters
idVR id (DCM_VR_AE, ...).

Definition at line 85 of file dcmvr.c.

88 {
89 unsigned short int i=0;
90 while(dcm_vr[i].vr!=DCM_VR_INVALID) {
91 if(id==dcm_vr[i].vr) return(dcm_vr[i].res);
92 i++;
93 }
94 return(2);
95}

Referenced by dcmReadFileVR(), dcmReadFileVRVL(), dcmReadTransferSyntaxUID(), and dcmWriteFileVRVL().

◆ dcmVRVLength()

size_t dcmVRVLength ( dcmvr id)

Get the DICOM VR max value length in bytes; 0 if not defined.

Returns
Returns the length in bytes.
See also
dcmIdentifyVR
Parameters
idVR id (DCM_VR_AE, ...).

Definition at line 144 of file dcmvr.c.

147 {
148 unsigned short int i=0;
149 while(dcm_vr[i].vr!=DCM_VR_INVALID) {
150 if(id==dcm_vr[i].vr) return(dcm_vr[i].s);
151 i++;
152 }
153 return(dcm_vr[DCM_VR_INVALID].s);
154}

Referenced by dcmAddItem(), dcmFileReadNextElement(), dcmFileWrite(), and dcmValueString().

◆ dcmWriteFileSQDelimItem()

int dcmWriteFileSQDelimItem ( FILE * fp)

Write DICOM Sequence delimitation item into current file position.

This item consists of four byte sequence delimitation tag (0xFFFE, 0xE0DD) and four byte item length (0x00000000), i.e. together 8 bytes.

See also
dcmWriteFileTag, dcmReadFileTag, dcmWriteFileSQItemDelimTag
Returns
Code tpcerror, TPCERROR_OK (0) when successful.
Author
Vesa Oikonen
Parameters
fpFile pointer, at the write position.

Definition at line 191 of file dcmio.c.

194 {
195 if(fp==NULL) return(TPCERROR_FAIL);
196 int ret;
197 DCMTAG tag;
198 tag.group=0xFFFE; tag.element=0xE0DD;
199 ret=dcmWriteFileTag(fp, &tag); if(ret!=TPCERROR_OK) return(ret);
200 tag.group=0x0000; tag.element=0x0000;
201 ret=dcmWriteFileTag(fp, &tag); if(ret!=TPCERROR_OK) return(ret);
202 return(TPCERROR_OK);
203}

Referenced by dcmFileWrite().

◆ dcmWriteFileSQItemDelimTag()

int dcmWriteFileSQItemDelimTag ( FILE * fp)

Write DICOM Sequence Item Delimitation Tag with VL into current file position.

This tag consists of four bytes, sequence item delimitation tag (0xFFFE, 0xE00D), followed by four byte item length (0x00000000), i.e. together 8 bytes.

See also
dcmWriteFileTag, dcmReadFileTag, dcmWriteFileSQDelimItem
Returns
Code tpcerror, TPCERROR_OK (0) when successful.
Author
Vesa Oikonen
Parameters
fpFile pointer, at the write position.

Definition at line 216 of file dcmio.c.

219 {
220 if(fp==NULL) return(TPCERROR_FAIL);
221 int ret;
222 DCMTAG tag;
223 tag.group=0xFFFE; tag.element=0xE00D;
224 ret=dcmWriteFileTag(fp, &tag); if(ret!=TPCERROR_OK) return(ret);
225 tag.group=0x0000; tag.element=0x0000;
226 ret=dcmWriteFileTag(fp, &tag); if(ret!=TPCERROR_OK) return(ret);
227 return(TPCERROR_OK);
228}

Referenced by dcmFileWrite().

◆ dcmWriteFileTag()

int dcmWriteFileTag ( FILE * fp,
DCMTAG * tag )

Write DICOM tag into current file position.

See also
dcmWriteFile, dcmReadFileTag
Returns
Code tpcerror, TPCERROR_OK (0) when successful.
Author
Vesa Oikonen
Parameters
fpFile pointer, at the write position.
tagPointer to DICOM tag struct to write.

Definition at line 165 of file dcmio.c.

170 {
171 if(fp==NULL || tag==NULL) return(TPCERROR_FAIL);
172 unsigned short int buf[2];
173 buf[0]=tag->group;
174 buf[1]=tag->element;
175 if(!endianLittle()) swabip(buf, 4); // tag is by default little endian
176 if(fwrite(&buf, 2, 2, fp)!=2) return TPCERROR_CANNOT_WRITE;
177 return(TPCERROR_OK);
178}

Referenced by dcmFileWrite(), dcmWriteFileSQDelimItem(), and dcmWriteFileSQItemDelimTag().

◆ dcmWriteFileVRVL()

int dcmWriteFileVRVL ( FILE * fp,
dcmvr vr,
unsigned int vl,
unsigned int * n )

Write DICOM Value Representation (VR, 2 or 4 bytes) and Value Length (VL, 2 or 4 bytes) into current file position.

See also
dcmWriteFileTag, dcmReadFileElement, dcmWriteFileVRVL
Returns
Code tpcerror, TPCERROR_OK (0) when successful.
Author
Vesa Oikonen
Parameters
fpFile pointer, opened fro writing in binary mode.
vrEnumerated VR value.
vlVL
nPointer for number of bytes written into file; enter NULL if not needed.

Definition at line 366 of file dcmio.c.

375 {
376 if(n!=NULL) *n=0;
377 if(fp==NULL || vr==DCM_VR_INVALID) return(TPCERROR_FAIL);
378
379 /* If this VR has extra 2 byte reserved space, then
380 we need to write VR and VL with 4 bytes each, other wise with 2 bytes each. */
381 unsigned int bsize=2+dcmVRReserved(vr);
382
383 char buf[10];
384
385 /* Write VR */
386 memcpy(buf, dcmVRName(vr), 2); buf[2]=buf[3]=(char)0;
387 if(fwrite(buf, bsize, 1, fp)!=1) return(TPCERROR_CANNOT_WRITE);
388 if(n!=NULL) *n+=bsize;
389
390 /* Write VL */
391 memcpy(buf, &vl, bsize);
392 if(bsize==2) buf[2]=buf[3]=(char)0;
393// if(!endianLittle()) swabip(buf, bsize);
394 if(!endianLittle()) swap(buf, buf, bsize);
395 if(fwrite(buf, bsize, 1, fp)!=1) return(TPCERROR_CANNOT_WRITE);
396 if(n!=NULL) *n+=bsize;
397
398 return(TPCERROR_OK);
399}

Referenced by dcmFileWrite().

◆ dcmXformToQuatern()

int dcmXformToQuatern ( double * xform,
double * quatern,
double * qoffset,
const int verbose )

Calculate quatern parameters for NIfTI from xform matrix.

Based on dcm2niix, but results are compatible with TPC ImageConverter.

See also
dcmImgXform, dcmImgOrient, dcmImgPxlsize, dcmImgPos, dcmImgDim
Returns
0 if successful, otherwise >0.
Parameters
xformPointer to xform 4x4 matrix stored as an array of 16 doubles; not modified.
quaternPointer to quatern parameter b, c, and d array (size of 3); filled here; enter NULL, if not needed.
qoffsetPointer to qoffset parameter x, y, and z array (size of 3); filled here; enter NULL, if not needed.
verboseVerbose level; if zero, then nothing is printed to stderr or stdout.

Definition at line 540 of file dcmimage.c.

551 {
552 if(verbose>0) {printf("%s(xform[16], quatern[3], qoffset[3])\n", __func__); fflush(stdout);}
553 if(xform==NULL) return(1);
554 if(quatern!=NULL) for(int i=0; i<3; i++) quatern[i]=nan("");
555 if(qoffset!=NULL) for(int i=0; i<3; i++) qoffset[i]=nan("");
556
557 /* Copy array to matrix */
558 double xformM[4][4];
559 for(int i=0; i<4; i++)
560 for(int j=0; j<4; j++)
561 xformM[i][j]=xform[j+4*i];
562 /* DICOM LPS to NIfTI RAS */
563 for(int i=0; i<2; i++)
564 for(int j=0; j<4; j++)
565 xformM[i][j]=-xformM[i][j];
566
567 /* Set quatern offsets */
568 if(qoffset!=NULL) for(int i=0; i<3; i++) qoffset[i]=xformM[i][3];
569
570 /* Ready, if quatern parameters not needed */
571 if(quatern==NULL) return(0);
572
573 // compute lengths
574 double mt[3][3];
575 for(int i=0; i<3; i++)
576 for(int j=0; j<3; j++)
577 mt[i][j]=xformM[i][j];
578 double xd, yd, zd;
579 xd=sqrt(mt[0][0]*mt[0][0] + mt[1][0]*mt[1][0] + mt[2][0]*mt[2][0]);
580 yd=sqrt(mt[0][1]*mt[0][1] + mt[1][1]*mt[1][1] + mt[2][1]*mt[2][1]);
581 zd=sqrt(mt[0][2]*mt[0][2] + mt[1][2]*mt[1][2] + mt[2][2]*mt[2][2]);
582 if(!(xd>0.0)) {mt[0][0]=1.0; mt[1][0]=mt[2][0]=0.0; xd=1.0;}
583 if(!(yd>0.0)) {mt[1][1]=1.0; mt[0][1]=mt[2][1]=0.0; yd=1.0;}
584 if(!(zd>0.0)) {mt[2][2]=1.0; mt[0][2]=mt[1][2]=0.0; zd=1.0;}
585 // normalize
586 for(int i=0; i<3; i++) mt[i][0]/=xd;
587 for(int i=0; i<3; i++) mt[i][1]/=yd;
588 for(int i=0; i<3; i++) mt[i][2]/=zd;
589 // check orthogonality (to be added)
590
591 // determinant
592 double dt;
593 dt= mt[0][0]*mt[1][1]*mt[2][2] - mt[0][0]*mt[2][1]*mt[1][2] - mt[1][0]*mt[0][1]*mt[2][2]
594 +mt[1][0]*mt[2][1]*mt[0][2] + mt[2][0]*mt[0][1]*mt[1][2] - mt[2][0]*mt[1][1]*mt[0][2];
595 if(verbose>3) printf("determinant=%g\n", dt);
596 if(dt<0.0) for(int i=0; i<3; i++) mt[i][2]=-mt[i][2];
597
598 // Calculate quatern parameters
599 double a, b, c, d;
600 a=1.0+mt[0][0]+mt[1][1]+mt[2][2];
601 if(a>0.5) {
602 a=0.5*sqrt(a);
603 b=0.25*(mt[2][1]-mt[1][2])/a;
604 c=0.25*(mt[0][2]-mt[2][0])/a;
605 d=0.25*(mt[1][0]-mt[0][1])/a;
606 } else {
607 xd=1.0+mt[0][0]-(mt[1][1]+mt[2][2]);
608 yd=1.0+mt[1][1]-(mt[0][0]+mt[2][2]);
609 zd=1.0+mt[2][2]-(mt[0][0]+mt[1][1]);
610 if(xd>1.0) {
611 b=0.50*sqrt(xd);
612 c=0.25*(mt[0][1]+mt[1][0])/b;
613 d=0.25*(mt[0][2]+mt[2][0])/b;
614 a=0.25*(mt[2][1]-mt[1][2])/b;
615 } else if(yd>1.0) {
616 c=0.50*sqrt(yd);
617 b=0.25*(mt[0][1]+mt[1][0])/c;
618 d=0.25*(mt[1][2]+mt[2][0])/c;
619 a=0.25*(mt[0][2]-mt[2][0])/c;
620 } else {
621 d=0.50*sqrt(zd);
622 b=0.25*(mt[0][2]+mt[2][0])/d;
623 c=0.25*(mt[1][2]+mt[2][1])/d;
624 a=0.25*(mt[1][0]-mt[0][1])/d;
625 }
626 }
627 if(a<0.0) {b=-b; c=-c; d=-d;}
628 quatern[0]=b;
629 quatern[1]=c;
630 quatern[2]=d;
631
632 return(0);
633}

Referenced by imgReadDICOM().