📄 gr32_resamplers.pas
字号:
if DstH <= 1 then Scale := 0
else if FullEdge then Scale := SrcH / DstH
else Scale := (SrcH - 1) / (DstH - 1);
if CombineOp = dmOpaque then
begin
DstLine := PColor32Array(Dst.PixelPtr[DstClip.Left, DstClip.Top]);
OldSrcY := -1;
for J := 0 to DstClipH - 1 do
begin
if DstH <= 1 then
SrcY := (SrcRect.Top + SrcRect.Bottom - 1) div 2
else if FullEdge then
SrcY := Trunc(SrcRect.Top + (J + DstClip.Top - DstRect.Top) * Scale)
else
SrcY := Round(SrcRect.Top + (J + DstClip.Top - DstRect.Top) * Scale);
if SrcY <> OldSrcY then
begin
SrcLine := Src.ScanLine[SrcY];
DstLinePtr := @DstLine[0];
MapPtr := @MapHorz[0];
for I := 0 to DstClipW - 1 do
begin
DstLinePtr^ := SrcLine[MapPtr^];
Inc(DstLinePtr);
Inc(MapPtr);
end;
OldSrcY := SrcY;
end
else
MoveLongWord(DstLine[-Dst.Width], DstLine[0], DstClipW);
Inc(DstLine, Dst.Width);
end;
end
else
begin
SetLength(Buffer, DstClipW);
DstLine := PColor32Array(Dst.PixelPtr[DstClip.Left, DstClip.Top]);
OldSrcY := -1;
if Src.MasterAlpha >= 255 then
begin
BlendLine := BLEND_LINE[Src.CombineMode];
BlendLineEx := nil; // stop compiler warnings...
end
else
begin
BlendLineEx := BLEND_LINE_EX[Src.CombineMode];
BlendLine := nil; // stop compiler warnings...
end;
for J := 0 to DstClipH - 1 do
begin
if DstH > 1 then
begin
EMMS;
if FullEdge then
SrcY := Trunc(SrcRect.Top + (J + DstClip.Top - DstRect.Top) * Scale)
else
SrcY := Round(SrcRect.Top + (J + DstClip.Top - DstRect.Top) * Scale);
end
else
SrcY := (SrcRect.Top + SrcRect.Bottom - 1) div 2;
if SrcY <> OldSrcY then
begin
SrcLine := Src.ScanLine[SrcY];
DstLinePtr := @Buffer[0];
MapPtr := @MapHorz[0];
for I := 0 to DstClipW - 1 do
begin
DstLinePtr^ := SrcLine[MapPtr^];
Inc(DstLinePtr);
Inc(MapPtr);
end;
OldSrcY := SrcY;
end;
case CombineOp of
dmBlend:
if Src.MasterAlpha >= 255 then
BlendLine(@Buffer[0], @DstLine[0], DstClipW)
else
BlendLineEx(@Buffer[0], @DstLine[0], DstClipW, Src.MasterAlpha);
dmTransparent:
for I := 0 to DstClipW - 1 do
if Buffer[I] <> Src.OuterColor then DstLine[I] := Buffer[I];
dmCustom:
for I := 0 to DstClipW - 1 do
CombineCallBack(Buffer[I], DstLine[I], Src.MasterAlpha);
end;
Inc(DstLine, Dst.Width);
end;
end;
end;
finally
EMMS;
end;
end;
procedure StretchHorzStretchVertLinear(
Dst: TBitmap32; DstRect, DstClip: TRect;
Src: TBitmap32; SrcRect: TRect;
CombineOp: TDrawMode; CombineCallBack: TPixelCombineEvent);
//Assure DstRect is >= SrcRect, otherwise quality loss will occur
var
SrcW, SrcH, DstW, DstH, DstClipW, DstClipH: Integer;
MapHorz, MapVert: array of TPointRec;
t2, Scale: TFloat;
SrcLine, DstLine: PColor32Array;
SrcIndex: Integer;
I, J: Integer;
WY: Cardinal;
C: TColor32;
BlendMemEx: TBlendMemEx;
begin
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;
SetLength(MapHorz, DstClipW);
if FullEdge then Scale := SrcW / DstW
else Scale := (SrcW - 1) / (DstW - 1);
for I := 0 to DstClipW - 1 do
begin
if FullEdge then t2 := SrcRect.Left - 0.5 + (I + DstClip.Left - DstRect.Left + 0.5) * Scale
else t2 := SrcRect.Left + (I + DstClip.Left - DstRect.Left) * Scale;
if t2 < 0 then t2 := 0
else if t2 > Src.Width - 1 then t2 := Src.Width - 1;
MapHorz[I].Pos := Floor(t2);
MapHorz[I].Weight := 256 - Round(Frac(t2) * 256);
//Pre-pack weights to reduce MMX Reg. setups per pixel:
MapHorz[I].Weight:= MapHorz[I].Weight shl 16 + MapHorz[I].Weight;
end;
I := DstClipW - 1;
while MapHorz[I].Pos = SrcRect.Right - 1 do
begin
Dec(MapHorz[I].Pos);
MapHorz[I].Weight := 0;
Dec(I);
end;
SetLength(MapVert, DstClipH);
if FullEdge then Scale := SrcH / DstH
else Scale := (SrcH - 1) / (DstH - 1);
for I := 0 to DstClipH - 1 do
begin
if FullEdge then t2 := SrcRect.Top - 0.5 + (I + DstClip.Top - DstRect.Top + 0.5) * Scale
else t2 := SrcRect.Top + (I + DstClip.Top - DstRect.Top) * Scale;
if t2 < 0 then t2 := 0
else if t2 > Src.Height - 1 then t2 := Src.Height - 1;
MapVert[I].Pos := Floor(t2);
MapVert[I].Weight := 256 - Round(Frac(t2) * 256);
//Pre-pack weights to reduce MMX Reg. setups per pixel:
MapVert[I].Weight := MapVert[I].Weight shl 16 + MapVert[I].Weight;
end;
I := DstClipH - 1;
while MapVert[I].Pos = SrcRect.Bottom - 1 do
begin
Dec(MapVert[I].Pos);
MapVert[I].Weight := 0;
Dec(I);
end;
DstLine := PColor32Array(Dst.PixelPtr[DstClip.Left, DstClip.Top]);
case CombineOp of
dmOpaque:
for J := 0 to DstClipH - 1 do
begin
SrcLine := Src.ScanLine[MapVert[J].Pos];
WY := MapVert[J].Weight;
for I := 0 to DstClipW - 1 do
begin
SrcIndex := MapHorz[I].Pos;
DstLine[I] := LinearInterpolator(MapHorz[I].Weight, WY, @SrcLine[SrcIndex],
@SrcLine[SrcIndex + Src.Width]);
end;
Inc(DstLine, Dst.Width);
end;
dmBlend:
begin
BlendMemEx := BLEND_MEM_EX[Src.CombineMode];
for J := 0 to DstClipH - 1 do
begin
SrcLine := Src.ScanLine[MapVert[J].Pos];
WY := MapVert[J].Weight;
for I := 0 to DstClipW - 1 do
begin
SrcIndex := MapHorz[I].Pos;
C := LinearInterpolator(MapHorz[I].Weight, WY, @SrcLine[SrcIndex],
@SrcLine[SrcIndex + Src.Width]);
BlendMemEx(C, DstLine[I], Src.MasterAlpha)
end;
Inc(DstLine, Dst.Width);
end
end;
dmTransparent:
begin
for J := 0 to DstClipH - 1 do
begin
SrcLine := Src.ScanLine[MapVert[J].Pos];
WY := MapVert[J].Weight;
for I := 0 to DstClipW - 1 do
begin
SrcIndex := MapHorz[I].Pos;
C := LinearInterpolator(MapHorz[I].Weight, WY, @SrcLine[SrcIndex],
@SrcLine[SrcIndex + Src.Width]);
if C <> Src.OuterColor then DstLine[I] := C;
end;
Inc(DstLine, Dst.Width);
end
end;
else // cmCustom
for J := 0 to DstClipH - 1 do
begin
SrcLine := Src.ScanLine[MapVert[J].Pos];
WY := MapVert[J].Weight;
for I := 0 to DstClipW - 1 do
begin
SrcIndex := MapHorz[I].Pos;
C := LinearInterpolator(MapHorz[I].Weight, WY, @SrcLine[SrcIndex],
@SrcLine[SrcIndex + Src.Width]);
CombineCallBack(C, DstLine[I], Src.MasterAlpha);
end;
Inc(DstLine, Dst.Width);
end;
end;
EMMS;
end;
function BuildMappingTable(
DstLo, DstHi: Integer;
ClipLo, ClipHi: Integer;
SrcLo, SrcHi: Integer;
Kernel: TCustomKernel): TMappingTable;
var
SrcW, DstW, ClipW: Integer;
Filter: TFilterMethod;
FilterWidth: TFloat;
Scale, OldScale: TFloat;
Center: TFloat;
Count: Integer;
Left, Right: Integer;
I, J, K: Integer;
Weight: Integer;
begin
SrcW := SrcHi - SrcLo;
DstW := DstHi - DstLo;
ClipW := ClipHi - ClipLo;
if SrcW = 0 then
begin
Result := nil;
Exit;
end
else if SrcW = 1 then
begin
SetLength(Result, ClipW);
for I := 0 to ClipW - 1 do
begin
SetLength(Result[I], 1);
Result[I][0].Pos := 0;
Result[I][0].Weight := 256;
end;
Exit;
end;
SetLength(Result, ClipW);
if ClipW = 0 then Exit;
if FullEdge then Scale := DstW / SrcW
else Scale := (DstW - 1) / (SrcW - 1);
Filter := Kernel.Filter;
FilterWidth := Kernel.GetWidth;
K := 0;
if Scale = 0 then
begin
Assert(Length(Result) = 1);
SetLength(Result[0], 1);
Result[0][0].Pos := (SrcLo + SrcHi) div 2;
Result[0][0].Weight := 256;
end
else if Scale < 1 then
begin
OldScale := Scale;
Scale := 1 / Scale;
FilterWidth := FilterWidth * Scale;
for I := 0 to ClipW - 1 do
begin
if FullEdge then
Center := SrcLo - 0.5 + (I - DstLo + ClipLo + 0.5) * Scale
else
Center := SrcLo + (I - DstLo + ClipLo) * Scale;
Left := Floor(Center - FilterWidth);
Right := Ceil(Center + FilterWidth);
Count := -256;
for J := Left to Right do
begin
Weight := Round(256 * Filter((Center - J) * OldScale) * OldScale);
if Weight <> 0 then
begin
Inc(Count, Weight);
K := Length(Result[I]);
SetLength(Result[I], K + 1);
Result[I][K].Pos := Constrain(J, SrcLo, SrcHi - 1);
Result[I][K].Weight := Weight;
end;
end;
if Length(Result[I]) = 0 then
begin
SetLength(Result[I], 1);
Result[I][0].Pos := Floor(Center);
Result[I][0].Weight := 256;
end
else if Count <> 0 then
Dec(Result[I][K div 2].Weight, Count);
end;
end
else // scale > 1
begin
Scale := 1 / Scale;
for I := 0 to ClipW - 1 do
begin
if FullEdge then
Center := SrcLo - 0.5 + (I - DstLo + ClipLo + 0.5) * Scale
else
Center := SrcLo + (I - DstLo + ClipLo) * Scale;
Left := Floor(Center - FilterWidth);
Right := Ceil(Center + FilterWidth);
Count := -256;
for J := Left to Right do
begin
Weight := Round(256 * Filter(Center - j));
if Weight <> 0 then
begin
Inc(Count, Weight);
K := Length(Result[I]);
SetLength(Result[I], k + 1);
Result[I][K].Pos := Constrain(j, SrcLo, SrcHi - 1);
Result[I][K].Weight := Weight;
end;
end;
if Count <> 0 then
Dec(Result[I][K div 2].Weight, Count);
end;
end;
end;
{$WARNINGS OFF}
procedure Resample(
Dst: TBitmap32; DstRect: TRect; DstClip: TRect;
Src: TBitmap32; SrcRect: TRect;
Kernel: TCustomKernel;
CombineOp: TDrawMode; CombineCallBack: TPixelCombineEvent);
var
SrcW, SrcH: TFloat;
DstW, DstH: Integer;
DstClipW, DstClipH: Integer;
t: TFloat;
MapX, MapY: TMappingTable;
I, J, X, Y, Index: Integer;
MapXLoPos, MapXHiPos: Integer;
HorzBuffer: array of TBufferEntry;
ClusterX, ClusterY: TCluster;
ClusterXSize, ClusterYSize: Integer;
C, Wt, Cr, Cg, Cb, Ca: Integer;
ClustYP, ClustYW, ClustXP, ClustXW: Integer;
SrcP: PColor32;
DstLine: PColor32Array;
RangeCheck: Boolean;
BlendMemEx: TBlendMemEx;
begin
if (CombineOp = dmCustom) and not Assigned(CombineCallBack) then
CombineOp := dmOpaque;
{ check source and destination }
if (CombineOp = dmBlend) and (Src.MasterAlpha = 0) then Exit;
BlendMemEx := BLEND_MEM_EX[Src.CombineMode]; // store in local variable
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;
// mapping tables
MapX := BuildMappingTable(DstRect.Left, DstRect.Right, DstClip.Left, DstClip.Right, SrcRect.Left, SrcRect.Right, Kernel);
MapY := BuildMappingTable(DstRect.Top, DstRect.Bottom, DstClip.Top, DstClip.Bottom, SrcRect.Top, SrcRect.Bottom, Kernel);
ClusterX := nil;
ClusterY := nil;
try
RangeCheck := Kernel.RangeCheck; //StretchFilter in [sfLanczos, sfMitchell];
if (MapX = nil) or (MapY = nil) then Exit;
MapXLoPos := MapX[0][0].Pos;
MapXHiPos := MapX[DstClipW - 1][High(MapX[DstClipW - 1])].Pos;
SetLength(HorzBuffer, MapXHiPos - MapXLoPos + 1);
{ transfer pixels }
for J := DstClip.Top to DstClip.Bottom - 1 do
begin
ClusterY := MapY[J - DstClip.Top];
for X := MapXLoPos to MapXHiPos do
begin
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -