home *** CD-ROM | disk | FTP | other *** search
/ Monster Media 1994 #1 / monster.zip / monster / BBS_GAME / LOD400G.ZIP / GETBIG.PAS < prev    next >
Pascal/Delphi Source File  |  1993-09-07  |  20KB  |  742 lines

  1. program gifslow;
  2.  
  3. uses crt,dos,graph;
  4.  
  5. type
  6.  
  7.     RasterArray = Array [0..63999] of byte;
  8.     RasterP = ^RasterArray;
  9.     imagetype= array[1..11138] of byte;
  10.  
  11. var
  12.     ofsx,ofsy: word;
  13.     tx,ty: word;
  14.     m1,m2,m3,m4: word;
  15.     cursorx,cursory: word;
  16.     cursorimg: imagetype;
  17.     tempimg: imagetype;
  18.  
  19.     GifFile:File of RasterArray;  {The input file}
  20.     GifStuff:RasterP;   {The heap array to hold it, raw}
  21.     Raster:RasterP;     {The raster data stream, unblocked}
  22.     Raster2:RasterP;    {More raster data stream if needed}
  23.     Regs:Registers;     {Turbo's predefined record}
  24.  
  25.     Byteoffset,         {Computed byte position in RASTER array}
  26.     Bitoffset           {Bit offset of next code in RASTER array}
  27.     :LongInt;
  28.  
  29.     Width,      {Read from GIF header, image width}
  30.     Height,     { ditto, image height}
  31.     LeftOfs,    { ditto, image offset from left}
  32.     TopOfs,     { ditto, image offset from top}
  33.     RWidth,     { ditto, raster width}
  34.     RHeight,    { ditto, raster height}
  35.     ClearCode,  {GIF clear code}
  36.     EOFCode,    {GIF end-of-information code}
  37.     OutCount,   {Decompressor output 'stack count'}
  38.     MaxCode,    {Decompressor limiting value for current code size}
  39.     Code,       {Value returned by ReadCode}
  40.     CurCode,    {Decompressor variable}
  41.     OldCode,    {Decompressor variable}
  42.     InCode,     {Decompressor variable}
  43.     FirstFree,  {First free code, generated per GIF spec}
  44.     FreeCode,   {Decompressor, next free slot in hash table}
  45.     GIFPtr,     {Array pointers used during file read}
  46.     RasterPtr,
  47.     XC,YC,      {Screen X and Y coords of current pixel}
  48.     Pindex,     {Index into screen save array}
  49.     ReadMask,   {Code AND mask for current code size}
  50.     I           {Loop counter, what else?}
  51.     :word;
  52.  
  53.  
  54.     Interlace,  {True if interlaced image}
  55.     NextRaster, {True if file > 64000 bytes}
  56.     ColorMap    {True if colormap present}
  57.     :Boolean;
  58.  
  59.     ch           {Utility}
  60.     :char;
  61.  
  62.     a,              {Utility}
  63.     Resolution,     {Resolution, read from GIF header}
  64.     BitsPerPixel,   {Bits per pixel, read from GIF header}
  65.     Background,     {Background color, read from GIF header}
  66.     ColorMapSize,   {Length of color map, from GIF header}
  67.     CodeSize,       {Code size, read from GIF header}
  68.     InitCodeSize,   {Starting code size, used during Clear}
  69.     FinChar,        {Decompressor variable}
  70.     Pass,           {Used by video output if interlaced pic}
  71.     BitMask,        {AND mask for data size}
  72.     R,G,B
  73.     :byte;
  74.  
  75.  
  76.     {The hash table used by the decompressor}
  77.     Prefix: Array [0..4095] of word;
  78.     Suffix: Array [0..4095] of byte;
  79.  
  80.     {An output array used by the decompressor}
  81.     Outcode:Array [0..1024] of byte;
  82.  
  83.     {The color map, read from the GIF header}
  84.     Red,Green,Blue: array [0..255] of byte;
  85.  
  86.     {The EGA palette, derived from the color map}
  87.     Palette: Array [0..255] of byte;
  88.  
  89.     {Strings to hold the filenames}
  90.     FileString:String [80];
  91.  
  92.     outpf: text;
  93.  
  94.  
  95. Const
  96.  
  97.     MaxCodes: Array [0..9] of Word = (4,8,16,$20,$40,$80,$100,$200,$400,$800);
  98.  
  99.     CodeMask:Array [1..4] of byte= (1,3,7,15);
  100.  
  101.     PowersOf2: Array [0..8] of word=(1,2,4,8,16,32,64,128,256);
  102.  
  103.     Masks: Array [0..9] of Integer = (7,15,$1f,$3f,$7f,$ff,$1ff,$3ff,$7ff,$fff);
  104.  
  105.     Rastersize:Word = 64000;
  106.  
  107.  
  108. procedure SaveImage(x,y: word);
  109. var
  110.  imagefile: file of imagetype;
  111. begin;
  112.  setcolor(lightblue);
  113.  line(x,y,x,y+120);
  114.  line(x,y,x+180,y);
  115.  line(x,y+120,x+180,y+120);
  116.  line(x+180,y,x+180,y+120);
  117.  getimage(x,y,x+180,y+120,tempimg);
  118.  
  119.  assign(imagefile,'GETBIG.DAT');
  120.  rewrite(imagefile);
  121.  seek(imagefile,filesize(imagefile));
  122.  write(imagefile,tempimg);
  123.  close(imagefile);
  124. end;
  125.  
  126. Procedure AllocMem (Var P:RasterP);
  127. Var
  128.  ASize:Longint;
  129. Begin
  130.      ASize:=MaxAvail;
  131.      If ASize<RasterSize then
  132.         Begin
  133.              Textmode (15);
  134.              Writeln ('Insufficient memory available!');
  135.              Halt;
  136.         End
  137.         Else
  138.         Getmem (P,RasterSize);
  139. End;
  140.  
  141.  
  142. Function Getbyte:Byte;
  143. Begin
  144.  If GIFPtr=RasterSize then Exit;
  145.  Getbyte:=GIFStuff^[GIFPtr];
  146.  GIFPtr:=Succ(GIFPtr);
  147. End;
  148.  
  149.  
  150. Function Getword:Word;
  151. Var
  152.  A,B:Byte;
  153. Begin
  154.  A:=Getbyte;
  155.  B:=Getbyte;
  156.  Getword:=A+(256*B);
  157. End;
  158.  
  159. Procedure ReadRaster;
  160.  
  161. Var BlockLength:Byte;
  162.     I,IOR:Integer;
  163.  
  164. Begin
  165.    RasterPtr:=0;
  166.    Repeat
  167.    BlockLength:=Getbyte;
  168.      For I:=0 to Blocklength-1 do
  169.        Begin
  170.          If Gifptr = RasterSize then
  171.             Begin
  172.                  {$I-}
  173.                  Read (GIFFile,GIFStuff^);
  174.                  {$I+}
  175.                  IOR:=IOResult;
  176.                  GIFPtr:=0;
  177.             End;
  178.          If not Nextraster then
  179.                   Raster^[RasterPtr]:=Getbyte else
  180.                          Raster2^[RasterPtr]:=Getbyte;
  181.          RasterPtr:=Succ (RasterPtr);
  182.          If RasterPtr=RasterSize then
  183.          Begin
  184.             NextRaster:=True;
  185.             Rasterptr:=0;
  186.             AllocMem (Raster2);
  187.          End;
  188.        End;
  189.    Until Blocklength=0;
  190. End;
  191.  
  192.  
  193. {Fetch the next code from the raster data stream. The codes can be any
  194. length from 3 to 12 bits, packed into 8-bit bytes, so we have to maintain
  195. our location in the Raster array as a BIT offset. We compute the byte offset
  196. into the raster array by dividing this by 8, pick up three bytes, compute
  197. the bit offset into our 24-bit chunk, shift to bring the desired code to
  198. the bottom, then mask it off and return it. If the unblocked raster data
  199. overflows the original RASTER array, we switch to the second one}
  200.  
  201. Procedure ReadCode;
  202.  
  203. Var RawCode:LongInt;
  204.     A,B:Word;
  205.  
  206.  
  207. Begin
  208.      ByteOffset:=BitOffset div 8;
  209.  
  210. {Pick up our 24-bit chunk}
  211.  
  212.      A:=Raster^[Byteoffset]+(256*Raster^[ByteOffset+1]);
  213.      If CodeSize>=8 then
  214.      Begin
  215.      B:=Raster^[Byteoffset+2];
  216.      RawCode:=A+(65536*B);
  217.      End
  218.      Else Rawcode:=A;
  219.  
  220. {Doing the above calculation as a single statement, i.e.
  221. Rawcode:=Raster^[Byteoffset]+(256*Raster^[Byteoffset+1])+
  222.          (65536*Raster[Byteoffset+2])
  223. sometimes returns incorrect results. This may or may not be a bug.}
  224.  
  225.  
  226.      RawCode:=RawCode shr (BitOffset mod 8);
  227.      Code:=RawCode and ReadMask;
  228.  
  229. {Cope with overflow of the first RASTER array}
  230.  
  231.      If (Nextraster) and (Byteoffset>=63000) then
  232.         Begin
  233.              Move (Raster^[Byteoffset],Raster^[0],RasterSize-Byteoffset);
  234.              Move (Raster2^[0],Raster^[RasterSize-Byteoffset],63000);
  235.              Bitoffset:=Bitoffset mod 8;
  236.              FreeMem (Raster2,RasterSize);
  237.         End;
  238.  
  239.      BitOffset:=BitOffset+CodeSize;
  240.  
  241. End;
  242.  
  243.  
  244. Procedure AddToPixel (Index:Byte);
  245.  
  246.  
  247. Begin
  248.      putpixel(xc,yc,index);
  249. {     Regs.AH:=12;
  250.      Regs.AL:=Index;
  251.      Regs.CX:=XC;
  252.      Regs.DX:=YC;
  253.      Intr ($10,Regs);}
  254.  
  255. {Update the X-coordinate, and if it overflows, update the Y-coordinate}
  256.  
  257.      XC:=Succ (XC);
  258.      If XC=Width then
  259.  
  260. {If a non-interlaced picture, just increment YC to the next scan line. If
  261. it's interlaced, deal with the interlace as described in the GIF spec. Put
  262. the decoded scan line out to the screen if we haven't gone past the bottom
  263. of it}
  264.  
  265.         Begin
  266.  
  267.         XC:=0;
  268.         If not Interlace then YC:=Succ (YC) else
  269.             Begin
  270.                Case Pass of
  271.                0: Begin
  272.                   YC:=YC+8;
  273.                   If YC>=Height then
  274.                   Begin
  275.                      Pass:=Succ(Pass);
  276.                      YC:=4;
  277.                   End;
  278.                   End;
  279.                1: Begin
  280.                   YC:=YC+8;
  281.                   If YC>=Height then
  282.                      Begin
  283.                        Pass:=Succ(Pass);
  284.                        YC:=2;
  285.                      End;
  286.                   End;
  287.                2: Begin
  288.                   YC:=YC+4;
  289.                   If YC>=Height then
  290.                      Begin
  291.                           Pass:=Succ(Pass);
  292.                           YC:=1;
  293.                      End;
  294.                   End;
  295.                3: Begin
  296.                   YC:=YC+2;
  297.                   End;
  298.                End;    {Case}
  299.             End;  {If interlace}
  300.         End;
  301.  
  302. End;
  303.  
  304. Procedure InitEGA;
  305. var
  306.  grdriver,grmode: integer;
  307.  a,b,c: integer;
  308.  pal2: palettetype;
  309.  p: word;
  310. Begin
  311.  grdriver:=ega;
  312.  grmode:=egahi;
  313.  initgraph(grdriver,grmode,'');
  314.  getpalette(pal2);
  315.  {for a:=0 to 15 do setpalette(a,palette[a]);
  316.  for a:=0 to 15 do begin;
  317.   c:=0;
  318.   for b:=0 to 15 do if pal2.colors[b]=palette[a] then c:=b;
  319.   if c<>0 then begin; write(^g); delay(1000); end;
  320.   if c<>0 then setpalette(a,pal2.colors[c]);
  321.  end;}
  322.  
  323.  setfillstyle(1,7);
  324.  floodfill(1,1,1);
  325.  getimage(0,0,180,120,cursorimg);
  326. End;
  327.  
  328. procedure translate;
  329. var
  330.  a,b,c: word;
  331.  p: byte;
  332.  pal2: palettetype;
  333.  trans: array[0..15] of byte;
  334. begin;
  335.  getpalette(pal2);
  336.  for a:=0 to 15 do begin;
  337.   trans[a]:=a;
  338.   c:=0;
  339.   for b:=0 to 15 do if pal2.colors[b]=palette[a] then c:=b;
  340.   if c<>0 then trans[a]:=c;
  341.  end;
  342. { trans[lightcyan]:=14;
  343.  trans[crt.lightblue]:=magenta;
  344.  trans[yellow]:=lightcyan;}
  345. { trans[lightblue]:=4;
  346.  trans[lightcyan]:=14;
  347.  trans[3]:=lightcyan;}
  348.  for a:=0 to 180 do for b:=0 to 120 do begin;
  349.   p:=trans[getpixel(a,b)];
  350.   putpixel(a,b,p);
  351.  end;
  352. end;
  353.  
  354.  
  355. {Determine the palette value corresponding to the GIF colormap intensity
  356. value.}
  357.  
  358. Procedure DetColor (Var PValue:Byte;MapValue:Byte);
  359.  
  360. Var Local:Byte;
  361.  
  362. Begin
  363.      PValue:=MapValue div 64;
  364.      If PValue=1 then PValue:=2 else
  365.      If PValue=2 then PValue:=1;
  366. End;
  367.  
  368. {Set the key variables to
  369. their necessary initial values.}
  370.  
  371. Procedure ReInitialize;
  372. Begin
  373.      XC:=0;          {X and Y screen coords back to home}
  374.      YC:=0;
  375.      Pass:=0;        {Interlace pass counter back to 0}
  376.      Bitoffset:=0;   {Point to the start of the raster data stream}
  377.      GIFPtr:=0;      {Mock file read pointer back to 0}
  378. End;
  379.  
  380. {React to GIF clear code, or reset GIF decompression values back to their
  381. initial state when restarting.}
  382.  
  383. Procedure DoClear;
  384.  
  385.     Begin
  386.       CodeSize:=InitCodeSize;
  387.       MaxCode:=MaxCodes [CodeSize-2];
  388.       FreeCode:=FirstFree;
  389.       ReadMask:=Masks [CodeSize-3];
  390.     End;
  391.  
  392. procedure mouse(var m1,m2,m3,m4: word);
  393. var
  394.  regs: registers;
  395. begin;
  396.  regs.ax:=m1;
  397.  regs.bx:=m2;
  398.  regs.cx:=m3;
  399.  regs.dx:=m4;
  400.  intr(51,regs);
  401.  m1:=regs.ax;
  402.  m2:=regs.bx;
  403.  m3:=regs.cx;
  404.  m4:=regs.dx;
  405. end;
  406.  
  407. procedure clear_mouse;
  408. begin;
  409.  repeat;
  410.   m1:=3;
  411.   mouse(m1,m2,m3,m4);
  412.  until ((m2 and 1)=0);
  413. end;
  414.  
  415. procedure show_cursor;
  416. begin;
  417.  m1:=1; mouse(m1,m2,m3,m4);
  418. end;
  419.  
  420. procedure hide_cursor;
  421. begin;
  422.  m1:=2; mouse(m1,m2,m3,m4);
  423. end;
  424.  
  425. procedure init_mouse;
  426. begin;
  427.  m1:=0; mouse(m1,m2,m3,m4);
  428. end;
  429.  
  430. procedure getmouse(var x,y: word);
  431. begin;
  432.  m1:=3; mouse(m1,m2,m3,m4);
  433.  x:=m3;
  434.  y:=m4;
  435. end;
  436.  
  437. Begin    {the main program}
  438.  
  439. {Initialize a bunch of variables}
  440.  
  441.      ReInitialize;         {Initialize common vars}
  442.      Nextraster:=False;    {Over 64000 flag off}
  443.  
  444. {Get memory for the raster data array, and the input file data array}
  445.  
  446.      AllocMem (Raster);
  447.      AllocMem (GIFStuff);
  448.  
  449. {Prompt the user for the filename}
  450.  
  451.      writeln('A mouse driver must be used with this program.');
  452.      writeln('Captured image will be written to GETBIG.DAT.');
  453.      writeln('Press [space] to capture, [ESC] to quit, and mouse or 8/4/6/2 to move');
  454.      writeln;
  455.      Write ('Input Filename (.GIF File in 640x350x16 res): ');
  456.      Readln (Filestring);
  457.  
  458.  
  459. {Open the file}
  460.  
  461. {$I-}
  462.      Assign (giffile,FileString);
  463.      Reset (giffile);
  464. {$I+}
  465.  
  466. {Cope with I/O error should one occur}
  467.  
  468.      I:=IOResult;
  469.      If I<>0 then
  470.         Begin
  471.              Writeln ('Error opening file ',FileString,'. Press any key ');
  472.              Readln;
  473.              Exit;
  474.         End;
  475.  
  476. {Read in the GIF file. Reading it as one big hunk rather than N bytes results
  477. in far faster disk I/O; see user notes. Error checking is turned off in
  478. order to avoid 'attempt to read past EOF' errors. If the file does not exist,
  479. this will be detected at RESET}
  480.  
  481.      Writeln ('Reading . . . ');
  482. {$I-}
  483.      Read (GIFFile,GIFStuff^);
  484. {$I+}
  485.  
  486. {Note that 4.0 requires this assignment, or else if an error results (as it
  487. will if the file is smaller than 64000 bytes) no I/O will be allowed for
  488. the remainder of the run}
  489.  
  490. I:=IOResult;
  491.  
  492. {Deal with the GIF header. Start by checking the GIF tag to make sure this
  493. is a GIF file}
  494.  
  495.      FileString:='';
  496.      for i:=1 to 6 do
  497.      Begin
  498.          FileString:=FileString+chr(Getbyte);
  499.      End;
  500.      If FileString<>'GIF87a' then
  501.         Begin
  502.              Writeln ('Not a GIF file, or header read error. Press any key ');
  503.              Readln;
  504.              Exit;
  505.         End;
  506.  
  507. {Get variables from the GIF screen descriptor}
  508.  
  509.      RWidth:=Getword;         {The raster width and height}
  510.      RHeight:=Getword;
  511.      {Get the packed byte immediately following and decode it}
  512.      B:=Getbyte;
  513.      If B and $80=$80 then Colormap:=True else Colormap:=False;
  514.      Resolution:=B and $70 shr 5 +1;
  515.      BitsPerPixel:=B and 7 +1;
  516.      If BitsPerPixel=1 then I:=2 else I:=1 shl BitsPerPixel;
  517.      Write ('Colors: ',I);
  518.      BitMask:=CodeMask [BitsPerPixel];
  519.      Background:=Getbyte;
  520.      B:=Getbyte;         {Skip byte of 0's}
  521.  
  522. {Compute size of colormap, and read in the global one if there. Compute
  523. values to be used when we set up the EGA palette}
  524.  
  525.      ColorMapSize:=1 shl BitsPerPixel;
  526.      If Colormap then Begin
  527.       assign(outpf,'PAL.TXT');
  528.       rewrite(outpf);
  529.       For I:=0 to ColorMapSize-1 do Begin
  530.          Red [I]:=Getbyte;
  531.          Green [I]:=Getbyte;
  532.          Blue [I]:=Getbyte;
  533.          DetColor (R,Red[I]);
  534.          DetColor (G,Green [I]);
  535.          DetColor (B,Blue [I]);
  536.          writeln(outpf,i,' ',r,' ',g,' ',b);
  537.          Palette [I]:=B and 1+(2*(G and 1))+(4*(R and 1))+(8*(B div 2))+(16*(G div 2))+(32*(R div 2));
  538.       End;
  539.       close(outpf);
  540.       Writeln;
  541.       Palette [16]:=Background;
  542.      End;
  543.  
  544. {Now read in values from the image descriptor}
  545.  
  546.      B:=Getbyte;  {skip image seperator}
  547.      Leftofs:=Getword;
  548.      Topofs:=Getword;
  549.      Width:=Getword;
  550.      Writeln ('Width: ',Width);
  551.      Height:=Getword;
  552.      Writeln ('Height: ',Height);
  553.      A:=Getbyte;
  554.      If A and $40=$40 then Interlace:=True else Interlace:=False;
  555.  
  556.  
  557. {Note that we ignore the possible existence of a local color map. I've yet
  558. to encounter an image that had one, and the spec says it's defined for
  559. future use. This could lead to an error reading some files}
  560.  
  561. {Start reading the raster data. First we get the intial code size}
  562.  
  563.      Codesize:=Getbyte;
  564.  
  565. {Compute decompressor constant values, based on the code size}
  566.  
  567.      ClearCode:=PowersOf2 [Codesize];
  568.      EOFCode:=ClearCode+1;
  569.      FirstFree:=ClearCode+2;
  570.      FreeCode:=FirstFree;
  571.  
  572. {The GIF spec has it that the code size is the code size used to compute the
  573. above values is the code size given in the file, but the code size used in
  574. compression/decompression is the code size given in the file plus one.}
  575.  
  576.      Codesize:=Succ (Codesize);
  577.      InitCodeSize:=Codesize;
  578.      Maxcode:=Maxcodes [Codesize-2];
  579.      ReadMask:=Masks [Codesize-3];
  580.  
  581. {Read the raster data. Here we just transpose it from the GIF array to the
  582. Raster array, turning it from a series of blocks into one long data stream,
  583. which makes life much easier for ReadCode}
  584.  
  585.      Writeln ('Unblocking');
  586.      ReadRaster;
  587.  
  588. {Get ready to do the actual read/display. Free up the heap used by the
  589. GIF array since we don't need it any more, and if the user wants to save,
  590. reclaim it for the Picture array}
  591.  
  592.      FreeMem (GIFStuff,RasterSize);
  593.      OutCount:=0;
  594.  
  595. {Set up the EGA}
  596.  
  597.      InitEGA;
  598.  
  599. {Decompress the file, continuing until you see the GIF EOF code. One
  600. obvious enhancement is to add checking for corrupt files here.}
  601.  
  602.    Repeat
  603.  
  604.      {Get the next code from the raster array}
  605.  
  606.           ReadCode;
  607.  
  608.           If Code <> EOFCode then
  609.           Begin
  610.  
  611.      {Clear code sets everything back to its initial value, then reads
  612.       the immediately subsequent code as uncompressed data.}
  613.  
  614.             If Code = ClearCode then
  615.                Begin
  616.                  DoClear;
  617.                  ReadCode;
  618.                  CurCode:=Code;
  619.                  OldCode:=Code;
  620.                  FinChar:=Code and BitMask;
  621.                  AddToPixel (FinChar);
  622.                End
  623.                Else
  624.  
  625.      {If not a clear code, then must be data: save same as CurCode and InCode}
  626.  
  627.                Begin
  628.                 CurCode:=Code;
  629.                 InCode:=Code;
  630.  
  631.      {If greater or equal to FreeCode, not in the hash table yet; repeat
  632.       the last character decoded}
  633.  
  634.                 If Code>=FreeCode then
  635.                   Begin
  636.                     CurCode:=OldCode;
  637.                     OutCode [OutCount]:=FinChar;
  638.                     OutCount:=Succ (OutCount);
  639.                   End;
  640.  
  641.      {Unless this code is raw data, pursue the chain pointed to by CurCode
  642.      through the hash table to its end; each code in the chain puts its
  643.      associated output code on the output queue.}
  644.  
  645.                 If CurCode>BitMask then
  646.                    Repeat
  647.                      OutCode [OutCount]:=Suffix [CurCode];
  648.                      OutCount:=Succ (OutCount);
  649.                      CurCode:=Prefix [CurCode];
  650.                    Until CurCode<=BitMask;
  651.  
  652.       {The last code in the chain is treated as raw data.}
  653.  
  654.                FinChar:=CurCode and BitMask;
  655.                OutCode [OutCount]:=FinChar;
  656.                OutCount:=Succ (OutCount);
  657.  
  658.      {Now we put the data out to the using routine. It's been stacked
  659.       LIFO, so deal with it that way}
  660.  
  661.                For I:=OutCount-1 downto 0 do
  662.                     AddToPixel (Outcode [I]);
  663.  
  664.       {Make darned sure OutCount gets set back to start}
  665.  
  666.                OutCount:=0;
  667.  
  668.       {Build the hash table on-the-fly. No table is stored in the file.}
  669.  
  670.                Prefix [FreeCode]:=OldCode;
  671.                Suffix [FreeCode]:=FinChar;
  672.                OldCode:=InCode;
  673.  
  674.      {Point to the next slot in the table. If we exceed the current MaxCode
  675.       value, increment the code size unless it's already 12. If it is, do
  676.       nothing: the next code decompressed better be CLEAR}
  677.  
  678.                FreeCode:=Succ (FreeCode);
  679.                If FreeCode>=MaxCode then
  680.                 Begin
  681.                   If CodeSize < 12 then
  682.                   Begin
  683.                      CodeSize:=Succ (CodeSize);
  684.                      MaxCode:=MaxCode*2;
  685.                      ReadMask:=Masks [CodeSize-3];
  686.                   End;
  687.                 End;
  688.                End {not Clear};
  689.  
  690.                If Keypressed then
  691.                   Begin
  692.                        Ch:=Readkey;
  693.                        If Ch=#27 then
  694.                           Begin
  695.                                Textmode (15);
  696.                                Exit;
  697.                           End;
  698.                   End;
  699.             End; {not EOFCode}
  700.        Until Code=EOFCode;
  701.  
  702.        Writeln (^G); {signals whole picture decoded}
  703.  
  704.     {Read one key, then pack it in}
  705.  
  706.  
  707.     init_mouse;
  708.     hide_cursor;
  709.     cursorx:=0;
  710.     cursory:=0;
  711.     ofsx:=0;
  712.     ofsy:=0;
  713.     ch:=' ';
  714.     repeat;
  715.      putimage(cursorx+ofsx,cursory+ofsy,cursorimg,xorput);
  716.      getmouse(tx,ty);
  717.      while (tx=cursorx) and (ty=cursory) and (not keypressed) do getmouse(tx,ty);
  718.      putimage(cursorx+ofsx,cursory+ofsy,cursorimg,xorput);
  719.      getmouse(cursorx,cursory);
  720.      if keypressed then begin;
  721.       ch:=readkey;
  722.       case ch of
  723.        'T': translate;
  724.        '6': inc(ofsx);
  725.        '4': dec(ofsx);
  726.        '8': dec(ofsy);
  727.        '2': inc(ofsy);
  728.        ' ': begin;
  729.              write(^G);
  730.              saveimage(cursorx+ofsx,cursory+ofsy);
  731.             end;
  732.       end;
  733.      end;
  734.     until ch=#27;
  735.     cursorx:=imagesize(0,0,180,120);
  736.     restorecrtmode;
  737.     writeln(cursorx);
  738.     Close (GifFile);
  739.     FreeMem (Raster,RasterSize);
  740. End.
  741.  
  742.