Working with two images

If you want to work with two images in pascal, using the data from one to effect the other image, you could set up something like the following code. You can easily work with two InfoPtr's to do the job. You might pass the picture number from a macro for convenience

SrcInfo := Info;
DestPic := Trunc(FinalImage); 
Info := pointer(WindowPeek(PicWindow[DestPic])^.RefCon); 
DstInfo := Info;{assign it to DstInfo}
  for vloc := RoiTop to RoiBottom - 1 do begin
    Info := SrcInfo; 
    GetLine(RoiLeft, vloc, width, CurLinePtr^);

{Do something with the data and put the data to the other window}
    NewLinePtr^[hloc] := CurLinePtr^[hloc]*myfactor

    Info := DstInfo; 
    PutLine(RoiLeft, vloc, width, NewLinePtr^);

4D dataset

If you have multiple stacks of images which all relate to each other in some manner, you can load them all into memory for calculations. A program such as SpyGlass is useful for viewing this type of data, but it may not provide you with the means for calculating terribly much. If you wish to have a unique calculated value, or any type of value, for each point in each stack you could use Image and set something up like the below. Make sure you use Long integers for just about everything of the integer type. This routine should work with stacks of differing sizes loaded (i.e. one stack could be 200x200x5 and others might be 256x256x10 and so on).
{Set up multiple for loops for nPics and each SliceCount}
for PictureNumber := 1 to npics...
{You must find the previous data offset for the final array}
CurrentInfo := Info;
PreviousEndOfData := 0;
for i := 1 to PictureNumber - 1 do begin
  TempInfo := pointer(WindowPeek(PicWindow[i])^.RefCon);
  Info := TempInfo;
  with Info^.PicRect do begin
    Previouswidth := right - left;
    Previousheight := bottom - top;
  if Info^.StackInfo <> nil then
    PreviousSliceCount := Info^.StackInfo^.nSlices
    PreviousSliceCount := 1;
  BytesUsed := PreviousSliceCount * PreviousWidth * PreviousHeight;
  PreviousEndOfData := PreviousEndOfData + BytesUsed;
Info := CurrentInfo;
{Find how many slices in the current pic}
if Info^.StackInfo <> nil then
  SliceCount := Info^.StackInfo^.nSlices
  SliceCount := 1;
For SliceNumber := 1 to SliceCount ....
{Set up rest of the for loops here. The usual, up to hloc & vloc}
{put those here}
{Now compute a unique array offset}
ArrayOffset := PreviousEndOfData + (SliceNumber - 1) * LongInt(width) * height + LongInt(width) * longInt(vloc) + LongInt(hloc);
{Finally store your calculation into a unique location}
MyHugeArray^[ArrayOffset] := SomeCalculatedValue;

Creating a dialog box

     function GetDNum (TheDialog: DialogPtr; item: integer): LongInt;
     function GetDString (TheDialog: DialogPtr; item: integer): str255;
     function GetDReal (TheDialog: DialogPtr; item: integer): extended;

     procedure SetDNum (TheDialog: DialogPtr; item: integer; n: LongInt);
     procedure SetDReal (TheDialog: DialogPtr; item: integer; n: extended; fwidth: integer);
     procedure SetDString (TheDialog: DialogPtr; item: integer; str: str255);
     procedure SetDialogItem (TheDialog: DialogPtr; item, value: integer);

Dialogs are a good way to handle user I/O. If you can't get by with the set of dialogs in Image you could add one of your own. They can be used to set parameters or give options to the user. Several example dialogs in Image are the preferences dialog box and the SaveAs dialog. The template for dialog boxes are in the Image.rsrc file under DLOG and DITL. The DITL resource is for creation of each dialog item in the DLOG. Naturally, each item in the dialog template has a reference integer value associated with it. This allows you to keep track of what you are pressing or which box you are entering information into. To handle the dialog to user I/O, you need to have a tight loop checking what is being pressed or entered. If the user is entering a number or string you need to retrieve it with one of the GET dialog functions. Likewise, you can pass information or turn off a button with the SET procedures. The basic form for a dialog loop appears below:
mylog := GetNewDialog(130, nil, pointer(-1)); {retrieve the dialog box}
Do default SET's here
OutlineButton(MyLog, ok, 16);
     ModalDialog(nil, item);
     if item = SomeDialogItemID then begin
        Get or Set something
...  lots of if statements to check which item is pressed
until (item = ok) or (item = cancel);

Key & mouse

 function OptionKeyDown: boolean;
 function ShiftKeyDown: boolean;
 function ControlKeyDown: boolean;
 function SpaceBarDown: boolean;

It is fairly common for a menu selection to have several possible paths to follow. The selection process can be dictated via use of simple boolean functions. For the most part they are self explanatory. Holding the option key down when selecting a menu item is the most common way to select a divergent path. Your routine need only execute the function to test the key status.
if OptionKeyDown then begin
  else begin


 function CommandPeriod: boolean;

The CommandPeriod function is used when you want to interrupt execution of a procedure. For example you might include the following bit of code in a prolonged looping routine that you write:

    if CommandPeriod then begin

Mouse button

Apple has supplied several mouse button routines such as the true or false button boolean. It's functionality is the same as in the macro language.
Function Button:boolean;
The button functions are explained in Inside Mac

Image and text

There are a number of ways to handle text with Image. If you are working in the context of macros, then a text window should handle most of what you want to do. Copy and paste functions work with the text window. Sample macros, such as the example under SelectPic and Selectwindow in the macros section above, show how to handle the majority of text data handling needs.

If your needs are larger, or if you are considering extensive data to disk handling, then you should consider using the textbuffer pascal routines described below. You can use these routines to export as text all the data you can possibly fill memory with. These are NOT connected with the text window routines, which are seperately seen in the Text.p file.

Global declarations

  MaxTextBufSize = 32700;
  TextBufType = packed array[1..MaxTextBufSize] of char;
  TextBufPtr = ^TextBufType;
  TextBufP: TextBufPtr;
  TextBufSize, TextBufColumn, TextBufLineCount: integer;

Other useful definitions include:
  cr := chr(13);
  tab := chr(9);
  BackSpace := chr(8);
  eof := chr(4);

Dynamic memory allocation for the textbuffer (under Init.p) sets up a non-relocatable block of memory.
   TextBufP := TextBufPtr(NewPtr(Sizeof(TextBufType)));

To clear the buffer set TextBufSize equal to zero. Use TextBufSize to keep track of what data within the textbuffer is valid. Anything beyond the length of TextBufSize is not useful. Many Apple routines, such as FSWrite, require the number of bytes be passed as a parameter.

Text buffer utilities

Some of the utilities associated with the textbuffer include:

procedure PutChar (c: char); procedure PutTab; procedure PutString (str: str255); procedure PutReal (n: extended; width, fwidth: integer); procedure PutLong (n: LongInt; FieldWidth: integer);
Expansion of PutString may help in the understanding of the functionality involved:
procedure PutString (str: str255);
   i: integer;
  for i := 1 to length(str) do begin
    if TextBufSize < MaxTextBufSize then
     TextBufSize := TextBufSize + 1;
    TextBufP^[TextBufSize] := str[i];
    TextBufColumn := TextBufColumn + 1;
An example call sequence which places text into textbuffer might look something like:
PutSting('Number of Pixels');
To Save the textbuffer, the procedure SaveAsText can be used after a SFPPutfile to FSWrite data to the disk or other output.

Saving a text buffer

To Save the textbuffer, the procedure SaveAsText can be used after a SFPutfile. SaveAsText will FSWrite data to the disk. SFPutfile shows the standard file dialog box and FSWrite (within SaveAsText) does the actually saving to disk.

procedure SampleSaveBuffer;
   Where: point;
   reply: SFReply;
  SFPutFile(Where, 'Save as?', 'Buffer data', nil, reply);
  if not reply.good then
  with reply do
   SaveAsText(fname, vRefNum);    {this will handle the FSWriting}