Anifile.pas
上传用户:hylc_2004
上传日期:2014-01-23
资源大小:46800k
文件大小:18k
源码类别:

Delphi控件源码

开发平台:

Delphi

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