55using Microsoft . UI . Xaml . Controls ;
66using Microsoft . UI . Xaml . Hosting ;
77using Microsoft . UI . Xaml . Media ;
8+ using Microsoft . UI . Xaml . Media . Imaging ;
89using System . Diagnostics ;
10+ using System . Runtime . InteropServices . WindowsRuntime ;
911using Windows . ApplicationModel . DataTransfer ;
1012using Windows . Foundation ;
1113using Windows . Storage ;
@@ -21,18 +23,43 @@ public sealed partial class PreviewImage : UserControl
2123 private readonly StorageFile _imageFile ;
2224 private readonly int _sideLength = 0 ;
2325
24- public PreviewImage ( StorageFile imageFile , int sideLength , string originalName )
26+ public PreviewImage ( StorageFile imageFile , int sideLength , string originalName , bool showCheckerBackground )
2527 {
2628 InitializeComponent ( ) ;
2729 _imageFile = imageFile ;
2830 _sideLength = sideLength ;
31+ ShowCheckerBackground = showCheckerBackground ;
2932 ToolTipService . SetToolTip ( this , $ "{ sideLength } x { sideLength } ") ;
3033 OriginalName = originalName ;
34+ ActualThemeChanged += ( _ , _ ) =>
35+ {
36+ int size = isZooming ? ZoomedWidthSpace : _sideLength ;
37+ mainImageCanvas . Background = _showCheckerBackground
38+ ? CreateCheckerBrush ( size , _sideLength , ActualTheme )
39+ : new SolidColorBrush ( Colors . Transparent ) ;
40+ } ;
3141 }
3242
3343 private bool isZooming = false ;
44+ private bool _showCheckerBackground = true ;
3445 public int ZoomedWidthSpace = 100 ;
3546
47+ public bool ShowCheckerBackground
48+ {
49+ get => _showCheckerBackground ;
50+ set
51+ {
52+ if ( value != _showCheckerBackground )
53+ {
54+ _showCheckerBackground = value ;
55+ int size = isZooming ? ZoomedWidthSpace : _sideLength ;
56+ mainImageCanvas . Background = _showCheckerBackground
57+ ? CreateCheckerBrush ( size , _sideLength , ActualTheme )
58+ : new SolidColorBrush ( Colors . Transparent ) ;
59+ }
60+ }
61+ }
62+
3663 public bool ZoomPreview
3764 {
3865 get => isZooming ;
@@ -41,9 +68,8 @@ public bool ZoomPreview
4168 if ( value != isZooming )
4269 {
4370 isZooming = value ;
44- mainImageCanvas . Children . Clear ( ) ;
71+ LoadImageOnToCanvas ( ) ;
4572 InvalidateMeasure ( ) ;
46- InvalidateArrange ( ) ;
4773 }
4874 }
4975 }
@@ -52,17 +78,13 @@ protected override Size ArrangeOverride(Size finalSize)
5278 {
5379 double dim = Math . Min ( finalSize . Width , finalSize . Height ) ;
5480 mainImageCanvas . Arrange ( new Rect ( new Point ( ( finalSize . Width - dim ) / 2 , ( finalSize . Height - dim ) / 2 ) , new Size ( dim , dim ) ) ) ;
55- LoadImageOnToCanvas ( ) ;
5681 return finalSize ;
5782 }
5883
5984 protected override Size MeasureOverride ( Size availableSize )
6085 {
61- double dim = Math . Min ( availableSize . Width , availableSize . Height ) ;
62- // smallerAvailableSize = (int)dim;
63- if ( double . IsPositiveInfinity ( dim ) )
64- dim = 3000 ;
65- return new Size ( dim , dim ) ;
86+ int size = isZooming ? ZoomedWidthSpace : _sideLength ;
87+ return new Size ( size , size ) ;
6688 }
6789
6890 private async void MenuFlyoutItem_Click ( object sender , RoutedEventArgs e )
@@ -106,6 +128,12 @@ private void UserControl_Loaded(object sender, RoutedEventArgs e)
106128 private void LoadImageOnToCanvas ( )
107129 {
108130 mainImageCanvas . Children . Clear ( ) ;
131+
132+ int size = isZooming ? ZoomedWidthSpace : _sideLength ;
133+ mainImageCanvas . Background = ShowCheckerBackground
134+ ? CreateCheckerBrush ( size , _sideLength , ActualTheme )
135+ : new SolidColorBrush ( Colors . Transparent ) ;
136+
109137 // from StackOverflow
110138 // user:
111139 // https://stackoverflow.com/users/403671/simon-mourier
@@ -128,10 +156,6 @@ private void LoadImageOnToCanvas()
128156 LoadedImageSurface image = LoadedImageSurface . StartLoadFromUri ( new Uri ( _imageFile . Path ) ) ;
129157 brush . Surface = image ;
130158
131- int size = isZooming ? ZoomedWidthSpace : _sideLength ;
132- Width = size ;
133- Height = size ;
134-
135159 // set the visual size when the image has loaded
136160 image . LoadCompleted += ( s , e ) =>
137161 {
@@ -153,6 +177,42 @@ private void LoadImageOnToCanvas()
153177 mainImageCanvas . Children . Add ( tempGrid ) ;
154178 }
155179
180+ private static ImageBrush CreateCheckerBrush ( int size , int baseSideLength , ElementTheme theme )
181+ {
182+ // idealTileSize targets ~8 px at the baseSideLength and scales proportionally for
183+ // zoomed views. NearestDivisor then rounds it to the closest exact divisor of
184+ // 'size', guaranteeing size % tileSize == 0 — no partial tile, no sliver at the
185+ // edge regardless of the canvas size or DPI scale.
186+ int idealTileSize = Math . Max ( 1 , ( int ) Math . Round ( 8.0 * size / baseSideLength ) ) ;
187+
188+ WriteableBitmap bitmap = new ( size , size ) ;
189+
190+ // Light mode: #F0F0F0 / #C4C4C4 — Dark mode: #404040 / #2A2A2A
191+ bool isDark = theme == ElementTheme . Dark ;
192+ byte tileLight = isDark ? ( byte ) 0x40 : ( byte ) 0xF0 ;
193+ byte tileDark = isDark ? ( byte ) 0x2A : ( byte ) 0xC4 ;
194+
195+ byte [ ] pixels = new byte [ size * size * 4 ] ; // BGRA format
196+ for ( int row = 0 ; row < size ; row ++ )
197+ {
198+ for ( int col = 0 ; col < size ; col ++ )
199+ {
200+ bool isLightTile = ( ( row / idealTileSize ) + ( col / idealTileSize ) ) % 2 == 0 ;
201+ byte val = isLightTile ? tileLight : tileDark ;
202+ int idx = ( row * size + col ) * 4 ;
203+ pixels [ idx ] = val ; // B
204+ pixels [ idx + 1 ] = val ; // G
205+ pixels [ idx + 2 ] = val ; // R
206+ pixels [ idx + 3 ] = 255 ; // A
207+ }
208+ }
209+
210+ using Stream stream = bitmap . PixelBuffer . AsStream ( ) ;
211+ stream . Write ( pixels , 0 , pixels . Length ) ;
212+
213+ return new ImageBrush { ImageSource = bitmap , Stretch = Stretch . Fill } ;
214+ }
215+
156216 private async void ImagePreview_DragStarting ( UIElement sender , DragStartingEventArgs args )
157217 {
158218 DragOperationDeferral deferral = args . GetDeferral ( ) ;
0 commit comments