-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;i<nbCode;i++) {
- if(memcmp(_ID_dicom_vr[i].dicom_VR,VR,(size_t)2)==0) {
- (e->pleCourant)->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
+/**
+ * \ingroup gdcmHeader
+ * \brief Retrieve the number of Bits Allocated
+ * (8, 12 -compacted ACR-NEMA files, 16, ...)
+ * @return The encountered number of Bits Allocated, 0 by default.
+ * 0 means the file is NOT USABLE. The caller has to check it !
+ */
+int gdcmHeader::GetBitsAllocated()
+{
+ std::string strSize = GetEntryByNumber(0x0028,0x0100);
+ if ( strSize == GDCM_UNFOUND )
+ {
+ dbg.Verbose(0, "gdcmHeader::GetBitsStored: this is supposed to be mandatory");
+ return 0; // It's supposed to be mandatory
+ // the caller will have to check
+ }
+ return atoi( strSize.c_str() );
+}
+
+/**
+ * \ingroup gdcmHeader
+ * \brief Retrieve the number of Samples Per Pixel
+ * (1 : gray level, 3 : RGB -1 or 3 Planes-)
+ * @return The encountered number of Samples Per Pixel, 1 by default.
+ * (Gray level Pixels)
+ */
+int gdcmHeader::GetSamplesPerPixel()
+{
+ std::string strSize = GetEntryByNumber(0x0028,0x0002);
+ if ( strSize == GDCM_UNFOUND )
+ {
+ dbg.Verbose(0, "gdcmHeader::GetBitsStored: this is supposed to be mandatory");
+ return 1; // Well, it's supposed to be mandatory ...
+ // but sometimes it's missing : *we* assume Gray pixels
+ }
+ return atoi( strSize.c_str() );
+}
+
+/**
+ * \ingroup gdcmHeader
+ * \brief Retrieve the Planar Configuration for RGB images
+ * (0 : RGB Pixels , 1 : R Plane + G Plane + B Plane)
+ * @return The encountered Planar Configuration, 0 by default.
+ */
+int gdcmHeader::GetPlanarConfiguration()
+{
+ std::string strSize = GetEntryByNumber(0x0028,0x0006);
+ if ( strSize == GDCM_UNFOUND )
+ {
+ return 0;
+ }
+ return atoi( strSize.c_str() );
+}
+
+/**
+ * \ingroup gdcmHeader
+ * \brief Return the size (in bytes) of a single pixel of data.
+ * @return The size in bytes of a single pixel of data; 0 by default
+ * 0 means the file is NOT USABLE; the caller will have to check
+ */
+int gdcmHeader::GetPixelSize()
+{
+ // 0028 0100 US IMG Bits Allocated
+ // (in order no to be messed up by old RGB images)
+ // if (gdcmHeader::GetEntryByNumber(0x0028,0x0100) == "24")
+ // return 3;
+
+ std::string pixelType = GetPixelType();
+ if ( pixelType == "8U" || pixelType == "8S" )
+ {
+ return 1;
+ }
+ if ( pixelType == "16U" || pixelType == "16S")
+ {
+ return 2;
+ }
+ if ( pixelType == "32U" || pixelType == "32S")
+ {
+ return 4;
+ }
+ if ( pixelType == "FD" )
+ {
+ return 8;
+ }
+ dbg.Verbose(0, "gdcmHeader::GetPixelSize: Unknown pixel type");
+ return 0;
+}
+
+/**
+ * \ingroup gdcmHeader
+ * \brief Build the Pixel Type of the image.
+ * Possible values are:
+ * - 8U unsigned 8 bit,
+ * - 8S signed 8 bit,
+ * - 16U unsigned 16 bit,
+ * - 16S signed 16 bit,
+ * - 32U unsigned 32 bit,
+ * - 32S signed 32 bit,
+ * - FD floating double 64 bits (Not kosher DICOM, but so usefull!)
+ * \warning 12 bit images appear as 16 bit.
+ * 24 bit images appear as 8 bit
+ * @return 0S if nothing found. NOT USABLE file. The caller has to check
+ */
+std::string gdcmHeader::GetPixelType()
+{
+ std::string bitsAlloc = GetEntryByNumber(0x0028, 0x0100); // Bits Allocated
+ if ( bitsAlloc == GDCM_UNFOUND )
+ {
+ dbg.Verbose(0, "gdcmHeader::GetPixelType: unfound Bits Allocated");
+ bitsAlloc = "16";
+ }
+
+ if ( bitsAlloc == "64" )
+ {
+ return "FD";
+ }
+ if ( bitsAlloc == "12" )
+ {
+ // It will be unpacked
+ bitsAlloc = "16";
+ }
+ else if ( bitsAlloc == "24" )
+ {
+ // (in order no to be messed up
+ bitsAlloc = "8"; // by old RGB images)
+ }
+
+ std::string sign = GetEntryByNumber(0x0028, 0x0103); // "Pixel Representation"
+
+ if (sign == GDCM_UNFOUND )
+ {
+ dbg.Verbose(0, "gdcmHeader::GetPixelType: unfound Pixel Representation");
+ bitsAlloc = "0";
+ }
+ if ( sign == "0" )
+ {
+ sign = "U";
+ }
+ else
+ {
+ sign = "S";
+ }
+ return bitsAlloc + sign;
+}
+
+
+/**
+ * \ingroup gdcmHeader
+ * \brief Recover the offset (from the beginning of the file)
+ * of *image* pixels (not *icone image* pixels, if any !)
+ * @return Pixel Offset
+ */
+size_t gdcmHeader::GetPixelOffset()
+{
+ gdcmDocEntry* pxlElement = GetDocEntryByNumber(GrPixel,NumPixel);
+ if ( pxlElement )
+ {
+ return pxlElement->GetOffset();
+ }
+ else
+ {
+#ifdef GDCM_DEBUG
+ std::cout << "Big trouble : Pixel Element ("
+ << std::hex << GrPixel<<","<< NumPixel<< ") NOT found"
+ << std::endl;
+#endif //GDCM_DEBUG
+ return 0;
+ }
+}
+
+// TODO : unify those two (previous one and next one)
+/**
+ * \ingroup gdcmHeader
+ * \brief Recover the pixel area length (in Bytes)
+ * @return Pixel Element Length, as stored in the header
+ * (NOT the memory space necessary to hold the Pixels
+ * -in case of embeded compressed image-)
+ * 0 : NOT USABLE file. The caller has to check.
+ */
+size_t gdcmHeader::GetPixelAreaLength()
+{
+ gdcmDocEntry* pxlElement = GetDocEntryByNumber(GrPixel,NumPixel);
+ if ( pxlElement )
+ {
+ return pxlElement->GetLength();
+ }
+ else
+ {
+#ifdef GDCM_DEBUG
+ std::cout << "Big trouble : Pixel Element ("
+ << std::hex << GrPixel<<","<< NumPixel<< ") NOT found"
+ << std::endl;
+#endif //GDCM_DEBUG
+ return 0;
+ }
+}
+
+/**
+ * \ingroup gdcmHeader
+ * \brief tells us if LUT are used
+ * \warning Right now, 'Segmented xxx Palette Color Lookup Table Data'
+ * are NOT considered as LUT, since nobody knows
+ * how to deal with them
+ * Please warn me if you know sbdy that *does* know ... jprx
+ * @return true if LUT Descriptors and LUT Tables were found
+ */
+bool gdcmHeader::HasLUT()
+{
+ // Check the presence of the LUT Descriptors, and LUT Tables
+ // LutDescriptorRed
+ if ( !GetDocEntryByNumber(0x0028,0x1101) )
+ {
+ return false;
+ }
+ // LutDescriptorGreen
+ if ( !GetDocEntryByNumber(0x0028,0x1102) )
+ {
+ return false;
+ }
+ // LutDescriptorBlue
+ if ( !GetDocEntryByNumber(0x0028,0x1103) )
+ {
+ return false;
+ }
+ // Red Palette Color Lookup Table Data
+ if ( !GetDocEntryByNumber(0x0028,0x1201) )
+ {
+ return false;
+ }
+ // Green Palette Color Lookup Table Data
+ if ( !GetDocEntryByNumber(0x0028,0x1202) )
+ {
+ return false;
+ }
+ // Blue Palette Color Lookup Table Data
+ if ( !GetDocEntryByNumber(0x0028,0x1203) )
+ {
+ return false;
+ }
+
+ // FIXME : (0x0028,0x3006) : LUT Data (CTX dependent)
+ // NOT taken into account, but we don't know how to use it ...
+ return true;
+}
+
+/**
+ * \ingroup gdcmHeader
+ * \brief gets the info from 0028,1101 : Lookup Table Desc-Red
+ * else 0
+ * @return Lookup Table number of Bits , 0 by default
+ * when (0028,0004),Photometric Interpretation = [PALETTE COLOR ]
+ * @ return bit number of each LUT item
+ */
+int gdcmHeader::GetLUTNbits()
+{
+ std::vector<std::string> tokens;
+ int lutNbits;
+
+ //Just hope Lookup Table Desc-Red = Lookup Table Desc-Red = Lookup Table Desc-Blue
+ // Consistency already checked in GetLUTLength
+ std::string lutDescription = GetEntryByNumber(0x0028,0x1101);
+ if ( lutDescription == GDCM_UNFOUND )
+ {
+ return 0;
+ }
+
+ tokens.clear(); // clean any previous value
+ Tokenize ( lutDescription, tokens, "\\" );
+ //LutLength=atoi(tokens[0].c_str());
+ //LutDepth=atoi(tokens[1].c_str());
+
+ lutNbits = atoi( tokens[2].c_str() );
+ tokens.clear();
+
+ return lutNbits;
+}
+
+/**
+ * \ingroup gdcmHeader
+ * \brief builts Red/Green/Blue/Alpha LUT from Header
+ * when (0028,0004),Photometric Interpretation = [PALETTE COLOR ]
+ * and (0028,1101),(0028,1102),(0028,1102)
+ * - xxx Palette Color Lookup Table Descriptor - are found
+ * and (0028,1201),(0028,1202),(0028,1202)
+ * - xxx Palette Color Lookup Table Data - are found
+ * \warning does NOT deal with :
+ * 0028 1100 Gray Lookup Table Descriptor (Retired)
+ * 0028 1221 Segmented Red Palette Color Lookup Table Data
+ * 0028 1222 Segmented Green Palette Color Lookup Table Data
+ * 0028 1223 Segmented Blue Palette Color Lookup Table Data
+ * no known Dicom reader deals with them :-(
+ * @return a RGBA Lookup Table
+ */
+uint8_t* gdcmHeader::GetLUTRGBA()
+{
+ // Not so easy : see
+ // http://www.barre.nom.fr/medical/dicom2/limitations.html#Color%20Lookup%20Tables
+
+// if Photometric Interpretation # PALETTE COLOR, no LUT to be done
+ if ( GetEntryByNumber(0x0028,0x0004) != "PALETTE COLOR " )
+ {
+ return NULL;
+ }
+
+ int lengthR, debR, nbitsR;
+ int lengthG, debG, nbitsG;
+ int lengthB, debB, nbitsB;
+
+ // Get info from Lut Descriptors
+ // (the 3 LUT descriptors may be different)
+ std::string lutDescriptionR = GetEntryByNumber(0x0028,0x1101);
+ if ( lutDescriptionR == GDCM_UNFOUND )
+ {
+ return NULL;
+ }
+
+ std::string lutDescriptionG = GetEntryByNumber(0x0028,0x1102);
+ if ( lutDescriptionG == GDCM_UNFOUND )
+ {
+ return NULL;
+ }
+
+ std::string lutDescriptionB = GetEntryByNumber(0x0028,0x1103);
+ if ( lutDescriptionB == GDCM_UNFOUND )
+ {
+ return NULL;
+ }
+
+ // lengthR: Red LUT length in Bytes
+ // debR: subscript of the first Lut Value
+ // nbitsR: Lut item size (in Bits)
+ int nbRead = sscanf( lutDescriptionR.c_str(), "%d\\%d\\%d",
+ &lengthR, &debR, &nbitsR );
+ if( nbRead != 3 )
+ {
+ dbg.Verbose(0, "gdcmHeader::GetLUTRGBA: trouble reading red LUT");
+ }
+
+ // lengthG: Green LUT length in Bytes
+ // debG: subscript of the first Lut Value
+ // nbitsG: Lut item size (in Bits)
+ nbRead = sscanf( lutDescriptionG.c_str(), "%d\\%d\\%d",
+ &lengthG, &debG, &nbitsG );
+ if( nbRead != 3 )
+ {
+ dbg.Verbose(0, "gdcmHeader::GetLUTRGBA: trouble reading green LUT");
+ }
+
+ // lengthB: Blue LUT length in Bytes
+ // debB: subscript of the first Lut Value
+ // nbitsB: Lut item size (in Bits)
+ nbRead = sscanf( lutDescriptionB.c_str(), "%d\\%d\\%d",
+ &lengthB, &debB, &nbitsB );
+ if( nbRead != 3 )
+ {
+ dbg.Verbose(0, "gdcmHeader::GetLUTRGBA: trouble reading blue LUT");
+ }
+
+ // Load LUTs into memory, (as they were stored on disk)
+ uint8_t* lutR = (uint8_t*) GetEntryVoidAreaByNumber(0x0028,0x1201);
+ uint8_t* lutG = (uint8_t*) GetEntryVoidAreaByNumber(0x0028,0x1202);
+ uint8_t* lutB = (uint8_t*) GetEntryVoidAreaByNumber(0x0028,0x1203);
+
+ if ( !lutR || !lutG || !lutB )
+ {
+ dbg.Verbose(0, "gdcmHeader::GetLUTRGBA: trouble with one of the LUT");
+ return NULL;
+ }
+ // forge the 4 * 8 Bits Red/Green/Blue/Alpha LUT
+
+ uint8_t* LUTRGBA = new uint8_t[1024]; // 256 * 4 (R, G, B, Alpha)
+ if ( !LUTRGBA )
+ {
+ return NULL;
+ }
+ memset(LUTRGBA, 0, 1024);
+
+ // Bits Allocated
+ int nb;
+ std::string str_nb = GetEntryByNumber(0x0028,0x0100);
+ if ( str_nb == GDCM_UNFOUND )
+ {
+ nb = 16;
+ }
+ else
+ {
+ nb = atoi( str_nb.c_str() );
+ }
+ int mult;
+
+ if ( nbitsR == 16 && nb == 8)
+ {
+ // when LUT item size is different than pixel size
+ mult = 2; // high byte must be = low byte
+ }
+ else
+ {
+ // See PS 3.3-2003 C.11.1.1.2 p 619
+ mult = 1;
+ }
+
+ // if we get a black image, let's just remove the '+1'
+ // from 'i*mult+1' and check again
+ // if it works, we shall have to check the 3 Palettes
+ // to see which byte is ==0 (first one, or second one)
+ // and fix the code
+ // We give up the checking to avoid some (useless ?)overhead
+ // (optimistic asumption)
+ uint8_t* a;
+ int i;
+
+ a = LUTRGBA + 0;
+ for( i=0; i < lengthR; ++i)
+ {
+ *a = lutR[i*mult+1];
+ a += 4;
+ }
+
+ a = LUTRGBA + 1;
+ for( i=0; i < lengthG; ++i)
+ {
+ *a = lutG[i*mult+1];
+ a += 4;
+ }
+
+ a = LUTRGBA + 2;
+ for(i=0; i < lengthB; ++i)
+ {
+ *a = lutB[i*mult+1];
+ a += 4;
+ }
+
+ a = LUTRGBA + 3;
+ for(i=0; i < 256; ++i)
+ {
+ *a = 1; // Alpha component
+ a += 4;
+ }
+ return LUTRGBA;
+}
+
+/**
+ * \brief Accesses the info from 0002,0010 : Transfert Syntax and gdcmTS
+ * else 1.
+ * @return The full Transfert Syntax Name (as opposed to Transfert Syntax UID)
+ */
+std::string gdcmHeader::GetTransfertSyntaxName()
+{
+ // use the gdcmTS (TS : Transfert Syntax)
+ std::string transfertSyntax = GetEntryByNumber(0x0002,0x0010);
+
+ if ( transfertSyntax == GDCM_NOTLOADED ) { // fusible
+ std::cout << "Transfert Syntax not loaded. " << std::endl
+ << "Better you increase MAX_SIZE_LOAD_ELEMENT_VALUE"
+ << std::endl;
+ return "Uncompressed ACR-NEMA";
+ }
+ if ( transfertSyntax == GDCM_UNFOUND )
+ {
+ dbg.Verbose(0, "gdcmHeader::GetTransfertSyntaxName:"
+ " unfound Transfert Syntax (0002,0010)");
+ return "Uncompressed ACR-NEMA";
+ }
+
+ while ( ! isdigit(transfertSyntax[transfertSyntax.length()-1]) )
+ {
+ transfertSyntax.erase(transfertSyntax.length()-1, 1);
+ }
+ // we do it only when we need it
+ gdcmTS* ts = gdcmGlobal::GetTS();
+ std::string tsName = ts->GetValue( transfertSyntax );
+
+ //delete ts; /// \todo Seg Fault when deleted ?!
+ return tsName;
+}
+
+/**
+ * \brief Sets the Pixel Area size in the Header
+ * --> not-for-rats function
+ * @param ImageDataSize new Pixel Area Size
+ * warning : nothing else is checked
+ */
+void gdcmHeader::SetImageDataSize(size_t ImageDataSize)
+{
+ char car[20];
+ sprintf(car,"%d",ImageDataSize);
+
+ gdcmDocEntry *a = GetDocEntryByNumber(GrPixel, NumPixel);
+ a->SetLength(ImageDataSize);
+
+ ImageDataSize += 8;
+ sprintf(car,"%d",ImageDataSize);
+
+ const std::string content1 = car;
+ SetEntryByNumber(content1, GrPixel, NumPixel);
+}
+
+//-----------------------------------------------------------------------------
+// Protected
+
+/**
+ * \brief anonymize a Header (removes Patient's personal info)
+ * (read the code to see which ones ...)
+ */
+bool gdcmHeader::AnonymizeHeader()
+{
+ // If exist, replace by spaces
+ SetEntryByNumber (" ",0x0010, 0x2154); // Telephone
+ SetEntryByNumber (" ",0x0010, 0x1040); // Adress
+ SetEntryByNumber (" ",0x0010, 0x0020); // Patient ID
+
+ gdcmDocEntry* patientNameHE = GetDocEntryByNumber (0x0010, 0x0010);