5 #include "jpeg/ljpg/jpegless.h"
7 /////////////////////////////////////////////////////////////////
10 * \brief Constructor dedicated to writing a new DICOMV3 part10 compliant
11 * file (see SetFileName, SetDcmTag and Write)
12 * Opens (in read only and when possible) an existing file and checks
13 * for DICOM compliance. Returns NULL on failure.
14 * \Note the in-memory representation of all available tags found in
15 * the DICOM header is post-poned to first header information access.
16 * This avoid a double parsing of public part of the header when
17 * one sets an a posteriori shadow dictionary (efficiency can be
18 * seen as a side effect).
20 * @param header file to be opened for reading datas
25 gdcmFile::gdcmFile(gdcmHeader *header)
30 if (Header->IsReadable())
31 SetPixelDataSizeFromHeader();
34 /////////////////////////////////////////////////////////////////
37 * \brief Constructor dedicated to writing a new DICOMV3 part10 compliant
38 * file (see SetFileName, SetDcmTag and Write)
39 * Opens (in read only and when possible) an existing file and checks
40 * for DICOM compliance. Returns NULL on failure.
41 * \Note the in-memory representation of all available tags found in
42 * the DICOM header is post-poned to first header information access.
43 * This avoid a double parsing of public part of the header when
44 * one sets an a posteriori shadow dictionary (efficiency can be
45 * seen as a side effect).
47 * @param filename file to be opened for parsing
51 gdcmFile::gdcmFile(std::string & filename)
53 Header=new gdcmHeader(filename.c_str());
56 if (Header->IsReadable())
57 SetPixelDataSizeFromHeader();
60 gdcmFile::gdcmFile(const char * filename)
62 Header=new gdcmHeader(filename);
65 if (Header->IsReadable())
66 SetPixelDataSizeFromHeader();
69 /////////////////////////////////////////////////////////////////
72 * \brief Destructor dedicated to writing a new DICOMV3 part10 compliant
73 * file (see SetFileName, SetDcmTag and Write)
74 * Opens (in read only and when possible) an existing file and checks
75 * for DICOM compliance. Returns NULL on failure.
76 * \Note If the gdcmHeader is created by the gdcmFile, it is destroyed
80 gdcmFile::~gdcmFile(void)
93 gdcmHeader *gdcmFile::GetHeader(void)
100 * \brief calcule la longueur (in bytes) A ALLOUER pour recevoir les
101 * pixels de l'image ou DES images dans le cas d'un multiframe
103 * ATTENTION : il ne s'agit PAS de la longueur du groupe des Pixels
104 * (dans le cas d'images compressees, elle n'a pas de sens).
106 * @return longueur a allouer
108 void gdcmFile::SetPixelDataSizeFromHeader(void) {
111 str_nb=Header->GetPubElValByNumber(0x0028,0x0100);
112 if (str_nb == GDCM_UNFOUND ) {
115 nb = atoi(str_nb.c_str() );
116 if (nb == 12) nb =16;
118 lgrTotale = lgrTotaleRaw = Header->GetXSize() * Header->GetYSize()
119 * Header->GetZSize() * (nb/8)* Header->GetSamplesPerPixel();
120 std::string str_PhotometricInterpretation =
121 Header->GetPubElValByNumber(0x0028,0x0004);
123 /*if ( str_PhotometricInterpretation == "PALETTE COLOR " )*/
124 // pb when undealt Segmented Palette Color
126 if (Header->HasLUT()) {
131 // see PS 3.3-2003 : C.7.6.3.2.1
141 // YBR_FULL_422 (no LUT, no Palette)
147 // ex : gdcm-US-ALOKA-16.dcm
148 // 0028|1221 [OW] [Segmented Red Palette Color Lookup Table Data]
149 // 0028|1222 [OW] [Segmented Green Palette Color Lookup Table Data]
150 // 0028|1223 [OW] [Segmented Blue Palette Color Lookup Table Data]
152 // ex : OT-PAL-8-face.dcm
153 // 0028|1201 [US] [Red Palette Color Lookup Table Data]
154 // 0028|1202 [US] [Green Palette Color Lookup Table Data]
155 // 0028|1203 [US] [Blue Palette Color Lookup Table Data]
158 /////////////////////////////////////////////////////////////////
161 * \brief Returns the size (in bytes) of required memory to hold
162 * \ the pixel data represented in this file, when user DOESN'T want
163 * \ to get RGB pixels image when it's stored as a PALETTE COLOR image
164 * \ - the (vtk) user is supposed to know how deal with LUTs -
165 * \ warning to be used with GetImagePixelsRaw()
166 * @return The size of pixel data in bytes.
169 size_t gdcmFile::GetImageDataSizeRaw(void) {
170 return (lgrTotaleRaw);
173 /////////////////////////////////////////////////////////////////
176 * \brief Returns the size (in bytes) of required memory to hold
177 * the pixel data represented in this file.
178 * @return The size of pixel data in bytes.
181 size_t gdcmFile::GetImageDataSize(void) {
186 /////////////////////////////////////////////////////////////////
189 * \brief Read pixel data from disk (optionaly decompressing) into the
190 * caller specified memory location.
191 * @param destination where the pixel data should be stored.
194 bool gdcmFile::ReadPixelData(void* destination) {
198 if ( !(fp=Header->OpenFile()))
201 if ( fseek(fp, Header->GetPixelOffset(), SEEK_SET) == -1 ) {
207 // ---------------------- Compacted File (12 Bits Per Pixel)
209 /* unpack 12 Bits pixels into 16 Bits pixels */
210 /* 2 pixels 12bit = [0xABCDEF] */
211 /* 2 pixels 16bit = [0x0ABD] + [0x0FCE] */
213 if (Header->GetBitsAllocated()==12) {
214 int nbPixels = Header->GetXSize() * Header->GetYSize();
215 unsigned char b0, b1, b2;
217 unsigned short int* pdestination = (unsigned short int*)destination;
218 for(int p=0;p<nbPixels;p+=2) {
222 //Two steps is necessary to please VC++
223 *pdestination++ = ((b0 >> 4) << 8) + ((b0 & 0x0f) << 4) + (b1 & 0x0f);
224 /* A */ /* B */ /* D */
225 *pdestination++ = ((b2 & 0x0f) << 8) + ((b1 >> 4) << 4) + (b2 >> 4);
226 /* F */ /* C */ /* E */
228 // Troubles expected on Big-Endian processors ?
233 // ---------------------- Uncompressed File
235 if ( !Header->IsDicomV3() ||
236 Header->IsImplicitVRLittleEndianTransferSyntax() ||
237 Header->IsExplicitVRLittleEndianTransferSyntax() ||
238 Header->IsExplicitVRBigEndianTransferSyntax() ||
239 Header->IsDeflatedExplicitVRLittleEndianTransferSyntax() ) {
241 size_t ItemRead = fread(destination, Header->GetPixelAreaLength(), 1, fp);
243 if ( ItemRead != 1 ) {
252 // ---------------------- Run Length Encoding
254 if (Header->IsRLELossLessTransferSyntax()) {
255 bool res = (bool)gdcm_read_RLE_file (fp,destination);
259 // --------------- SingleFrame/Multiframe JPEG Lossless/Lossy/2000
262 std::string str_nb=Header->GetPubElValByNumber(0x0028,0x0100);
263 if (str_nb == GDCM_UNFOUND ) {
266 nb = atoi(str_nb.c_str() );
267 if (nb == 12) nb =16; // ?? 12 should be ACR-NEMA only ?
272 int taille = Header->GetXSize() * Header->GetYSize()
273 * Header->GetSamplesPerPixel();
274 long fragmentBegining; // for ftell, fseek
276 bool jpg2000 = Header->IsJPEG2000();
277 bool jpgLossless = Header->IsJPEGLossless();
280 guint16 ItemTagGr,ItemTagEl;
283 // Position on begining of Jpeg Pixels
285 fread(&ItemTagGr,2,1,fp); // Reading (fffe) : Item Tag Gr
286 fread(&ItemTagEl,2,1,fp); // Reading (e000) : Item Tag El
287 if(Header->GetSwapCode()) {
288 ItemTagGr=Header->SwapShort(ItemTagGr);
289 ItemTagEl=Header->SwapShort(ItemTagEl);
292 if(Header->GetSwapCode())
293 ln=Header->SwapLong(ln); // Basic Offset Table Item length
296 // What is it used for ?!?
297 char *BasicOffsetTableItemValue = (char *)malloc(ln+1);
298 fread(BasicOffsetTableItemValue,ln,1,fp);
301 // first Fragment initialisation
302 fread(&ItemTagGr,2,1,fp); // Reading (fffe) : Item Tag Gr
303 fread(&ItemTagEl,2,1,fp); // Reading (e000) : Item Tag El
304 if(Header->GetSwapCode()) {
305 ItemTagGr=Header->SwapShort(ItemTagGr);
306 ItemTagEl=Header->SwapShort(ItemTagEl);
309 // parsing fragments until Sequence Delim. Tag found
311 while ( ( ItemTagGr == 0xfffe) && (ItemTagEl != 0xe0dd) ) {
312 // --- for each Fragment
315 if(Header->GetSwapCode())
316 ln=Header->SwapLong(ln); // Fragment Item length
318 fragmentBegining=ftell(fp);
320 if (jpg2000) { // JPEG 2000 : call to ???
322 res = (bool)gdcm_read_JPEG2000_file (fp,destination); // Not Yet written
324 } // ------------------------------------- endif (JPEG2000)
326 else if (jpgLossless) { // JPEG LossLess : call to xmedcom JPEG
328 JPEGLosslessDecodeImage (fp, // Reading Fragment pixels
329 (unsigned short *)destination,
330 Header->GetPixelSize()*8* Header->GetSamplesPerPixel(),
332 res=1; // in order not to break the loop
334 } // ------------------------------------- endif (JPEGLossless)
336 else { // JPEG Lossy : call to IJG 6b
338 if (Header->GetBitsStored() == 8) {
339 res = (bool)gdcm_read_JPEG_file (fp,destination); // Reading Fragment pixels
341 res = (bool)gdcm_read_JPEG_file12 (fp,destination);// Reading Fragment pixels
343 } // ------------------------------------- endif (JPEGLossy)
347 destination = (char *)destination + taille * nBytes; // location in user's memory
348 // for next fragment (if any)
350 fseek(fp,fragmentBegining,SEEK_SET); // To be sure we start
351 fseek(fp,ln,SEEK_CUR); // at the begining of next fragment
353 ItemTagGr = ItemTagEl =0;
354 fread(&ItemTagGr,2,1,fp); // Reading (fffe) : Item Tag Gr
355 fread(&ItemTagEl,2,1,fp); // Reading (e000) : Item Tag El
356 if(Header->GetSwapCode()) {
357 ItemTagGr=Header->SwapShort(ItemTagGr);
358 ItemTagEl=Header->SwapShort(ItemTagEl);
361 } // endWhile parsing fragments until Sequence Delim. Tag found
369 * \brief Allocates necessary memory, copies the pixel data
370 * (image[s]/volume[s]) to newly allocated zone.
371 * Transforms YBR pixels into RGB pixels if any
372 Transforms 3 planes R, G, B into a single RGB Plane
373 Transforms single Grey plane + 3 Palettes into a RGB Plane
374 * @return Pointer to newly allocated pixel data.
375 * \ NULL if alloc fails
377 void * gdcmFile::GetImageData (void) {
378 PixelData = (void *) malloc(lgrTotale);
380 GetImageDataIntoVector(PixelData, lgrTotale);
386 * \brief Allocates necessary memory, copies the pixel data
387 * (image[s]/volume[s]) to newly allocated zone.
388 * Transforms YBR pixels into RGB pixels if any
389 Transforms 3 planes R, G, B into a single RGB Plane
390 DOES NOT transform Grey plane + 3 Palettes into a RGB Plane
391 * @return Pointer to newly allocated pixel data.
392 * \ NULL if alloc fails
394 void * gdcmFile::GetImageDataRaw (void) {
395 if (Header->HasLUT())
396 lgrTotale /= 3; // TODO Let gdcmHeadar user a chance
397 // to get the right value
398 // Create a member lgrTotaleRaw ???
399 PixelData = (void *) malloc(lgrTotale);
401 GetImageDataIntoVectorRaw(PixelData, lgrTotale);
407 * \brief Copies at most MaxSize bytes of pixel data to caller's
409 * \warning This function was designed to avoid people that want to build
410 * a volume from an image stack to need first to get the image pixels
411 * and then move them to the volume area.
412 * It's absolutely useless for any VTK user since vtk chooses
413 * to invert the lines of an image, that is the last line comes first
414 * (for some axis related reasons?). Hence he will have
415 * to load the image line by line, starting from the end.
416 * VTK users have to call GetImageData
418 * @param destination Address (in caller's memory space) at which the
419 * pixel data should be copied
420 * @param MaxSize Maximum number of bytes to be copied. When MaxSize
421 * is not sufficient to hold the pixel data the copy is not
422 * executed (i.e. no partial copy).
423 * @return On success, the number of bytes actually copied. Zero on
424 * failure e.g. MaxSize is lower than necessary.
427 size_t gdcmFile::GetImageDataIntoVector (void* destination, size_t MaxSize) {
429 size_t l = GetImageDataIntoVectorRaw (destination, MaxSize);
431 if (!Header->HasLUT())
434 // from Lut R + Lut G + Lut B
436 unsigned char * newDest = (unsigned char *)malloc(lgrTotale);
437 unsigned char * a = (unsigned char *)destination;
438 unsigned char * lutRGBA = Header->GetLUTRGBA();
440 int l = lgrTotaleRaw;
441 memmove(newDest, destination, l);// move Gray pixels to temp area
443 for (int i=0;i<l; i++) { // Build RGB Pixels
451 // now, it's an RGB image
452 // Lets's write it in the Header
454 // CreateOrReplaceIfExist ?
456 std::string spp = "3"; // Samples Per Pixel
457 Header->SetPubElValByNumber(spp,0x0028,0x0002);
458 std::string rgb= "RGB "; // Photometric Interpretation
459 Header->SetPubElValByNumber(rgb,0x0028,0x0004);
460 std::string planConfig = "0"; // Planar Configuration
461 Header->SetPubElValByNumber(planConfig,0x0028,0x0006);
465 // need to make RGB Pixels (?)
466 // from grey Pixels (?!)
467 // and Gray Lut (!?!)
468 // or Segmented xxx Palette Color Lookup Table Data and so on
470 // Well . I'll wait till I find such an image
472 // Oops! I get one (gdcm-US-ALOKA-16.dcm)
473 // No idea how to manage it
474 // It seems that *no Dicom Viewer* has any idea :-(
475 // Segmented xxx Palette Color are *more* than 65535 long ?!?
477 std::string rgb= "MONOCHROME1 "; // Photometric Interpretation
478 Header->SetPubElValByNumber(rgb,0x0028,0x0004);
482 // TODO : Drop Palette Color out of the Header?
490 * \brief Copies at most MaxSize bytes of pixel data to caller's
492 * \warning This function was designed to avoid people that want to build
493 * a volume from an image stack to need first to get the image pixels
494 * and then move them to the volume area.
495 * It's absolutely useless for any VTK user since vtk chooses
496 * to invert the lines of an image, that is the last line comes first
497 * (for some axis related reasons?). Hence he will have
498 * to load the image line by line, starting from the end.
499 * VTK users hace to call GetImageData
500 * \warning DOES NOT transform the Grey Plane + Palette Color (if any)
501 * into a single RGB Pixels Plane
502 * the (VTK) user will manage the palettes
504 * @param destination Address (in caller's memory space) at which the
505 * pixel data should be copied
506 * @param MaxSize Maximum number of bytes to be copied. When MaxSize
507 * is not sufficient to hold the pixel data the copy is not
508 * executed (i.e. no partial copy).
509 * @return On success, the number of bytes actually copied. Zero on
510 * failure e.g. MaxSize is lower than necessary.
513 size_t gdcmFile::GetImageDataIntoVectorRaw (void* destination, size_t MaxSize) {
515 int nb, nbu, highBit, signe;
516 std::string str_nbFrames, str_nb, str_nbu, str_highBit, str_signe;
518 if ( lgrTotale > MaxSize ) {
519 dbg.Verbose(0, "gdcmFile::GetImageDataIntoVector: pixel data bigger"
520 "than caller's expected MaxSize");
524 (void)ReadPixelData(destination);
526 // Nombre de Bits Alloues pour le stockage d'un Pixel
527 str_nb = Header->GetPubElValByNumber(0x0028,0x0100);
528 if (str_nb == GDCM_UNFOUND ) {
531 nb = atoi(str_nb.c_str() );
534 // Nombre de Bits Utilises
535 str_nbu=Header->GetPubElValByNumber(0x0028,0x0101);
536 if (str_nbu == GDCM_UNFOUND ) {
539 nbu = atoi(str_nbu.c_str() );
542 // Position du Bit de Poids Fort
543 str_highBit=Header->GetPubElValByNumber(0x0028,0x0102);
544 if (str_highBit == GDCM_UNFOUND ) {
547 highBit = atoi(str_highBit.c_str() );
552 str_signe=Header->GetPubElValByNumber(0x0028,0x0103);
553 if (str_signe == GDCM_UNFOUND ) {
554 signe = 0; // default is unsigned
556 signe = atoi(str_signe.c_str() );
559 // re arange bytes inside the integer
561 SwapZone(destination, Header->GetSwapCode(), lgrTotale, nb);
563 // to avoid pb with some xmedcon breakers images
564 if (nb==16 && nbu<nb && signe==0) {
565 int l = (int)lgrTotale / (nb/8);
566 guint16 *deb = (guint16 *)destination;
567 for(int i = 0; i<l; i++) {
574 // re arange bits inside the bytes
576 int l = (int)lgrTotale / (nb/8);
578 guint16 mask = 0xffff;
579 mask = mask >> (nb-nbu);
580 guint16 *deb = (guint16 *)destination;
581 for(int i = 0; i<l; i++) {
582 *deb = (*deb >> (nbu-highBit-1)) & mask;
585 } else if (nb == 32 ) {
586 guint32 mask = 0xffffffff;
587 mask = mask >> (nb-nbu);
588 guint32 *deb = (guint32 *)destination;
589 for(int i = 0; i<l; i++) {
590 *deb = (*deb >> (nbu-highBit-1)) & mask;
594 dbg.Verbose(0, "gdcmFile::GetImageDataIntoVector: wierd image");
599 // Just to 'see' what was actually read on disk :-(
600 // Some troubles expected
602 // f2 = fopen("SpuriousFile.raw","wb");
603 // fwrite(destination,lgrTotale,1,f2);
606 // Deal with the color
607 // -------------------
609 std::string str_PhotometricInterpretation =
610 Header->GetPubElValByNumber(0x0028,0x0004);
612 if ( (str_PhotometricInterpretation == "MONOCHROME1 ")
613 || (str_PhotometricInterpretation == "MONOCHROME2 ") ) {
617 // Planar configuration = 0 : Pixels are already RGB
618 // Planar configuration = 1 : 3 planes : R, G, B
619 // Planar configuration = 2 : 1 gray Plane + 3 LUT
621 // Well ... supposed to be !
622 // See US-PAL-8-10x-echo.dcm: PlanarConfiguration=0,
623 // PhotometricInterpretation=PALETTE COLOR
624 // and heuristic has to be found :-(
626 int planConf=Header->GetPlanarConfiguration(); // 0028,0006
628 // Whatever Planar Configuration is,
629 // "PALETTE COLOR " implies that we deal with the palette.
630 if (str_PhotometricInterpretation == "PALETTE COLOR ")
635 // Pixels are already RGB
641 if (str_PhotometricInterpretation == "YBR_FULL") {
643 // Warning : YBR_FULL_422 acts as RGB
644 // : we need to make RGB Pixels from Planes Y,cB,cR
645 // see http://lestourtereaux.free.fr/papers/data/yuvrgb.pdf
646 // for code optimisation
648 // to see the tricks about YBR_FULL, YBR_FULL_422,
649 // YBR_PARTIAL_422, YBR_ICT, YBR_RCT have a look at :
650 // ftp://medical.nema.org/medical/dicom/final/sup61_ft.pdf
651 // and be *very* affraid
653 int l = Header->GetXSize()*Header->GetYSize();
654 int nbFrames = Header->GetZSize();
656 unsigned char * newDest = (unsigned char*) malloc(lgrTotale);
657 unsigned char *x = newDest;
658 unsigned char * a = (unsigned char *)destination;
659 unsigned char * b = a + l;
660 unsigned char * c = b + l;
664 // TODO : Replace by the 'well known'
665 // integer computation counterpart
666 for (int i=0;i<nbFrames;i++) {
667 for (int j=0;j<l; j++) {
668 R= 1.164 *(*a-16) + 1.596 *(*c -128) + 0.5;
669 G= 1.164 *(*a-16) - 0.813 *(*c -128) - 0.392 *(*b -128) + 0.5;
670 B= 1.164 *(*a-16) + 2.017 *(*b -128) + 0.5;
675 if (R>255.0) R=255.0;
676 if (G>255.0) G=255.0;
677 if (B>255.0) B=255.0;
679 *(x++) = (unsigned char)R;
680 *(x++) = (unsigned char)G;
681 *(x++) = (unsigned char)B;
685 memmove(destination,newDest,lgrTotale);
690 // need to make RGB Pixels from R,G,B Planes
691 // (all the Frames at a time)
693 int l = Header->GetXSize()*Header->GetYSize()*Header->GetZSize();
695 char * newDest = (char*) malloc(lgrTotale);
697 char * a = (char *)destination;
701 for (int j=0;j<l; j++) {
707 memmove(destination,newDest,lgrTotale);
715 // Palettes were found
716 // Let the user deal with them !
719 // now, it's an RGB image
720 // Lets's write it in the Header
722 // CreateOrReplaceIfExist ?
726 std::string spp = "3"; // Samples Per Pixel
727 Header->SetPubElValByNumber(spp,0x0028,0x0002);
728 std::string rgb="RGB "; // Photometric Interpretation
729 Header->SetPubElValByNumber(rgb,0x0028,0x0004);
731 std::string planConfig = "0"; // Planar Configuration
732 Header->SetPubElValByNumber(planConfig,0x0028,0x0006);
734 // TODO : Drop Palette Color out of the Header?
743 * \brief Swap the bytes, according to swap code.
744 * \warning not end user intended
745 * @param im area to deal with
746 * @param swap swap code
747 * @param lgr Area Length
748 * @param nb Pixels Bit number
751 void gdcmFile::SwapZone(void* im, int swap, int lgr, int nb) {
769 ((unsigned short int*)im)[i]= ((((unsigned short int*)im)[i])>>8)
770 | ((((unsigned short int*)im)[i])<<8);
774 printf("valeur de SWAP (16 bits) not allowed : %d\n", swap);
785 faible= ((unsigned long int*)im)[i]&0x0000ffff; /* 4321 */
786 fort =((unsigned long int*)im)[i]>>16;
787 fort= (fort>>8) | (fort<<8);
788 faible=(faible>>8) | (faible<<8);
790 ((unsigned long int*)im)[i]=(s32<<16)|fort;
796 faible= ((unsigned long int*)im)[i]&0x0000ffff; /* 2143 */
797 fort=((unsigned long int*)im)[i]>>16;
798 fort= (fort>>8) | (fort<<8);
799 faible=(faible>>8) | (faible<<8);
801 ((unsigned long int*)im)[i]=(s32<<16)|faible;
807 faible= ((unsigned long int*)im)[i]&0x0000ffff; /* 3412 */
808 fort=((unsigned long int*)im)[i]>>16;
810 ((unsigned long int*)im)[i]=(s32<<16)|fort;
815 printf(" SWAP value (32 bits) not allowed : %d\n", swap);
820 /////////////////////////////////////////////////////////////////
824 * \warning doit-etre etre publique ?
825 * TODO : y a-t-il un inconvenient à fusioner ces 2 fonctions
828 * @param ExpectedSize
830 * @return integer acts as a boolean
832 bool gdcmFile::SetImageData(void * inData, size_t ExpectedSize) {
833 Header->SetImageDataSize(ExpectedSize);
835 lgrTotale = ExpectedSize;
840 /////////////////////////////////////////////////////////////////
843 * \brief Ecrit sur disque les pixels d'UNE image
844 * Aucun test n'est fait sur l'"Endiannerie" du processeur.
845 * Ca sera à l'utilisateur d'appeler son Reader correctement
846 * (Equivalent a IdImaWriteRawFile)
852 bool gdcmFile::WriteRawData (std::string fileName) {
854 fp1 = fopen(fileName.c_str(),"wb");
856 printf("Echec ouverture (ecriture) Fichier [%s] \n",fileName.c_str());
859 fwrite (PixelData,lgrTotale, 1, fp1);
864 /////////////////////////////////////////////////////////////////
867 * \brief Ecrit sur disque UNE image Dicom
868 * Aucun test n'est fait sur l'"Endiannerie" du processeur.
869 * Ca fonctionnera correctement (?) sur processeur Intel
870 * (Equivalent a IdDcmWrite)
873 * @return int acts as a boolean
876 bool gdcmFile::WriteDcmImplVR (std::string fileName) {
877 return WriteBase(fileName, ImplicitVR);
880 /////////////////////////////////////////////////////////////////
885 * @return int acts as a boolean
888 bool gdcmFile::WriteDcmImplVR (const char* fileName) {
889 return WriteDcmImplVR (std::string (fileName));
892 /////////////////////////////////////////////////////////////////
897 * @return int acts as a boolean
900 bool gdcmFile::WriteDcmExplVR (std::string fileName) {
901 return WriteBase(fileName, ExplicitVR);
904 /////////////////////////////////////////////////////////////////
907 * \brief Ecrit au format ACR-NEMA sur disque l'entete et les pixels
908 * (a l'attention des logiciels cliniques
909 * qui ne prennent en entrée QUE des images ACR ...
910 * \warning si un header DICOM est fourni en entree,
911 * les groupes < 0x0008 et les groupes impairs sont ignores)
912 * \warning Aucun test n'est fait sur l'"Endiannerie" du processeur.
913 * Ca fonctionnera correctement (?) sur processeur Intel
914 * (Equivalent a IdDcmWrite)
917 * @return int acts as a boolean
920 bool gdcmFile::WriteAcr (std::string fileName) {
921 return WriteBase(fileName, ACR);
924 /////////////////////////////////////////////////////////////////
931 * @return int acts as a boolean
933 bool gdcmFile::WriteBase (std::string FileName, FileType type) {
936 fp1 = fopen(FileName.c_str(),"wb");
938 printf("Echec ouverture (ecriture) Fichier [%s] \n",FileName.c_str());
942 if ( (type == ImplicitVR) || (type == ExplicitVR) ) {
944 // writing Dicom File Preamble
945 filePreamble=(char*)calloc(128,1);
946 fwrite(filePreamble,128,1,fp1);
947 fwrite("DICM",4,1,fp1);
950 // --------------------------------------------------------------
951 // Special Patch to allow gdcm to re-write ACR-LibIDO formated images
953 // if recognition code tells us we dealt with a LibIDO image
954 // we reproduce on disk the switch between lineNumber and columnNumber
955 // just before writting ...
957 std::string rows, columns;
958 if ( Header->GetFileType() == ACR_LIBIDO){
959 rows = Header->GetPubElValByNumber(0x0028, 0x0010);
960 columns = Header->GetPubElValByNumber(0x0028, 0x0011);
961 Header->SetPubElValByNumber(columns, 0x0028, 0x0010);
962 Header->SetPubElValByNumber(rows , 0x0028, 0x0011);
964 // ----------------- End of Special Patch ----------------
966 Header->Write(fp1, type);
968 // --------------------------------------------------------------
969 // Special Patch to allow gdcm to re-write ACR-LibIDO formated images
971 // ...and we restore the Header to be Dicom Compliant again
972 // just after writting
974 if (Header->GetFileType() == ACR_LIBIDO){
975 Header->SetPubElValByNumber(rows , 0x0028, 0x0010);
976 Header->SetPubElValByNumber(columns, 0x0028, 0x0011);
978 // ----------------- End of Special Patch ----------------
980 fwrite(PixelData, lgrTotale, 1, fp1);