Skip to content

Commit b4c15f1

Browse files
committed
Resizing, pillow style
Note: Downsample has been removed as that's the same as EResizeAlgo.BOX
1 parent cf06389 commit b4c15f1

11 files changed

Lines changed: 948 additions & 430 deletions
124 KB
Loading

DocGen/images/resample_upscale.png

124 KB
Loading
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
begin
2+
asm
3+
push rsi
4+
push rdi
5+
push rbx
6+
push r12
7+
push r13
8+
push r14
9+
push r15
10+
pxor xmm3, xmm3 // zero (byte->word unpack)
11+
mov eax, $2000 // 1<<13 bias
12+
movd xmm4, eax
13+
pshufd xmm4, xmm4, 0
14+
mov eax, $FF000000 // alpha-force mask
15+
movd xmm5, eax
16+
17+
mov r8d, RowCount
18+
test r8d, r8d
19+
jle @@hdone
20+
mov r12, Src
21+
mov r13, Dst
22+
mov r14d, SrcStride
23+
mov r15d, OutDim
24+
@@hrow:
25+
mov r10, Starts // reset per row (per-column tables)
26+
mov rbx, Counts
27+
mov r11, KK
28+
xor r9d, r9d // xx = 0
29+
@@hxx:
30+
cmp r9d, r15d
31+
jge @@hrowend
32+
mov eax, dword ptr [r10] // xmin
33+
mov ecx, dword ptr [rbx] // count
34+
lea rsi, [r12 + rax*4] // P = srcrow + xmin
35+
mov rdi, r11 // K
36+
pxor xmm0, xmm0
37+
@@hpair:
38+
cmp ecx, 2
39+
jl @@htail
40+
movd xmm1, dword ptr [rsi]
41+
movd xmm2, dword ptr [rsi+4]
42+
punpcklbw xmm1, xmm2
43+
punpcklbw xmm1, xmm3
44+
movd xmm2, dword ptr [rdi]
45+
pshufd xmm2, xmm2, 0
46+
pmaddwd xmm1, xmm2
47+
paddd xmm0, xmm1
48+
add rsi, 8
49+
add rdi, 4
50+
sub ecx, 2
51+
jmp @@hpair
52+
@@htail:
53+
test ecx, ecx
54+
jz @@hstore
55+
movd xmm1, dword ptr [rsi]
56+
punpcklbw xmm1, xmm1
57+
punpcklbw xmm1, xmm3
58+
movd xmm2, dword ptr [rdi]
59+
pshufd xmm2, xmm2, 0
60+
pmaddwd xmm1, xmm2
61+
paddd xmm0, xmm1
62+
@@hstore:
63+
paddd xmm0, xmm4
64+
psrad xmm0, 14
65+
packssdw xmm0, xmm0
66+
packuswb xmm0, xmm0
67+
por xmm0, xmm5
68+
movd dword ptr [r13 + r9*4], xmm0
69+
add r10, 4 // Starts++
70+
add rbx, 4 // Counts++
71+
mov edx, KSize
72+
lea r11, [r11 + rdx*2]
73+
inc r9d
74+
jmp @@hxx
75+
@@hrowend:
76+
lea r12, [r12 + r14*4] // srcrow += SrcStride
77+
lea r13, [r13 + r15*4] // dstrow += OutDim
78+
dec r8d
79+
jnz @@hrow
80+
@@hdone:
81+
pop r15
82+
pop r14
83+
pop r13
84+
pop r12
85+
pop rbx
86+
pop rdi
87+
pop rsi
88+
end;
89+
end;
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
begin
2+
asm
3+
push rsi
4+
push rdi
5+
push r12
6+
push r13
7+
push r14
8+
push r15
9+
pxor xmm3, xmm3
10+
mov eax, $2000
11+
movd xmm4, eax
12+
pshufd xmm4, xmm4, 0
13+
mov eax, $FF000000
14+
movd xmm5, eax
15+
16+
mov r8d, RowCount
17+
test r8d, r8d
18+
jle @@vdone
19+
mov r13, Dst
20+
mov r15d, OutDim // row stride == width (src and dst)
21+
mov r10, Starts
22+
mov r14, Counts
23+
mov r11, KK
24+
@@vrow:
25+
mov eax, dword ptr [r10] // ymin
26+
mov ecx, dword ptr [r14] // count
27+
imul rax, r15 // ymin * stride
28+
mov r12, Src
29+
lea r12, [r12 + rax*4] // srcbase = Src + ymin*stride
30+
xor r9d, r9d
31+
@@vxx:
32+
cmp r9d, r15d
33+
jge @@vrowend
34+
lea rsi, [r12 + r9*4] // P = srcbase + xx
35+
mov rdi, r11
36+
mov edx, ecx
37+
pxor xmm0, xmm0
38+
@@vpair:
39+
cmp edx, 2
40+
jl @@vtail
41+
movd xmm1, dword ptr [rsi]
42+
lea rax, [rsi + r15*4] // + one row
43+
movd xmm2, dword ptr [rax]
44+
punpcklbw xmm1, xmm2
45+
punpcklbw xmm1, xmm3
46+
movd xmm2, dword ptr [rdi]
47+
pshufd xmm2, xmm2, 0
48+
pmaddwd xmm1, xmm2
49+
paddd xmm0, xmm1
50+
lea rsi, [rsi + r15*8] // += two rows
51+
add rdi, 4
52+
sub edx, 2
53+
jmp @@vpair
54+
@@vtail:
55+
test edx, edx
56+
jz @@vstore
57+
movd xmm1, dword ptr [rsi]
58+
punpcklbw xmm1, xmm1
59+
punpcklbw xmm1, xmm3
60+
movd xmm2, dword ptr [rdi]
61+
pshufd xmm2, xmm2, 0
62+
pmaddwd xmm1, xmm2
63+
paddd xmm0, xmm1
64+
@@vstore:
65+
paddd xmm0, xmm4
66+
psrad xmm0, 14
67+
packssdw xmm0, xmm0
68+
packuswb xmm0, xmm0
69+
por xmm0, xmm5
70+
movd dword ptr [r13 + r9*4], xmm0
71+
inc r9d
72+
jmp @@vxx
73+
@@vrowend:
74+
mov edx, KSize
75+
lea r11, [r11 + rdx*2]
76+
lea r13, [r13 + r15*4]
77+
add r10, 4
78+
add r14, 4
79+
dec r8d
80+
jnz @@vrow
81+
@@vdone:
82+
pop r15
83+
pop r14
84+
pop r13
85+
pop r12
86+
pop rdi
87+
pop rsi
88+
end;
89+
end;

Source/script/imports/simba.import_image.pas

Lines changed: 45 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,29 @@ implementation
3636
```
3737
*)
3838

39+
(*
40+
EImageResizeAlgo
41+
----------------
42+
```
43+
enum(NEAREST_NEIGHBOUR, BILINEAR, LANCZOS, BOX, HAMMING, BICUBIC)
44+
```
45+
The resampling filter used by `TImage.Resize`, from fastest to highest quality:
46+
47+
- `NEAREST_NEIGHBOUR`: No blending - fastest, but blocky. Good for pixel-art.
48+
- `BOX`: Simple averaging - cheap, mainly for downscaling.
49+
- `BILINEAR`: Fast and smooth, but a little soft.
50+
- `HAMMING`: A little sharper than bilinear.
51+
- `BICUBIC`: Smooth and sharp - a good default.
52+
- `LANCZOS`: Sharpest and highest quality, but the slowest.
53+
54+
![enlarging comparison](../../images/resample_upscale.png)
55+
![downscale and rebuild comparison](../../images/resample_roundtrip.png)
56+
57+
```{note}
58+
This enum is scoped so use like `EImageResizeAlgo.BILINEAR`
59+
```
60+
*)
61+
3962
(*
4063
TImage.Construct
4164
----------------
@@ -654,8 +677,9 @@ procedure _LapeImage_ReplaceColorBinary2(const Params: PParamArray); LAPE_WRAPPE
654677
TImage.Resize
655678
-------------
656679
```
657-
function TImage.Resize(Algo: EImageResizeAlgo; NewWidth, NewHeight: Integer): TSimbaImage;
680+
function TImage.Resize(Algo: EImageResizeAlgo; NewWidth, NewHeight: Integer): TImage;
658681
```
682+
Returns a new image resized to `NewWidth` by `NewHeight`, sampled with the given `Algo` filter (see `EImageResizeAlgo`). The original image is left unchanged.
659683
*)
660684
procedure _LapeImage_Resize1(const Params: PParamArray; const Result: Pointer); LAPE_WRAPPER_CALLING_CONV
661685
begin
@@ -666,50 +690,38 @@ procedure _LapeImage_Resize1(const Params: PParamArray; const Result: Pointer);
666690
TImage.Resize
667691
-------------
668692
```
669-
function TImage.Resize(Algo: EImageResizeAlgo; Scale: Single): TSimbaImage;
693+
function TImage.Resize(Algo: EImageResizeAlgo; Scale: Single): TImage;
670694
```
695+
Resizes by a `Scale` factor instead of absolute dimensions - e.g. `0.5` halves the width and height and `2.0` doubles them.
671696
*)
672697
procedure _LapeImage_Resize2(const Params: PParamArray; const Result: Pointer); LAPE_WRAPPER_CALLING_CONV
673698
begin
674699
PLapeObjectImage(Result)^^ := PLapeObjectImage(Params^[0])^^.Resize(EImageResizeAlgo(Params^[1]^), PSingle(Params^[2])^);
675700
end;
676701

677702
(*
678-
TImage.Rotate
703+
TImage.Resize
679704
-------------
680705
```
681-
function TImage.Rotate(Algo: EImageRotateAlgo; Radians: Single; Expand: Boolean): TSimbaImage;
682-
```
683-
*)
684-
procedure _LapeImage_Rotate(const Params: PParamArray; const Result: Pointer); LAPE_WRAPPER_CALLING_CONV
685-
begin
686-
PLapeObjectImage(Result)^^ := PLapeObjectImage(Params^[0])^^.Rotate(EImageRotateAlgo(Params^[1]^), PSingle(Params^[2])^, PBoolean(Params^[3])^);
687-
end;
688-
689-
(*
690-
TImage.Downsample
691-
-----------------
692-
```
693-
function TImage.Downsample(Scale: Integer): TImage;
706+
function TImage.Resize(Algo: EImageResizeAlgo; NewWidth, NewHeight: Integer; IgnorePoints: TPointArray): TImage;
694707
```
708+
Resize, but source pixels listed in `IgnorePoints` are excluded from sampling.
695709
*)
696-
procedure _LapeImage_DownSample1(const Params: PParamArray; const Result: Pointer); LAPE_WRAPPER_CALLING_CONV
710+
procedure _LapeImage_Resize3(const Params: PParamArray; const Result: Pointer); LAPE_WRAPPER_CALLING_CONV
697711
begin
698-
PLapeObjectImage(Result)^^ := PLapeObjectImage(Params^[0])^^.Downsample(PInteger(Params^[1])^);
712+
PLapeObjectImage(Result)^^ := PLapeObjectImage(Params^[0])^^.Resize(EImageResizeAlgo(Params^[1]^), PInteger(Params^[2])^, PInteger(Params^[3])^, PPointArray(Params^[4])^);
699713
end;
700714

701715
(*
702-
TImage.Downsample
703-
-----------------
716+
TImage.Rotate
717+
-------------
704718
```
705-
function TImage.Downsample(Scale: Integer; IgnorePoints: TPointArray): TImage;
719+
function TImage.Rotate(Algo: EImageRotateAlgo; Radians: Single; Expand: Boolean): TSimbaImage;
706720
```
707-
708-
Downsample but points in `IgnorePoints` are not sampled from.
709721
*)
710-
procedure _LapeImage_DownSample2(const Params: PParamArray; const Result: Pointer); LAPE_WRAPPER_CALLING_CONV
722+
procedure _LapeImage_Rotate(const Params: PParamArray; const Result: Pointer); LAPE_WRAPPER_CALLING_CONV
711723
begin
712-
PLapeObjectImage(Result)^^ := PLapeObjectImage(Params^[0])^^.Downsample(PInteger(Params^[1])^, PPointArray(Params^[2])^);
724+
PLapeObjectImage(Result)^^ := PLapeObjectImage(Params^[0])^^.Rotate(EImageRotateAlgo(Params^[1]^), PSingle(Params^[2])^, PBoolean(Params^[3])^);
713725
end;
714726

715727
(*
@@ -1339,20 +1351,18 @@ procedure _LapeImage_Blend2(const Params: PParamArray; const Result: Pointer); L
13391351
TImage.Blur
13401352
-----------
13411353
```
1342-
function TImage.Blur(Algo: EImageBlurAlgo; Radius: Integer): TSimbaImage;
1343-
```
1344-
1345-
Algo can be either EImageBlurAlgo.BOX, EImageBlurAlgo.GAUSS.
1354+
function TImage.Blur(Algo: EImageBlurAlgo; Radius: Single): TSimbaImage;
1355+
``
1356+
Algo can be either `EImageBlurAlgo.BOX` or `EImageBlurAlgo.GAUSS`.
13461357
13471358
```{note}
1348-
EImageBlurAlgo.GAUSS is not true gaussian blur it's an approximation (in linear time).
1349-
1359+
Gauss is not true gaussian blur it's an approximation (in linear time).
13501360
<https://blog.ivank.net/fastest-gaussian-blur.html>
13511361
```
13521362
*)
13531363
procedure _LapeImage_Blur(const Params: PParamArray; const Result: Pointer); LAPE_WRAPPER_CALLING_CONV
13541364
begin
1355-
PLapeObjectImage(Result)^^ := PLapeObjectImage(Params^[0])^^.Blur(EImageBlurAlgo(Params^[1]^), PInteger(Params^[2])^);
1365+
PLapeObjectImage(Result)^^ := PLapeObjectImage(Params^[0])^^.Blur(EImageBlurAlgo(Params^[1]^), PSingle(Params^[2])^);
13561366
end;
13571367

13581368
(*
@@ -1685,7 +1695,7 @@ procedure ImportSimbaImage(Script: TSimbaScript);
16851695

16861696
addGlobalType('array of TImage', 'TImageArray');
16871697
addGlobalType('enum(WIDTH, HEIGHT, LINE)', 'EImageMirrorStyle');
1688-
addGlobalType('enum(NEAREST_NEIGHBOUR, BILINEAR)', 'EImageResizeAlgo');
1698+
addGlobalType('enum(NEAREST_NEIGHBOUR, BILINEAR, LANCZOS, BOX, HAMMING, BICUBIC)', 'EImageResizeAlgo');
16891699
addGlobalType('enum(NEAREST_NEIGHBOUR, BILINEAR)', 'EImageRotateAlgo');
16901700
addGlobalType('enum(BOX, GAUSS)', 'EImageBlurAlgo');
16911701
addGlobalType('set of enum(LEFT, CENTER, RIGHT, JUSTIFY, TOP, VERTICAL_CENTER, BASE_LINE, BOTTOM)', 'EImageTextAlign');
@@ -1748,9 +1758,8 @@ procedure ImportSimbaImage(Script: TSimbaScript);
17481758

17491759
addGlobalFunc('function TImage.Resize(Algo: EImageResizeAlgo; NewWidth, NewHeight: Integer): TImage; overload;', @_LapeImage_Resize1);
17501760
addGlobalFunc('function TImage.Resize(Algo: EImageResizeAlgo; Scale: Single): TImage; overload;', @_LapeImage_Resize2);
1761+
addGlobalFunc('function TImage.Resize(Algo: EImageResizeAlgo; NewWidth, NewHeight: Integer; IgnorePoints: TPointArray): TImage; overload;', @_LapeImage_Resize3);
17511762
addGlobalFunc('function TImage.Rotate(Algo: EImageRotateAlgo; Radians: Single; Expand: Boolean): TImage;', @_LapeImage_Rotate);
1752-
addGlobalFunc('function TImage.Downsample(Scale: Integer): TImage; overload', @_LapeImage_Downsample1);
1753-
addGlobalFunc('function TImage.Downsample(Scale: Integer; IgnorePoints: TPointArray): TImage; overload', @_LapeImage_Downsample2);
17541763
addGlobalFunc('function TImage.Mirror(Style: EImageMirrorStyle): TImage', @_LapeImage_Mirror);
17551764

17561765
addGlobalFunc('function TImage.TextWidth(Text: String): Integer;', @_LapeImage_TextWidth);
@@ -1815,7 +1824,7 @@ procedure ImportSimbaImage(Script: TSimbaScript);
18151824
addGlobalFunc('function TImage.ThresholdAdaptiveSauvola(Invert: Boolean = False; Radius: Integer = 25; C: Single = 0.2): TImage', @_LapeImage_ThresholdAdaptiveSauvola);
18161825
addGlobalFunc('function TImage.Blend(Points: TPointArray; Radius: Integer): TImage; overload', @_LapeImage_Blend1);
18171826
addGlobalFunc('function TImage.Blend(Points: TPointArray; Radius: Integer; IgnorePoints: TPointArray): TImage; overload', @_LapeImage_Blend2);
1818-
addGlobalFunc('function TImage.Blur(Algo: EImageBlurAlgo; Radius: Integer): TImage;', @_LapeImage_Blur);
1827+
addGlobalFunc('function TImage.Blur(Algo: EImageBlurAlgo; Radius: Single): TImage;', @_LapeImage_Blur);
18191828

18201829
addGlobalFunc('function TImage.ToGreyMatrix: TByteMatrix', @_LapeImage_ToGreyMatrix);
18211830
addGlobalFunc('function TImage.ToMatrix: TIntegerMatrix; overload', @_LapeImage_ToMatrix1);

0 commit comments

Comments
 (0)