@@ -283,23 +283,95 @@ private System.Windows.Shapes.Line CreateLine(double x1, double y1, double x2, d
283283 } ;
284284 }
285285
286- public string CaptionText
286+ private Tuple < int , int > ImageSize
287287 {
288288 get
289289 {
290- return String . Format ( CultureInfo . InvariantCulture ,
291- "{0}\u00D7 {1}" ,
290+ return new Tuple < int , int > (
292291 ( int ) ( this . WindowWidth - 2 * OuterBorderWidth ) ,
293292 ( int ) ( this . WindowHeight - 2 * OuterBorderWidth - HeaderHeight ) ) ;
294293 }
295294 }
296295
296+ // TODO: move code to Models, add tests
297+
298+ /// <summary>
299+ /// Common aspect ratios
300+ /// https://en.wikipedia.org/wiki/Aspect_ratio_%28image%29
301+ /// </summary>
302+ private static Dictionary < double , string > CommonAspectRatios = new Dictionary < double , string > ( )
303+ {
304+ // TODO: create class with separated properties
305+ // TODO: add descriptions for displaying in tooltip
306+ { 1.0 , "1:1" } ,
307+ { 6.0 / 5.0 , "6:5" } ,
308+ { 5.0 / 4.0 , "5:4" } ,
309+ { 4.0 / 3.0 , "4:3" } ,
310+ { 11.0 / 8.0 , "11:8" } ,
311+ { Math . Sqrt ( 2.0 ) , "1.41:1" } , // ISO 216 paper sizes
312+ { 1.43 , "1.43:1" } ,
313+ { 3.0 / 2.0 , "3:2" } ,
314+ { 16.0 / 10.0 , "16:10" } , // The golden ratio
315+ { 1.618 , "16.18:10" } ,
316+ { 5.0 / 3.0 , "5:3" } ,
317+ { 16.0 / 9.0 , "16:9" } ,
318+ { 1.85 , "1.85:1" } ,
319+ { 2.35 , "2.35:1" } ,
320+ { 2.39 , "2.39:1" } ,
321+ { 2.414 , "2.414:1" } , // The silver ratio
322+ { 2.76 , "2.76:1" } ,
323+ } ;
324+
325+ private string AspectRatio
326+ {
327+ get
328+ {
329+ const double tolerance = 0.01 ;
330+ var ratio = ( ( double ) this . ImageSize . Item1 ) / ( ( double ) this . ImageSize . Item2 ) ;
331+
332+ if ( ratio >= 1.0 )
333+ {
334+ // Horizontal
335+ var nearest = CommonAspectRatios . OrderBy ( kvp => Math . Abs ( kvp . Key - ratio ) ) . First ( ) ;
336+ if ( Math . Abs ( nearest . Key - ratio ) < tolerance )
337+ {
338+ return nearest . Value ;
339+ }
340+ }
341+ else
342+ {
343+ // Vertical
344+ ratio = 1.0 / ratio ;
345+ var nearest = CommonAspectRatios . OrderBy ( kvp => Math . Abs ( kvp . Key - ratio ) ) . First ( ) ;
346+ if ( Math . Abs ( nearest . Key - ratio ) < tolerance )
347+ {
348+ var arr = nearest . Value . Split ( ':' ) ;
349+ return String . Format ( CultureInfo . InvariantCulture , "{0}:{1}" , arr [ 1 ] , arr [ 0 ] ) ;
350+ }
351+ }
352+
353+ return String . Empty ;
354+ }
355+ }
356+
357+ public string CaptionText
358+ {
359+ get
360+ {
361+ return String . Format ( CultureInfo . InvariantCulture ,
362+ "{0}\u00D7 {1}{2}" ,
363+ ImageSize . Item1 ,
364+ ImageSize . Item2 ,
365+ String . IsNullOrEmpty ( this . AspectRatio ) ? String . Empty : " (" + this . AspectRatio + ")" ) ;
366+ }
367+ }
368+
297369 public void SnapToImageBounds ( )
298370 {
299371 // select foreground window from several processes of supported applications
300372 var nativeWindow = Models . AppsInterop . NativeWindow . GetTopMostWindow ( ) ;
301373
302- if ( nativeWindow != null )
374+ if ( nativeWindow != null ) // TODO: display error if no window was found
303375 {
304376 if ( nativeWindow . ClassName == Models . AppsInterop . PhotoViewerWindow . MainWindowClassName )
305377 {
0 commit comments