~ubuntu-branches/ubuntu/utopic/mricron/utopic

1 by Michael Hanke
Import upstream version 0.20100725.1~dfsg.1
1
unit MultiSlice;
2
interface
3
4
uses
5
{$IFNDEF Unix} Windows,wgraphics,
6
{$ELSE}
7
//not used by Darwin... RGBGraphics,rgbroutines,
8
{$ENDIF}
9
 LResources,LCLType,SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
10
  ExtCtrls,nifti_img,define_types,nifti_img_view,
11
  StdCtrls,GraphicsMathLibrary, Menus,ClipBrd,IniFiles,userdir;
12
const
13
	kMaxMultiSlice  = 24;
14
type
15
 TMultiSlice =  record
16
   Orient,nSlices,OverslicePct: integer;
17
   OrthoView,SliceLabel: boolean;
18
   SliceList: array [1..kMaxMultiSlice] of integer;
19
 end;//TMultiSlice
20
21
  { TMultiSliceForm }
22
23
  TMultiSliceForm = class(TForm)
24
	MainMenu1: TMainMenu;
25
	File1: TMenuItem;
26
	Closewindow1: TMenuItem;
27
	Saveasbitmap1: TMenuItem;
28
	Edit1: TMenuItem;
29
	Copy1: TMenuItem;
30
	MultiPanel: TScrollBox;
31
	MultiImage: TImage;
32
	View1: TMenuItem;
33
    OrientMenu: TMenuItem;
34
	Axial1: TMenuItem;
35
	Sagittal1: TMenuItem;
36
	Coronal1: TMenuItem;
37
    Orthoview: TMenuItem;
38
	Slices1: TMenuItem;
39
	Savesettings1: TMenuItem;
40
	Settings1: TMenuItem;
41
    MultiSaveDialog: TSaveDialog;
42
	SliceLabelCheck: TMenuItem;
43
    OversliceMenu: TMenuItem;
44
    N501: TMenuItem;
45
    N331: TMenuItem;
46
    N201: TMenuItem;
47
    N01: TMenuItem;
48
    N202: TMenuItem;
49
    N351: TMenuItem;
50
    N502: TMenuItem;
51
	procedure Copy1Click(Sender: TObject);
52
procedure MenuItem1Click(Sender: TObject);
53
	procedure Saveasbitmap1Click(Sender: TObject);
54
	procedure OrientClick(Sender: TObject);
55
	procedure FormShow(Sender: TObject);
56
	procedure CreateMultiAx;
57
	procedure CreateMultiCor;
58
	procedure CreateMultiSag;
59
	procedure CreateMultiSlice;
60
	procedure OrthoviewClick(Sender: TObject);
61
procedure Settings1Click(Sender: TObject);
62
	procedure Slices1Click(Sender: TObject);
63
	procedure Closewindow1Click(Sender: TObject);
64
	procedure FormCreate(Sender: TObject);
65
	procedure UpdateMultiSliceDisplay;
66
	procedure OpenMultiMRU(Sender:TObject);
67
	procedure UpdateMultiSliceMRU;
68
 {$IFNDEF FPC}
69
	procedure FormClose(Sender: TObject; var Action: TCloseAction);
70
 {$ELSE}
71
	procedure FormClose(Sender: TObject);
72
73
 {$ENDIF}
74
	procedure Savesettings1Click(Sender: TObject);
75
    procedure SliceLabelCheckClick(Sender: TObject);
76
    procedure OverlsiceClick(Sender: TObject);
77
  private
78
	{ Private declarations }
79
  public
80
	{ Public declarations }
81
  end;
82
83
var
84
  MultiSliceForm: TMultiSliceForm;
85
  gMulti:TMultiSlice;
86
  gMultiSliceDir,gMultiSliceStartupFilename,gMultiSliceDefaultsFilename:string;
87
{$IFDEF FPC}
88
  gMultiBuff: RGBQuadp;
89
  gMultiWid,gMultiHt: Integer;
90
  gMultiXCenterRA: array [1..kMaxMultiSlice] of integer;
91
{$ENDIF}
92
implementation
93
94
 {$IFNDEF FPC}
95
{$R *.DFM}
96
 {$ENDIF}
97
98
function MultiSliceNum2String: string;
99
var
100
	lSlice: integer;
101
begin
102
 if gMulti.nSlices = 0 then begin
103
     gMulti.nSlices := 1;
104
     gMulti.SliceList[1] := 1;
105
 end;
106
 result := '';
107
	for lSlice := 1 to gMulti.nSlices do  begin
108
		result := result+inttostr(gMulti.SliceList[lSlice]);
109
		if lSlice < gMulti.nSlices then
110
			result := result+',';
111
	end; //for each slice
112
end;
113
114
procedure MultiSliceString2Num (var lStr: string);
115
var
116
	lSliceStr: string;
117
	lStrPos,lStrLen,lSlice: integer;
118
begin
119
 //showmessage(lStr);
120
 lStrLen := length(lStr);
121
	if lStrLen < 1 then exit;
122
	lSlice := 0;
123
	lSliceStr := '';
124
	for lStrPos := 1 to lStrLen do begin
125
		if lStr[lStrPos] in  ['0'..'9'] then
126
			lSliceStr := lSliceStr+lStr[lStrPos];
127
		if ((not (lStr[lStrPos] in  ['0'..'9'])) or (lStrPos=lStrLen)) and (lSliceStr<>'') then begin
128
			inc(lSlice);
129
			if lSlice <= kMaxMultiSlice then
130
				gMulti.SliceList[lSlice] := strtoint(lSliceStr);
131
			lSliceStr := '';
132
		end; //if white space or eoln
133
	end; //for lStrPos
134
	gMulti.nSlices := lSlice;
135
	if lSlice > kMaxMultiSlice then begin
136
		showmessage('Warning: maximum number of slices is '+inttostr(kMaxMultiSlice));
137
		gMulti.nSlices := kMaxMultiSlice;
138
	end;
139
end;
140
141
procedure WriteMultiSliceIniFile (lFilename: string);
142
var
143
  lIniFile: TIniFile;
144
begin
145
  if DiskFreeEx(lFilename) < 1 then
146
	exit;
147
  if not DirectoryExists(extractfiledir(lFilename)) then begin
148
		mkDir(extractfiledir(lFilename));
149
  end;
150
  lIniFile := TIniFile.Create(lFilename);
151
  //Slice Index
152
  lIniFile.WriteString('STR', 'Slices', MultiSliceNum2String);
153
  //Booleans
154
  lIniFile.WriteString('BOOL', 'OrthoView',Bool2Char( gMulti.OrthoView));
155
  lIniFile.WriteString('BOOL', 'SliceLabel',Bool2Char( gMulti.SliceLabel));
156
  //Integers        LicenseID
157
  lIniFile.WriteString('INT', 'Orient',IntToStr(gMulti.Orient));
158
  lIniFile.WriteString('INT', 'OverslicePct',IntToStr(gMulti.OverslicePct));
159
  lIniFile.Free;
160
end;
161
162
procedure ReadMultiSliceIniFile (lFilename: string);
163
var
164
  lStr: string;
165
  lIniFile: TIniFile;
166
begin
167
	if not FileexistsEx(lFilename) then begin
168
		exit;
169
	end;
170
  lIniFile := TIniFile.Create(lFilename);
171
  lStr := lIniFile.ReadString('STR', 'Slices', '10,20,30');//file0 - last file viewed
172
  MultiSliceString2Num(lStr);
173
  gMulti.OrthoView := IniBool(lIniFile,'OrthoView',gMulti.OrthoView);
174
  gMulti.SliceLabel := IniBool(lIniFile,'SliceLabel',gMulti.SliceLabel);
175
  gMulti.Orient:= IniInt(lIniFile,'Orient',gMulti.Orient);
176
  gMulti.OverslicePct:= IniInt(lIniFile,'OverslicePct',gMulti.OverslicePct);
177
	lIniFile.Free;
178
end;
179
180
procedure TMultiSliceForm.OpenMultiMRU(Sender:TObject);
181
var
182
	lFilename: string;
183
begin
184
   lFilename := gMultiSliceDir +(Sender as TMenuItem).caption+'.ini' ;
185
   ReadMultiSliceIniFile(lFilename);
186
   UpdateMultiSliceDisplay;
187
   CreateMultiSlice;
188
end;
189
190
procedure TMultiSliceForm.UpdateMultiSliceMRU;
191
var
192
	NewItem: TMenuItem;
193
	lSearchRec: TSearchRec;
194
begin
195
  While Settings1.Count > 0 do Settings1.Items[0].Free;
196
  if FindFirst(gMultiSliceDir +'*.ini', faAnyFile, lSearchRec) = 0 then
197
	 repeat
198
		   NewItem := TMenuItem.Create(Self);
199
		   NewItem.Caption := ParseFileName(ExtractFileName(lSearchRec.Name));
200
                   {$IFDEF FPC}
201
                    NewItem.Onclick := @OpenMultiMRU; //Lazarus
202
                    {$ELSE}
203
                     NewItem.Onclick := OpenMultiMRU;
204
                     {$ENDIF}
205
		   Settings1.Add(NewItem);
206
		until (FindNext(lSearchRec) <> 0);
207
  FindClose(lSearchRec);
208
end;
209
210
procedure TMultiSliceForm.Copy1Click(Sender: TObject);
211
{$IFNDEF FPC}
212
var
213
  MyFormat : Word;
214
  AData: THandle;
215
  APalette : HPalette;
216
  {$ENDIF}
217
begin
218
           {$IFDEF Darwin}
219
        Showmessage('Copy not yet supported with OSX: use File/Save');
220
        {$ENDIF}
221
	 if (MultiImage.Picture.Graphic = nil) then begin //1420z
222
		Showmessage('You need to load an image before you can copy it to the clipboard.');
223
		exit;
224
	 end;
225
 {$IFNDEF FPC}
226
	 MultiImage.Picture.Bitmap.SaveToClipBoardFormat(MyFormat,AData,APalette);
227
	 ClipBoard.SetAsHandle(MyFormat,AData);
228
 {$ELSE}
229
        MultiSliceForm.MultiImage.Picture.Bitmap.SaveToClipboardFormat(2);
230
 {$ENDIF}
231
end;
232
233
procedure TMultiSliceForm.MenuItem1Click(Sender: TObject);
234
begin
235
236
237
end;
238
239
240
241
procedure TMultiSliceForm.Saveasbitmap1Click(Sender: TObject);
242
begin
243
	 SaveImgAsPNGBMP (MultiImage);
244
end;
245
246
 {$IFNDEF FPC} //if delphi...
247
procedure CreateBlankBitmap (lPGHt,lPGWid:integer;var lImage: TImage);
248
var
249
 sbBits : PByteArray;
250
 l32BitP: DWordp;
251
 lBGInvisibleColor: DWord;
252
   lBMP: TBitmap;
253
   lInc : integer;
254
begin
255
	 lBMP := TBitmap.Create;
256
	 TRY
257
			 lBMP.PixelFormat := pf32bit;
258
			 lBMP.Width := lPGwid;
259
			 lBMP.Height := lPGHt;
260
			 sbBits := lBmp.ScanLine[lPGHt-1];
261
			 //FillChar(sbBits^,(lPGHt*lPGwid*4), 0);
262
			 //FillChar fills with black, the next bit will fill current background color
263
			 lBGInvisibleColor := gMRIcroOverlay[kBGOverlayNum].LUTinvisible;
264
			 l32BitP := DWordp(sbBits);
265
			 for lInc := 1 to (lPGwid*lPGHt) do
266
				l32BitP[lInc] := lBGInvisibleColor;
267
			 lImage.Width := (lBmp.Width);//xx
268
			 lImage.Height := (lBmp.Height);//xx
269
			 lImage.Picture.Graphic := lBMP;
270
	 FINALLY
271
			   lBMP.Free;
272
	 END; //try..finally
273
end; //proc CreateBlankBitmap
274
 {$ELSE} //else freepascal
275
276
procedure CreateBlankBitmap (lPGHt,lPGWid:integer;var lImage: TImage);
277
var
278
   lPos: integer;
279
   lBGInvisibleColor: TRGBQuad;
280
begin
281
{$IFDEF ENDIAN_BIG}
282
lBGInvisibleColor :=TColor2TRGBQuad(clBlack);
283
 {$ELSE}
284
  //lBGInvisibleColor := gMRIcroOverlay[kBGOverlayNum].LUTinvisible;
285
  lBGInvisibleColor := gMRIcroOverlay[kBGOverlayNum].LUT[0];
286
 {$ENDIF}
287
   gMultiWid := lPGWid;
288
  gMultiHt := lPGHt;
289
  if (gMultiWid < 1) or (gMultiHt < 1) then
290
     exit;
291
  getmem (gMultiBuff, gMultiHt*gMultiWid*sizeof(TRGBQuad) );
292
  //fillchar(gMultiBuff^,gMultiHt*gMultiWid*sizeof(TRGBQuad),0);
293
  for lPos := 1 to (gMultiHt*gMultiWid) do
294
      gMultiBuff^[lPos] :=  lBGInvisibleColor;
295
end;
296
{$ENDIF}
297
298
procedure MultiHLine (lX1,lX2,lY1,lThick: integer; lClr: TRGBQuad);
299
var
300
   lLine,lY,lYPos,lX,lXlo,lXhi: integer;
301
begin
302
  if (lThick < 1) or (gMultiWid < 1) or (gMultiHt < 1) or (lY1 < 1) or (lY1 >gMultiHt) or (gMultiBuff = nil) then
303
     exit;
304
  lXlo := lX1;
305
  lXHi := lX2;
306
  SortInteger(lXlo,lXhi);
307
  if lXlo < 1 then
308
     lXlo := 1;
309
  if lXlo > gMultiWid then
310
     lXlo := gMultiWid;
311
  if lXhi < 1 then
312
     lXhi := 1;
313
  if lXhi > gMultiWid then
314
     lXhi := gMultiWid;
315
  lY := lY1-((lThick{+1}) div 2);
316
  for lLine := 1 to lThick do begin
317
      lYPos := (lY)*gMultiWid;
318
      if lY < gMultiHt then
319
          for lX := lXlo to lXhi do
320
          gMultiBuff^[lYPos+lX] := lClr;
321
      inc(lY);
322
  end;
323
end;
324
325
procedure MultiVLine (lX1,lY1,lY2,lThick: integer; lClr: TRGBQuad);
326
var
327
   lXs, lX,lY,lYlo,lYhi: integer;
328
begin
329
  if (lThick < 1) or (gMultiWid < 1) or (gMultiHt < 1) or (lX1 < 1) or (lX1 >gMultiWid) or (gMultiBuff = nil) then
330
     exit;
331
  lYlo := lY1;
332
  lYHi := lY2;
333
  SortInteger(lYlo,lYhi);
334
  if lYlo < 1 then
335
     lYlo := 1;
336
  if lYlo > gMultiHt then
337
     lYlo := gMultiHt;
338
  if lYhi < 1 then
339
     lYhi := 1;
340
  if lYhi > gMultiHt then
341
     lYhi := gMultiHt;
342
  lXs := lX1-((lThick{+1}) div 2)-2;//-2 as indexed from 0 and line is at least 1 pixel thick
343
  for lX := lXs to (lXs+lThick-1) do
344
      if (lX >= 0) and (lX < gMultiWid) then
345
         for lY := lYlo to lYHi do
346
             gMultiBuff^[((lY-1)*gMultiWid)+lX] := lClr;
347
348
end;
349
350
procedure DefineBackGround(var lBMP: DWordp; lBGInvisibleColor: DWord; lMaskHt,lMaskWid: integer);
351
//lMaskP should have all invis voxels as 128, non as 255
352
//sets all invis boundary voxels to 0
353
var
354
	lMaskP: ByteP;
355
	lBGvisibleColor: DWord;
356
	lPos,lMaskSz,
357
	lQSz,lQHead,lQTail: integer;
358
	lQRA: LongIntp;
359
Procedure IncQra(var lVal, lQSz: integer);
360
begin
361
	inc(lVal);
362
	if lVal >= lQSz then
363
	 lVal := 1;
364
end;
365
PROCEDURE RetirePixel; //FIFO cleanup
366
VAR
367
   lVal,lPos: integer;
368
BEGIN
369
   lVal := lQra^[lQTail];
370
   lPos := lVal-1;
371
   if (lPos > 0) and (lMaskP^[lPos]=128) then begin//add item to left
372
		incQra(lQHead,lQSz);
373
		lMaskP^[lPos] := 0;
374
		lQra^[lQHead] := lPos;
375
   end;
376
   if (lPos > 0) then lMaskP^[lPos] := 0;
377
   lPos := lVal+1;
378
   if (lPos < lMaskSz) and (lMaskP^[lPos]=128) then begin//add item to right
379
		incQra(lQHead,lQSz);
380
		lMaskP^[lPos] := 0;
381
		lQra^[lQHead] := lPos;
382
   end;
383
   if (lPos < lMaskSz) then lMaskP^[lPos] := 0;
384
   lPos := lVal-lMaskWid;
385
   if (lPos > 0) and (lMaskP^[lPos]=128) then begin//add item above
386
		incQra(lQHead,lQSz);
387
		lMaskP^[lPos] := 0;
388
		lQra^[lQHead] := lPos;
389
   end;
390
   if (lPos > 0) then lMaskP^[lPos] := 0;
391
   lPos := lVal+lMaskWid;
392
   if (lPos < lMaskSz) and(lMaskP^[lPos]=128) then begin//add item below
393
		incQra(lQHead,lQSz);
394
		lMaskP^[lPos] := 0;
395
		lQra^[lQHead] := lPos;
396
   end;
397
   if (lPos < lMaskSz) then lMaskP^[lPos] := 0;
398
   incQra(lQTail,lQSz); //done with this pixel
399
END;
400
401
procedure FillStart (lPt: integer); {FIFO algorithm: keep memory VERY low}
402
begin
403
  if (lPt < 1) or (lPt > lMaskSz) or (lMaskP^[lPt] <> 128) then exit;
404
  //lQSz := 8000;//size of FIFO Queue Array
405
  lQHead := 1;
406
  lQTail := 1;
407
  lQra^[lQTail] := (lPt); //NOTE: both X and Y start from 0 not 1
408
  lMaskP^[lPt] := 0;
409
  RetirePixel;
410
  if lQHead >= lQTail then begin
411
	while lQHead <> lQTail do
412
		RetirePixel;
413
  end;
414
end;
415
begin //proc DefineBG
416
  lMaskSz := lMaskWid * lMaskHt;
417
  Getmem(lMaskP,lMaskSz);
418
  for lPos := 1 to lMaskSz do
419
	if lBMP^[lPos] = lBGInvisibleColor then
420
		lMaskP^[lPos] := 128
421
	else
422
		lMaskP^[lPos] := 255;
423
  lQSz := lMaskSz div 4;
424
  GetMem(lQra,lQSz*sizeof(LongInt));
425
  //erase all rows
426
  for lPos := 1 to lMaskHt do begin
427
	  FillStart( (lPos-1)*lMaskWid + 1);
428
	  FillStart( (lPos)*lMaskWid);
429
  end;
430
  //erase all cols
431
  for lPos := 1 to lMaskWid do begin
432
	  FillStart( lPos + 1);
433
	  FillStart( ((lMaskHt-1) *lMaskWid) + lPos);
434
  end;
435
  Freemem(lQRa);
436
  //make sure bright blue 0000FF becauses neighbor 0000FE instead of 000100
437
  if (lBGInvisibleColor and 255) = 255 then
438
	lBGVisibleColor:= lBGInvisibleColor-1
439
  else
440
	lBGVisibleColor:= lBGInvisibleColor+1;
441
  //now, fill in islands so they are not transparent
442
  for lPos := 1 to lMaskSz do
443
	if lMaskP^[lPos] = 128 then
444
		lBMP^[lPos] := lBGVisibleColor;
445
  Freemem(lMaskP);
446
end;
447
448
{$IFDEF FPC} //Delphi draws bitmaps directly, Lazarus can use two indirect methods...
449
procedure SetDim (lInPGHt,lInPGWid,lWriteColumn: integer; var l32OutBitP : DWordp);
450
var
451
   lLen,lSrc,lDest,lY: integer;
452
   lTBuff:    RGBQuadp;
453
begin
454
        getmem(lTBuff,lInPGHt*lWriteColumn*4);
455
        lLen := lWriteColumn*4;
456
        lSrc := 1;
457
        lDest := 1;
458
        for lY := 1 to lInPGHt do begin
459
           //svn Move(Pointer(l32OutBitP^[lSrc]),Pointer(lTBuff^[lDest]),lLen);
460
           Move(l32OutBitP^[lSrc],lTBuff^[lDest],lLen);
461
           lSrc := lSrc + lInPGWid;
462
           lDest := lDest + lWriteColumn;
463
        end;
464
        DrawBMP( lWriteColumn, lInPGHt, lTBuff, MultiSliceForm.MultiImage);
465
        freemem(lTBuff);
466
end;
467
{$ENDIF} //ifdef FPC
468
469
procedure RemoveHorizGaps (lMaxOverlapWid,lColWid: integer); //will overlap gaps from 1..lMaxOverlapWid, leave right non-overlapped);
470
var
471
 l32BitP,l32OutBitP : DWordp;
472
 lBGInvisibleColor,lBGInvisibleColorShr8: DWord;
473
 lIsGap,lPrevIsGap: boolean;
474
 lInc,lPrevSliceStart,lPrevSliceEnd,lPrevWriteColumn,lWid,lHt,lReadRow,
475
 lMaxWriteColumn,lReadColumn,lWriteColumn,lReadOffset,lWriteOffset,lPos,x,y: integer;
476
 lTextPos,lTextReadColumn: integer;
477
begin
478
      (*freemem (gMultiBuff );
479
 gMultiBuff := nil;
480
 exit;*)
481
482
483
     for lTextPos := 1 to kMaxMultiSlice do
484
         gMultiXCenterRA[lTextPos] := 0;
485
       lTextPos := 0;
486
       lTextReadColumn := lColWid div 2;
487
       if (gMultiWid < 1) or (gMultiHt < 1) or (gMultiBuff = nil) then
488
          exit;
489
     lBGInvisibleColor := TRGBQuad2DWord(gMRIcroOverlay[kBGOverlayNum].LUTinvisible);
490
     //fx(lBGInvisibleColor);
491
     //lBGInvisibleColorShr8 := lBGInvisibleColor Shr 8;
492
	lHt := gMultiHt;//MultiSliceForm.MultiImage.Picture.Bitmap.Height;
493
	lWid := gMultiWid; //MultiSliceForm.MultiImage.Picture.Bitmap.Width;
494
	if (lHt < 2) or (lWid < 2) then exit;
495
	//next: prepare input
496
        l32BitP := DWordP(gMultiBuff);
497
        (*GetMem(l32BitP,lHt*lWid*sizeof(DWord));
498
        lPos := 0;
499
        for y:=  0 to (lHt-1) do begin
500
            for x:=0 to lWid-1 do begin
501
                inc(lPos);
502
                l32BitP^[lPos] := MultiSliceForm.MultiImage.Picture.Bitmap.Canvas.Pixels[x,y];
503
            end;
504
        end;*)
505
        lBGInvisibleColor := l32BitP^[1];
506
	DefineBackGround(l32BitP,lBGInvisibleColor, lHt,lWid);
507
	//next prepare output
508
         GetMem(l32OutBitP,lHt*lWid*sizeof(DWord));
509
	 for lInc := 1 to (lwid*lHt) do
510
		l32OutBitP^[lInc] := lBGInvisibleColor;
511
	//next: compress by deleting empty columns
512
	lWriteColumn := 0;
513
	lPrevIsGap := true;
514
	lPrevSliceStart := maxint -10;
515
	lPrevSliceEnd := 0;
516
	lPrevWriteColumn := maxint-10;//do not degap 1st line
517
518
519
if gMulti.OverSlicePct = 0 then begin //simply remove gaps between slice
520
	for lReadColumn := 1 to lWid do begin
521
		lReadOffset := lReadColumn;
522
		lIsGap := true;
523
		lReadRow := 1;
524
                if lReadColumn >= lTextReadColumn then begin
525
                   inc(lTextPos);
526
                   lTextReadColumn := lTextReadColumn+lColWid;
527
                   if lTextPos <= kMaxMultiSlice then
528
                      gMultiXCenterRA[lTextPos] := lWriteColumn;
529
                end;
530
		while (lReadRow < lHt) and (lIsGap) do begin
531
			if l32BitP^[lReadOffset] <> lBGInvisibleColor then
532
				lIsGap := false;
533
			inc(lReadOffset,lWid);
534
			inc(lReadRow);
535
		end; //while each readrow
536
		if not lIsGap then begin//data in this column
537
			if lReadColumn > (lPrevWriteColumn+1) then begin //leave one pixel gap between noncontiguous columns
538
				inc(lWriteColumn);
539
				lReadOffset := lReadColumn-1;
540
				lWriteOffset := lWriteColumn;
541
				//showmessage(inttostr(lWriteColumn)+'  '+inttostr(lReadOffset));
542
				for lReadRow := 1 to lHt do begin
543
					l32OutBitP[lWriteOffset] := l32BitP[lReadOffset];
544
					inc(lReadOffset,lWid);
545
					inc(lWriteOffset,lWid);
546
				end;
547
			end; //leave 1 pixel gap
548
			inc(lWriteColumn);
549
			lReadOffset := lReadColumn;
550
			lWriteOffset := lWriteColumn;
551
			for lReadRow := 1 to lHt do begin
552
				l32OutBitP[lWriteOffset] := l32BitP[lReadOffset];
553
				inc(lReadOffset,lWid);
554
				inc(lWriteOffset,lWid);
555
			end;
556
			lPrevWriteColumn := lReadColumn;
557
		end; //not Gap - write this column
558
	end; //for each column
559
end else begin //overslice <> 0: show subsequent slices above/below each other
560
         lMaxWriteColumn := -maxint;
561
         for lReadColumn := 1 to lMaxOverlapWid do begin
562
		lReadOffset := lReadColumn;
563
		lIsGap := true;
564
		lReadRow := 1;
565
		while (lReadRow < lHt) and (lIsGap) do begin
566
			//ovx
567
			if l32BitP^[lReadOffset] <> lBGInvisibleColor then
568
				lIsGap := false;
569
			inc(lReadOffset,lWid);
570
			inc(lReadRow);
571
		end; //while each readrow
572
		if (lPrevIsGap <> lIsGap) then begin//change from prev column
573
			if not (lIsGap) then begin
574
                              //fx(lPrevSliceStart,lPrevSliceEnd,lReadColumn,abs(((lPrevSliceEnd-lPrevSliceStart) * gMulti.OverSlicePct)div 100));
575
			   if lPrevSliceEnd > lPrevSliceStart then
576
				lWriteColumn := lPrevSliceEnd-abs(((lPrevSliceEnd-lPrevSliceStart) * gMulti.OverSlicePct)div 100);
577
			   lPrevSliceStart := lWriteColumn;
578
579
			end;
580
			if (lIsGap) then
581
			   lPrevSliceEnd := lWriteColumn;
582
		end;
583
		lPrevIsGap := lIsGap;
584
		if gMulti.OverSlicePct > 0 then begin
585
		  if not lIsGap then begin//data in this column
586
			inc(lWriteColumn);
587
			lReadOffset := lReadColumn;
588
			lWriteOffset := lWriteColumn;
589
			for lReadRow := 1 to lHt do begin
590
				if l32BitP^[lReadOffset] <> lBGInvisibleColor then
591
					l32OutBitP^[lWriteOffset] := l32BitP^[lReadOffset];
592
				inc(lReadOffset,lWid);
593
				inc(lWriteOffset,lWid);
594
			end;
595
		  end; //not Gap - write this column
596
		end else begin //if overwrite, else underwrite
597
		  if not lIsGap then begin//data in this column
598
			inc(lWriteColumn);
599
			lReadOffset := lReadColumn;
600
			lWriteOffset := lWriteColumn;
601
		        for lReadRow := 1 to lHt do begin
602
				if l32OutBitP^[lWriteOffset] = lBGInvisibleColor then
603
					l32OutBitP^[lWriteOffset] := l32BitP^[lReadOffset];
604
				inc(lReadOffset,lWid);
605
				inc(lWriteOffset,lWid);
606
			end;
607
		  end; //not Gap - write this column
608
		end;
609
                if lReadColumn >= lTextReadColumn then begin //text
610
                   inc(lTextPos);
611
                   lTextReadColumn := lTextReadColumn+lColWid;
612
                   if lTextPos <= kMaxMultiSlice then
613
                      gMultiXCenterRA[lTextPos] := lWriteColumn;
614
                end;  //text
615
       		if lWriteColumn > lMaxWriteColumn then
616
			lMaxWriteColumn := lWriteColumn;
617
	end; //for each column
618
	if lWriteColumn < lMaxWriteColumn then
619
		lWriteColumn := lMaxWriteColumn;
620
       if lMaxOverlapWid < lWid then begin
621
		lReadColumn := lMaxOverlapWid;
622
		if (lWriteColumn) < lReadColumn then //add gap if some compression
623
			inc(lWriteColumn);
624
		for lReadColumn := (lMaxOverlapWid+1) to lWid do begin
625
		  lReadOffset := lReadColumn;
626
		  lIsGap := true;
627
		  lReadRow := 1;
628
		  while (lReadRow < lHt) and (lIsGap) do begin
629
			if l32BitP^[lReadOffset] <> lBGInvisibleColor then
630
				lIsGap := false;
631
			inc(lReadOffset,lWid);
632
			inc(lReadRow);
633
		  end; //while each readrow
634
		  if not lIsGap then begin
635
			inc(lWriteColumn);
636
			lReadOffset := lReadColumn;
637
			lWriteOffset := lWriteColumn;
638
			for lReadRow := 1 to lHt do begin
639
				l32OutBitP[lWriteOffset] := l32BitP[lReadOffset];
640
				inc(lReadOffset,lWid);
641
				inc(lWriteOffset,lWid);
642
			end; //for each row
643
		  end; //not gap
644
		end; //for each column
645
		if (lWriteColumn+1) < lWid then
646
			inc(lWriteColumn);
647
	end; //if maxwid < wid - unoverlapped
648
end;
649
650
 SetDim (lHt,lWid,lWriteColumn,l32OutBitP);
651
 FreeMem(l32OutBitP);
652
   freemem (gMultiBuff );
653
 gMultiBuff := nil;
654
end;
655
656
657
procedure TMultiSliceForm.CreateMultiSag;
658
var
659
	lSlice,lHt,lWid,lSlicePos,lSliceWid: integer;
660
begin
661
662
  lHt:= gBGIMg.ScrnDim[3];
663
  lSliceWid :=gBGIMg.ScrnDim[2]+2;//+1 for 1-voxel gap between slices - ensures we can detect slice boundary
664
  lWid := (lSliceWid*gMulti.nSlices);
665
  if lWid < 2 then exit;
666
  if gMulti.OrthoView then //coro crossview
667
	lWid := lWid + gBGIMg.ScrnDim[1]+2;
668
  if lWid < 2 then exit;
669
670
  CreateBlankBitmap (lHt,lWid, MultiImage);
671
  for lSlice := 1 to gMulti.nSlices do begin
672
	DrawSag (gMulti.SliceList[lSlice],1+((lSlice-1)*lSliceWid));//+lSlice because we want 1-voxel gap between slices
673
	//if gMulti.SliceLabel then DrawLabel(MultiImage,DimToMM(gMulti.SliceList[lSlice],1),((lSlice-1)*lSliceWid)+(lSliceWid div 2),lWid);
674
  end;
675
  if gMulti.OrthoView then begin //coro crossview
676
	DrawCor (gBGImg.ScrnDim[2] div 2,(lSliceWid*gMulti.nSlices)-1);
677
        //MultiImage.Canvas.Pen.Color := clWhite;
678
	//MultiImage.Canvas.Pen.Color := gBGIMg.XBarClr;
679
        //MultiImage.Canvas.Pen.Width := gBGImg.XBarThick;
680
        for lSlice := 1 to gMulti.nSlices do begin //draw lines
681
		lSlicePos := (gMulti.nSlices*lSliceWid)+(gMulti.SliceList[lSlice]);
682
                MultiVLine (lSlicePos,0,lHt,gBGImg.XBarThick,TColor2TRGBQuad(gBGImg.XBarClr));
683
		{MultiImage.Canvas.MoveTo(lSlicePos,0);
684
		MultiImage.Canvas.LineTo(lSlicePos,lHt);}
685
	end;//line for each slice
686
  end;//if cross view
687
  RemoveHorizGaps(lSliceWid*gMulti.nSlices,lSliceWid);
688
end; //CreateMultiSag
689
690
procedure TMultiSliceForm.CreateMultiCor;
691
var
692
	lSlice,lHt,lWid,lLeft,lSliceWid: integer;
693
begin
694
  lHt:= gBGIMg.ScrnDim[3];
695
  lSliceWid :=gBGIMg.ScrnDim[1]+2;//+1 for 1-voxel gap between slices - ensures we can detect slice boundary
696
  lWid := lSliceWid*gMulti.nSlices;
697
  if lWid < 2 then exit;
698
  if gMulti.OrthoView then  //sag crossview
699
	lWid := lWid + gBGIMg.ScrnDim[2]+2;
700
  if lWid < 2 then exit;
701
  CreateBlankBitmap (lHt,lWid, MultiImage);
702
  for lSlice := 1 to gMulti.nSlices do begin
703
	//ImgForm.YViewEdit.value := gMulti.SliceList[lSlice];
704
	DrawCor (gMulti.SliceList[lSlice],1+((lSlice-1)*lSliceWid));
705
	//if gMulti.SliceLabel then DrawLabel(MultiImage,DimToMM(gMulti.SliceList[lSlice],2),((lSlice-1)*lSliceWid)+(gBGIMg.ScrnDim[1] div 2),lWid);
706
  end;
707
  if gMulti.OrthoView then begin
708
	DrawSag (gBGImg.ScrnDim[1] div 2,(gMulti.nSlices*lSliceWid)-1);
709
	//MultiImage.Canvas.Pen.Color := gBGIMg.XBarClr;
710
        //MultiImage.Canvas.Pen.Color := clWhite;
711
	MultiImage.Canvas.Pen.Color := gBGIMg.XBarClr;
712
        MultiImage.Canvas.Pen.Width := gBGImg.XBarThick;
713
714
        for lSlice := 1 to gMulti.nSlices do begin
715
		lLeft := gMulti.nSlices*lSliceWid+(gMulti.SliceList[lSlice]);
716
                MultiVLine (lLeft,0,lHt,gBGImg.XBarThick,TColor2TRGBQuad(gBGImg.XBarClr));
717
718
		{MultiImage.Canvas.MoveTo(lLeft,0);
719
		MultiImage.Canvas.LineTo(lLeft,lHt);}
720
	end;
721
  end;//if orthoview
722
  RemoveHorizGaps(lSliceWid*gMulti.nSlices,lSliceWid);
723
end; //CreateMultiCor
724
725
procedure TMultiSliceForm.CreateMultiAx;
726
var
727
	lSliceWid,lSlice,lHt,lWid,lLeft: integer;
728
begin
729
  lHt:= gBGIMg.ScrnDim[2];
730
  lSliceWid :=gBGIMg.ScrnDim[1]+2;//+1 for 1-voxel gap between slices - ensures we can detect slice boundary
731
  lWid := lSliceWid*gMulti.nSlices;
732
  if lWid < 2 then exit;
733
  if gMulti.OrthoView then begin //sag crossview
734
	lWid := lWid + gBGIMg.ScrnDim[2]+2;
735
	if gBGIMg.ScrnDim[3]> lHt then
736
		lHt := gBGIMg.ScrnDim[3];
737
  end;
738
  if lWid < 2 then exit;
739
  CreateBlankBitmap (lHt,lWid, MultiImage);
740
  for lSlice := 1 to gMulti.nSlices do begin
741
	DrawAxial (gMulti.SliceList[lSlice],1+((lSlice-1)*lSliceWid));
742
	//if gMulti.SliceLabel then DrawLabel(MultiImage,DimToMM(gMulti.SliceList[lSlice],3),((lSlice-1)*lSliceWid)+(gBGIMg.ScrnDim[1] div 2),lWid);
743
  end;
744
  if gMulti.OrthoView then begin
745
	lLeft := gMulti.nSlices*lSliceWid;
746
	//DrawSag (gBGImg.ScrnDim[1] div 2,lLeft);
747
	DrawSag (gBGImg.ScrnDim[1] div 2,lLeft-1);
748
749
        //MultiImage.Canvas.pen.Color := clWhite;
750
        //MultiImage.Canvas.Pen.Color := gBGIMg.XBarClr;
751
        //MultiImage.Canvas.Pen.Width := gBGImg.XBarThick;
752
753
        for lSlice := 1 to gMulti.nSlices do begin
754
		lHt := gBGImg.ScrnDim[3]-(gMulti.SliceList[lSlice]);
755
                MultiHLine (lLeft,lWid,lHt,gBGImg.XBarThick,TColor2TRGBQuad(gBGImg.XBarClr));
756
	end;
757
  end;
758
  RemoveHorizGaps(lSliceWid*gMulti.nSlices,lSliceWid);
759
end; //CreateMultiAx
760
761
procedure DrawLabels;
762
var
763
   lSlice,lOrient: integer;
764
begin
765
 case gMulti.Orient of
766
	3: lOrient := 2;
767
	2: lOrient := 1;
768
	else lOrient := 3;
769
 end;//case
770
771
  if not gMulti.SliceLabel then
772
     exit;
773
  for lSlice := 1 to gMulti.nSlices do begin
774
	if gMultiXCenterRA[lSlice] > 0 then DrawLabel(MultiSliceForm.MultiImage,DimToMM(gMulti.SliceList[lSlice],gMulti.SliceList[lSlice],gMulti.SliceList[lSlice],lOrient),gMultiXCenterRA[lSlice],maxint);
775
  end;
776
end;
777
//gMultiXCenterRA
778
779
procedure TMultiSliceForm.CreateMultiSlice;
780
//test var lI: integer;
781
begin
782
 if gMulti.nSlices < 1 then begin
783
	showmessage('No valid slices selected - please use View/Slices.');
784
 end;
785
 //MultiImage.Canvas.Font.Color := clWhite;
786
//for lI := 1 to 32 do begin //test
787
 case gMulti.Orient of
788
	3: CreateMultiCor;
789
	2: CreateMultiSag;
790
	else CreateMultiAx;
791
 end;//case
792
 DrawLabels;
793
   // end; //test
794
end;//CreateMultiSlice
795
796
procedure TMultiSliceForm.OrientClick(Sender: TObject);
797
begin
798
	(sender as TMenuItem).checked := true;
799
	gMulti.Orient := (sender as TMenuItem).tag;
800
	CreateMultiSlice;
801
end;
802
803
procedure TMultiSliceForm.FormShow(Sender: TObject);
804
begin
805
   ReadMultiSliceIniFile (gMultiSliceStartupFilename );
806
   UpdateMultiSliceMRU;
807
   UpdateMultiSliceDisplay;
808
   CreateMultiSlice;
809
   MultiSliceForm.BringToFront;
810
end;
811
812
procedure TMultiSliceForm.OrthoviewClick(Sender: TObject);
813
begin
814
	OrthoView.checked := not OrthoView.Checked;
815
	gMulti.OrthoView := OrthoView.checked;
816
	CreateMultiSlice;
817
end;
818
819
procedure TMultiSliceForm.Settings1Click(Sender: TObject);
820
begin
821
822
end;
823
824
procedure TMultiSliceForm.Slices1Click(Sender: TObject);
825
var
826
	lStr: string;
827
begin
828
	lStr := InputBox('Select multislices', 'Slice numbers [e.g. 10,16,24]',MultiSliceNum2String);
829
	//now parse line
830
	MultiSliceString2Num(lStr);
831
	CreateMultiSlice;
832
end;
833
834
procedure TMultiSliceForm.Closewindow1Click(Sender: TObject);
835
begin
836
	MultiSliceForm.Close;
837
end;
838
839
procedure TMultiSliceForm.UpdateMultiSliceDisplay;
840
begin
841
	SetSubmenuWithTag(OversliceMenu, gMulti.OverslicePct);
842
	SetSubmenuWithTag(OrientMenu, gMulti.Orient);
843
	OrthoView.Checked := gMulti.OrthoView;
844
	SliceLabelCheck.Checked := gMulti.SliceLabel;
845
end;
846
847
procedure TMultiSliceForm.FormCreate(Sender: TObject);
848
var
849
	lSlice:integer;
850
begin
851
     gMultiBuff := nil;
852
     gMultiSliceDir  := DefaultsDir('multislice');
853
     //gMultiSliceDir := extractfiledir(paramstr(0))+pathdelim+'multislice'+pathdelim;
854
     gMultiSliceDefaultsFilename := gMultiSliceDir + 'default.ini';
855
     gMultiSliceStartupFilename := gMultiSliceDefaultsFilename;
856
     gMulti.Orient := 1;
857
     gMulti.OverslicePct := 0;
858
     gMulti.nSlices:= 4;
859
     gMulti.OrthoView := true;
860
     gMulti.SliceLabel := true;
861
     for lSlice := 1 to gMulti.nSlices do
862
	gMulti.SliceList[lSlice] := 62+10*lSlice;
863
end;
864
865
 {$IFNDEF FPC}
866
procedure TMultiSliceForm.FormClose(Sender: TObject; var Action: TCloseAction);
867
 {$ELSE}
868
procedure TMultiSliceForm.FormClose(Sender: TObject);
869
 {$ENDIF}
870
begin
871
WriteMultiSliceIniFile (gMultiSliceDefaultsFilename );
872
end;
873
874
procedure TMultiSliceForm.Savesettings1Click(Sender: TObject);
875
begin
876
  MultiSaveDialog.InitialDir := extractfiledir(gMultiSliceDir );
877
  if not MultiSaveDialog.Execute then exit;
878
  {$IFDEF Unix}
879
  WriteMultiSliceIniFile(extractfiledir(gMultiSliceDir)+pathdelim+extractfilename(MultiSaveDialog.Filename));
880
881
  {$ELSE}
882
  WriteMultiSliceIniFile(MultiSaveDialog.Filename);
883
  {$ENDIF}
884
  UpdateMultiSliceMRU;
885
end;
886
887
procedure TMultiSliceForm.SliceLabelCheckClick(Sender: TObject);
888
begin
889
	SliceLabelCheck.checked := not SliceLabelCheck.Checked;
890
	gMulti.SliceLabel := SliceLabelCheck.checked;
891
	CreateMultiSlice;
892
end;
893
894
procedure TMultiSliceForm.OverlsiceClick(Sender: TObject);
895
begin
896
	(sender as TMenuItem).checked := true;
897
	gMulti.OverslicePct := (sender as TMenuItem).tag;
898
	CreateMultiSlice;
899
end;
900
901
  {$IFDEF FPC}
902
initialization
903
  {$I MultiSlice.lrs}
904
{$ENDIF}
905
906
end.