imagereader.pas
上传用户:raido2005
上传日期:2022-06-22
资源大小:5044k
文件大小:43k
源码类别:

Delphi控件源码

开发平台:

Delphi

  1. //*******************************************************//
  2. //                                                       //
  3. //                      DelphiFlash.com                  //
  4. //         Copyright (c) 2004-2007 FeatherySoft, Inc.    //
  5. //                    info@delphiflash.com               //
  6. //                                                       //
  7. //*******************************************************//
  8. //  Description:  Image routines
  9. //  Last update:  28 mar 2007
  10. unit ImageReader;
  11. interface
  12. uses Windows, Classes;
  13. type
  14.   PFColor =^TFColor;
  15.   TFColor = packed record
  16.     b,g,r: Byte;
  17.   end;
  18.   PFColorA =^TFColorA;
  19.   TFColorA = packed record
  20.     case Integer of
  21.       0: (i: DWord);
  22.       1: (c: TFColor);
  23.       2: (hi,lo: Word);
  24.       3: (b,g,r,a: Byte);
  25.     end;
  26.   PFColorTable =^TFColorTable;
  27.   TFColorTable = array[Byte]of TFColorA;
  28.   PFPackedColorTable =^TFPackedColorTable;
  29.   TFPackedColorTable = array[Byte]of TFColor;
  30.   TLines    = array[Word]of Pointer;  PLines    =^TLines;
  31.   TLine8    = array[Word]of Byte;     PLine8    =^TLine8;
  32.   TLine16   = array[Word]of Word;     PLine16   =^TLine16;
  33.   TLine24   = array[Word]of TFColor;  PLine24   =^TLine24;
  34.   TLine32   = array[Word]of TFColorA; PLine32   =^TLine32;
  35.   TPixels8  = array[Word]of PLine8;   PPixels8  =^TPixels8;
  36.   TPixels16 = array[Word]of PLine16;  PPixels16 =^TPixels16;
  37.   TPixels24 = array[Word]of PLine24;  PPixels24 =^TPixels24;
  38.   TPixels32 = array[Word]of PLine32;  PPixels32 =^TPixels32;
  39.   PBMInfo =^TBMInfo;
  40.   TBMInfo = packed record
  41.     Header: TBitmapInfoHeader;
  42.     case Integer of
  43.       0: (Colors: TFColorTable);
  44.       1: (RMask,GMask,BMask: DWord);
  45.     end;
  46.   TBMPReader = class
  47.   private
  48.     Info:      TBMInfo;      // bitmap information
  49.     FreeDC:     Boolean; // default true, free GDI surface on destroy
  50.     FreeBits:   Boolean; // default true, free Bits on destroy (non GDI only)
  51.     FreeHandle: Boolean;
  52.     FTransparentIndex: integer;
  53.     procedure SetTransparentIndex(const Value: integer); // default true, free GDI handle on destroy
  54.     function GetBMask: DWord;
  55.     function GetGMask: DWord;
  56.     function GetRMask: DWord;
  57.     procedure SetBMask(const Value: DWord);
  58.     procedure SetGMask(const Value: DWord);
  59.     procedure SetRMask(const Value: DWord); 
  60.     
  61.     function GetClrUsed: DWord;
  62.     procedure SetClrUsed(const Value: DWord);
  63.     function GetSizeImage: DWord;
  64.     procedure SetSizeImage(const Value: DWord); 
  65.     function GetCompression: DWord;
  66.     procedure SetCompression(const Value: DWord);
  67.     function GetBpp: Word;
  68.     procedure SetBpp(const Value: Word);
  69.     function GetHeight: Integer;
  70.     procedure SetHeight(const Value: Integer);
  71.     function GetWidth: Integer;
  72.     procedure SetWidth(const Value: Integer);
  73.   protected
  74.     procedure PrepareAlphaTables(bmHeader: TBitmapInfoHeader);
  75.   public
  76.     DC:    HDC;
  77.     Handle: HBITMAP; // current DIB in hDC
  78.     BWidth:    Integer;      // number of bytes per scanline
  79.     AbsHeight: Integer;      // number of scanlines in bitmap
  80.     Gap:       Integer;      // number of pad bytes at end of scanline
  81.     Bits:      PLine8;       // typed pointer to bits
  82.     Colors:    PFColorTable; // typed pointer to color table
  83.     Bpb,Bpg,Bpr:    Byte; // bits per channel (only 16 & 32bpp)
  84.     BShr,GShr,RShr: Byte; // (B shr BShr)or(G shr GShr shl GShl)or
  85.     BShl,GShl,RShl: Byte; // (R shr RShr shl RShl) = 16bit/32bit pixel
  86.     Scanlines:  PLines;    // typed pointer to array of scanline offsets
  87.     Pixels8:    PPixels8;  // typed scanlines - Pixels8[y,x]:  Byte
  88.     Pixels16:   PPixels16; // typed scanlines - Pixels16[y,x]: Word
  89.     Pixels24:   PPixels24; // typed scanlines - Pixels24[y,x]: TFColor
  90.     Pixels32:   PPixels32; // typed scanlines - Pixels32[y,x]: TFColorA
  91.     constructor Create;
  92.     destructor Destroy; override;
  93.     procedure FreeHandles;
  94.     procedure Assign(Bmp:TBMPReader);
  95.     // use these for debugging or reference (these don't belong in long loops)
  96.     procedure SetPixel(y,x:Integer;c:TFColor);
  97.     procedure SetPixelB(y,x:Integer;c:Byte);
  98.     function GetPixel(y,x:Integer):TFColor;
  99.     function GetPixelB(y,x:Integer):Byte;
  100.     property Pixels[y,x:Integer]:TFColor read GetPixel write SetPixel;
  101.     property PixelsB[y,x:Integer]:Byte read GetPixelB write SetPixelB;
  102.     property Width: Integer read GetWidth write SetWidth;
  103.     property Height: Integer read GetHeight write SetHeight;
  104.     property Bpp: Word read GetBpp write SetBpp;
  105.     property Compression: DWord read GetCompression write SetCompression;
  106.     property SizeImage: DWord read GetSizeImage write SetSizeImage;
  107.     property ClrUsed: DWord read GetClrUsed write SetClrUsed;
  108.     property RMask: DWord read GetRMask write SetRMask;
  109.     property GMask: DWord read GetGMask write SetGMask;
  110.     property BMask: DWord read GetBMask write SetBMask;
  111.     // initializers
  112.     procedure SetSize(fWidth,fHeight:Integer;fBpp:Byte);
  113.     procedure SetSizeEx(fWidth, fHeight: Integer; fBpp, fBpr, fBpg, fBpb: Byte);
  114.     procedure SetSizeIndirect(bmInfo: TBMInfo);
  115.     procedure SetInterface(fBits: Pointer; fWidth, fHeight: Integer; fBpp, fBpr, fBpg, fBpb: Byte);
  116.     procedure SetInterfaceIndirect(fBits:Pointer;bmInfo:TBMInfo);
  117.     procedure MakeCopy(Bmp:TBMPReader;CopyBits:Boolean);
  118.     procedure LoadFromHandle(hBmp:HBITMAP);
  119.     procedure LoadFromFile(FileName:string);
  120.     procedure LoadFromStream(stream: TStream);
  121.     procedure LoadFromRes(hInst:HINST;ResID,ResType:PChar);
  122.     // blitting methods
  123.     procedure UpdateColors;
  124.     property TransparentIndex: integer read FTransparentIndex write SetTransparentIndex;
  125.     // utilities
  126.     procedure Clear(c:TFColor);
  127.     procedure ClearB(c:DWord);
  128.     procedure SaveToFile(FileName:string);
  129.     procedure SaveToStream(stream: TStream);
  130.     procedure CopyRect(Src:TBMPReader; x,y, w,h, sx,sy:Integer);
  131.     procedure ShiftColors(i1,i2,Amount:Integer);
  132.   end;
  133. function CreateDIB(fDC:HDC;bmInfo:PBMInfo;iColor:DWord;var Bits:PLine8;hSection,dwOffset:DWord):HBITMAP; stdcall;
  134. Function LoadHeaderFromFile(FileName:string): TBMInfo;
  135. procedure SetAlphaChannel(Bmp, Alpha: TBMPReader);
  136. procedure FillAlpha(Bmp: TBMPReader; Alpha: byte);
  137. procedure FillAlphaNoSrc(Bmp: TBMPReader; Alpha: byte);
  138. function IsInitAlpha(Bmp: TBMPReader): boolean;
  139. procedure MultiplyAlpha(Bmp:TBMPReader);
  140. procedure SwapChannels(Bmp:TBMPReader);
  141. procedure FillMem(Mem:Pointer;Size,Value:Integer);
  142. procedure Clear(Bmp:TBMPReader;c:TFColor);
  143. procedure ClearB(Bmp:TBMPReader;c:DWord);
  144. procedure DecodeRLE4(Bmp:TBMPReader;Data:Pointer);
  145. procedure DecodeRLE8(Bmp:TBMPReader;Data:Pointer);
  146. function  ClosestColor(Pal:PFColorTable;Max:Integer;c:TFColor):Byte;
  147. function  LoadHeader(Data:Pointer; var bmInfo:TBMInfo):Integer;
  148. function  PackedDIB(Bmp:TBMPReader):Pointer;
  149. function  CountColors(Bmp:TBMPReader):DWord;
  150. procedure IntToMask(Bpr,Bpg,Bpb:DWord;var RMsk,GMsk,BMsk:DWord);
  151. procedure MaskToInt(RMsk,GMsk,BMsk:DWord;var Bpr,Bpg,Bpb:DWord);
  152. function  UnpackColorTable(Table:TFPackedColorTable):TFColorTable;
  153. function  PackColorTable(Table:TFColorTable):TFPackedColorTable;
  154. function  FRGB(r,g,b:Byte):TFColor;
  155. function  FRGBA(r,g,b,a:Byte):TFColorA;
  156. function  ColorToInt(c:TFColor):DWord;
  157. function  ColorToIntA(c:TFColorA):DWord;
  158. function  IntToColor(i:DWord):TFColor;
  159. function  IntToColorA(i:DWord):TFColorA;
  160. function  Scale8(i,n:Integer):Integer;
  161. function  Get16Bpg:Byte;
  162. Function isSupportImageFormat(fn: string): boolean;
  163. procedure GetJPGSize(const sFile: string; var wWidth, wHeight: word);
  164. //procedure GetPNGSize(const sFile: string; var wWidth, wHeight: word);
  165. //procedure GetGIFSize(const sGIFFile: string; var wWidth, wHeight: word);
  166. implementation
  167. Uses SysUtils;
  168. function CreateDIB; external 'gdi32.dll' name 'CreateDIBSection';
  169. function ReadMWord(f: TFileStream): word;
  170. type
  171.   TMotorolaWord = record
  172.   case byte of
  173.   0: (Value: word);
  174.   1: (Byte1, Byte2: byte);
  175. end;
  176. var
  177.   MW: TMotorolaWord;
  178. begin
  179. {It would probably be better to just read these two bytes in normally and
  180. then do a small ASM routine to swap them. But we aren't talking about
  181. reading entire files, so I doubt the performance gain would be worth the trouble.}
  182.   f.Read(MW.Byte2, SizeOf(Byte));
  183.   f.Read(MW.Byte1, SizeOf(Byte));
  184.   Result := MW.Value;
  185. end;
  186. procedure GetJPGSize(const sFile: string; var wWidth, wHeight: word);
  187. const
  188.   ValidSig : array[0..1] of byte = ($FF, $D8);
  189.   Parameterless = [$01, $D0, $D1, $D2, $D3, $D4, $D5, $D6, $D7];
  190. var
  191.   Sig: array[0..1] of byte;
  192.   f: TFileStream;
  193.   x: integer;
  194.   Seg: byte;
  195.   Dummy: array[0..15] of byte;
  196.   Len: word;
  197.   ReadLen: LongInt;
  198. begin
  199.   FillChar(Sig, SizeOf(Sig), #0);
  200.   f := TFileStream.Create(sFile, fmOpenRead+fmShareDenyWrite);
  201.   try
  202.     ReadLen := f.Read(Sig[0], SizeOf(Sig));
  203.     for x := Low(Sig) to High(Sig) do
  204.     if Sig[x] <> ValidSig[x] then ReadLen := 0;
  205.     if ReadLen > 0 then begin
  206.       ReadLen := f.Read(Seg, 1);
  207.       while (Seg = $FF) and (ReadLen > 0) do begin
  208.         ReadLen := f.Read(Seg, 1);
  209.         if Seg <> $FF then begin
  210.           if (Seg = $C0) or (Seg = $C1) then begin
  211.             ReadLen := f.Read(Dummy[0], 3); { don't need these bytes }
  212.             wHeight := ReadMWord(f);
  213.             wWidth := ReadMWord(f);
  214.           end else begin
  215.             if not (Seg in Parameterless) then begin
  216.               Len := ReadMWord(f);
  217.               f.Seek(Len-2, 1);
  218.               f.Read(Seg, 1);
  219.             end else
  220.               Seg := $FF; { Fake it to keep looping. }
  221.             end;
  222.           end;
  223.         end;
  224.       end;
  225.   finally
  226.     f.Free;
  227.   end;
  228. end;
  229. Function isSupportImageFormat(fn: string): boolean;
  230.   var Ext: string;
  231. begin
  232.   Ext := UpperCase(ExtractFileExt(fn));
  233.   Result := (Ext = '.BMP') or (Ext = '.JPG') or (Ext = '.JPEG');
  234. end;
  235. constructor TBMPReader.Create;
  236. begin
  237.   inherited Create;
  238.   Bits := nil;
  239.   Scanlines := nil;
  240.   FTransparentIndex := -1;
  241.   FillChar(Info, SizeOf(Info),0);
  242.   Info.Header.biSize := SizeOf(TBitmapInfoHeader);
  243.   Info.Header.biPlanes := 1;
  244.   Colors := @Info.Colors;
  245. end;
  246. destructor TBMPReader.Destroy;
  247. begin
  248.   FreeHandles;
  249.   inherited Destroy;
  250. end;
  251. procedure TBMPReader.FreeHandles;
  252. begin
  253.   if (DC <> 0) and FreeDC then DeleteDC(DC);
  254.   if (Handle <> 0) and FreeHandle then DeleteObject(Handle);
  255.   if (Scanlines <> nil) then ReallocMem(Scanlines, 0);
  256.   if (Bits <> nil) and FreeBits then ReallocMem(Bits, 0);
  257. end;
  258. procedure TBMPReader.Assign(Bmp:TBMPReader);
  259. begin
  260.   FreeHandles;
  261.   DC := Bmp.DC;
  262.   Handle:=Bmp.Handle;       BWidth:=Bmp.BWidth;
  263.   AbsHeight:=Bmp.AbsHeight; Gap:=Bmp.Gap;
  264.   Bits:=Bmp.Bits;           Colors^:=Bmp.Colors^;
  265.   Info:=Bmp.Info;           BShr:=Bmp.BShr;
  266.   GShr:=Bmp.GShr;           GShl:=Bmp.GShl;
  267.   RShr:=Bmp.RShr;           RShl:=Bmp.RShl;
  268.   Bpr:=Bmp.Bpr;             Bpg:=Bmp.Bpg;
  269.   Bpb:=Bmp.Bpb;             Scanlines:=Bmp.Scanlines;
  270.   Pixels8:=Bmp.Pixels8;     Pixels16:=Bmp.Pixels16;
  271.   Pixels24:=Bmp.Pixels24;   Pixels32:=Bmp.Pixels32;
  272.   FreeDC:=Bmp.FreeDC;
  273.   FreeBits:=Bmp.FreeBits;   FreeHandle:=Bmp.FreeHandle;
  274.   Bmp.FreeDC:=False;
  275.   Bmp.FreeHandle:=False;
  276.   Bmp.Scanlines:=nil;
  277.   Bmp.FreeBits:=False;
  278.   Bmp.Free;
  279. end;
  280. procedure TBMPReader.SetPixel(y,x:Integer;c:TFColor);
  281. begin
  282.   case Bpp of
  283.     1,4,8: PixelsB[y,x]:=ClosestColor(Colors,(1 shl Bpp)-1,c);
  284.     16: Pixels16[y,x]:=
  285.           c.r shr RShr shl RShl or
  286.           c.g shr GShr shl GShl or
  287.           c.b shr BShr;
  288.     24: Pixels24[y,x]:=c;
  289.     32: if Compression=0 then Pixels32[y,x].c:=c else
  290.         Pixels32[y,x].i:=
  291.           c.r shr RShr shl RShl or
  292.           c.g shr GShr shl GShl or
  293.           c.b shr BShr;
  294.   end;
  295. end;
  296. procedure TBMPReader.SetPixelB(y,x:Integer;c:Byte);
  297. var
  298.   mo: Byte;
  299.   pb: PByte;
  300. begin
  301.   case Bpp of
  302.     1:
  303.     begin
  304.       c:=c and 1;
  305.       mo:=(x and 7)xor 7;
  306.       pb:=@Pixels8[y,x shr 3];
  307.       pb^:=pb^ and(not(1 shl mo))or(c shl mo);
  308.     end;
  309.     4:
  310.     begin
  311.       c:=c and 15;
  312.       pb:=@Pixels8[y,x shr 1];
  313.       if(x and 1)=0 then pb^:=(pb^and $0F)or(c shl 4)else pb^:=(pb^and $F0)or c;
  314.     end;
  315.     8: Pixels8[y,x]:=c;
  316.   end;
  317. end;
  318. function TBMPReader.GetBMask: DWord;
  319. begin
  320.   Result := Info.BMask;
  321. end;
  322. procedure TBMPReader.SetRMask(const Value: DWord);
  323. begin
  324.   Info.RMask := Value;
  325. end;
  326. function TBMPReader.GetBpp: Word;
  327. begin
  328.   Result := Info.Header.biBitCount;
  329. end;
  330. function TBMPReader.GetClrUsed: DWord;
  331. begin
  332.  Result := Info.Header.biClrUsed
  333. end;
  334. function TBMPReader.GetCompression: DWord;
  335. begin
  336.   Result := Info.Header.biCompression
  337. end;
  338. function TBMPReader.GetGMask: DWord;
  339. begin
  340.   Result := Info.GMask;
  341. end;
  342. function TBMPReader.GetHeight: Integer;
  343. begin
  344.   Result := Info.Header.biHeight;
  345. end;
  346. function TBMPReader.GetPixel(y,x:Integer):TFColor;
  347. var
  348.   w: Word;
  349.   d: DWord;
  350. begin
  351.   case Bpp of
  352.     1,4,8: Result:=Colors[PixelsB[y,x]].c;
  353.     16:
  354.     begin
  355.       w:=Pixels16[y,x];
  356.       Result.b:=Scale8(w and BMask,Bpb);
  357.       Result.g:=Scale8(w and GMask shr GShl,Bpg);
  358.       Result.r:=Scale8(w and RMask shr RShl,Bpr);
  359.     end;
  360.     24: Result:=Pixels24[y,x];
  361.     32:
  362.     if Compression=0 then Result:=Pixels32[y,x].c else
  363.     begin
  364.       d:=Pixels32[y,x].i;
  365.       Result.b:=Scale8(d and BMask,Bpb);
  366.       Result.g:=Scale8(d and GMask shr GShl,Bpg);
  367.       Result.r:=Scale8(d and RMask shr RShl,Bpr);
  368.     end;
  369.   end;
  370. end;
  371. function TBMPReader.GetPixelB(y,x:Integer):Byte;
  372. var
  373.   mo: Byte;
  374. begin
  375.   case Bpp of
  376.     1:
  377.     begin
  378.       mo := (x and 7)xor 7;
  379.       Result := Pixels8[y, x shr 3] and (1 shl mo) shr mo;
  380.     end;
  381.     4: if (x and 1) = 0 then Result := Pixels8[y,x shr 1] shr 4 else Result:=Pixels8[y,x shr 1] and 15;
  382.     8: Result:=Pixels8[y,x];
  383.     else Result:=0;
  384.   end;
  385. end;
  386. function TBMPReader.GetRMask: DWord;
  387. begin
  388.   Result := Info.RMask;
  389. end;
  390. function TBMPReader.GetSizeImage: DWord;
  391. begin
  392.   Result := Info.Header.biSizeImage;
  393. end;
  394. procedure TBMPReader.SetWidth(const Value: Integer);
  395. begin
  396.   Info.Header.biWidth := Value;
  397. end;
  398. procedure TBMPReader.SetSize(fWidth,fHeight:Integer;fBpp:Byte);
  399. begin
  400.   SetInterface(nil,fWidth,fHeight,fBpp,0,0,0);
  401. end;
  402. procedure TBMPReader.SetSizeEx(fWidth,fHeight:Integer;fBpp,fBpr,fBpg,fBpb:Byte);
  403. begin
  404.   SetInterface(nil,fWidth,fHeight,fBpp,fBpr,fBpg,fBpb);
  405. end;
  406. procedure TBMPReader.SetSizeImage(const Value: DWord);
  407. begin
  408.   Info.Header.biSizeImage := Value;
  409. end;
  410. procedure TBMPReader.SetSizeIndirect(bmInfo: TBMInfo);
  411. var
  412.   r, g, b: DWord;
  413. begin
  414.   if bmInfo.Header.biCompression in [1, 2] then
  415.     if (bmInfo.RMask <> 0) or (bmInfo.GMask <> 0) or (bmInfo.BMask <> 0)then
  416.       bmInfo.Header.biCompression := 3 else bmInfo.Header.biCompression := 0;
  417.   if (bmInfo.Header.biBitCount in [16, 32]) and (bmInfo.Header.biCompression = 3) then
  418.     MaskToInt(bmInfo.RMask, bmInfo.GMask, bmInfo.BMask, r, g, b) else
  419.   begin
  420.     r:=0;
  421.     g:=0;
  422.     b:=0;
  423.   end;
  424.   FTransparentIndex := -1;
  425.   if bmInfo.Header.biBitCount <= 8 then
  426.     Colors^ := bmInfo.Colors;
  427.   PrepareAlphaTables(bmInfo.Header);
  428.   SetInterface(nil, bmInfo.Header.biWidth, bmInfo.Header.biHeight, bmInfo.Header.biBitCount, r, g, b);
  429. end;
  430. procedure TBMPReader.SetTransparentIndex(const Value: integer);
  431. begin
  432.   if (BPP <= 8) and (FTransparentIndex <> Value) then
  433.     begin
  434.       Colors[FTransparentIndex].A := $FF;
  435.       FTransparentIndex := Value;
  436.       Colors[FTransparentIndex].A := 0;
  437.     end;
  438. end;
  439. function TBMPReader.GetWidth: Integer;
  440. begin
  441.   Result := Info.Header.biWidth;
  442. end;
  443. procedure TBMPReader.SetBMask(const Value: DWord);
  444. begin
  445.   Info.BMask := Value;
  446. end;
  447. procedure TBMPReader.SetBpp(const Value: Word);
  448. begin
  449.   Info.Header.biBitCount := Value;
  450. end;
  451. procedure TBMPReader.SetClrUsed(const Value: DWord);
  452. begin
  453.   Info.Header.biClrUsed := Value;
  454. end;
  455. procedure TBMPReader.SetCompression(const Value: DWord);
  456. begin
  457.   Info.Header.biCompression := Value;
  458. end;
  459. procedure TBMPReader.SetGMask(const Value: DWord);
  460. begin
  461.   Info.GMask := Value;
  462. end;
  463. procedure TBMPReader.SetHeight(const Value: Integer);
  464. begin
  465.   Info.Header.biHeight := Value; 
  466. end;
  467. procedure TBMPReader.SetInterface(fBits: Pointer; fWidth, fHeight: Integer;
  468.                                   fBpp, fBpr, fBpg, fBpb: Byte);
  469. var
  470.   x, il: Integer;
  471.   sDC: Windows.HDC;
  472. begin
  473.   if fBpp=0 then
  474.   begin
  475.     sDC:=GetDC(0);
  476.     fBpp:=GetDeviceCaps(sDC, BITSPIXEL);
  477.     ReleaseDC(0,sDC);
  478.     if fBpp=16 then
  479.     begin
  480.       fBpr:=5;
  481.       fBpg:=Get16Bpg;
  482.       fBpb:=5;
  483.     end else if fBpp=32 then
  484.     begin
  485.       fBpr:=8;
  486.       fBpg:=8;
  487.       fBpb:=8;
  488.     end;
  489.   end;
  490.   if (fBpr = 0) and (fBpg = 0) and (fBpb = 0) then
  491.   begin
  492.     Compression:=0;
  493.     if fBpp=16 then
  494.     begin
  495.       fBpr:=5;
  496.       fBpg:=5;
  497.       fBpb:=5;
  498.     end else if fBpp=32 then
  499.     begin
  500.       fBpr:=8;
  501.       fBpg:=8;
  502.       fBpb:=8;
  503.     end;
  504.   end else Compression:=3;
  505.   if( fBpp=16) or (fBpp=32) then IntToMask(fBpr, fBpg, fBpb, Info.RMask, Info.GMask, Info.BMask);
  506.   if((fBits=nil) and (fWidth=Width) and (fHeight=Height) and (fBpp=Bpp) and
  507.      (fBpr=Bpr) and (fBpg=Bpg) and (fBpb=Bpb)) and (DC<>0) then Exit;
  508.   Width:=fWidth;            Height:=fHeight;
  509.   AbsHeight:=Abs(fHeight);  Bpp:=fBpp;
  510.   Bpr:=fBpr;                Bpg:=fBpg;
  511.   Bpb:=fBpb;                GShl:=Bpb;
  512.   RShl:=Bpb+Bpg;
  513.   if Bpb<8 then BShr:=8-Bpb else BShr:=0;
  514.   if Bpg<8 then GShr:=8-Bpg else GShr:=0;
  515.   if Bpr<8 then RShr:=8-Bpr else RShr:=0;
  516.   case Bpp of
  517.     1:
  518.     begin
  519.       x:=(Width+7)and -8;
  520.       BWidth:=((x+31)and -32)shr 3;
  521.       Gap:=BWidth-(x shr 3);
  522.     end;
  523.     4:
  524.     begin
  525.       x:=((Width shl 2)+7)and -8;
  526.       BWidth:=((x+31)and -32)shr 3;
  527.       Gap:=BWidth-(x shr 3);
  528.     end;
  529.     8:
  530.     begin
  531.       BWidth:=(((Width shl 3)+31)and -32)shr 3;
  532.       Gap:=BWidth-Width;
  533.     end;
  534.     16:
  535.     begin
  536.       BWidth:=(((Width shl 4)+31)and -32)shr 3;
  537.       Gap:=BWidth-(Width shl 1);
  538.     end;
  539.     24:
  540.     begin
  541.       BWidth:=(((Width*24)+31)and -32)shr 3;
  542.       Gap:=BWidth-((Width shl 1)+Width);
  543.     end;
  544.     32:
  545.     begin
  546.       BWidth:=(((Width shl 5)+31)and -32)shr 3;
  547.       Gap:=0;
  548.     end;
  549.   end;
  550.   SizeImage := AbsHeight * BWidth;
  551.   if (fBits<>nil) then Bits := fBits else
  552.   begin
  553.     if (DC<>0) and FreeDC then DeleteDC(DC);
  554.     if (Handle<>0) and FreeHandle then DeleteObject(Handle);
  555.     if (Bits <> nil) and FreeBits then ReallocMem(Bits, 0);
  556.     Handle := CreateDIB(0, @Info, 0, Bits, 0, 0);
  557.     DC := CreateCompatibleDC(0);
  558.     SelectObject(DC, Handle);
  559.     FreeBits := False;
  560.     FreeDC := True;
  561.     FreeHandle := True;
  562.   end;
  563.   ReallocMem(Scanlines, AbsHeight shl 2);
  564.   Pixels8 := Pointer(Scanlines);
  565.   Pixels16 := Pointer(Scanlines);
  566.   Pixels24 := Pointer(Scanlines);
  567.   Pixels32 := Pointer(Scanlines);
  568.   if AbsHeight>0 then
  569.   begin
  570.     x := Integer(Bits);
  571.     for il:=0 to AbsHeight-1 do
  572.     begin
  573.       Scanlines[il] := Ptr(x);
  574.       Inc(x, BWidth);
  575.     end;
  576.   end;
  577. end;
  578. procedure TBMPReader.SetInterfaceIndirect(fBits: Pointer; bmInfo: TBMInfo);
  579. var
  580.   r, g, b: DWord;
  581. begin
  582.   With bmInfo.Header do
  583.    begin
  584.      if biCompression in [1, 2] then
  585.        if (bmInfo.RMask<>0) or (bmInfo.GMask<>0) or (bmInfo.BMask<>0) then
  586.          biCompression := 3 else biCompression := 0;
  587.      if (biBitCount in [16, 32]) and (biCompression = 3) then
  588.        MaskToInt(bmInfo.RMask, bmInfo.GMask, bmInfo.BMask, r, g, b) else
  589.      begin
  590.        r:=0; g:=0; b:=0;
  591.      end;
  592.      if biBitCount<=8 then Colors^:=bmInfo.Colors;
  593.    end;
  594.   SetInterface(fBits, bmInfo.Header.biWidth, bmInfo.Header.biHeight, bmInfo.Header.biBitCount, r, g, b);
  595. end;
  596. procedure TBMPReader.MakeCopy(Bmp: TBMPReader; CopyBits: Boolean);
  597. begin
  598.   SetSizeIndirect(Bmp.Info);
  599.   if CopyBits then Move(Bmp.Bits^, Bits^, SizeImage);
  600. end;
  601. procedure TBMPReader.PrepareAlphaTables(bmHeader: TBitmapInfoHeader);
  602. var
  603.   il, maxCheck: integer;
  604.   NeedFillAlpha, is0, is255: boolean;
  605. begin
  606.   FTransparentIndex := -1;
  607.   if bmHeader.biBitCount <= 8 then
  608.     begin
  609.       if bmHeader.biBitCount = 8 then
  610.         begin
  611.           is0 := false;
  612.           is255 := false;
  613.           if bmHeader.biClrUsed > 0 then maxCheck := bmHeader.biClrUsed - 1
  614.             else maxCheck := $FF;
  615.           for il := 0 to maxCheck do
  616.             begin
  617.               if Colors[il].A = $FF then is255 := true else
  618.                 if Colors[il].A = 0 then is0 := true;
  619.             end;
  620.           NeedFillAlpha := (is0 and not is255);
  621.           if is0 and is255 then
  622.             for il := 0 to $FF do
  623.               if Colors[il].A = 0 then
  624.                 begin
  625.                   FTransparentIndex := il;
  626.                   Break;
  627.                 end;
  628.         end else
  629.           NeedFillAlpha := true;
  630.       if NeedFillAlpha then
  631.         for il := 0 to (1 shl bmHeader.biBitCount) - 1 do
  632.           Colors[il].A := $FF;
  633.     end;
  634. end;
  635. procedure TBMPReader.LoadFromHandle(hBmp:HBITMAP);
  636. var
  637.   dsInfo: TDIBSection;
  638. begin
  639.   if GetObject(hBmp,SizeOf(dsInfo),@dsInfo)=84 then
  640.   begin
  641.     SetSizeIndirect(PBMInfo(@dsInfo.dsBmih)^);
  642.     if dsInfo.dsBmih.biCompression = 1 then DecodeRLE8(Self,dsInfo.dsBm.bmBits)
  643.     else if dsInfo.dsBmih.biCompression = 2 then DecodeRLE4(Self,dsInfo.dsBm.bmBits)
  644.     else Move(dsInfo.dsBm.bmBits^, Bits^, dsInfo.dsBmih.biSizeImage);
  645.     if Bpp <= 8 then
  646.     begin
  647.       GetDIBits(DC, hBmp, 0, 0, nil, PBitmapInfo(@Info)^, 0);
  648.       UpdateColors;
  649.       PrepareAlphaTables(Info.Header);
  650.     end;
  651.   end else
  652.   begin
  653.     SetSize(dsInfo.dsBm.bmWidth, dsInfo.dsBm.bmHeight, 0);
  654.     GetDIBits(DC, hBmp, 0, AbsHeight, Bits, PBitmapInfo(@Info)^, 0);
  655.     if Bpp <= 8 then
  656.       begin
  657.         UpdateColors;
  658.         PrepareAlphaTables(Info.Header);
  659.       end;
  660.   end;
  661. end;
  662. procedure TBMPReader.LoadFromFile(FileName: string);
  663. var
  664.   FS : TFileStream;
  665. begin
  666.    FS := TFileStream.Create(FileName, fmOpenRead + fmShareDenyWrite);
  667.    LoadFromStream(FS);
  668.    FS.Free;
  669. end;
  670. procedure TBMPReader.LoadFromStream(stream: TStream);
  671. var
  672.   Buffer: Pointer;
  673.   bmInfo: TBMInfo;
  674.   fBits, xSize: DWord;
  675. begin
  676.   xSize := stream.size;
  677.   if xSize > 1078 then xSize := 1078;
  678.   GetMem(Buffer, 1078);
  679.   stream.read(Buffer^, xSize);
  680.   fBits := LoadHeader(Buffer, bmInfo);
  681.   SetSizeIndirect(bmInfo);
  682.   stream.Seek(fBits - xSize, soFromCurrent);
  683.   if bmInfo.Header.biCompression in [1, 2] then xSize := PDWord(Integer(Buffer)+2)^ - fBits
  684.    else
  685.     if (stream.size - fBits) > SizeImage then xSize := SizeImage else xSize := stream.size - fBits;
  686.   if bmInfo.Header.biCompression in [0, 3] then stream.read(Bits^, xSize) else
  687.    begin
  688.     ReAllocMem(Buffer, xSize);
  689.     stream.read(Buffer^, xSize);
  690.     if bmInfo.Header.biCompression=1 then DecodeRLE8(Self, Buffer) else DecodeRLE4(Self, Buffer);
  691.    end;
  692.   FreeMem(Buffer);
  693. end;
  694. Function LoadHeaderFromFile(FileName:string): TBMInfo;
  695. var
  696.   Buffer: Pointer;
  697.   hFile: Windows.HFILE;
  698.   xSize, fSize, i: DWord;
  699. begin
  700.   hFile := CreateFile(PChar(FileName),GENERIC_READ,FILE_SHARE_READ,nil,OPEN_EXISTING,0,0);
  701.   fSize := GetFileSize(hFile,nil);
  702.   xSize := fSize;
  703.   if xSize > 1078 then xSize :=1078;
  704.   GetMem(Buffer, 1078);
  705.   ReadFile(hFile, Buffer^, xSize, i, nil);
  706.   LoadHeader(Buffer, Result);
  707.   CloseHandle(hFile);
  708.   FreeMem(Buffer);
  709. end;
  710. procedure TBMPReader.LoadFromRes(hInst: HINST; ResID, ResType: PChar);
  711. var
  712.   pMem: Pointer;
  713.   bmInfo: TBMInfo;
  714.   fSize,fBits: DWord;
  715. begin
  716.   pMem := LockResource(LoadResource(hInst, FindResource(hInst, ResID, ResType)));
  717.   if pMem<>nil then
  718.   begin
  719.     fBits := LoadHeader(pMem,bmInfo);
  720.     fSize := PDWord(pMem)^-DWord(fBits);
  721.     SetSizeIndirect(bmInfo);
  722.     if SizeImage < fSize then fSize := SizeImage;
  723.     if bmInfo.Header.biCompression=1 then DecodeRLE8(Self, Ptr(DWord(pMem) + fBits))
  724.       else
  725.       if bmInfo.Header.biCompression=2 then DecodeRLE4(Self, Ptr(DWord(pMem) + fBits))
  726.        else Move(Ptr(DWord(pMem)+fBits)^,Bits^,fSize);
  727.   end;
  728. end;
  729. procedure TBMPReader.UpdateColors;
  730. begin
  731.   SetDIBColorTable(DC, 0, 1 shl Bpp, Colors^);
  732. end;
  733. procedure TBMPReader.Clear(c:TFColor);
  734. begin
  735.   ImageReader.Clear(Self, c);
  736. end;
  737. procedure TBMPReader.ClearB(c:DWord);
  738. begin
  739.   ImageReader.ClearB(Self,c);
  740. end;
  741. procedure TBMPReader.SaveToFile(FileName:string);
  742. var
  743.   FS: TFileStream;
  744. begin
  745.   if fileExists(FileName) then DeleteFile(FileName);
  746.   FS := TFileStream.Create(FileName, fmCreate);
  747.   SaveToStream(FS);
  748.   FS.Free;
  749. end;
  750. procedure TBMPReader.SaveToStream(stream: TStream);
  751.  var
  752.   cSize: DWord;
  753.   fHead: TBitmapFileHeader;
  754. begin
  755.   if Info.Header.biClrUsed<>0
  756.     then cSize := (Info.Header.biClrUsed shl 2)
  757.     else if Info.Header.biCompression=BI_BITFIELDS then cSize := 12
  758.       else if Bpp <= 8 then cSize := (1 shl Bpp) shl 2
  759.         else cSize := 0;
  760.   fHead.bfType := $4D42;
  761.   fHead.bfOffBits := 54 + cSize;
  762.   fHead.bfSize := fHead.bfOffBits + SizeImage;
  763.   stream.Write(fHead, SizeOf(fHead));
  764.   stream.Write(Info,cSize+40);
  765.   stream.WriteBuffer(Bits^, SizeImage);
  766. end;
  767. procedure TBMPReader.CopyRect(Src:TBMPReader;x,y,w,h,sx,sy:Integer);
  768. var
  769.   iy,pc,sc,b: Integer;
  770. begin
  771.   if Height>0 then y:=AbsHeight-h-y;
  772.   if Src.Height>0 then sy:=Src.Height-h-sy;
  773.   if x<0 then
  774.   begin
  775.     Dec(sx,x);
  776.     Inc(w,x);
  777.     x:=0;
  778.   end;
  779.   if y<0 then
  780.   begin
  781.     Dec(sy,y);
  782.     Inc(h,y);
  783.     y:=0;
  784.   end;
  785.   if sx<0 then
  786.   begin
  787.     Dec(x,sx);
  788.     Inc(w,sx);
  789.     sx:=0;
  790.   end;
  791.   if sy<0 then
  792.   begin
  793.     Dec(y,sy);
  794.     Inc(h,sy);
  795.     sy:=0;
  796.   end;
  797.   if(sx<Src.Width)and(sy<Src.AbsHeight)and(x<Width)and(y<AbsHeight)then
  798.   begin
  799.     if w+sx>=Src.Width then w:=Src.Width-sx;
  800.     if h+sy>=Src.AbsHeight then h:=Src.AbsHeight-sy;
  801.     if w+x>=Width then w:=Width-x;
  802.     if h+y>=AbsHeight then h:=AbsHeight-y;
  803.     if (Bpp <= 8) and (Bpp=Src.Bpp) then
  804.       Move(Src.Colors^, Colors^, SizeOf(TFColorTable));
  805.     if(Bpp>=8)and(Bpp=Src.Bpp)then
  806.     begin
  807.       b:=w;
  808.       case Bpp of
  809.         16:
  810.         begin
  811.           b:=w shl 1;
  812.           x:=x shl 1;
  813.           sx:=sx shl 1;
  814.         end;
  815.         24:
  816.         begin
  817.           b:=w*3;
  818.           x:=x*3;
  819.           sx:=sx*3;
  820.         end;
  821.         32:
  822.         begin
  823.           b:=w shl 2;
  824.           x:=x shl 2;
  825.           sx:=sx shl 2;
  826.         end;
  827.       end;
  828.       pc:=Integer(Scanlines[y])+x;
  829.       sc:=Integer(Src.Scanlines[sy])+sx;
  830.       for iy:=0 to h-1 do
  831.       begin
  832.         Move(Ptr(sc)^,Ptr(pc)^,b);
  833.         Inc(pc,BWidth);
  834.         Inc(sc,Src.BWidth);
  835.       end;
  836.     end else
  837.     begin
  838.       for iy:=0 to h-1 do
  839.       for b:=0 to w-1 do
  840.         Pixels[y+iy,x+b]:=Src.Pixels[sy+iy,sx+b];
  841.     end;
  842.   end;
  843. end;
  844. procedure TBMPReader.ShiftColors(i1, i2, Amount: Integer);
  845. var
  846.   p: PFColorTable;
  847.   i: Integer;
  848. begin
  849.   i:= i2 - i1;
  850.   if (Amount < i) and (Amount > 0) then
  851.   begin
  852.     GetMem(p, i shl 2);
  853.     Move(Colors[i1], p[0], i shl 2);
  854.     Move(p[0], Colors[i1 + Amount], (i - Amount) shl 2);
  855.     Move(p[i - Amount], Colors[i1], Amount shl 2);
  856.     FreeMem(p);
  857.   end;
  858.   if DC <> 0 then UpdateColors;
  859. end;
  860. ////////////////////////////////////////////////////////////////////////////////
  861. procedure SetAlphaChannel(Bmp, Alpha: TBMPReader);
  862. var
  863.   pb: PByte;
  864.   pc: PFColorA;
  865.   x,y: Integer;
  866. begin
  867.   pb := Pointer(Alpha.Bits);
  868.   pc := Pointer(Bmp.Bits);
  869.   for y := 0 to Alpha.AbsHeight - 1 do
  870.   begin
  871.     for x := 0 to Alpha.Width - 1 do
  872.     begin
  873.       pc^.a := pb^;
  874.       Inc(pc);
  875.       Inc(pb);
  876.     end;
  877.     pc := Ptr(Integer(pc) + Bmp.Gap);
  878.     Inc(pb, Alpha.Gap);
  879.   end;
  880. end;
  881. procedure FillAlpha(Bmp: TBMPReader; Alpha: byte);
  882. var
  883.   pc: PFColorA;
  884.   x,y: Integer;
  885. begin
  886.   pc := Pointer(Bmp.Bits);
  887.   for y := 0 to Bmp.AbsHeight - 1 do
  888.   begin
  889.     for x := 0 to Bmp.Width - 1 do
  890.     begin
  891.       pc^.a := Alpha;
  892.       Inc(pc);
  893.     end;
  894.     pc := Ptr(Integer(pc) + Bmp.Gap);
  895.   end;
  896. end;
  897. procedure FillAlphaNoSrc(Bmp: TBMPReader; Alpha: byte);
  898. var
  899.   pc: PFColorA;
  900.   x,y: Integer;
  901. begin
  902.   pc := Pointer(Bmp.Bits);
  903.   for y := 0 to Bmp.AbsHeight - 1 do
  904.   begin
  905.     for x := 0 to Bmp.Width - 1 do
  906.     begin
  907.       if (pc^.r > 0) or (pc^.g > 0) or (pc^.b > 0)
  908.         then pc^.a := Alpha
  909.         else pc^.a := 0;
  910.       Inc(pc);
  911.     end;
  912.     pc := Ptr(Integer(pc) + Bmp.Gap);
  913.   end;
  914. end;
  915. function IsInitAlpha(Bmp: TBMPReader): boolean;
  916. var
  917.   pc: PFColorA;
  918.   x,y: Integer;
  919. begin
  920.   pc := Pointer(Bmp.Bits);
  921.   Result := false;
  922.   for y := 0 to Bmp.AbsHeight - 1 do
  923.   begin
  924.     for x := 0 to Bmp.Width - 1 do
  925.     begin
  926.       Result := pc^.a > 0;
  927.       if Result then Exit;
  928.       Inc(pc);
  929.     end;
  930.     pc := Ptr(Integer(pc) + Bmp.Gap);
  931.   end;
  932. end;
  933. procedure MultiplyAlpha(Bmp:TBMPReader);
  934. var
  935.   pc: PFColorA;
  936.   x,y,i: Integer;
  937. begin
  938.   pc:=Pointer(Bmp.Bits);
  939.   for y:=0 to Bmp.AbsHeight-1 do
  940.   begin
  941.     for x:=0 to Bmp.Width-1 do
  942.     begin
  943.       i:=pc.a;
  944.       if i=0 then
  945.       begin
  946.         pc.b:=0;
  947.         pc.g:=0;
  948.         pc.r:=0;
  949.       end else if i<255 then
  950.       begin
  951.         pc.b:=(pc.b*i)shr 8;
  952.         pc.g:=(pc.g*i)shr 8;
  953.         pc.r:=(pc.r*i)shr 8;
  954.       end;
  955.       Inc(pc);
  956.     end;
  957.     pc:=Ptr(Integer(pc)+Bmp.Gap);
  958.   end;
  959. end;
  960. procedure SwapChannels24(Bmp:TBMPReader);
  961. var
  962.   pc: PFColor;
  963.   x,y,z: Integer;
  964. begin
  965.   pc:=Pointer(Bmp.Bits);
  966.   for y:=0 to Bmp.AbsHeight-1 do
  967.   begin
  968.     for x:=0 to Bmp.Width-1 do
  969.     begin
  970.       z:=pc.r;
  971.       pc.r:=pc.b;
  972.       pc.b:=z;
  973.       Inc(pc);
  974.     end;
  975.     pc:=Ptr(Integer(pc)+Bmp.Gap);
  976.   end;
  977. end;
  978. procedure SwapChannels32(Bmp:TBMPReader);
  979. var
  980.   pc: PFColorA;
  981.   x,y,z: Integer;
  982. begin
  983.   pc:=Pointer(Bmp.Bits);
  984.   for y:=0 to Bmp.AbsHeight-1 do
  985.   begin
  986.     for x:=0 to Bmp.Width-1 do
  987.     begin
  988.       z:=pc.r;
  989.       pc.r:=pc.b;
  990.       pc.b:=z;
  991.       Inc(pc);
  992.     end;
  993.     pc:=Ptr(Integer(pc)+Bmp.Gap);
  994.   end;
  995. end;
  996. procedure SwapChannels(Bmp:TBMPReader);
  997. begin
  998.   case Bmp.Bpp of
  999.     24: SwapChannels24(Bmp);
  1000.     32: SwapChannels32(Bmp);
  1001.   end;
  1002. end;
  1003. procedure FillMem(Mem:Pointer;Size,Value:Integer);
  1004. asm
  1005.   push edi
  1006.   push ebx
  1007.   mov ebx,edx
  1008.   mov edi,eax
  1009.   mov eax,ecx
  1010.   mov ecx,edx
  1011.   shr ecx,2
  1012.   jz  @word
  1013.   rep stosd
  1014.   @word:
  1015.   mov ecx,ebx
  1016.   and ecx,2
  1017.   jz  @byte
  1018.   mov [edi],ax
  1019.   add edi,2
  1020.   @byte:
  1021.   mov ecx,ebx
  1022.   and ecx,1
  1023.   jz  @exit
  1024.   mov [edi],al
  1025.   @exit:
  1026.   pop ebx
  1027.   pop edi
  1028. end;
  1029. procedure Clear(Bmp:TBMPReader;c:TFColor);
  1030. begin
  1031.   case Bmp.Bpp of
  1032.     1,4,8: ClearB(Bmp,ClosestColor(Bmp.Colors,(1 shl Bmp.Bpp)-1,c));
  1033.     16: ClearB(Bmp,c.r shr Bmp.RShr shl Bmp.RShl or
  1034.           c.g shr Bmp.GShr shl Bmp.GShl or
  1035.           c.b shr Bmp.BShr);
  1036.     24: ClearB(Bmp,PDWord(@c)^);
  1037.     32: if Bmp.Compression = 0 then ClearB(Bmp,PDWord(@c)^) else
  1038.         ClearB(Bmp,c.r shr Bmp.RShr shl Bmp.RShl or
  1039.           c.g shr Bmp.GShr shl Bmp.GShl or
  1040.           c.b shr Bmp.BShr);
  1041.   end;
  1042. end;
  1043. procedure ClearB(Bmp:TBMPReader;c:DWord);
  1044. var
  1045.   i: Integer;
  1046.   pc: PFColor;
  1047. begin
  1048.   if(Bmp.Bpp=1)and(c=1)then c:=15;
  1049.   if Bmp.Bpp<=4 then c:=c or c shl 4;
  1050.   if Bmp.Bpp<=8 then
  1051.   begin
  1052.     c:=c or c shl 8;
  1053.     c:=c or c shl 16;
  1054.   end else if Bmp.Bpp=16 then c:=c or c shl 16;
  1055.   if Bmp.Bpp=24 then
  1056.   begin
  1057.     pc:=Pointer(Bmp.Bits);
  1058.     for i:=0 to Bmp.Width-1 do
  1059.     begin
  1060.       pc^:=PFColor(@c)^;
  1061.       Inc(pc);
  1062.     end;
  1063.     for i:=1 to Bmp.AbsHeight-1 do
  1064.       Move(Bmp.Bits^,Bmp.Scanlines[i]^,Bmp.BWidth-Bmp.Gap);
  1065.   end else
  1066.   begin
  1067.     if Bmp.SizeImage <> 0 then FillMem(Bmp.Bits, Bmp.SizeImage, c) else
  1068.       for i:=0 to Bmp.AbsHeight-1 do
  1069.         FillMem(Bmp.Scanlines[i],Bmp.BWidth-Bmp.Gap,c);
  1070.   end;
  1071. end;
  1072. procedure DecodeRLE4(Bmp:TBMPReader;Data:Pointer);
  1073.   procedure OddMove(Src,Dst:PByte;Size:Integer);
  1074.   begin
  1075.     if Size=0 then Exit;
  1076.     repeat
  1077.       Dst^:=(Dst^ and $F0)or(Src^ shr 4);
  1078.       Inc(Dst);
  1079.       Dst^:=(Dst^ and $0F)or(Src^ shl 4);
  1080.       Inc(Src);
  1081.       Dec(Size);
  1082.     until Size=0;
  1083.   end;
  1084.   procedure OddFill(Mem:PByte;Size,Value:Integer);
  1085.   begin
  1086.     Value:=(Value shr 4)or(Value shl 4);
  1087.     Mem^:=(Mem^ and $F0)or(Value and $0F);
  1088.     Inc(Mem);
  1089.     if Size>1 then FillChar(Mem^,Size,Value);
  1090.     Mem^:=(Mem^ and $0F)or(Value and $F0);
  1091.   end;
  1092. var
  1093.   pb: PByte;
  1094.   x,y,z,i: Integer;
  1095. begin
  1096.   pb:=Data; x:=0; y:=0;
  1097.   while y<Bmp.AbsHeight do
  1098.   begin
  1099.     if pb^=0 then
  1100.     begin
  1101.       Inc(pb);
  1102.       z:=pb^;
  1103.       case pb^ of
  1104.         0: begin
  1105.              Inc(y);
  1106.              x:=0;
  1107.            end;
  1108.         1: Break;
  1109.         2: begin
  1110.              Inc(pb); Inc(x,pb^);
  1111.              Inc(pb); Inc(y,pb^);
  1112.            end;
  1113.         else
  1114.         begin
  1115.           Inc(pb);
  1116.           i:=(z+1)shr 1;
  1117.           if(z and 2)=2 then Inc(i);
  1118.           if((x and 1)=1)and(x+i<Bmp.Width)then
  1119.             OddMove(pb,@Bmp.Pixels8[y,x shr 1],i)
  1120.           else
  1121.             Move(pb^,Bmp.Pixels8[y,x shr 1],i);
  1122.           Inc(pb,i-1);
  1123.           Inc(x,z);
  1124.         end;
  1125.       end;
  1126.     end else
  1127.     begin
  1128.       z:=pb^;
  1129.       Inc(pb);
  1130.       if((x and 1)=1)and(x+z<Bmp.Width)then
  1131.         OddFill(@Bmp.Pixels8[y,x shr 1],z shr 1,pb^)
  1132.       else
  1133.         FillChar(Bmp.Pixels8[y,x shr 1],z shr 1,pb^);
  1134.       Inc(x,z);
  1135.     end;
  1136.     Inc(pb);
  1137.   end;
  1138. end;
  1139. procedure DecodeRLE8(Bmp:TBMPReader;Data:Pointer);
  1140. var
  1141.   pb: PByte;
  1142.   x,y,z,i,s: Integer;
  1143. begin
  1144.   pb:=Data; y:=0; x:=0;
  1145.   while y<Bmp.AbsHeight do
  1146.   begin
  1147.     if pb^=0 then
  1148.     begin
  1149.       Inc(pb);
  1150.       case pb^ of
  1151.         0: begin
  1152.              Inc(y);
  1153.              x:=0;
  1154.            end;
  1155.         1: Break;
  1156.         2: begin
  1157.              Inc(pb); Inc(x,pb^);
  1158.              Inc(pb); Inc(y,pb^);
  1159.            end;
  1160.         else
  1161.         begin
  1162.           i:=pb^;
  1163.           s:=(i+1)and(not 1);
  1164.           z:=s-1;
  1165.           Inc(pb);
  1166.           if x+s>Bmp.Width then s:=Bmp.Width-x;
  1167.           Move(pb^,Bmp.Pixels8[y,x],s);
  1168.           Inc(pb,z);
  1169.           Inc(x,i);
  1170.         end;
  1171.       end;
  1172.     end else
  1173.     begin
  1174.       i:=pb^; Inc(pb);
  1175.       if i+x>Bmp.Width then i:=Bmp.Width-x;
  1176.       FillChar(Bmp.Pixels8[y,x],i,pb^);
  1177.       Inc(x,i);
  1178.     end;
  1179.     Inc(pb);
  1180.   end;
  1181. end;
  1182. procedure FillColors(Pal:PFColorTable;i1,i2,nKeys:Integer;Keys:PLine24);
  1183. var
  1184.   pc: PFColorA;
  1185.   c1,c2: TFColor;
  1186.   i,n,cs,w1,w2,x,ii: Integer;
  1187. begin
  1188.   i:=0;
  1189.   n:=i2-i1;
  1190.   Dec(nKeys);
  1191.   ii:=(nKeys shl 16)div n;
  1192.   pc:=@Pal[i1];
  1193.   for x:=0 to n-1 do
  1194.   begin
  1195.     cs:=i shr 16;
  1196.     c1:=Keys[cs];
  1197.     if cs<nKeys then Inc(cs);
  1198.     c2:=Keys[cs];
  1199.     w1:=((not i)and $FFFF)+1;
  1200.     w2:=i and $FFFF;
  1201.     if(w1<(ii-w1))then pc.c:=c2 else
  1202.     if(w2<(ii-w2))then pc.c:=c1 else
  1203.     begin
  1204.       pc.b:=((c1.b*w1)+(c2.b*w2))shr 16;
  1205.       pc.g:=((c1.g*w1)+(c2.g*w2))shr 16;
  1206.       pc.r:=((c1.r*w1)+(c2.r*w2))shr 16;
  1207.     end;
  1208.     Inc(i,ii);
  1209.     Inc(pc);
  1210.   end;
  1211.   pc.c:=c2;
  1212. end;
  1213. function ClosestColor(Pal:PFColorTable;Max:Integer;c:TFColor):Byte;
  1214. var
  1215.   n: Byte;
  1216.   pc: PFColorA;
  1217.   i,x,d: Integer;
  1218. begin
  1219.   x:=765; n:=0;
  1220.   pc:=Pointer(Pal);
  1221.   for i:=0 to Max do
  1222.   begin
  1223.     if pc.b>c.b then d:=pc.b-c.b else d:=c.b-pc.b;
  1224.     if pc.g>c.g then Inc(d,pc.g-c.g) else Inc(d,c.g-pc.g);
  1225.     if pc.r>c.r then Inc(d,pc.r-c.r) else Inc(d,c.r-pc.r);
  1226.     if d<x then
  1227.     begin
  1228.       x:=d;
  1229.       n:=i;
  1230.     end;
  1231.     Inc(pc);
  1232.   end;
  1233.   Result:=n;
  1234. end;
  1235. function LoadHeader(Data:Pointer; var bmInfo:TBMInfo):Integer;
  1236. var
  1237.   i: Integer;
  1238. begin
  1239.   if PDWord(Ptr(Integer(Data)+14))^ = 40 then
  1240.     Move(Ptr(Integer(Data)+14)^, bmInfo, SizeOf(bmInfo))
  1241.   else
  1242.    if PDWord(Ptr(Integer(Data)+14))^ = 12 then
  1243.     with PBitmapCoreInfo(Ptr(Integer(Data)+14))^ do
  1244.     begin
  1245.       FillChar(bmInfo, SizeOf(bmInfo), 0);
  1246.       bmInfo.Header.biWidth := bmciHeader.bcWidth;
  1247.       bmInfo.Header.biHeight := bmciHeader.bcHeight;
  1248.       bmInfo.Header.biBitCount := bmciHeader.bcBitCount;
  1249.       if bmciHeader.bcBitCount <= 8 then
  1250.       for i:=0 to (1 shl bmciHeader.bcBitCount)-1 do
  1251.         bmInfo.Colors[i] := PFColorA(@bmciColors[i])^;
  1252.     end;
  1253.   Result:=PDWord(Ptr(Integer(Data)+10))^;
  1254. end;
  1255. function PackedDIB(Bmp:TBMPReader):Pointer;
  1256. var
  1257.   i: DWord;
  1258. begin
  1259.   if Bmp.Bpp <= 8 then i := 40 + ((1 shl Bmp.Bpp) shl 2) else
  1260.   if (((Bmp.Bpp = 16) or (Bmp.Bpp = 32)) and (Bmp.Compression =3 )) then i:=52 else i:=40;
  1261.   GetMem(Result, Bmp.SizeImage + i);
  1262.   Move(Bmp.Info, Result^,i);
  1263.   Move(Bmp.Bits^, Ptr(DWord(Result)+i)^, Bmp.SizeImage);
  1264. end;
  1265. function Count1(Bmp:TBMPReader):Integer;
  1266. var
  1267.   pb: PByte;
  1268.   w,c,x,y: Integer;
  1269. begin
  1270.   Result:=2;
  1271.   pb:=Pointer(Bmp.Bits); c:=pb^;
  1272.   if(c<>0)and(c<>255)then Exit;
  1273.   w:=(Bmp.Width div 8)-1;
  1274.   for y:=0 to Bmp.AbsHeight-1 do
  1275.   begin
  1276.     for x:=0 to w do
  1277.     begin
  1278.       if pb^<>c then Exit;
  1279.       Inc(pb);
  1280.     end;
  1281.     Inc(pb,Bmp.Gap);
  1282.   end;
  1283.   Result:=1;
  1284. end;
  1285. function Count4(Bmp:TBMPReader):Integer;
  1286. var
  1287.   I,J: Integer;
  1288.   pb,pc: PByte;
  1289.   x,y,w: Integer;
  1290.   Check: array[0..15]of Byte;
  1291. begin
  1292.   Result:=0;
  1293.   FillChar(Check,SizeOf(Check),0);
  1294.   pb:=Pointer(Bmp.Bits);
  1295.   w:=(Bmp.Width div 2)-1;
  1296.   for y:=0 to Bmp.AbsHeight-1 do
  1297.   begin
  1298.     for x:=0 to w do
  1299.     begin
  1300.       pc:=@Check[pb^ shr 4];
  1301.       if pc^=0 then
  1302.       begin
  1303.         Inc(Result);
  1304.         pc^:=1;
  1305.       end;
  1306.       pc:=@Check[pb^ and 15];
  1307.       if pc^=0 then
  1308.       begin
  1309.         Inc(Result);
  1310.         pc^:=1;
  1311.       end;
  1312.       if Result=16 then Exit;
  1313.       Inc(pb);
  1314.     end;
  1315.     Inc(pb,Bmp.Gap);
  1316.   end;
  1317.   x:=0; y:=0; w:=w*Bmp.AbsHeight-1;
  1318.   for I := 0 to Result - 1 do
  1319.   begin
  1320.     while check[x]=0 do inc(x);
  1321.     if x<>y then
  1322.     begin
  1323.       Bmp.Colors[y]:=Bmp.Colors[x];
  1324.       pb:=Pointer(Bmp.Bits);
  1325.       for J := 0 to w do    // Iterate
  1326.       begin
  1327.         if x=(pb^ shr 4) then pb^:=(pb^ and 15) or (y shl 4);
  1328.         if x=(pb^ and 15) then pb^:=(pb^ and $f0) or y;
  1329.         inc(pb);
  1330.       end;    // for  J
  1331.     end;
  1332.     inc(x); inc(y);
  1333.   end;    // for   I
  1334. end;
  1335. function Count8(Bmp:TBMPReader):Integer;
  1336. var
  1337.   x,y: Integer;
  1338.   I,J : Integer;
  1339.   pb: PByte;
  1340.   Check: array[Byte]of Byte;
  1341. begin
  1342.   Result:=0;
  1343.   FillChar(Check,SizeOf(Check),0);
  1344.   pb:=Pointer(Bmp.Bits);
  1345.   for y:=0 to Bmp.AbsHeight-1 do
  1346.   begin
  1347.     for x:=0 to Bmp.Width-1 do
  1348.     begin
  1349. //      pc:=@Check[pb^];
  1350.       if Check[pb^] = 0 then
  1351.       begin
  1352.         Inc(Result);
  1353.         Check[pb^] := 1;
  1354.       end;
  1355.       if Result=256 then Exit;
  1356.       Inc(pb);
  1357.     end;
  1358.     Inc(pb,Bmp.Gap);
  1359.   end;
  1360.   if (Result = 1) and (Check[0] = 0) and (Check[1] = 1) then
  1361.     begin
  1362.       Result := 2;
  1363.       exit; // bug monobrush
  1364.     end;
  1365.   j := 0;
  1366.   for I := 0 to 255 do
  1367.    if Check[i] = 0 then inc(J) else Check[i] := J;
  1368.   if J > 0 then
  1369.     begin
  1370.       pb:=Pointer(Bmp.Bits);
  1371.       for y:=0 to Bmp.AbsHeight-1 do
  1372.       begin
  1373.         for x:=0 to Bmp.Width-1 do
  1374.         begin
  1375.           if Check[pb^] > 0 then pb^ := pb^ - Check[pb^];
  1376.           Inc(pb);
  1377.         end;
  1378.         Inc(pb,Bmp.Gap);
  1379.       end;
  1380.       for I := 1 to 255 do
  1381.        if Check[i] > 0 then
  1382.          Bmp.Colors[i - Check[i]] := Bmp.Colors[i];
  1383.     end;
  1384. end;
  1385. function Count16(Bmp:TBMPReader):Integer;
  1386. var
  1387.   pw: PWord;
  1388.   pc: PByte;
  1389.   x,y: Integer;
  1390.   Check: array[Word]of Byte;
  1391. begin
  1392.   Result:=0;
  1393.   FillChar(Check,SizeOf(Check),0);
  1394.   pw:=Pointer(Bmp.Bits);
  1395.   for y:=0 to Bmp.AbsHeight-1 do
  1396.   begin
  1397.     for x:=0 to Bmp.Width-1 do
  1398.     begin
  1399.       pc:=@Check[pw^];
  1400.       if pc^=0 then
  1401.       begin
  1402.         Inc(Result);
  1403.         pc^:=1;
  1404.       end;
  1405.       Inc(pw);
  1406.     end;
  1407.     pw:=Ptr(Integer(pw)+Bmp.Gap);
  1408.   end;
  1409. end;
  1410. function Count24(Bmp:TBMPReader):Integer;
  1411. type
  1412.   PCheck =^TCheck;
  1413.   TCheck = array[Byte,Byte,0..31]of Byte;
  1414. var
  1415.   pb: PByte;
  1416.   pc: PFColor;
  1417.   Check: PCheck;
  1418.   x,y,c: Integer;
  1419. begin
  1420.   Result:=0;
  1421.   New(Check);
  1422.   FillChar(Check^,SizeOf(TCheck),0);
  1423.   pc:=Pointer(Bmp.Bits);
  1424.   for y:=0 to Bmp.AbsHeight-1 do
  1425.   begin
  1426.     for x:=0 to Bmp.Width-1 do
  1427.     begin
  1428.       pb:=@Check[pc.r,pc.g,pc.b shr 3];
  1429.       c:=1 shl(pc.b and 7);
  1430.       if(c and pb^)=0 then
  1431.       begin
  1432.         Inc(Result);
  1433.         pb^:=pb^ or c;
  1434.       end;
  1435.       Inc(pc);
  1436.     end;
  1437.     pc:=Ptr(Integer(pc)+Bmp.Gap);
  1438.   end;
  1439.   Dispose(Check);
  1440. end;
  1441. function Count32(Bmp:TBMPReader):Integer;
  1442. type
  1443.   PCheck =^TCheck;
  1444.   TCheck = array[Byte,Byte,0..31]of Byte;
  1445. var
  1446.   pb: PByte;
  1447.   pc: PFColorA;
  1448.   i,c: Integer;
  1449.   Check: PCheck;
  1450. begin
  1451.   Result:=0;
  1452.   New(Check);
  1453.   FillChar(Check^,SizeOf(TCheck),0);
  1454.   pc:=Pointer(Bmp.Bits);
  1455.   for i:=0 to (Bmp.SizeImage shr 2)-1 do
  1456.   begin
  1457.     pb:=@Check[pc.r,pc.g,pc.b shr 3];
  1458.     c:=1 shl(pc.b and 7);
  1459.     if(c and pb^)=0 then
  1460.     begin
  1461.       Inc(Result);
  1462.       pb^:=pb^ or c;
  1463.     end;
  1464.     Inc(pc);
  1465.   end;
  1466.   Dispose(Check);
  1467. end;
  1468. function CountColors(Bmp:TBMPReader):DWord;
  1469. begin
  1470.   case Bmp.Bpp of
  1471.     1:  Result:=Count1(Bmp);
  1472.     4:  Result:=Count4(Bmp);
  1473.     8:  Result:=Count8(Bmp);
  1474.     16: Result:=Count16(Bmp);
  1475.     24: Result:=Count24(Bmp);
  1476.     32: Result:=Count32(Bmp);
  1477.     else Result:=0;
  1478.   end;
  1479. end;
  1480. procedure IntToMask(Bpr,Bpg,Bpb:DWord;var RMsk,GMsk,BMsk:DWord);
  1481. begin
  1482.   BMsk:=(1 shl Bpb)-1;
  1483.   GMsk:=((1 shl(Bpb+Bpg))-1)and not BMsk;
  1484.   if(Bpr+Bpg+Bpb)=32 then RMsk:=$FFFFFFFF else RMsk:=(1 shl(Bpr+Bpb+Bpg))-1;
  1485.   RMsk:=RMsk and not(BMsk or GMsk);
  1486. end;
  1487. procedure MaskToInt(RMsk,GMsk,BMsk:DWord;var Bpr,Bpg,Bpb:DWord);
  1488.   function CountBits(i:DWord):DWord;
  1489.   asm
  1490.     bsr edx,eax
  1491.     bsf ecx,eax
  1492.     sub edx,ecx
  1493.     inc edx
  1494.     mov eax,edx
  1495.   end;
  1496. begin
  1497.   Bpb:=CountBits(BMsk);
  1498.   Bpg:=CountBits(GMsk);
  1499.   Bpr:=CountBits(RMsk);
  1500. end;
  1501. function UnpackColorTable(Table:TFPackedColorTable):TFColorTable;
  1502. var
  1503.   i: Integer;
  1504. begin
  1505.   for i:=0 to 255 do
  1506.     Result[i].c:=Table[i];
  1507. end;
  1508. function PackColorTable(Table:TFColorTable):TFPackedColorTable;
  1509. var
  1510.   i: Integer;
  1511. begin
  1512.   for i:=0 to 255 do
  1513.     Result[i]:=Table[i].c;
  1514. end;
  1515. function FRGB(r,g,b:Byte):TFColor;
  1516. begin
  1517.   Result.b:=b;
  1518.   Result.g:=g;
  1519.   Result.r:=r;
  1520. end;
  1521. function FRGBA(r,g,b,a:Byte):TFColorA;
  1522. begin
  1523.   Result.b:=b;
  1524.   Result.g:=g;
  1525.   Result.r:=r;
  1526.   Result.a:=a;
  1527. end;
  1528. function ColorToInt(c:TFColor):DWord;
  1529. begin
  1530.   Result:=c.b shl 16 or c.g shl 8 or c.r;
  1531. end;
  1532. function ColorToIntA(c:TFColorA):DWord;
  1533. begin
  1534.   Result:=c.b shl 24 or c.g shl 16 or c.r shl 8 or c.a;
  1535. end;
  1536. function IntToColor(i:DWord):TFColor;
  1537. begin
  1538.   Result.b:=i shr 16;
  1539.   Result.g:=i shr 8;
  1540.   Result.r:=i;
  1541. end;
  1542. function IntToColorA(i:DWord):TFColorA;
  1543. begin
  1544.   Result.a:=i shr 24;
  1545.   Result.b:=i shr 16;
  1546.   Result.g:=i shr 8;
  1547.   Result.r:=i;
  1548. end;
  1549. function Scale8(i,n:Integer):Integer;
  1550. begin // Result:=(i*255)div([1 shl n]-1);
  1551.   case n of
  1552.     1: if Boolean(i) then Result:=255 else Result:=0;
  1553.     2: Result:=(i shl 6)or(i shl 4)or(i shl 2)or i;
  1554.     3: Result:=(i shl 5)or(i shl 2)or(i shr 1);
  1555.     4: Result:=(i shl 4)or i;
  1556.     5: Result:=(i shl 3)or(i shr 2);
  1557.     6: Result:=(i shl 2)or(i shr 4);
  1558.     7: Result:=(i shl 1)or(i shr 6);
  1559.     else Result:=i;
  1560.   end;
  1561. end;
  1562. function Get16Bpg:Byte;
  1563. var
  1564.   c: DWord;
  1565.   hBM: HBITMAP;
  1566.   sDC,bDC: Windows.HDC;
  1567. begin
  1568.   sDC:=GetDC(0);
  1569.   bDC:=CreateCompatibleDC(sDC);
  1570.   hBM:=CreateCompatibleBitmap(sDC,1,1);
  1571.   SelectObject(bDC,hBM);
  1572.   SetPixel(bDC,0,0,RGB(0,100,0));
  1573.   c:=GetPixel(bDC,0,0);
  1574.   DeleteDC(bDC);
  1575.   DeleteObject(hBM);
  1576.   ReleaseDC(0,sDC);
  1577.   if GetGValue(c)>=100 then Result:=6 else Result:=5;
  1578. end;
  1579. initialization
  1580. finalization
  1581. end.