#include #include #include #include //#include #include #include #include #ifdef _MSC_VER #include // Pour ntohs - BigEndianeries - #else #include // Pour ntohs - BigEndianeries - #endif #define LGR_ENTETE_A_LIRE 256 // on ne lit plus que le debut #define DEBUG 0 static char * var_itoa(void * , int ); static guint32 _IdDcmRecupLgr(ID_DCM_HDR *, int, int*, int *); static int _IdDcmCheckSwap(ID_DCM_HDR *); static int _IdDcmLireEtStockerElement(ID_DCM_HDR *, char **, int, int, char *, int); static char ** _IdDcmInquireImageInfoXXX (ID_DCM_HDR *, char **); static void _setAcrLibido(ID_DCM_HDR *); // ----------------------------------------------------------------- /** * \ingroup dcm * \brief Alloue un ID_DCM_HDR * @return Pointeur sur structure Allouée, NULL si échec */ ID_DCM_HDR * IdDcmHdrAlloc () { ID_DCM_HDR *e = (ID_DCM_HDR *) g_malloc0 (sizeof(ID_DCM_HDR)); if (!e) return e; e->deb = (char *) g_malloc(LGR_ENTETE_A_LIRE); if (!e->deb) { g_free(e); printf("Echec alloc ID_DCM_HDR\n"); } e->plist = IdLstAlloc(); if (!e->plist) { g_free(e->deb); g_free(e); printf("Echec alloc ID_DCM_HDR->deb\n"); return (ID_DCM_HDR *)NULL; } return(e); } // ------------------------------------------------------------------ /** * \ingroup dcm * \brief Libere un ID_DCM_HDR * @param e pointeur sur le ID_DCM_HDR a liberer. * @return void */ void IdDcmHdrFree (ID_DCM_HDR * e) { if (e) { if (e->deb) g_free(e->deb); if (e->deb) g_free(e->plist); // LIBERER LES ELEMENTS DE LA LISTE AVANT g_free(e); } } /* ======================================================================= * _IdDcmSWAP_SHORT * remet les octets dans un ordre compatible avec celui du processeur * ======================================================================= */ short int _IdDcmSWAP_SHORT(short int a,int sw) { if ( (sw==4321) || (sw==2143) ) a =(((a<<8) & 0x0ff00) | ((a>>8)&0x00ff)); return (a); } /* ======================================================================= * _IdDcmSWAP_LONG * remet les octets dans un ordre compatible avec celui du processeur * ======================================================================= */ guint32 _IdDcmSWAP_LONG(guint32 a, int sw) { /* ATTENTION: il pourrait y avoir un pb pour les entiers negatifs ... * */ switch (sw) { case 4321 : a=( ((a<<24) & 0xff000000) | ((a<<8) & 0x00ff0000) | ((a>>8) & 0x0000ff00) | ((a>>24) & 0x000000ff) ); break; case 3412 : a=( ((a<<16) & 0xffff0000) | ((a>>16) & 0x0000ffff) ); break; case 2143 : a=( ((a<<8) & 0xff00ff00) | ((a>>8) & 0x00ff00ff) ); break; default : printf("\n\n\n *******\n erreur code swap ?!?\n\n\n"); a=0; } return(a); } // ----------------------------------------------------------------------------------- /** * \ingroup dcm * \brief renvoie un pointeur sur le ID_DCM_HDR correspondant au fichier * @param filename Nom du fichier ACR / LibIDO / DICOM * @return le ID_DCM_HDR */ ID_DCM_HDR * IdDcmGetHeader(char *filename) { ID_DCM_HDR *e=NULL; _ID_DCM_ELEM * ple; e = IdDcmHdrAlloc(); if(!e) { printf("echec alloc HDR \n"); return(NULL); } if((e->fp=fopen(filename,ID_RFILE_BIN))==0) { // OK // IdDcmHdrAFree(e); printf ("echec ouverture %s\n",filename); return (NULL); } e->filename = strdup(filename); fseek(e->fp, 0L, SEEK_END); /* * obtains the current value of the file-position * indicator for the stream pointed to by stream */ e->taille_fich = ftell(e->fp); if(DEBUG) printf("IdDcmGetHeader : lgr fich %f\n",(float)e->taille_fich); // FORMAT IMPRESSION long int ??? rewind(e->fp); e->sw= _IdDcmCheckSwap(e); e->__NumeroGroupePrecedent = 0; // Pour etre sur que le premier sera + grand e->grPixelTrouve = 0; e->PixelsTrouves = 0; while ( (ple=_IdDcmReadNextElement(e,e->sw)) ) { IdLstAddLast(e->plist, ple); } // Positionnement ACR_LIBIDO _setAcrLibido(e); fclose(e->fp); return (e); } static void _setAcrLibido(ID_DCM_HDR *e) { _ID_DCM_ELEM * ple; PLIST_ELEMENT plelem; PLIST pl; // Positionnement ACR_LIBIDO if(DEBUG) printf("Entree ds _setAcrLibido\n"); e->ACR_LIBIDO = 0; if ( e->__TrueDicom == 0) { // Recognition Code --> n'existe plus en DICOM V3 ... pl = e->plist; plelem = IdLstFirst(pl); while (plelem) { ple= IdLstPtrObj(plelem); if(DEBUG) printf("gr %04x Num %04x\n", ple->Gr, ple->Num); if(ple->Gr > 0x0008) break; // On a depasse if(ple->Gr == 0x0008) { if(ple->Num > 0x0010) break; // On a depasse if(ple->Num == 0x0010) { if ( (memcmp(ple->valeurElem,"ACRNEMA_LIBIDO",14)==0) // si c'est egal || (memcmp(ple->valeurElem,"CANRME_AILIBOD",14)==0)) { // en cas d'objet ACRLibido fait sr 1 autre machine) e->ACR_LIBIDO =1; } // fin if memcmp break; } // fin if ple->Num==0x0010 } // fin ple->Gr==0x0008 plelem = IdLstNext(plelem); } // fin while } // fin if TrueDicom if(DEBUG) printf("ACR_LIBIDO = %d\n", e->ACR_LIBIDO); return; } /* ======================================================================= * _IdDcmRecupLgr * * ACR-NEMA : On a toujours * GroupNumber (2 Octets) * ElementNumber (2 Octets) * ElementSize (4 Octets) * * * DICOM : On peut avoir (implicit Value Representation) * GroupNumber (2 Octets) * ElementNumber (2 Octets) * ElementSize (4 Octets) * * On peut avoir (explicit Value Representation) * GroupNumber (2 Octets) * ElementNumber (2 Octets) * ValueRepresentation (2 Octets) * ElementSize (2 Octets) * * ATTENTION : dans le cas ou ValueRepresentation = OB, OW, SQ, UN * GroupNumber (2 Octets) * ElementNumber (2 Octets) * ValueRepresentation (2 Octets) * zone reservee (2 Octets) * ElementSize (4 Octets) * * * ======================================================================= */ /** * \ingroup dcm * \brief recupere la longueur d'un champ DICOM. * (le fichier doit deja avoir ete ouvert, * _IdAcrCheckSwap(ID_DCM_HDR *e) avoir ete appele) * et la partie 'group' ainsi que la partie 'elem' * de l'acr_element doivent avoir ete lues. * @param sw code swap * @param skippedLength pointeur sur nombre d'octets que l'on a saute qd la lecture est finie * @param longueurLue pointeur sur longueur (en nombre d'octets) effectivement lue * @return longueur retenue pour le champ */ static guint32 _IdDcmRecupLgr(ID_DCM_HDR *e, int sw, int *skippedLength, int *longueurLue) { guint32 l_gr; unsigned short int l_gr_2; int i, trouve; char VR[5]; int lgrLue; /* * ATTENTION : */ int nbCode=26; // nombre d'elements dans la table de type DICOM_VR definie dans dicom.c /* ================ */ // ID_DCM_HDR *e sert uniquement de passe-plat pour __ExplicitVR if (e->__ExplicitVR == 1) { lgrLue=fread (&VR, (size_t)2,(size_t)1, e->fp); VR[2]=0; // ATTENTION : // Ce n'est pas parce qu'on a trouve UL la premiere fois qu'on respecte // Explicit VR tout le temps // (cf e=film ...) for(i=0,trouve=0;ipleCourant)->VR=_ID_dicom_vr[i].dicom_VR; trouve=1; break; } } if ( trouve == 0) { // On est mal : implicit VR repere // mais ce n'est pas un code connu ... // On reconstitue la longueur if(DEBUG) printf("IdDcmRecupLgr : Explicit VR, mais pas trouve de code connu\n"); memcpy(&l_gr, VR,(size_t)2); lgrLue=fread ( ((char*)&l_gr)+2, (size_t)2, (size_t)1, e->fp); if(sw) l_gr = _IdDcmSWAP_LONG(((guint32)l_gr),sw); if(DEBUG) printf("IdDcmRecupLgr : lgr deduite : %08x , %d\n",l_gr,l_gr); *longueurLue=l_gr; if ( (int)l_gr == -1) { l_gr=0; } *skippedLength = 4; if (DEBUG) printf(" 1 : lgr %08x (%d )skippedLength %d\n",l_gr,l_gr, *skippedLength); return(l_gr); } // On repart dans la sequence 'sensee' if(DEBUG) printf("VR : [%01x , %01x] (%c%c) en position %d du tableau\n", VR[0],VR[1],VR[0],VR[1],i); //printf(" %d , %s\n", i,_ID_dicom_vr[i].dicom_VR); if ( (!memcmp( VR,"OB",(size_t)2 )) || (!memcmp( VR,"OW",(size_t)2 )) || (!memcmp( VR,"SQ",(size_t)2 )) || (!memcmp( VR,"UN",(size_t)2 )) ) { // les 2 octets suivants sont reserves if(DEBUG) printf("IdDcmRecupLgr : les 2 octets suivants sont reserves\n"); //on les saute fseek(e->fp, 2L,SEEK_CUR); //on lit la lgr sur QUATRE octets lgrLue=fread (&l_gr, (size_t)4,(size_t)1, e->fp); if(sw) l_gr = _IdDcmSWAP_LONG(((guint32)l_gr),sw); *skippedLength = 8; } else { //on lit la lgr sur DEUX octets lgrLue=fread (&l_gr_2, (size_t)2,(size_t)1, e->fp); if(sw) l_gr_2 = _IdDcmSWAP_SHORT((unsigned short)l_gr_2,sw); *longueurLue=l_gr_2; if ( l_gr_2 == 0xffff) { l_gr = 0; } else { l_gr = l_gr_2; } *skippedLength = 4; } } else { // Explicit VR = 0 //on lit la lgr sur QUATRE octets lgrLue=fread (&l_gr, (size_t)4,(size_t)1, e->fp); if(sw)l_gr=_IdDcmSWAP_LONG(((long)l_gr),sw); *skippedLength = 4; } *longueurLue=l_gr; // Traitement des curiosites sur la longueur if ( (int)l_gr == 0xffffffff) l_gr=0; if(!memcmp( VR,"SQ",(size_t)2 )) { // ca annonce une SEQUENCE d'items ?! l_gr=0; // on lira donc les items de la sequence if (DEBUG) printf(" SQ trouve : lgr %d \n",l_gr); } if (DEBUG) printf(" 2 : lgr %08x (%d) skippedLength %d\n",l_gr,l_gr, *skippedLength); return(l_gr); } /* ======================================================================= _IdDcmReadNextElement lit l'acr_element courant le fichier doit deja avoir ete ouvert, ======================================================================= */ /** * \ingroup dcm * \brief lit le dicom_element suivant. * (le fichier doit deja avoir ete ouvert, * _IdAcrCheckSwap(ID_DCM_HDR *e) avoir ete appele) * @param e ID_DCM_HDR dans lequel effectuer la recherche. * @param sw code swap. * @return En cas de succes, 1 * 0 en cas d'echec. */ _ID_DCM_ELEM * _IdDcmReadNextElement(ID_DCM_HDR * e, int sw) { unsigned short g; unsigned short n; guint32 l; long int posFich; int skL; size_t lgrLue; int i; DICOM_ELEMENTS *t; _ID_DCM_ELEM *nouvDcmElem; if (DEBUG) printf(" ===> entree ds _IdDcmReadNextElement\n"); if(e->offsetCourant == e->taille_fich) { // On a atteint la fin du fichier if (DEBUG) printf(" On a atteint la fin du fichier\n"); return(NULL); } else { if (DEBUG) { posFich = ftell(e->fp); printf("lgrFich %f positionDsFich %f offset courant %f\n", (float)e->taille_fich, (float)posFich, (float)e->offsetCourant); } } nouvDcmElem = (_ID_DCM_ELEM *)g_malloc(sizeof(_ID_DCM_ELEM)); if (!nouvDcmElem) { printf("Echec alloc _ID_DCM_ELEM *nouvDcmElem\n"); return(NULL); } e->pleCourant = nouvDcmElem; // ------------------------- Lecture Num group : g lgrLue=fread (&g, (size_t)2,(size_t)1, e->fp); if (feof(e->fp)) { if (DEBUG) printf("_IdDcmReadNextElement : eof trouve\n"); return (NULL); } if (ferror(e->fp)){ if (DEBUG) printf(" IdDcmReadNextElement : echec lecture NumGr\n"); return (NULL); } if (DEBUG) printf("_IdDcmReadNextElement : " " gr %04x\n",g ); if (sw) g=_IdDcmSWAP_SHORT(((short)g),sw); nouvDcmElem->Gr=g; e->__NumeroGroupePrecedent =g; // ------------------------- Lecture Num Elem : n lgrLue=fread (&n, (size_t)2,(size_t)1, e->fp); if (feof(e->fp)) { if (DEBUG) printf("_IdDcmReadNextElement : eof trouve\n"); return (NULL); } if (ferror(e->fp)){ if (DEBUG) printf(" IdDcmReadNextElement : echec lecture NumElem\n"); return (NULL); } if (DEBUG) printf("_IdDcmReadNextElement : " " num %04x\n",n ); if(sw)n=_IdDcmSWAP_SHORT(((short)n),sw); nouvDcmElem->Num=n; // ------------------------- Lecture longueur element : l l = _IdDcmRecupLgr(e, sw, &skL, &nouvDcmElem->LgrLueElem); if(g==0xfffe) l=0; // pour sauter les indicateurs de 'SQ' nouvDcmElem->LgrElem=l; if (DEBUG) if (n!=0) printf("_IdDcmReadNextElement : " " gr %04x\tnum %04x\tlong %08x (%d)\n", g,n,l,l); // ------------------------- Lecture Valeur element nouvDcmElem->valeurElem = g_malloc(l+1); if(nouvDcmElem->valeurElem) { nouvDcmElem->valeurElem[l]= 0; } else { if (DEBUG) printf(" IdDcmReadNextElement : echec Alloc valeurElem lgr : %d\n",l); return (NULL); } // ------------------------ On n'amene pas en mémoire les Elem 'trop longs' lgrLue=fread (nouvDcmElem->valeurElem, (size_t)l,(size_t)1, e->fp); e->offsetCourant += 2 + 2 + skL; // gr + num + lgr nouvDcmElem->Offset = e->offsetCourant; e->offsetCourant += l; // debut elem suivant // ------------------------- Doit-on le Swapper ? if ((n==0) && sw) { // n=0 : lgr du groupe : guint32 *(guint32 *) nouvDcmElem->valeurElem = _IdDcmSWAP_LONG ((*(guint32 *) nouvDcmElem->valeurElem),sw); nouvDcmElem->Swap = 1; } else { if(sw) { if ( (g/2)*2-g==0) { /* on ne teste pas les groupes impairs */ if ((l==4)||(l==2)) { /*pour eviter de swapper les chaines de lgr 2 ou 4 */ if (DEBUG) printf("Consultation Dictionary DICOM g %04x n %0xx l %d\n", g,n,l); for (t=_ID_dicom_elements; t->dicom_group!=0xffff; t++) { if( (t->dicom_group==g) && (t->dicom_elem==n) ) { nouvDcmElem->VR= t->dicom_type; break; } } if ( (strcmp(t->dicom_type,"UL") ==0) || (strcmp(t->dicom_type,"US") ==0) || (strcmp(t->dicom_type,"SL") ==0) || (strcmp(t->dicom_type,"SS") ==0) || (g == 0x0028 && ( n == 0x0005 || n == 0x0200) ) ) { // seuls (28,5) de vr RET // et (28,200) sont des entiers // ... jusqu'a preuve du contraire nouvDcmElem->Swap = 1; if(l==4) { *(guint32 *) nouvDcmElem->valeurElem= _IdDcmSWAP_LONG ((*(guint32 *) nouvDcmElem->valeurElem),sw); nouvDcmElem->valInt = _IdDcmSWAP_LONG ((*(guint32 *) nouvDcmElem->valeurElem),sw); } else { if(l==2) *(unsigned short *) nouvDcmElem->valeurElem= _IdDcmSWAP_SHORT ((*(unsigned short *)nouvDcmElem->valeurElem),sw); nouvDcmElem->valShort = _IdDcmSWAP_SHORT ((*(unsigned short *)nouvDcmElem->valeurElem),sw); } } } /* fin if l==2 ==4 */ } /* fin if g pair */ } /* fin sw */ } // ------------------------- A-t-on trouve l'info donnant le 'num groupe' des Pixels ? if (!e->grPixelTrouve) { // on n a pas encore trouve les pixels if (g > 0x0028) { if (n > 0x0200 || g == 0x7FE0 ) { // on a depasse (28,200) e->grPixel = 0x7FE0; e->numPixel = 0x0010; e->grPixelTrouve = 1; if (DEBUG) printf("------------------------grPixel %04x numPixel %04x\n", e->grPixel,e->numPixel); } } else { // on est sur (28,200) if (g == 0x0028) { if (n == 0x0200) { e->grPixelTrouve = 1; for(i=0;i<4;i++) *((char*)(&e->grPixel)+i) = *(nouvDcmElem->valeurElem+i); if (DEBUG) printf("------------------------GrPixel %04x\n", e->grPixel); if (e->grPixel != 0x7FE0) // Vieux pb Philips e->numPixel = 0x1010; // encore utile ?? else e->numPixel = 0x0010; if (DEBUG) printf("------------------------grPixel %04x numPixel %04x\n", e->grPixel,e->numPixel); } } } } else { // on vient de trouver les pixels if (g == e->grPixel) { if (n == e->numPixel) { e->PixelPosition = nouvDcmElem->Offset; e->PixelsTrouves = 1; if (DEBUG) printf(" \t===> Pixels Trouves\n"); } } } e->nbElem ++; //printf("nb Elem %d\n",e->nbElem); return(nouvDcmElem); } /* ======================================================================= _IdDcmCheckSwap La seule maniere sure que l'on aie pour determiner si on est en LITTLE_ENDIAN, BIG-ENDIAN, BAD-LITTLE-ENDIAN, BAD-BIG-ENDIAN est de trouver l'element qui donne la longueur d'un 'GROUP' (on sait que la longueur de cet element vaut 0x00000004) et de regarder comment cette longueur est codee en memoire Le probleme vient de ce que parfois, il n'y en a pas ... On fait alors le pari qu'on a a faire a du LITTLE_ENDIAN propre. (Ce qui est la norme -pas respectee- depuis ACR-NEMA) Si ce n'est pas le cas, on ne peut rien faire. (il faudrait avoir des fonctions auxquelles on passe le code Swap en parametre, pour faire des essais 'manuels') ======================================================================= */ static int _IdDcmCheckSwap(ID_DCM_HDR * e) { guint32 s, x=4; // x : pour ntohs int sw; int lgrLue; char * entCur; char deb[LGR_ENTETE_A_LIRE]; // On teste le processeur if (x==ntohs(x)) { /* si le HostByteOrder est le meme que le NetworkByteOrder */ e->net2host = 1; } else { e->net2host = 0; } //printf("\t\t\t\te->net2host %d \n",e->net2host); /* On commence par verifier si c'est du DICOM 'actuel' */ /* ------------- */ lgrLue = fread(deb,1,LGR_ENTETE_A_LIRE,e->fp); entCur = deb+128; if(memcmp(entCur, "DICM", (size_t)4) == 0) { e->__TrueDicom=1; if (DEBUG) printf ("_IdDcmCheckSwap : C est du DICOM actuel \n"); } else { e->__TrueDicom=0; if (DEBUG) printf ("_IdDcmCheckSwap : Ce n'est PAS du DICOM actuel\n"); } if(e->__TrueDicom) { entCur = deb+136; /* on saute le File Preamble (souvent a ZERO) : 128 Octets */ /* le DICM, et le 0002, 0000 */ if(memcmp(entCur, "UL", (size_t)2) == 0) { /* les 2 premiers octets de la lgr peuvent valoir UL --> Explicit VR */ e->__ExplicitVR = 1; if (DEBUG) printf ("_IdDcmCheckSwap : Explicit VR\n"); } else { e->__ExplicitVR = 0; if (DEBUG) printf ("_IdDcmCheckSwap : PAS Explicit VR\n"); } if (e->net2host == 0) { /* si le HostByteOrder est different du NetworkByteOrder */ sw = 0; /* on est sur PC ou DEC --> LITTLE-ENDIAN -> Rien a faire */ if (DEBUG) printf("HostByteOrder = NetworkByteOrder\n"); } else { /* on est sur une Sun ou une SGI */ sw = 4321; if (DEBUG) printf("HostByteOrder != NetworkByteOrder\n"); } rewind(e->fp); fseek (e->fp, 132L, SEEK_SET); //On se positionne sur le debut des info e->offsetCourant=132; return sw; } /* fin TrueDicom */ /* ----- SINON ----- */ /* Si c'est de l'ACR 'propre', la lgr du premier element du groupe est FORCEMENT 4 */ entCur=deb + 4; s=str2num(entCur,int); switch (s) { case 0x00040000 : sw=3412; if(DEBUG) printf("s : %08x sw : %d\n",s,sw); break; case 0x04000000 : sw=4321; if(DEBUG) printf("s : %08x sw : %d\n",s,sw); break; case 0x00000400 : sw=2143; if(DEBUG) printf("s : %08x sw : %d\n",s,sw); break; case 0x00000004 : sw=0; if(DEBUG) printf("s : %08x sw : %d\n",s,sw); break; default : sw = -1; if (DEBUG) printf (" Pas trouve l info de Swap; On va parier\n"); } /* Si c'est de l'ACR 'pas propre', il manque la lgr du groupe */ if(sw==-1) { /* On n'a pas trouve l'info de swap 28/11/2000 JPR */ /* Si c'est du VRAI ACR NEMA si on est sur une DEC ou un PC swap=0, SUN ou SGI SWAP=4321 */ /* si c'est du RAW, ca degagera + tard */ if (DEBUG) printf("On force la chance \n"); if (x!=ntohs(x)) /* si le HostByteOrder est different du NetworkByteOrder */ sw = 0; /* on est sur PC ou DEC --> LITTLE-ENDIAN -> Rien a faire */ else sw = 4321; /* on est sur Sun ou SGI */ } rewind(e->fp); // les info commencent au debut e->offsetCourant=0; return (sw); } // /* ================================================================== */ // /** * \ingroup dcm * \brief renvoie dans un tableau de chaines de caracteres la description des info pertinentes d'une image ACR /DCM (la soixantaine de champs utiles) a partir du nom du fichier * * @param filename Nom du fichier. * @return ID_DCM_HDR * * * Pour avoir la liste a jour des elements renvoyes dans ce tableau, * Consulter src/idacr.h et src/dicom.c * */ /* Pour rajouter une entree ici, penser a modifier le fichier dicom.c penser a modifier la fonction idacr.h pour maintenir la coherence. */ char ** IdDcmInquireImageInfoFromFile(char *filename) { ID_DCM_HDR *e; char **imageInfo; e = IdDcmGetHeader(filename); if (!e) { printf("fichier %s : gros problème :\n", filename); IdErrno = IDERR_NON_ACR_FILE; return (0); } imageInfo = _IdDcmInquireImageInfoXXX(e, NULL); // LIBERER LE HEADER return (imageInfo); } // /* ================================================================== */ // /** * \ingroup dcm * \brief renvoie dans un tableau de chaines de caracteres * la description des info pertinentes d'une image ACR /DCM * a partir d'un ID_DCM_HDR deja fabrique * * @param e ID_DCM_HDR de l'image * @return Tableau : * * Pour avoir la liste a jour des elements renvoyes dans ce tableau, * Consulter src/idacr.h et src/dicom.c * */ /* Pour rajouter une entree ici, penser a modifier le fichier dicom.c penser a modifier la fonction idacr.h pour maintenir la coherence. */ char ** IdDcmInquireImageInfoFromDcmHdr(ID_DCM_HDR *e) { char **imageInfo; if (!e) { printf("ID_DCM_HDR pas alloue\n"); IdErrno = IDERR_NON_ACR_FILE; return (0); } imageInfo = _IdDcmInquireImageInfoXXX(e, NULL); return (imageInfo); } /* ----------------------------------------------------------------------- */ static char ** _IdDcmInquireImageInfoXXX(ID_DCM_HDR *e, char **imageInfo) { int boolTrouveQqChose=0,trouv,k; DICOM_INFO *t; t = _ID_dicom_info; if (!imageInfo) imageInfo = (char **) g_malloc0((_ID_Number_of_Items + 1) * sizeof(char *)); for(k=0;k<_ID_Number_of_Items;k++) { trouv=_IdDcmLireEtStockerElement(e, imageInfo,t[k].dicom_group, t[k].dicom_elem, t[k].dicom_info_libelle, t[k].dicom_info_ind); if(trouv) boolTrouveQqChose=1; } if(boolTrouveQqChose) return (imageInfo); else return(0); } /* ----------------------------------------------------------------------- * ID_DCM_HDR *e : doit avoir ete cree dans l'appelant * char **TableauImageInfo : doit avoir ete alloue dans l'appelant; * ses elements sont alloues dans la fonction * int numGroupe : gr et el du Tag DICOM * int numElem * char *nomElem : libelle imprime si element pas trouve * int position : indice dans TableauImageInfo -----------------------------------------------------------------------*/ static int _IdDcmLireEtStockerElement(ID_DCM_HDR *e, char **TableauImageInfo, int numGroupe, int numElem, char *nomElem, int position) { int z; char *chaine; /* * Lecture Element */ //if (!( chaine = _IdDcmReadElement(numGroupe, numElem, e) )) { if (!( chaine = _IdDcmReadElementNoSQ(numGroupe, numElem, e) )) { if (DEBUG) printf ("%d : _IdDcmLireEtStockerElement : " "%s (%04x,%04x) pas trouve \n", position, nomElem, numGroupe, numElem); return (0); } else { if (DEBUG) printf ("%d : _IdDcmLireEtStockerElement : " "%s (%04x,%04x) \t[%s] \n", position, nomElem, numGroupe, numElem,chaine); z = strlen(chaine); while (chaine[z] == ' ') { chaine[z] = 0; z--; } TableauImageInfo[position] = (char *) g_malloc(1 + strlen(chaine)); strcpy(TableauImageInfo[position], chaine); if (DEBUG) printf ("%d : %s (_IdDcmLireEtStockerElement : " "%04x,%04x)\t[%s]\n", position, nomElem, numGroupe, numElem, chaine); return (1); } } // Converts an integer represented with num_byte bytes within the // buffer buff to a string. // Refer to comp.lang.faq FAQ, question 12.21 : How can I tell how much // destination buffer space I'll need for an arbitrary sprintf call? How can // I avoid overflowing the destination buffer with sprintf? static char * var_itoa(void * buff, int num_byte) { char * retbuf; // We double the recommended value since we also have to deal // with long integers. Pfff... retbuf = g_malloc(2 * ( (sizeof(int) * CHAR_BIT + 2) / 3 + 1 + 1)); switch (num_byte) { case 2: sprintf(retbuf, "%d", *((int*)buff)); break; case 4: sprintf(retbuf, "%dl", *((int*)buff)); break; default: sprintf(retbuf, "var_itoa?????"); } return retbuf; } /* ======================================================================= int _IdStrGetDicomTag(char * label, int *gr, int * num, char *vr) recherche le Dicom tag d'un libelle donne par inspection du Dictionnaire DICOM (retourne 0 si pas trouve) ======================================================================= */ static int _IdStrGetDcmTag (char* libelle, unsigned long *gr, unsigned long *num, char **vr) { DICOM_ELEMENTS *t; int i; t=_ID_dicom_elements; for (i=0; t[i].dicom_group != 0xffff; i++) { if( strcmp(t[i].dicom_libelle, libelle) ==0 ) { *gr= t[i].dicom_group; *num=t[i].dicom_elem; *vr =t[i].dicom_type; return(1); } } return(0); } /** * \ingroup dcm * \brief Tente de lire un dicom_element a partir de son libelle. Le * resultat est range dans buff. * @param libelle Libelle de l'acr_element a lire. Il s'agit du dernier * champ de la variable globale _ID_dicom_elements, tel que * "Group Length", "Priority" ou encore "AE Title". * @param e ID_DCM_HDR dans lequel effectuer la recherche. * @param vr DICOM_VR (cf la variable globale _ID_dicom_vr) retourne', * pour permettre a l'appelant d'interpreter le contenu de buff. * @param buff Ou placer l'acr_element en cas de succes. Si NULL, * l'allocation est faite localement. * @return En cas de succes, le contenu de l'acr_element lu. Null * en cas d'echec. */ char * _IdDcmReadElementFromLabel(char *libelle, ID_DCM_HDR *e, char * vr, void *buff) { int i; unsigned long gr; unsigned long num; char * caster; i = _IdStrGetDcmTag (libelle, &gr, &num, &vr); if (i == 0) { if (DEBUG) printf("champ [%s] pas trouve\n",libelle); caster = g_malloc(4); sprintf(caster, "???"); return (caster); //return (NULL); } buff = _IdDcmReadElement(gr, num, e); if (buff == 0) { caster = g_malloc(4); sprintf(caster, "???"); return (caster); } if ( (strcmp(vr,"UL") != 0) && (strcmp(vr,"US") != 0) && (strcmp(vr,"SL") != 0) && (strcmp(vr,"SS") != 0) && (gr != 0x0028 || ( num != 0x0005 && num != 0x0200) ) ) { // les champs de vr RET sont des caract // sauf (28,5) et (28,200) Pixel Location return((void *) strdup(buff)); } if ( (strcmp(vr, "US") == 0) || (strcmp(vr, "SS") == 0) || (gr == 0x0028 && (num == 0x0005 || num == 0x0200) ) ) { // les champs de vr RET sont des caract // sauf (28,5) et (28,200) Pixel Location // Buff should contain an int16 caster = var_itoa(buff, 2); return(caster); } if ( (strcmp(vr,"UL") == 0) || (strcmp(vr,"SL") == 0) ) { // Buff should contain a guint32 caster = var_itoa(buff, 2); return(caster); } if (DEBUG) printf("impossible de passer ici, mais le compilo rale\n"); return (NULL); } // /* ============================================================================= */ // /* ----------------------------------------------------------------------- */ static void _IdImprimerElement(char **TableauImageInfo, int numGroupe, int numElem, char *nomElem, int position) { if (!TableauImageInfo[position]) printf("%d : %s \t(%04x,%04x) pas trouve \n", position, nomElem, numGroupe, numElem); else printf("%d : %s \t(%04x,%04x)\t[%s]\n", position, nomElem, numGroupe, numElem, TableauImageInfo[position]); } /* ----------------------------------------------------------------------- */ /** * \ingroup dcm * \brief imprime la description des info 'pertinentes' d'une image DICOM * obtenue par IdDcmInquireImageInfoFromXXX (File/DcmHdr) * * @param TableauImageInfo Tableau des info. * * Pour avoir la liste a jour des DICOM Elements renvoyes par IdDcmInquireImageInfo * Consultez le fichier src/dicom.c * * @return 1 : OK * 0 : pointeur sur Tableau NULL */ int IdDcmPrintImageInfo(char **TableauImageInfo) { int k; DICOM_INFO *t; t = _ID_dicom_info; if (!TableauImageInfo) return(0); for(k=0;k<_ID_Number_of_Items;k++) { _IdImprimerElement(TableauImageInfo, t[k].dicom_group, t[k].dicom_elem, t[k].dicom_info_libelle, t[k].dicom_info_ind); } return (1); } /* ----------------------------------------------------------------------- */ void IdDcmAffDcmHdr(ID_DCM_HDR *e, int npriv, int noffset) { DICOM_ELEMENTS *t = NULL; PLIST pl; PLIST_ELEMENT plelem; _ID_DCM_ELEM *ple; /* MANQUE le retrait, avant impression en %s, des caract non ASCII */ pl=e->plist; plelem = IdLstFirst(pl); while (plelem) { ple= IdLstPtrObj(plelem); // le _ID_DCM_ELEM pointé par le PLIST_ELEMENT if (ple->Num==0) { if(!npriv) printf("\n"); } else { for (t=_ID_dicom_elements; t->dicom_group!=0xffff; t++) { if( (t->dicom_group==ple->Gr) && (t->dicom_elem==ple->Num) ) break; } } if(!(ple->Gr%2) || !npriv) { if (noffset) printf(" gr %04x num %04x long %d", ple->Gr, ple->Num, ple->LgrLueElem); else printf(" gr %04x num %04x long %d _offset %d", ple->Gr, ple->Num, ple->LgrLueElem, ple->Offset); } if (ple->Num!=0) { if(ple->VR == NULL) { if(!(ple->Gr%2) || !npriv) printf("\t%s\t%s\t\t", t->dicom_type, t->dicom_libelle); } else { if(!(ple->Gr%2) || !npriv) printf("\t%s\t%s\t\t", ple->VR, t->dicom_libelle); } } if (ple->Num==0) { if(!(ple->Gr%2) || !npriv){ printf(" lgr du grp = %d\n -------\n", str2num(ple->valeurElem,int) ); } } else { switch (ple->LgrElem) { case 2: // LGR = 2 if ( (strcmp(t->dicom_type, "US") == 0) || (strcmp(t->dicom_type, "SS") == 0) || (t->dicom_group == 0x0028 && ( t->dicom_elem == 0x0005 || t->dicom_elem == 0x0200) ) ) { if(!(ple->Gr%2) || !npriv) { printf("\t \t \t %d \tx(%04x)\n", str2num(ple->valeurElem,unsigned short int), str2num(ple->valeurElem,unsigned short int) ); } } else { if(!(ple->Gr%2) || !npriv){ printf("\t[%s] \t %d \tx(%04x)\n", ple->valeurElem, str2num(ple->valeurElem,unsigned short int), str2num(ple->valeurElem,unsigned short int)); } } break; case 4 : // LGR = 4 if ( (strcmp(t->dicom_type,"UL") == 0) || (strcmp(t->dicom_type,"SL") == 0) ) { if(!(ple->Gr%2) || !npriv) { printf("\t \t \t %d \tx(%08x)\n", str2num(ple->valeurElem,int), str2num(ple->valeurElem,int)); } } else { if(!(ple->Gr%2) || !npriv) { printf("\t[%s] \t %d \tx(%08x)\n", ple->valeurElem, str2num(ple->valeurElem,int), str2num(ple->valeurElem,int)); } } break; default : // AUTRES LGR if (ple->LgrElem > 5000) { if(!(ple->Gr%2) || !npriv) printf(" --> Too Long. Not Printed...\n"); } else { if(!(ple->Gr%2) || !npriv) printf(" \t[%s]\n",ple->valeurElem); } } } plelem = IdLstNext(plelem); } } // ----------------------------------------------------------------------------------------------- /** * \ingroup dcm * \brief Verifie le caractère Acr/Dcm/LibIdo d'un fichier. * * @param filename Nom du Fichier * @return ID_DCM_HDR (ca sera fait pour plus tard) si lisible * O sinon. * */ ID_DCM_HDR * IdDcmIsDcmReadable(char * filename) { return IdDcmReadFile(filename, 0xFFFF); } // ---------------------------------------------------------------------------------------------- /** * \ingroup dcm * \brief Verifie le caractère Jpeg Lossless d'un fichier, a partir du DCM_HDR. * * @param e ID_DCM_HDR deja cree * @return 1 si Jpeg Losless * O sinon. * */ int IdDcmIsJpegLossless (ID_DCM_HDR * e) { char * Derivation_Description; char * Transfert_Syntax_UID; char * valeur = "Compress BN JPEG Lossless"; if (!e) return (0); Transfert_Syntax_UID = _IdDcmReadElement(0x0002, 0x0010, e); if (Transfert_Syntax_UID != NULL) { if ( (memcmp(Transfert_Syntax_UID + strlen(Transfert_Syntax_UID)-2, "70", 2) == 0) || (memcmp(Transfert_Syntax_UID + strlen(Transfert_Syntax_UID)-2, "55", 2) == 0) ) { return (1); } else { Derivation_Description = _IdDcmReadElement(0x0008, 0x2111, e); if (Derivation_Description != NULL) { if (memcmp (Derivation_Description, valeur, strlen(valeur)) == 0) return (1); } } } return (0); }