{$R-,I-}
Program panGIF;
uses CRT,Dos,GRAPH,DEGIF;

  type
    row = array [0..1023] of byte;
    rowPtr = ^row;

var  InFileName:string;   BlockType:char;
     I,NewBottom,NewLeft,NewRight,NewTop,
     OffLeft,OffTop,Pass,XCord,YCord:integer;
     InFile:File;
     Buffer:array[0..32767] of byte;
     BufIndx,Count:word;
     Done,EOFin,SkipIt,Smash,Squeeze:Boolean;
     image: array [0..1023] of rowPtr;
     scale: longint;
     xadj,yadj: array [0..1023] of integer;
     white: byte;
     scaleHeight,scaleWidth: integer;

procedure quit;
 begin
   textmode(lastmode);
   halt;
 end;

procedure Abort;
 begin
  close(InFile);Quit
 end;

{$F+}
function GetByte: byte;
begin
 if not Done
  then begin
        if BufIndx >= Count
         then begin
               Done:=EOFIn;BlockRead(InFile,Buffer,SizeOf(Buffer),Count);
               EOFIn:=Count < sizeof(Buffer); BufIndx:=0
              end;
        GetByte:=Buffer[BufIndx]; Inc(BufIndx)
       end
  else GetByte:=0
end;
{$F-}

{$F+}
procedure PutByte(Pix: integer);
const YInc:array [1..5] of integer=(8,8,4,2,1);
      YLin:array [1..5] of integer=(0,4,2,1,0);
var x,y:integer;
begin
 x:=xadj[xCord];
 y:=yadj[yCord];
 if (x<320) and (y<200) then
   mem[$A000:word(320*y+x)]:=Pix;
 image[y]^[x]:=Pix;
 Inc(XCord);
 if XCord = NewRight
  then begin XCord:=NewLeft;
             if KeyPressed then Abort;
             Inc(YCord,YInc[Pass]);
             SkipIt:=Smash and ((YCord and 1)=1);
             if YCord >= NewBottom then
               begin
                 if Interlaced then Inc(Pass);
                 YCord:=YLin[Pass]+NewTop
               end;
       end
end;
{$F-}

procedure DoMapping;
    var
      i: integer;
      regs: registers;
      r,g,b: byte;
      temp,max: longint;
 begin
    max:=0;
    for i:=0 to NumberOfColors[CurMap]-1 do
      begin
        temp:=Sqr(Longint(redvalue[i]))+Sqr(Longint(greenvalue[i]))+Sqr(Longint(bluevalue[i]));
        if temp>max then
          begin max:=temp; white:=i; end;
        r:=redvalue[i] div 4;
        g:=greenvalue[i] div 4;
        b:=bluevalue[i] div 4;
        Inline($B8/$10/$10/$8B/$9E/>I/$8A/$B6/>R/$8A/$AE/>G/$8A/$8E/>B/$CD/$10);
      end;
 end;

procedure AdjustImage;
  var i: integer;
 begin
  NewLeft  := ImageLeft + OffLeft;
  NewTop   := ImageTop + OffTop;
  NewRight := ImageWidth + NewLeft;
  NewBottom:= ImageHeight + NewTop;
  XCord:=NewLeft;   YCord:=NewTop;
  if Interlaced then Pass:=1 else Pass:=5;
  scale:=1024;
  while MemAvail*15 div 16<(scale*imageWidth div 1024)*(scale*imageHeight div 1024) do
    Dec(scale);
  for i:=0 to ImageWidth-1 do
    xadj[i]:=scale*i div 1024;
  for i:=0 to ImageHeight-1 do
    yadj[i]:=scale*i div 1024;
  scaleHeight:=scale*ImageHeight div 1024;
  scaleWidth:=scale*ImageWidth div 1024;
  for i:=0 to scaleHeight-1 do
    GetMem(image[i],scaleWidth);
 end;

procedure DisplayScrDes;
var I:integer;
    AnsCh:char;
begin
 Writeln(ScreenWidth,'x',ScreenHeight,'  ',NumberOfColors[Global],' colors');
 OffLeft:=0; OffTop:=0;
 Smash:=false; Squeeze:=false;
 end;

  procedure GraphColorMode;
  begin { procedure GraphColorMode }
    inline($B8/$13/$00/$CD/$10);
    DoMapping;
  end; { procedure GraphColorMode }

  procedure pan;
    var
      done: boolean;
      ch: char;
      x,y: integer;

    procedure slideRight;
      var h,v,b: word; x0: integer;
    begin { procedure slideRight }
      if x=0 then exit;
      x0:=x;
      Dec(x,10); if x<0 then x:=0;
      for v:=0 to 199 do
        begin
          b:=word(320*v);
          Move(mem[$A000:b],mem[$A000:b+x0-x],320+x-x0);
          Move(image[y+v]^[x],mem[$A000:b],x0-x);
        end;
    end; { procedure slideRight }

    procedure slideLeft;
      var h,v,b: word; x0: integer;
    begin { procedure slideLeft }
      if x=scaleWidth-320 then exit;
      x0:=x;
      Inc(x,10); if x+320>scaleWidth then x:=scaleWidth-320;
      for v:=0 to 199 do
        begin
          b:=word(320*v);
          Move(mem[$A000:b+x-x0],mem[$A000:b],320+x0-x);
          Move(image[y+v]^[320+x0],mem[$A000:b+320+x0-x],x-x0);
        end;
    end; { procedure slideLeft }

    procedure slideDown;
      var h,v,b: word; y0: integer;
    begin { procedure slideDown }
      if y=0 then exit;
      y0:=y;
      Dec(y,10); if y<0 then y:=0;
      Move(mem[$a000:0],mem[$a000:320*(y0-y)],word(320*(200+y-y0)));
      for v:=0 to y0-y-1 do
        begin
          b:=word(320*v);
          Move(image[y+v]^[x],mem[$A000:b],320);
        end;
    end; { procedure slideDown }

    procedure slideUp;
      var h,v,b: word; y0: integer;
    begin { procedure slideUp }
      if y=scaleHeight-200 then exit;
      y0:=y;
      Inc(y,10); if y+200>scaleHeight then y:=scaleHeight-200;
      Move(mem[$A000:320*(y-y0)],mem[$A000:0],word(320*(200+y0-y)));
      for v:=200+y0-y to 199 do
        begin
          b:=word(320*v);
          Move(image[y+v]^[x],mem[$A000:b],320);
        end;
    end; { procedure slideUp }

  begin { procedure pan }
    x:=0; y:=0; done:=false;
    repeat
      ch:=readkey;
      if ch=#0 then
        case readkey of
          #75: if scaleWidth>320 then slideRight;
          #77: if scaleWidth>320 then slideLeft;
          #72: if scaleHeight>200 then slideDown;
          #80: if scaleHeight>200 then slideUp;
        end
      else
        case ch of
          #27: done:=True;
        end;
    until done;
  end; { procedure pan }

begin
 AddrGetByte:=@GetByte;
 AddrPutByte:=@PutByte;
 AssignCrt(output);Rewrite(OUTPUT);
 if paramcount=0
  then begin
        write('Enter GIF file name:  '); readln(infilename);
       end
  else InFileName:=paramstr(1);
 if length(InFileName)>0 then
  begin
   if pos('.',infilename)=0 then infilename:=infilename+'.gif';
   assign(InFile,InFileName);
   {$I-}
   reset(InFile,1);
   if ioresult<>0
    then begin writeln('GIF datafile could not be found.'); halt; end;
   SkipIt:=false;
   EOFin:=false;
   Done:=false;
   BufIndx:=999;Count:=0;
   CurMap:=Global;
   GetGIFSig;
   if GIFSig<>'GIF87a' then
     begin
       BufIndx:=128;
       GetGIFSig;
       if GIFSig<>'GIF87a' then
         begin
           writeln('Invalid GIF signature');
           Halt;
         end;
     end;
   GetScrDes;
   DisplayScrDes;
   if MapExists[Global] then GetColorMap;
   writeln('Press <Enter> to display and wait for beep');
   writeln('before scrolling image with arrow keys');
   readln;
   GraphColorMode;
   while not Done Do
    begin
     BlockType:=chr(GetByte);
     case BlockType of
      ',':begin
           GetImageDescription;
           AdjustImage;
           if MapExists[Local]
            then begin CurMap:=Local; GetColorMap; DoMapping end
            else CurMap:=Global;
           if ExpandGIF <>0 then Halt
          end;
      '!':SkipExtendBlock;
     end;
    end;
  end;
 Sound(1000);Delay(100);NoSound;
 pan;
 textmode(lastmode);
end.
