home *** CD-ROM | disk | FTP | other *** search
/ io Programmo 23 / IOPROG_23.ISO / SOFT / DELPHIX.ZIP / Source / DIB.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1998-10-06  |  80.9 KB  |  3,139 lines

  1. unit DIB;
  2.  
  3. interface
  4.  
  5. {$INCLUDE DelphiXcfg.inc}
  6.  
  7. uses
  8.   Windows, SysUtils, Classes, Graphics, Controls;
  9.  
  10. type
  11.   TRGBQuads = array[0..255] of TRGBQuad;
  12.  
  13.   TPaletteEntries = array[0..255] of TPaletteEntry;
  14.  
  15.   PBGR = ^TBGR;
  16.   TBGR = packed record
  17.     B, G, R: Byte;
  18.   end;
  19.  
  20.   PArrayBGR = ^TArrayBGR;
  21.   TArrayBGR = array[0..0] of TBGR;
  22.  
  23.   PArrayByte = ^TArrayByte;
  24.   TArrayByte = array[0..0] of Byte;
  25.  
  26.   PArrayWord = ^TArrayWord;
  27.   TArrayWord = array[0..0] of Word;
  28.  
  29.   PArrayDWord = ^TArrayDWord;
  30.   TArrayDWord = array[0..0] of DWord;
  31.  
  32.   {  TDIB  }
  33.  
  34.   TDIBPixelFormat = record
  35.     RBitMask, GBitMask, BBitMask: Integer;
  36.     RBitCount, GBitCount, BBitCount: Integer;
  37.     RShift, GShift, BShift: Integer;
  38.     RBitCount2, GBitCount2, BBitCount2: Integer;
  39.   end;
  40.  
  41.   TDIBSharedImage = class(TSharedImage)
  42.   private       
  43.     FBitCount: Integer;
  44.     FBitmapInfo: PBitmapInfo;
  45.     FBitmapInfoSize: Integer;
  46.     FChangePalette: Boolean;
  47.     FColorTable: TRGBQuads;
  48.     FColorTablePos: Integer;
  49.     FCompressed: Boolean;
  50.     FDC: THandle;
  51.     FHandle: THandle;
  52.     FHeight: Integer;
  53.     FMemoryImage: Boolean;
  54.     FNextLine: Integer;
  55.     FOldHandle: THandle;
  56.     FPalette: HPalette;
  57.     FPaletteCount: Integer;
  58.     FPBits: Pointer;
  59.     FPixelFormat: TDIBPixelFormat;
  60.     FSize: Integer;
  61.     FTopPBits: Pointer;
  62.     FWidth: Integer;
  63.     FWidthBytes: Integer;
  64.     constructor Create;
  65.     procedure NewImage(AWidth, AHeight, ABitCount: Integer;
  66.       const PixelFormat: TDIBPixelFormat; const ColorTable: TRGBQuads; MemoryImage, Compressed: Boolean);
  67.     procedure Duplicate(Source: TDIBSharedImage; MemoryImage: Boolean);
  68.     procedure Compress(Source: TDIBSharedImage);
  69.     procedure Decompress(Source: TDIBSharedImage; MemoryImage: Boolean);
  70.     procedure ReadData(Stream: TStream; MemoryImage: Boolean);
  71.     function GetPalette: THandle;
  72.     procedure SetColorTable(const Value: TRGBQuads);
  73.   protected
  74.     procedure FreeHandle; override;
  75.   public
  76.     destructor Destroy; override;
  77.   end;
  78.  
  79.   TDIB = class(TGraphic)
  80.   private
  81.     FCanvas: TCanvas;
  82.     FImage: TDIBSharedImage;    
  83.  
  84.     FProgressName: string;
  85.     FProgressOldY: DWORD;
  86.     FProgressOldTime: DWORD;
  87.     FProgressOld: DWORD;
  88.     FProgressY: DWORD;
  89.     {  For speed-up  }
  90.     FBitCount: Integer;
  91.     FHeight: Integer;
  92.     FNextLine: Integer;
  93.     FNowPixelFormat: TDIBPixelFormat;
  94.     FPBits: Pointer;
  95.     FSize: Integer;
  96.     FTopPBits: Pointer;
  97.     FWidth: Integer;
  98.     FWidthBytes: Integer;
  99.     procedure CanvasChanging(Sender: TObject);
  100.     procedure Changing(MemoryImage: Boolean);
  101.     procedure ConvertBitCount(ABitCount: Integer);
  102.     function GetBitmapInfo: PBitmapInfo;
  103.     function GetBitmapInfoSize: Integer;
  104.     function GetCanvas: TCanvas;
  105.     function GetHandle: THandle;
  106.     function GetPaletteCount: Integer;
  107.     function GetPixel(X, Y: Integer): DWORD;
  108.     function GetPBits: Pointer;
  109.     function GetScanLine(Y: Integer): Pointer;
  110.     function GetTopPBits: Pointer;
  111.     procedure SetBitCount(Value: Integer);
  112.     procedure SetImage(Value: TDIBSharedImage);
  113.     procedure SetNowPixelFormat(const Value: TDIBPixelFormat);
  114.     procedure SetPixel(X, Y: Integer; Value: DWORD);
  115.     procedure StartProgress(const Name: string);
  116.     procedure EndProgress;
  117.     procedure UpdateProgress(PercentY: Integer);
  118.   protected
  119.     procedure DefineProperties(Filer: TFiler); override;
  120.     procedure Draw(ACanvas: TCanvas; const Rect: TRect); override;
  121.     function GetEmpty: Boolean; override;
  122.     function GetHeight: Integer; override;
  123.     function GetPalette: HPalette; override;
  124.     function GetWidth: Integer; override;
  125.     procedure ReadData(Stream: TStream); override;
  126.     procedure SetHeight(Value: Integer); override;
  127.     procedure SetPalette(Value: HPalette); override;
  128.     procedure SetWidth(Value: Integer); override;
  129.     procedure WriteData(Stream: TStream); override;
  130.   public
  131.     ColorTable: TRGBQuads;
  132.     PixelFormat: TDIBPixelFormat;
  133.     constructor Create; override;
  134.     destructor Destroy; override;
  135.     procedure Assign(Source: TPersistent); override;
  136.     procedure Clear; virtual;
  137.     procedure Compress;
  138.     procedure Decompress;
  139.     procedure Dormant;
  140.     procedure FreeImage;
  141.     procedure LoadFromClipboardFormat(AFormat: Word; AData: THandle;
  142.       APalette: HPALETTE); override;
  143.     procedure LoadFromStream(Stream: TStream); override;
  144.     procedure SaveToClipboardFormat(var AFormat: Word; var AData: THandle;
  145.       var APalette: HPALETTE); override;
  146.     procedure SaveToStream(Stream: TStream); override;
  147.     procedure SetSize(AWidth, AHeight, ABitCount: Integer);
  148.     procedure UpdatePalette;
  149.     {  Special effect  }
  150.     procedure Blur(ABitCount: Integer; Radius: Integer);
  151.     procedure Greyscale(ABitCount: Integer);
  152.     procedure Mirror(MirrorX, MirrorY: Boolean);
  153.     procedure Negative;
  154.  
  155.     property BitCount: Integer read FBitCount write SetBitCount;
  156.     property BitmapInfo: PBitmapInfo read GetBitmapInfo;
  157.     property BitmapInfoSize: Integer read GetBitmapInfoSize;
  158.     property Canvas: TCanvas read GetCanvas;
  159.     property Handle: THandle read GetHandle;
  160.     property Height: Integer read FHeight write SetHeight;
  161.     property NextLine: Integer read FNextLine;
  162.     property NowPixelFormat: TDIBPixelFormat read FNowPixelFormat write SetNowPixelFormat;
  163.     property PaletteCount: Integer read GetPaletteCount;
  164.     property PBits: Pointer read GetPBits;
  165.     property Pixels[X, Y: Integer]: DWORD read GetPixel write SetPixel;
  166.     property ScanLine[Y: Integer]: Pointer read GetScanLine;
  167.     property Size: Integer read FSize;
  168.     property TopPBits: Pointer read GetTopPBits;
  169.     property Width: Integer read FWidth write SetWidth;
  170.     property WidthBytes: Integer read FWidthBytes;
  171.   end;
  172.  
  173.   TDIBitmap = class(TDIB) end;
  174.  
  175.   {  TCustomDXDIB  }
  176.  
  177.   TCustomDXDIB = class(TComponent)
  178.   private
  179.     FDIB: TDIB;
  180.     procedure SetDIB(Value: TDIB);
  181.   public
  182.     constructor Create(AOnwer: TComponent); override;
  183.     destructor Destroy; override;
  184.     property DIB: TDIB read FDIB write SetDIB;
  185.   end;
  186.  
  187.   {  TDXDIB  }
  188.  
  189.   TDXDIB = class(TCustomDXDIB)
  190.   published
  191.     property DIB;
  192.   end;
  193.  
  194.   {  TCustomDXPaintBox  }
  195.  
  196.   TCustomDXPaintBox = class(TGraphicControl)
  197.   private
  198.     FAutoStretch: Boolean;
  199.     FCenter: Boolean;
  200.     FDIB: TDIB;
  201.     FKeepAspect: Boolean;
  202.     FStretch: Boolean;
  203.     procedure SetAutoStretch(Value: Boolean);
  204.     procedure SetCenter(Value: Boolean);
  205.     procedure SetDIB(Value: TDIB);
  206.     procedure SetKeepAspect(Value: Boolean);
  207.     procedure SetStretch(Value: Boolean);
  208.   protected
  209.     function GetPalette: HPALETTE; override;
  210.   public
  211.     constructor Create(AOwner: TComponent); override;
  212.     destructor Destroy; override;
  213.     procedure Paint; override;
  214.     property AutoStretch: Boolean read FAutoStretch write SetAutoStretch;
  215.     property Canvas;
  216.     property Center: Boolean read FCenter write SetCenter;
  217.     property DIB: TDIB read FDIB write SetDIB;
  218.     property KeepAspect: Boolean read FKeepAspect write SetKeepAspect;
  219.     property Stretch: Boolean read FStretch write SetStretch;
  220.   end;
  221.  
  222.   {  TDXPaintBox  }
  223.  
  224.   TDXPaintBox = class(TCustomDXPaintBox)
  225.   published
  226.     property AutoStretch;
  227.     property Center;
  228.     property DIB;
  229.     property KeepAspect;
  230.     property Stretch;
  231.  
  232.     property Align;
  233.     property DragCursor;
  234.     property DragMode;
  235.     property Enabled;
  236.     property ParentShowHint;
  237.     property PopupMenu;
  238.     property ShowHint;
  239.     property Visible;
  240.     property OnClick;
  241.     property OnDblClick;
  242.     property OnDragDrop;
  243.     property OnDragOver;
  244.     property OnEndDrag;
  245.     property OnMouseDown;
  246.     property OnMouseMove;
  247.     property OnMouseUp;
  248.     property OnStartDrag;
  249.   end;
  250.  
  251. function MakeDIBPixelFormat(RBitCount, GBitCount, BBitCount: Integer): TDIBPixelFormat;
  252. function MakeDIBPixelFormatMask(RBitMask, GBitMask, BBitMask: Integer): TDIBPixelFormat;
  253. function pfRGB(const PixelFormat: TDIBPixelFormat; R, G, B: Byte): Integer;
  254. procedure pfGetRGB(const PixelFormat: TDIBPixelFormat; Color: Integer; var R, G, B: Byte);
  255. function pfGetRValue(const PixelFormat: TDIBPixelFormat; Color: Integer): Byte;
  256. function pfGetGValue(const PixelFormat: TDIBPixelFormat; Color: Integer): Byte;
  257. function pfGetBValue(const PixelFormat: TDIBPixelFormat; Color: Integer): Byte;
  258.  
  259. function GreyscaleColorTable: TRGBQuads;
  260.  
  261. function RGBQuad(R, G, B: Byte): TRGBQuad;
  262. function PaletteEntryToRGBQuad(Entry: TPaletteEntry): TRGBQuad;
  263. function PaletteEntriesToRGBQuads(const Entries: TPaletteEntries): TRGBQuads;
  264. function RGBQuadToPaletteEntry(RGBQuad: TRGBQuad): TPaletteEntry;
  265. function RGBQuadsToPaletteEntries(const RGBQuads: TRGBQuads): TPaletteEntries;
  266.  
  267. implementation
  268.  
  269. uses DXConsts;
  270.  
  271. function Min(B1, B2: Integer): Integer;
  272. begin
  273.   if B1<=B2 then Result := B1 else Result := B2;
  274. end;
  275.  
  276. function Max(B1, B2: Integer): Integer;
  277. begin
  278.   if B1>=B2 then Result := B1 else Result := B2;
  279. end;
  280.  
  281. function MakeDIBPixelFormat(RBitCount, GBitCount, BBitCount: Integer): TDIBPixelFormat;
  282. begin
  283.   Result.RBitMask := ((1 shl RBitCount)-1) shl (GBitCount+BBitCount);
  284.   Result.GBitMask := ((1 shl GBitCount)-1) shl (BBitCount);
  285.   Result.BBitMask := (1 shl BBitCount)-1;
  286.   Result.RBitCount := RBitCount;
  287.   Result.GBitCount := GBitCount;
  288.   Result.BBitCount := BBitCount;
  289.   Result.RBitCount2 := 8-RBitCount;
  290.   Result.GBitCount2 := 8-GBitCount;
  291.   Result.BBitCount2 := 8-BBitCount;
  292.   Result.RShift := (GBitCount+BBitCount)-(8-RBitCount);
  293.   Result.GShift := BBitCount-(8-GBitCount);
  294.   Result.BShift := 8-BBitCount;
  295. end;
  296.  
  297. function MakeDIBPixelFormatMask(RBitMask, GBitMask, BBitMask: Integer): TDIBPixelFormat;
  298.  
  299.   function GetBitCount(b: Integer): Integer;
  300.   var
  301.     i: Integer;
  302.   begin
  303.     i := 0;
  304.     while (i<31) and (((1 shl i) and b)=0) do Inc(i);
  305.  
  306.     Result := 0;
  307.     while ((1 shl i) and b)<>0 do
  308.     begin
  309.       Inc(i);
  310.       Inc(Result);
  311.     end;
  312.   end;
  313.  
  314. begin
  315.   Result := MakeDIBPixelFormat(GetBitCount(RBitMask), GetBitCount(GBitMask),
  316.     GetBitCount(BBitMask));
  317. end;
  318.  
  319. function pfRGB(const PixelFormat: TDIBPixelFormat; R, G, B: Byte): Integer;
  320. begin
  321.   with PixelFormat do
  322.     Result := ((R shl RShift) and RBitMask) or ((G shl GShift) and GBitMask) or
  323.       ((B shr BShift) and BBitMask);
  324. end;
  325.  
  326. procedure pfGetRGB(const PixelFormat: TDIBPixelFormat; Color: Integer; var R, G, B: Byte);
  327. begin
  328.   with PixelFormat do
  329.   begin
  330.     R := (Color and RBitMask) shr PixelFormat.RShift;
  331.     R := R or (R shr RBitCount2);
  332.     G := (Color and GBitMask) shr PixelFormat.GShift;
  333.     G := G or (G shr GBitCount2);
  334.     B := (Color and BBitMask) shl PixelFormat.BShift;
  335.     B := B or (B shr BBitCount2);
  336.   end;
  337. end;
  338.  
  339. function pfGetRValue(const PixelFormat: TDIBPixelFormat; Color: Integer): Byte;
  340. begin
  341.   with PixelFormat do
  342.   begin
  343.     Result := (Color and RBitMask) shr PixelFormat.RShift;
  344.     Result := Result or (Result shr RBitCount2);
  345.   end;
  346. end;
  347.  
  348. function pfGetGValue(const PixelFormat: TDIBPixelFormat; Color: Integer): Byte;
  349. begin
  350.   with PixelFormat do
  351.   begin
  352.     Result := (Color and GBitMask) shr PixelFormat.GShift;
  353.     Result := Result or (Result shr GBitCount2);
  354.   end;
  355. end;
  356.  
  357. function pfGetBValue(const PixelFormat: TDIBPixelFormat; Color: Integer): Byte;
  358. begin
  359.   with PixelFormat do
  360.   begin
  361.     Result := (Color and BBitMask) shl PixelFormat.BShift;
  362.     Result := Result or (Result shr BBitCount2);
  363.   end;
  364. end;
  365.  
  366. function GreyscaleColorTable: TRGBQuads;
  367. var
  368.   i: Integer;
  369. begin
  370.   for i:=0 to 255 do
  371.     with Result[i] do
  372.     begin
  373.       rgbRed := i;
  374.       rgbGreen := i;
  375.       rgbBlue := i;
  376.       rgbReserved := 0;
  377.     end;
  378. end;
  379.  
  380. function RGBQuad(R, G, B: Byte): TRGBQuad;
  381. begin
  382.   with Result do
  383.   begin
  384.     rgbRed := R;
  385.     rgbGreen := G;
  386.     rgbBlue := B;
  387.     rgbReserved := 0;
  388.   end;
  389. end;
  390.  
  391. function PaletteEntryToRGBQuad(Entry: TPaletteEntry): TRGBQuad;
  392. begin
  393.   with Result do
  394.     with Entry do
  395.     begin
  396.       rgbRed := peRed;
  397.       rgbGreen := peGreen;
  398.       rgbBlue := peBlue;
  399.       rgbReserved := 0;
  400.     end;
  401. end;
  402.  
  403. function PaletteEntriesToRGBQuads(const Entries: TPaletteEntries): TRGBQuads;
  404. var
  405.   i: Integer;
  406. begin
  407.   for i:=0 to 255 do
  408.     Result[i] := PaletteEntryToRGBQuad(Entries[i]);
  409. end;
  410.  
  411. function RGBQuadToPaletteEntry(RGBQuad: TRGBQuad): TPaletteEntry;
  412. begin
  413.   with Result do
  414.     with RGBQuad do
  415.     begin
  416.       peRed := rgbRed;
  417.       peGreen := rgbGreen;
  418.       peBlue := rgbBlue;
  419.       peFlags := 0;
  420.     end;
  421. end;
  422.  
  423. function RGBQuadsToPaletteEntries(const RGBQuads: TRGBQuads): TPaletteEntries;
  424. var
  425.   i: Integer;
  426. begin
  427.   for i:=0 to 255 do
  428.     Result[i] := RGBQuadToPaletteEntry(RGBQuads[i]);
  429. end;
  430.  
  431. {  TDIBSharedImage  }
  432.  
  433. type
  434.   PLocalDIBPixelFormat = ^TLocalDIBPixelFormat;
  435.   TLocalDIBPixelFormat = packed record
  436.     RBitMask, GBitMask, BBitMask: DWORD;
  437.   end;
  438.  
  439.   TPaletteItem = class(TCollectionItem)
  440.   private
  441.     ID: Integer;
  442.     Palette: HPalette;
  443.     RefCount: Integer;
  444.     ColorTable: TRGBQuads;
  445.     ColorTableCount: Integer;
  446.     destructor Destroy; override;
  447.     procedure AddRef;
  448.     procedure Release;
  449.   end;
  450.  
  451.   TPaletteManager = class
  452.   private
  453.     FList: TCollection;
  454.     constructor Create;
  455.     destructor Destroy; override;
  456.     function CreatePalette(const ColorTable: TRGBQuads; ColorTableCount: Integer): HPalette;
  457.     procedure DeletePalette(var Palette: HPalette);
  458.   end;
  459.  
  460. destructor TPaletteItem.Destroy;
  461. begin
  462.   DeleteObject(Palette);
  463.   inherited Destroy;
  464. end;
  465.  
  466. procedure TPaletteItem.AddRef;
  467. begin
  468.   Inc(RefCount);
  469. end;
  470.  
  471. procedure TPaletteItem.Release;
  472. begin
  473.   Dec(RefCount);
  474.   if RefCount<=0 then Free;
  475. end;
  476.  
  477. constructor TPaletteManager.Create;
  478. begin
  479.   inherited Create;
  480.   FList := TCollection.Create(TPaletteItem);
  481. end;
  482.  
  483. destructor TPaletteManager.Destroy;
  484. begin
  485.   FList.Free;
  486.   inherited Destroy;
  487. end;
  488.  
  489. function TPaletteManager.CreatePalette(const ColorTable: TRGBQuads; ColorTableCount: Integer): HPalette;
  490. type
  491.   TMyLogPalette = record
  492.     palVersion: Word;
  493.     palNumEntries: Word;
  494.     palPalEntry: TPaletteEntries;
  495.   end;
  496. var
  497.   i, ID: Integer;
  498.   Item: TPaletteItem;
  499.   LogPalette: TMyLogPalette;
  500. begin
  501.   {  Hash key making  }
  502.   ID := ColorTableCount;
  503.   for i:=0 to ColorTableCount-1 do
  504.     with ColorTable[i] do
  505.     begin
  506.       Inc(ID, rgbRed);
  507.       Inc(ID, rgbGreen);
  508.       Inc(ID, rgbBlue);
  509.     end;
  510.  
  511.   {  Does the same palette already exist?  }
  512.   for i:=0 to FList.Count-1 do
  513.   begin
  514.     Item := TPaletteItem(FList.Items[i]);
  515.     if (Item.ID=ID) and (Item.ColorTableCount=ColorTableCount) and
  516.       CompareMem(@Item.ColorTable, @ColorTable, ColorTableCount*SizeOf(TRGBQuad)) then
  517.     begin
  518.       Item.AddRef; Result := Item.Palette;
  519.       Exit;
  520.     end;
  521.   end;
  522.  
  523.   {  New palette making  }
  524.   Item := TPaletteItem.Create(FList);
  525.   Item.ID := ID;
  526.   Move(ColorTable, Item.ColorTable, ColorTableCount*SizeOf(TRGBQuad));
  527.   Item.ColorTableCount := ColorTableCount;
  528.  
  529.   with LogPalette do
  530.   begin
  531.     palVersion := $300;
  532.     palNumEntries := ColorTableCount;
  533.     palPalEntry := RGBQuadsToPaletteEntries(ColorTable);
  534.   end;
  535.  
  536.   Item.Palette := Windows.CreatePalette(PLogPalette(@LogPalette)^);
  537.   Item.AddRef; Result := Item.Palette;
  538. end;
  539.  
  540. procedure TPaletteManager.DeletePalette(var Palette: HPalette);
  541. var
  542.   i: Integer;
  543.   Item: TPaletteItem;
  544. begin
  545.   if Palette=0 then Exit;
  546.  
  547.   for i:=0 to FList.Count-1 do
  548.   begin
  549.     Item := TPaletteItem(FList.Items[i]);
  550.     if (Item.Palette=Palette) then
  551.     begin
  552.       Palette := 0;
  553.       Item.Release;
  554.       Exit;
  555.     end;
  556.   end;
  557. end;
  558.  
  559. var
  560.   FPaletteManager: TPaletteManager;
  561.  
  562. function PaletteManager: TPaletteManager;
  563. begin
  564.   if FPaletteManager=nil then
  565.     FPaletteManager := TPaletteManager.Create;
  566.   Result := FPaletteManager;
  567. end;
  568.  
  569. constructor TDIBSharedImage.Create;
  570. begin
  571.   inherited Create;
  572.   FMemoryImage := True;
  573.   SetColorTable(GreyscaleColorTable);
  574.   FColorTable := GreyscaleColorTable;
  575.   FPixelFormat := MakeDIBPixelFormat(8, 8, 8);
  576. end;
  577.  
  578. procedure TDIBSharedImage.NewImage(AWidth, AHeight, ABitCount: Integer;
  579.   const PixelFormat: TDIBPixelFormat; const ColorTable: TRGBQuads; MemoryImage, Compressed: Boolean);
  580. var
  581.   InfoOfs: Integer;
  582.   UsePixelFormat: Boolean;
  583. begin
  584.   Create;
  585.  
  586.   {  Pixel format check  }
  587.   case ABitCount of
  588.     1 : if not ((PixelFormat.RBitMask=$FF0000) and (PixelFormat.GBitMask=$00FF00) and (PixelFormat.BBitMask=$0000FF)) then
  589.             raise EInvalidGraphicOperation.Create(SInvalidDIBPixelFormat);
  590.     4 : if not ((PixelFormat.RBitMask=$FF0000) and (PixelFormat.GBitMask=$00FF00) and (PixelFormat.BBitMask=$0000FF)) then
  591.             raise EInvalidGraphicOperation.Create(SInvalidDIBPixelFormat);
  592.     8 : if not ((PixelFormat.RBitMask=$FF0000) and (PixelFormat.GBitMask=$00FF00) and (PixelFormat.BBitMask=$0000FF)) then
  593.             raise EInvalidGraphicOperation.Create(SInvalidDIBPixelFormat);
  594.     16: begin
  595.           if not (((PixelFormat.RBitMask=$7C00) and (PixelFormat.GBitMask=$03E0) and (PixelFormat.BBitMask=$001F)) or
  596.             ((PixelFormat.RBitMask=$F800) and (PixelFormat.GBitMask=$07E0) and (PixelFormat.BBitMask=$001F))) then
  597.             raise EInvalidGraphicOperation.Create(SInvalidDIBPixelFormat);
  598.         end;
  599.     24: begin
  600.           if not ((PixelFormat.RBitMask=$FF0000) and (PixelFormat.GBitMask=$00FF00) and (PixelFormat.BBitMask=$0000FF)) then
  601.             raise EInvalidGraphicOperation.Create(SInvalidDIBPixelFormat);
  602.         end;
  603.     32: begin
  604.           if not ((PixelFormat.RBitMask=$FF0000) and (PixelFormat.GBitMask=$00FF00) and (PixelFormat.BBitMask=$0000FF)) then
  605.             raise EInvalidGraphicOperation.Create(SInvalidDIBPixelFormat);
  606.         end;
  607.   else
  608.     raise EInvalidGraphicOperation.CreateFmt(SInvalidDIBBitCount, [ABitCount]);
  609.   end;
  610.  
  611.   FBitCount := ABitCount;
  612.   FHeight := AHeight;
  613.   FWidth := AWidth;
  614.   FWidthBytes := (((AWidth*ABitCount)+31) shr 5) * 4;
  615.   FNextLine := -FWidthBytes;
  616.   FSize := FWidthBytes*FHeight;
  617.   UsePixelFormat := ABitCount in [16, 32];
  618.  
  619.   FPixelFormat := PixelFormat;
  620.  
  621.   FPaletteCount := 0;
  622.   if FBitCount<=8 then
  623.     FPaletteCount := 1 shl FBitCount;
  624.  
  625.   FBitmapInfoSize := SizeOf(TBitmapInfoHeader);
  626.   if UsePixelFormat then
  627.     Inc(FBitmapInfoSize, SizeOf(TLocalDIBPixelFormat));
  628.   Inc(FBitmapInfoSize, SizeOf(TRGBQuad)*FPaletteCount);
  629.  
  630.   GetMem(FBitmapInfo, FBitmapInfoSize);
  631.   FillChar(FBitmapInfo^, FBitmapInfoSize, 0);
  632.  
  633.   {  BitmapInfo setting.  }
  634.   with FBitmapInfo^.bmiHeader do
  635.   begin
  636.     biSize := SizeOf(TBitmapInfoHeader);
  637.     biWidth := FWidth;
  638.     biHeight := FHeight;
  639.     biPlanes := 1;
  640.     biBitCount := FBitCount;
  641.     if UsePixelFormat then
  642.       biCompression := BI_BITFIELDS
  643.     else
  644.     begin
  645.       if (FBitCount=4) and (Compressed) then
  646.         biCompression := BI_RLE4
  647.       else if (FBitCount=8) and (Compressed) then
  648.         biCompression := BI_RLE8
  649.       else
  650.         biCompression := BI_RGB;
  651.     end;
  652.     biSizeImage := FSize;
  653.     biXPelsPerMeter := 0;
  654.     biYPelsPerMeter := 0;
  655.     biClrUsed := 0;
  656.     biClrImportant := 0;
  657.   end;
  658.   InfoOfs := SizeOf(TBitmapInfoHeader);
  659.  
  660.   if UsePixelFormat then
  661.   begin
  662.     with PLocalDIBPixelFormat(Integer(FBitmapInfo)+InfoOfs)^ do
  663.     begin
  664.       RBitMask := PixelFormat.RBitMask;
  665.       GBitMask := PixelFormat.GBitMask;
  666.       BBitMask := PixelFormat.BBitMask;
  667.     end;
  668.  
  669.     Inc(InfoOfs, SizeOf(TLocalDIBPixelFormat));
  670.   end;
  671.  
  672.   FColorTablePos := InfoOfs;
  673.  
  674.   FColorTable := ColorTable;
  675.   Move(FColorTable, Pointer(Integer(FBitmapInfo)+FColorTablePos)^, SizeOf(TRGBQuad)*FPaletteCount);
  676.  
  677.   FCompressed := FBitmapInfo^.bmiHeader.biCompression in [BI_RLE4, BI_RLE8];
  678.   FMemoryImage := MemoryImage or FCompressed;
  679.  
  680.   {  DIB making.  }
  681.   if not Compressed then
  682.   begin
  683.     if MemoryImage then
  684.     begin
  685.       GetMem(FPBits, FSize);
  686.     end else
  687.     begin
  688.       FDC := CreateCompatibleDC(0);
  689.  
  690.       FHandle := CreateDIBSection(FDC, FBitmapInfo^, DIB_RGB_COLORS, FPBits, 0, 0);
  691.       if FHandle=0 then
  692.         raise EOutOfResources.CreateFmt(SCannotMade, ['DIB']);
  693.  
  694.       FOldHandle := SelectObject(FDC, FHandle);
  695.     end;
  696.   end;
  697.  
  698.   FTopPBits := Pointer(Integer(FPBits)+(FHeight-1)*FWidthBytes);
  699. end;
  700.  
  701. procedure TDIBSharedImage.Duplicate(Source: TDIBSharedImage; MemoryImage: Boolean);
  702. begin
  703.   if Source.FSize=0 then
  704.   begin
  705.     Create;
  706.     FMemoryImage := MemoryImage;
  707.   end else
  708.   begin
  709.     NewImage(Source.FWidth, Source.FHeight, Source.FBitCount,
  710.       Source.FPixelFormat, Source.FColorTable, MemoryImage, Source.FCompressed);
  711.     if FCompressed then
  712.     begin
  713.       FBitmapInfo.bmiHeader.biSizeImage := Source.FBitmapInfo.bmiHeader.biSizeImage;
  714.       GetMem(FPBits, FBitmapInfo.bmiHeader.biSizeImage);
  715.       Move(Source.FPBits^, FPBits^, FBitmapInfo.bmiHeader.biSizeImage);
  716.     end else
  717.     begin
  718.       Move(Source.FPBits^, FPBits^, FBitmapInfo.bmiHeader.biSizeImage);
  719.     end;
  720.   end;
  721. end;
  722.  
  723. procedure TDIBSharedImage.Compress(Source: TDIBSharedImage);
  724.  
  725.   procedure EncodeRLE4;
  726.   var
  727.     Size: Integer;
  728.  
  729.     function AllocByte: PByte;
  730.     begin
  731.       if Size mod 4096=0 then
  732.         ReAllocMem(FPBits, Size+4095);
  733.       Result := Pointer(Integer(FPBits)+Size);
  734.       Inc(Size);
  735.     end;
  736.  
  737.   var
  738.     B1, B2, C: Byte;
  739.     PB1, PB2: Integer;
  740.     Src: PByte;
  741.     X, Y: Integer;
  742.  
  743.     function GetPixel(x: Integer): Integer;
  744.     begin
  745.       if X and 1=0 then
  746.         Result := PArrayByte(Src)[X shr 1] shr 4
  747.       else
  748.         Result := PArrayByte(Src)[X shr 1] and $0F;
  749.     end;
  750.  
  751.   begin
  752.     Size := 0;
  753.  
  754.     for y:=0 to Source.FHeight-1 do
  755.     begin
  756.       x := 0;
  757.       Src := Pointer(Integer(Source.FPBits)+y*FWidthBytes);
  758.       while x<Source.FWidth do
  759.       begin
  760.         if (Source.FWidth-x>3) and (GetPixel(x)=GetPixel(x+2)) then
  761.         begin
  762.           {  Encoding mode  }
  763.           B1 := 2;
  764.           B2 := (GetPixel(x) shl 4) or GetPixel(x+1);
  765.  
  766.           Inc(x, 2);
  767.  
  768.           C := B2;
  769.  
  770.           while (x<Source.FWidth) and (C and $F=GetPixel(x)) and (B1<255) do
  771.           begin
  772.             Inc(B1);
  773.             Inc(x);
  774.             C := (C shr 4) or (C shl 4);
  775.           end;
  776.  
  777.           AllocByte^ := B1;
  778.           AllocByte^ := B2;
  779.         end else
  780.         if (Source.FWidth-x>5) and ((GetPixel(x)<>GetPixel(x+2)) or (GetPixel(x+1)<>GetPixel(x+3))) and
  781.           ((GetPixel(x+2)=GetPixel(x+4)) and (GetPixel(x+3)=GetPixel(x+5))) then
  782.         begin
  783.           {  Encoding mode }
  784.           AllocByte^ := 2;
  785.           AllocByte^ := (GetPixel(x) shl 4) or GetPixel(x+1);
  786.           Inc(x, 2);
  787.         end else
  788.         begin
  789.           if (Source.FWidth-x<4) then
  790.           begin
  791.             {  Encoding mode }
  792.             while Source.FWidth-x>=2 do
  793.             begin
  794.               AllocByte^ := 2;
  795.               AllocByte^ := (GetPixel(x) shl 4) or GetPixel(x+1);
  796.               Inc(x, 2);
  797.             end;
  798.  
  799.             if Source.FWidth-x=1 then
  800.             begin
  801.               AllocByte^ := 1;
  802.               AllocByte^ := GetPixel(x) shl 4;
  803.               Inc(x);
  804.             end;
  805.           end else
  806.           begin
  807.             {  Absolute mode  }
  808.             PB1 := Size; AllocByte;
  809.             PB2 := Size; AllocByte;
  810.  
  811.             B1 := 0;
  812.             B2 := 4;
  813.  
  814.             AllocByte^ := (GetPixel(x) shl 4) or GetPixel(x+1);
  815.             AllocByte^ := (GetPixel(x+2) shl 4) or GetPixel(x+3);
  816.  
  817.             Inc(x, 4);
  818.  
  819.             while (x+1<Source.FWidth) and (B2<254) do
  820.             begin
  821.               if (Source.FWidth-x>3) and (GetPixel(x)=GetPixel(x+2)) and (GetPixel(x+1)=GetPixel(x+3)) then
  822.                 Break;
  823.  
  824.               AllocByte^ := (GetPixel(x) shl 4) or GetPixel(x+1);
  825.               Inc(B2, 2);
  826.               Inc(x, 2);
  827.             end;
  828.  
  829.             PByte(Integer(FPBits)+PB1)^ := B1;
  830.             PByte(Integer(FPBits)+PB2)^ := B2;
  831.           end;
  832.         end;
  833.  
  834.         if Size and 1=1 then AllocByte;
  835.       end;
  836.  
  837.       {  End of line  }
  838.       AllocByte^ := 0;
  839.       AllocByte^ := 0;
  840.     end;
  841.  
  842.     {  End of bitmap  }
  843.     AllocByte^ := 0;
  844.     AllocByte^ := 1;
  845.  
  846.     FBitmapInfo.bmiHeader.biSizeImage := Size;
  847.   end;
  848.  
  849.   procedure EncodeRLE8;
  850.   var
  851.     Size: Integer;
  852.  
  853.     function AllocByte: PByte;
  854.     begin
  855.       if Size mod 4096=0 then
  856.         ReAllocMem(FPBits, Size+4095);
  857.       Result := Pointer(Integer(FPBits)+Size);
  858.       Inc(Size);
  859.     end;
  860.  
  861.   var
  862.     B1, B2: Byte;
  863.     PB1, PB2: Integer;
  864.     Src: PByte;
  865.     X, Y: Integer;
  866.   begin
  867.     Size := 0;
  868.  
  869.     for y:=0 to Source.FHeight-1 do
  870.     begin
  871.       x := 0;
  872.       Src := Pointer(Integer(Source.FPBits)+y*FWidthBytes);
  873.       while x<Source.FWidth do
  874.       begin
  875.         if (Source.FWidth-x>2) and (Src^=PByte(Integer(Src)+1)^) then
  876.         begin
  877.           {  Encoding mode  }
  878.           B1 := 2;
  879.           B2 := Src^;
  880.  
  881.           Inc(x, 2);
  882.           Inc(Src, 2);
  883.  
  884.           while (x<Source.FWidth) and (Src^=B2) and (B1<255) do
  885.           begin
  886.             Inc(B1);
  887.             Inc(x);
  888.             Inc(Src);
  889.           end;
  890.  
  891.           AllocByte^ := B1;
  892.           AllocByte^ := B2;
  893.         end else
  894.         if (Source.FWidth-x>2) and (Src^<>PByte(Integer(Src)+1)^) and (PByte(Integer(Src)+1)^=PByte(Integer(Src)+2)^) then
  895.         begin
  896.           {  Encoding mode }
  897.           AllocByte^ := 1;
  898.           AllocByte^ := Src^; Inc(Src);
  899.           Inc(x);
  900.         end else
  901.         begin
  902.           if (Source.FWidth-x<4) then
  903.           begin
  904.             {  Encoding mode }
  905.             if Source.FWidth-x=2 then
  906.             begin
  907.               AllocByte^ := 1;
  908.               AllocByte^ := Src^; Inc(Src);
  909.  
  910.               AllocByte^ := 1;
  911.               AllocByte^ := Src^; Inc(Src);
  912.               Inc(x, 2);
  913.             end else
  914.             begin
  915.               AllocByte^ := 1;
  916.               AllocByte^ := Src^; Inc(Src);
  917.               Inc(x);
  918.             end;
  919.           end else
  920.           begin
  921.             {  Absolute mode  }
  922.             PB1 := Size; AllocByte;
  923.             PB2 := Size; AllocByte;
  924.  
  925.             B1 := 0;
  926.             B2 := 3;
  927.  
  928.             Inc(x, 3);
  929.  
  930.             AllocByte^ := Src^; Inc(Src);
  931.             AllocByte^ := Src^; Inc(Src);
  932.             AllocByte^ := Src^; Inc(Src);
  933.  
  934.             while (x<Source.FWidth) and (B2<255) do
  935.             begin
  936.               if (Source.FWidth-x>3) and (Src^=PByte(Integer(Src)+1)^) and (Src^=PByte(Integer(Src)+2)^) and (Src^=PByte(Integer(Src)+3)^) then
  937.                 Break;
  938.  
  939.               AllocByte^ := Src^; Inc(Src);
  940.               Inc(B2);
  941.               Inc(x);
  942.             end;
  943.  
  944.             PByte(Integer(FPBits)+PB1)^ := B1;
  945.             PByte(Integer(FPBits)+PB2)^ := B2;
  946.           end;
  947.         end;
  948.  
  949.         if Size and 1=1 then AllocByte;
  950.       end;
  951.  
  952.       {  End of line  }
  953.       AllocByte^ := 0;
  954.       AllocByte^ := 0;
  955.     end;
  956.  
  957.     {  End of bitmap  }
  958.     AllocByte^ := 0;
  959.     AllocByte^ := 1;
  960.  
  961.     FBitmapInfo.bmiHeader.biSizeImage := Size;
  962.   end;
  963.  
  964. begin
  965.   if Source.FCompressed then
  966.     Duplicate(Source, Source.FMemoryImage)
  967.   else begin
  968.     NewImage(Source.FWidth, Source.FHeight, Source.FBitCount,
  969.       Source.FPixelFormat, Source.FColorTable, True, True);
  970.     case FBitmapInfo.bmiHeader.biCompression of
  971.       BI_RLE4: EncodeRLE4;
  972.       BI_RLE8: EncodeRLE8;
  973.     else
  974.       Duplicate(Source, Source.FMemoryImage);
  975.     end;
  976.   end;
  977. end;
  978.  
  979. procedure TDIBSharedImage.Decompress(Source: TDIBSharedImage; MemoryImage: Boolean);
  980.  
  981.   procedure DecodeRLE4;
  982.   var
  983.     B1, B2, C: Byte;
  984.     Dest, Src, P: PByte;
  985.     X, Y, i: Integer;
  986.   begin
  987.     Src := Source.FPBits;
  988.     X := 0;
  989.     Y := 0;
  990.  
  991.     while True do
  992.     begin
  993.       B1 := Src^; Inc(Src);
  994.       B2 := Src^; Inc(Src);
  995.  
  996.       if B1=0 then
  997.       begin
  998.         case B2 of
  999.           0: begin  {  End of line  }
  1000.                X := 0;
  1001.                Inc(Y);
  1002.              end;
  1003.           1: Break; {  End of bitmap  }
  1004.           2: begin  {  Difference of coordinates  }
  1005.                Inc(X, B1);
  1006.                Inc(Y, B2); Inc(Src, 2);
  1007.              end;
  1008.         else
  1009.           {  Absolute mode  }
  1010.           Dest := Pointer(Longint(FPBits)+Y*FWidthBytes);
  1011.  
  1012.           C := 0;
  1013.           for i:=0 to B2-1 do
  1014.           begin
  1015.             if i and 1=0 then
  1016.             begin
  1017.               C := Src^; Inc(Src);
  1018.             end else
  1019.             begin
  1020.               C := C shl 4;
  1021.             end;
  1022.  
  1023.             P := Pointer(Integer(Dest)+X shr 1);
  1024.             if X and 1=0 then
  1025.               P^ := (P^ and $0F) or (C and $F0)
  1026.             else
  1027.               P^ := (P^ and $F0) or ((C and $F0) shr 4);
  1028.  
  1029.             Inc(X);
  1030.           end;
  1031.         end;
  1032.       end else
  1033.       begin
  1034.         {  Encoding mode  }
  1035.         Dest := Pointer(Longint(FPBits)+Y*FWidthBytes);
  1036.  
  1037.         for i:=0 to B1-1 do
  1038.         begin
  1039.           P := Pointer(Integer(Dest)+X shr 1);
  1040.           if X and 1=0 then
  1041.             P^ := (P^ and $0F) or (B2 and $F0)
  1042.           else
  1043.             P^ := (P^ and $F0) or ((B2 and $F0) shr 4);
  1044.  
  1045.           Inc(X);
  1046.  
  1047.           // Swap nibble
  1048.           B2 := (B2 shr 4) or (B2 shl 4);
  1049.         end;
  1050.       end;
  1051.  
  1052.       {  Word arrangement  }
  1053.       Inc(Src, Longint(Src) and 1);
  1054.     end;
  1055.   end;
  1056.  
  1057.   procedure DecodeRLE8;
  1058.   var
  1059.     B1, B2: Byte;
  1060.     Dest, Src: PByte;
  1061.     X, Y: Integer;
  1062.   begin
  1063.     Dest := FPBits;
  1064.     Src := Source.FPBits;
  1065.     X := 0;
  1066.     Y := 0;
  1067.  
  1068.     while True do
  1069.     begin
  1070.       B1 := Src^; Inc(Src);
  1071.       B2 := Src^; Inc(Src);
  1072.  
  1073.       if B1=0 then
  1074.       begin
  1075.         case B2 of
  1076.           0: begin  {  End of line  }
  1077.                X := 0; Inc(Y);
  1078.                Dest := Pointer(Longint(FPBits)+Y*FWidthBytes+X);
  1079.              end;
  1080.           1: Break; {  End of bitmap  }
  1081.           2: begin  {  Difference of coordinates  }
  1082.                Inc(X, B1); Inc(Y, B2); Inc(Src, 2);
  1083.                Dest := Pointer(Longint(FPBits)+Y*FWidthBytes+X);
  1084.              end;
  1085.         else
  1086.           {  Absolute mode  }
  1087.           Move(Src^, Dest^, B2); Inc(Dest, B2); Inc(Src, B2);
  1088.         end;
  1089.       end else
  1090.       begin
  1091.         {  Encoding mode  }
  1092.         FillChar(Dest^, B1, B2); Inc(Dest, B1);
  1093.       end;
  1094.  
  1095.       {  Word arrangement  }
  1096.       Inc(Src, Longint(Src) and 1);
  1097.     end;
  1098.   end;
  1099.  
  1100. begin
  1101.   if not Source.FCompressed then
  1102.     Duplicate(Source, MemoryImage)
  1103.   else begin
  1104.     NewImage(Source.FWidth, Source.FHeight, Source.FBitCount,
  1105.       Source.FPixelFormat, Source.FColorTable, MemoryImage, False);
  1106.     case Source.FBitmapInfo.bmiHeader.biCompression of
  1107.       BI_RLE4: DecodeRLE4;
  1108.       BI_RLE8: DecodeRLE8;
  1109.     else
  1110.       Duplicate(Source, MemoryImage);
  1111.     end;
  1112.   end;
  1113. end;
  1114.  
  1115. procedure TDIBSharedImage.ReadData(Stream: TStream; MemoryImage: Boolean);
  1116. var
  1117.   BI: TBitmapInfoHeader;
  1118.   BC: TBitmapCoreHeader;
  1119.   BCRGB: array[0..255] of TRGBTriple;
  1120.  
  1121.   procedure LoadRLE4;
  1122.   begin
  1123.     GetMem(FPBits, BI.biSizeImage);
  1124.     FBitmapInfo.bmiHeader.biSizeImage := BI.biSizeImage;
  1125.     Stream.ReadBuffer(FPBits^, BI.biSizeImage);
  1126.   end;
  1127.  
  1128.   procedure LoadRLE8;
  1129.   begin
  1130.     GetMem(FPBits, BI.biSizeImage);
  1131.     FBitmapInfo.bmiHeader.biSizeImage := BI.biSizeImage;
  1132.     Stream.ReadBuffer(FPBits^, BI.biSizeImage);
  1133.   end;
  1134.  
  1135.   procedure LoadRGB;
  1136.   var
  1137.     y: Integer;
  1138.   begin
  1139.     if BI.biHeight<0 then
  1140.     begin
  1141.       for y:=0 to Abs(BI.biHeight)-1 do
  1142.         Stream.ReadBuffer(Pointer(Integer(FTopPBits)+y*FNextLine)^, FWidthBytes);
  1143.     end else
  1144.     begin                             
  1145.       Stream.ReadBuffer(FPBits^, FSize);
  1146.     end;
  1147.   end;
  1148.  
  1149. var
  1150.   i, PalCount: Integer;
  1151.   OS2: Boolean;
  1152.   Localpf: TLocalDIBPixelFormat;
  1153.   AColorTable: TRGBQuads;
  1154.   APixelFormat: TDIBPixelFormat;
  1155. begin
  1156.   {  Header size reading  }
  1157.   i := Stream.Read(BI.biSize, 4);
  1158.  
  1159.   if i=0 then
  1160.   begin
  1161.     Create;
  1162.     Exit;
  1163.   end;
  1164.   if i<>4 then
  1165.     raise EInvalidGraphic.Create(SInvalidDIB);
  1166.  
  1167.   {  Kind check of DIB  }
  1168.   OS2 := False;
  1169.  
  1170.   case BI.biSize of
  1171.     SizeOf(TBitmapCoreHeader):
  1172.       begin
  1173.         {  OS/2 type  }
  1174.         Stream.ReadBuffer(Pointer(Integer(@BC)+4)^, SizeOf(TBitmapCoreHeader)-4);
  1175.  
  1176.         with BI do
  1177.         begin
  1178.           biClrUsed := 0;
  1179.           biCompression := BI_RGB;
  1180.           biBitCount := BC.bcBitCount;
  1181.           biHeight := BC.bcHeight;
  1182.           biWidth := BC.bcWidth;
  1183.         end;
  1184.  
  1185.         OS2 := True;
  1186.       end;
  1187.     SizeOf(TBitmapInfoHeader):
  1188.       begin
  1189.         {  Windows type  }
  1190.         Stream.ReadBuffer(Pointer(Integer(@BI)+4)^, SizeOf(TBitmapInfoHeader)-4);
  1191.       end;
  1192.   else
  1193.     raise EInvalidGraphic.Create(SInvalidDIB);
  1194.   end;
  1195.  
  1196.   {  Bit mask reading.  }
  1197.   if BI.biCompression = BI_BITFIELDS then
  1198.   begin
  1199.     Stream.ReadBuffer(Localpf, SizeOf(Localpf));
  1200.     with Localpf do
  1201.       APixelFormat := MakeDIBPixelFormatMask(RBitMask, GBitMask, BBitMask);
  1202.   end else
  1203.   begin
  1204.     if BI.biBitCount=16 then
  1205.       APixelFormat := MakeDIBPixelFormat(5, 5, 5)
  1206.     else if BI.biBitCount=32 then
  1207.       APixelFormat := MakeDIBPixelFormat(8, 8, 8)
  1208.     else
  1209.       APixelFormat := MakeDIBPixelFormat(8, 8, 8);
  1210.   end;
  1211.  
  1212.     {  Palette reading  }
  1213.   PalCount := BI.biClrUsed;
  1214.   if (PalCount=0) and (BI.biBitCount<=8) then
  1215.     PalCount := 1 shl BI.biBitCount;
  1216.   if PalCount>256 then PalCount := 256;
  1217.  
  1218.   FillChar(AColorTable, SizeOf(AColorTable), 0);
  1219.  
  1220.   if OS2 then
  1221.   begin
  1222.     {  OS/2 type  }
  1223.     Stream.ReadBuffer(BCRGB, SizeOf(TRGBTriple)*PalCount);
  1224.     for i:=0 to PalCount-1 do
  1225.     begin
  1226.       with BCRGB[i] do
  1227.         AColorTable[i] := RGBQuad(rgbtRed, rgbtGreen, rgbtBlue);
  1228.     end;
  1229.   end else
  1230.   begin
  1231.     {  Windows type  }
  1232.     Stream.ReadBuffer(AColorTable, SizeOf(TRGBQuad)*PalCount);
  1233.   end;
  1234.  
  1235.   {  DIB Ã¬âˆžÃ‰Â¼  }
  1236.   NewImage(BI.biWidth, Abs(BI.biHeight), BI.biBitCount, APixelFormat, AColorTable,
  1237.     MemoryImage, BI.biCompression in [BI_RLE4, BI_RLE8]);
  1238.  
  1239.   {  Pixel data reading  }
  1240.   case BI.biCompression of
  1241.     BI_RGB      : LoadRGB;
  1242.     BI_RLE4     : LoadRLE4;
  1243.     BI_RLE8     : LoadRLE8;
  1244.     BI_BITFIELDS: LoadRGB;
  1245.   else
  1246.     raise EInvalidGraphic.Create(SInvalidDIB);
  1247.   end;
  1248. end;
  1249.  
  1250. destructor TDIBSharedImage.Destroy;
  1251. begin
  1252.   if FHandle<>0 then
  1253.   begin
  1254.     if FOldHandle<>0 then SelectObject(FDC, FOldHandle);
  1255.     DeleteObject(FHandle);
  1256.   end else
  1257.     FreeMem(FPBits);
  1258.  
  1259.   PaletteManager.DeletePalette(FPalette);
  1260.   if FDC<>0 then DeleteDC(FDC);
  1261.  
  1262.   FreeMem(FBitmapInfo);
  1263.   inherited Destroy;
  1264. end;
  1265.  
  1266. procedure TDIBSharedImage.FreeHandle;
  1267. begin
  1268. end;
  1269.  
  1270. function TDIBSharedImage.GetPalette: THandle;
  1271. begin
  1272.   if FPaletteCount>0 then
  1273.   begin
  1274.     if FChangePalette then
  1275.     begin
  1276.       FChangePalette := False;
  1277.       PaletteManager.DeletePalette(FPalette);
  1278.       FPalette := PaletteManager.CreatePalette(FColorTable, FPaletteCount);
  1279.     end;
  1280.     Result := FPalette;
  1281.   end else
  1282.     Result := 0;
  1283. end;
  1284.  
  1285. procedure TDIBSharedImage.SetColorTable(const Value: TRGBQuads);
  1286. begin
  1287.   FColorTable := Value;
  1288.   FChangePalette := True;
  1289.  
  1290.   if (FSize>0) and (FPaletteCount>0) then
  1291.   begin
  1292.     SetDIBColorTable(FDC, 0, 256, FColorTable);
  1293.     Move(FColorTable, Pointer(Integer(FBitmapInfo)+FColorTablePos)^, SizeOf(TRGBQuad)*FPaletteCount);
  1294.   end;
  1295. end;
  1296.  
  1297. { TDIB }
  1298.  
  1299. var
  1300.   FEmptyDIBImage: TDIBSharedImage;
  1301.  
  1302. function EmptyDIBImage: TDIBSharedImage;
  1303. begin
  1304.   if FEmptyDIBImage=nil then
  1305.   begin
  1306.     FEmptyDIBImage := TDIBSharedImage.Create;
  1307.     FEmptyDIBImage.Reference;
  1308.   end;
  1309.   Result := FEmptyDIBImage;
  1310. end;
  1311.  
  1312. constructor TDIB.Create;
  1313. begin
  1314.   inherited Create;
  1315.   SetImage(EmptyDIBImage);
  1316. end;
  1317.  
  1318. destructor TDIB.Destroy;
  1319. begin
  1320.   SetImage(EmptyDIBImage);
  1321.   FCanvas.Free;
  1322.   inherited Destroy;
  1323. end;
  1324.  
  1325. procedure TDIB.Assign(Source: TPersistent);
  1326.  
  1327.   procedure AssignBitmap(Source: TBitmap);
  1328.   var
  1329.     Data: array[0..1023] of Byte;
  1330.     BitmapRec: Windows.PBitmap;
  1331.     DIBSectionRec: PDIBSection;
  1332.     PaletteEntries: TPaletteEntries;
  1333.   begin
  1334.     GetPaletteEntries(Source.Palette, 0, 256, PaletteEntries);
  1335.     ColorTable := PaletteEntriesToRGBQuads(PaletteEntries);
  1336.     UpdatePalette;
  1337.  
  1338.     case GetObject(Source.Handle, SizeOf(Data), @Data) of
  1339.       SizeOf(Windows.TBitmap):
  1340.           begin
  1341.             BitmapRec := @Data;
  1342.             case BitmapRec^.bmBitsPixel of
  1343.               16: PixelFormat := MakeDIBPixelFormat(5, 5, 5);
  1344.             else
  1345.               PixelFormat := MakeDIBPixelFormat(8, 8, 8);
  1346.             end;
  1347.             SetSize(BitmapRec^.bmWidth, BitmapRec^.bmHeight, BitmapRec^.bmBitsPixel);
  1348.           end;
  1349.       SizeOf(TDIBSection):
  1350.           begin
  1351.             DIBSectionRec := @Data;
  1352.             if DIBSectionRec^.dsBm.bmBitsPixel>=24 then
  1353.             begin
  1354.               PixelFormat := MakeDIBPixelFormat(8, 8, 8);
  1355.             end else
  1356.             if DIBSectionRec^.dsBm.bmBitsPixel>8 then
  1357.             begin
  1358.               PixelFormat := MakeDIBPixelFormat(DIBSectionRec^.dsBitfields[0],
  1359.                 DIBSectionRec^.dsBitfields[1], DIBSectionRec^.dsBitfields[2]);
  1360.             end else
  1361.             begin
  1362.               PixelFormat := MakeDIBPixelFormat(8, 8, 8);
  1363.             end;
  1364.             SetSize(DIBSectionRec^.dsBm.bmWidth, DIBSectionRec^.dsBm.bmHeight,
  1365.               DIBSectionRec^.dsBm.bmBitsPixel);
  1366.           end;
  1367.     else
  1368.       Exit;
  1369.     end;
  1370.  
  1371.     FillChar(PBits^, Size, 0);
  1372.     Canvas.Draw(0, 0, Source);
  1373.   end;
  1374.  
  1375.   procedure AssignGraphic(Source: TGraphic);
  1376.   begin
  1377.     if Source is TBitmap then
  1378.       AssignBitmap(TBitmap(Source))
  1379.     else
  1380.     begin
  1381.       SetSize(Source.Width, Source.Height, 24);
  1382.       FillChar(PBits^, Size, 0);
  1383.       Canvas.Draw(0, 0, Source);
  1384.     end;
  1385.   end;
  1386.  
  1387. begin
  1388.   if Source=nil then
  1389.   begin
  1390.     Clear;
  1391.   end else if Source is TDIB then
  1392.   begin
  1393.     if Source<>Self then
  1394.       SetImage(TDIB(Source).FImage);
  1395.   end else if Source is TGraphic then
  1396.   begin
  1397.     AssignGraphic(TGraphic(Source));
  1398.   end else if Source is TPicture then
  1399.   begin
  1400.     if TPicture(Source).Graphic<>nil then
  1401.       AssignGraphic(TPicture(Source).Graphic)
  1402.     else
  1403.       Clear;
  1404.   end else 
  1405.     inherited Assign(Source);
  1406. end;
  1407.  
  1408. procedure TDIB.Draw(ACanvas: TCanvas; const Rect: TRect);
  1409. var
  1410.   OldPalette: HPalette;
  1411.   OldMode: Integer;
  1412. begin
  1413.   if Size>0 then
  1414.   begin
  1415.     if PaletteCount>0 then
  1416.     begin
  1417.       OldPalette := SelectPalette(ACanvas.Handle, Palette, False);
  1418.       RealizePalette(ACanvas.Handle);
  1419.     end else
  1420.       OldPalette := 0;
  1421.     try
  1422.       OldMode := SetStretchBltMode(ACanvas.Handle, COLORONCOLOR);
  1423.       try
  1424.         if FImage.FMemoryImage then
  1425.         begin
  1426.           with Rect do
  1427.             StretchDIBits(ACanvas.Handle, Left, Top, Right - Left, Bottom - Top,
  1428.               0, 0, Width, Height, FImage.FPBits, FImage.FBitmapInfo^, DIB_RGB_COLORS , ACanvas.CopyMode);
  1429.         end else
  1430.         begin
  1431.           with Rect do
  1432.             StretchBlt(ACanvas.Handle, Left, Top, Right - Left, Bottom - Top,
  1433.               FImage.FDC, 0, 0, Width, Height, ACanvas.CopyMode);
  1434.         end;
  1435.       finally
  1436.         SetStretchBltMode(ACanvas.Handle, OldMode);
  1437.       end;
  1438.     finally
  1439.       SelectPalette(ACanvas.Handle, OldPalette, False);
  1440.     end;
  1441.   end;
  1442. end;
  1443.  
  1444. procedure TDIB.Clear;
  1445. begin
  1446.   SetImage(EmptyDIBImage);
  1447. end;
  1448.  
  1449. procedure TDIB.CanvasChanging(Sender: TObject);
  1450. begin
  1451.   Changing(False);
  1452. end;
  1453.  
  1454. procedure TDIB.Changing(MemoryImage: Boolean);
  1455. var
  1456.   TempImage: TDIBSharedImage;
  1457. begin
  1458.   if (FImage.RefCount>1) or (FImage.FCompressed) or ((not MemoryImage) and (FImage.FMemoryImage)) then
  1459.   begin
  1460.     TempImage := TDIBSharedImage.Create;
  1461.     try
  1462.       TempImage.Decompress(FImage, FImage.FMemoryImage and MemoryImage);
  1463.     except
  1464.       TempImage.Free;
  1465.       raise;
  1466.     end;
  1467.     SetImage(TempImage);
  1468.   end;
  1469. end;
  1470.                       
  1471. procedure TDIB.Compress;
  1472. var
  1473.   TempImage: TDIBSharedImage;
  1474. begin
  1475.   if (not FImage.FCompressed) and (BitCount in [4, 8]) then
  1476.   begin
  1477.     TempImage := TDIBSharedImage.Create;
  1478.     try
  1479.       TempImage.Compress(FImage);
  1480.     except
  1481.       TempImage.Free;
  1482.       raise;
  1483.     end;
  1484.     SetImage(TempImage);
  1485.   end;
  1486. end;
  1487.  
  1488. procedure TDIB.Decompress;
  1489. var
  1490.   TempImage: TDIBSharedImage;
  1491. begin
  1492.   if FImage.FCompressed then
  1493.   begin
  1494.     TempImage := TDIBSharedImage.Create;
  1495.     try
  1496.       TempImage.Decompress(FImage, FImage.FMemoryImage);
  1497.     except
  1498.       TempImage.Free;
  1499.       raise;
  1500.     end;
  1501.     SetImage(TempImage);
  1502.   end;
  1503. end;
  1504.  
  1505. procedure TDIB.Dormant;
  1506. var
  1507.   TempImage: TDIBSharedImage;
  1508. begin
  1509.   if not FImage.FMemoryImage then
  1510.   begin
  1511.     TempImage := TDIBSharedImage.Create;
  1512.     try
  1513.       TempImage.Duplicate(FImage, True);
  1514.     except
  1515.       TempImage.Free;
  1516.       raise;
  1517.     end;
  1518.     SetImage(TempImage);
  1519.   end;
  1520. end;
  1521.  
  1522. procedure TDIB.FreeImage;
  1523. var
  1524.   TempImage: TDIBSharedImage;
  1525. begin
  1526.   if FImage.FMemoryImage then
  1527.   begin
  1528.     TempImage := TDIBSharedImage.Create;
  1529.     try
  1530.       TempImage.Decompress(FImage, False);
  1531.     except
  1532.       TempImage.Free;
  1533.       raise;
  1534.     end;
  1535.     SetImage(TempImage);
  1536.   end;
  1537. end;
  1538.  
  1539. function TDIB.GetBitmapInfo: PBitmapInfo;
  1540. begin
  1541.   Result := FImage.FBitmapInfo;
  1542. end;
  1543.  
  1544. function TDIB.GetBitmapInfoSize: Integer;
  1545. begin
  1546.   Result := FImage.FBitmapInfoSize;
  1547. end;
  1548.  
  1549. function TDIB.GetCanvas: TCanvas;
  1550. begin
  1551.   if FCanvas=nil then
  1552.   begin
  1553.     FreeImage;
  1554.  
  1555.     FCanvas := TCanvas.Create;
  1556.     FCanvas.Handle := FImage.FDC;
  1557.     FCanvas.OnChanging := CanvasChanging;
  1558.   end;
  1559.   Result := FCanvas;
  1560. end;
  1561.  
  1562. function TDIB.GetEmpty: Boolean;
  1563. begin
  1564.   Result := Size=0;
  1565. end;
  1566.  
  1567. function TDIB.GetHandle: THandle;
  1568. begin
  1569.   Changing(True);
  1570.   Result := FImage.FHandle;
  1571. end;
  1572.  
  1573. function TDIB.GetHeight: Integer;
  1574. begin
  1575.   Result := FHeight;
  1576. end;
  1577.  
  1578. function TDIB.GetPalette: HPalette;
  1579. begin
  1580.   Result := FImage.GetPalette;
  1581. end;
  1582.  
  1583. function TDIB.GetPaletteCount: Integer;
  1584. begin
  1585.   Result := FImage.FPaletteCount;
  1586. end;
  1587.  
  1588. function TDIB.GetPBits: Pointer;
  1589. begin
  1590.   Changing(True);
  1591.   Result := FPBits;
  1592. end;
  1593.  
  1594. function TDIB.GetScanLine(Y: Integer): Pointer;
  1595. begin
  1596.   Changing(True);
  1597.   if (Y<0) or (Y>=FHeight) then
  1598.     raise EInvalidGraphicOperation.CreateFmt(SScanline, [Y]);
  1599.   Result := Pointer(Integer(FTopPBits)+Y*FNextLine);
  1600. end;
  1601.  
  1602. function TDIB.GetTopPBits: Pointer;
  1603. begin
  1604.   Changing(True);
  1605.   Result := FTopPBits;
  1606. end;
  1607.  
  1608. function TDIB.GetWidth: Integer;
  1609. begin
  1610.   Result := FWidth;
  1611. end;
  1612.  
  1613. const
  1614.   Mask1: array[0..7] of DWORD = ($80, $40, $20, $10, $08, $04, $02, $01);
  1615.   Mask1n: array[0..7] of DWORD = ($FFFFFF7F, $FFFFFFBF, $FFFFFFDF, $FFFFFFEF,
  1616.     $FFFFFFF7, $FFFFFFFB, $FFFFFFFD, $FFFFFFFE);
  1617.   Mask4: array[0..1] of DWORD = ($F0, $0F);
  1618.   Mask4n: array[0..1] of DWORD = ($FFFFFF0F, $FFFFFFF0);
  1619.  
  1620.   Shift1: array[0..7] of DWORD = (7, 6, 5, 4, 3, 2, 1, 0);
  1621.   Shift4: array[0..1] of DWORD = (4, 0);
  1622.  
  1623. function TDIB.GetPixel(X, Y: Integer): DWORD;
  1624. begin
  1625.   Decompress;
  1626.  
  1627.   Result := 0;
  1628.   if (X>=0) and (X<FWidth) and (Y>=0) and (Y<FHeight) then
  1629.   begin
  1630.     case FBitCount of
  1631.       1 : Result := (PArrayByte(Integer(FTopPBits)+Y*FNextLine)[X shr 3] and Mask1[X and 7]) shr Shift1[X and 7];
  1632.       4 : Result := (PArrayByte(Integer(FTopPBits)+Y*FNextLine)[X shr 1] and Mask4[X and 1]) shr Shift4[X and 1];
  1633.       8 : Result := PArrayByte(Integer(FTopPBits)+Y*FNextLine)[X];
  1634.       16: Result := PArrayWord(Integer(FTopPBits)+Y*FNextLine)[X];
  1635.       24: with PArrayBGR(Integer(FTopPBits)+Y*FNextLine)[X] do
  1636.             Result := R or (G shl 8) or (B shl 16);
  1637.       32: Result := PArrayDWord(Integer(FTopPBits)+Y*FNextLine)[X];
  1638.     end;
  1639.   end;
  1640. end;
  1641.  
  1642. procedure TDIB.SetPixel(X, Y: Integer; Value: DWORD);
  1643. var
  1644.   P: PByte;
  1645. begin
  1646.   Changing(True);
  1647.  
  1648.   if (X>=0) and (X<FWidth) and (Y>=0) and (Y<FHeight) then
  1649.   begin
  1650.     case FBitCount of
  1651.       1 : begin
  1652.             P := @PArrayByte(Integer(FTopPBits)+Y*FNextLine)[X shr 3];
  1653.             P^ := (P^ and Mask1n[X and 7]) or ((Value and 1) shl Shift1[X and 7]);
  1654.           end;
  1655.       4 : begin
  1656.             P := @PArrayByte(Integer(FTopPBits)+Y*FNextLine)[X shr 3];
  1657.             P^ := (P^ and Mask4n[X and 1]) or ((Value and 15) shl Shift4[X and 1]);
  1658.           end;
  1659.       8 : PArrayByte(Integer(FTopPBits)+Y*FNextLine)[X] := Value;
  1660.       16: PArrayWord(Integer(FTopPBits)+Y*FNextLine)[X] := Value;
  1661.       24: with PArrayBGR(Integer(FTopPBits)+Y*FNextLine)[X] do
  1662.           begin
  1663.             B := Byte(Value shr 16);
  1664.             G := Byte(Value shr 8);
  1665.             R := Byte(Value);
  1666.           end;
  1667.       32: PArrayDWord(Integer(FTopPBits)+Y*FNextLine)[X] := Value;
  1668.     end;
  1669.   end;
  1670. end;
  1671.                             
  1672. procedure TDIB.DefineProperties(Filer: TFiler);
  1673. begin
  1674.   inherited DefineProperties(Filer);
  1675.   {  For interchangeability with an old version.  }
  1676.   Filer.DefineBinaryProperty('DIB', LoadFromStream, nil, False);
  1677. end;
  1678.  
  1679. type
  1680.   TGlobalMemoryStream = class(TMemoryStream)
  1681.   private
  1682.     FHandle: THandle;
  1683.   public
  1684.     constructor Create(AHandle: THandle);
  1685.     destructor Destroy; override;
  1686.   end;
  1687.  
  1688. constructor TGlobalMemoryStream.Create(AHandle: THandle);
  1689. begin
  1690.   inherited Create;
  1691.   FHandle := AHandle;
  1692.   SetPointer(GlobalLock(AHandle), GlobalSize(AHandle));
  1693. end;
  1694.  
  1695. destructor TGlobalMemoryStream.Destroy;
  1696. begin
  1697.   GlobalUnLock(FHandle);
  1698.   SetPointer(nil, 0);
  1699.   inherited Destroy;
  1700. end;
  1701.  
  1702. procedure TDIB.LoadFromClipboardFormat(AFormat: Word; AData: THandle;
  1703.   APalette: HPALETTE);
  1704. var
  1705.   Stream: TGlobalMemoryStream;
  1706. begin
  1707.   Stream := TGlobalMemoryStream.Create(AData);
  1708.   try
  1709.     ReadData(Stream);
  1710.   finally
  1711.     Stream.Free;
  1712.   end;
  1713. end;
  1714.  
  1715. const
  1716.   BitmapFileType = Ord('B') + Ord('M')*$100;
  1717.  
  1718. procedure TDIB.LoadFromStream(Stream: TStream);
  1719. var
  1720.   BF: TBitmapFileHeader;
  1721.   i: Integer;
  1722. begin
  1723.   {  File header reading  }
  1724.   i := Stream.Read(BF, SizeOf(TBitmapFileHeader));
  1725.   if i=0 then Exit;
  1726.   if i<>SizeOf(TBitmapFileHeader) then
  1727.     raise EInvalidGraphic.Create(SInvalidDIB);
  1728.  
  1729.   {  Is the head 'BM'?  }
  1730.   if BF.bfType<>BitmapFileType then
  1731.     raise EInvalidGraphic.Create(SInvalidDIB);
  1732.  
  1733.   ReadData(Stream);
  1734. end;
  1735.  
  1736. procedure TDIB.ReadData(Stream: TStream);
  1737. var
  1738.   TempImage: TDIBSharedImage;
  1739. begin
  1740.   TempImage := TDIBSharedImage.Create;
  1741.   try
  1742.     TempImage.ReadData(Stream, FImage.FMemoryImage);
  1743.   except
  1744.     TempImage.Free;
  1745.     raise;
  1746.   end;
  1747.   SetImage(TempImage);
  1748. end;
  1749.  
  1750. procedure TDIB.SaveToClipboardFormat(var AFormat: Word; var AData: THandle;
  1751.   var APalette: HPALETTE);
  1752. var
  1753.   P: Pointer;
  1754.   Stream: TMemoryStream;
  1755. begin
  1756.   AFormat := CF_DIB;
  1757.   APalette := 0;
  1758.  
  1759.   Stream := TMemoryStream.Create;
  1760.   try
  1761.     WriteData(Stream);
  1762.  
  1763.     AData := GlobalAlloc(GHND, Stream.Size);
  1764.     if AData=0 then OutOfMemoryError;
  1765.  
  1766.     P := GlobalLock(AData);
  1767.     Move(Stream.Memory^, P^, Stream.Size);
  1768.     GlobalUnLock(AData);
  1769.   finally
  1770.     Stream.Free;
  1771.   end;
  1772. end;
  1773.  
  1774. procedure TDIB.SaveToStream(Stream: TStream);
  1775. var
  1776.   BF: TBitmapFileHeader;
  1777. begin
  1778.   if Empty then Exit;
  1779.  
  1780.   with BF do
  1781.   begin
  1782.     bfType    := BitmapFileType;
  1783.     bfOffBits := SizeOf(TBitmapFileHeader)+BitmapInfoSize;
  1784.     bfSize    := bfOffBits+FImage.FBitmapInfo^.bmiHeader.biSizeImage;
  1785.     bfReserved1 := 0;
  1786.     bfReserved2 := 0;
  1787.   end;
  1788.   Stream.WriteBuffer(BF, SizeOf(TBitmapFileHeader));
  1789.  
  1790.   WriteData(Stream);
  1791. end;
  1792.  
  1793. procedure TDIB.WriteData(Stream: TStream);
  1794. begin
  1795.   if Empty then Exit;
  1796.  
  1797.   Stream.WriteBuffer(FImage.FBitmapInfo^, FImage.FBitmapInfoSize);
  1798.   Stream.WriteBuffer(FImage.FPBits^, FImage.FBitmapInfo^.bmiHeader.biSizeImage);
  1799. end;
  1800.  
  1801. procedure TDIB.SetBitCount(Value: Integer);
  1802. begin
  1803.   if Value<=0 then
  1804.     Clear
  1805.   else
  1806.   begin
  1807.     if Empty then
  1808.     begin
  1809.       SetSize(Max(Width, 1), Max(Height, 1), Value)
  1810.     end else
  1811.     begin
  1812.       ConvertBitCount(Value);
  1813.     end;
  1814.   end;
  1815. end;
  1816.  
  1817. procedure TDIB.SetHeight(Value: Integer);
  1818. begin
  1819.   if Value<=0 then
  1820.     Clear
  1821.   else
  1822.   begin
  1823.     if Empty then
  1824.       SetSize(Max(Width, 1), Value, 8)
  1825.     else
  1826.       SetSize(Width, Value, BitCount);
  1827.   end;
  1828. end;
  1829.  
  1830. procedure TDIB.SetWidth(Value: Integer);
  1831. begin
  1832.   if Value<=0 then
  1833.     Clear
  1834.   else
  1835.   begin
  1836.     if Empty then
  1837.       SetSize(Value, Max(Height, 1), 8)
  1838.     else
  1839.       SetSize(Value, Height, BitCount);
  1840.   end;
  1841. end;
  1842.  
  1843. procedure TDIB.SetImage(Value: TDIBSharedImage);
  1844. begin
  1845.   if FImage<>Value then
  1846.   begin
  1847.     if FCanvas<>nil then
  1848.       FCanvas.Handle := 0;
  1849.  
  1850.     FImage.Release;
  1851.     FImage := Value;
  1852.     FImage.Reference;
  1853.  
  1854.     if FCanvas<>nil then
  1855.       FCanvas.Handle := Value.FDC;
  1856.  
  1857.     ColorTable := FImage.FColorTable;
  1858.     PixelFormat := FImage.FPixelFormat;
  1859.  
  1860.     FBitCount := FImage.FBitCount;
  1861.     FHeight := FImage.FHeight;
  1862.     FNextLine := FImage.FNextLine;
  1863.     FNowPixelFormat := FImage.FPixelFormat;
  1864.     FPBits := FImage.FPBits;
  1865.     FSize := FImage.FSize;
  1866.     FTopPBits := FImage.FTopPBits;
  1867.     FWidth := FImage.FWidth;
  1868.     FWidthBytes := FImage.FWidthBytes;
  1869.   end;
  1870. end;
  1871.  
  1872. procedure TDIB.SetNowPixelFormat(const Value: TDIBPixelFormat);
  1873. var
  1874.   Temp: TDIB;
  1875. begin
  1876.   if CompareMem(@Value, @FImage.FPixelFormat, SizeOf(TDIBPixelFormat)) then exit;
  1877.  
  1878.   PixelFormat := Value;
  1879.  
  1880.   Temp := TDIB.Create;
  1881.   try
  1882.     Temp.Assign(Self);
  1883.     SetSize(Width, Height, BitCount);
  1884.     Canvas.Draw(0, 0, Temp);
  1885.   finally
  1886.     Temp.Free;
  1887.   end;
  1888. end;
  1889.  
  1890. procedure TDIB.SetPalette(Value: HPalette);
  1891. var
  1892.   PaletteEntries: TPaletteEntries;
  1893. begin
  1894.   GetPaletteEntries(Value, 0, 256, PaletteEntries);
  1895.   DeleteObject(Value);
  1896.  
  1897.   ColorTable := PaletteEntriesToRGBQuads(PaletteEntries);
  1898.   UpdatePalette;
  1899. end;
  1900.  
  1901. procedure TDIB.SetSize(AWidth, AHeight, ABitCount: Integer);
  1902. var
  1903.   TempImage: TDIBSharedImage;
  1904. begin
  1905.   if (AWidth=Width) and (AHeight=Height) and (ABitCount=BitCount) and
  1906.     (NowPixelFormat.RBitMask=PixelFormat.RBitMask) and
  1907.     (NowPixelFormat.GBitMask=PixelFormat.GBitMask) and
  1908.     (NowPixelFormat.BBitMask=PixelFormat.BBitMask) then Exit;
  1909.  
  1910.   if (AWidth<=0) or (AHeight<=0) then
  1911.   begin
  1912.     Clear;
  1913.     Exit;
  1914.   end;
  1915.  
  1916.   TempImage := TDIBSharedImage.Create;
  1917.   try
  1918.     TempImage.NewImage(AWidth, AHeight, ABitCount,
  1919.       PixelFormat, ColorTable, FImage.FMemoryImage, False);
  1920.   except
  1921.     TempImage.Free;
  1922.     raise;
  1923.   end;
  1924.   SetImage(TempImage);
  1925.  
  1926.   PaletteModified := True;
  1927. end;
  1928.  
  1929. procedure TDIB.UpdatePalette;
  1930. var
  1931.   Col: TRGBQuads;
  1932. begin
  1933.   if CompareMem(@ColorTable, @FImage.FColorTable, SizeOf(ColorTable)) then Exit;
  1934.  
  1935.   Col := ColorTable;
  1936.   Changing(True);
  1937.   ColorTable := Col;
  1938.   FImage.SetColorTable(ColorTable);
  1939.  
  1940.   PaletteModified := True;
  1941. end;
  1942.  
  1943. procedure TDIB.ConvertBitCount(ABitCount: Integer);
  1944. var
  1945.   Temp: TDIB;
  1946.  
  1947.   procedure CreateHalftonePalette(R, G, B: Integer);
  1948.   var
  1949.     i: Integer;
  1950.   begin
  1951.     for i:=0 to 255 do
  1952.       with ColorTable[i] do
  1953.       begin
  1954.         rgbRed   := ((i shr (G+B-1)) and (1 shl R-1)) * 255 div (1 shl R-1);
  1955.         rgbGreen := ((i shr (B-1)) and (1 shl G-1)) * 255 div (1 shl G-1);
  1956.         rgbBlue  := ((i shr 0) and (1 shl B-1)) * 255 div (1 shl B-1);
  1957.       end;
  1958.   end;
  1959.  
  1960.   procedure PaletteToPalette_Inc;
  1961.   var
  1962.     x, y: Integer;
  1963.     i: DWORD;
  1964.     SrcP, DestP: Pointer;
  1965.     P: PByte;
  1966.   begin
  1967.     i := 0;
  1968.  
  1969.     for y:=0 to Height-1 do
  1970.     begin
  1971.       SrcP := Temp.ScanLine[y];
  1972.       DestP := ScanLine[y];
  1973.  
  1974.       for x:=0 to Width-1 do
  1975.       begin
  1976.         case Temp.BitCount of
  1977.           1 : begin
  1978.                 i := (PArrayByte(SrcP)[X shr 3] and Mask1[X and 7]) shr Shift1[X and 7];
  1979.               end;
  1980.           4 : begin
  1981.                 i := (PArrayByte(SrcP)[X and 1] and Mask4[X and 1]) shr Shift4[X and 1];
  1982.               end;
  1983.           8 : begin
  1984.                 i := PByte(SrcP)^;
  1985.                 Inc(PByte(SrcP));
  1986.               end;
  1987.         end;
  1988.  
  1989.         case BitCount of
  1990.           1 : begin
  1991.                 P := @PArrayByte(DestP)[X shr 3];
  1992.                 P^ := (P^ and Mask1n[X and 7]) or (i shl Shift1[X shr 3]);
  1993.               end;
  1994.           4 : begin
  1995.                 P := @PArrayByte(DestP)[X shr 1];
  1996.                 P^ := (P^ and Mask4n[X and 1]) or (i shl Shift4[X and 1]);
  1997.               end;
  1998.           8 : begin
  1999.                 PByte(DestP)^ := i;
  2000.                 Inc(PByte(DestP));
  2001.               end;
  2002.         end;
  2003.       end;
  2004.     end;
  2005.   end;
  2006.  
  2007.   procedure PaletteToRGB_or_RGBToRGB;
  2008.   var
  2009.     x, y: Integer;
  2010.     SrcP, DestP: Pointer;
  2011.     cR, cG, cB: Byte;
  2012.   begin
  2013.     cR := 0;
  2014.     cG := 0;
  2015.     cB := 0;
  2016.  
  2017.     for y:=0 to Height-1 do
  2018.     begin
  2019.       SrcP := Temp.ScanLine[y];
  2020.       DestP := ScanLine[y];
  2021.  
  2022.       for x:=0 to Width-1 do
  2023.       begin
  2024.         case Temp.BitCount of
  2025.           1 : begin
  2026.                 with Temp.ColorTable[(PArrayByte(SrcP)[X shr 3] and Mask1[X and 7]) shr Shift1[X and 7]] do
  2027.                 begin
  2028.                   cR := rgbRed;
  2029.                   cG := rgbGreen;
  2030.                   cB := rgbBlue;
  2031.                 end;
  2032.               end;
  2033.           4 : begin
  2034.                 with Temp.ColorTable[(PArrayByte(SrcP)[X shr 1] and Mask4[X and 1]) shr Shift4[X and 1]] do
  2035.                 begin
  2036.                   cR := rgbRed;
  2037.                   cG := rgbGreen;
  2038.                   cB := rgbBlue;
  2039.                 end;
  2040.               end;
  2041.           8 : begin
  2042.                 with Temp.ColorTable[PByte(SrcP)^] do
  2043.                 begin
  2044.                   cR := rgbRed;
  2045.                   cG := rgbGreen;
  2046.                   cB := rgbBlue;
  2047.                 end;
  2048.                 Inc(PByte(SrcP));
  2049.               end;
  2050.           16: begin
  2051.                 pfGetRGB(Temp.NowPixelFormat, PWord(SrcP)^, cR, cG, cB);
  2052.                 Inc(PWord(SrcP));
  2053.               end;
  2054.           24: begin
  2055.                 with PBGR(SrcP)^ do
  2056.                 begin
  2057.                   cR := R;
  2058.                   cG := G;
  2059.                   cB := B;
  2060.                 end;
  2061.  
  2062.                 Inc(PBGR(SrcP));
  2063.               end;
  2064.           32: begin
  2065.                 pfGetRGB(Temp.NowPixelFormat, PDWORD(SrcP)^, cR, cG, cB);
  2066.                 Inc(PDWORD(SrcP));
  2067.               end;
  2068.         end;
  2069.  
  2070.         case BitCount of
  2071.           16: begin
  2072.                 PWord(DestP)^ := pfRGB(NowPixelFormat, cR, cG, cB);
  2073.                 Inc(PWord(DestP));
  2074.               end;
  2075.           24: begin
  2076.                 with PBGR(DestP)^ do
  2077.                 begin
  2078.                   R := cR;
  2079.                   G := cG;
  2080.                   B := cB;
  2081.                 end;
  2082.                 Inc(PBGR(DestP));
  2083.               end;
  2084.           32: begin
  2085.                 PDWORD(DestP)^ := pfRGB(NowPixelFormat, cR, cG, cB);
  2086.                 Inc(PDWORD(DestP));
  2087.               end;
  2088.         end;
  2089.       end;
  2090.     end;
  2091.   end;
  2092.  
  2093. begin
  2094.   if Size=0 then exit;
  2095.  
  2096.   Temp := TDIB.Create;
  2097.   try
  2098.     Temp.Assign(Self);
  2099.     SetSize(Temp.Width, Temp.Height, ABitCount);
  2100.  
  2101.     if FImage=Temp.FImage then Exit;
  2102.  
  2103.     if (Temp.BitCount<=8) and (BitCount<=8) then
  2104.     begin
  2105.       {  The image is converted from the palette color image into the palette color image.  }
  2106.       if Temp.BitCount<=BitCount then
  2107.       begin
  2108.         PaletteToPalette_Inc;
  2109.       end else
  2110.       begin
  2111.         case BitCount of
  2112.           1: begin
  2113.                ColorTable[0] := RGBQuad(0, 0, 0);
  2114.                ColorTable[1] := RGBQuad(255, 255, 255);
  2115.              end;
  2116.           4: CreateHalftonePalette(1, 2, 1);
  2117.           8: CreateHalftonePalette(3, 3, 2);
  2118.         end;
  2119.         UpdatePalette;
  2120.  
  2121.         Canvas.Draw(0, 0, Temp);
  2122.       end;
  2123.     end else
  2124.     if (Temp.BitCount<=8) and (BitCount>8) then
  2125.     begin
  2126.       {  The image is converted from the palette color image into the rgb color image.  }
  2127.       PaletteToRGB_or_RGBToRGB;
  2128.     end else
  2129.     if (Temp.BitCount>8) and (BitCount<=8) then
  2130.     begin
  2131.       {  The image is converted from the rgb color image into the palette color image.  }
  2132.       case BitCount of
  2133.         1: begin
  2134.              ColorTable[0] := RGBQuad(0, 0, 0);
  2135.              ColorTable[1] := RGBQuad(255, 255, 255);
  2136.            end;
  2137.         4: CreateHalftonePalette(1, 2, 1);
  2138.         8: CreateHalftonePalette(3, 3, 2);
  2139.       end;
  2140.       UpdatePalette;
  2141.  
  2142.       Canvas.Draw(0, 0, Temp);
  2143.     end else
  2144.     if (Temp.BitCount>8) and (BitCount>8) then
  2145.     begin
  2146.       {  The image is converted from the rgb color image into the rgb color image.  }
  2147.       PaletteToRGB_or_RGBToRGB;
  2148.     end;
  2149.   finally
  2150.     Temp.Free;
  2151.   end;
  2152. end;
  2153.  
  2154. {  Special effect  }
  2155.  
  2156. procedure TDIB.StartProgress(const Name: string);
  2157. begin
  2158.   FProgressName := Name;
  2159.   FProgressOld := 0;
  2160.   FProgressOldTime := GetTickCount;
  2161.   FProgressY := 0;
  2162.   FProgressOldY := 0;
  2163.   Progress(Self, psStarting, 0, False, Rect(0, 0, Width, Height), FProgressName);
  2164. end;
  2165.  
  2166. procedure TDIB.EndProgress;
  2167. begin
  2168.   Progress(Self, psEnding, 100, True, Rect(0, FProgressOldY, Width, Height), FProgressName);
  2169. end;
  2170.  
  2171. procedure TDIB.UpdateProgress(PercentY: Integer);
  2172. var
  2173.   Redraw: Boolean;
  2174.   Percent: DWORD;
  2175. begin
  2176.   Redraw := (GetTickCount-FProgressOldTime>200) and (FProgressY-FProgressOldY>32) and
  2177.     (((Height div 3>Integer(FProgressY)) and (FProgressOldY=0)) or (FProgressOldY<>0));
  2178.  
  2179.   Percent := PercentY*100 div Height;
  2180.  
  2181.   if (Percent<>FProgressOld) or (Redraw) then
  2182.   begin
  2183.     Progress(Self, psRunning, Percent, Redraw,
  2184.       Rect(0, FProgressOldY, Width, FProgressY), FProgressName);
  2185.     if Redraw then
  2186.     begin
  2187.       FProgressOldY := FProgressY;
  2188.       FProgressOldTime := GetTickCount;
  2189.     end;
  2190.  
  2191.     FProgressOld := Percent;
  2192.   end;
  2193.  
  2194.   Inc(FProgressY);
  2195. end;
  2196.  
  2197. procedure TDIB.Blur(ABitCount: Integer; Radius: Integer);
  2198. type
  2199.   TAve = record
  2200.     cR, cG, cB: DWORD;
  2201.     c: DWORD;
  2202.   end;
  2203.   TArrayAve = array[0..0] of TAve;
  2204.  
  2205. var
  2206.   Temp: TDIB;
  2207.  
  2208.   procedure AddAverage(Y, XCount: Integer; var Ave: TArrayAve);
  2209.   var
  2210.     X: Integer;
  2211.     SrcP: Pointer;
  2212.     AveP: ^TAve;
  2213.     R, G, B: Byte;
  2214.   begin
  2215.     case Temp.BitCount of
  2216.       1 : begin
  2217.             SrcP := Pointer(Integer(Temp.TopPBits)+Y*Temp.NextLine);
  2218.             AveP := @Ave;
  2219.             for x:=0 to XCount-1 do
  2220.             begin
  2221.               with Temp.ColorTable[(PByte(Integer(SrcP)+X shr 3)^ and Mask1[x and 7]) shr Shift1[x and 7]], AveP^ do
  2222.               begin
  2223.                 Inc(cR, rgbRed);
  2224.                 Inc(cG, rgbGreen);
  2225.                 Inc(cB, rgbBlue);
  2226.                 Inc(c);
  2227.               end;
  2228.               Inc(AveP);
  2229.             end;
  2230.           end;
  2231.       4 : begin
  2232.             SrcP := Pointer(Integer(Temp.TopPBits)+Y*Temp.NextLine);
  2233.             AveP := @Ave;
  2234.             for x:=0 to XCount-1 do
  2235.             begin
  2236.               with Temp.ColorTable[(PByte(Integer(SrcP)+X shr 1)^ and Mask4[x and 1]) shr Shift4[x and 1]], AveP^ do
  2237.               begin
  2238.                 Inc(cR, rgbRed);
  2239.                 Inc(cG, rgbGreen);
  2240.                 Inc(cB, rgbBlue);
  2241.                 Inc(c);
  2242.               end;
  2243.               Inc(AveP);
  2244.             end;
  2245.           end;
  2246.       8 : begin
  2247.             SrcP := Pointer(Integer(Temp.TopPBits)+Y*Temp.NextLine);
  2248.             AveP := @Ave;
  2249.             for x:=0 to XCount-1 do
  2250.             begin
  2251.               with Temp.ColorTable[PByte(SrcP)^], AveP^ do
  2252.               begin
  2253.                 Inc(cR, rgbRed);
  2254.                 Inc(cG, rgbGreen);
  2255.                 Inc(cB, rgbBlue);
  2256.                 Inc(c);
  2257.               end;
  2258.               Inc(PByte(SrcP));
  2259.               Inc(AveP);
  2260.             end;
  2261.           end;
  2262.       16: begin
  2263.             SrcP := Pointer(Integer(Temp.TopPBits)+Y*Temp.NextLine);
  2264.             AveP := @Ave;
  2265.             for x:=0 to XCount-1 do
  2266.             begin
  2267.               pfGetRGB(Temp.NowPixelFormat, PWord(SrcP)^, R, G, B);
  2268.               with AveP^ do
  2269.               begin
  2270.                 Inc(cR, R);
  2271.                 Inc(cG, G);
  2272.                 Inc(cB, B);
  2273.                 Inc(c);
  2274.               end;
  2275.               Inc(PWord(SrcP));
  2276.               Inc(AveP);
  2277.             end;
  2278.           end;
  2279.       24: begin
  2280.             SrcP := Pointer(Integer(Temp.TopPBits)+Y*Temp.NextLine);
  2281.             AveP := @Ave;
  2282.             for x:=0 to XCount-1 do
  2283.             begin
  2284.               with PBGR(SrcP)^, AveP^ do
  2285.               begin
  2286.                 Inc(cR, R);
  2287.                 Inc(cG, G);
  2288.                 Inc(cB, B);
  2289.                 Inc(c);
  2290.               end;
  2291.               Inc(PBGR(SrcP));
  2292.               Inc(AveP);
  2293.             end;
  2294.           end;
  2295.       32: begin
  2296.             SrcP := Pointer(Integer(Temp.TopPBits)+Y*Temp.NextLine);
  2297.             AveP := @Ave;
  2298.             for x:=0 to XCount-1 do
  2299.             begin
  2300.               pfGetRGB(Temp.NowPixelFormat, PDWORD(SrcP)^, R, G, B);
  2301.               with AveP^ do
  2302.               begin
  2303.                 Inc(cR, R);
  2304.                 Inc(cG, G);
  2305.                 Inc(cB, B);
  2306.                 Inc(c);
  2307.               end;
  2308.               Inc(PDWORD(SrcP));
  2309.               Inc(AveP);
  2310.             end;
  2311.           end;
  2312.     end;
  2313.   end;
  2314.  
  2315.   procedure DeleteAverage(Y, XCount: Integer; var Ave: TArrayAve);
  2316.   var
  2317.     X: Integer;
  2318.     SrcP: Pointer;
  2319.     AveP: ^TAve;
  2320.     R, G, B: Byte;
  2321.   begin
  2322.     case Temp.BitCount of
  2323.       1 : begin
  2324.             SrcP := Pointer(Integer(Temp.TopPBits)+Y*Temp.NextLine);
  2325.             AveP := @Ave;
  2326.             for x:=0 to XCount-1 do
  2327.             begin
  2328.               with Temp.ColorTable[(PByte(Integer(SrcP)+X shr 3)^ and Mask1[x and 7]) shr Shift1[x and 7]], AveP^ do
  2329.               begin
  2330.                 Dec(cR, rgbRed);
  2331.                 Dec(cG, rgbGreen);
  2332.                 Dec(cB, rgbBlue);
  2333.                 Dec(c);
  2334.               end;
  2335.               Inc(AveP);
  2336.             end;
  2337.           end;
  2338.       4 : begin
  2339.             SrcP := Pointer(Integer(Temp.TopPBits)+Y*Temp.NextLine);
  2340.             AveP := @Ave;
  2341.             for x:=0 to XCount-1 do
  2342.             begin
  2343.               with Temp.ColorTable[(PByte(Integer(SrcP)+X shr 1)^ and Mask4[x and 1]) shr Shift4[x and 1]], AveP^ do
  2344.               begin
  2345.                 Dec(cR, rgbRed);
  2346.                 Dec(cG, rgbGreen);
  2347.                 Dec(cB, rgbBlue);
  2348.                 Dec(c);
  2349.               end;
  2350.               Inc(AveP);
  2351.             end;
  2352.           end;
  2353.       8 : begin
  2354.             SrcP := Pointer(Integer(Temp.TopPBits)+Y*Temp.NextLine);
  2355.             AveP := @Ave;
  2356.             for x:=0 to XCount-1 do
  2357.             begin
  2358.               with Temp.ColorTable[PByte(SrcP)^], AveP^ do
  2359.               begin
  2360.                 Dec(cR, rgbRed);
  2361.                 Dec(cG, rgbGreen);
  2362.                 Dec(cB, rgbBlue);
  2363.                 Dec(c);
  2364.               end;
  2365.               Inc(PByte(SrcP));
  2366.               Inc(AveP);
  2367.             end;
  2368.           end;
  2369.       16: begin
  2370.             SrcP := Pointer(Integer(Temp.TopPBits)+Y*Temp.NextLine);
  2371.             AveP := @Ave;
  2372.             for x:=0 to XCount-1 do
  2373.             begin
  2374.               pfGetRGB(Temp.NowPixelFormat, PWord(SrcP)^, R, G, B);
  2375.               with AveP^ do
  2376.               begin
  2377.                 Dec(cR, R);
  2378.                 Dec(cG, G);
  2379.                 Dec(cB, B);
  2380.                 Dec(c);
  2381.               end;
  2382.               Inc(PWord(SrcP));
  2383.               Inc(AveP);
  2384.             end;
  2385.           end;
  2386.       24: begin
  2387.             SrcP := Pointer(Integer(Temp.TopPBits)+Y*Temp.NextLine);
  2388.             AveP := @Ave;
  2389.             for x:=0 to XCount-1 do
  2390.             begin
  2391.               with PBGR(SrcP)^, AveP^ do
  2392.               begin
  2393.                 Dec(cR, R);
  2394.                 Dec(cG, G);
  2395.                 Dec(cB, B);
  2396.                 Dec(c);
  2397.               end;
  2398.               Inc(PBGR(SrcP));
  2399.               Inc(AveP);
  2400.             end;
  2401.           end;
  2402.       32: begin
  2403.             SrcP := Pointer(Integer(Temp.TopPBits)+Y*Temp.NextLine);
  2404.             AveP := @Ave;
  2405.             for x:=0 to XCount-1 do
  2406.             begin
  2407.               pfGetRGB(Temp.NowPixelFormat, PDWORD(SrcP)^, R, G, B);
  2408.               with AveP^ do
  2409.               begin
  2410.                 Dec(cR, R);
  2411.                 Dec(cG, G);
  2412.                 Dec(cB, B);
  2413.                 Dec(c);
  2414.               end;
  2415.               Inc(PDWORD(SrcP));
  2416.               Inc(AveP);
  2417.             end;
  2418.           end;
  2419.     end;
  2420.   end;
  2421.  
  2422.   procedure Blur_Radius_Other;
  2423.   var
  2424.     FirstX, LastX, FirstX2, LastX2, FirstY, LastY: Integer;
  2425.     x, y, x2, y2, jx, jy: Integer;
  2426.     Ave: TAve;
  2427.     AveX: ^TArrayAve;
  2428.     DestP: Pointer;
  2429.     P: PByte;
  2430.   begin
  2431.     GetMem(AveX, Width*SizeOf(TAve));
  2432.     try
  2433.       FillChar(AveX^, Width*SizeOf(TAve), 0);
  2434.  
  2435.       FirstX2 := -1;
  2436.       LastX2 := -1;
  2437.       FirstY := -1;
  2438.       LastY := -1;
  2439.  
  2440.       x := 0;
  2441.       for x2:=-Radius to Radius do
  2442.       begin
  2443.         jx := x+x2;
  2444.         if (jx>=0) and (jx<Width) then
  2445.         begin
  2446.           if FirstX2=-1 then FirstX2 := jx;
  2447.           if LastX2<jx then LastX2 := jx;
  2448.         end;
  2449.       end;
  2450.  
  2451.       y := 0;
  2452.       for y2:=-Radius to Radius do
  2453.       begin
  2454.         jy := y+y2;
  2455.         if (jy>=0) and (jy<Height) then
  2456.         begin
  2457.           if FirstY=-1 then FirstY := jy;
  2458.           if LastY<jy then LastY := jy;
  2459.         end;
  2460.       end;
  2461.  
  2462.       for y:=FirstY to LastY do
  2463.         AddAverage(y, Temp.Width, AveX^);
  2464.  
  2465.       for y:=0 to Height-1 do
  2466.       begin
  2467.         DestP := ScanLine[y];
  2468.  
  2469.         {  The average is updated.  }
  2470.         if y-FirstY=Radius+1 then
  2471.         begin
  2472.           DeleteAverage(FirstY, Temp.Width, AveX^);
  2473.           Inc(FirstY);
  2474.         end;
  2475.  
  2476.         if LastY-y=Radius-1 then
  2477.         begin
  2478.           Inc(LastY); if LastY>=Height then LastY := Height-1;
  2479.           AddAverage(LastY, Temp.Width, AveX^);
  2480.         end;
  2481.  
  2482.         {  The average is calculated again.  }
  2483.         FirstX := FirstX2;
  2484.         LastX := LastX2;
  2485.  
  2486.         FillChar(Ave, SizeOf(Ave), 0);
  2487.         for x:=FirstX to LastX do
  2488.           with AveX[x] do
  2489.           begin
  2490.             Inc(Ave.cR, cR);
  2491.             Inc(Ave.cG, cG);
  2492.             Inc(Ave.cB, cB);
  2493.             Inc(Ave.c, c);
  2494.           end;
  2495.  
  2496.         for x:=0 to Width-1 do
  2497.         begin
  2498.           {  The average is updated.  }
  2499.           if x-FirstX=Radius+1 then
  2500.           begin
  2501.             with AveX[FirstX] do
  2502.             begin
  2503.               Dec(Ave.cR, cR);
  2504.               Dec(Ave.cG, cG);
  2505.               Dec(Ave.cB, cB);
  2506.               Dec(Ave.c, c);
  2507.             end;
  2508.             Inc(FirstX);
  2509.           end;
  2510.  
  2511.           if LastX-x=Radius-1 then
  2512.           begin
  2513.             Inc(LastX); if LastX>=Width then LastX := Width-1;
  2514.             with AveX[LastX] do
  2515.             begin
  2516.               Inc(Ave.cR, cR);
  2517.               Inc(Ave.cG, cG);
  2518.               Inc(Ave.cB, cB);
  2519.               Inc(Ave.c, c);
  2520.             end;
  2521.           end;
  2522.  
  2523.           {  The average is written.  }
  2524.           case BitCount of
  2525.             1 : begin
  2526.                   P := @PArrayByte(DestP)[X shr 3];
  2527.                   with Ave do
  2528.                     P^ := (P^ and Mask1n[X and 7]) or (DWORD(Ord(((cR+cG+cB) div c) div 3>127)) shl Shift1[X and 7]);
  2529.                 end;
  2530.             4 : begin
  2531.                   P := @PArrayByte(DestP)[X shr 1];
  2532.                   with Ave do
  2533.                     P^ := (P^ and Mask4n[X and 1]) or (((((cR+cG+cB) div c) div 3) shr 4) shl Shift4[X and 1]);
  2534.                 end;
  2535.             8 : begin
  2536.                   with Ave do
  2537.                     PByte(DestP)^ := ((cR+cG+cB) div c) div 3;
  2538.                   Inc(PByte(DestP));
  2539.                 end;
  2540.             16: begin
  2541.                   with Ave do
  2542.                     PWORD(DestP)^ := pfRGB(NowPixelFormat, cR div c, cG div c, cB div c);
  2543.                   Inc(PWORD(DestP));
  2544.                 end;
  2545.             24: begin
  2546.                   with PBGR(DestP)^, Ave do
  2547.                   begin
  2548.                     R := cR div c;
  2549.                     G := cG div c;
  2550.                     B := cB div c;
  2551.                   end;
  2552.                   Inc(PBGR(DestP));
  2553.                 end;
  2554.             32: begin
  2555.                   with Ave do
  2556.                     PDWORD(DestP)^ := pfRGB(NowPixelFormat, cR div c, cG div c, cB div c);
  2557.                   Inc(PDWORD(DestP));
  2558.                 end;
  2559.           end;
  2560.         end;
  2561.  
  2562.         UpdateProgress(y);
  2563.       end;
  2564.     finally
  2565.       FreeMem(AveX);
  2566.     end;
  2567.   end;
  2568.  
  2569. var
  2570.   i, j: Integer;
  2571. begin
  2572.   if Empty or (Radius=0) then Exit;
  2573.  
  2574.   Radius := Abs(Radius);
  2575.  
  2576.   StartProgress('Blur');
  2577.   try
  2578.     Temp := TDIB.Create;
  2579.     try
  2580.       Temp.Assign(Self);
  2581.       SetSize(Width, Height, ABitCount);
  2582.  
  2583.       if ABitCount<=8 then
  2584.       begin
  2585.         FillChar(ColorTable, SizeOf(ColorTable), 0);
  2586.         for i:=0 to (1 shl ABitCount)-1 do
  2587.         begin
  2588.           j := i * (1 shl (8-ABitCount));
  2589.           j := j or (j shr ABitCount);
  2590.           ColorTable[i] := RGBQuad(j, j, j);
  2591.         end;
  2592.         UpdatePalette;
  2593.       end;
  2594.  
  2595.       Blur_Radius_Other;
  2596.     finally
  2597.       Temp.Free;
  2598.     end;
  2599.   finally
  2600.     EndProgress;
  2601.   end;
  2602. end;
  2603.  
  2604. procedure TDIB.Greyscale(ABitCount: Integer);
  2605. var
  2606.   YTblR, YTblG, YTblB: array[0..255] of Byte;
  2607.   i, j, x, y: Integer;
  2608.   c: DWORD;
  2609.   R, G, B: Byte;
  2610.   Temp: TDIB;
  2611.   DestP, SrcP: Pointer;
  2612.   P: PByte;
  2613. begin
  2614.   if Empty then exit;
  2615.  
  2616.   Temp := TDIB.Create;
  2617.   try
  2618.     Temp.Assign(Self);
  2619.     SetSize(Width, Height, ABitCount);
  2620.  
  2621.     if ABitCount<=8 then
  2622.     begin
  2623.       FillChar(ColorTable, SizeOf(ColorTable), 0);
  2624.       for i:=0 to (1 shl ABitCount)-1 do
  2625.       begin
  2626.         j := i * (1 shl (8-ABitCount));
  2627.         j := j or (j shr ABitCount);
  2628.         ColorTable[i] := RGBQuad(j, j, j);
  2629.       end;
  2630.       UpdatePalette;
  2631.     end;
  2632.  
  2633.     for i:=0 to 255 do
  2634.     begin
  2635.       YTblR[i] := Trunc(0.3588*i);
  2636.       YTblG[i] := Trunc(0.4020*i);
  2637.       YTblB[i] := Trunc(0.2392*i);
  2638.     end;
  2639.  
  2640.     c := 0;
  2641.  
  2642.     StartProgress('Greyscale');
  2643.     try
  2644.       for y:=0 to Height-1 do
  2645.       begin
  2646.         DestP := ScanLine[y];
  2647.         SrcP := Temp.ScanLine[y];
  2648.  
  2649.         for x:=0 to Width-1 do
  2650.         begin
  2651.           case Temp.BitCount of
  2652.             1 : begin
  2653.                   with Temp.ColorTable[(PArrayByte(SrcP)[X shr 3] and Mask1[X and 7]) shr Shift1[X and 7]] do
  2654.                     c := YTblR[rgbRed]+YTblG[rgbGreen]+YTblB[rgbBlue];
  2655.                 end;
  2656.             4 : begin
  2657.                   with Temp.ColorTable[(PArrayByte(SrcP)[X shr 1] and Mask4[X and 1]) shr Shift4[X and 1]] do
  2658.                     c := YTblR[rgbRed]+YTblG[rgbGreen]+YTblB[rgbBlue];
  2659.                 end;
  2660.             8 : begin
  2661.                   with Temp.ColorTable[PByte(SrcP)^] do
  2662.                     c := YTblR[rgbRed]+YTblG[rgbGreen]+YTblB[rgbBlue];
  2663.                   Inc(PByte(SrcP));
  2664.                 end;
  2665.             16: begin
  2666.                   pfGetRGB(Temp.NowPixelFormat, PWord(SrcP)^, R, G, B);
  2667.                   c := YTblR[R]+YTblR[G]+YTblR[B];
  2668.                   Inc(PWord(SrcP));
  2669.                 end;
  2670.             24: begin
  2671.                   with PBGR(SrcP)^ do
  2672.                     c := YTblR[R]+YTblG[G]+YTblB[B];
  2673.                   Inc(PBGR(SrcP));
  2674.                 end;
  2675.             32: begin
  2676.                   pfGetRGB(Temp.NowPixelFormat, PDWORD(SrcP)^, R, G, B);
  2677.                   c := YTblR[R]+YTblR[G]+YTblR[B];
  2678.                   Inc(PDWORD(SrcP));
  2679.                 end;
  2680.           end;
  2681.  
  2682.           case BitCount of
  2683.             1 : begin
  2684.                   P := @PArrayByte(DestP)[X shr 3];
  2685.                   P^ := (P^ and Mask1n[X and 7]) or (DWORD(Ord(c>127)) shl Shift1[X and 7]);
  2686.                 end;
  2687.             4 : begin
  2688.                   P := @PArrayByte(DestP)[X shr 1];
  2689.                   P^ := (P^ and Mask4n[X and 1]) or ((c shr 4) shl Shift4[X and 1]);
  2690.                 end;
  2691.             8 : begin
  2692.                   PByte(DestP)^ := c;
  2693.                   Inc(PByte(DestP));
  2694.                 end;
  2695.             16: begin
  2696.                   PWord(DestP)^ := pfRGB(NowPixelFormat, c, c, c);
  2697.                   Inc(PWord(DestP));
  2698.                 end;
  2699.             24: begin
  2700.                   with PBGR(DestP)^ do
  2701.                   begin
  2702.                     R := c;
  2703.                     G := c;
  2704.                     B := c;
  2705.                   end;
  2706.                   Inc(PBGR(DestP));
  2707.                 end;
  2708.             32: begin
  2709.                   PDWORD(DestP)^ := pfRGB(NowPixelFormat, c, c, c);
  2710.                   Inc(PDWORD(DestP));
  2711.                 end;
  2712.           end;
  2713.         end;
  2714.  
  2715.         UpdateProgress(y);
  2716.       end;
  2717.     finally
  2718.       EndProgress;
  2719.     end;
  2720.   finally
  2721.     Temp.Free;
  2722.   end;
  2723. end;
  2724.  
  2725. procedure TDIB.Mirror(MirrorX, MirrorY: Boolean);
  2726. var
  2727.   x, y, Width2, c: Integer;
  2728.   P1, P2, TempBuf: Pointer;
  2729. begin
  2730.   if Empty then exit;
  2731.   if (not MirrorX) and (not MirrorY) then Exit;
  2732.  
  2733.   if (not MirrorX) and (MirrorY) then
  2734.   begin
  2735.     GetMem(TempBuf, WidthBytes);
  2736.     try
  2737.       StartProgress('Mirror');
  2738.       try
  2739.         for y:=0 to Height shr 1-1 do
  2740.         begin
  2741.           P1 := ScanLine[y];
  2742.           P2 := ScanLine[Height-y-1];
  2743.  
  2744.           Move(P1^, TempBuf^, WidthBytes);
  2745.           Move(P2^, P1^, WidthBytes);
  2746.           Move(TempBuf^, P2^, WidthBytes);
  2747.  
  2748.           UpdateProgress(y*2);
  2749.         end;
  2750.       finally
  2751.         EndProgress;
  2752.       end;
  2753.     finally
  2754.       FreeMem(TempBuf, WidthBytes);
  2755.     end;
  2756.   end else if (MirrorX) and (not MirrorY) then
  2757.   begin
  2758.     Width2 := Width shr 1;
  2759.  
  2760.     StartProgress('Mirror');
  2761.     try
  2762.       for y:=0 to Height-1 do
  2763.       begin
  2764.         P1 := ScanLine[y];
  2765.  
  2766.         case BitCount of
  2767.           1 : begin
  2768.                 for x:=0 to Width2-1 do
  2769.                 begin
  2770.                   c := Pixels[x, y];
  2771.                   Pixels[x, y] := Pixels[Width-x-1, y];
  2772.                   Pixels[Width-x-1, y] := c;
  2773.                 end;
  2774.               end;
  2775.           4 : begin
  2776.                 for x:=0 to Width2-1 do
  2777.                 begin
  2778.                   c := Pixels[x, y];
  2779.                   Pixels[x, y] := Pixels[Width-x-1, y];
  2780.                   Pixels[Width-x-1, y] := c;
  2781.                 end;
  2782.               end;
  2783.           8 : begin
  2784.                 P2 := Pointer(Integer(P1)+Width-1);
  2785.                 for x:=0 to Width2-1 do
  2786.                 begin
  2787.                   PByte(@c)^ := PByte(P1)^;
  2788.                   PByte(P1)^ := PByte(P2)^;
  2789.                   PByte(P2)^ := PByte(@c)^;
  2790.                   Inc(PByte(P1));
  2791.                   Dec(PByte(P2));
  2792.                 end;
  2793.               end;
  2794.           16: begin
  2795.                 P2 := Pointer(Integer(P1)+(Width-1)*2);
  2796.                 for x:=0 to Width2-1 do
  2797.                 begin
  2798.                   PWord(@c)^ := PWord(P1)^;
  2799.                   PWord(P1)^ := PWord(P2)^;
  2800.                   PWord(P2)^ := PWord(@c)^;
  2801.                   Inc(PWord(P1));
  2802.                   Dec(PWord(P2));
  2803.                 end;       
  2804.               end;
  2805.           24: begin
  2806.                 P2 := Pointer(Integer(P1)+(Width-1)*3);
  2807.                 for x:=0 to Width2-1 do              
  2808.                 begin
  2809.                   PBGR(@c)^ := PBGR(P1)^;
  2810.                   PBGR(P1)^ := PBGR(P2)^;
  2811.                   PBGR(P2)^ := PBGR(@c)^;
  2812.                   Inc(PBGR(P1));
  2813.                   Dec(PBGR(P2));
  2814.                 end;
  2815.               end;
  2816.           32: begin
  2817.                 P2 := Pointer(Integer(P1)+(Width-1)*4);
  2818.                 for x:=0 to Width2-1 do
  2819.                 begin
  2820.                   PDWORD(@c)^ := PDWORD(P1)^;
  2821.                   PDWORD(P1)^ := PDWORD(P2)^;
  2822.                   PDWORD(P2)^ := PDWORD(@c)^;
  2823.                   Inc(PDWORD(P1));
  2824.                   Dec(PDWORD(P2));
  2825.                 end;
  2826.               end;
  2827.         end;
  2828.  
  2829.         UpdateProgress(y);
  2830.       end;
  2831.     finally
  2832.       EndProgress;
  2833.     end;
  2834.   end else if (MirrorX) and (MirrorY) then
  2835.   begin
  2836.     StartProgress('Mirror');
  2837.     try
  2838.       for y:=0 to Height shr 1-1 do
  2839.       begin
  2840.         P1 := ScanLine[y];
  2841.         P2 := ScanLine[Height-y-1];
  2842.  
  2843.         case BitCount of
  2844.           1 : begin
  2845.                 for x:=0 to Width-1 do
  2846.                 begin
  2847.                   c := Pixels[x, y];
  2848.                   Pixels[x, y] := Pixels[Width-x-1, Height-y-1];
  2849.                   Pixels[Width-x-1, Height-y-1] := c;
  2850.                 end;
  2851.               end;
  2852.           4 : begin
  2853.                 for x:=0 to Width-1 do
  2854.                 begin
  2855.                   c := Pixels[x, y];
  2856.                   Pixels[x, y] := Pixels[Width-x-1, Height-y-1];
  2857.                   Pixels[Width-x-1, Height-y-1] := c;
  2858.                 end;
  2859.               end;
  2860.           8 : begin
  2861.                 P2 := Pointer(Integer(P2)+Width-1);
  2862.                 for x:=0 to Width-1 do
  2863.                 begin
  2864.                   PByte(@c)^ := PByte(P1)^;
  2865.                   PByte(P1)^ := PByte(P2)^;
  2866.                   PByte(P2)^ := PByte(@c)^;
  2867.                   Inc(PByte(P1));
  2868.                   Dec(PByte(P2));
  2869.                 end;
  2870.               end;
  2871.           16: begin
  2872.                 P2 := Pointer(Integer(P2)+(Width-1)*2);
  2873.                 for x:=0 to Width-1 do
  2874.                 begin
  2875.                   PWord(@c)^ := PWord(P1)^;
  2876.                   PWord(P1)^ := PWord(P2)^;
  2877.                   PWord(P2)^ := PWord(@c)^;
  2878.                   Inc(PWord(P1));
  2879.                   Dec(PWord(P2));
  2880.                 end;
  2881.               end;
  2882.           24: begin
  2883.                 P2 := Pointer(Integer(P2)+(Width-1)*3);
  2884.                 for x:=0 to Width-1 do
  2885.                 begin
  2886.                   PBGR(@c)^ := PBGR(P1)^;
  2887.                   PBGR(P1)^ := PBGR(P2)^;
  2888.                   PBGR(P2)^ := PBGR(@c)^;
  2889.                   Inc(PBGR(P1));
  2890.                   Dec(PBGR(P2));
  2891.                 end;
  2892.               end;
  2893.           32: begin
  2894.                 P2 := Pointer(Integer(P2)+(Width-1)*4);
  2895.                 for x:=0 to Width-1 do
  2896.                 begin
  2897.                   PDWORD(@c)^ := PDWORD(P1)^;
  2898.                   PDWORD(P1)^ := PDWORD(P2)^;
  2899.                   PDWORD(P2)^ := PDWORD(@c)^;
  2900.                   Inc(PDWORD(P1));
  2901.                   Dec(PDWORD(P2));
  2902.                 end;
  2903.               end;
  2904.         end;
  2905.  
  2906.         UpdateProgress(y*2);
  2907.       end;
  2908.     finally
  2909.       EndProgress;
  2910.     end;
  2911.   end;
  2912. end;
  2913.  
  2914. procedure TDIB.Negative;
  2915. var
  2916.   i, i2: Integer;
  2917.   P: Pointer;
  2918. begin
  2919.   if Empty then exit;
  2920.  
  2921.   if BitCount<=8 then
  2922.   begin
  2923.     for i:=0 to 255 do
  2924.       with ColorTable[i] do
  2925.       begin
  2926.         rgbRed := 255-rgbRed;
  2927.         rgbGreen := 255-rgbGreen;
  2928.         rgbBlue := 255-rgbBlue;
  2929.       end;
  2930.     UpdatePalette;
  2931.   end else
  2932.   begin
  2933.     P := PBits;
  2934.     i2 := Size;
  2935.     asm
  2936.       mov ecx,i2
  2937.       mov eax,P
  2938.       mov edx,ecx
  2939.  
  2940.     {  Unit of DWORD.  }
  2941.     @@qword_skip:
  2942.       shr ecx,2
  2943.       jz @@dword_skip
  2944.  
  2945.       dec ecx
  2946.     @@dword_loop:
  2947.       not dword ptr [eax+ecx*4]
  2948.       dec ecx
  2949.       jnl @@dword_loop
  2950.  
  2951.       mov ecx,edx
  2952.       shr ecx,2
  2953.       add eax,ecx*4
  2954.  
  2955.     {  Unit of Byte.  }
  2956.     @@dword_skip:
  2957.       mov ecx,edx
  2958.       and ecx,3
  2959.       jz @@byte_skip
  2960.  
  2961.       dec ecx
  2962.     @@loop_byte:
  2963.       not byte ptr [eax+ecx]
  2964.       dec ecx
  2965.       jnl @@loop_byte
  2966.  
  2967.     @@byte_skip:
  2968.     end;
  2969.   end;
  2970. end;
  2971.  
  2972. {  TCustomDXDIB  }
  2973.  
  2974. constructor TCustomDXDIB.Create(AOnwer: TComponent);
  2975. begin
  2976.   inherited Create(AOnwer);
  2977.   FDIB := TDIB.Create;
  2978. end;
  2979.  
  2980. destructor TCustomDXDIB.Destroy;
  2981. begin
  2982.   FDIB.Free;
  2983.   inherited Destroy;
  2984. end;
  2985.  
  2986. procedure TCustomDXDIB.SetDIB(Value: TDIB);
  2987. begin
  2988.   FDIB.Assign(Value);
  2989. end;
  2990.  
  2991. {  TCustomDXPaintBox  }
  2992.  
  2993. constructor TCustomDXPaintBox.Create(AOwner: TComponent);
  2994. begin
  2995.   inherited Create(AOwner);
  2996.   FDIB := TDIB.Create;
  2997.  
  2998.   ControlStyle := ControlStyle + [csReplicatable];
  2999.   Height := 105;
  3000.   Width := 105;
  3001. end;
  3002.  
  3003. destructor TCustomDXPaintBox.Destroy;
  3004. begin
  3005.   FDIB.Free;
  3006.   inherited Destroy;
  3007. end;
  3008.  
  3009. function TCustomDXPaintBox.GetPalette: HPALETTE;
  3010. begin
  3011.   Result := FDIB.Palette;
  3012. end;
  3013.  
  3014. procedure TCustomDXPaintBox.Paint;
  3015.  
  3016.   procedure Draw2(Width, Height: Integer);
  3017.   begin
  3018.     if (Width<>FDIB.Width) or (Height<>FDIB.Height) then
  3019.     begin
  3020.       if FCenter then
  3021.       begin
  3022.         inherited Canvas.StretchDraw(Bounds(-(Width-ClientWidth) shr 1,
  3023.           -(Height-ClientHeight) shr 1, Width, Height), FDIB);
  3024.       end else
  3025.       begin
  3026.         inherited Canvas.StretchDraw(Bounds(0, 0, Width, Height), FDIB);
  3027.       end;
  3028.     end else
  3029.     begin
  3030.       if FCenter then
  3031.       begin
  3032.         inherited Canvas.Draw(-(Width-ClientWidth) shr 1, -(Height-ClientHeight) shr 1,
  3033.           FDIB);
  3034.       end else
  3035.       begin
  3036.         inherited Canvas.Draw(0, 0, FDIB);
  3037.       end;
  3038.     end;
  3039.   end;
  3040.  
  3041. var
  3042.   r, r2: Single;
  3043. begin
  3044.   inherited Paint;
  3045.  
  3046.   with inherited Canvas do
  3047.   begin
  3048.     if (csDesigning in ComponentState) then
  3049.     begin
  3050.       Pen.Style := psDash;
  3051.       Brush.Style := bsClear;
  3052.       Rectangle(0, 0, Width, Height);
  3053.     end;
  3054.  
  3055.     if FDIB.Empty then Exit;
  3056.  
  3057.     if FAutoStretch then
  3058.     begin
  3059.       if (FDIB.Width>ClientWidth) or (FDIB.Height>ClientHeight) then
  3060.       begin
  3061.         r := ClientWidth/FDIB.Width;
  3062.         r2 := ClientHeight/FDIB.Height;
  3063.         if r>r2 then
  3064.           r := r2;
  3065.         Draw2(Round(r*FDIB.Width), Round(r*FDIB.Height));
  3066.       end else
  3067.         Draw2(FDIB.Width, FDIB.Height);
  3068.     end else
  3069.     if FStretch then
  3070.     begin
  3071.       if FKeepAspect then
  3072.       begin
  3073.         r := ClientWidth/FDIB.Width;
  3074.         r2 := ClientHeight/FDIB.Height;
  3075.         if r>r2 then
  3076.           r := r2;
  3077.         Draw2(Round(r*FDIB.Width), Round(r*FDIB.Height));
  3078.       end else
  3079.         Draw2(ClientWidth, ClientHeight);
  3080.     end else
  3081.       Draw2(FDIB.Width, FDIB.Height);
  3082.   end;
  3083. end;
  3084.  
  3085. procedure TCustomDXPaintBox.SetAutoStretch(Value: Boolean);
  3086. begin
  3087.   if FAutoStretch<>Value then
  3088.   begin
  3089.     FAutoStretch := Value;
  3090.     Invalidate;
  3091.   end;
  3092. end;
  3093.  
  3094. procedure TCustomDXPaintBox.SetCenter(Value: Boolean);
  3095. begin
  3096.   if FCenter<>Value then
  3097.   begin
  3098.     FCenter := Value;
  3099.     Invalidate;
  3100.   end;
  3101. end;
  3102.  
  3103. procedure TCustomDXPaintBox.SetDIB(Value: TDIB);
  3104. begin
  3105.   if FDIB<>Value then
  3106.   begin
  3107.     FDIB.Assign(Value);
  3108.     Invalidate;
  3109.   end;
  3110. end;
  3111.  
  3112. procedure TCustomDXPaintBox.SetKeepAspect(Value: Boolean);
  3113. begin
  3114.   if Value<>FKeepAspect then
  3115.   begin
  3116.     FKeepAspect := Value;
  3117.     Invalidate;
  3118.   end;
  3119. end;
  3120.  
  3121. procedure TCustomDXPaintBox.SetStretch(Value: Boolean);
  3122. begin
  3123.   if Value<>FStretch then
  3124.   begin
  3125.     FStretch := Value;
  3126.     Invalidate;
  3127.   end;
  3128. end;
  3129.  
  3130. initialization
  3131.   TPicture.RegisterClipBoardFormat(CF_DIB, TDIB);
  3132.   TPicture.RegisterFileFormat('dib', 'Device Independent Bitmap', TDIB);
  3133. finalization
  3134.   TPicture.UnRegisterGraphicClass(TDIB);
  3135.  
  3136.   FEmptyDIBImage.Free;
  3137.   FPaletteManager.Free;
  3138. end.
  3139.