4
{$Define NoTroubleshoot}
11
SysUtils,Classes,define_types,filename,dicomtypes,dicomfastread,prefs,convertsimple;
14
kUseDateTimeForID: boolean = false;
15
procedure read_afni_data(var lDICOMdata: DICOMdata; var lHdrOK, lImageFormatOK: boolean; var lDynStr: string;var lFileName: string; var lRotation1,lRotation2,lRotation3: integer);
16
procedure read_ecat_data(var lDICOMdata: DICOMdata;lVerboseRead,lReadECAToffsetTables:boolean; var lHdrOK, lImageFormatOK: boolean; var lDynStr: string;lFileName: string);
17
procedure read_siemens_data(var lDICOMdata: DICOMdata; var lHdrOK, lImageFormatOK: boolean; var lDynStr: string;lFileName: string);
18
procedure read_ge_data(var lDICOMdata: DICOMdata; var lHdrOK, lImageFormatOK: boolean; var lDynStr: string;lFileName: string);
19
procedure read_interfile_data(var lDICOMdata: DICOMdata; var lHdrOK, lImageFormatOK: boolean; var lDynStr: string;var lFileName: string);
20
procedure read_voxbo_data(var lDICOMdata: DICOMdata; var lHdrOK, lImageFormatOK: boolean; var lDynStr: string;var lFileName: string);
21
procedure read_VFF_data(var lDICOMdata: DICOMdata; var lHdrOK, lImageFormatOK: boolean; var lDynStr: string;var lFileName: string);
22
procedure read_picker_data(lVerboseRead: boolean; var lDICOMdata: DICOMdata; var lHdrOK, lImageFormatOK: boolean; var lDynStr: string;lFileName: string);
23
procedure read_tiff_data(var lDICOMdata: DICOMdata; var lReadOffsets,lHdrOK, lImageFormatOK: boolean; var lDynStr: string;lFileName: string);
24
procedure read_dicom_data_compat(lReadJPEGtables,lVerboseRead,lAutoDECAT7,lReadECAToffsetTables,lAutodetectInterfile,lAutoDetectGenesis,lReadColorTables: boolean; var lDICOMdata: DICOMdata; var lHdrOK, lImageFormatOK: boolean; var lDynStr: string;var lFileName: string; var lPrefs: TPrefs);
27
gSizeMMWarningShown : boolean = false;
28
gECATJPEG_table_entries: integer = 0;
29
gECATJPEG_pos_table,gECATJPEG_size_table : LongIntP;
30
red_table_size : Integer = 0;
31
green_table_size : Integer = 0;
32
blue_table_size : Integer = 0;
40
procedure read_ecat_data(var lDICOMdata: DICOMdata;lVerboseRead,lReadECAToffsetTables:boolean; var lHdrOK, lImageFormatOK: boolean; var lDynStr: string;lFileName: string);
48
lECAT7sigUpcase,lECAT7sig : array [0..6] of Char;
49
lParse,lSPos,lFPos{,lScomplement},lF,lS,lYear,lFrames,lVox,lHlfVox,lJ,lPass,lVolume,lNextDirectory,lSlice,lSliceSz,lVoxelType,lPos,lEntry,
50
lSlicePos,lLongRApos,lLongRAsz,{lSingleRApos,lSingleRAsz,}{lMatri,}lX,lY,lZ,lCacheSz,lImgSz,lSubHeadStart,lMatrixStart,lMatrixEnd,lInt,lInt2,lInt3,lINt4,n,filesz: LongInt;
51
lPlanes,lGates,lAqcType,lFileType: word;
52
lXmm,lYmm,lZmm,lCalibrationFactor, lQuantScale: real;
54
lCreateTable,lSwapBytes,lMR,lECAT6: boolean;
55
function xWord(lPos: longint): word;
60
BlockRead(fp, s, 2, n);
63
else result := s; //assign address of s to inguy
66
function swap32i(lPos: longint): Longint;
68
swaptype = packed record
70
0:(Word1,Word2 : word); //word is 16 bit
73
swaptypep = ^swaptype;
80
BlockRead(fp, s, 4, n);
81
inguy := @s; //assign address of s to inguy
82
if not lSwapBytes then begin
83
result := inguy^.long;
86
outguy.Word1 := swap(inguy^.Word2);
87
outguy.Word2 := swap(inguy^.Word1);
90
function StrRead (lPos, lSz: longint) : string;
93
tx : array [1..kStrSz] of Char;
96
if lSz > kStrSz then exit;
98
BlockRead(fp, tx, lSz*SizeOf(Char), n);
99
for I := 1 to (lSz-1) do begin
100
if tx[I] in [' ','[',']','+','-','.','\','~','/', '0'..'9','a'..'z','A'..'Z'] then
101
{if (tx[I] <> kCR) and (tx[I] <> UNIXeoln) then}
102
result := result + tx[I];
105
function fswap4r (lPos: longint): single;
107
swaptype = packed record
109
0:(Word1,Word2 : word); //word is 16 bit
112
swaptypep = ^swaptype;
119
if not lSwapBytes then begin
120
BlockRead(fp, result, 4, n);
123
BlockRead(fp, s, 4, n);
124
inguy := @s; //assign address of s to inguy
125
outguy.Word1 := swap(inguy^.Word2);
126
outguy.Word2 := swap(inguy^.Word1);
127
fswap4r:=outguy.float;
129
function fvax4r (lPos: longint): single;
131
swaptype = packed record
133
0:(Word1,Word2 : word); //word is 16 bit
136
swaptypep = ^swaptype;
143
BlockRead(fp, s, 4, n);
145
if (inguy^.Word1 =0) and (inguy^.Word2 = 0) then begin
149
lT1 := inguy^.Word1 and $80FF;
150
lT2 := ((inguy^.Word1 and $7F00) +$FF00) and $7F00;
151
inguy^.Word1 := inguy^.Word2;
152
inguy^.Word2 := (lt1+lT2);
153
fvax4r:=inguy^.float;
156
Clear_Dicom_Data(lDicomData);
157
if gECATJPEG_table_entries <> 0 then begin
158
freemem (gECATJPEG_pos_table);
159
freemem (gECATJPEG_size_table);
160
gECATJPEG_table_entries := 0;
164
lCalibrationFactor := 1;
167
lImageFormatOK := false;
169
if not fileexists(lFileName) then begin
170
Msg('Unable to find the image '+lFileName);
173
FileMode := 0; //set to readonly
174
AssignFile(fp, lFileName);
176
FileSz := FileSize(fp);
177
if filesz < (2048) then begin
178
Msg('This file is to small to be a ECAT format image.');
182
BlockRead(fp, lECAT7Sig, 6*SizeOf(Char){, n});
183
for lInt4 := 0 to (5) do begin
184
if lECAT7Sig[lInt4] in ['a'..'z','A'..'Z'] then
185
lECAT7SigUpCase[lInt4] := upcase(lECAT7Sig[lInt4])
187
lECAT7SigUpCase[lInt4] := ' ';
189
if (lECAT7SigUpCase[0]='M') and (lECAT7SigUpCase[1]='A') and (lECAT7SigUpCase[2]='T') and (lECAT7SigUpCase[3]='R') and
190
(lECAT7SigUpCase[4]='I') and (lECAT7SigUpCase[5]='X') then
196
lFileType := xWord(27*2);
197
if lFileType > 255 then lSwapBytes := not lSwapBytes;
198
lFileType := xWord(27*2);
199
lAqcType := xWord(175*2);
200
lPlanes := xWord(188*2);
201
lFrames := xword(189*2);
202
lGates := xWord(190*2);
204
if (lPlanes < 1) or (lFrames < 1) or (lGates < 1) then begin
205
case MsgDlg('Warning: one of the planes/frames/gates values is less than 1 ['+inttostr(lPlanes)+'/'+inttostr(lFrames)+'/'+inttostr(lGates)+']. Is this file really ECAT 6 format? Press abort to cancel conversion. ',
206
mterror,[mbOK,mbAbort], 0) of
209
end else if (lYear < 1940) or (lYear > 3000) then begin
210
case MsgDlg('Warning: the year value appears invalid ['+inttostr(lYear)+']. Is this file really ECAT 6 format? Press abort to cancel conversion. ',
211
mterror,[mbOK,mbAbort], 0) of
215
if lVerboseRead then begin
216
lDynStr :='ECAT6 data';
217
lDynStr :=lDynStr+kCR+('Patient Name:'+StrRead(190,32));
218
lDynStr :=lDynStr+kCR+('Patient ID:'+StrRead(174,16));
219
lDynStr :=lDynStr+kCR+('Study Desc:'+StrRead(318,32));
220
lDynStr := lDynStr+kCR+('Facility: '+StrRead(356,20));
221
lDynStr := lDynStr+kCR+('Planes: '+inttostr(lPlanes));
222
lDynStr := lDynStr+kCR+('Frames: '+inttostr(lFrames));
223
lDynStr := lDynStr+kCR+('Gates: '+inttostr(lGates));
224
lDynStr := lDynStr+kCR+('Date DD/MM/YY: '+ inttostr(xWord(66))+'/'+inttostr(xWord(68))+'/'+inttostr(lYear));
226
end else begin //NOT ECAT6
228
lFileType := xWord(50);
229
if lFileType > 255 then lSwapBytes := not lSwapBytes;
230
lFileType := xWord(50);
231
lAqcType := xWord(328);
232
lPlanes := xWord(352);
233
lFrames := xWord(354);
234
lGates := xWord(356);
235
lCalibrationFactor := fswap4r(144);
236
if {(true) or} (lPlanes < 1) or (lFrames < 1) or (lGates < 1) then begin
237
case MsgDlg('Warning: on of the planes/frames/gates values is less than 1 ['+inttostr(lPlanes)+'/'+inttostr(lFrames)+'/'+inttostr(lGates)+']. Is this file really ECAT 7 format? Press abort to cancel conversion. ',
238
mterror,[mbOK,mbAbort], 0) of
242
if lVerboseRead then begin
243
lDynStr := 'ECAT 7 format';
244
lDynStr := lDynStr+kCR+('Serial Number:'+StrRead(52,10));
245
lDynStr := lDynStr+kCR+('Patient Name:'+StrRead(182,32));
246
lDynStr := lDynStr+kCR+('Patient ID:'+StrRead(166,16));
247
lDynStr := lDynStr+kCR+('Study Desc:'+StrRead(296,32));
248
lDynStr := lDynStr+kCR+('Facility: '+StrRead(332,20));
249
lDynStr := lDynStr+kCR+('Scanner: '+inttostr(xWord(48)));
250
lDynStr := lDynStr+kCR+('Planes: '+inttostr(lPlanes));
251
lDynStr := lDynStr+kCR+('Frames: '+inttostr(lFrames));
252
lDynStr := lDynStr+kCR+('Gates: '+inttostr(lGates));
253
lDynStr := lDynStr+kCR+'Calibration: '+floattostr(lCalibrationFactor);
256
if lFiletype = 9 then lFiletype := 7; //1364: treat projections as Volume16's
257
if not (lFileType in [1,2,3,4,7]) then begin
258
Msg('This software does not recognize the ECAT file type. Selected filetype: '+inttostr(lFileType));
262
if lFileType = 3 then lVoxelType := 4;
263
if lVerboseRead then begin
265
1: lDynStr := lDynStr+kCR+('File type: Scan File');
266
2: lDynStr := lDynStr+kCR+('File type: Image File'); //x
267
3: lDynStr := lDynStr+kCR+('File type: Attn File');
268
4: lDynStr := lDynStr+kCR+('File type: Norm File');
269
7: lDynStr := lDynStr+kCR+('File type: Volume 16'); //x
272
1:lDynStr := lDynStr+kCR+('Acquisition type: Blank');
273
2:lDynStr := lDynStr+kCR+('Acquisition type: Transmission');
274
3:lDynStr := lDynStr+kCR+('Acquisition type: Static Emission');
275
4:lDynStr := lDynStr+kCR+('Acquisition type: Dynamic Emission');
276
5:lDynStr := lDynStr+kCR+('Acquisition type: Gated Emission');
277
6:lDynStr := lDynStr+kCR+('Acquisition type: Transmission Rect');
278
7:lDynStr := lDynStr+kCR+('Acquisition type: Emission Rect');
279
8:lDynStr := lDynStr+kCR+('Acquisition type: Whole Body Transm');
280
9:lDynStr := lDynStr+kCR+('Acquisition type: Whole Body Static');
281
else lDynStr := lDynStr+kCR+('Acquisition type: Undefined');
284
if ((lECAT6) and (lFiletype =2)) or ({(not lECAT6) and} (lFileType=7)) then //Kludge
286
Msg('Unusual ECAT filetype. Please contact the author.');
290
lImageFormatOK := true;
291
lLongRASz := kMaxnSlices * sizeof(longint);
292
getmem(lLongRA,lLongRAsz);
294
//lSingleRASz := kMaxnSlices * sizeof(single);
295
//getmem(lSingleRA,lSingleRAsz);
301
lInt := swap32i(lPos);
302
lInt2 := swap32i(lPos+4);
303
lNextDirectory := lInt2;
307
lInt := swap32i(lPos);
308
lInt2 := swap32i(lPos+4);
309
lInt3 := swap32i(lPos+8);
310
lInt4 := swap32i(lPos+12);
312
lSubHeadStart := lINt2 *512;
313
lMatrixStart := ((lInt2) * 512)+512 {add subhead sz};
314
lMatrixEnd := lInt3 * 512;
315
if (lInt4 = 1) and (lMatrixStart < FileSz) and (lMatrixEnd <= FileSz) then begin
316
if (lFileType= 7) {or (lFileType = 4) } or (lFileType = 2) then begin //Volume of 16-bit integers
318
lX := xWord(lSubHeadStart+(66*2));
319
lY := xWord(lSubHeadStart+(67*2));
320
lZ := 1;//uxWord(lSubHeadStart+8);
321
lXmm := 10*fvax4r(lSubHeadStart+(92*2));// fswap4r(lSubHeadStart+(92*2));
322
lYmm := lXmm;//read32r(lSubHeadStart+(94*2));
323
lZmm := 10 * fvax4r(lSubHeadStart+(94*2));
324
lCalibrationFactor := fvax4r(lSubHeadStart+(194*2));
325
lQuantScale := fvax4r(lSubHeadStart+(86*2));
327
lDynStr := lDynStr+kCR+'Plane '+inttostr(lPass+1)+' Calibration/Scale Factor: '+floattostr(lCalibrationFactor)+'/'+floattostr(lQuantScale);
330
lX := xWord(lSubHeadStart+4);
331
lY := xWord(lSubHeadStart+6);
332
lZ := xWord(lSubHeadStart+8);
333
//if lFileType <> 4 then begin
334
lXmm := 10*fswap4r(lSubHeadStart+34);
335
lYmm := 10*fswap4r(lSubHeadStart+38);
336
lZmm := 10*fswap4r(lSubHeadStart+42);
337
lQuantScale := fswap4r(lSubHeadStart+26);
339
lDynStr := lDynStr+kCR+'Volume: '+inttostr(lPass+1)+' Scale Factor: '+floattostr(lQuantScale);
340
//end; //filetype <> 4
343
//FileMode := 2; //set to read/write
345
lImgSz := lX * lY * lZ * lVoxelType; {2 bytes per voxel}
346
lSliceSz := lX * lY * lVoxelType;
351
lSlicePos := lMatrixStart;
352
if ((lECAT6) and (lPass = 1)) or ( (not lECAT6)) then begin
353
lDICOMdata.XYZdim[1] := lX;
354
lDICOMdata.XYZdim[2] := lY;
355
lDICOMdata.XYZdim[3] := lZ;
356
lDICOMdata.XYZmm[1] := lXmm;
357
lDICOMdata.XYZmm[2] := lYmm;
358
lDICOMdata.XYZmm[3] := lZmm;
361
Msg('Error: 8-bit data not supported [yet]. Please contact the author.');
362
lDicomData.Allocbits_per_pixel := 8;
367
Msg('Error: 32-bit data not supported [yet]. Please contact the author.');
371
else begin //16-bit integers
372
lDicomData.Allocbits_per_pixel := 16;
374
end; {case lVoxelType}
375
end else begin //if lECAT6
376
if (lDICOMdata.XYZdim[1] <> lX) or (lDICOMdata.XYZdim[2] <> lY) or (lDICOMdata.XYZdim[3] <> lZ) then begin
377
Msg('Error: different slices in this volume have different slice sizes. Please contact the author.');
380
end; //dimensions have changed
381
//lSlicePos :=((lMatri-1)*lImgSz);
383
lVox := lSliceSz div 2;
384
lHlfVox := lSliceSz div 4;
385
for lSlice := 1 to lZ do begin
387
lSlicePos := ((lSlice-1)*lSliceSz)+lMatrixStart;
388
if lLongRAPos >= kMaxnSLices then begin
393
lLongRA^[lLongRAPos] := lSlicePos;
395
if lCalibTableType = 1 then
396
lSingleRA[lSingleRAPos] := lQuantScale
398
lSingleRA[lSingleRAPos] := lCalibrationFactor *lQuantScale;}
401
if not lECAT6 then inc(lVolume);
403
end; //correct filetype
404
end; //matrix start/end within filesz
405
if (lMatrixStart > FileSz) or (lMatrixEnd >= FileSz) then goto 539;
406
if ((lEntry mod 32) = 0) then begin
407
if ((lNextDirectory-1)*512) <= lPos then goto 539; //no more directories
408
lPos := (lNextDirectory-1)*512;
414
FileMode := 2; //set to read/write
415
lDicomData.XYZdim[3] := lLongRApos;
416
if not lECAT6 then dec(lVolume); //ECAT7 increments immediately before exiting loop - once too often
417
lDicomData.XYZdim[4] :=(lVolume);
419
lDicomData.little_endian := 0
421
lDicomData.little_endian := 1;
422
if (lLongRApos > 0) and (lHdrOK) then begin
423
lDicomData.ImageStart := lLongRA^[1];
424
lCreateTable := false;
425
if (lLongRApos > 1) then begin
426
lFPos := lDICOMdata.ImageStart;
427
for lS := 2 to lLongRApos do begin
428
lFPos := lFPos + lSliceSz;
429
if lFPos <> lLongRA^[lS] then lCreateTable := true;
431
if (lCreateTable) and (lReadECAToffsetTables) then begin
432
gECATJPEG_table_entries := lLongRApos;
433
getmem (gECATJPEG_pos_table, gECATJPEG_table_entries*sizeof(longint));
434
getmem (gECATJPEG_size_table, gECATJPEG_table_entries*sizeof(longint));
435
for lS := 1 to gECATJPEG_table_entries do
436
gECATJPEG_pos_table^[lS] := lLongRA^[lS]
437
end else if (lCreateTable) then
438
lImageFormatOK := false; //slices are offset within this file
440
if (lVerboseRead) and (lHdrOK) then begin
441
lDynStr :=lDynStr+kCR+('XYZdim:'+inttostr(lX)+'/'+inttostr(lY)+'/'+inttostr(gECATJPEG_table_entries));
442
lDynStr :=lDynStr+kCR+('XYZmm: '+floattostrf(lDicomData.XYZmm[1],ffFixed,7,7)+'/'+floattostrf(lDicomData.XYZmm[2],ffFixed,7,7)
443
+'/'+floattostrf(lDicomData.XYZmm[3],ffFixed,7,7));
444
//xlDynStr :=lDynStr+kCR+('Bits per voxel: '+inttostr(lDicomData.Storedbits_per_pixel));
445
lDynStr :=lDynStr+kCR+('Image Start: '+inttostr(lDicomData.ImageStart));
447
lDynStr :=lDynStr+kCR+('Note: staggered slice offsets');
450
//xlDicomData.Storedbits_per_pixel:= lDicomData.Allocbits_per_pixel;
451
if lLongRASz > 0 then
453
(*if (lSingleRApos > 0) and (lHdrOK) and (lCalibTableType <> 0) then begin
454
gECAT_scalefactor_entries := lSingleRApos;
455
getmem (gECAT_scalefactor_table, gECAT_scalefactor_entries*sizeof(single));
456
for lS := 1 to gECAT_scalefactor_entries do
457
gECAT_scalefactor_table[lS] := lSingleRA[lS];
459
if lSingleRASz > 0 then
460
freemem(lSingleRA);*)
463
(*procedure write_slc (lFileName: string; var pDICOMdata: DICOMdata;var lSz: integer; lDICOM3: boolean);
465
lXra: array [1..kMaxRA] of byte = (7,8,9,21,22,26,27,
469
97,103,104,105,106,111,
472
146,147,148,149,155,156,157,
473
166,167,168,169,170);
476
lX,lClr,lPos,lRApos: integer;
478
procedure WriteString(lStr: string; lCR: boolean);
482
lStrLen := length(lStr);
483
for n := 1 to lstrlen do begin
485
lP[lPos] := ord(lStr[n]);
489
lP[lPos] := ord(kCR);
497
WriteString('11111',true);
498
WriteString(inttostr(pDicomData.XYZdim[1])+' '+inttostr(pDicomData.XYZdim[2])+' '+inttostr(pDicomData.XYZdim[3])+' 8',true);
499
WriteString(floattostrf(pDicomData.XYZmm[1],ffFixed,7,7)+' '+floattostrf(pDicomData.XYZmm[2],ffFixed,7,7)+' '+floattostrf(pDicomData.XYZmm[3],ffFixed,7,7),true);
500
WriteString('1 1 0 0',true); //mmunits,MR,original,nocompress
501
WriteString('16 12 X',false); //icon is 8x8 grid, so 64 bytes for red,green blue
502
for lClr := 1 to 3 do begin
504
for lX := 1 to 192 do begin
506
if (lRApos <= kMaxRA) and (lX = lXra[lRApos]) then begin
511
end; {icongrid 1..192}
513
if lFileName <> '' then begin
514
AssignFile(fp, lFileName);
516
blockwrite(fp,lP^,lPos);
522
procedure read_interfile_data(var lDICOMdata: DICOMdata; var lHdrOK, lImageFormatOK: boolean; var lDynStr: string;var lFileName: string);
524
const UNIXeoln = chr(10);
526
lInStr,lUpCaseStr: string;
527
lHdrEnd,lFloat,lUnsigned: boolean;
528
lPos,lLen,FileSz,linPos: integer;
531
function readInterFloat:real;
535
While (lPos <= lLen) and (lInStr[lPos] <> ';') do begin
536
if lInStr[lPos] in ['+','-','e','E','.','0'..'9'] then
537
lStr := lStr+(linStr[lPos]);
541
result := strtofloat(lStr);
543
on EConvertError do begin
544
Msg('Unable to convert the string '+lStr+' to a number');
550
function readInterStr:string;
554
While (lPos <= lLen) and (lInStr[lPos] = ' ') do begin
557
While (lPos <= lLen) and (lInStr[lPos] <> ';') do begin
558
if lInStr[lPos] <> ' ' then //1.39 build 6
559
lStr := lStr+upcase(linStr[lPos]); //zebra upcase
568
lImageFormatOK := true;
569
Clear_Dicom_Data(lDicomData);
571
FileMode := 0; //set to readonly
572
AssignFile(fp, lFileName);
574
FileSz := FileSize(fp);
576
//lDicomData.ImageStart := FileSz;
577
GetMem( lCharRA, FileSz+1 );
578
BlockRead(fp, lCharRA^, FileSz, linpos);
579
if lInPos <> FileSz then Msg('Disk error: Unable to read full input file.');
582
FileMode := 2; //set to read/write
585
while (linPos < FileSz) and (lCharRA^[linPos] <> ord(kCR)) and (lCharRA^[linPos] <> ord(UNIXeoln)) do begin
586
lInStr := lInstr + chr(lCharRA^[linPos]);
589
inc(lInPos); //read EOLN
590
lLen := length(lInStr);
593
While (lPos <= lLen) and (lInStr[lPos] <> ';') and (lInStr[lPos] <> '=') and (lUpCaseStr <>'INTERFILE') do begin
594
if lInStr[lPos] in ['[',']','(',')','/','+','-',{' ',} '0'..'9','a'..'z','A'..'Z'] then
595
lUpCaseStr := lUpCaseStr+upcase(linStr[lPos]);
598
inc(lPos); {read equal sign in := statement}
599
if lUpCaseStr ='INTERFILE' then begin
601
lDicomData.little_endian := 0;
603
if lUpCaseStr ='DATASTARTINGBLOCK'then lDicomData.ImageStart := 2048 * round(readInterFloat);
604
if lUpCaseStr ='DATAOFFSETINBYTES'then lDicomData.ImageStart := round(readInterFloat);
605
if (lUpCaseStr ='MATRIXSIZE[1]') or (lUpCaseStr ='MATRIXSIZE[X]') then lDicomData.XYZdim[1] := round(readInterFloat);
606
if (lUpCaseStr ='MATRIXSIZE[2]')or (lUpCaseStr ='MATRIXSIZE[Y]')then lDicomData.XYZdim[2] := round(readInterFloat);
607
if (lUpCaseStr ='MATRIXSIZE[3]')or (lUpCaseStr ='MATRIXSIZE[Z]') or (lUpCaseStr ='NUMBEROFSLICES') or (lUpCaseStr ='TOTALNUMBEROFIMAGES') then begin
608
lDicomData.XYZdim[3] := round(readInterFloat);
610
if lUpCaseStr ='IMAGEDATABYTEORDER' then begin
611
if readInterStr = 'LITTLEENDIAN' then lDicomData.little_endian := 1;
613
if lUpCaseStr ='NUMBERFORMAT' then begin
614
lTmpStr := readInterStr;
615
if (lTmpStr = 'ASCII') or (lTmpStr='BIT') then begin
617
Msg('This software can not convert '+lTmpStr+' data type.');
620
if lTmpStr = 'UNSIGNEDINTEGER' then lUnsigned := true;
621
if (lTmpStr='FLOAT') or (lTmpStr='SHORTFLOAT') or (lTmpStr='LONGFLOAT') then begin //1395
625
if lUpCaseStr ='NAMEOFDATAFILE' then lFileName := ExtractFilePath(lFileName)+readInterStr;
626
if lUpCaseStr ='NUMBEROFBYTESPERPIXEL' then
627
lDicomData.Allocbits_per_pixel := round(readInterFloat)*8;
628
if (lUpCaseStr ='SCALINGFACTOR(MM/PIXEL)[1]') or (lUpCaseStr ='SCALINGFACTOR(MM/PIXEL)[X]') then
629
lDicomData.XYZmm[1] := (readInterFloat);
630
if (lUpCaseStr ='SCALINGFACTOR(MM/PIXEL)[2]') or (lUpCaseStr ='SCALINGFACTOR(MM/PIXEL)[Y]')then lDicomData.XYZmm[2] := (readInterFloat);
631
if (lUpCaseStr ='SCALINGFACTOR(MM/PIXEL)[3]')or (lUpCaseStr ='SCALINGFACTOR(MM/PIXEL)[Z]')or (lUpCaseStr ='SLICETHICKNESS')then lDicomData.XYZmm[3] := (readInterFloat);
632
if (lUpCaseStr ='ENDOFINTERFILE') then lHdrEnd := true;
633
if not lHdrOK then goto 333;
635
lDynStr := lDynStr + lInStr+kCr;
637
until (linPos >= FileSz) or (lHdrEnd){EOF(fp)};
638
//xlDicomData.Storedbits_per_pixel := lDicomData.Allocbits_per_pixel;
639
lImageFormatOK := true;
640
if (not lFLoat) and (lUnsigned) and ((lDicomData.Allocbits_per_pixel = 16)) then begin
641
Msg('Warning: this Interfile image uses UNSIGNED 16-bit data [values 0..65535]. Analyze specifies SIGNED 16-bit data [-32768..32767]. Some images may not transfer well. [Future versions of MRIcro should fix this].');
642
lImageFormatOK := false;
643
end else if (not lFLoat) and (lDicomData.Allocbits_per_pixel > 16) then begin
644
Msg('WARNING: The image '+lFileName+' is a '+inttostr(lDicomData.Allocbits_per_pixel)+'-bit integer data type. This software may display this as SIGNED data. Bits per voxel: '+inttostr(lDicomData.Allocbits_per_pixel));
645
lImageFormatOK := false;
646
end else if (lFloat) then begin //zebra change float check
647
//Msg('WARNING: The image '+lFileName+' uses floating point [real] numbers. The current software can only read integer data type Interfile images.');
648
lDicomData.Float := true;
649
//lImageFormatOK := false;
658
function ParseFileName (lFilewExt:String): string;
664
lLen := length(lFilewExt);
669
until (lFileWExt[lInc] = '.') or (lInc = 1);
671
for lLen := 1 to (lInc - 1) do
672
lName := lName + lFileWExt[lLen]
674
lName := lFilewExt; //no extension
675
ParseFileName := lName;
678
procedure read_afni_data(var lDICOMdata: DICOMdata; var lHdrOK, lImageFormatOK: boolean; var lDynStr: string;var lFileName: string; var lRotation1,lRotation2,lRotation3: integer);
680
const UNIXeoln = chr(10);
683
var lTmpStr,lInStr,lUpCaseStr: string;
686
lOri : array [1..4] of single;
687
lTmpInt,lPos,lLen,FileSz,linPos: integer;
690
procedure readAFNIeoln;
692
while (linPos < FileSz) and (lCharRA^[linPos] <> ord(kCR)) and (lCharRA^[linPos] <> ord(UNIXeoln)) do
694
inc(lInPos); //read EOLN
696
function readAFNIFloat:real;
701
while (linPos < FileSz) and ((lStr='') or ((lCharRA^[lInPos] <> kTab) and (lCharRA^[lInPos] <> kSpace))) do begin
702
lCh:= chr(lCharRA^[linPos]);
703
if lCh in ['+','-','e','E','.','0'..'9'] then
707
if lStr = '' then exit;
709
result := strtofloat(lStr);
711
on EConvertError do begin
712
Msg('Unable to convert the string '+lStr+' to a number');
720
lImageFormatOK := true;
721
Clear_Dicom_Data(lDicomData);
723
lTmpStr := string(StrUpper(PChar(ExtractFileExt(lFileName))));
724
if lTmpStr <> '.HEAD' then exit;
725
for lInPos := 1 to 3 do
726
lOri[lInPos] := -6666;
727
FileMode := 0; //set to readonly
728
AssignFile(fp, lFileName);
730
FileSz := FileSize(fp);
732
//lDicomData.ImageStart := FileSz;
733
GetMem( lCharRA, FileSz+1 );
734
BlockRead(fp, lCharRA^, FileSz, linpos);
735
if lInPos <> FileSz then Msg('Disk error: Unable to read full input file.');
738
FileMode := 2; //set to read/write
741
while (linPos < FileSz) and (lCharRA^[linPos] <> ord(kCR)) and (lCharRA^[linPos] <> ord(UNIXeoln)) do begin
742
lInStr := lInstr + chr(lCharRA^[linPos]);
745
inc(lInPos); //read EOLN
746
lLen := length(lInStr);
749
While (lPos <= lLen) do begin
750
if lInStr[lPos] in ['_','[',']','(',')','/','+','-','=',{' ',} '0'..'9','a'..'z','A'..'Z'] then
751
lUpCaseStr := lUpCaseStr+upcase(linStr[lPos]);
754
inc(lPos); {read equal sign in := statement}
755
if lUpCaseStr ='NAME=DATASET_DIMENSIONS'then begin
756
lImageFormatOK := true;
758
lFileName := parsefilename(lFilename)+'.BRIK'; //always UPPERcase
760
lDICOMdata.XYZdim[1] := round(readAFNIFloat);
761
lDICOMdata.XYZdim[2] := round(readAFNIFloat);
762
lDICOMdata.XYZdim[3] := round(readAFNIFloat);
763
//lDicomData.ImageStart := 2048 * round(readInterFloat);
765
if lUpCaseStr ='NAME=BRICK_FLOAT_FACS'then begin
767
lDICOMdata.IntenScale := readAFNIFloat; //1380 read slope of intensity
769
if lUpCaseStr ='NAME=DATASET_RANK'then begin
771
//2nd value is number of volumes
773
lDICOMdata.XYZdim[4] := round(readAFNIFloat);
775
if lUpCaseStr ='NAME=BRICK_TYPES'then begin
777
lTmpInt := round(readAFNIFloat);
779
0:lDicomData.Allocbits_per_pixel := 8;
781
lDicomData.Allocbits_per_pixel := 16;
782
//lDicomData.MaxIntensity := 65535; //Old AFNI were UNSIGNED, new ones are SIGNED???
785
lDicomData.Allocbits_per_pixel := 32;
786
lDicomData.Float := true;
790
Msg('Unsupported AFNI BRICK_TYPES: '+inttostr(lTmpInt));
795
0 = byte (unsigned char; 1 byte)
796
1 = short (2 bytes, signed)
797
3 = float (4 bytes, assumed to be IEEE format)
798
5 = complex (8 bytes: real+imaginary parts)}
800
if lUpCaseStr ='NAME=BYTEORDER_STRING'then begin
802
if ((linPos+2) < FileSz) then begin
803
lMSBch := chr(lCharRA^[linPos+1]);
804
if lMSBCh = 'L' then lDicomData.Little_Endian := 1;
805
if lMSBCh = 'M' then begin
806
lDicomData.Little_Endian := 0;
808
linPos := lInPos + 2;
812
if lUpCaseStr ='NAME=ORIGIN'then begin
814
lOri[1] := (abs(readAFNIFloat));
815
lOri[2] := (abs(readAFNIFloat));
816
lOri[3] := (abs(readAFNIFloat));
819
if lUpCaseStr ='NAME=DELTA'then begin
821
lDICOMdata.XYZmm[1] := abs(readAFNIFloat);
822
lDICOMdata.XYZmm[2] := abs(readAFNIFloat);
823
lDICOMdata.XYZmm[3] := abs(readAFNIFloat);
827
if lUpCaseStr ='NAME=ORIENT_SPECIFIC'then begin
829
lRotation1 := round(readAFNIFloat);
830
lRotation2 := round(readAFNIFloat);
831
lRotation3 := round(readAFNIFloat);
832
end; //ORIENT_SPECIFIC rotation details
834
lDynStr := lDynStr + lInStr+kCr;
835
until (linPos >= FileSz) or (lHdrEnd){EOF(fp)};
836
//xlDicomData.Storedbits_per_pixel := lDicomData.Allocbits_per_pixel;
837
for lInPos := 1 to 3 do begin
838
if lOri[lInPos] < -6666 then //value not set
839
lDICOMdata.XYZori[lInPos] := round((1.0+lDICOMdata.XYZdim[lInPos])/2)
840
else if lDICOMdata.XYZmm[lInPos] <> 0 then
841
lDICOMdata.XYZori[lInPos] := round(1.5+lOri[lINPos] / lDICOMdata.XYZmm[lInPos]);
843
// lDicomData.Float := true;
848
procedure read_voxbo_data(var lDICOMdata: DICOMdata; var lHdrOK, lImageFormatOK: boolean; var lDynStr: string;var lFileName: string);
850
const UNIXeoln = chr(10);
852
var lTmpStr,lInStr,lUpCaseStr: string;
853
lFileTypeKnown,lHdrEnd,lFloat: boolean;
854
lStartPos,lPos,lLen,FileSz,linPos: integer;
857
procedure readVBfloats (var lF1,lF2,lF3: double);
858
// While (lPos <= lLen) and ((lInStr[lPos] = kTab) or (lInStr[lPos] = ' ')) do begin
860
var //lDigit : boolean;
861
n,lItemIndex: integer;
868
for lItemIndex := 1 to 3 do begin
870
While (lPos <= lLen) and ((lInStr[lPos] = kTab) or (lInStr[lPos] = ' ')) do
876
lStr := lStr+upcase(linStr[lPos]);
878
until (lPos > lLen) or (lInStr[lPos] = kTab) or (lInStr[lPos] = ' ');
879
if lStr <> '' then begin //string to convert
882
1: lF1 := strtofloat(lStr);
883
2: lF2 := strtofloat(lStr);
884
3: lF3 := strtofloat(lStr);
887
on EConvertError do begin
888
Msg('Unable to convert the string '+lfStr+' to a real number');
892
end; //if string to convert
896
procedure readVBints (var lI1,lI2,lI3: integer);
897
var lF1,lF2,lF3: double;
899
readVBfloats (lF1,lF2,lF3);
904
function readVBStr:string;
908
While (lPos <= lLen) and ((lInStr[lPos] = kTab) or (lInStr[lPos] = ' ')) do begin
911
While (lPos <= lLen) {and (lInStr[lPos] <> ';')} do begin
912
lStr := lStr+upcase(linStr[lPos]); //zebra upcase
920
lImageFormatOK := true;
921
Clear_Dicom_Data(lDicomData);
923
FileMode := 0; //set to readonly
924
AssignFile(fp, lFileName);
926
FileSz := FileSize(fp);
928
//lDicomData.ImageStart := FileSz;
929
GetMem( lCharRA, FileSz+1 );
930
BlockRead(fp, lCharRA^, FileSz, linpos);
931
if lInPos <> FileSz then Msg('Disk error: Unable to read full input file.');
934
FileMode := 2; //set to read/write
935
lFileTypeKnown := false;
939
while (linPos < FileSz) and (lCharRA^[linPos] <> ord(kCR)) and (lCharRA^[linPos] <> ord(UNIXeoln)) do begin
940
lInStr := lInstr + chr(lCharRA^[linPos]);
943
inc(lInPos); //read EOLN
944
lLen := length(lInStr);
947
While (lPos <= lLen) and (lInStr[lPos] <> ':') do begin
948
if lInStr[lPos] in ['[',']','(',')','/','+','-', '0'..'9','a'..'z','A'..'Z'] then
949
lUpCaseStr := lUpCaseStr+upcase(linStr[lPos]);
952
inc(lPos); {read equal sign in := statement}
953
if (lHdrOK) and (not lFileTypeKnown) and (lUpCaseStr = 'CUB1') then
954
lFileTypeKnown := true;
955
if (lHdrOK) and (not lFileTypeKnown) then begin
956
Msg('This software can not read this kind of VoxBo image. (Type:"'+lUpCaseStr+'")');
960
if (not lHdrOK) and (lUpCaseStr ='VB98') then begin
961
lDicomData.little_endian := 0;//all VoxBo files are Big Endian!
963
lFileTypeKnown := true; //test for While Loop
964
while (linPos < FileSz) and lFileTypeKnown do begin
965
if (lCharRA^[linPos-1] = $0C) and (lCharRA^[linPos] = $0A) then begin
966
lFileTypeKnown := false;
967
lDicomData.ImageStart := linPos;
968
FileSz := linPos; //size of VoxBo header
972
if lFileTypeKnown then begin //end of file character not found: abort!
973
Msg('Unable to find the end of the VoxBo header.');
977
linPos := lStartPos; //now that we have found the header size, we can start from the beginning of the header
979
if not lHdrOK then lHdrEnd := true;
980
if (lUpCaseStr ='BYTEORDER') and (readVBStr = 'LSBFIRST') then
981
lDicomData.little_endian := 1;
982
if lUpCaseStr ='DATATYPE'then begin
983
lTmpStr := readVBStr;
984
if lTmpStr = 'Byte' then
985
lDicomData.Allocbits_per_pixel := 8
986
else if (lTmpStr = 'INTEGER') or (lTmpStr = 'INT16') then
987
lDicomData.Allocbits_per_pixel := 16
988
else if (lTmpStr = 'LONG') or (lTmpStr = 'INT32') then
989
lDicomData.Allocbits_per_pixel := 32
990
else if (lTmpStr = 'FLOAT') then begin
992
lDicomData.Allocbits_per_pixel := 32;
993
end else if (lTmpStr = 'DOUBLE') then begin
995
lDicomData.Allocbits_per_pixel := 64;
997
Msg('Unknown VoxBo data format: '+lTmpStr);
1000
if lUpCaseStr ='VOXDIMS(XYZ)'then readVBints(lDicomData.XYZdim[1],lDicomData.XYZdim[2],lDicomData.XYZdim[3]);
1001
if (lUpCaseStr ='VOXSIZES(XYZ)') then readVBfloats(lDicomData.XYZmm[1],lDicomData.XYZmm[2],lDicomData.XYZmm[3]);
1002
if (lUpCaseStr ='ORIGIN(XYZ)')then begin
1003
readVBints(lDicomData.XYZori[1],lDicomData.XYZori[2],lDicomData.XYZori[3]);
1004
inc(lDicomData.XYZori[1]);//1393
1005
inc(lDicomData.XYZori[2]);//1393
1006
inc(lDicomData.XYZori[3]);//1393
1008
if not lHdrOK then goto 333;
1009
if lInStr <> '' then
1010
lDynStr := lDynStr + lInStr+kCr;
1011
until (linPos >= FileSz) or (lHdrEnd){EOF(fp)};
1012
//xlDicomData.Storedbits_per_pixel := lDicomData.Allocbits_per_pixel;
1013
//xlDicomData.Rotate180deg := true;
1014
lImageFormatOK := true;
1015
if (lFloat) then begin //zebra change float check
1016
lDicomData.Float := true;
1017
//lImageFormatOK := false;
1024
procedure read_vff_data(var lDICOMdata: DICOMdata; var lHdrOK, lImageFormatOK: boolean; var lDynStr: string;var lFileName: string);
1026
const UNIXeoln = chr(10);
1027
var lInStr,lUpCaseStr: string;
1029
lPos,lLen,FileSz,linPos: integer;
1030
lDummy1,lDummy2,lDummy3 : double;
1033
procedure readVFFvals (var lFloat1,lFloat2,lFloat3: double);
1038
for lInc := 1 to 3 do begin
1040
While (lPos <= lLen) and (lInStr[lPos] = ' ') do begin
1043
While (lPos <= lLen) and (lInStr[lPos] <> ';') and (lInStr[lPos] <> ' ') do begin
1044
if lInStr[lPos] in ['+','-','e','E','.','0'..'9'] then
1045
lStr := lStr+(linStr[lPos]);
1048
if lStr <> '' then begin
1050
lDouble := strtofloat(lStr);
1052
on EConvertError do begin
1053
Msg('Unable to convert the string '+lStr+' to a number');
1058
2: lFloat2 := lDouble;
1059
3: lFloat3 := lDouble;
1060
else lFloat1 := lDouble;
1064
end; //interstr func
1067
lImageFormatOK := true;
1068
Clear_Dicom_Data(lDicomData);
1069
lDicomData.little_endian := 0; //big-endian
1071
FileMode := 0; //set to readonly
1072
AssignFile(fp, lFileName);
1074
FileSz := FileSize(fp);
1075
if FileSz > 2047 then FileSz := 2047;
1076
GetMem( lCharRA, FileSz+1 );
1077
BlockRead(fp, lCharRA^, FileSz, linpos);
1078
if lInPos <> FileSz then Msg('Disk error: Unable to read full input file.');
1080
while (lCharRA^[lInPos] <> 12) and (lInPos < FileSz) do begin
1084
if (lInPos >= FileSz) or (lInPos < 12) then goto 333; //unable to find
1085
lDynStr := lDynStr + 'Sun VFF Volume File Format'+kCr;
1086
lDicomData.ImageStart := lInPos;
1090
FileMode := 2; //set to read/write
1093
while (linPos < FileSz) and (lCharRA^[linPos] <> ord(kCR)) and (lCharRA^[linPos] <> ord(UNIXeoln)) do begin
1094
lInStr := lInstr + chr(lCharRA^[linPos]);
1097
inc(lInPos); //read EOLN
1098
lLen := length(lInStr);
1101
While (lPos <= lLen) and (lInStr[lPos] <> ';') and (lInStr[lPos] <> '=') and (lUpCaseStr <>'NCAA') do begin
1102
if lInStr[lPos] in ['[',']','(',')','/','+','-',{' ',} '0'..'9','a'..'z','A'..'Z'] then
1103
lUpCaseStr := lUpCaseStr+upcase(linStr[lPos]);
1106
inc(lPos); {read equal sign in := statement}
1107
if lUpCaseStr ='NCAA' then begin
1110
if lUpCaseStr ='BITS' then begin
1112
readVFFvals(lDummy1,lDummy2,lDummy3);
1113
lDicomData.Allocbits_per_pixel := round(lDummy1);
1115
if lUpCaseStr ='SIZE' then begin
1116
lDummy1 := 1; lDummy2 := 1; lDummy3 := 1;
1117
readVFFvals(lDummy1,lDummy2,lDummy3);
1118
lDicomData.XYZdim[1] := round(lDummy1);
1119
lDicomData.XYZdim[2] := round(lDummy2);
1120
lDicomData.XYZdim[3] := round(lDummy3);
1122
if lUpCaseStr ='ASPECT' then begin
1123
lDummy1 := 1; lDummy2 := 1; lDummy3 := 1;
1124
readVFFvals(lDummy1,lDummy2,lDummy3);
1125
lDicomData.XYZmm[1] := (lDummy1);
1126
lDicomData.XYZmm[2] := (lDummy2);
1127
lDicomData.XYZmm[3] := (lDummy3);
1129
if not lHdrOK then goto 333;
1130
if lInStr <> '' then
1131
lDynStr := lDynStr + lInStr+kCr;
1133
until (linPos >= FileSz);
1134
//xlDicomData.Storedbits_per_pixel := lDicomData.Allocbits_per_pixel;
1135
lImageFormatOK := true;
1139
//********************************************************************
1140
(*procedure ShellSortItems (first, last: integer; var lPositionRA, lIndexRA: LongintP; var lRepeatedValues: boolean);
1141
{Shell sort chuck uses this- see 'Numerical Recipes in C' for similar sorts.}
1146
aln2i = 1.442695022;
1148
n,t, nn, m, lognb2, l, k, j, i: longint;
1150
lRepeatedValues := false;
1151
n := abs(last - first + 1);
1152
lognb2 := trunc(ln(n) * aln2i + tiny);
1154
for nn := 1 to lognb2 do
1158
for j := 1 to k do begin
1162
if (lIndexRA^[lPositionRA^[l]] = lIndexRA^[lPositionRA^[i]]) then begin
1163
lRepeatedValues := true;
1166
if (lIndexRA^[lPositionRA^[l]] < lIndexRA^[lPositionRA^[i]]) then begin
1167
//swap values for i and l
1168
t := lPositionRA^[i];
1169
lPositionRA^[i] := lPositionRA^[l];
1170
lPositionRA^[l] := t;
1177
end; //shellsort is fast and requires less memory than quicksort *)
1180
(*procedure PAR2DICOMstudyDate(var lDicomData: DICOMdata);
1181
{input: lDicomData.StudyDate = 2002.12.29 / 19:48:58.0000
1182
output: StudyDate = YYYYMMDD StudyTime= hhmmss }
1187
if length(lDicomData.StudyDate) < 14 then exit;
1189
for I := 1 to length(lDicomData.StudyDate) do
1190
if lDicomData.StudyDate[I] in ['0'..'9'] then
1191
lStr := lStr+ lDicomData.StudyDate[I];
1192
if length(lStr) < 14 then exit;
1193
lDicomData.StudyDate := '';
1195
lDicomData.StudyDate := lDicomData.StudyDate+lStr[I];
1196
lDicomData.StudyTime := '';
1198
lDicomData.StudyTime := lDicomData.StudyTime+lStr[I];
1199
lDicomData.PatientIDInt := StudySecSince2K(lDicomData.StudyDate,lDicomData.StudyTime);
1201
type tRange = record
1202
Min,Val,Max: double; //some vals are ints, others floats
1205
procedure read_PAR_data(var lDICOMdata: DICOMdata; var lHdrOK, lImageFormatOK:boolean; var lDynStr: string;var lFileName: string; lReadOffsetTables: boolean; var lOffset_pos_table: LongIntp; var lOffsetTableEntries: integer; lReadVaryingScaleFactors: boolean; var lVaryingScaleFactors_table,lVaryingIntercept_table: Singlep; var lVaryingScaleFactorsTableEntries,lnum4Ddatasets: integer);
1206
label 333; //1384 now reads up to 8 dimensional data....
1207
const UNIXeoln = chr(10);
1208
kMaxnSLices = 32000;
1218
kCalibratedSlope = 10; //1393 - attempt to use calibrated values
1227
lIsParVers3x: boolean = true;
1228
lRepeatedValues : boolean = false;
1229
lSlicesNotInSequence: boolean = false;
1230
lMaxSlice : integer = 0;
1232
lErrorStr,lInStr,lUpCaseStr,lReportedTRStr: string;
1233
lSliceSequenceRA,lSortedSliceSequence: LongintP;
1234
lSliceIndexRA: array [1..kMaxnSlices] of Longint;
1235
lSliceSlopeRA,lSliceInterceptRA,lCalibratedSliceSlopeRA: array [1..kMaxnSlices] of single;
1236
lSliceHeaderRA: array [1..32] of double;
1237
lRangeRA: array [kXdim..kIndex] of tRange;
1238
lMaxIndex,lSliceSz,lSliceInfoCount,lPos,lLen,lFileSz,lHdrPos,linPos,lInc: LongInt;
1242
procedure MinMaxTRange (var lDimension: tRange; lNewVal: double); //nested
1244
lDimension.Val := lNewVal;
1245
if lSliceInfoCount < 2 then begin
1246
lDimension.Min := lDimension.Val;
1247
lDimension.Max := lDimension.Val;
1249
if lNewVal < lDimension.Min then lDimension.Min := lNewVal;
1250
if lNewVal > lDimension.Max then lDimension.Max := lNewVal;
1251
end; //nested InitTRange proc
1253
function readParStr:string;//nested
1257
While (lPos <= lLen) do begin
1258
if (lStr <> '') or (linStr[lPos]<>' ') then //strip leading spaces
1259
lStr := lStr+(linStr[lPos]);
1261
end; //while lPOs < lLen
1263
end; //nested func ReadParStr
1264
function readParFloat:double;//nested
1269
While (lPos <= lLen) and ((lStr='') or(lInStr[lPos] <> ' ')) do begin
1270
if lInStr[lPos] in ['+','-','e','E','.','0'..'9'] then
1271
lStr := lStr+(linStr[lPos]);
1274
if lStr = '' then exit;
1276
result := strtofloat(lStr);
1278
on EConvertError do begin
1279
Msg('read_PAR_data: Unable to convert the string '+lStr+' to a number');
1284
end; //nested func ReadParFloat
1286
//Initialize parameters
1287
lnum4Ddatasets := 1;
1288
lSliceInfoCount := 0;
1289
for lInc := kXdim to kIndex do //initialize all values: important as PAR3 will not explicitly report all
1290
MinMaxTRange(lRangeRA[lInc],0);
1292
lImageFormatOK := false;
1293
lIsParVers3x := true;
1294
lOffsetTableEntries := 0;
1295
lVaryingScaleFactorsTableEntries := 0;
1296
Clear_Dicom_Data(lDicomData);
1298
//Read text header to buffer (lCharRA)
1299
FileMode := 0; //set to readonly
1300
AssignFile(fp, lFileName);
1302
lFileSz := FileSize(fp);
1303
GetMem( lCharRA, lFileSz+1 ); //note: must free dynamic memory: goto 333 if any error
1304
GetMem (lSliceSequenceRA, kMaxnSLices*sizeof(longint)); //note: must free dynamic memory: goto 333 if any error
1305
BlockRead(fp, lCharRA^, lFileSz, lInpos);
1306
if lInPos <> lFileSz then begin
1307
Msg('read_PAR_data: Disk error, unable to read full input file.');
1312
FileMode := 2; //set to read/write
1313
//Next: read each line of header file...
1314
repeat //for each line in file....
1316
while (linPos < lFileSz) and (lCharRA^[linPos] <> ord(kCR)) and (lCharRA^[linPos] <> ord(UNIXeoln)) do begin
1317
lInStr := lInstr + chr(lCharRA^[linPos]);
1320
inc(lInPos); //read EOLN
1321
lLen := length(lInStr);
1325
//ignore blank lines
1326
else if (lInStr[1] = '*') and (not lHdrOK) then //# -> comment
1327
//ignore comment lines prior to start of header
1328
else if (lInStr[1] = '#') and (lHdrOK) then //# -> comment
1329
//ignore comment lines
1330
else if (lInStr[1] = '.') or (not lHdrOK) then begin // GENERAL_INFORMATION section (line starts with '.')
1331
//Note we also read in lines that do not have '.' if we have HdrOK=false, this allows us to detect the DATADESCRIPTIONFILE signature
1332
While (lPos <= lLen) and (lInStr[lPos] <> ':') and ((not lHdrOK) or (lInStr[lPos] <> '#')) do begin
1333
if lInStr[lPos] in ['[',']','(',')','/','+','-',{' ',} '0'..'9','a'..'z','A'..'Z'] then
1334
lUpCaseStr := lUpCaseStr+upcase(linStr[lPos]);
1336
end; //while reading line
1337
inc(lPos); {read equal sign in := statement}
1338
lDynStr := lDynStr + lInStr+kCR;
1339
if (not lHdrOK) and (lUpcaseStr = ('DATADESCRIPTIONFILE')) then begin //1389 PAR file
1341
lDicomData.little_endian := 1;
1346
if (lUpCaseStr ='REPETITIONTIME[MSEC]') then
1347
lDicomData.TR := round(readParFloat);
1348
if (lUpCaseStr ='MAXNUMBEROFSLICES/LOCATIONS') then
1349
lDicomData.XYZdim[3] := round(readParFloat);
1350
if (lUpCaseStr ='SLICETHICKNESS[MM]') then
1351
MinMaxTRange(lRangeRA[kSliceThick],readParFloat);
1352
if (lUpCaseStr ='SLICEGAP[MM]') then
1353
MinMaxTRange(lRangeRA[kSliceGap],readParFloat);
1354
if lUpCaseStr = 'RECONRESOLUTION(XY)' then begin
1355
MinMaxTRange(lRangeRA[kXdim],readParFloat);
1356
MinMaxTRange(lRangeRA[kYdim],readParFloat);
1358
if lUpCaseStr = 'RECONSTRUCTIONNR' then
1359
lDicomData.AcquNum := round(readParFloat);
1360
if lUpCaseStr = 'ACQUISITIONNR' then
1361
lDicomData.SeriesNum := round(readParFloat);
1362
if lUpCaseStr = 'MAXNUMBEROFDYNAMICS' then begin
1363
lDicomData.XYZdim[4] := round(readParFloat);
1365
if lUpCaseStr = 'EXAMINATIONDATE/TIME' then begin
1366
lDicomData.StudyDate := readParStr;
1367
PAR2DICOMstudyDate(lDicomData);
1369
//if lUpCaseStr = 'PROTOCOLNAME' then
1370
// lDicomData.modality := readParStr;
1371
if lUpCaseStr = 'PATIENTNAME' then
1372
lDicomData.PatientName := readParStr;
1373
if lUpCaseStr ='IMAGEPIXELSIZE[8OR16BITS]' then begin
1374
MinMaxTRange(lRangeRA[kBitsPerVoxel],readParFloat);
1376
if not lHdrOK then begin
1377
Msg('read_PAR_data: Error reading header');
1380
end else begin //SliceInfo: IMAGE_INFORMATION (line does NOT start with '.' or '#')
1381
inc(lSliceInfoCount);
1382
if (lSliceInfoCount < 2) and (lRangeRA[kBitsPerVoxel].val < 1) then //PARvers3 has imagedepth in general header, only in image header for later versions
1383
lIsParVers3x := false;
1384
for lHdrPos := 1 to 26 do
1385
lSliceHeaderRA[lHdrPos] := readparfloat;
1386
//The next few values are in the same location for both PAR3 and PAR4
1387
MinMaxTRange(lRangeRA[kSlice], round(lSliceHeaderRA[1]));
1388
MinMaxTRange(lRangeRA[kEcho], round(lSliceHeaderRA[2]));
1389
MinMaxTRange(lRangeRA[kDyn], round(lSliceHeaderRA[3]));
1390
MinMaxTRange(lRangeRA[kCardiac], round(lSliceHeaderRA[4]));
1391
MinMaxTRange(lRangeRA[kType], round(lSliceHeaderRA[5]));
1392
MinMaxTRange(lRangeRA[kSequence], round(lSliceHeaderRA[6]));
1393
MinMaxTRange(lRangeRA[kIndex], round(lSliceHeaderRA[7]));
1394
if lIsParVers3x then begin //Read PAR3 data
1395
MinMaxTRange(lRangeRA[kIntercept], lSliceHeaderRA[8]);; //8=intercept in PAR3
1396
MinMaxTRange(lRangeRA[kSlope],lSliceHeaderRA[9]); //9=slope in PAR3
1397
MinMaxTRange(lRangeRA[kCalibratedSlope],lSliceHeaderRA[10]); //10=lcalibrated slope in PAR3 1393 - attempt to use calibrated values
1398
MinMaxTRange(lRangeRA[kXmm],lSliceHeaderRA[23]); //23 PIXEL SPACING X in PAR3
1399
MinMaxTRange(lRangeRA[kYmm],lSliceHeaderRA[24]); //24 PIXEL SPACING Y IN PAR3
1400
MinMaxTRange(lRangeRA[kDynTime],(lSliceHeaderRA[26])); //26= dyn_scan_begin_time in PAR3
1401
end else begin //not PAR: assume PAR4
1402
for lHdrPos := 27 to 32 do
1403
lSliceHeaderRA[lHdrPos] := readparfloat;
1404
MinMaxTRange(lRangeRA[kBitsPerVoxel],lSliceHeaderRA[8]);//8 BITS in PAR4
1405
MinMaxTRange(lRangeRA[kXdim], lSliceHeaderRA[10]); //10 XDim in PAR4
1406
MinMaxTRange(lRangeRA[kYdim], lSliceHeaderRA[11]); //11 YDim in PAR4
1407
MinMaxTRange(lRangeRA[kIntercept],lSliceHeaderRA[12]); //12=intercept in PAR4
1408
MinMaxTRange(lRangeRA[kSlope],lSliceHeaderRA[13]); //13=lslope in PAR4
1409
MinMaxTRange(lRangeRA[kCalibratedSlope],lSliceHeaderRA[14]); //14=lcalibrated slope in PAR4 1393 - attempt to use calibrated values
1410
MinMaxTRange(lRangeRA[kSliceThick],lSliceHeaderRA[23]);//23 SLICE THICK in PAR4
1411
MinMaxTRange(lRangeRA[kSliceGap], lSliceHeaderRA[24]); //24 SLICE GAP in PAR4
1412
MinMaxTRange(lRangeRA[kXmm],lSliceHeaderRA[29]); //29 PIXEL SPACING X in PAR4
1413
MinMaxTRange(lRangeRA[kYmm],lSliceHeaderRA[30]); //30 PIXEL SPACING Y in PAR4
1414
MinMaxTRange(lRangeRA[kDynTime],(lSliceHeaderRA[32]));//32= dyn_scan_begin_time in PAR4
1416
if lSliceInfoCount < kMaxnSlices then begin
1417
lSliceSequenceRA^[lSliceInfoCount] := ( (round(lRangeRA[kSequence].val)+round(lRangeRA[kType].val)+round(lRangeRA[kCardiac].val+lRangeRA[kEcho].val)) shl 24)+(round(lRangeRA[kDyn].val) shl 10)+round(lRangeRA[kSlice].val);
1418
lSliceSlopeRA [lSliceInfoCount] := lRangeRA[kSlope].Val;
1419
lCalibratedSliceSlopeRA [lSliceInfoCount] := lRangeRA[kCalibratedSlope].Val;
1420
lSliceInterceptRA [lSliceInfoCount] := lRangeRA[kIntercept].val;
1421
lSliceIndexRA[lSliceInfoCount]:= round(lRangeRA[kIndex].val);
1423
end; //SliceInfo Line
1424
until (linPos >= lFileSz);//until done reading entire file...
1425
//describe generic DICOM parameters
1426
lDicomData.XYZdim[1] := round(lRangeRA[kXdim].Val);
1427
lDicomData.XYZdim[2] := round(lRangeRA[kYdim].Val);
1428
lDicomData.XYZdim[3] := 1+round(lRangeRA[kSlice].Max-lRangeRA[kSlice].Min);
1429
if (lSliceInfoCount mod lDicomData.XYZdim[3]) <> 0 then
1430
Msg('read_PAR_data: Total number of slices not divisible by number of slices per volume. Reconstruction error?');
1431
if lDicomData.XYZdim[3] > 0 then
1432
lDicomData.XYZdim[4] := lSliceInfoCount div lDicomData.XYZdim[3] //nVolumes = nSlices/nSlicePerVol
1434
lDicomData.XYZdim[4] := 1;
1436
lDicomData.XYZmm[1] := lRangeRA[kXmm].Val;
1437
lDicomData.XYZmm[2] := lRangeRA[kYmm].Val;
1438
lDicomData.XYZmm[3] := lRangeRA[kSliceThick].Val+lRangeRA[kSliceGap].Val;
1439
lDicomData.Allocbits_per_pixel := round(lRangeRA[kBitsPerVoxel].Val);
1440
lDicomData.IntenScale := lRangeRA[kSlope].Val;
1441
lDicomData.IntenIntercept := lRangeRA[kIntercept].Val;
1442
if gPARprecise then begin
1443
if (lDicomData.IntenIntercept <> 0) or (lRangeRA[kCalibratedSlope].val = 0) then
1444
Msg('Warning: Unable to save calibrated Philips image intensity (non-zero scaling intercept). Turn off Etc/Options/CalibratedScaling to hide warning.');
1445
if (lRangeRA[kSlope].min = lRangeRA[kSlope].max)
1446
and (lRangeRA[kIntercept].min = lRangeRA[kIntercept].max)
1447
and (lRangeRA[kCalibratedSlope].min = lRangeRA[kCalibratedSlope].max)
1448
and (lDicomData.IntenIntercept = 0) and (lRangeRA[kCalibratedSlope].val <> 0) then
1449
lDicomData.IntenScale := 1 / lRangeRA[kCalibratedSlope].val;
1450
end; //if PARprecise
1451
//Next: report number of Dynamic scans, this allows people to parse DynScans from Type/Cardiac/Echo/Sequence 4D files
1452
lnum4Ddatasets := (round(lRangeRA[kDyn].Max - lRangeRA[kDyn].Min)+1)*lDicomData.XYZdim[3]; //slices in each dynamic session
1453
if ((lSliceInfoCount mod lnum4Ddatasets) = 0) and ((lSliceInfoCount div lnum4Ddatasets) > 1) then
1454
lnum4Ddatasets := (lSliceInfoCount div lnum4Ddatasets) //infer multiple Type/Cardiac/Echo/Sequence
1456
lnum4Ddatasets := 1;
1457
//next: Determine actual interscan interval
1458
if (lDicomData.XYZdim[4] > 1) and ((lRangeRA[kDynTime].max-lRangeRA[kDynTime].min)> 0) {1384} then begin
1459
lReportedTRStr := 'Reported TR: '+floattostrf(lDicomData.TR,ffFixed,8,2)+kCR;
1460
lDicomData.TR := (lRangeRA[kDynTime].max-lRangeRA[kDynTime].min) /(lDicomData.XYZdim[4] - 1)*1000; //infer TR in ms
1462
lReportedTRStr :='';
1463
//next: report header details
1464
lDynStr := 'Philips PAR/REC Format' //'PAR/REC Format'
1465
+kCR+ 'Patient name:'+lDicomData.PatientName
1466
+kCR+ 'XYZ dim: ' +inttostr(lDicomData.XYZdim[1])+'/'+inttostr(lDicomData.XYZdim[2])+'/'+inttostr(lDicomData.XYZdim[3])
1467
+kCR+'Volumes: ' +inttostr(lDicomData.XYZdim[4])
1468
+kCR+'XYZ mm: '+floattostrf(lDicomData.XYZmm[1],ffFixed,8,2)+'/'
1469
+floattostrf(lDicomData.XYZmm[2],ffFixed,8,2)+'/'+floattostrf(lDicomData.XYZmm[3],ffFixed,8,2)
1470
+kCR+'TR: '+floattostrf(lDicomData.TR,ffFixed,8,2)
1471
+kCR+lReportedTRStr+kCR+lDynStr;
1472
//if we get here, the header is fine, next steps will see if image format is readable...
1474
if lSliceInfoCount < 1 then
1476
//next: see if slices are in sequence
1477
lSlicesNotInSequence := false;
1478
if lSliceInfoCount > 1 then begin
1479
lMaxSlice := lSliceSequenceRA^[1];
1480
lMaxIndex := lSliceIndexRA[1];
1484
if lSliceSequenceRA^[lInc] < lMaxSlice then //not in sequence if image has lower slice order than previous image
1485
lSlicesNotInSequence := true
1487
lMaxSlice := lSliceSequenceRA^[lInc];
1488
if lSliceIndexRA[lInc] < lMaxIndex then //not in sequence if image has lower slice index than previous image
1489
lSlicesNotInSequence := true
1491
lMaxIndex := lSliceIndexRA[lInc];
1492
until (lInc = lSliceInfoCount) or (lSlicesNotInSequence);
1493
end; //at least 2 slices
1494
//Next: report any errors
1496
if (lSlicesNotInSequence) and (not lReadOffsetTables) then
1497
lErrorStr := lErrorStr + ' Slices not saved sequentially [using MRIcro''s ''Philips PAR to Analyze'' command may solve this]'+kCR;
1498
if lSliceInfoCount > kMaxnSlices then
1499
lErrorStr := lErrorStr + ' Too many slices: >'+inttostr(kMaxnSlices)+kCR;
1500
if (not lReadVaryingScaleFactors) and ( (lRangeRA[kSlope].min <> lRangeRA[kSlope].max)
1501
or (lRangeRA[kIntercept].min <> lRangeRA[kIntercept].max)) then
1502
lErrorStr := lErrorStr + ' Differing intensity slope/intercept [using MRIcro''s ''Philips PAR to Analyze'' command may solve this]'+kCR;
1503
if (lRangeRA[kBitsPerVoxel].min <> lRangeRA[kBitsPerVoxel].max) then //5D file space+time+cardiac
1504
lErrorStr := lErrorStr + ' Differing bits per voxel'+kCR;
1505
//if (lRangeRA^[kCardiac].min <> lRangeRA^[kCardiac].max) then //5D file space+time+cardiac
1506
// lErrorStr := lErrorStr + 'Multiple cardiac timepoints'+kCR;
1507
//if (lRangeRA^[kEcho].min <> lRangeRA^[kEcho].max) then //5D file space+time+echo
1508
// lErrorStr := lErrorStr + 'Multiple echo timepoints'+kCR;
1509
if (lRangeRA[kSliceThick].min <> lRangeRA[kSliceThick].max) or (lRangeRA[kSliceGap].min <> lRangeRA[kSliceGap].max)
1510
or (lRangeRA[kXdim].min <> lRangeRA[kXdim].max) or (lRangeRA[kYDim].min <> lRangeRA[kYDim].max)
1511
or (lRangeRA[kXmm].min <> lRangeRA[kXmm].max) or (lRangeRA[kYmm].min <> lRangeRA[kYmm].max) then
1512
lErrorStr := lErrorStr + ' Multiple/varying slice dimensions'+kCR;
1513
//if any errors were encountered, report them....
1514
if lErrorStr <> '' then begin
1515
Msg('read_PAR_data: This software can not convert this Philips data:'+kCR+lErrorStr);
1518
//Next sort image indexes here...
1519
if (lSliceInfoCount > 1) and(lSlicesNotInSequence) and ( lReadOffsetTables) then begin //sort image order...
1520
//ShellSort (first, last: integer; var lPositionRA, lIndexLoRA,lIndexHiRA: LongintP; var lRepeatedValues: boolean)
1521
GetMem (lOffset_pos_table, lSliceInfoCount*sizeof(longint));
1522
for lInc := 1 to lSliceInfoCount do
1523
lOffset_pos_table^[lInc] := lInc;
1524
ShellSortItems (1, lSliceInfoCount,lOffset_pos_table,lSliceSequenceRA, lRepeatedValues);
1525
if lRepeatedValues then begin
1526
Msg('read_PAR_data: fatal error, slices do not appear to have unique indexes [multiple copies of same slice]');
1527
FreeMem (lOffset_pos_table);
1530
lOffsetTableEntries := lSliceInfoCount;
1531
end; //sort image order...
1532
//Next, generate list of scale slope
1533
if (lSliceInfoCount > 1) and (lReadVaryingScaleFactors) and ( (lRangeRA[kSlope].min <> lRangeRA[kSlope].max)
1534
or (lRangeRA[kIntercept].min <> lRangeRA[kIntercept].max)) then begin {create offset LUT}
1535
lVaryingScaleFactorsTableEntries := lSliceInfoCount;
1536
getmem (lVaryingScaleFactors_table, lVaryingScaleFactorsTableEntries*sizeof(single));
1537
getmem (lVaryingIntercept_table, lVaryingScaleFactorsTableEntries*sizeof(single));
1538
if lOffsetTableEntries = lSliceInfoCount then begin //need to sort slices
1540
for lInc := 1 to lSliceInfoCount do begin
1541
lVaryingScaleFactors_table^[lInc] := lSliceSlopeRA[lOffset_pos_table^[lInc]];
1542
lVaryingIntercept_table^[lInc] := lSliceInterceptRA[lOffset_pos_table^[lInc]];
1543
if gPARprecise then begin
1544
if (lVaryingIntercept_table^[lInc] <> 0) or (lCalibratedSliceSlopeRA[lOffset_pos_table^[lInc]]=0) then
1545
Msg('Warning: Unable to save calibrated Philips image intensity (non-zero scaling intercept). Turn off Etc/Options/CalibratedScaling to hide warning.')
1547
lVaryingScaleFactors_table^[lInc] := 1 / lCalibratedSliceSlopeRA[lOffset_pos_table^[lInc]];
1549
end; //if PARprecise
1552
end else begin //if sorted, else unsorted
1554
for lInc := 1 to lSliceInfoCount do begin
1555
lVaryingScaleFactors_table^[lInc] := lSliceSlopeRA[lInc];
1556
lVaryingIntercept_table^[lInc] := lSliceInterceptRA[lInc];
1557
if gPARprecise then begin
1558
if (lVaryingIntercept_table^[lInc] <> 0) or (lCalibratedSliceSlopeRA[lInc]=0) then
1559
Msg('Warning: Unable to save calibrated Philips image intensity (non-zero scaling intercept). Turn off Etc/Options/CalibratedScaling to hide warning.')
1561
lVaryingScaleFactors_table^[lInc] := 1 / lCalibratedSliceSlopeRA[lInc];
1562
end; //if PARprecise
1565
end; //slices sorted
1566
end;//read scale factors
1567
//Next: now adjust Offsets to point to byte offset instead of slice number
1568
lSliceSz := lDicomData.XYZdim[1]*lDicomData.XYZdim[2]*(lDicomData.Allocbits_per_pixel div 8);
1569
if lOffsetTableEntries = lSliceInfoCount then
1570
for lInc := 1 to lSliceInfoCount do
1571
lOffset_pos_table^[lInc] := lSliceSz * (lSliceIndexRA[lOffset_pos_table^[lInc]]);
1572
//report if 5D/6D/7D file is being saved as 4D
1573
if (lRangeRA[kCardiac].min <> lRangeRA[kCardiac].max)
1574
or (lRangeRA[kEcho].min <> lRangeRA[kEcho].max) //5D file space+time+echo
1575
or (lRangeRA[kType].min <> lRangeRA[kType].max) //5D file space+time+echo
1576
or (lRangeRA[kSequence].min <> lRangeRA[kSequence].max) then //5D file space+time+echo
1577
Msg('Warning: note that this image has more than 4 dimensions (multiple Cardiac/Echo/Type/Sequence)');
1578
//if we get here, the Image Format is OK
1579
lImageFormatOK := true;
1580
lFileName := changefileextX(lFilename,'.rec'); //for Linux: case sensitive extension search '.rec' <> '.REC'
1581
333: //abort clause: skips lHdrOK and lImageFormatOK
1582
//next: free dynamically allocated memory
1584
FreeMem (lSliceSequenceRA);
1587
procedure read_ge_data(var lDICOMdata: DICOMdata; var lHdrOK, lImageFormatOK: boolean; var lDynStr: string;lFileName: string);
1591
lGap,lSliceThick,lTempFloat: single;
1593
lSeriesOffset,lTemp32,lExamHdr,lImgHdr,lDATFormatOffset,lHdrOffset,lCompress,linitialoffset,n,filesz: LongInt;
1594
tx : array [0..36] of Char;
1596
lGEodd,lGEFlag,{lSpecial,}lMR: boolean;
1597
function GEflag: boolean;
1599
if (tx[0] = 'I') AND (tx[1]= 'M') AND (tx[2] = 'G')AND (tx[3]= 'F') then
1604
function swap16i(lPos: longint): word;
1609
BlockRead(fp, W, 2);
1613
function swap32i(lPos: longint): Longint;
1615
swaptype = packed record
1617
0:(Word1,Word2 : word); //word is 16 bit
1620
swaptypep = ^swaptype;
1627
BlockRead(fp, s, 4, n);
1628
inguy := @s; //assign address of s to inguy
1629
outguy.Word1 := swap(inguy^.Word2);
1630
outguy.Word2 := swap(inguy^.Word1);
1631
swap32i:=outguy.Long;
1633
function fswap4r (lPos: longint): single;
1635
swaptype = packed record
1637
0:(Word1,Word2 : word); //word is 16 bit
1640
swaptypep = ^swaptype;
1647
BlockRead(fp, s, 4, n);
1648
inguy := @s; //assign address of s to inguy
1649
outguy.Word1 := swap(inguy^.Word2);
1650
outguy.Word2 := swap(inguy^.Word1);
1651
fswap4r:=outguy.float;
1654
lImageFormatOK := true;
1660
if not fileexists(lFileName) then begin
1661
lImageFormatOK := false;
1664
FileMode := 0; //set to readonly
1665
AssignFile(fp, lFileName);
1667
FIleSz := FileSize(fp);
1668
lDATFormatOffset := 0;
1669
Clear_Dicom_Data(lDicomData);
1670
if filesz < (3240) then begin
1671
Msg('This file is too small to be a Genesis DAT format image.');
1676
lInitialOffset := 3228;//3240;
1677
seek(fp, lInitialOffset);
1678
BlockRead(fp, tx, 4*SizeOf(Char), n);
1680
if not lGEFlag then begin
1681
lInitialOffset := 3240;
1682
seek(fp, lInitialOffset);
1683
BlockRead(fp, tx, 4*SizeOf(Char), n);
1687
if not lGEFlag then begin
1688
lInitialOffset := 0;
1689
seek(fp, lInitialOffset);
1690
BlockRead(fp, tx, 4*SizeOf(Char), n);
1691
if not GEflag then begin {DAT format}
1692
lDynStr := lDynStr+'GE Genesis Signa DAT tape format'+kCR;
1694
BlockRead(fp, tx, 4*SizeOf(Char), n);
1695
lDynStr := lDynStr + 'Suite: ';
1697
lDynStr := lDynStr + tx[lI];
1698
lDynStr := lDynStr + kCR;
1701
BlockRead(fp, tx, 25*SizeOf(Char), n);
1702
lDynStr := lDynStr + 'Patient Name: ';
1703
for lI := 0 to 24 do
1704
lDynStr := lDynStr + tx[lI];
1705
lDynStr := lDynStr + kCR;
1707
BlockRead(fp, tx, 13*SizeOf(Char), n);
1708
lDynStr := lDynStr + 'Patient ID: ';
1709
for lI := 0 to 12 do
1710
lDynStr := lDynStr + tx[lI];
1711
lDynStr := lDynStr + kCR;
1713
BlockRead(fp, tx, 3*SizeOf(Char), n);
1714
if (tx[0]='M') and (tx[1] = 'R') then
1716
else if (tx[0] = 'C') and(tx[1] = 'T') then
1719
Msg('Is this a Genesis DAT image? The modality is '+tx[0]+tx[1]+tx[3]
1720
+'. Expected ''MR'' or ''CT''.');
1724
lInitialOffset := 3180
1726
lInitialOffset := 3178;
1727
seek(fp, lInitialOffset);
1728
BlockRead(fp, tx, 4*SizeOf(Char), n);
1729
if (tx[0] <> 'I') OR (tx[1] <> 'M') OR (tx[2] <> 'G') OR (tx[3] <> 'F') then begin
1730
Msg('This image does not have the required label ''IMGF''. This is not a Genesis DAT image.');
1733
lDicomData.ImageNum := swap16i(2158+12);
1734
lDicomData.XYZmm[3] := fswap4r (2158+26);// slice thickness mm
1735
lDicomData.XYZmm[1] := fswap4r (2158+50);// pixel size- X
1736
lDicomData.XYZmm[2] := fswap4r (2158+54);//pixel size - Y
1737
lSliceThick := lDicomData.XYZmm[3];
1738
lGap := fswap4r (lHdrOffset+118);//1410 gap thickness mm
1740
lDicomData.XYZmm[3] := lDicomData.XYZmm[3] + lGap;
1741
lDATFormatOffset := 4;
1743
lTemp32 := swap32i(2158+194);
1744
lDynStr := lDynStr +'TR[usec]: '+inttostr(lTemp32) + kCR;
1745
lTemp32 := swap32i(2158+198);
1746
lDynStr := lDynStr +'TInvert[usec]: '+inttostr(lTemp32) + kCR;
1747
lTemp32 := swap32i(2158+202);
1748
lDynStr := lDynStr +'TE[usec]: '+inttostr(lTemp32) + kCR;
1749
lTemp16 := swap16i(2158+210);
1750
lDynStr := lDynStr +'Number of echoes: '+inttostr(lTemp16) + kCR;
1751
lTemp16 := swap16i(2158+212);
1752
lDynStr := lDynStr +'Echo: '+inttostr(lTemp16) + kCR;
1754
lTempFloat := fswap4r (2158+50); //not sure why I changed this to 50... 218 in Clunie's Description
1755
lDynStr := lDynStr +'NEX: '+floattostr(lTempFloat) + kCR;
1758
BlockRead(fp, tx, 33*SizeOf(Char), n);
1759
lDynStr := lDynStr + 'Sequence: ';
1760
for lI := 0 to 32 do
1761
lDynStr := lDynStr + tx[lI];
1762
lDynStr := lDynStr + kCR;
1766
BlockRead(fp, tx, 17*SizeOf(Char), n);
1767
lDynStr := lDynStr + 'Coil: ';
1768
for lI := 0 to 16 do
1769
lDynStr := lDynStr + tx[lI];
1770
lDynStr := lDynStr + kCR;
1777
lDicomData.ImageStart := lDATFormatOffset+linitialoffset + swap32i(linitialoffset+4);//byte displacement to image data
1778
lDicomData.XYZdim[1] := swap32i(linitialoffset+8); //width
1779
lDicomData.XYZdim[2] := swap32i(linitialoffset+12);//height
1780
lDicomData.Allocbits_per_pixel := swap32i(linitialoffset+16);//bits
1781
//xlDicomData.Storedbits_per_pixel:= lDicomData.Allocbits_per_pixel;
1782
lCompress := swap32i(linitialoffset+20); //compression
1783
lExamHdr := swap32i(linitialoffset+136);
1784
lImgHdr := swap32i(linitialoffset+152);
1785
if (lImgHdr = 0) and (lDicomData.ImageStart = 8432) then begin
1786
lDicomData.ImageNum := swap16i(2310+12);
1787
lDicomData.XYZmm[3] := fswap4r (2310+26);// slice thickness mm
1788
lDicomData.XYZmm[1] := fswap4r (2310+50);// pixel size- X
1789
lDicomData.XYZmm[2] := fswap4r (2310+54);//pixel size - Y
1790
lSliceThick := lDicomData.XYZmm[3];
1791
lGap := fswap4r (lHdrOffset+118);//1410 gap thickness mm
1793
lDicomData.XYZmm[3] := lDicomData.XYZmm[3] + lGap;
1795
end else if {(lSpecial = false) and} (lDATFormatOffset = 0) then begin
1796
lDynStr := lDynStr+'GE Genesis Signa format'+kCR;
1797
if (not lGEodd) and (lExamHdr <> 0) then begin
1798
lHdrOffset := swap32i(linitialoffset+132);//x132- int ptr to exam heade
1800
seek(fp,lHdrOffset+84);
1801
BlockRead(fp, tx, 13*SizeOf(Char), n);
1802
lDynStr := lDynStr + 'Patient ID: ';
1803
for lI := 0 to 12 do
1804
lDynStr := lDynStr + tx[lI];
1805
lDynStr := lDynStr + kCR;
1807
seek(fp,lHdrOffset+97);
1808
BlockRead(fp, tx, 25*SizeOf(Char), n);
1809
lDynStr := lDynStr + 'Patient Name: ';
1810
for lI := 0 to 24 do
1811
lDynStr := lDynStr + tx[lI];
1812
lDynStr := lDynStr + kCR;
1814
lI := swap16i(lHdrOffset+122);
1815
lDynStr := lDynStr+'Patient Age: '+inttostr(lI)+kCR;
1816
//Modality: MR or CT
1817
seek(fp,lHdrOffset+305);
1818
BlockRead(fp, tx, 3*SizeOf(Char), n);
1819
lDynStr := lDynStr + 'Type: ';
1821
lDynStr := lDynStr + tx[lI];
1822
lDynStr := lDynStr + kCR;
1823
//Read series header
1824
lSeriesOffset := swap32i(linitialoffset+144);//read size of series header: only read if >0
1825
if lSeriesOffset > 12 then begin
1826
lSeriesOffset := swap32i(linitialoffset+140);//read size of series header: only read if >0
1827
lI := swap16i(lSeriesOffset+10);
1828
//lDynStr := lDynStr+'Series number: '+inttostr(lI)+kCR;
1829
lDicomData.SeriesNum := lI;
1834
lHdrOffset := swap32i(linitialoffset+148);//x148- int ptr to image heade
1836
if lGEodd then lHdrOffset := 2158+28;
1837
if ((lHdrOffset +58) < FileSz) and (lImgHdr <> 0) then begin
1838
lDicomData.AcquNum := swap16i(lHdrOffset+12); //note SERIES not IMAGE number, despite what Clunies FAQ says
1839
lDicomData.ImageNum := swap16i(lHdrOffset+14); //this is IMAGEnum
1841
//lDynStr := lDynStr +'Image number: '+inttostr(lDicomData.ImageNum)+ kCR;
1842
lDicomData.XYZmm[3] := fswap4r (lHdrOffset{linitialoffset+lHdrOffset}+26);// slice thickness mm
1843
lDicomData.XYZmm[1] := fswap4r (lHdrOffset{linitialoffset+lHdrOffset}+50);// pixel size- X
1844
lDicomData.XYZmm[2] := fswap4r (lHdrOffset{linitialoffset+lHdrOffset}+54);//pixel size - Y
1845
lSliceThick := lDicomData.XYZmm[3];
1846
lGap := fswap4r (lHdrOffset+118);//1410 gap thickness mm
1848
lDicomData.XYZmm[3] := lDicomData.XYZmm[3] + lGap;
1851
if (lCompress = 3) or (lCompress = 4) then begin
1852
lImageFormatOK := false;//xlDicomData.GenesisCpt := true;
1853
lDynStr := lDynStr+'Compressed data'+kCR;
1855
;//xlDicomData.GenesisCpt := false;
1856
if (lCompress = 2) or (lCompress = 4) then begin
1857
lImageFormatOK := false;//xlDicomData.GenesisPackHdr := swap32i(linitialoffset+64);
1858
lDynStr := lDynStr+'Packed data'+kCR;
1860
//xlDicomData.GenesisPackHdr := 0;
1861
lDynStr := lDynStr+'Series Number: '+inttostr(lDicomData.SeriesNum)
1862
+kCR+'Acquisition Number: '+inttostr(lDicomData.AcquNum)
1863
+kCR+'Image Number: '+inttostr(lDicomData.ImageNum)
1864
+kCR+'Slice Thickness/Gap: '+floattostrf(lSliceThick,ffFixed,8,2)+'/'+floattostrf(lGap,ffFixed,8,2)
1865
+kCR+'XYZ dim: ' +inttostr(lDicomData.XYZdim[1])+'/'+inttostr(lDicomData.XYZdim[2])+'/'+inttostr(lDicomData.XYZdim[3])
1866
+kCR+'XYZ mm: '+floattostrf(lDicomData.XYZmm[1],ffFixed,8,2)+'/'
1867
+floattostrf(lDicomData.XYZmm[2],ffFixed,8,2)+'/'+floattostrf(lDicomData.XYZmm[3],ffFixed,8,2);
1871
FileMode := 2; //set to read/write
1876
procedure read_siemens_data(var lDICOMdata: DICOMdata; var lHdrOK, lImageFormatOK: boolean; var lDynStr: string;lFileName: string);
1881
lYear,lMonth,lDay,n,filesz,lFullSz,lMatrixSz,lIHour,lIMin,lISec{,lAHour,lAMin,lASec}: LongInt;
1882
lFlipAngle,lGap,lSliceThick: double;
1883
tx : array [0..26] of Char;
1884
lMagField,lTE,lTR: double;
1885
lInstitution,lName, lID,lMinStr,lSecStr{,lAMinStr,lASecStr}: String;
1887
function swap32i(lPos: longint): Longint;
1889
swaptype = packed record
1891
0:(Word1,Word2 : word); //word is 16 bit
1894
swaptypep = ^swaptype;
1901
BlockRead(fp, s, 4, n);
1902
inguy := @s; //assign address of s to inguy
1903
outguy.Word1 := swap(inguy^.Word2);
1904
outguy.Word2 := swap(inguy^.Word1);
1905
swap32i:=outguy.Long;
1906
//swap32i:=inguy.Long;
1908
function fswap8r (lPos: longint): double;
1910
swaptype = packed record
1912
0:(Word1,Word2,Word3,Word4 : word); //word is 16 bit
1915
swaptypep = ^swaptype;
1922
BlockRead(fp, s, 8, n);
1923
inguy := @s; //assign address of s to inguy
1924
outguy.Word1 := swap(inguy^.Word4);
1925
outguy.Word2 := swap(inguy^.Word3);
1926
outguy.Word3 := swap(inguy^.Word2);
1927
outguy.Word4 := swap(inguy^.Word1);
1928
fswap8r:=outguy.float;
1931
lImageFormatOK := true;
1933
if not fileexists(lFileName) then begin
1934
lImageFormatOK := false;
1937
FileMode := 0; //set to readonly
1938
AssignFile(fp, lFileName);
1940
FIleSz := FileSize(fp);
1941
Clear_Dicom_Data(lDicomData);
1942
if filesz < (6144) then begin
1943
Msg('This file is to small to be a Siemens Magnetom Vision image.');
1947
BlockRead(fp, tx, 7*SizeOf(Char), n);
1948
if (tx[0] <> 'S') OR (tx[1] <> 'I') OR (tx[2] <> 'E') OR (tx[3] <> 'M') then begin {manufacturer is not SIEMENS}
1949
Msg('Is this a Siemens Magnetom Vision image [Manufacturer tag should be ''SIEMENS''].');
1951
end; {manufacturer not siemens}
1953
BlockRead(fp, Tx, 25*SizeOf(Char), n);
1955
for lI := 0 to 24 do begin
1956
if tx[lI] in ['/','\','a'..'z','A'..'Z',' ','+','-','.',',','0'..'9'] then lINstitution := lINstitution + tx[lI];
1958
BlockRead(fp, Tx, 25*SizeOf(Char), n);
1960
for lI := 0 to 24 do begin
1961
if tx[lI] in ['/','\','a'..'z','A'..'Z',' ','+','-','.',',','0'..'9'] then lName := lName + tx[lI];
1964
BlockRead(fp, Tx, 12*SizeOf(Char), n);
1966
for lI := 0 to 11 do begin
1967
if tx[lI] in ['/','\','a'..'z','A'..'Z',' ','+','-','.',',','0'..'9'] then lID := lID + tx[lI];
1969
lDicomData.ImageStart := 6144;
1970
lYear := swap32i(0);
1971
lMonth := swap32i(4);
1973
lIHour := swap32i(68);
1974
lIMin := swap32i(72);
1975
lISec := swap32i(76);
1976
lDicomData.XYZmm[3] := fswap8r (1544);
1977
lMagField := fswap8r (2560);
1978
lTR := fswap8r (1560);
1979
lTE := fswap8r (1568);
1980
lDIcomData.AcquNum := swap32i(3212);
1981
lMatrixSz := swap32i(2864);
1982
lDicomData.SiemensSlices := swap32i(4004); //1366
1983
//lFullSz := swap32i(4008);
1984
//lInterleaveIf4 := swap32i(2888);
1985
lFullSz := (2*lMatrixSz*lMatrixSz);//16bitdata
1986
if ((FileSz - 6144) mod lFullSz) = 0 then begin
1987
case ((FileSz-6144) div lFullSz) of
1988
4: lFullSz := 2*lMatrixSz;
1989
9: lFullSz := 3*lMatrixSz;
1990
16: lFullSz := 4*lMatrixSz;
1991
25: lFullSz := 5*lMatrixSz;
1992
36: lFullSz := 6*lMatrixSz;
1993
49: lFullSz := 7*lMatrixSz;
1994
64: lFullSz := 8*lMatrixSz;
1995
else lFullSz := lMatrixSz;
1997
end else lFullSz := lMatrixSz;
1998
{3744/3752 are XY FOV in mm!}
1999
lDicomData.XYZdim[1] := lFullSz;//lMatrixSz; //width
2000
lDicomData.XYZdim[2] := lFullSz;//lMatrixSz;//height
2001
{5000/5008 are size in mm, but wrong for mosaics}
2002
if lMatrixSz <> 0 then begin
2003
lDicomData.XYZmm[2] := fswap8r (3744)/lMatrixSz;
2004
lDicomData.XYZmm[1] := fswap8r (3752)/lMatrixSz;
2005
if ((lDicomData.XYZdim[1] mod lMatrixSz)=0) then
2006
lDicomData.SiemensMosaicX := lDicomData.XYZdim[1] div lMatrixSz;
2007
if ((lDicomData.XYZdim[2] mod lMatrixSz)=0) then
2008
lDicomData.SiemensMosaicY := lDicomData.XYZdim[2] div lMatrixSz;
2009
if lDicomData.SiemensMosaicX < 1 then lDicomData.SiemensMosaicX := 1; //1366
2010
if lDicomData.SiemensMosaicY < 1 then lDicomData.SiemensMosaicY := 1; //1366
2012
lFlipAngle := fswap8r (2112); //1414
2013
{ lDicomData.XYZmm[2] := fswap8r (5000);
2014
lDicomData.XYZmm[1] := fswap8r (5008);}
2015
lSliceThick := lDicomData.XYZmm[3];
2016
lGap := fswap8r (4136); //gap as ratio of slice thickness?!?!
2017
if {lGap > 0} (lGap=-1) or (lGap=-19222) then //1410: exclusion values: do not ask me why 19222: from John Ashburner
2019
//lDicomData.XYZmm[3] := abs(lDicomData.XYZmm[3] * (1+lGap));
2020
lGap := lDicomData.XYZmm[3] * (lGap);
2021
lDicomData.XYZmm[3] := abs(lDicomData.XYZmm[3] +lGap);
2023
lDicomData.Allocbits_per_pixel := 16;//bits
2024
//xlDicomData.Storedbits_per_pixel:= lDicomData.Allocbits_per_pixel;
2025
//xlDicomData.GenesisCpt := false;
2026
//xlDicomData.GenesisPackHdr := 0;
2027
lMinStr := inttostr(lIMin);
2028
if length(lMinStr) = 1 then lMinStr := '0'+lMinStr;
2029
lSecStr := inttostr(lISec);
2030
if length(lSecStr) = 1 then lSecStr := '0'+lSecStr;
2034
lDynStr := 'Siemens Magnetom Vision Format'+kCR+'Name: '+lName+kCR+'ID: '+lID+kCR+'Institution: '+lInstitution+kCR+
2035
'Study DD/MM/YYYY: '+inttostr(lDay)+'/'+inttostr(lMonth)+'/'+inttostr(lYear)+kCR+
2036
'Image Hour/Min/Sec: '+inttostr(lIHour)+':'+lMinStr+':'+lSecStr+kCR+
2037
//'Acquisition Hour/Min/Sec: '+inttostr(lAHour)+':'+lAMinStr+':'+lASecStr+kCR+
2038
'Magnetic Field Strength: '+ floattostrf(lMagField,ffFixed,8,2)+kCR+
2039
'Image index: '+inttostr(lDIcomData.AcquNum)+kCR+
2040
'Time Repitition/Echo [TR/TE]: '+ floattostrf(lTR,ffFixed,8,2)+'/'+ floattostrf(lTE,ffFixed,8,2)+kCR+
2041
'Flip Angle: '+ floattostrf(lFlipAngle,ffFixed,8,2)+kCR+
2042
'Slice Thickness/Gap: '+floattostrf(lSliceThick,ffFixed,8,2)+'/'+floattostrf(lGap,ffFixed,8,2)+kCR+
2043
'XYZ dim:' +inttostr(lDicomData.XYZdim[1])+'/'
2044
+inttostr(lDicomData.XYZdim[2])+'/'+inttostr(lDicomData.XYZdim[3])+kCR+
2045
'XY matrix:' +inttostr(lDicomData.SiemensMosaicX)+'/'
2046
+inttostr(lDicomData.SiemensMosaicY)+kCR+
2047
'XYZ mm:'+floattostrf(lDicomData.XYZmm[1],ffFixed,8,2)+'/'
2048
+floattostrf(lDicomData.XYZmm[2],ffFixed,8,2)+'/'+floattostrf(lDicomData.XYZmm[3],ffFixed,8,2);
2050
//lDIcomData.AcquNum := 0;
2053
FileMode := 2; //set to read/write
2057
procedure read_elscint_data(var lDICOMdata: DICOMdata; var lHdrOK, lImageFormatOK: boolean; var lDynStr: string;lFileName: string);
2061
//lExamHdr,lImgHdr,lDATFormatOffset,lHdrOffset,
2062
{lDate,}lI,lCompress,n,filesz: LongInt;
2063
tx : array [0..41] of Char;
2065
function readStr(lPos,lLen: integer): string;
2070
BlockRead(fp, tx, lLen, n);
2072
for lStrInc := 0 to (lLen-1) do
2073
lStr := lStr + tx[lStrInc];
2076
function read8ch(lPos: integer): char;
2079
BlockRead(fp, result, 1, n);
2080
//lDicomData.ImageNum := ord(tx[0]);
2082
procedure read16i(lPos: longint; var lVal: integer);
2086
BlockRead(fp, lInWord, 2);
2089
procedure read32i(lPos: longint; var lVal: integer);
2090
var lInINt: integer;
2093
BlockRead(fp, lInINt, 4);
2098
lImageFormatOK := true;
2100
if not fileexists(lFileName) then begin
2101
lImageFormatOK := false;
2104
FileMode := 0; //set to readonly
2105
AssignFile(fp, lFileName);
2107
FIleSz := FileSize(fp);
2108
Clear_Dicom_Data(lDicomData);
2109
if filesz < (3240) then begin
2110
Msg('This file is too small to be a Elscint format image.');
2115
if (lI <> 64206) then begin
2116
Msg('Unable to read this file: it does start with the Elscint signature.');
2119
lDicomdata.little_endian := 1;
2120
lDynStr:= 'Elscint Format'+kCR;
2121
lDynStr := lDynStr+'Patient Name: '+readstr(4,20)+kCR;
2122
lDynStr := lDynStr+'Patient ID: '+readstr(24,13)+kCR;
2123
read16i(38,lDicomData.AcquNum);
2124
lDicomData.ImageNum := ord(read8Ch(40));
2125
lDynStr := lDynStr+'Doctor & Ward: '+readstr(100,20)+kCR;
2126
lDynStr := lDynStr+'Comments: '+readstr(120,40)+kCR;
2127
if ord(read8Ch(163)) = 1 then
2128
lDynStr := lDynStr + 'Sex: M'+kCR
2130
lDynStr := lDynStr + 'Sex: F'+kCR;
2132
lDicomData.XYZmm[3] := lI * 0.1;
2133
read16i(370,lDicomData.XYZdim[1]);
2134
read16i(372,lDicomData.XYZdim[2]);
2136
lDicomData.XYZmm[1] := lI / 256;
2137
lDicomData.XYZmm[2] := lDicomData.XYZmm[1];
2138
lCompress := ord(read8Ch(376));
2139
//xlDicomData.ElscintCompress := true;
2140
//xread16i(400,lDicomData.WindowWidth);
2141
//x read16i(398,lDicomData.WindowCenter);
2144
lDynStr := lDynStr + 'Compression: None'+kCR;
2145
//xlDicomData.ElscintCompress := false;
2147
1: lImageFormatOK := false;//xlDynStr := lDynStr + 'Compression: Old'+kCR;
2148
2: lImageFormatOK := false;//xlDynStr := lDynStr + 'Compression: 2400 Elite'+kCR;
2149
22: lImageFormatOK := false;//xlDynStr := lDynStr + 'Compression: Twin'+kCR;
2151
lImageFormatOK := false;//xlDynStr := lDynStr + 'Compression: Unknown '+inttostr(lCOmpress)+kCR;
2152
//lDicomData.ElscintCompress := false;
2155
//lDicomData.XYZdim[1] := swap32i(linitialoffset+8); //width
2156
//lDicomData.XYZdim[2] := swap32i(linitialoffset+12);//height
2157
lDicomData.ImageStart := 396;
2158
lDicomData.Allocbits_per_pixel := 16;
2159
//xlDicomData.Storedbits_per_pixel:= lDicomData.Allocbits_per_pixel;
2160
if (lDicomData.XYZdim[1]=160) and (lDicomData.XYZdim[2]= 160) and (FIleSz=52224) then begin
2161
lDicomData.ImageStart := 1024;
2162
lImageFormatOK := true;//x//xlDicomData.ElscintCompress := False;
2164
//lDicomData.XYZmm[3] := fswap4r (2310+26);// slice thickness mm
2165
lDynStr := lDynStr+'Image/Study Number: '+inttostr(lDicomData.ImageNum)+'/'+ inttostr(lDicomData.AcquNum)+kCR
2166
+'XYZ dim: ' +inttostr(lDicomData.XYZdim[1])+'/'
2167
+inttostr(lDicomData.XYZdim[2])+'/'+inttostr(lDicomData.XYZdim[3])
2168
//x+kCR+'Window Center/Width: '+inttostr(lDicomData.WindowCenter)+'/'+inttostr(lDicomData.WindowWidth)
2169
+kCR+'XYZ mm: '+floattostrf(lDicomData.XYZmm[1],ffFixed,8,2)+'/'
2170
+floattostrf(lDicomData.XYZmm[2],ffFixed,8,2)+'/'+floattostrf(lDicomData.XYZmm[3],ffFixed,8,2);
2172
lImageFormatOK := true;
2175
FileMode := 2; //set to read/write
2182
procedure read_picker_data(lVerboseRead: boolean; var lDICOMdata: DICOMdata; var lHdrOK, lImageFormatOK: boolean; var lDynStr: string;lFileName: string);
2184
const kPickerHeader =8192;
2185
kRecStart = 280; //is this a constant?
2187
lDataStart,lVal,lDBPos,lPos,lRecSz, lNumRecs,lRec,FileSz,n: Longint;
2188
lThkM,lThkN,lSiz: double;
2189
tx : array [0..6] of Char;
2191
lDiskCacheRA: pChar;
2192
function ReadRec(lRecNum: integer): boolean;
2194
lNameStr,lValStr: string;
2195
lOffset,lLen,lFPOs,lFEnd: integer;
2196
function ValStrToFloat: double;
2197
var lConvStr: string;
2201
lLen := Length(lValStr);
2202
if lLen < 1 then exit;
2204
for lI := 1 to lLen do
2205
if lValStr[lI] in ['0'..'9'] then
2206
lConvStr := lConvStr+ lValStr[lI];
2207
if Length(lConvStr) < 1 then exit;
2208
Result := strtofloat(lConvStr);
2212
lFPos := ((lRecNum-1) * lRecSz)+ kRecStart;
2215
for lFPos := lFPos to lFEnd do
2216
if ord(lDiskCacheRA[lFPos]) <> 0 then
2217
lNameStr := lNameStr +lDiskCacheRA[lFPos];
2218
if (lVerboseRead) or (lNameStr = 'RCNFSIZ') or (lNameStr='SCNTHKM') or (lNameStr='SCNTHKN') then begin
2219
lFPos := ((lRecNum-1) * lRecSz)+ kRecStart+8;
2222
for lFPos := lFPos to lFend do
2223
lOffset := ((lOffset)shl 8)+(ord(lDiskCacheRA[lFPos]));
2224
lFPos := ((lRecNum-1) * lRecSz)+ kRecStart+10;
2227
for lFPos := lFPos to lFend do
2228
lLen := ((lLen)shl 8)+(ord(lDiskCacheRA[lFPos]));
2229
lOffset := lDataStart+lOffset+1;
2230
lFEnd := lOffset+lLen-1;
2231
if (lLen < 1) or (lFEnd > kPickerHeader) then exit;
2233
for lFPos := (lOffset) to lFEnd do begin
2234
lValStr := lValStr+lDiskCacheRA[lFPos];
2236
if lVerboseRead then lDynStr := lDynStr+kCR+lNameStr+': '+ lValStr;
2237
if (lNameStr = 'RCNFSIZ') then lSiz := ValStrToFloat;
2238
if (lNameStr='SCNTHKM') then lThkM := ValStrToFloat;
2239
if (lNameStr='SCNTHKN') then lThkN := ValStrToFloat;
2240
end; //verboseread, or vital value
2243
function FindStr(l1,l2,l3,l4,l5: Char; lReadNum: boolean; var lNum: integer): boolean;
2244
var //lMarker: integer;
2249
if (lDiskCacheRA[lPos-4]=l1) and (lDiskCacheRA[lPos-3]=l2)
2250
and (lDiskCacheRA[lPos-2]=l3) and (lDiskCacheRA[lPos-1]=l4)
2251
and (lDiskCacheRA[lPos]=l5) then Result := true;
2253
until (Result) or (lPos >= kPickerHeader);
2254
if not Result then exit;
2255
if not lReadNum then exit;
2259
if (lDiskCacheRA[lPos] in ['0'..'9']) then
2260
lNumStr := lNumStr + lDiskCacheRA[lPos]
2261
else if lNumStr <> '' then Result := true;
2263
until (Result) or (lPos = kPickerHeader);
2264
lNum := strtoint(lNumStr);
2270
lImageFormatOK := true;
2272
if not fileexists(lFileName) then begin
2273
lImageFormatOK := false;
2276
FileMode := 0; //set to readonly
2277
AssignFile(fp, lFileName);
2279
FIleSz := FileSize(fp);
2280
Clear_Dicom_Data(lDicomData);
2281
if filesz < (kPickerHeader) then begin
2282
Msg('This file is to small to be a Picker image: '+lFileName );
2284
FileMode := 2; //set to read/write
2288
BlockRead(fp, tx, 4*SizeOf(Char), n);
2289
if (tx[0] <> '*') OR (tx[1] <> '*') OR (tx[2] <> '*') OR (tx[3] <> ' ') then begin {manufacturer is not SIEMENS}
2290
Msg('Is this a Picker image? Expected ''***'' at the start of the file.'+ lFileName);
2292
FileMode := 2; //set to read/write
2295
if filesz = (kPickerHeader + (1024*1024*2)) then begin
2296
lDICOMdata.XYZdim[1] := 1024;
2297
lDICOMdata.XYZdim[2] := 1024;
2298
lDICOMdata.XYZdim[3] := 1;
2299
lDICOMdata.ImageStart := 8192;
2301
if filesz = (kPickerHeader + (512*512*2)) then begin
2302
lDICOMdata.XYZdim[1] := 512;
2303
lDICOMdata.XYZdim[2] := 512;
2304
lDICOMdata.XYZdim[3] := 1;
2305
lDICOMdata.ImageStart := 8192;
2307
if filesz = (8192 + (256*256*2)) then begin
2308
lDICOMdata.XYZdim[1] := 256;
2309
lDICOMdata.XYZdim[2] := 256;
2310
lDICOMdata.XYZdim[3] := 1;
2311
lDICOMdata.ImageStart := 8192;
2313
Msg('This file is the incorrect size to be a Picker image.');
2315
FileMode := 2; //set to read/write
2318
getmem(lDiskCacheRA,kPickerHeader*sizeof(char));
2320
BlockRead(fp, lDiskCacheRA, kPickerHeader, n);
2324
if not FindStr('d','b','r','e','c',false, lVal) then goto 423;
2326
if not FindStr('r','e','c','s','z',true, lRecSz) then goto 423;
2328
if not FindStr('n','r','e','c','s',true, lnumRecs) then goto 423;
2329
lPos := kRecStart; // IS THIS A CONSTANT???
2330
lDataStart :=kRecStart + (lRecSz*lnumRecs)-1; //file starts at 0, so -1
2331
if (lNumRecs = 0) or (lDataStart> kPickerHeader) then goto 423;
2333
lDynStr := 'Picker Format';
2336
until (not (ReadRec(lRec))) or (lRec >= lnumRecs);
2337
if lSiz <> 0 then begin
2338
lDICOMdata.XYZmm[1] := lSiz/lDICOMdata.XYZdim[1];
2339
lDICOMdata.XYZmm[2] := lSiz/lDICOMdata.XYZdim[2];
2340
if lVerboseRead then
2341
lDynStr := lDynStr+kCR+'Voxel Size: '+floattostrf(lDicomData.XYZmm[1],ffFixed,8,2)
2342
+'x'+ floattostrf(lDicomData.XYZmm[2],ffFixed,8,2);
2344
if (lThkM <> 0) and (lThkN <> 0) then begin
2345
lDICOMdata.XYZmm[3] := lThkN/lThkM;
2346
if lVerboseRead then
2347
lDynStr := lDynStr+kCR+'Slice Thickness: '+floattostrf(lDicomData.XYZmm[3],ffFixed,8,2);
2350
freemem(lDiskCacheRA);
2353
FileMode := 2; //set to read/write
2357
procedure read_minc_data(var lDICOMdata: DICOMdata; var lHdrOK, lImageFormatOK: boolean; var lDynStr: string;lFileName: string);
2360
lnOri,lnDim,lStartPosition,nelem0,jj,lDT0,vSizeRA,BeginRA,m,nnelem,nc_type,nc_size,lLen,nelem,j,lFilePosition,lDT,lFileSz,lSignature,lWord: integer;
2362
lOri: array [1..3] of double;
2363
//tx : array [0..80] of Char;
2364
lVarStr,lStr: string;
2366
function dTypeStr (lV: integer): integer;
2370
3: result := 2; //int16
2371
4: result := 4; //int32
2372
5: result := 4; //single
2373
6: result := 8; //double
2375
end; //nested fcn dTypeStr
2377
function read32i: Longint;
2379
swaptype = packed record
2381
0:(Word1,Word2 : word); //word is 16 bit
2384
swaptypep = ^swaptype;
2390
seek(fp,lFilePosition);
2391
lFilePosition := lFilePosition + 4;
2392
BlockRead(fp, s, 4);
2393
inguy := @s; //assign address of s to inguy
2394
if lDICOMdata.Little_Endian = 0 then begin
2395
outguy.Word1 := swap(inguy^.Word2);
2396
outguy.Word2 := swap(inguy^.Word1);
2398
outguy.long := inguy^.long;
2399
result:=outguy.Long;
2402
function read64r (lDataType: integer): Double;
2404
swaptype = packed record
2406
0:(Word1,Word2,Word3,Word4 : word); //word is 16 bit
2409
swaptypep = ^swaptype;
2416
if lDataType <> 6 then begin
2417
Msg('Unknown data type: MRIcro is unable to determine the voxel size.');
2420
seek(fp,lFilePosition);
2421
lFilePosition := lFilePosition + 8;
2422
BlockRead(fp, s, 8);
2423
inguy := @s; //assign address of s to inguy
2424
if lDICOMdata.Little_Endian = 0 then begin
2425
outguy.Word1 := swap(inguy^.Word4);
2426
outguy.Word2 := swap(inguy^.Word3);
2427
outguy.Word3 := swap(inguy^.Word2);
2428
outguy.Word4 := swap(inguy^.Word1);
2430
outguy.long := inguy^.long;
2431
result:=outguy.Long;
2434
function readname: String;
2435
var lI,lLen: integer;
2439
seek(fp,lFilePosition);
2441
if lLen < 1 then begin
2442
Msg('Terminal error reading netCDF/MINC header (String length < 1)');
2445
for lI := 1 to lLen do begin
2446
BlockRead(fp, lCh, 1);
2447
result := result + lCh;
2449
lFilePosition := lFilePosition + (((lLen+3) div 4) * 4);
2453
lImageFormatOK := true;
2455
if not fileexists(lFileName) then begin
2456
lImageFormatOK := false;
2459
for lnOri := 1 to 3 do
2463
FileMode := 0; //set to readonly
2464
AssignFile(fp, lFileName);
2466
lFileSz := FileSize(fp);
2467
Clear_Dicom_Data(lDicomData);
2468
if lFilesz < (77) then exit; //to small to be MINC
2471
lSignature := read32i;
2472
if not (lSignature=1128547841) then begin
2474
FileMode := 2; //set to read/write
2475
Msg('Problem with MINC signature: '+ inttostr(lSignature));
2478
//xlDicomData.Rotate180deg := true;
2479
lWord := read32i;//numrecs
2481
while (lDt=10) or (lDT=11) or (lDT=12) do begin
2482
if lDT = 10 then begin //DT=10, Dimensions
2484
for j := 1 to nelem do begin
2487
if lStr = 'xspace' then lDicomData.XYZdim[3] := lLen;//DOES MINC always reverse X and Z? see also XYZmm
2488
if lStr = 'yspace' then lDicomData.XYZdim[2] := lLen;
2489
if lStr = 'zspace' then lDicomData.XYZdim[1] := lLen;
2492
end;//DT=10, Dimensions
2493
if lDT = 11 then begin //DT=11, Variables
2495
for j := 1 to nelem do begin
2496
lVarStr := readname;
2498
for m := 1 to nnelem do
2501
if lDT0 = 12 then begin
2503
for jj := 1 to nelem0 do begin
2506
nc_size := dTypeStr(nc_Type);
2508
lStartPosition := lFilePosition;
2510
if (lStr = 'step') then begin
2512
if (lVarStr = 'xspace') or (lVarStr = 'yspace') or (lVarStr = 'zspace') then begin
2514
if (lnDim < 4) and (lnDim>0) then
2515
lDicomData.XYZmm[lnDim] := read64r(nc_Type)
2518
end else if (lStr = 'start') then begin
2519
if (lVarStr = 'xspace') or (lVarStr = 'yspace') or (lVarStr = 'zspace') then begin
2521
if (lnOri < 4) and (lnOri > 0) then
2522
lOri[lnOri] := read64r(nc_Type)
2525
lFilePosition := lStartPosition + ((((nnelem*nc_size)+3) div 4)*4);
2529
if lVarStr = 'image' then begin
2531
1,2: lDicomData.Allocbits_per_pixel := 8;
2532
3: lDicomData.Allocbits_per_pixel := 16; //int16
2533
4: lDicomData.Allocbits_per_pixel := 32; //int32
2534
5: lDicomData.Allocbits_per_pixel := 32; //single
2535
6: lDicomData.Allocbits_per_pixel := 64; //double
2537
if (lDT0 = 5) or (lDT0 = 6) then
2538
lDicomData.Float := true;
2539
//xlDicomData.Storedbits_per_pixel := lDicomData.Allocbits_per_pixel;
2540
//lImgNC_Type := lDT0;
2545
if lVarStr = 'image' then begin
2546
lDICOMdata.ImageStart := BeginRA;
2551
if lDT = 12 then begin //DT=12, Attributes
2553
for j := 1 to nelem do begin
2556
nc_size := dTypeStr(nc_Type);
2558
lFilePosition := lFilePosition + ((((nnelem*nc_size)+3) div 4)*4);
2561
end;//DT=12, Dimensions
2564
if lOri[1] <> 0 then
2565
lDicomData.XYZori[1] := round((-lOri[1])/lDicomData.XYZmm[1])+1;
2566
if lOri[2] <> 0 then
2567
lDicomData.XYZori[2] := round((-lOri[2])/lDicomData.XYZmm[2])+1;
2568
if lOri[3] <> 0 then
2569
lDicomData.XYZori[3] := round((-lOri[3])/lDicomData.XYZmm[3])+1;
2571
lDynStr := 'MINC image'+kCR+
2572
'XYZ dim:' +inttostr(lDicomData.XYZdim[1])+'/'
2573
+inttostr(lDicomData.XYZdim[2])+'/'+inttostr(lDicomData.XYZdim[3])
2574
+kCR+'XYZ origin:' +inttostr(lDicomData.XYZori[1])+'/'
2575
+inttostr(lDicomData.XYZori[2])+'/'+inttostr(lDicomData.XYZori[3])
2576
+kCR+'XYZ size [mm or micron]:'+floattostrf(lDicomData.XYZmm[1],ffFixed,8,2)+'/'
2577
+floattostrf(lDicomData.XYZmm[2],ffFixed,8,2)+'/'+floattostrf(lDicomData.XYZmm[3],ffFixed,8,2)
2578
+kCR+'Bits per sample/Samples per pixel: '+inttostr( lDICOMdata.Allocbits_per_pixel)
2579
+kCR+'Data offset:' +inttostr(lDicomData.ImageStart);
2581
lImageFormatOK := true;
2583
FileMode := 2; //set to read/write
2589
procedure read_tiff_data(var lDICOMdata: DICOMdata; var lReadOffsets, lHdrOK, lImageFormatOK: boolean; var lDynStr: string;lFileName: string);
2596
lStackSameDim,lContiguous: boolean;
2597
l1stDicomData: DicomData;
2599
//lXmm,lYmm,lZmm: double;
2601
lImageDataEndPosition,lStripPositionOffset,lStripPositionType,lStripPositionItems,
2602
lStripCountOffset,lStripCountType,lStripCountItems,
2603
lItem,lTagItems,lTagItemBytes,lTagPointer,lNumerator, lDenominator,
2604
lImage_File_Directory,lTagType,lVal,lDirOffset,lOffset,lFileSz,
2605
lnDirectories,lDir,lnSlices: Integer;
2606
lTag,lWord,lWord2: word;
2608
(*FUNCTION longint2single ({var} s:longint): single;
2609
//returns true if s is Infinity, NAN or Indeterminate
2610
//4byte IEEE: msb[31] = signbit, bits[23-30] exponent, bits[0..22] mantissa
2611
//exponent of all 1s = Infinity, NAN or Indeterminate
2612
VAR Overlay: Single ABSOLUTE s;
2617
function read64r(lPos: integer):double;
2619
swaptype = packed record
2621
0:(Word1,Word2,Word3,Word4 : word); //word is 16 bit
2624
swaptypep = ^swaptype;
2631
BlockRead(fp, s, 8);
2632
inguy := @s; //assign address of s to inguy
2633
if lDICOMdata.Little_Endian = 0{false} then begin
2634
outguy.Word1 := swap(inguy^.Word4);
2635
outguy.Word2 := swap(inguy^.Word3);
2636
outguy.Word3 := swap(inguy^.Word2);
2637
outguy.Word4 := swap(inguy^.Word1);
2639
outguy.float := inguy^.float;
2640
result:=outguy.float;
2643
function read32i(lPos: longint): Longint;
2645
swaptype = packed record
2647
0:(Word1,Word2 : word); //word is 16 bit
2650
swaptypep = ^swaptype;
2657
BlockRead(fp, s, 4);
2658
inguy := @s; //assign address of s to inguy
2659
if lDICOMdata.Little_Endian = 0 then begin
2660
outguy.Word1 := swap(inguy^.Word2);
2661
outguy.Word2 := swap(inguy^.Word1);
2663
outguy.long := inguy^.long;
2664
result:=outguy.Long;
2666
function read16(lPos: longint): Longint;
2671
BlockRead(fp, s, 2);
2672
if lDICOMdata.Little_Endian = 0 then
2678
function read8(lPos: longint): Longint;
2683
BlockRead(fp, s, 1);
2687
function readItem(lItemNum,lTagTypeI,lTagPointerI: integer): integer;
2689
if lTagTypeI= 4 then
2690
result := read32i(lTagPointerI+((lItemNum-1)*4))
2692
result := read16(lTagPointerI+((lItemNum-1)*2));
2696
Clear_Dicom_Data(lDicomData);
2697
if gECATJPEG_table_entries <> 0 then begin
2698
freemem (gECATJPEG_pos_table);
2699
freemem (gECATJPEG_size_table);
2700
gECATJPEG_table_entries := 0;
2702
//lXmm := -1; //not read
2703
lImageFormatOK := true;
2705
if not fileexists(lFileName) then begin
2706
lImageFormatOK := false;
2709
//lLongRASz := kMaxnSlices * sizeof(longint);
2710
getmem(lLongRA,kMaxnSlices*sizeof(longint));
2711
FileMode := 0; //set to readonly
2712
AssignFile(fp, lFileName);
2714
lFileSz := FileSize(fp);
2715
Clear_Dicom_Data(lDicomData);
2716
//xlDicomData.PlanarConfig:=0;
2717
if lFilesz < (28) then begin
2720
//TmpStr := string(StrUpper(PChar(ExtractFileExt(lFileName))));
2721
//if not (TmpStr = '.TIF') or (TmpStr = '.TIFF') then exit;
2723
if lWord = $4d4d then
2724
lDICOMdata.little_endian := 0
2725
else if lWord = $4949 then lDICOMdata.little_endian := 1;
2726
lWord2 := read16(2); //bits per pixel
2727
if ((lWord=$4d4d) or (lWord=$4949)) and (lWord2 = $002a) then
2729
lOffset := read32i(4);
2730
lImage_File_Directory := 0;
2731
lContiguous := true;
2733
//xlDicomData.SamplesPerPixel := 1;
2734
//START while for each image_file_directory
2735
while (lOffset > 0) and ((lOffset+2+12+4) < lFileSz) do begin
2736
inc(lImage_File_Directory);
2737
lnDirectories := read16(lOffset);
2738
if (lnDirectories < 1) or ((lOffset+2+(12*lnDirectories)+4) > lFileSz) then
2740
for lDir := 1 to lnDirectories do begin
2741
lDirOffset := lOffset+2+((lDir-1)*12);
2742
lTag := read16(lDirOffset);
2743
lTagType := read16(lDirOffset+2);
2744
lTagItems := read32i(lDirOffset+4);
2746
1: lVal := 1;//bytes
2749
5: lVal := 8;//rational
2750
else lVal := 1; //CHAR variable length
2752
lTagItemBytes := lVal * lTagItems;
2753
if lTagItemBytes > 4 then
2754
lTagPointer := read32i(lDirOffset+8)
2756
lTagPointer := (lDirOffset+8);
2758
1: lVal := read8(lDirOffset+8);
2759
3: lVal := read16(lDirOffset+8);
2760
4: lVal := read32i(lDirOffset+8);
2761
5: begin //rational: two longs representing numerator and denominator
2762
lVal := read32i(lDirOffset+8);
2763
lNumerator := read32i(lVal);
2764
lDenominator := read32i(lVal+4);
2765
if lDenominator <> 0 then
2766
lSingle := lNumerator/lDenominator
2769
if lSingle <> 0 then
2770
lSingle := 1/lSingle; //Xresolution/Yresolution refer to number of pixels per resolution_unit
2771
if lTag = 282 then lDicomData.XYZmm[1] := lSingle;
2772
if lTag = 283 then lDicomData.XYZmm[2] := lSingle;
2777
//254: ;//NewSubFileType
2778
256: lDicomData.XYZdim[1] := lVal;//image_width
2779
257: lDicomData.XYZdim[2] := lVal;//image_height
2780
258: begin //bits per sample
2781
if lTagItemBytes > 4 then lVal := 8;
2782
//if lVal <> 8 then goto 566;
2783
lDicomData.Allocbits_per_pixel := lVal;//bits
2784
//xlDicomData.Storedbits_per_pixel:= lDicomData.Allocbits_per_pixel;
2787
if lVal <> 1 then begin
2788
Msg('TIFF Read Error: Image data is compressed. Currently only uncompressed data is supported.');
2789
goto 566; //compressed data
2792
//x262: if lVal = 0 then lDicomdata.monochrome := 1;//invert colors //photometric_interpretation //MinIsWhite,MinIsBlack,Palette
2793
//270: ; //ImageDescription
2794
273: begin //get offset to data
2795
lStripPositionOffset := lTagPointer;
2796
lStripPositionType := lTagType;
2797
lStripPositionItems := lTagItems;
2798
if (lImage_File_Directory=1) then
2799
lDicomData.ImageStart := readItem(1,lStripPositionType,lStripPositionOffset);
2801
//274: ; //orientation
2803
//xlDicomData.SamplesPerPixel := lVal;
2804
//if lVal <> 1 then goto 566; //samples per pixel
2807
lStripCountOffset := lTagPointer;
2808
lStripCountType := lTagType;
2809
lStripCountItems := lTagItems;
2811
//278: message('rows:'+inttostr(lVal));//StripByteCount
2812
//279: message('count:'+inttostr(lVal));//StripByteCount
2813
//282 and 283 are rational values and read separately
2816
lDicomData.PlanarConfig:= 0
2818
lDicomData.PlanarConfig:= 1;//planarConfig
2822
//0020h float x size of a pixel (ļæ½m or s)
2823
//0024h float y size of a pixel (ļæ½m or s)
2824
//0028h float z distance in a sequence (ļæ½m or s)
2825
{stream.seek((int)position + 40);
2826
VOXELSIZE_X = swap(stream.readDouble());
2827
stream.seek((int)position + 48);
2828
VOXELSIZE_Y = swap(stream.readDouble());
2829
stream.seek((int)position + 56);
2830
VOXELSIZE_Z = swap(stream.readDouble());}
2831
lVal := read16(lTagPointer+2);
2832
if lVal = 1024 then begin //LSM510 v2.8 images
2833
lDicomData.XYZmm[1]{lXmm} := read64r(lTagPointer+40)*1000000;
2834
lDicomData.XYZmm[2]{lYmm} := read64r(lTagPointer+48)*1000000;
2835
lDicomData.XYZmm[3]{lZmm} := read64r(lTagPointer+56)*1000000;
2837
//following may work if lVal = 2, different type of LSM file I have not seen
2838
//lXmm := longint2single(read32i(lTagPointer+$0020));
2839
//lYmm := longint2single(read32i(lTagPointer+$0024));
2840
//lZmm := longint2single(read32i(lTagPointer+$0028));
2842
//296: ;//resolutionUnit 1=undefined, 2=inch, 3=centimeter
2849
//COLORMAP = 320 => essntially custom LookUpTable
2850
//EXTRASAMPLES = 338
2851
//SAMPLEFORMAT = 339
2853
// lDicomData.ImageStart := lVal
2854
//else if lImage_File_Directory = 1 then Msg(inttostr(lTag)+'@'+inttostr(lTagPointer)+' value: '+inttostr(lVal));
2856
end; //For Each Directory in Image_File_Directory
2857
lOffset := read32i(lOffset+2+(12*lnDirectories));
2858
//NEXT: check that each slice in 3D slice is the same dimension
2859
lStackSameDim := true;
2860
if (lImage_File_Directory=1) then begin
2861
l1stDicomData := lDICOMdata;
2862
lnSlices := 1; //inc(lnSlices);
2864
if lDicomData.XYZdim[1] <> l1stDicomData.XYZdim[1] then lStackSameDim := false;
2865
if lDicomData.XYZdim[2] <> l1stDicomData.XYZdim[2] then lStackSameDim := false;
2866
if lDicomData.Allocbits_per_pixel <> l1stDicomData.Allocbits_per_pixel then lStackSameDim := false;
2867
//xif lDicomData.SamplesPerPixel <> l1stDicomData.SamplesPerPixel then lStackSameDim := false;
2868
//xif lDicomData.PlanarConfig <> l1stDicomData.PlanarConfig then lStackSameDim := false;
2869
if not lStackSameDim then begin
2870
//Msg(inttostr(lDicomData.XYZdim[1])+'x'+inttostr(l1stDicomData.XYZdim[1]));
2871
if (lDicomData.XYZdim[1]*lDicomData.XYZdim[2]) > (l1stDicomData.XYZdim[1]*l1stDicomData.XYZdim[2]) then begin
2872
l1stDicomData := lDICOMdata;
2874
lStackSameDim := true;
2876
//Msg('TIFF Read Error: Different 2D slices in this 3D stack have different dimensions.');
2879
inc(lnSlices); //if not samedim
2880
end; //check that each slice is same dimension as 1st
2881
//END check each 2D slice in 3D stack is same dimension
2882
//NEXT: check if image data is contiguous
2883
if (lStripCountItems > 0) and (lStripCountItems = lStripPositionItems) then begin
2884
if (lnSlices=1) then lImageDataEndPosition := lDicomData.ImageStart;
2885
for lItem := 1 to lStripCountItems do begin
2886
lVal := readItem(lItem,lStripPositionType,lStripPositionOffset);
2887
if (lVal <> lImageDataEndPosition) then
2888
lContiguous := false;
2889
//Msg(inttostr(lImage_File_Directory)+'@'+inttostr(lItem));
2890
lImageDataEndPosition := lImageDataEndPosition+readItem(lItem,lStripCountType,lStripCountOffset);
2891
if not lcontiguous then begin
2892
if (lReadOffsets) and (lStackSameDim) then begin
2893
lLongRA^[lnSlices] := lVal;
2894
end else if (lReadOffsets) then
2895
//not correct size, but do not generate an error as we will read non-contiguous files
2897
Msg('TIFF Read Error: Image data is not stored contiguously. '+
2898
'Solution: convert this image using MRIcro''s ''Convert TIFF/Zeiss to Analyze...'' command [Import menu].');
2901
end; //if not contiguous
2902
end; //for each item
2903
end;//at least one StripItem}
2904
//END check image data is contiguous
2905
end; //END while each Image_file_directory
2906
lDicomData := l1stDicomData;
2907
lDicomData.XYZdim[3] := lnSlices;
2908
if (lReadOffsets) and (lnSlices > 1) and (not lcontiguous) then begin
2909
gECATJPEG_table_entries := lnSlices; //Offset tables for TIFF
2910
getmem (gECATJPEG_pos_table, gECATJPEG_table_entries*sizeof(longint));
2911
getmem (gECATJPEG_size_table, gECATJPEG_table_entries*sizeof(longint));
2912
gECATJPEG_pos_table^[1] := l1stDicomData.ImageStart;
2913
for lVal := 2 to gECATJPEG_table_entries do
2914
gECATJPEG_pos_table^[lVal] := lLongRA^[lVal]
2918
lDynStr := 'TIFF image'+kCR+
2919
'XYZ dim:' +inttostr(lDicomData.XYZdim[1])+'/'
2920
+inttostr(lDicomData.XYZdim[2])+'/'+inttostr(lDicomData.XYZdim[3])
2921
+kCR+'XYZ size [mm or micron]:'+floattostrf(lDicomData.XYZmm[1],ffFixed,8,2)+'/'
2922
+floattostrf(lDicomData.XYZmm[2],ffFixed,8,2)+'/'+floattostrf(lDicomData.XYZmm[3],ffFixed,8,2)
2923
+kCR+'Bits per sample/Samples per pixel: '+inttostr( lDICOMdata.Allocbits_per_pixel)
2924
+kCR+'Data offset:' +inttostr(lDicomData.ImageStart);
2926
lDynStr := lDynStr +kCR+'Zeiss XYZ mm:'+floattostr(lXmm)+'/'
2927
+floattostr(lYmm)+'/'
2932
FileMode := 2; //set to read/write
2935
procedure read_biorad_data(var lDICOMdata: DICOMdata; var lHdrOK, lImageFormatOK: boolean; var lDynStr: string;lFileName: string);
2939
lSpaces,liPos,lFileSz,lWord,lNotes,lStart,lEnd: integer;
2940
tx : array [0..80] of Char;
2941
lInfo,lStr,lTmpStr: string;
2943
procedure read16(lPos: longint; var lVal: integer);
2947
BlockRead(fp, lInWord, 2);
2950
procedure read32(lPos: longint; var lVal: integer);
2951
var lInINt: integer;
2954
BlockRead(fp, lInINt, 4);
2959
lImageFormatOK := true;
2961
if not fileexists(lFileName) then begin
2962
lImageFormatOK := false;
2965
FileMode := 0; //set to readonly
2966
AssignFile(fp, lFileName);
2968
lFileSz := FileSize(fp);
2969
Clear_Dicom_Data(lDicomData);
2970
if lFilesz < (77) then exit; //to small to be biorad
2972
if (lWord=12345) then begin
2973
lDicomData.little_endian := 1;
2974
read16(0,lDicomData.XYZdim[1]);
2975
read16(2,lDicomData.XYZdim[2]);
2976
read16(4,lDicomData.XYZdim[3]);
2977
read16(14,lWord);//byte format
2979
lDicomData.Allocbits_per_pixel := 8
2981
lDicomData.Allocbits_per_pixel := 16;//bits
2982
//xlDicomData.Storedbits_per_pixel:= lDicomData.Allocbits_per_pixel;
2983
lDicomData.ImageStart := 76;
2985
lStart := (lDicomData.XYZdim[1]*lDicomData.XYZdim[2]*lDicomData.XYZdim[3])+76;
2986
lEnd := lStart + 96;
2987
lDynStr := 'BIORAD PIC image'+kCR;
2988
while (lNotes > 0) and (lFileSz >= lEnd) do begin
2989
read32(lStart+2,lNotes); //final note has bytes 2..5 set to zero
2990
//read16(lStart+10,lNoteType);
2991
//if lNoteType <> 1 then begin //ignore 'LIVE' notes - they do not include calibration info
2992
seek(fp, lStart+16);
2993
BlockRead(fp, tx, 80{, n});
2999
if (lByte >= 32) and (lByte <= 126) then
3003
until (liPos = 80) or (lByte = 0);
3004
if length(lStr) > 6 then begin
3006
for liPos := 1 to 6 do
3007
lInfo := lInfo+upcase(lStr[liPos]);
3010
for liPos := 1 to 80 do begin
3011
if lStr[liPos]=' ' then inc(lSpaces)
3012
else if lSpaces = 3 then
3013
ltmpstr := ltmpstr + lStr[liPos];
3015
if ltmpstr = '' then {no value to read}
3016
else if lInfo = 'AXIS_2' then
3017
lDicomData.XYZmm[1] := strtofloat(ltmpstr)
3018
else if lInfo = 'AXIS_3' then
3019
lDicomData.XYZmm[2] := strtofloat(ltmpstr)
3020
else if linfo = 'AXIS_4' then
3021
lDicomData.XYZmm[3] := strtofloat(ltmpstr);
3022
lDynStr := lDynStr+lStr+kCR;
3023
end; //Str length > 6
3029
//lImageFormatOK := true;
3030
end;//biorad signature
3032
FileMode := 2; //set to read/write
3033
lDynStr := 'BioRad image'+kCR+
3034
'XYZ dim:' +inttostr(lDicomData.XYZdim[1])+'/'
3035
+inttostr(lDicomData.XYZdim[2])+'/'+inttostr(lDicomData.XYZdim[3])
3036
+kCR+'XYZ size [mm or micron]:'+floattostrf(lDicomData.XYZmm[1],ffFixed,8,2)+'/'
3037
+floattostrf(lDicomData.XYZmm[2],ffFixed,8,2)+'/'+floattostrf(lDicomData.XYZmm[3],ffFixed,8,2)
3038
+kCR+'Bits per sample/Samples per pixel: '+inttostr( lDICOMdata.Allocbits_per_pixel)
3039
+kCR+'Data offset:' +inttostr(lDicomData.ImageStart);
3046
procedure read_dicom_data_compat(lReadJPEGtables,lVerboseRead,lAutoDECAT7,lReadECAToffsetTables,lAutoDetectInterfile,lAutoDetectGenesis,lReadColorTables: boolean; var lDICOMdata: DICOMdata; var lHdrOK, lImageFormatOK: boolean; var lDynStr: string;var lFileName: string; var lPrefs: TPrefs);
3049
kMaxTextBuf = 50000; //maximum for screen output
3050
kDiskCache = 16384; //size of disk buffer
3053
dicom_types = (unknown, i8, i16, i32, ui8, ui16, ui32, _string{,_float} );
3055
// lTextF: TextFile; //abba
3056
lDICOMdataBackUp: DICOMdata;
3057
lWord,lWord2,lWord3: word;
3059
lDiskCacheRA: pChar{ByteP};
3060
lRot1,lRot2,lRot3 : integer;//rotation dummies for AFNI
3062
lT0,lT1,lT2,lT3:byte;
3063
lImagePositionPatientRead,
3064
lResearchMode,lManufacturerIsPhilips,lManufacturerIsBruker,lMediface0002_0013,lSiemensMosaic0008_0008,lDICM_at_128, lTextOverFlow,lGenesis,lFirstPass,lrOK,lBig,lBigSet,lGrp,explicitVR,first_one : Boolean;
3065
lTestError,lByteSwap,lGELX,time_to_quit,lProprietaryImageThumbnail,lFirstFragment,lOldSiemens_IncorrectMosaicMM : Boolean;
3066
group, element, e_len, remaining, tmp : uint32;
3068
lgrpstr,lStr,info,lDummyStr : string;
3070
lfloat1,lfloat2,lfloat3,lThickness: double;
3071
lTempInt,lEchoNum,lnVol,lnSlicePerVol,lJPEGentries,lErr,liPos,lCacheStart,lCachePos,lDiskCacheSz,n, i,value, Ht,Width,
3072
max16,min16,filesz,where,lMatrixSz,lPhaseEncodingSteps,lJunk,lJunk2,lJunk3 : LongInt;
3073
tx : array [0..96] of Char;
3074
l4DDistanceBetweenSliceCenters,lPhilipsScaleSlope: single;
3078
lSingleRA,lInterceptRA: Singlep;
3079
//lPapyrusnSlices,lPapyrusSlice : integer;
3080
//lPapyrusZero,lPapyrus : boolean;
3081
procedure ByteSwap (var lInOut: integer);
3085
lWord := swap(lWord);
3088
procedure dReadCache (lFileStart: integer);
3090
lCacheStart := lFileStart{lCacheStart + lDiskCacheSz};//eliminate old start
3091
if lCacheStart < 0 then lCacheStart := 0;
3092
if lDiskCacheSz > 0 then freemem(lDiskCacheRA);
3093
if (FileSz-(lCacheStart)) < kDiskCache then
3094
lDiskCacheSz := FileSz - (lCacheStart)
3096
lDiskCacheSz := kDiskCache;
3098
if (lDiskCacheSz < 1) then exit{goto 666};
3099
if (lDiskCacheSz+lCacheStart) > FileSz then exit;
3100
Seek(fp, lCacheStart);
3102
GetMem(lDiskCacheRA, lDiskCacheSz {bytes});
3103
BlockRead(fp, lDiskCacheRA^, lDiskCacheSz, n);
3106
function dFilePos (var lInFP: file): integer;
3108
Result := lCacheStart + lCachePos;
3110
procedure dSeek (var lInFP: file; lPos: integer);
3112
if (lPos >= lCacheStart) and (lPos < (lDiskCacheSz+lCacheStart)) then begin
3113
lCachePos := lPos-lCacheStart;
3119
procedure dBlockRead (var lInfp: file; lInbuff: pChar; e_len: integer; var n: integer);
3123
if e_len < 0 then exit;
3124
for lN := 0 to (e_len-1) do begin
3125
if lCachePos >= lDiskCacheSz then begin
3126
dReadCache(lCacheStart+lDiskCacheSz);
3127
if lDiskCacheSz < 1 then exit;
3131
lInBuff[N] := lDiskCacheRA[lCachePos];
3135
procedure readfloats (var fp: file; remaining: integer; var lOutStr: string; var lf1, lf2: double; var lReadOK: boolean);
3136
var lDigit : boolean;
3142
if e_len = 0 then begin
3146
if (dFilePos(fp) > (filesz-remaining)) or (remaining < 1) then begin
3153
GetMem( buff, e_len);
3154
dBlockRead(fp, buff{^}, e_len, n);
3155
for li := 0 to e_len-1 do
3156
if Char(buff[li]) in [{'/','\', delete: rev18}'e','E','+','-','.','0'..'9']
3157
then lOutStr := lOutStr +(Char(buff[li]))
3159
lOutStr := lOutStr + ' ';
3163
lLen := length(lOutStr);
3168
if (lOutStr[li] in ['+','-','e','E','.','0'..'9']) then
3169
lfStr := lfStr + lOutStr[li];
3170
if lOutStr[li] in ['0'..'9'] then lDigit := true;
3172
until (li > lLen) or (lDigit);
3173
if not lDigit then exit;
3174
if li <= li then begin
3176
if not (lOutStr[li] in ['+','-','e','E','.','0'..'9']) then lDigit := false
3178
if lOutStr[li] = 'E' then lfStr := lfStr+'e'
3180
lfStr := lfStr + lOutStr[li];
3183
until (li > lLen) or (not lDigit);
3187
lf1 := strtofloat(lfStr);
3189
on EConvertError do begin
3190
Msg('Unable to convert the string '+lfStr+' to a real number');
3196
if li > llen then exit;
3198
if (lOutStr[li] in ['+','E','e','.','-','0'..'9']) then begin
3199
if lOutStr[li] = 'E' then lfStr := lfStr+'e'
3201
lfStr := lfStr + lOutStr[li];
3203
if (lOutStr[li] in ['0'..'9']) then lDigit := true;
3205
until (li > lLen) or ((lDigit) and (lOutStr[li]=' ')); //second half: rev18
3206
if not lDigit then exit;
3209
lf2 := strtofloat(lfStr);
3211
on EConvertError do begin
3212
Msg('Unable to convert the string '+lfStr+' to a real number');
3219
procedure readfloats3 (var fp: file; remaining: integer; var lOutStr: string; var lf1, lf2,lf3: double; var lReadOK: boolean);
3220
var lDigit : boolean;
3221
lItem,li,lLen,n: integer;
3229
if e_len = 0 then begin
3233
if (dFilePos(fp) > (filesz-remaining)) or (remaining < 1) then begin
3238
GetMem( buff, e_len);
3239
dBlockRead(fp, buff{^}, e_len, n);
3240
for li := 0 to e_len-1 do
3241
if Char(buff[li]) in [{'/','\', delete: rev18}'e','E','+','-','.','0'..'9']
3242
then lOutStr := lOutStr +(Char(buff[li]))
3243
else lOutStr := lOutStr + ' ';
3246
lLen := length(lOutStr);
3247
for lItem := 1 to 3 do begin
3248
if li > llen then exit;
3250
lLen := length(lOutStr);
3253
if (lOutStr[li] in ['+','-','e','E','.','0'..'9']) then
3254
lfStr := lfStr + lOutStr[li];
3255
if lOutStr[li] in ['0'..'9'] then lDigit := true;
3257
until (li > lLen) or (lDigit);
3258
if not lDigit then exit;
3259
if li <= li then begin
3261
if not (lOutStr[li] in ['+','-','e','E','.','0'..'9']) then lDigit := false
3263
if lOutStr[li] = 'E' then lfStr := lfStr+'e'
3265
lfStr := lfStr + lOutStr[li];
3268
until (li > lLen) or (not lDigit);
3272
lftemp := strtofloat(lfStr);
3274
on EConvertError do begin
3275
Msg('Unable to convert the string '+lfStr+' to a real number');
3284
end; //case of lItem
3285
end; //for each of 3 lItems
3288
procedure CheckIntersliceDistance (var lMinDistance: single);
3290
lX,lY,lZ,lDx: double;
3292
readfloats3 (fp, remaining, lDummyStr, lX, lY,lZ, lROK);
3296
//compute Distance between current slice and 1st slice...
3297
lDx := sqrt( sqr(lX-lDicomData.PatientPosX)+sqr(lY-lDicomData.PatientPosY)+sqr(lZ-lDicomData.PatientPosZ));
3298
if (lDx > 0) and (lDx < lMinDistance) then //if 0 then this is a repeat, not a new slice
3299
lMinDistance := lDx;
3302
procedure readfloats6 (var fp: file; remaining: integer; var lOutStr: string; var lf1, lf2,lf3,lf4,lf5,lf6: double; var lReadOK: boolean);
3303
var lDigit : boolean;
3304
lItem,li,lLen,n: integer;
3315
if e_len = 0 then begin
3319
if (dFilePos(fp) > (filesz-remaining)) or (remaining < 1) then begin
3324
GetMem( buff, e_len);
3325
dBlockRead(fp, buff{^}, e_len, n);
3326
for li := 0 to e_len-1 do
3327
if Char(buff[li]) in [{'/','\', delete: rev18}'e','E','+','-','.','0'..'9']
3328
then lOutStr := lOutStr +(Char(buff[li]))
3329
else lOutStr := lOutStr + ' ';
3332
lLen := length(lOutStr);
3333
for lItem := 1 to 6 do begin
3334
if li > llen then exit;
3336
lLen := length(lOutStr);
3339
if (lOutStr[li] in ['+','-','e','E','.','0'..'9']) then
3340
lfStr := lfStr + lOutStr[li];
3341
if lOutStr[li] in ['0'..'9'] then lDigit := true;
3343
until (li > lLen) or (lDigit);
3344
if not lDigit then exit;
3345
if li <= li then begin
3347
if not (lOutStr[li] in ['+','-','e','E','.','0'..'9']) then lDigit := false
3349
if lOutStr[li] = 'E' then lfStr := lfStr+'e'
3351
lfStr := lfStr + lOutStr[li];
3354
until (li > lLen) or (not lDigit);
3359
lftemp := strtofloat(lfStr);
3361
on EConvertError do begin
3362
Msg('Unable to convert the string '+lfStr+' to a real number');
3374
end; //case of lItem
3375
end; //for each of 3 lItems
3378
function read16( var fp : File; var lReadOK: boolean ): uint16;
3383
if dFilePos(fp) > (filesz-2) then begin
3390
dBlockRead(fp, buff{^}, 2, n);
3394
if lDICOMdata.little_endian <> 0
3395
then Result := (t1 + t2*256) AND $FFFF
3396
else Result := (t1*256 + t2) AND $FFFF;
3399
function ReadStr(var fp: file; remaining: integer; var lReadOK: boolean; VAR lmaxval:integer) : string;
3400
var lInc, lN,Val,n: integer;
3405
if dFilePos(fp) > (filesz-remaining) then begin
3411
lN := remaining div 2;
3412
if lN < 1 then exit;
3414
for lInc := 1 to lN do begin
3416
dBlockRead(fp, buff{^}, 2, n);
3420
if lDICOMdata.little_endian <> 0 then
3421
Val := (t1 + t2*256) AND $FFFF
3423
Val := (t1*256 + t2) AND $FFFF;
3425
lStr := lStr + inttostr(Val)+ ', '
3427
lStr := lStr + inttostr(Val);
3428
if Val > lMaxVal then
3432
if odd(remaining) then begin
3434
dBlockRead(fp, buff{t1}, SizeOf(uint8), n);
3439
(*function ReadStrABC(var fp: file; remaining: integer; var lReadOK: boolean; VAR lA,lB,lC:integer) : string;
3440
var lInc, lN,Val,n: integer;
3447
if dFilePos(fp) > (filesz-remaining) then begin
3453
lN := remaining div 2;
3454
if lN < 1 then exit;
3456
for lInc := 1 to lN do begin
3458
dBlockRead(fp, buff{^}, 2, n);
3462
if lDICOMdata.little_endian <> 0 then
3463
Val := (t1 + t2*256) AND $FFFF
3465
Val := (t1*256 + t2) AND $FFFF;
3467
lStr := lStr + inttostr(Val)+ ', '
3469
lStr := lStr + inttostr(Val);
3480
if odd(remaining) then begin
3482
dBlockRead(fp, buff{t1}, SizeOf(uint8), n);
3487
function ReadStrHex(var fp: file; remaining: integer; var lReadOK: boolean) : string;
3488
var lInc, lN,Val,n: integer;
3492
if dFilePos(fp) > (filesz-remaining) then begin
3498
lN := remaining div 2;
3499
if lN < 1 then exit;
3501
for lInc := 1 to lN do begin
3503
dBlockRead(fp, buff, 2, n);
3507
if lDICOMdata.little_endian <> 0 then
3508
Val := (t1 + t2*256) AND $FFFF
3510
Val := (t1*256 + t2) AND $FFFF;
3511
if lInc < lN then lStr := lStr + 'x'+inttohex(Val,4)+ ', '
3512
else lStr := lStr + 'x'+inttohex(Val,4);
3515
if odd(remaining) then begin
3517
dBlockRead(fp, {t1}buff, SizeOf(uint8), n);
3521
function SomaTomFloat: double;
3522
var lSomaStr: String;
3524
//dSeek(fp,5992); //Slice Thickness from 5790 "SL 3.0"
3525
//dSeek(fp,5841); //Field of View from 5838 "FoV 281"
3529
while (length(lSomaStr) < 64) and (tx[0] <> chr(0)) and (tx[0] <> '/') do begin
3530
dBlockRead(fp, tx, 1, n);
3531
if tx[0] in ['+','-','.','0'..'9','e','E'] then
3532
lSomaStr := lSomaStr + tx[0];
3534
if length(lSOmaStr) > 0 then
3535
result := StrToFloat(lSomaStr)
3540
function PGMreadInt: integer;
3541
//reads integer from PGM header, disregards comment lines (which start with '#' symbol);
3549
dBlockRead(fp, tx, 1, n);
3550
if tx[0] = '#' then begin //comment
3552
dBlockRead(fp, tx, 1, n);
3553
until (ord(tx[0]) = $0A) or (dFilePos(fp) > (filesz-4)); //eoln indicates end of comment
3554
end; //finished reading comment
3555
if tx[0] in ['0'..'9'] then begin
3556
lStr := lStr + tx[0];
3560
until ((lStr <> '') and (not lDigit)) or (dFilePos(fp) > (filesz-4)); //read digits until you hit whitespace
3562
Result := strtoint(lStr);
3566
while (length(lStr) < 64) and (ord(tx[0]) <> $0A) do begin
3567
dBlockRead(fp, tx, 1, n);
3568
if tx[0] in ['#','+','-','.','0'..'9','e','E',' ','a'..'z','A'..'Z'] then
3569
lStr := lStr + tx[0];
3574
function read32 ( var fp : File; var lReadOK: boolean ): uint32;
3576
t1, t2, t3, t4 : byte;
3579
if dFilePos(fp) > (filesz-4) then begin
3586
dBlockRead(fp, buff{^}, 4, n);
3592
if lDICOMdata.little_endian <> 0 then
3593
Result := t1 + (t2 shl 8) + (t3 shl 16) + (t4 shl 24)
3595
Result := t4 + (t3 shl 8) + (t2 shl 16) + (t1 shl 24)
3596
//if lDICOMdata.little_endian <> 0
3597
//then Result := (t1 + t2*256 + t3*256*256 + t4*256*256*256) AND $FFFFFFFF
3598
//else Result := (t1*256*256*256 + t2*256*256 + t3*256 + t4) AND $FFFFFFFF;
3601
function read32r ( var fp : File; var lReadOK: boolean ): single; //1382
3603
swaptype = packed record
3605
0:(Word1,Word2 : word); //word is 16 bit
3608
swaptypep = ^swaptype;
3614
if dFilePos(fp) > (filesz-4) then begin
3621
dBlockRead(fp, @s, 4, n);
3622
inguy := @s; //assign address of s to inguy
3623
if lDICOMdata.little_endian <> 1 then begin
3624
outguy.Word1 := swap(inguy^.Word2);
3625
outguy.Word2 := swap(inguy^.Word1);
3627
outguy.float := s; //1382 read64 needs to handle little endian in this way as well...
3628
read32r:=outguy.float;
3631
function read64 ( var fp : File; var lReadOK: boolean ): double;
3633
swaptype = packed record
3635
0:(Word1,Word2,Word3,Word4 : word); //word is 16 bit
3638
swaptypep = ^swaptype;
3644
if dFilePos(fp) > (filesz-8) then begin
3651
dBlockRead(fp, @s, 8, n);
3652
inguy := @s; //assign address of s to inguy
3653
if lDICOMdata.little_endian <> 1 then begin
3654
outguy.Word1 := swap(inguy^.Word4);
3655
outguy.Word2 := swap(inguy^.Word3);
3656
outguy.Word3 := swap(inguy^.Word2);
3657
outguy.Word4 := swap(inguy^.Word1);
3659
outguy.float := inguy^.float; //1382
3660
read64:=outguy.float;
3664
function SafeStrToInt(var lInput: string): integer;
3665
var li,lLen: integer;
3668
lLen := length(lInput);
3670
if lLen < 1 then exit;
3671
for li := 1 to lLen do
3672
if lInput[li] in ['+','-','0'..'9']
3673
then lStr := lStr +lInput[li];
3676
result := lI;//strtoint(lStr);
3680
procedure DICOMHeaderStringToInt (var lInput: integer);
3685
if dFilePos(fp) > (filesz-e_len) then exit;//goto 666;
3686
GetMem( buff, e_len);
3687
dBlockRead(fp, buff{^}, e_len, n);
3688
for li := 0 to e_len-1 do
3689
if Char(buff[li]) in ['+','-','0'..'9']
3690
then lStr := lStr +(Char(buff[li]));
3693
if lErr = 0 then lInput := li;//strtoint(lStr);
3698
procedure DICOMHeaderString (var lInput: kDICOMStr);
3699
var li,lStartPos: integer;
3702
lStartPos := dFilePos(fp);
3704
if e_len < 1 then exit; //DICOM: should always be even
3705
GetMem( buff, e_len);
3706
dBlockRead(fp, buff{^}, e_len, n);
3707
for li := 0 to e_len-1 do
3708
if Char(buff[li]) in ['+','-','/','\',' ','0'..'9','a'..'z','A'..'Z'] then
3709
lInput := lInput +(Char(buff[li]))
3710
else {if (buff[i] = 0) then}
3711
lInput := lInput +' ';
3714
dseek(fp, lStartPos);
3716
procedure DICOMHeaderStringTime (var lInput: kDICOMstr);
3717
var li,lStartPos: integer;
3720
lStartPos := dFilePos(fp);
3722
if e_len < 1 then exit; //DICOM: should always be even
3723
GetMem( buff, e_len);
3724
dBlockRead(fp, buff{^}, e_len, n);
3725
for li := 0 to e_len-1 do
3726
if Char(buff[li]) in ['+','-','/','\',' ','0'..'9','a'..'z','A'..'Z','.'] then
3727
lInput := lInput +(Char(buff[li]))
3728
else if li <> (e_len-1) then
3729
lInput := lInput +':'
3731
lInput := lInput +' ';
3734
dseek(fp, lStartPos);
3739
//for lnVol := 1 to kMaxOrderVal do
3740
// lDICOMdata.OrderSlope[lDICOMdata.nOrder] := 0; //show this was not set
3743
Clear_Dicom_Data(lDicomData);
3744
Clear_Dicom_Data(lDICOMdataBackUp);
3745
lDicomData.XYZdim[1] := 1;
3746
lImagePositionPatientRead := false;// for 4D files, we need first volume
3747
l4DDistanceBetweenSliceCenters := maxint;
3750
lTestError := false;
3751
lPhilipsScaleSlope := 0;
3752
lManufacturerIsPhilips := false;
3753
lManufacturerIsBruker := false;
3756
lResearchMode := false;
3758
lPhaseEncodingSteps := 0;
3759
lSiemensMosaic0008_0008 := false;
3760
lMediface0002_0013 := false;//false wblate
3761
lOldSiemens_IncorrectMosaicMM := false;
3770
lDICM_at_128 := false; //no DICOM signature
3771
lFirstFragment := true;
3772
lTextOverFlow := false;
3773
lImageFormatOK := true;
3775
//if lverboseRead then msg('xxx'+lFileName);
3776
if not fileexists(lFileName) then begin
3777
lImageFormatOK := false;
3780
//if lverboseRead then msg('zzzzz000000000');
3781
TmpStr := string(StrUpper(PChar(ExtractFileExt(lFileName))));
3783
if TmpStr = '.FDF' then begin
3784
if FDF( lFileName, lDicomData) then begin
3786
lImageFormatOK := true;
3790
if (TmpStr = '.REC') then begin //1417z: check in Unix: character upper/lower case may matter
3791
lStr := changefileext(lFilename,'.par');
3792
if fileexists(lStr) then
3794
else begin //Linux is case sensitive 1382...
3795
lStr := changefileext(lFilename,'.PAR');
3796
if fileexists(lStr) then
3800
if (TmpStr = '.BRIK') then begin //1417z: check in Unix: character upper/lower case may matter
3801
lStr := changefileext(lFilename,'.HEAD');
3802
if fileexists(lStr) then lFilename := lStr;
3804
FileMode := 0; //set to readonly
3805
AssignFile(fp, lFileName);
3807
FIleSz := FileSize(fp);
3808
if fileSz < 1 then begin
3809
lImageFormatOK := false;
3812
lDICOMdata.Little_Endian := 1;
3813
if FileSz > 200 then begin
3815
dBlockRead(fp, tx, 4*SizeOf(Char), n);
3816
if (tx[0] = 'D') and (tx[1] = 'I') and (tx[2] = 'C') and (tx[3] = 'M') then
3817
lDICM_at_128 := true;
3818
end;//filesize > 200: check for 'DICM' at byte 128 - DICOM signature
3819
if (lAutoDetectGenesis) and (FileSz > (5820{114+35+4})) then begin
3821
if (ord(tx[0])=206) and (ord(tx[1])=250) then begin
3822
//Elscint format signature: check height and width to make sure
3825
group := read16(fp,lrOK);//Width
3827
element := read16(fp,lrOK);//Ht
3828
if ((Group=160) or(Group =256) or (Group= 340) or (Group=512) or (group =640)) and
3829
((element=160) or (element =256) or (element= 340) or (element=512) ) then begin
3831
if lDiskCacheSz > 0 then
3832
freemem(lDiskCacheRA);
3833
FileMode := 2; //set to read/write
3834
read_elscint_data(lDICOMdata, lHdrOK, lImageFormatOK,lDynStr,lFileName);
3836
end; //confirmed: Elscint
3839
if ((tx[0] <> 'I') OR (tx[1] <> 'M') OR (tx[2] <> 'G') OR (tx[3] <> 'F')) then begin {DAT format}
3840
{if (FileSz > 114+305+4) then begin
3842
dBlockRead(fp, tx, 3*SizeOf(Char), n);
3843
if ((tx[0]='M') and (tx[1] = 'R')) or ((tx[0] = 'C') and(tx[1] = 'T')) then
3848
if (not lGenesis) and (FileSz > 3252) then begin
3850
dBlockRead(fp, tx, 4*SizeOf(Char), n);
3851
if ((tx[0] = 'I') AND (tx[1] = 'M')AND (tx[2] = 'G') AND (tx[3] = 'F')) then
3853
if (not lGenesis) then begin
3855
dBlockRead(fp, tx, 4*SizeOf(Char), n);
3856
if ((tx[0] = 'I') AND (tx[1] = 'M')AND (tx[2] = 'G') AND (tx[3] = 'F')) then
3859
if (not lGenesis) then begin
3861
dBlockRead(fp, tx, 4*SizeOf(Char), n);
3862
if ((tx[0] = 'I') AND (tx[1] = 'M')AND (tx[2] = 'G') AND (tx[3] = 'F')) then
3865
if (not lGenesis) then begin //1499K
3867
dBlockRead(fp, tx, 4*SizeOf(Char), n);
3868
if ((tx[0] = 'I') AND (tx[1] = 'M')AND (tx[2] = 'G') AND (tx[3] = 'F')) then
3873
if (not lGenesis) and (FileSz > 3252) then begin
3875
dBlockRead(fp, tx, 4*SizeOf(Char), n);
3876
if (tx[0] = 'I') AND (tx[1]= 'M') AND (tx[2] = 'G')AND (tx[3]= 'F') then
3879
if lGenesis then begin
3881
if lDiskCacheSz > 0 then
3882
freemem(lDiskCacheRA);
3883
FileMode := 2; //set to read/write
3884
read_ge_data(lDICOMdata, lHdrOK, lImageFormatOK,lDynStr,lFileName);
3887
end; //AutodetectGenesis xxDCIM
3889
if (lAutoDetectInterfile) and (FileSz > 256) and (not lDICM_at_128) then begin
3890
if Copy(extractfilename(lFileName), 1, 4) = 'COR-' then begin
3891
lStr := extractfiledir(lFilename) + '\COR-.info';
3892
TmpStr := extractfiledir(lFilename) + '\COR-128';
3893
if fileexists(lStr) and fileexists(TmpStr) then begin
3894
lFilename := TmpStr;
3895
lDynStr := 'FreeSurfer COR format' + kCR+'Only displaying image 128'+kCR+'Use MRIcro''s Import menu to convert this image'+kCR;
3896
with lDicomData do begin
3897
little_endian := 0; // don't care
3899
Allocbits_per_pixel := 8;
3906
//xStoredbits_per_pixel:= Allocbits_per_pixel;
3909
lImageFormatOK := True;
3911
end; //COR-.info file exists
3912
end; //if filename is COR-
3914
//TIF IMAGES DO NOT ALWAYS HAVE EXTENSION if (TmpStr = '.TIF') or (TmpStr = '.TIFF') then begin
3916
lWord := read16(fp,lrOK);
3917
if lWord = $4d4d then
3918
lDICOMdata.little_endian := 0
3919
else if lWord = $4949 then lDICOMdata.little_endian := 1;
3921
lWord2 := read16(fp,lrOK); //bits per pixel
3922
if ((lWord=$4d4d) or (lWord=$4949)) and (lWord2 = $002a) then begin
3924
if lDiskCacheSz > 0 then
3925
freemem(lDiskCacheRA);
3926
FileMode := 2; //set to read/write
3927
read_tiff_data(lDICOMdata, lReadECAToffsetTables, lHdrOK, lImageFormatOK, lDynStr, lFileName);
3928
//if lHdrOk then exit;
3931
//end; //.TIF extension
3934
TmpStr := string(StrUpper(PChar(ExtractFileExt(lFileName))));
3935
if TmpStr = '.BMP' then begin
3937
lWord := read16(fp,lrOK);
3939
lWord2 := read16(fp,lrOK); //bits per pixel
3940
if (lWord=19778) and (lWord2 = 8) then begin //bitmap signature
3942
lDicomData.ImageStart := read32(fp,lrOK);//1078;
3944
lDicomData.XYZdim[1] := read32(fp,lrOK);
3946
lDicomData.XYZdim[2] := read32(fp,lrOK);
3947
lDicomData.XYZdim[3] := 1;//read16(fp,lrOK);
3948
lDicomData.Allocbits_per_pixel := 8;//bits
3949
//xlDicomData.Storedbits_per_pixel:= lDicomData.Allocbits_per_pixel;
3950
lDynStr := 'BMP format';
3952
if lDiskCacheSz > 0 then
3953
freemem(lDiskCacheRA);
3954
FileMode := 2; //set to read/write
3956
lImageFormatOK:= true;
3959
end; //.BMP extension
3961
if TmpStr = '.VOL' then begin //start SPACE vol format 1382
3963
dBlockRead(fp, tx, 6*SizeOf(Char), n);
3964
if (tx[0] = 'm') and (tx[1] = 'd') and (tx[2] = 'v') and (tx[3] = 'o') and (tx[4] = 'l') and (tx[5] = '1') then begin
3965
lDicomData.ImageStart := read32(fp,lrOK);//1078;
3966
lDICOMdata.little_endian := 1;
3967
lDicomData.XYZdim[1] := read32(fp,lrOK);
3968
lDicomData.XYZdim[2] := read32(fp,lrOK);
3969
lDicomData.XYZdim[3] := read32(fp,lrOK);
3970
lDicomData.XYZmm[1] := read32r(fp,lrOK);
3971
lDicomData.XYZmm[2] := read32r(fp,lrOK);
3972
lDicomData.XYZmm[3] := read32r(fp,lrOK);
3973
lDicomData.Allocbits_per_pixel := 8;//bits
3974
//xlDicomData.Storedbits_per_pixel:= lDicomData.Allocbits_per_pixel;
3975
lDynStr := 'Space VOL format';
3977
if lDiskCacheSz > 0 then
3978
freemem(lDiskCacheRA);
3979
FileMode := 2; //set to read/write
3981
lImageFormatOK:= true;
3984
end; //.VOL extension
3985
//end space .VOL format
3986
//start DF3 PovRay DF3 density files
3987
if (TmpStr = '.DF3') then begin
3989
lWord := swap (read16(fp,lrOK));
3990
lWord2 := swap (read16(fp,lrOK));
3991
lWord3 := swap (read16(fp,lrOK));
3992
//note: I assume all df3 headers are little endian. is this always true? if not, unswapped values could be tested for filesize
3993
lMatrixSz := (lWord*lWord2*lWord3)+6;
3994
if (lMatrixSz=FileSz)then begin //df3 signature
3995
lDicomData.ImageStart := 6;//1078;
3996
lDicomData.XYZdim[1] := lWord;
3998
lDicomData.XYZdim[2] := lWord2;
3999
lDicomData.XYZdim[3] := lWord3;
4000
lDicomData.Allocbits_per_pixel := 8;//bits
4001
//xlDicomData.Storedbits_per_pixel:= lDicomData.Allocbits_per_pixel;
4003
if lDiskCacheSz > 0 then
4004
freemem(lDiskCacheRA);
4005
FileMode := 2; //set to read/write
4006
lDynStr := 'PovRay DF3 density format';
4008
lImageFormatOK:= true;
4015
if (TmpStr = '.PGM') or (TmpStr = '.PPM') then begin
4017
lWord := read16(fp,lrOK);
4018
if (lWord=13648){'P5'=1x8BIT GRAYSCALE} or (lWord=13904) {'P6'=3x8bit RGB} then begin //bitmap signature
4020
PGMreadStr(lDicomData.XYZdim[1],lDicomData.XYZdim[2]);
4021
until (lDicomData.XYZdim[2] > 0) ;}
4022
lDicomData.XYZdim[1] := PGMreadInt;
4023
lDicomData.XYZdim[2] := PGMreadInt;
4024
PGMreadInt; //read maximum value
4026
lDicomData.XYZdim[3] := 1;//read16(fp,lrOK);
4027
lDicomData.Allocbits_per_pixel := 8;//bits
4028
//xlDicomData.Storedbits_per_pixel:= lDicomData.Allocbits_per_pixel;
4029
lDicomData.ImageStart := dFilepos(fp);
4030
if lWord = 13904 then begin//RGB
4031
//xlDicomData.SamplesPerPixel := 3;
4032
//xlDicomData.PlanarConfig := 0;//RGBRGBRGB..., not RRR..RGGG..GBBB...B
4034
lDynStr:='PGM/PPM format 8-bit grayscale image [data saved in binary, not ASCII format]';
4036
if lDiskCacheSz > 0 then
4037
freemem(lDiskCacheRA);
4038
FileMode := 2; //set to read/write
4040
lImageFormatOK:= true;
4042
end else if (lWord=12880){'P2'=1x8BIT ASCII} or (lWord=13136) {'P3'=3x8bit ASCI} then begin
4043
Msg('Warning: this image appears to be an ASCII ppm/pgm image. This software can only read binary ppm/pgm images');
4044
end;//pgm/ppm binary signature signature
4045
end; //.PPM/PGM extension
4049
//start BioRadPIC 1667
4050
if TmpStr = '.PIC' then begin
4052
lWord := read16(fp,lrOK);
4053
if (lWord=12345) then begin
4055
if lDiskCacheSz > 0 then
4056
freemem(lDiskCacheRA);
4057
FileMode := 2; //set to read/write
4058
read_biorad_data(lDICOMdata, lHdrOK, lImageFormatOK,lDynStr,lFileName);
4060
end;//biorad signature
4061
end; //.PIC extension biorad?
4063
if TmpStr = '.HEAD' then begin
4064
read_afni_data(lDICOMdata, lHdrOK, lImageFormatOK, lDynStr, lFileName,lRot1,lRot2,lRot3);
4065
if (lHdrOK) and (lImageFormatOK) then begin
4067
if lDiskCacheSz > 0 then
4068
freemem(lDiskCacheRA);
4069
FileMode := 2; //set to read/write
4074
dBlockRead(fp, tx, 20*SizeOf(Char), n);
4075
if (tx[0] = 'n') and (tx[1] = 'c') and (tx[2] = 'a') and (tx[3] = 'a') then begin
4076
//SUN Vision File Format = .vff
4078
if lDiskCacheSz > 0 then
4079
freemem(lDiskCacheRA);
4080
FileMode := 2; //set to read/write
4081
read_vff_data(lDICOMdata, lHdrOK, lImageFormatOK, lDynStr, lFileName);
4086
{999 While (liPos <= 20) and (lStr <> 'INTERFILE') do begin
4087
if tx[liPos] in ['i','n','t','e','r', 'f','i','l','e','I','N','T','E','R', 'F','I','L','E'] then
4088
lStr := lStr+upcase(tx[liPos]);
4091
if lStr = 'INTERFILE' then begin
4093
if lDiskCacheSz > 0 then
4094
freemem(lDiskCacheRA);
4095
FileMode := 2; //set to read/write
4096
read_interfile_data(lDICOMdata, lHdrOK, lImageFormatOK, lDynStr, lFileName);
4097
if lHdrOk then exit;
4099
end; //'INTERFILE' in first 20 char
4101
// try DICOM part 10 i.e. a 128 byte file preamble followed by "DICM"
4102
if filesz <= 300 then goto 666;
4103
{begin siemens somatom: DO THIS BEFORE MAGNETOM: BOTH HAVE 'SIEMENS' SIGNATURE, SO CHECK FOR 'SOMATOM'}
4104
if filesz = 530432 then begin
4106
dBlockRead(fp, tx, 8*SizeOf(Char), n);
4107
if (tx[0] = 'S') and (tx[1] = 'O') and (tx[2] = 'M') and (tx[3] = 'A') and (tx[4] = 'T') and (tx[5] = 'O') and (tx[6] = 'M') then begin
4108
lDicomData.ImageStart := 6144;
4109
lDicomData.Allocbits_per_pixel := 16;
4110
//xlDicomData.Storedbits_per_pixel := 16;
4111
lDicomData.little_endian := 0;
4112
lDicomData.XYZdim[1] := 512;
4113
lDicomData.XYZdim[2] := 512;
4114
lDicomData.XYZdim[3] := 1;
4115
dSeek(fp,5999); //Study/Image from 5292 "STU/IMA 1070/16"
4116
lDicomData.AcquNum := trunc(SomaTomFloat);//Slice Thickness from 5790 "SL 3.0"
4117
lDicomData.ImageNum := trunc(SomaTomFloat);//Slice Thickness from 5790 "SL 3.0"
4118
dSeek(fp,5792); //Slice Thickness from 5790 "SL 3.0"
4119
lDicomData.XYZmm[3] := SomaTomFloat;//Slice Thickness from 5790 "SL 3.0"
4120
dSeek(fp,5841); //Field of View from 5838 "FoV 281"
4121
lDicomData.XYZmm[1] := SomaTomFloat; //Field of View from 5838 "FoV 281"
4122
lDicomData.XYZmm[2] := lDicomData.XYZmm[1]/lDicomData.XYZdim[2];//do mm[2] first before FOV is overwritten
4123
lDicomData.XYZmm[1] := lDicomData.XYZmm[1]/lDicomData.XYZdim[1];
4124
if lVerboseRead then
4125
lDynStr := 'Siemens Somatom Format'+kCR+
4126
'Image Series/Number: '+inttostr(lDicomData.AcquNum)+'/'+inttostr(lDicomData.ImageNum)+kCR+
4127
'XYZ dim:' +inttostr(lDicomData.XYZdim[1])+'/'
4128
+inttostr(lDicomData.XYZdim[2])+'/'+inttostr(lDicomData.XYZdim[3])
4129
+kCR+'XYZ mm:'+floattostrf(lDicomData.XYZmm[1],ffFixed,8,2)+'/'
4130
+floattostrf(lDicomData.XYZmm[2],ffFixed,8,2)+'/'+floattostrf(lDicomData.XYZmm[3],ffFixed,8,2);
4132
if lDiskCacheSz > 0 then
4133
freemem(lDiskCacheRA);
4134
FileMode := 2; //set to read/write
4135
lImageFormatOK := true;
4138
end; //signature found
4139
end; //correctsize for somatom
4140
{end siemens somatom}
4144
dBlockRead(fp, tx, 7*SizeOf(Char), n);
4145
if (tx[0] = 'S') and (tx[1] = 'I') and (tx[2] = 'E') and (tx[3] = 'M') and (tx[4] = 'E') and (tx[5] = 'N') and (tx[6] = 'S') then begin
4147
if lDiskCacheSz > 0 then
4148
freemem(lDiskCacheRA);
4149
FileMode := 2; //set to read/write
4150
read_siemens_data(lDICOMdata, lHdrOK, lImageFormatOK, lDynStr, lFileName);
4153
{end siemens magnetom vision}
4154
{siemens somatom plus}
4156
dBlockRead(fp, tx, 8*SizeOf(Char), n);
4157
if (tx[0] = 'S') and (tx[1] = 'I') and (tx[2] = 'E') and (tx[3] = 'M') and (tx[4] = 'E') and (tx[5] = 'N') and (tx[6] = 'S') then begin
4158
lDicomData.ImageStart := 8192;
4159
lDicomData.Allocbits_per_pixel := 16;
4160
//xlDicomData.Storedbits_per_pixel := 16;
4161
lDicomData.little_endian := 0;
4162
dseek(fp, 1800); //slice thickness
4163
lDicomData.XYZmm[3] := read64(fp,lrOK);
4165
lDicomData.AcquNum := read32(fp,lrOK);
4167
lDicomData.ImageNum := read32(fp,lrOK);
4168
dseek(fp, 4992); //X FOV
4169
lDicomData.XYZmm[1] := read64(fp,lrOK);
4170
dseek(fp, 5000); //Y FOV
4171
lDicomData.XYZmm[2] := read64(fp,lrOK);
4173
lDicomData.XYZdim[1] := read32(fp,lrOK);
4175
lDicomData.XYZdim[2] := read32(fp,lrOK);
4176
lDicomData.XYZdim[3] := 1;
4177
if lDicomData.XYZdim[1] > 0 then
4178
lDicomData.XYZmm[1] := lDicomData.XYZmm[1]/lDicomData.XYZdim[1];
4179
if lDicomData.XYZdim[2] > 0 then
4180
lDicomData.XYZmm[2] := lDicomData.XYZmm[2]/lDicomData.XYZdim[2];
4181
if lVerboseRead then
4182
lDynStr := 'Siemens Somatom Plus Format'+kCR+
4183
'Image Series/Number: '+inttostr(lDicomData.AcquNum)+'/'+inttostr(lDicomData.ImageNum)+kCR+
4184
'XYZ dim:' +inttostr(lDicomData.XYZdim[1])+'/'
4185
+inttostr(lDicomData.XYZdim[2])+'/'+inttostr(lDicomData.XYZdim[3])
4186
+kCR+'XYZ mm:'+floattostrf(lDicomData.XYZmm[1],ffFixed,8,2)+'/'
4187
+floattostrf(lDicomData.XYZmm[2],ffFixed,8,2)+'/'+floattostrf(lDicomData.XYZmm[3],ffFixed,8,2);
4190
if lDiskCacheSz > 0 then
4191
freemem(lDiskCacheRA);
4192
FileMode := 2; //set to read/write
4193
lImageFormatOK := true;
4197
{end siemens somatom plus }
4200
dBlockRead(fp, tx, 8*SizeOf(Char), n);
4201
if (tx[0]='C') and (tx[1]='D') and (tx[2]='F') and (ord(tx[3]) = 1) then begin
4203
if lDiskCacheSz > 0 then
4204
freemem(lDiskCacheRA);
4205
FileMode := 2; //set to read/write
4206
read_minc_data(lDICOMdata, lHdrOK, lImageFormatOK,lDynStr,lFileName);
4209
if (lAutoDECAT7) and (tx[0]='M') and (tx[1]='A') and (tx[2]='T') and (tx[3]='R') and (tx[4]='I') and (tx[5]='X') then begin
4211
if lDiskCacheSz > 0 then
4212
freemem(lDiskCacheRA);
4213
FileMode := 2; //set to read/write
4214
read_ecat_data(lDICOMdata, lVerboseRead,lReadECAToffsetTables,lHdrOK, lImageFormatOK, lDynStr, lFileName);
4217
if (tx[0] = '*') AND (tx[1] = '*') AND (tx[2] = '*') AND (tx[3] = ' ') then begin {picker Standard}
4219
if lDiskCacheSz > 0 then
4220
freemem(lDiskCacheRA);
4221
FileMode := 2; //set to read/write
4222
read_picker_data(lVerboseRead,lDICOMdata, lHdrOK, lImageFormatOK, lDynStr, lFileName);
4224
end; {not picker standard}
4225
//Start Picker Prism
4226
ljunk := filesz-2048;
4227
lDICOMdata.little_endian := 0;
4230
Width := read16(fp,lrOK);
4234
Ht := read16(fp,lrOK);
4235
lMatrixSz := Width * Ht;
4237
//check if correct filesize for picker prism
4238
if (ord(tx[0]) = 1) and (ord(tx[1])=2) and ((ljunk mod lMatrixSz)=0){128*128*2bytes = 32768} then begin //Picker PRISM
4239
lDicomData.little_endian := 0;
4240
lDicomData.XYZdim[1] := Width;
4241
lDicomData.XYZdim[2] := Ht;
4242
lDicomData.XYZdim[3] := (ljunk div 32768); {128*128*2bytes = 32768}
4243
lDicomData.Allocbits_per_pixel := 16;
4244
//xlDicomData.Storedbits_per_pixel := 16;
4245
lDicomData.ImageStart := 2048;
4246
//start: read slice thicness
4248
dBlockRead(fp, tx, 12*SizeOf(Char), n);
4250
for ljunk := 0 to 11 do
4251
if tx[ljunk] in ['0'..'9','.'] then
4252
lStr := lStr+ tx[ljunk];
4254
lDicomData.XYZmm[3] := strtofloat(lStr);
4257
dBlockRead(fp, tx, 12*SizeOf(Char), n);
4259
for ljunk := 0 to 11 do
4260
if tx[ljunk] in ['0'..'9','.'] then
4261
lStr := lStr+ tx[ljunk];
4263
lDicomData.XYZmm[1] := strtofloat(lStr);
4264
lDicomData.XYZmm[2] := lDicomData.XYZmm[1];
4265
//end: read voxel sizes
4266
//start: patient name
4268
dBlockRead(fp, tx, 22*SizeOf(Char), n);
4271
while (ljunk < 22) and (ord(tx[ljunk]) <> 0) do begin
4272
lStr := lStr+ tx[ljunk];
4275
lDicomData.PatientName := lStr;
4278
dBlockRead(fp, tx, 15*SizeOf(Char), n);
4281
while (ljunk < 15) and (ord(tx[ljunk]) <> 0) do begin
4282
lstr := lstr+ tx[ljunk];
4285
//xlDicomData.PatientID := lStr;
4288
dBlockRead(fp, tx, 25*SizeOf(Char), n);
4291
while (ljunk < 25) and (ord(tx[ljunk]) <> 0) do begin
4292
lstr := lstr+ tx[ljunk];
4295
//start: scanner type
4297
dBlockRead(fp, tx, 25*SizeOf(Char), n);
4300
while (ljunk < 25) and (ord(tx[ljunk]) <> 0) do begin
4301
lgrpstr := lgrpstr+ tx[ljunk];
4305
if lVerboseRead then
4306
lDynStr := 'Picker Format '+lgrpstr+kCR+
4307
'Patient Name: '+lDicomData.PatientName+kCR+
4308
//x'Patient ID: '+lDicomData.PatientID+kCR+
4309
'Scan Time: '+lStr+kCR+
4310
'XYZ dim:' +inttostr(lDicomData.XYZdim[1])+'/'
4311
+inttostr(lDicomData.XYZdim[2])+'/'+inttostr(lDicomData.XYZdim[3])
4312
+kCR+'XYZ mm:'+floattostrf(lDicomData.XYZmm[1],ffFixed,8,2)+'/'
4313
+floattostrf(lDicomData.XYZmm[2],ffFixed,8,2)+'/'+floattostrf(lDicomData.XYZmm[3],ffFixed,8,2);
4315
if lDiskCacheSz > 0 then
4316
freemem(lDiskCacheRA);
4317
FileMode := 2; //set to read/write
4318
lImageFormatOK := true;
4322
end; //end Picker PRISM
4325
lDICOMdata.little_endian := 1;
4328
//where := FilePos(fp);
4329
dBlockRead(fp, tx, 4*SizeOf(Char), n);
4330
if (tx[0] <> 'D') OR (tx[1] <> 'I') OR (tx[2] <> 'C') OR (tx[3] <> 'M') then begin
4332
//if filesz > 132 then begin
4333
dseek(fp, 0{128}); //skip the preamble - next 4 bytes should be 'DICM'
4334
//where := FilePos(fp);
4335
dBlockRead(fp, tx, 4*SizeOf(Char), n);
4337
if (tx[0] <> 'D') OR (tx[1] <> 'I') OR (tx[2] <> 'C') OR (tx[3] <> 'M') then begin
4339
group := read16(fp,lrOK);
4341
if not lrOK then goto 666;
4343
if group > $0008 then begin
4344
group := swap(group);
4347
if NOT (group in [$0000, $0001, $0002,$0003, $0004, $0008]) then // one more group added
4353
//Msg('DICM not at 0 or 128: ' +lFilename);
4355
end; //else Msg('DICM at 128{0}');;
4356
time_to_quit := FALSE;
4357
lProprietaryImageThumbnail := false;
4358
explicitVR := false;
4363
while NOT time_to_quit do begin
4365
where := dFilePos(fp);
4368
group := read16(fp,lrOK);
4370
if not lrOK then goto 666;
4372
if (lFirstPass) and (group = 2048) then begin
4373
if lDicomData.little_endian = 1 then lDicomData.Little_endian := 0
4374
else lDicomData.little_endian := 1;
4376
lFirstPass := false;
4379
element := read16(fp,lrOK);
4380
if not lrOK then goto 666;
4381
e_len:= read32(fp,lrOK);
4382
if not lrOK then goto 666;
4384
lt0 := e_len and 255;
4385
lt1 := (e_len shr 8) and 255;
4386
lt2 := (e_len shr 16) and 255;
4387
lt3 := (e_len shr 24) and 255;
4388
if (explicitVR) and (lT0=13) and (lT1=0) and (lT2=0) and (lT3=0) then
4389
e_len := 10; //hack for some GE Dicom images
4392
if explicitVR or first_one then begin
4393
if group = $FFFE then else //1384 - ACUSON images switch off ExplicitVR for file image fragments
4394
if ((lT0=kO) and (lT1=kB)) or ((lT0=kU) and (lT1=kN)){<-UN added} or ((lT0=kO) and (lT1=kW)) or ((lT0=kS) and (lT1=kQ)) then begin
4395
lGrpStr := chr(lT0)+chr(lT1);
4396
e_len:= read32(fp,lrOK);
4397
if not lrOK then goto 666;
4398
if first_one then explicitVR := true;
4399
end else if ((lT3=kO) and (lT2=kB)) or ((lT3=kU) and (lT2=kN)){<-UN added} or((lT3=kO) and (lT2=kW)) or ((lT3=kS) and (lT2=kQ)) then begin
4400
e_len:= read32(fp,lrOK);
4401
if not lrOK then goto 666;
4402
if first_one then explicitVR := true;
4404
if ( ((lT0=kA) and (lT1=kE)) or ((lT0=kA) and (lT1=kS))
4405
or ((lT0=kA) and (lT1=kT)) or ((lT0=kC) and (lT1=kS)) or ((lT0=kD) and (lT1=kA))
4406
or ((lT0=kD) and (lT1=kS))
4407
or ((lT0=kD) and (lT1=kT)) or ((lT0=kF) and (lT1=kL)) or ((lT0=kF) and (lT1=kD))
4408
or ((lT0=kI) and (lT1=kS)) or ((lT0=kL) and (lT1=kO))or ((lT0=kL) and (lT1=kT))
4409
or ((lT0=kP) and (lT1=kN)) or ((lT0=kS) and (lT1=kH)) or ((lT0=kS) and (lT1=kL))
4410
or ((lT0=kS) and (lT1=kS)) or ((lT0=kS) and (lT1=kT)) or ((lT0=kT) and (lT1=kM))
4411
or ((lT0=kU) and (lT1=kI)) or ((lT0=kU) and (lT1=kL)) or ((lT0=kU) and (lT1=kS))
4412
or ((lT0=kA) and (lT1=kE)) or ((lT0=kA) and (lT1=kS)) )
4414
lGrpStr := chr(lT0) + chr(lT1);
4415
if lDicomData.little_endian = 1 then
4416
e_len := (e_len and $ffff0000) shr 16
4418
e_len := swap((e_len and $ffff0000) shr 16);
4419
if first_one then begin
4423
((lT3=kA) and (lT2=kT)) or ((lT3=kC) and (lT2=kS)) or ((lT3=kD) and (lT2=kA))
4424
or ((lT3=kD) and (lT2=kS))
4425
or ((lT3=kD) and (lT2=kT)) or ((lT3=kF) and (lT2=kL)) or ((lT3=kF) and (lT2=kD))
4426
or ((lT3=kI) and (lT2=kS)) or ((lT3=kL) and (lT2=kO))or ((lT3=kL) and (lT2=kT))
4427
or ((lT3=kP) and (lT2=kN)) or ((lT3=kS) and (lT2=kH)) or ((lT3=kS) and (lT2=kL))
4428
or ((lT3=kS) and (lT2=kS)) or ((lT3=kS) and (lT2=kT)) or ((lT3=kT) and (lT2=kM))
4429
or ((lT3=kU) and (lT2=kI)) or ((lT3=kU) and (lT2=kL)) or ((lT3=kU) and (lT2=kS)))
4431
if lDicomData.little_endian = 1 then
4432
e_len := (256 * lT0) + lT1
4434
e_len := (lT0) + (256*lT1);
4435
if first_one then begin
4439
end; //not first_one or explicit
4441
if (first_one) and (lDicomdata.little_endian =0) and (e_len = $04000000) then begin
4442
Msg('Switching to little endian');
4443
lDicomData.little_endian := 1;
4447
end else if (first_one) and (lDicomData.little_endian =1) and (e_len = $04000000) then begin
4448
Msg('Switching to little endian');
4449
lDicomData.little_endian := 0;
4455
if e_len = ($FFFFFFFF) then begin
4459
e_len := e_len and $FFFF;
4466
$0001 : // group for normal reading elscint DICOM
4468
$0010 : info := 'Name';
4469
$1001 : info := 'Elscint info';
4473
$00 : info := 'File Meta Elements Group Len';
4474
$01 : info := 'File Meta Info Version';
4475
$02 : info := 'Media Storage SOP Class UID';
4476
$03 : info := 'Media Storage SOP Inst UID';
4478
//lTransferSyntaxReported := true;
4479
info := 'Transfer Syntax UID';
4481
if dFilePos(fp) > (filesz-e_len) then goto 666;
4483
GetMem( buff, e_len);
4484
dBlockRead(fp, buff{^}, e_len, n);
4485
for i := 0 to e_len-1 do
4486
if Char(buff[i]) in ['+','-',' ', '0'..'9','a'..'z','A'..'Z']
4487
then TmpStr := TmpStr +(Char(buff[i]))
4488
else TmpStr := TmpStr +('.');
4491
if TmpStr = '1.2.840.113619.5.2' then begin
4496
if length(TmpStr) >= 19 then begin
4498
if TmpStr[19] = '1' then begin
4500
explicitVR := true; //duran
4502
end else if TmpStr[19] = '2' then begin
4504
explicitVR := true; //duran
4506
end else if TmpStr[19] = '4' then begin
4507
if length(TmpStr) >= 21 then begin
4508
//lDicomData.JPEGCpt := true;
4509
if not lReadJPEGtables then begin
4510
lImageFormatOK := false;
4513
i := strtoint(TmpStr[21]+TmpStr[22]);
4514
//if (TmpStr[22] <> '0') or ((TmpStr[21] <> '7') or (TmpStr[21] <> '0'))
4517
if (i <> 57) and (i <> 70) then begin
4518
lImageFormatOK := false;
4519
//lDicomData.JPEGLossyCpt := true
4521
//lImageFormatOK := false;//x
4522
lDicomData.JPEGLosslessCpt := true;
4526
lImageFormatOK := false;
4528
end else if TmpStr[19] = '5' then begin
4529
lImageFormatOK := false;//xlDicomData.RunLengthEncoding := true;
4531
lImageFormatOK := false;
4533
if not lImageFormatOK then
4534
Msg('Unsupported Transfer Syntax '+(TmpStr)+' Solution: use MRIcro');
4538
e_len := 0; {use tempstr}
4541
info := 'Implementation Class UID';
4544
info := 'Implementation Version Name';
4545
if e_len > 4 then begin
4547
DICOMHeaderString(TmpStr);
4548
lDicomData.ImplementationVersion := Str2Int(TmpStr);
4549
if TmpStr = 'MEDIFACE 1 5' then
4550
lMediface0002_0013 := true; //detect MEDIFACE 1.5 error: error in length of two elements 0008:1111 and 0008:1140
4553
$16 : info := 'Source App Entity Title';
4554
$100: info := 'Private Info Creator UID';
4555
$102: info := 'Private Info';
4560
info := 'Identifying Group Length';
4562
$01 : info := 'Length to End';
4563
$05 : info := 'Specific Character Set';
4565
info := 'Image Type';
4566
//Only read last word, e.g. 'TYPE\MOSAIC' will be read as 'MOSAIC'
4568
if dFilePos(fp) > (filesz-e_len) then goto 666;
4569
GetMem( buff, e_len);
4570
dBlockRead(fp, buff{^}, e_len, n);
4572
while (i>-1) and (Char(buff[i]) in ['a'..'z','A'..'Z',' ']) do begin
4573
if (Char(buff[i])) <> ' ' then //strip filler characters: DICOM elements must be padded for even length
4574
TmpStr := upcase(Char(buff[i]))+TmpStr;
4579
e_len := 0; {use tempstr}
4580
if TmpStr = 'MOSAIC' then begin
4581
lSiemensMosaic0008_0008:= true;
4582
//if lMatrixSz < 1 then lMatrixSz := 64;//B13
4585
$10 : info := 'Recognition Code';
4586
$12 : info := 'Instance Creation Date';
4587
$13 : info := 'Instance Creation Time';
4588
$14 : info := 'Instance Creator UID';
4589
$16 : info := 'SOP Class UID';
4590
$18 : info := 'SOP Instance UID';
4592
info := 'Study Date';
4593
//lDicomData.StudyDatePos := dFilePos(fp);
4594
DICOMHeaderString(lDicomData.StudyDate);
4596
$21 : info := 'Series Date';
4597
$22 : info := 'Acquisition Date';
4598
$23 : info := 'Image Date';
4599
$30 : begin info := 'Study Time';
4600
DICOMHeaderStringTime(lDicomData.StudyTime);
4602
$31 : info := 'Series Time';
4603
$32 : begin info := 'Acquisition Time';
4604
//xxDICOMHeaderStringTime(lDicomData.AcqTime);
4606
$33 : begin info := 'Image Time';
4607
//xxDICOMHeaderStringTime(lDicomData.ImgTime);
4609
$40 : info := 'Data Set Type';
4610
$41 : info := 'Data Set Subtype';
4612
//xDICOMHeaderStringtoInt(lDicomData.accession);
4613
info := 'Accession Number';
4616
$60 : begin info := 'Modality'; t := _string; end;
4617
$64 : begin info := 'Conversion Type'; t := _string; end;
4619
info := 'Manufacturer';
4620
//Only read last word, e.g. 'TYPE\MOSAIC' will be read as 'MOSAIC'
4623
if dFilePos(fp) > (filesz-e_len) then goto 666;
4624
GetMem( buff, e_len);
4625
dBlockRead(fp, buff{^}, e_len, n);
4627
while (i>-1) and (Char(buff[i]) in ['a'..'z','A'..'Z',' ']) do begin
4628
if (Char(buff[i])) <> ' ' then //strip filler characters: DICOM elements must be padded for even length
4629
TmpStr := upcase(Char(buff[i]))+TmpStr;
4634
e_len := 0; {use tempstr}
4635
if (length(TmpStr) > 3) and (TmpStr[1]='P') and (TmpStr[2]='H') and (TmpStr[3]='I') then
4636
lManufacturerIsPhilips := true;
4637
if (length(TmpStr) > 3) and (TmpStr[1]='B') and (TmpStr[2]='R') and (TmpStr[3]='U') then
4638
lManufacturerIsBruker := true;
4640
if lManufacturerIsPhilips then
4641
lDicomData.ManufacturerID := kPhilipsID;
4642
if (length(TmpStr) > 3) and (TmpStr[1]='G') and (TmpStr[2]='E') then
4643
lDicomData.ManufacturerID := kGEID;
4644
if (length(TmpStr) > 3) and (TmpStr[1]='S') and (TmpStr[2]='I') and (TmpStr[3]='E') then
4645
lDicomData.ManufacturerID := kSiemensID;
4648
$80 : info := 'Institution Name';
4649
$81 : info := 'City Name';
4650
$90 : info := 'Referring Physician''s Name';
4651
$100: info := 'Code Value';
4653
info := 'Coding Schema Designator';
4656
$104: info := 'Code Meaning';
4657
$1010: info := 'Station Name';
4658
$1030: begin info := 'Study Description'; t := _string; end;
4659
$103e: begin info := 'Series Description'; t := _string; end;
4660
$1040: info := 'Institutional Dept. Name';
4661
$1050: info := 'Performing Physician''s Name';
4662
$1060: info := 'Name Phys(s) Read Study';
4663
$1070: begin info := 'Operator''s Name'; t := _string; end;
4664
$1080: info := 'Admitting Diagnosis Description';
4665
$1090: begin info := 'Manufacturer''s Model Name';t := _string; end;
4667
if lMediface0002_0013 then E_LEN := 8;//+e_len;
4668
end; //ABBA: patches error in DICOM images seen from Sheffield 0002,0013=MEDIFACE.1.5; 0002,0016=PICKER.MR.SCU
4670
if (lMediface0002_0013) and (E_LEN > 255) then E_LEN := 8;
4671
end; //ABBA: patches error in DICOM images seen from Sheffield 0002,0013=MEDIFACE.1.5; 0002,0016=PICKER.MR.SCU
4672
$2111: info := 'Derivation Description';
4673
$2120: info := 'Stage Name';
4674
$2122: begin info := 'Stage Number';t := _string; end;
4675
$2124: begin info := 'Number of Stages';t := _string; end;
4676
$2128: begin info := 'View Number';t := _string; end;
4677
$212A: begin info := 'Number of Views in stage';t := _string; end;
4678
$2204: info := 'Transducer Orientation';
4680
info := 'ComplexImageComponent';
4682
DICOMHeaderString(TmpStr);
4685
if length(TmpStr) >= 2 then begin
4686
if (TmpStr[1] = 'M') and (TmpStr[2] = 'A') then
4688
if (TmpStr[1] = 'P') and (TmpStr[2] = 'H') then
4690
if (TmpStr[1] = 'R') and (TmpStr[2] = 'E') then
4692
if (TmpStr[1] = 'I') and (TmpStr[2] = 'M') then
4695
//mixed will be followed by subsequent settings, so do not use it here....
4696
if (i > 0) and (lDICOMdata.nOrder < kMaxOrderVal) then begin
4697
inc(lDICOMdata.nOrder);
4699
lDICOMdata.order[lDICOMdata.nOrder] := i;
4701
(*[ magnitude * MAGNITUDE
4704
[ imaginary * IMAGINARY
4710
$0009: if element = $0010 then begin
4712
if e_len > 4 then begin
4714
if dFilePos(fp) > (filesz-e_len) then goto 666;
4715
GetMem( buff, e_len);
4716
dBlockRead(fp, buff{^}, e_len, n);
4719
while (i>-1) {and (Char(buff[i]) in ['a'..'z','A'..'Z',' '])} do begin
4720
if (Char(buff[i])) in ['a'..'z','A'..'Z'] then //strip filler characters: DICOM elements must be padded for even length
4721
TmpStr := upcase(Char(buff[i]))+TmpStr;
4726
if (Length(TmpStr)>4) and (TmpStr[1]='M') and (TmpStr[2]='E') and (TmpStr[3]='R') and (TmpStr[4]='G') then
4727
lOldSiemens_IncorrectMosaicMM := true; //detect MERGE technologies mosaics
4728
e_len := 0; {use tempstr}
4735
$00 : info := 'Patient Group Length';
4736
$10 : begin info := 'Patient''s Name'; t := _string;
4737
//xlDicomData.NamePos := dFilePos(fp);
4738
DICOMHeaderString(lDicomData.PatientName);
4740
$20 : begin info := 'Patient ID';
4741
//xDICOMHeaderString(lDicomData.PatientID);
4742
//xlDicomData.PatientIDInt := safestrtoint(lDicomData.PatientID);
4744
30: info := 'Date of Birth'; //"Age String" type: e.g 067y for 67 years old, 067d for 67 days
4745
//$30 : info := 'Patient Date of Birth';
4746
$32 : info := 'Patient Birth Time';
4747
$40 : begin info := 'Patient Sex'; t := _string; end;
4748
$1000: info := 'Other Patient IDs';
4749
$1001: info := 'Other Patient Names';
4750
$1005: info := 'Patient''s Birth Name';
4751
$1010: begin info := 'Patient Age'; t := _string; end;
4752
$1030: info := 'Patient Weight';
4753
$21b0: info := 'Additional Patient History';
4754
$4000: info := 'Patient Comments';
4759
$00 : info := 'Acquisition Group Length';
4760
$10 : begin info := 'Contrast/Bolus Agent'; t := _string; end;
4761
$15: info := 'Body Part Examined';
4763
info := 'Scanning Sequence';t := _string;
4765
DICOMHeaderString(TmpStr);
4766
if TmpStr = 'RM' then lResearchMode := true;
4768
$21 : begin info := 'Sequence Variant';t := _string; end;
4769
$22 : info := 'Scan Options';
4770
$23 : begin info := 'MR Acquisition Type'; t := _string; end;
4771
$24 : info := 'Sequence Name';
4772
$25 : begin info := 'Angio Flag';t := _string; end;
4773
$30 : info := 'Radionuclide';
4774
$50 : begin info := 'Slice Thickness';
4775
readfloats (fp, remaining, lDummyStr, lfloat1, lfloat2, lROK);
4776
if not lrOK then goto 666;
4777
e_len := 0; remaining := 0;
4778
lDICOMdata.XYZmm[3] := lfloat1;
4780
lThickness := lfloat1;//lDICOMdata.Thickness := lfloat1; //1391b
4782
//$60: begin info := 'KVP [Peak Output, KV]'; t := _string; end; //aqw
4784
info := 'KVP [Peak KV]';
4785
readfloats (fp, remaining, lDummyStr, lfloat1, lfloat2, lROK);
4786
if not lrOK then goto 666;
4787
e_len := 0; remaining := 0;
4788
//lDicomData.kV := lFloat1;
4791
$70: begin t := _string; info := 'Counts Accumulated'; end;
4792
$71: begin t := _string; info := 'Acquisition Condition'; end;
4793
//$80 : begin info := 'Repetition Time'; t := _string; end; //aqw
4794
//$81 : begin info := 'Echo Time'; t := _string; end; //aqw
4795
$80 : begin info := 'Repetition Time [TR, ms]';
4796
readfloats (fp, remaining, lDummyStr, lfloat1, lfloat2, lROK);
4797
if not lrOK then goto 666;
4798
e_len := 0; remaining := 0;
4799
lDicomData.TR := lFloat1;
4803
info := 'Echo Time [TE, ms]';
4804
readfloats (fp, remaining, lDummyStr, lfloat1, lfloat2, lROK);
4805
if not lrOK then goto 666;
4806
e_len := 0; remaining := 0;
4807
lDicomData.TE := lFloat1;
4809
$82 : begin t := _string; info := 'Inversion Time';end;
4810
$83 : begin t := _string; info := 'Number of Averages'; end;
4811
$84 : info := 'Imaging Frequency';
4812
$85 : begin info := 'Imaged Nucleus'; t := _string; end;
4813
$86 : begin info := 'Echo Number';t := _string;
4815
DICOMHeaderStringToInt(lEchoNum);
4816
//lDICOMdata.Echo := lEchoNum;
4820
$87 : info := 'Magnetic Field Strength';
4822
info := 'Spacing Between Slices';
4823
readfloats (fp, remaining, lDummyStr, lfloat1, lfloat2, lROK);
4824
if not lrOK then goto 666;
4825
e_len := 0; remaining := 0; //1362 some use this for gap size, others for sum of gap and slicethickness!
4826
//3333 if (lfloat1 > lDICOMdata.XYZmm[3]) or (lDICOMdata.XYZmm[3]=1) then
4827
//lDICOMdata.XYZmm[3] := lfloat1;
4828
//fx(lDICOMdata.XYZmm[3],lThickness,lfloat1);
4830
lDICOMdata.XYZmm[3] := lFloat1//does not make sense - found in some eFilm images from Marconi P3000
4831
else if ( (lThickness/2) > lfloat1 ) then
4832
lDICOMdata.XYZmm[3] := lfloat1+lThickness
4834
lDICOMdata.XYZmm[3] := lfloat1;//1392
4835
//xldicomdata.spacing:=lfloat1;
4839
info := 'Number of Phase Encoding Steps';
4840
//1499c This is a indirect method for detecting SIemens Mosaics: check if image height is evenly divisible by encoding steps
4841
// A real kludge due to Siemens not documenting mosaics explicitly: this workaround may incorrectly think rescaled images are mosaics!
4842
readfloats (fp, remaining, lDummyStr, lfloat1, lfloat2, lROK);
4843
lPhaseEncodingSteps := round(lfloat1);
4844
//xxxMsg(floattostr(lFloat1));
4845
if not lrOK then goto 666;
4846
e_len := 0; remaining := 0; //1362 some use this for gap size, others for sum of gap and slicethickness!
4847
//if (lfloat1 > lDICOMdata.XYZmm[3]) or (lDICOMdata.XYZmm[3]=1) then
4848
//lDICOMdata.XYZmm[3] := lfloat1;
4849
//ldicomdata.spacing:=lfloat1;
4853
$90 : info := 'Data collection diameter';
4854
$91 : begin info := 'Echo Train Length';t := _string; end;
4855
$93: begin info := 'Percent Sampling'; t := _string; end;
4856
$94: begin info := 'Percent Phase Field View'; t := _string; end;
4857
$95 : begin info := 'Pixel Bandwidth'; t := _string; end;
4858
$1000: begin t := _string; info := 'Device Serial Number'; end;
4859
$1004: info := 'Plate ID';
4860
$1020: begin info := 'Software Version';t := _string; end;
4862
info := 'Protocol Name';t := _string;
4864
DICOMHeaderString(TmpStr);
4865
lDicomData.ProtocolName := TmpStr;
4866
AplhaNumericStrDICOM (lDicomData.ProtocolName);
4868
$1040: info := 'Contrast/Bolus Route';
4870
t := _string; info := 'Spatial Resolution'; end;
4871
$1060: info := 'Trigger Time';
4872
$1062: info := 'Nominal Interval';
4873
$1063: info := 'Frame Time';
4874
$1081: info := 'Low R-R Value';
4875
$1082: info := 'High R-R Value';
4876
$1083: info := 'Intervals Acquired';
4877
$1084: info := 'Intervals Rejected';
4878
$1088: begin info := 'Heart Rate'; t := _string; end;
4879
$1090: begin info := 'Cardiac Number of Images'; t := _string; end;
4880
$1094: begin info := 'Trigger Window';t := _string; end;
4881
$1100: info := 'Reconstruction Diameter';
4882
$1110: info := 'Distance Source to Detector [mm]';
4883
$1111: info := 'Distance Source to Patient [mm]';
4884
$1120: info := 'Gantry/Detector Tilt';
4885
$1130: info := 'Table Height';
4886
$1140: info := 'Rotation Direction';
4887
$1147: info := 'Field of View Shape';
4889
t := _string; info := 'Field of View Dimension[s]'; end;
4891
info := 'Exposure Time [ms]';
4895
info := 'X-ray Tube Current [mA]';
4896
readfloats (fp, remaining, lDummyStr, lfloat1, lfloat2, lROK);
4897
if not lrOK then goto 666;
4898
e_len := 0; remaining := 0;
4899
//xlDicomData.mA := lFloat1;
4902
$1152 : info := 'Acquisition Device Processing Description';
4903
$1155: info := 'Radiation Setting';
4904
$1160: info := 'Filter Type';
4905
$1164: info :='Imager Pixel Spacing';
4906
$1166: info := 'Grid';
4907
$1170 : info := 'Generator Power';
4908
$1180 : info := 'Collimator/grid Name';
4910
info := 'Focal Spot[s]';
4914
info := 'Body Part Thickness';
4917
$11A2 : info := 'Compression Force';
4918
$1200 : info := 'Date of Last Calibration';
4919
$1201 : info := 'Time of Last Calibration';
4920
$1210: info := 'Convolution Kernel';
4921
$1250: begin t := _string; info := 'Receiving Coil'; end;
4922
$1251: begin t := _string; info := 'Transmitting Coil'; end;
4924
t := _string; info := 'Plate Type'; end;
4926
t := _string; info := 'Phosphor Type'; end;
4927
$1310: begin info := 'Acquisition Matrix'; //Siemens Mosaics converted by Merge can report the incorrect mm
4930
//NOTE: Matrix Information for MERGE converted images. Used Innocently for other uses by Siemens
4932
if (lOldSiemens_IncorrectMosaicMM) or ((lSiemensMosaic0008_0008) and (lMatrixSz < 1){B13}) then begin
4934
//TmpStr := ReadStrABC(fp, remaining,lrOK,lA,lB,lC);
4936
TmpStr := ReadStr(fp, remaining,lrOK,lMatrixSz);
4940
readfloats (fp, remaining, lDummyStr, lfloat1, lfloat2, lROK);
4941
if not lrOK then goto 666;
4942
e_len := 0; remaining := 0;
4945
lMatrixSz := round(lFloat1);
4947
fx(lMatrixSz,lFLoat1,lFloat2,4321);*)
4952
TmpStr := ReadStr(fp, remaining,lrOK,lJunk);//1362
4954
if not lrOK then goto 666;
4955
e_len := 0; remaining := 0;
4958
t := _string; info := 'Phase Encoding Direction';
4960
DICOMHeaderString(TmpStr);
4961
lDicomData.PhaseEncoding := TmpStr;
4962
AplhaNumericStrDICOM (lDicomData.PhaseEncoding);
4965
t := _string; info := 'Flip Angle'; end;
4967
t := _string;info := 'Variable Flip Angle Flag'; end;
4969
t := _string;info := 'SAR'; end;
4970
$1400: info := 'Acquisition Device Processing Description';
4971
$1401: begin info := 'Acquisition Device Processing Code';t := _string; end;
4972
$1402: info := 'Cassette Orientation';
4973
$1403: info := 'Cassette Size';
4974
$1404: info := 'Exposures on Plate';
4976
info := 'Relative X-Ray Exposure';
4979
$1500: info := 'Positioner Motion';
4980
$1508: info := 'Positioner Type';
4982
info := 'Positioner Primary Angle';
4985
$1511: info := 'Positioner Secondary Angle';
4986
$5020: info := 'Processing Function';
4988
t := _string; info := 'Patient Position';
4990
DICOMHeaderString(TmpStr);
4991
lDicomData.PatientPos := TmpStr;
4992
AplhaNumericStrDICOM (lDicomData.PatientPos);
4994
$5101: begin info := 'View Position';t := _string; end;
4995
$6000: begin info := 'Sensitivity'; t := _string; end;
4996
$7004: info := 'Detector Type';
4998
info := 'Detector Configuration';
5001
$7006: info := 'Detector Description';
5002
$700A: info := 'Detector ID';
5003
$700C: info := 'Date of Last Detector Calibration';
5004
$700E: info := 'Date of Last Detector Calibration';
5005
$7048: info := 'Grid Period';
5006
$7050: info := 'Filter Material LT';
5007
$7060: info := 'Exposure Control Mode';
5010
(*case element of //1362
5011
//3/3/2008 this old method for detecting mosaics has a problem - if image is interpolated x2, you will assume a 2x2 mosaic
5013
info := 'Matrix';t := _string;
5014
readfloats (fp, remaining, lDummyStr, lfloat1, lfloat2, lROK);
5015
if not lrOK then goto 666;
5017
if lfloat2 > lfloat1 then lfloat1 := lfloat2;
5018
lMatrixSz := round(lfloat1);
5019
//if >32767 then there will be wrap around if read as signed value!
5023
info := 'Matrix';t := _string;
5024
readfloats (fp, remaining, lDummyStr, lfloat1, lfloat2, lROK);
5025
if not lrOK then goto 666;
5027
if lfloat2 > lfloat1 then lfloat1 := lfloat2;
5028
lMatrixSz := round(lfloat1);
5029
//if >32767 then there will be wrap around if read as signed value!
5032
end; *) //case element
5034
if lDicomData.ManufacturerID = kSiemensID then begin
5035
case element of //1362
5037
info := 'Siemens b-value';
5038
readfloats (fp, remaining, lDummyStr, lfloat1, lfloat2, lROK);
5039
if not lrOK then goto 666;
5040
e_len := 0; remaining := 0;
5041
tmpstr := floattostr(lFloat1);
5042
lDICOMdata.DTI[1].bval := round(lFloat1);
5043
lDICOMdata.SiemensDICOMDTI := true ;
5044
//msgfx( 777,lDICOMdata.DTI[1].bval,lDICOMdata.DTI[1].bval,lDICOMdata.DTI[1].bval);
5047
info := 'Siemens Gradient vector [x,y,z]';
5048
//readfloats (fp, remaining, lDummyStr, lfloat1, lfloat2, lROK);
5049
lDICOMdata.DTI[1].v1 := read64 (fp,lrOK);
5050
if not lrOK then goto 666;
5051
lDICOMdata.DTI[1].v2 := read64 (fp,lrOK);
5052
if not lrOK then goto 666;
5053
lDICOMdata.DTI[1].v3 := read64 (fp,lrOK);
5054
if not lrOK then goto 666;
5055
//msgfx( 666,lDICOMdata.DTI[1].v1,lDICOMdata.DTI[1].v2,lDICOMdata.DTI[1].v3);
5056
//readfloats3 (fp, remaining, lDummyStr, lDICOMdata.DTI[1].v1,lDICOMdata.DTI[1].v2,lDICOMdata.DTI[1].v3, lROK);
5057
//ShowMsg(lDummyStr);
5058
//fx(e_len,lDICOMdata.DTI[1].v1,lDICOMdata.DTI[1].v2,lDICOMdata.DTI[1].v3);
5060
e_len := 0; remaining := 0;
5061
//lDICOMdata.DTI[1].v1 := lFloat1;
5062
end; // X diffusion direction
5068
if lDicomData.ManufacturerID = kGEID then begin
5069
case element of //1362
5071
info := 'GE Gradient vector [x]';
5072
readfloats (fp, remaining, lDummyStr, lfloat1, lfloat2, lROK);
5073
if not lrOK then goto 666;
5074
e_len := 0; remaining := 0;
5075
lDICOMdata.DTI[1].v1 := lFloat1;
5076
end; // X diffusion direction
5078
info := 'GE Gradient vector [y]';
5079
readfloats (fp, remaining, lDummyStr, lfloat1, lfloat2, lROK);
5080
if not lrOK then goto 666;
5081
e_len := 0; remaining := 0;
5082
lDICOMdata.DTI[1].v2 := lFloat1;
5083
end;//Y diffusion direction
5085
info := 'GE Gradient vector [z]';
5086
readfloats (fp, remaining, lDummyStr, lfloat1, lfloat2, lROK);
5087
if not lrOK then goto 666;
5088
e_len := 0; remaining := 0;
5089
lDICOMdata.DTI[1].v3 := lFloat1;
5090
end;// Z diffusion direction
5100
$00 : info := 'Relationship Group Length';
5101
$0d : info := 'Study Instance UID';
5102
$0e : info := 'Series Instance UID';
5107
$11 : begin info := 'Series Number';
5108
DICOMHeaderStringToInt(lDicomData.SeriesNum);
5110
$12 : // begin info := 'Acquisition Number'; t := _string; end;
5111
begin info := 'Acquisition Number';
5112
DICOMHeaderStringToInt(lDicomData.AcquNum);
5115
$13 : begin info := 'Image Number';
5116
DICOMHeaderStringToInt(lTempInt);
5117
if (lDicomData.ImageNum < 2) and (lTempInt >= 0) then
5118
lDicomData.ImageNum := lTempInt;
5119
//March2008 - some Philips data has multiple image numbers...
5120
// 0018,1020,Software Version=1.5.4\1.5.4.3\Gyroscan PMS/DICOM 2.0 MR .Id. datadefs.v 5.27 2004/10/18 06.50
5121
//msg(inttostr(lDicomData.ImageNum)+lDicomData.Filename);
5123
$20 : begin info := 'Patient Orientation';
5126
$30 : info := 'Image Position';
5128
info := 'Image Position Patient';
5129
//June 2009 - for Philips new 4D format we want value from the first slice...
5130
if not lImagePositionPatientRead then begin
5131
readfloats3 (fp, remaining, lDummyStr, lDicomData.PatientPosX, lDicomData.PatientPosY,lDicomData.PatientPosZ, lROK);
5132
if not lrOK then goto 666;
5135
lImagePositionPatientRead := true;
5136
//we assume Philips reports the slice thickness correctly....
5137
//an alternative would be to read both 1st and 2nd ImagePositionPatient and
5138
//compute the function DICOMinterslicedistance
5140
CheckIntersliceDistance(l4DDistanceBetweenSliceCenters);
5144
$35 : info := 'Image Orientation';
5146
info := 'Image Orientation (Patient)';
5147
readfloats6 (fp, remaining, lDummyStr, lDicomData.Orient[1], lDicomData.Orient[2],lDicomData.Orient[3],lDicomData.Orient[4], lDicomData.Orient[5],lDicomData.Orient[6], lROK);
5148
if not lrOK then goto 666;
5153
$50 : info := 'Location';
5154
$52 : info := 'Frame of Reference UID';
5155
$91 : info := 'Echo Train Length';
5156
$70 : info := 'Image Geometry Type';
5157
$60 : info := 'Laterality';
5161
DICOMHeaderStringToInt(lnVol);
5163
//Number of temporal positions=105
5165
$1001: info := 'Acquisitions in Series';
5166
$1002: info := 'Images in Acquisition';
5167
$1020: info := 'Reference';
5168
$1040: begin info := 'Position Reference'; t := _string; end;
5169
$1041: begin info := 'Slice Location';
5170
readfloats (fp, remaining, lDummyStr, lfloat1, lfloat2, lROK);
5171
if not lrOK then goto 666;
5172
e_len := 0; remaining := 0;
5173
ldicomdata.location:=lfloat1;
5176
info := 'Other Study Numbers';
5179
$3401: info := 'Modifying Device ID';
5180
$3402: info := 'Modified Image ID';
5181
$3403: info := 'Modified Image Date';
5182
$3404: info := 'Modifying Device Mfg.';
5183
$3405: info := 'Modified Image Time';
5184
$3406: info := 'Modified Image Desc.';
5185
$4000: info := 'Image Comments';
5186
$5000: info := 'Original Image ID';
5187
$5002: info := 'Original Image... Nomenclature';
5189
$0021:case element of
5191
info :='GE Locations in acquisition';
5193
if lPrefs.UseGE_0021_104F then begin
5194
//June 2009 - Thomas Stephan sent me a GE image where this was set to 2, but should have been 1
5195
//I hope removing this does not cause problems with other GE images...
5196
if e_len = 2 then begin
5197
lDicomData.SlicesPer3DVol := read16(fp,lrOK);
5198
e_len := 0; remaining := 0;
5199
/// fx(9999, lDicomData.SlicesPer3DVol);
5201
end; //use 0021_104F
5205
info :='Siemens Mosaic Slice Count';
5206
DICOMHeaderStringToInt(lDicomData.SiemensSlices);
5210
info :='Siemens Order of Slices';
5212
lDICOMdata.SiemensInterleaved := 0; //0=no,1=yes,2=undefined
5213
//look for "INTERLEAVED"
5215
if dFilePos(fp) > (filesz-e_len) then goto 666;
5216
GetMem( buff, e_len);
5217
dBlockRead(fp, buff{^}, e_len, n);
5218
for i := 0 to e_len-1 do
5219
if Char(buff[i]) in ['?','A'..'Z','a'..'z']
5220
then lStr := lStr +upcase(Char(buff[i]));
5222
if(lStr[1]= 'I') then lDICOMdata.SiemensInterleaved := 1; //0=no,1=yes,2=undefined
5228
$00 : info := 'Image Presentation Group Length';
5230
info := 'Samples Per Pixel';
5231
tmp := read16(fp,lrOK);
5232
if not lrOK then goto 666;
5233
lDicomData.SamplesPerPixel :=tmp;
5234
if e_len > 255 then begin
5235
explicitVR := true; //kludge: switch between implicit and explicitVR
5237
tmpstr := inttostr(tmp);
5242
info := 'Photometric Interpretation';
5244
if dFilePos(fp) > (filesz-e_len) then goto 666;
5245
GetMem( buff, e_len);
5246
dBlockRead(fp, buff{^}, e_len, n);
5247
for i := 0 to e_len-1 do
5248
if Char(buff[i]) in [{'+','-',' ', }'0'..'9','a'..'z','A'..'Z']
5249
then TmpStr := TmpStr +(Char(buff[i]));
5251
(*xif TmpStr = 'MONOCHROME1' then lDicomdata.monochrome := 1
5252
else if TmpStr = 'MONOCHROME2' then lDicomdata.monochrome := 2
5253
else if (length(TMpStr)> 0) and (TmpStr[1] = 'Y') then lDICOMdata.monochrome := 4
5254
else lDICOMdata.monochrome := 3; *)
5256
e_len := 0; {use tempstr}
5259
$05 : info := 'Image Dimensions (ret)';
5261
info := 'Planar Configuration';
5262
tmp := read16(fp,lrOK);
5263
if not lrOK then goto 666;
5264
lDicomData.PlanarConfig :=tmp;
5269
//if lPapyrusnSlices < 1 then
5270
// if remaining = 2 then begin
5271
// tmp := read16(fp,lrOK);
5274
DICOMHeaderStringToInt(lDicomData.XYZdim[3]);
5275
if lDicomData.XYZdim[3] < 1 then lDicomData.XYZdim[3] := 1;
5276
info := 'Number of Frames';
5278
$09: begin info := 'Frame Increment Pointer'; TmpStr := ReadStrHex(fp, remaining,lrOK); if not lrOK then goto 666;
5279
e_len := 0; remaining := 0; end;
5280
$10 : begin info := 'Rows';
5281
lDicomData.XYZdim[2] := read16(fp,lrOK);
5282
if not lrOK then goto 666;
5283
tmp := lDicomData.XYZdim[2];
5286
$11 : begin info := 'Columns';
5287
lDicomData.XYZdim[1] := read16(fp,lrOK);
5288
if not lrOK then goto 666;
5289
tmp := lDicomData.XYZdim[1];
5292
$30 : begin info := 'Pixel Spacing';
5293
readfloats (fp, remaining, lDummyStr, lfloat1, lfloat2, lROK);
5294
if not lrOK then goto 666;
5296
//row spacing [y], then column spacing [x]: see part 3 of DICOM
5297
e_len := 0; remaining := 0;
5298
lDICOMdata.XYZmm[2] := lfloat1;
5299
lDICOMdata.XYZmm[1] := lfloat2;
5301
$31: info := 'Zoom Factor';
5302
$32: info := 'Zoom Center';
5303
$34: begin info :='Pixel Aspect Ratio';t := _string; end;
5304
$40: info := 'Image Format [ret]';
5305
$50 : info := 'Manipulated Image [ret]';
5306
$51: info := 'Corrected Image';
5307
$60: begin info := 'Compression Code [ret]';t := _string; end;
5308
$100: begin info := 'Bits Allocated';
5309
if remaining = 4 then
5310
tmp := read32(fp,lrOK)
5312
tmp := read16(fp,lrOK);
5313
//lWord := read16(fp,lrOK);
5314
//lWord := read16(fp,lrOK);
5316
if not lrOK then goto 666;
5317
if tmp = 8 then lDicomData.Allocbits_per_pixel := 8
5318
else if tmp = 12 then lDicomData.Allocbits_per_pixel := 12
5319
else if tmp = 16 then lDicomData.Allocbits_per_pixel := 16
5320
else if tmp = 24 then begin
5321
//xlDicomData.SamplesPerPixel := 3;
5322
lDicomData.Allocbits_per_pixel := 8
5325
lWord := swap(lWord);
5326
if lWord in [8,12,16,24] then begin
5327
lDicomData.Allocbits_per_pixel := tmp;
5330
if lImageFormatOK then
5331
Msg('This software only reads 8, 12 and 16 bit DICOM files. This file allocates '+inttostr(tmp)+' bits per voxel.');
5332
lImageFormatOK := false;
5335
//remaining := 2;//remaining; //1371->
5338
$0101: begin info := 'Bits Stored';
5339
if remaining = 4 then
5340
tmp := read32(fp,lrOK)
5342
tmp := read16(fp,lrOK);
5344
if not lrOK then goto 666;
5346
(*if tmp <= 8 then lDicomData.Storedbits_per_pixel := 8
5347
else if tmp <= 16 then lDicomData.Storedbits_per_pixel := 16
5348
else if tmp <= 24 then begin
5349
lDicomData.Storedbits_per_pixel := 24;
5350
lDicomData.SamplesPerPixel := 3;
5353
lWord := swap(lWord);
5354
if lWord in [8,12,16] then begin
5355
lDicomData.Storedbits_per_pixel := tmp;
5358
if lImageFormatOK then
5359
Msg('This software can only read 8, 12 and 16 bit DICOM files. This file stores '+inttostr(tmp)+' bits per voxel.');
5360
lDicomData.Storedbits_per_pixel := tmp;
5361
lImageFormatOK := false;{ }
5366
$0102: begin info := 'High Bit';
5367
if remaining = 4 then
5368
tmp := read32(fp,lrOK)
5370
tmp := read16(fp,lrOK);
5376
info := 'Pixel Representation';
5378
$0104: info := 'Smallest Valid Pixel Value';
5379
$0105: info := 'Largest Valid Pixel Value';
5381
//xlDicomData.MinIntensitySet:= true;
5382
info := 'Smallest Image Pixel Value';
5383
tmp := read16(fp,lrOK);
5384
if not lrOK then goto 666;
5385
//xlDicomData.Minintensity := tmp;
5386
//if >32767 then there will be wrap around if read as signed value!
5390
info := 'Largest Image Pixel Value';
5391
if remaining = 4 then
5392
tmp := read32(fp,lrOK)
5394
tmp := read16(fp,lrOK);
5395
if not lrOK then goto 666;
5396
//xlDicomData.Maxintensity := tmp;
5397
//if >32767 then there will be wrap around if read as signed value!
5400
$120: info := 'Pixel Padding Value';
5401
$200: info := 'Image Location [ret]';
5402
$1040: begin t := _string; info := 'Pixel Intensity Relationship'; end;
5404
info := 'Window Center';
5405
if e_len > 0 then begin
5406
readfloats (fp, remaining, lDummyStr, lfloat1, lfloat2, lROK);
5407
if not lrOK then goto 666;
5408
e_len := 0; remaining := 0;
5409
//xlDICOMdata.WindowCenter := round(lfloat1);
5412
$1051: begin info := 'Window Width';
5413
if e_len > 0 then begin
5414
readfloats (fp, remaining, lDummyStr, lfloat1, lfloat2, lROK);
5415
if not lrOK then goto 666;
5418
//xlDICOMdata.WindowWidth := round(lfloat1);
5419
end; //ignore empty elements, e.g. LeadTech's image6.dic
5421
$1052: begin t := _string;info :='Rescale Intercept';
5422
readfloats (fp, remaining, lDummyStr, lfloat1, lfloat2, lROK);
5423
if not lrOK then goto 666;
5424
e_len := 0; remaining := 0;
5425
lDICOMdata.intenIntercept := lfloat1;
5426
//if (lDICOMdata.nOrder > 0) and (lDICOMdata.nOrder < kMaxOrderVal) then
5427
// lDICOMdata.OrderIntercept[lDICOMdata.nOrder] := lfloat1;
5431
t := _string; info := 'Rescale Slope';
5432
readfloats (fp, remaining, lDummyStr, lfloat1, lfloat2, lROK);
5433
if not lrOK then goto 666;
5434
e_len := 0; remaining := 0;
5435
if lFloat1 < 0.000000001 then begin
5436
lFLoat1 := 1; //misused in some images, see IMG000025
5438
lDICOMdata.intenScale := lfloat1;
5439
//if (lDICOMdata.nOrder > 0) and (lDICOMdata.nOrder < kMaxOrderVal) then
5440
// lDICOMdata.OrderSlope[lDICOMdata.nOrder] := lfloat1;
5442
$1054:begin t := _string; info := 'Rescale Type';end;
5443
$1100: info := 'Gray Lookup Table [ret]';
5444
$1101: begin info := 'Red Palette Descriptor'; TmpStr := ReadStr(fp, remaining,lrOK,lJunk);
5445
if not lrOK then goto 666;
5446
e_len := 0; remaining := 0; end;
5447
$1102: begin info := 'Green Palette Descriptor'; TmpStr := ReadStr(fp, remaining,lrOK,lJunk);
5448
if not lrOK then goto 666;
5449
e_len := 0; remaining := 0; end;
5450
$1103: begin info := 'Blue Palette Descriptor'; TmpStr := ReadStr(fp, remaining,lrOK,lJunk);
5451
if not lrOK then goto 666;
5452
e_len := 0; remaining := 0; end;
5454
info := 'Palette Color Lookup Table UID';
5456
$1200: info := 'Gray Lookup Data [ret]';
5457
$1201, $1202,$1203: begin
5459
$1201: info := 'Red Table'; {future}
5460
$1202: info := 'Green Table'; {future}
5461
$1203: info := 'Blue Table'; {future}
5464
if dFilePos(fp) > (filesz-remaining) then
5466
if not lReadColorTables then begin
5467
dSeek(fp, dFilePos(fp) + remaining);
5468
end else begin {load color}
5469
width := remaining div 2;
5471
if width > 0 then begin
5472
getmem(lWordRA,width*2);
5473
for i := (width) downto 1 do
5474
lWordRA^[i] := read16(fp,lrOK);
5476
value := lWordRA^[1];
5479
for i := (width) downto 1 do begin
5480
value := lWordRA^[i];
5481
if value < min16 then min16 := value;
5482
if value > max16 then max16 := value;
5484
if max16 - min16 = 0 then
5485
max16 := min16+1; {avoid divide by 0}
5486
if (lDicomData.Allocbits_per_pixel <= 8) and (width > 256) then width := 256; //currently only accepts palettes up to 8-bits
5487
GetMem( lColorRA, width );(**)
5488
for i := width downto 1 do
5489
lColorRA^[i] := (lWordRA^[i] shr 8) {and 255};
5493
red_table_size := width;
5494
red_table :=lColorRA;;
5497
green_table_size := width;
5498
green_table :=lColorRA;;
5500
else {x$1203:} begin
5501
blue_table_size := width;
5502
blue_table :=lColorRA;;
5506
if odd(remaining) then
5507
dSeek(fp, dFilePos(fp) + 1{remaining});
5511
e_len := 0; {show tempstr}
5513
$1221, $1222,$1223: begin
5514
info := 'Color Palette ['+inttostr(dFilePos(fp))+']';
5517
lDicomData.RLEredOffset:= dFilePos(fp);
5518
lDicomData.RLEredSz:= e_len;
5521
lDicomData.RLEgreenOffset:= dFilePos(fp);
5522
lDicomData.RLEgreenSz:= e_len;
5525
lDicomData.RLEblueOffset:= dFilePos(fp);
5526
lDicomData.RLEblueSz:= e_len;
5528
end;*)//Case set offset and length
5530
tmpstr := inttostr(e_len);
5531
dSeek(fp, dFilePos(fp)+ e_LEN);
5535
$3002: info := 'LUT Descriptor';
5536
$3003: info := 'LUT Explanation';
5537
$3006: info := 'LUT Data';
5539
info := 'VOI LUT Sequence';
5540
if (explicitVR) and (lT0=kS) and (lT1=kQ) then
5545
$41: case element of //Papyrus Private Group
5547
info := 'Papyrus Icon [bytes skipped]';
5548
dSeek(fp, dFilePos(fp) + e_len);
5549
tmpstr := inttostr(e_len);
5552
end; //element $0041:$1010
5555
info := 'Papyrus Slices';
5556
(*Papyrus format is buggy - see lsjpeg.pas for details, therefore, I have removed extensive support
5557
if e_len = 2 then begin
5558
lDicomData.XYZdim[3] := read16(fp,lrOK);
5559
if not lrOK then goto 666;
5561
if lDicomData.XYZdim[3] < 1 then lDicomData.XYZdim[3] := 1;
5562
if {(false) and }(lDicomData.XYZdim[3] > 1) and (lReadJPEGtables) and (gECATJPEG_table_entries = 0) then begin
5563
//Papyrus multislice files keep separate DICOM headers for each slice within a DICOM file
5564
lPapyrusnSlices := lDicomData.XYZdim[3];
5566
//lPapyrusData := lDicomData;
5567
gECATJPEG_table_entries := lDICOMdata.XYZDim[3];
5568
getmem (gECATJPEG_pos_table, gECATJPEG_table_entries*sizeof(longint));
5569
getmem (gECATJPEG_size_table, gECATJPEG_table_entries*sizeof(longint));
5571
lDicomData.XYZdim[3] := 1;
5572
tmpstr := inttostr(lDicomData.XYZdim[3]);
5575
end; //element $0041:$1015
5577
info := 'Papyrus Bizarre Element'; //bizarre osiris problem
5578
if (dfilepos(fp)+e_len)= (filesz) then
5580
end; //element $0041:$1050
5581
end; //group $0041: Papyrus
5585
if lDicomData.ManufacturerID = kGEID then begin
5588
// 0043,1039 (or 0043,a039). b value (as the first number in the string).
5590
info := 'GE Bvalue';
5591
if e_len > 0 then begin
5592
readfloats (fp, remaining, lDummyStr, lfloat1, lfloat2, lROK);
5593
if not lrOK then goto 666;
5594
e_len := 0; remaining := 0;
5595
lDICOMdata.DTI[1].bval := round(lfloat1);
5596
lDICOMdata.nDTIdir := 1;
5600
end; //Manufacturer = GE
5601
end;//$0043 - GE bvalues
5603
$54: case element of
5604
$0: info := 'Nuclear Acquisition Group Length';
5605
$11: info := 'Number of Energy Windows';
5606
$21: info := 'Number of Detectors';
5607
$51: info := 'Number of Rotations';
5608
$80: begin info := 'Slice Vector'; TmpStr := ReadStr(fp, remaining,lrOK,lJunk); if not lrOK then goto 666;
5609
e_len := 0; remaining := 0; end;
5610
$81: info := 'Number of Slices';
5611
$202: info := 'Type of Detector Motion';
5612
$400: info := 'Image ID';
5617
$0: info := 'Film Box Group Length';
5618
$100: info := 'Border Density';
5620
$4000 : info := 'Text';
5624
//lSiemensMosaic0029_1010:= true;
5625
lDicomData.CSAImageHeaderInfoPos := (dFilePos(fp));
5626
lDicomData.CSAImageHeaderInfoSz := e_len;
5627
info := 'Private Sequence Delimiter ['+inttostr(dFilePos(fp))+']';
5628
if not lImageFormatOK
5629
//x(lDicomData.RunLengthEncoding) or ( ((lDicomData.JPEGLossycpt) or (lDicomData.JPEGLosslesscpt)) and (gECATJPEG_table_entries >= lDICOMdata.XYZdim[3]))}
5630
then time_to_quit := TRUE;
5631
dSeek(fp, dFilePos(fp) + e_len);
5632
tmpstr := inttostr(e_len);
5634
e_len := 0; {show tempstr}
5637
info :='Philips Scale Slope';
5638
readfloats (fp, remaining, lDummyStr, lfloat1, lfloat2, lROK);
5639
if not lrOK then goto 666;
5640
e_len := 0; remaining := 0;
5641
lPhilipsScaleSlope := lfloat1;
5642
{if e_len = 4 then begin
5643
lPhilipsScaleSlope := read32r(fp,lrOK);
5644
TmpStr := floattostr(lPhilipsScaleSlope);
5647
if not lrOK then goto 666;
5663
end; //element $1010
5665
end; //CASE...element
5672
lProprietaryImageThumbnail := true;
5673
//lImageFormatOK := false;
5674
end; //element $1010
5680
//lProprietaryImageThumbnail := true;
5681
//lImageFormatOK := false;
5682
end; //element $1010
5684
end; //CASE...element
5688
if lDicomData.ManufacturerID = kPhilipsID then begin
5691
$1003: begin //bvalue
5692
if e_len = 4 then begin
5693
if lDICOMdata.nDTIdir < kMaxDTIdir then
5694
inc(lDICOMdata.nDTIdir);
5695
lDICOMdata.DTI[lDICOMdata.nDTIdir].bval := round(read32r(fp,lrOK));
5696
TmpStr := inttostr(lDICOMdata.DTI[lDICOMdata.nDTIdir].bval);
5699
if not lrOK then goto 666;
5700
e_len := 0; remaining := 0;
5704
info := 'philips: slice orientation';t := _string;
5706
DICOMHeaderString(TmpStr);
5707
lDicomData.PhilipsSliceOrient := TmpStr;
5708
AplhaNumericStrDICOM (lDicomData.PhilipsSliceOrient);
5709
end;//PhilipsSliceOrient
5711
if e_len = 4 then begin
5712
info :='number of slices';
5713
lDicomData.SlicesPer3DVol := read32(fp,lrOK);
5715
e_len := 0; remaining := 0;
5716
if lResearchMode then
5717
lDicomData.SeriesNum := lDicomData.SeriesNum + 50; //do not jumble research recons and normal images
5719
TmpStr := floattostr(lDicomData.SlicesPer3DVol);
5725
if e_len = 2 then begin
5726
lnSlicePerVol := read16(fp,lrOK);
5727
e_len := 0; remaining := 0;
5729
//fx(213,lnSlicePerVol);
5732
$105F: begin //Philips Stack Sequence
5734
if e_len > 8 then e_len := 8;
5737
end; //if manufacturer = Philips
5743
//if lDicomData.ManufacturerID = kPhilipsID then Msg(inttohex(element,4));
5744
if lDicomData.ManufacturerID = kPhilipsID then begin
5747
if e_len = 4 then begin
5748
lPhilipsScaleSlope := read32r(fp,lrOK);
5749
TmpStr := floattostr(lPhilipsScaleSlope);
5751
info :='Philips Scale Slope';
5752
if not lrOK then goto 666;
5753
e_len := 0; remaining := 0;
5755
end; //element $1010
5759
if e_len = 4 then begin
5760
lDicomData.AngulationAP := read32r(fp,lrOK);
5761
TmpStr := floattostr(lDicomData.AngulationAP);
5763
info :='angulation midslice, AP (degrees)';
5764
if not lrOK then goto 666;
5765
e_len := 0; remaining := 0;
5767
end; // Philips AP angulation : -8.74086
5769
if e_len = 4 then begin
5770
lDicomData.AngulationFH := read32r(fp,lrOK);
5771
TmpStr := floattostr(lDicomData.AngulationFH);
5773
info :='angulation midslice, FH (degrees)';
5774
if not lrOK then goto 666;
5775
e_len := 0; remaining := 0;
5777
end; // Philips Philips FH angulation : -3.53147
5779
if e_len = 4 then begin
5780
lDicomData.AngulationRL := read32r(fp,lrOK);
5781
TmpStr := floattostr(lDicomData.AngulationRL);
5783
info :='angulation midslice, RL (degrees)';
5784
if not lrOK then goto 666;
5785
e_len := 0; remaining := 0;
5787
end; // Philips RL angulation
5789
if e_len = 4 then begin
5790
lDICOMdata.DTI[lDICOMdata.nDTIdir].v1 := read32r(fp,lrOK);
5791
TmpStr := floattostr(lDICOMdata.DTI[lDICOMdata.nDTIdir].v1);
5793
info :='Gradient vector [x]';
5794
if not lrOK then goto 666;
5795
e_len := 0; remaining := 0;
5799
if e_len = 4 then begin
5800
lDICOMdata.DTI[lDICOMdata.nDTIdir].v2 := read32r(fp,lrOK);
5801
TmpStr := floattostr(lDICOMdata.DTI[lDICOMdata.nDTIdir].v2);
5803
info :='Gradient vector [y]';
5804
if not lrOK then goto 666;
5805
e_len := 0; remaining := 0;
5809
if e_len = 4 then begin
5810
lDICOMdata.DTI[lDICOMdata.nDTIdir].v3 := read32r(fp,lrOK);
5811
TmpStr := floattostr(lDICOMdata.DTI[lDICOMdata.nDTIdir].v3);
5813
info :='Gradient vector [z]';
5814
//fx(lDICOMdata.DTI[lDICOMdata.nDTIdir].v1,lDICOMdata.DTI[lDICOMdata.nDTIdir].v2,lDICOMdata.DTI[lDICOMdata.nDTIdir].v3);
5815
if not lrOK then goto 666;
5816
e_len := 0; remaining := 0;
5819
end; //CASE...element
5820
end; //if Manufacturer = Philips
5825
if (lDicomData.ManufacturerID = kPhilipsID) and (orientation_not_visible( lDICOMdata))then
5826
read_philips_hidden(lFilename, dFilePos(fp),e_len,lDICOMdata);
5833
//For papyrus multislice format: if (lPapyrusSlice >= lPapyrusnSlices) then
5834
time_to_quit := TRUE;
5841
(*iif lJPEGEntries > 17 then
5845
if not lProprietaryImageThumbnail then begin
5846
f (lReadJPEGtables) and ((lDICOMdata.RunLengthEncoding) or (lDICOMdata.JPEGLossyCpt) or (lDICOMdata.JPEGLosslessCpt)) and (not lFirstFragment) and (e_len > 1024) {1384} and ( (e_len+dFilePos(fp)) <= FileSz) then begin
5847
//first fragment is the index table, so the previous line skips the first fragment
5848
if (gECATJPEG_table_entries = 0) then begin
5849
gECATJPEG_table_entries := lDICOMdata.XYZDim[3];
5850
getmem (gECATJPEG_pos_table, gECATJPEG_table_entries*sizeof(longint));
5851
getmem (gECATJPEG_size_table, gECATJPEG_table_entries*sizeof(longint));
5853
if lJPEGentries < gECATJPEG_table_entries then begin
5855
gECATJPEG_pos_table^[lJPEGEntries] := dFilePos(fp);
5856
gECATJPEG_size_table^[lJPEGEntries] := e_len;
5860
if (lDICOMdata.CompressOffset =0) and ( (e_len+dFilePos(fp)) <= FileSz) and (e_len > 1024){ALOKA} then begin
5861
lDICOMdata.CompressOffset := dFilePos(fp);
5862
lDICOMdata.CompressSz := e_len;
5864
//if e_len > lDICOMdata.CompressSz then lDICOMdata.CompressSz := e_len;
5865
if (e_len > 1024) and (lDICOMdata.CompressSz=0) then begin //ABBA RLE ALOKA
5866
//Time_To_Quit := true;//ABBA
5867
lDICOMdata.CompressSz := e_len;
5868
lDICOMdata.CompressOffset := dFilePos(fp);
5870
if (lFirstFragment) or ((e_len > lDICOMdata.CompressSz) and not (lDicomData.RunLengthEncoding)) then
5871
lDICOMdata.CompressOffset := dFilePos(fp);
5872
if (e_len > lDICOMdata.CompressSz) and (e_len > 1024){ALOKA} then
5873
lDICOMdata.CompressSz := e_len;
5874
lFirstFragment := false;
5875
lDICOMdataBackUp := lDICOMData;
5877
if (gECATJPEG_table_entries = 1) then begin //updatex
5878
gECATJPEG_size_table^[1] := lDICOMdata.CompressSz;
5879
gECATJPEG_pos_table^[1] := lDICOMdata.CompressOffset;
5882
end; //not proprietaryThumbnail
5883
lProprietaryImageThumbnail := false; //1496
5885
lFirstFragment := false;//Dec09
5886
lDICOMdataBackUp := lDICOMData;//Dec09
5887
//fx(999,e_len,dFilePos(fp));
5888
if (e_len > 108) and (lDicomData.XYZdim[1]> 1) then begin
5889
lDICOMdata.CompressOffset := dFilePos(fp);
5890
lDICOMdata.CompressSz := e_len;
5891
Time_To_Quit := true;
5892
//msg('abba'+inttostr(lDICOMdata.CompressOffset)+' '+inttostr(lDICOMdata.CompressSz));
5894
info := 'Image Fragment ['+inttostr(dFilePos(fp))+']';
5896
if (dFilePos(fp) + e_len) >= filesz then
5897
Time_To_Quit := true;
5898
dSeek(fp, dFilePos(fp) + e_len);
5899
tmpstr := inttostr(e_len);
5904
info := 'Sequence Delimiter';
5905
if (lDICOMdata.XYZdim[1]<lDICOMdataBackUp.XYZdim[1]) then begin
5906
lDICOMData := lDICOMdataBackUp;
5907
dSeek(fp, dFilePos(fp) + e_len);
5908
//lDICOMData := lDICOMdataBackUp;
5909
end else if not lImageFormatOK then begin
5910
//x(lDicomData.RunLengthEncoding) or ( ((lDicomData.JPEGLossycpt) or (lDicomData.JPEGLosslesscpt)) and (gECATJPEG_table_entries >= lDICOMdata.XYZdim[3])) then
5912
time_to_quit := TRUE;
5915
if (e_len = 0) then begin //ALOKA
5917
time_to_quit := FALSE;//RLE16=false
5921
dSeek(fp, dFilePos(fp) + e_len);
5922
tmpstr := inttostr(e_len);
5929
dSeek(fp, dFilePos(fp) + e_len);
5930
tmpstr := inttostr(e_len);
5934
$72FF : case element of
5935
$1041: time_to_quit := TRUE;
5940
info := 'Pixel Data Group Length';
5941
if not lImageFormatOK then time_to_quit := TRUE;
5944
info := 'Pixel Data';
5945
TmpStr := inttostr(e_len);
5946
if (lDICOMdata.XYZdim[1]<lDICOMdataBackUp.XYZdim[1]) then begin
5947
lDICOMData := lDICOMdataBackUp;
5948
dSeek(fp, dFilePos(fp) + e_len);
5949
//lDICOMData := lDICOMdataBackUp;
5950
end else if {(not lDicomData.RunLengthEncoding) and} (not lDicomData.JPEGLossycpt) and (not lDicomData.JPEGLosslesscpt) then begin
5951
time_to_quit := TRUE;
5952
//xlDicomData.ImageSz := e_len;
5963
if (group >= $6000) AND (group <= $601e) AND ((group AND 1) = 0)
5965
info := 'Overlay'+inttostr(dfilepos(fp))+'x'+inttostr(e_len);
5967
if element = $0000 then info := 'Group Length';
5968
if element = $4000 then info := 'Comments';
5974
if (Time_TO_Quit) and (not lImageFormatOK) then begin
5979
//Msg(inttohex(group,4) +':'+inttohex(element,4) +' '+inttostr(e_len)+'@'+ inttostr(dfilepos(fp)));
5981
if (e_len + dfilepos(fp)) > FileSz then begin//patch for GE files that only fill top 16-bytes w Random data
5982
e_len := e_len and $FFFF;
5985
if (e_len > 131072) then begin
5988
if (NOT time_to_quit) AND (e_len > 0) and (remaining > 0) then begin
5989
if (e_len + dfilepos(fp)) > FileSz then begin
5990
if not lImageFormatOK(*x(lDICOMdata.GenesisCpt) or (lDICOMdata.JPEGlosslessCpt) or (lDICOMdata.JPEGlossyCpt)*) then
5993
Msg('dcm Error: not a DICOM image: '+lFilename);
5994
{Msg('Diagnostics saved as: c:\dcmcrash.txt');
5996
assignfile(lTextF,'c:\dcmcrash.txt');
5999
Write(lTextF,lDynStr);
6000
closefile(lTextF); }
6002
//Msg(inttohex(group,4) +':'+inttohex(element,4) +' '+inttostr(e_len)+'@'+ inttostr(dfilepos(fp)));
6007
if e_len > 0 then begin
6008
GetMem( buff, e_len);
6009
dBlockRead(fp, buff, e_len, n);
6010
if lVerboseRead then
6014
1 : lStr := ( IntToStr(Integer(buff[0])));
6016
if lDicomData.little_endian <> 0
6017
then i := Integer(buff[0]) + 256*Integer(buff[1])
6018
else i := Integer(buff[0])*256 + Integer(buff[1]);
6019
lStr :=( IntToStr(i));
6022
if lDicomData.little_endian <> 0
6023
then i := Integer(buff[0])
6024
+ 256*Integer(buff[1])
6025
+ 256*256*Integer(buff[2])
6026
+ 256*256*256*Integer(buff[3])
6027
else i := Integer(buff[0])*256*256*256
6028
+ Integer(buff[1])*256*256
6029
+ Integer(buff[2])*256
6031
lStr := (IntToStr(i));
6034
if e_len > 0 then begin
6035
for i := 0 to e_len-1 do begin
6036
if Char(buff[i]) in ['+','-','/','\',' ', '0'..'9','a'..'z','A'..'Z'] then
6037
lStr := lStr+(Char(buff[i]))
6042
lStr := '*NO DATA*';
6046
i8, i16, i32, ui8, ui16, ui32,
6047
_string : for i := 0 to e_len-1 do
6048
if Char(buff[i]) in ['+','-','/','\',' ', '0'..'9','a'..'z','A'..'Z']
6049
then lStr := lStr +(Char(buff[i]))
6050
else lStr := lStr +('.');
6056
else if e_len > 0 then lStr := (IntToStr(tmp))
6060
(*if (lGrp) then if MessageDlg(lStr+'= '+info+' '+IntToHex(where,4)+': ('+IntToHex(group,4)+','+IntToHex(element,4)+')'+IntToStr(e_len)+'. Continue?',
6061
mtConfirmation, [mbYes, mbNo], 0) = mrNo then GOTO 666;
6063
//if (Group > $2005) then
6064
// msg(info+' '+IntToStr(where)+': ('+IntToHex(group,4)+','+IntToHex(element,4)+')'+IntToStr(e_len));
6065
{$IFDEF Troubleshoot}
6066
Msg( IntToHex(group,4)+','+IntToHex(element,4)+','+Info+'='+lStr);
6067
{$ENDIF Troubleshoot}
6070
if lverboseRead then begin
6071
if length(lDynStr) > kMaxTextBuf then begin
6072
if not lTextOverFlow then begin
6073
lDynStr := lDynStr + 'Only showing the first '+inttostr(kMaxTextBuf) +' characters of this LARGE header';
6074
lTextOverFlow := true;
6079
lDynStr := lDynStr+IntToHex(group,4)+','+IntToHex(element,4)+','+Info+'='+lStr+kCR ;
6080
Msg( IntToHex(group,4)+','+IntToHex(element,4)+','+Info+'='+lStr);
6081
end; //not verbose read
6085
lDicomData.ImageStart := dfilepos(fp);
6087
if lBigSet then begin
6088
if lBig then lDicomData.little_endian := 0
6089
else lDicomData.little_endian := 1;
6092
if lByteSwap then begin
6093
ByteSwap(lDicomdata.XYZdim[1]);
6094
ByteSwap(lDicomdata.XYZdim[2]);
6095
if lDicomdata.XYZdim[3] <> 1 then
6096
ByteSwap(lDicomdata.XYZdim[3]);
6097
//xByteSwap(lDicomdata.SamplesPerPixel);
6098
ByteSwap(lDicomData.Allocbits_per_pixel);
6099
//xByteSwap(lDicomData.Storedbits_per_pixel);
6102
if (lDICOMdata.ManufacturerID = kPhilipsID) and (l4DDistanceBetweenSliceCenters <> MaxInt) then //some 3D and 4D Philips files do not correctly report interslice distance in 0018,0088 and 0018,0050...
6103
lDICOMdata.XYZmm[3] := (l4DDistanceBetweenSliceCenters);
6104
if (lPrefs.PhilipsPrecise) and (lManufacturerIsPhilips) and (lPhilipsScaleSlope <> 0) then begin
6105
PhilipsPrecise (lDicomData.IntenScale, lDICOMdata.intenIntercept,lPhilipsScaleSlope, lDicomData.IntenScale, lDICOMdata.intenIntercept,true);
6106
end; //if PARprecise
6107
if (lDICOMdata.ManufacturerID = kPhilipsID) and (lDICOMdata.nDTIdir > 1) then begin
6109
for i := 1 to lDICOMdata.nDTIdir do
6110
if lDICOMdata.DTI[lDICOMdata.nDTIdir].bval <> lDICOMdata.DTI[1].bval then
6111
lGELX := false;//multiple B0 directions
6113
lDICOMdata.nDTIdir := 1;
6116
if (lMatrixSz > 1) and (lDicomData.CSAImageHeaderInfoPos > 0) and (lDicomData.CSAImageHeaderInfoSz > 0) and
6117
not (((lDicomdata.XYZdim[1] mod lMatrixSz) = 0) and ((lDicomdata.XYZdim[2] mod lMatrixSz) = 0)) then begin
6118
//Slow method for non-square Siemens matrices - 0018:1310 based on phase/freq, so it is easier to read CSA to decode rows/columns
6120
GetCSAImageHeaderInfo (lFilename, lDicomData.CSAImageHeaderInfoPos ,lDicomData.CSAImageHeaderInfoSz, lTempInt,lDICOMdata.SiemensMosaicX,lDICOMdata.SiemensMosaicY, lfloat1,lfloat2,lfloat3)
6122
if (lMatrixSz > 1) and ((lDicomdata.XYZdim[1] mod lMatrixSz) = 0) and ((lDicomdata.XYZdim[2] mod lMatrixSz) = 0) then begin
6124
if ((lDicomData.XYZdim[1] mod lMatrixSz)=0) then
6125
lDicomData.SiemensMosaicX := lDicomData.XYZdim[1] div lMatrixSz;
6126
if ((lDicomData.XYZdim[2] mod lMatrixSz)=0) then
6127
lDicomData.SiemensMosaicY := lDicomData.XYZdim[2] div lMatrixSz;
6128
if lDicomData.SiemensMosaicX < 1 then lDicomData.SiemensMosaicX := 1; //1366
6129
if lDicomData.SiemensMosaicY < 1 then lDicomData.SiemensMosaicY := 1; //1366
6131
if lOldSiemens_IncorrectMosaicMM then begin //old formats convert size in mm incorrectly - modern versions are correct and include transfer syntax
6132
lDicomdata.XYZmm[1] := lDicomdata.XYZmm[1] * (lDicomdata.XYZdim[1] div lMatrixSz);
6133
lDicomdata.XYZmm[2] := lDicomdata.XYZmm[2] * (lDicomdata.XYZdim[2] div lMatrixSz);
6135
end else if (lSiemensMosaic0008_0008) and (lPhaseEncodingSteps > 0) and (lPhaseEncodingSteps < lDicomdata.XYZdim[2]) and ((lDicomdata.XYZdim[2] mod lPhaseEncodingSteps) = 0) and ((lDicomdata.XYZdim[2] mod (lDicomdata.XYZdim[2] div lPhaseEncodingSteps)) = 0) then begin
6136
//1499c kludge for detecting new Siemens mosaics: WARNING may cause false positives - Siemens fault not mine!
6137
lDicomData.SiemensMosaicY :=lDicomdata.XYZdim[2] div lPhaseEncodingSteps;
6138
lDicomData.SiemensMosaicX := lDicomData.SiemensMosaicY; //We also need to assume as many mosaic rows as columns, as Siemens does not save the phase encoding lines in the header...
6140
// fx(lnSlicePerVol,lnVol, lDicomData.SlicesPer3DVol,lDicomdata.XYZdim[3] );
6141
//fx(lnVol,lnSlicePerVol,lDicomData.SlicesPer3DVol,lDicomdata.XYZdim[3]);
6142
//fx(lnSlicePerVol,lDicomData.ManufacturerID,kPhilipsID );
6143
if (lnSlicePerVol > 0) and (lDicomData.ManufacturerID = kPhilipsID) {and (lnVol > 1)} and (lDicomdata.XYZdim[3] > 1) and (lDicomData.SlicesPer3DVol > 0)and ((lDicomdata.XYZdim[3] mod lDicomData.SlicesPer3DVol) = 0) then begin
6144
lDICOMdata.File4D := true;
6145
lnVol := lDicomdata.XYZdim[3] div lDicomData.SlicesPer3DVol;
6147
if lManufacturerIsBruker then
6148
lDicomData.AcquNum := 1; //Bruker varies this for every image
6150
if (lEchoNum > 0) and (lEchoNum < 16) then begin
6151
lDicomData.AcquNum := lDicomData.AcquNum + (1000*lEchoNum);
6153
if lVerboseRead then begin
6155
Msg ('Image Series/Number: '+inttostr(lDicomData.AcquNum)+'/'+inttostr(lDicomData.ImageNum));
6156
Msg ('BPP: '+inttostr(lDicomData.Allocbits_per_pixel));
6157
Msg ('XYZ dim:' +inttostr(lDicomData.XYZdim[1])+'/'+inttostr(lDicomData.XYZdim[2])+'/'+inttostr(lDicomData.XYZdim[3]) );
6158
Msg ('XYZ mm:'+floattostrf(lDicomData.XYZmm[1],ffFixed,8,2)+'/'+floattostrf(lDicomData.XYZmm[2],ffFixed,8,2)+'/'+floattostrf(lDicomData.XYZmm[3],ffFixed,8,2) );
6159
Msg ('DTI bvalue:'+ inttostr(lDICOMdata.DTI[1].bval));
6160
Msg ('DTI bvec:'+floattostrf(lDicomData.DTI[1].v1,ffFixed,8,2)+'/'+floattostrf(lDicomData.DTI[1].v2,ffFixed,8,2)+'/'+floattostrf(lDicomData.DTI[1].v3,ffFixed,8,2) );
6162
//msg('abba'+inttostr(lDICOMdata.CompressOffset)+' '+inttostr(lDICOMdata.CompressSz));
6164
//if not lHdrOk then Msg('zx'+lFilename);
6165
if lDiskCacheSz > 0 then
6166
freemem(lDiskCacheRA);
6167
if not lHdrOK then lImageFormatOK := false;
6169
FileMode := 2; //set to read/write
6170
//if kUseDateTimeForID then
6171
lDicomData.DateTime := StudyDateTime(lDicomData.StudyDate,lDicomData.StudyTime);
6172
if (lDicomData.SiemensMosaicX > 1) then
6173
lDicomData.AcquNum := 1;