home *** CD-ROM | disk | FTP | other *** search
/ Chip 2002 September / Chip_2002-09_cd1.bin / zkuste / delphi / navody / JBOOSTER.ZIP / Source / Support.pas < prev    next >
Pascal/Delphi Source File  |  2002-06-15  |  63KB  |  1,988 lines

  1. (*************************************************************************)
  2. (*                                jBooster                               *)
  3. (*                        (c) pulsar@mail.primorye.ru                    *)
  4. (*************************************************************************)
  5.  Unit Support;
  6.  {$J+,H+,A+,B-,I-}
  7.  
  8.  Interface
  9.  
  10.  Uses
  11.   { standart }
  12.     SysUtils, Windows, Classes,
  13.   { vcl }
  14.     StdCtrls, Controls, Graphics, Dialogs, Forms,
  15.   { formats }
  16.     JPeg,
  17.   { private }
  18.     Rasters;
  19.  
  20. (*************************************************************************)
  21. (*                         customizable values                           *)
  22. (*************************************************************************)
  23.  Const
  24.   { Application }
  25.     AppName = 'jBooster';
  26.     Version = '1.09b';
  27.   { names }
  28.     IniName = AppName + '.ini';
  29.     LogName = AppName + '.log';
  30.     HlpName = AppName + '.txt';
  31.     ScvName = AppName + '.csv';
  32.     DatName = AppName + '.dat';
  33.  
  34. (*************************************************************************)
  35. (*                          report\error handlers                        *)
  36. (*************************************************************************)
  37.  Type
  38.      PReportHandler = procedure (const Mssg: string; Prx: TMsgDlgType);
  39.  
  40.  procedure Alarm (const Mssg: string; Pfx: TMsgDlgType);
  41.  function Confirm (const Wrn, Qst: string): boolean;
  42.  procedure Error (const Name, Mssg: string);
  43.  procedure SysError (const Name: string; RC: Dword);
  44.  procedure Warning (const Name, Mssg: string);
  45.  procedure Inform (const Mssg: string);
  46.  
  47.  Const
  48.    { report handler }
  49.      Report : PReportHandler = Alarm;
  50.    { error count }
  51.      Errors : integer = 0;
  52.    { report prefixs }
  53.      ErrPrefix = '!';
  54.      BegPrefix = '?';
  55.      EndPrefix = '=';
  56.      AnyPrefix = ' ';
  57.  
  58. (*************************************************************************)
  59. (*                              support                                  *)
  60. (*************************************************************************)
  61.  Const
  62.   { special chars + prefix chars }
  63.     Illegals = [#0..#31,'\','|','/','*','?',':','>','<','"','.'] + ['!','='];
  64.   { digits }
  65.     Numerics = ['0'..'9'];
  66.  
  67.  function StrToInt (const S: string; var I: integer): boolean;
  68.  function StrToDateTime (const S: string; var DT: TDateTime): boolean;
  69.  function PathDelimiter (const Path: string; Del: boolean = false): string;
  70.  function SizeStr (W, H : integer): string;
  71.  function FileSizeStr (Z: longword): string;
  72.  function TrackToQuality (Track: integer): integer;
  73.  function TrackToLikeness (Track: integer): integer;
  74.  function isThumbnail (const FileName: string): boolean;
  75.  function isValid: boolean;
  76.  procedure AppTitle;
  77.  function CatalogTime (var Time: TFileTime): boolean;
  78.  function OpenText (var Txt: Text; const Name: string; Mode: boolean): boolean;
  79.  
  80. (*************************************************************************)
  81. (*                                parameters                             *)
  82. (*************************************************************************)
  83.  Type
  84.     TFormat = 0..1;
  85.     TOrder = 0..7;
  86.  
  87.  Const
  88.   { autorun flag }
  89.     ParmAuto = 'AUTO';
  90.   { list breaker }
  91.     ListBreak = ';';
  92.   { text breaker }
  93.     TextBreak = ',';
  94.   { path history }
  95.     MaxHistory = 8;
  96.   { extension }
  97.     ExtLen = 4;
  98.   { format }
  99.     MaxFormat = High (TFormat);
  100.     MinFormat = Low (TFormat);
  101.   { pixel format }
  102.     MaxPixelFormat = 2;
  103.   { panels }
  104.     MaxPanel = 2;
  105.   { scale }
  106.     MaxScale = 10;
  107.     MinScale = 0;
  108.   { quality }
  109.     MaxQuality = 10;
  110.     MinQuality = 0;
  111.   { preview font }
  112.     MaxColor = $00FFFFFF;
  113.     MinColor = $00000000;
  114.     MaxFont  = 9;
  115.     MinFont  = 6;
  116.   { firstnumber }
  117.     MinFirst = 0;
  118.     MaxFirst = 999999999;
  119.     LenFirst = 9;
  120.   { digits }
  121.     MaxDigits = 9;
  122.     MinDigits = 0;
  123.     LenDigits = 1;
  124.   { step }
  125.     MaxStep = 999999;
  126.     MinStep = 1;
  127.     LenStep = 6;
  128.   { anchor }
  129.     MinAnchor = Low (TAnchor);
  130.     MaxAnchor = High (TAnchor);
  131.   { order }
  132.     MinOrder = Low (TOrder);
  133.     MaxOrder = High (TOrder);
  134.   { custom width\height }
  135.     MinCustom = 1;
  136.     MaxCustom = 999;
  137.     LenCustom = 3;
  138.     StdCustom = 90;
  139.   { compare }
  140.     MinLike = 0;
  141.     MaxLike = 25;
  142.   { other }
  143.     LenNamePart = 64;
  144.     LenComment = 24;
  145.   { forms  }
  146.     MinView = 100;
  147.     MinTop = -18;
  148.     MinLeft = -100;
  149.     MinWidth = 400;
  150.     MinHeight = 357;
  151.  
  152.  Const
  153.   { curr format }
  154.     Files : integer = 0;
  155.   { curr path }
  156.     PathIndex : integer = 0;
  157.   { curr panel }
  158.     PanelIndex: integer = 0;
  159.   { list sort flag }
  160.     fSortList : boolean = true;
  161.   { numerate }
  162.     fRename : boolean = false;
  163.     Order : integer = 0;
  164.     fDecs : boolean = false;
  165.     FirstNum : integer = 0;
  166.     NextFirst : boolean = true;
  167.     Digits : integer = 0;
  168.     StepCount : integer = 1;
  169.     Prefix : string = '';
  170.     Postfix : string = '';
  171.     fAttribute : boolean = false;
  172.     fFileTime : boolean = false;
  173.   { thumbnails }
  174.     fThumbnail : boolean = false;
  175.     Scale : integer = 3;
  176.     ThumbnailQuality : integer = 7;
  177.     Mark : string = '$';
  178.   { custom size }
  179.     fCustom : boolean = false;
  180.     CtmWidth : integer = StdCustom;
  181.     CtmHeight : integer = StdCustom;
  182.     CtmMode : boolean = false;
  183.     AnchorX : integer = 1;
  184.     AnchorY : integer = 1;
  185.     FillColor : integer = MinColor;
  186.   { include }
  187.     fInclude : boolean = false;
  188.     Comment : string = '';
  189.     fImgSize : boolean = false;
  190.     fFilSize : boolean = false;
  191.   { font }
  192.     FontBold : boolean = false;
  193.     FontItalic : boolean = false;
  194.     FontUnderline : boolean = false;
  195.     FontStrikeOut : boolean = false;
  196.     FontName : string = 'MS Serif';
  197.     FontColor : TColor = MinColor;
  198.     FontSize : integer = 6;
  199.     BGround  : TColor = 15724275;
  200.   { collection }
  201.     fCollection : boolean = false;
  202.     fDuplicate : boolean = false;
  203.     Likeness : integer = 0;
  204.     fDescription : boolean = false;
  205.   { autosave }
  206.     AutoSave : boolean = false;
  207.   { custom colors }
  208.     Colors : TStringList = nil;
  209.   { forms position and size }
  210.     MainLeft : integer = 200;
  211.     MainTop : integer = 100;
  212.     MainWidth : integer = MinWidth;
  213.     MainHeight : integer = MinHeight;
  214.     ViewLeft : integer = 10;
  215.     ViewTop : integer = 10;
  216.     ViewWidth : integer = 360;
  217.     ViewHeight: integer = 400;
  218.  
  219.  Const
  220.   { curr format }
  221.     psFiles = 'FilesIndex';
  222.   { curr path }
  223.     psPath = 'Path';
  224.     psPathIndex = 'PathIndex';
  225.   { curr panel }
  226.     psPanelIndex = 'PanelIndex';
  227.   { list sort flag }
  228.     psSortList = 'SortList';
  229.   { numerate }
  230.     psRename = 'Numerate';
  231.     psOrder = 'OrderIndex';
  232.     psDecs = 'Decrease';
  233.     psFirstNum = 'First';
  234.     psNextFirst = 'UpdateFirst';
  235.     psDigits = 'Digits';
  236.     psStepCount = 'Step';
  237.     psPrefix = 'Prefix';
  238.     psPostfix = 'Postfix';
  239.     psAttribute = 'SetReadOnly';
  240.     psFileTime = 'UpdateFileTime';
  241.   { thumbnails }
  242.     psThumbnail = 'CreateThumbnails';
  243.     psScale = 'ThumbnailScale';
  244.     psThumbnailQuality  = 'ThumbnailQuality';
  245.     psMark  = 'ThumbnailMark';
  246.   { custom size }
  247.     psCustom = 'CustomSize';
  248.     psCtmWidth = 'CustomWidth';
  249.     psCtmHeight = 'CustomHeight';
  250.     psCtmMode = 'CutOrFill';
  251.     psAnchorX = 'HorAlign';
  252.     psAnchorY  = 'VerAlign';
  253.     psFillColor = 'FillColor';
  254.   { include }
  255.     psInclude = 'Include';
  256.     psComment = 'IncludeText';
  257.     psImgSize = 'IncludeImageSize';
  258.     psFilSize = 'IncludeFileSize';
  259.   { font }
  260.     psFontBold = 'FontBold';
  261.     psFontItalic = 'FontItalic';
  262.     psFontUnderline = 'FontUnderline';
  263.     psFontStrikeOut = 'FontStrikeOut';
  264.     psFontName = 'FontName';
  265.     psFontColor = 'FontColor';
  266.     psFontSize = 'FontSize';
  267.     psBGround = 'FontBackGround';
  268.   { custom colors }
  269.     psColors = 'Color';
  270.   { collection }
  271.     psCollection = 'CollectionCheck';
  272.     psDuplicate = 'FindDuplicate';
  273.     psLikeness = 'Likeness';
  274.     psDescription = 'Description';
  275.   { autosave }
  276.     psAutoSave = 'AutoSave';
  277.   { forms position and size }
  278.     psMainLeft = 'WindowLeft';
  279.     psMainTop  = 'WindowTop';
  280.     psMainWidth = 'WindowWidth';
  281.     psMainHeight = 'WindowHeight';
  282.     psViewLeft = 'ViewerWindowLeft';
  283.     psViewTop = 'ViewerWindowTop';
  284.     psViewWidth = 'ViewerWindowWidth';
  285.     psViewHeight = 'ViewerWindowHeight';
  286.  
  287.  Const
  288.   { formats }
  289.     Formats : array [TFormat] of string [ExtLen]
  290.             = ('.jpg', '.bmp' {, '.gif', '.tif', '.pcx', '.png'});
  291.  
  292.   { sort order }
  293.     Orders : array [TOrder] of string
  294.            = ('by file name',
  295.               'by file size',
  296.               'by file time',
  297.               'by image width',
  298.               'by image height',
  299.               'by (width * height)',
  300.               'by (width / height)',
  301.               'by random');
  302.  
  303.   { align }
  304.     HAnchors : array [TAnchor] of string = ('Left','Center','Right');
  305.     VAnchors : array [TAnchor] of string = ('Top','Middle','Bottom');
  306.  
  307.  Const
  308.    { autorun flag }
  309.      RunAuto : boolean = false;
  310.    { self dir }
  311.      ExePath : string = '';
  312.    { work dir }
  313.      Catalog : string = '';
  314.    { ini-file }
  315.      IniFile : string = '';
  316.    { buffer }
  317.      Params : TStringList = nil;
  318.  
  319. { font }
  320.  procedure ParmsToFont (Font: TFont);
  321.  procedure FontToParms (Font: TFont);
  322. { load\save parameters }
  323.  function LoadParameters (Path, Colors: TStrings): boolean;
  324.  procedure SaveParameters  (Path, Colors: TStrings);
  325.  
  326. (*************************************************************************)
  327. (*                               formats support                         *)
  328. (*************************************************************************)
  329.  function LoadImage (Bmp: TBitMap; const FileName: string): integer;
  330.  function SaveImage (Bmp: TBitMap; Compression: integer; const FileName: string): boolean;
  331.  function ImageSize (const FileName: string; var Width, Height : integer): boolean;
  332.  
  333. (*************************************************************************)
  334. (*                                image list                             *)
  335. (*************************************************************************)
  336.  Type
  337.     TDataFile = File of TMatrix;
  338.  
  339.     PImageInfo = ^TImageInfo;
  340.     TImageInfo = packed record
  341.     { work }
  342.       Thumbnail : PImageInfo;
  343.       Temp : integer;
  344.       Data : PMatrix;
  345.     { image parms }
  346.       Width  : integer;
  347.       Height : integer;
  348.     { file parms }
  349.       Size : integer;
  350.       Attr : integer;
  351.       Time : TFileTime;
  352.       Name : string;
  353.     end; { TImageInfo }
  354.  
  355.     TImageList = Class (TList)
  356.     private
  357.       ViewCount : integer;
  358.       SortOrder : integer;
  359.       Decrease  : boolean;
  360.       HaveSize  : boolean;
  361.       HaveData  : boolean;
  362.     { support }
  363.       procedure Drop;
  364.       procedure DisposeItem (var P: PImageInfo);
  365.       procedure InitInfo (var Find : TSearchRec; Info: PImageInfo);
  366.       function NewData (P: PImageInfo): boolean;
  367.       function Search (const Name: string; var Index: integer): boolean;
  368.       function isCancel : boolean;
  369.       procedure Start (const Mssg: string);
  370.       procedure Stop;
  371.       procedure SetTemp (Mode: integer);
  372.       function LoadSize: boolean;
  373.     { test }
  374.       function Pack: boolean;
  375.     { create thumbnails }
  376.       function CreateThumbnails: boolean;
  377.     { rename }
  378.       function RenameImage (P: PImageInfo; const Name: string): boolean;
  379.       function Rename: boolean;
  380.     { update }
  381.       function SetReadOnly (P: PImageInfo; ReadOnly: boolean): boolean;
  382.       function UpdateTime (P: PImageInfo; const Time: TSystemTime): boolean;
  383.       function Update: boolean;
  384.     { create description }
  385.       function CreateDescription: boolean;
  386.     { find duplicates }
  387.       function LoadData: boolean;
  388.       function FindDups: boolean;
  389.     public
  390.       constructor Create;
  391.       procedure Clear; override;
  392.       function Scan: boolean;
  393.       function Sort (Odr: TOrder; Dcs: boolean): boolean;
  394.       function Run: boolean;
  395.       procedure MarkChange;
  396.       property ThumbnailCount: integer read ViewCount;
  397.     end; { TImageList }
  398.  
  399.  Var
  400.     Images : TImageList;
  401.     Cancel : boolean;
  402.  
  403.  Implementation
  404.  
  405. (*************************************************************************)
  406. (*                          report\error handlers                        *)
  407. (*************************************************************************)
  408.  procedure Alarm (const Mssg: string; Pfx: TMsgDlgType);
  409.  begin
  410.      With CreateMessageDialog (Mssg, Pfx, [mbOK]) do begin
  411.           Position := poMainFormCenter;
  412.           ShowModal;
  413.           Free;
  414.      end; { With }
  415.  end; { Alarm }
  416.  
  417.  function Confirm (const Wrn, Qst: string): boolean;
  418.  begin
  419.      With CreateMessageDialog (Wrn + #13#13 + Qst + '?', mtConfirmation, [mbYes, mbNo])
  420.      do begin
  421.         Position := poMainFormCenter;
  422.         Result := ShowModal = mrYes;
  423.         Free;
  424.      end; { With }
  425.  end; { Confirm }
  426.  
  427.  procedure Error (const Name, Mssg: string);
  428.  var
  429.      S : string;
  430.  begin
  431.      Inc (Errors);
  432.      if Name > '' then S := '"' + Name + '". ' else S := '';
  433.      Report (ErrPrefix + AnyPrefix + 'Error: ' + S + Mssg, mtError)
  434.  end; { Error }
  435.  
  436.  procedure SysError (const Name: string; RC: Dword);
  437.  begin
  438.      Error (Name, SysErrorMessage (RC));
  439.  end; { SysError }
  440.  
  441.  procedure Warning (const Name, Mssg: string);
  442.  var
  443.      S : string;
  444.  begin
  445.      if Name > '' then S := '"' + Name + '". ' else S := '';
  446.      Report (ErrPrefix + AnyPrefix + 'Warning: ' + S + Mssg, mtWarning)
  447.  end; { Warning }
  448.  
  449.  procedure Inform (const Mssg: string);
  450.  begin
  451.      Report (Mssg, mtInformation);
  452.  end; { Inform }
  453.  
  454. (*************************************************************************)
  455. (*                               support                                 *)
  456. (*************************************************************************)
  457.  function StrToInt (const S : string; var I: integer): boolean;
  458.  var
  459.      c, n : integer;
  460.  begin
  461.       {$R-}
  462.         Val (S, n, c);
  463.         if c = 0 then begin
  464.            Result := true;
  465.            I := n;
  466.         end { if }
  467.         else Result := false;
  468.  end; { StrToInt }
  469.  
  470.  function StrToDateTime (const S: string; var DT: TDateTime): boolean;
  471.  begin
  472.      Try
  473.        DT := SysUtils.StrToDateTime (S);
  474.        Result := true;
  475.      Except
  476.        Result := false;
  477.      end;
  478.  end; { StrToDateTime }
  479.  
  480.  function PathDelimiter (const Path: string; Del: boolean = false): string;
  481.  var
  482.      l : integer;
  483.  begin
  484.      l := Length (Path);
  485.      Result := Path;
  486.      if l > 0 then begin
  487.         if IsPathDelimiter (Path, Length (Path)) then begin
  488.            if Del then SetLength (Result, Pred (l))
  489.         end { if }
  490.         else if not Del then Result := Result + '\';
  491.      end; { if }
  492.  end; { PathDelimiter }
  493.  
  494.  function SetDigits (Num: integer): string;
  495.  var
  496.      k : integer;
  497.  begin
  498.      Result := IntToStr (Num);
  499.      if Digits > 0 then begin
  500.         k := Digits - Length (Result);
  501.         if k > 0 then Result := StringOfChar ('0', k) + Result;
  502.      end; { if }
  503.  end; { SetDigits }
  504.  
  505.  function isThumbnail (const FileName: string): boolean;
  506.  var
  507.      k : integer;
  508.  begin
  509.      k := Length (Mark);
  510.      Result := (k > 0) and (AnsiCompareText (Copy (FileName, Length (FileName) - k - Pred (ExtLen), k), Mark) = 0);
  511.  end; { isThumbnail }
  512.  
  513.  procedure DecodeName (const FileName: string; var Pfx, Num, Ptx: string);
  514.  var
  515.      i, j, k, n : integer;
  516.  begin
  517.    { len }
  518.      n := Length (FileName) - ExtLen;
  519.    { find digit }
  520.      j := Succ (n);
  521.      k := j;
  522.      for i := 1 to n do begin
  523.          if FileName [i] in Numerics then begin
  524.             j := i;
  525.             Break;
  526.          end; { if }
  527.      end; { for }
  528.    { find char }
  529.      for i := Succ (j) to n do begin
  530.          if not (FileName [i] in Numerics) then begin
  531.             k := i;
  532.             Break;
  533.          end; { if }
  534.      end; { for }
  535.    { result }
  536.      Pfx := Copy (FileName, 1, Pred (j));
  537.      Ptx := Copy (FileName, k, n - k + 1);
  538.      Num := Copy (FileName, j, k - j);
  539.  end; { DecodeName }
  540.  
  541.  function EncodeName (Number: integer): string;
  542.  begin
  543.      Result := Prefix + SetDigits (Number) + Postfix + Formats [Files];
  544.  end; { EncodeName }
  545.  
  546.  function ThumbnailName (const FileName: string): string;
  547.  var
  548.      n : integer;
  549.  begin
  550.      n := Length (FileName);
  551.      Result := Copy (FileName, 1, n - ExtLen) + Mark +
  552.                Copy (FileName, n - Pred (ExtLen), ExtLen);
  553.  end; { ThumbnailName }
  554.  
  555.  function SizeStr (W, H : integer): string;
  556.  begin
  557.      Result := IntToStr (W) + 'x' + IntToStr (H);
  558.  end; { SizeStr }
  559.  
  560.  function FileSizeStr (Z: longword): string;
  561.  var
  562.      k : integer;
  563.  begin
  564.      k := Round (Z / 1024);
  565.      if k = 0 then k := 1;
  566.      Result := IntToStr (k) + 'k';
  567.  end; { FileSizeStr }
  568.  
  569.  function TrackToQuality (Track: integer): integer;
  570.  begin
  571.      Result := 20 + (Track * 8);
  572.  end; { JpgeQuality }
  573.  
  574.  function TrackToLikeness (Track: integer): integer;
  575.  begin
  576.      Result := Track + 75;
  577.  end; { TrackToLikeness }
  578.  
  579.  function isPathExist (const Name: string): boolean;
  580.  var
  581.      A : integer;
  582.  begin
  583.      A := FileGetAttr (Name);
  584.      Result := (A > 0) and ((A and faDirectory) > 0);
  585.  end; { isPathExist }
  586.  
  587.  function isValid: boolean;
  588.  begin
  589.      Result := (fRename or fThumbnail or fCollection) and
  590.                (Images <> nil) and (Images.Count > 0);
  591.  end; { isValid }
  592.  
  593.  procedure AppTitle;
  594.  begin
  595.      Inform (AppName + ' ' + Version + '. Freeware. (c) pulsar@mail.primorye.ru');
  596.  end; { AppTitle }
  597.  
  598.  function CatalogTime (var Time: TFileTime): boolean;
  599.  var
  600.      Find : TSearchRec;
  601.  begin
  602.      Result := false;
  603.      if Catalog > '' then begin
  604.         if SysUtils.FindFirst (PathDelimiter (Catalog, true), faAnyFile, Find) = 0
  605.         then With Find.FindData do begin
  606.              if CompareFileTime (ftLastWriteTime, ftCreationTime) > 0
  607.                 then Time := ftLastWriteTime
  608.                 else Time := ftCreationTime;
  609.              Result := true;
  610.         end; { if }
  611.       { close }
  612.         SysUtils.FindClose (Find);
  613.      end; { if }
  614.  end; { CatalogTime }
  615.  
  616.  function OpenText (var Txt: Text; const Name: string; Mode: boolean): boolean;
  617.  begin
  618.      AssignFile (Txt, Name);
  619.      if Mode then begin
  620.         FileMode := 1;
  621.         Rewrite (Txt)
  622.      end { if }
  623.      else begin
  624.           FileMode := 0;
  625.           Reset (Txt);
  626.      end; { else }     
  627.      Result := IOresult = 0;
  628.  end; { OpenTxt }
  629.  
  630.  function SetFileAttr (const FileName: string; Attr: integer): boolean;
  631.  begin
  632.      if FileSetAttr (FileName, Attr) <> 0 then begin
  633.         SysError (FileName, GetLastError);
  634.         Result := false;
  635.      end { if }
  636.      else Result := true;
  637.  end; { if }
  638.  
  639.  function FileTimeToDateTime (var Time: TFileTime): TDateTime;
  640.  var
  641.      F : TFileTime;
  642.      U : TSystemTime;
  643.  begin
  644.      FileTimeToLocalFileTime (Time, F);
  645.      FileTimeToSystemTime (F, U);
  646.      Result := SystemTimeToDateTime (U);
  647.  end; { FileTimeToDateTime }
  648.  
  649. (*************************************************************************)
  650. (*                              formats support                          *)
  651. (*************************************************************************)
  652.  function LoadImage (Bmp: TBitMap; const FileName: string): integer;
  653.  var
  654.     Jpg : TJpegImage;
  655.  begin
  656.      Result := -1;
  657.      Try
  658.        Case Files of
  659.         { jpg }
  660.           0: begin
  661.              Jpg := TJpegImage.Create;
  662.              Jpg.LoadFromFile (Catalog + FileName);
  663.              if Jpg.PixelFormat = jf8bit then Bmp.PixelFormat := pf8bit
  664.                 else Bmp.PixelFormat := pf24bit;
  665.              Bmp.Width := Jpg.Width;
  666.              Bmp.Height := Jpg.Height;
  667.              Bmp.Canvas.Draw (0, 0, Jpg);
  668.              Result := Jpg.CompressionQuality;
  669.              Jpg.Free;
  670.           end; { 0 }
  671.         { bmp }
  672.           1: begin
  673.              Bmp.LoadFromFile (Catalog + FileName);
  674.              Result := 0;
  675.           end; { 1 }
  676.         { unsupported }
  677.           else Error (FileName, 'Unsupported format')
  678.        end; { Case }
  679.      Except
  680.        on E: Exception do Error (Catalog + FileName, E.Message);
  681.      end; { try }
  682.  end; { LoadImage }
  683.  
  684.  function SaveImage (Bmp: TBitMap; Compression: integer; const FileName: string): boolean;
  685.  var
  686.     Jpg : TJpegImage;
  687.  begin
  688.      Try
  689.        Case Files of
  690.         { jpg }
  691.           0: begin
  692.              Jpg := TJpegImage.Create;
  693.              Jpg.CompressionQuality := Compression;
  694.              if Bmp.PixelFormat > pf8bit then Jpg.PixelFormat := jf24bit
  695.                 else Jpg.PixelFormat := jf8bit;
  696.              Jpg.Assign (Bmp);
  697.              Jpg.SaveToFile (Catalog + FileName);
  698.              Jpg.Free;
  699.           end; { 0 }
  700.         { bmp }
  701.           1: begin
  702.              Bmp.SaveToFile (Catalog + FileName);
  703.           end; { 1 }
  704.         { unsupported }
  705.           else Error (FileName, 'Unsupported format')
  706.        end; { Case }
  707.        Result := true;
  708.      Except
  709.        on E: Exception do begin
  710.           Error (FileName, E.Message);
  711.           Result := false;
  712.        end;
  713.      end; { try }
  714.  end; { SaveImage }
  715.  
  716.  function ImageSize (const FileName: string; var Width, Height : integer): boolean;
  717.  const
  718.      BufSize = 24;
  719.      BufHalf = 12;
  720.      BufTerm = 6;
  721.      BufOffs = 16;
  722.  type
  723.      TByteBuffer = packed array [0..Pred (BufSize)] of Byte;
  724.      TWordBuffer = packed array [0..Pred (BufHalf)] of Word;
  725.      TLongBuffer = packed array [0..Pred (BufTerm)] of integer;
  726.  var
  727.      Bytes : TByteBuffer;
  728.      Words : TWordBuffer absolute Bytes;
  729.      Longs : TLongBuffer absolute Bytes;
  730.      Image : THandle;
  731.      E, F  : boolean;
  732.      w, h  : word;
  733.      x     : word;
  734.      i     : integer;
  735.  
  736.      function SwapBytes (const Pos: integer): word;
  737.      var
  738.          R : TByteBuffer absolute Result;
  739.      begin
  740.          R [1] := Bytes [Pos];
  741.          R [0] := Bytes [Succ (Pos)];
  742.      end; { SwapBytes }
  743.  
  744.      function Swap32 (const Value: integer): integer;
  745.      var
  746.          P : TWordBuffer absolute Value;
  747.          R : TWordBuffer absolute Result;
  748.      begin
  749.          R [0] := Swap (P [1]);
  750.          R [1] := Swap (P [0]);
  751.      end; { Swap32 }
  752.  
  753.  begin
  754.    { init }
  755.      Result := false;
  756.    { open }
  757.      Image := FileOpen (Catalog + FileName, fmOpenRead);
  758.      if Image <= 0 then Exit;
  759.    { read buffer }
  760.      if FileRead (Image, Bytes, BufSize) = BufSize then begin
  761.       { by format }
  762.         Case Files of
  763.          { JPEG }
  764.            0: begin
  765.               E := false;
  766.               F := false;
  767.               Repeat
  768.                  i := 0;
  769.                { find markers }
  770.                  While i < BufSize do begin
  771.                    { ok }
  772.                      if Bytes [i] = $FF then begin
  773.                       { next }
  774.                         Inc (i);
  775.                       { shift }
  776.                         if i > BufOffs then begin
  777.                          { move }
  778.                            Longs [0] := Longs [4];
  779.                            Longs [1] := Longs [5];
  780.                          { add }
  781.                            E := FileRead (Image, Longs [2], BufOffs) <> BufOffs;
  782.                          { pos }
  783.                            Dec (i, BufOffs);
  784.                         end; { if }
  785.                       { segment marker }
  786.                         if F and (not E) then begin
  787.                            if Bytes [i] in [$C0, $C1, $C2, $C3] then begin
  788.                               Inc (i, 4);
  789.                               Height := SwapBytes (i);
  790.                               Inc (i, 2);
  791.                               Width := SwapBytes (i);
  792.                             { ok }
  793.                               E := true;
  794.                               Break;
  795.                            end { else }
  796.                            else if not (Bytes [i] in [$01, $D0..$D7, $FF]) then begin
  797.                             { length }
  798.                               w := SwapBytes (Succ (i));
  799.                             { skip }
  800.                               E := FileSeek (Image, w - Succ (BufSize) + i, 1) <= 0;
  801.                             { reset buffer }
  802.                               i := BufSize;
  803.                            end; { else if }
  804.                         end { if }
  805.                       { start marker }
  806.                         else F := (Bytes [i] = $D8);
  807.                      end { if }
  808.                    { next }
  809.                      else Inc (i);
  810.                  end; { While }
  811.             { exit or read }
  812.               Until E or (FileRead (Image, Bytes, BufSize) <> BufSize);
  813.            end; { 0 }
  814.          { BMP }
  815.            1: begin
  816.               Width := Words [9];
  817.               Height := Words [11];
  818.            end; { 1 }
  819.          { GIF }
  820.            2: begin
  821.               Width := Words [3];
  822.               Height := Words [4];
  823.            end; { 2 }
  824.          { TIFF }
  825.            3: begin
  826.             { swap tif }
  827.               E := Bytes[0] = 77;
  828.             { entry pos }
  829.               if E then i := Swap32 (Longs [1])
  830.                  else i := Longs [1];
  831.             { number of entries }
  832.               if (FileSeek (Image, i, 0) > 0) and (FileRead (Image, h, 2) = 2) then begin
  833.                  if E then h := Swap (h);
  834.                { each entry }
  835.                  i := 0;
  836.                  While (i < h) and ((Width = 0) or (Height = 0)) and
  837.                        (FileRead (Image, Bytes, BufHalf) = BufHalf)
  838.                  do begin
  839.                     if E then begin
  840.                        w := Swap(Words [0]);
  841.                        x := Swap(Words [1]);
  842.                     end { if }
  843.                     else begin
  844.                        w := Words [0];
  845.                        x := Words [1];
  846.                     end; { else }
  847.                   { width entry }
  848.                     if w = 256 then begin
  849.                        Case x of
  850.                           1: Width := Bytes [8];
  851.                           3: if E then Width := Swap(Words [4]) else Width := Words [4];
  852.                           4: if E then Width := Swap32(Longs [2]) else Width := Longs [2];
  853.                        end; { Case }
  854.                     end { if }
  855.                   { height entry }
  856.                     else if w = 257 then begin
  857.                        Case x of
  858.                           1: Height := Bytes [8];
  859.                           3: if E then Height := Swap(Words [4]) else Height := Words [4];
  860.                           4: if E then Height := Swap32(Longs [2]) else Height := Longs [2];
  861.                        end; { Case }
  862.                     end; { if }
  863.                     Inc (i);
  864.                  end; { While }
  865.               end; { if }
  866.            end; { 3 }
  867.          { PCX }
  868.            4: begin
  869.               Width := Succ (Words[4] - Words [2]);
  870.               Height := Succ (Words[5] - Words[3]);
  871.            end; { 4 }
  872.          { PNG }
  873.            5: begin
  874.               Width := Swap(Words [9]);
  875.               Height := Swap(Words [11]);
  876.            end; { 5 }
  877.          { unsupported }
  878.            else Error (FileName, 'Unsupported format')
  879.         end; { Case }
  880.      end; { if }
  881.    { close }
  882.      FileClose (Image);
  883.    { result }
  884.      if (Width <= 0) or (Height <= 0) or  (Width > MAXSHORT) or (Height > MAXSHORT)
  885.      then begin
  886.         Error (FileName, 'Image format is not correct');
  887.         Result := false;
  888.      end { if }
  889.      else Result := true;
  890.  end; { ImageSize }
  891.  
  892. (*************************************************************************)
  893. (*                         operations support                            *)
  894. (*************************************************************************)
  895.  function ResizeBmp (Bmp: TBitMap; const Name: string): boolean;
  896.  var
  897.      S     : single;
  898.      w, h  : integer;
  899.  begin
  900.   { custom size }
  901.     if fCustom then begin
  902.        if not ThumbnailBmp (Bmp, CtmWidth, CtmHeight, AnchorX, AnchorY, CtmMode, FillColor)
  903.        then begin
  904.           Error (Name, 'Cannot create thumbnail because image is too small');
  905.           Result := false;
  906.        end { if }
  907.        else Result := true;
  908.     end { if }
  909.   { scale }
  910.     else begin
  911.        w := Bmp.Width;
  912.        h := Bmp.Height;
  913.        S := ((w * h) / (h + w)) / (30 + (Scale * 2.5));
  914.        Result := ThumbnailBmp (Bmp, nil, S, S);
  915.     end; { else }
  916.  end; { ResizeBmp }
  917.  
  918.  function Include (Bmp: TBitMap; const Name: string; W, H, Z: longword): boolean;
  919.  var
  920.      S : string;
  921.      R : TRect;
  922.      q : integer;
  923.  
  924.      procedure Plus (const A: string);
  925.      begin
  926.          if S > '' then S := S + ' ' + A else S := A;
  927.      end; { Plus }
  928.  
  929.  begin
  930.      S := '';
  931.    { comment }
  932.      if Comment > '' then Plus (Comment);
  933.    { image size }
  934.      if fImgSize then Plus (SizeStr (W, H));
  935.    { file size }
  936.      if fFilSize then Plus (FileSizeStr (Z));
  937.    { font }
  938.      ParmsToFont (Bmp.Canvas.Font);
  939.    { width }
  940.      q := Bmp.Canvas.TextWidth (S);
  941.    { test }
  942.      if Bmp.Width >= Pred (q) then With Bmp do begin
  943.       { resize }
  944.         R.Left := 0;
  945.         R.Right := Width;
  946.         R.Top := Height;
  947.         Height := R.Top + Canvas.TextHeight ('X0');
  948.         R.Bottom := Height;
  949.       { bground }
  950.         Canvas.Brush.Color := BGround;
  951.         Canvas.FillRect (R);
  952.       { text }
  953.         R.Left := (Width - q) div 2;
  954.         Canvas.TextOut (R.Left, R.Top, S);
  955.       { ok }
  956.         Result := true;
  957.      end { if With }
  958.    { error }
  959.      else begin
  960.           Error (Name, 'Cannot include in the thumbnail because it is too small');
  961.           Result := false;
  962.      end; { else }
  963.  end; { Include }
  964.  
  965. (*************************************************************************)
  966. (*                           load\save parameters                        *)
  967. (*************************************************************************)
  968.  procedure ParmsToFont (Font: TFont);
  969.  begin
  970.      With Font do begin
  971.           Name := FontName;
  972.           Size := FontSize;
  973.           Color := FontColor;
  974.           if FontBold then Style := Style + [fsBold];
  975.           if FontItalic then Style := Style + [fsItalic];
  976.           if FontUnderline then Style := Style + [fsUnderline];
  977.           if FontStrikeOut then Style := Style + [fsStrikeOut];
  978.      end; { With }
  979.  end; { ParmsToFont }
  980.  
  981.  procedure FontToParms (Font: TFont);
  982.  begin
  983.      With Font do begin
  984.           FontName := Name;
  985.           FontSize := Size;
  986.           FontColor := Color;
  987.           FontBold := fsBold in Style;
  988.           FontItalic := fsItalic in Style;
  989.           FontUnderline := fsUnderline in Style;
  990.           FontStrikeOut := fsStrikeOut in Style;
  991.      end; { With }
  992.  end; { FontToParms }
  993.  
  994.  procedure SaveParameters (Path, Colors: TStrings);
  995.  
  996.    procedure AddStr (const Name, Value: string);
  997.    begin
  998.        Params.Add (Name + '=' + Value);
  999.    end; { AddStr }
  1000.  
  1001.    procedure AddInt (const Name: string; Value: integer);
  1002.    begin
  1003.        AddStr (Name, IntToStr (Value));
  1004.    end; { AddInt }
  1005.  
  1006.  var
  1007.      i : integer;
  1008.  begin
  1009.      Params.Clear;
  1010.      Try
  1011.      { main }
  1012.        if Path = nil then begin
  1013.           AddStr (psPath + '0', Catalog);
  1014.           PathIndex := 0;
  1015.        end { if }
  1016.        else begin
  1017.             for i := 0 to Pred (Path.Count) do AddStr (psPath + IntToStr (i), Path [i]);
  1018.             if PathIndex < 0 then PathIndex := 0;
  1019.        end; { else }
  1020.        AddInt (psPathIndex, PathIndex);
  1021.        AddInt (psFiles, Files);
  1022.        AddInt (psPanelIndex, PanelIndex);
  1023.        AddInt (psSortList, Byte (fSortList));
  1024.      { numerate }
  1025.        AddInt (psRename, Byte(fRename));
  1026.        AddInt (psOrder, Order);
  1027.        AddInt (psDecs, Byte(fDecs));
  1028.        AddInt (psFirstNum, FirstNum);
  1029.        AddInt (psNextFirst, Byte (NextFirst));
  1030.        AddInt (psDigits, Digits);
  1031.        AddInt (psStepCount, StepCount);
  1032.        AddStr (psPrefix, Prefix);
  1033.        AddStr (psPostfix, Postfix);
  1034.        AddInt (psAttribute, Byte(fAttribute));
  1035.        AddInt (psFileTime, Byte(fFileTime));
  1036.      { thumbnails }
  1037.        AddInt (psThumbnail, Byte(fThumbnail));
  1038.        AddStr (psMark, Mark);
  1039.        AddInt (psScale, Scale);
  1040.        AddInt (psThumbnailQuality, ThumbnailQuality);
  1041.      { custom }
  1042.        AddInt (psCustom, Byte(fCustom));
  1043.        AddInt (psCtmWidth, CtmWidth);
  1044.        AddInt (psCtmHeight, CtmHeight);
  1045.        AddInt (psCtmMode, Byte(CtmMode));
  1046.        AddInt (psAnchorX, AnchorX);
  1047.        AddInt (psAnchorY, AnchorY);
  1048.        AddInt (psFillColor, FillColor);
  1049.      { include }
  1050.        AddInt (psInclude, Byte (fInclude));
  1051.        AddStr (psComment, Comment);
  1052.        AddInt (psImgSize, Byte (fImgSize));
  1053.        AddInt (psFilSize, Byte (fFilSize));
  1054.        AddStr (psFontName, FontName);
  1055.        AddInt (psFontColor, FontColor);
  1056.        AddInt (psFontSize, FontSize);
  1057.        AddInt (psBGround, BGround);
  1058.      { font style }
  1059.        AddInt (psFontBold, Byte (FontBold));
  1060.        AddInt (psFontItalic, Byte (FontItalic));
  1061.        AddInt (psFontUnderline, Byte (FontUnderline));
  1062.        AddInt (psFontStrikeOut, Byte (FontStrikeOut));
  1063.      { collection }
  1064.        AddInt (psCollection, Byte (fCollection));
  1065.        AddInt (psDuplicate, Byte (fDuplicate));
  1066.        AddInt (psLikeness, Likeness);
  1067.        AddInt (psDescription, Byte (fDescription));
  1068.      { autosave }
  1069.        AddInt (psAutoSave, Byte(AutoSave));
  1070.      { colors }
  1071.        if Colors <> nil then Params.AddStrings (Colors);
  1072.      { forms }
  1073.        AddInt (psMainLeft, MainLeft);
  1074.        AddInt (psMainTop, MainTop);
  1075.        AddInt (psMainWidth, MainWidth);
  1076.        AddInt (psMainHeight, MainHeight);
  1077.        AddInt (psViewWidth, ViewWidth);
  1078.        AddInt (psViewHeight, ViewHeight);
  1079.        AddInt (psViewLeft, ViewLeft);
  1080.        AddInt (psViewTop, ViewTop);
  1081.      { save }
  1082.        Params.SaveToFile (IniFile);
  1083.      Except
  1084.           on E: Exception do Error (IniFile, E.Message);
  1085.      end; { try }
  1086.  end; { SaveParameters }
  1087.  
  1088.  function LoadParameters (Path, Colors: TStrings): boolean;
  1089.  var
  1090.      Value : integer;
  1091.      Line  : string;
  1092.  
  1093.    procedure Alert (const Name: string);
  1094.    begin
  1095.        Error (IniFile, 'The parameter "' + Name + '" is incorrect');
  1096.        Result := false;
  1097.    end; { Alert }
  1098.  
  1099.    function GetStr (const Name: string; Min, Max: integer): boolean;
  1100.    var
  1101.        i, j : integer;
  1102.    begin
  1103.        Result := false;
  1104.        for i := 0 to Pred (Params.Count) do begin
  1105.            Line := Params [i];
  1106.            j := AnsiPos ('=', Line);
  1107.            if (j > 0) and (AnsiCompareText (Trim (Copy (Line, 1, j - 1)), Name) = 0)
  1108.            then begin
  1109.               Line := Trim (Copy (Line, j + 1, Length (Line) - j));
  1110.               j := Length (Line);
  1111.               if (j >= Min) and (j <= Max) then Result := true
  1112.                  else Alert (Name);
  1113.               Params.Delete (i);
  1114.               Exit;
  1115.            end; { if }
  1116.        end; { for }
  1117.    end; { GetStr }
  1118.  
  1119.    function GetInt (const Name: string; Min, Max: integer): boolean;
  1120.    begin
  1121.        Result := false;
  1122.        if GetStr (Name, 1, 10) then begin
  1123.           if StrToInt (Line, Value) and (Value >= Min) and (Value <= Max) then Result := true
  1124.              else Alert (Name);
  1125.        end; { if }
  1126.    end; { GetInt }
  1127.  
  1128.  var
  1129.      S    : string;
  1130.      i, j : integer;
  1131.  begin
  1132.      Result := true;
  1133.      Try
  1134.         Params.LoadFromFile (IniFile);
  1135.       { path }
  1136.         if GetInt (psPathIndex, 0, Pred (MaxHistory)) then PathIndex := Value;
  1137.         j := 0;
  1138.         for i := 0 to Pred (MaxHistory) do begin
  1139.             if GetStr (psPath + IntToStr (i), 1, MAX_PATH) then begin
  1140.                Line := PathDelimiter (AnsiUpperCase (Line));
  1141.                if i = PathIndex then Catalog := Line;
  1142.                if Path <> nil then Path.Add (Line);
  1143.                Inc (j);
  1144.             end; { if }
  1145.         end; { for }
  1146.       { test }
  1147.         if PathIndex >= j then begin
  1148.            Alert (psPathIndex);
  1149.            PathIndex := -1;
  1150.         end; { if }
  1151.         if GetInt (psFiles, MinFormat, MaxFormat) then Files := Value;
  1152.         if GetInt (psPanelIndex, 0, MaxPanel) then PanelIndex := Value;
  1153.         if GetInt (psSortList, 0, 1) then fSortList := Boolean (Value);
  1154.       { numerate }
  1155.         if GetInt (psRename, 0, 1) then fRename := Boolean (Value);
  1156.         if GetInt (psOrder, MinOrder, MaxOrder) then Order := Value;
  1157.         if GetInt (psDecs, 0, 1) then fDecs := Boolean (Value);
  1158.         if GetInt (psFirstNum, MinFirst, MaxFirst) then FirstNum := Value;
  1159.         if GetInt (psNextFirst, 0, 1) then NextFirst := Boolean (Value);
  1160.         if GetInt (psDigits, MinDigits, MaxDigits) then Digits := Value;
  1161.         if GetInt (psStepCount, MinStep, MaxStep) then StepCount := Value;
  1162.         if GetStr (psPrefix, 0, LenNamePart) then Prefix := Line;
  1163.         if GetStr (psPostfix, 0, LenNamePart) then Postfix := Line;
  1164.         if GetInt (psAttribute, 0, 1) then fAttribute := Boolean (Value);
  1165.         if GetInt (psFileTime, 0, 1) then fFileTime := Boolean (Value);
  1166.       { thumbnails }
  1167.         if GetInt (psThumbnail, 0, 1) then fThumbnail := Boolean (Value);
  1168.         if GetStr (psMark, 1, LenNamePart) then Mark := Line;
  1169.         if GetInt (psScale, MinScale, MaxScale) then Scale := Value;
  1170.         if GetInt (psThumbnailQuality, MinQuality, MaxQuality) then ThumbnailQuality := Value;
  1171.       { custom }
  1172.         if GetInt (psCustom, 0, 1) then fCustom := Boolean (Value);
  1173.         if GetInt (psCtmWidth, MinCustom, MaxCustom) then CtmWidth := Value;
  1174.         if GetInt (psCtmHeight, MinCustom, MaxCustom) then CtmHeight := Value;
  1175.         if GetInt (psCtmMode, 0, 1) then CtmMode := Boolean (Value);
  1176.         if GetInt (psAnchorX, MinAnchor, MaxAnchor) then AnchorX := Value;
  1177.         if GetInt (psAnchorY, MinAnchor, MaxAnchor) then AnchorY := Value;
  1178.         if GetInt (psFillColor, MinColor, MaxColor) then FillColor := Value;
  1179.       { include }
  1180.         if GetInt (psInclude, 0, 1) then fInclude := Boolean (Value);
  1181.         if GetStr (psComment, 0, LenComment) then Comment := Line;
  1182.         if GetInt (psImgSize, 0, 1) then fImgSize := Boolean (Value);
  1183.         if GetInt (psFilSize, 0, 1) then fFilSize := Boolean (Value);
  1184.         if GetStr (psFontName, 0, 128) then FontName := Line;
  1185.         if GetInt (psFontColor, MinColor, MaxColor) then FontColor := Value;
  1186.         if GetInt (psFontSize, MinFont, MaxFont) then FontSize := Value;
  1187.         if GetInt (psBGround, MinColor, MaxColor) then BGround := Value;
  1188.       { font style }
  1189.         if GetInt (psFontBold, 0, 1) then FontBold := Boolean (Value);
  1190.         if GetInt (psFontItalic, 0, 1) then FontItalic := Boolean (Value);
  1191.         if GetInt (psFontUnderline, 0, 1) then FontUnderline := Boolean (Value);
  1192.         if GetInt (psFontStrikeOut, 0, 1) then FontStrikeOut := Boolean (Value);
  1193.       { collection }
  1194.         if GetInt (psCollection, 0, 1) then fCollection := Boolean (Value);
  1195.         if GetInt (psDuplicate, 0, 1) then fDuplicate := Boolean (Value);
  1196.         if GetInt (psLikeness, MinLike, MaxLike) then Likeness := Value;
  1197.         if GetInt (psDescription, 0, 1) then fDescription := Boolean (Value);
  1198.       { autosave }
  1199.         if GetInt (psAutoSave, 0, 1) then AutoSave := Boolean (Value);
  1200.       { colors }
  1201.         if Colors <> nil then begin
  1202.            for i := 0 to 15 do begin
  1203.                S := psColors + Chr (i + Ord ('A'));
  1204.                if GetStr (S, 0, MaxColor) then Colors.Add (S + '=' + Line);
  1205.            end; { for }
  1206.         end; { if }
  1207.       { forms }
  1208.         i := Screen.DesktopWidth - MinLeft;
  1209.         j := Screen.DesktopHeight - MinTop;
  1210.         if GetInt (psMainLeft, MinLeft, i) then MainLeft := Value;
  1211.         if GetInt (psMainTop, MinTop, j) then MainTop := Value;
  1212.         if GetInt (psMainWidth, MinWidth, i) then MainWidth := Value;
  1213.         if GetInt (psMainHeight, MinHeight, j) then MainHeight := Value;
  1214.         if GetInt (psViewWidth, MinView, i) then ViewWidth := Value;
  1215.         if GetInt (psViewHeight, MinView, j) then ViewHeight := Value;
  1216.         if GetInt (psViewLeft, MinLeft, i) then ViewLeft := Value;
  1217.         if GetInt (psViewTop, MinTop, j) then ViewTop := Value;
  1218.       { test }
  1219.         if Params.Count > 0 then Alert (Params [0]);
  1220.       Except
  1221.         on E: Exception do begin
  1222.            Error (IniFile, E.Message);
  1223.            Result := false;
  1224.         end; { on }
  1225.       end; { try }
  1226.  end; { LoadParameters }
  1227.  
  1228. (*************************************************************************)
  1229. (*                             compare                                   *)
  1230. (*************************************************************************)
  1231.  function CmpNumber (F, S: pointer): integer;
  1232.  var
  1233.      A, B : string;
  1234.      C, D : string;
  1235.      X, Y : string;
  1236.      n, k : integer;
  1237.  begin
  1238.      DecodeName (PImageInfo (F)^.Name, A, C, X);
  1239.      DecodeName (PImageInfo (S)^.Name, B, D, Y);
  1240.      Result := AnsiCompareText (A, B);
  1241.      if (Result = 0) and StrToInt (C, n) and StrToInt (D, k) then Result := n - k;
  1242.      if Result = 0 then Result := AnsiCompareText (C, D);
  1243.      if Result = 0 then Result := AnsiCompareText (X, Y);
  1244.      if fDecs then Result := - Result;
  1245.  end; { CmpNumber }
  1246.  
  1247.  function CmpSize (F, S: pointer): integer;
  1248.  begin
  1249.      Result := PImageInfo (F)^.Size - PImageInfo (S)^.Size;
  1250.      if fDecs then Result := - Result;
  1251.  end; { CmpSize }
  1252.  
  1253.  function CmpTime (F, S: pointer): integer;
  1254.  begin
  1255.      Result := CompareFileTime (PImageInfo (F)^.Time, PImageInfo (S)^.Time);
  1256.      if Result = 0 then Result := PImageInfo (F)^.Size - PImageInfo (S)^.Size;
  1257.      if fDecs then Result := - Result;
  1258.  end; { CmpTime }
  1259.  
  1260.  function CmpHeight (F, S: pointer): integer;
  1261.  begin
  1262.      Result := PImageInfo (F)^.Height - PImageInfo (S)^.Height;
  1263.      if Result = 0 then Result := PImageInfo (F)^.Width - PImageInfo (S)^.Width;
  1264.      if Result = 0 then Result := PImageInfo (F)^.Size - PImageInfo (S)^.Size;
  1265.      if fDecs then Result := - Result;
  1266.  end; { CmpHeight }
  1267.  
  1268.  function CmpWidth (F, S: pointer): integer;
  1269.  begin
  1270.      Result := PImageInfo (F)^.Width - PImageInfo (S)^.Width;
  1271.      if Result = 0 then Result := PImageInfo (F)^.Height - PImageInfo (S)^.Height;
  1272.      if Result = 0 then Result := PImageInfo (F)^.Size - PImageInfo (S)^.Size;
  1273.      if fDecs then Result := - Result;
  1274.  end; { CmpWidth }
  1275.  
  1276.  function CmpTemp (F, S: pointer): integer;
  1277.  begin
  1278.      Result := PImageInfo (F)^.Temp - PImageInfo (S)^.Temp;
  1279.      if Result = 0 then Result := PImageInfo (F)^.Size - PImageInfo (S)^.Size;
  1280.      if fDecs then Result := - Result;
  1281.  end; { CmpTemp }
  1282.  
  1283. (*************************************************************************)
  1284. (*                                image list                             *)
  1285. (*************************************************************************)
  1286.  Const
  1287.      faUse = faAnyFile and (not faVolumeID) and (not faDirectory);
  1288.  
  1289.  constructor TImageList.Create;
  1290.  begin
  1291.      inherited Create;
  1292.      Capacity := 512;
  1293.      Drop;
  1294.  end; { Create }
  1295.  
  1296.  procedure TImageList.Drop;
  1297.  begin
  1298.      SortOrder := -1;
  1299.      Decrease  := false;
  1300.      HaveSize  := false;
  1301.      HaveData  := false;
  1302.      ViewCount := 0;
  1303.  end; { Drop }
  1304.  
  1305.  procedure TImageList.DisposeItem (var P: PImageInfo);
  1306.  begin
  1307.      if P <> nil then begin
  1308.         SetLength (P^.Name, 0);
  1309.         if P^.Data <> nil then FreeMem (P^.Data);
  1310.         Dispose (P);
  1311.         P := nil;
  1312.      end; { if }
  1313.  end; { DisposeItem }
  1314.  
  1315.  procedure TImageList.Clear;
  1316.  var
  1317.      i : integer;
  1318.  begin
  1319.      for i := 0 to Pred (Count) do begin
  1320.          if List [i] <> nil then begin
  1321.             DisposeItem (PImageInfo (List [i])^.Thumbnail);
  1322.             DisposeItem (PImageInfo (List [i]));
  1323.          end; { if }
  1324.      end; { for }
  1325.      Drop;
  1326.      inherited Clear;
  1327.  end; { Clear }
  1328.  
  1329.  procedure TImageList.InitInfo (var Find : TSearchRec; Info: PImageInfo);
  1330.  begin
  1331.      With Info^ do begin
  1332.         { file parm }
  1333.           Time := Find.FindData.ftLastWriteTime;
  1334.           Size := Find.Size;
  1335.           Attr := Find.Attr;
  1336.           Name := Find.Name;
  1337.         { image parm }
  1338.           Height := 0;
  1339.           Width := 0;
  1340.         { work }
  1341.           Thumbnail := nil;
  1342.           Temp := 0;
  1343.           Data := nil;
  1344.           if isThumbnail (Name) then Inc (ViewCount);
  1345.      end; { With }
  1346.  end; { InitInfo }
  1347.  
  1348.  function TImageList.NewData (P: PImageInfo): boolean;
  1349.  begin
  1350.      if P^.Data = nil then begin
  1351.         GetMem (P^.Data, SizeOf (TMatrix));
  1352.         Result := true;
  1353.      end { if }
  1354.      else Result := false;
  1355.  end; { NewData }
  1356.  
  1357.  function TImageList.Scan: boolean;
  1358.  var
  1359.      Find : TSearchRec;
  1360.      Info : PImageInfo;
  1361.  begin
  1362.    { init }
  1363.      Clear;
  1364.    { test path }
  1365.      if isPathExist (Catalog) then begin
  1366.         Result := true;
  1367.       { scan }
  1368.         if SysUtils.FindFirst (Catalog + '*' + Formats [Files], faUse, Find) = 0 then begin
  1369.            Repeat
  1370.                 New (Info);
  1371.                 InitInfo (Find, Info);
  1372.                 Add (Info);
  1373.            Until (SysUtils.FindNext (Find) <> 0);
  1374.         end; { if }
  1375.         SysUtils.FindClose (Find);
  1376.      end { if }
  1377.      else begin
  1378.           SysError (Catalog, ERROR_PATH_NOT_FOUND);
  1379.           Result := false;
  1380.      end; { else }
  1381.  end; { Scan }
  1382.  
  1383.  procedure TImageList.Start (const Mssg: string);
  1384.  begin
  1385.      Inform (BegPrefix + AnyPrefix + Mssg);
  1386.  end; { Start }
  1387.  
  1388.  procedure TImageList.Stop;
  1389.  begin
  1390.      Inform (EndPrefix + AnyPrefix + 'Done');
  1391.  end; { Stop }
  1392.  
  1393.  procedure TImageList.MarkChange;
  1394.  var
  1395.      i : integer;
  1396.  begin
  1397.      ViewCount := 0;
  1398.      for i := 0 to Pred (Count)
  1399.       do if isThumbnail (PImageInfo (List[i])^.Name) then Inc (ViewCount);
  1400.  end; { MarkChange }
  1401.  
  1402.  procedure TImageList.SetTemp;
  1403.  var
  1404.      i : integer;
  1405.  begin
  1406.      for i := 0 to Pred (Count) do begin
  1407.          With PImageInfo (List[i])^ do begin
  1408.             Case Mode of
  1409.              { order }
  1410.                0: Temp := i;
  1411.              { image size }
  1412.                1: Temp := Width * Height;
  1413.              { image size }
  1414.                2: begin
  1415.                   if Height > 0 then Temp := Round ((Width / Height) * 1000)
  1416.                      else Temp := 0;
  1417.                end; { 2 }
  1418.              { random }
  1419.                3: Temp := Random (MaxInt);
  1420.              { clear }
  1421.                else Temp := 0;
  1422.             end; { Case }
  1423.          end; { With }
  1424.      end; { for }
  1425.  end; { SetTemp }
  1426.  
  1427.  function TImageList.LoadSize : boolean;
  1428.  var
  1429.      i : integer;
  1430.  begin
  1431.      Result := true;
  1432.    { test }
  1433.      if HaveSize then Exit;
  1434.    { mssg }
  1435.      Start ('Loading sizes of images');
  1436.    { load }
  1437.      for i := 0 to Pred (Count) do begin
  1438.          With PImageInfo (List[i])^ do begin
  1439.             if (Width = 0) or (Height = 0) then ImageSize (Name, Width, Height);
  1440.          end; { With }
  1441.        { abort }
  1442.          if isCancel then begin
  1443.             Result := false;
  1444.             Exit;
  1445.          end; { if }
  1446.      end; { for }
  1447.      if Result then begin
  1448.         HaveSize := true;
  1449.         Stop;
  1450.      end; { if }
  1451.  end; { LoadSize }
  1452.  
  1453.  function TImageList.Sort (Odr: TOrder; Dcs: boolean): boolean;
  1454.  var
  1455.      Cmp : TListSortCompare;
  1456.  begin
  1457.      Result := true;
  1458.      if (Odr = SortOrder) and (Decrease = Dcs) then Exit;
  1459.    { init }
  1460.      Case Odr of
  1461.         1: Cmp := @CmpSize;
  1462.         2: Cmp := @CmpTime;
  1463.         3: begin
  1464.            Result := LoadSize;
  1465.            Cmp := @CmpWidth;
  1466.         end; { 3 }
  1467.         4: begin
  1468.            Result := LoadSize;
  1469.            Cmp := @CmpHeight;
  1470.         end { 4 };
  1471.         5: begin
  1472.            Result := LoadSize;
  1473.            SetTemp (1);
  1474.            Cmp := @CmpTemp;
  1475.         end; { 5 }
  1476.         6: begin
  1477.            Result := LoadSize;
  1478.            SetTemp (2);
  1479.            Cmp := @CmpTemp;
  1480.         end; { 6 }
  1481.         7: begin
  1482.            SetTemp (3);
  1483.            Cmp := @CmpTemp;
  1484.         end; { 7 }
  1485.         else Cmp := @CmpNumber;
  1486.      end; { Case }
  1487.    { ok }
  1488.      if Result then begin
  1489.       { order }
  1490.         SortOrder := Odr;
  1491.       { exchange }
  1492.         Decrease := fDecs;
  1493.         fDecs := Dcs;
  1494.       { sort }
  1495.         inherited Sort (Cmp);
  1496.       { restore }
  1497.         fDecs := Decrease;
  1498.         Decrease := Dcs;
  1499.      end; { if }
  1500.  end; { Sort }
  1501.  
  1502.  function TImageList.Search (const Name: string; var Index: integer): boolean;
  1503.  var
  1504.      i : integer;
  1505.  begin
  1506.      for i := 0 to Pred (Count) do begin
  1507.          if (List[i] <> nil) and
  1508.             (AnsiCompareText (PImageInfo (List[i])^.Name, Name) = 0)
  1509.          then begin
  1510.             Index := i;
  1511.             Result := true;
  1512.             Exit;
  1513.          end; { if }
  1514.      end; { for }
  1515.      Result := false;
  1516.  end; { Search }
  1517.  
  1518.  function TImageList.isCancel : boolean;
  1519.  begin
  1520.      Application.ProcessMessages;
  1521.      if Cancel then Support.Error ('', 'Job was cancelled');
  1522.      Result := Cancel;
  1523.  end; { isCancel }
  1524.  
  1525.  function TImageList.SetReadOnly (P: PImageInfo; ReadOnly: boolean): boolean;
  1526.  var
  1527.      A : integer;
  1528.  begin
  1529.      if ReadOnly then A := P^.Attr or faReadOnly
  1530.         else A := P^.Attr and (not faReadOnly);
  1531.      Result := true;
  1532.    { change }
  1533.      if A <> P^.Attr then begin
  1534.         if not SetFileAttr (Catalog + P^.Name, A) then Result := false
  1535.            else P^.Attr := A;
  1536.      end; { if }
  1537.  end; { SetReadOnly }
  1538.  
  1539.  function TImageList.Pack: boolean;
  1540.  var
  1541.      P    : PImageInfo;
  1542.      i, j : integer;
  1543.  begin
  1544.      Result := true;
  1545.      Start ('Conformity test');
  1546.    { have thumbnails }
  1547.      if ViewCount > 0 then begin
  1548.       { find thumbnails }
  1549.         for i := 0 to Pred (Count) do begin
  1550.             P := PImageInfo (List [i]);
  1551.             if (P <> nil) and (not isThumbnail (P^.Name)) and
  1552.                Search (ThumbnailName (P^.Name), j)
  1553.             then begin
  1554.                  P^.Thumbnail := List [j];
  1555.                  List [j] := nil;
  1556.             end; { if }
  1557.         end; { for }
  1558.       { pack and test }
  1559.         for i := Pred (Count) downto 0 do begin
  1560.             P := PImageInfo (List [i]);
  1561.             if P <> nil then begin
  1562.               { invalid thumnail }
  1563.                if P^.Thumbnail = nil then begin
  1564.                   if isThumbnail (P^.Name) then begin
  1565.                      Support.Error (P^.Name, 'The program cannot find the image for the thumbnail');
  1566.                      Result := false;
  1567.                   end { if }
  1568.                   else if not fThumbnail then begin
  1569.                      Warning (P^.Name, 'The program cannot find the thumbnail for the image');
  1570.                   end; { if }
  1571.                end; { if }
  1572.             end { if }
  1573.             else Delete (i);
  1574.           { cancel }
  1575.             if isCancel then begin
  1576.                Result := false;
  1577.                Exit;
  1578.             end; { if }
  1579.         end; { for }
  1580.      end; { if }
  1581.      Stop;
  1582.  end; { Pack }
  1583.  
  1584.  function TImageList.CreateThumbnails: boolean;
  1585.  var
  1586.      P    : PImageInfo;
  1587.      Bmp  : TBitMap;
  1588.      Find : TSearchRec;
  1589.      E    : boolean;
  1590.      i    : integer;
  1591.  begin
  1592.      Start ('Creating thumbnails');
  1593.    { init }
  1594.      Bmp := TBitMap.Create;
  1595.    { create }
  1596.      for i := 0 to Pred (Count) do begin
  1597.          P := List [i];
  1598.        { open & convert }
  1599.          if LoadImage (Bmp, P^.Name) >= 0 then begin
  1600.           { parms }
  1601.             P^.Height := Bmp.Height;
  1602.             P^.Width := Bmp.Width;
  1603.           { data }
  1604.             if fDuplicate and NewData (P) then BmpMatrix (Bmp, P^.Data^);
  1605.           { resize }
  1606.             if ResizeBmp (Bmp, P^.Name) then begin
  1607.              { new }
  1608.                if P^.Thumbnail = nil then begin
  1609.                   New (P^.Thumbnail);
  1610.                   FillChar (P^.Thumbnail^, SizeOf (TImageInfo), #0);
  1611.                   P^.Thumbnail^.Name := ThumbnailName (P^.Name);
  1612.                   E := true;
  1613.                end { if }
  1614.                else E := false;
  1615.              { write comment }
  1616.                if fInclude then With P^ do Include (Bmp, Thumbnail^.Name, Width, Height, Size);
  1617.              { clear readonly & save }
  1618.                if (E or SetReadOnly (P^.Thumbnail, false)) and
  1619.                    SaveImage (Bmp, TrackToQuality (ThumbnailQuality), P^.Thumbnail^.Name)
  1620.                then begin
  1621.                 { init }
  1622.                   SysUtils.FindFirst (Catalog + P^.Thumbnail^.Name, faUse, Find);
  1623.                   InitInfo (Find, P^.Thumbnail);
  1624.                   SysUtils.FindClose (Find);
  1625.                 { thumbnail size }
  1626.                   With P^.Thumbnail^ do begin
  1627.                      Height := Bmp.Height;
  1628.                      Width := Bmp.Width;
  1629.                   end; { With }
  1630.                 { report }
  1631.                   With P^.Thumbnail^ do Inform (Name + ' ' + SizeStr (Width, Height) + ' ' + IntToStr (Size));
  1632.                end { if }
  1633.              { free }
  1634.                else if E then DisposeItem (P^.Thumbnail);
  1635.             end; { if }
  1636.          end; { if }
  1637.        { abort }
  1638.          if isCancel then Break;
  1639.      end; { for }
  1640.    { ok }
  1641.      if not Cancel then begin
  1642.         HaveData := fDuplicate;
  1643.         HaveSize := true;
  1644.         Result := true;
  1645.         Stop;
  1646.      end { if }
  1647.      else Result := false;
  1648.    { free }
  1649.      Bmp.Free;
  1650.  end; { Thumbnails }
  1651.  
  1652.  function TImageList.RenameImage (P: PImageInfo; const Name: string): boolean;
  1653.  
  1654.   function RenameFile (var Dst: string; const Src: string): boolean;
  1655.   begin
  1656.       Inform (Dst + ' ' + Src);
  1657.       Result := SysUtils.RenameFile (Catalog + Dst, Catalog + Src);
  1658.       if Result then Dst := Src
  1659.          else SysError (Dst, GetLastError);
  1660.   end; { RenameFile }
  1661.  
  1662.  begin
  1663.      Result := RenameFile (P^.Name, Name) and
  1664.          ((P^.Thumbnail = nil) or RenameFile (P^.Thumbnail^.Name, ThumbnailName (Name)));
  1665.  end; { RenameImage }
  1666.  
  1667.  function TImageList.Rename: boolean;
  1668.  
  1669.  var
  1670.      Img : PImageInfo;
  1671.      Tmp : string;
  1672.      i   : integer;
  1673.  
  1674.    function CircleRename (P: PImageInfo): boolean;
  1675.    var
  1676.        Cur : string;
  1677.        j   : integer;
  1678.    begin
  1679.      { end of circle }
  1680.        if P^.Temp < 0  then begin
  1681.           Result := RenameImage (P, Tmp);
  1682.           Exit;
  1683.        end; { if }
  1684.      { new name }
  1685.        j := P^.Temp * StepCount + FirstNum;
  1686.        Cur := EncodeName  (j);
  1687.      { validate }
  1688.        if not isThumbnail (Cur) then begin
  1689.        { init }
  1690.          Result := true;
  1691.        { reset }
  1692.          P^.Temp := -1;
  1693.        { test }
  1694.          if P^.Name <> Cur then begin
  1695.           { test for exist }
  1696.             if AnsiCompareText (P^.Name, Cur) <> 0 then begin
  1697.                if Search (Cur, j) then Result := CircleRename (List [j]);
  1698.             end; { if }
  1699.          { rename }
  1700.             if Result then Result := RenameImage (P, Cur);
  1701.          end; { if }
  1702.        end { if }
  1703.      { error }
  1704.        else begin
  1705.           Support.Error (Cur, 'The filename ending is equal to the thumbnail mark');
  1706.           Result := false;
  1707.        end; { else }
  1708.    end; { CircleRename }
  1709.  
  1710.  begin
  1711.    { sort by order }
  1712.      if not Sort (Order, fDecs) then begin
  1713.         Result := false;
  1714.         Exit;
  1715.      end { if }
  1716.      else Result := true;
  1717.    { set order }
  1718.      SetTemp (0);
  1719.    { temp name }
  1720.      Repeat
  1721.           Tmp := AppName + IntToStr (Random (MaxInt)) + Formats [Files];
  1722.      Until not (isThumbnail (Tmp) or FileExists (Catalog + Tmp));
  1723.    { rename all }
  1724.      Start ('Renaming files');
  1725.      for i := 0 to Pred (Count) do begin
  1726.        { item }
  1727.          Img := List [i];
  1728.        { rename }
  1729.          if Img^.Temp >= 0 then begin
  1730.             Result := (not isCancel) and CircleRename (Img);
  1731.           { abort }
  1732.             if not Result then Exit;
  1733.          end; { if }
  1734.      end; { for }
  1735.      Stop;
  1736.    { set new first }
  1737.      if NextFirst then FirstNum := (Pred (Count) * StepCount + FirstNum) + StepCount;
  1738.  end; { Rename }
  1739.  
  1740.  function TImageList.UpdateTime (P: PImageInfo; const Time: TSystemTime): boolean;
  1741.  var
  1742.      H : THandle;
  1743.      T : TFileTime;
  1744.  begin
  1745.      Result := false;
  1746.    { drop redonly }
  1747.      if SetReadOnly (P, false) then begin
  1748.       { open }
  1749.         H := FileOpen (Catalog + P^.Name, fmOpenWrite);
  1750.         if H > 0 then begin
  1751.          { update }
  1752.            Result := SystemTimeToFileTime (Time, T) and SetFileTime (H, nil, nil, @T);
  1753.          { close }
  1754.            FileClose (H);
  1755.         end; { if }
  1756.       { error }
  1757.         if not Result then SysError (P^.Name, GetLastError)
  1758.            else P^.Time := T;
  1759.      end; { if }
  1760.  end; { UpdateTime }
  1761.  
  1762.  function TImageList.Update: boolean;
  1763.  const
  1764.      OneMSec : TDateTime = 1 / (1000 * 60 * 60 * 24);
  1765.  var
  1766.      P : PImageInfo;
  1767.      U : TSystemTime;
  1768.      T : TDateTime;
  1769.      i : integer;
  1770.  begin
  1771.      Result := true;
  1772.    { update time }
  1773.      if fFileTime then begin
  1774.       { init }
  1775.         Start ('Updating file time');
  1776.         GetSystemTime (U);
  1777.         T := SystemTimeToDateTime (U);
  1778.       { update }
  1779.          for i := 0 to Pred (Count) do begin
  1780.              P := List [i];
  1781.            { time }
  1782.              T := T + OneMSec;
  1783.              DateTimeToSystemTime (T, U);
  1784.            { image }
  1785.              Result := (not isCancel) and UpdateTime (P, U) and
  1786.                        ((P^.Thumbnail = nil) or UpdateTime (P^.Thumbnail, U));
  1787.            { abort }
  1788.              if not Result then Exit;
  1789.          end; { for }
  1790.          Stop;
  1791.      end; { if }
  1792.    { read only }
  1793.      if fAttribute then Start ('Setting readonly attribute')
  1794.         else Start ('Clearing readonly attribute');
  1795.      for i := 0 to Pred (Count) do begin
  1796.          P := List [i];
  1797.          Result := (not isCancel) and SetReadOnly (P, fAttribute) and
  1798.                    ((P^.Thumbnail = nil) or SetReadOnly (P^.Thumbnail, fAttribute));
  1799.        { abort }
  1800.          if not Result then Exit;
  1801.      end; { for }
  1802.      Stop;
  1803.  end; { Update }
  1804.  
  1805.  function TImageList.CreateDescription: boolean;
  1806.  var
  1807.      Line : string;
  1808.      Name : string;
  1809.      Data : Text;
  1810.      P    : PImageInfo;
  1811.      T    : TDateTime;
  1812.      i    : integer;
  1813.  begin
  1814.    { get size }
  1815.      if not LoadSize then begin
  1816.         Result := false;
  1817.         Exit;
  1818.      end; { if }
  1819.    { init }
  1820.      Name := Catalog + ScvName;
  1821.      Start ('Creating description file ' + Name);
  1822.    { open }
  1823.      if OpenText (Data, Name, true) then begin
  1824.         Result := true;
  1825.       { output }
  1826.         for i := 0 to Pred (Count) do begin
  1827.             P := List [i];
  1828.           { name }
  1829.             Line := P^.Name + TextBreak;
  1830.           { size }
  1831.             Line := Line + IntToStr (P^.Size) + TextBreak;
  1832.           { time }
  1833.             T := FileTimeToDateTime (P^.Time);
  1834.             Line := Line + DateTimeToStr (T) + TextBreak;
  1835.           { width & height }
  1836.             if (P^.Width > 0) and (P^.Height > 0) then begin
  1837.                 Line := Line + IntToStr (P^.Width) + TextBreak;
  1838.                 Line := Line + IntToStr (P^.Height);
  1839.             end; { if }
  1840.           { write }
  1841.             Writeln (Data, Line);
  1842.           { test }
  1843.             if IOResult <> 0 then begin
  1844.                SysError (Name, GetLastError);
  1845.                Result := false;
  1846.                Break;
  1847.             end; { if }
  1848.           { abort }
  1849.             if isCancel then begin
  1850.                Result := false;
  1851.                Break;
  1852.             end; { if }
  1853.         end; { for }
  1854.       { close }
  1855.         Close (Data);
  1856.         if Result then Stop;
  1857.      end { if }
  1858.      else begin
  1859.           SysError (Name, GetLastError);
  1860.           Result := false;
  1861.      end; { else }
  1862.  end; { CreateDescription }
  1863.  
  1864.  function TImageList.LoadData: boolean;
  1865.  var
  1866.      Bmp  : TBitMap;
  1867.      P    : PImageInfo;
  1868.      i    : integer;
  1869.  begin
  1870.      Result := true;
  1871.    { test }
  1872.      if HaveData then Exit;
  1873.    { init }
  1874.      Start ('Loading parameters of images');
  1875.      Bmp := TBitMap.Create;
  1876.    { get }
  1877.      for i := 0 to Pred (Count) do begin
  1878.          P := List [i];
  1879.        { matrix }
  1880.          if P^.Data = nil then begin
  1881.             if LoadImage (Bmp, P^.Name) >= 0 then begin
  1882.                P^.Width := Bmp.Width;
  1883.                P^.Height := Bmp.Height;
  1884.                NewData (P);
  1885.                BmpMatrix (Bmp, P^.Data^);
  1886.             end; { if }
  1887.          end; { if }
  1888.        { abort }
  1889.          if isCancel then begin
  1890.             Result := false;
  1891.             Break;
  1892.          end; { if }
  1893.      end; { for }
  1894.    { free }
  1895.      Bmp.Free;
  1896.    { flags }
  1897.      if Result then begin
  1898.         HaveData := true;
  1899.         HaveSize := true;
  1900.         Stop;
  1901.      end; { if }
  1902.  end; { LoadData }
  1903.  
  1904.  function TImageList.FindDups: boolean;
  1905.  var
  1906.      P, S : PImageInfo;
  1907.      i, j : integer;
  1908.  begin
  1909.    { init database }
  1910.      if not LoadData then begin
  1911.         Result := false;
  1912.         Exit;
  1913.      end { if }
  1914.      else Result := true;
  1915.    { init }
  1916.      Start ('Finding duplicate images');
  1917.      SetTemp (0);
  1918.    { scasn }
  1919.      for i := 0 to Pred (Count) do begin
  1920.          P := List [i];
  1921.          if (P <> nil) and (P^.Data <> nil) and (P^.Temp >= 0) then begin
  1922.             for j := Succ (i) to Pred (Count) do begin
  1923.                 S := List [j];
  1924.                 if (S <> nil) and (S^.Data <> nil) and (S^.Temp >= 0) and
  1925.                    EquMatrix (P^.Data, S^.Data, TrackToLikeness (Likeness))
  1926.                 then begin
  1927.                      Warning (P^.Name, 'The file maybe equal to "' + S^.Name + '"');
  1928.                      S^.Temp := -1;
  1929.                 end; { if }
  1930.             end; { for }
  1931.          end; { if }
  1932.        { abort }
  1933.          if isCancel then begin
  1934.              Result := false;
  1935.              Break;
  1936.          end; { if }
  1937.      end; { for }
  1938.      if Result then Stop;
  1939.  end; { FindDups }
  1940.  
  1941.  function TImageList.Run: boolean;
  1942.  begin
  1943.      AppTitle;
  1944.    { init }
  1945.      Inform ('START ' + DateTimeToStr (Now) + ' ' + Catalog);
  1946.      Cancel := false;
  1947.    { pack and test }
  1948.      if Pack then begin
  1949.       { thumbnails }
  1950.         if fThumbnail then Result := CreateThumbnails
  1951.            else Result := true;
  1952.       { rename }
  1953.         if Result and fRename then Result := Rename and Update;
  1954.       { create description }
  1955.         if Result and fCollection then begin
  1956.            if fDuplicate then Result := FindDups;
  1957.            if Result and fDescription then Result := CreateDescription;
  1958.         end; { if }
  1959.      end { if }
  1960.      else Result := false;
  1961.      Inform ('STOP ' + DateTimeToStr (Now));
  1962.  end; { Run }
  1963.  
  1964. (*************************************************************************)
  1965. (*                                  init                                 *)
  1966. (*************************************************************************)
  1967.  initialization
  1968.    { self path }
  1969.      ExePath := PathDelimiter (ExtractFilePath (ParamStr (0)));
  1970.      Catalog := ExePath;
  1971.    { ini-file name }
  1972.      IniFile := ParamStr (1);
  1973.      if IniFile = '' then IniFile := ExePath + IniName;
  1974.    { autorun }
  1975.      RunAuto := AnsiCompareText (ParamStr (2), ParmAuto) = 0;
  1976.    { lists }
  1977.      Params := TStringList.Create;
  1978.    { init }
  1979.      Randomize;
  1980.    { image list }
  1981.      Images := TImageList.Create;
  1982.  
  1983.   finalization
  1984.      Images.Free;
  1985.      Params.Free;
  1986.  
  1987.  End.
  1988.