Base2D.pas
上传用户:yj_qiu
上传日期:2022-08-08
资源大小:23636k
文件大小:58k
源码类别:

游戏引擎

开发平台:

Delphi

  1. (*
  2.  @Abstract(Basic 2D Unit)
  3.  (C) 2004-2007 George "Mirage" Bakhtadze
  4.  The source code may be used under either MPL 1.1 or LGPL 2.1 license. See included license.txt file <br>
  5.  Unit contains basic 2D types and routines
  6. *)
  7. {$Include GDefines.inc}
  8. unit Base2D;
  9. interface
  10. uses BaseTypes, Basics, Models;
  11. const
  12.   // Pixel format for image processing
  13.   ProcessingFormat = pfA8R8G8B8;
  14.   // Size in bytes of pixel in ProcessingFormat
  15.   ProcessingFormatBpP = 4;
  16.   // Max value of component (R, G, B, etc) in processing format
  17.   ProcessingComponentMax = 255;
  18.   // Maximum of mip levels an image can have
  19.   MaxMipLevels = 32;
  20.   // Maximum number of image repeats in imagesource
  21.   MaxImageRepeats = 4096;
  22. type
  23.   // Image resize filter
  24.   TImageResizeFilter = (// No filter. Image will not be processed.
  25.                         ifNone,
  26.                         // Simple filter working only when image size is increased/decreased by N tymes where N positive integer value
  27.                         ifSimple2X,
  28.                         // Box filter
  29.                         ifBox,
  30.                         // Triangle filter
  31.                         ifTriangle,
  32.                         // Hermite filter
  33.                         ifHermite,
  34.                         // Bell filter
  35.                         ifBell,
  36.                         // Spline filter
  37.                         ifSpline,
  38.                         // Lanczos filter
  39.                         ifLanczos,
  40.                         // Mitchell filter
  41.                         ifMitchell);
  42.   // Image filter function
  43.   TImageFilterFunction = function (Value: Single): Single;
  44.   // Image origin
  45.   TImageOrigin = (// Top-down image and its origin is the upper-left corner.
  46.                   ioTopLeft,
  47.                   // Bottom-up image and its origin is the lower-left corner
  48.                   ioBottomLeft);
  49.   // Image parameters data structure
  50.   TImageHeader = record
  51.     Format: Integer;
  52.     LineSize: Integer;
  53.     Width, Height: Integer;
  54.     BitsPerPixel, ImageSize: Integer;
  55.     ImageOrigin: TImageOrigin;
  56.     PaletteSize: Cardinal;
  57.     Palette: PPalette;
  58.     Data: Pointer;
  59.   end;
  60.   // Generic image source class
  61.   TBaseImageSource = class
  62.   private
  63.     FFormat: Integer;
  64.     FWidth, FHeight: Integer;
  65. //    PaletteSize: Cardinal;
  66. //    Palette: PPalette;
  67.     function GetBitsPerPixel: Integer;
  68.     function GetBytesPerPixel: Integer;
  69.   protected
  70.     // Copies a rectangular area of the specified mip level of the image to an image with width DestImageWidth and data located in memory at Dest and returns True if success
  71.     function GetData(const Rect: TRect; Dest: Pointer; DestImageWidth: Integer): Boolean; virtual; abstract;
  72.     // Copies a rectangular area of the specified mip level of the image to an RGBA image with width DestImageWidth and data located in memory at Dest and returns True if success
  73.     function GetDataAsRGBA(const Rect: TRect; Dest: Pointer; DestImageWidth: Integer): Boolean; virtual; abstract;
  74.   public
  75.     constructor Create(AFormat, AWidth, AHeight: Integer);
  76.     // Calls implementation-dependent GetData() to load image data
  77.     function LoadData(Rect: TRect; Dest: Pointer; DestImageWidth: Integer): Boolean;
  78.     // Calls implementation-dependent GetDataAsRGBA() to load image data
  79.     function LoadDataAsRGBA(Rect: TRect; Dest: Pointer; DestImageWidth: Integer): Boolean;
  80.     // Image width
  81.     property Width: Integer read FWidth;
  82.     // Image height
  83.     property Height: Integer read FHeight;
  84.     // Number of bits per pixel
  85.     property BitsPerPixel: Integer read GetBitsPerPixel;
  86.     // Number of bytes per pixel
  87.     property BytesPerPixel: Integer read GetBytesPerPixel;
  88.   end;
  89.   // Image source impementation for usual bitmap images
  90.   TImageSource = class(TBaseImageSource)
  91.   private
  92.     FFormat: Integer;
  93.     FBuf: Pointer;
  94.   protected
  95.     function GetData(const Rect: TRect; Dest: Pointer; DestImageWidth: Integer): Boolean; override;
  96.     function GetDataAsRGBA(const Rect: TRect; Dest: Pointer; DestImageWidth: Integer): Boolean; override;
  97.   public
  98.     constructor Create(const ABuf: Pointer; AFormat, AWidth, AHeight: Integer);
  99.   end;
  100. const
  101.   // Default values for resize filters
  102.   DefaultResizeFilterValue: array [TImageResizeFilter] of Single = (0, 0, 0.5, 1.0, 1.0, 1.5, 2.0, 3.0, 2.0);
  103. type
  104.   // Image mip level record. Width, Height - level dimensions, Size - size of level data in bytes, Offset - offset of level data on bytes from top level data
  105.   TImageLevel = record
  106.     Width, Height: Integer;
  107.     Size, Offset: Integer;
  108.   end;
  109.   // Image levels info
  110.   TImageLevels = array[0..MaxMipLevels-1] of TImageLevel;
  111.   // .bmp file information header data structure
  112.   TBitmapInfoHeader = packed record
  113.     biSize: Cardinal;
  114.     biWidth, biHeight: Longint;
  115.     biPlanes: Word;
  116.     biBitCount: Word;
  117.     biCompression: Cardinal;
  118.     biSizeImage: Cardinal;
  119.     biXPelsPerMeter, biYPelsPerMeter: Longint;
  120.     biClrUsed: Cardinal;
  121.     biClrImportant: Cardinal;
  122.   end;
  123.   // .bmp file header data structure
  124.   TBitmapFileHeader = packed record
  125.     bfType: Word;
  126.     bfSize: Cardinal;
  127.     bfReserved1, bfReserved2: Word;
  128.     bfOffBits: Cardinal;
  129.   end;
  130.   // Determines how source and destination colors should be combined
  131.   TColorCombineOperation = (// Copy source color instead of destination (SrcColor)
  132.                             coSet,
  133.                             // Add corresponding color components (DestColor + SrcColor)
  134.                             coAdd,
  135.                             // Modulate corresponding color components (DestColor * SrcColor)
  136.                             coMod,
  137.                             // Substract corresponding color components (DestColor - SrcColor)
  138.                             coSub);
  139.   // The class incapsulates a brush which is used to paint over images
  140.   TBrush = class
  141.   private
  142.     FShape: TImageHeader;
  143.     FPattern: TImageHeader;
  144.     FSource: TBaseImageSource;
  145.     function GetHeight: Integer;
  146.     function GetShapeData: Pointer;
  147.     function GetWidth: Integer;
  148.     function GetPatternData: Pointer;
  149.   public
  150.     Color: TColor;
  151.     ColorCombineOperation: TColorCombineOperation;
  152.     constructor Create;
  153.     destructor Destroy; override;
  154.     // Inits the brush with size, color combining operation and a bitmaps which determines the shape (8 bits per pixel) and color (32 bits per pixel) pattern of the brush
  155.     procedure Init(AWidth, AHeight: Integer; AShape, APattern: Pointer; ABitmapFormat: Integer; AColor: TColor; AColorCombineOperation: TColorCombineOperation; ASource: TBaseImageSource); virtual;
  156.     // Returns True if the brush can be used for draw operations
  157.     function IsValid: Boolean;
  158.     property Width: Integer read GetWidth;
  159.     property Height: Integer read GetHeight;
  160.     property ShapeData: Pointer read GetShapeData;
  161.     property PatternData: Pointer read GetPatternData;
  162.     property Source: TBaseImageSource read FSource;
  163.   end;
  164.   // Base class for operations affecting an image
  165.   TImageOperation = class(Models.TOperation)
  166.   protected
  167.     // Pointer to image data
  168.     FImageData,
  169.     // Pointer to operation data
  170.     FData: Pointer;
  171.     // Image pixel format
  172.     FImageFormat,
  173.     // Image line length in pixels
  174.     FImageLineLength,
  175.     // Image bytes per pixel
  176.     FImageBpP: Integer;
  177.     // Rectangle on image affected by the operation
  178.     FRect: BaseTypes.TRect;
  179.     procedure DoApply; override;
  180.   public
  181.     constructor Create(AImageData: Pointer; AImageLineLength, AImageFormat: Integer; const ARect: BaseTypes.TRect);
  182.     // Rectangle on image affected by the operation
  183.     property Rect: BaseTypes.TRect read FRect;
  184.   end;
  185.   // Paint on an image with a brush operation
  186.   TImagePaintOp = class(TImageOperation)
  187.   public
  188.     constructor Create(X, Y: Integer; AImageData: Pointer; AImageLineLength, AImageFormat: Integer; ABrush: TBrush; const ARect: BaseTypes.TRect);
  189.   end;
  190.   // Paint on an image with source image using the shape of a brush operation
  191.   TImageCloneOp = class(TImageOperation)
  192.   public
  193.     constructor Create(X, Y: Integer; AImageData: Pointer; AImageLineLength, AImageFormat: Integer; ABrush: TBrush;
  194.                        SrcX, SrcY: Integer; ASource: TBaseImageSource; const ARect: BaseTypes.TRect);
  195.   end;
  196. function SwapRB(Color: BaseTypes.TColor): BaseTypes.TColor;
  197. function GetIntensity(Color: BaseTypes.TColor): Integer;
  198. function VCLColorToColor(Color: Integer): BaseTypes.TColor;
  199. function ColorToVCLColor(Color: BaseTypes.TColor): Integer;
  200. // Returns the number of mip levels (including 0-th) which an image with the specified dimensions should have and fills in the levels info
  201. function GetSuggestedMipLevelsInfo(Width, Height, Format: Integer; out Levels: TImageLevels): Integer;
  202. // Converts the specified number of pixels from any known format to ProcessingFormat. Returns False if input format is unknown or cannot be converted.
  203. function ConvertToProcessing(Format, Size:Integer; Src: Pointer; PaletteSize: Integer; Palette: PPalette; Dest: Pointer): Boolean;
  204. // Converts the specified number of pixels from ProcessingFormat to any known format. Returns False if input format is unknown or cannot be converted.
  205. function ConvertFromProcessing(Format, Size:Integer; Src: Pointer; var PaletteSize: Integer; Palette: PPalette; Dest: Pointer): Boolean;
  206. // Converts the specified number of pixels from any known format to another known format. Returns False if input format is unknown or cannot be converted.
  207. function ConvertImage(SrcFormat, DestFormat, TotalPixels: Integer; Src: Pointer; PaletteSize: Integer; Palette: PPalette; Dest: Pointer): Boolean;
  208. // Creates in Dest a thumbnail image of the given size and format from a rectangular area of original image. Returns True if success or False if conversion to <b>Format</b> is unsupported.
  209. function CreateThumbnail(SrcFormat, SrcWidth: Integer; const SrcRect: BaseTypes.TRect; Src: Pointer; PaletteSize: Integer; Palette: PPalette; DestFormat, Width, Height: Integer; Dest: Pointer): Boolean;
  210. function ResizeImage(Filter: TImageResizeFilter; FilterValue: Single; Format:Integer; Src: PImageBuffer; const SrcArea: BaseTypes.TRect; SrcLineLength: Integer;
  211.                                                           const Dest: PImageBuffer; const DestArea: BaseTypes.TRect; DestLineLength: Integer): Boolean;
  212. // Stretches a rectangular area of an ARGB image to a rectangular area of another ARGB image
  213. procedure StretchARGBImage(Filter: TImageFilterFunction; const Radius: Single; Src: PImageBuffer; const SrcArea: BaseTypes.TRect; SrcLineLength: Integer; const Dest: PImageBuffer; const DestArea: BaseTypes.TRect; DestLineLength: Integer);
  214. function ImageBoxFilter(Value: Single): Single;
  215. function ImageTriangleFilter(Value: Single): Single;
  216. function ImageHermiteFilter(Value: Single): Single;
  217. function ImageBellFilter(Value: Single): Single;
  218. function ImageSplineFilter(Value: Single): Single;
  219. function ImageLanczos3Filter(Value: Single): Single;
  220. function ImageMitchellFilter(Value: Single): Single;
  221. function SaveIDF(const Stream: TStream; const IDFHeader: TIDFHeader; const Buffers: array of Pointer): Boolean;
  222. function LoadIDF(const Stream: TStream; var IDFHeader: TIDFHeader; var Buffer: Pointer; var TotalSize: Integer): Boolean;
  223. function LoadIDFBuffers(const Stream: TStream; var IDFHeader: TIDFHeader; var Buffers: TPointerArray; var TotalSize: Integer): Boolean;
  224. // Loads a .bmp file header and positions Stream at raw data start. Returns True if sucess.
  225. function LoadBitmapHeader(const Stream: TStream; out Header: TImageHeader): Boolean;
  226. // Loads a .bmp file and returns True if success. 
  227. function LoadBitmap(const Stream: TStream; out LineSize: Integer; out Width: Integer; out Height: Integer; out BitsPerPixel: Integer; out PaletteSize: Cardinal; out Palette: PPalette; out Data: Pointer): Boolean; overload;
  228. // Loads a .bmp file and returns True if success. All image parameters are placed in Header.
  229. function LoadBitmap(const Stream: TStream; var Header: TImageHeader): Boolean; overload;
  230. // Copies a rectangular area from one buffer to another
  231. procedure BufferCopy(const SBuf, DBuf: Pointer; const BufLineLength, BpP: Integer; const Rect: BaseTypes.TRect);
  232. // Copies a rectangular area from one buffer to the top of another assuming width of destination buffer equal to width of the rectangle
  233. procedure BufferCut(const SBuf, DBuf: Pointer; const SrcLineLength, DestLineLength, BpP: Integer; const Rect: BaseTypes.TRect);
  234. // Copies a rectangular area from the top of one buffer to specified Rect of another assuming width of source buffer equal to width of the rectangle
  235. procedure BufferPaste(const SBuf, DBuf: Pointer; const SrcLineLength, DestLineLength, BpP: Integer; const Rect: BaseTypes.TRect);
  236. // Swaps contents of a rectangular area of one buffer with the contents of another assuming width of destination buffer equal to width of the rectangle
  237. procedure BufferSwap(const SBuf, DBuf: Pointer; const SrcLineLength, DestLineLength, BpP: Integer; const Rect: BaseTypes.TRect);
  238. // Copies a rectangular area from one buffer to the top of another changing its format to ARGB and returns True if success
  239. function BufferCutAsRGBA(const SBuf, DBuf: Pointer; const SrcLineLength, DestLineLength, SrcFormat: Integer; const Rect: BaseTypes.TRect): Boolean;
  240. // Copies a rectangular area from the top of RGBA buffer to specified Rect of another buffer with the specified format and returns True if success
  241. function BufferRGBAPaste(const SBuf, DBuf: Pointer; const SrcLineLength, DestLineLength, DestFormat: Integer; const Rect: BaseTypes.TRect): Boolean;
  242. // Combines a rectangular area from the top of RGBA buffer with specified Rect of another buffer with the specified format and returns True if success
  243. function BufferRGBACombine(const SBuf, DBuf: Pointer; const SrcLineLength, DestLineLength, DestFormat: Integer; const Rect: BaseTypes.TRect): Boolean;
  244. // Blends a rectangular area from the top of RGBA buffer with specified Rect of another buffer with the specified format using a separate 8-bit alpha-channel in ABuf and returns True if success
  245. function BufferRGBABlend(const SBuf, DBuf, ABuf: Pointer; const SrcLineLength, DestLineLength, DestFormat: Integer; const Rect: BaseTypes.TRect): Boolean;
  246. var
  247.   OnProgress: TProgressDelegate;
  248. implementation
  249. const
  250.   MaxImageRepeatsHalf = MaxImageRepeats div 2;
  251. type
  252.   PContributor = ^TContributor;
  253.   TContributor = record
  254.     Weight, Pixel: Integer;
  255.   end;
  256.   TContributors = array of TContributor;
  257.   TContributorEntry = record
  258.     N: Integer;
  259.     Contributors: TContributors;
  260.   end;
  261.   TContributorList = array of TContributorEntry;
  262. function SwapRB(Color: BaseTypes.TColor): BaseTypes.TColor;
  263. begin
  264. //  Result := (Color and 255) shl 16 + (Color shr 16) and 255 + Color and (255 shl 8);
  265.   Result := Color;
  266.   Result.R := Color.B;
  267.   Result.B := Color.R;
  268. end;
  269. function GetIntensity(Color: BaseTypes.TColor): Integer;
  270. begin
  271.   Result := MaxI(MaxI(Color.R, Color.G), Color.B);
  272. end;
  273. function VCLColorToColor(Color: Integer): BaseTypes.TColor;
  274. begin
  275.   Result.C := Color;
  276.   Result := SwapRB(Result);
  277. end;
  278. function ColorToVCLColor(Color: BaseTypes.TColor): Integer;
  279. begin
  280.   Color.A := 0;
  281.   Result := SwapRB(Color).C;
  282. end;
  283. function GetSuggestedMipLevelsInfo(Width, Height, Format: Integer; out Levels: TImageLevels): Integer;
  284. var MaxDim: Integer;
  285. begin
  286.   Levels[0].Width  := Width;
  287.   Levels[0].Height := Height;
  288.   Levels[0].Size   := Levels[0].Width * Levels[0].Height * GetBytesPerPixel(Format);
  289.   Levels[0].Offset := 0;
  290.   Result := 1;
  291.   MaxDim := MaxI(Width, Height);
  292.   while MaxDim > 1 do begin
  293.     Levels[Result].Width  := MaxI(1, Levels[Result-1].Width  div 2);
  294.     Levels[Result].Height := MaxI(1, Levels[Result-1].Height div 2);
  295.     Levels[Result].Offset := Levels[Result-1].Offset + Levels[Result-1].Size;
  296.     Levels[Result].Size   := Levels[Result].Width * Levels[Result].Height * GetBytesPerPixel(Format);
  297.     Inc(Result);
  298.     MaxDim := MaxDim div 2;
  299.     Assert(Result < MaxMipLevels);
  300.   end;
  301. end;
  302. function ConvertFromProcessing(Format, Size: Integer; Src: Pointer; var PaletteSize: Integer; Palette: PPalette; Dest: Pointer): Boolean;
  303. var i: Integer;
  304. begin
  305.   Result := True;
  306.   case Format of
  307.     pfR8G8B8: for i := 0 to Size-1 do begin
  308.       TRGBArray(Dest^)[i].R := TARGBArray(Src^)[i].B;
  309.       TRGBArray(Dest^)[i].G := TARGBArray(Src^)[i].G;
  310.       TRGBArray(Dest^)[i].B := TARGBArray(Src^)[i].R;
  311.     end;
  312.     pfB8G8R8: for i := 0 to Size-1 do begin
  313.       TRGBArray(Dest^)[i].R := TARGBArray(Src^)[i].R;
  314.       TRGBArray(Dest^)[i].G := TARGBArray(Src^)[i].G;
  315.       TRGBArray(Dest^)[i].B := TARGBArray(Src^)[i].B;
  316.     end;
  317.     pfA8B8G8R8: for i := 0 to Size-1 do begin
  318.       TARGBArray(Dest^)[i].A := TARGBArray(Src^)[i].A;
  319.       TARGBArray(Dest^)[i].B := TARGBArray(Src^)[i].R;
  320.       TARGBArray(Dest^)[i].G := TARGBArray(Src^)[i].G;
  321.       TARGBArray(Dest^)[i].R := TARGBArray(Src^)[i].B;
  322.     end;
  323.     pfA8R8G8B8, pfX8R8G8B8, pfX8L8V8U8, pfQ8W8V8U8: Move(Src^, Dest^, Size*4);
  324.     pfR5G6B5: for i := 0 to Size-1 do
  325.      TWordBuffer(Dest^)[i] := Round(TARGBArray(Src^)[i].R / 255 * 31) shl 11 +
  326.                               Round(TARGBArray(Src^)[i].G / 255 * 63) shl 5 +
  327.                               Round(TARGBArray(Src^)[i].B / 255 * 31);
  328.     pfX1R5G5B5, pfA1R5G5B5: for i := 0 to Size-1 do
  329.      TWordBuffer(Dest^)[i] := Ord(TARGBArray(Src^)[i].A <> 0) shl 15 +
  330.                               Round(TARGBArray(Src^)[i].R / 255 * 31) shl 10 +
  331.                               Round(TARGBArray(Src^)[i].G / 255 * 31) shl 5 +
  332.                               Round(TARGBArray(Src^)[i].B / 255 * 31);
  333.     pfA4R4G4B4, pfX4R4G4B4: for i := 0 to Size-1 do
  334.      TWordBuffer(Dest^)[i] := Round(TARGBArray(Src^)[i].A / 255 * 15) shl 12 +
  335.                               Round(TARGBArray(Src^)[i].R / 255 * 15) shl 8 +
  336.                               Round(TARGBArray(Src^)[i].G / 255 * 15) shl 4 +
  337.                               Round(TARGBArray(Src^)[i].B / 255 * 15);
  338.     pfA8, pfL8: for i := 0 to Size-1 do TByteBuffer(Dest^)[i] := Round((TARGBArray(Src^)[i].R +
  339.                                                                               TARGBArray(Src^)[i].G +
  340.                                                                               TARGBArray(Src^)[i].B) / 3);
  341. //    pfP8:;
  342. //    pfA8P8:;
  343.     pfA8L8: for i := 0 to Size-1 do TWordBuffer(Dest^)[i] := TARGBArray(Src^)[i].A shl 8 + Round((TARGBArray(Src^)[i].R + TARGBArray(Src^)[i].G + TARGBArray(Src^)[i].B) / 3);
  344.     pfV8U8: for i := 0 to Size-1 do TWordBuffer(Dest^)[i] := TARGBArray(Src^)[i].G shl 8 + TARGBArray(Src^)[i].B;
  345.     pfA4L4: for i := 0 to Size-1 do TByteBuffer(Dest^)[i] := TARGBArray(Src^)[i].A and $F0 + Round((TARGBArray(Src^)[i].R + TARGBArray(Src^)[i].G + TARGBArray(Src^)[i].B) / 3/255*15);
  346. //    pfL6V5U5:;
  347. //    pfV16U16:;
  348. //    pfW11V11U10:;
  349. //    pfD32:;
  350.     pfD16: for i := 0 to Size-1 do begin
  351.       TWordBuffer(Dest^)[i] := Round((TARGBArray(Src^)[i].R + TARGBArray(Src^)[i].G + TARGBArray(Src^)[i].B) / 3/255*65535);
  352.     end;
  353.     else Result := False;
  354.   end;
  355. end;
  356. function ConvertToProcessing(Format, Size: Integer; Src: Pointer; PaletteSize: Integer; Palette: PPalette; Dest: Pointer): Boolean;
  357. var i: Integer; Temp: Byte;
  358. begin
  359.   Result := True;
  360.   case Format of
  361.     pfR8G8B8: for i := 0 to Size-1 do begin
  362.       TARGBArray(Dest^)[i].A := 0;
  363.       TARGBArray(Dest^)[i].R := TByteBuffer(Src^)[i*3];
  364.       TARGBArray(Dest^)[i].G := TByteBuffer(Src^)[i*3 + 1];
  365.       TARGBArray(Dest^)[i].B := TByteBuffer(Src^)[i*3 + 2];
  366.     end;
  367.     pfB8G8R8: for i := 0 to Size-1 do begin
  368.       TARGBArray(Dest^)[i].A := 0;
  369.       TARGBArray(Dest^)[i].B := TByteBuffer(Src^)[i*3];
  370.       TARGBArray(Dest^)[i].G := TByteBuffer(Src^)[i*3 + 1];
  371.       TARGBArray(Dest^)[i].R := TByteBuffer(Src^)[i*3 + 2];
  372.     end;
  373.     pfA8B8G8R8: for i := 0 to Size-1 do begin
  374.       TARGBArray(Dest^)[i].A := TARGBArray(Src^)[i].A;
  375.       TARGBArray(Dest^)[i].B := TARGBArray(Src^)[i].R;
  376.       TARGBArray(Dest^)[i].G := TARGBArray(Src^)[i].G;
  377.       TARGBArray(Dest^)[i].R := TARGBArray(Src^)[i].B;
  378.     end;
  379.     pfA8R8G8B8, pfX8R8G8B8, pfX8L8V8U8, pfQ8W8V8U8: Move(Src^, Dest^, Size*4);
  380.     pfR5G6B5: for i := 0 to Size-1 do begin
  381.       TARGBArray(Dest^)[i].A := 0;
  382.       TARGBArray(Dest^)[i].R := Round((TWordBuffer(Src^)[i] shr 11) and 31 / 31*255);
  383.       TARGBArray(Dest^)[i].G := Round((TWordBuffer(Src^)[i] shr 5) and 63 / 63*255);
  384.       TARGBArray(Dest^)[i].B := Round( TWordBuffer(Src^)[i] and 31 / 31*255);
  385.     end;
  386.     pfX1R5G5B5, pfA1R5G5B5: for i := 0 to Size-1 do begin
  387.       TARGBArray(Dest^)[i].A := Round( TWordBuffer(Src^)[i] shr 15 * 255);
  388.       TARGBArray(Dest^)[i].R := Round((TWordBuffer(Src^)[i] shr 10) and 31 / 31*255);
  389.       TARGBArray(Dest^)[i].G := Round((TWordBuffer(Src^)[i] shr 5) and 31 / 31*255);
  390.       TARGBArray(Dest^)[i].B := Round( TWordBuffer(Src^)[i] and 31 / 31*255);
  391.     end;
  392.     pfA4R4G4B4, pfX4R4G4B4: for i := 0 to Size-1 do begin
  393.       TARGBArray(Dest^)[i].A := Round((TWordBuffer(Src^)[i] shr 12) and 15 / 15*255);
  394.       TARGBArray(Dest^)[i].R := Round((TWordBuffer(Src^)[i] shr 8) and 15 / 15*255);
  395.       TARGBArray(Dest^)[i].G := Round((TWordBuffer(Src^)[i] shr 4) and 15 / 15*255);
  396.       TARGBArray(Dest^)[i].B := Round( TWordBuffer(Src^)[i] and 15 / 15*255);
  397.     end;
  398.     pfA8, pfL8: for i := 0 to Size-1 do begin
  399.       TARGBArray(Dest^)[i].A := TByteBuffer(Src^)[i];
  400.       TARGBArray(Dest^)[i].R := TByteBuffer(Src^)[i];
  401.       TARGBArray(Dest^)[i].G := TByteBuffer(Src^)[i];
  402.       TARGBArray(Dest^)[i].B := TByteBuffer(Src^)[i];
  403.     end;
  404.     pfP8: for i := 0 to Size-1 do with TARGBArray(Dest^)[i] do begin
  405.       A := Palette^[TByteBuffer(Src^)[i]].A;
  406.       R := Palette^[TByteBuffer(Src^)[i]].R;
  407.       G := Palette^[TByteBuffer(Src^)[i]].G;
  408.       B := Palette^[TByteBuffer(Src^)[i]].B;
  409.     end;
  410.     pfA8P8: for i := 0 to Size-1 do with TARGBArray(Dest^)[i] do begin
  411.       A := TWordBuffer(Src^)[i] shr 8;
  412.       R := Palette^[TWordBuffer(Src^)[i] and 255].R;
  413.       G := Palette^[TWordBuffer(Src^)[i] and 255].G;
  414.       B := Palette^[TWordBuffer(Src^)[i] and 255].B;
  415.     end;
  416.     pfA8L8: for i := 0 to Size-1 do begin
  417.       TARGBArray(Dest^)[i].A := TWordBuffer(Src^)[i] shr 8;
  418.       TARGBArray(Dest^)[i].R := TWordBuffer(Src^)[i] and 255;
  419.       TARGBArray(Dest^)[i].G := TWordBuffer(Src^)[i] and 255;
  420.       TARGBArray(Dest^)[i].B := TWordBuffer(Src^)[i] and 255;
  421.     end;
  422.     pfV8U8: for i := 0 to Size-1 do begin
  423.       TARGBArray(Dest^)[i].A := 0;
  424.       TARGBArray(Dest^)[i].R := 0;
  425.       TARGBArray(Dest^)[i].G := TWordBuffer(Src^)[i] shr 8;
  426.       TARGBArray(Dest^)[i].B := TWordBuffer(Src^)[i] and 255;
  427.     end;
  428.     pfA4L4: for i := 0 to Size-1 do begin
  429.       TARGBArray(Dest^)[i].A := TByteBuffer(Src^)[i] and $F0;
  430.       Temp := Round((TByteBuffer(Src^)[i] and 15)*17);
  431.       TARGBArray(Dest^)[i].R := Temp;
  432.       TARGBArray(Dest^)[i].G := Temp;
  433.       TARGBArray(Dest^)[i].B := Temp;
  434.     end;
  435. //    pfL6V5U5:;
  436. //    pfV16U16:;
  437. //    pfW11V11U10:;
  438. //    pfD32:;
  439.     pfD16: for i := 0 to Size-1 do begin
  440.       TARGBArray(Dest^)[i].A := Round(TWordBuffer(Src^)[i]/65535*255);
  441.       TARGBArray(Dest^)[i].R := Round(TWordBuffer(Src^)[i]/65535*255);
  442.       TARGBArray(Dest^)[i].G := Round(TWordBuffer(Src^)[i]/65535*255);
  443.       TARGBArray(Dest^)[i].B := Round(TWordBuffer(Src^)[i]/65535*255);
  444.     end;
  445.     else Result := False;
  446.   end;
  447. end;
  448. //procedure ConvertImage(SrcFormat, DestFormat: Cardinal; LineLength, Width, Height: Integer; Src: Pointer; PaletteSize: Integer; Palette: Basics.PPalette; Dest: Pointer);
  449. function ConvertImage(SrcFormat, DestFormat, TotalPixels: Integer; Src: Pointer; PaletteSize: Integer; Palette: PPalette; Dest: Pointer): Boolean;
  450. var Temp: Pointer;
  451. begin
  452.   Result := False;
  453.   if (Src = nil) or (Dest = nil) then Exit;
  454.   if SrcFormat = DestFormat then begin
  455.     Result := True;
  456.     Move(Src^, Dest^, TotalPixels * GetBytesPerPixel(SrcFormat));
  457.   end else begin
  458.     GetMem(Temp, TotalPixels*ProcessingFormatBpP);
  459.     Result := ConvertToProcessing(SrcFormat, TotalPixels, Src, PaletteSize, Palette, Temp) and
  460.               ConvertFromProcessing(DestFormat, TotalPixels, Temp, PaletteSize, Palette, Dest);
  461.     FreeMem(Temp);
  462.   end;
  463. end;
  464. function ResizeImage(Filter: TImageResizeFilter; FilterValue: Single; Format:Integer; Src: PImageBuffer; const SrcArea: BaseTypes.TRect; SrcLineLength: Integer; const Dest: PImageBuffer; const DestArea: BaseTypes.TRect; DestLineLength: Integer): Boolean;
  465. var
  466.   NeedConvert: Boolean;
  467.   MarginX, MarginY: Integer;
  468.   ow, oh, nw, nh: Integer;
  469.   NSrc, NDest: Pointer;
  470.   NSrcArea, NDestArea: BaseTypes.TRect;
  471.   NSrcLineLength, NDestLineLength: Integer;
  472.   Garbage: IRefcountedContainer;
  473.   procedure CheckFormat;
  474.   begin
  475.     NeedConvert := (Format <> pfA8R8G8B8) and (Filter <> ifNone) and (Filter <> ifSimple2X);
  476.     if NeedConvert then begin
  477.       MarginX := Ceil(FilterValue * ow/nw);
  478.       MarginY := Ceil(FilterValue * oh/nh);
  479.       RectMove(SrcArea,  -SrcArea.Left,  -SrcArea.Top,  NSrcArea);
  480.       RectMove(DestArea, -DestArea.Left, -DestArea.Top, NDestArea);
  481.       NSrcLineLength  := NSrcArea.Right  - NSrcArea.Left;
  482.       NDestLineLength := NDestArea.Right - NDestArea.Left;
  483.       GetMem(NSrc,  ow*oh * ProcessingFormatBpP);
  484.       GetMem(NDest, ow*oh * ProcessingFormatBpP);
  485.       Garbage.AddPointers([NSrc, NDest]);
  486.       BufferCutAsRGBA(Src, NSrc, SrcLineLength, NSrcLineLength, Format, SrcArea);
  487.     end else begin
  488.       NSrc  := Src;
  489.       NDest := Dest;
  490.       NSrcArea  := SrcArea;
  491.       NDestArea := DestArea;
  492.       NSrcLineLength  := SrcLineLength;
  493.       NDestLineLength := DestLineLength;
  494.     end;
  495.   end;
  496. var
  497.   XRatio, YRatio: Integer;
  498.   i, j, BpP, FillValue: Integer;
  499. begin
  500.   Result := False;
  501.   Garbage := CreateRefcountedContainer;
  502.   ow := SrcArea.Right   - SrcArea.Left;
  503.   oh := SrcArea.Bottom  - SrcArea.Top;
  504.   nw := DestArea.Right  - DestArea.Left;
  505.   nh := DestArea.Bottom - DestArea.Top;
  506.   if (ow <= 0) or (oh <= 0) or (nw <= 0) or (nh <= 0){ or ((nw = ow) and (nh = oh))} then Exit;
  507.   CheckFormat;
  508.   BpP := GetBytesPerPixel(Format);
  509.   case Filter of
  510.     ifNone: begin
  511.       FillValue := Round(FilterValue);
  512.       for i := 0 to Basics.MinI(nh-1, oh-1) do begin
  513.         Move(PtrOffs(NSrc, i*ow * BpP)^, PtrOffs(NDest, i*nw * BpP)^, Basics.MinI(nw, ow)*BpP);
  514.         if nw > ow then FillChar(PtrOffs(NDest, (i*nw+ow) * BpP)^, (nw - ow)*BpP, FillValue);
  515.       end;
  516.       if nh > oh then for i := oh to nh-1 do FillChar(PtrOffs(NDest, (i*nw) * BpP)^, nw*BpP, FillValue);
  517.     end;
  518.     ifSimple2X: begin
  519.       XRatio := ow mod nw;
  520.       YRatio := oh mod nh;
  521.       if (XRatio <> 0) or (YRatio <> 0) then begin
  522.         ErrorHandler(TInvalidArgument.Create('ResizeImage: ifSimple2X filter can be used only to shrink image by an integer factor'));
  523.         Exit;
  524.       end;
  525.       XRatio := ow div nw;
  526.       YRatio := oh div nh;
  527.       case BpP of
  528.         1: for j := 0 to nh-1 do for i := 0 to nw-1 do
  529.              PByteBuffer(NDest)^[(j + DestArea.Top)*DestLineLength + DestArea.Left + i] :=
  530.                PByteBuffer(NSrc)^[(j*YRatio + SrcArea.Top)*SrcLineLength + SrcArea.Left + i*XRatio];
  531.         2: for j := 0 to nh-1 do for i := 0 to nw-1 do
  532.              PWordBuffer(NDest)^[(j + DestArea.Top)*DestLineLength + DestArea.Left + i] :=
  533.                PWordBuffer(NSrc)^[(j*YRatio + SrcArea.Top)*SrcLineLength + SrcArea.Left + i*XRatio];
  534.         4: for j := 0 to nh-1 do for i := 0 to nw-1 do
  535.              PImageBuffer(NDest)^[(j + DestArea.Top)*DestLineLength + DestArea.Left + i] :=
  536.                PImageBuffer(NSrc)^[(j*YRatio + SrcArea.Top)*SrcLineLength + SrcArea.Left + i*XRatio];
  537.         else begin
  538.           ErrorHandler(TInvalidFormat.Create('Invalid pixel format'));
  539.           Exit;
  540.         end;
  541.       end;
  542.     end;
  543.     ifBox:      StretchARGBImage(ImageBoxFilter,      FilterValue, NSrc, NSrcArea, NSrcLineLength, NDest, NDestArea, NDestLineLength);
  544.     ifTriangle: StretchARGBImage(ImageTriangleFilter, FilterValue, NSrc, NSrcArea, NSrcLineLength, NDest, NDestArea, NDestLineLength);
  545.     ifHermite:  StretchARGBImage(ImageHermiteFilter,  FilterValue, NSrc, NSrcArea, NSrcLineLength, NDest, NDestArea, NDestLineLength);
  546.     ifBell:     StretchARGBImage(ImageBellFilter,     FilterValue, NSrc, NSrcArea, NSrcLineLength, NDest, NDestArea, NDestLineLength);
  547.     ifSpline:   StretchARGBImage(ImageSplineFilter,   FilterValue, NSrc, NSrcArea, NSrcLineLength, NDest, NDestArea, NDestLineLength);
  548.     ifLanczos:  StretchARGBImage(ImageLanczos3Filter, FilterValue, NSrc, NSrcArea, NSrcLineLength, NDest, NDestArea, NDestLineLength);
  549.     ifMitchell: StretchARGBImage(ImageMitchellFilter, FilterValue, NSrc, NSrcArea, NSrcLineLength, NDest, NDestArea, NDestLineLength);
  550.   end;
  551.   if NeedConvert then begin
  552.     BufferRGBAPaste(NDest, Dest, NDestLineLength, DestLineLength, Format, DestArea);
  553.   end;
  554.   Result := True;
  555. end;
  556. function CreateThumbnail(SrcFormat, SrcWidth: Integer; const SrcRect: BaseTypes.TRect; Src: Pointer; PaletteSize: Integer; Palette: PPalette; DestFormat, Width, Height: Integer; Dest: Pointer): Boolean;
  557. var i, j, SrcBpP, DestBpP: Integer; CurX, CurY, StepX, StepY: Single; Temp: Longword;
  558. begin
  559.   Result := False;
  560.   Assert((Width <> 0) and (Height <> 0));
  561.   SrcBpP  := GetBytesPerPixel(SrcFormat);
  562.   DestBpP := GetBytesPerPixel(DestFormat);
  563.   if (SrcBpP = 0) or (DestBpP = 0) then Exit;
  564.   StepX := (SrcRect.Right  - SrcRect.Left) / (Width);
  565.   StepY := (SrcRect.Bottom - SrcRect.Top) / (Height);
  566.   CurY := SrcRect.Top;
  567.   for j := 0 to Height-1 do begin
  568.     CurX := SrcRect.Left;
  569.     for i := 0 to Width-1 do begin
  570.       if not ConvertToProcessing(SrcFormat, 1, PtrOffs(Src, (Round(CurY) * SrcWidth + Round(CurX)) * SrcBpP), PaletteSize, Palette, @Temp) or
  571.          not ConvertFromProcessing(DestFormat, 1, @Temp, PaletteSize, Palette, PtrOffs(Dest, (j*Width + i) * DestBpP)) then Exit;
  572.       CurX := CurX + StepX;
  573. //      if Odd(j) then pdwordbuffer(dest)^[j*Width+i] := $FFFFFF else pdwordbuffer(dest)^[j*Width+i] := 0;
  574.     end;                                                                       
  575.     CurY := CurY + StepY;
  576.   end;
  577.   Result := True;
  578. end;
  579. function ImageBoxFilter(Value: Single): Single;
  580. begin
  581.   if (Value > -0.5) and (Value <= 0.5) then Result := 1.0 else Result := 0.0;
  582. end;
  583. function ImageTriangleFilter(Value: Single): Single;
  584. begin
  585.   if Value < 0.0 then Value := -Value;
  586.   if Value < 1.0 then Result := 1.0 - Value else Result := 0.0;
  587. end;
  588. function ImageHermiteFilter(Value: Single): Single;
  589. begin
  590.   if Value < 0.0 then
  591.     Value := -Value;
  592.   if Value < 1 then
  593.     Result := (2 * Value - 3) * Sqr(Value) + 1
  594.   else
  595.     Result := 0;
  596. end;
  597. function ImageBellFilter(Value: Single): Single;
  598. begin
  599.   if Value < 0.0 then Value := -Value;
  600.   if Value < 0.5 then Result := 0.75 - Sqr(Value) else if Value < 1.5 then begin
  601.     Value := Value - 1.5;
  602.     Result := 0.5 * Sqr(Value);
  603.   end else Result := 0.0;
  604. end;
  605. function ImageSplineFilter(Value: Single): Single;
  606. var Temp: Single;
  607. begin
  608.   if Value < 0.0 then Value := -Value;
  609.   if Value < 1.0 then begin
  610.     Temp := Sqr(Value);
  611.     Result := 0.5 * Temp * Value - Temp + 2.0 / 3.0;
  612.   end else if Value < 2.0 then begin
  613.     Value := 2.0 - Value;
  614.     Result := Sqr(Value) * Value / 6.0;
  615.   end else Result := 0.0;
  616. end;
  617. //--------------------------------------------------------------------------------------------------
  618. {function ImageLanczos3Filter(Value: Single): Single;
  619.   function SinC(Value: Single): Single;
  620.   begin
  621.     if Value <> 0.0 then begin
  622.       Value := Value * Pi;
  623.       Result := System.Sin(Value) / Value;
  624.     end else Result := 1.0;
  625.   end;
  626. begin
  627.   if Value < 0.0 then Value := -Value;
  628.   if Value < 3.0 then Result := SinC(Value) * SinC(Value / 3.0) else Result := 0.0;
  629. end;}
  630. function ImageLanczos3Filter(Value: Single): Single;
  631. const Radius = 3.0;
  632. begin
  633.   Result := 1;
  634.   if Value = 0 then Exit;
  635.   if Value < 0.0 then Value := -Value;
  636.   if Value < Radius then begin
  637.     Value := Value * pi;
  638.     Result := Radius * Sin(Value) * Sin(Value / Radius) / (Value * Value);
  639.   end else Result := 0.0;
  640. end;
  641. //--------------------------------------------------------------------------------------------------
  642. function ImageMitchellFilter(Value: Single): Single;
  643. const B = 1.0 / 3.0; C = 1.0 / 3.0;
  644. var Temp: Single;
  645. begin
  646.   if Value < 0.0 then Value := -Value;
  647.   Temp := Sqr(Value);
  648.   if Value < 1.0 then begin
  649.     Value := (((12.0 - 9.0 * B - 6.0 * C) * (Value * Temp)) +
  650.              ((-18.0 + 12.0 * B + 6.0 * C) * Temp) +
  651.              (6.0 - 2.0 * B));
  652.     Result := Value / 6.0;
  653.   end else if Value < 2.0 then begin
  654.     Value := (((-B - 6.0 * C) * (Value * Temp)) +
  655.              ((6.0 * B + 30.0 * C) * Temp) +
  656.              ((-12.0 * B - 48.0 * C) * Value) +
  657.              (8.0 * B + 24.0 * C));
  658.     Result := Value / 6.0;
  659.   end else Result := 0.0;
  660. end;
  661. function IntToByte(Value: Integer): Byte;
  662. begin
  663.   Result := MaxI(0, MinI(255, Value));
  664. end;
  665. procedure StretchARGBImage(Filter: TImageFilterFunction; const Radius: Single; Src: PImageBuffer; const SrcArea: BaseTypes.TRect; SrcLineLength: Integer; const Dest: PImageBuffer; const DestArea: BaseTypes.TRect; DestLineLength: Integer);
  666. var
  667.   Temp: PImageBuffer; TempSize: Integer;
  668.   SX1, SY1, SX2, SY2, DX1, DY1, DX2, DY2: Integer;
  669.   XStep, YStep: Single;
  670.   Width, Center: Single;
  671.   i, j, k, n: Integer;
  672.   Left, Right, Weight: Integer;
  673.   ContributorList: TContributorList;
  674.   function ApplyContributors(Mult, N: Integer; Contributors: TContributors; Buf: PImageBuffer): TARGB;
  675.   var J: Integer; RGB: TARGBInt; Total, Weight: Integer; Pixel: Cardinal; Contr: ^TContributor;
  676.   begin
  677.     RGB.R := 0; RGB.G := 0; RGB.B := 0; RGB.A := 0; Total := 0;
  678.     Contr := @Contributors[0];
  679.     for J := 0 to N-1 do begin
  680.       Weight := Contr^.Weight;
  681.       Inc(Total, Weight);
  682.       Pixel := Contr^.Pixel;
  683. {      if not ((Buf <> Temp) or (Cardinal(K*Mult)+Pixel < TempSize)) then begin
  684.         Assert((Buf <> Temp) or (Cardinal(K*Mult)+Pixel < TempSize));
  685.       end;}
  686.       Inc(RGB.R, TARGB(Buf^[Cardinal(K*Mult)+Pixel]).R * Weight);
  687.       Inc(RGB.G, TARGB(Buf^[Cardinal(K*Mult)+Pixel]).G * Weight);
  688.       Inc(RGB.B, TARGB(Buf^[Cardinal(K*Mult)+Pixel]).B * Weight);
  689.       Inc(RGB.A, TARGB(Buf^[Cardinal(K*Mult)+Pixel]).A * Weight);
  690.       Inc(Contr);
  691.     end;
  692.     if Total = 0 then begin
  693.       Result.R := IntToByte(RGB.R shr 8); Result.G := IntToByte(RGB.G shr 8); Result.B := IntToByte(RGB.B shr 8); Result.A := IntToByte(RGB.A shr 8);
  694.     end else begin
  695.       Result.R := IntToByte(RGB.R div Total); Result.G := IntToByte(RGB.G div Total); Result.B := IntToByte(RGB.B div Total); Result.A := IntToByte(RGB.A div Total);
  696.     end;
  697.   end;
  698. begin
  699.   with SrcArea do begin
  700.     SX1 := MinI(Left, Right); SY1 := MinI(Top, Bottom);
  701.     SX2 := MaxI(Left, Right); SY2 := MaxI(Top, Bottom);
  702.   end;
  703.   with DestArea do begin
  704.     DX1 := MinI(Left, Right); DY1 := MinI(Top, Bottom);
  705.     DX2 := MaxI(Left, Right); DY2 := MaxI(Top, Bottom);
  706.   end;
  707.   TempSize := DestLineLength{  (DX2-DX1)} * MaxI(DY2-DY1, SY2-SY1);
  708.   GetMem(Temp, TempSize * ProcessingFormatBpP);
  709.   XStep := (DX2-DX1)/(SX2-SX1);
  710.   if XStep < 1 then Width := Radius / XStep else Width := Radius;
  711.   SetLength(ContributorList, DX2);
  712.   for I := 0 to DX2 - 1 do begin
  713.     ContributorList[I].N := 0;
  714.     SetLength(ContributorList[I].Contributors, Trunc(2 * Width + 3));
  715.     Center := I / XStep;
  716.     Left  := MinI(Floor(Center - Width), SrcLineLength-1);
  717.     Right := MinI(Ceil(Center + Width), SrcLineLength-1);
  718.     for J := Left to Right do begin
  719.       if XStep < 1 then Weight := Round(Filter((Center - J) * XStep) * XStep * 256) else Weight := Round(Filter(Center - J) * 256);
  720.       if Weight <> 0 then begin
  721.         if J < 0 then N := -J else if J >= SX2 then N := SX2 - J + SX2 - 1 else N := J; // ToFix: SX2
  722.         N := N mod SX2;
  723.         K := ContributorList[I].N;
  724.         Inc(ContributorList[I].N);
  725.         ContributorList[I].Contributors[K].Pixel := N;
  726.         ContributorList[I].Contributors[K].Weight := Weight;
  727.       end;
  728.     end;
  729.   end;
  730.   for K := 0 to SY2 - 1 do for I := 0 to DX2 - 1 do with ContributorList[I] do
  731.     TARGB(Temp^[K*DestLineLength+I]) := ApplyContributors(SrcLineLength, N, ContributorList[I].Contributors, Src);
  732.   for I := 0 to DX2 - 1 do ContributorList[I].Contributors := nil;
  733.   ContributorList := nil;
  734.   YStep := (DY2-DY1)/(SY2-SY1);
  735.   if YStep < 1 then Width := Radius / YStep else Width := Radius;
  736.   SetLength(ContributorList, DY2);
  737.   for I := 0 to DY2 - 1 do begin
  738.     ContributorList[I].N := 0;
  739.     SetLength(ContributorList[I].Contributors, Trunc(2 * Width + 3));
  740.     Center := I / YStep;
  741.     Left  := MinI(Floor(Center - Width), SY2-SY1);
  742.     Right := MinI(Ceil(Center + Width), SY2-SY1);
  743.     for J := Left to Right do begin
  744.       if YStep < 1 then Weight := Round(Filter((Center - J) * YStep) * YStep * 256) else Weight := Round(Filter(Center - J) * 256);
  745.       if Weight <> 0 then begin
  746.         if J < 0 then N := -J else if J >= SY2 then N := SY2 - J + SY2 - 1 else N := J; // ToFix: SY2
  747.         N := N mod SY2;
  748.         K := ContributorList[I].N;
  749.         Inc(ContributorList[I].N);
  750. //        ContributorList[I].Contributors[K].Pixel  := N*DX2;     // ? DX2=>(DX2-DX1) ?
  751.         ContributorList[I].Contributors[K].Pixel  := N*(DX2-DX1);
  752.         ContributorList[I].Contributors[K].Weight := Weight;
  753.       end;
  754.     end;
  755.   end;
  756.   for K := 0 to DX2 - 1 do for I := 0 to DY2 - 1 do with ContributorList[I] do
  757.     TARGB(Dest^[I*DestLineLength+K]) := ApplyContributors(1, N, ContributorList[I].Contributors, Temp);
  758.   for I := 0 to DY2 - 1 do ContributorList[I].Contributors := nil;
  759.   ContributorList := nil;
  760.   FreeMem(Temp);
  761. end;
  762. function SaveIDF(const Stream: TStream; const IDFHeader: TIDFHeader; const Buffers: array of Pointer): Boolean;
  763. var i, CurW, CurH, BpP: Integer;
  764. begin
  765.   Result := False;
  766.   if not Stream.WriteCheck(IDFHeader, SizeOf(IDFHeader)) then Exit;
  767.   CurW := IDFHeader.Width; CurH := IDFHeader.Height;
  768.   BpP := GetBytesPerPixel(IDFHeader.PixelFormat);
  769.   if BpP = 0 then begin
  770.     ErrorHandler(TInvalidFormat.Create('Invalid pixel format'));
  771.     Exit;                                                        // Unrecoverable
  772.   end;
  773.   for i := 0 to Length(Buffers)-1 do begin
  774.     if not Stream.WriteCheck(Buffers[i]^, CurW*CurH*BpP) then Exit;
  775.     CurW := MaxI(1, CurW div 2); CurH := MaxI(1, CurH div 2);
  776.   end;
  777.   Result := True;
  778. end;
  779. function LoadIDF(const Stream: TStream; var IDFHeader: TIDFHeader; var Buffer: Pointer; var TotalSize: Integer): Boolean;
  780. var i, CurW, CurH, BpP: Integer;
  781. begin
  782.   Result := False;
  783.   if not Stream.ReadCheck(IDFHeader, SizeOf(IDFHeader)) or (IDFHeader.Signature <> 'IDF') then Exit;
  784.   CurW := IDFHeader.Width; CurH := IDFHeader.Height;
  785.   BpP := GetBytesPerPixel(IDFHeader.PixelFormat);
  786.   if BpP = 0 then begin
  787.     ErrorHandler(TInvalidFormat.Create('Invalid pixel format'));
  788.     Exit;                                                        // Unrecoverable
  789.   end;
  790.     TotalSize := 0;
  791.   for i := 0 to IDFHeader.MipLevels do begin
  792.     Inc(TotalSize, CurW*CurH);
  793.     CurW := MaxI(1, CurW div 2);
  794.     CurH := MaxI(1, CurH div 2);
  795.   end;
  796.   GetMem(Buffer, TotalSize*BpP);
  797.   if not Stream.ReadCheck(Buffer^, TotalSize*BpP) then begin FreeMem(Buffer); TotalSize := 0; end else Result := True;
  798. end;
  799. function LoadIDFBuffers(const Stream: TStream; var IDFHeader: TIDFHeader; var Buffers: TPointerArray; var TotalSize: Integer): Boolean;
  800. var i, j, CurW, CurH, BpP: Integer;
  801. begin
  802.   Result := False;
  803.   if (not Stream.ReadCheck(IDFHeader, SizeOf(IDFHeader))) or (IDFHeader.Signature <> 'IDF') then Exit;
  804.   CurW := IDFHeader.Width; CurH := IDFHeader.Height;
  805.   BpP := GetBytesPerPixel(IDFHeader.PixelFormat);
  806.   if BpP = 0 then begin
  807.     ErrorHandler(TInvalidFormat.Create('Invalid pixel format'));
  808.     Exit;                                                        // Unrecoverable
  809.   end;
  810.   TotalSize := 0;
  811.   SetLength(Buffers, IDFHeader.MipLevels+1);
  812.   for i := 0 to Length(Buffers)-1 do begin
  813.     Inc(TotalSize, CurW*CurH);
  814.     GetMem(Buffers[i], CurW*CurH*BpP);
  815.     if not Stream.ReadCheck(Buffers[i]^, CurW*CurH*BpP) then begin
  816.       for j := 0 to i do FreeMem(Buffers[i]);
  817.       TotalSize := 0;
  818.       Exit;
  819.     end;
  820.     CurW := MaxI(1, CurW div 2);
  821.     CurH := MaxI(1, CurH div 2);
  822.   end;
  823.   Result := True;
  824. end;
  825. function LoadBitmapHeader(const Stream: TStream; out Header: TImageHeader): Boolean;
  826. var
  827.  FileHeader: TBITMAPFILEHEADER;
  828.  InfoHeader: TBITMAPINFOHEADER;
  829. begin
  830.   Result := False;
  831.   if not Stream.ReadCheck(FileHeader, SizeOf(FileHeader)) then Exit;
  832.   if FileHeader.bfType <> Ord('M')*256 + Ord('B') then begin
  833.     ErrorHandler(TInvalidFormat.Create('Not a .bmp file'));
  834.     Exit;
  835.   end;
  836.   if not Stream.ReadCheck(InfoHeader, SizeOf(InfoHeader)) then Exit;
  837.   Header.Width  := InfoHeader.biWidth;
  838.   Header.Height := Abs(InfoHeader.biHeight);
  839.   Header.BitsPerPixel := InfoHeader.biBitCount;
  840.   Header.LineSize := Header.Width * Header.BitsPerPixel div 8;
  841.   if InfoHeader.biHeight < 0 then Header.ImageOrigin := ioTopLeft else Header.ImageOrigin := ioBottomLeft;
  842.   if Header.LineSize and 3 <> 0 then Header.LineSize := Header.LineSize + 4 - Header.LineSize and 3;
  843.   case Header.BitsPerPixel of                                  // ToDo: Test with more .bmp files and fix if necessary
  844.     1..8:   Header.Format := pfP8;
  845.     15, 16: Header.Format := pfR5G6B5;
  846.     24:     Header.Format := pfB8G8R8;
  847.     32:     Header.Format := pfA8R8G8B8;
  848.   end;
  849.   Header.PaletteSize := InfoHeader.biClrUsed;
  850.   if (InfoHeader.biBitCount <= 8) and (Header.PaletteSize = 0) then Header.PaletteSize := 256;
  851.   Getmem(Header.Palette, Header.PaletteSize * SizeOf(TPaletteItem));
  852.   if not Stream.ReadCheck(Header.Palette^, Header.PaletteSize * SizeOf(TPaletteItem)) then begin FreeMem(Header.Palette); Exit; end;
  853.   Header.ImageSize := InfoHeader.biSizeImage;
  854.   if Header.ImageSize = 0 then Header.ImageSize := Header.LineSize * Header.Height;
  855.   Result := True;
  856. end;
  857. function LoadBitmap(const Stream: TStream; out LineSize: Integer; out Width: Integer; out Height: Integer; out BitsPerPixel: Integer; out PaletteSize: Cardinal; out Palette: PPalette; out Data: Pointer): Boolean;
  858. var Header: TImageHeader;
  859. begin
  860.   Result := False;
  861.   if not LoadBitmap(Stream, Header) then Exit;
  862.   Width        := Header.Width;
  863.   Height       := Header.Height;
  864.   BitsPerPixel := Header.BitsPerPixel;
  865.   LineSize     := Header.LineSize;
  866.   PaletteSize  := Header.PaletteSize;
  867.   Palette      := Header.Palette;
  868.   Data         := Header.Data;
  869.   Result := True;
  870. end;
  871. function LoadBitmap(const Stream: TStream; var Header: TImageHeader): Boolean;
  872. var i, CurLine, Remainder, RemData: Integer;
  873. begin
  874.   Result := False;
  875.   if not LoadBitmapHeader(Stream, Header) then Exit;
  876.   // Convert header from .bmp to usual image
  877.   Remainder := Header.LineSize - Header.Width * Header.BitsPerPixel div 8;
  878.   Assert((Remainder >= 0) and (Remainder < 4));
  879.   Header.LineSize  := Header.Width * Header.BitsPerPixel div 8;
  880.   Header.ImageSize := Header.LineSize * Header.Height;
  881.   // Get the actual pixel data
  882.   GetMem(Header.Data, Header.ImageSize);
  883.   if Header.ImageOrigin = ioTopLeft then CurLine := 0 else CurLine := Header.Height-1;
  884.   for i := 0 to Header.Height-1 do begin
  885.     if not Stream.ReadCheck(PtrOffs(Header.Data, CurLine*Header.LineSize)^, Header.LineSize) or
  886.        not Stream.ReadCheck(RemData, Remainder) then begin
  887.       FreeMem(Header.Data);
  888.       Exit;
  889.     end;
  890.     if Header.ImageOrigin = ioTopLeft then Inc(CurLine) else Dec(CurLine);
  891.   end;
  892.   Result := True;
  893. end;
  894. procedure BufferCopy(const SBuf, DBuf: Pointer; const BufLineLength, BpP: Integer; const Rect: BaseTypes.TRect);
  895. var j: Integer;
  896. begin
  897.   for j := Rect.Top to Rect.Bottom-1 do
  898.     Move(PByteBuffer(SBuf)^[(j*BufLineLength+Rect.Left)*BpP],
  899.          PByteBuffer(DBuf)^[(j*BufLineLength+Rect.Left)*BpP], (Rect.Right-Rect.Left)*BpP);
  900. end;
  901. procedure BufferCut(const SBuf, DBuf: Pointer; const SrcLineLength, DestLineLength, BpP: Integer; const Rect: BaseTypes.TRect);
  902. var w, j: Integer;
  903. begin
  904.   w := Rect.Right-Rect.Left;
  905.   for j := Rect.Top to Rect.Bottom-1 do
  906.     Move(PByteBuffer(SBuf)^[(j*SrcLineLength+Rect.Left)*BpP], PByteBuffer(DBuf)^[(j-Rect.Top)*DestLineLength*BpP], w*BpP);
  907. end;
  908. procedure BufferPaste(const SBuf, DBuf: Pointer; const SrcLineLength, DestLineLength, BpP: Integer; const Rect: BaseTypes.TRect);
  909. var w, j: Integer;
  910. begin
  911.   w := Rect.Right-Rect.Left;
  912.   for j := Rect.Top to Rect.Bottom-1 do
  913.     Move(PByteBuffer(SBuf)^[(j-Rect.Top)*SrcLineLength*BpP], PByteBuffer(DBuf)^[(j*DestLineLength+Rect.Left)*BpP], w*BpP);
  914. end;
  915. procedure BufferSwap(const SBuf, DBuf: Pointer; const SrcLineLength, DestLineLength, BpP: Integer; const Rect: BaseTypes.TRect);
  916. const MaxLineSize = $FFFF*4;
  917. var w, j: Integer; Temp: array[0..MaxLineSize] of Byte;
  918. begin
  919.   w := Rect.Right-Rect.Left;
  920.   Assert(w*BpP <= MaxLineSize, 'BufferSwap: Line size is too big');
  921.   for j := Rect.Top to Rect.Bottom-1 do begin
  922.     Move(PByteBuffer(DBuf)^[(j-Rect.Top)*DestLineLength*BpP], Temp[0], w*BpP);
  923.     Move(PByteBuffer(SBuf)^[(j*SrcLineLength+Rect.Left)*BpP], PByteBuffer(DBuf)^[(j-Rect.Top)*DestLineLength*BpP], w*BpP);
  924.     Move(Temp[0], PByteBuffer(SBuf)^[(j*SrcLineLength+Rect.Left)*BpP], w*BpP);
  925.   end;
  926. end;
  927. function BufferCutAsRGBA(const SBuf, DBuf: Pointer; const SrcLineLength, DestLineLength, SrcFormat: Integer; const Rect: BaseTypes.TRect): Boolean;
  928. var w, j, BpP: Integer;
  929. begin
  930.   Result := False;
  931.   w := Rect.Right-Rect.Left;
  932.   BpP := GetBytesPerPixel(SrcFormat);
  933.   for j := Rect.Top to Rect.Bottom-1 do
  934.     if not ConvertToProcessing(SrcFormat, w, PtrOffs(SBuf, (j*SrcLineLength+Rect.Left)*BpP), 0, nil, PtrOffs(DBuf, (j-Rect.Top)*DestLineLength*ProcessingFormatBpP)) then Exit;
  935.   Result := True;
  936. end;
  937. function BufferRGBAPaste(const SBuf, DBuf: Pointer; const SrcLineLength, DestLineLength, DestFormat: Integer; const Rect: BaseTypes.TRect): Boolean;
  938. var w, j, BpP, tmp: Integer;
  939. begin
  940.   Result := False;
  941.   w := Rect.Right-Rect.Left;
  942.   BpP := GetBytesPerPixel(DestFormat);
  943.   for j := Rect.Top to Rect.Bottom-1 do
  944.     if not ConvertFromProcessing(DestFormat, w, PtrOffs(SBuf, (j-Rect.Top)*SrcLineLength*ProcessingFormatBpP), tmp, nil, PtrOffs(DBuf, (j*DestLineLength+Rect.Left)*BpP)) then Exit;
  945.   Result := True;
  946. end;
  947. function BufferRGBACombine(const SBuf, DBuf: Pointer; const SrcLineLength, DestLineLength, DestFormat: Integer; const Rect: BaseTypes.TRect): Boolean;
  948. const MaxLineLength = $FFFF;
  949. var w, i, j, BpP, tmp: Integer; Temp: array[0..MaxLineLength] of TColor; Col: TColor;
  950. begin                       
  951.   Result := False;
  952.   w := Rect.Right-Rect.Left;
  953.   Assert(w <= MaxLineLength, 'Base2D.BufferRGBACombine: Line length is too big');
  954.   BpP := GetBytesPerPixel(DestFormat);
  955.   for j := Rect.Top to Rect.Bottom-1 do begin
  956.     if not ConvertToProcessing(DestFormat, w, PtrOffs(DBuf, (j*DestLineLength+Rect.Left)*BpP), 0, nil, @Temp[0]) then Exit;
  957.     for i := 0 to Rect.Right-Rect.Left-1 do begin
  958.       Col := PColor(PtrOffs(SBuf, ((j-Rect.Top)*SrcLineLength+i)*ProcessingFormatBpP))^;
  959.       Temp[i] := BlendColor(Temp[i], Col, Col.A/255);
  960.     end;
  961.     if not ConvertFromProcessing(DestFormat, w, @Temp[0], tmp, nil, PtrOffs(DBuf, (j*DestLineLength+Rect.Left)*BpP)) then Exit;
  962.   end;
  963.   Result := True;
  964. end;
  965. function BufferRGBABlend(const SBuf, DBuf, ABuf: Pointer; const SrcLineLength, DestLineLength, DestFormat: Integer; const Rect: BaseTypes.TRect): Boolean;
  966. const MaxLineLength = $FFFF;
  967. var w, i, j, BpP, tmp, Addr: Integer; Temp: array[0..MaxLineLength] of TColor; Col: TColor;
  968. begin
  969.   Result := False;
  970.   w := Rect.Right-Rect.Left;
  971.   Assert(w <= MaxLineLength, 'Base2D.BufferRGBABlend: Line length is too big');
  972.   BpP := GetBytesPerPixel(DestFormat);
  973.   for j := Rect.Top to Rect.Bottom-1 do begin
  974.     if not ConvertToProcessing(DestFormat, w, PtrOffs(DBuf, (j*DestLineLength+Rect.Left)*BpP), 0, nil, @Temp[0]) then Exit;
  975.     for i := 0 to Rect.Right-Rect.Left-1 do begin
  976.       Addr := ((j-Rect.Top)*SrcLineLength+i);
  977.       Col := PColor(PtrOffs(SBuf, Addr*ProcessingFormatBpP))^;
  978.       Temp[i] := BlendColor(Temp[i], Col, PByteBuffer(ABuf)^[Addr]/255);
  979.     end;
  980.     if not ConvertFromProcessing(DestFormat, w, @Temp[0], tmp, nil, PtrOffs(DBuf, (j*DestLineLength+Rect.Left)*BpP)) then Exit;
  981.   end;
  982.   Result := True;
  983. end;
  984. { TBaseImageSource }
  985. function TBaseImageSource.GetBitsPerPixel: Integer;
  986. begin
  987.   Result := Basics.GetBitsPerPixel(FFormat);
  988. end;
  989. function TBaseImageSource.GetBytesPerPixel: Integer;
  990. begin
  991.   Result := Basics.GetBytesPerPixel(FFormat);
  992. end;
  993. constructor TBaseImageSource.Create(AFormat, AWidth, AHeight: Integer);
  994. begin
  995.   FFormat := AFormat;
  996.   FWidth  := AWidth;
  997.   FHeight := AHeight;
  998. end;
  999. function TBaseImageSource.LoadData(Rect: TRect; Dest: Pointer; DestImageWidth: Integer): Boolean;
  1000. begin
  1001.   Result := GetData(Rect, Dest, DestImageWidth);
  1002. end;
  1003. function TBaseImageSource.LoadDataAsRGBA(Rect: TRect; Dest: Pointer; DestImageWidth: Integer): Boolean;
  1004. var xo1, xo2, xn, yo1, yo2, yn, tmp: Integer;
  1005.   function GetLine(ATop, AHeight: Integer): Boolean;
  1006.     function GetCol(ALeft, AWidth: Integer): Boolean;
  1007.     var LRect: TRect;
  1008.     begin
  1009.       LRect := GetRectWH((ALeft + FWidth  * (xn+1)) mod FWidth,
  1010.                          (ATop  + FHeight * (yn+1)) mod FHeight,
  1011.                          AWidth, AHeight);
  1012.       Result := GetDataAsRGBA(LRect, PtrOffs(Dest, ((ATop - Rect.Top) * DestImageWidth + ALeft - Rect.Left) * ProcessingFormatBpP), DestImageWidth);
  1013.     end;
  1014.   var l, lxn: Integer;
  1015.   begin
  1016.     Result := False;
  1017.     l := Rect.Left;
  1018.     if xo1 > 0 then begin
  1019.       if not GetCol(l, xo1) then Exit;
  1020.       l := l + xo1;
  1021.       if l mod FWidth  <> 0 then begin
  1022.         Assert(l mod FWidth = 0);
  1023.       end;  
  1024.     end;
  1025.     lxn := xn;
  1026.     while lxn > 0 do begin
  1027.       if not GetCol(l, FWidth) then Exit;
  1028.       l := l + FWidth;
  1029.       Dec(lxn);
  1030.     end;
  1031.     if xo2 > 0 then begin
  1032.       if not GetCol(l, xo2) then Exit;
  1033.       l := l + xo2;
  1034.     end;
  1035.     Assert(l = Rect.Right);
  1036.     Result := True;
  1037.   end;
  1038.   var t: Integer;
  1039. //   _ ___ --- ___ __
  1040. //  xo1 w   w   w  xo2
  1041. begin
  1042.   Result := True;
  1043.   if (Rect.Right <= Rect.Left) or (Rect.Bottom <= Rect.Top) then Exit;
  1044.   Result := False;
  1045.   RectMove(Rect, MaxImageRepeatsHalf * FWidth, MaxImageRepeatsHalf * FHeight, Rect);
  1046.   xo1 := (FWidth - (Rect.Left mod FWidth)) mod FWidth;
  1047.   xo2 := Rect.Right mod FWidth;
  1048.   tmp := (Rect.Right - Rect.Left - xo1 - xo2);
  1049.   xn := tmp div FWidth;
  1050.   if tmp < 0 then begin
  1051.     xo2 := -FWidth + xo1 + xo2;
  1052.     xo1 := 0;
  1053.   end;
  1054.   yo1 := (FHeight - (Rect.Top mod FHeight)) mod FHeight;
  1055.   yo2 := Rect.Bottom mod FHeight;
  1056.   tmp :=(Rect.Bottom - Rect.Top - yo1 - yo2);
  1057.   yn := tmp div FHeight;
  1058.   if tmp < 0 then begin
  1059.     yo2 := -FHeight + yo1 + yo2;
  1060.     yo1 := 0;
  1061.   end;
  1062.   t := Rect.Top;
  1063.   if yo1 > 0 then begin
  1064.     if not GetLine(t, yo1) then Exit;
  1065.     t := t + yo1;
  1066.     Assert(t mod FHeight = 0);
  1067.   end;
  1068.   while yn > 0 do begin
  1069.     if not GetLine(t, FHeight) then Exit;
  1070.     t := t + FHeight;
  1071.     Dec(yn);
  1072.   end;
  1073.   if yo2 > 0 then begin
  1074.     if not GetLine(t, yo2) then Exit;
  1075.     t := t + yo2;
  1076.   end;
  1077.   Assert(t = Rect.Bottom);
  1078.   Result := True;
  1079. end;
  1080. { TImageOperation }
  1081. procedure TImageOperation.DoApply;
  1082. begin
  1083.   Assert(Assigned(FImageData), 'TImageOperation.DoApply: Image data is undefined');
  1084.   BufferSwap(FImageData, FData, FImageLineLength, FRect.Right-FRect.Left, FImageBpP, FRect);
  1085. end;
  1086. constructor TImageOperation.Create(AImageData: Pointer; AImageLineLength, AImageFormat: Integer; const ARect: BaseTypes.TRect);
  1087. begin
  1088.   FImageData       := AImageData;
  1089.   FImageLineLength := AImageLineLength;
  1090.   FImageFormat     := AImageFormat;
  1091.   FImageBpP        := GetBytesPerPixel(FImageFormat);
  1092.   FRect            := ARect;
  1093.   GetMem(FData, (FRect.Bottom-FRect.Top) * (FRect.Right-FRect.Left) * FImageBpP);
  1094. //  FillChar(FData^, (FRect.Bottom-FRect.Top) * (FRect.Right-FRect.Left) * FImageBpP, 0);
  1095. end;
  1096. function CombineValues(OldValue, NewValue, Mask: Longword; ColorOp: TColorCombineOperation): BaseTypes.TColor;
  1097. begin
  1098.   NewValue := NewValue and Mask;
  1099.   case ColorOp of
  1100.     coSet: Result.C := Longword(OldValue and (not Mask)) + NewValue;
  1101.     coAdd: asm
  1102.       movd            MM0, OldValue
  1103.       movd            MM1, NewValue
  1104.       paddusb         MM0, MM1
  1105.       movd            Result, MM0
  1106.       emms
  1107.     end;
  1108.     coSub: asm
  1109.       movd            MM0, OldValue
  1110.       movd            MM1, NewValue
  1111.       psubusb         MM0, MM1
  1112.       movd            Result, MM0
  1113.       emms
  1114.     end;
  1115.     coMod: asm
  1116.       pxor            MM2, MM2
  1117.       movd            MM0, OldValue
  1118.       mov             EAX, NewValue
  1119.       mov             DX, AX
  1120.       shl             EAX, 16
  1121.       mov             AX, DX
  1122. //      movd            MM1, EAX
  1123.       psllq           MM1, 32
  1124. //      psllw           MM1, 8
  1125.       movd            MM3, EAX
  1126.       por             MM1, MM3
  1127.       punpcklbw       MM0, MM2
  1128.       pmullw          MM0, MM1
  1129.       psrlw           MM0, 8
  1130.       packuswb        MM0, MM2
  1131.       mov             EAX, Mask
  1132.       not             EAX
  1133.       and             OldValue, EAX
  1134.       movd            EAX, MM0
  1135.       and             EAX, Mask
  1136.       or              EAX, OldValue
  1137. //      mov             Result, EAX
  1138.       emms
  1139.     end;
  1140.   end;
  1141. end;
  1142. { TImagePaintOp }
  1143. constructor TImagePaintOp.Create(X, Y: Integer; AImageData: Pointer; AImageLineLength, AImageFormat: Integer; ABrush: TBrush; const ARect: BaseTypes.TRect);
  1144. begin
  1145.   inherited Create(AImageData, AImageLineLength, AImageFormat, GetRectIntersect(GetRect(X, Y, X+ABrush.Width, Y+ABrush.Height), ARect));
  1146.   BufferCut(FImageData, FData, FImageLineLength, Rect.Right-Rect.Left, FImageBpP, Rect);
  1147.   BufferRGBABlend(PtrOffs(ABrush.PatternData, (MaxI(0, -Y) * ABrush.Width + MaxI(0, -X)) * SizeOf(TColor)),
  1148.                   FData,
  1149.                   PtrOffs(ABrush.ShapeData, (MaxI(0, -Y) * ABrush.Width + MaxI(0, -X))),
  1150.                   ABrush.Width, Rect.Right-Rect.Left, FImageFormat, GetRectMoved(Rect, -Rect.Left, -Rect.Top));
  1151. //  BufferRGBACombine(PtrOffs(ABrush.PatternData, (MaxI(0, -Y) * ABrush.Width + MaxI(0, -X)) * SizeOf(TColor)),
  1152. //                  FData,
  1153. //                  ABrush.Width, Rect.Right-Rect.Left, FImageFormat, GetRectMove(Rect, -Rect.Left, -Rect.Top));
  1154. end;
  1155. { TImageCloneOp }
  1156. constructor TImageCloneOp.Create(X, Y: Integer; AImageData: Pointer; AImageLineLength, AImageFormat: Integer; ABrush: TBrush;
  1157.                                  SrcX, SrcY: Integer; ASource: TBaseImageSource; const ARect: TRect);
  1158. begin
  1159.   if not Assigned(ASource) then begin
  1160.     ErrorHandler(TInvalidArgument.Create('TImageCloneOp.Create: Can''t create operation: invalid image source'));
  1161.     Exit;
  1162.   end;
  1163.   inherited Create(AImageData, AImageLineLength, AImageFormat, GetRectIntersect(GetRect(X, Y, X+ABrush.Width, Y+ABrush.Height), ARect));
  1164. //  ASource.GetData(GetRectWH(SrcX, SrcY, Rect.Right-Rect.Left, Rect.Bottom-Rect.Top), FData, Rect.Right-Rect.Left);
  1165.   BufferRGBABlend(PtrOffs(ABrush.PatternData, (MaxI(0, -Y) * ABrush.Width + MaxI(0, -X)) * SizeOf(TColor)),
  1166.                   FData,
  1167.                   PtrOffs(ABrush.ShapeData, (MaxI(0, -Y) * ABrush.Width + MaxI(0, -X))),
  1168.                   ABrush.Width, Rect.Right-Rect.Left, FImageFormat, GetRectMoved(Rect, -Rect.Left, -Rect.Top));
  1169. //  BufferRGBACombine(PtrOffs(ABrush.ShapeData, (MaxI(0, -Y) * ABrush.Width + MaxI(0, -X)) * SizeOf(TColor)),
  1170. //                    FData, ABrush.Width, Rect.Right-Rect.Left, FImageFormat, GetRectMove(Rect, -Rect.Left, -Rect.Top));
  1171. end;
  1172. { TBrush }
  1173. function TBrush.GetWidth: Integer;
  1174. begin
  1175.   Result := FShape.Width;
  1176. end;
  1177. function TBrush.GetHeight: Integer;
  1178. begin
  1179.   Result := FShape.Height;
  1180. end;
  1181. function TBrush.GetShapeData: Pointer;
  1182. begin
  1183.   Result := FShape.Data;
  1184. end;
  1185. function TBrush.GetPatternData: Pointer;
  1186. begin
  1187.   Result := FPattern.Data;
  1188. end;
  1189. constructor TBrush.Create;
  1190. begin
  1191.   FShape.Data   := nil;
  1192.   FPattern.Data := nil;
  1193. end;
  1194. destructor TBrush.Destroy;
  1195. begin
  1196.   if Assigned(FShape.Data)   then FreeMem(FShape.Data);
  1197.   if Assigned(FPattern.Data) then FreeMem(FPattern.Data);
  1198.   inherited;
  1199. end;
  1200. procedure TBrush.Init(AWidth, AHeight: Integer; AShape, APattern: Pointer; ABitmapFormat: Integer; AColor: TColor; AColorCombineOperation: TColorCombineOperation; ASource: TBaseImageSource);
  1201. begin
  1202.   FShape.Format       := pfA8;
  1203.   FShape.Width        := AWidth;
  1204.   FShape.Height       := AHeight;
  1205.   FShape.BitsPerPixel := GetBitsPerPixel(FShape.Format);
  1206.   FShape.PaletteSize  := 0;
  1207.   FShape.Palette      := nil;
  1208.   FShape.LineSize     := FShape.Width * FShape.BitsPerPixel div BitsInByte;
  1209.   FShape.ImageSize    := FShape.LineSize * FShape.Height;
  1210.   FPattern.Format       := pfA8R8G8B8;
  1211.   FPattern.Width        := AWidth;
  1212.   FPattern.Height       := AHeight;
  1213.   FPattern.BitsPerPixel := GetBitsPerPixel(FPattern.Format);
  1214.   FPattern.PaletteSize  := 0;
  1215.   FPattern.Palette      := nil;
  1216.   FPattern.LineSize     := FPattern.Width * FPattern.BitsPerPixel div BitsInByte;
  1217.   FPattern.ImageSize    := FPattern.LineSize * FPattern.Height;
  1218.   ReallocMem(FShape.Data, FShape.ImageSize);
  1219. //  ConvertImage(ABitmapFormat, FShape.Format, AWidth*AHeight, ABitmap, 0, nil, FShape.Data);
  1220.   ReallocMem(FPattern.Data, FPattern.ImageSize);
  1221.   if Assigned(AShape)   then Move(AShape^,   FShape.Data^,   FShape.ImageSize);
  1222.   if Assigned(APattern) then Move(APattern^, FPattern.Data^, FPattern.ImageSize);
  1223.   Color := AColor;
  1224.   ColorCombineOperation := AColorCombineOperation;
  1225.   FSource := ASource;
  1226.   Assert(IsValid);
  1227. end;
  1228. function TBrush.IsValid: Boolean;
  1229. begin
  1230.   Result := (FShape.Format <> pfUndefined) and (FShape.BitsPerPixel > 0) and
  1231.             (FShape.Width > 0) and (FShape.Height > 0) and
  1232.              Assigned(FShape.Data) and
  1233.             (FPattern.Format <> pfUndefined) and (FPattern.BitsPerPixel > 0) and
  1234.             (FPattern.Width > 0) and (FPattern.Height > 0) and
  1235.              Assigned(FPattern.Data)
  1236. end;
  1237. { TImageSource }
  1238. function TImageSource.GetData(const Rect: TRect; Dest: Pointer; DestImageWidth: Integer): Boolean;
  1239. begin
  1240.   BufferCut(FBuf, Dest, FWidth, DestImageWidth, Basics.GetBytesPerPixel(FFormat), Rect);
  1241.   Result := True;
  1242. end;
  1243. function TImageSource.GetDataAsRGBA(const Rect: TRect; Dest: Pointer; DestImageWidth: Integer): Boolean;
  1244. begin
  1245.   Result := BufferCutAsRGBA(FBuf, Dest, FWidth, DestImageWidth, FFormat, Rect);
  1246. end;
  1247. constructor TImageSource.Create(const ABuf: Pointer; AFormat, AWidth, AHeight: Integer);
  1248. begin
  1249.   FFormat := AFormat;
  1250.   FWidth  := AWidth;
  1251.   FHeight := AHeight;
  1252.   FBuf    := ABuf;
  1253. end;
  1254. end.