mirror of
http://gitlab.expertsoft.com.ua/git/expertcad
synced 2026-01-11 22:45:39 +02:00
3174 lines
88 KiB
ObjectPascal
3174 lines
88 KiB
ObjectPascal
unit PaintForm;
|
|
|
|
interface
|
|
|
|
uses
|
|
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
|
|
ExtCtrls, ComCtrls, ToolWin, Menus, Grids, StdCtrls, ImgList, jpeg,
|
|
ExtDlgs,Math, Spin,imgfx, Buttons,ClipBrd;
|
|
|
|
type
|
|
|
|
pRGBArray = ^TRGBArray; // Use SysUtils.pByteArray for 8-bit color
|
|
TRGBArray = ARRAY[0..32767] OF TRGBTriple;
|
|
TDoublePoint = record
|
|
x: Double;
|
|
y: Double;
|
|
end;
|
|
|
|
TBmpLayer = class(TObject)
|
|
Name: String;
|
|
Source: TBitmap;
|
|
Bitmap: TBitmap;
|
|
p1,p2,p3,p4: TPoint;
|
|
Opaq: Integer;
|
|
Transparent: Boolean;
|
|
Visible: Boolean;
|
|
SelMode: Integer;
|
|
Skewed: Boolean;
|
|
Rotated: Boolean;
|
|
Scaled: Boolean;
|
|
Procedure Move(dx,dy:Integer);
|
|
Procedure Modify(mIndex: Integer);
|
|
Procedure Scale(mIndex:Integer; perx,pery: Double);
|
|
Function Duplicate: TBmpLayer;
|
|
Destructor Destroy;
|
|
end;
|
|
|
|
TSelObject = class(TMyObject)
|
|
xType: Integer; //1:rect 2:ellipse 3:polygon
|
|
CMode: Integer;
|
|
pCount: Integer;
|
|
points: array of TPoint;
|
|
Constructor Create(aType,aMode:Integer);
|
|
Procedure AddPoint(pt:TPoint);
|
|
Destructor destroy;
|
|
end;
|
|
|
|
TfrmPaint = class(TForm)
|
|
scmain: TScrollBox;
|
|
Panel1: TPanel;
|
|
Panel2: TPanel;
|
|
Panel3: TPanel;
|
|
ScrollBox2: TScrollBox;
|
|
Panel6: TPanel;
|
|
scH: TScrollBar;
|
|
scV: TScrollBar;
|
|
pc: TPageControl;
|
|
TabSheet1: TTabSheet;
|
|
TabSheet2: TTabSheet;
|
|
lGrid: TStringGrid;
|
|
Panel5: TPanel;
|
|
pBox: TPaintBox;
|
|
Panel4: TPanel;
|
|
Panel7: TPanel;
|
|
Label1: TLabel;
|
|
Label2: TLabel;
|
|
ImageList1: TImageList;
|
|
ImageList2: TImageList;
|
|
TabSheet3: TTabSheet;
|
|
ToolBar2: TToolBar;
|
|
ToolButton8: TToolButton;
|
|
ToolButton7: TToolButton;
|
|
ToolButton9: TToolButton;
|
|
ToolButton10: TToolButton;
|
|
ToolButton13: TToolButton;
|
|
ToolButton16: TToolButton;
|
|
ToolButton14: TToolButton;
|
|
ToolButton15: TToolButton;
|
|
Panel8: TPanel;
|
|
ScrollBox3: TScrollBox;
|
|
Panel9: TPanel;
|
|
Shape1: TShape;
|
|
ColorDialog1: TColorDialog;
|
|
Button1: TButton;
|
|
chRatio: TCheckBox;
|
|
opd: TOpenPictureDialog;
|
|
Image1: TImage;
|
|
TabSheet4: TTabSheet;
|
|
chLayer: TCheckBox;
|
|
Label3: TLabel;
|
|
Bevel1: TBevel;
|
|
tblayer: TTrackBar;
|
|
Label4: TLabel;
|
|
Edit1: TEdit;
|
|
Label5: TLabel;
|
|
ToolBar3: TToolBar;
|
|
lb1: TToolButton;
|
|
lb2: TToolButton;
|
|
lb3: TToolButton;
|
|
lb4: TToolButton;
|
|
ToolButton20: TToolButton;
|
|
ToolButton21: TToolButton;
|
|
ToolBar5: TToolBar;
|
|
ToolButton24: TToolButton;
|
|
lb5: TToolButton;
|
|
lb6: TToolButton;
|
|
lb7: TToolButton;
|
|
ToolButton30: TToolButton;
|
|
lb8: TToolButton;
|
|
lb9: TToolButton;
|
|
pnOptions: TPanel;
|
|
PageControl2: TPageControl;
|
|
TabSheet5: TTabSheet;
|
|
TabSheet6: TTabSheet;
|
|
pnPen: TPanel;
|
|
pnBrush: TPanel;
|
|
cbFHand: TCheckBox;
|
|
spPen: TSpinEdit;
|
|
Label6: TLabel;
|
|
bGrid: TStringGrid;
|
|
ToolButton25: TToolButton;
|
|
mEdit1: TEdit;
|
|
mEdit2: TEdit;
|
|
cmbFilter: TComboBox;
|
|
tbEffect: TTrackBar;
|
|
Label7: TLabel;
|
|
Button2: TButton;
|
|
Shape2: TShape;
|
|
pbFilter: TPaintBox;
|
|
lb10: TToolButton;
|
|
SpeedButton1: TSpeedButton;
|
|
SpeedButton2: TSpeedButton;
|
|
ToolBar1: TToolBar;
|
|
ToolButton2: TToolButton;
|
|
ToolButton3: TToolButton;
|
|
ToolButton4: TToolButton;
|
|
ToolButton5: TToolButton;
|
|
procedure Shape1MouseUp(Sender: TObject; Button: TMouseButton;
|
|
Shift: TShiftState; X, Y: Integer);
|
|
procedure pBoxPaint(Sender: TObject);
|
|
procedure ToolButton8Click(Sender: TObject);
|
|
procedure Button1Click(Sender: TObject);
|
|
procedure medit1Change(Sender: TObject);
|
|
procedure medit2Change(Sender: TObject);
|
|
procedure FormCreate(Sender: TObject);
|
|
procedure ToolButton1Click(Sender: TObject);
|
|
procedure lGridDrawCell(Sender: TObject; ACol, ARow: Integer;
|
|
Rect: TRect; State: TGridDrawState);
|
|
procedure lGridClick(Sender: TObject);
|
|
procedure chLayerClick(Sender: TObject);
|
|
procedure tblayerChange(Sender: TObject);
|
|
procedure Edit1Change(Sender: TObject);
|
|
procedure pBoxMouseDown(Sender: TObject; Button: TMouseButton;
|
|
Shift: TShiftState; X, Y: Integer);
|
|
procedure pBoxMouseMove(Sender: TObject; Shift: TShiftState; X,
|
|
Y: Integer);
|
|
procedure pBoxMouseUp(Sender: TObject; Button: TMouseButton;
|
|
Shift: TShiftState; X, Y: Integer);
|
|
procedure lGridMouseDown(Sender: TObject; Button: TMouseButton;
|
|
Shift: TShiftState; X, Y: Integer);
|
|
procedure lb4Click(Sender: TObject);
|
|
procedure lb1Click(Sender: TObject);
|
|
procedure lb2Click(Sender: TObject);
|
|
procedure lb3Click(Sender: TObject);
|
|
procedure lGridMouseMove(Sender: TObject; Shift: TShiftState; X,
|
|
Y: Integer);
|
|
procedure lGridMouseUp(Sender: TObject; Button: TMouseButton;
|
|
Shift: TShiftState; X, Y: Integer);
|
|
procedure lGridDragOver(Sender, Source: TObject; X, Y: Integer;
|
|
State: TDragState; var Accept: Boolean);
|
|
procedure lGridDragDrop(Sender, Source: TObject; X, Y: Integer);
|
|
procedure scmainResize(Sender: TObject);
|
|
procedure FormKeyUp(Sender: TObject; var Key: Word;
|
|
Shift: TShiftState);
|
|
procedure scVChange(Sender: TObject);
|
|
procedure scHChange(Sender: TObject);
|
|
procedure lb6Click(Sender: TObject);
|
|
procedure lb7Click(Sender: TObject);
|
|
procedure lb5Click(Sender: TObject);
|
|
procedure lb8Click(Sender: TObject);
|
|
procedure lb9Click(Sender: TObject);
|
|
procedure bGridDrawCell(Sender: TObject; ACol, ARow: Integer;
|
|
Rect: TRect; State: TGridDrawState);
|
|
procedure FormKeyDown(Sender: TObject; var Key: Word;
|
|
Shift: TShiftState);
|
|
procedure mEdit1KeyPress(Sender: TObject; var Key: Char);
|
|
procedure pcChange(Sender: TObject);
|
|
procedure pbFilterPaint(Sender: TObject);
|
|
procedure cmbFilterChange(Sender: TObject);
|
|
procedure tbEffectChange(Sender: TObject);
|
|
procedure Button2Click(Sender: TObject);
|
|
procedure lb10Click(Sender: TObject);
|
|
procedure SpeedButton1Click(Sender: TObject);
|
|
procedure SpeedButton2Click(Sender: TObject);
|
|
procedure ToolButton2Click(Sender: TObject);
|
|
procedure ToolButton5Click(Sender: TObject);
|
|
procedure ToolButton3Click(Sender: TObject);
|
|
procedure ToolButton4Click(Sender: TObject);
|
|
procedure FormDestroy(Sender: TObject);
|
|
private
|
|
{ Private declarations }
|
|
Procedure DrawSel;
|
|
Procedure DrawTempSel;
|
|
Procedure DrawTempPolygon;
|
|
Function CreatePolyRegion(pList:array of TPoint;scaled: Boolean):HRGN;
|
|
Procedure PolyPointsToSelObj(sObj:TSelObject);
|
|
Procedure ClearPointLists;
|
|
Procedure AddSelPoint(pt:TPoint);
|
|
Procedure SelectLayerBounds;
|
|
Function CheckModPoint(x,y:Integer):Integer;
|
|
Procedure HandleMod(x,y:Integer);
|
|
Procedure ModifyPoints(x,y:Integer);
|
|
Procedure BlankLayer;
|
|
Procedure FlattenImage;
|
|
Procedure MergeVisible;
|
|
Procedure Clearlayers;
|
|
Procedure LayerFix;
|
|
public
|
|
{ Public declarations }
|
|
mp: Integer;
|
|
rpx,rpy: Integer;
|
|
rotPoint: TPoint;
|
|
LockScroll: Boolean;
|
|
SelVisible:Boolean;
|
|
MGridDown : Boolean;
|
|
isMod: Boolean;
|
|
mgx,mgy: Integer;
|
|
ClickIndex: Integer;
|
|
SelRgn: HRGN;
|
|
mvx,mvy: Integer;
|
|
isMoving: Boolean;
|
|
Layers: TList;
|
|
CommandId: Integer;
|
|
SelMode: Integer;
|
|
Ratio: Double;
|
|
lock1,lock2: Boolean;
|
|
cLayer: TBmpLayer;
|
|
rp1,trp1: Tpoint;
|
|
rp2,trp2,trp3,trp4: Tpoint;
|
|
dw,dh: Integer;
|
|
PointList: Array of TPoint;
|
|
tPointList: Array of TPoint;
|
|
SelLayer: Integer;
|
|
SelObjects: TList;
|
|
SelModified : Boolean;
|
|
locx : Integer;
|
|
locy : Integer;
|
|
Procedure DrawBuffer(hasback:Boolean=True);
|
|
Function EditBitmap(var xBmp:Tbitmap;mStream:TStream):Boolean;
|
|
Function NewLayer(bmp: TBitmap;lName:String;x:Integer = 0;y:Integer=0):TBmpLayer;
|
|
Procedure InsertBitmap;
|
|
Procedure ShowLayerOptions;
|
|
Procedure HandleCommand(x,y:Integer;up:Boolean; shift: TShiftState);
|
|
Procedure KillSelections;
|
|
Function CreateSelRegion(Scaled: Boolean = True):HRGN;
|
|
Procedure MoveSelObjects(dx,dy:Integer);
|
|
Procedure ClearSelObjects;
|
|
Procedure DrawlayerSel;
|
|
Procedure DrawLine(x1,y1,x2,y2: Integer);
|
|
Procedure DrawFreeHand;
|
|
Procedure DrawFreeBrush;
|
|
Function GetBSize: Integer;
|
|
Function bCircle:Boolean;
|
|
Function GetBmpColor(x,y:Integer; var cl: TColor):Boolean;
|
|
Procedure BucketFill(x,y:Integer);
|
|
Function GetFilterBitmap: TBitmap;
|
|
Function GetSelBitmap: TBitmap;
|
|
Procedure RedrawFilter;
|
|
Procedure ApplyFilter;
|
|
Procedure SaveToStream(mStream:Tstream);
|
|
Procedure LoadFromStream(mStream:TStream);
|
|
Procedure CopySelection;
|
|
Procedure PasteFromCBoard;
|
|
Procedure CutSelection;
|
|
Procedure ClearSelection;
|
|
end;
|
|
|
|
|
|
function BitmapToRegion(Bitmap: TBitmap; TransColor: TColor;dx,dy:Integer;selList:TList): HRGN;
|
|
Procedure DrawGlassBitmap(BCanvas: TBitmap; FBitmap:TBitmap; sx,sy,Transity: Integer;
|
|
FTransColor: TColor;isTrans: Boolean);
|
|
Procedure ConvertPoint(var x,y: Integer);
|
|
Procedure DeConvertPoint(var x,y: Integer);
|
|
Procedure RotateBitmap(var BitmapOriginal,BitmapRotated: TBitmap; Teta: Double; isTrans: Boolean);
|
|
Function SkewBitmap(p1,p2,p3,p4: TPoint; pic: TBitmap; var ResultBmp: TBitmap;isTrans:Boolean): Boolean;
|
|
Function RotatePoint(cpoint, opoint: Tpoint; ang: real):TPoint;
|
|
Function ScalePoint(cpoint, opoint: Tpoint; px,py: real):TPoint;
|
|
Function MPoint(p1,p2:TPoint):TPoint;
|
|
Function MVPoint(p:TPoint;dy:Integer):TPoint;
|
|
Function MHPoint(p:TPoint;dx:Integer):TPoint;
|
|
Function MXPoint(p:TPoint;dx,dy:Integer):TPoint;
|
|
Function GetRadOfLine(cp,p: TPoint):Real;
|
|
Function GetLineSegmentPoint(p1,p2:TDoublePoint; ratio: double):TDoublePoint;overload;
|
|
Function GetLineSegmentPoint(p1,p2:TPoint; ratio: double):TDoublePoint;overload;
|
|
Function DP2P(pt:TDoublepoint):TPoint;
|
|
function GetLineLenght(p1,p2: TPoint):Real;
|
|
Function ReadStringFromStream(Stream:TStream):String;
|
|
Procedure WriteString(Stream:TStream; str:string);
|
|
|
|
|
|
var
|
|
frmPaint: TfrmPaint;
|
|
Buffer,temp: TBitmap;
|
|
Scale: Integer;
|
|
dy,dx: Integer;
|
|
mp1,mp2,mp3,mp4: TPoint;
|
|
op1,op2,op3,op4: TPoint;
|
|
oPanel: TPanel;
|
|
px,py: Integer;
|
|
FilterBitmap,FilteredBmp : Tbitmap;
|
|
FilterRgn: HRGN;
|
|
|
|
implementation
|
|
|
|
const
|
|
crZoomp = crDefault + 31;
|
|
crZoomm = crDefault + 32;
|
|
crPen = crDefault + 33;
|
|
crBrush = crDefault + 35;
|
|
crBucket = crDefault + 36;
|
|
crDropper = crDefault + 37;
|
|
crPan = crDefault + 38;
|
|
crMove = crDefault + 39;
|
|
crMoveS = crDefault + 40;
|
|
crCrossp = crDefault + 41;
|
|
crCrossm = crDefault + 42;
|
|
crCrossn = crDefault + 43;
|
|
|
|
|
|
{$R *.DFM}
|
|
{$R *.RES}
|
|
|
|
{ TfrmPaint }
|
|
|
|
Function TfrmPaint.EditBitmap(var xBmp:Tbitmap; mStream: TStream):Boolean;
|
|
var orgBmp: TBitmap;
|
|
BackBmp: TBitmap;
|
|
begin
|
|
pc.ActivePageIndex := 0;
|
|
pc.Height := 110;
|
|
tabsheet2.DoubleBuffered := True;
|
|
cmbFilter.ItemIndex := 0;
|
|
Scale := 100;
|
|
mvx := 0;
|
|
mvy := 0;
|
|
mp := 0;
|
|
isMoving := False;
|
|
SelVisible := True;
|
|
LockScroll := False;
|
|
scmain.DoubleBuffered := True;
|
|
isMod := False;
|
|
oPanel := nil;
|
|
lock1 := true;
|
|
lock2 := true;
|
|
cLayer := nil;
|
|
lGrid.RowCount := 0;
|
|
cLayer := nil;
|
|
SelModified := False;
|
|
locx := 0;
|
|
locy := 0;
|
|
ClickIndex := 0;
|
|
OrgBmp := nil;
|
|
Buffer:= nil;
|
|
FilterBitmap := nil;
|
|
FilteredBmp := nil;
|
|
if assigned(mStream) then begin
|
|
LoadFromStream(mStream);
|
|
end else if assigned(xBmp) then begin
|
|
OrgBmp := TBitmap.Create;
|
|
orgBmp.Width := xBmp.Width;
|
|
orgBmp.Height := xBmp.Height;
|
|
medit1.Text := inttostr(orgbmp.width);
|
|
medit2.Text := inttostr(orgbmp.height);
|
|
orgbmp.canvas.Draw(0,0,xBmp);
|
|
end else begin
|
|
medit1.Text := '500';
|
|
medit2.Text := '500';
|
|
end;
|
|
|
|
if assigned(OrgBmp) then begin
|
|
BackBmp := TBitmap.Create;
|
|
BackBmp.Width := strtoint(medit1.Text);
|
|
BackBmp.Height := strtoint(medit2.Text);
|
|
BackBmp.Canvas.Draw(0,0,orgBmp);
|
|
NewLayer(BackBmp,'BackGround');
|
|
end;
|
|
|
|
bGrid.Row := 0;
|
|
bGrid.Col := 0;
|
|
FilterBitmap := Tbitmap.Create;
|
|
FilterBitmap.Width := 200;
|
|
FilterBitmap.Height := 200;
|
|
FilteredBmp := Tbitmap.Create;
|
|
FilteredBmp.Width := 200;
|
|
FilteredBmp.Height := 200;
|
|
|
|
CommandId := 1;
|
|
pbox.Cursor := crMove;
|
|
SelObjects := TList.Create;
|
|
Buffer := TBitmap.Create;
|
|
Buffer.Width := strtoint(medit1.Text);
|
|
Buffer.Height := strtoint(medit2.Text);
|
|
Buffer.PixelFormat := pf24bit;
|
|
Temp := TBitmap.Create;
|
|
Temp.Width := strtoint(medit1.Text);
|
|
Temp.Height := strtoint(medit2.Text);
|
|
Temp.PixelFormat := pf24bit;
|
|
|
|
drawbuffer;
|
|
|
|
ratio := strtoint(medit1.Text) / strtoint(medit1.Text);
|
|
lock1 := false;
|
|
lock2 := false;
|
|
SelRgn := 0;
|
|
ShowLayerOptions;
|
|
SelLayer := -1;
|
|
MGridDown := False;
|
|
|
|
ShowModal;
|
|
if ModalResult = mrOk then
|
|
begin
|
|
if Layers.Count > 0 then begin
|
|
DrawBuffer(False);
|
|
if not assigned(xBmp) then xBmp := Tbitmap.Create;
|
|
xbmp.Width := Buffer.Width;
|
|
xBmp.Height := Buffer.Height;
|
|
xBmp.Canvas.Draw(0,0,Buffer);
|
|
result := true;
|
|
end;
|
|
end;
|
|
if assigned(orgBmp) then begin
|
|
orgBmp.free;
|
|
end;
|
|
|
|
end;
|
|
|
|
procedure TfrmPaint.Shape1MouseUp(Sender: TObject; Button: TMouseButton;
|
|
Shift: TShiftState; X, Y: Integer);
|
|
begin
|
|
colordialog1.color := shape1.brush.color;
|
|
if colordialog1.Execute then begin
|
|
shape1.Brush.color := colordialog1.color;
|
|
Self.BringToFront;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmPaint.pBoxPaint(Sender: TObject);
|
|
var pw,ph: Integer;
|
|
Procedure CalculateScrolls;
|
|
begin
|
|
scH.Visible := (dw > pw);
|
|
scV.Visible := (dh > ph);
|
|
if scH.Visible then begin
|
|
sch.Min := 0;
|
|
sch.Max := dw-pw;
|
|
sch.Position := 0;
|
|
end;
|
|
if scV.Visible then begin
|
|
scv.Min := 0;
|
|
scv.Max := dh-ph;
|
|
scv.Position := 0;
|
|
end;
|
|
end;
|
|
begin
|
|
Temp.Canvas.Draw(0,0,Buffer);
|
|
pW := pbox.width;
|
|
ph := pbox.height;
|
|
dw := Round(Buffer.Width* (Scale/100));
|
|
dh := Round(Buffer.Height* (Scale/100));
|
|
|
|
if dw >= pw then dx := 0 else dx := (pw-dw) div 2;
|
|
if dh >= ph then dy := 0 else dy := (ph-dh) div 2;
|
|
|
|
if SelModified then
|
|
begin
|
|
lockScroll := True;
|
|
CalculateScrolls;
|
|
DeConvertPoint(locx,locy);
|
|
if dx = 0 then begin
|
|
dx := (pw div 2) - locx;
|
|
if dx < -(scH.Max) then dx := -(sch.Max);
|
|
if dx > 0 then dx := 0;
|
|
sch.Position := -dx;
|
|
end;
|
|
if dy = 0 then begin
|
|
dy := (ph div 2) - locy;
|
|
if dy < -(scV.Max) then dy := -(scV.Max);
|
|
if dy > 0 then dy := 0;
|
|
scv.Position := -dy;
|
|
end;
|
|
lockScroll := False;
|
|
end else begin
|
|
if dx = 0 then dx := -(scH.Position);
|
|
if dy = 0 then dy := -(scV.Position);
|
|
end;
|
|
pbox.Canvas.StretchDraw(Rect(dx,dy,dx+dw,dy+dh),Temp);
|
|
if SelModified then begin
|
|
DeleteObject(SelRgn);
|
|
selRgn := CreateSelRegion(true);
|
|
SelModified := False;
|
|
SelVisible := True;
|
|
RedrawFilter;
|
|
end;
|
|
if selVisible then DrawSel;
|
|
DrawLayerSel;
|
|
end;
|
|
|
|
procedure TfrmPaint.ToolButton8Click(Sender: TObject);
|
|
begin
|
|
CommandId := TToolButton(Sender).Tag;
|
|
if assigned(oPanel) then oPanel.Visible := False;
|
|
Case CommandId of
|
|
4: oPanel := pnBrush;
|
|
5: oPanel := pnPen;
|
|
else oPanel := nil;
|
|
end;
|
|
if assigned(oPanel) then
|
|
begin
|
|
oPanel.Parent := pnOptions;
|
|
oPanel.Visible := True;
|
|
end;
|
|
|
|
case commandId of
|
|
1: pbox.Cursor := crMove;
|
|
2: pbox.Cursor := crCrossn;
|
|
3: pbox.Cursor := crCrossn;
|
|
4: pbox.Cursor := crBrush;
|
|
5: pbox.Cursor := crPen;
|
|
6: pbox.Cursor := crDropper;
|
|
7: pbox.Cursor := crPan;
|
|
8: pbox.Cursor := crZoomp;
|
|
9: pbox.Cursor := crCrossn;
|
|
10:pbox.Cursor := crBucket;
|
|
else pbox.Cursor := crDefault;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmPaint.pBoxMouseDown(Sender: TObject; Button: TMouseButton;
|
|
Shift: TShiftState; X, Y: Integer);
|
|
begin
|
|
if (CommandId = 1) and (SelLayer <> -1) then
|
|
begin
|
|
mp := CheckModPoint(x,y);
|
|
if mp > 0 then begin
|
|
op1 := mp1;op2 := mp2;op3 := mp3;op4 := mp4;
|
|
rpx := x;
|
|
rpy := y;
|
|
isMod := True;
|
|
DrawTempSel;
|
|
exit;
|
|
end;
|
|
end;
|
|
|
|
if (commandId = 1) or (CommandId = 7) then begin
|
|
isMoving := True;
|
|
mvx := x;
|
|
mvy := y;
|
|
end;
|
|
|
|
if (CommandId = 2) or (CommandId = 3) then begin
|
|
trp1 := point(x,y);
|
|
trp2 := point(x,y);
|
|
end;
|
|
if CommandId = 9 then begin
|
|
ClearPointLists;
|
|
ClickIndex := 1;
|
|
AddSelPoint(Point(x,y));
|
|
end;
|
|
|
|
if (commandId = 5) then begin
|
|
isMoving := True;
|
|
trp1 := point(x,y);
|
|
trp2 := point(x,y);
|
|
if cbFHand.Checked then begin
|
|
ClearPointLists;
|
|
AddselPoint(point(x,y));
|
|
end;
|
|
end;
|
|
|
|
if (commandId = 4) then begin
|
|
isMoving := True;
|
|
trp1 := point(x,y);
|
|
trp2 := point(x,y);
|
|
ClearPointLists;
|
|
AddselPoint(point(x,y));
|
|
end;
|
|
|
|
|
|
ConvertPoint(x,y);
|
|
HandleCommand(x,y,false,shift);
|
|
end;
|
|
|
|
procedure TfrmPaint.Button1Click(Sender: TObject);
|
|
begin
|
|
buffer.width := strtoint(medit1.Text);
|
|
buffer.Height := strtoint(medit2.Text);
|
|
temp.width := Buffer.Width;
|
|
temp.height := Buffer.height;
|
|
ratio := strtoint(medit1.Text)/strtoint(medit2.Text);
|
|
DrawBuffer;
|
|
SelModified := true;
|
|
pbox.refresh;
|
|
end;
|
|
|
|
procedure TfrmPaint.DrawBuffer(hasback:Boolean=True);
|
|
var i: Integer;
|
|
xLayer: TBmpLayer;
|
|
x,y,xMax,xMin,yMax,yMin: Integer;
|
|
dSize: Integer;
|
|
clpRgn: HRGN;
|
|
points: array [0..3] of TPoint;
|
|
gBitmap: Tbitmap;
|
|
begin
|
|
if not assigned(buffer) then exit;
|
|
Buffer.Canvas.Brush.Color := clWhite;
|
|
Buffer.Canvas.Brush.Style := bsSolid;
|
|
Buffer.Canvas.FillRect(rect(0,0,Buffer.Width,Buffer.Height));
|
|
if hasback then begin
|
|
Buffer.Canvas.Brush.Color := RGB(220,220,220);
|
|
x := 0;y := 0;dSize := 10;
|
|
i := 0;
|
|
repeat
|
|
Buffer.Canvas.FillRect(rect(x,y,x+dSize,y+dsize));
|
|
x := x+dsize*2;
|
|
if x > Buffer.Width then begin
|
|
i := i+1;
|
|
if odd(i) then x := dSize else x := 0;
|
|
y := y+(dsize);
|
|
end;
|
|
until y >= Buffer.Height;
|
|
end;
|
|
for i := Layers.Count-1 downto 0 do
|
|
begin
|
|
xLayer := TBmpLayer(layers[i]);
|
|
if xLayer.Visible then begin
|
|
xLayer.Bitmap.Transparent := xLayer.Transparent;
|
|
points[0] := xlayer.p1;points[1] := xlayer.p2;
|
|
points[2] := xlayer.p3;points[3] := xlayer.p4;
|
|
clpRgn := CreatePolygonRgn(points,4,ALTERNATE);
|
|
SelectClipRgn(Buffer.Canvas.Handle,ClpRgn);
|
|
xmax := MaxIntValue([xlayer.p1.x,xlayer.p2.x,xlayer.p3.x,xlayer.p4.x]);
|
|
ymax := MaxIntValue([xlayer.p1.y,xlayer.p2.y,xlayer.p3.y,xlayer.p4.y]);
|
|
xmin := MinIntValue([xlayer.p1.x,xlayer.p2.x,xlayer.p3.x,xlayer.p4.x]);
|
|
ymin := MinIntValue([xlayer.p1.y,xlayer.p2.y,xlayer.p3.y,xlayer.p4.y]);
|
|
|
|
if xLayer.Opaq = 100 then
|
|
Buffer.Canvas.StretchDraw(Rect(xmin,ymin,xmax,ymax),xLayer.Bitmap)
|
|
else begin
|
|
gbitmap := TBitmap.Create;
|
|
gbitmap.Width := xmax-xmin;
|
|
gbitmap.Height := ymax-ymin;
|
|
gbitmap.Canvas.CopyRect(Rect(0,0,gbitmap.Width,gbitmap.Height),Buffer.Canvas,Rect(xmin,ymin,xmax,ymax));
|
|
DrawGlassBitmap(gbitmap,xLayer.Bitmap,0,0,xlayer.Opaq,
|
|
xLayer.Bitmap.Canvas.Pixels[0,Height-1],xLayer.Transparent);
|
|
Buffer.Canvas.StretchDraw(Rect(xmin,ymin,xmax,ymax),gBitmap);
|
|
gbitmap.free;
|
|
end;
|
|
SelectClipRgn(Buffer.Canvas.Handle,0);
|
|
DeleteObject(clprgn);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmPaint.medit1Change(Sender: TObject);
|
|
begin
|
|
if lock1 then exit;
|
|
if medit1.text = '' then medit1.text := '5';
|
|
lock2 := true;
|
|
if (ratio <> 0) and (chRatio.Checked) then
|
|
begin
|
|
medit2.Text := Inttostr(round(StrToInt(medit1.text)/ratio));
|
|
end;
|
|
lock2 := false;
|
|
end;
|
|
|
|
procedure TfrmPaint.medit2Change(Sender: TObject);
|
|
begin
|
|
if lock2 then exit;
|
|
if medit2.text = '' then medit2.text := '5';
|
|
lock1 := true;
|
|
if (chRatio.Checked) then medit1.text := Inttostr(Round(StrToInt(medit2.text)*ratio));
|
|
lock1 := false;
|
|
end;
|
|
|
|
procedure TfrmPaint.FormCreate(Sender: TObject);
|
|
begin
|
|
screen.Cursors[crZoomp] := LoadCursor(HInstance,'CRZOOMP');
|
|
screen.Cursors[crZoomm] := LoadCursor(HInstance,'CRZOOMM');
|
|
screen.Cursors[crPen] := LoadCursor(HInstance,'CRPEN');
|
|
screen.Cursors[crBrush] := LoadCursor(HInstance,'CRBRUSH');
|
|
screen.Cursors[crBucket] := LoadCursor(HInstance,'CRBUCKET');
|
|
screen.Cursors[crDropper] := LoadCursor(HInstance,'CRDROPPER');
|
|
screen.Cursors[crPan] := LoadCursor(HInstance,'CRPAN');
|
|
screen.Cursors[crMove] := LoadCursor(HInstance,'CRMOVE');
|
|
screen.Cursors[crMoveS] := LoadCursor(HInstance,'CRMOVES');
|
|
screen.Cursors[crCrossp] := LoadCursor(HInstance,'CRCROSSP');
|
|
screen.Cursors[crCrossm] := LoadCursor(HInstance,'CRCROSSM');
|
|
screen.Cursors[crCrossn] := LoadCursor(HInstance,'CRCROSSN');
|
|
Layers := TList.Create;
|
|
opd.Filter := GraphicFilter(TGraphic);
|
|
end;
|
|
|
|
Function TfrmPaint.NewLayer(bmp: TBitmap;lName:String;x:Integer = 0;y:Integer=0):TBmpLayer;
|
|
var xlayer: TBmplayer;
|
|
begin
|
|
|
|
xLayer := TBmpLayer.Create;
|
|
xLayer.Source := TBitmap.Create;
|
|
xLayer.Source.Width := bmp.Width;
|
|
xlayer.Source.Height := bmp.Height;
|
|
xLayer.Source.Canvas.Draw(0,0,bmp);
|
|
xLayer.Source.PixelFormat := pf24Bit;
|
|
xlayer.Bitmap := bmp;
|
|
xLayer.Name := lName;
|
|
xLayer.Transparent := False;
|
|
xLayer.Visible := True;
|
|
xLayer.Opaq := 100;
|
|
xLayer.Skewed := False;
|
|
xLayer.Rotated := False;
|
|
xLayer.Scaled := False;
|
|
xLayer.p1 := Point(x,y);
|
|
xLayer.p2 := Point(x+bmp.Width,y);
|
|
xLayer.p3 := Point(x+bmp.Width,y+bmp.Height);
|
|
xLayer.p4 := Point(x,y+bmp.Height);
|
|
xLayer.SelMode := 0;
|
|
Layers.Insert(0,xLayer);
|
|
|
|
lGrid.RowCount := layers.count;
|
|
lGrid.Row := 0;
|
|
Result := xLayer;
|
|
ShowLayerOptions;
|
|
if SelLayer <> -1 then SelLayer := SelLayer+1;
|
|
DrawBuffer;
|
|
end;
|
|
|
|
procedure TfrmPaint.InsertBitmap;
|
|
var TempPic : TPicture;
|
|
Picturename: String;
|
|
LayerBmp: Tbitmap;
|
|
begin
|
|
if OPD.Execute then
|
|
begin
|
|
TempPic := TPicture.Create;
|
|
PictureName := extractFileName(opd.fileName);
|
|
try
|
|
TempPic.LoadFromFile(opd.fileName);
|
|
LayerBmp := TBitmap.Create;
|
|
LayerBmp.Width := TempPic.Graphic.Width;
|
|
LayerBmp.Height := TempPic.Graphic.Height;
|
|
LayerBmp.Canvas.Draw(0,0,TempPic.Graphic);
|
|
LayerBmp.PixelFormat := pf24bit;
|
|
NewLayer(LayerBmp,PictureName);
|
|
DrawBuffer;
|
|
Self.BringToFront;
|
|
pbox.refresh;
|
|
except
|
|
on EInvalidGraphic do
|
|
begin
|
|
ShowMessage('Not a valid picture format');
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmPaint.ToolButton1Click(Sender: TObject);
|
|
begin
|
|
InsertBitmap;
|
|
end;
|
|
|
|
procedure TfrmPaint.lGridDrawCell(Sender: TObject; ACol, ARow: Integer;
|
|
Rect: TRect; State: TGridDrawState);
|
|
var xlayer: TBmplayer;
|
|
procedure drawthumb;
|
|
var ww,hh,w,h,x,y: Integer;
|
|
xRect: Trect;
|
|
begin
|
|
ww := xLayer.Bitmap.Width;
|
|
hh := xLayer.Bitmap.Height;
|
|
if ww > hh then begin
|
|
w := 30;
|
|
h := Round(30* (hh/ww));
|
|
x := 0;
|
|
y := (30 - h) div 2;
|
|
end
|
|
else begin
|
|
h := 30;
|
|
w := Round(30* (ww/hh));
|
|
y := 0;
|
|
x := (30 - w) div 2;
|
|
end;
|
|
lGrid.Canvas.StretchDraw(Classes.rect(rect.left+2+x,rect.top+2+y,rect.left+2+x+w,rect.top+2+y+h),xLayer.Bitmap);
|
|
end;
|
|
begin
|
|
Lgrid.Canvas.Brush.Color := clWhite;
|
|
LGrid.Canvas.Brush.Style := bsSolid;
|
|
Lgrid.Canvas.Fillrect(rect);
|
|
|
|
if Layers.Count = 0 then exit;
|
|
|
|
xLayer := TBmpLayer(Layers[aRow]);
|
|
lGrid.Canvas.Font := lgrid.Font;
|
|
if gdSelected in State then
|
|
begin
|
|
Lgrid.Canvas.Brush.Color := clRed;
|
|
lGrid.Canvas.Font.Color := clWhite;
|
|
end
|
|
|
|
else
|
|
begin
|
|
Lgrid.Canvas.Brush.Color := clWhite;
|
|
lGrid.Canvas.Font.Color := clBlack;
|
|
end;
|
|
LGrid.Canvas.Brush.Style := bsSolid;
|
|
Lgrid.Canvas.Fillrect(rect);
|
|
if acol = 0 then begin
|
|
if xLayer.Visible then
|
|
lGrid.Canvas.Draw(rect.left+2,rect.top+4,image1.picture.bitmap);
|
|
end else if acol = 1 then begin
|
|
DrawThumb;
|
|
lGrid.Canvas.TextOut(rect.left+36,rect.top+4,xLayer.name);
|
|
end;
|
|
LGrid.Canvas.Pen.Color := clBlack;
|
|
LGrid.Canvas.Pen.Style := psSolid;
|
|
LGrid.Canvas.Pen.Width := 1;
|
|
LGrid.Canvas.MoveTo(rect.left,rect.bottom-1);
|
|
LGrid.Canvas.LineTo(rect.right,rect.bottom-1);
|
|
end;
|
|
|
|
procedure TfrmPaint.lGridClick(Sender: TObject);
|
|
begin
|
|
ShowLayerOptions;
|
|
end;
|
|
|
|
procedure TfrmPaint.ShowLayerOptions;
|
|
begin
|
|
//***
|
|
if Layers.Count = 0 then exit;
|
|
if (LGrid.Row > -1) and (lGrid.row < Layers.count) then
|
|
begin
|
|
cLayer := TBmpLayer(layers[lGrid.Row]);
|
|
edit1.Text := cLayer.Name;
|
|
label3.Caption := cLayer.Name + ' Options';
|
|
chLayer.Checked := clayer.Transparent;
|
|
tblayer.Position := cLayer.Opaq;
|
|
edit1.enabled := true;
|
|
chlayer.Enabled := true;
|
|
tbLayer.Enabled := True;
|
|
lb1.Enabled := true;lb2.Enabled := true;
|
|
lb3.Enabled := true;lb4.Enabled := true;
|
|
lb6.Enabled := True;lb7.Enabled := True;
|
|
end else begin
|
|
edit1.Text := '';
|
|
edit1.enabled := false;
|
|
label3.Caption := 'No Layer Selected';
|
|
chLayer.Checked := false;
|
|
chlayer.Enabled := false;
|
|
tbLayer.Position := 100;
|
|
tbLayer.Enabled := False;
|
|
lb1.Enabled := false;lb2.Enabled := false;
|
|
lb3.Enabled := false;lb4.Enabled := false;
|
|
lb6.Enabled := false;lb7.Enabled := false;
|
|
end;
|
|
RedrawFilter;
|
|
end;
|
|
|
|
procedure TfrmPaint.chLayerClick(Sender: TObject);
|
|
begin
|
|
if not assigned(cLayer) then exit;
|
|
cLayer.Transparent := chLayer.Checked;
|
|
DrawBuffer;
|
|
pBox.Refresh;
|
|
lGrid.Refresh;
|
|
end;
|
|
|
|
procedure TfrmPaint.tblayerChange(Sender: TObject);
|
|
begin
|
|
if not assigned(cLayer) then exit;
|
|
cLayer.Opaq := tbLayer.Position;
|
|
DrawBUffer;
|
|
pBox.Refresh;
|
|
end;
|
|
|
|
procedure TfrmPaint.Edit1Change(Sender: TObject);
|
|
begin
|
|
if not assigned(cLayer) then exit;
|
|
cLayer.Name := edit1.text;
|
|
ShowLayerOptions;
|
|
lGrid.Refresh;
|
|
end;
|
|
|
|
procedure TfrmPaint.pBoxMouseMove(Sender: TObject; Shift: TShiftState; X,
|
|
Y: Integer);
|
|
var dpx: Integer;
|
|
dpy: Integer;
|
|
pt1,pt2: TPoint;
|
|
begin
|
|
if isMod then begin
|
|
DrawTempSel;
|
|
ModifyPoints(x,y);
|
|
DrawTempSel;
|
|
end else if isMoving and (CommandId = 1) then begin
|
|
pt1 := Point(mvx,mvy);
|
|
pt2 := Point(x,y);
|
|
ConvertPoint(pt1.x,pt1.y);
|
|
ConvertPoint(pt2.x,pt2.y);
|
|
if ssCtrl in Shift then begin
|
|
if SelRgn <> 0 then begin
|
|
DrawSel;
|
|
MoveSelObjects(pt2.x-pt1.x,pt2.y-pt1.y);
|
|
OffsetRgn(SelRgn,x- mvx,y- mvy);
|
|
DrawSel;
|
|
end;
|
|
end else begin
|
|
if not assigned(cLayer) then exit;
|
|
cLayer.Move(pt2.x-pt1.x,pt2.y-pt1.y);
|
|
DrawBuffer;
|
|
pbox.refresh;
|
|
end;
|
|
mvx := x;
|
|
mvy := y;
|
|
end else if isMoving and (CommandId = 7) then begin
|
|
dpx := x- mvx;
|
|
dpy := y- mvy;
|
|
if (scV.Visible) and (abs(dpy) > 1) then scV.Position := scv.Position - dpy;
|
|
if (scH.Visible) and (abs(dpx) > 1) then scH.Position := scH.Position - dpx;
|
|
mvx := x;
|
|
mvy := y;
|
|
end else if ((ClickIndex = 1) and ((CommandId = 2) or (CommandId = 3))) or isMod then begin
|
|
DrawTempSel;
|
|
trp2 := Point(x,y);
|
|
DrawTempSel;
|
|
end else if (CommandId = 5) and isMoving then begin
|
|
if cbFHand.Checked then begin
|
|
trp1 := trp2;
|
|
trp2 := Point(x,y);
|
|
DrawTempSel;
|
|
AddselPoint(point(x,y));
|
|
end else begin
|
|
DrawTempSel;
|
|
trp2 := Point(x,y);
|
|
DrawTempSel;
|
|
end;
|
|
end else if (CommandId = 4) and isMoving then begin
|
|
trp1 := trp2;
|
|
trp2 := Point(x,y);
|
|
DrawTempSel;
|
|
AddselPoint(point(x,y));
|
|
end else if (ClickIndex > 0) and (CommandId = 9) then begin
|
|
DrawTempSel;
|
|
ClickIndex := ClickIndex+1;
|
|
AddSelPoint(Point(x,y));
|
|
DrawTempSel;
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TfrmPaint.pBoxMouseUp(Sender: TObject; Button: TMouseButton;
|
|
Shift: TShiftState; X, Y: Integer);
|
|
begin
|
|
if ismod then begin
|
|
HandleMod(x,y);
|
|
exit;
|
|
end;
|
|
isMoving := False;
|
|
ConvertPoint(x,y);
|
|
HandleCommand(x,y,true,shift);
|
|
end;
|
|
|
|
procedure TfrmPaint.lGridMouseDown(Sender: TObject; Button: TMouseButton;
|
|
Shift: TShiftState; X, Y: Integer);
|
|
var aRow,aCol: Integer;
|
|
xLayer: TBmpLayer;
|
|
begin
|
|
if layers.count = 0 then exit;
|
|
lGrid.MouseToCell(x,y,aCol,aRow);
|
|
if arow = -1 then exit;
|
|
if (aCol = 0) then begin
|
|
xLayer := TBmpLayer(Layers[arow]);
|
|
xLayer.Visible := not xLayer.Visible;
|
|
lGrid.Refresh;
|
|
DrawBuffer;
|
|
pBox.Refresh;
|
|
end else begin
|
|
mGridDown := true;
|
|
mgx := x;
|
|
mgy := y;
|
|
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmPaint.HandleCommand(x, y: Integer; Up: Boolean;shift: TShiftState);
|
|
var tRgn : HRGN;
|
|
SelObject: TSelObject;
|
|
cMode: Integer;
|
|
bColor:TColor;
|
|
begin
|
|
if (commandId = 8) and Up then begin
|
|
if ssctrl in shift then Scale := scale - 30
|
|
else Scale := Scale+10;
|
|
if scale <= 0 then scale := 10;
|
|
SelModified := True;
|
|
locx := x;
|
|
locy := y;
|
|
pbox.refresh;
|
|
end else if (commandId = 2) then begin
|
|
ClickIndex := ClickIndex+1;
|
|
if not up then begin
|
|
rp1 := Point(x,y);
|
|
rp2 := Point(x,y);
|
|
end
|
|
else if up then begin
|
|
rp2 := Point(x,y);ClickIndex := 0;
|
|
if pbox.Cursor = crCrossp then begin
|
|
cMode := RGN_OR;
|
|
end else if pbox.Cursor = crCrossm then begin
|
|
cMode := RGN_DIFF;
|
|
end else begin
|
|
cMode := 0;
|
|
ClearSelObjects;
|
|
end;
|
|
selObject := TSelObject.Create(1,cMode);
|
|
selObject.AddPoint(rp1);selObject.AddPoint(rp2);
|
|
SelObjects.Add(selObject);
|
|
SelModified := True;
|
|
pBox.refresh;
|
|
end;
|
|
end else if (commandId = 3) then begin
|
|
ClickIndex := ClickIndex+1;
|
|
if not up then begin
|
|
rp1 := Point(x,y);
|
|
rp2 := Point(x,y);
|
|
end
|
|
else if up then begin
|
|
rp2 := Point(x,y);ClickIndex := 0;
|
|
rp2 := Point(x,y);ClickIndex := 0;
|
|
if pbox.Cursor = crCrossp then begin
|
|
cMode := RGN_OR;
|
|
end else if pbox.Cursor = crCrossm then begin
|
|
cMode := RGN_DIFF;
|
|
end else begin
|
|
cMode := 0;
|
|
ClearSelObjects;
|
|
end;
|
|
selObject := TSelObject.Create(2,cMode);
|
|
selObject.AddPoint(rp1);selObject.AddPoint(rp2);
|
|
SelObjects.Add(selObject);
|
|
SelModified := True;
|
|
pBox.refresh;
|
|
end;
|
|
end else if (commandId = 4) then begin
|
|
if up then begin
|
|
DrawFreeBrush;
|
|
LayerFix;
|
|
Drawbuffer;
|
|
pbox.refresh;
|
|
end;
|
|
end else if (commandId = 10) then begin
|
|
if up then begin
|
|
BucketFill(x,y);
|
|
LayerFix;
|
|
Drawbuffer;
|
|
pbox.refresh;
|
|
end;
|
|
|
|
end else if (commandId = 5) then begin
|
|
if not up then begin
|
|
px := x; py := y;
|
|
end else begin
|
|
if not cbFHand.Checked then begin
|
|
DrawLine(px,py,x,y);
|
|
Layerfix;
|
|
Drawbuffer;
|
|
pbox.refresh;
|
|
end else begin
|
|
DrawFreehand;
|
|
LayerFix;
|
|
Drawbuffer;
|
|
pbox.refresh;
|
|
end;
|
|
end;
|
|
end else if (commandId = 6) and up then begin
|
|
if GetBmpColor(x,y,bcolor) then Shape1.Brush.Color := bcolor;
|
|
end else if (commandId = 9) and up then begin
|
|
if pbox.Cursor = crCrossp then begin
|
|
cMode := RGN_OR;
|
|
end else if pbox.Cursor = crCrossm then begin
|
|
cMode := RGN_DIFF;
|
|
end else begin
|
|
cMode := 0;
|
|
ClearSelObjects;
|
|
end;
|
|
selObject := TSelObject.Create(3,cMode);
|
|
PolyPointsToSelObj(selObject);
|
|
SelObjects.Add(selObject);
|
|
SelModified := True;
|
|
ClickIndex := 0;
|
|
pBox.refresh;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmPaint.ClearPointLists;
|
|
begin
|
|
SetLength(PointList,0);
|
|
SetLength(tPointList,0);
|
|
end;
|
|
|
|
type
|
|
PPoints = ^TPoints;
|
|
TPoints = array[0..0] of TPoint;
|
|
// Tolik 04/04/2019
|
|
Function TfrmPaint.CreatePolyRegion(pList: array of TPoint;scaled:Boolean):HRGN;
|
|
var ip: Pointer;
|
|
i,size: Integer;
|
|
p1: TPoint;
|
|
begin
|
|
size := Length(pList);
|
|
GetMem(ip,size*8);
|
|
for i := 0 to size -1 do begin
|
|
p1 := pList[i];
|
|
if scaled then DeConvertPoint(p1.x,p1.y);
|
|
PInt(PAnsiChar(ip)+i*8+0)^:= p1.x;
|
|
PInt(PAnsiChar(ip)+i*8+4)^:= p1.y;
|
|
end;
|
|
Result := CreatePolygonRgn(PPoints(ip)^,size,ALTERNATE);
|
|
FreeMem(ip,size*8);
|
|
end;
|
|
{
|
|
Function TfrmPaint.CreatePolyRegion(pList: array of TPoint;scaled:Boolean):HRGN;
|
|
var ip: Pointer;
|
|
i,size: Integer;
|
|
p1: TPoint;
|
|
begin
|
|
size := Length(pList);
|
|
GetMem(ip,size*8);
|
|
for i := 0 to size -1 do begin
|
|
p1 := pList[i];
|
|
if scaled then DeConvertPoint(p1.x,p1.y);
|
|
|
|
// Tolik 23/04/2019 --
|
|
// PInt(PChar(ip)+i*8+0)^:= p1.x;
|
|
// PInt(PChar(ip)+i*8+4)^:= p1.y;
|
|
PInt(PAnsiChar(ip)+i*8+0)^:= p1.x;
|
|
PInt(PAnsiChar(ip)+i*8+4)^:= p1.y;
|
|
//
|
|
end;
|
|
Result := CreatePolygonRgn(PPoints(ip)^,size,ALTERNATE);
|
|
FreeMem(ip,size*8);
|
|
end;
|
|
}
|
|
procedure TfrmPaint.DrawTempPolygon;
|
|
begin
|
|
pBox.Canvas.PolyLine(tPointList);
|
|
end;
|
|
|
|
|
|
procedure TfrmPaint.DrawSel;
|
|
begin
|
|
pBox.Canvas.Pen.Mode := pmXor;
|
|
pBox.Canvas.Brush.Style := bsSolid;
|
|
pBox.Canvas.Brush.Color := clRed;
|
|
pBox.Canvas.Pen.color := clRed;
|
|
pBox.Canvas.Pen.Style :=psDash;
|
|
FillRgn(pBox.Canvas.Handle,selrgn,pBox.Canvas.Brush.Handle);
|
|
pBox.Canvas.Pen.Mode := pmCopy;
|
|
end;
|
|
|
|
procedure ConvertPoint(var x, y: Integer);
|
|
begin
|
|
x := Round((x-dx)/(scale/100));
|
|
y := Round((y-dy)/(Scale/100));
|
|
end;
|
|
|
|
procedure TfrmPaint.DrawTempSel;
|
|
begin
|
|
pbox.Canvas.Pen.Mode := pmXor;
|
|
pbox.Canvas.Brush.Style := bsClear;
|
|
pbox.Canvas.Pen.color := clLime;
|
|
pbox.Canvas.Pen.Style :=psDash;
|
|
if (CommandId = 1) then begin
|
|
pbox.Canvas.Polygon([mp1,mp2,mp3,mp4]);
|
|
end else if (CommandId = 2)then
|
|
pbox.Canvas.Rectangle(trp1.x,trp1.y,trp2.x,trp2.y)
|
|
else if CommandId = 3 then
|
|
pbox.Canvas.Ellipse(trp1.x,trp1.y,trp2.x,trp2.y)
|
|
else if CommandId = 9 then DrawTempPolygon
|
|
else if (CommandId = 5) or (CommandId = 4) then begin
|
|
pbox.Canvas.MoveTo(trp1.x,trp1.y);
|
|
pbox.Canvas.LineTo(trp2.x,trp2.y);
|
|
end;
|
|
pbox.Canvas.Pen.Mode := pmCopy;
|
|
end;
|
|
|
|
procedure TfrmPaint.AddSelPoint(pt: TPoint);
|
|
var cnt: Integer;
|
|
begin
|
|
cnt := Length(PointList);
|
|
Setlength(PointList,cnt+1);
|
|
Setlength(tPointList,cnt+1);
|
|
tPointList[cnt] := pt;
|
|
ConvertPoint(pt.x,pt.y);
|
|
PointList[cnt] := pt;
|
|
end;
|
|
|
|
function BitmapToRegion(Bitmap: TBitmap; TransColor: TColor;dx,dy:Integer;selList:TList): HRGN;
|
|
var
|
|
X, Y: Integer;
|
|
XStart: Integer;
|
|
SelObject: TSelObject;
|
|
cMode: Integer;
|
|
row: pRGBArray;
|
|
tRGB: TRGBTriple;
|
|
begin
|
|
|
|
Result := 0;
|
|
trgb.rgbtBlue := GEtBValue(TransColor);
|
|
trgb.rgbtRed := GEtRValue(TransColor);
|
|
trgb.rgbtGreen := GEtRValue(TransColor);
|
|
for Y := 0 to Bitmap.Height - 1 do begin
|
|
row := Bitmap.ScanLine[y];
|
|
X := 0;
|
|
while X < Bitmap.Width do begin
|
|
while (X < Bitmap.Width) and (row[X].rgbtBlue = tRgb.rgbtBlue )
|
|
and (row[X].rgbtRed = tRgb.rgbtRed )
|
|
and (row[X].rgbtGreen = tRgb.rgbtGreen )
|
|
do
|
|
Inc(X);
|
|
if X >= Bitmap.Width then
|
|
Break;
|
|
XStart := X;
|
|
while (X < Bitmap.Width) and not ((row[X].rgbtBlue = tRgb.rgbtBlue )
|
|
and (row[X].rgbtRed = tRgb.rgbtRed )
|
|
and (row[X].rgbtGreen = tRgb.rgbtGreen ))
|
|
do
|
|
Inc(X);
|
|
cMode := RGN_OR;
|
|
SelObject := TSelObject.Create(1,cMode);
|
|
SelObject.AddPoint(Point(XStart+dx, Y+dy));
|
|
SelObject.AddPoint(Point(X+dx, Y+dy + 1));
|
|
selList.add(SelObject);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
Procedure DrawGlassBitmap(BCanvas: TBitmap; FBitmap:TBitmap; sx,sy,Transity: Integer; FTransColor: TColor;isTrans: Boolean);
|
|
var
|
|
SL,BL: PRGBArray;
|
|
X, Y: Integer;
|
|
SWidth, SHeight: Integer;
|
|
pix:TRGBTriple;
|
|
trColor : TRGBTriple;
|
|
begin
|
|
SWidth := FBitmap.Width;
|
|
SHeight:= FBitmap.Height;
|
|
FBitmap.PixelFormat := pf24bit;
|
|
BCanvas.PixelFormat := pf24bit;
|
|
SL := FBitmap.ScanLine[SHeight - 1];
|
|
trColor := SL[0];
|
|
|
|
for Y := 0 to SHeight - 1 do begin
|
|
SL := FBitmap.ScanLine[Y];
|
|
if (sy+y < BCanvas.Height) and (sy+y > 0) then begin
|
|
BL := BCanvas.Scanline[sy+Y];
|
|
for X := 0 to SWidth - 1 do begin
|
|
try
|
|
if (sx+x < BCanvas.Width) and (sx+x > 0) then begin
|
|
pix := BL[sx+X];
|
|
if (isTrans) and (SL[x].rgbtBlue = trColor.rgbtBlue )
|
|
and (SL[x].rgbtGreen = trColor.rgbtGreen )
|
|
and (SL[x].rgbtRed = trColor.rgbtRed ) then
|
|
begin
|
|
end else begin
|
|
BL[sx+X].rgbtRed := (Transity * SL[X].rgbtRed + (100 - Transity) * pix.rgbtRed ) div 100;
|
|
BL[sx+X].rgbtGreen := (Transity * SL[X].rgbtGreen + (100 - Transity)* pix.rgbtGreen ) div 100;
|
|
BL[sx+X].rgbtBlue := (Transity * SL[X].rgbtBlue + (100 - Transity) * pix.rgbtBlue ) div 100;
|
|
end;
|
|
end;
|
|
except
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TfrmPaint.lb4Click(Sender: TObject);
|
|
begin
|
|
SelectLayerBounds;
|
|
end;
|
|
|
|
procedure TfrmPaint.SelectLayerBounds;
|
|
var bmp: TBitmap;
|
|
SelObject:TSelObject;
|
|
xMin,yMin:Integer;
|
|
begin
|
|
if not assigned(cLayer) then exit;
|
|
ClearSelObjects;
|
|
SelLayer := -1;
|
|
bmp := cLayer.Bitmap;
|
|
if cLayer.Transparent then begin
|
|
xmin := MinIntValue([clayer.p1.x,clayer.p2.x,cLayer.p3.x,clayer.p4.x]);
|
|
ymin := MinIntValue([clayer.p1.y,clayer.p2.y,cLayer.p3.y,clayer.p4.y]);
|
|
BitmapToRegion(bmp,bmp.Canvas.Pixels[0,bmp.height-1],xMin,yMin,SelObjects);
|
|
SelModified := True;
|
|
pBox.refresh;
|
|
end else begin
|
|
SelObject := tSelObject.Create(3,0);
|
|
SelObject.AddPoint(Point(cLayer.p1.x,cLayer.p1.y));
|
|
SelObject.AddPoint(Point(cLayer.p2.x,cLayer.p2.y));
|
|
SelObject.AddPoint(Point(cLayer.p3.x,cLayer.p3.y));
|
|
SelObject.AddPoint(Point(cLayer.p4.x,cLayer.p4.y));
|
|
SelObjects.add(SelObject);
|
|
SelModified := True;
|
|
pBox.refresh;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmPaint.lb1Click(Sender: TObject);
|
|
begin
|
|
if not assigned(clayer) then exit;
|
|
KillSelections;
|
|
CLayer.SelMode := 1;
|
|
SelMode := 1;
|
|
SelLayer := Layers.IndexOf(CLayer);
|
|
pbox.Refresh;
|
|
end;
|
|
|
|
procedure TfrmPaint.KillSelections;
|
|
var i: Integer;
|
|
xLayer : TBmpLayer;
|
|
begin
|
|
SelLAyer := -1;
|
|
DeleteObject(SelRgn);
|
|
SelRgn := 0;
|
|
for i := 0 to Layers.Count -1 do
|
|
begin
|
|
xLayer := TBmpLayer(Layers[i]);
|
|
xLayer.SelMode := 0;
|
|
end;
|
|
pbox.Refresh;
|
|
end;
|
|
|
|
procedure TfrmPaint.lb2Click(Sender: TObject);
|
|
begin
|
|
if not assigned(clayer) then exit;
|
|
KillSelections;
|
|
CLayer.SelMode := 2;
|
|
SelMode := 2;
|
|
SelLayer := Layers.IndexOf(CLayer);
|
|
pbox.Refresh;
|
|
end;
|
|
|
|
procedure TfrmPaint.lb3Click(Sender: TObject);
|
|
begin
|
|
if not assigned(clayer) then exit;
|
|
KillSelections;
|
|
CLayer.SelMode := 3;
|
|
SelMode := 3;
|
|
SelLayer := Layers.IndexOf(CLayer);
|
|
pbox.Refresh;
|
|
|
|
end;
|
|
|
|
procedure TfrmPaint.PolyPointsToSelObj(sObj: TSelObject);
|
|
var i,size: Integer;
|
|
begin
|
|
size := Length(PointList);
|
|
for i := 0 to size -1 do
|
|
SObj.Addpoint(PointList[i]);
|
|
end;
|
|
|
|
Function TfrmPaint.CreateSelRegion(Scaled: Boolean = True):HRGN;
|
|
var i: Integer;
|
|
selObj: TSelObject;
|
|
xRgn: HRGN;
|
|
p1,p2: TPoint;
|
|
sRgn: HRGN;
|
|
begin
|
|
//**
|
|
sRgn := 0;
|
|
//DeleteObject(SelRgn);
|
|
for i := 0 to SelObjects.Count -1 do
|
|
begin
|
|
selObj := TSelObject(SelObjects[i]);
|
|
case selObj.xType of
|
|
1: begin
|
|
p1 := selObj.Points[0];p2 := selObj.Points[1];
|
|
if scaled then begin
|
|
DeConvertPoint(p1.x,p1.y);DeConvertPoint(p2.x,p2.y);
|
|
end;
|
|
xRgn := CreateRectRgn(p1.x,p1.y,p2.x,p2.y);
|
|
end;
|
|
2: begin
|
|
p1 := selObj.Points[0];p2 := selObj.Points[1];
|
|
if scaled then begin
|
|
DeConvertPoint(p1.x,p1.y);DeConvertPoint(p2.x,p2.y);
|
|
end;
|
|
xRgn := CreateEllipticRgn(p1.x,p1.y,p2.x,p2.y);
|
|
end;
|
|
3: xRgn := CreatePolyRegion(selObj.Points,Scaled);
|
|
end;
|
|
if i = 0 then
|
|
SRgn := xRgn
|
|
else
|
|
begin
|
|
CombineRgn(SRgn,sRgn,xRgn,selObj.cMode);
|
|
DeleteObject(xRgn);
|
|
end;
|
|
end;
|
|
result := sRgn;
|
|
end;
|
|
|
|
procedure TfrmPaint.ClearSelObjects;
|
|
var selObj: TSelObject;
|
|
i: Integer;
|
|
begin
|
|
SelLayer := -1;
|
|
for i := 0 to SelObjects.Count -1 do
|
|
begin
|
|
selObj := TSelObject(SelObjects[i]);
|
|
SetLength(selObj.Points,0);
|
|
selObj.Free;
|
|
end;
|
|
SelObjects.Clear;
|
|
end;
|
|
|
|
procedure DeConvertPoint(var x, y: Integer);
|
|
begin
|
|
x := Round(x*(scale/100))+dx;
|
|
y := Round(y*(Scale/100))+dy;
|
|
end;
|
|
|
|
procedure TfrmPaint.DrawlayerSel;
|
|
var xLayer:TBMPLayer;
|
|
x1,y1,x2,y2,x3,y3,x4,y4,xmin,ymin,xmax,ymax:Integer;
|
|
begin
|
|
if SelLayer = -1 then exit;
|
|
xLayer := TBmpLayer(Layers[SelLayer]);
|
|
pbox.Canvas.Pen.Mode := pmCopy;
|
|
pBox.Canvas.Pen.Color := clBlack;
|
|
pbox.Canvas.pen.Style := psSolid;
|
|
pBox.Canvas.Brush.Style := bsClear;
|
|
x1 := xLayer.p1.x; x2 := xLayer.p2.x; x3 := xLayer.p3.x; x4 := xLayer.p4.x;
|
|
y1 := xLayer.p1.y; y2 := xLayer.p2.y; y3 := xLayer.p3.y; y4 := xLayer.p4.y;
|
|
DeConvertPoint(x1,y1);DeConvertPoint(x2,y2);
|
|
DeConvertPoint(x3,y3);DeConvertPoint(x4,y4);
|
|
|
|
if selmode = 2 then begin
|
|
xmin := MinIntValue([x1,x2,x3,x4]);
|
|
xmax := MaxIntValue([x1,x2,x3,x4]);
|
|
ymin := MinIntValue([y1,y2,y3,y4]);
|
|
ymax := MaxIntValue([y1,y2,y3,y4]);
|
|
mp1 := Point(xmin,ymin);mp2 := Point(xmax,ymin);
|
|
mp3 := Point(xmax,ymax);mp4 := Point(xmin,ymax);
|
|
end else begin
|
|
mp1 := Point(x1,y1);mp2 := Point(x2,y2);
|
|
mp3 := Point(x3,y3);mp4 := Point(x4,y4);
|
|
end;
|
|
|
|
pBox.Canvas.Polygon([mp1,mp2,mp3,mp4]);
|
|
pBox.Canvas.Brush.Style := bsSolid;
|
|
if selMode = 1 then pBox.Canvas.Brush.Color := clRed
|
|
else if selMode = 2 then pBox.Canvas.Brush.Color := clBlue
|
|
else if selMode = 3 then pBox.Canvas.Brush.Color := clGreen;
|
|
pbox.canvas.Ellipse(mp1.x-6,mp1.y-6,mp1.x+6,mp1.y+6);
|
|
pbox.canvas.Ellipse(mp2.x-6,mp2.y-6,mp2.x+6,mp2.y+6);
|
|
pbox.canvas.Ellipse(mp3.x-6,mp3.y-6,mp3.x+6,mp3.y+6);
|
|
pbox.canvas.Ellipse(mp4.x-6,mp4.y-6,mp4.x+6,mp4.y+6);
|
|
if SelMode = 1 then begin
|
|
RotPoint := MPoint(MPoint(mp1,mp2),MPoint(mp3,mp4));
|
|
pbox.canvas.Ellipse(RotPoint.x-6,RotPoint.y-6,RotPoint.x+6,RotPoint.y+6);
|
|
end;
|
|
end;
|
|
|
|
function TfrmPaint.CheckModPoint(x, y: Integer): Integer;
|
|
var d,dx,dy: Integer;
|
|
|
|
begin
|
|
result := 0;
|
|
dx := (x-mp1.x); dy := (y-mp1.y);
|
|
d := Round(sqrt(dx*dx+dy*dy));
|
|
if d < 6 then begin
|
|
result := 1;
|
|
exit;
|
|
end;
|
|
dx := (x-mp2.x); dy := (y-mp2.y);
|
|
d := Round(sqrt(dx*dx+dy*dy));
|
|
if d < 6 then begin
|
|
result := 2;
|
|
exit;
|
|
end;
|
|
dx := (x-mp3.x); dy := (y-mp3.y);
|
|
d := Round(sqrt(dx*dx+dy*dy));
|
|
if d < 6 then begin
|
|
result := 3;
|
|
exit;
|
|
end;
|
|
dx := (x-mp4.x); dy := (y-mp4.y);
|
|
d := Round(sqrt(dx*dx+dy*dy));
|
|
if d < 6 then begin
|
|
result := 4;
|
|
exit;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmPaint.HandleMod(x, y: Integer);
|
|
var xLayer: TBMPLayer;
|
|
selMode : Integer;
|
|
begin
|
|
isMod := false;
|
|
if (selLayer =-1) or (selLayer >= Layers.COunt) then exit;
|
|
xLayer := TBMPLayer(Layers[SelLayer]);
|
|
xLayer.Modify(mp);
|
|
DrawBuffer;
|
|
pbox.refresh;
|
|
end;
|
|
|
|
procedure TfrmPaint.ModifyPoints(x, y: Integer);
|
|
var hitPoint,orPoint: TPoint;
|
|
dax,day,ddx,ddy,distx,disty: Integer;
|
|
xAngle: Double;
|
|
a1,a2: Double;
|
|
begin
|
|
if selMode = 1 then begin
|
|
if mp = 5 then begin
|
|
//TraceFigure.RotPoint := DoublePoint(x,y);
|
|
end else begin
|
|
a1 := GetRadOfLine(rotPoint,Point(rpx,rpy));
|
|
a2 := GetRadOfLine(rotPoint,Point(x,y));
|
|
mp1 := RotatePoint(RotPoint,op1,a2-a1);
|
|
mp2 := RotatePoint(RotPoint,op2,a2-a1);
|
|
mp3 := RotatePoint(RotPoint,op3,a2-a1);
|
|
mp4 := RotatePoint(RotPoint,op4,a2-a1);
|
|
end;
|
|
|
|
end else if selmode = 2 then begin
|
|
if mp = 1 then
|
|
begin
|
|
mp1 := Point(x,y);
|
|
mp2.y := y;
|
|
mp4.x := x;
|
|
end else if mp = 2 then begin
|
|
mp2 := Point(x,y);
|
|
mp1.y := y;
|
|
mp3.x := x;
|
|
end else if mp = 3 then begin
|
|
mp3 := Point(x,y);
|
|
mp4.y := y;
|
|
mp2.x := x;
|
|
end else if mp = 4 then begin
|
|
mp4 := Point(x,y);
|
|
mp3.y := y;
|
|
mp1.x := x;
|
|
end;
|
|
end else if selmode = 3 then begin
|
|
if mp =1 then mp1 := Point(x,y)
|
|
else if mp = 2 then mp2 := Point(x,y)
|
|
else if mp = 3 then mp3 := Point(x,y)
|
|
else if mp = 4 then mp4 := Point(x,y);
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmPaint.BlankLayer;
|
|
var bmp: TBitmap;
|
|
lName: String;
|
|
begin
|
|
lName := 'New Layer';
|
|
if InputQuery('New Layer Bitmap','Enter a name for the Layer',lName) then
|
|
begin
|
|
bmp := TBitmap.Create;
|
|
bmp.Width := buffer.Width;
|
|
bmp.Height := buffer.Height;
|
|
bmp.PixelFormat := pf24bit;
|
|
NewLayer(bmp,lname);
|
|
DrawBuffer;
|
|
pbox.refresh;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmPaint.FlattenImage;
|
|
var i: Integer;
|
|
xLayer: TBmpLayer;
|
|
x,y,xMax,xMin,yMax,yMin: Integer;
|
|
dSize: Integer;
|
|
clpRgn: HRGN;
|
|
points: array [0..3] of TPoint;
|
|
gBitmap: Tbitmap;
|
|
buf: Tbitmap;
|
|
lName: String;
|
|
begin
|
|
if layers.Count = 0 then exit;
|
|
Buf := Tbitmap.Create;
|
|
Buf.Width := Buffer.Width;
|
|
Buf.Height := Buffer.Height;
|
|
Buf.PixelFormat := pf24bit;
|
|
for i := Layers.Count-1 downto 0 do
|
|
begin
|
|
xLayer := TBmpLayer(layers[i]);
|
|
if xLayer.Visible then begin
|
|
xLayer.Bitmap.Transparent := xLayer.Transparent;
|
|
points[0] := xlayer.p1;points[1] := xlayer.p2;
|
|
points[2] := xlayer.p3;points[3] := xlayer.p4;
|
|
clpRgn := CreatePolygonRgn(points,4,ALTERNATE);
|
|
SelectClipRgn(Buffer.Canvas.Handle,ClpRgn);
|
|
xmax := MaxIntValue([xlayer.p1.x,xlayer.p2.x,xlayer.p3.x,xlayer.p4.x]);
|
|
ymax := MaxIntValue([xlayer.p1.y,xlayer.p2.y,xlayer.p3.y,xlayer.p4.y]);
|
|
xmin := MinIntValue([xlayer.p1.x,xlayer.p2.x,xlayer.p3.x,xlayer.p4.x]);
|
|
ymin := MinIntValue([xlayer.p1.y,xlayer.p2.y,xlayer.p3.y,xlayer.p4.y]);
|
|
if xLayer.Opaq = 100 then
|
|
buf.Canvas.StretchDraw(Rect(xmin,ymin,xmax,ymax),xLayer.Bitmap)
|
|
else begin
|
|
gbitmap := TBitmap.Create;
|
|
gbitmap.Width := xmax-xmin;
|
|
gbitmap.Height := ymax-ymin;
|
|
gbitmap.Canvas.CopyRect(Rect(0,0,gbitmap.Width,gbitmap.Height),buf.Canvas,Rect(xmin,ymin,xmax,ymax));
|
|
DrawGlassBitmap(gbitmap,xLayer.Bitmap,0,0,xlayer.Opaq,
|
|
xLayer.Bitmap.Canvas.Pixels[0,Height-1],xLayer.Transparent);
|
|
buf.Canvas.StretchDraw(Rect(xmin,ymin,xmax,ymax),gBitmap);
|
|
gbitmap.free;
|
|
end;
|
|
SelectClipRgn(buf.Canvas.Handle,0);
|
|
DeleteObject(clprgn);
|
|
end;
|
|
end;
|
|
lName := TBmpLayer(Layers[layers.Count-1]).Name;
|
|
ClearLayers;
|
|
NewLayer(buf,lName);
|
|
DrawBuffer;
|
|
lGrid.Row := 0;
|
|
ShowLayerOptions;
|
|
pbox.refresh;
|
|
end;
|
|
|
|
procedure TfrmPaint.Clearlayers;
|
|
var i: Integer;
|
|
xLayer : TBmpLayer;
|
|
begin
|
|
for i := 0 to Layers.Count-1 do
|
|
begin
|
|
xLayer := TbmpLayer(Layers[i]);
|
|
xLayer.Free;
|
|
end;
|
|
Layers.Clear;
|
|
LGrid.RowCount := 1;
|
|
SelLayer := -1;
|
|
cLayer := nil;
|
|
end;
|
|
|
|
procedure TfrmPaint.MergeVisible;
|
|
var i: Integer;
|
|
xLayer: TBmpLayer;
|
|
x,y,xMax,xMin,yMax,yMin: Integer;
|
|
dSize: Integer;
|
|
clpRgn: HRGN;
|
|
points: array [0..3] of TPoint;
|
|
gBitmap: Tbitmap;
|
|
buf: Tbitmap;
|
|
lName: String;
|
|
index: Integer;
|
|
begin
|
|
if layers.Count = 0 then exit;
|
|
Buf := Tbitmap.Create;
|
|
Buf.Width := Buffer.Width;
|
|
Buf.Height := Buffer.Height;
|
|
Buf.PixelFormat := pf24Bit;
|
|
lName := '';
|
|
index := -1;
|
|
for i := Layers.Count-1 downto 0 do
|
|
begin
|
|
xLayer := TBmpLayer(layers[i]);
|
|
if xLayer.Visible then begin
|
|
if lname = '' then lName := xLayer.name;
|
|
if index = -1 then index := i;
|
|
xLayer.Bitmap.Transparent := xLayer.Transparent;
|
|
points[0] := xlayer.p1;points[1] := xlayer.p2;
|
|
points[2] := xlayer.p3;points[3] := xlayer.p4;
|
|
clpRgn := CreatePolygonRgn(points,4,ALTERNATE);
|
|
SelectClipRgn(Buffer.Canvas.Handle,ClpRgn);
|
|
xmax := MaxIntValue([xlayer.p1.x,xlayer.p2.x,xlayer.p3.x,xlayer.p4.x]);
|
|
ymax := MaxIntValue([xlayer.p1.y,xlayer.p2.y,xlayer.p3.y,xlayer.p4.y]);
|
|
xmin := MinIntValue([xlayer.p1.x,xlayer.p2.x,xlayer.p3.x,xlayer.p4.x]);
|
|
ymin := MinIntValue([xlayer.p1.y,xlayer.p2.y,xlayer.p3.y,xlayer.p4.y]);
|
|
if xLayer.Opaq = 100 then
|
|
buf.Canvas.StretchDraw(Rect(xmin,ymin,xmax,ymax),xLayer.Bitmap)
|
|
else begin
|
|
gbitmap := TBitmap.Create;
|
|
gbitmap.Width := xmax-xmin;
|
|
gbitmap.Height := ymax-ymin;
|
|
gbitmap.Canvas.CopyRect(Rect(0,0,gbitmap.Width,gbitmap.Height),buf.Canvas,Rect(xmin,ymin,xmax,ymax));
|
|
DrawGlassBitmap(gbitmap,xLayer.Bitmap,0,0,xlayer.Opaq,
|
|
xLayer.Bitmap.Canvas.Pixels[0,Height-1],xLayer.Transparent);
|
|
buf.Canvas.StretchDraw(Rect(xmin,ymin,xmax,ymax),gBitmap);
|
|
gbitmap.free;
|
|
end;
|
|
SelectClipRgn(buf.Canvas.Handle,0);
|
|
DeleteObject(clprgn);
|
|
end;
|
|
end;
|
|
|
|
if index = -1 then begin
|
|
buf.free;
|
|
exit;
|
|
end;
|
|
|
|
for i := Layers.Count-1 downto 0 do
|
|
begin
|
|
xLayer := TBmpLayer(layers[i]);
|
|
if xLayer.Visible then begin
|
|
Layers.Delete(i);
|
|
xLayer.Free;
|
|
end;
|
|
end;
|
|
|
|
NewLayer(buf,lName);
|
|
DrawBuffer;
|
|
pbox.refresh;
|
|
end;
|
|
|
|
procedure TfrmPaint.DrawLine(x1, y1, x2, y2: Integer);
|
|
var x,y: Integer;
|
|
begin
|
|
if not assigned(cLayer) then exit;
|
|
x := MinIntValue([clayer.p1.x,clayer.p2.x,clayer.p3.x,clayer.p4.x]);
|
|
y := MinIntValue([clayer.p1.y,clayer.p2.y,clayer.p3.y,clayer.p4.y]);
|
|
clayer.Bitmap.Canvas.Pen.Color := Shape1.Brush.Color;
|
|
clayer.Bitmap.Canvas.Pen.Width := spPen.Value;
|
|
clayer.Bitmap.Canvas.Pen.Style := psSolid;
|
|
cLayer.Bitmap.Canvas.MoveTo(x1-x,y1-y);
|
|
cLayer.Bitmap.Canvas.LineTo(x2-x,y2-y);
|
|
end;
|
|
|
|
procedure TfrmPaint.DrawFreeHand;
|
|
var i,x,y: Integer;
|
|
pt: TPoint;
|
|
begin
|
|
if not assigned(cLayer) then exit;
|
|
x := MinIntValue([clayer.p1.x,clayer.p2.x,clayer.p3.x,clayer.p4.x]);
|
|
y := MinIntValue([clayer.p1.y,clayer.p2.y,clayer.p3.y,clayer.p4.y]);
|
|
clayer.Bitmap.Canvas.Pen.Color := Shape1.Brush.Color;
|
|
clayer.Bitmap.Canvas.Pen.Width := spPen.Value;
|
|
clayer.Bitmap.Canvas.Pen.Style := psSolid;
|
|
for i := 0 to Length(PointList)-1 do
|
|
begin
|
|
pt := PointList[i];
|
|
if i = 0 then
|
|
cLayer.Bitmap.Canvas.MoveTo(pt.x-x,pt.y-y)
|
|
else
|
|
cLayer.Bitmap.Canvas.LineTo(pt.x-x,pt.y-y)
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmPaint.DrawFreeBrush;
|
|
var i,x,y: Integer;
|
|
pt: TPoint;
|
|
sz: Integer;
|
|
crc: Boolean;
|
|
dx,dy: Integer;
|
|
begin
|
|
if not assigned(cLayer) then exit;
|
|
x := MinIntValue([clayer.p1.x,clayer.p2.x,clayer.p3.x,clayer.p4.x]);
|
|
y := MinIntValue([clayer.p1.y,clayer.p2.y,clayer.p3.y,clayer.p4.y]);
|
|
clayer.Bitmap.Canvas.Pen.Color := Shape1.Brush.Color;
|
|
clayer.Bitmap.Canvas.Brush.Color := Shape1.Brush.Color;
|
|
clayer.Bitmap.Canvas.Brush.Style := bsSolid;
|
|
clayer.Bitmap.Canvas.Pen.Width := 1;
|
|
clayer.Bitmap.Canvas.Pen.Style := psSolid;
|
|
|
|
sz := GetbSize;
|
|
crc := bCircle;
|
|
|
|
for i := 0 to Length(PointList)-1 do
|
|
begin
|
|
pt := PointList[i];
|
|
dx := pt.x-x;
|
|
dy := pt.y-y;
|
|
dx := dx - (sz div 2);
|
|
dy := dy - (sz div 2);
|
|
if crc then begin
|
|
cLayer.Bitmap.Canvas.Ellipse(dx,dy,dx+sz,dy+sz);
|
|
end else begin
|
|
cLayer.Bitmap.Canvas.Rectangle(dx,dy,dx+sz,dy+sz);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TfrmPaint.GetBSize: Integer;
|
|
begin
|
|
if (bGrid.Row = 0) or (bGrid.Row = 2) then begin
|
|
result := bGrid.Col+3;
|
|
end else begin
|
|
result := bGrid.Col+11;
|
|
end;
|
|
end;
|
|
|
|
function TfrmPaint.bCircle: Boolean;
|
|
begin
|
|
result := (bGrid.Row > 1);
|
|
end;
|
|
|
|
function TfrmPaint.GetBmpColor(x, y: Integer; var cl: TColor): Boolean;
|
|
var cx,cy: Integer;
|
|
begin
|
|
if not assigned(cLayer) then exit;
|
|
cx := MinIntValue([clayer.p1.x,clayer.p2.x,clayer.p3.x,clayer.p4.x]);
|
|
cy := MinIntValue([clayer.p1.y,clayer.p2.y,clayer.p3.y,clayer.p4.y]);
|
|
x := x-cx;
|
|
y := y-cy;
|
|
if (x < 0) or (y < 0) or (y > cLayer.Bitmap.Height-1) or (x > cLayer.Bitmap.Width-1)
|
|
then result := false else begin
|
|
result := true;
|
|
cl := cLayer.Bitmap.Canvas.Pixels[x,y];
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmPaint.BucketFill(x, y: Integer);
|
|
var cx,cy: Integer;
|
|
begin
|
|
if not assigned(cLayer) then exit;
|
|
cx := MinIntValue([clayer.p1.x,clayer.p2.x,clayer.p3.x,clayer.p4.x]);
|
|
cy := MinIntValue([clayer.p1.y,clayer.p2.y,clayer.p3.y,clayer.p4.y]);
|
|
x := x-cx;
|
|
y := y-cy;
|
|
if not ((x < 0) or (y < 0) or (y > cLayer.Bitmap.Height-1) or (x > cLayer.Bitmap.Width-1))
|
|
then begin
|
|
cLayer.Bitmap.Canvas.Brush.Color := shape1.brush.color;
|
|
cLayer.Bitmap.Canvas.Brush.Style := bsSolid;
|
|
cLayer.Bitmap.Canvas.FloodFill(x,y,cLayer.Bitmap.Canvas.Pixels[x,y],fsSurface);
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmPaint.MoveSelObjects(dx, dy: Integer);
|
|
var i,k: Integer;
|
|
selObj: TSelObject;
|
|
begin
|
|
for i := 0 to SelObjects.Count -1 do
|
|
begin
|
|
selObj := TSelObject(SelObjects[i]);
|
|
for k := 0 to selObj.pCount -1 do begin
|
|
selObj.Points[k] := Point(selObj.Points[k].x+dx,selObj.Points[k].y+dy);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TfrmPaint.GetFilterBitmap: TBitmap;
|
|
var resBmp: Tbitmap;
|
|
xRect: Trect;
|
|
srgn: HRGN;
|
|
xMin,ymin,w,h: Integer;
|
|
begin
|
|
result := nil;
|
|
Filterrgn := 0;
|
|
if not assigned(cLayer) then exit;
|
|
sRgn := CreateSelRegion(False);
|
|
if sRgn = 0 then begin
|
|
result := Tbitmap.Create;
|
|
result.width := 200;
|
|
result.Height := 200;
|
|
result.Canvas.Draw(0,0,cLayer.Bitmap);
|
|
end else begin
|
|
GetrgnBox(srgn,xRect);
|
|
if (xRect.Right = xRect.Left) and (xRect.Top = xRect.Bottom) then begin
|
|
result := Tbitmap.Create;
|
|
result.width := 200;
|
|
result.Height := 200;
|
|
result.Canvas.Draw(0,0,cLayer.Bitmap);
|
|
end else begin
|
|
result := Tbitmap.Create;
|
|
w := xRect.Right - xRect.left;
|
|
h := xRect.bottom - xRect.top;
|
|
result.width := 200;
|
|
result.Height := 200;
|
|
xmin := MinIntValue([clayer.p1.x,clayer.p2.x,cLayer.p3.x,clayer.p4.x]);
|
|
ymin := MinIntValue([clayer.p1.y,clayer.p2.y,cLayer.p3.y,clayer.p4.y]);
|
|
Offsetrgn(sRgn,-xmin,-ymin);
|
|
GetrgnBox(srgn,xRect);
|
|
Offsetrgn(sRgn,-xRect.left,-xrect.top);
|
|
FilterRgn := sRgn;
|
|
result.canvas.copyrect(Rect(0,0,200,200),cLayer.bitmap.canvas,
|
|
Rect(xRect.Left,xRect.top,xRect.left+200,xRect.top+200));
|
|
end;
|
|
end;
|
|
|
|
end;
|
|
|
|
procedure TfrmPaint.RedrawFilter;
|
|
var xBmp: Tbitmap;
|
|
begin
|
|
if not assigned(FilterBitmap) then exit;
|
|
if not assigned(FilteredBmp) then exit;
|
|
xbmp := nil;
|
|
xBmp := GetFilterBitmap;
|
|
if not assigned(xBmp) then exit;
|
|
FilterBitmap.Canvas.Brush.Color := clWhite;
|
|
FilterBitmap.Canvas.Brush.Style := bsSolid;
|
|
FilterBitmap.Canvas.FillRect(rect(0,0,200,200));
|
|
FilterBitmap.Canvas.Draw(0,0,xBmp);
|
|
FilteredBmp.Canvas.Draw(0,0,FilterBitmap);
|
|
xbmp.Free;
|
|
pbFilter.Repaint;
|
|
end;
|
|
|
|
procedure TfrmPaint.ApplyFilter;
|
|
var BB: Tbitmap;
|
|
amount: Integer;
|
|
xRect: Trect;
|
|
srgn: HRGN;
|
|
xMin,ymin,w,h: Integer;
|
|
full: Boolean;
|
|
isTrans: Boolean;
|
|
begin
|
|
|
|
if not assigned(cLayer) then exit;
|
|
isTrans := cLayer.Transparent;
|
|
sRgn := CreateSelRegion(False);
|
|
full := false;
|
|
if sRgn = 0 then begin
|
|
BB := Tbitmap.Create;
|
|
BB.Assign(cLayer.Bitmap);
|
|
full := true;
|
|
end else begin
|
|
GetrgnBox(srgn,xRect);
|
|
if (xRect.Right = xRect.Left) and (xRect.Top = xRect.Bottom) then begin
|
|
BB := Tbitmap.Create;
|
|
BB.Assign(cLayer.Bitmap);
|
|
full := true;
|
|
end else begin
|
|
BB := Tbitmap.Create;
|
|
w := xRect.Right - xRect.left;
|
|
h := xRect.bottom - xRect.top;
|
|
BB.width := w;
|
|
BB.Height := H;
|
|
xmin := MinIntValue([clayer.p1.x,clayer.p2.x,cLayer.p3.x,clayer.p4.x]);
|
|
ymin := MinIntValue([clayer.p1.y,clayer.p2.y,cLayer.p3.y,clayer.p4.y]);
|
|
Offsetrgn(sRgn,-xmin,-ymin);
|
|
GetrgnBox(srgn,xRect);
|
|
BB.canvas.copyrect(Rect(0,0,w,h),cLayer.bitmap.canvas,Rect(xRect.Left,xRect.top,xRect.left+w,xRect.top+h));
|
|
end;
|
|
end;
|
|
BB.PixelFormat := pf24bit;
|
|
|
|
|
|
amount := tbEffect.Position;
|
|
case cmbFilter.ItemIndex of
|
|
//Gaussian Blur
|
|
0: begin
|
|
if amount > 0 then GaussianBlur (BB,Amount div 10,isTrans);
|
|
end;
|
|
//Add Color Noise
|
|
1: begin
|
|
if amount > 0 then AddColorNoise (bb,amount*3,isTrans);
|
|
end;
|
|
//Antialias
|
|
2: begin
|
|
if amount = 1 then Antialias(BB,isTrans);
|
|
end;
|
|
//Contrast
|
|
3: begin
|
|
if amount > 0 then Contrast (bb,Amount*3,isTrans);
|
|
end;
|
|
//Lightness
|
|
4: begin
|
|
if amount > 0 then Lightness (BB,Amount*2,isTrans);
|
|
end;
|
|
//Darkness
|
|
5: begin
|
|
if amount > 0 then Darkness (BB,Amount*2,isTrans);
|
|
end;
|
|
//Saturation
|
|
6: begin
|
|
if amount > 0 then Saturation (BB,255-((Amount * 255) div 100),isTrans);
|
|
end;
|
|
//Mosaic
|
|
7: begin
|
|
if amount > 0 then Mosaic (BB,Amount div 2,isTrans);
|
|
end;
|
|
//Emboss
|
|
8: begin
|
|
if amount = 1 then begin
|
|
bb.width := bb.width+3;
|
|
bb.height := bb.Height+1;
|
|
bb.Canvas.StretchDraw(Rect(0,0,bb.width,bb.Height),FilterBitmap);
|
|
Emboss(BB,isTrans);
|
|
end;
|
|
end;
|
|
//Solorize
|
|
9: begin
|
|
if amount > 0 then Solorize (FilterBitmap,BB,255-((Amount * 255) div 100),isTrans);
|
|
end;
|
|
//Posterize
|
|
10: begin
|
|
if amount > 0 then Posterize (FilterBitmap,BB,((Amount * 255) div 100)+1,isTrans);
|
|
end;
|
|
//Grayscale
|
|
11: begin
|
|
if amount = 1 then Grayscale(BB,isTrans);
|
|
end;
|
|
//Invert
|
|
12: begin
|
|
if amount = 1 then PicInvert(BB,isTrans);
|
|
end;
|
|
end;
|
|
if full then begin
|
|
Clayer.Bitmap.Canvas.Draw(0,0,BB);
|
|
end else begin
|
|
SelectClipRgn(Clayer.Bitmap.Canvas.Handle,sRgn);
|
|
Clayer.Bitmap.Canvas.Draw(xRect.Left,xRect.top,BB);
|
|
SelectClipRgn(Clayer.Bitmap.Canvas.Handle,0);
|
|
end;
|
|
BB.Free;
|
|
DeleteObject(sRgn);
|
|
end;
|
|
|
|
procedure TfrmPaint.LayerFix;
|
|
var xmin,ymin,xmax,ymax: Integer;
|
|
begin
|
|
if not assigned(cLayer) then exit;
|
|
cLayer.Source.Assign(cLayer.Bitmap);
|
|
xmax := MaxIntValue([cLayer.p1.x,cLayer.p2.x,cLayer.p3.x,cLayer.p4.x]);
|
|
ymax := MaxIntValue([cLayer.p1.y,cLayer.p2.y,cLayer.p3.y,cLayer.p4.y]);
|
|
xmin := MinIntValue([cLayer.p1.x,cLayer.p2.x,cLayer.p3.x,cLayer.p4.x]);
|
|
ymin := MinIntValue([cLayer.p1.y,cLayer.p2.y,cLayer.p3.y,cLayer.p4.y]);
|
|
|
|
cLayer.p1 := Point(xmin,ymin);
|
|
cLayer.p2 := Point(xmax,ymin);
|
|
cLayer.p3 := Point(xmax,ymax);
|
|
cLayer.p4 := Point(xmin,ymax);
|
|
|
|
end;
|
|
|
|
procedure TfrmPaint.SaveToStream(mStream: Tstream);
|
|
var i: Integer;
|
|
xLayer:TBmpLayer;
|
|
xByte: Byte;
|
|
w,h:Integer;
|
|
xMin,yMin:Integer;
|
|
begin
|
|
w := buffer.Width;
|
|
h := buffer.height;
|
|
mStream.Write(w,4);
|
|
mStream.Write(h,4);
|
|
mStream.Write(layers.count,4);
|
|
for i := Layers.Count -1 downto 0 do
|
|
begin
|
|
xLayer := TBmpLayer(Layers[i]);
|
|
if xLayer.Transparent then xByte := 1 else xByte := 0;mStream.Write(xByte,1);
|
|
if xLayer.Visible then xByte := 1 else xByte := 0;mStream.Write(xByte,1);
|
|
mStream.Write(xlayer.Opaq,4);
|
|
xmin := MinIntValue([xlayer.p1.x,xlayer.p2.x,xlayer.p3.x,xlayer.p4.x]);
|
|
ymin := MinIntValue([xlayer.p1.y,xlayer.p2.y,xlayer.p3.y,xlayer.p4.y]);
|
|
mStream.Write(xMin,4);mStream.Write(yMin,4);
|
|
WriteString(mStream,xLayer.Name);
|
|
xLayer.Bitmap.SaveToStream(mStream);
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmPaint.LoadFromStream(mStream: TStream);
|
|
var i: Integer;
|
|
xLayer:TBmpLayer;
|
|
xByte: Byte;
|
|
w,h:Integer;
|
|
x,y:Integer;
|
|
cnt: Integer;
|
|
vis,isTrans: Boolean;
|
|
opaq:Integer;
|
|
Bitmap: Tbitmap;
|
|
lName: String;
|
|
begin
|
|
|
|
mStream.Position := 0;
|
|
mStream.Read(w,4);
|
|
mStream.Read(h,4);
|
|
mStream.Read(cnt,4);
|
|
medit1.Text := inttostr(w);
|
|
medit2.Text := inttostr(h);
|
|
|
|
for i := 1 to cnt do
|
|
begin
|
|
|
|
mStream.Read(xByte,1);
|
|
isTrans := (xByte = 1);
|
|
mStream.Read(xByte,1);
|
|
vis := (xByte =1);
|
|
mStream.Read(opaq,4);
|
|
mStream.Read(x,4);
|
|
mStream.Read(y,4);
|
|
lname :=ReadStringFromStream(mStream);
|
|
Bitmap := Tbitmap.Create;
|
|
Bitmap.LoadFromStream(mStream);
|
|
xLayer := NewLayer(Bitmap,lName,x,y);
|
|
xLayer.Transparent := isTrans;
|
|
xLayer.Opaq := Opaq;
|
|
xLayer.Visible := vis;
|
|
end;
|
|
|
|
end;
|
|
|
|
procedure TfrmPaint.ClearSelection;
|
|
var TrColor: TColor;
|
|
sRgn: HRGN;
|
|
xrect: Trect;
|
|
xMin,ymin : Integer;
|
|
brs: HBRUSh;
|
|
begin
|
|
if not assigned(cLayer) then exit;
|
|
sRgn := CreateSelRegion(False);
|
|
if sRgn = 0 then exit;
|
|
GetrgnBox(srgn,xRect);
|
|
if (xRect.Right = xRect.Left) and (xRect.Top = xRect.Bottom) then exit;
|
|
xmin := MinIntValue([clayer.p1.x,clayer.p2.x,cLayer.p3.x,clayer.p4.x]);
|
|
ymin := MinIntValue([clayer.p1.y,clayer.p2.y,cLayer.p3.y,clayer.p4.y]);
|
|
Offsetrgn(sRgn,-xmin,-ymin);
|
|
trColor := cLayer.Bitmap.Canvas.Pixels[0,cLayer.Bitmap.Height-1];
|
|
brs := CreateSolidBrush(trColor);
|
|
FillRgn(cLayer.Bitmap.Canvas.Handle,srgn,brs);
|
|
DeleteObject(brs);
|
|
DeleteObject(srgn);
|
|
LayerFix;
|
|
CLayer.Transparent := True;
|
|
Drawbuffer;
|
|
pbox.refresh;
|
|
end;
|
|
|
|
procedure TfrmPaint.CopySelection;
|
|
var bmp: TBitmap;
|
|
Format: Word;
|
|
Data: THandle;
|
|
Palette: HPALETTE;
|
|
begin
|
|
bmp := GetSelBitmap;
|
|
if bmp = nil then exit;
|
|
OpenClipBoard(0);
|
|
bmp.SaveToClipboardFormat(Format, Data, Palette);
|
|
SetClipboardData(Format, Data);
|
|
if Palette <> 0 then SetClipboardData(CF_PALETTE, Palette);
|
|
CloseClipBoard;
|
|
bmp.Free;
|
|
end;
|
|
|
|
procedure TfrmPaint.CutSelection;
|
|
var bmp: TBitmap;
|
|
Format: Word;
|
|
Data: THandle;
|
|
Palette: HPALETTE;
|
|
begin
|
|
bmp := GetSelBitmap;
|
|
if bmp = nil then exit;
|
|
OpenClipBoard(0);
|
|
bmp.SaveToClipboardFormat(Format, Data, Palette);
|
|
SetClipboardData(Format, Data);
|
|
if Palette <> 0 then SetClipboardData(CF_PALETTE, Palette);
|
|
CloseClipBoard;
|
|
bmp.Free;
|
|
ClearSelection;
|
|
end;
|
|
|
|
procedure TfrmPaint.PasteFromCBoard;
|
|
var bmp: TBitmap;
|
|
begin
|
|
if IsClipboardFormatAvailable(CF_BITMAP) then begin
|
|
bmp := TBitmap.Create;
|
|
bmp.Assign(ClipBoard);
|
|
NewLayer(bmp,'ClipBoard Bitmap',0,0);
|
|
DrawBuffer;
|
|
pBox.refresh;
|
|
end;
|
|
|
|
end;
|
|
|
|
function TfrmPaint.GetSelBitmap: TBitmap;
|
|
var resBmp: Tbitmap;
|
|
xRect: Trect;
|
|
srgn: HRGN;
|
|
xMin,ymin,w,h: Integer;
|
|
begin
|
|
result := nil;
|
|
if not assigned(cLayer) then exit;
|
|
sRgn := CreateSelRegion(False);
|
|
if sRgn = 0 then exit;
|
|
GetrgnBox(srgn,xRect);
|
|
if (xRect.Right = xRect.Left) and (xRect.Top = xRect.Bottom) then exit;
|
|
result := Tbitmap.Create;
|
|
w := xRect.Right - xRect.left;
|
|
h := xRect.bottom - xRect.top;
|
|
result.width := w;
|
|
result.Height := h;
|
|
xmin := MinIntValue([clayer.p1.x,clayer.p2.x,cLayer.p3.x,clayer.p4.x]);
|
|
ymin := MinIntValue([clayer.p1.y,clayer.p2.y,cLayer.p3.y,clayer.p4.y]);
|
|
Offsetrgn(sRgn,-xmin,-ymin);
|
|
GetrgnBox(srgn,xRect);
|
|
Offsetrgn(sRgn,-xRect.left,-xrect.top);
|
|
SelectCliprgn(result.canvas.handle,sRgn);
|
|
result.canvas.copyrect(Rect(0,0,w,h),cLayer.bitmap.canvas,
|
|
Rect(xRect.Left,xRect.top,xRect.left+w,xRect.top+h));
|
|
SelectCliprgn(result.canvas.handle,0);
|
|
DeleteObject(srgn);
|
|
end;
|
|
|
|
{ TSelObject }
|
|
procedure TSelObject.AddPoint(pt:TPoint);
|
|
begin
|
|
pCount := pCount+1;
|
|
SetLength(points,pCount);
|
|
points[pCount-1] := pt;
|
|
end;
|
|
|
|
constructor TSelObject.Create(aType,aMode:Integer);
|
|
begin
|
|
inherited Create;
|
|
xType := aType;
|
|
cMode := aMode;
|
|
pCount := 0;
|
|
end;
|
|
|
|
Destructor destroy;
|
|
begin
|
|
SetLength(points,0);
|
|
inherited;
|
|
end;
|
|
|
|
procedure TfrmPaint.lGridMouseMove(Sender: TObject; Shift: TShiftState; X,
|
|
Y: Integer);
|
|
begin
|
|
if (mGridDown) and (abs(x- mgx) > 2) and (abs(y-mgy)> 2) then begin
|
|
mGridDown := False;
|
|
lGrid.BeginDrag(True);
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmPaint.lGridMouseUp(Sender: TObject; Button: TMouseButton;
|
|
Shift: TShiftState; X, Y: Integer);
|
|
begin
|
|
mGridDown := False;
|
|
end;
|
|
|
|
procedure TfrmPaint.lGridDragOver(Sender, Source: TObject; X, Y: Integer;
|
|
State: TDragState; var Accept: Boolean);
|
|
begin
|
|
if Source = Sender then Accept := True;
|
|
end;
|
|
|
|
procedure TfrmPaint.lGridDragDrop(Sender, Source: TObject; X, Y: Integer);
|
|
var acol,arow: Integer;
|
|
r1,r2: Integer;
|
|
sLayer: Pointer;
|
|
begin
|
|
if (sender = source) and (Layers.Count > 0) then
|
|
begin
|
|
lGrid.MouseToCell(x,y,acol,arow);
|
|
if arow = -1 then arow := lGrid.RowCount-1;
|
|
if arow <> Lgrid.Row then begin
|
|
r1 := LGrid.row;
|
|
r2 := arow;
|
|
if SelLayer <> -1 then begin
|
|
sLayer := Layers[SelLayer];
|
|
end;
|
|
Layers.Move(r1,r2);
|
|
if SelLayer <> -1 then selLayer := Layers.IndexOf(slayer);
|
|
LGrid.Row := aRow;
|
|
DrawBuffer;
|
|
PBox.Refresh;
|
|
lGrid.Refresh;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmPaint.scmainResize(Sender: TObject);
|
|
begin
|
|
SelModified := True;
|
|
end;
|
|
|
|
procedure TfrmPaint.FormKeyUp(Sender: TObject; var Key: Word;
|
|
Shift: TShiftState);
|
|
var pt: TPoint;
|
|
begin
|
|
if (ssCtrl in Shift) and (Key = Ord('H')) then
|
|
begin
|
|
selVisible := not selVisible;
|
|
pBox.Refresh;
|
|
end else if (ssCtrl in Shift) and (Key = Ord('C')) then
|
|
begin
|
|
CopySelection;
|
|
end else if (ssCtrl in Shift) and (Key = Ord('X')) then
|
|
begin
|
|
CutSelection;
|
|
end else if (ssCtrl in Shift) and (Key = Ord('V')) then
|
|
begin
|
|
PasteFromCBoard;
|
|
end else if (Key = vk_delete) or (Key = vk_escape) then
|
|
begin
|
|
ClearSelection;
|
|
end else if (Key = vk_escape) then
|
|
begin
|
|
ClearSelObjects;
|
|
DeleteObject(SelRgn);
|
|
pbox.refresh;
|
|
end else if (CommandId = 8) and (key = vk_control) and (pbox.cursor <> crZoomp) then begin
|
|
pbox.Cursor := crZoomp;
|
|
GetCursorPos(pt);SetCursorPos(pt.x,pt.y);
|
|
end else if (CommandId = 1) and (key = vk_control) and (pbox.cursor <> crMove) then begin
|
|
pbox.Cursor := crMove;
|
|
GetCursorPos(pt);SetCursorPos(pt.x,pt.y);
|
|
end else if (CommandId in [2,3,9]) then
|
|
begin
|
|
if (key = vk_control) and (ssShift in Shift) then
|
|
begin
|
|
pBox.Cursor := crCrossm;
|
|
GetCursorPos(pt);SetCursorPos(pt.x,pt.y);
|
|
end
|
|
else if (key = vk_control) then
|
|
begin
|
|
pBox.Cursor := crCrossn;
|
|
GetCursorPos(pt);SetCursorPos(pt.x,pt.y);
|
|
end
|
|
else if (key = vk_shift) and (ssCtrl in Shift) then
|
|
begin
|
|
pBox.Cursor := crCrossp;
|
|
GetCursorPos(pt);SetCursorPos(pt.x,pt.y);
|
|
end
|
|
else if (key = vk_shift) then begin
|
|
pBox.Cursor := crCrossn;
|
|
GetCursorPos(pt);SetCursorPos(pt.x,pt.y);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmPaint.scVChange(Sender: TObject);
|
|
begin
|
|
if not lockScroll then pbox.Refresh;
|
|
end;
|
|
|
|
procedure TfrmPaint.scHChange(Sender: TObject);
|
|
begin
|
|
if not lockScroll then pbox.Refresh;
|
|
end;
|
|
|
|
{ TBmpLayer }
|
|
|
|
destructor TBmpLayer.Destroy;
|
|
begin
|
|
source.free;
|
|
bitmap.free;
|
|
inherited destroy;
|
|
end;
|
|
|
|
function TBmpLayer.Duplicate: TBmpLayer;
|
|
var xlayer: TBmplayer;
|
|
begin
|
|
xLayer := TBmpLayer.Create;
|
|
xLayer.Source := TBitmap.Create;
|
|
xLayer.Source.Width := Source.Width;
|
|
xlayer.Source.Height := Source.Height;
|
|
xLayer.Source.Canvas.Draw(0,0,Source);
|
|
xLayer.Source.PixelFormat := pf24Bit;
|
|
|
|
xLayer.Bitmap := TBitmap.Create;
|
|
xLayer.Bitmap.Width := Bitmap.Width;
|
|
xlayer.Bitmap.Height := Bitmap.Height;
|
|
xLayer.Bitmap.Canvas.Draw(0,0,Bitmap);
|
|
xLayer.Bitmap.PixelFormat := pf24Bit;
|
|
|
|
xLayer.Name := Name+' Copy';
|
|
xLayer.Transparent := Transparent;
|
|
xLayer.Visible := True;
|
|
xLayer.Opaq := Opaq;
|
|
xLayer.Skewed := Skewed;
|
|
xLayer.Rotated := Rotated;
|
|
xLayer.Scaled := Scaled;
|
|
xLayer.p1 := p1;
|
|
xLayer.p2 := p2;
|
|
xLayer.p3 := p3;
|
|
xLayer.p4 := p4;
|
|
xLayer.SelMode := 0;
|
|
result := xLayer;
|
|
end;
|
|
|
|
procedure TBmpLayer.Modify(mIndex: Integer);
|
|
var tBmp: TBitmap;
|
|
x,y: Integer;
|
|
a: double;
|
|
oh,ow,h,w: Double;
|
|
np1,np2,np3,np4: TPoint;
|
|
perx,pery: Double;
|
|
xmin,ymin,xmax,ymax: Integer;
|
|
begin
|
|
ow := GetLineLenght(op1,op2);
|
|
oh := GetLineLenght(op2,op3);
|
|
|
|
x := mp1.x; y := mp1.y; ConvertPoint(x,y); np1 := Point(x,y);
|
|
x := mp2.x; y := mp2.y; ConvertPoint(x,y); np2 := Point(x,y);
|
|
x := mp3.x; y := mp3.y; ConvertPoint(x,y); np3 := Point(x,y);
|
|
x := mp4.x; y := mp4.y; ConvertPoint(x,y); np4 := Point(x,y);
|
|
w := GetLineLenght(mp1,mp2);
|
|
h := GetLineLenght(mp2,mp3);
|
|
|
|
if SelMode <> 2 then begin
|
|
p1 := np1; p2 := np2; p3 := np3; p4 := np4;
|
|
end else begin
|
|
perx := w/ow;
|
|
pery := h/oh;
|
|
if rotated then
|
|
if perx < pery then pery := perx else perx := pery;
|
|
Scale(mIndex,perx,pery);
|
|
Scaled := True;
|
|
end;
|
|
|
|
if skewed or (selmode = 3) then begin
|
|
SkewBitmap(p1,p2,p3,p4,Source,Bitmap,Transparent);
|
|
Skewed := True;
|
|
end else if rotated or (SelMode = 1) then begin
|
|
a := - GetRadOfLine(p1,p2);
|
|
if scaled then
|
|
begin
|
|
w := GetLineLenght(p1,p2);
|
|
h := GetLineLenght(p2,p3);
|
|
tBmp := TBitmap.Create;
|
|
tbmp.Height := Source.Height;
|
|
tbmp.Width := Round((Source.Height) *(w/h));
|
|
tbmp.Canvas.StretchDraw(rect(0,0,tbmp.Width,tbmp.Height),Source);
|
|
tbmp.PixelFormat := pf24Bit;
|
|
RotateBitmap(tbmp,Bitmap,a,Transparent);
|
|
|
|
xmax := MaxIntValue([p1.x,p2.x,p3.x,p4.x]);
|
|
ymax := MaxIntValue([p1.y,p2.y,p3.y,p4.y]);
|
|
xmin := MinIntValue([p1.x,p2.x,p3.x,p4.x]);
|
|
ymin := MinIntValue([p1.y,p2.y,p3.y,p4.y]);
|
|
|
|
tbmp.Width := abs(xmax-xmin);
|
|
tbmp.Height := abs(ymax-ymin);
|
|
Bitmap.Transparent := false;
|
|
tbmp.Canvas.StretchDraw(Rect(0,0,tbmp.Width,tbmp.Height),Bitmap);
|
|
tbmp.PixelFormat := pf24Bit;
|
|
tbmp.Transparent := Transparent;
|
|
Bitmap.Free;
|
|
Bitmap := tbmp;
|
|
|
|
|
|
end else
|
|
RotateBitmap(Source,Bitmap,a,Transparent);
|
|
Rotated := True;
|
|
end else if selmode = 2 then begin
|
|
Scaled := True;
|
|
tbmp := Tbitmap.Create;
|
|
tbmp.Width := abs(p2.x-p1.x);
|
|
tbmp.Height := abs(p3.y-p1.y);
|
|
Bitmap.Transparent := false;
|
|
tbmp.Canvas.StretchDraw(Rect(0,0,tbmp.Width,tbmp.Height),Source);
|
|
tbmp.PixelFormat := pf24Bit;
|
|
tbmp.Transparent := Transparent;
|
|
Bitmap.Free;
|
|
Bitmap := tbmp;
|
|
end;
|
|
end;
|
|
|
|
procedure TBmpLayer.Move(dx, dy: Integer);
|
|
begin
|
|
p1.x := p1.x+dx;
|
|
p2.x := p2.x+dx;
|
|
p3.x := p3.x+dx;
|
|
p4.x := p4.x+dx;
|
|
p1.y := p1.y+dy;
|
|
p2.y := p2.y+dy;
|
|
p3.y := p3.y+dy;
|
|
p4.y := p4.y+dy;
|
|
end;
|
|
|
|
Function SkewBitmap(p1,p2,p3,p4: TPoint; pic: TBitmap; var ResultBmp: TBitmap;isTrans:Boolean): Boolean;
|
|
var i,k: Integer;
|
|
RowOriginal : pRGBArray;
|
|
RowRotated : pRGBArray;
|
|
pa,pb: TDoublePoint;
|
|
px: Tpoint;
|
|
bRect: Trect;
|
|
x,y,h,w: Integer;
|
|
CalCPoints: array of array of TPoint;
|
|
begin
|
|
Screen.Cursor := crHourGlass;
|
|
|
|
if (p1.x = p4.x) and (p2.x = p3.x) and (p1.y = p2.y) and (p4.y = p3.y) then
|
|
begin
|
|
ResultBmp.Width := pic.width;
|
|
ResultBmp.Height := pic.Height;
|
|
ResultBmp.PixelFormat := pf24bit;
|
|
Resultbmp.Canvas.Draw(0,0,pic);
|
|
ResultBmp.Transparent := isTrans;
|
|
Screen.Cursor := crDefault;
|
|
exit;
|
|
end;
|
|
|
|
bRect.TopLeft := p1;
|
|
bRect.BottomRight := p3;
|
|
if p1.x < bRect.Left then bRect.Left := p1.x;
|
|
if p2.x < bRect.Left then bRect.Left := p2.x;
|
|
if p3.x < bRect.Left then bRect.Left := p3.x;
|
|
if p4.x < bRect.Left then bRect.Left := p4.x;
|
|
if p1.x > bRect.Right then bRect.Right := p1.x;
|
|
if p2.x > bRect.Right then bRect.Right := p2.x;
|
|
if p3.x > bRect.Right then bRect.Right := p3.x;
|
|
if p4.x > bRect.Right then bRect.Right := p4.x;
|
|
if p1.y < bRect.top then bRect.top := p1.y;
|
|
if p2.y < bRect.top then bRect.top := p2.y;
|
|
if p3.y < bRect.top then bRect.top := p3.y;
|
|
if p4.y < bRect.top then bRect.top := p4.y;
|
|
if p1.y > bRect.bottom then bRect.bottom := p1.y;
|
|
if p2.y > bRect.bottom then bRect.bottom := p2.y;
|
|
if p3.y > bRect.bottom then bRect.bottom := p3.y;
|
|
if p4.y > bRect.bottom then bRect.bottom := p4.y;
|
|
|
|
|
|
ResultBmp.Width := bRect.right-bRect.left;
|
|
ResultBmp.Height := bRect.bottom-bRect.top;
|
|
ResultBmp.PixelFormat := pf24bit;
|
|
|
|
//if isTrans then begin
|
|
ResultBmp.Canvas.Brush.Color := pic.Canvas.Pixels[0,pic.Height-1];
|
|
ResultBmp.Canvas.Brush.Style := bsSolid;
|
|
ResultBmp.Canvas.FillRect(Rect(0,0,ResultBmp.Width,ResultBmp.Height));
|
|
//end;
|
|
|
|
SetLength(CalcPoints,ResultBmp.Width);
|
|
for i := 0 to ResultBmp.Width-1 do begin
|
|
SetLength(CalcPoints[i],ResultBmp.Height);
|
|
for k := 0 to ResultBmp.Height-1 do CalcPoints[i,k] := Point(-1,-1);
|
|
end;
|
|
|
|
|
|
for i := 0 to pic.Height-1 do
|
|
begin
|
|
pa := GetLineSegmentPoint(p1,p4,(i/(pic.Height-1)));
|
|
pb := GetLineSegmentPoint(p2,p3,(i/(pic.Height-1)));
|
|
for k := 0 to pic.Width-1 do
|
|
begin
|
|
px := DP2P(GetLineSegmentPoint(pa,pb,(k/(pic.Width-1))));
|
|
px.x := px.x-bRect.left;
|
|
px.y := px.y-bRect.top;
|
|
|
|
if px.y < 0 then px.y := 0;
|
|
if px.y > ResultBmp.Height-1 then px.y := ResultBmp.Height-1;
|
|
if px.x < 0 then px.x := 0;
|
|
if px.x > ResultBmp.Width-1 then px.x := ResultBmp.Width-1;
|
|
CalcPoints[px.x,px.y] := Point(k,i);
|
|
end;
|
|
end;
|
|
|
|
h := ResultBmp.Height-1;
|
|
w := ResultBmp.Width-1;
|
|
for i := 0 to ResultBmp.Height -1 do
|
|
begin
|
|
RowRotated := ResultBmp.Scanline[i];
|
|
for k := 0 to ResultBmp.Width -1 do
|
|
begin
|
|
px := CalcPoints[k,i];
|
|
if (px.y = -1) and (i > 0) then px := CalcPoints[k,i-1];
|
|
if (px.y = -1) and (k > 0) then px := CalcPoints[k-1,i];
|
|
if (px.y = -1) and (k > 0) and (i > 0) then px := CalcPoints[k-1,i-1];
|
|
if (px.y = -1) and (i < h) then px := CalcPoints[k,i+1];
|
|
if (px.y = -1) and (k < w) then px := CalcPoints[k+1,i];
|
|
if (px.y = -1) and (k < w) and (i < h) then px := CalcPoints[k+1,i+1];
|
|
if (px.y = -1) and (k < w) and (i > 0) then px := CalcPoints[k+1,i-1];
|
|
if (px.y = -1) and (k > 0) and (i < h) then px := CalcPoints[k-1,i+1];
|
|
if (px.y <> -1) then
|
|
begin
|
|
RowOriginal := pic.ScanLine[px.y];
|
|
RowRotated[k] := RowOriginal[px.x];
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
ResultBmp.Transparent := isTrans;
|
|
Screen.Cursor := crDefault;
|
|
end;
|
|
|
|
|
|
Procedure RotateBitmap(var BitmapOriginal,BitmapRotated: TBitmap; Teta: Double; isTrans: Boolean);
|
|
VAR
|
|
cosTheta : DOUBLE;
|
|
i : INTEGER;
|
|
iRotationAxis : INTEGER;
|
|
iOriginal : INTEGER;
|
|
iPrime : INTEGER;
|
|
iPrimeRotated : INTEGER;
|
|
j : INTEGER;
|
|
jRotationAxis : INTEGER;
|
|
jOriginal : INTEGER;
|
|
jPrime : INTEGER;
|
|
jPrimeRotated : INTEGER;
|
|
RowOriginal : pRGBArray;
|
|
RowRotated : pRGBArray;
|
|
sinTheta : DOUBLE;
|
|
Theta : DOUBLE; // radians
|
|
|
|
OldHeight : integer;
|
|
OldWidth : integer;
|
|
NewWidth : integer;
|
|
NewHeight : integer;
|
|
NB : INTEGER;
|
|
NG : INTEGER;
|
|
NR : INTEGER;
|
|
add: integer;
|
|
begin
|
|
|
|
RowOriginal := BitmapOriginal.Scanline[0];
|
|
NB:=RowOriginal[0].rgbtBlue;
|
|
NG:=RowOriginal[0].rgbtGreen;
|
|
NR:=RowOriginal[0].rgbtRed;
|
|
|
|
Theta := teta;
|
|
sinTheta := SIN(Theta);
|
|
cosTheta := COS(Theta);
|
|
|
|
OldWidth := BitmapOriginal.Width;
|
|
OldHeight := BitmapOriginal.Height;
|
|
|
|
NewWidth := abs(round(OldHeight * sinTheta)) + abs(round(OldWidth *cosTheta));
|
|
NewHeight := abs(round(OldWidth * sinTheta)) + abs(round(OldHeight *cosTheta));
|
|
|
|
BitmapRotated.Width := NewWidth;
|
|
BitmapRotated.Height := NewHeight;
|
|
BitmapRotated.PixelFormat := pf24bit;
|
|
|
|
iRotationAxis := OldWidth div 2;
|
|
jRotationAxis := OldHeight div 2;
|
|
|
|
// Step through each row of rotated image.
|
|
FOR j := BitmapRotated.Height-1 DOWNTO 0 DO
|
|
BEGIN
|
|
RowRotated := BitmapRotated.Scanline[j];
|
|
jPrime := 2*(j - (NewHeight - OldHeight) div 2 - jRotationAxis) + 1 ;
|
|
|
|
FOR i := BitmapRotated.Width-1 DOWNTO 0 DO
|
|
BEGIN
|
|
|
|
// offset origin by the growth factor (NewWidth - OldWidth) div 2
|
|
iPrime := 2*(i - (NewWidth - OldWidth) div 2 - iRotationAxis) + 1;
|
|
|
|
iPrimeRotated := ROUND(iPrime * CosTheta - jPrime * sinTheta);
|
|
jPrimeRotated := ROUND(iPrime * sinTheta + jPrime * cosTheta);
|
|
|
|
// Transform back to pixel coordinates of image, including translation
|
|
// of origin from axis of rotation to origin of image.
|
|
iOriginal := (iPrimeRotated - 1) DIV 2 + iRotationAxis;
|
|
jOriginal := (jPrimeRotated - 1) DIV 2 + jRotationAxis;
|
|
|
|
// Make sure (iOriginal, jOriginal) is in BitmapOriginal. If not,
|
|
// assign blue color to corner points.
|
|
IF (iOriginal >= 0) AND (iOriginal <= BitmapOriginal.Width-1) AND
|
|
(jOriginal >= 0) AND (jOriginal <= BitmapOriginal.Height-1)
|
|
THEN BEGIN
|
|
// Assign pixel from rotated space to current pixel in BitmapRotated
|
|
RowOriginal := BitmapOriginal.Scanline[jOriginal];
|
|
RowRotated[i] := RowOriginal[iOriginal]
|
|
END
|
|
ELSE BEGIN
|
|
//if isTrans then add := 0 else add := 100;
|
|
add := 0;
|
|
RowRotated[i].rgbtBlue := NB+add; // assign "corner" color
|
|
RowRotated[i].rgbtGreen := NG+add;
|
|
RowRotated[i].rgbtRed := NR+add;
|
|
END
|
|
|
|
END
|
|
END;
|
|
END;
|
|
|
|
Function RotatePoint(cpoint, opoint: Tpoint; ang: real):TPoint;
|
|
var p:Tpoint;
|
|
begin
|
|
oPoint := Point (oPoint.x-cpoint.x,oPoint.y-cPoint.y);
|
|
p.y := round(oPoint.x * sin(ang) + oPoint.y*cos(ang));
|
|
p.x := round(oPoint.x * cos(ang) - oPoint.y*sin(ang));
|
|
p := Point(p.x+cpoint.x,p.y+cpoint.y);
|
|
result := p;
|
|
end;
|
|
|
|
Function ScalePoint(cpoint, opoint: Tpoint; px,py: real):TPoint;
|
|
var respoint: TPoint;
|
|
deltax,deltay : double;
|
|
begin
|
|
if px = 1 then begin
|
|
respoint.x := oPoint.x;
|
|
end else begin
|
|
deltax := cPoint.x - oPoint.x;
|
|
deltax := deltax * px;
|
|
respoint.x := Round(cpoint.x - deltax);
|
|
end;
|
|
|
|
if py = 1 then begin
|
|
respoint.y := oPoint.y;
|
|
end else begin
|
|
deltay := cPoint.y - oPoint.y;
|
|
deltay := deltay * py;
|
|
respoint.y := Round(cpoint.y - deltay);
|
|
end;
|
|
result := respoint;
|
|
end;
|
|
|
|
|
|
Function MPoint(p1,p2:TPoint):TPoint;
|
|
begin
|
|
Result := Point((p1.x+p2.x)div 2,(p1.y+p2.y) div 2);
|
|
end;
|
|
|
|
Function MVPoint(p:TPoint;dy:Integer):TPoint;
|
|
begin
|
|
Result := Point(p.x,p.y+dy);
|
|
end;
|
|
|
|
Function MHPoint(p:TPoint;dx:Integer):TPoint;
|
|
begin
|
|
Result := Point(p.x+dx,p.y);
|
|
end;
|
|
|
|
Function MXPoint(p:TPoint;dx,dy:Integer):TPoint;
|
|
begin
|
|
Result := Point(p.x+dx,p.y+dy);
|
|
end;
|
|
|
|
Function DP2P(pt:TDoublepoint):TPoint;
|
|
begin
|
|
Result := Point(Round(pt.x),Round(pt.y));
|
|
end;
|
|
|
|
function GetLineLenght(p1,p2: TPoint):Real;
|
|
begin
|
|
result := sqrt(sqr(p1.x - p2.x)+sqr(p1.y - p2.y));
|
|
end;
|
|
|
|
Function ReadStringFromStream(stream:TStream):String;
|
|
var xByte: Byte;
|
|
res:string;
|
|
begin
|
|
xByte := 0;
|
|
res := '';
|
|
repeat
|
|
stream.Read(xByte,1);
|
|
if xByte <> 0 then res := res+ chr(xByte);
|
|
until xByte = 0;
|
|
result := res;
|
|
end;
|
|
|
|
Procedure WriteString(Stream:TStream; str:string);
|
|
var xByte: Byte;
|
|
begin
|
|
xByte := 0;
|
|
Stream.Write(pchar(str)^,length(str));
|
|
Stream.Write(xByte,1);
|
|
end;
|
|
|
|
|
|
Function GetLineSegmentPoint(p1,p2:TPoint; ratio: double):TDoublePoint;overload;
|
|
var a,l: double;
|
|
dx,dy,dx0,dy0: double;
|
|
begin
|
|
l := sqrt(sqr(p1.x - p2.x)+sqr(p1.y - p2.y));
|
|
if l > 0 then begin
|
|
dx := p2.x-p1.x;
|
|
dy := p2.y-p1.y;
|
|
a := ratio*l;
|
|
dx0 := (a*dx)/l;
|
|
dy0 := (a*dy)/l;
|
|
end else begin
|
|
dx0 := 0;
|
|
dy0 := 0;
|
|
end;
|
|
result.x := p1.x+dx0;
|
|
result.y := p1.y+dy0;
|
|
end;
|
|
|
|
Function GetLineSegmentPoint(p1,p2:TDoublePoint; ratio: double):TDoublePoint;
|
|
var a,l: double;
|
|
dx,dy,dx0,dy0: double;
|
|
begin
|
|
l := sqrt(sqr(p1.x - p2.x)+sqr(p1.y - p2.y));
|
|
if l > 0 then begin
|
|
dx := p2.x-p1.x;
|
|
dy := p2.y-p1.y;
|
|
a := ratio*l;
|
|
dx0 := (a*dx)/l;
|
|
dy0 := (a*dy)/l;
|
|
end else begin
|
|
dx0 := 0;
|
|
dy0 := 0;
|
|
end;
|
|
result.x := p1.x+dx0;
|
|
result.y := p1.y+dy0;
|
|
end;
|
|
|
|
|
|
Function GetRadOfLine(cp,p: TPoint):Real;
|
|
var dx,dy: integer;
|
|
ang: real;
|
|
reg:integer;
|
|
Begin
|
|
dx := abs(p.x - cp.x);
|
|
dy := abs(p.y - cp.y);
|
|
if (dx=0) and (dy=0) then // error
|
|
begin
|
|
result := 0;
|
|
exit;
|
|
end;
|
|
if dx = 0 then
|
|
begin
|
|
if p.y > cp.y then result := pi/2
|
|
else result := pi*1.5;
|
|
end
|
|
else if dy = 0 then
|
|
begin
|
|
if p.x > cp.x then result := 0
|
|
else result := pi;
|
|
end
|
|
else
|
|
begin
|
|
ang := arctan(dy/dx);
|
|
if (p.x > cp.x) and (p.y > cp.y) then begin
|
|
ang := ang; reg := 1; end
|
|
else if (p.x < cp.x) and (p.y > cp.y) then begin
|
|
ang := PI - ang; reg := 2; end
|
|
else if (p.x < cp.x) and (p.y < cp.y) then begin
|
|
ang := PI + ang; reg := 3; end
|
|
else if (p.x > cp.x) and (p.y < cp.y) then begin
|
|
ang := 2*PI - ang; reg := 4; end;
|
|
Result := ang;
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
procedure TBmpLayer.Scale(mIndex: Integer; perx, pery: Double);
|
|
var cp: TPoint;
|
|
begin
|
|
//**
|
|
Case mIndex of
|
|
1: cp := p3;
|
|
2: cp := p4;
|
|
3: cp := p1;
|
|
4: cp := p2;
|
|
end;
|
|
p1 := ScalePoint(cp,p1,perx,pery);
|
|
p2 := ScalePoint(cp,p2,perx,pery);
|
|
p3 := ScalePoint(cp,p3,perx,pery);
|
|
p4 := ScalePoint(cp,p4,perx,pery);
|
|
|
|
end;
|
|
|
|
procedure TfrmPaint.lb6Click(Sender: TObject);
|
|
var xlayer: TBmPlayer;
|
|
slayer: Pointer;
|
|
begin
|
|
if not assigned(clayer) then exit;
|
|
if SelLayer <> -1 then sLayer := Layers[SelLayer];
|
|
xLayer := CLayer.Duplicate;
|
|
Layers.Insert(Layers.IndexOf(cLayer),xLayer);
|
|
lGrid.RowCount := layers.count;
|
|
lGrid.Row := Layers.IndexOf(xlayer);
|
|
if SelLayer <> -1 then SelLayer := Layers.IndexOf(slayer);
|
|
ShowLayerOptions;
|
|
DrawBuffer;
|
|
pbox.refresh;
|
|
end;
|
|
|
|
procedure TfrmPaint.lb7Click(Sender: TObject);
|
|
var xlayer: TBmPlayer;
|
|
slayer: Pointer;
|
|
index: Integer;
|
|
begin
|
|
if not assigned(clayer) then exit;
|
|
if SelLayer <> -1 then sLayer := Layers[SelLayer];
|
|
index := Layers.IndexOf(clayer);
|
|
if sLayer = cLayer then SelLayer := -1;
|
|
Layers.Remove(cLayer);
|
|
lGrid.RowCount := lGrid.RowCount-1;
|
|
cLayer.Free;
|
|
if (Index >= Layers.Count) then Index := Layers.Count-1;
|
|
if Layers.Count > 0 then lGrid.Row := Index;
|
|
if SelLayer <> -1 then SelLayer := Layers.IndexOf(slayer);
|
|
ShowLayerOptions;
|
|
DrawBuffer;
|
|
pbox.refresh;
|
|
lgrid.Refresh;
|
|
end;
|
|
|
|
procedure TfrmPaint.lb5Click(Sender: TObject);
|
|
begin
|
|
BlankLayer;
|
|
end;
|
|
|
|
procedure TfrmPaint.lb8Click(Sender: TObject);
|
|
begin
|
|
FlattenImage;
|
|
end;
|
|
|
|
procedure TfrmPaint.lb9Click(Sender: TObject);
|
|
begin
|
|
MergeVisible;
|
|
end;
|
|
|
|
procedure TfrmPaint.bGridDrawCell(Sender: TObject; ACol, ARow: Integer;
|
|
Rect: TRect; State: TGridDrawState);
|
|
var xrect: TRect;
|
|
w,h: Integer;
|
|
|
|
procedure DrawRect(sz: Integer);
|
|
var d: Integer;
|
|
begin
|
|
d := (w - sz) div 2;
|
|
xRect := classes.Rect(rect.left+d,rect.top+d,rect.left+d+sz,rect.top+d+sz);
|
|
bGrid.Canvas.Rectangle(xRect);
|
|
end;
|
|
|
|
procedure DrawCircle(sz: Integer);
|
|
var d: Integer;
|
|
begin
|
|
d := (w - sz) div 2;
|
|
xRect := classes.Rect(rect.left+d,rect.top+d,rect.left+d+sz,rect.top+d+sz);
|
|
bGrid.Canvas.Ellipse(xRect);
|
|
end;
|
|
|
|
begin
|
|
if gdSelected in State then
|
|
bGrid.Canvas.Brush.Color := clRed
|
|
else
|
|
bGrid.Canvas.Brush.Color := clWhite;
|
|
bGrid.Canvas.Brush.Style := bsSolid;
|
|
bGrid.Canvas.FillRect(Rect);
|
|
w := 22; h := 22;
|
|
|
|
bGrid.Canvas.Brush.Color := $00FF6464;
|
|
bGrid.Canvas.Brush.Style := bsSolid;
|
|
bGrid.Canvas.pen.Style := psSolid;
|
|
bGrid.Canvas.pen.Width := 1;
|
|
bGrid.Canvas.pen.Color := $00FF6464;;
|
|
|
|
|
|
if arow = 0 then begin
|
|
DrawRect(acol+3);
|
|
end else if arow = 1 then begin
|
|
DrawRect(acol+11);
|
|
end else if arow = 2 then begin
|
|
DrawCircle(acol+3);
|
|
end else if arow = 3 then begin
|
|
DrawCircle(acol+11);
|
|
end;
|
|
|
|
end;
|
|
|
|
procedure TfrmPaint.FormKeyDown(Sender: TObject; var Key: Word;
|
|
Shift: TShiftState);
|
|
var pt: TPoint;
|
|
begin
|
|
if (CommandId = 8) and (key = vk_control) and (pbox.cursor <> crZoomm) then
|
|
begin
|
|
pbox.Cursor := crZoomm;
|
|
GetCursorPos(pt);SetCursorPos(pt.x,pt.y);
|
|
end else if (CommandId = 1) and (key = vk_control) and (pbox.cursor <> crMoves) then
|
|
begin
|
|
pbox.Cursor := crMoveS;
|
|
GetCursorPos(pt);SetCursorPos(pt.x,pt.y);
|
|
end else if (CommandId in [2,3,9]) and (key = vk_control) and (pbox.cursor <> crCrossp) then
|
|
begin
|
|
pbox.Cursor := crCrossp;
|
|
GetCursorPos(pt);SetCursorPos(pt.x,pt.y);
|
|
end else if (CommandId in [2,3,9]) and (key = vk_shift) and (pbox.cursor <> crCrossm) then
|
|
begin
|
|
pbox.Cursor := crCrossm;
|
|
GetCursorPos(pt);SetCursorPos(pt.x,pt.y);
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmPaint.mEdit1KeyPress(Sender: TObject; var Key: Char);
|
|
begin
|
|
if not (((Key >= '0') and (Key <= '9')) or
|
|
(Key = chr(8)) or (key = Chr(13)))
|
|
then begin
|
|
Key := Chr(0);
|
|
beep;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmPaint.pcChange(Sender: TObject);
|
|
begin
|
|
if pc.ActivePageIndex = 0 then begin
|
|
pc.Height := 110;
|
|
end else if pc.ActivePageIndex = 1 then begin
|
|
pc.Height := 360;
|
|
end else if pc.ActivePageIndex = 2 then begin
|
|
pc.Height := 180;
|
|
end else if pc.ActivePageIndex = 3 then begin
|
|
pc.Height := 185;
|
|
end;
|
|
|
|
end;
|
|
|
|
procedure TfrmPaint.pbFilterPaint(Sender: TObject);
|
|
var w,h,x,y: Integer;
|
|
begin
|
|
pbFilter.Canvas.Draw(0,0,FilteredBmp);
|
|
end;
|
|
|
|
procedure TfrmPaint.cmbFilterChange(Sender: TObject);
|
|
begin
|
|
RedrawFilter;
|
|
tbEffect.Min := 0;
|
|
tbEffect.Max := 100;
|
|
tbEffect.Position := 0;
|
|
case cmbFilter.ItemIndex of
|
|
//Gaussian Blur
|
|
0: begin
|
|
tbEffect.Max := 5;
|
|
end;
|
|
//Add Color Noise
|
|
1: begin
|
|
end;
|
|
//Antialias
|
|
2: begin
|
|
tbEffect.Max := 1;
|
|
end;
|
|
//Contrast
|
|
3: begin
|
|
end;
|
|
//Lightness
|
|
4: begin
|
|
end;
|
|
//Darkness
|
|
5: begin
|
|
end;
|
|
//Saturation
|
|
6: begin
|
|
end;
|
|
//Mosaic
|
|
7: begin
|
|
end;
|
|
//Emboss
|
|
8: begin
|
|
tbEffect.Max := 1;
|
|
end;
|
|
//Solorize
|
|
9: begin
|
|
end;
|
|
//Posterize
|
|
10: begin
|
|
end;
|
|
//Grayscale
|
|
11: begin
|
|
tbEffect.Max := 1;
|
|
end;
|
|
//Invert
|
|
12: begin
|
|
tbEffect.Max := 1;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmPaint.tbEffectChange(Sender: TObject);
|
|
var BB: Tbitmap;
|
|
amount: Integer;
|
|
begin
|
|
BB := TBitmap.Create;
|
|
BB.Assign (FilterBitmap);
|
|
BB.PixelFormat := pf24bit;
|
|
amount := tbEffect.Position;
|
|
|
|
case cmbFilter.ItemIndex of
|
|
//Gaussian Blur
|
|
0: begin
|
|
if amount > 0 then GaussianBlur (BB,Amount div 10,false);
|
|
end;
|
|
//Add Color Noise
|
|
1: begin
|
|
if amount > 0 then AddColorNoise (bb,amount*3,false);
|
|
end;
|
|
//Antialias
|
|
2: begin
|
|
if amount = 1 then Antialias(BB,false);
|
|
end;
|
|
//Contrast
|
|
3: begin
|
|
if amount > 0 then Contrast (bb,Amount*3,false);
|
|
end;
|
|
//Lightness
|
|
4: begin
|
|
if amount > 0 then Lightness (BB,Amount*2,false);
|
|
end;
|
|
//Darkness
|
|
5: begin
|
|
if amount > 0 then Darkness (BB,Amount*2,false);
|
|
end;
|
|
//Saturation
|
|
6: begin
|
|
if amount > 0 then Saturation (BB,255-((Amount * 255) div 100),false);
|
|
end;
|
|
//Mosaic
|
|
7: begin
|
|
if amount > 0 then Mosaic (BB,Amount div 2,false);
|
|
end;
|
|
//Emboss
|
|
8: begin
|
|
if amount = 1 then begin
|
|
bb.width := bb.width+3;
|
|
bb.height := bb.Height+1;
|
|
bb.Canvas.StretchDraw(Rect(0,0,bb.width,bb.Height),FilterBitmap);
|
|
Emboss(BB,false);
|
|
end;
|
|
end;
|
|
//Solorize
|
|
9: begin
|
|
if amount > 0 then Solorize (FilterBitmap,BB,255-((Amount * 255) div 100),false);
|
|
end;
|
|
//Posterize
|
|
10: begin
|
|
if amount > 0 then Posterize (FilterBitmap,BB,((Amount * 255) div 100)+1,false);
|
|
end;
|
|
//Grayscale
|
|
11: begin
|
|
if amount = 1 then Grayscale(BB,false);
|
|
end;
|
|
//Invert
|
|
12: begin
|
|
if amount = 1 then PicInvert(BB,false);
|
|
end;
|
|
end;
|
|
SelectClipRgn(FilteredBmp.Canvas.Handle,FilterRgn);
|
|
FilteredBmp.Canvas.Draw(0,0,BB);
|
|
BB.Free;
|
|
pbFilter.repaint;
|
|
end;
|
|
|
|
procedure TfrmPaint.Button2Click(Sender: TObject);
|
|
begin
|
|
ApplyFilter;
|
|
LayerFix;
|
|
DrawBuffer;
|
|
pbox.refresh;
|
|
end;
|
|
|
|
procedure TfrmPaint.lb10Click(Sender: TObject);
|
|
begin
|
|
InsertBitmap;
|
|
end;
|
|
|
|
procedure TfrmPaint.SpeedButton1Click(Sender: TObject);
|
|
begin
|
|
modalresult := mrok;
|
|
end;
|
|
|
|
procedure TfrmPaint.SpeedButton2Click(Sender: TObject);
|
|
begin
|
|
modalresult := mrcancel;
|
|
end;
|
|
|
|
procedure TfrmPaint.ToolButton2Click(Sender: TObject);
|
|
begin
|
|
CopySelection;
|
|
end;
|
|
|
|
procedure TfrmPaint.ToolButton5Click(Sender: TObject);
|
|
begin
|
|
ClearSelection;
|
|
end;
|
|
|
|
procedure TfrmPaint.ToolButton3Click(Sender: TObject);
|
|
begin
|
|
CutSelection;
|
|
end;
|
|
|
|
procedure TfrmPaint.ToolButton4Click(Sender: TObject);
|
|
begin
|
|
PastefromCBoard;
|
|
end;
|
|
|
|
procedure TfrmPaint.FormDestroy(Sender: TObject);
|
|
begin
|
|
if assigned(buffer) then buffer.free;
|
|
end;
|
|
|
|
end.
|