home *** CD-ROM | disk | FTP | other *** search
/ Chip 2001 September / Chip_2001-09_cd1.bin / zkuste / delphi / kolekce / d6 / RX275D6.ZIP / Units / ANIFILE.PAS next >
Pascal/Delphi Source File  |  2001-06-24  |  19KB  |  669 lines

  1. {*******************************************************}
  2. {                                                       }
  3. {         Delphi VCL Extensions (RX)                    }
  4. {                                                       }
  5. {         Copyright (c) 1997, 1998 Master-Bank          }
  6. {                                                       }
  7. {*******************************************************}
  8.  
  9. unit AniFile;
  10.  
  11. {$I RX.INC}
  12.  
  13. interface
  14.  
  15. uses SysUtils, Windows, RTLConsts, Classes, Graphics;
  16.  
  17. type
  18.   TFourCC = array[0..3] of Char;
  19.  
  20.   PAniTag = ^TAniTag;
  21.   TAniTag = packed record
  22.     ckID: TFourCC;
  23.     ckSize: Longint;
  24.   end;
  25.  
  26.   TAniHeader = packed record
  27.     cbSizeOf: Longint;
  28.     cSteps: Longint;
  29.     cFrames: Longint;
  30.     cReserved: array[0..3] of Longint;
  31.     jifRate: Longint; { 1 Jiffy = 1/60 sec }
  32.     fl: Longint;
  33.   end;
  34.  
  35. const
  36.   AF_ICON     = $00000001;
  37.   AF_SEQUENCE = $00000002;
  38.  
  39. { TIconFrame }
  40.  
  41. type
  42.   TIconFrame = class(TPersistent)
  43.   private
  44.     FIcon: TIcon;
  45.     FIsIcon: Boolean;
  46.     FTag: TAniTag;
  47.     FHotSpot: TPoint;
  48.     FJiffRate: Longint;
  49.     FSeq: Integer;
  50.   public
  51.     constructor Create(Index: Integer; Jiff: Longint);
  52.     destructor Destroy; override;
  53.     procedure Assign(Source: TPersistent); override;
  54.     property JiffRate: Longint read FJiffRate;
  55.     property Seq: Integer read FSeq;
  56.   end;
  57.  
  58. { TAnimatedCursorImage }
  59.  
  60.   TANINAME = array[0..255] of Char;
  61.  
  62.   TAnimatedCursorImage = class(TPersistent)
  63.   private
  64.     FHeader: TAniHeader;
  65.     FTitle: TANINAME;
  66.     FCreator: TANINAME;
  67.     FIcons: TList;
  68.     FOriginalColors: Word;
  69.     procedure NewImage;
  70.     procedure RiffReadError;
  71.     function ReadCreateIcon(Stream: TStream; ASize: Longint;
  72.       var HotSpot: TPoint; var IsIcon: Boolean): TIcon;
  73.     function GetIconCount: Integer;
  74.     function GetIcon(Index: Integer): TIcon;
  75.     function GetFrame(Index: Integer): TIconFrame;
  76.     function GetTitle: string;
  77.     function GetCreator: string;
  78.     function GetDefaultRate: Longint;
  79.     procedure ReadAniStream(Stream: TStream);
  80.     procedure ReadStream(Size: Longint; Stream: TStream);
  81.     procedure WriteStream(Stream: TStream; WriteSize: Boolean);
  82.   protected
  83.     procedure AssignTo(Dest: TPersistent); override;
  84.     procedure Draw(ACanvas: TCanvas; const ARect: TRect);
  85.   public
  86.     constructor Create;
  87.     destructor Destroy; override;
  88.     procedure Assign(Source: TPersistent); override;
  89.     procedure Clear;
  90.     procedure LoadFromStream(Stream: TStream); virtual;
  91.     procedure SaveToStream(Stream: TStream); virtual;
  92.     procedure LoadFromFile(const Filename: string); virtual;
  93.     procedure AssignToBitmap(Bitmap: TBitmap; BackColor: TColor;
  94.       DecreaseColors, Vertical: Boolean);
  95.     property DefaultRate: Longint read GetDefaultRate;
  96.     property IconCount: Integer read GetIconCount;
  97.     property Icons[Index: Integer]: TIcon read GetIcon;
  98.     property Frames[Index: Integer]: TIconFrame read GetFrame;
  99.     property Title: string read GetTitle;
  100.     property Creator: string read GetCreator;
  101.     property OriginalColors: Word read FOriginalColors;
  102.   end;
  103.  
  104. implementation
  105.  
  106. { This implementation based on animated cursor editor source code
  107.   (ANIEDIT.C, copyright (C) Microsoft Corp., 1993-1996) }
  108.  
  109. uses Consts, VCLUtils, MaxMin, RxGraph, IcoList, ClipIcon;
  110.  
  111. const
  112.   FOURCC_ACON = 'ACON';
  113.   FOURCC_RIFF = 'RIFF';
  114.   FOURCC_INFO = 'INFO';
  115.   FOURCC_INAM = 'INAM';
  116.   FOURCC_IART = 'IART';
  117.   FOURCC_LIST = 'LIST';
  118.   FOURCC_anih = 'anih';
  119.   FOURCC_rate = 'rate';
  120.   FOURCC_seq  = 'seq ';
  121.   FOURCC_fram = 'fram';
  122.   FOURCC_icon = 'icon';
  123.  
  124. function PadUp(Value: Longint): Longint;
  125.   { Up Value to nearest word boundary }
  126. begin
  127.   Result := Value + (Value mod 2);
  128. end;
  129.  
  130. procedure DecreaseBMPColors(Bmp: TBitmap; Colors: Integer);
  131. var
  132.   Stream: TStream;
  133. begin
  134.   if (Bmp <> nil) and (Colors > 0) then begin
  135.     Stream := BitmapToMemory(Bmp, Colors);
  136.     try
  137.       Bmp.LoadFromStream(Stream);
  138.     finally
  139.       Stream.Free;
  140.     end;
  141.   end;
  142. end;
  143.  
  144. function GetDInColors(BitCount: Word): Integer;
  145. begin
  146.   case BitCount of
  147.     1, 4, 8: Result := 1 shl BitCount;
  148.     else Result := 0;
  149.   end;
  150. end;
  151.  
  152. { ReadTag, ReadChunk, SkipChunk. Some handy functions for reading RIFF files. }
  153.  
  154. function ReadTag(S: TStream; pTag: PAniTag): Boolean;
  155. begin
  156.   pTag^.ckID := #0#0#0#0;
  157.   pTag^.ckSize := 0;
  158.   Result := S.Read(pTag^, SizeOf(TAniTag)) = SizeOf(TAniTag);
  159. end;
  160.  
  161. function ReadChunk(S: TStream; pTag: PAniTag; Data: Pointer): Boolean;
  162. begin
  163.   Result := S.Read(Data^, pTag^.ckSize) = pTag^.ckSize;
  164.   if Result then
  165.     Result := S.Seek(pTag^.ckSize mod 2, soFromCurrent) <> -1;
  166. end;
  167.  
  168. function ReadChunkN(S: TStream; pTag: PAniTag; Data: Pointer;
  169.   cbMax: Longint): Boolean;
  170. var
  171.   cbRead: Longint;
  172. begin
  173.   cbRead := pTag^.ckSize;
  174.   if cbMax < cbRead then cbRead := cbMax;
  175.   Result := S.Read(Data^, cbRead) = cbRead;
  176.   if Result then begin
  177.     cbRead := PadUp(pTag^.ckSize) - cbRead;
  178.     Result := S.Seek(cbRead, soFromCurrent) <> -1;
  179.   end;
  180. end;
  181.  
  182. function SkipChunk(S: TStream; pTag: PAniTag): Boolean;
  183. begin
  184.   { Round pTag^.ckSize up to nearest word boundary to maintain alignment }
  185.   Result := S.Seek(PadUp(pTag^.ckSize), soFromCurrent) <> -1;
  186. end;
  187.  
  188. { Icon and cursor types }
  189.  
  190. const
  191.   rc3_StockIcon = 0;
  192.   rc3_Icon = 1;
  193.   rc3_Cursor = 2;
  194.  
  195. type
  196.   PCursorOrIcon = ^TCursorOrIcon;
  197.   TCursorOrIcon = packed record
  198.     Reserved: Word;
  199.     wType: Word;
  200.     Count: Word;
  201.   end;
  202.  
  203.   PIconRec = ^TIconRec;
  204.   TIconRec = packed record
  205.     Width: Byte;
  206.     Height: Byte;
  207.     Colors: Word;
  208.     xHotspot: Word;
  209.     yHotspot: Word;
  210.     DIBSize: Longint;
  211.     DIBOffset: Longint;
  212.   end;
  213.  
  214. { TIconFrame }
  215.  
  216. constructor TIconFrame.Create(Index: Integer; Jiff: Longint);
  217. begin
  218.   inherited Create;
  219.   FSeq := Index;
  220.   FJiffRate := Jiff;
  221. end;
  222.  
  223. destructor TIconFrame.Destroy;
  224. begin
  225.   if FIcon <> nil then FIcon.Free;
  226.   inherited Destroy;
  227. end;
  228.  
  229. procedure TIconFrame.Assign(Source: TPersistent);
  230. begin
  231.   if Source is TIconFrame then begin
  232.     with TIconFrame(Source) do begin
  233.       if Self.FIcon = nil then Self.FIcon := TIcon.Create;
  234.       Self.FIcon.Assign(FIcon);
  235.       Self.FIsIcon := FIsIcon;
  236.       Move(FTag, Self.FTag, SizeOf(TAniTag));
  237.       Self.FHotSpot.X := FHotSpot.X;
  238.       Self.FHotSpot.Y := FHotSpot.Y;
  239.       Self.FJiffRate := FJiffRate;
  240.       Self.FSeq := FSeq;
  241.     end;
  242.   end
  243.   else inherited Assign(Source);
  244. end;
  245.  
  246. { TAnimatedCursorImage }
  247.  
  248. constructor TAnimatedCursorImage.Create;
  249. begin
  250.   inherited Create;
  251.   FIcons := TList.Create;
  252. end;
  253.  
  254. destructor TAnimatedCursorImage.Destroy;
  255. begin
  256.   NewImage;
  257.   FIcons.Free;
  258.   inherited Destroy;
  259. end;
  260.  
  261. procedure TAnimatedCursorImage.Clear;
  262. begin
  263.   NewImage;
  264. end;
  265.  
  266. procedure TAnimatedCursorImage.NewImage;
  267. var
  268.   I: Integer;
  269. begin
  270.   for I := 0 to FIcons.Count - 1 do TIconFrame(FIcons[I]).Free;
  271.   FIcons.Clear;
  272.   FillChar(FTitle, SizeOf(FTitle), 0);
  273.   FillChar(FCreator, SizeOf(FCreator), 0);
  274.   FillChar(FHeader, SizeOf(FHeader), 0);
  275.   FOriginalColors := 0;
  276. end;
  277.  
  278. procedure TAnimatedCursorImage.RiffReadError;
  279. begin
  280.   raise EReadError.Create(ResStr(SReadError));
  281. end;
  282.  
  283. function TAnimatedCursorImage.GetTitle: string;
  284. begin
  285.   Result := StrPas(FTitle);
  286. end;
  287.  
  288. function TAnimatedCursorImage.GetCreator: string;
  289. begin
  290.   Result := StrPas(FCreator);
  291. end;
  292.  
  293. function TAnimatedCursorImage.GetIconCount: Integer;
  294. begin
  295.   Result := FIcons.Count;
  296. end;
  297.  
  298. function TAnimatedCursorImage.GetIcon(Index: Integer): TIcon;
  299. begin
  300.   Result := TIconFrame(FIcons[Index]).FIcon;
  301. end;
  302.  
  303. function TAnimatedCursorImage.GetFrame(Index: Integer): TIconFrame;
  304. begin
  305.   Result := TIconFrame(FIcons[Index]);
  306. end;
  307.  
  308. function TAnimatedCursorImage.GetDefaultRate: Longint;
  309. begin
  310.   Result := Max(0, Min((FHeader.jifRate * 100) div 6, High(Result)));
  311. end;
  312.  
  313. procedure TAnimatedCursorImage.Assign(Source: TPersistent);
  314. var
  315.   I: Integer;
  316.   Frame: TIconFrame;
  317. begin
  318.   if Source = nil then begin
  319.     Clear;
  320.   end
  321.   else if Source is TAnimatedCursorImage then begin
  322.     NewImage;
  323.     try
  324.       with TAnimatedCursorImage(Source) do begin
  325.         Move(FHeader, Self.FHeader, SizeOf(FHeader));
  326.         Self.FTitle := FTitle;
  327.         Self.FCreator := FCreator;
  328.         Self.FOriginalColors := FOriginalColors;
  329.         for I := 0 to FIcons.Count - 1 do begin
  330.           Frame := TIconFrame.Create(-1, FHeader.jifRate);
  331.           try
  332.             Frame.Assign(TIconFrame(FIcons[I]));
  333.             Self.FIcons.Add(Frame);
  334.           except
  335.             Frame.Free;
  336.             raise;
  337.           end;
  338.         end;
  339.       end;
  340.     except
  341.       NewImage;
  342.       raise;
  343.     end;
  344.   end
  345.   else inherited Assign(Source);
  346. end;
  347.  
  348. procedure TAnimatedCursorImage.AssignTo(Dest: TPersistent);
  349. var
  350.   I: Integer;
  351. begin
  352.   if Dest is TIcon then begin
  353.     if IconCount > 0 then Dest.Assign(Icons[0])
  354.     else Dest.Assign(nil);
  355.   end
  356.   else if Dest is TBitmap then begin
  357.     if IconCount > 0 then
  358.       AssignToBitmap(TBitmap(Dest), TBitmap(Dest).Canvas.Brush.Color,
  359.         True, False)
  360.     else Dest.Assign(nil);
  361.   end
  362.   else if Dest is TIconList then begin
  363.     TIconList(Dest).BeginUpdate;
  364.     try
  365.       TIconList(Dest).Clear;
  366.       for I := 0 to IconCount - 1 do TIconList(Dest).Add(Icons[I]);
  367.     finally
  368.       TIconList(Dest).EndUpdate;
  369.     end;
  370.   end
  371.   else inherited AssignTo(Dest);
  372. end;
  373.  
  374. function TAnimatedCursorImage.ReadCreateIcon(Stream: TStream; ASize: Longint;
  375.   var HotSpot: TPoint; var IsIcon: Boolean): TIcon;
  376. type
  377.   PIconRecArray = ^TIconRecArray;
  378.   TIconRecArray = array[0..300] of TIconRec;
  379. var
  380.   List: PIconRecArray;
  381.   Mem: TMemoryStream;
  382.   HeaderLen, I: Integer;
  383.   BI: PBitmapInfoHeader;
  384. begin
  385.   Result := nil;
  386.   Mem := TMemoryStream.Create;
  387.   try
  388.     Mem.SetSize(ASize);
  389.     Mem.CopyFrom(Stream, Mem.Size);
  390.     HotSpot := Point(0, 0);
  391.     IsIcon := PCursorOrIcon(Mem.Memory)^.wType = RC3_ICON;
  392.     if PCursorOrIcon(Mem.Memory)^.wType = RC3_CURSOR then
  393.       PCursorOrIcon(Mem.Memory)^.wType := RC3_ICON;
  394.     if PCursorOrIcon(Mem.Memory)^.wType = RC3_ICON then begin
  395.       { determinate original icon color }
  396.       HeaderLen := PCursorOrIcon(Mem.Memory)^.Count * SizeOf(TIconRec);
  397.       GetMem(List, HeaderLen);
  398.       try
  399.         Mem.Position := SizeOf(TCursorOrIcon);
  400.         Mem.Read(List^, HeaderLen);
  401.         for I := 0 to PCursorOrIcon(Mem.Memory)^.Count - 1 do
  402.           with List^[I] do begin
  403.             GetMem(BI, DIBSize);
  404.             try
  405.               Mem.Seek(DIBOffset, soFromBeginning);
  406.               Mem.Read(BI^, DIBSize);
  407.               FOriginalColors := Max(GetDInColors(BI^.biBitCount), FOriginalColors);
  408.               HotSpot := Point(xHotspot, yHotspot);
  409.             finally
  410.               FreeMem(BI, DIBSize)
  411.             end;
  412.           end;
  413.       finally
  414.         FreeMem(List, HeaderLen);
  415.       end;
  416.       { return to start of stream }
  417.       Mem.Position := 0;
  418.       Result := TIcon.Create;
  419.       try
  420.         Result.LoadFromStream(Mem);
  421.         if IsIcon then
  422.           HotSpot := Point(Result.Width div 2, Result.Height div 2);
  423.       except
  424.         Result.Free;
  425.         Result := nil;
  426.       end;
  427.     end;
  428.   finally
  429.     Mem.Free;
  430.   end;
  431. end;
  432.  
  433. { Loads an animatied cursor from a RIFF file. The RIFF file format for
  434.   animated cursors looks like this:
  435.  
  436.   RIFF('ACON'
  437.     LIST('INFO'
  438.           INAM(<name>)
  439.           IART(<artist>))
  440.       anih(<anihdr>)
  441.       [rate(<rateinfo>)]
  442.       ['seq '( <seq_info>)]
  443.       LIST('fram' icon(<icon_file>)))
  444. }
  445.  
  446. procedure TAnimatedCursorImage.ReadAniStream(Stream: TStream);
  447. var
  448.   iFrame, iRate, iSeq, I: Integer;
  449.   Tag: TAniTag;
  450.   Frame: TIconFrame;
  451.   cbChunk, cbRead, Temp: Longint;
  452.   Icon: TIcon;
  453.   bFound, IsIcon: Boolean;
  454.   HotSpot: TPoint;
  455. begin
  456.   iFrame := 0; iRate := 0; iSeq := 0;
  457.   { Make sure it's a RIFF ANI file }
  458.   if not ReadTag(Stream, @Tag) or (Tag.ckID <> FOURCC_RIFF) then
  459.     RiffReadError;
  460.   if (Stream.Read(Tag.ckID, SizeOf(Tag.ckID)) < SizeOf(Tag.ckID)) or
  461.     (Tag.ckID <> FOURCC_ACON) then RiffReadError;
  462.   NewImage;
  463.   { look for 'anih', 'rate', 'seq ', and 'icon' chunks }
  464.   while ReadTag(Stream, @Tag) do begin
  465.     if Tag.ckID = FOURCC_anih then begin
  466.       if not ReadChunk(Stream, @Tag, @FHeader) then Break;
  467.       if ((FHeader.fl and AF_ICON) <> AF_ICON) or
  468.         (FHeader.cFrames = 0) then RiffReadError;
  469.       for I := 0 to FHeader.cSteps - 1 do begin
  470.         Frame := TIconFrame.Create(I, FHeader.jifRate);
  471.         FIcons.Add(Frame);
  472.       end;
  473.     end
  474.     else if Tag.ckID = FOURCC_rate then begin
  475.       { If we find a rate chunk, read it into its preallocated space }
  476.       if not ReadChunkN(Stream, @Tag, @Temp, SizeOf(Longint)) then
  477.         Break;
  478.       if iRate < FIcons.Count then
  479.         TIconFrame(FIcons[iRate]).FJiffRate := Temp;
  480.       Inc(iRate);
  481.     end
  482.     else if Tag.ckID = FOURCC_seq then begin
  483.       { If we find a seq chunk, read it into its preallocated space }
  484.       if not ReadChunkN(Stream, @Tag, @Temp, SizeOf(Longint)) then
  485.         Break;
  486.       if iSeq < FIcons.Count then
  487.         TIconFrame(FIcons[iSeq]).FSeq := Temp;
  488.       Inc(iSeq);
  489.     end
  490.     else if Tag.ckID = FOURCC_LIST then begin
  491.       cbChunk := PadUp(Tag.ckSize);
  492.       { See if this list is the 'fram' list of icon chunks }
  493.       cbRead := Stream.Read(Tag.ckID, SizeOf(Tag.ckID));
  494.       if cbRead < SizeOf(Tag.ckID) then Break;
  495.       Dec(cbChunk, cbRead);
  496.       if (Tag.ckID = FOURCC_fram) then begin
  497.         while (cbChunk >= SizeOf(Tag)) do begin
  498.           if not ReadTag(Stream, @Tag) then Break;
  499.           Dec(cbChunk, SizeOf(Tag));
  500.           if (Tag.ckID = FOURCC_icon) then begin
  501.             { Ok, load the icon/cursor bits }
  502.             Icon := ReadCreateIcon(Stream, Tag.ckSize, HotSpot, IsIcon);
  503.             if Icon = nil then Break;
  504.             bFound := False;
  505.             for I := 0 to FIcons.Count - 1 do begin
  506.               if TIconFrame(FIcons[I]).FSeq = iFrame then begin
  507.                 TIconFrame(FIcons[I]).FIcon := Icon;
  508.                 TIconFrame(FIcons[I]).FTag := Tag;
  509.                 TIconFrame(FIcons[I]).FHotSpot := HotSpot;
  510.                 TIconFrame(FIcons[I]).FIsIcon := IsIcon;
  511.                 bFound := True;
  512.               end;
  513.             end;
  514.             if not bFound then begin
  515.               Frame := TIconFrame.Create(-1, FHeader.jifRate);
  516.               Frame.FIcon := Icon;
  517.               Frame.FIsIcon := IsIcon;
  518.               Frame.FTag := Tag;
  519.               Frame.FHotSpot := HotSpot;
  520.               FIcons.Add(Frame);
  521.             end;
  522.             Inc(iFrame);
  523.           end
  524.           else begin
  525.             { Unknown chunk in fram list, just ignore it }
  526.             SkipChunk(Stream, @Tag);
  527.           end;
  528.           Dec(cbChunk, PadUp(Tag.ckSize));
  529.         end;
  530.       end
  531.       else if (Tag.ckID = FOURCC_INFO) then begin
  532.         { now look for INAM and IART chunks }
  533.         while (cbChunk >= SizeOf(Tag)) do begin
  534.           if not ReadTag(Stream, @Tag) then Break;
  535.           Dec(cbChunk, SizeOf(Tag));
  536.           if Tag.ckID = FOURCC_INAM then begin
  537.             if (cbChunk < Tag.ckSize) or not
  538.               ReadChunkN(Stream, @Tag, @FTitle, SizeOf(TANINAME) - 1) then
  539.               Break;
  540.             Dec(cbChunk, PadUp(Tag.ckSize));
  541.           end
  542.           else if Tag.ckID = FOURCC_IART then begin
  543.             if (cbChunk < Tag.ckSize) or not
  544.               ReadChunkN(Stream, @Tag, @FCreator, SizeOf(TANINAME) - 1) then
  545.               Break;
  546.             Dec(cbChunk, PadUp(Tag.ckSize));
  547.           end
  548.           else begin
  549.             if not SkipChunk(Stream, @Tag) then Break;
  550.             Dec(cbChunk, PadUp(Tag.ckSize));
  551.           end;
  552.         end;
  553.       end
  554.       else begin
  555.         { Not the fram list or the INFO list. Skip the rest of this
  556.           chunk. (Don't forget that we have already skipped one dword) }
  557.         Tag.ckSize := cbChunk;
  558.         SkipChunk(Stream, @Tag);
  559.       end;
  560.     end
  561.     else begin { We're not interested in this chunk, skip it. }
  562.       if not SkipChunk(Stream, @Tag) then Break;
  563.     end;
  564.   end; { while }
  565.   { Update the frame count incase we coalesced some frames while reading
  566.     in the file. }
  567.   for I := FIcons.Count - 1 downto 0 do begin
  568.     if TIconFrame(FIcons[I]).FIcon = nil then begin
  569.       TIconFrame(FIcons[I]).Free;
  570.       FIcons.Delete(I);
  571.     end;
  572.   end;
  573.   FHeader.cFrames := FIcons.Count;
  574.   if FHeader.cFrames = 0 then RiffReadError;
  575. end;
  576.  
  577. procedure TAnimatedCursorImage.ReadStream(Size: Longint; Stream: TStream);
  578. var
  579.   Data: TMemoryStream;
  580. begin
  581.   Data := TMemoryStream.Create;
  582.   try
  583.     Data.SetSize(Size);
  584.     Stream.ReadBuffer(Data.Memory^, Size);
  585.     if Size > 0 then begin
  586.       Data.Position := 0;
  587.       ReadAniStream(Data);
  588.     end;
  589.   finally
  590.     Data.Free;
  591.   end;
  592. end;
  593.  
  594. procedure TAnimatedCursorImage.WriteStream(Stream: TStream;
  595.   WriteSize: Boolean);
  596. begin
  597.   NotImplemented;
  598. end;
  599.  
  600. procedure TAnimatedCursorImage.LoadFromStream(Stream: TStream);
  601. begin
  602.   ReadStream(Stream.Size - Stream.Position, Stream);
  603. end;
  604.  
  605. procedure TAnimatedCursorImage.SaveToStream(Stream: TStream);
  606. begin
  607.   WriteStream(Stream, False);
  608. end;
  609.  
  610. procedure TAnimatedCursorImage.LoadFromFile(const Filename: string);
  611. var
  612.   Stream: TStream;
  613. begin
  614.   Stream := TFileStream.Create(Filename, fmOpenRead + fmShareDenyNone);
  615.   try
  616.     try
  617.       LoadFromStream(Stream);
  618.     except
  619.       NewImage;
  620.       raise;
  621.     end;
  622.   finally
  623.     Stream.Free;
  624.   end;
  625. end;
  626.  
  627. procedure TAnimatedCursorImage.Draw(ACanvas: TCanvas; const ARect: TRect);
  628. begin
  629.   if FIcons.Count > 0 then
  630.     DrawRealSizeIcon(ACanvas, Icons[0], ARect.Left, ARect.Top);
  631. end;
  632.  
  633. procedure TAnimatedCursorImage.AssignToBitmap(Bitmap: TBitmap; BackColor: TColor;
  634.   DecreaseColors, Vertical: Boolean);
  635. var
  636.   I: Integer;
  637.   Temp: TBitmap;
  638. begin
  639.   Temp := TBitmap.Create;
  640.   try
  641.     if FIcons.Count > 0 then begin
  642.       with Temp do begin
  643.         Monochrome := False;
  644.         Canvas.Brush.Color := BackColor;
  645.         if Vertical then begin
  646.           Width := Icons[0].Width;
  647.           Height := Icons[0].Height * FIcons.Count;
  648.         end
  649.         else begin
  650.           Width := Icons[0].Width * FIcons.Count;
  651.           Height := Icons[0].Height;
  652.         end;
  653.         Canvas.FillRect(Bounds(0, 0, Width, Height));
  654.         for I := 0 to FIcons.Count - 1 do begin
  655.           if Icons[I] <> nil then
  656.             Canvas.Draw(Icons[I].Width * I * Ord(not Vertical),
  657.               Icons[I].Height * I * Ord(Vertical), Icons[I]);
  658.         end;
  659.       end;
  660.       if DecreaseColors then
  661.         DecreaseBMPColors(Temp, Max(OriginalColors, 16));
  662.     end;
  663.     Bitmap.Assign(Temp);
  664.   finally
  665.     Temp.Free;
  666.   end;
  667. end;
  668.  
  669. end.