Refactoring while writing an article, bump version number

Notable changes:
- Rename Guid property to PropertyId to not confuse with Guid type
- Move camera initialization to MainPage, it does it always anyway
- Move Parameters to DataContext and delete Settings completely
- Remove manual WB parameter as it overlaps with WB preset
This commit is contained in:
Sakari Hyoty 2012-10-18 15:47:56 +03:00
Родитель ea8c45c460
Коммит bd872462d9
16 изменённых файлов: 146 добавлений и 279 удалений

Просмотреть файл

@ -17,8 +17,6 @@ namespace CameraExplorer
{
public partial class App : Application
{
private CameraExplorer.DataContext _dataContext = CameraExplorer.DataContext.Singleton;
/// <summary>
/// Provides easy access to the root frame of the Phone Application.
/// </summary>
@ -77,7 +75,10 @@ namespace CameraExplorer
// This code will not execute when the application is closing
private void Application_Deactivated(object sender, DeactivatedEventArgs e)
{
_dataContext.UnitializeCamera();
CameraExplorer.DataContext d = CameraExplorer.DataContext.Singleton;
d.Device.Dispose();
d.Device = null;
}
// Code to execute when the application is closing (eg, user hit Back)

Просмотреть файл

@ -1,14 +1,8 @@
using Microsoft.Devices;
using Microsoft.Phone.Shell;
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Media.Imaging;
using Windows.Phone.Media.Capture;
namespace CameraExplorer
@ -107,7 +101,7 @@ namespace CameraExplorer
{
private List<ArrayParameterOption> _options = new List<ArrayParameterOption>();
private ArrayParameterOption _selectedOption;
private Guid _guid;
private Guid _propertyId;
private bool _refreshing = false;
public ArrayParameter(PhotoCaptureDevice device, string name)
@ -115,10 +109,10 @@ namespace CameraExplorer
{
}
public ArrayParameter(PhotoCaptureDevice device, Guid guid, string name)
public ArrayParameter(PhotoCaptureDevice device, Guid propertyId, string name)
: base(device, name)
{
_guid = guid;
_propertyId = propertyId;
}
public override void Refresh()
@ -208,11 +202,11 @@ namespace CameraExplorer
return new ArrayParameterEnumerator(this, _options.Count);
}
protected Guid Guid
protected Guid PropertyId
{
get
{
return _guid;
return _propertyId;
}
}
@ -289,7 +283,7 @@ namespace CameraExplorer
Options.Add(option);
CameraCapturePropertyRange range = PhotoCaptureDevice.GetSupportedPropertyRange(Device.SensorLocation, KnownCameraPhotoProperties.ExposureTime);
object value = Device.GetProperty(Guid);
object value = Device.GetProperty(PropertyId);
UInt32[] standardValues = { /* 16000, 8000, 4000,*/ 2000, 1000, 500, 250, 125, 60, 30, 15, 8, 4, 2, 1 };
UInt32 min = (UInt32)range.Min;
@ -317,7 +311,7 @@ namespace CameraExplorer
protected override void SetOption(ArrayParameterOption option)
{
Device.SetProperty(Guid, option.Value);
Device.SetProperty(PropertyId, option.Value);
}
public override void SetDefault()
@ -340,8 +334,8 @@ namespace CameraExplorer
Options.Add(option);
CameraCapturePropertyRange range = PhotoCaptureDevice.GetSupportedPropertyRange(Device.SensorLocation, Guid);
object value = Device.GetProperty(Guid);
CameraCapturePropertyRange range = PhotoCaptureDevice.GetSupportedPropertyRange(Device.SensorLocation, PropertyId);
object value = Device.GetProperty(PropertyId);
UInt32[] standardValues = { 100, 200, 400, 800, 1600, 3200 };
UInt32 min = (UInt32)range.Min;
@ -367,64 +361,7 @@ namespace CameraExplorer
protected override void SetOption(ArrayParameterOption option)
{
Device.SetProperty(Guid, option.Value);
}
public override void SetDefault()
{
if (Options.Count > 0)
{
SelectedOption = Options.First();
}
else
{
SelectedOption = null;
}
}
}
public class ManualWhiteBalanceParameter : ArrayParameter
{
public ManualWhiteBalanceParameter(PhotoCaptureDevice device)
: base(device, KnownCameraPhotoProperties.ManualWhiteBalance, "Manual white balance")
{
}
protected override void PopulateOptions()
{
ArrayParameterOption option = new ArrayParameterOption(null, "Auto");
ArrayParameterOption selectedOption = option;
Options.Add(option);
CameraCapturePropertyRange range = PhotoCaptureDevice.GetSupportedPropertyRange(Device.SensorLocation, Guid);
object value = Device.GetProperty(Guid);
UInt32[] standardValues = { 2700, 3000, 5200, 5400, 6000, 6500, 7200, 8000 };
UInt32 min = (UInt32)range.Min;
UInt32 max = (UInt32)range.Max;
foreach (UInt32 i in standardValues)
{
if (i >= min && i <= max)
{
option = new ArrayParameterOption(i, i.ToString() + " K");
Options.Add(option);
if (i.Equals(value))
{
selectedOption = option;
}
}
}
SelectedOption = selectedOption;
}
protected override void SetOption(ArrayParameterOption option)
{
Device.SetProperty(Guid, option.Value);
Device.SetProperty(PropertyId, option.Value);
}
public override void SetDefault()
@ -449,8 +386,8 @@ namespace CameraExplorer
protected override void PopulateOptions()
{
IReadOnlyList<object> supportedValues = PhotoCaptureDevice.GetSupportedPropertyValues(Device.SensorLocation, Guid);
object value = Device.GetProperty(Guid);
IReadOnlyList<object> supportedValues = PhotoCaptureDevice.GetSupportedPropertyValues(Device.SensorLocation, PropertyId);
object value = Device.GetProperty(PropertyId);
foreach (dynamic i in supportedValues)
{
@ -469,7 +406,7 @@ namespace CameraExplorer
protected override void SetOption(ArrayParameterOption option)
{
Device.SetProperty(Guid, option.Value);
Device.SetProperty(PropertyId, option.Value);
}
public override void SetDefault()
@ -502,8 +439,8 @@ namespace CameraExplorer
protected override void PopulateOptions()
{
IReadOnlyList<object> supportedValues = PhotoCaptureDevice.GetSupportedPropertyValues(Device.SensorLocation, Guid);
object value = Device.GetProperty(Guid);
IReadOnlyList<object> supportedValues = PhotoCaptureDevice.GetSupportedPropertyValues(Device.SensorLocation, PropertyId);
object value = Device.GetProperty(PropertyId);
foreach (dynamic i in supportedValues)
{
@ -522,7 +459,7 @@ namespace CameraExplorer
protected override void SetOption(ArrayParameterOption option)
{
Device.SetProperty(Guid, (FlashMode)option.Value);
Device.SetProperty(PropertyId, (FlashMode)option.Value);
}
public override void SetDefault()
@ -555,8 +492,8 @@ namespace CameraExplorer
protected override void PopulateOptions()
{
IReadOnlyList<object> supportedValues = PhotoCaptureDevice.GetSupportedPropertyValues(Device.SensorLocation, Guid);
object value = Device.GetProperty(Guid);
IReadOnlyList<object> supportedValues = PhotoCaptureDevice.GetSupportedPropertyValues(Device.SensorLocation, PropertyId);
object value = Device.GetProperty(PropertyId);
foreach (dynamic i in supportedValues)
{
@ -575,7 +512,7 @@ namespace CameraExplorer
protected override void SetOption(ArrayParameterOption option)
{
Device.SetProperty(Guid, option.Value);
Device.SetProperty(PropertyId, option.Value);
}
public override void SetDefault()
@ -613,8 +550,8 @@ namespace CameraExplorer
Options.Add(option);
IReadOnlyList<object> supportedValues = PhotoCaptureDevice.GetSupportedPropertyValues(Device.SensorLocation, Guid);
object value = Device.GetProperty(Guid);
IReadOnlyList<object> supportedValues = PhotoCaptureDevice.GetSupportedPropertyValues(Device.SensorLocation, PropertyId);
object value = Device.GetProperty(PropertyId);
foreach (dynamic i in supportedValues)
{
@ -635,7 +572,7 @@ namespace CameraExplorer
protected override void SetOption(ArrayParameterOption option)
{
Device.SetProperty(Guid, option.Value);
Device.SetProperty(PropertyId, option.Value);
}
public override void SetDefault()
@ -653,8 +590,8 @@ namespace CameraExplorer
protected override void PopulateOptions()
{
IReadOnlyList<object> supportedValues = PhotoCaptureDevice.GetSupportedPropertyValues(Device.SensorLocation, Guid);
object value = Device.GetProperty(Guid);
IReadOnlyList<object> supportedValues = PhotoCaptureDevice.GetSupportedPropertyValues(Device.SensorLocation, PropertyId);
object value = Device.GetProperty(PropertyId);
foreach (dynamic i in supportedValues)
{
@ -673,7 +610,7 @@ namespace CameraExplorer
protected override void SetOption(ArrayParameterOption option)
{
Device.SetProperty(Guid, option.Value);
Device.SetProperty(PropertyId, option.Value);
}
public override void SetDefault()

Просмотреть файл

@ -116,7 +116,6 @@
<DesignTime>True</DesignTime>
<DependentUpon>AppResources.resx</DependentUpon>
</Compile>
<Compile Include="Settings.cs" />
<Compile Include="SettingsPage.xaml.cs">
<DependentUpon>SettingsPage.xaml</DependentUpon>
</Compile>

Просмотреть файл

@ -1,13 +1,7 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.IO.IsolatedStorage;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Controls;
using System.Windows.Media.Imaging;
using Windows.Phone.Media.Capture;
namespace CameraExplorer
@ -16,31 +10,45 @@ namespace CameraExplorer
{
public event PropertyChangedEventHandler PropertyChanged;
static DataContext _singleton;
public static CameraExplorer.DataContext Singleton
private static DataContext _singleton;
private PhotoCaptureDevice _device = null;
private ObservableCollection<Parameter> _parameters = new ObservableCollection<Parameter>();
public static DataContext Singleton
{
get
{
if (_singleton == null)
_singleton = new CameraExplorer.DataContext();
{
_singleton = new DataContext();
}
return _singleton;
}
}
Settings _settings = null;
public Settings Settings
public ObservableCollection<Parameter> Parameters
{
get
{
if (_settings == null)
_settings = new Settings();
return _parameters;
}
return _settings;
private set
{
if (_parameters != value)
{
_parameters = value;
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("Parameters"));
}
}
}
}
PhotoCaptureDevice _device = null;
public PhotoCaptureDevice Device
{
get
@ -53,8 +61,46 @@ namespace CameraExplorer
if (_device != value)
{
_device = value;
if (_device != null)
{
ObservableCollection<Parameter> newParameters = new ObservableCollection<Parameter>();
Settings.CreateParameters();
Action<Parameter> addParameter = (Parameter parameter) =>
{
if (parameter.Supported && parameter.Modifiable)
{
try
{
parameter.Refresh();
parameter.SetDefault();
newParameters.Add(parameter);
}
catch (Exception)
{
System.Diagnostics.Debug.WriteLine("Setting default to " + parameter.Name.ToLower() + " failed");
}
}
else
{
System.Diagnostics.Debug.WriteLine("Parameter " + parameter.Name.ToLower() + " is not supported or not modifiable");
}
};
addParameter(new SceneModeParameter(_device));
addParameter(new WhiteBalancePresetParameter(_device));
addParameter(new FlashModeParameter(_device));
addParameter(new FlashPowerParameter(_device));
addParameter(new IsoParameter(_device));
addParameter(new ExposureCompensationParameter(_device));
addParameter(new ExposureTimeParameter(_device));
addParameter(new AutoFocusRangeParameter(_device));
addParameter(new FocusIlluminationModeParameter(_device));
addParameter(new CaptureResolutionParameter(_device));
Parameters = newParameters;
}
if (PropertyChanged != null)
{
@ -65,30 +111,5 @@ namespace CameraExplorer
}
public MemoryStream ImageStream { get; set; }
public async Task InitializeCamera(CameraSensorLocation sensorLocation)
{
Windows.Foundation.Size initialResolution = new Windows.Foundation.Size(640, 480);
Windows.Foundation.Size previewResolution = new Windows.Foundation.Size(640, 480);
Windows.Foundation.Size captureResolution = new Windows.Foundation.Size(640, 480);
PhotoCaptureDevice d = await PhotoCaptureDevice.OpenAsync(sensorLocation, initialResolution);
await d.SetPreviewResolutionAsync(previewResolution);
await d.SetCaptureResolutionAsync(captureResolution);
d.SetProperty(KnownCameraGeneralProperties.EncodeWithOrientation, d.SensorLocation == CameraSensorLocation.Back ? d.SensorRotationInDegrees : - d.SensorRotationInDegrees);
Device = d;
}
public void UnitializeCamera()
{
if (Device != null)
{
Device.Dispose();
Device = null;
}
}
}
}

Просмотреть файл

@ -51,7 +51,7 @@
</Grid>
<phone:PhoneApplicationPage.ApplicationBar>
<shell:ApplicationBar IsVisible="True">
<shell:ApplicationBar>
<shell:ApplicationBarIconButton x:Name="sensorButton" Text="sensor"
IconUri="Assets/Icons/appbar.sensor.png" Click="sensorButton_Click" IsEnabled="False"/>
<shell:ApplicationBarIconButton x:Name="captureButton" Text="capture"

Просмотреть файл

@ -1,24 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Devices;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Shell;
using CameraExplorer.Resources;
using Microsoft.Devices;
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using System.Windows.Media;
using System.Windows.Navigation;
using Windows.Phone.Media.Capture;
using System.Threading.Tasks;
using Microsoft.Xna.Framework.Media;
using System.IO;
using System.Windows.Media.Imaging;
namespace CameraExplorer
{
@ -49,7 +38,7 @@ namespace CameraExplorer
{
ShowProgress("Initializing camera...");
await _dataContext.InitializeCamera(CameraSensorLocation.Back);
await InitializeCamera(CameraSensorLocation.Back);
HideProgress();
}
@ -58,7 +47,8 @@ namespace CameraExplorer
{
CenterX = 0.5,
CenterY = 0.5,
Rotation = _dataContext.Device.SensorLocation == CameraSensorLocation.Back ? _dataContext.Device.SensorRotationInDegrees : - _dataContext.Device.SensorRotationInDegrees
Rotation = _dataContext.Device.SensorLocation == CameraSensorLocation.Back ?
_dataContext.Device.SensorRotationInDegrees : - _dataContext.Device.SensorRotationInDegrees
};
videoBrush.SetSource(_dataContext.Device);
@ -126,24 +116,26 @@ namespace CameraExplorer
CameraSensorLocation currentSensorLocation = _dataContext.Device.SensorLocation;
_dataContext.UnitializeCamera();
_dataContext.Device.Dispose();
_dataContext.Device = null;
IReadOnlyList<CameraSensorLocation> sensorLocations = PhotoCaptureDevice.AvailableSensorLocations;
if (currentSensorLocation == sensorLocations[1])
{
await _dataContext.InitializeCamera(sensorLocations[0]);
await InitializeCamera(sensorLocations[0]);
}
else
{
await _dataContext.InitializeCamera(sensorLocations[1]);
await InitializeCamera(sensorLocations[1]);
}
videoBrush.RelativeTransform = new CompositeTransform()
{
CenterX = 0.5,
CenterY = 0.5,
Rotation = _dataContext.Device.SensorLocation == CameraSensorLocation.Back ? _dataContext.Device.SensorRotationInDegrees : _dataContext.Device.SensorRotationInDegrees + 180
Rotation = _dataContext.Device.SensorLocation == CameraSensorLocation.Back ?
_dataContext.Device.SensorRotationInDegrees : _dataContext.Device.SensorRotationInDegrees + 180
};
videoBrush.SetSource(_dataContext.Device);
@ -184,6 +176,22 @@ namespace CameraExplorer
SystemTray.SetProgressIndicator(this, _progressIndicator);
}
private async Task InitializeCamera(CameraSensorLocation sensorLocation)
{
Windows.Foundation.Size initialResolution = new Windows.Foundation.Size(640, 480);
Windows.Foundation.Size previewResolution = new Windows.Foundation.Size(640, 480);
Windows.Foundation.Size captureResolution = new Windows.Foundation.Size(640, 480);
PhotoCaptureDevice d = await PhotoCaptureDevice.OpenAsync(sensorLocation, initialResolution);
await d.SetPreviewResolutionAsync(previewResolution);
await d.SetCaptureResolutionAsync(captureResolution);
d.SetProperty(KnownCameraGeneralProperties.EncodeWithOrientation, d.SensorLocation == CameraSensorLocation.Back ? d.SensorRotationInDegrees : -d.SensorRotationInDegrees);
_dataContext.Device = d;
}
private async Task AutoFocus()
{
if (!_capturing && PhotoCaptureDevice.IsFocusSupported(_dataContext.Device.SensorLocation))

Просмотреть файл

@ -1,14 +1,4 @@
using Microsoft.Devices;
using Microsoft.Phone.Shell;
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Media.Imaging;
using System.ComponentModel;
using Windows.Phone.Media.Capture;
namespace CameraExplorer

Просмотреть файл

@ -42,6 +42,7 @@ namespace CameraExplorer
_dataContext.ImageStream.Position = 0;
MediaLibrary library = new MediaLibrary();
library.SavePictureToCameraRoll("CameraExplorer_" + DateTime.Now.ToString() + ".jpg", _dataContext.ImageStream);
}
catch (Exception)

Просмотреть файл

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Deployment xmlns="http://schemas.microsoft.com/windowsphone/2012/deployment" AppPlatformVersion="8.0">
<DefaultLanguage xmlns="" code="en-US" />
<App xmlns="" ProductID="{94f53777-5783-47b2-9bcb-ce46ccb0f219}" Title="Camera Explorer" RuntimeType="Silverlight" Version="0.0.0.6" Genre="apps.normal" Author="" Description="" Publisher="" PublisherID="{cc336b25-5e51-419a-8c64-3c4a7a4383f4}">
<App xmlns="" ProductID="{94f53777-5783-47b2-9bcb-ce46ccb0f219}" Title="Camera Explorer" RuntimeType="Silverlight" Version="0.0.0.7" Genre="apps.normal" Author="" Description="" Publisher="" PublisherID="{cc336b25-5e51-419a-8c64-3c4a7a4383f4}">
<IconPath IsRelative="true" IsResource="false">Assets\ApplicationIcon.png</IconPath>
<Capabilities>
<Capability Name="ID_CAP_NETWORKING" />

Просмотреть файл

@ -15,29 +15,24 @@ namespace CameraExplorer
{
public abstract class RangeParameter<T> : Parameter
{
private Guid _guid;
private Guid _propertyId;
private T _value;
private T _minimum;
private T _maximum;
private bool _constructing;
protected RangeParameter(PhotoCaptureDevice device, Guid guid, string name)
protected RangeParameter(PhotoCaptureDevice device, Guid propertyId, string name)
: base(device, name)
{
_guid = guid;
_constructing = true;
_propertyId = propertyId;
Refresh();
_constructing = false;
}
public override void Refresh()
{
try
{
CameraCapturePropertyRange range = PhotoCaptureDevice.GetSupportedPropertyRange(Device.SensorLocation, _guid);
CameraCapturePropertyRange range = PhotoCaptureDevice.GetSupportedPropertyRange(Device.SensorLocation, _propertyId);
if (range == null)
{
@ -47,7 +42,7 @@ namespace CameraExplorer
{
Minimum = (T)range.Min;
Maximum = (T)range.Max;
Value = (T)Device.GetProperty(_guid);
_value = (T)Device.GetProperty(_propertyId);
Supported = true;
}
}
@ -112,20 +107,20 @@ namespace CameraExplorer
set
{
try
if (!_value.Equals(value))
{
if (!_constructing)
try
{
Device.SetProperty(_guid, (T)value);
_value = value;
Device.SetProperty(_propertyId, (T)value);
NotifyPropertyChanged("Value");
}
catch (Exception)
{
System.Diagnostics.Debug.WriteLine("Setting " + Name.ToLower() + " failed");
}
_value = value;
NotifyPropertyChanged("Value");
}
catch (Exception)
{
System.Diagnostics.Debug.WriteLine("Setting " + Name.ToLower() + " failed");
}
}
}

Просмотреть файл

@ -1,85 +0,0 @@
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using Windows.Phone.Media.Capture;
namespace CameraExplorer
{
class Settings : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private CameraExplorer.DataContext _dataContext = CameraExplorer.DataContext.Singleton;
private ObservableCollection<Parameter> _parameters = new ObservableCollection<Parameter>();
public ObservableCollection<Parameter> Parameters
{
get
{
return _parameters;
}
private set
{
if (_parameters != value)
{
_parameters = value;
PropertyChanged(this, new PropertyChangedEventArgs("Parameters"));
}
}
}
public void CreateParameters()
{
if (_dataContext.Device != null)
{
ObservableCollection<Parameter> newParameters = new ObservableCollection<Parameter>();
Action<Parameter> addParameter = (Parameter parameter) =>
{
if (parameter.Supported && parameter.Modifiable)
{
try
{
parameter.Refresh();
parameter.SetDefault();
newParameters.Add(parameter);
}
catch (Exception)
{
System.Diagnostics.Debug.WriteLine("Setting default to " + parameter.Name.ToLower() + " failed");
}
}
else
{
System.Diagnostics.Debug.WriteLine("Parameter " + parameter.Name.ToLower() + " is not supported or not modifiable");
}
};
addParameter(new SceneModeParameter(_dataContext.Device));
addParameter(new WhiteBalancePresetParameter(_dataContext.Device));
addParameter(new FlashModeParameter(_dataContext.Device)); // todo throws exception when setting this
addParameter(new FlashPowerParameter(_dataContext.Device));
addParameter(new IsoParameter(_dataContext.Device));
addParameter(new ExposureCompensationParameter(_dataContext.Device)); // todo does not work, does not capture after setting this
addParameter(new ManualWhiteBalanceParameter(_dataContext.Device)); // todo dependency with wb preset
addParameter(new ExposureTimeParameter(_dataContext.Device));
addParameter(new AutoFocusRangeParameter(_dataContext.Device));
addParameter(new FocusIlluminationModeParameter(_dataContext.Device));
addParameter(new CaptureResolutionParameter(_dataContext.Device));
Parameters = newParameters;
}
}
public void Refresh()
{
foreach (Parameter p in _parameters)
{
p.Refresh();
}
}
}
}

Просмотреть файл

@ -26,7 +26,7 @@
</StackPanel>
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<ListBox x:Name="listBox" ItemsSource="{Binding Settings.Parameters}">
<ListBox ItemsSource="{Binding Parameters}">
<ListBox.ItemTemplate>
<DataTemplate>
<local:SettingsTemplateSelector Content="{Binding}">

Просмотреть файл

@ -41,7 +41,7 @@ namespace CameraExplorer
{
SetScreenButtonsEnabled(false);
foreach (Parameter i in _dataContext.Settings.Parameters)
foreach (Parameter i in _dataContext.Parameters)
{
i.SetDefault();
}

Просмотреть файл

@ -37,4 +37,4 @@ namespace CameraExplorer
}
}
}
}
}

Двоичные данные
Documentation/CameraExplorer.mdzip

Двоичный файл не отображается.

Двоичные данные
Documentation/architecture.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 115 KiB

После

Ширина:  |  Высота:  |  Размер: 115 KiB