1+ using System . Reflection ;
2+ using System . Runtime . CompilerServices ;
3+ using SkiaSharp ;
4+
5+ namespace TwitchDownloaderCore . Tests . ToolTests
6+ {
7+ // ReSharper disable once InconsistentNaming
8+ public class ColorVisibilityTests
9+ {
10+ // AdjustColorVisibility should be extracted and made public at some point, but for now just use reflection
11+ private static readonly MethodInfo AdjustVisibilityMethodInfo = typeof ( ChatRenderer ) . GetMethod ( "AdjustColorVisibility" , BindingFlags . NonPublic | BindingFlags . Static ) ! ;
12+ private static readonly Func < SKColor , SKColor , SKColor > AdjustVisibilityDelegate = ( Func < SKColor , SKColor , SKColor > ) Delegate . CreateDelegate ( typeof ( Func < SKColor , SKColor , SKColor > ) , AdjustVisibilityMethodInfo ) ;
13+
14+ [ Fact ]
15+ public void RenderTestPattern ( )
16+ {
17+ const int HUE_LEN = 360 ; // Hue sweep length
18+ const int SAT_LEN = 100 ; // Sweep height
19+ const int TILE_W = HUE_LEN + 40 ; // Tile width
20+ const int TILE_H = SAT_LEN + 40 ; // Tile height
21+ const int TILE_X_OFFSET = ( TILE_W - HUE_LEN ) / 2 ; // Tile inner-sweep X offset
22+ const int TILE_Y_OFFSET = ( TILE_H - SAT_LEN ) / 2 ; // Tile inner-sweep Y offset
23+
24+ var imageInfo = new SKImageInfo ( TILE_W * 6 , TILE_H * 2 ) ;
25+ using var bitmap = new SKBitmap ( imageInfo ) ;
26+ using var canvas = new SKCanvas ( bitmap ) ;
27+ using var paint = new SKPaint ( ) ;
28+ paint . BlendMode = SKBlendMode . Src ;
29+
30+ var backgrounds = new [ ] { SKColors . Black , SKColors . White , SKColors . Gray , SKColors . Red , SKColors . Blue , SKColors . Lime } ;
31+ for ( var i = 0 ; i < backgrounds . Length ; i ++ )
32+ {
33+ var background = backgrounds [ i ] ;
34+ var tileStartX = TILE_W * i ;
35+ DrawTile ( tileStartX , TILE_H * 0 , background , false ) ; // Row 0 (reference)
36+ DrawTile ( tileStartX , TILE_H * 1 , background , true ) ; // Row 1 (adjusted)
37+
38+ background . ToHsv ( out var bgHue , out var bgSat , out _ ) ;
39+ if ( bgSat > 28 )
40+ {
41+ AssertPixelMatrix ( tileStartX , bgHue , background ) ;
42+ }
43+ }
44+
45+ // WriteDebugBitmap(bitmap);
46+
47+ return ;
48+
49+ void DrawTile ( int startX , int startY , SKColor background , bool adjust )
50+ {
51+ paint . Color = background ;
52+ canvas . DrawRect ( startX , startY , TILE_W , TILE_H , paint ) ;
53+
54+ // Hue sweep
55+ for ( var x = 0 ; x < HUE_LEN ; x ++ )
56+ for ( var y = 0 ; y < SAT_LEN ; y ++ )
57+ {
58+ var color = SKColor . FromHsv ( x , y , 100 ) ;
59+ if ( adjust ) color = AdjustVisibilityDelegate ( color , background ) ;
60+
61+ paint . Color = color ;
62+ canvas . DrawPoint ( TILE_X_OFFSET + startX + x , TILE_Y_OFFSET + startY + y , paint ) ;
63+ }
64+
65+ // Value sweep
66+ for ( var x = startX + TILE_X_OFFSET - 3 ; x < startX + TILE_X_OFFSET ; x ++ )
67+ for ( var y = 0 ; y < SAT_LEN ; y ++ )
68+ {
69+ var color = SKColor . FromHsv ( 0 , 0 , 100 - y ) ;
70+ if ( adjust ) color = AdjustVisibilityDelegate ( color , background ) ;
71+
72+ paint . Color = color ;
73+ canvas . DrawPoint ( x , TILE_Y_OFFSET + startY + y , paint ) ;
74+ }
75+ }
76+
77+ void AssertPixelMatrix ( int startX , float bgHue , SKColor background )
78+ {
79+ const int MATRIX_W = 9 ;
80+ const int MATRIX_H = 9 ;
81+ for ( var x = - MATRIX_W ; x <= MATRIX_W ; x ++ )
82+ for ( var y = - MATRIX_H ; y <= MATRIX_H ; y ++ )
83+ {
84+ var x2 = x + ( int ) bgHue ;
85+ if ( x2 < 0 ) x2 += HUE_LEN ;
86+ x2 %= HUE_LEN ;
87+
88+ var y2 = y + SAT_LEN / 2 ;
89+ if ( y2 < 0 ) y2 += SAT_LEN ;
90+ y2 %= SAT_LEN ;
91+
92+ var sourcePx = bitmap . GetPixel (
93+ TILE_X_OFFSET + startX + x2 ,
94+ TILE_Y_OFFSET + TILE_H * 0 + y2
95+ ) ;
96+ var actualPx = bitmap . GetPixel (
97+ TILE_X_OFFSET + startX + x2 ,
98+ TILE_Y_OFFSET + TILE_H * 1 + y2
99+ ) ;
100+
101+ Assert . NotEqual ( background , actualPx ) ;
102+ Assert . NotEqual ( sourcePx , actualPx ) ;
103+ }
104+ }
105+ }
106+
107+ private static void WriteDebugBitmap ( SKBitmap bitmap , string nameSuffix = "Output" , [ CallerFilePath ] string filePath = "" , [ CallerMemberName ] string methodName = "" )
108+ {
109+ using var fs = new FileStream ( $ "{ Path . GetFileNameWithoutExtension ( filePath ) } .{ methodName } _{ nameSuffix } .png", FileMode . Create ) ;
110+ bitmap . Encode ( fs , SKEncodedImageFormat . Png , 100 ) ;
111+ }
112+ }
113+ }
0 commit comments