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
79 * @param filename file to be opened for parsing
83 gdcmFile::~gdcmFile(void)
96 gdcmHeader *gdcmFile::GetHeader(void)
103 * \brief calcule la longueur (in bytes) A ALLOUER pour recevoir les
104 * pixels de l'image ou DES images dans le cas d'un multiframe
106 * ATTENTION : il ne s'agit PAS de la longueur du groupe des Pixels
107 * (dans le cas d'images compressees, elle n'a pas de sens).
109 * @return longueur a allouer
111 void gdcmFile::SetPixelDataSizeFromHeader(void) {
114 str_nb=Header->GetPubElValByNumber(0x0028,0x0100);
115 if (str_nb == GDCM_UNFOUND ) {
118 nb = atoi(str_nb.c_str() );
119 if (nb == 12) nb =16;
121 lgrTotale = lgrTotaleRaw = Header->GetXSize() * Header->GetYSize()
122 * Header->GetZSize() * (nb/8)* Header->GetSamplesPerPixel();
123 std::string str_PhotometricInterpretation =
124 Header->GetPubElValByNumber(0x0028,0x0004);
126 /*if ( str_PhotometricInterpretation == "PALETTE COLOR " )*/
127 // pb when undealt Segmented Palette Color
129 if (Header->HasLUT()) {
134 // see PS 3.3-2003 : C.7.6.3.2.1
144 // YBR_FULL_422 (no LUT, no Palette)
150 // ex : gdcm-US-ALOKA-16.dcm
151 // 0028|1221 [OW] [Segmented Red Palette Color Lookup Table Data]
152 // 0028|1222 [OW] [Segmented Green Palette Color Lookup Table Data]
153 // 0028|1223 [OW] [Segmented Blue Palette Color Lookup Table Data]
155 // ex : OT-PAL-8-face.dcm
156 // 0028|1201 [US] [Red Palette Color Lookup Table Data]
157 // 0028|1202 [US] [Green Palette Color Lookup Table Data]
158 // 0028|1203 [US] [Blue Palette Color Lookup Table Data]
161 /////////////////////////////////////////////////////////////////
164 * \brief Returns the size (in bytes) of required memory to hold
165 * \ the pixel data represented in this file, when user DOESN'T want
166 * \ to get RGB pixels image when it's stored as a PALETTE COLOR image
167 * \ - the (vtk) user is supposed to know how deal with LUTs -
168 * \ warning to be used with GetImagePixelsRaw()
169 * @return The size of pixel data in bytes.
172 size_t gdcmFile::GetImageDataSizeRaw(void) {
173 return (lgrTotaleRaw);
176 /////////////////////////////////////////////////////////////////
179 * \brief Returns the size (in bytes) of required memory to hold
180 * the pixel data represented in this file.
181 * @return The size of pixel data in bytes.
184 size_t gdcmFile::GetImageDataSize(void) {
189 /////////////////////////////////////////////////////////////////
192 * \brief Read pixel data from disk (optionaly decompressing) into the
193 * caller specified memory location.
194 * @param destination where the pixel data should be stored.
197 bool gdcmFile::ReadPixelData(void* destination) {
201 if ( !(fp=Header->OpenFile()))
204 if ( fseek(fp, Header->GetPixelOffset(), SEEK_SET) == -1 ) {
210 // ---------------------- Compacted File (12 Bits Per Pixel)
212 /* unpack 12 Bits pixels into 16 Bits pixels */
213 /* 2 pixels 12bit = [0xABCDEF] */
214 /* 2 pixels 16bit = [0x0ABD] + [0x0FCE] */
216 if (Header->GetBitsAllocated()==12) {
217 int nbPixels = Header->GetXSize() * Header->GetYSize();
218 unsigned char b0, b1, b2;
220 unsigned short int* pdestination = (unsigned short int*)destination;
221 for(int p=0;p<nbPixels;p+=2) {
225 //Two steps is necessary to please VC++
226 *pdestination++ = ((b0 >> 4) << 8) + ((b0 & 0x0f) << 4) + (b1 & 0x0f);
227 /* A */ /* B */ /* D */
228 *pdestination++ = ((b2 & 0x0f) << 8) + ((b1 >> 4) << 4) + (b2 >> 4);
229 /* F */ /* C */ /* E */
231 // Troubles expected on Big-Endian processors ?
236 // ---------------------- Uncompressed File
238 if ( !Header->IsDicomV3() ||
239 Header->IsImplicitVRLittleEndianTransferSyntax() ||
240 Header->IsExplicitVRLittleEndianTransferSyntax() ||
241 Header->IsExplicitVRBigEndianTransferSyntax() ||
242 Header->IsDeflatedExplicitVRLittleEndianTransferSyntax() ) {
244 size_t ItemRead = fread(destination, Header->GetPixelAreaLength(), 1, fp);
246 if ( ItemRead != 1 ) {
255 // ---------------------- Run Length Encoding
257 if (Header->IsRLELossLessTransferSyntax()) {
258 bool res = (bool)gdcm_read_RLE_file (fp,destination);
262 // --------------- SingleFrame/Multiframe JPEG Lossless/Lossy/2000
265 std::string str_nb=Header->GetPubElValByNumber(0x0028,0x0100);
266 if (str_nb == GDCM_UNFOUND ) {
269 nb = atoi(str_nb.c_str() );
270 if (nb == 12) nb =16; // ?? 12 should be ACR-NEMA only ?
275 int taille = Header->GetXSize() * Header->GetYSize()
276 * Header->GetSamplesPerPixel();
277 long fragmentBegining; // for ftell, fseek
279 bool jpg2000 = Header->IsJPEG2000();
280 bool jpgLossless = Header->IsJPEGLossless();
283 guint16 ItemTagGr,ItemTagEl;
286 // Position on begining of Jpeg Pixels
288 fread(&ItemTagGr,2,1,fp); // Reading (fffe) : Item Tag Gr
289 fread(&ItemTagEl,2,1,fp); // Reading (e000) : Item Tag El
290 if(Header->GetSwapCode()) {
291 ItemTagGr=Header->SwapShort(ItemTagGr);
292 ItemTagEl=Header->SwapShort(ItemTagEl);
295 if(Header->GetSwapCode())
296 ln=Header->SwapLong(ln); // Basic Offset Table Item length
299 // What is it used for ?!?
300 char *BasicOffsetTableItemValue = (char *)malloc(ln+1);
301 fread(BasicOffsetTableItemValue,ln,1,fp);
304 // first Fragment initialisation
305 fread(&ItemTagGr,2,1,fp); // Reading (fffe) : Item Tag Gr
306 fread(&ItemTagEl,2,1,fp); // Reading (e000) : Item Tag El
307 if(Header->GetSwapCode()) {
308 ItemTagGr=Header->SwapShort(ItemTagGr);
309 ItemTagEl=Header->SwapShort(ItemTagEl);
312 // parsing fragments until Sequence Delim. Tag found
314 while ( ( ItemTagGr == 0xfffe) && (ItemTagEl != 0xe0dd) ) {
315 // --- for each Fragment
318 if(Header->GetSwapCode())
319 ln=Header->SwapLong(ln); // Fragment Item length
321 fragmentBegining=ftell(fp);
323 if (jpg2000) { // JPEG 2000 : call to ???
325 res = (bool)gdcm_read_JPEG2000_file (fp,destination); // Not Yet written
327 } // ------------------------------------- endif (JPEG2000)
329 else if (jpgLossless) { // JPEG LossLess : call to xmedcom JPEG
331 JPEGLosslessDecodeImage (fp, // Reading Fragment pixels
332 (unsigned short *)destination,
333 Header->GetPixelSize()*8* Header->GetSamplesPerPixel(),
335 res=1; // in order not to break the loop
337 } // ------------------------------------- endif (JPEGLossless)
339 else { // JPEG Lossy : call to IJG 6b
341 if (Header->GetBitsStored() == 8) {
342 res = (bool)gdcm_read_JPEG_file (fp,destination); // Reading Fragment pixels
344 res = (bool)gdcm_read_JPEG_file12 (fp,destination);// Reading Fragment pixels
346 } // ------------------------------------- endif (JPEGLossy)
350 destination = (char *)destination + taille * nBytes; // location in user's memory
351 // for next fragment (if any)
353 fseek(fp,fragmentBegining,SEEK_SET); // To be sure we start
354 fseek(fp,ln,SEEK_CUR); // at the begining of next fragment
356 ItemTagGr = ItemTagEl =0;
357 fread(&ItemTagGr,2,1,fp); // Reading (fffe) : Item Tag Gr
358 fread(&ItemTagEl,2,1,fp); // Reading (e000) : Item Tag El
359 if(Header->GetSwapCode()) {
360 ItemTagGr=Header->SwapShort(ItemTagGr);
361 ItemTagEl=Header->SwapShort(ItemTagEl);
364 } // endWhile parsing fragments until Sequence Delim. Tag found
372 * \brief Allocates necessary memory, copies the pixel data
373 * (image[s]/volume[s]) to newly allocated zone.
374 * Transforms YBR pixels into RGB pixels if any
375 Transforms 3 planes R, G, B into a single RGB Plane
376 Transforms single Grey plane + 3 Palettes into a RGB Plane
377 * @return Pointer to newly allocated pixel data.
378 * \ NULL if alloc fails
380 void * gdcmFile::GetImageData (void) {
381 PixelData = (void *) malloc(lgrTotale);
383 GetImageDataIntoVector(PixelData, lgrTotale);
389 * \brief Allocates necessary memory, copies the pixel data
390 * (image[s]/volume[s]) to newly allocated zone.
391 * Transforms YBR pixels into RGB pixels if any
392 Transforms 3 planes R, G, B into a single RGB Plane
393 DOES NOT transform Grey plane + 3 Palettes into a RGB Plane
394 * @return Pointer to newly allocated pixel data.
395 * \ NULL if alloc fails
397 void * gdcmFile::GetImageDataRaw (void) {
398 if (Header->HasLUT())
399 lgrTotale /= 3; // TODO Let gdcmHeadar user a chance
400 // to get the right value
401 // Create a member lgrTotaleRaw ???
402 PixelData = (void *) malloc(lgrTotale);
404 GetImageDataIntoVectorRaw(PixelData, lgrTotale);
410 * \brief Copies at most MaxSize bytes of pixel data to caller's
412 * \warning This function was designed to avoid people that want to build
413 * a volume from an image stack to need first to get the image pixels
414 * and then move them to the volume area.
415 * It's absolutely useless for any VTK user since vtk chooses
416 * to invert the lines of an image, that is the last line comes first
417 * (for some axis related reasons?). Hence he will have
418 * to load the image line by line, starting from the end.
419 * VTK users have to call GetImageData
421 * @param destination Address (in caller's memory space) at which the
422 * pixel data should be copied
423 * @param MaxSize Maximum number of bytes to be copied. When MaxSize
424 * is not sufficient to hold the pixel data the copy is not
425 * executed (i.e. no partial copy).
426 * @return On success, the number of bytes actually copied. Zero on
427 * failure e.g. MaxSize is lower than necessary.
430 size_t gdcmFile::GetImageDataIntoVector (void* destination, size_t MaxSize) {
432 size_t l = GetImageDataIntoVectorRaw (destination, MaxSize);
434 if (!Header->HasLUT())
437 // from Lut R + Lut G + Lut B
439 unsigned char * newDest = (unsigned char *)malloc(lgrTotale);
440 unsigned char * a = (unsigned char *)destination;
441 unsigned char * lutRGBA = Header->GetLUTRGBA();
443 int l = lgrTotaleRaw;
444 memmove(newDest, destination, l);// move Gray pixels to temp area
446 for (int i=0;i<l; i++) { // Build RGB Pixels
454 // now, it's an RGB image
455 // Lets's write it in the Header
457 // CreateOrReplaceIfExist ?
459 std::string spp = "3"; // Samples Per Pixel
460 Header->SetPubElValByNumber(spp,0x0028,0x0002);
461 std::string rgb= "RGB "; // Photometric Interpretation
462 Header->SetPubElValByNumber(rgb,0x0028,0x0004);
463 std::string planConfig = "0"; // Planar Configuration
464 Header->SetPubElValByNumber(planConfig,0x0028,0x0006);
468 // need to make RGB Pixels (?)
469 // from grey Pixels (?!)
470 // and Gray Lut (!?!)
471 // or Segmented xxx Palette Color Lookup Table Data and so on
473 // Well . I'll wait till I find such an image
475 // Oops! I get one (gdcm-US-ALOKA-16.dcm)
476 // No idea how to manage it
477 // It seems that *no Dicom Viewer* has any idea :-(
478 // Segmented xxx Palette Color are *more* than 65535 long ?!?
480 std::string rgb= "MONOCHROME1 "; // Photometric Interpretation
481 Header->SetPubElValByNumber(rgb,0x0028,0x0004);
485 // TODO : Drop Palette Color out of the Header?
493 * \brief Copies at most MaxSize bytes of pixel data to caller's
495 * \warning This function was designed to avoid people that want to build
496 * a volume from an image stack to need first to get the image pixels
497 * and then move them to the volume area.
498 * It's absolutely useless for any VTK user since vtk chooses
499 * to invert the lines of an image, that is the last line comes first
500 * (for some axis related reasons?). Hence he will have
501 * to load the image line by line, starting from the end.
502 * VTK users hace to call GetImageData
503 * \warning DOES NOT transform the Grey Plane + Palette Color (if any)
504 * into a single RGB Pixels Plane
505 * the (VTK) user will manage the palettes
507 * @param destination Address (in caller's memory space) at which the
508 * pixel data should be copied
509 * @param MaxSize Maximum number of bytes to be copied. When MaxSize
510 * is not sufficient to hold the pixel data the copy is not
511 * executed (i.e. no partial copy).
512 * @return On success, the number of bytes actually copied. Zero on
513 * failure e.g. MaxSize is lower than necessary.
516 size_t gdcmFile::GetImageDataIntoVectorRaw (void* destination, size_t MaxSize) {
518 int nb, nbu, highBit, signe;
519 std::string str_nbFrames, str_nb, str_nbu, str_highBit, str_signe;
521 if ( lgrTotale > MaxSize ) {
522 dbg.Verbose(0, "gdcmFile::GetImageDataIntoVector: pixel data bigger"
523 "than caller's expected MaxSize");
527 (void)ReadPixelData(destination);
529 // Nombre de Bits Alloues pour le stockage d'un Pixel
530 str_nb = Header->GetPubElValByNumber(0x0028,0x0100);
531 if (str_nb == GDCM_UNFOUND ) {
534 nb = atoi(str_nb.c_str() );
537 // Nombre de Bits Utilises
538 str_nbu=Header->GetPubElValByNumber(0x0028,0x0101);
539 if (str_nbu == GDCM_UNFOUND ) {
542 nbu = atoi(str_nbu.c_str() );
545 // Position du Bit de Poids Fort
546 str_highBit=Header->GetPubElValByNumber(0x0028,0x0102);
547 if (str_highBit == GDCM_UNFOUND ) {
550 highBit = atoi(str_highBit.c_str() );
555 str_signe=Header->GetPubElValByNumber(0x0028,0x0103);
556 if (str_signe == GDCM_UNFOUND ) {
557 signe = 0; // default is unsigned
559 signe = atoi(str_signe.c_str() );
562 // re arange bytes inside the integer
564 SwapZone(destination, Header->GetSwapCode(), lgrTotale, nb);
566 // to avoid pb with some xmedcon breakers images
567 if (nb==16 && nbu<nb && signe==0) {
568 int l = (int)lgrTotale / (nb/8);
569 guint16 *deb = (guint16 *)destination;
570 for(int i = 0; i<l; i++) {
577 // re arange bits inside the bytes
579 int l = (int)lgrTotale / (nb/8);
581 guint16 mask = 0xffff;
582 mask = mask >> (nb-nbu);
583 guint16 *deb = (guint16 *)destination;
584 for(int i = 0; i<l; i++) {
585 *deb = (*deb >> (nbu-highBit-1)) & mask;
588 } else if (nb == 32 ) {
589 guint32 mask = 0xffffffff;
590 mask = mask >> (nb-nbu);
591 guint32 *deb = (guint32 *)destination;
592 for(int i = 0; i<l; i++) {
593 *deb = (*deb >> (nbu-highBit-1)) & mask;
597 dbg.Verbose(0, "gdcmFile::GetImageDataIntoVector: wierd image");
602 // Just to 'see' what was actually read on disk :-(
603 // Some troubles expected
605 // f2 = fopen("SpuriousFile.raw","wb");
606 // fwrite(destination,lgrTotale,1,f2);
609 // Deal with the color
610 // -------------------
612 std::string str_PhotometricInterpretation =
613 Header->GetPubElValByNumber(0x0028,0x0004);
615 if ( (str_PhotometricInterpretation == "MONOCHROME1 ")
616 || (str_PhotometricInterpretation == "MONOCHROME2 ") ) {
620 // Planar configuration = 0 : Pixels are already RGB
621 // Planar configuration = 1 : 3 planes : R, G, B
622 // Planar configuration = 2 : 1 gray Plane + 3 LUT
624 // Well ... supposed to be !
625 // See US-PAL-8-10x-echo.dcm: PlanarConfiguration=0,
626 // PhotometricInterpretation=PALETTE COLOR
627 // and heuristic has to be found :-(
629 int planConf=Header->GetPlanarConfiguration(); // 0028,0006
631 // Whatever Planar Configuration is,
632 // "PALETTE COLOR " implies that we deal with the palette.
633 if (str_PhotometricInterpretation == "PALETTE COLOR ")
638 // Pixels are already RGB
644 if (str_PhotometricInterpretation == "YBR_FULL") {
646 // Warning : YBR_FULL_422 acts as RGB
647 // : we need to make RGB Pixels from Planes Y,cB,cR
648 // see http://lestourtereaux.free.fr/papers/data/yuvrgb.pdf
649 // for code optimisation
651 // to see the tricks about YBR_FULL, YBR_FULL_422,
652 // YBR_PARTIAL_422, YBR_ICT, YBR_RCT have a look at :
653 // ftp://medical.nema.org/medical/dicom/final/sup61_ft.pdf
654 // and be *very* affraid
656 int l = Header->GetXSize()*Header->GetYSize();
657 int nbFrames = Header->GetZSize();
659 unsigned char * newDest = (unsigned char*) malloc(lgrTotale);
660 unsigned char *x = newDest;
661 unsigned char * a = (unsigned char *)destination;
662 unsigned char * b = a + l;
663 unsigned char * c = b + l;
667 // TODO : Replace by the 'well known'
668 // integer computation counterpart
669 for (int i=0;i<nbFrames;i++) {
670 for (int j=0;j<l; j++) {
671 R= 1.164 *(*a-16) + 1.596 *(*c -128) + 0.5;
672 G= 1.164 *(*a-16) - 0.813 *(*c -128) - 0.392 *(*b -128) + 0.5;
673 B= 1.164 *(*a-16) + 2.017 *(*b -128) + 0.5;
678 if (R>255.0) R=255.0;
679 if (G>255.0) G=255.0;
680 if (B>255.0) B=255.0;
682 *(x++) = (unsigned char)R;
683 *(x++) = (unsigned char)G;
684 *(x++) = (unsigned char)B;
688 memmove(destination,newDest,lgrTotale);
693 // need to make RGB Pixels from R,G,B Planes
694 // (all the Frames at a time)
696 int l = Header->GetXSize()*Header->GetYSize()*Header->GetZSize();
698 char * newDest = (char*) malloc(lgrTotale);
700 char * a = (char *)destination;
704 for (int j=0;j<l; j++) {
710 memmove(destination,newDest,lgrTotale);
718 // Palettes were found
719 // Let the user deal with them !
722 // now, it's an RGB image
723 // Lets's write it in the Header
725 // CreateOrReplaceIfExist ?
729 std::string spp = "3"; // Samples Per Pixel
730 Header->SetPubElValByNumber(spp,0x0028,0x0002);
731 std::string rgb="RGB "; // Photometric Interpretation
732 Header->SetPubElValByNumber(rgb,0x0028,0x0004);
734 std::string planConfig = "0"; // Planar Configuration
735 Header->SetPubElValByNumber(planConfig,0x0028,0x0006);
737 // TODO : Drop Palette Color out of the Header?
746 * \brief Swap the bytes, according to swap code.
747 * \warning not end user intended
748 * @param im area to deal with
749 * @param swap swap code
750 * @param lgr Area Length
751 * @param nb Pixels Bit number
754 void gdcmFile::SwapZone(void* im, int swap, int lgr, int nb) {
772 ((unsigned short int*)im)[i]= ((((unsigned short int*)im)[i])>>8)
773 | ((((unsigned short int*)im)[i])<<8);
777 printf("valeur de SWAP (16 bits) not allowed : %d\n", swap);
788 faible= ((unsigned long int*)im)[i]&0x0000ffff; /* 4321 */
789 fort =((unsigned long int*)im)[i]>>16;
790 fort= (fort>>8) | (fort<<8);
791 faible=(faible>>8) | (faible<<8);
793 ((unsigned long int*)im)[i]=(s32<<16)|fort;
799 faible= ((unsigned long int*)im)[i]&0x0000ffff; /* 2143 */
800 fort=((unsigned long int*)im)[i]>>16;
801 fort= (fort>>8) | (fort<<8);
802 faible=(faible>>8) | (faible<<8);
804 ((unsigned long int*)im)[i]=(s32<<16)|faible;
810 faible= ((unsigned long int*)im)[i]&0x0000ffff; /* 3412 */
811 fort=((unsigned long int*)im)[i]>>16;
813 ((unsigned long int*)im)[i]=(s32<<16)|fort;
818 printf(" SWAP value (32 bits) not allowed : %d\n", swap);
823 /////////////////////////////////////////////////////////////////
827 * \warning doit-etre etre publique ?
828 * TODO : y a-t-il un inconvenient à fusioner ces 2 fonctions
831 * @param ExpectedSize
833 * @return integer acts as a boolean
835 int gdcmFile::SetImageData(void * inData, size_t ExpectedSize) {
836 Header->SetImageDataSize(ExpectedSize);
838 lgrTotale = ExpectedSize;
843 /////////////////////////////////////////////////////////////////
846 * \brief Ecrit sur disque les pixels d'UNE image
847 * Aucun test n'est fait sur l'"Endiannerie" du processeur.
848 * Ca sera à l'utilisateur d'appeler son Reader correctement
849 * (Equivalent a IdImaWriteRawFile)
855 int gdcmFile::WriteRawData (std::string fileName) {
857 fp1 = fopen(fileName.c_str(),"wb");
859 printf("Echec ouverture (ecriture) Fichier [%s] \n",fileName.c_str());
862 fwrite (PixelData,lgrTotale, 1, fp1);
867 /////////////////////////////////////////////////////////////////
870 * \brief Ecrit sur disque UNE image Dicom
871 * Aucun test n'est fait sur l'"Endiannerie" du processeur.
872 * Ca fonctionnera correctement (?) sur processeur Intel
873 * (Equivalent a IdDcmWrite)
876 * @return int acts as a boolean
879 int gdcmFile::WriteDcmImplVR (std::string fileName) {
880 return WriteBase(fileName, ImplicitVR);
883 /////////////////////////////////////////////////////////////////
888 * @return int acts as a boolean
891 int gdcmFile::WriteDcmImplVR (const char* fileName) {
892 return WriteDcmImplVR (std::string (fileName));
895 /////////////////////////////////////////////////////////////////
900 * @return int acts as a boolean
903 int gdcmFile::WriteDcmExplVR (std::string fileName) {
904 return WriteBase(fileName, ExplicitVR);
907 /////////////////////////////////////////////////////////////////
910 * \brief Ecrit au format ACR-NEMA sur disque l'entete et les pixels
911 * (a l'attention des logiciels cliniques
912 * qui ne prennent en entrée QUE des images ACR ...
913 * \warning si un header DICOM est fourni en entree,
914 * les groupes < 0x0008 et les groupes impairs sont ignores)
915 * \warning Aucun test n'est fait sur l'"Endiannerie" du processeur.
916 * Ca fonctionnera correctement (?) sur processeur Intel
917 * (Equivalent a IdDcmWrite)
920 * @return int acts as a boolean
923 int gdcmFile::WriteAcr (std::string fileName) {
924 return WriteBase(fileName, ACR);
927 /////////////////////////////////////////////////////////////////
934 * @return int acts as a boolean
936 int gdcmFile::WriteBase (std::string FileName, FileType type) {
939 fp1 = fopen(FileName.c_str(),"wb");
941 printf("Echec ouverture (ecriture) Fichier [%s] \n",FileName.c_str());
945 if ( (type == ImplicitVR) || (type == ExplicitVR) ) {
947 // writing Dicom File Preamble
948 filePreamble=(char*)calloc(128,1);
949 fwrite(filePreamble,128,1,fp1);
950 fwrite("DICM",4,1,fp1);
953 // --------------------------------------------------------------
954 // Special Patch to allow gdcm to re-write ACR-LibIDO formated images
956 // if recognition code tells us we dealt with a LibIDO image
957 // we reproduce on disk the switch between lineNumber and columnNumber
958 // just before writting ...
960 std::string rows, columns;
961 if ( Header->GetFileType() == ACR_LIBIDO){
962 rows = Header->GetPubElValByNumber(0x0028, 0x0010);
963 columns = Header->GetPubElValByNumber(0x0028, 0x0011);
964 Header->SetPubElValByNumber(columns, 0x0028, 0x0010);
965 Header->SetPubElValByNumber(rows , 0x0028, 0x0011);
967 // ----------------- End of Special Patch ----------------
969 Header->Write(fp1, type);
971 // --------------------------------------------------------------
972 // Special Patch to allow gdcm to re-write ACR-LibIDO formated images
974 // ...and we restore the Header to be Dicom Compliant again
975 // just after writting
977 if (Header->GetFileType() == ACR_LIBIDO){
978 Header->SetPubElValByNumber(rows , 0x0028, 0x0010);
979 Header->SetPubElValByNumber(columns, 0x0028, 0x0011);
981 // ----------------- End of Special Patch ----------------
983 fwrite(PixelData, lgrTotale, 1, fp1);