1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
| function ClampByte(const Value: Integer): Byte;
begin
Result := Value;
if Value > 255 then Result := 255
else if Value < 0 then Result := 0;
end;
{ https://en.wikipedia.org/wiki/Bicubic_interpolation du chinois pour moi toutes ces formules :) }
{ Fonction adapté du code source de ??
d'après le code source en C de Paul Toth (trouvé je ne sais plus ou)
}
Procedure TFastBitmap.StretchBicubic(Var NW, NH: Integer; Const KeepRatio: Boolean = False);
Var
SrcH, SrcW: Integer;
TmpBmp: TFastBitmap;
xd, yd, xs, ys, ii, jj, n, m: Integer;
cx, cy, dx, dy, weight, red, green, blue, alpha: Single;
AColor, DstCol: TColor32;
DstPtr: PColor32;
Ind1, Ind2: Integer;
Const
BiCubicRPrecal: Array[1..16] Of Single = (0.00260416666666667, 0.0208333333333333, 0.0703125, 0.166666666666667,
0.315104166666667, 0.479166666666667, 0.611979166666667, 0.666666666666667,
0.611979166666667, 0.479166666666667, 0.315104166666667, 0.166666666666667,
0.0703125, 0.0208333333333333, 0.00260416666666667, 0.0);
Begin
SrcW := Self.Width;
SrcH := self.Height;
If KeepRatio Then KeepAspectRatio(SrcW, SrcH, NW, NH);
If (NW = SrcW) And (NH = SrcH) Then exit;
TmpBmp := TFastBitmap.Create(NW, NH);
DstPtr := TmpBmp.GetScanLine(0);
For yd := 0 To TmpBmp.Height-1 Do
Begin
For xd := 0 To TmpBmp.Width-1 Do
Begin
xs := (xd * SrcW) Div NW;
ys := (yd * SrcH) Div NH;
cx := xd * SrcW / NW;
cy := yd * SrcH / NH;
dx := cx - xs;
dy := cy - ys;
red := 0;
green := 0;
blue := 0;
alpha := 0;
For m := -1 To 2 Do
Begin
For n := -1 To 2 Do
Begin
ii := Clamp(xs + m, 0, self.width-1);
jj := Clamp(ys + n, 0, self.Height-1);
Ind1 := round(4 * (m - dx)) + 8; // Indice de correspondance avec la table précalculée
Ind2 := round(4 * (n - dy)) + 8; // Idem
// Evite un bug d'indice hors limites
Ind1 := Max(Min(Ind1, 16), 1);
Ind2 := Max(Min(Ind2, 16), 1);
weight := BiCubicRPrecal[ind1] * BiCubicRPrecal[ind2];
AColor := Self.getPixel(ii, jj);
red := red + weight * AColor.Red;
green := green + weight * AColor.Green;
blue := blue + weight * AColor.Blue;
alpha := alpha + weight * AColor.Alpha;
End;
End;
DstCol.Red := ClampByte(Round(red));
DstCol.Green := ClampByte(Round(green));
DstCol.Blue := ClampByte(Round(blue));
DstCol.Alpha := ClampByte(Round(alpha));
DstPtr^ := DstCol;
Inc(DstPtr);
End;
End;
self.Assign(TmpBmp);
FreeAndNil(TmpBmp);
End; |
Partager