📄 gr32_resamplers.pas
字号:
var
SrcX, SrcY, SrcWidth, SrcHeight: Integer;
begin
CheckBitmaps(Dst, Src);
if Dst.Empty or Src.Empty or ((CombineOp = dmBlend) and (Src.MasterAlpha = 0)) then Exit;
SrcWidth := SrcRect.Right - SrcRect.Left;
SrcHeight := SrcRect.Bottom - SrcRect.Top;
if not Dst.MeasuringMode then
begin
if (CombineOp = dmCustom) and not Assigned(CombineCallBack) then
CombineOp := dmOpaque;
SrcX := SrcRect.Left;
SrcY := SrcRect.Top;
IntersectRect(DstClip, DstClip, Dst.BoundsRect);
IntersectRect(SrcRect, SrcRect, Src.BoundsRect);
OffsetRect(SrcRect, DstX - SrcX, DstY - SrcY);
IntersectRect(SrcRect, DstClip, SrcRect);
DstClip := SrcRect;
OffsetRect(SrcRect, SrcX - DstX, SrcY - DstY);
if not IsRectEmpty(SrcRect) then
try
BlendBlock(Dst, DstClip, Src, SrcRect.Left, SrcRect.Top, CombineOp, CombineCallBack);
finally
EMMS;
end;
end;
Dst.Changed(MakeRect(DstX, DstY, DstX + SrcWidth, DstY + SrcHeight));
end;
{$WARNINGS OFF}
procedure BlockTransferX(
Dst: TBitmap32; DstX, DstY: TFixed;
Src: TBitmap32; SrcRect: TRect;
CombineOp: TDrawMode; CombineCallBack: TPixelCombineEvent = nil);
type
TColor32Array = array [0..1] of TColor32;
PColor32Array = ^TColor32Array;
var
I, Index, SrcW, SrcRectW, SrcRectH, DstW, DstH: Integer;
FracX, FracY: Integer;
Buffer: array [0..1] of TArrayOfColor32;
SrcP, Buf1, Buf2: PColor32Array;
DstP: PColor32;
C1, C2, C3, C4: TColor32;
LW, RW, TW, BW, MA: Integer;
DstBounds: TRect;
BlendLineEx: TBlendLineEx;
BlendMemEx: TBlendMemEx;
begin
CheckBitmaps(Dst, Src);
if Dst.Empty or Src.Empty or ((CombineOp = dmBlend) and (Src.MasterAlpha = 0)) then Exit;
SrcRectW := SrcRect.Right - SrcRect.Left - 1;
SrcRectH := SrcRect.Bottom - SrcRect.Top - 1;
if not Dst.MeasuringMode then
begin
FracX := (DstX and $FFFF) shr 8;
FracY := (DstY and $FFFF) shr 8;
DstX := DstX div $10000;
DstY := DstY div $10000;
DstW := Dst.Width;
DstH := Dst.Height;
MA := Src.MasterAlpha;
if (DstX >= DstW) or (DstY >= DstH) or (MA = 0) then Exit;
if (DstX + SrcRectW <= 0) or (Dsty + SrcRectH <= 0) then Exit;
if DstX < 0 then LW := $FF else LW := FracX xor $FF;
if DstY < 0 then TW := $FF else TW := FracY xor $FF;
if DstX + SrcRectW >= DstW then RW := $FF else RW := FracX;
if DstY + SrcRectH >= DstH then BW := $FF else BW := FracY;
DstBounds := Dst.BoundsRect;
Dec(DstBounds.Right);
Dec(DstBounds.Bottom);
OffsetRect(DstBounds, SrcRect.Left - DstX, SrcRect.Top - DstY);
IntersectRect(SrcRect, SrcRect, DstBounds);
if IsRectEmpty(SrcRect) then Exit;
SrcW := Src.Width;
SrcRectW := SrcRect.Right - SrcRect.Left;
SrcRectH := SrcRect.Bottom - SrcRect.Top;
SetLength(Buffer[0], SrcRectW + 1);
SetLength(Buffer[1], SrcRectW + 1);
if DstX < 0 then DstX := 0;
if DstY < 0 then DstY := 0;
BlendLineEx := BLEND_LINE_EX[Src.CombineMode];
BlendMemEx := BLEND_MEM_EX[Src.CombineMode];
try
SrcP := PColor32Array(Src.PixelPtr[SrcRect.Left, SrcRect.Top - 1]);
DstP := Dst.PixelPtr[DstX, DstY];
Buf1 := @Buffer[0][0];
Buf2 := @Buffer[1][0];
if SrcRect.Top > 0 then
begin
MoveLongWord(SrcP[0], Buf1[0], SrcRectW);
CombineLine(@Buf1[1], @Buf1[0], SrcRectW, FracX);
if SrcRect.Left > 0 then
C2 := CombineReg(PColor32(Integer(SrcP) - 4)^, SrcP[0], FracX xor $FF)
else
C2 := SrcP[0];
if SrcRect.Right < SrcW then
C4 := CombineReg(SrcP[SrcRectW - 1], SrcP[SrcRectW], FracX)
else
C4 := SrcP[SrcRectW - 1];
end;
Inc(PColor32(SrcP), SrcW);
MoveLongWord(SrcP^, Buf2^, SrcRectW);
CombineLine(@Buf2[1], @Buf2[0], SrcRectW, FracX xor $FF);
if SrcRect.Left > 0 then
C1 := CombineReg(PColor32(Integer(SrcP) - 4)^, SrcP[0], FracX)
else
C1 := SrcP[0];
if SrcRect.Right < SrcW then
C3 := CombineReg(SrcP[SrcRectW - 1], SrcP[SrcRectW], FracX)
else
C3 := SrcP[SrcRectW - 1];
if SrcRect.Top > 0 then
begin
BlendMemEx(CombineReg(C1, C2, FracY), DstP^, LW * TW * MA shr 16);
CombineLine(@Buf2[0], @Buf1[0], SrcRectW, FracY xor $FF);
end
else
begin
BlendMemEx(C1, DstP^, LW * TW * MA shr 16);
MoveLongWord(Buf2^, Buf1^, SrcRectW);
end;
Inc(DstP, 1);
BlendLineEx(@Buf1[0], DstP, SrcRectW - 1, TW * MA shr 8);
Inc(DstP, SrcRectW - 1);
if SrcRect.Top > 0 then
BlendMemEx(CombineReg(C3, C4, FracY), DstP^, RW * TW * MA shr 16)
else
BlendMemEx(C3, DstP^, RW * TW * MA shr 16);
Inc(DstP, DstW - SrcRectW);
Index := 1;
for I := SrcRect.Top to SrcRect.Bottom - 2 do
begin
Buf1 := @Buffer[Index][0];
Buf2 := @Buffer[Index xor 1][0];
Inc(PColor32(SrcP), SrcW);
MoveLongWord(SrcP[0], Buf2^, SrcRectW);
// Horizontal translation
CombineLine(@Buf2[1], @Buf2[0], SrcRectW, FracX xor $FF);
if SrcRect.Left > 0 then
C2 := CombineReg(PColor32(Integer(SrcP) - 4)^, SrcP[0], FracX xor $FF)
else
C2 := SrcP[0];
BlendMemEx(CombineReg(C1, C2, FracY), DstP^, LW * MA shr 8);
Inc(DstP);
C1 := C2;
// Vertical translation
CombineLine(@Buf2[0], @Buf1[0], SrcRectW, FracY xor $FF);
// Blend horizontal line to Dst
BlendLineEx(@Buf1[0], DstP, SrcRectW - 1, MA);
Inc(DstP, SrcRectW - 1);
if SrcRect.Right < SrcW then
C4 := CombineReg(SrcP[SrcRectW - 1], SrcP[SrcRectW], FracX)
else
C4 := SrcP[SrcRectW - 1];
BlendMemEx(CombineReg(C3, C4, FracY), DstP^, RW * MA shr 8);
Inc(DstP, DstW - SrcRectW);
C3 := C4;
Index := Index xor 1;
end;
Buf1 := @Buffer[Index][0];
Buf2 := @Buffer[Index xor 1][0];
Inc(PColor32(SrcP), SrcW);
if SrcRect.Bottom < Src.Height then
begin
MoveLongWord(SrcP[0], Buf2^, SrcRectW);
CombineLine(@Buf2[1], @Buf2[0], SrcRectW, FracY xor $FF);
CombineLine(@Buf2[0], @Buf1[0], SrcRectW, FracY xor $FF);
if SrcRect.Left > 0 then
C2 := CombineReg(PColor32(Integer(SrcP) - 4)^, SrcP[0], FracX xor $FF)
else
C2 := SrcP[0];
BlendMemEx(CombineReg(C1, C2, FracY), DstP^, LW * BW * MA shr 16)
end
else
BlendMemEx(C1, DstP^, LW * BW * MA shr 16);
Inc(DstP);
BlendLineEx(@Buf1[0], DstP, SrcRectW - 1, BW * MA shr 8);
Inc(DstP, SrcRectW - 1);
if SrcRect.Bottom < Src.Height then
begin
if SrcRect.Right < SrcW then
C4 := CombineReg(SrcP[SrcRectW - 1], SrcP[SrcRectW], FracX)
else
C4 := SrcP[SrcRectW - 1];
BlendMemEx(CombineReg(C3, C4, FracY), DstP^, RW * BW * MA shr 16);
end
else
BlendMemEx(C3, DstP^, RW * BW * MA shr 16);
finally
EMMS;
Buffer[0] := nil;
Buffer[1] := nil;
end;
end;
Dst.Changed(MakeRect(DstX, DstY, DstX + SrcRectW + 1, DstY + SrcRectH + 1));
end;
{$WARNINGS ON}
procedure BlendTransfer(
Dst: TBitmap32; DstX, DstY: Integer; DstClip: TRect;
SrcF: TBitmap32; SrcRectF: TRect;
SrcB: TBitmap32; SrcRectB: TRect;
BlendCallback: TBlendReg);
var
I, J, SrcFX, SrcFY, SrcBX, SrcBY: Integer;
PSrcF, PSrcB, PDst: PColor32Array;
begin
if not Assigned(Dst) then raise EBitmapException.Create(SDstNil);
if not Assigned(SrcF) then raise EBitmapException.Create(SSrcNil);
if not Assigned(SrcB) then raise EBitmapException.Create(SSrcNil);
if Dst.Empty or SrcF.Empty or SrcB.Empty or not Assigned(BlendCallback) then Exit;
if not Dst.MeasuringMode then
begin
SrcFX := SrcRectF.Left - DstX;
SrcFY := SrcRectF.Top - DstY;
SrcBX := SrcRectB.Left - DstX;
SrcBY := SrcRectB.Top - DstY;
IntersectRect(DstClip, DstClip, Dst.BoundsRect);
IntersectRect(SrcRectF, SrcRectF, SrcF.BoundsRect);
IntersectRect(SrcRectB, SrcRectB, SrcB.BoundsRect);
OffsetRect(SrcRectF, -SrcFX, -SrcFY);
OffsetRect(SrcRectB, -SrcBX, -SrcFY);
IntersectRect(DstClip, DstClip, SrcRectF);
IntersectRect(DstClip, DstClip, SrcRectB);
if not IsRectEmpty(DstClip) then
try
for I := DstClip.Top to DstClip.Bottom - 1 do
begin
PSrcF := PColor32Array(SrcF.PixelPtr[SrcFX, SrcFY + I]);
PSrcB := PColor32Array(SrcB.PixelPtr[SrcBX, SrcBY + I]);
PDst := Dst.ScanLine[I];
for J := DstClip.Left to DstClip.Right - 1 do
PDst[J] := BlendCallback(PSrcF[J], PSrcB[J]);
end;
finally
EMMS;
end;
end;
Dst.Changed(DstClip);
end;
procedure BlendTransfer(
Dst: TBitmap32; DstX, DstY: Integer; DstClip: TRect;
SrcF: TBitmap32; SrcRectF: TRect;
SrcB: TBitmap32; SrcRectB: TRect;
BlendCallback: TBlendRegEx; MasterAlpha: Integer);
var
I, J, SrcFX, SrcFY, SrcBX, SrcBY: Integer;
PSrcF, PSrcB, PDst: PColor32Array;
begin
if not Assigned(Dst) then raise EBitmapException.Create(SDstNil);
if not Assigned(SrcF) then raise EBitmapException.Create(SSrcNil);
if not Assigned(SrcB) then raise EBitmapException.Create(SSrcNil);
if Dst.Empty or SrcF.Empty or SrcB.Empty or not Assigned(BlendCallback) then Exit;
if not Dst.MeasuringMode then
begin
SrcFX := SrcRectF.Left - DstX;
SrcFY := SrcRectF.Top - DstY;
SrcBX := SrcRectB.Left - DstX;
SrcBY := SrcRectB.Top - DstY;
IntersectRect(DstClip, DstClip, Dst.BoundsRect);
IntersectRect(SrcRectF, SrcRectF, SrcF.BoundsRect);
IntersectRect(SrcRectB, SrcRectB, SrcB.BoundsRect);
OffsetRect(SrcRectF, -SrcFX, -SrcFY);
OffsetRect(SrcRectB, -SrcBX, -SrcFY);
IntersectRect(DstClip, DstClip, SrcRectF);
IntersectRect(DstClip, DstClip, SrcRectB);
if not IsRectEmpty(DstClip) then
try
for I := DstClip.Top to DstClip.Bottom - 1 do
begin
PSrcF := PColor32Array(SrcF.PixelPtr[SrcFX, SrcFY + I]);
PSrcB := PColor32Array(SrcB.PixelPtr[SrcBX, SrcBY + I]);
PDst := Dst.ScanLine[I];
for J := DstClip.Left to DstClip.Right - 1 do
PDst[J] := BlendCallback(PSrcF[J], PSrcB[J], MasterAlpha);
end;
finally
EMMS;
end;
end;
Dst.Changed(DstClip);
end;
procedure StretchNearest(
Dst: TBitmap32; DstRect, DstClip: TRect;
Src: TBitmap32; SrcRect: TRect;
CombineOp: TDrawMode; CombineCallBack: TPixelCombineEvent);
var
R: TRect;
SrcW, SrcH, DstW, DstH, DstClipW, DstClipH: Integer;
SrcY, OldSrcY: Integer;
I, J: Integer;
MapHorz: array of Integer;
SrcLine, DstLine: PColor32Array;
Buffer: TArrayOfColor32;
Scale: TFloat;
BlendLine: TBlendLine;
BlendLineEx: TBlendLineEx;
DstLinePtr, MapPtr: PColor32;
begin
IntersectRect(DstClip, DstClip, MakeRect(0, 0, Dst.Width, Dst.Height));
IntersectRect(DstClip, DstClip, DstRect);
if IsRectEmpty(DstClip) then Exit;
IntersectRect(R, DstClip, DstRect);
if IsRectEmpty(R) then Exit;
if (SrcRect.Left < 0) or (SrcRect.Top < 0) or (SrcRect.Right > Src.Width) or
(SrcRect.Bottom > Src.Height) then raise Exception.Create('Invalid SrcRect');
SrcW := SrcRect.Right - SrcRect.Left;
SrcH := SrcRect.Bottom - SrcRect.Top;
DstW := DstRect.Right - DstRect.Left;
DstH := DstRect.Bottom - DstRect.Top;
DstClipW := DstClip.Right - DstClip.Left;
DstClipH := DstClip.Bottom - DstClip.Top;
try
if (SrcW = DstW) and (SrcH = DstH) then
begin
{ Copy without resampling }
BlendBlock(Dst, DstClip, Src, SrcRect.Left + DstClip.Left - DstRect.Left,
SrcRect.Top + DstClip.Top - DstRect.Top, CombineOp, CombineCallBack);
end
else
begin
SetLength(MapHorz, DstClipW);
if DstW > 1 then
begin
if FullEdge then
begin
Scale := SrcW / DstW;
for I := 0 to DstClipW - 1 do
MapHorz[I] := Trunc(SrcRect.Left + (I + DstClip.Left - DstRect.Left) * Scale);
end
else
begin
Scale := (SrcW - 1) / (DstW - 1);
for I := 0 to DstClipW - 1 do
MapHorz[I] := Round(SrcRect.Left + (I + DstClip.Left - DstRect.Left) * Scale);
end;
Assert(MapHorz[0] >= SrcRect.Left);
Assert(MapHorz[DstClipW - 1] < SrcRect.Right);
end
else
MapHorz[0] := (SrcRect.Left + SrcRect.Right - 1) div 2;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -