📄 gr32.pas
字号:
unit GR32;
(* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Graphics32
*
* The Initial Developer of the Original Code is
* Alex A. Denisov
*
* Portions created by the Initial Developer are Copyright (C) 2000-2006
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Michael Hansen <dyster_tid@hotmail.com>
* Andre Beckedorf <Andre@metaException.de>
* Mattias Andersson <mattias@centaurix.com>
* J. Tulach <tulach at position.cz>
* Jouni Airaksinen <markvera at spacesynth.net>
* Timothy Weber <teejaydub at users.sourceforge.net>
*
* ***** END LICENSE BLOCK ***** *)
interface
{$I GR32.inc}
uses
{$IFDEF CLX}
Qt, Types,
{$IFDEF LINUX}Libc,{$ENDIF}
{$IFDEF MSWINDOWS}Windows,{$ENDIF}
QControls, QGraphics, QConsts,
{$ELSE}
Windows, Messages, Controls, Graphics,
{$ENDIF}
Classes, SysUtils;
{ Version Control }
const
Graphics32Version = '1.8.1';
{ 32-bit Color }
type
PColor32 = ^TColor32;
TColor32 = type Cardinal;
PColor32Array = ^TColor32Array;
TColor32Array = array [0..0] of TColor32;
TArrayOfColor32 = array of TColor32;
PColor32Entry = ^TColor32Entry;
TColor32Entry = packed record
case Integer of
0: (B, G, R, A: Byte);
1: (ARGB: TColor32);
2: (Planes: array[0..3] of Byte);
end;
PColor32EntryArray = ^TColor32EntryArray;
TColor32EntryArray = array [0..0] of TColor32Entry;
TArrayOfColor32Entry = array of TColor32Entry;
PPalette32 = ^TPalette32;
TPalette32 = array [Byte] of TColor32;
const
// Some predefined color constants
clBlack32 = TColor32($FF000000);
clDimGray32 = TColor32($FF3F3F3F);
clGray32 = TColor32($FF7F7F7F);
clLightGray32 = TColor32($FFBFBFBF);
clWhite32 = TColor32($FFFFFFFF);
clMaroon32 = TColor32($FF7F0000);
clGreen32 = TColor32($FF007F00);
clOlive32 = TColor32($FF7F7F00);
clNavy32 = TColor32($FF00007F);
clPurple32 = TColor32($FF7F007F);
clTeal32 = TColor32($FF007F7F);
clRed32 = TColor32($FFFF0000);
clLime32 = TColor32($FF00FF00);
clYellow32 = TColor32($FFFFFF00);
clBlue32 = TColor32($FF0000FF);
clFuchsia32 = TColor32($FFFF00FF);
clAqua32 = TColor32($FF00FFFF);
// Some semi-transparent color constants
clTrWhite32 = TColor32($7FFFFFFF);
clTrBlack32 = TColor32($7F000000);
clTrRed32 = TColor32($7FFF0000);
clTrGreen32 = TColor32($7F00FF00);
clTrBlue32 = TColor32($7F0000FF);
// Color construction and conversion functions
function Color32(WinColor: TColor): TColor32; overload;
function Color32(R, G, B: Byte; A: Byte = $FF): TColor32; overload;
function Color32(Index: Byte; var Palette: TPalette32): TColor32; overload;
function Gray32(Intensity: Byte; Alpha: Byte = $FF): TColor32; {$IFDEF USEINLINING} inline; {$ENDIF}
function WinColor(Color32: TColor32): TColor;
function ArrayOfColor32(Colors: array of TColor32): TArrayOfColor32;
// Color component access
procedure Color32ToRGB(Color32: TColor32; var R, G, B: Byte);
procedure Color32ToRGBA(Color32: TColor32; var R, G, B, A: Byte);
function RedComponent(Color32: TColor32): Integer; {$IFDEF USEINLINING} inline; {$ENDIF}
function GreenComponent(Color32: TColor32): Integer; {$IFDEF USEINLINING} inline; {$ENDIF}
function BlueComponent(Color32: TColor32): Integer; {$IFDEF USEINLINING} inline; {$ENDIF}
function AlphaComponent(Color32: TColor32): Integer; {$IFDEF USEINLINING} inline; {$ENDIF}
function Intensity(Color32: TColor32): Integer; {$IFDEF USEINLINING} inline; {$ENDIF}
function SetAlpha(Color32: TColor32; NewAlpha: Integer): TColor32; {$IFDEF USEINLINING} inline; {$ENDIF}
// Color space conversion
function HSLtoRGB(H, S, L: Single): TColor32; overload;
procedure RGBtoHSL(RGB: TColor32; out H, S, L : Single); overload;
function HSLtoRGB(H, S, L: Integer): TColor32; overload;
procedure RGBtoHSL(RGB: TColor32; out H, S, L: Byte); overload;
{$IFNDEF CLX}
// Palette conversion functions
function WinPalette(const P: TPalette32): HPALETTE;
{$ENDIF}
{ A fixed-point type }
type
// This type has data bits arrangement compatible with Windows.TFixed
PFixed = ^TFixed;
TFixed = type Integer;
PFixedRec = ^TFixedRec;
TFixedRec = packed record
case Integer of
0: (Fixed: TFixed);
1: (Frac: Word; Int: SmallInt);
end;
PFixedArray = ^TFixedArray;
TFixedArray = array [0..0] of TFixed;
PArrayOfFixed = ^TArrayOfFixed;
TArrayOfFixed = array of TFixed;
PArrayOfArrayOfFixed = ^TArrayOfArrayOfFixed;
TArrayOfArrayOfFixed = array of TArrayOfFixed;
// TFloat determines the precision level for certain floating-point operations
PFloat = ^TFloat;
TFloat = Single;
{ Other dynamic arrays }
type
PByteArray = ^TByteArray;
TByteArray = array [0..0] of Byte;
PArrayOfByte = ^TArrayOfByte;
TArrayOfByte = array of Byte;
PWordArray = ^TWordArray;
TWordArray = array [0..0] of Word;
PArrayOfWord = ^TArrayOfWord;
TArrayOfWord = array of Word;
PIntegerArray = ^TIntegerArray;
TIntegerArray = array [0..0] of Integer;
PArrayOfInteger = ^TArrayOfInteger;
TArrayOfInteger = array of Integer;
PArrayOfArrayOfInteger = ^TArrayOfArrayOfInteger;
TArrayOfArrayOfInteger = array of TArrayOfInteger;
PSingleArray = ^TSingleArray;
TSingleArray = array [0..0] of Single;
PArrayOfSingle = ^TArrayOfSingle;
TArrayOfSingle = array of Single;
const
// Fixed point math constants
FixedOne = $10000;
FixedPI = Round(PI * FixedOne);
FixedToFloat = 1/FixedOne;
function Fixed(S: Single): TFixed; overload; {$IFDEF USEINLINING} inline; {$ENDIF}
function Fixed(I: Integer): TFixed; overload; {$IFDEF USEINLINING} inline; {$ENDIF}
{ Points }
type
PPoint = ^TPoint;
{$IFNDEF BCB}
TPoint = {$IFDEF CLX}Types{$ELSE}Windows{$ENDIF}.TPoint;
{$ENDIF}
PPointArray = ^TPointArray;
TPointArray = array [0..0] of TPoint;
PArrayOfPoint = ^TArrayOfPoint;
TArrayOfPoint = array of TPoint;
PArrayOfArrayOfPoint = ^TArrayOfArrayOfPoint;
TArrayOfArrayOfPoint = array of TArrayOfPoint;
PFloatPoint = ^TFloatPoint;
TFloatPoint = record
X, Y: TFloat;
end;
PFloatPointArray = ^TFloatPointArray;
TFloatPointArray = array [0..0] of TFloatPoint;
PArrayOfFloatPoint = ^TArrayOfFloatPoint;
TArrayOfFloatPoint = array of TFloatPoint;
PArrayOfArrayOfFloatPoint = ^TArrayOfArrayOfFloatPoint;
TArrayOfArrayOfFloatPoint = array of TArrayOfFloatPoint;
PFixedPoint = ^TFixedPoint;
TFixedPoint = record
X, Y: TFixed;
end;
PFixedPointArray = ^TFixedPointArray;
TFixedPointArray = array [0..0] of TFixedPoint;
PArrayOfFixedPoint = ^TArrayOfFixedPoint;
TArrayOfFixedPoint = array of TFixedPoint;
PArrayOfArrayOfFixedPoint = ^TArrayOfArrayOfFixedPoint;
TArrayOfArrayOfFixedPoint = array of TArrayOfFixedPoint;
// construction and conversion of point types
function Point(X, Y: Integer): TPoint; overload; {$IFDEF USEINLINING} inline; {$ENDIF}
function Point(const FP: TFloatPoint): TPoint; overload; {$IFDEF USEINLINING} inline; {$ENDIF}
function Point(const FXP: TFixedPoint): TPoint; overload; {$IFDEF USEINLINING} inline; {$ENDIF}
function FloatPoint(X, Y: Single): TFloatPoint; overload; {$IFDEF USEINLINING} inline; {$ENDIF}
function FloatPoint(const P: TPoint): TFloatPoint; overload; {$IFDEF USEINLINING} inline; {$ENDIF}
function FloatPoint(const FXP: TFixedPoint): TFloatPoint; overload; {$IFDEF USEINLINING} inline; {$ENDIF}
function FixedPoint(X, Y: Integer): TFixedPoint; overload; {$IFDEF USEINLINING} inline; {$ENDIF}
function FixedPoint(X, Y: Single): TFixedPoint; overload; {$IFDEF USEINLINING} inline; {$ENDIF}
function FixedPoint(const P: TPoint): TFixedPoint; overload; {$IFDEF USEINLINING} inline; {$ENDIF}
function FixedPoint(const FP: TFloatPoint): TFixedPoint; overload; {$IFDEF USEINLINING} inline; {$ENDIF}
{ Rectangles }
type
{$IFDEF CLX}
PRect = Types.PRect;
TRect = Types.TRect;
{$ELSE}
PRect = Windows.PRect;
TRect = Windows.TRect;
{$ENDIF}
PFloatRect = ^TFloatRect;
TFloatRect = packed record
case Integer of
0: (Left, Top, Right, Bottom: TFloat);
1: (TopLeft, BottomRight: TFloatPoint);
end;
PFixedRect = ^TFixedRect;
TFixedRect = packed record
case Integer of
0: (Left, Top, Right, Bottom: TFixed);
1: (TopLeft, BottomRight: TFixedPoint);
end;
TRectRounding = (rrClosest, rrOutside, rrInside);
// Rectangle construction/conversion functions
function MakeRect(const L, T, R, B: Integer): TRect; overload; {$IFDEF USEINLINING} inline; {$ENDIF}
function MakeRect(const FR: TFloatRect; Rounding: TRectRounding = rrClosest): TRect; overload;
function MakeRect(const FXR: TFixedRect; Rounding: TRectRounding = rrClosest): TRect; overload;
function FixedRect(const L, T, R, B: TFixed): TFixedRect; overload; {$IFDEF USEINLINING} inline; {$ENDIF}
function FixedRect(const ARect: TRect): TFixedRect; overload; {$IFDEF USEINLINING} inline; {$ENDIF}
function FixedRect(const FR: TFloatRect): TFixedRect; overload; {$IFDEF USEINLINING} inline; {$ENDIF}
function FloatRect(const L, T, R, B: TFloat): TFloatRect; overload; {$IFDEF USEINLINING} inline; {$ENDIF}
function FloatRect(const ARect: TRect): TFloatRect; overload; {$IFDEF USEINLINING} inline; {$ENDIF}
function FloatRect(const FXR: TFixedRect): TFloatRect; overload; {$IFDEF USEINLINING} inline; {$ENDIF}
// Some basic operations over rectangles
function IntersectRect(out Dst: TRect; const R1, R2: TRect): Boolean; overload;
function IntersectRect(out Dst: TFloatRect; const FR1, FR2: TFloatRect): Boolean; overload;
function UnionRect(out Rect: TRect; const R1, R2: TRect): Boolean; overload;
function UnionRect(out Rect: TFloatRect; const R1, R2: TFloatRect): Boolean; overload;
function EqualRect(const R1, R2: TRect): Boolean; {$IFDEF USEINLINING} inline; {$ENDIF}
procedure InflateRect(var R: TRect; Dx, Dy: Integer); overload; {$IFDEF USEINLINING} inline; {$ENDIF}
procedure InflateRect(var FR: TFloatRect; Dx, Dy: TFloat); overload; {$IFDEF USEINLINING} inline; {$ENDIF}
procedure OffsetRect(var R: TRect; Dx, Dy: Integer); overload; {$IFDEF USEINLINING} inline; {$ENDIF}
procedure OffsetRect(var FR: TFloatRect; Dx, Dy: TFloat); overload; {$IFDEF USEINLINING} inline; {$ENDIF}
function IsRectEmpty(const R: TRect): Boolean; overload; {$IFDEF USEINLINING} inline; {$ENDIF}
function IsRectEmpty(const FR: TFloatRect): Boolean; overload; {$IFDEF USEINLINING} inline; {$ENDIF}
function PtInRect(const R: TRect; const P: TPoint): Boolean; {$IFDEF USEINLINING} inline; {$ENDIF}
function EqualRectSize(const R1, R2: TRect): Boolean; overload; {$IFDEF USEINLINING} inline; {$ENDIF}
function EqualRectSize(const R1, R2: TFloatRect): Boolean; overload; {$IFDEF USEINLINING} inline; {$ENDIF}
type
{$IFDEF CLX}
HBITMAP = QImageH;
HDC = QPainterH;
HFont = QFontH;
{$ENDIF}
{ TBitmap32 draw mode }
TDrawMode = (dmOpaque, dmBlend, dmCustom, dmTransparent);
TCombineMode = (cmBlend, cmMerge);
TWrapMode = (wmClamp, wmRepeat, wmMirror);
{$IFDEF DEPRECATEDMODE}
{ Stretch filters }
TStretchFilter = (sfNearest, sfDraft, sfLinear, sfCosine, sfSpline,
sfLanczos, sfMitchell);
{$ENDIF}
{ Gamma bias for line/pixel antialiasing }
var
GAMMA_TABLE: array [Byte] of Byte;
Interpolator: function(WX_256, WY_256: Cardinal; C11, C21: PColor32): TColor32;
procedure SetGamma(Gamma: Single = 0.7);
{$IFDEF CLX}
{ TextOut Flags for WinAPI compatibility }
const
DT_LEFT = Integer(AlignmentFlags_AlignLeft);
DT_RIGHT = Integer(AlignmentFlags_AlignRight);
DT_TOP = Integer(AlignmentFlags_AlignTop);
DT_BOTTOM = Integer(AlignmentFlags_AlignBottom);
DT_CENTER = Integer(AlignmentFlags_AlignHCenter);
DT_VCENTER = Integer(AlignmentFlags_AlignVCenter);
DT_EXPANDTABS = Integer(AlignmentFlags_ExpandTabs);
DT_NOCLIP = Integer(AlignmentFlags_DontClip);
DT_WORDBREAK = Integer(AlignmentFlags_WordBreak);
DT_SINGLELINE = Integer(AlignmentFlags_SingleLine);
{ missing since there is no QT equivalent:
DT_CALCRECT (makes no sense with TBitmap32.TextOut[2])
DT_EDITCONTOL
DT_END_ELLIPSIS and DT_PATH_ELLIPSIS
DT_EXTERNALLEADING
DT_MODIFYSTRING
DT_NOPREFIX
DT_RTLREADING
DT_TABSTOP
}
{$ENDIF}
type
{ TNotifiablePersistent }
{ TNotifiablePersistent provides a change notification mechanism }
TNotifiablePersistent = class(TPersistent)
private
FUpdateCount: Integer;
FOnChange: TNotifyEvent;
protected
property UpdateCount: Integer read FUpdateCount;
public
procedure Changed; virtual;
procedure BeginUpdate; virtual;
procedure EndUpdate; virtual;
property OnChange: TNotifyEvent read FOnChange write FOnChange;
end;
{ TThreadPersistent }
{ TThreadPersistent is an ancestor for TBitmap32 object. In addition to
TPersistent methods, it provides thread-safe locking and change notification }
TThreadPersistent = class(TNotifiablePersistent)
private
FLock: TRTLCriticalSection;
FLockCount: Integer;
protected
property LockCount: Integer read FLockCount;
public
constructor Create; virtual;
destructor Destroy; override;
procedure Lock;
procedure Unlock;
end;
{ TCustomMap }
{ An ancestor for bitmaps and similar 2D distributions wich have width and
height properties }
TCustomMap = class(TThreadPersistent)
private
FHeight: Integer;
FWidth: Integer;
FOnResize: TNotifyEvent;
procedure SetHeight(NewHeight: Integer);
procedure SetWidth(NewWidth: Integer);
protected
procedure ChangeSize(var Width, Height: Integer; NewWidth, NewHeight: Integer); virtual;
public
procedure Delete; virtual;
function Empty: Boolean; virtual;
procedure Resized; virtual;
function SetSizeFrom(Source: TPersistent): Boolean;
function SetSize(NewWidth, NewHeight: Integer): Boolean; virtual;
property Height: Integer read FHeight write SetHeight;
property Width: Integer read FWidth write SetWidth;
property OnResize: TNotifyEvent read FOnResize write FOnResize;
end;
{ TBitmap32 }
{ This is the core of Graphics32 unit. The TBitmap32 class is responsible
for storage of a bitmap, as well as for drawing in it.
The OnCombine event is fired only when DrawMode is set to dmCustom and two
bitmaps are blended together. Unlike most normal events, it does not contain
"Sender" parameter and is not called through some virtual method. This
(a little bit non-standard) approach allows for faster operation. }
const
// common cases
AREAINFO_RECT = $80000000;
AREAINFO_LINE = $40000000; // 24 bits for line width in pixels...
AREAINFO_ELLIPSE = $20000000;
AREAINFO_ABSOLUTE = $10000000;
AREAINFO_MASK = $FF000000;
type
TPixelCombineEvent = procedure(F: TColor32; var B: TColor32; M: TColor32) of object;
TAreaChangedEvent = procedure(Sender: TObject; const Area: TRect;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -