Advanced Camera APIの実用化

最近、APIの検討が始まり 、その出力はMWC-2013展示会で発表されました。









Windows Phone 8 Advanced Photo Capture API



Windows Phone 8では、カメラ設定を非常に細かく構成できます。 新しいカメラ機能の主なエントリポイントはWindows.Phone.Media.Capture.PhotoCaptureDevice



クラスであり、次のメソッドを提供します。



-サポートされているカメラ設定の設定を要求して調整します。



static CameraCapturePropertyRange SupportedPropertyRange(CameraSensorLocation sensor, Guid propertyId)





static IReadOnlyList

• object GetProperty(Guid propertyId)

void SetProperty(Guid propertyId, object value)







— , .



static bool IsFocusSupported(CameraSensorLocation sensor)





static bool IsFocusRegionSupported(CameraSensorLocation sensor)





IAsyncOperation FocusAsync()

• IAsyncOperation ResetFocusAsync()



— .



• static IReadOnlyList GetAvailablePreviewResolutions()

• static IReadOnlyList GetAvailableCaptureResolutions()

• IAsyncAction SetPreviewResolutionAsync(Size value)






IAsyncAction SetCaptureResolutionAsync(Size value)







— .



event TypedEventHandler<ICameraCaptureDevice, Object> PreviewFrameAvailable





void GetPreviewBufferArgb(out int[] pixels)





void GetPreviewBufferY(out byte[] pixels)





void GetPreviewBufferYCbCr(out byte[] pixels)







— .



CameraCaptureSequence CreateCaptureSequence(uint numberOfFrames)





IAsyncAction PrepareCaptureSequenceAsync(CameraCaptureSequence sequence)







— . . API . GUID. , .

, ID_CAP_ISV_CAMERA



WMAppManifest.xml . ID_CAP_MEDIALIB_PHOTO



.



Lumia

Nokia Lumia 820 920.





Camera Explorer — , PhotoCaptureDevice



. , .







, Camera Explorer.







Windows Phone DataContext



, Settings



PhotoCaptureDevice



.

PhotoCaptureDevice



DataContext, , , PhotoCaptureDevice



, , MainPage, .



Camera Explorer .

, PhotoCaptureDevice , Camera Explorer. , , . .



DataContext, , .



... class DataContext : INotifyPropertyChanged { ... public static DataContext Singleton { ... } public ObservableCollection<Parameter> Parameters { ... } public PhotoCaptureDevice Device { ... } public MemoryStream ImageStream { ... } }









, PhotoCaptureDevice



. MainPage xaml Canvas



VideoBrush



, .



<phone:PhoneApplicationPage x:Class="CameraExplorer.MainPage" ... > ... <Grid x:Name="LayoutRoot" ... > ... <Grid x:Name="ContentPanel" ... > <Canvas x:Name="VideoCanvas"> <Canvas.Background> <VideoBrush x:Name="videoBrush"/> </Canvas.Background> </Canvas> ... </Grid> </Grid> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar> <shell:ApplicationBarIconButton Text="capture" Click="captureButton_Click" ... /> ... </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> ... </phone:PhoneApplicationPage>







C# MainPage PhotoCaptureDevice



InitializeCamera



, DataContext. , XAML, , .



... public partial class MainPage : PhoneApplicationPage { private CameraExplorer.DataContext _dataContext = CameraExplorer.DataContext.Singleton; ... protected async override void OnNavigatedTo(NavigationEventArgs e) { if (_dataContext.Device == null) { ... await InitializeCamera(CameraSensorLocation.Back); ... } videoBrush.RelativeTransform = new CompositeTransform() { CenterX = 0.5, CenterY = 0.5, Rotation = _dataContext.Device.SensorLocation == CameraSensorLocation.Back ? _dataContext.Device.SensorRotationInDegrees : - _dataContext.Device.SensorRotationInDegrees }; videoBrush.SetSource(_dataContext.Device); ... } 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 void captureButton_Click(object sender, EventArgs e) { if (!_manuallyFocused) { await AutoFocus(); } await Capture(); } private async Task AutoFocus() { if (!_capturing && PhotoCaptureDevice.IsFocusSupported(_dataContext.Device.SensorLocation)) { ... await _dataContext.Device.FocusAsync(); ... _capturing = false; } } private async Task Capture() { if (!_capturing) { _capturing = true; MemoryStream stream = new MemoryStream(); CameraCaptureSequence sequence = _dataContext.Device.CreateCaptureSequence(1); sequence.Frames[0].CaptureStream = stream.AsOutputStream(); await _dataContext.Device.PrepareCaptureSequenceAsync(sequence); await sequence.StartCaptureAsync(); _dataContext.ImageStream = stream; ... } ... } ... }









. Camera Explorer , XAML Image BitmapImage



. , , , void MediaLibrary.SavePictureToCameraRoll(string name, Stream source)



, .



<phone:PhoneApplicationPage x:Class="CameraExplorer.PreviewPage" ... > ... <Grid x:Name="LayoutRoot" ... > ... <Grid x:Name="ContentPanel" ... > <Image x:Name="image" Stretch="UniformToFill"/> </Grid> </Grid> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar> <shell:ApplicationBarIconButton Text="save" Click="saveButton_Click" ... /> </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> ... </phone:PhoneApplicationPage>







... public partial class PreviewPage : PhoneApplicationPage { private CameraExplorer.DataContext _dataContext = CameraExplorer.DataContext.Singleton; private BitmapImage _bitmap = new BitmapImage(); protected override void OnNavigatedTo(NavigationEventArgs e) { ... _bitmap.SetSource(_dataContext.ImageStream); image.Source = _bitmap; ... } private void saveButton_Click(object sender, EventArgs e) { try { _dataContext.ImageStream.Position = 0; MediaLibrary library = new MediaLibrary(); library.SavePictureToCameraRoll("CameraExplorer_" + DateTime.Now.ToString() + ".jpg", _dataContext.ImageStream); } catch (Exception) { ... } ... } }







Camera Explorer , ArrayParameters



RangeParameters



, Parameters



. , , ComboBox



, Slider



Text



. , .

Parameter



, .



... public abstract class Parameter : INotifyPropertyChanged { ... protected Parameter(PhotoCaptureDevice device, string name) { ... } public PhotoCaptureDevice Device { ... } public string Name { ... } public bool Supported { ... } public abstract void Refresh(); ... }







, . _propertyId



, static CameraCapturePropertyRange PhotoCaptureDevice.GetSupportedPropertyRange(CameraSensorLocation sensor, Guid propertyId)



. object PhotoCaptureDevice.GetProperty(Guid propertyId)



. void PhotoCaptureDevice.SetProperty(Guid propertyId, object value)



.



... public abstract class RangeParameter<T> : Parameter { private Guid _propertyId; private T _value; ... protected RangeParameter(PhotoCaptureDevice device, Guid propertyId, string name) : base(device, name) { ... } public override void Refresh() { try { CameraCapturePropertyRange range = PhotoCaptureDevice.GetSupportedPropertyRange( Device.SensorLocation, _propertyId); if (range == null) { Supported = false; } else { Minimum = (T)range.Min; Maximum = (T)range.Max; _value = (T)Device.GetProperty(_propertyId); Supported = true; } } catch (Exception) { Supported = false; } ... } public T Minimum { ... } public T Maximum { ... } public T Value { ... set { if (!_value.Equals(value)) { try { Device.SetProperty(_propertyId, (T)value); _value = value; ... } catch (Exception) { ... } } } } ... }







ExposureCompensationParameter



, Guid RangeParameter



KnownCameraPhotoProperties.ExposureCompensation



, — , . , Int32



, .



... public class ExposureCompensationParameter : RangeParameter<Int32> { public ExposureCompensationParameter(PhotoCaptureDevice device) : base(device, KnownCameraPhotoProperties.ExposureCompensation, "Exposure compensation") { } ... }







Camera Explorer ArrayParameter



. . — void PopulateOptions()



void SetOption(ArrayParameterOption option)



, .



... public class ArrayParameterOption { ... public ArrayParameterOption(dynamic value, string name) { ... } public dynamic Value { ... } public string Name { ... } ... } public abstract class ArrayParameter : Parameter, IReadOnlyCollection<ArrayParameterOption> { private List<ArrayParameterOption> _options = new List<ArrayParameterOption>(); private ArrayParameterOption _selectedOption; ... public ArrayParameter(PhotoCaptureDevice device, string name) : base(device, name) { ... } public override void Refresh() { ... _options.Clear(); _selectedOption = null; try { PopulateOptions(); Supported = _options.Count > 0; } catch (Exception) { Supported = false; } ... } protected List<ArrayParameterOption> Options { ... } public ArrayParameterOption SelectedOption { ... set { if (_selectedOption != value) { ... if (_selectedOption != null)) { SetOption(value); } _selectedOption = value; } } } protected abstract void PopulateOptions(); protected abstract void SetOption(ArrayParameterOption option); ... }







, , , . void PopulateOptions()



, , ArrayParameterOption



SelectedOption



, void SetOption(ArrayParameterOption option)



. , static IReadOnlyList , KnownCameraPhotoProperties.SceneMode



object PhotoCaptureDevice.GetProperty(Guid propertyId)



. void PhotoCaptureDevice.SetProperty(Guid propertyId, object value)



.



... public class SceneModeParameter : ArrayParameter { public SceneModeParameter(PhotoCaptureDevice device) : base(device, KnownCameraPhotoProperties.SceneMode, "Scene mode") { } protected override void PopulateOptions() { IReadOnlyList<object> supportedValues = PhotoCaptureDevice.GetSupportedPropertyValues( Device.SensorLocation, PropertyId); object value = Device.GetProperty(PropertyId); foreach (dynamic i in supportedValues) { CameraSceneMode csm = (CameraSceneMode)i; ArrayParameterOption option = new ArrayParameterOption(csm, csm.ToString()); Options.Add(option); if (i.Equals(value)) { SelectedOption = option; } } } protected override void SetOption(ArrayParameterOption option) { Device.SetProperty(PropertyId, option.Value); } ... }







Tap-to-focus

«». Tap-to-focus , , , . , Tap-to-focus .



Rectangle



Canvas



, :



<Rectangle x:Name="FocusIndicator" Stroke="Red" Opacity="0.7" Width="80" Height="80" StrokeThickness="5" Visibility="Collapsed"/>







, .

Canvas Tap:



public MainPage() { ... VideoCanvas.Tap += new EventHandler<GestureEventArgs>(videoCanvas_Tap); ... }







. API- , VideoCanvas



, , .



, . , , , .



, , , , .



private async void videoCanvas_Tap(object sender, GestureEventArgs e) { System.Windows.Point uiTapPoint = e.GetPosition(VideoCanvas); if (PhotoCaptureDevice.IsFocusRegionSupported(_dataContext.Device.SensorLocation) && _focusSemaphore.WaitOne(0)) { // . Windows.Foundation.Point tapPoint = new Windows.Foundation.Point(uiTapPoint.X, uiTapPoint.Y); double xRatio = VideoCanvas.ActualWidth / _dataContext.Device.PreviewResolution.Width; double yRatio = VideoCanvas.ActualHeight / _dataContext.Device.PreviewResolution.Height; // , Windows.Foundation.Point displayOrigin = new Windows.Foundation.Point( tapPoint.X - _focusRegionSize.Width / 2, tapPoint.Y - _focusRegionSize.Height / 2); // canvas Windows.Foundation.Point viewFinderOrigin = new Windows.Foundation.Point( displayOrigin.X / xRatio, displayOrigin.Y / yRatio); Windows.Foundation.Rect focusrect = new Windows.Foundation.Rect( viewFinderOrigin, _focusRegionSize); // Windows.Foundation.Rect viewPortRect = new Windows.Foundation.Rect( 0, 0, _dataContext.Device.PreviewResolution.Width, _dataContext.Device.PreviewResolution.Height); focusrect.Intersect(viewPortRect); _dataContext.Device.FocusRegion = focusrect; // FocusIndicator.SetValue(Shape.StrokeProperty, _notFocusedBrush); FocusIndicator.SetValue(Canvas.LeftProperty, uiTapPoint.X - _focusRegionSize.Width / 2); FocusIndicator.SetValue(Canvas.TopProperty, uiTapPoint.Y - _focusRegionSize.Height / 2); FocusIndicator.SetValue(Canvas.VisibilityProperty, Visibility.Visible); CameraFocusStatus status = await _dataContext.Device.FocusAsync(); if (status == CameraFocusStatus.Locked) { FocusIndicator.SetValue(Shape.StrokeProperty, _focusedBrush); _manuallyFocused = true; _dataContext.Device.SetProperty( KnownCameraPhotoProperties.LockedAutoFocusParameters, AutoFocusParameters.Exposure & AutoFocusParameters.Focus & AutoFocusParameters.WhiteBalance); } else { _manuallyFocused = false; _dataContext.Device.SetProperty( KnownCameraPhotoProperties.LockedAutoFocusParameters, AutoFocusParameters.None); } _focusSemaphore.Release(); } }







, . FocusAsync



, , . , WaitOne



, , , false



— , .





, «», Lens Picker. «» , . Lens Picker, XML App:



<Extensions> <Extension ExtensionName="Camera_Capture_App" ConsumerId="{5B04B775-356B-4AA0-AAF8-6491FFEA5631]" TaskId="_default" /> </Extensions>







, Lens Picker, . , Lens Picker Assets



. , Lens design guidelines for Windows Phone .



Maps API.




























static IReadOnlyList

• object GetProperty(Guid propertyId)






void SetProperty(Guid propertyId, object value)







— , .



static bool IsFocusSupported(CameraSensorLocation sensor)





static bool IsFocusRegionSupported(CameraSensorLocation sensor)





IAsyncOperation FocusAsync()

• IAsyncOperation ResetFocusAsync()



— .



• static IReadOnlyList GetAvailablePreviewResolutions()

• static IReadOnlyList GetAvailableCaptureResolutions()

• IAsyncAction SetPreviewResolutionAsync(Size value)






IAsyncAction SetCaptureResolutionAsync(Size value)







— .



event TypedEventHandler<ICameraCaptureDevice, Object> PreviewFrameAvailable





void GetPreviewBufferArgb(out int[] pixels)





void GetPreviewBufferY(out byte[] pixels)





void GetPreviewBufferYCbCr(out byte[] pixels)







— .



CameraCaptureSequence CreateCaptureSequence(uint numberOfFrames)





IAsyncAction PrepareCaptureSequenceAsync(CameraCaptureSequence sequence)







— . . API . GUID. , .

, ID_CAP_ISV_CAMERA



WMAppManifest.xml . ID_CAP_MEDIALIB_PHOTO



.



Lumia

Nokia Lumia 820 920.





Camera Explorer — , PhotoCaptureDevice



. , .







, Camera Explorer.







Windows Phone DataContext



, Settings



PhotoCaptureDevice



.

PhotoCaptureDevice



DataContext, , , PhotoCaptureDevice



, , MainPage, .



Camera Explorer .

, PhotoCaptureDevice , Camera Explorer. , , . .



DataContext, , .



... class DataContext : INotifyPropertyChanged { ... public static DataContext Singleton { ... } public ObservableCollection<Parameter> Parameters { ... } public PhotoCaptureDevice Device { ... } public MemoryStream ImageStream { ... } }









, PhotoCaptureDevice



. MainPage xaml Canvas



VideoBrush



, .



<phone:PhoneApplicationPage x:Class="CameraExplorer.MainPage" ... > ... <Grid x:Name="LayoutRoot" ... > ... <Grid x:Name="ContentPanel" ... > <Canvas x:Name="VideoCanvas"> <Canvas.Background> <VideoBrush x:Name="videoBrush"/> </Canvas.Background> </Canvas> ... </Grid> </Grid> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar> <shell:ApplicationBarIconButton Text="capture" Click="captureButton_Click" ... /> ... </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> ... </phone:PhoneApplicationPage>







C# MainPage PhotoCaptureDevice



InitializeCamera



, DataContext. , XAML, , .



... public partial class MainPage : PhoneApplicationPage { private CameraExplorer.DataContext _dataContext = CameraExplorer.DataContext.Singleton; ... protected async override void OnNavigatedTo(NavigationEventArgs e) { if (_dataContext.Device == null) { ... await InitializeCamera(CameraSensorLocation.Back); ... } videoBrush.RelativeTransform = new CompositeTransform() { CenterX = 0.5, CenterY = 0.5, Rotation = _dataContext.Device.SensorLocation == CameraSensorLocation.Back ? _dataContext.Device.SensorRotationInDegrees : - _dataContext.Device.SensorRotationInDegrees }; videoBrush.SetSource(_dataContext.Device); ... } 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 void captureButton_Click(object sender, EventArgs e) { if (!_manuallyFocused) { await AutoFocus(); } await Capture(); } private async Task AutoFocus() { if (!_capturing && PhotoCaptureDevice.IsFocusSupported(_dataContext.Device.SensorLocation)) { ... await _dataContext.Device.FocusAsync(); ... _capturing = false; } } private async Task Capture() { if (!_capturing) { _capturing = true; MemoryStream stream = new MemoryStream(); CameraCaptureSequence sequence = _dataContext.Device.CreateCaptureSequence(1); sequence.Frames[0].CaptureStream = stream.AsOutputStream(); await _dataContext.Device.PrepareCaptureSequenceAsync(sequence); await sequence.StartCaptureAsync(); _dataContext.ImageStream = stream; ... } ... } ... }









. Camera Explorer , XAML Image BitmapImage



. , , , void MediaLibrary.SavePictureToCameraRoll(string name, Stream source)



, .



<phone:PhoneApplicationPage x:Class="CameraExplorer.PreviewPage" ... > ... <Grid x:Name="LayoutRoot" ... > ... <Grid x:Name="ContentPanel" ... > <Image x:Name="image" Stretch="UniformToFill"/> </Grid> </Grid> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar> <shell:ApplicationBarIconButton Text="save" Click="saveButton_Click" ... /> </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> ... </phone:PhoneApplicationPage>







... public partial class PreviewPage : PhoneApplicationPage { private CameraExplorer.DataContext _dataContext = CameraExplorer.DataContext.Singleton; private BitmapImage _bitmap = new BitmapImage(); protected override void OnNavigatedTo(NavigationEventArgs e) { ... _bitmap.SetSource(_dataContext.ImageStream); image.Source = _bitmap; ... } private void saveButton_Click(object sender, EventArgs e) { try { _dataContext.ImageStream.Position = 0; MediaLibrary library = new MediaLibrary(); library.SavePictureToCameraRoll("CameraExplorer_" + DateTime.Now.ToString() + ".jpg", _dataContext.ImageStream); } catch (Exception) { ... } ... } }







Camera Explorer , ArrayParameters



RangeParameters



, Parameters



. , , ComboBox



, Slider



Text



. , .

Parameter



, .



... public abstract class Parameter : INotifyPropertyChanged { ... protected Parameter(PhotoCaptureDevice device, string name) { ... } public PhotoCaptureDevice Device { ... } public string Name { ... } public bool Supported { ... } public abstract void Refresh(); ... }







, . _propertyId



, static CameraCapturePropertyRange PhotoCaptureDevice.GetSupportedPropertyRange(CameraSensorLocation sensor, Guid propertyId)



. object PhotoCaptureDevice.GetProperty(Guid propertyId)



. void PhotoCaptureDevice.SetProperty(Guid propertyId, object value)



.



... public abstract class RangeParameter<T> : Parameter { private Guid _propertyId; private T _value; ... protected RangeParameter(PhotoCaptureDevice device, Guid propertyId, string name) : base(device, name) { ... } public override void Refresh() { try { CameraCapturePropertyRange range = PhotoCaptureDevice.GetSupportedPropertyRange( Device.SensorLocation, _propertyId); if (range == null) { Supported = false; } else { Minimum = (T)range.Min; Maximum = (T)range.Max; _value = (T)Device.GetProperty(_propertyId); Supported = true; } } catch (Exception) { Supported = false; } ... } public T Minimum { ... } public T Maximum { ... } public T Value { ... set { if (!_value.Equals(value)) { try { Device.SetProperty(_propertyId, (T)value); _value = value; ... } catch (Exception) { ... } } } } ... }







ExposureCompensationParameter



, Guid RangeParameter



KnownCameraPhotoProperties.ExposureCompensation



, — , . , Int32



, .



... public class ExposureCompensationParameter : RangeParameter<Int32> { public ExposureCompensationParameter(PhotoCaptureDevice device) : base(device, KnownCameraPhotoProperties.ExposureCompensation, "Exposure compensation") { } ... }







Camera Explorer ArrayParameter



. . — void PopulateOptions()



void SetOption(ArrayParameterOption option)



, .



... public class ArrayParameterOption { ... public ArrayParameterOption(dynamic value, string name) { ... } public dynamic Value { ... } public string Name { ... } ... } public abstract class ArrayParameter : Parameter, IReadOnlyCollection<ArrayParameterOption> { private List<ArrayParameterOption> _options = new List<ArrayParameterOption>(); private ArrayParameterOption _selectedOption; ... public ArrayParameter(PhotoCaptureDevice device, string name) : base(device, name) { ... } public override void Refresh() { ... _options.Clear(); _selectedOption = null; try { PopulateOptions(); Supported = _options.Count > 0; } catch (Exception) { Supported = false; } ... } protected List<ArrayParameterOption> Options { ... } public ArrayParameterOption SelectedOption { ... set { if (_selectedOption != value) { ... if (_selectedOption != null)) { SetOption(value); } _selectedOption = value; } } } protected abstract void PopulateOptions(); protected abstract void SetOption(ArrayParameterOption option); ... }







, , , . void PopulateOptions()



, , ArrayParameterOption



SelectedOption



, void SetOption(ArrayParameterOption option)



. , static IReadOnlyList , KnownCameraPhotoProperties.SceneMode



object PhotoCaptureDevice.GetProperty(Guid propertyId)



. void PhotoCaptureDevice.SetProperty(Guid propertyId, object value)



.



... public class SceneModeParameter : ArrayParameter { public SceneModeParameter(PhotoCaptureDevice device) : base(device, KnownCameraPhotoProperties.SceneMode, "Scene mode") { } protected override void PopulateOptions() { IReadOnlyList<object> supportedValues = PhotoCaptureDevice.GetSupportedPropertyValues( Device.SensorLocation, PropertyId); object value = Device.GetProperty(PropertyId); foreach (dynamic i in supportedValues) { CameraSceneMode csm = (CameraSceneMode)i; ArrayParameterOption option = new ArrayParameterOption(csm, csm.ToString()); Options.Add(option); if (i.Equals(value)) { SelectedOption = option; } } } protected override void SetOption(ArrayParameterOption option) { Device.SetProperty(PropertyId, option.Value); } ... }







Tap-to-focus

«». Tap-to-focus , , , . , Tap-to-focus .



Rectangle



Canvas



, :



<Rectangle x:Name="FocusIndicator" Stroke="Red" Opacity="0.7" Width="80" Height="80" StrokeThickness="5" Visibility="Collapsed"/>







, .

Canvas Tap:



public MainPage() { ... VideoCanvas.Tap += new EventHandler<GestureEventArgs>(videoCanvas_Tap); ... }







. API- , VideoCanvas



, , .



, . , , , .



, , , , .



private async void videoCanvas_Tap(object sender, GestureEventArgs e) { System.Windows.Point uiTapPoint = e.GetPosition(VideoCanvas); if (PhotoCaptureDevice.IsFocusRegionSupported(_dataContext.Device.SensorLocation) && _focusSemaphore.WaitOne(0)) { // . Windows.Foundation.Point tapPoint = new Windows.Foundation.Point(uiTapPoint.X, uiTapPoint.Y); double xRatio = VideoCanvas.ActualWidth / _dataContext.Device.PreviewResolution.Width; double yRatio = VideoCanvas.ActualHeight / _dataContext.Device.PreviewResolution.Height; // , Windows.Foundation.Point displayOrigin = new Windows.Foundation.Point( tapPoint.X - _focusRegionSize.Width / 2, tapPoint.Y - _focusRegionSize.Height / 2); // canvas Windows.Foundation.Point viewFinderOrigin = new Windows.Foundation.Point( displayOrigin.X / xRatio, displayOrigin.Y / yRatio); Windows.Foundation.Rect focusrect = new Windows.Foundation.Rect( viewFinderOrigin, _focusRegionSize); // Windows.Foundation.Rect viewPortRect = new Windows.Foundation.Rect( 0, 0, _dataContext.Device.PreviewResolution.Width, _dataContext.Device.PreviewResolution.Height); focusrect.Intersect(viewPortRect); _dataContext.Device.FocusRegion = focusrect; // FocusIndicator.SetValue(Shape.StrokeProperty, _notFocusedBrush); FocusIndicator.SetValue(Canvas.LeftProperty, uiTapPoint.X - _focusRegionSize.Width / 2); FocusIndicator.SetValue(Canvas.TopProperty, uiTapPoint.Y - _focusRegionSize.Height / 2); FocusIndicator.SetValue(Canvas.VisibilityProperty, Visibility.Visible); CameraFocusStatus status = await _dataContext.Device.FocusAsync(); if (status == CameraFocusStatus.Locked) { FocusIndicator.SetValue(Shape.StrokeProperty, _focusedBrush); _manuallyFocused = true; _dataContext.Device.SetProperty( KnownCameraPhotoProperties.LockedAutoFocusParameters, AutoFocusParameters.Exposure & AutoFocusParameters.Focus & AutoFocusParameters.WhiteBalance); } else { _manuallyFocused = false; _dataContext.Device.SetProperty( KnownCameraPhotoProperties.LockedAutoFocusParameters, AutoFocusParameters.None); } _focusSemaphore.Release(); } }







, . FocusAsync



, , . , WaitOne



, , , false



— , .





, «», Lens Picker. «» , . Lens Picker, XML App:



<Extensions> <Extension ExtensionName="Camera_Capture_App" ConsumerId="{5B04B775-356B-4AA0-AAF8-6491FFEA5631]" TaskId="_default" /> </Extensions>







, Lens Picker, . , Lens Picker Assets



. , Lens design guidelines for Windows Phone .



Maps API.
























static IReadOnlyList

• object GetProperty(Guid propertyId)






void SetProperty(Guid propertyId, object value)







— , .



static bool IsFocusSupported(CameraSensorLocation sensor)





static bool IsFocusRegionSupported(CameraSensorLocation sensor)





IAsyncOperation FocusAsync()

• IAsyncOperation ResetFocusAsync()



— .



• static IReadOnlyList GetAvailablePreviewResolutions()

• static IReadOnlyList GetAvailableCaptureResolutions()

• IAsyncAction SetPreviewResolutionAsync(Size value)






IAsyncAction SetCaptureResolutionAsync(Size value)







— .



event TypedEventHandler<ICameraCaptureDevice, Object> PreviewFrameAvailable





void GetPreviewBufferArgb(out int[] pixels)





void GetPreviewBufferY(out byte[] pixels)





void GetPreviewBufferYCbCr(out byte[] pixels)







— .



CameraCaptureSequence CreateCaptureSequence(uint numberOfFrames)





IAsyncAction PrepareCaptureSequenceAsync(CameraCaptureSequence sequence)







— . . API . GUID. , .

, ID_CAP_ISV_CAMERA



WMAppManifest.xml . ID_CAP_MEDIALIB_PHOTO



.



Lumia

Nokia Lumia 820 920.





Camera Explorer — , PhotoCaptureDevice



. , .







, Camera Explorer.







Windows Phone DataContext



, Settings



PhotoCaptureDevice



.

PhotoCaptureDevice



DataContext, , , PhotoCaptureDevice



, , MainPage, .



Camera Explorer .

, PhotoCaptureDevice , Camera Explorer. , , . .



DataContext, , .



... class DataContext : INotifyPropertyChanged { ... public static DataContext Singleton { ... } public ObservableCollection<Parameter> Parameters { ... } public PhotoCaptureDevice Device { ... } public MemoryStream ImageStream { ... } }









, PhotoCaptureDevice



. MainPage xaml Canvas



VideoBrush



, .



<phone:PhoneApplicationPage x:Class="CameraExplorer.MainPage" ... > ... <Grid x:Name="LayoutRoot" ... > ... <Grid x:Name="ContentPanel" ... > <Canvas x:Name="VideoCanvas"> <Canvas.Background> <VideoBrush x:Name="videoBrush"/> </Canvas.Background> </Canvas> ... </Grid> </Grid> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar> <shell:ApplicationBarIconButton Text="capture" Click="captureButton_Click" ... /> ... </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> ... </phone:PhoneApplicationPage>







C# MainPage PhotoCaptureDevice



InitializeCamera



, DataContext. , XAML, , .



... public partial class MainPage : PhoneApplicationPage { private CameraExplorer.DataContext _dataContext = CameraExplorer.DataContext.Singleton; ... protected async override void OnNavigatedTo(NavigationEventArgs e) { if (_dataContext.Device == null) { ... await InitializeCamera(CameraSensorLocation.Back); ... } videoBrush.RelativeTransform = new CompositeTransform() { CenterX = 0.5, CenterY = 0.5, Rotation = _dataContext.Device.SensorLocation == CameraSensorLocation.Back ? _dataContext.Device.SensorRotationInDegrees : - _dataContext.Device.SensorRotationInDegrees }; videoBrush.SetSource(_dataContext.Device); ... } 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 void captureButton_Click(object sender, EventArgs e) { if (!_manuallyFocused) { await AutoFocus(); } await Capture(); } private async Task AutoFocus() { if (!_capturing && PhotoCaptureDevice.IsFocusSupported(_dataContext.Device.SensorLocation)) { ... await _dataContext.Device.FocusAsync(); ... _capturing = false; } } private async Task Capture() { if (!_capturing) { _capturing = true; MemoryStream stream = new MemoryStream(); CameraCaptureSequence sequence = _dataContext.Device.CreateCaptureSequence(1); sequence.Frames[0].CaptureStream = stream.AsOutputStream(); await _dataContext.Device.PrepareCaptureSequenceAsync(sequence); await sequence.StartCaptureAsync(); _dataContext.ImageStream = stream; ... } ... } ... }









. Camera Explorer , XAML Image BitmapImage



. , , , void MediaLibrary.SavePictureToCameraRoll(string name, Stream source)



, .



<phone:PhoneApplicationPage x:Class="CameraExplorer.PreviewPage" ... > ... <Grid x:Name="LayoutRoot" ... > ... <Grid x:Name="ContentPanel" ... > <Image x:Name="image" Stretch="UniformToFill"/> </Grid> </Grid> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar> <shell:ApplicationBarIconButton Text="save" Click="saveButton_Click" ... /> </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> ... </phone:PhoneApplicationPage>







... public partial class PreviewPage : PhoneApplicationPage { private CameraExplorer.DataContext _dataContext = CameraExplorer.DataContext.Singleton; private BitmapImage _bitmap = new BitmapImage(); protected override void OnNavigatedTo(NavigationEventArgs e) { ... _bitmap.SetSource(_dataContext.ImageStream); image.Source = _bitmap; ... } private void saveButton_Click(object sender, EventArgs e) { try { _dataContext.ImageStream.Position = 0; MediaLibrary library = new MediaLibrary(); library.SavePictureToCameraRoll("CameraExplorer_" + DateTime.Now.ToString() + ".jpg", _dataContext.ImageStream); } catch (Exception) { ... } ... } }







Camera Explorer , ArrayParameters



RangeParameters



, Parameters



. , , ComboBox



, Slider



Text



. , .

Parameter



, .



... public abstract class Parameter : INotifyPropertyChanged { ... protected Parameter(PhotoCaptureDevice device, string name) { ... } public PhotoCaptureDevice Device { ... } public string Name { ... } public bool Supported { ... } public abstract void Refresh(); ... }







, . _propertyId



, static CameraCapturePropertyRange PhotoCaptureDevice.GetSupportedPropertyRange(CameraSensorLocation sensor, Guid propertyId)



. object PhotoCaptureDevice.GetProperty(Guid propertyId)



. void PhotoCaptureDevice.SetProperty(Guid propertyId, object value)



.



... public abstract class RangeParameter<T> : Parameter { private Guid _propertyId; private T _value; ... protected RangeParameter(PhotoCaptureDevice device, Guid propertyId, string name) : base(device, name) { ... } public override void Refresh() { try { CameraCapturePropertyRange range = PhotoCaptureDevice.GetSupportedPropertyRange( Device.SensorLocation, _propertyId); if (range == null) { Supported = false; } else { Minimum = (T)range.Min; Maximum = (T)range.Max; _value = (T)Device.GetProperty(_propertyId); Supported = true; } } catch (Exception) { Supported = false; } ... } public T Minimum { ... } public T Maximum { ... } public T Value { ... set { if (!_value.Equals(value)) { try { Device.SetProperty(_propertyId, (T)value); _value = value; ... } catch (Exception) { ... } } } } ... }







ExposureCompensationParameter



, Guid RangeParameter



KnownCameraPhotoProperties.ExposureCompensation



, — , . , Int32



, .



... public class ExposureCompensationParameter : RangeParameter<Int32> { public ExposureCompensationParameter(PhotoCaptureDevice device) : base(device, KnownCameraPhotoProperties.ExposureCompensation, "Exposure compensation") { } ... }







Camera Explorer ArrayParameter



. . — void PopulateOptions()



void SetOption(ArrayParameterOption option)



, .



... public class ArrayParameterOption { ... public ArrayParameterOption(dynamic value, string name) { ... } public dynamic Value { ... } public string Name { ... } ... } public abstract class ArrayParameter : Parameter, IReadOnlyCollection<ArrayParameterOption> { private List<ArrayParameterOption> _options = new List<ArrayParameterOption>(); private ArrayParameterOption _selectedOption; ... public ArrayParameter(PhotoCaptureDevice device, string name) : base(device, name) { ... } public override void Refresh() { ... _options.Clear(); _selectedOption = null; try { PopulateOptions(); Supported = _options.Count > 0; } catch (Exception) { Supported = false; } ... } protected List<ArrayParameterOption> Options { ... } public ArrayParameterOption SelectedOption { ... set { if (_selectedOption != value) { ... if (_selectedOption != null)) { SetOption(value); } _selectedOption = value; } } } protected abstract void PopulateOptions(); protected abstract void SetOption(ArrayParameterOption option); ... }







, , , . void PopulateOptions()



, , ArrayParameterOption



SelectedOption



, void SetOption(ArrayParameterOption option)



. , static IReadOnlyList , KnownCameraPhotoProperties.SceneMode



object PhotoCaptureDevice.GetProperty(Guid propertyId)



. void PhotoCaptureDevice.SetProperty(Guid propertyId, object value)



.



... public class SceneModeParameter : ArrayParameter { public SceneModeParameter(PhotoCaptureDevice device) : base(device, KnownCameraPhotoProperties.SceneMode, "Scene mode") { } protected override void PopulateOptions() { IReadOnlyList<object> supportedValues = PhotoCaptureDevice.GetSupportedPropertyValues( Device.SensorLocation, PropertyId); object value = Device.GetProperty(PropertyId); foreach (dynamic i in supportedValues) { CameraSceneMode csm = (CameraSceneMode)i; ArrayParameterOption option = new ArrayParameterOption(csm, csm.ToString()); Options.Add(option); if (i.Equals(value)) { SelectedOption = option; } } } protected override void SetOption(ArrayParameterOption option) { Device.SetProperty(PropertyId, option.Value); } ... }







Tap-to-focus

«». Tap-to-focus , , , . , Tap-to-focus .



Rectangle



Canvas



, :



<Rectangle x:Name="FocusIndicator" Stroke="Red" Opacity="0.7" Width="80" Height="80" StrokeThickness="5" Visibility="Collapsed"/>







, .

Canvas Tap:



public MainPage() { ... VideoCanvas.Tap += new EventHandler<GestureEventArgs>(videoCanvas_Tap); ... }







. API- , VideoCanvas



, , .



, . , , , .



, , , , .



private async void videoCanvas_Tap(object sender, GestureEventArgs e) { System.Windows.Point uiTapPoint = e.GetPosition(VideoCanvas); if (PhotoCaptureDevice.IsFocusRegionSupported(_dataContext.Device.SensorLocation) && _focusSemaphore.WaitOne(0)) { // . Windows.Foundation.Point tapPoint = new Windows.Foundation.Point(uiTapPoint.X, uiTapPoint.Y); double xRatio = VideoCanvas.ActualWidth / _dataContext.Device.PreviewResolution.Width; double yRatio = VideoCanvas.ActualHeight / _dataContext.Device.PreviewResolution.Height; // , Windows.Foundation.Point displayOrigin = new Windows.Foundation.Point( tapPoint.X - _focusRegionSize.Width / 2, tapPoint.Y - _focusRegionSize.Height / 2); // canvas Windows.Foundation.Point viewFinderOrigin = new Windows.Foundation.Point( displayOrigin.X / xRatio, displayOrigin.Y / yRatio); Windows.Foundation.Rect focusrect = new Windows.Foundation.Rect( viewFinderOrigin, _focusRegionSize); // Windows.Foundation.Rect viewPortRect = new Windows.Foundation.Rect( 0, 0, _dataContext.Device.PreviewResolution.Width, _dataContext.Device.PreviewResolution.Height); focusrect.Intersect(viewPortRect); _dataContext.Device.FocusRegion = focusrect; // FocusIndicator.SetValue(Shape.StrokeProperty, _notFocusedBrush); FocusIndicator.SetValue(Canvas.LeftProperty, uiTapPoint.X - _focusRegionSize.Width / 2); FocusIndicator.SetValue(Canvas.TopProperty, uiTapPoint.Y - _focusRegionSize.Height / 2); FocusIndicator.SetValue(Canvas.VisibilityProperty, Visibility.Visible); CameraFocusStatus status = await _dataContext.Device.FocusAsync(); if (status == CameraFocusStatus.Locked) { FocusIndicator.SetValue(Shape.StrokeProperty, _focusedBrush); _manuallyFocused = true; _dataContext.Device.SetProperty( KnownCameraPhotoProperties.LockedAutoFocusParameters, AutoFocusParameters.Exposure & AutoFocusParameters.Focus & AutoFocusParameters.WhiteBalance); } else { _manuallyFocused = false; _dataContext.Device.SetProperty( KnownCameraPhotoProperties.LockedAutoFocusParameters, AutoFocusParameters.None); } _focusSemaphore.Release(); } }







, . FocusAsync



, , . , WaitOne



, , , false



— , .





, «», Lens Picker. «» , . Lens Picker, XML App:



<Extensions> <Extension ExtensionName="Camera_Capture_App" ConsumerId="{5B04B775-356B-4AA0-AAF8-6491FFEA5631]" TaskId="_default" /> </Extensions>







, Lens Picker, . , Lens Picker Assets



. , Lens design guidelines for Windows Phone .



Maps API.
























static IReadOnlyList

• object GetProperty(Guid propertyId)






void SetProperty(Guid propertyId, object value)







— , .



static bool IsFocusSupported(CameraSensorLocation sensor)





static bool IsFocusRegionSupported(CameraSensorLocation sensor)





IAsyncOperation FocusAsync()

• IAsyncOperation ResetFocusAsync()



— .



• static IReadOnlyList GetAvailablePreviewResolutions()

• static IReadOnlyList GetAvailableCaptureResolutions()

• IAsyncAction SetPreviewResolutionAsync(Size value)






IAsyncAction SetCaptureResolutionAsync(Size value)







— .



event TypedEventHandler<ICameraCaptureDevice, Object> PreviewFrameAvailable





void GetPreviewBufferArgb(out int[] pixels)





void GetPreviewBufferY(out byte[] pixels)





void GetPreviewBufferYCbCr(out byte[] pixels)







— .



CameraCaptureSequence CreateCaptureSequence(uint numberOfFrames)





IAsyncAction PrepareCaptureSequenceAsync(CameraCaptureSequence sequence)







— . . API . GUID. , .

, ID_CAP_ISV_CAMERA



WMAppManifest.xml . ID_CAP_MEDIALIB_PHOTO



.



Lumia

Nokia Lumia 820 920.





Camera Explorer — , PhotoCaptureDevice



. , .







, Camera Explorer.







Windows Phone DataContext



, Settings



PhotoCaptureDevice



.

PhotoCaptureDevice



DataContext, , , PhotoCaptureDevice



, , MainPage, .



Camera Explorer .

, PhotoCaptureDevice , Camera Explorer. , , . .



DataContext, , .



... class DataContext : INotifyPropertyChanged { ... public static DataContext Singleton { ... } public ObservableCollection<Parameter> Parameters { ... } public PhotoCaptureDevice Device { ... } public MemoryStream ImageStream { ... } }









, PhotoCaptureDevice



. MainPage xaml Canvas



VideoBrush



, .



<phone:PhoneApplicationPage x:Class="CameraExplorer.MainPage" ... > ... <Grid x:Name="LayoutRoot" ... > ... <Grid x:Name="ContentPanel" ... > <Canvas x:Name="VideoCanvas"> <Canvas.Background> <VideoBrush x:Name="videoBrush"/> </Canvas.Background> </Canvas> ... </Grid> </Grid> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar> <shell:ApplicationBarIconButton Text="capture" Click="captureButton_Click" ... /> ... </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> ... </phone:PhoneApplicationPage>







C# MainPage PhotoCaptureDevice



InitializeCamera



, DataContext. , XAML, , .



... public partial class MainPage : PhoneApplicationPage { private CameraExplorer.DataContext _dataContext = CameraExplorer.DataContext.Singleton; ... protected async override void OnNavigatedTo(NavigationEventArgs e) { if (_dataContext.Device == null) { ... await InitializeCamera(CameraSensorLocation.Back); ... } videoBrush.RelativeTransform = new CompositeTransform() { CenterX = 0.5, CenterY = 0.5, Rotation = _dataContext.Device.SensorLocation == CameraSensorLocation.Back ? _dataContext.Device.SensorRotationInDegrees : - _dataContext.Device.SensorRotationInDegrees }; videoBrush.SetSource(_dataContext.Device); ... } 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 void captureButton_Click(object sender, EventArgs e) { if (!_manuallyFocused) { await AutoFocus(); } await Capture(); } private async Task AutoFocus() { if (!_capturing && PhotoCaptureDevice.IsFocusSupported(_dataContext.Device.SensorLocation)) { ... await _dataContext.Device.FocusAsync(); ... _capturing = false; } } private async Task Capture() { if (!_capturing) { _capturing = true; MemoryStream stream = new MemoryStream(); CameraCaptureSequence sequence = _dataContext.Device.CreateCaptureSequence(1); sequence.Frames[0].CaptureStream = stream.AsOutputStream(); await _dataContext.Device.PrepareCaptureSequenceAsync(sequence); await sequence.StartCaptureAsync(); _dataContext.ImageStream = stream; ... } ... } ... }









. Camera Explorer , XAML Image BitmapImage



. , , , void MediaLibrary.SavePictureToCameraRoll(string name, Stream source)



, .



<phone:PhoneApplicationPage x:Class="CameraExplorer.PreviewPage" ... > ... <Grid x:Name="LayoutRoot" ... > ... <Grid x:Name="ContentPanel" ... > <Image x:Name="image" Stretch="UniformToFill"/> </Grid> </Grid> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar> <shell:ApplicationBarIconButton Text="save" Click="saveButton_Click" ... /> </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> ... </phone:PhoneApplicationPage>







... public partial class PreviewPage : PhoneApplicationPage { private CameraExplorer.DataContext _dataContext = CameraExplorer.DataContext.Singleton; private BitmapImage _bitmap = new BitmapImage(); protected override void OnNavigatedTo(NavigationEventArgs e) { ... _bitmap.SetSource(_dataContext.ImageStream); image.Source = _bitmap; ... } private void saveButton_Click(object sender, EventArgs e) { try { _dataContext.ImageStream.Position = 0; MediaLibrary library = new MediaLibrary(); library.SavePictureToCameraRoll("CameraExplorer_" + DateTime.Now.ToString() + ".jpg", _dataContext.ImageStream); } catch (Exception) { ... } ... } }







Camera Explorer , ArrayParameters



RangeParameters



, Parameters



. , , ComboBox



, Slider



Text



. , .

Parameter



, .



... public abstract class Parameter : INotifyPropertyChanged { ... protected Parameter(PhotoCaptureDevice device, string name) { ... } public PhotoCaptureDevice Device { ... } public string Name { ... } public bool Supported { ... } public abstract void Refresh(); ... }







, . _propertyId



, static CameraCapturePropertyRange PhotoCaptureDevice.GetSupportedPropertyRange(CameraSensorLocation sensor, Guid propertyId)



. object PhotoCaptureDevice.GetProperty(Guid propertyId)



. void PhotoCaptureDevice.SetProperty(Guid propertyId, object value)



.



... public abstract class RangeParameter<T> : Parameter { private Guid _propertyId; private T _value; ... protected RangeParameter(PhotoCaptureDevice device, Guid propertyId, string name) : base(device, name) { ... } public override void Refresh() { try { CameraCapturePropertyRange range = PhotoCaptureDevice.GetSupportedPropertyRange( Device.SensorLocation, _propertyId); if (range == null) { Supported = false; } else { Minimum = (T)range.Min; Maximum = (T)range.Max; _value = (T)Device.GetProperty(_propertyId); Supported = true; } } catch (Exception) { Supported = false; } ... } public T Minimum { ... } public T Maximum { ... } public T Value { ... set { if (!_value.Equals(value)) { try { Device.SetProperty(_propertyId, (T)value); _value = value; ... } catch (Exception) { ... } } } } ... }







ExposureCompensationParameter



, Guid RangeParameter



KnownCameraPhotoProperties.ExposureCompensation



, — , . , Int32



, .



... public class ExposureCompensationParameter : RangeParameter<Int32> { public ExposureCompensationParameter(PhotoCaptureDevice device) : base(device, KnownCameraPhotoProperties.ExposureCompensation, "Exposure compensation") { } ... }







Camera Explorer ArrayParameter



. . — void PopulateOptions()



void SetOption(ArrayParameterOption option)



, .



... public class ArrayParameterOption { ... public ArrayParameterOption(dynamic value, string name) { ... } public dynamic Value { ... } public string Name { ... } ... } public abstract class ArrayParameter : Parameter, IReadOnlyCollection<ArrayParameterOption> { private List<ArrayParameterOption> _options = new List<ArrayParameterOption>(); private ArrayParameterOption _selectedOption; ... public ArrayParameter(PhotoCaptureDevice device, string name) : base(device, name) { ... } public override void Refresh() { ... _options.Clear(); _selectedOption = null; try { PopulateOptions(); Supported = _options.Count > 0; } catch (Exception) { Supported = false; } ... } protected List<ArrayParameterOption> Options { ... } public ArrayParameterOption SelectedOption { ... set { if (_selectedOption != value) { ... if (_selectedOption != null)) { SetOption(value); } _selectedOption = value; } } } protected abstract void PopulateOptions(); protected abstract void SetOption(ArrayParameterOption option); ... }







, , , . void PopulateOptions()



, , ArrayParameterOption



SelectedOption



, void SetOption(ArrayParameterOption option)



. , static IReadOnlyList , KnownCameraPhotoProperties.SceneMode



object PhotoCaptureDevice.GetProperty(Guid propertyId)



. void PhotoCaptureDevice.SetProperty(Guid propertyId, object value)



.



... public class SceneModeParameter : ArrayParameter { public SceneModeParameter(PhotoCaptureDevice device) : base(device, KnownCameraPhotoProperties.SceneMode, "Scene mode") { } protected override void PopulateOptions() { IReadOnlyList<object> supportedValues = PhotoCaptureDevice.GetSupportedPropertyValues( Device.SensorLocation, PropertyId); object value = Device.GetProperty(PropertyId); foreach (dynamic i in supportedValues) { CameraSceneMode csm = (CameraSceneMode)i; ArrayParameterOption option = new ArrayParameterOption(csm, csm.ToString()); Options.Add(option); if (i.Equals(value)) { SelectedOption = option; } } } protected override void SetOption(ArrayParameterOption option) { Device.SetProperty(PropertyId, option.Value); } ... }







Tap-to-focus

«». Tap-to-focus , , , . , Tap-to-focus .



Rectangle



Canvas



, :



<Rectangle x:Name="FocusIndicator" Stroke="Red" Opacity="0.7" Width="80" Height="80" StrokeThickness="5" Visibility="Collapsed"/>







, .

Canvas Tap:



public MainPage() { ... VideoCanvas.Tap += new EventHandler<GestureEventArgs>(videoCanvas_Tap); ... }







. API- , VideoCanvas



, , .



, . , , , .



, , , , .



private async void videoCanvas_Tap(object sender, GestureEventArgs e) { System.Windows.Point uiTapPoint = e.GetPosition(VideoCanvas); if (PhotoCaptureDevice.IsFocusRegionSupported(_dataContext.Device.SensorLocation) && _focusSemaphore.WaitOne(0)) { // . Windows.Foundation.Point tapPoint = new Windows.Foundation.Point(uiTapPoint.X, uiTapPoint.Y); double xRatio = VideoCanvas.ActualWidth / _dataContext.Device.PreviewResolution.Width; double yRatio = VideoCanvas.ActualHeight / _dataContext.Device.PreviewResolution.Height; // , Windows.Foundation.Point displayOrigin = new Windows.Foundation.Point( tapPoint.X - _focusRegionSize.Width / 2, tapPoint.Y - _focusRegionSize.Height / 2); // canvas Windows.Foundation.Point viewFinderOrigin = new Windows.Foundation.Point( displayOrigin.X / xRatio, displayOrigin.Y / yRatio); Windows.Foundation.Rect focusrect = new Windows.Foundation.Rect( viewFinderOrigin, _focusRegionSize); // Windows.Foundation.Rect viewPortRect = new Windows.Foundation.Rect( 0, 0, _dataContext.Device.PreviewResolution.Width, _dataContext.Device.PreviewResolution.Height); focusrect.Intersect(viewPortRect); _dataContext.Device.FocusRegion = focusrect; // FocusIndicator.SetValue(Shape.StrokeProperty, _notFocusedBrush); FocusIndicator.SetValue(Canvas.LeftProperty, uiTapPoint.X - _focusRegionSize.Width / 2); FocusIndicator.SetValue(Canvas.TopProperty, uiTapPoint.Y - _focusRegionSize.Height / 2); FocusIndicator.SetValue(Canvas.VisibilityProperty, Visibility.Visible); CameraFocusStatus status = await _dataContext.Device.FocusAsync(); if (status == CameraFocusStatus.Locked) { FocusIndicator.SetValue(Shape.StrokeProperty, _focusedBrush); _manuallyFocused = true; _dataContext.Device.SetProperty( KnownCameraPhotoProperties.LockedAutoFocusParameters, AutoFocusParameters.Exposure & AutoFocusParameters.Focus & AutoFocusParameters.WhiteBalance); } else { _manuallyFocused = false; _dataContext.Device.SetProperty( KnownCameraPhotoProperties.LockedAutoFocusParameters, AutoFocusParameters.None); } _focusSemaphore.Release(); } }







, . FocusAsync



, , . , WaitOne



, , , false



— , .





, «», Lens Picker. «» , . Lens Picker, XML App:



<Extensions> <Extension ExtensionName="Camera_Capture_App" ConsumerId="{5B04B775-356B-4AA0-AAF8-6491FFEA5631]" TaskId="_default" /> </Extensions>







, Lens Picker, . , Lens Picker Assets



. , Lens design guidelines for Windows Phone .



Maps API.
























 static IReadOnlyList 
      

object GetProperty(Guid propertyId)






void SetProperty(Guid propertyId, object value)







— , .



static bool IsFocusSupported(CameraSensorLocation sensor)





static bool IsFocusRegionSupported(CameraSensorLocation sensor)





IAsyncOperation FocusAsync()

• IAsyncOperation ResetFocusAsync()



— .



• static IReadOnlyList GetAvailablePreviewResolutions()

• static IReadOnlyList GetAvailableCaptureResolutions()

• IAsyncAction SetPreviewResolutionAsync(Size value)






IAsyncAction SetCaptureResolutionAsync(Size value)







— .



event TypedEventHandler<ICameraCaptureDevice, Object> PreviewFrameAvailable





void GetPreviewBufferArgb(out int[] pixels)





void GetPreviewBufferY(out byte[] pixels)





void GetPreviewBufferYCbCr(out byte[] pixels)







— .



CameraCaptureSequence CreateCaptureSequence(uint numberOfFrames)





IAsyncAction PrepareCaptureSequenceAsync(CameraCaptureSequence sequence)







— . . API . GUID. , .

, ID_CAP_ISV_CAMERA



WMAppManifest.xml . ID_CAP_MEDIALIB_PHOTO



.



Lumia

Nokia Lumia 820 920.





Camera Explorer — , PhotoCaptureDevice



. , .







, Camera Explorer.







Windows Phone DataContext



, Settings



PhotoCaptureDevice



.

PhotoCaptureDevice



DataContext, , , PhotoCaptureDevice



, , MainPage, .



Camera Explorer .

, PhotoCaptureDevice , Camera Explorer. , , . .



DataContext, , .



... class DataContext : INotifyPropertyChanged { ... public static DataContext Singleton { ... } public ObservableCollection<Parameter> Parameters { ... } public PhotoCaptureDevice Device { ... } public MemoryStream ImageStream { ... } }









, PhotoCaptureDevice



. MainPage xaml Canvas



VideoBrush



, .



<phone:PhoneApplicationPage x:Class="CameraExplorer.MainPage" ... > ... <Grid x:Name="LayoutRoot" ... > ... <Grid x:Name="ContentPanel" ... > <Canvas x:Name="VideoCanvas"> <Canvas.Background> <VideoBrush x:Name="videoBrush"/> </Canvas.Background> </Canvas> ... </Grid> </Grid> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar> <shell:ApplicationBarIconButton Text="capture" Click="captureButton_Click" ... /> ... </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> ... </phone:PhoneApplicationPage>







C# MainPage PhotoCaptureDevice



InitializeCamera



, DataContext. , XAML, , .



... public partial class MainPage : PhoneApplicationPage { private CameraExplorer.DataContext _dataContext = CameraExplorer.DataContext.Singleton; ... protected async override void OnNavigatedTo(NavigationEventArgs e) { if (_dataContext.Device == null) { ... await InitializeCamera(CameraSensorLocation.Back); ... } videoBrush.RelativeTransform = new CompositeTransform() { CenterX = 0.5, CenterY = 0.5, Rotation = _dataContext.Device.SensorLocation == CameraSensorLocation.Back ? _dataContext.Device.SensorRotationInDegrees : - _dataContext.Device.SensorRotationInDegrees }; videoBrush.SetSource(_dataContext.Device); ... } 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 void captureButton_Click(object sender, EventArgs e) { if (!_manuallyFocused) { await AutoFocus(); } await Capture(); } private async Task AutoFocus() { if (!_capturing && PhotoCaptureDevice.IsFocusSupported(_dataContext.Device.SensorLocation)) { ... await _dataContext.Device.FocusAsync(); ... _capturing = false; } } private async Task Capture() { if (!_capturing) { _capturing = true; MemoryStream stream = new MemoryStream(); CameraCaptureSequence sequence = _dataContext.Device.CreateCaptureSequence(1); sequence.Frames[0].CaptureStream = stream.AsOutputStream(); await _dataContext.Device.PrepareCaptureSequenceAsync(sequence); await sequence.StartCaptureAsync(); _dataContext.ImageStream = stream; ... } ... } ... }









. Camera Explorer , XAML Image BitmapImage



. , , , void MediaLibrary.SavePictureToCameraRoll(string name, Stream source)



, .



<phone:PhoneApplicationPage x:Class="CameraExplorer.PreviewPage" ... > ... <Grid x:Name="LayoutRoot" ... > ... <Grid x:Name="ContentPanel" ... > <Image x:Name="image" Stretch="UniformToFill"/> </Grid> </Grid> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar> <shell:ApplicationBarIconButton Text="save" Click="saveButton_Click" ... /> </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> ... </phone:PhoneApplicationPage>







... public partial class PreviewPage : PhoneApplicationPage { private CameraExplorer.DataContext _dataContext = CameraExplorer.DataContext.Singleton; private BitmapImage _bitmap = new BitmapImage(); protected override void OnNavigatedTo(NavigationEventArgs e) { ... _bitmap.SetSource(_dataContext.ImageStream); image.Source = _bitmap; ... } private void saveButton_Click(object sender, EventArgs e) { try { _dataContext.ImageStream.Position = 0; MediaLibrary library = new MediaLibrary(); library.SavePictureToCameraRoll("CameraExplorer_" + DateTime.Now.ToString() + ".jpg", _dataContext.ImageStream); } catch (Exception) { ... } ... } }







Camera Explorer , ArrayParameters



RangeParameters



, Parameters



. , , ComboBox



, Slider



Text



. , .

Parameter



, .



... public abstract class Parameter : INotifyPropertyChanged { ... protected Parameter(PhotoCaptureDevice device, string name) { ... } public PhotoCaptureDevice Device { ... } public string Name { ... } public bool Supported { ... } public abstract void Refresh(); ... }







, . _propertyId



, static CameraCapturePropertyRange PhotoCaptureDevice.GetSupportedPropertyRange(CameraSensorLocation sensor, Guid propertyId)



. object PhotoCaptureDevice.GetProperty(Guid propertyId)



. void PhotoCaptureDevice.SetProperty(Guid propertyId, object value)



.



... public abstract class RangeParameter<T> : Parameter { private Guid _propertyId; private T _value; ... protected RangeParameter(PhotoCaptureDevice device, Guid propertyId, string name) : base(device, name) { ... } public override void Refresh() { try { CameraCapturePropertyRange range = PhotoCaptureDevice.GetSupportedPropertyRange( Device.SensorLocation, _propertyId); if (range == null) { Supported = false; } else { Minimum = (T)range.Min; Maximum = (T)range.Max; _value = (T)Device.GetProperty(_propertyId); Supported = true; } } catch (Exception) { Supported = false; } ... } public T Minimum { ... } public T Maximum { ... } public T Value { ... set { if (!_value.Equals(value)) { try { Device.SetProperty(_propertyId, (T)value); _value = value; ... } catch (Exception) { ... } } } } ... }







ExposureCompensationParameter



, Guid RangeParameter



KnownCameraPhotoProperties.ExposureCompensation



, — , . , Int32



, .



... public class ExposureCompensationParameter : RangeParameter<Int32> { public ExposureCompensationParameter(PhotoCaptureDevice device) : base(device, KnownCameraPhotoProperties.ExposureCompensation, "Exposure compensation") { } ... }







Camera Explorer ArrayParameter



. . — void PopulateOptions()



void SetOption(ArrayParameterOption option)



, .



... public class ArrayParameterOption { ... public ArrayParameterOption(dynamic value, string name) { ... } public dynamic Value { ... } public string Name { ... } ... } public abstract class ArrayParameter : Parameter, IReadOnlyCollection<ArrayParameterOption> { private List<ArrayParameterOption> _options = new List<ArrayParameterOption>(); private ArrayParameterOption _selectedOption; ... public ArrayParameter(PhotoCaptureDevice device, string name) : base(device, name) { ... } public override void Refresh() { ... _options.Clear(); _selectedOption = null; try { PopulateOptions(); Supported = _options.Count > 0; } catch (Exception) { Supported = false; } ... } protected List<ArrayParameterOption> Options { ... } public ArrayParameterOption SelectedOption { ... set { if (_selectedOption != value) { ... if (_selectedOption != null)) { SetOption(value); } _selectedOption = value; } } } protected abstract void PopulateOptions(); protected abstract void SetOption(ArrayParameterOption option); ... }







, , , . void PopulateOptions()



, , ArrayParameterOption



SelectedOption



, void SetOption(ArrayParameterOption option)



. , static IReadOnlyList , KnownCameraPhotoProperties.SceneMode



object PhotoCaptureDevice.GetProperty(Guid propertyId)



. void PhotoCaptureDevice.SetProperty(Guid propertyId, object value)



.



... public class SceneModeParameter : ArrayParameter { public SceneModeParameter(PhotoCaptureDevice device) : base(device, KnownCameraPhotoProperties.SceneMode, "Scene mode") { } protected override void PopulateOptions() { IReadOnlyList<object> supportedValues = PhotoCaptureDevice.GetSupportedPropertyValues( Device.SensorLocation, PropertyId); object value = Device.GetProperty(PropertyId); foreach (dynamic i in supportedValues) { CameraSceneMode csm = (CameraSceneMode)i; ArrayParameterOption option = new ArrayParameterOption(csm, csm.ToString()); Options.Add(option); if (i.Equals(value)) { SelectedOption = option; } } } protected override void SetOption(ArrayParameterOption option) { Device.SetProperty(PropertyId, option.Value); } ... }







Tap-to-focus

«». Tap-to-focus , , , . , Tap-to-focus .



Rectangle



Canvas



, :



<Rectangle x:Name="FocusIndicator" Stroke="Red" Opacity="0.7" Width="80" Height="80" StrokeThickness="5" Visibility="Collapsed"/>







, .

Canvas Tap:



public MainPage() { ... VideoCanvas.Tap += new EventHandler<GestureEventArgs>(videoCanvas_Tap); ... }







. API- , VideoCanvas



, , .



, . , , , .



, , , , .



private async void videoCanvas_Tap(object sender, GestureEventArgs e) { System.Windows.Point uiTapPoint = e.GetPosition(VideoCanvas); if (PhotoCaptureDevice.IsFocusRegionSupported(_dataContext.Device.SensorLocation) && _focusSemaphore.WaitOne(0)) { // . Windows.Foundation.Point tapPoint = new Windows.Foundation.Point(uiTapPoint.X, uiTapPoint.Y); double xRatio = VideoCanvas.ActualWidth / _dataContext.Device.PreviewResolution.Width; double yRatio = VideoCanvas.ActualHeight / _dataContext.Device.PreviewResolution.Height; // , Windows.Foundation.Point displayOrigin = new Windows.Foundation.Point( tapPoint.X - _focusRegionSize.Width / 2, tapPoint.Y - _focusRegionSize.Height / 2); // canvas Windows.Foundation.Point viewFinderOrigin = new Windows.Foundation.Point( displayOrigin.X / xRatio, displayOrigin.Y / yRatio); Windows.Foundation.Rect focusrect = new Windows.Foundation.Rect( viewFinderOrigin, _focusRegionSize); // Windows.Foundation.Rect viewPortRect = new Windows.Foundation.Rect( 0, 0, _dataContext.Device.PreviewResolution.Width, _dataContext.Device.PreviewResolution.Height); focusrect.Intersect(viewPortRect); _dataContext.Device.FocusRegion = focusrect; // FocusIndicator.SetValue(Shape.StrokeProperty, _notFocusedBrush); FocusIndicator.SetValue(Canvas.LeftProperty, uiTapPoint.X - _focusRegionSize.Width / 2); FocusIndicator.SetValue(Canvas.TopProperty, uiTapPoint.Y - _focusRegionSize.Height / 2); FocusIndicator.SetValue(Canvas.VisibilityProperty, Visibility.Visible); CameraFocusStatus status = await _dataContext.Device.FocusAsync(); if (status == CameraFocusStatus.Locked) { FocusIndicator.SetValue(Shape.StrokeProperty, _focusedBrush); _manuallyFocused = true; _dataContext.Device.SetProperty( KnownCameraPhotoProperties.LockedAutoFocusParameters, AutoFocusParameters.Exposure & AutoFocusParameters.Focus & AutoFocusParameters.WhiteBalance); } else { _manuallyFocused = false; _dataContext.Device.SetProperty( KnownCameraPhotoProperties.LockedAutoFocusParameters, AutoFocusParameters.None); } _focusSemaphore.Release(); } }







, . FocusAsync



, , . , WaitOne



, , , false



— , .





, «», Lens Picker. «» , . Lens Picker, XML App:



<Extensions> <Extension ExtensionName="Camera_Capture_App" ConsumerId="{5B04B775-356B-4AA0-AAF8-6491FFEA5631]" TaskId="_default" /> </Extensions>







, Lens Picker, . , Lens Picker Assets



. , Lens design guidelines for Windows Phone .



Maps API.
























static IReadOnlyList

• object GetProperty(Guid propertyId)






void SetProperty(Guid propertyId, object value)







— , .



static bool IsFocusSupported(CameraSensorLocation sensor)





static bool IsFocusRegionSupported(CameraSensorLocation sensor)





IAsyncOperation FocusAsync()

• IAsyncOperation ResetFocusAsync()



— .



• static IReadOnlyList GetAvailablePreviewResolutions()

• static IReadOnlyList GetAvailableCaptureResolutions()

• IAsyncAction SetPreviewResolutionAsync(Size value)






IAsyncAction SetCaptureResolutionAsync(Size value)







— .



event TypedEventHandler<ICameraCaptureDevice, Object> PreviewFrameAvailable





void GetPreviewBufferArgb(out int[] pixels)





void GetPreviewBufferY(out byte[] pixels)





void GetPreviewBufferYCbCr(out byte[] pixels)







— .



CameraCaptureSequence CreateCaptureSequence(uint numberOfFrames)





IAsyncAction PrepareCaptureSequenceAsync(CameraCaptureSequence sequence)







— . . API . GUID. , .

, ID_CAP_ISV_CAMERA



WMAppManifest.xml . ID_CAP_MEDIALIB_PHOTO



.



Lumia

Nokia Lumia 820 920.





Camera Explorer — , PhotoCaptureDevice



. , .







, Camera Explorer.







Windows Phone DataContext



, Settings



PhotoCaptureDevice



.

PhotoCaptureDevice



DataContext, , , PhotoCaptureDevice



, , MainPage, .



Camera Explorer .

, PhotoCaptureDevice , Camera Explorer. , , . .



DataContext, , .



... class DataContext : INotifyPropertyChanged { ... public static DataContext Singleton { ... } public ObservableCollection<Parameter> Parameters { ... } public PhotoCaptureDevice Device { ... } public MemoryStream ImageStream { ... } }









, PhotoCaptureDevice



. MainPage xaml Canvas



VideoBrush



, .



<phone:PhoneApplicationPage x:Class="CameraExplorer.MainPage" ... > ... <Grid x:Name="LayoutRoot" ... > ... <Grid x:Name="ContentPanel" ... > <Canvas x:Name="VideoCanvas"> <Canvas.Background> <VideoBrush x:Name="videoBrush"/> </Canvas.Background> </Canvas> ... </Grid> </Grid> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar> <shell:ApplicationBarIconButton Text="capture" Click="captureButton_Click" ... /> ... </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> ... </phone:PhoneApplicationPage>







C# MainPage PhotoCaptureDevice



InitializeCamera



, DataContext. , XAML, , .



... public partial class MainPage : PhoneApplicationPage { private CameraExplorer.DataContext _dataContext = CameraExplorer.DataContext.Singleton; ... protected async override void OnNavigatedTo(NavigationEventArgs e) { if (_dataContext.Device == null) { ... await InitializeCamera(CameraSensorLocation.Back); ... } videoBrush.RelativeTransform = new CompositeTransform() { CenterX = 0.5, CenterY = 0.5, Rotation = _dataContext.Device.SensorLocation == CameraSensorLocation.Back ? _dataContext.Device.SensorRotationInDegrees : - _dataContext.Device.SensorRotationInDegrees }; videoBrush.SetSource(_dataContext.Device); ... } 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 void captureButton_Click(object sender, EventArgs e) { if (!_manuallyFocused) { await AutoFocus(); } await Capture(); } private async Task AutoFocus() { if (!_capturing && PhotoCaptureDevice.IsFocusSupported(_dataContext.Device.SensorLocation)) { ... await _dataContext.Device.FocusAsync(); ... _capturing = false; } } private async Task Capture() { if (!_capturing) { _capturing = true; MemoryStream stream = new MemoryStream(); CameraCaptureSequence sequence = _dataContext.Device.CreateCaptureSequence(1); sequence.Frames[0].CaptureStream = stream.AsOutputStream(); await _dataContext.Device.PrepareCaptureSequenceAsync(sequence); await sequence.StartCaptureAsync(); _dataContext.ImageStream = stream; ... } ... } ... }









. Camera Explorer , XAML Image BitmapImage



. , , , void MediaLibrary.SavePictureToCameraRoll(string name, Stream source)



, .



<phone:PhoneApplicationPage x:Class="CameraExplorer.PreviewPage" ... > ... <Grid x:Name="LayoutRoot" ... > ... <Grid x:Name="ContentPanel" ... > <Image x:Name="image" Stretch="UniformToFill"/> </Grid> </Grid> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar> <shell:ApplicationBarIconButton Text="save" Click="saveButton_Click" ... /> </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> ... </phone:PhoneApplicationPage>







... public partial class PreviewPage : PhoneApplicationPage { private CameraExplorer.DataContext _dataContext = CameraExplorer.DataContext.Singleton; private BitmapImage _bitmap = new BitmapImage(); protected override void OnNavigatedTo(NavigationEventArgs e) { ... _bitmap.SetSource(_dataContext.ImageStream); image.Source = _bitmap; ... } private void saveButton_Click(object sender, EventArgs e) { try { _dataContext.ImageStream.Position = 0; MediaLibrary library = new MediaLibrary(); library.SavePictureToCameraRoll("CameraExplorer_" + DateTime.Now.ToString() + ".jpg", _dataContext.ImageStream); } catch (Exception) { ... } ... } }







Camera Explorer , ArrayParameters



RangeParameters



, Parameters



. , , ComboBox



, Slider



Text



. , .

Parameter



, .



... public abstract class Parameter : INotifyPropertyChanged { ... protected Parameter(PhotoCaptureDevice device, string name) { ... } public PhotoCaptureDevice Device { ... } public string Name { ... } public bool Supported { ... } public abstract void Refresh(); ... }







, . _propertyId



, static CameraCapturePropertyRange PhotoCaptureDevice.GetSupportedPropertyRange(CameraSensorLocation sensor, Guid propertyId)



. object PhotoCaptureDevice.GetProperty(Guid propertyId)



. void PhotoCaptureDevice.SetProperty(Guid propertyId, object value)



.



... public abstract class RangeParameter<T> : Parameter { private Guid _propertyId; private T _value; ... protected RangeParameter(PhotoCaptureDevice device, Guid propertyId, string name) : base(device, name) { ... } public override void Refresh() { try { CameraCapturePropertyRange range = PhotoCaptureDevice.GetSupportedPropertyRange( Device.SensorLocation, _propertyId); if (range == null) { Supported = false; } else { Minimum = (T)range.Min; Maximum = (T)range.Max; _value = (T)Device.GetProperty(_propertyId); Supported = true; } } catch (Exception) { Supported = false; } ... } public T Minimum { ... } public T Maximum { ... } public T Value { ... set { if (!_value.Equals(value)) { try { Device.SetProperty(_propertyId, (T)value); _value = value; ... } catch (Exception) { ... } } } } ... }







ExposureCompensationParameter



, Guid RangeParameter



KnownCameraPhotoProperties.ExposureCompensation



, — , . , Int32



, .



... public class ExposureCompensationParameter : RangeParameter<Int32> { public ExposureCompensationParameter(PhotoCaptureDevice device) : base(device, KnownCameraPhotoProperties.ExposureCompensation, "Exposure compensation") { } ... }







Camera Explorer ArrayParameter



. . — void PopulateOptions()



void SetOption(ArrayParameterOption option)



, .



... public class ArrayParameterOption { ... public ArrayParameterOption(dynamic value, string name) { ... } public dynamic Value { ... } public string Name { ... } ... } public abstract class ArrayParameter : Parameter, IReadOnlyCollection<ArrayParameterOption> { private List<ArrayParameterOption> _options = new List<ArrayParameterOption>(); private ArrayParameterOption _selectedOption; ... public ArrayParameter(PhotoCaptureDevice device, string name) : base(device, name) { ... } public override void Refresh() { ... _options.Clear(); _selectedOption = null; try { PopulateOptions(); Supported = _options.Count > 0; } catch (Exception) { Supported = false; } ... } protected List<ArrayParameterOption> Options { ... } public ArrayParameterOption SelectedOption { ... set { if (_selectedOption != value) { ... if (_selectedOption != null)) { SetOption(value); } _selectedOption = value; } } } protected abstract void PopulateOptions(); protected abstract void SetOption(ArrayParameterOption option); ... }







, , , . void PopulateOptions()



, , ArrayParameterOption



SelectedOption



, void SetOption(ArrayParameterOption option)



. , static IReadOnlyList , KnownCameraPhotoProperties.SceneMode



object PhotoCaptureDevice.GetProperty(Guid propertyId)



. void PhotoCaptureDevice.SetProperty(Guid propertyId, object value)



.



... public class SceneModeParameter : ArrayParameter { public SceneModeParameter(PhotoCaptureDevice device) : base(device, KnownCameraPhotoProperties.SceneMode, "Scene mode") { } protected override void PopulateOptions() { IReadOnlyList<object> supportedValues = PhotoCaptureDevice.GetSupportedPropertyValues( Device.SensorLocation, PropertyId); object value = Device.GetProperty(PropertyId); foreach (dynamic i in supportedValues) { CameraSceneMode csm = (CameraSceneMode)i; ArrayParameterOption option = new ArrayParameterOption(csm, csm.ToString()); Options.Add(option); if (i.Equals(value)) { SelectedOption = option; } } } protected override void SetOption(ArrayParameterOption option) { Device.SetProperty(PropertyId, option.Value); } ... }







Tap-to-focus

«». Tap-to-focus , , , . , Tap-to-focus .



Rectangle



Canvas



, :



<Rectangle x:Name="FocusIndicator" Stroke="Red" Opacity="0.7" Width="80" Height="80" StrokeThickness="5" Visibility="Collapsed"/>







, .

Canvas Tap:



public MainPage() { ... VideoCanvas.Tap += new EventHandler<GestureEventArgs>(videoCanvas_Tap); ... }







. API- , VideoCanvas



, , .



, . , , , .



, , , , .



private async void videoCanvas_Tap(object sender, GestureEventArgs e) { System.Windows.Point uiTapPoint = e.GetPosition(VideoCanvas); if (PhotoCaptureDevice.IsFocusRegionSupported(_dataContext.Device.SensorLocation) && _focusSemaphore.WaitOne(0)) { // . Windows.Foundation.Point tapPoint = new Windows.Foundation.Point(uiTapPoint.X, uiTapPoint.Y); double xRatio = VideoCanvas.ActualWidth / _dataContext.Device.PreviewResolution.Width; double yRatio = VideoCanvas.ActualHeight / _dataContext.Device.PreviewResolution.Height; // , Windows.Foundation.Point displayOrigin = new Windows.Foundation.Point( tapPoint.X - _focusRegionSize.Width / 2, tapPoint.Y - _focusRegionSize.Height / 2); // canvas Windows.Foundation.Point viewFinderOrigin = new Windows.Foundation.Point( displayOrigin.X / xRatio, displayOrigin.Y / yRatio); Windows.Foundation.Rect focusrect = new Windows.Foundation.Rect( viewFinderOrigin, _focusRegionSize); // Windows.Foundation.Rect viewPortRect = new Windows.Foundation.Rect( 0, 0, _dataContext.Device.PreviewResolution.Width, _dataContext.Device.PreviewResolution.Height); focusrect.Intersect(viewPortRect); _dataContext.Device.FocusRegion = focusrect; // FocusIndicator.SetValue(Shape.StrokeProperty, _notFocusedBrush); FocusIndicator.SetValue(Canvas.LeftProperty, uiTapPoint.X - _focusRegionSize.Width / 2); FocusIndicator.SetValue(Canvas.TopProperty, uiTapPoint.Y - _focusRegionSize.Height / 2); FocusIndicator.SetValue(Canvas.VisibilityProperty, Visibility.Visible); CameraFocusStatus status = await _dataContext.Device.FocusAsync(); if (status == CameraFocusStatus.Locked) { FocusIndicator.SetValue(Shape.StrokeProperty, _focusedBrush); _manuallyFocused = true; _dataContext.Device.SetProperty( KnownCameraPhotoProperties.LockedAutoFocusParameters, AutoFocusParameters.Exposure & AutoFocusParameters.Focus & AutoFocusParameters.WhiteBalance); } else { _manuallyFocused = false; _dataContext.Device.SetProperty( KnownCameraPhotoProperties.LockedAutoFocusParameters, AutoFocusParameters.None); } _focusSemaphore.Release(); } }







, . FocusAsync



, , . , WaitOne



, , , false



— , .





, «», Lens Picker. «» , . Lens Picker, XML App:



<Extensions> <Extension ExtensionName="Camera_Capture_App" ConsumerId="{5B04B775-356B-4AA0-AAF8-6491FFEA5631]" TaskId="_default" /> </Extensions>







, Lens Picker, . , Lens Picker Assets



. , Lens design guidelines for Windows Phone .



Maps API.
























static IReadOnlyList

• object GetProperty(Guid propertyId)






void SetProperty(Guid propertyId, object value)







— , .



static bool IsFocusSupported(CameraSensorLocation sensor)





static bool IsFocusRegionSupported(CameraSensorLocation sensor)





IAsyncOperation FocusAsync()

• IAsyncOperation ResetFocusAsync()



— .



• static IReadOnlyList GetAvailablePreviewResolutions()

• static IReadOnlyList GetAvailableCaptureResolutions()

• IAsyncAction SetPreviewResolutionAsync(Size value)






IAsyncAction SetCaptureResolutionAsync(Size value)







— .



event TypedEventHandler<ICameraCaptureDevice, Object> PreviewFrameAvailable





void GetPreviewBufferArgb(out int[] pixels)





void GetPreviewBufferY(out byte[] pixels)





void GetPreviewBufferYCbCr(out byte[] pixels)







— .



CameraCaptureSequence CreateCaptureSequence(uint numberOfFrames)





IAsyncAction PrepareCaptureSequenceAsync(CameraCaptureSequence sequence)







— . . API . GUID. , .

, ID_CAP_ISV_CAMERA



WMAppManifest.xml . ID_CAP_MEDIALIB_PHOTO



.



Lumia

Nokia Lumia 820 920.





Camera Explorer — , PhotoCaptureDevice



. , .







, Camera Explorer.







Windows Phone DataContext



, Settings



PhotoCaptureDevice



.

PhotoCaptureDevice



DataContext, , , PhotoCaptureDevice



, , MainPage, .



Camera Explorer .

, PhotoCaptureDevice , Camera Explorer. , , . .



DataContext, , .



... class DataContext : INotifyPropertyChanged { ... public static DataContext Singleton { ... } public ObservableCollection<Parameter> Parameters { ... } public PhotoCaptureDevice Device { ... } public MemoryStream ImageStream { ... } }









, PhotoCaptureDevice



. MainPage xaml Canvas



VideoBrush



, .



<phone:PhoneApplicationPage x:Class="CameraExplorer.MainPage" ... > ... <Grid x:Name="LayoutRoot" ... > ... <Grid x:Name="ContentPanel" ... > <Canvas x:Name="VideoCanvas"> <Canvas.Background> <VideoBrush x:Name="videoBrush"/> </Canvas.Background> </Canvas> ... </Grid> </Grid> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar> <shell:ApplicationBarIconButton Text="capture" Click="captureButton_Click" ... /> ... </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> ... </phone:PhoneApplicationPage>







C# MainPage PhotoCaptureDevice



InitializeCamera



, DataContext. , XAML, , .



... public partial class MainPage : PhoneApplicationPage { private CameraExplorer.DataContext _dataContext = CameraExplorer.DataContext.Singleton; ... protected async override void OnNavigatedTo(NavigationEventArgs e) { if (_dataContext.Device == null) { ... await InitializeCamera(CameraSensorLocation.Back); ... } videoBrush.RelativeTransform = new CompositeTransform() { CenterX = 0.5, CenterY = 0.5, Rotation = _dataContext.Device.SensorLocation == CameraSensorLocation.Back ? _dataContext.Device.SensorRotationInDegrees : - _dataContext.Device.SensorRotationInDegrees }; videoBrush.SetSource(_dataContext.Device); ... } 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 void captureButton_Click(object sender, EventArgs e) { if (!_manuallyFocused) { await AutoFocus(); } await Capture(); } private async Task AutoFocus() { if (!_capturing && PhotoCaptureDevice.IsFocusSupported(_dataContext.Device.SensorLocation)) { ... await _dataContext.Device.FocusAsync(); ... _capturing = false; } } private async Task Capture() { if (!_capturing) { _capturing = true; MemoryStream stream = new MemoryStream(); CameraCaptureSequence sequence = _dataContext.Device.CreateCaptureSequence(1); sequence.Frames[0].CaptureStream = stream.AsOutputStream(); await _dataContext.Device.PrepareCaptureSequenceAsync(sequence); await sequence.StartCaptureAsync(); _dataContext.ImageStream = stream; ... } ... } ... }









. Camera Explorer , XAML Image BitmapImage



. , , , void MediaLibrary.SavePictureToCameraRoll(string name, Stream source)



, .



<phone:PhoneApplicationPage x:Class="CameraExplorer.PreviewPage" ... > ... <Grid x:Name="LayoutRoot" ... > ... <Grid x:Name="ContentPanel" ... > <Image x:Name="image" Stretch="UniformToFill"/> </Grid> </Grid> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar> <shell:ApplicationBarIconButton Text="save" Click="saveButton_Click" ... /> </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> ... </phone:PhoneApplicationPage>







... public partial class PreviewPage : PhoneApplicationPage { private CameraExplorer.DataContext _dataContext = CameraExplorer.DataContext.Singleton; private BitmapImage _bitmap = new BitmapImage(); protected override void OnNavigatedTo(NavigationEventArgs e) { ... _bitmap.SetSource(_dataContext.ImageStream); image.Source = _bitmap; ... } private void saveButton_Click(object sender, EventArgs e) { try { _dataContext.ImageStream.Position = 0; MediaLibrary library = new MediaLibrary(); library.SavePictureToCameraRoll("CameraExplorer_" + DateTime.Now.ToString() + ".jpg", _dataContext.ImageStream); } catch (Exception) { ... } ... } }







Camera Explorer , ArrayParameters



RangeParameters



, Parameters



. , , ComboBox



, Slider



Text



. , .

Parameter



, .



... public abstract class Parameter : INotifyPropertyChanged { ... protected Parameter(PhotoCaptureDevice device, string name) { ... } public PhotoCaptureDevice Device { ... } public string Name { ... } public bool Supported { ... } public abstract void Refresh(); ... }







, . _propertyId



, static CameraCapturePropertyRange PhotoCaptureDevice.GetSupportedPropertyRange(CameraSensorLocation sensor, Guid propertyId)



. object PhotoCaptureDevice.GetProperty(Guid propertyId)



. void PhotoCaptureDevice.SetProperty(Guid propertyId, object value)



.



... public abstract class RangeParameter<T> : Parameter { private Guid _propertyId; private T _value; ... protected RangeParameter(PhotoCaptureDevice device, Guid propertyId, string name) : base(device, name) { ... } public override void Refresh() { try { CameraCapturePropertyRange range = PhotoCaptureDevice.GetSupportedPropertyRange( Device.SensorLocation, _propertyId); if (range == null) { Supported = false; } else { Minimum = (T)range.Min; Maximum = (T)range.Max; _value = (T)Device.GetProperty(_propertyId); Supported = true; } } catch (Exception) { Supported = false; } ... } public T Minimum { ... } public T Maximum { ... } public T Value { ... set { if (!_value.Equals(value)) { try { Device.SetProperty(_propertyId, (T)value); _value = value; ... } catch (Exception) { ... } } } } ... }







ExposureCompensationParameter



, Guid RangeParameter



KnownCameraPhotoProperties.ExposureCompensation



, — , . , Int32



, .



... public class ExposureCompensationParameter : RangeParameter<Int32> { public ExposureCompensationParameter(PhotoCaptureDevice device) : base(device, KnownCameraPhotoProperties.ExposureCompensation, "Exposure compensation") { } ... }







Camera Explorer ArrayParameter



. . — void PopulateOptions()



void SetOption(ArrayParameterOption option)



, .



... public class ArrayParameterOption { ... public ArrayParameterOption(dynamic value, string name) { ... } public dynamic Value { ... } public string Name { ... } ... } public abstract class ArrayParameter : Parameter, IReadOnlyCollection<ArrayParameterOption> { private List<ArrayParameterOption> _options = new List<ArrayParameterOption>(); private ArrayParameterOption _selectedOption; ... public ArrayParameter(PhotoCaptureDevice device, string name) : base(device, name) { ... } public override void Refresh() { ... _options.Clear(); _selectedOption = null; try { PopulateOptions(); Supported = _options.Count > 0; } catch (Exception) { Supported = false; } ... } protected List<ArrayParameterOption> Options { ... } public ArrayParameterOption SelectedOption { ... set { if (_selectedOption != value) { ... if (_selectedOption != null)) { SetOption(value); } _selectedOption = value; } } } protected abstract void PopulateOptions(); protected abstract void SetOption(ArrayParameterOption option); ... }







, , , . void PopulateOptions()



, , ArrayParameterOption



SelectedOption



, void SetOption(ArrayParameterOption option)



. , static IReadOnlyList , KnownCameraPhotoProperties.SceneMode



object PhotoCaptureDevice.GetProperty(Guid propertyId)



. void PhotoCaptureDevice.SetProperty(Guid propertyId, object value)



.



... public class SceneModeParameter : ArrayParameter { public SceneModeParameter(PhotoCaptureDevice device) : base(device, KnownCameraPhotoProperties.SceneMode, "Scene mode") { } protected override void PopulateOptions() { IReadOnlyList<object> supportedValues = PhotoCaptureDevice.GetSupportedPropertyValues( Device.SensorLocation, PropertyId); object value = Device.GetProperty(PropertyId); foreach (dynamic i in supportedValues) { CameraSceneMode csm = (CameraSceneMode)i; ArrayParameterOption option = new ArrayParameterOption(csm, csm.ToString()); Options.Add(option); if (i.Equals(value)) { SelectedOption = option; } } } protected override void SetOption(ArrayParameterOption option) { Device.SetProperty(PropertyId, option.Value); } ... }







Tap-to-focus

«». Tap-to-focus , , , . , Tap-to-focus .



Rectangle



Canvas



, :



<Rectangle x:Name="FocusIndicator" Stroke="Red" Opacity="0.7" Width="80" Height="80" StrokeThickness="5" Visibility="Collapsed"/>







, .

Canvas Tap:



public MainPage() { ... VideoCanvas.Tap += new EventHandler<GestureEventArgs>(videoCanvas_Tap); ... }







. API- , VideoCanvas



, , .



, . , , , .



, , , , .



private async void videoCanvas_Tap(object sender, GestureEventArgs e) { System.Windows.Point uiTapPoint = e.GetPosition(VideoCanvas); if (PhotoCaptureDevice.IsFocusRegionSupported(_dataContext.Device.SensorLocation) && _focusSemaphore.WaitOne(0)) { // . Windows.Foundation.Point tapPoint = new Windows.Foundation.Point(uiTapPoint.X, uiTapPoint.Y); double xRatio = VideoCanvas.ActualWidth / _dataContext.Device.PreviewResolution.Width; double yRatio = VideoCanvas.ActualHeight / _dataContext.Device.PreviewResolution.Height; // , Windows.Foundation.Point displayOrigin = new Windows.Foundation.Point( tapPoint.X - _focusRegionSize.Width / 2, tapPoint.Y - _focusRegionSize.Height / 2); // canvas Windows.Foundation.Point viewFinderOrigin = new Windows.Foundation.Point( displayOrigin.X / xRatio, displayOrigin.Y / yRatio); Windows.Foundation.Rect focusrect = new Windows.Foundation.Rect( viewFinderOrigin, _focusRegionSize); // Windows.Foundation.Rect viewPortRect = new Windows.Foundation.Rect( 0, 0, _dataContext.Device.PreviewResolution.Width, _dataContext.Device.PreviewResolution.Height); focusrect.Intersect(viewPortRect); _dataContext.Device.FocusRegion = focusrect; // FocusIndicator.SetValue(Shape.StrokeProperty, _notFocusedBrush); FocusIndicator.SetValue(Canvas.LeftProperty, uiTapPoint.X - _focusRegionSize.Width / 2); FocusIndicator.SetValue(Canvas.TopProperty, uiTapPoint.Y - _focusRegionSize.Height / 2); FocusIndicator.SetValue(Canvas.VisibilityProperty, Visibility.Visible); CameraFocusStatus status = await _dataContext.Device.FocusAsync(); if (status == CameraFocusStatus.Locked) { FocusIndicator.SetValue(Shape.StrokeProperty, _focusedBrush); _manuallyFocused = true; _dataContext.Device.SetProperty( KnownCameraPhotoProperties.LockedAutoFocusParameters, AutoFocusParameters.Exposure & AutoFocusParameters.Focus & AutoFocusParameters.WhiteBalance); } else { _manuallyFocused = false; _dataContext.Device.SetProperty( KnownCameraPhotoProperties.LockedAutoFocusParameters, AutoFocusParameters.None); } _focusSemaphore.Release(); } }







, . FocusAsync



, , . , WaitOne



, , , false



— , .





, «», Lens Picker. «» , . Lens Picker, XML App:



<Extensions> <Extension ExtensionName="Camera_Capture_App" ConsumerId="{5B04B775-356B-4AA0-AAF8-6491FFEA5631]" TaskId="_default" /> </Extensions>







, Lens Picker, . , Lens Picker Assets



. , Lens design guidelines for Windows Phone .



Maps API.
























static IReadOnlyList

• object GetProperty(Guid propertyId)






void SetProperty(Guid propertyId, object value)







— , .



static bool IsFocusSupported(CameraSensorLocation sensor)





static bool IsFocusRegionSupported(CameraSensorLocation sensor)





IAsyncOperation FocusAsync()

• IAsyncOperation ResetFocusAsync()



— .



• static IReadOnlyList GetAvailablePreviewResolutions()

• static IReadOnlyList GetAvailableCaptureResolutions()

• IAsyncAction SetPreviewResolutionAsync(Size value)






IAsyncAction SetCaptureResolutionAsync(Size value)







— .



event TypedEventHandler<ICameraCaptureDevice, Object> PreviewFrameAvailable





void GetPreviewBufferArgb(out int[] pixels)





void GetPreviewBufferY(out byte[] pixels)





void GetPreviewBufferYCbCr(out byte[] pixels)







— .



CameraCaptureSequence CreateCaptureSequence(uint numberOfFrames)





IAsyncAction PrepareCaptureSequenceAsync(CameraCaptureSequence sequence)







— . . API . GUID. , .

, ID_CAP_ISV_CAMERA



WMAppManifest.xml . ID_CAP_MEDIALIB_PHOTO



.



Lumia

Nokia Lumia 820 920.





Camera Explorer — , PhotoCaptureDevice



. , .







, Camera Explorer.







Windows Phone DataContext



, Settings



PhotoCaptureDevice



.

PhotoCaptureDevice



DataContext, , , PhotoCaptureDevice



, , MainPage, .



Camera Explorer .

, PhotoCaptureDevice , Camera Explorer. , , . .



DataContext, , .



... class DataContext : INotifyPropertyChanged { ... public static DataContext Singleton { ... } public ObservableCollection<Parameter> Parameters { ... } public PhotoCaptureDevice Device { ... } public MemoryStream ImageStream { ... } }









, PhotoCaptureDevice



. MainPage xaml Canvas



VideoBrush



, .



<phone:PhoneApplicationPage x:Class="CameraExplorer.MainPage" ... > ... <Grid x:Name="LayoutRoot" ... > ... <Grid x:Name="ContentPanel" ... > <Canvas x:Name="VideoCanvas"> <Canvas.Background> <VideoBrush x:Name="videoBrush"/> </Canvas.Background> </Canvas> ... </Grid> </Grid> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar> <shell:ApplicationBarIconButton Text="capture" Click="captureButton_Click" ... /> ... </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> ... </phone:PhoneApplicationPage>







C# MainPage PhotoCaptureDevice



InitializeCamera



, DataContext. , XAML, , .



... public partial class MainPage : PhoneApplicationPage { private CameraExplorer.DataContext _dataContext = CameraExplorer.DataContext.Singleton; ... protected async override void OnNavigatedTo(NavigationEventArgs e) { if (_dataContext.Device == null) { ... await InitializeCamera(CameraSensorLocation.Back); ... } videoBrush.RelativeTransform = new CompositeTransform() { CenterX = 0.5, CenterY = 0.5, Rotation = _dataContext.Device.SensorLocation == CameraSensorLocation.Back ? _dataContext.Device.SensorRotationInDegrees : - _dataContext.Device.SensorRotationInDegrees }; videoBrush.SetSource(_dataContext.Device); ... } 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 void captureButton_Click(object sender, EventArgs e) { if (!_manuallyFocused) { await AutoFocus(); } await Capture(); } private async Task AutoFocus() { if (!_capturing && PhotoCaptureDevice.IsFocusSupported(_dataContext.Device.SensorLocation)) { ... await _dataContext.Device.FocusAsync(); ... _capturing = false; } } private async Task Capture() { if (!_capturing) { _capturing = true; MemoryStream stream = new MemoryStream(); CameraCaptureSequence sequence = _dataContext.Device.CreateCaptureSequence(1); sequence.Frames[0].CaptureStream = stream.AsOutputStream(); await _dataContext.Device.PrepareCaptureSequenceAsync(sequence); await sequence.StartCaptureAsync(); _dataContext.ImageStream = stream; ... } ... } ... }









. Camera Explorer , XAML Image BitmapImage



. , , , void MediaLibrary.SavePictureToCameraRoll(string name, Stream source)



, .



<phone:PhoneApplicationPage x:Class="CameraExplorer.PreviewPage" ... > ... <Grid x:Name="LayoutRoot" ... > ... <Grid x:Name="ContentPanel" ... > <Image x:Name="image" Stretch="UniformToFill"/> </Grid> </Grid> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar> <shell:ApplicationBarIconButton Text="save" Click="saveButton_Click" ... /> </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> ... </phone:PhoneApplicationPage>







... public partial class PreviewPage : PhoneApplicationPage { private CameraExplorer.DataContext _dataContext = CameraExplorer.DataContext.Singleton; private BitmapImage _bitmap = new BitmapImage(); protected override void OnNavigatedTo(NavigationEventArgs e) { ... _bitmap.SetSource(_dataContext.ImageStream); image.Source = _bitmap; ... } private void saveButton_Click(object sender, EventArgs e) { try { _dataContext.ImageStream.Position = 0; MediaLibrary library = new MediaLibrary(); library.SavePictureToCameraRoll("CameraExplorer_" + DateTime.Now.ToString() + ".jpg", _dataContext.ImageStream); } catch (Exception) { ... } ... } }







Camera Explorer , ArrayParameters



RangeParameters



, Parameters



. , , ComboBox



, Slider



Text



. , .

Parameter



, .



... public abstract class Parameter : INotifyPropertyChanged { ... protected Parameter(PhotoCaptureDevice device, string name) { ... } public PhotoCaptureDevice Device { ... } public string Name { ... } public bool Supported { ... } public abstract void Refresh(); ... }







, . _propertyId



, static CameraCapturePropertyRange PhotoCaptureDevice.GetSupportedPropertyRange(CameraSensorLocation sensor, Guid propertyId)



. object PhotoCaptureDevice.GetProperty(Guid propertyId)



. void PhotoCaptureDevice.SetProperty(Guid propertyId, object value)



.



... public abstract class RangeParameter<T> : Parameter { private Guid _propertyId; private T _value; ... protected RangeParameter(PhotoCaptureDevice device, Guid propertyId, string name) : base(device, name) { ... } public override void Refresh() { try { CameraCapturePropertyRange range = PhotoCaptureDevice.GetSupportedPropertyRange( Device.SensorLocation, _propertyId); if (range == null) { Supported = false; } else { Minimum = (T)range.Min; Maximum = (T)range.Max; _value = (T)Device.GetProperty(_propertyId); Supported = true; } } catch (Exception) { Supported = false; } ... } public T Minimum { ... } public T Maximum { ... } public T Value { ... set { if (!_value.Equals(value)) { try { Device.SetProperty(_propertyId, (T)value); _value = value; ... } catch (Exception) { ... } } } } ... }







ExposureCompensationParameter



, Guid RangeParameter



KnownCameraPhotoProperties.ExposureCompensation



, — , . , Int32



, .



... public class ExposureCompensationParameter : RangeParameter<Int32> { public ExposureCompensationParameter(PhotoCaptureDevice device) : base(device, KnownCameraPhotoProperties.ExposureCompensation, "Exposure compensation") { } ... }







Camera Explorer ArrayParameter



. . — void PopulateOptions()



void SetOption(ArrayParameterOption option)



, .



... public class ArrayParameterOption { ... public ArrayParameterOption(dynamic value, string name) { ... } public dynamic Value { ... } public string Name { ... } ... } public abstract class ArrayParameter : Parameter, IReadOnlyCollection<ArrayParameterOption> { private List<ArrayParameterOption> _options = new List<ArrayParameterOption>(); private ArrayParameterOption _selectedOption; ... public ArrayParameter(PhotoCaptureDevice device, string name) : base(device, name) { ... } public override void Refresh() { ... _options.Clear(); _selectedOption = null; try { PopulateOptions(); Supported = _options.Count > 0; } catch (Exception) { Supported = false; } ... } protected List<ArrayParameterOption> Options { ... } public ArrayParameterOption SelectedOption { ... set { if (_selectedOption != value) { ... if (_selectedOption != null)) { SetOption(value); } _selectedOption = value; } } } protected abstract void PopulateOptions(); protected abstract void SetOption(ArrayParameterOption option); ... }







, , , . void PopulateOptions()



, , ArrayParameterOption



SelectedOption



, void SetOption(ArrayParameterOption option)



. , static IReadOnlyList , KnownCameraPhotoProperties.SceneMode



object PhotoCaptureDevice.GetProperty(Guid propertyId)



. void PhotoCaptureDevice.SetProperty(Guid propertyId, object value)



.



... public class SceneModeParameter : ArrayParameter { public SceneModeParameter(PhotoCaptureDevice device) : base(device, KnownCameraPhotoProperties.SceneMode, "Scene mode") { } protected override void PopulateOptions() { IReadOnlyList<object> supportedValues = PhotoCaptureDevice.GetSupportedPropertyValues( Device.SensorLocation, PropertyId); object value = Device.GetProperty(PropertyId); foreach (dynamic i in supportedValues) { CameraSceneMode csm = (CameraSceneMode)i; ArrayParameterOption option = new ArrayParameterOption(csm, csm.ToString()); Options.Add(option); if (i.Equals(value)) { SelectedOption = option; } } } protected override void SetOption(ArrayParameterOption option) { Device.SetProperty(PropertyId, option.Value); } ... }







Tap-to-focus

«». Tap-to-focus , , , . , Tap-to-focus .



Rectangle



Canvas



, :



<Rectangle x:Name="FocusIndicator" Stroke="Red" Opacity="0.7" Width="80" Height="80" StrokeThickness="5" Visibility="Collapsed"/>







, .

Canvas Tap:



public MainPage() { ... VideoCanvas.Tap += new EventHandler<GestureEventArgs>(videoCanvas_Tap); ... }







. API- , VideoCanvas



, , .



, . , , , .



, , , , .



private async void videoCanvas_Tap(object sender, GestureEventArgs e) { System.Windows.Point uiTapPoint = e.GetPosition(VideoCanvas); if (PhotoCaptureDevice.IsFocusRegionSupported(_dataContext.Device.SensorLocation) && _focusSemaphore.WaitOne(0)) { // . Windows.Foundation.Point tapPoint = new Windows.Foundation.Point(uiTapPoint.X, uiTapPoint.Y); double xRatio = VideoCanvas.ActualWidth / _dataContext.Device.PreviewResolution.Width; double yRatio = VideoCanvas.ActualHeight / _dataContext.Device.PreviewResolution.Height; // , Windows.Foundation.Point displayOrigin = new Windows.Foundation.Point( tapPoint.X - _focusRegionSize.Width / 2, tapPoint.Y - _focusRegionSize.Height / 2); // canvas Windows.Foundation.Point viewFinderOrigin = new Windows.Foundation.Point( displayOrigin.X / xRatio, displayOrigin.Y / yRatio); Windows.Foundation.Rect focusrect = new Windows.Foundation.Rect( viewFinderOrigin, _focusRegionSize); // Windows.Foundation.Rect viewPortRect = new Windows.Foundation.Rect( 0, 0, _dataContext.Device.PreviewResolution.Width, _dataContext.Device.PreviewResolution.Height); focusrect.Intersect(viewPortRect); _dataContext.Device.FocusRegion = focusrect; // FocusIndicator.SetValue(Shape.StrokeProperty, _notFocusedBrush); FocusIndicator.SetValue(Canvas.LeftProperty, uiTapPoint.X - _focusRegionSize.Width / 2); FocusIndicator.SetValue(Canvas.TopProperty, uiTapPoint.Y - _focusRegionSize.Height / 2); FocusIndicator.SetValue(Canvas.VisibilityProperty, Visibility.Visible); CameraFocusStatus status = await _dataContext.Device.FocusAsync(); if (status == CameraFocusStatus.Locked) { FocusIndicator.SetValue(Shape.StrokeProperty, _focusedBrush); _manuallyFocused = true; _dataContext.Device.SetProperty( KnownCameraPhotoProperties.LockedAutoFocusParameters, AutoFocusParameters.Exposure & AutoFocusParameters.Focus & AutoFocusParameters.WhiteBalance); } else { _manuallyFocused = false; _dataContext.Device.SetProperty( KnownCameraPhotoProperties.LockedAutoFocusParameters, AutoFocusParameters.None); } _focusSemaphore.Release(); } }







, . FocusAsync



, , . , WaitOne



, , , false



— , .





, «», Lens Picker. «» , . Lens Picker, XML App:



<Extensions> <Extension ExtensionName="Camera_Capture_App" ConsumerId="{5B04B775-356B-4AA0-AAF8-6491FFEA5631]" TaskId="_default" /> </Extensions>







, Lens Picker, . , Lens Picker Assets



. , Lens design guidelines for Windows Phone .



Maps API.
























 static IReadOnlyList 
      

object GetProperty(Guid propertyId)






void SetProperty(Guid propertyId, object value)







— , .



static bool IsFocusSupported(CameraSensorLocation sensor)





static bool IsFocusRegionSupported(CameraSensorLocation sensor)





IAsyncOperation FocusAsync()

• IAsyncOperation ResetFocusAsync()



— .



• static IReadOnlyList GetAvailablePreviewResolutions()

• static IReadOnlyList GetAvailableCaptureResolutions()

• IAsyncAction SetPreviewResolutionAsync(Size value)






IAsyncAction SetCaptureResolutionAsync(Size value)







— .



event TypedEventHandler<ICameraCaptureDevice, Object> PreviewFrameAvailable





void GetPreviewBufferArgb(out int[] pixels)





void GetPreviewBufferY(out byte[] pixels)





void GetPreviewBufferYCbCr(out byte[] pixels)







— .



CameraCaptureSequence CreateCaptureSequence(uint numberOfFrames)





IAsyncAction PrepareCaptureSequenceAsync(CameraCaptureSequence sequence)







— . . API . GUID. , .

, ID_CAP_ISV_CAMERA



WMAppManifest.xml . ID_CAP_MEDIALIB_PHOTO



.



Lumia

Nokia Lumia 820 920.





Camera Explorer — , PhotoCaptureDevice



. , .







, Camera Explorer.







Windows Phone DataContext



, Settings



PhotoCaptureDevice



.

PhotoCaptureDevice



DataContext, , , PhotoCaptureDevice



, , MainPage, .



Camera Explorer .

, PhotoCaptureDevice , Camera Explorer. , , . .



DataContext, , .



... class DataContext : INotifyPropertyChanged { ... public static DataContext Singleton { ... } public ObservableCollection<Parameter> Parameters { ... } public PhotoCaptureDevice Device { ... } public MemoryStream ImageStream { ... } }









, PhotoCaptureDevice



. MainPage xaml Canvas



VideoBrush



, .



<phone:PhoneApplicationPage x:Class="CameraExplorer.MainPage" ... > ... <Grid x:Name="LayoutRoot" ... > ... <Grid x:Name="ContentPanel" ... > <Canvas x:Name="VideoCanvas"> <Canvas.Background> <VideoBrush x:Name="videoBrush"/> </Canvas.Background> </Canvas> ... </Grid> </Grid> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar> <shell:ApplicationBarIconButton Text="capture" Click="captureButton_Click" ... /> ... </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> ... </phone:PhoneApplicationPage>







C# MainPage PhotoCaptureDevice



InitializeCamera



, DataContext. , XAML, , .



... public partial class MainPage : PhoneApplicationPage { private CameraExplorer.DataContext _dataContext = CameraExplorer.DataContext.Singleton; ... protected async override void OnNavigatedTo(NavigationEventArgs e) { if (_dataContext.Device == null) { ... await InitializeCamera(CameraSensorLocation.Back); ... } videoBrush.RelativeTransform = new CompositeTransform() { CenterX = 0.5, CenterY = 0.5, Rotation = _dataContext.Device.SensorLocation == CameraSensorLocation.Back ? _dataContext.Device.SensorRotationInDegrees : - _dataContext.Device.SensorRotationInDegrees }; videoBrush.SetSource(_dataContext.Device); ... } 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 void captureButton_Click(object sender, EventArgs e) { if (!_manuallyFocused) { await AutoFocus(); } await Capture(); } private async Task AutoFocus() { if (!_capturing && PhotoCaptureDevice.IsFocusSupported(_dataContext.Device.SensorLocation)) { ... await _dataContext.Device.FocusAsync(); ... _capturing = false; } } private async Task Capture() { if (!_capturing) { _capturing = true; MemoryStream stream = new MemoryStream(); CameraCaptureSequence sequence = _dataContext.Device.CreateCaptureSequence(1); sequence.Frames[0].CaptureStream = stream.AsOutputStream(); await _dataContext.Device.PrepareCaptureSequenceAsync(sequence); await sequence.StartCaptureAsync(); _dataContext.ImageStream = stream; ... } ... } ... }









. Camera Explorer , XAML Image BitmapImage



. , , , void MediaLibrary.SavePictureToCameraRoll(string name, Stream source)



, .



<phone:PhoneApplicationPage x:Class="CameraExplorer.PreviewPage" ... > ... <Grid x:Name="LayoutRoot" ... > ... <Grid x:Name="ContentPanel" ... > <Image x:Name="image" Stretch="UniformToFill"/> </Grid> </Grid> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar> <shell:ApplicationBarIconButton Text="save" Click="saveButton_Click" ... /> </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> ... </phone:PhoneApplicationPage>







... public partial class PreviewPage : PhoneApplicationPage { private CameraExplorer.DataContext _dataContext = CameraExplorer.DataContext.Singleton; private BitmapImage _bitmap = new BitmapImage(); protected override void OnNavigatedTo(NavigationEventArgs e) { ... _bitmap.SetSource(_dataContext.ImageStream); image.Source = _bitmap; ... } private void saveButton_Click(object sender, EventArgs e) { try { _dataContext.ImageStream.Position = 0; MediaLibrary library = new MediaLibrary(); library.SavePictureToCameraRoll("CameraExplorer_" + DateTime.Now.ToString() + ".jpg", _dataContext.ImageStream); } catch (Exception) { ... } ... } }







Camera Explorer , ArrayParameters



RangeParameters



, Parameters



. , , ComboBox



, Slider



Text



. , .

Parameter



, .



... public abstract class Parameter : INotifyPropertyChanged { ... protected Parameter(PhotoCaptureDevice device, string name) { ... } public PhotoCaptureDevice Device { ... } public string Name { ... } public bool Supported { ... } public abstract void Refresh(); ... }







, . _propertyId



, static CameraCapturePropertyRange PhotoCaptureDevice.GetSupportedPropertyRange(CameraSensorLocation sensor, Guid propertyId)



. object PhotoCaptureDevice.GetProperty(Guid propertyId)



. void PhotoCaptureDevice.SetProperty(Guid propertyId, object value)



.



... public abstract class RangeParameter<T> : Parameter { private Guid _propertyId; private T _value; ... protected RangeParameter(PhotoCaptureDevice device, Guid propertyId, string name) : base(device, name) { ... } public override void Refresh() { try { CameraCapturePropertyRange range = PhotoCaptureDevice.GetSupportedPropertyRange( Device.SensorLocation, _propertyId); if (range == null) { Supported = false; } else { Minimum = (T)range.Min; Maximum = (T)range.Max; _value = (T)Device.GetProperty(_propertyId); Supported = true; } } catch (Exception) { Supported = false; } ... } public T Minimum { ... } public T Maximum { ... } public T Value { ... set { if (!_value.Equals(value)) { try { Device.SetProperty(_propertyId, (T)value); _value = value; ... } catch (Exception) { ... } } } } ... }







ExposureCompensationParameter



, Guid RangeParameter



KnownCameraPhotoProperties.ExposureCompensation



, — , . , Int32



, .



... public class ExposureCompensationParameter : RangeParameter<Int32> { public ExposureCompensationParameter(PhotoCaptureDevice device) : base(device, KnownCameraPhotoProperties.ExposureCompensation, "Exposure compensation") { } ... }







Camera Explorer ArrayParameter



. . — void PopulateOptions()



void SetOption(ArrayParameterOption option)



, .



... public class ArrayParameterOption { ... public ArrayParameterOption(dynamic value, string name) { ... } public dynamic Value { ... } public string Name { ... } ... } public abstract class ArrayParameter : Parameter, IReadOnlyCollection<ArrayParameterOption> { private List<ArrayParameterOption> _options = new List<ArrayParameterOption>(); private ArrayParameterOption _selectedOption; ... public ArrayParameter(PhotoCaptureDevice device, string name) : base(device, name) { ... } public override void Refresh() { ... _options.Clear(); _selectedOption = null; try { PopulateOptions(); Supported = _options.Count > 0; } catch (Exception) { Supported = false; } ... } protected List<ArrayParameterOption> Options { ... } public ArrayParameterOption SelectedOption { ... set { if (_selectedOption != value) { ... if (_selectedOption != null)) { SetOption(value); } _selectedOption = value; } } } protected abstract void PopulateOptions(); protected abstract void SetOption(ArrayParameterOption option); ... }







, , , . void PopulateOptions()



, , ArrayParameterOption



SelectedOption



, void SetOption(ArrayParameterOption option)



. , static IReadOnlyList , KnownCameraPhotoProperties.SceneMode



object PhotoCaptureDevice.GetProperty(Guid propertyId)



. void PhotoCaptureDevice.SetProperty(Guid propertyId, object value)



.



... public class SceneModeParameter : ArrayParameter { public SceneModeParameter(PhotoCaptureDevice device) : base(device, KnownCameraPhotoProperties.SceneMode, "Scene mode") { } protected override void PopulateOptions() { IReadOnlyList<object> supportedValues = PhotoCaptureDevice.GetSupportedPropertyValues( Device.SensorLocation, PropertyId); object value = Device.GetProperty(PropertyId); foreach (dynamic i in supportedValues) { CameraSceneMode csm = (CameraSceneMode)i; ArrayParameterOption option = new ArrayParameterOption(csm, csm.ToString()); Options.Add(option); if (i.Equals(value)) { SelectedOption = option; } } } protected override void SetOption(ArrayParameterOption option) { Device.SetProperty(PropertyId, option.Value); } ... }







Tap-to-focus

«». Tap-to-focus , , , . , Tap-to-focus .



Rectangle



Canvas



, :



<Rectangle x:Name="FocusIndicator" Stroke="Red" Opacity="0.7" Width="80" Height="80" StrokeThickness="5" Visibility="Collapsed"/>







, .

Canvas Tap:



public MainPage() { ... VideoCanvas.Tap += new EventHandler<GestureEventArgs>(videoCanvas_Tap); ... }







. API- , VideoCanvas



, , .



, . , , , .



, , , , .



private async void videoCanvas_Tap(object sender, GestureEventArgs e) { System.Windows.Point uiTapPoint = e.GetPosition(VideoCanvas); if (PhotoCaptureDevice.IsFocusRegionSupported(_dataContext.Device.SensorLocation) && _focusSemaphore.WaitOne(0)) { // . Windows.Foundation.Point tapPoint = new Windows.Foundation.Point(uiTapPoint.X, uiTapPoint.Y); double xRatio = VideoCanvas.ActualWidth / _dataContext.Device.PreviewResolution.Width; double yRatio = VideoCanvas.ActualHeight / _dataContext.Device.PreviewResolution.Height; // , Windows.Foundation.Point displayOrigin = new Windows.Foundation.Point( tapPoint.X - _focusRegionSize.Width / 2, tapPoint.Y - _focusRegionSize.Height / 2); // canvas Windows.Foundation.Point viewFinderOrigin = new Windows.Foundation.Point( displayOrigin.X / xRatio, displayOrigin.Y / yRatio); Windows.Foundation.Rect focusrect = new Windows.Foundation.Rect( viewFinderOrigin, _focusRegionSize); // Windows.Foundation.Rect viewPortRect = new Windows.Foundation.Rect( 0, 0, _dataContext.Device.PreviewResolution.Width, _dataContext.Device.PreviewResolution.Height); focusrect.Intersect(viewPortRect); _dataContext.Device.FocusRegion = focusrect; // FocusIndicator.SetValue(Shape.StrokeProperty, _notFocusedBrush); FocusIndicator.SetValue(Canvas.LeftProperty, uiTapPoint.X - _focusRegionSize.Width / 2); FocusIndicator.SetValue(Canvas.TopProperty, uiTapPoint.Y - _focusRegionSize.Height / 2); FocusIndicator.SetValue(Canvas.VisibilityProperty, Visibility.Visible); CameraFocusStatus status = await _dataContext.Device.FocusAsync(); if (status == CameraFocusStatus.Locked) { FocusIndicator.SetValue(Shape.StrokeProperty, _focusedBrush); _manuallyFocused = true; _dataContext.Device.SetProperty( KnownCameraPhotoProperties.LockedAutoFocusParameters, AutoFocusParameters.Exposure & AutoFocusParameters.Focus & AutoFocusParameters.WhiteBalance); } else { _manuallyFocused = false; _dataContext.Device.SetProperty( KnownCameraPhotoProperties.LockedAutoFocusParameters, AutoFocusParameters.None); } _focusSemaphore.Release(); } }







, . FocusAsync



, , . , WaitOne



, , , false



— , .





, «», Lens Picker. «» , . Lens Picker, XML App:



<Extensions> <Extension ExtensionName="Camera_Capture_App" ConsumerId="{5B04B775-356B-4AA0-AAF8-6491FFEA5631]" TaskId="_default" /> </Extensions>







, Lens Picker, . , Lens Picker Assets



. , Lens design guidelines for Windows Phone .



Maps API.
























static IReadOnlyList

• object GetProperty(Guid propertyId)






void SetProperty(Guid propertyId, object value)







— , .



static bool IsFocusSupported(CameraSensorLocation sensor)





static bool IsFocusRegionSupported(CameraSensorLocation sensor)





IAsyncOperation FocusAsync()

• IAsyncOperation ResetFocusAsync()



— .



• static IReadOnlyList GetAvailablePreviewResolutions()

• static IReadOnlyList GetAvailableCaptureResolutions()

• IAsyncAction SetPreviewResolutionAsync(Size value)






IAsyncAction SetCaptureResolutionAsync(Size value)







— .



event TypedEventHandler<ICameraCaptureDevice, Object> PreviewFrameAvailable





void GetPreviewBufferArgb(out int[] pixels)





void GetPreviewBufferY(out byte[] pixels)





void GetPreviewBufferYCbCr(out byte[] pixels)







— .



CameraCaptureSequence CreateCaptureSequence(uint numberOfFrames)





IAsyncAction PrepareCaptureSequenceAsync(CameraCaptureSequence sequence)







— . . API . GUID. , .

, ID_CAP_ISV_CAMERA



WMAppManifest.xml . ID_CAP_MEDIALIB_PHOTO



.



Lumia

Nokia Lumia 820 920.





Camera Explorer — , PhotoCaptureDevice



. , .







, Camera Explorer.







Windows Phone DataContext



, Settings



PhotoCaptureDevice



.

PhotoCaptureDevice



DataContext, , , PhotoCaptureDevice



, , MainPage, .



Camera Explorer .

, PhotoCaptureDevice , Camera Explorer. , , . .



DataContext, , .



... class DataContext : INotifyPropertyChanged { ... public static DataContext Singleton { ... } public ObservableCollection<Parameter> Parameters { ... } public PhotoCaptureDevice Device { ... } public MemoryStream ImageStream { ... } }









, PhotoCaptureDevice



. MainPage xaml Canvas



VideoBrush



, .



<phone:PhoneApplicationPage x:Class="CameraExplorer.MainPage" ... > ... <Grid x:Name="LayoutRoot" ... > ... <Grid x:Name="ContentPanel" ... > <Canvas x:Name="VideoCanvas"> <Canvas.Background> <VideoBrush x:Name="videoBrush"/> </Canvas.Background> </Canvas> ... </Grid> </Grid> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar> <shell:ApplicationBarIconButton Text="capture" Click="captureButton_Click" ... /> ... </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> ... </phone:PhoneApplicationPage>







C# MainPage PhotoCaptureDevice



InitializeCamera



, DataContext. , XAML, , .



... public partial class MainPage : PhoneApplicationPage { private CameraExplorer.DataContext _dataContext = CameraExplorer.DataContext.Singleton; ... protected async override void OnNavigatedTo(NavigationEventArgs e) { if (_dataContext.Device == null) { ... await InitializeCamera(CameraSensorLocation.Back); ... } videoBrush.RelativeTransform = new CompositeTransform() { CenterX = 0.5, CenterY = 0.5, Rotation = _dataContext.Device.SensorLocation == CameraSensorLocation.Back ? _dataContext.Device.SensorRotationInDegrees : - _dataContext.Device.SensorRotationInDegrees }; videoBrush.SetSource(_dataContext.Device); ... } 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 void captureButton_Click(object sender, EventArgs e) { if (!_manuallyFocused) { await AutoFocus(); } await Capture(); } private async Task AutoFocus() { if (!_capturing && PhotoCaptureDevice.IsFocusSupported(_dataContext.Device.SensorLocation)) { ... await _dataContext.Device.FocusAsync(); ... _capturing = false; } } private async Task Capture() { if (!_capturing) { _capturing = true; MemoryStream stream = new MemoryStream(); CameraCaptureSequence sequence = _dataContext.Device.CreateCaptureSequence(1); sequence.Frames[0].CaptureStream = stream.AsOutputStream(); await _dataContext.Device.PrepareCaptureSequenceAsync(sequence); await sequence.StartCaptureAsync(); _dataContext.ImageStream = stream; ... } ... } ... }









. Camera Explorer , XAML Image BitmapImage



. , , , void MediaLibrary.SavePictureToCameraRoll(string name, Stream source)



, .



<phone:PhoneApplicationPage x:Class="CameraExplorer.PreviewPage" ... > ... <Grid x:Name="LayoutRoot" ... > ... <Grid x:Name="ContentPanel" ... > <Image x:Name="image" Stretch="UniformToFill"/> </Grid> </Grid> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar> <shell:ApplicationBarIconButton Text="save" Click="saveButton_Click" ... /> </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> ... </phone:PhoneApplicationPage>







... public partial class PreviewPage : PhoneApplicationPage { private CameraExplorer.DataContext _dataContext = CameraExplorer.DataContext.Singleton; private BitmapImage _bitmap = new BitmapImage(); protected override void OnNavigatedTo(NavigationEventArgs e) { ... _bitmap.SetSource(_dataContext.ImageStream); image.Source = _bitmap; ... } private void saveButton_Click(object sender, EventArgs e) { try { _dataContext.ImageStream.Position = 0; MediaLibrary library = new MediaLibrary(); library.SavePictureToCameraRoll("CameraExplorer_" + DateTime.Now.ToString() + ".jpg", _dataContext.ImageStream); } catch (Exception) { ... } ... } }







Camera Explorer , ArrayParameters



RangeParameters



, Parameters



. , , ComboBox



, Slider



Text



. , .

Parameter



, .



... public abstract class Parameter : INotifyPropertyChanged { ... protected Parameter(PhotoCaptureDevice device, string name) { ... } public PhotoCaptureDevice Device { ... } public string Name { ... } public bool Supported { ... } public abstract void Refresh(); ... }







, . _propertyId



, static CameraCapturePropertyRange PhotoCaptureDevice.GetSupportedPropertyRange(CameraSensorLocation sensor, Guid propertyId)



. object PhotoCaptureDevice.GetProperty(Guid propertyId)



. void PhotoCaptureDevice.SetProperty(Guid propertyId, object value)



.



... public abstract class RangeParameter<T> : Parameter { private Guid _propertyId; private T _value; ... protected RangeParameter(PhotoCaptureDevice device, Guid propertyId, string name) : base(device, name) { ... } public override void Refresh() { try { CameraCapturePropertyRange range = PhotoCaptureDevice.GetSupportedPropertyRange( Device.SensorLocation, _propertyId); if (range == null) { Supported = false; } else { Minimum = (T)range.Min; Maximum = (T)range.Max; _value = (T)Device.GetProperty(_propertyId); Supported = true; } } catch (Exception) { Supported = false; } ... } public T Minimum { ... } public T Maximum { ... } public T Value { ... set { if (!_value.Equals(value)) { try { Device.SetProperty(_propertyId, (T)value); _value = value; ... } catch (Exception) { ... } } } } ... }







ExposureCompensationParameter



, Guid RangeParameter



KnownCameraPhotoProperties.ExposureCompensation



, — , . , Int32



, .



... public class ExposureCompensationParameter : RangeParameter<Int32> { public ExposureCompensationParameter(PhotoCaptureDevice device) : base(device, KnownCameraPhotoProperties.ExposureCompensation, "Exposure compensation") { } ... }







Camera Explorer ArrayParameter



. . — void PopulateOptions()



void SetOption(ArrayParameterOption option)



, .



... public class ArrayParameterOption { ... public ArrayParameterOption(dynamic value, string name) { ... } public dynamic Value { ... } public string Name { ... } ... } public abstract class ArrayParameter : Parameter, IReadOnlyCollection<ArrayParameterOption> { private List<ArrayParameterOption> _options = new List<ArrayParameterOption>(); private ArrayParameterOption _selectedOption; ... public ArrayParameter(PhotoCaptureDevice device, string name) : base(device, name) { ... } public override void Refresh() { ... _options.Clear(); _selectedOption = null; try { PopulateOptions(); Supported = _options.Count > 0; } catch (Exception) { Supported = false; } ... } protected List<ArrayParameterOption> Options { ... } public ArrayParameterOption SelectedOption { ... set { if (_selectedOption != value) { ... if (_selectedOption != null)) { SetOption(value); } _selectedOption = value; } } } protected abstract void PopulateOptions(); protected abstract void SetOption(ArrayParameterOption option); ... }







, , , . void PopulateOptions()



, , ArrayParameterOption



SelectedOption



, void SetOption(ArrayParameterOption option)



. , static IReadOnlyList , KnownCameraPhotoProperties.SceneMode



object PhotoCaptureDevice.GetProperty(Guid propertyId)



. void PhotoCaptureDevice.SetProperty(Guid propertyId, object value)



.



... public class SceneModeParameter : ArrayParameter { public SceneModeParameter(PhotoCaptureDevice device) : base(device, KnownCameraPhotoProperties.SceneMode, "Scene mode") { } protected override void PopulateOptions() { IReadOnlyList<object> supportedValues = PhotoCaptureDevice.GetSupportedPropertyValues( Device.SensorLocation, PropertyId); object value = Device.GetProperty(PropertyId); foreach (dynamic i in supportedValues) { CameraSceneMode csm = (CameraSceneMode)i; ArrayParameterOption option = new ArrayParameterOption(csm, csm.ToString()); Options.Add(option); if (i.Equals(value)) { SelectedOption = option; } } } protected override void SetOption(ArrayParameterOption option) { Device.SetProperty(PropertyId, option.Value); } ... }







Tap-to-focus

«». Tap-to-focus , , , . , Tap-to-focus .



Rectangle



Canvas



, :



<Rectangle x:Name="FocusIndicator" Stroke="Red" Opacity="0.7" Width="80" Height="80" StrokeThickness="5" Visibility="Collapsed"/>







, .

Canvas Tap:



public MainPage() { ... VideoCanvas.Tap += new EventHandler<GestureEventArgs>(videoCanvas_Tap); ... }







. API- , VideoCanvas



, , .



, . , , , .



, , , , .



private async void videoCanvas_Tap(object sender, GestureEventArgs e) { System.Windows.Point uiTapPoint = e.GetPosition(VideoCanvas); if (PhotoCaptureDevice.IsFocusRegionSupported(_dataContext.Device.SensorLocation) && _focusSemaphore.WaitOne(0)) { // . Windows.Foundation.Point tapPoint = new Windows.Foundation.Point(uiTapPoint.X, uiTapPoint.Y); double xRatio = VideoCanvas.ActualWidth / _dataContext.Device.PreviewResolution.Width; double yRatio = VideoCanvas.ActualHeight / _dataContext.Device.PreviewResolution.Height; // , Windows.Foundation.Point displayOrigin = new Windows.Foundation.Point( tapPoint.X - _focusRegionSize.Width / 2, tapPoint.Y - _focusRegionSize.Height / 2); // canvas Windows.Foundation.Point viewFinderOrigin = new Windows.Foundation.Point( displayOrigin.X / xRatio, displayOrigin.Y / yRatio); Windows.Foundation.Rect focusrect = new Windows.Foundation.Rect( viewFinderOrigin, _focusRegionSize); // Windows.Foundation.Rect viewPortRect = new Windows.Foundation.Rect( 0, 0, _dataContext.Device.PreviewResolution.Width, _dataContext.Device.PreviewResolution.Height); focusrect.Intersect(viewPortRect); _dataContext.Device.FocusRegion = focusrect; // FocusIndicator.SetValue(Shape.StrokeProperty, _notFocusedBrush); FocusIndicator.SetValue(Canvas.LeftProperty, uiTapPoint.X - _focusRegionSize.Width / 2); FocusIndicator.SetValue(Canvas.TopProperty, uiTapPoint.Y - _focusRegionSize.Height / 2); FocusIndicator.SetValue(Canvas.VisibilityProperty, Visibility.Visible); CameraFocusStatus status = await _dataContext.Device.FocusAsync(); if (status == CameraFocusStatus.Locked) { FocusIndicator.SetValue(Shape.StrokeProperty, _focusedBrush); _manuallyFocused = true; _dataContext.Device.SetProperty( KnownCameraPhotoProperties.LockedAutoFocusParameters, AutoFocusParameters.Exposure & AutoFocusParameters.Focus & AutoFocusParameters.WhiteBalance); } else { _manuallyFocused = false; _dataContext.Device.SetProperty( KnownCameraPhotoProperties.LockedAutoFocusParameters, AutoFocusParameters.None); } _focusSemaphore.Release(); } }







, . FocusAsync



, , . , WaitOne



, , , false



— , .





, «», Lens Picker. «» , . Lens Picker, XML App:



<Extensions> <Extension ExtensionName="Camera_Capture_App" ConsumerId="{5B04B775-356B-4AA0-AAF8-6491FFEA5631]" TaskId="_default" /> </Extensions>







, Lens Picker, . , Lens Picker Assets



. , Lens design guidelines for Windows Phone .



Maps API.
























 static IReadOnlyList 
      

object GetProperty(Guid propertyId)






void SetProperty(Guid propertyId, object value)







— , .



static bool IsFocusSupported(CameraSensorLocation sensor)





static bool IsFocusRegionSupported(CameraSensorLocation sensor)





IAsyncOperation FocusAsync()

• IAsyncOperation ResetFocusAsync()



— .



• static IReadOnlyList GetAvailablePreviewResolutions()

• static IReadOnlyList GetAvailableCaptureResolutions()

• IAsyncAction SetPreviewResolutionAsync(Size value)






IAsyncAction SetCaptureResolutionAsync(Size value)







— .



event TypedEventHandler<ICameraCaptureDevice, Object> PreviewFrameAvailable





void GetPreviewBufferArgb(out int[] pixels)





void GetPreviewBufferY(out byte[] pixels)





void GetPreviewBufferYCbCr(out byte[] pixels)







— .



CameraCaptureSequence CreateCaptureSequence(uint numberOfFrames)





IAsyncAction PrepareCaptureSequenceAsync(CameraCaptureSequence sequence)







— . . API . GUID. , .

, ID_CAP_ISV_CAMERA



WMAppManifest.xml . ID_CAP_MEDIALIB_PHOTO



.



Lumia

Nokia Lumia 820 920.





Camera Explorer — , PhotoCaptureDevice



. , .







, Camera Explorer.







Windows Phone DataContext



, Settings



PhotoCaptureDevice



.

PhotoCaptureDevice



DataContext, , , PhotoCaptureDevice



, , MainPage, .



Camera Explorer .

, PhotoCaptureDevice , Camera Explorer. , , . .



DataContext, , .



... class DataContext : INotifyPropertyChanged { ... public static DataContext Singleton { ... } public ObservableCollection<Parameter> Parameters { ... } public PhotoCaptureDevice Device { ... } public MemoryStream ImageStream { ... } }









, PhotoCaptureDevice



. MainPage xaml Canvas



VideoBrush



, .



<phone:PhoneApplicationPage x:Class="CameraExplorer.MainPage" ... > ... <Grid x:Name="LayoutRoot" ... > ... <Grid x:Name="ContentPanel" ... > <Canvas x:Name="VideoCanvas"> <Canvas.Background> <VideoBrush x:Name="videoBrush"/> </Canvas.Background> </Canvas> ... </Grid> </Grid> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar> <shell:ApplicationBarIconButton Text="capture" Click="captureButton_Click" ... /> ... </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> ... </phone:PhoneApplicationPage>







C# MainPage PhotoCaptureDevice



InitializeCamera



, DataContext. , XAML, , .



... public partial class MainPage : PhoneApplicationPage { private CameraExplorer.DataContext _dataContext = CameraExplorer.DataContext.Singleton; ... protected async override void OnNavigatedTo(NavigationEventArgs e) { if (_dataContext.Device == null) { ... await InitializeCamera(CameraSensorLocation.Back); ... } videoBrush.RelativeTransform = new CompositeTransform() { CenterX = 0.5, CenterY = 0.5, Rotation = _dataContext.Device.SensorLocation == CameraSensorLocation.Back ? _dataContext.Device.SensorRotationInDegrees : - _dataContext.Device.SensorRotationInDegrees }; videoBrush.SetSource(_dataContext.Device); ... } 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 void captureButton_Click(object sender, EventArgs e) { if (!_manuallyFocused) { await AutoFocus(); } await Capture(); } private async Task AutoFocus() { if (!_capturing && PhotoCaptureDevice.IsFocusSupported(_dataContext.Device.SensorLocation)) { ... await _dataContext.Device.FocusAsync(); ... _capturing = false; } } private async Task Capture() { if (!_capturing) { _capturing = true; MemoryStream stream = new MemoryStream(); CameraCaptureSequence sequence = _dataContext.Device.CreateCaptureSequence(1); sequence.Frames[0].CaptureStream = stream.AsOutputStream(); await _dataContext.Device.PrepareCaptureSequenceAsync(sequence); await sequence.StartCaptureAsync(); _dataContext.ImageStream = stream; ... } ... } ... }









. Camera Explorer , XAML Image BitmapImage



. , , , void MediaLibrary.SavePictureToCameraRoll(string name, Stream source)



, .



<phone:PhoneApplicationPage x:Class="CameraExplorer.PreviewPage" ... > ... <Grid x:Name="LayoutRoot" ... > ... <Grid x:Name="ContentPanel" ... > <Image x:Name="image" Stretch="UniformToFill"/> </Grid> </Grid> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar> <shell:ApplicationBarIconButton Text="save" Click="saveButton_Click" ... /> </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> ... </phone:PhoneApplicationPage>







... public partial class PreviewPage : PhoneApplicationPage { private CameraExplorer.DataContext _dataContext = CameraExplorer.DataContext.Singleton; private BitmapImage _bitmap = new BitmapImage(); protected override void OnNavigatedTo(NavigationEventArgs e) { ... _bitmap.SetSource(_dataContext.ImageStream); image.Source = _bitmap; ... } private void saveButton_Click(object sender, EventArgs e) { try { _dataContext.ImageStream.Position = 0; MediaLibrary library = new MediaLibrary(); library.SavePictureToCameraRoll("CameraExplorer_" + DateTime.Now.ToString() + ".jpg", _dataContext.ImageStream); } catch (Exception) { ... } ... } }







Camera Explorer , ArrayParameters



RangeParameters



, Parameters



. , , ComboBox



, Slider



Text



. , .

Parameter



, .



... public abstract class Parameter : INotifyPropertyChanged { ... protected Parameter(PhotoCaptureDevice device, string name) { ... } public PhotoCaptureDevice Device { ... } public string Name { ... } public bool Supported { ... } public abstract void Refresh(); ... }







, . _propertyId



, static CameraCapturePropertyRange PhotoCaptureDevice.GetSupportedPropertyRange(CameraSensorLocation sensor, Guid propertyId)



. object PhotoCaptureDevice.GetProperty(Guid propertyId)



. void PhotoCaptureDevice.SetProperty(Guid propertyId, object value)



.



... public abstract class RangeParameter<T> : Parameter { private Guid _propertyId; private T _value; ... protected RangeParameter(PhotoCaptureDevice device, Guid propertyId, string name) : base(device, name) { ... } public override void Refresh() { try { CameraCapturePropertyRange range = PhotoCaptureDevice.GetSupportedPropertyRange( Device.SensorLocation, _propertyId); if (range == null) { Supported = false; } else { Minimum = (T)range.Min; Maximum = (T)range.Max; _value = (T)Device.GetProperty(_propertyId); Supported = true; } } catch (Exception) { Supported = false; } ... } public T Minimum { ... } public T Maximum { ... } public T Value { ... set { if (!_value.Equals(value)) { try { Device.SetProperty(_propertyId, (T)value); _value = value; ... } catch (Exception) { ... } } } } ... }







ExposureCompensationParameter



, Guid RangeParameter



KnownCameraPhotoProperties.ExposureCompensation



, — , . , Int32



, .



... public class ExposureCompensationParameter : RangeParameter<Int32> { public ExposureCompensationParameter(PhotoCaptureDevice device) : base(device, KnownCameraPhotoProperties.ExposureCompensation, "Exposure compensation") { } ... }







Camera Explorer ArrayParameter



. . — void PopulateOptions()



void SetOption(ArrayParameterOption option)



, .



... public class ArrayParameterOption { ... public ArrayParameterOption(dynamic value, string name) { ... } public dynamic Value { ... } public string Name { ... } ... } public abstract class ArrayParameter : Parameter, IReadOnlyCollection<ArrayParameterOption> { private List<ArrayParameterOption> _options = new List<ArrayParameterOption>(); private ArrayParameterOption _selectedOption; ... public ArrayParameter(PhotoCaptureDevice device, string name) : base(device, name) { ... } public override void Refresh() { ... _options.Clear(); _selectedOption = null; try { PopulateOptions(); Supported = _options.Count > 0; } catch (Exception) { Supported = false; } ... } protected List<ArrayParameterOption> Options { ... } public ArrayParameterOption SelectedOption { ... set { if (_selectedOption != value) { ... if (_selectedOption != null)) { SetOption(value); } _selectedOption = value; } } } protected abstract void PopulateOptions(); protected abstract void SetOption(ArrayParameterOption option); ... }







, , , . void PopulateOptions()



, , ArrayParameterOption



SelectedOption



, void SetOption(ArrayParameterOption option)



. , static IReadOnlyList , KnownCameraPhotoProperties.SceneMode



object PhotoCaptureDevice.GetProperty(Guid propertyId)



. void PhotoCaptureDevice.SetProperty(Guid propertyId, object value)



.



... public class SceneModeParameter : ArrayParameter { public SceneModeParameter(PhotoCaptureDevice device) : base(device, KnownCameraPhotoProperties.SceneMode, "Scene mode") { } protected override void PopulateOptions() { IReadOnlyList<object> supportedValues = PhotoCaptureDevice.GetSupportedPropertyValues( Device.SensorLocation, PropertyId); object value = Device.GetProperty(PropertyId); foreach (dynamic i in supportedValues) { CameraSceneMode csm = (CameraSceneMode)i; ArrayParameterOption option = new ArrayParameterOption(csm, csm.ToString()); Options.Add(option); if (i.Equals(value)) { SelectedOption = option; } } } protected override void SetOption(ArrayParameterOption option) { Device.SetProperty(PropertyId, option.Value); } ... }







Tap-to-focus

«». Tap-to-focus , , , . , Tap-to-focus .



Rectangle



Canvas



, :



<Rectangle x:Name="FocusIndicator" Stroke="Red" Opacity="0.7" Width="80" Height="80" StrokeThickness="5" Visibility="Collapsed"/>







, .

Canvas Tap:



public MainPage() { ... VideoCanvas.Tap += new EventHandler<GestureEventArgs>(videoCanvas_Tap); ... }







. API- , VideoCanvas



, , .



, . , , , .



, , , , .



private async void videoCanvas_Tap(object sender, GestureEventArgs e) { System.Windows.Point uiTapPoint = e.GetPosition(VideoCanvas); if (PhotoCaptureDevice.IsFocusRegionSupported(_dataContext.Device.SensorLocation) && _focusSemaphore.WaitOne(0)) { // . Windows.Foundation.Point tapPoint = new Windows.Foundation.Point(uiTapPoint.X, uiTapPoint.Y); double xRatio = VideoCanvas.ActualWidth / _dataContext.Device.PreviewResolution.Width; double yRatio = VideoCanvas.ActualHeight / _dataContext.Device.PreviewResolution.Height; // , Windows.Foundation.Point displayOrigin = new Windows.Foundation.Point( tapPoint.X - _focusRegionSize.Width / 2, tapPoint.Y - _focusRegionSize.Height / 2); // canvas Windows.Foundation.Point viewFinderOrigin = new Windows.Foundation.Point( displayOrigin.X / xRatio, displayOrigin.Y / yRatio); Windows.Foundation.Rect focusrect = new Windows.Foundation.Rect( viewFinderOrigin, _focusRegionSize); // Windows.Foundation.Rect viewPortRect = new Windows.Foundation.Rect( 0, 0, _dataContext.Device.PreviewResolution.Width, _dataContext.Device.PreviewResolution.Height); focusrect.Intersect(viewPortRect); _dataContext.Device.FocusRegion = focusrect; // FocusIndicator.SetValue(Shape.StrokeProperty, _notFocusedBrush); FocusIndicator.SetValue(Canvas.LeftProperty, uiTapPoint.X - _focusRegionSize.Width / 2); FocusIndicator.SetValue(Canvas.TopProperty, uiTapPoint.Y - _focusRegionSize.Height / 2); FocusIndicator.SetValue(Canvas.VisibilityProperty, Visibility.Visible); CameraFocusStatus status = await _dataContext.Device.FocusAsync(); if (status == CameraFocusStatus.Locked) { FocusIndicator.SetValue(Shape.StrokeProperty, _focusedBrush); _manuallyFocused = true; _dataContext.Device.SetProperty( KnownCameraPhotoProperties.LockedAutoFocusParameters, AutoFocusParameters.Exposure & AutoFocusParameters.Focus & AutoFocusParameters.WhiteBalance); } else { _manuallyFocused = false; _dataContext.Device.SetProperty( KnownCameraPhotoProperties.LockedAutoFocusParameters, AutoFocusParameters.None); } _focusSemaphore.Release(); } }







, . FocusAsync



, , . , WaitOne



, , , false



— , .





, «», Lens Picker. «» , . Lens Picker, XML App:



<Extensions> <Extension ExtensionName="Camera_Capture_App" ConsumerId="{5B04B775-356B-4AA0-AAF8-6491FFEA5631]" TaskId="_default" /> </Extensions>







, Lens Picker, . , Lens Picker Assets



. , Lens design guidelines for Windows Phone .



Maps API.
























static IReadOnlyList

• object GetProperty(Guid propertyId)






void SetProperty(Guid propertyId, object value)







— , .



static bool IsFocusSupported(CameraSensorLocation sensor)





static bool IsFocusRegionSupported(CameraSensorLocation sensor)





IAsyncOperation FocusAsync()

• IAsyncOperation ResetFocusAsync()



— .



• static IReadOnlyList GetAvailablePreviewResolutions()

• static IReadOnlyList GetAvailableCaptureResolutions()

• IAsyncAction SetPreviewResolutionAsync(Size value)






IAsyncAction SetCaptureResolutionAsync(Size value)







— .



event TypedEventHandler<ICameraCaptureDevice, Object> PreviewFrameAvailable





void GetPreviewBufferArgb(out int[] pixels)





void GetPreviewBufferY(out byte[] pixels)





void GetPreviewBufferYCbCr(out byte[] pixels)







— .



CameraCaptureSequence CreateCaptureSequence(uint numberOfFrames)





IAsyncAction PrepareCaptureSequenceAsync(CameraCaptureSequence sequence)







— . . API . GUID. , .

, ID_CAP_ISV_CAMERA



WMAppManifest.xml . ID_CAP_MEDIALIB_PHOTO



.



Lumia

Nokia Lumia 820 920.





Camera Explorer — , PhotoCaptureDevice



. , .







, Camera Explorer.







Windows Phone DataContext



, Settings



PhotoCaptureDevice



.

PhotoCaptureDevice



DataContext, , , PhotoCaptureDevice



, , MainPage, .



Camera Explorer .

, PhotoCaptureDevice , Camera Explorer. , , . .



DataContext, , .



... class DataContext : INotifyPropertyChanged { ... public static DataContext Singleton { ... } public ObservableCollection<Parameter> Parameters { ... } public PhotoCaptureDevice Device { ... } public MemoryStream ImageStream { ... } }









, PhotoCaptureDevice



. MainPage xaml Canvas



VideoBrush



, .



<phone:PhoneApplicationPage x:Class="CameraExplorer.MainPage" ... > ... <Grid x:Name="LayoutRoot" ... > ... <Grid x:Name="ContentPanel" ... > <Canvas x:Name="VideoCanvas"> <Canvas.Background> <VideoBrush x:Name="videoBrush"/> </Canvas.Background> </Canvas> ... </Grid> </Grid> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar> <shell:ApplicationBarIconButton Text="capture" Click="captureButton_Click" ... /> ... </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> ... </phone:PhoneApplicationPage>







C# MainPage PhotoCaptureDevice



InitializeCamera



, DataContext. , XAML, , .



... public partial class MainPage : PhoneApplicationPage { private CameraExplorer.DataContext _dataContext = CameraExplorer.DataContext.Singleton; ... protected async override void OnNavigatedTo(NavigationEventArgs e) { if (_dataContext.Device == null) { ... await InitializeCamera(CameraSensorLocation.Back); ... } videoBrush.RelativeTransform = new CompositeTransform() { CenterX = 0.5, CenterY = 0.5, Rotation = _dataContext.Device.SensorLocation == CameraSensorLocation.Back ? _dataContext.Device.SensorRotationInDegrees : - _dataContext.Device.SensorRotationInDegrees }; videoBrush.SetSource(_dataContext.Device); ... } 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 void captureButton_Click(object sender, EventArgs e) { if (!_manuallyFocused) { await AutoFocus(); } await Capture(); } private async Task AutoFocus() { if (!_capturing && PhotoCaptureDevice.IsFocusSupported(_dataContext.Device.SensorLocation)) { ... await _dataContext.Device.FocusAsync(); ... _capturing = false; } } private async Task Capture() { if (!_capturing) { _capturing = true; MemoryStream stream = new MemoryStream(); CameraCaptureSequence sequence = _dataContext.Device.CreateCaptureSequence(1); sequence.Frames[0].CaptureStream = stream.AsOutputStream(); await _dataContext.Device.PrepareCaptureSequenceAsync(sequence); await sequence.StartCaptureAsync(); _dataContext.ImageStream = stream; ... } ... } ... }









. Camera Explorer , XAML Image BitmapImage



. , , , void MediaLibrary.SavePictureToCameraRoll(string name, Stream source)



, .



<phone:PhoneApplicationPage x:Class="CameraExplorer.PreviewPage" ... > ... <Grid x:Name="LayoutRoot" ... > ... <Grid x:Name="ContentPanel" ... > <Image x:Name="image" Stretch="UniformToFill"/> </Grid> </Grid> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar> <shell:ApplicationBarIconButton Text="save" Click="saveButton_Click" ... /> </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> ... </phone:PhoneApplicationPage>







... public partial class PreviewPage : PhoneApplicationPage { private CameraExplorer.DataContext _dataContext = CameraExplorer.DataContext.Singleton; private BitmapImage _bitmap = new BitmapImage(); protected override void OnNavigatedTo(NavigationEventArgs e) { ... _bitmap.SetSource(_dataContext.ImageStream); image.Source = _bitmap; ... } private void saveButton_Click(object sender, EventArgs e) { try { _dataContext.ImageStream.Position = 0; MediaLibrary library = new MediaLibrary(); library.SavePictureToCameraRoll("CameraExplorer_" + DateTime.Now.ToString() + ".jpg", _dataContext.ImageStream); } catch (Exception) { ... } ... } }







Camera Explorer , ArrayParameters



RangeParameters



, Parameters



. , , ComboBox



, Slider



Text



. , .

Parameter



, .



... public abstract class Parameter : INotifyPropertyChanged { ... protected Parameter(PhotoCaptureDevice device, string name) { ... } public PhotoCaptureDevice Device { ... } public string Name { ... } public bool Supported { ... } public abstract void Refresh(); ... }







, . _propertyId



, static CameraCapturePropertyRange PhotoCaptureDevice.GetSupportedPropertyRange(CameraSensorLocation sensor, Guid propertyId)



. object PhotoCaptureDevice.GetProperty(Guid propertyId)



. void PhotoCaptureDevice.SetProperty(Guid propertyId, object value)



.



... public abstract class RangeParameter<T> : Parameter { private Guid _propertyId; private T _value; ... protected RangeParameter(PhotoCaptureDevice device, Guid propertyId, string name) : base(device, name) { ... } public override void Refresh() { try { CameraCapturePropertyRange range = PhotoCaptureDevice.GetSupportedPropertyRange( Device.SensorLocation, _propertyId); if (range == null) { Supported = false; } else { Minimum = (T)range.Min; Maximum = (T)range.Max; _value = (T)Device.GetProperty(_propertyId); Supported = true; } } catch (Exception) { Supported = false; } ... } public T Minimum { ... } public T Maximum { ... } public T Value { ... set { if (!_value.Equals(value)) { try { Device.SetProperty(_propertyId, (T)value); _value = value; ... } catch (Exception) { ... } } } } ... }







ExposureCompensationParameter



, Guid RangeParameter



KnownCameraPhotoProperties.ExposureCompensation



, — , . , Int32



, .



... public class ExposureCompensationParameter : RangeParameter<Int32> { public ExposureCompensationParameter(PhotoCaptureDevice device) : base(device, KnownCameraPhotoProperties.ExposureCompensation, "Exposure compensation") { } ... }







Camera Explorer ArrayParameter



. . — void PopulateOptions()



void SetOption(ArrayParameterOption option)



, .



... public class ArrayParameterOption { ... public ArrayParameterOption(dynamic value, string name) { ... } public dynamic Value { ... } public string Name { ... } ... } public abstract class ArrayParameter : Parameter, IReadOnlyCollection<ArrayParameterOption> { private List<ArrayParameterOption> _options = new List<ArrayParameterOption>(); private ArrayParameterOption _selectedOption; ... public ArrayParameter(PhotoCaptureDevice device, string name) : base(device, name) { ... } public override void Refresh() { ... _options.Clear(); _selectedOption = null; try { PopulateOptions(); Supported = _options.Count > 0; } catch (Exception) { Supported = false; } ... } protected List<ArrayParameterOption> Options { ... } public ArrayParameterOption SelectedOption { ... set { if (_selectedOption != value) { ... if (_selectedOption != null)) { SetOption(value); } _selectedOption = value; } } } protected abstract void PopulateOptions(); protected abstract void SetOption(ArrayParameterOption option); ... }







, , , . void PopulateOptions()



, , ArrayParameterOption



SelectedOption



, void SetOption(ArrayParameterOption option)



. , static IReadOnlyList , KnownCameraPhotoProperties.SceneMode



object PhotoCaptureDevice.GetProperty(Guid propertyId)



. void PhotoCaptureDevice.SetProperty(Guid propertyId, object value)



.



... public class SceneModeParameter : ArrayParameter { public SceneModeParameter(PhotoCaptureDevice device) : base(device, KnownCameraPhotoProperties.SceneMode, "Scene mode") { } protected override void PopulateOptions() { IReadOnlyList<object> supportedValues = PhotoCaptureDevice.GetSupportedPropertyValues( Device.SensorLocation, PropertyId); object value = Device.GetProperty(PropertyId); foreach (dynamic i in supportedValues) { CameraSceneMode csm = (CameraSceneMode)i; ArrayParameterOption option = new ArrayParameterOption(csm, csm.ToString()); Options.Add(option); if (i.Equals(value)) { SelectedOption = option; } } } protected override void SetOption(ArrayParameterOption option) { Device.SetProperty(PropertyId, option.Value); } ... }







Tap-to-focus

«». Tap-to-focus , , , . , Tap-to-focus .



Rectangle



Canvas



, :



<Rectangle x:Name="FocusIndicator" Stroke="Red" Opacity="0.7" Width="80" Height="80" StrokeThickness="5" Visibility="Collapsed"/>







, .

Canvas Tap:



public MainPage() { ... VideoCanvas.Tap += new EventHandler<GestureEventArgs>(videoCanvas_Tap); ... }







. API- , VideoCanvas



, , .



, . , , , .



, , , , .



private async void videoCanvas_Tap(object sender, GestureEventArgs e) { System.Windows.Point uiTapPoint = e.GetPosition(VideoCanvas); if (PhotoCaptureDevice.IsFocusRegionSupported(_dataContext.Device.SensorLocation) && _focusSemaphore.WaitOne(0)) { // . Windows.Foundation.Point tapPoint = new Windows.Foundation.Point(uiTapPoint.X, uiTapPoint.Y); double xRatio = VideoCanvas.ActualWidth / _dataContext.Device.PreviewResolution.Width; double yRatio = VideoCanvas.ActualHeight / _dataContext.Device.PreviewResolution.Height; // , Windows.Foundation.Point displayOrigin = new Windows.Foundation.Point( tapPoint.X - _focusRegionSize.Width / 2, tapPoint.Y - _focusRegionSize.Height / 2); // canvas Windows.Foundation.Point viewFinderOrigin = new Windows.Foundation.Point( displayOrigin.X / xRatio, displayOrigin.Y / yRatio); Windows.Foundation.Rect focusrect = new Windows.Foundation.Rect( viewFinderOrigin, _focusRegionSize); // Windows.Foundation.Rect viewPortRect = new Windows.Foundation.Rect( 0, 0, _dataContext.Device.PreviewResolution.Width, _dataContext.Device.PreviewResolution.Height); focusrect.Intersect(viewPortRect); _dataContext.Device.FocusRegion = focusrect; // FocusIndicator.SetValue(Shape.StrokeProperty, _notFocusedBrush); FocusIndicator.SetValue(Canvas.LeftProperty, uiTapPoint.X - _focusRegionSize.Width / 2); FocusIndicator.SetValue(Canvas.TopProperty, uiTapPoint.Y - _focusRegionSize.Height / 2); FocusIndicator.SetValue(Canvas.VisibilityProperty, Visibility.Visible); CameraFocusStatus status = await _dataContext.Device.FocusAsync(); if (status == CameraFocusStatus.Locked) { FocusIndicator.SetValue(Shape.StrokeProperty, _focusedBrush); _manuallyFocused = true; _dataContext.Device.SetProperty( KnownCameraPhotoProperties.LockedAutoFocusParameters, AutoFocusParameters.Exposure & AutoFocusParameters.Focus & AutoFocusParameters.WhiteBalance); } else { _manuallyFocused = false; _dataContext.Device.SetProperty( KnownCameraPhotoProperties.LockedAutoFocusParameters, AutoFocusParameters.None); } _focusSemaphore.Release(); } }







, . FocusAsync



, , . , WaitOne



, , , false



— , .





, «», Lens Picker. «» , . Lens Picker, XML App:



<Extensions> <Extension ExtensionName="Camera_Capture_App" ConsumerId="{5B04B775-356B-4AA0-AAF8-6491FFEA5631]" TaskId="_default" /> </Extensions>







, Lens Picker, . , Lens Picker Assets



. , Lens design guidelines for Windows Phone .



Maps API.
























static IReadOnlyList

• object GetProperty(Guid propertyId)






void SetProperty(Guid propertyId, object value)







— , .



static bool IsFocusSupported(CameraSensorLocation sensor)





static bool IsFocusRegionSupported(CameraSensorLocation sensor)





IAsyncOperation FocusAsync()

• IAsyncOperation ResetFocusAsync()



— .



• static IReadOnlyList GetAvailablePreviewResolutions()

• static IReadOnlyList GetAvailableCaptureResolutions()

• IAsyncAction SetPreviewResolutionAsync(Size value)






IAsyncAction SetCaptureResolutionAsync(Size value)







— .



event TypedEventHandler<ICameraCaptureDevice, Object> PreviewFrameAvailable





void GetPreviewBufferArgb(out int[] pixels)





void GetPreviewBufferY(out byte[] pixels)





void GetPreviewBufferYCbCr(out byte[] pixels)







— .



CameraCaptureSequence CreateCaptureSequence(uint numberOfFrames)





IAsyncAction PrepareCaptureSequenceAsync(CameraCaptureSequence sequence)







— . . API . GUID. , .

, ID_CAP_ISV_CAMERA



WMAppManifest.xml . ID_CAP_MEDIALIB_PHOTO



.



Lumia

Nokia Lumia 820 920.





Camera Explorer — , PhotoCaptureDevice



. , .







, Camera Explorer.







Windows Phone DataContext



, Settings



PhotoCaptureDevice



.

PhotoCaptureDevice



DataContext, , , PhotoCaptureDevice



, , MainPage, .



Camera Explorer .

, PhotoCaptureDevice , Camera Explorer. , , . .



DataContext, , .



... class DataContext : INotifyPropertyChanged { ... public static DataContext Singleton { ... } public ObservableCollection<Parameter> Parameters { ... } public PhotoCaptureDevice Device { ... } public MemoryStream ImageStream { ... } }









, PhotoCaptureDevice



. MainPage xaml Canvas



VideoBrush



, .



<phone:PhoneApplicationPage x:Class="CameraExplorer.MainPage" ... > ... <Grid x:Name="LayoutRoot" ... > ... <Grid x:Name="ContentPanel" ... > <Canvas x:Name="VideoCanvas"> <Canvas.Background> <VideoBrush x:Name="videoBrush"/> </Canvas.Background> </Canvas> ... </Grid> </Grid> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar> <shell:ApplicationBarIconButton Text="capture" Click="captureButton_Click" ... /> ... </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> ... </phone:PhoneApplicationPage>







C# MainPage PhotoCaptureDevice



InitializeCamera



, DataContext. , XAML, , .



... public partial class MainPage : PhoneApplicationPage { private CameraExplorer.DataContext _dataContext = CameraExplorer.DataContext.Singleton; ... protected async override void OnNavigatedTo(NavigationEventArgs e) { if (_dataContext.Device == null) { ... await InitializeCamera(CameraSensorLocation.Back); ... } videoBrush.RelativeTransform = new CompositeTransform() { CenterX = 0.5, CenterY = 0.5, Rotation = _dataContext.Device.SensorLocation == CameraSensorLocation.Back ? _dataContext.Device.SensorRotationInDegrees : - _dataContext.Device.SensorRotationInDegrees }; videoBrush.SetSource(_dataContext.Device); ... } 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 void captureButton_Click(object sender, EventArgs e) { if (!_manuallyFocused) { await AutoFocus(); } await Capture(); } private async Task AutoFocus() { if (!_capturing && PhotoCaptureDevice.IsFocusSupported(_dataContext.Device.SensorLocation)) { ... await _dataContext.Device.FocusAsync(); ... _capturing = false; } } private async Task Capture() { if (!_capturing) { _capturing = true; MemoryStream stream = new MemoryStream(); CameraCaptureSequence sequence = _dataContext.Device.CreateCaptureSequence(1); sequence.Frames[0].CaptureStream = stream.AsOutputStream(); await _dataContext.Device.PrepareCaptureSequenceAsync(sequence); await sequence.StartCaptureAsync(); _dataContext.ImageStream = stream; ... } ... } ... }









. Camera Explorer , XAML Image BitmapImage



. , , , void MediaLibrary.SavePictureToCameraRoll(string name, Stream source)



, .



<phone:PhoneApplicationPage x:Class="CameraExplorer.PreviewPage" ... > ... <Grid x:Name="LayoutRoot" ... > ... <Grid x:Name="ContentPanel" ... > <Image x:Name="image" Stretch="UniformToFill"/> </Grid> </Grid> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar> <shell:ApplicationBarIconButton Text="save" Click="saveButton_Click" ... /> </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> ... </phone:PhoneApplicationPage>







... public partial class PreviewPage : PhoneApplicationPage { private CameraExplorer.DataContext _dataContext = CameraExplorer.DataContext.Singleton; private BitmapImage _bitmap = new BitmapImage(); protected override void OnNavigatedTo(NavigationEventArgs e) { ... _bitmap.SetSource(_dataContext.ImageStream); image.Source = _bitmap; ... } private void saveButton_Click(object sender, EventArgs e) { try { _dataContext.ImageStream.Position = 0; MediaLibrary library = new MediaLibrary(); library.SavePictureToCameraRoll("CameraExplorer_" + DateTime.Now.ToString() + ".jpg", _dataContext.ImageStream); } catch (Exception) { ... } ... } }







Camera Explorer , ArrayParameters



RangeParameters



, Parameters



. , , ComboBox



, Slider



Text



. , .

Parameter



, .



... public abstract class Parameter : INotifyPropertyChanged { ... protected Parameter(PhotoCaptureDevice device, string name) { ... } public PhotoCaptureDevice Device { ... } public string Name { ... } public bool Supported { ... } public abstract void Refresh(); ... }







, . _propertyId



, static CameraCapturePropertyRange PhotoCaptureDevice.GetSupportedPropertyRange(CameraSensorLocation sensor, Guid propertyId)



. object PhotoCaptureDevice.GetProperty(Guid propertyId)



. void PhotoCaptureDevice.SetProperty(Guid propertyId, object value)



.



... public abstract class RangeParameter<T> : Parameter { private Guid _propertyId; private T _value; ... protected RangeParameter(PhotoCaptureDevice device, Guid propertyId, string name) : base(device, name) { ... } public override void Refresh() { try { CameraCapturePropertyRange range = PhotoCaptureDevice.GetSupportedPropertyRange( Device.SensorLocation, _propertyId); if (range == null) { Supported = false; } else { Minimum = (T)range.Min; Maximum = (T)range.Max; _value = (T)Device.GetProperty(_propertyId); Supported = true; } } catch (Exception) { Supported = false; } ... } public T Minimum { ... } public T Maximum { ... } public T Value { ... set { if (!_value.Equals(value)) { try { Device.SetProperty(_propertyId, (T)value); _value = value; ... } catch (Exception) { ... } } } } ... }







ExposureCompensationParameter



, Guid RangeParameter



KnownCameraPhotoProperties.ExposureCompensation



, — , . , Int32



, .



... public class ExposureCompensationParameter : RangeParameter<Int32> { public ExposureCompensationParameter(PhotoCaptureDevice device) : base(device, KnownCameraPhotoProperties.ExposureCompensation, "Exposure compensation") { } ... }







Camera Explorer ArrayParameter



. . — void PopulateOptions()



void SetOption(ArrayParameterOption option)



, .



... public class ArrayParameterOption { ... public ArrayParameterOption(dynamic value, string name) { ... } public dynamic Value { ... } public string Name { ... } ... } public abstract class ArrayParameter : Parameter, IReadOnlyCollection<ArrayParameterOption> { private List<ArrayParameterOption> _options = new List<ArrayParameterOption>(); private ArrayParameterOption _selectedOption; ... public ArrayParameter(PhotoCaptureDevice device, string name) : base(device, name) { ... } public override void Refresh() { ... _options.Clear(); _selectedOption = null; try { PopulateOptions(); Supported = _options.Count > 0; } catch (Exception) { Supported = false; } ... } protected List<ArrayParameterOption> Options { ... } public ArrayParameterOption SelectedOption { ... set { if (_selectedOption != value) { ... if (_selectedOption != null)) { SetOption(value); } _selectedOption = value; } } } protected abstract void PopulateOptions(); protected abstract void SetOption(ArrayParameterOption option); ... }







, , , . void PopulateOptions()



, , ArrayParameterOption



SelectedOption



, void SetOption(ArrayParameterOption option)



. , static IReadOnlyList , KnownCameraPhotoProperties.SceneMode



object PhotoCaptureDevice.GetProperty(Guid propertyId)



. void PhotoCaptureDevice.SetProperty(Guid propertyId, object value)



.



... public class SceneModeParameter : ArrayParameter { public SceneModeParameter(PhotoCaptureDevice device) : base(device, KnownCameraPhotoProperties.SceneMode, "Scene mode") { } protected override void PopulateOptions() { IReadOnlyList<object> supportedValues = PhotoCaptureDevice.GetSupportedPropertyValues( Device.SensorLocation, PropertyId); object value = Device.GetProperty(PropertyId); foreach (dynamic i in supportedValues) { CameraSceneMode csm = (CameraSceneMode)i; ArrayParameterOption option = new ArrayParameterOption(csm, csm.ToString()); Options.Add(option); if (i.Equals(value)) { SelectedOption = option; } } } protected override void SetOption(ArrayParameterOption option) { Device.SetProperty(PropertyId, option.Value); } ... }







Tap-to-focus

«». Tap-to-focus , , , . , Tap-to-focus .



Rectangle



Canvas



, :



<Rectangle x:Name="FocusIndicator" Stroke="Red" Opacity="0.7" Width="80" Height="80" StrokeThickness="5" Visibility="Collapsed"/>







, .

Canvas Tap:



public MainPage() { ... VideoCanvas.Tap += new EventHandler<GestureEventArgs>(videoCanvas_Tap); ... }







. API- , VideoCanvas



, , .



, . , , , .



, , , , .



private async void videoCanvas_Tap(object sender, GestureEventArgs e) { System.Windows.Point uiTapPoint = e.GetPosition(VideoCanvas); if (PhotoCaptureDevice.IsFocusRegionSupported(_dataContext.Device.SensorLocation) && _focusSemaphore.WaitOne(0)) { // . Windows.Foundation.Point tapPoint = new Windows.Foundation.Point(uiTapPoint.X, uiTapPoint.Y); double xRatio = VideoCanvas.ActualWidth / _dataContext.Device.PreviewResolution.Width; double yRatio = VideoCanvas.ActualHeight / _dataContext.Device.PreviewResolution.Height; // , Windows.Foundation.Point displayOrigin = new Windows.Foundation.Point( tapPoint.X - _focusRegionSize.Width / 2, tapPoint.Y - _focusRegionSize.Height / 2); // canvas Windows.Foundation.Point viewFinderOrigin = new Windows.Foundation.Point( displayOrigin.X / xRatio, displayOrigin.Y / yRatio); Windows.Foundation.Rect focusrect = new Windows.Foundation.Rect( viewFinderOrigin, _focusRegionSize); // Windows.Foundation.Rect viewPortRect = new Windows.Foundation.Rect( 0, 0, _dataContext.Device.PreviewResolution.Width, _dataContext.Device.PreviewResolution.Height); focusrect.Intersect(viewPortRect); _dataContext.Device.FocusRegion = focusrect; // FocusIndicator.SetValue(Shape.StrokeProperty, _notFocusedBrush); FocusIndicator.SetValue(Canvas.LeftProperty, uiTapPoint.X - _focusRegionSize.Width / 2); FocusIndicator.SetValue(Canvas.TopProperty, uiTapPoint.Y - _focusRegionSize.Height / 2); FocusIndicator.SetValue(Canvas.VisibilityProperty, Visibility.Visible); CameraFocusStatus status = await _dataContext.Device.FocusAsync(); if (status == CameraFocusStatus.Locked) { FocusIndicator.SetValue(Shape.StrokeProperty, _focusedBrush); _manuallyFocused = true; _dataContext.Device.SetProperty( KnownCameraPhotoProperties.LockedAutoFocusParameters, AutoFocusParameters.Exposure & AutoFocusParameters.Focus & AutoFocusParameters.WhiteBalance); } else { _manuallyFocused = false; _dataContext.Device.SetProperty( KnownCameraPhotoProperties.LockedAutoFocusParameters, AutoFocusParameters.None); } _focusSemaphore.Release(); } }







, . FocusAsync



, , . , WaitOne



, , , false



— , .





, «», Lens Picker. «» , . Lens Picker, XML App:



<Extensions> <Extension ExtensionName="Camera_Capture_App" ConsumerId="{5B04B775-356B-4AA0-AAF8-6491FFEA5631]" TaskId="_default" /> </Extensions>







, Lens Picker, . , Lens Picker Assets



. , Lens design guidelines for Windows Phone .



Maps API.
























static IReadOnlyList

• object GetProperty(Guid propertyId)






void SetProperty(Guid propertyId, object value)







— , .



static bool IsFocusSupported(CameraSensorLocation sensor)





static bool IsFocusRegionSupported(CameraSensorLocation sensor)





IAsyncOperation FocusAsync()

• IAsyncOperation ResetFocusAsync()



— .



• static IReadOnlyList GetAvailablePreviewResolutions()

• static IReadOnlyList GetAvailableCaptureResolutions()

• IAsyncAction SetPreviewResolutionAsync(Size value)






IAsyncAction SetCaptureResolutionAsync(Size value)







— .



event TypedEventHandler<ICameraCaptureDevice, Object> PreviewFrameAvailable





void GetPreviewBufferArgb(out int[] pixels)





void GetPreviewBufferY(out byte[] pixels)





void GetPreviewBufferYCbCr(out byte[] pixels)







— .



CameraCaptureSequence CreateCaptureSequence(uint numberOfFrames)





IAsyncAction PrepareCaptureSequenceAsync(CameraCaptureSequence sequence)







— . . API . GUID. , .

, ID_CAP_ISV_CAMERA



WMAppManifest.xml . ID_CAP_MEDIALIB_PHOTO



.



Lumia

Nokia Lumia 820 920.





Camera Explorer — , PhotoCaptureDevice



. , .







, Camera Explorer.







Windows Phone DataContext



, Settings



PhotoCaptureDevice



.

PhotoCaptureDevice



DataContext, , , PhotoCaptureDevice



, , MainPage, .



Camera Explorer .

, PhotoCaptureDevice , Camera Explorer. , , . .



DataContext, , .



... class DataContext : INotifyPropertyChanged { ... public static DataContext Singleton { ... } public ObservableCollection<Parameter> Parameters { ... } public PhotoCaptureDevice Device { ... } public MemoryStream ImageStream { ... } }









, PhotoCaptureDevice



. MainPage xaml Canvas



VideoBrush



, .



<phone:PhoneApplicationPage x:Class="CameraExplorer.MainPage" ... > ... <Grid x:Name="LayoutRoot" ... > ... <Grid x:Name="ContentPanel" ... > <Canvas x:Name="VideoCanvas"> <Canvas.Background> <VideoBrush x:Name="videoBrush"/> </Canvas.Background> </Canvas> ... </Grid> </Grid> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar> <shell:ApplicationBarIconButton Text="capture" Click="captureButton_Click" ... /> ... </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> ... </phone:PhoneApplicationPage>







C# MainPage PhotoCaptureDevice



InitializeCamera



, DataContext. , XAML, , .



... public partial class MainPage : PhoneApplicationPage { private CameraExplorer.DataContext _dataContext = CameraExplorer.DataContext.Singleton; ... protected async override void OnNavigatedTo(NavigationEventArgs e) { if (_dataContext.Device == null) { ... await InitializeCamera(CameraSensorLocation.Back); ... } videoBrush.RelativeTransform = new CompositeTransform() { CenterX = 0.5, CenterY = 0.5, Rotation = _dataContext.Device.SensorLocation == CameraSensorLocation.Back ? _dataContext.Device.SensorRotationInDegrees : - _dataContext.Device.SensorRotationInDegrees }; videoBrush.SetSource(_dataContext.Device); ... } 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 void captureButton_Click(object sender, EventArgs e) { if (!_manuallyFocused) { await AutoFocus(); } await Capture(); } private async Task AutoFocus() { if (!_capturing && PhotoCaptureDevice.IsFocusSupported(_dataContext.Device.SensorLocation)) { ... await _dataContext.Device.FocusAsync(); ... _capturing = false; } } private async Task Capture() { if (!_capturing) { _capturing = true; MemoryStream stream = new MemoryStream(); CameraCaptureSequence sequence = _dataContext.Device.CreateCaptureSequence(1); sequence.Frames[0].CaptureStream = stream.AsOutputStream(); await _dataContext.Device.PrepareCaptureSequenceAsync(sequence); await sequence.StartCaptureAsync(); _dataContext.ImageStream = stream; ... } ... } ... }









. Camera Explorer , XAML Image BitmapImage



. , , , void MediaLibrary.SavePictureToCameraRoll(string name, Stream source)



, .



<phone:PhoneApplicationPage x:Class="CameraExplorer.PreviewPage" ... > ... <Grid x:Name="LayoutRoot" ... > ... <Grid x:Name="ContentPanel" ... > <Image x:Name="image" Stretch="UniformToFill"/> </Grid> </Grid> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar> <shell:ApplicationBarIconButton Text="save" Click="saveButton_Click" ... /> </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> ... </phone:PhoneApplicationPage>







... public partial class PreviewPage : PhoneApplicationPage { private CameraExplorer.DataContext _dataContext = CameraExplorer.DataContext.Singleton; private BitmapImage _bitmap = new BitmapImage(); protected override void OnNavigatedTo(NavigationEventArgs e) { ... _bitmap.SetSource(_dataContext.ImageStream); image.Source = _bitmap; ... } private void saveButton_Click(object sender, EventArgs e) { try { _dataContext.ImageStream.Position = 0; MediaLibrary library = new MediaLibrary(); library.SavePictureToCameraRoll("CameraExplorer_" + DateTime.Now.ToString() + ".jpg", _dataContext.ImageStream); } catch (Exception) { ... } ... } }







Camera Explorer , ArrayParameters



RangeParameters



, Parameters



. , , ComboBox



, Slider



Text



. , .

Parameter



, .



... public abstract class Parameter : INotifyPropertyChanged { ... protected Parameter(PhotoCaptureDevice device, string name) { ... } public PhotoCaptureDevice Device { ... } public string Name { ... } public bool Supported { ... } public abstract void Refresh(); ... }







, . _propertyId



, static CameraCapturePropertyRange PhotoCaptureDevice.GetSupportedPropertyRange(CameraSensorLocation sensor, Guid propertyId)



. object PhotoCaptureDevice.GetProperty(Guid propertyId)



. void PhotoCaptureDevice.SetProperty(Guid propertyId, object value)



.



... public abstract class RangeParameter<T> : Parameter { private Guid _propertyId; private T _value; ... protected RangeParameter(PhotoCaptureDevice device, Guid propertyId, string name) : base(device, name) { ... } public override void Refresh() { try { CameraCapturePropertyRange range = PhotoCaptureDevice.GetSupportedPropertyRange( Device.SensorLocation, _propertyId); if (range == null) { Supported = false; } else { Minimum = (T)range.Min; Maximum = (T)range.Max; _value = (T)Device.GetProperty(_propertyId); Supported = true; } } catch (Exception) { Supported = false; } ... } public T Minimum { ... } public T Maximum { ... } public T Value { ... set { if (!_value.Equals(value)) { try { Device.SetProperty(_propertyId, (T)value); _value = value; ... } catch (Exception) { ... } } } } ... }







ExposureCompensationParameter



, Guid RangeParameter



KnownCameraPhotoProperties.ExposureCompensation



, — , . , Int32



, .



... public class ExposureCompensationParameter : RangeParameter<Int32> { public ExposureCompensationParameter(PhotoCaptureDevice device) : base(device, KnownCameraPhotoProperties.ExposureCompensation, "Exposure compensation") { } ... }







Camera Explorer ArrayParameter



. . — void PopulateOptions()



void SetOption(ArrayParameterOption option)



, .



... public class ArrayParameterOption { ... public ArrayParameterOption(dynamic value, string name) { ... } public dynamic Value { ... } public string Name { ... } ... } public abstract class ArrayParameter : Parameter, IReadOnlyCollection<ArrayParameterOption> { private List<ArrayParameterOption> _options = new List<ArrayParameterOption>(); private ArrayParameterOption _selectedOption; ... public ArrayParameter(PhotoCaptureDevice device, string name) : base(device, name) { ... } public override void Refresh() { ... _options.Clear(); _selectedOption = null; try { PopulateOptions(); Supported = _options.Count > 0; } catch (Exception) { Supported = false; } ... } protected List<ArrayParameterOption> Options { ... } public ArrayParameterOption SelectedOption { ... set { if (_selectedOption != value) { ... if (_selectedOption != null)) { SetOption(value); } _selectedOption = value; } } } protected abstract void PopulateOptions(); protected abstract void SetOption(ArrayParameterOption option); ... }







, , , . void PopulateOptions()



, , ArrayParameterOption



SelectedOption



, void SetOption(ArrayParameterOption option)



. , static IReadOnlyList , KnownCameraPhotoProperties.SceneMode



object PhotoCaptureDevice.GetProperty(Guid propertyId)



. void PhotoCaptureDevice.SetProperty(Guid propertyId, object value)



.



... public class SceneModeParameter : ArrayParameter { public SceneModeParameter(PhotoCaptureDevice device) : base(device, KnownCameraPhotoProperties.SceneMode, "Scene mode") { } protected override void PopulateOptions() { IReadOnlyList<object> supportedValues = PhotoCaptureDevice.GetSupportedPropertyValues( Device.SensorLocation, PropertyId); object value = Device.GetProperty(PropertyId); foreach (dynamic i in supportedValues) { CameraSceneMode csm = (CameraSceneMode)i; ArrayParameterOption option = new ArrayParameterOption(csm, csm.ToString()); Options.Add(option); if (i.Equals(value)) { SelectedOption = option; } } } protected override void SetOption(ArrayParameterOption option) { Device.SetProperty(PropertyId, option.Value); } ... }







Tap-to-focus

«». Tap-to-focus , , , . , Tap-to-focus .



Rectangle



Canvas



, :



<Rectangle x:Name="FocusIndicator" Stroke="Red" Opacity="0.7" Width="80" Height="80" StrokeThickness="5" Visibility="Collapsed"/>







, .

Canvas Tap:



public MainPage() { ... VideoCanvas.Tap += new EventHandler<GestureEventArgs>(videoCanvas_Tap); ... }







. API- , VideoCanvas



, , .



, . , , , .



, , , , .



private async void videoCanvas_Tap(object sender, GestureEventArgs e) { System.Windows.Point uiTapPoint = e.GetPosition(VideoCanvas); if (PhotoCaptureDevice.IsFocusRegionSupported(_dataContext.Device.SensorLocation) && _focusSemaphore.WaitOne(0)) { // . Windows.Foundation.Point tapPoint = new Windows.Foundation.Point(uiTapPoint.X, uiTapPoint.Y); double xRatio = VideoCanvas.ActualWidth / _dataContext.Device.PreviewResolution.Width; double yRatio = VideoCanvas.ActualHeight / _dataContext.Device.PreviewResolution.Height; // , Windows.Foundation.Point displayOrigin = new Windows.Foundation.Point( tapPoint.X - _focusRegionSize.Width / 2, tapPoint.Y - _focusRegionSize.Height / 2); // canvas Windows.Foundation.Point viewFinderOrigin = new Windows.Foundation.Point( displayOrigin.X / xRatio, displayOrigin.Y / yRatio); Windows.Foundation.Rect focusrect = new Windows.Foundation.Rect( viewFinderOrigin, _focusRegionSize); // Windows.Foundation.Rect viewPortRect = new Windows.Foundation.Rect( 0, 0, _dataContext.Device.PreviewResolution.Width, _dataContext.Device.PreviewResolution.Height); focusrect.Intersect(viewPortRect); _dataContext.Device.FocusRegion = focusrect; // FocusIndicator.SetValue(Shape.StrokeProperty, _notFocusedBrush); FocusIndicator.SetValue(Canvas.LeftProperty, uiTapPoint.X - _focusRegionSize.Width / 2); FocusIndicator.SetValue(Canvas.TopProperty, uiTapPoint.Y - _focusRegionSize.Height / 2); FocusIndicator.SetValue(Canvas.VisibilityProperty, Visibility.Visible); CameraFocusStatus status = await _dataContext.Device.FocusAsync(); if (status == CameraFocusStatus.Locked) { FocusIndicator.SetValue(Shape.StrokeProperty, _focusedBrush); _manuallyFocused = true; _dataContext.Device.SetProperty( KnownCameraPhotoProperties.LockedAutoFocusParameters, AutoFocusParameters.Exposure & AutoFocusParameters.Focus & AutoFocusParameters.WhiteBalance); } else { _manuallyFocused = false; _dataContext.Device.SetProperty( KnownCameraPhotoProperties.LockedAutoFocusParameters, AutoFocusParameters.None); } _focusSemaphore.Release(); } }







, . FocusAsync



, , . , WaitOne



, , , false



— , .





, «», Lens Picker. «» , . Lens Picker, XML App:



<Extensions> <Extension ExtensionName="Camera_Capture_App" ConsumerId="{5B04B775-356B-4AA0-AAF8-6491FFEA5631]" TaskId="_default" /> </Extensions>







, Lens Picker, . , Lens Picker Assets



. , Lens design guidelines for Windows Phone .



Maps API.
























 static IReadOnlyList 
      

object GetProperty(Guid propertyId)






void SetProperty(Guid propertyId, object value)







— , .



static bool IsFocusSupported(CameraSensorLocation sensor)





static bool IsFocusRegionSupported(CameraSensorLocation sensor)





IAsyncOperation FocusAsync()

• IAsyncOperation ResetFocusAsync()



— .



• static IReadOnlyList GetAvailablePreviewResolutions()

• static IReadOnlyList GetAvailableCaptureResolutions()

• IAsyncAction SetPreviewResolutionAsync(Size value)






IAsyncAction SetCaptureResolutionAsync(Size value)







— .



event TypedEventHandler<ICameraCaptureDevice, Object> PreviewFrameAvailable





void GetPreviewBufferArgb(out int[] pixels)





void GetPreviewBufferY(out byte[] pixels)





void GetPreviewBufferYCbCr(out byte[] pixels)







— .



CameraCaptureSequence CreateCaptureSequence(uint numberOfFrames)





IAsyncAction PrepareCaptureSequenceAsync(CameraCaptureSequence sequence)







— . . API . GUID. , .

, ID_CAP_ISV_CAMERA



WMAppManifest.xml . ID_CAP_MEDIALIB_PHOTO



.



Lumia

Nokia Lumia 820 920.





Camera Explorer — , PhotoCaptureDevice



. , .







, Camera Explorer.







Windows Phone DataContext



, Settings



PhotoCaptureDevice



.

PhotoCaptureDevice



DataContext, , , PhotoCaptureDevice



, , MainPage, .



Camera Explorer .

, PhotoCaptureDevice , Camera Explorer. , , . .



DataContext, , .



... class DataContext : INotifyPropertyChanged { ... public static DataContext Singleton { ... } public ObservableCollection<Parameter> Parameters { ... } public PhotoCaptureDevice Device { ... } public MemoryStream ImageStream { ... } }









, PhotoCaptureDevice



. MainPage xaml Canvas



VideoBrush



, .



<phone:PhoneApplicationPage x:Class="CameraExplorer.MainPage" ... > ... <Grid x:Name="LayoutRoot" ... > ... <Grid x:Name="ContentPanel" ... > <Canvas x:Name="VideoCanvas"> <Canvas.Background> <VideoBrush x:Name="videoBrush"/> </Canvas.Background> </Canvas> ... </Grid> </Grid> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar> <shell:ApplicationBarIconButton Text="capture" Click="captureButton_Click" ... /> ... </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> ... </phone:PhoneApplicationPage>







C# MainPage PhotoCaptureDevice



InitializeCamera



, DataContext. , XAML, , .



... public partial class MainPage : PhoneApplicationPage { private CameraExplorer.DataContext _dataContext = CameraExplorer.DataContext.Singleton; ... protected async override void OnNavigatedTo(NavigationEventArgs e) { if (_dataContext.Device == null) { ... await InitializeCamera(CameraSensorLocation.Back); ... } videoBrush.RelativeTransform = new CompositeTransform() { CenterX = 0.5, CenterY = 0.5, Rotation = _dataContext.Device.SensorLocation == CameraSensorLocation.Back ? _dataContext.Device.SensorRotationInDegrees : - _dataContext.Device.SensorRotationInDegrees }; videoBrush.SetSource(_dataContext.Device); ... } 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 void captureButton_Click(object sender, EventArgs e) { if (!_manuallyFocused) { await AutoFocus(); } await Capture(); } private async Task AutoFocus() { if (!_capturing && PhotoCaptureDevice.IsFocusSupported(_dataContext.Device.SensorLocation)) { ... await _dataContext.Device.FocusAsync(); ... _capturing = false; } } private async Task Capture() { if (!_capturing) { _capturing = true; MemoryStream stream = new MemoryStream(); CameraCaptureSequence sequence = _dataContext.Device.CreateCaptureSequence(1); sequence.Frames[0].CaptureStream = stream.AsOutputStream(); await _dataContext.Device.PrepareCaptureSequenceAsync(sequence); await sequence.StartCaptureAsync(); _dataContext.ImageStream = stream; ... } ... } ... }









. Camera Explorer , XAML Image BitmapImage



. , , , void MediaLibrary.SavePictureToCameraRoll(string name, Stream source)



, .



<phone:PhoneApplicationPage x:Class="CameraExplorer.PreviewPage" ... > ... <Grid x:Name="LayoutRoot" ... > ... <Grid x:Name="ContentPanel" ... > <Image x:Name="image" Stretch="UniformToFill"/> </Grid> </Grid> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar> <shell:ApplicationBarIconButton Text="save" Click="saveButton_Click" ... /> </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> ... </phone:PhoneApplicationPage>







... public partial class PreviewPage : PhoneApplicationPage { private CameraExplorer.DataContext _dataContext = CameraExplorer.DataContext.Singleton; private BitmapImage _bitmap = new BitmapImage(); protected override void OnNavigatedTo(NavigationEventArgs e) { ... _bitmap.SetSource(_dataContext.ImageStream); image.Source = _bitmap; ... } private void saveButton_Click(object sender, EventArgs e) { try { _dataContext.ImageStream.Position = 0; MediaLibrary library = new MediaLibrary(); library.SavePictureToCameraRoll("CameraExplorer_" + DateTime.Now.ToString() + ".jpg", _dataContext.ImageStream); } catch (Exception) { ... } ... } }







Camera Explorer , ArrayParameters



RangeParameters



, Parameters



. , , ComboBox



, Slider



Text



. , .

Parameter



, .



... public abstract class Parameter : INotifyPropertyChanged { ... protected Parameter(PhotoCaptureDevice device, string name) { ... } public PhotoCaptureDevice Device { ... } public string Name { ... } public bool Supported { ... } public abstract void Refresh(); ... }







, . _propertyId



, static CameraCapturePropertyRange PhotoCaptureDevice.GetSupportedPropertyRange(CameraSensorLocation sensor, Guid propertyId)



. object PhotoCaptureDevice.GetProperty(Guid propertyId)



. void PhotoCaptureDevice.SetProperty(Guid propertyId, object value)



.



... public abstract class RangeParameter<T> : Parameter { private Guid _propertyId; private T _value; ... protected RangeParameter(PhotoCaptureDevice device, Guid propertyId, string name) : base(device, name) { ... } public override void Refresh() { try { CameraCapturePropertyRange range = PhotoCaptureDevice.GetSupportedPropertyRange( Device.SensorLocation, _propertyId); if (range == null) { Supported = false; } else { Minimum = (T)range.Min; Maximum = (T)range.Max; _value = (T)Device.GetProperty(_propertyId); Supported = true; } } catch (Exception) { Supported = false; } ... } public T Minimum { ... } public T Maximum { ... } public T Value { ... set { if (!_value.Equals(value)) { try { Device.SetProperty(_propertyId, (T)value); _value = value; ... } catch (Exception) { ... } } } } ... }







ExposureCompensationParameter



, Guid RangeParameter



KnownCameraPhotoProperties.ExposureCompensation



, — , . , Int32



, .



... public class ExposureCompensationParameter : RangeParameter<Int32> { public ExposureCompensationParameter(PhotoCaptureDevice device) : base(device, KnownCameraPhotoProperties.ExposureCompensation, "Exposure compensation") { } ... }







Camera Explorer ArrayParameter



. . — void PopulateOptions()



void SetOption(ArrayParameterOption option)



, .



... public class ArrayParameterOption { ... public ArrayParameterOption(dynamic value, string name) { ... } public dynamic Value { ... } public string Name { ... } ... } public abstract class ArrayParameter : Parameter, IReadOnlyCollection<ArrayParameterOption> { private List<ArrayParameterOption> _options = new List<ArrayParameterOption>(); private ArrayParameterOption _selectedOption; ... public ArrayParameter(PhotoCaptureDevice device, string name) : base(device, name) { ... } public override void Refresh() { ... _options.Clear(); _selectedOption = null; try { PopulateOptions(); Supported = _options.Count > 0; } catch (Exception) { Supported = false; } ... } protected List<ArrayParameterOption> Options { ... } public ArrayParameterOption SelectedOption { ... set { if (_selectedOption != value) { ... if (_selectedOption != null)) { SetOption(value); } _selectedOption = value; } } } protected abstract void PopulateOptions(); protected abstract void SetOption(ArrayParameterOption option); ... }







, , , . void PopulateOptions()



, , ArrayParameterOption



SelectedOption



, void SetOption(ArrayParameterOption option)



. , static IReadOnlyList , KnownCameraPhotoProperties.SceneMode



object PhotoCaptureDevice.GetProperty(Guid propertyId)



. void PhotoCaptureDevice.SetProperty(Guid propertyId, object value)



.



... public class SceneModeParameter : ArrayParameter { public SceneModeParameter(PhotoCaptureDevice device) : base(device, KnownCameraPhotoProperties.SceneMode, "Scene mode") { } protected override void PopulateOptions() { IReadOnlyList<object> supportedValues = PhotoCaptureDevice.GetSupportedPropertyValues( Device.SensorLocation, PropertyId); object value = Device.GetProperty(PropertyId); foreach (dynamic i in supportedValues) { CameraSceneMode csm = (CameraSceneMode)i; ArrayParameterOption option = new ArrayParameterOption(csm, csm.ToString()); Options.Add(option); if (i.Equals(value)) { SelectedOption = option; } } } protected override void SetOption(ArrayParameterOption option) { Device.SetProperty(PropertyId, option.Value); } ... }







Tap-to-focus

«». Tap-to-focus , , , . , Tap-to-focus .



Rectangle



Canvas



, :



<Rectangle x:Name="FocusIndicator" Stroke="Red" Opacity="0.7" Width="80" Height="80" StrokeThickness="5" Visibility="Collapsed"/>







, .

Canvas Tap:



public MainPage() { ... VideoCanvas.Tap += new EventHandler<GestureEventArgs>(videoCanvas_Tap); ... }







. API- , VideoCanvas



, , .



, . , , , .



, , , , .



private async void videoCanvas_Tap(object sender, GestureEventArgs e) { System.Windows.Point uiTapPoint = e.GetPosition(VideoCanvas); if (PhotoCaptureDevice.IsFocusRegionSupported(_dataContext.Device.SensorLocation) && _focusSemaphore.WaitOne(0)) { // . Windows.Foundation.Point tapPoint = new Windows.Foundation.Point(uiTapPoint.X, uiTapPoint.Y); double xRatio = VideoCanvas.ActualWidth / _dataContext.Device.PreviewResolution.Width; double yRatio = VideoCanvas.ActualHeight / _dataContext.Device.PreviewResolution.Height; // , Windows.Foundation.Point displayOrigin = new Windows.Foundation.Point( tapPoint.X - _focusRegionSize.Width / 2, tapPoint.Y - _focusRegionSize.Height / 2); // canvas Windows.Foundation.Point viewFinderOrigin = new Windows.Foundation.Point( displayOrigin.X / xRatio, displayOrigin.Y / yRatio); Windows.Foundation.Rect focusrect = new Windows.Foundation.Rect( viewFinderOrigin, _focusRegionSize); // Windows.Foundation.Rect viewPortRect = new Windows.Foundation.Rect( 0, 0, _dataContext.Device.PreviewResolution.Width, _dataContext.Device.PreviewResolution.Height); focusrect.Intersect(viewPortRect); _dataContext.Device.FocusRegion = focusrect; // FocusIndicator.SetValue(Shape.StrokeProperty, _notFocusedBrush); FocusIndicator.SetValue(Canvas.LeftProperty, uiTapPoint.X - _focusRegionSize.Width / 2); FocusIndicator.SetValue(Canvas.TopProperty, uiTapPoint.Y - _focusRegionSize.Height / 2); FocusIndicator.SetValue(Canvas.VisibilityProperty, Visibility.Visible); CameraFocusStatus status = await _dataContext.Device.FocusAsync(); if (status == CameraFocusStatus.Locked) { FocusIndicator.SetValue(Shape.StrokeProperty, _focusedBrush); _manuallyFocused = true; _dataContext.Device.SetProperty( KnownCameraPhotoProperties.LockedAutoFocusParameters, AutoFocusParameters.Exposure & AutoFocusParameters.Focus & AutoFocusParameters.WhiteBalance); } else { _manuallyFocused = false; _dataContext.Device.SetProperty( KnownCameraPhotoProperties.LockedAutoFocusParameters, AutoFocusParameters.None); } _focusSemaphore.Release(); } }







, . FocusAsync



, , . , WaitOne



, , , false



— , .





, «», Lens Picker. «» , . Lens Picker, XML App:



<Extensions> <Extension ExtensionName="Camera_Capture_App" ConsumerId="{5B04B775-356B-4AA0-AAF8-6491FFEA5631]" TaskId="_default" /> </Extensions>







, Lens Picker, . , Lens Picker Assets



. , Lens design guidelines for Windows Phone .



Maps API.
























static IReadOnlyList

• object GetProperty(Guid propertyId)






void SetProperty(Guid propertyId, object value)







— , .



static bool IsFocusSupported(CameraSensorLocation sensor)





static bool IsFocusRegionSupported(CameraSensorLocation sensor)





IAsyncOperation FocusAsync()

• IAsyncOperation ResetFocusAsync()



— .



• static IReadOnlyList GetAvailablePreviewResolutions()

• static IReadOnlyList GetAvailableCaptureResolutions()

• IAsyncAction SetPreviewResolutionAsync(Size value)






IAsyncAction SetCaptureResolutionAsync(Size value)







— .



event TypedEventHandler<ICameraCaptureDevice, Object> PreviewFrameAvailable





void GetPreviewBufferArgb(out int[] pixels)





void GetPreviewBufferY(out byte[] pixels)





void GetPreviewBufferYCbCr(out byte[] pixels)







— .



CameraCaptureSequence CreateCaptureSequence(uint numberOfFrames)





IAsyncAction PrepareCaptureSequenceAsync(CameraCaptureSequence sequence)







— . . API . GUID. , .

, ID_CAP_ISV_CAMERA



WMAppManifest.xml . ID_CAP_MEDIALIB_PHOTO



.



Lumia

Nokia Lumia 820 920.





Camera Explorer — , PhotoCaptureDevice



. , .







, Camera Explorer.







Windows Phone DataContext



, Settings



PhotoCaptureDevice



.

PhotoCaptureDevice



DataContext, , , PhotoCaptureDevice



, , MainPage, .



Camera Explorer .

, PhotoCaptureDevice , Camera Explorer. , , . .



DataContext, , .



... class DataContext : INotifyPropertyChanged { ... public static DataContext Singleton { ... } public ObservableCollection<Parameter> Parameters { ... } public PhotoCaptureDevice Device { ... } public MemoryStream ImageStream { ... } }









, PhotoCaptureDevice



. MainPage xaml Canvas



VideoBrush



, .



<phone:PhoneApplicationPage x:Class="CameraExplorer.MainPage" ... > ... <Grid x:Name="LayoutRoot" ... > ... <Grid x:Name="ContentPanel" ... > <Canvas x:Name="VideoCanvas"> <Canvas.Background> <VideoBrush x:Name="videoBrush"/> </Canvas.Background> </Canvas> ... </Grid> </Grid> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar> <shell:ApplicationBarIconButton Text="capture" Click="captureButton_Click" ... /> ... </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> ... </phone:PhoneApplicationPage>







C# MainPage PhotoCaptureDevice



InitializeCamera



, DataContext. , XAML, , .



... public partial class MainPage : PhoneApplicationPage { private CameraExplorer.DataContext _dataContext = CameraExplorer.DataContext.Singleton; ... protected async override void OnNavigatedTo(NavigationEventArgs e) { if (_dataContext.Device == null) { ... await InitializeCamera(CameraSensorLocation.Back); ... } videoBrush.RelativeTransform = new CompositeTransform() { CenterX = 0.5, CenterY = 0.5, Rotation = _dataContext.Device.SensorLocation == CameraSensorLocation.Back ? _dataContext.Device.SensorRotationInDegrees : - _dataContext.Device.SensorRotationInDegrees }; videoBrush.SetSource(_dataContext.Device); ... } 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 void captureButton_Click(object sender, EventArgs e) { if (!_manuallyFocused) { await AutoFocus(); } await Capture(); } private async Task AutoFocus() { if (!_capturing && PhotoCaptureDevice.IsFocusSupported(_dataContext.Device.SensorLocation)) { ... await _dataContext.Device.FocusAsync(); ... _capturing = false; } } private async Task Capture() { if (!_capturing) { _capturing = true; MemoryStream stream = new MemoryStream(); CameraCaptureSequence sequence = _dataContext.Device.CreateCaptureSequence(1); sequence.Frames[0].CaptureStream = stream.AsOutputStream(); await _dataContext.Device.PrepareCaptureSequenceAsync(sequence); await sequence.StartCaptureAsync(); _dataContext.ImageStream = stream; ... } ... } ... }









. Camera Explorer , XAML Image BitmapImage



. , , , void MediaLibrary.SavePictureToCameraRoll(string name, Stream source)



, .



<phone:PhoneApplicationPage x:Class="CameraExplorer.PreviewPage" ... > ... <Grid x:Name="LayoutRoot" ... > ... <Grid x:Name="ContentPanel" ... > <Image x:Name="image" Stretch="UniformToFill"/> </Grid> </Grid> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar> <shell:ApplicationBarIconButton Text="save" Click="saveButton_Click" ... /> </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> ... </phone:PhoneApplicationPage>







... public partial class PreviewPage : PhoneApplicationPage { private CameraExplorer.DataContext _dataContext = CameraExplorer.DataContext.Singleton; private BitmapImage _bitmap = new BitmapImage(); protected override void OnNavigatedTo(NavigationEventArgs e) { ... _bitmap.SetSource(_dataContext.ImageStream); image.Source = _bitmap; ... } private void saveButton_Click(object sender, EventArgs e) { try { _dataContext.ImageStream.Position = 0; MediaLibrary library = new MediaLibrary(); library.SavePictureToCameraRoll("CameraExplorer_" + DateTime.Now.ToString() + ".jpg", _dataContext.ImageStream); } catch (Exception) { ... } ... } }







Camera Explorer , ArrayParameters



RangeParameters



, Parameters



. , , ComboBox



, Slider



Text



. , .

Parameter



, .



... public abstract class Parameter : INotifyPropertyChanged { ... protected Parameter(PhotoCaptureDevice device, string name) { ... } public PhotoCaptureDevice Device { ... } public string Name { ... } public bool Supported { ... } public abstract void Refresh(); ... }







, . _propertyId



, static CameraCapturePropertyRange PhotoCaptureDevice.GetSupportedPropertyRange(CameraSensorLocation sensor, Guid propertyId)



. object PhotoCaptureDevice.GetProperty(Guid propertyId)



. void PhotoCaptureDevice.SetProperty(Guid propertyId, object value)



.



... public abstract class RangeParameter<T> : Parameter { private Guid _propertyId; private T _value; ... protected RangeParameter(PhotoCaptureDevice device, Guid propertyId, string name) : base(device, name) { ... } public override void Refresh() { try { CameraCapturePropertyRange range = PhotoCaptureDevice.GetSupportedPropertyRange( Device.SensorLocation, _propertyId); if (range == null) { Supported = false; } else { Minimum = (T)range.Min; Maximum = (T)range.Max; _value = (T)Device.GetProperty(_propertyId); Supported = true; } } catch (Exception) { Supported = false; } ... } public T Minimum { ... } public T Maximum { ... } public T Value { ... set { if (!_value.Equals(value)) { try { Device.SetProperty(_propertyId, (T)value); _value = value; ... } catch (Exception) { ... } } } } ... }







ExposureCompensationParameter



, Guid RangeParameter



KnownCameraPhotoProperties.ExposureCompensation



, — , . , Int32



, .



... public class ExposureCompensationParameter : RangeParameter<Int32> { public ExposureCompensationParameter(PhotoCaptureDevice device) : base(device, KnownCameraPhotoProperties.ExposureCompensation, "Exposure compensation") { } ... }







Camera Explorer ArrayParameter



. . — void PopulateOptions()



void SetOption(ArrayParameterOption option)



, .



... public class ArrayParameterOption { ... public ArrayParameterOption(dynamic value, string name) { ... } public dynamic Value { ... } public string Name { ... } ... } public abstract class ArrayParameter : Parameter, IReadOnlyCollection<ArrayParameterOption> { private List<ArrayParameterOption> _options = new List<ArrayParameterOption>(); private ArrayParameterOption _selectedOption; ... public ArrayParameter(PhotoCaptureDevice device, string name) : base(device, name) { ... } public override void Refresh() { ... _options.Clear(); _selectedOption = null; try { PopulateOptions(); Supported = _options.Count > 0; } catch (Exception) { Supported = false; } ... } protected List<ArrayParameterOption> Options { ... } public ArrayParameterOption SelectedOption { ... set { if (_selectedOption != value) { ... if (_selectedOption != null)) { SetOption(value); } _selectedOption = value; } } } protected abstract void PopulateOptions(); protected abstract void SetOption(ArrayParameterOption option); ... }







, , , . void PopulateOptions()



, , ArrayParameterOption



SelectedOption



, void SetOption(ArrayParameterOption option)



. , static IReadOnlyList , KnownCameraPhotoProperties.SceneMode



object PhotoCaptureDevice.GetProperty(Guid propertyId)



. void PhotoCaptureDevice.SetProperty(Guid propertyId, object value)



.



... public class SceneModeParameter : ArrayParameter { public SceneModeParameter(PhotoCaptureDevice device) : base(device, KnownCameraPhotoProperties.SceneMode, "Scene mode") { } protected override void PopulateOptions() { IReadOnlyList<object> supportedValues = PhotoCaptureDevice.GetSupportedPropertyValues( Device.SensorLocation, PropertyId); object value = Device.GetProperty(PropertyId); foreach (dynamic i in supportedValues) { CameraSceneMode csm = (CameraSceneMode)i; ArrayParameterOption option = new ArrayParameterOption(csm, csm.ToString()); Options.Add(option); if (i.Equals(value)) { SelectedOption = option; } } } protected override void SetOption(ArrayParameterOption option) { Device.SetProperty(PropertyId, option.Value); } ... }







Tap-to-focus

«». Tap-to-focus , , , . , Tap-to-focus .



Rectangle



Canvas



, :



<Rectangle x:Name="FocusIndicator" Stroke="Red" Opacity="0.7" Width="80" Height="80" StrokeThickness="5" Visibility="Collapsed"/>







, .

Canvas Tap:



public MainPage() { ... VideoCanvas.Tap += new EventHandler<GestureEventArgs>(videoCanvas_Tap); ... }







. API- , VideoCanvas



, , .



, . , , , .



, , , , .



private async void videoCanvas_Tap(object sender, GestureEventArgs e) { System.Windows.Point uiTapPoint = e.GetPosition(VideoCanvas); if (PhotoCaptureDevice.IsFocusRegionSupported(_dataContext.Device.SensorLocation) && _focusSemaphore.WaitOne(0)) { // . Windows.Foundation.Point tapPoint = new Windows.Foundation.Point(uiTapPoint.X, uiTapPoint.Y); double xRatio = VideoCanvas.ActualWidth / _dataContext.Device.PreviewResolution.Width; double yRatio = VideoCanvas.ActualHeight / _dataContext.Device.PreviewResolution.Height; // , Windows.Foundation.Point displayOrigin = new Windows.Foundation.Point( tapPoint.X - _focusRegionSize.Width / 2, tapPoint.Y - _focusRegionSize.Height / 2); // canvas Windows.Foundation.Point viewFinderOrigin = new Windows.Foundation.Point( displayOrigin.X / xRatio, displayOrigin.Y / yRatio); Windows.Foundation.Rect focusrect = new Windows.Foundation.Rect( viewFinderOrigin, _focusRegionSize); // Windows.Foundation.Rect viewPortRect = new Windows.Foundation.Rect( 0, 0, _dataContext.Device.PreviewResolution.Width, _dataContext.Device.PreviewResolution.Height); focusrect.Intersect(viewPortRect); _dataContext.Device.FocusRegion = focusrect; // FocusIndicator.SetValue(Shape.StrokeProperty, _notFocusedBrush); FocusIndicator.SetValue(Canvas.LeftProperty, uiTapPoint.X - _focusRegionSize.Width / 2); FocusIndicator.SetValue(Canvas.TopProperty, uiTapPoint.Y - _focusRegionSize.Height / 2); FocusIndicator.SetValue(Canvas.VisibilityProperty, Visibility.Visible); CameraFocusStatus status = await _dataContext.Device.FocusAsync(); if (status == CameraFocusStatus.Locked) { FocusIndicator.SetValue(Shape.StrokeProperty, _focusedBrush); _manuallyFocused = true; _dataContext.Device.SetProperty( KnownCameraPhotoProperties.LockedAutoFocusParameters, AutoFocusParameters.Exposure & AutoFocusParameters.Focus & AutoFocusParameters.WhiteBalance); } else { _manuallyFocused = false; _dataContext.Device.SetProperty( KnownCameraPhotoProperties.LockedAutoFocusParameters, AutoFocusParameters.None); } _focusSemaphore.Release(); } }







, . FocusAsync



, , . , WaitOne



, , , false



— , .





, «», Lens Picker. «» , . Lens Picker, XML App:



<Extensions> <Extension ExtensionName="Camera_Capture_App" ConsumerId="{5B04B775-356B-4AA0-AAF8-6491FFEA5631]" TaskId="_default" /> </Extensions>







, Lens Picker, . , Lens Picker Assets



. , Lens design guidelines for Windows Phone .



Maps API.
























 static IReadOnlyList 
      

object GetProperty(Guid propertyId)






void SetProperty(Guid propertyId, object value)







— , .



static bool IsFocusSupported(CameraSensorLocation sensor)





static bool IsFocusRegionSupported(CameraSensorLocation sensor)





IAsyncOperation FocusAsync()

• IAsyncOperation ResetFocusAsync()



— .



• static IReadOnlyList GetAvailablePreviewResolutions()

• static IReadOnlyList GetAvailableCaptureResolutions()

• IAsyncAction SetPreviewResolutionAsync(Size value)






IAsyncAction SetCaptureResolutionAsync(Size value)







— .



event TypedEventHandler<ICameraCaptureDevice, Object> PreviewFrameAvailable





void GetPreviewBufferArgb(out int[] pixels)





void GetPreviewBufferY(out byte[] pixels)





void GetPreviewBufferYCbCr(out byte[] pixels)







— .



CameraCaptureSequence CreateCaptureSequence(uint numberOfFrames)





IAsyncAction PrepareCaptureSequenceAsync(CameraCaptureSequence sequence)







— . . API . GUID. , .

, ID_CAP_ISV_CAMERA



WMAppManifest.xml . ID_CAP_MEDIALIB_PHOTO



.



Lumia

Nokia Lumia 820 920.





Camera Explorer — , PhotoCaptureDevice



. , .







, Camera Explorer.







Windows Phone DataContext



, Settings



PhotoCaptureDevice



.

PhotoCaptureDevice



DataContext, , , PhotoCaptureDevice



, , MainPage, .



Camera Explorer .

, PhotoCaptureDevice , Camera Explorer. , , . .



DataContext, , .



... class DataContext : INotifyPropertyChanged { ... public static DataContext Singleton { ... } public ObservableCollection<Parameter> Parameters { ... } public PhotoCaptureDevice Device { ... } public MemoryStream ImageStream { ... } }









, PhotoCaptureDevice



. MainPage xaml Canvas



VideoBrush



, .



<phone:PhoneApplicationPage x:Class="CameraExplorer.MainPage" ... > ... <Grid x:Name="LayoutRoot" ... > ... <Grid x:Name="ContentPanel" ... > <Canvas x:Name="VideoCanvas"> <Canvas.Background> <VideoBrush x:Name="videoBrush"/> </Canvas.Background> </Canvas> ... </Grid> </Grid> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar> <shell:ApplicationBarIconButton Text="capture" Click="captureButton_Click" ... /> ... </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> ... </phone:PhoneApplicationPage>







C# MainPage PhotoCaptureDevice



InitializeCamera



, DataContext. , XAML, , .



... public partial class MainPage : PhoneApplicationPage { private CameraExplorer.DataContext _dataContext = CameraExplorer.DataContext.Singleton; ... protected async override void OnNavigatedTo(NavigationEventArgs e) { if (_dataContext.Device == null) { ... await InitializeCamera(CameraSensorLocation.Back); ... } videoBrush.RelativeTransform = new CompositeTransform() { CenterX = 0.5, CenterY = 0.5, Rotation = _dataContext.Device.SensorLocation == CameraSensorLocation.Back ? _dataContext.Device.SensorRotationInDegrees : - _dataContext.Device.SensorRotationInDegrees }; videoBrush.SetSource(_dataContext.Device); ... } 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 void captureButton_Click(object sender, EventArgs e) { if (!_manuallyFocused) { await AutoFocus(); } await Capture(); } private async Task AutoFocus() { if (!_capturing && PhotoCaptureDevice.IsFocusSupported(_dataContext.Device.SensorLocation)) { ... await _dataContext.Device.FocusAsync(); ... _capturing = false; } } private async Task Capture() { if (!_capturing) { _capturing = true; MemoryStream stream = new MemoryStream(); CameraCaptureSequence sequence = _dataContext.Device.CreateCaptureSequence(1); sequence.Frames[0].CaptureStream = stream.AsOutputStream(); await _dataContext.Device.PrepareCaptureSequenceAsync(sequence); await sequence.StartCaptureAsync(); _dataContext.ImageStream = stream; ... } ... } ... }









. Camera Explorer , XAML Image BitmapImage



. , , , void MediaLibrary.SavePictureToCameraRoll(string name, Stream source)



, .



<phone:PhoneApplicationPage x:Class="CameraExplorer.PreviewPage" ... > ... <Grid x:Name="LayoutRoot" ... > ... <Grid x:Name="ContentPanel" ... > <Image x:Name="image" Stretch="UniformToFill"/> </Grid> </Grid> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar> <shell:ApplicationBarIconButton Text="save" Click="saveButton_Click" ... /> </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> ... </phone:PhoneApplicationPage>







... public partial class PreviewPage : PhoneApplicationPage { private CameraExplorer.DataContext _dataContext = CameraExplorer.DataContext.Singleton; private BitmapImage _bitmap = new BitmapImage(); protected override void OnNavigatedTo(NavigationEventArgs e) { ... _bitmap.SetSource(_dataContext.ImageStream); image.Source = _bitmap; ... } private void saveButton_Click(object sender, EventArgs e) { try { _dataContext.ImageStream.Position = 0; MediaLibrary library = new MediaLibrary(); library.SavePictureToCameraRoll("CameraExplorer_" + DateTime.Now.ToString() + ".jpg", _dataContext.ImageStream); } catch (Exception) { ... } ... } }







Camera Explorer , ArrayParameters



RangeParameters



, Parameters



. , , ComboBox



, Slider



Text



. , .

Parameter



, .



... public abstract class Parameter : INotifyPropertyChanged { ... protected Parameter(PhotoCaptureDevice device, string name) { ... } public PhotoCaptureDevice Device { ... } public string Name { ... } public bool Supported { ... } public abstract void Refresh(); ... }







, . _propertyId



, static CameraCapturePropertyRange PhotoCaptureDevice.GetSupportedPropertyRange(CameraSensorLocation sensor, Guid propertyId)



. object PhotoCaptureDevice.GetProperty(Guid propertyId)



. void PhotoCaptureDevice.SetProperty(Guid propertyId, object value)



.



... public abstract class RangeParameter<T> : Parameter { private Guid _propertyId; private T _value; ... protected RangeParameter(PhotoCaptureDevice device, Guid propertyId, string name) : base(device, name) { ... } public override void Refresh() { try { CameraCapturePropertyRange range = PhotoCaptureDevice.GetSupportedPropertyRange( Device.SensorLocation, _propertyId); if (range == null) { Supported = false; } else { Minimum = (T)range.Min; Maximum = (T)range.Max; _value = (T)Device.GetProperty(_propertyId); Supported = true; } } catch (Exception) { Supported = false; } ... } public T Minimum { ... } public T Maximum { ... } public T Value { ... set { if (!_value.Equals(value)) { try { Device.SetProperty(_propertyId, (T)value); _value = value; ... } catch (Exception) { ... } } } } ... }







ExposureCompensationParameter



, Guid RangeParameter



KnownCameraPhotoProperties.ExposureCompensation



, — , . , Int32



, .



... public class ExposureCompensationParameter : RangeParameter<Int32> { public ExposureCompensationParameter(PhotoCaptureDevice device) : base(device, KnownCameraPhotoProperties.ExposureCompensation, "Exposure compensation") { } ... }







Camera Explorer ArrayParameter



. . — void PopulateOptions()



void SetOption(ArrayParameterOption option)



, .



... public class ArrayParameterOption { ... public ArrayParameterOption(dynamic value, string name) { ... } public dynamic Value { ... } public string Name { ... } ... } public abstract class ArrayParameter : Parameter, IReadOnlyCollection<ArrayParameterOption> { private List<ArrayParameterOption> _options = new List<ArrayParameterOption>(); private ArrayParameterOption _selectedOption; ... public ArrayParameter(PhotoCaptureDevice device, string name) : base(device, name) { ... } public override void Refresh() { ... _options.Clear(); _selectedOption = null; try { PopulateOptions(); Supported = _options.Count > 0; } catch (Exception) { Supported = false; } ... } protected List<ArrayParameterOption> Options { ... } public ArrayParameterOption SelectedOption { ... set { if (_selectedOption != value) { ... if (_selectedOption != null)) { SetOption(value); } _selectedOption = value; } } } protected abstract void PopulateOptions(); protected abstract void SetOption(ArrayParameterOption option); ... }







, , , . void PopulateOptions()



, , ArrayParameterOption



SelectedOption



, void SetOption(ArrayParameterOption option)



. , static IReadOnlyList , KnownCameraPhotoProperties.SceneMode



object PhotoCaptureDevice.GetProperty(Guid propertyId)



. void PhotoCaptureDevice.SetProperty(Guid propertyId, object value)



.



... public class SceneModeParameter : ArrayParameter { public SceneModeParameter(PhotoCaptureDevice device) : base(device, KnownCameraPhotoProperties.SceneMode, "Scene mode") { } protected override void PopulateOptions() { IReadOnlyList<object> supportedValues = PhotoCaptureDevice.GetSupportedPropertyValues( Device.SensorLocation, PropertyId); object value = Device.GetProperty(PropertyId); foreach (dynamic i in supportedValues) { CameraSceneMode csm = (CameraSceneMode)i; ArrayParameterOption option = new ArrayParameterOption(csm, csm.ToString()); Options.Add(option); if (i.Equals(value)) { SelectedOption = option; } } } protected override void SetOption(ArrayParameterOption option) { Device.SetProperty(PropertyId, option.Value); } ... }







Tap-to-focus

«». Tap-to-focus , , , . , Tap-to-focus .



Rectangle



Canvas



, :



<Rectangle x:Name="FocusIndicator" Stroke="Red" Opacity="0.7" Width="80" Height="80" StrokeThickness="5" Visibility="Collapsed"/>







, .

Canvas Tap:



public MainPage() { ... VideoCanvas.Tap += new EventHandler<GestureEventArgs>(videoCanvas_Tap); ... }







. API- , VideoCanvas



, , .



, . , , , .



, , , , .



private async void videoCanvas_Tap(object sender, GestureEventArgs e) { System.Windows.Point uiTapPoint = e.GetPosition(VideoCanvas); if (PhotoCaptureDevice.IsFocusRegionSupported(_dataContext.Device.SensorLocation) && _focusSemaphore.WaitOne(0)) { // . Windows.Foundation.Point tapPoint = new Windows.Foundation.Point(uiTapPoint.X, uiTapPoint.Y); double xRatio = VideoCanvas.ActualWidth / _dataContext.Device.PreviewResolution.Width; double yRatio = VideoCanvas.ActualHeight / _dataContext.Device.PreviewResolution.Height; // , Windows.Foundation.Point displayOrigin = new Windows.Foundation.Point( tapPoint.X - _focusRegionSize.Width / 2, tapPoint.Y - _focusRegionSize.Height / 2); // canvas Windows.Foundation.Point viewFinderOrigin = new Windows.Foundation.Point( displayOrigin.X / xRatio, displayOrigin.Y / yRatio); Windows.Foundation.Rect focusrect = new Windows.Foundation.Rect( viewFinderOrigin, _focusRegionSize); // Windows.Foundation.Rect viewPortRect = new Windows.Foundation.Rect( 0, 0, _dataContext.Device.PreviewResolution.Width, _dataContext.Device.PreviewResolution.Height); focusrect.Intersect(viewPortRect); _dataContext.Device.FocusRegion = focusrect; // FocusIndicator.SetValue(Shape.StrokeProperty, _notFocusedBrush); FocusIndicator.SetValue(Canvas.LeftProperty, uiTapPoint.X - _focusRegionSize.Width / 2); FocusIndicator.SetValue(Canvas.TopProperty, uiTapPoint.Y - _focusRegionSize.Height / 2); FocusIndicator.SetValue(Canvas.VisibilityProperty, Visibility.Visible); CameraFocusStatus status = await _dataContext.Device.FocusAsync(); if (status == CameraFocusStatus.Locked) { FocusIndicator.SetValue(Shape.StrokeProperty, _focusedBrush); _manuallyFocused = true; _dataContext.Device.SetProperty( KnownCameraPhotoProperties.LockedAutoFocusParameters, AutoFocusParameters.Exposure & AutoFocusParameters.Focus & AutoFocusParameters.WhiteBalance); } else { _manuallyFocused = false; _dataContext.Device.SetProperty( KnownCameraPhotoProperties.LockedAutoFocusParameters, AutoFocusParameters.None); } _focusSemaphore.Release(); } }







, . FocusAsync



, , . , WaitOne



, , , false



— , .





, «», Lens Picker. «» , . Lens Picker, XML App:



<Extensions> <Extension ExtensionName="Camera_Capture_App" ConsumerId="{5B04B775-356B-4AA0-AAF8-6491FFEA5631]" TaskId="_default" /> </Extensions>







, Lens Picker, . , Lens Picker Assets



. , Lens design guidelines for Windows Phone .



Maps API.
























static IReadOnlyList

• object GetProperty(Guid propertyId)






void SetProperty(Guid propertyId, object value)







— , .



static bool IsFocusSupported(CameraSensorLocation sensor)





static bool IsFocusRegionSupported(CameraSensorLocation sensor)





IAsyncOperation FocusAsync()

• IAsyncOperation ResetFocusAsync()



— .



• static IReadOnlyList GetAvailablePreviewResolutions()

• static IReadOnlyList GetAvailableCaptureResolutions()

• IAsyncAction SetPreviewResolutionAsync(Size value)






IAsyncAction SetCaptureResolutionAsync(Size value)







— .



event TypedEventHandler<ICameraCaptureDevice, Object> PreviewFrameAvailable





void GetPreviewBufferArgb(out int[] pixels)





void GetPreviewBufferY(out byte[] pixels)





void GetPreviewBufferYCbCr(out byte[] pixels)







— .



CameraCaptureSequence CreateCaptureSequence(uint numberOfFrames)





IAsyncAction PrepareCaptureSequenceAsync(CameraCaptureSequence sequence)







— . . API . GUID. , .

, ID_CAP_ISV_CAMERA



WMAppManifest.xml . ID_CAP_MEDIALIB_PHOTO



.



Lumia

Nokia Lumia 820 920.





Camera Explorer — , PhotoCaptureDevice



. , .







, Camera Explorer.







Windows Phone DataContext



, Settings



PhotoCaptureDevice



.

PhotoCaptureDevice



DataContext, , , PhotoCaptureDevice



, , MainPage, .



Camera Explorer .

, PhotoCaptureDevice , Camera Explorer. , , . .



DataContext, , .



... class DataContext : INotifyPropertyChanged { ... public static DataContext Singleton { ... } public ObservableCollection<Parameter> Parameters { ... } public PhotoCaptureDevice Device { ... } public MemoryStream ImageStream { ... } }









, PhotoCaptureDevice



. MainPage xaml Canvas



VideoBrush



, .



<phone:PhoneApplicationPage x:Class="CameraExplorer.MainPage" ... > ... <Grid x:Name="LayoutRoot" ... > ... <Grid x:Name="ContentPanel" ... > <Canvas x:Name="VideoCanvas"> <Canvas.Background> <VideoBrush x:Name="videoBrush"/> </Canvas.Background> </Canvas> ... </Grid> </Grid> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar> <shell:ApplicationBarIconButton Text="capture" Click="captureButton_Click" ... /> ... </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> ... </phone:PhoneApplicationPage>







C# MainPage PhotoCaptureDevice



InitializeCamera



, DataContext. , XAML, , .



... public partial class MainPage : PhoneApplicationPage { private CameraExplorer.DataContext _dataContext = CameraExplorer.DataContext.Singleton; ... protected async override void OnNavigatedTo(NavigationEventArgs e) { if (_dataContext.Device == null) { ... await InitializeCamera(CameraSensorLocation.Back); ... } videoBrush.RelativeTransform = new CompositeTransform() { CenterX = 0.5, CenterY = 0.5, Rotation = _dataContext.Device.SensorLocation == CameraSensorLocation.Back ? _dataContext.Device.SensorRotationInDegrees : - _dataContext.Device.SensorRotationInDegrees }; videoBrush.SetSource(_dataContext.Device); ... } 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 void captureButton_Click(object sender, EventArgs e) { if (!_manuallyFocused) { await AutoFocus(); } await Capture(); } private async Task AutoFocus() { if (!_capturing && PhotoCaptureDevice.IsFocusSupported(_dataContext.Device.SensorLocation)) { ... await _dataContext.Device.FocusAsync(); ... _capturing = false; } } private async Task Capture() { if (!_capturing) { _capturing = true; MemoryStream stream = new MemoryStream(); CameraCaptureSequence sequence = _dataContext.Device.CreateCaptureSequence(1); sequence.Frames[0].CaptureStream = stream.AsOutputStream(); await _dataContext.Device.PrepareCaptureSequenceAsync(sequence); await sequence.StartCaptureAsync(); _dataContext.ImageStream = stream; ... } ... } ... }









. Camera Explorer , XAML Image BitmapImage



. , , , void MediaLibrary.SavePictureToCameraRoll(string name, Stream source)



, .



<phone:PhoneApplicationPage x:Class="CameraExplorer.PreviewPage" ... > ... <Grid x:Name="LayoutRoot" ... > ... <Grid x:Name="ContentPanel" ... > <Image x:Name="image" Stretch="UniformToFill"/> </Grid> </Grid> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar> <shell:ApplicationBarIconButton Text="save" Click="saveButton_Click" ... /> </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> ... </phone:PhoneApplicationPage>







... public partial class PreviewPage : PhoneApplicationPage { private CameraExplorer.DataContext _dataContext = CameraExplorer.DataContext.Singleton; private BitmapImage _bitmap = new BitmapImage(); protected override void OnNavigatedTo(NavigationEventArgs e) { ... _bitmap.SetSource(_dataContext.ImageStream); image.Source = _bitmap; ... } private void saveButton_Click(object sender, EventArgs e) { try { _dataContext.ImageStream.Position = 0; MediaLibrary library = new MediaLibrary(); library.SavePictureToCameraRoll("CameraExplorer_" + DateTime.Now.ToString() + ".jpg", _dataContext.ImageStream); } catch (Exception) { ... } ... } }







Camera Explorer , ArrayParameters



RangeParameters



, Parameters



. , , ComboBox



, Slider



Text



. , .

Parameter



, .



... public abstract class Parameter : INotifyPropertyChanged { ... protected Parameter(PhotoCaptureDevice device, string name) { ... } public PhotoCaptureDevice Device { ... } public string Name { ... } public bool Supported { ... } public abstract void Refresh(); ... }







, . _propertyId



, static CameraCapturePropertyRange PhotoCaptureDevice.GetSupportedPropertyRange(CameraSensorLocation sensor, Guid propertyId)



. object PhotoCaptureDevice.GetProperty(Guid propertyId)



. void PhotoCaptureDevice.SetProperty(Guid propertyId, object value)



.



... public abstract class RangeParameter<T> : Parameter { private Guid _propertyId; private T _value; ... protected RangeParameter(PhotoCaptureDevice device, Guid propertyId, string name) : base(device, name) { ... } public override void Refresh() { try { CameraCapturePropertyRange range = PhotoCaptureDevice.GetSupportedPropertyRange( Device.SensorLocation, _propertyId); if (range == null) { Supported = false; } else { Minimum = (T)range.Min; Maximum = (T)range.Max; _value = (T)Device.GetProperty(_propertyId); Supported = true; } } catch (Exception) { Supported = false; } ... } public T Minimum { ... } public T Maximum { ... } public T Value { ... set { if (!_value.Equals(value)) { try { Device.SetProperty(_propertyId, (T)value); _value = value; ... } catch (Exception) { ... } } } } ... }







ExposureCompensationParameter



, Guid RangeParameter



KnownCameraPhotoProperties.ExposureCompensation



, — , . , Int32



, .



... public class ExposureCompensationParameter : RangeParameter<Int32> { public ExposureCompensationParameter(PhotoCaptureDevice device) : base(device, KnownCameraPhotoProperties.ExposureCompensation, "Exposure compensation") { } ... }







Camera Explorer ArrayParameter



. . — void PopulateOptions()



void SetOption(ArrayParameterOption option)



, .



... public class ArrayParameterOption { ... public ArrayParameterOption(dynamic value, string name) { ... } public dynamic Value { ... } public string Name { ... } ... } public abstract class ArrayParameter : Parameter, IReadOnlyCollection<ArrayParameterOption> { private List<ArrayParameterOption> _options = new List<ArrayParameterOption>(); private ArrayParameterOption _selectedOption; ... public ArrayParameter(PhotoCaptureDevice device, string name) : base(device, name) { ... } public override void Refresh() { ... _options.Clear(); _selectedOption = null; try { PopulateOptions(); Supported = _options.Count > 0; } catch (Exception) { Supported = false; } ... } protected List<ArrayParameterOption> Options { ... } public ArrayParameterOption SelectedOption { ... set { if (_selectedOption != value) { ... if (_selectedOption != null)) { SetOption(value); } _selectedOption = value; } } } protected abstract void PopulateOptions(); protected abstract void SetOption(ArrayParameterOption option); ... }







, , , . void PopulateOptions()



, , ArrayParameterOption



SelectedOption



, void SetOption(ArrayParameterOption option)



. , static IReadOnlyList , KnownCameraPhotoProperties.SceneMode



object PhotoCaptureDevice.GetProperty(Guid propertyId)



. void PhotoCaptureDevice.SetProperty(Guid propertyId, object value)



.



... public class SceneModeParameter : ArrayParameter { public SceneModeParameter(PhotoCaptureDevice device) : base(device, KnownCameraPhotoProperties.SceneMode, "Scene mode") { } protected override void PopulateOptions() { IReadOnlyList<object> supportedValues = PhotoCaptureDevice.GetSupportedPropertyValues( Device.SensorLocation, PropertyId); object value = Device.GetProperty(PropertyId); foreach (dynamic i in supportedValues) { CameraSceneMode csm = (CameraSceneMode)i; ArrayParameterOption option = new ArrayParameterOption(csm, csm.ToString()); Options.Add(option); if (i.Equals(value)) { SelectedOption = option; } } } protected override void SetOption(ArrayParameterOption option) { Device.SetProperty(PropertyId, option.Value); } ... }







Tap-to-focus

«». Tap-to-focus , , , . , Tap-to-focus .



Rectangle



Canvas



, :



<Rectangle x:Name="FocusIndicator" Stroke="Red" Opacity="0.7" Width="80" Height="80" StrokeThickness="5" Visibility="Collapsed"/>







, .

Canvas Tap:



public MainPage() { ... VideoCanvas.Tap += new EventHandler<GestureEventArgs>(videoCanvas_Tap); ... }







. API- , VideoCanvas



, , .



, . , , , .



, , , , .



private async void videoCanvas_Tap(object sender, GestureEventArgs e) { System.Windows.Point uiTapPoint = e.GetPosition(VideoCanvas); if (PhotoCaptureDevice.IsFocusRegionSupported(_dataContext.Device.SensorLocation) && _focusSemaphore.WaitOne(0)) { // . Windows.Foundation.Point tapPoint = new Windows.Foundation.Point(uiTapPoint.X, uiTapPoint.Y); double xRatio = VideoCanvas.ActualWidth / _dataContext.Device.PreviewResolution.Width; double yRatio = VideoCanvas.ActualHeight / _dataContext.Device.PreviewResolution.Height; // , Windows.Foundation.Point displayOrigin = new Windows.Foundation.Point( tapPoint.X - _focusRegionSize.Width / 2, tapPoint.Y - _focusRegionSize.Height / 2); // canvas Windows.Foundation.Point viewFinderOrigin = new Windows.Foundation.Point( displayOrigin.X / xRatio, displayOrigin.Y / yRatio); Windows.Foundation.Rect focusrect = new Windows.Foundation.Rect( viewFinderOrigin, _focusRegionSize); // Windows.Foundation.Rect viewPortRect = new Windows.Foundation.Rect( 0, 0, _dataContext.Device.PreviewResolution.Width, _dataContext.Device.PreviewResolution.Height); focusrect.Intersect(viewPortRect); _dataContext.Device.FocusRegion = focusrect; // FocusIndicator.SetValue(Shape.StrokeProperty, _notFocusedBrush); FocusIndicator.SetValue(Canvas.LeftProperty, uiTapPoint.X - _focusRegionSize.Width / 2); FocusIndicator.SetValue(Canvas.TopProperty, uiTapPoint.Y - _focusRegionSize.Height / 2); FocusIndicator.SetValue(Canvas.VisibilityProperty, Visibility.Visible); CameraFocusStatus status = await _dataContext.Device.FocusAsync(); if (status == CameraFocusStatus.Locked) { FocusIndicator.SetValue(Shape.StrokeProperty, _focusedBrush); _manuallyFocused = true; _dataContext.Device.SetProperty( KnownCameraPhotoProperties.LockedAutoFocusParameters, AutoFocusParameters.Exposure & AutoFocusParameters.Focus & AutoFocusParameters.WhiteBalance); } else { _manuallyFocused = false; _dataContext.Device.SetProperty( KnownCameraPhotoProperties.LockedAutoFocusParameters, AutoFocusParameters.None); } _focusSemaphore.Release(); } }







, . FocusAsync



, , . , WaitOne



, , , false



— , .





, «», Lens Picker. «» , . Lens Picker, XML App:



<Extensions> <Extension ExtensionName="Camera_Capture_App" ConsumerId="{5B04B775-356B-4AA0-AAF8-6491FFEA5631]" TaskId="_default" /> </Extensions>







, Lens Picker, . , Lens Picker Assets



. , Lens design guidelines for Windows Phone .



Maps API.
























 static IReadOnlyList 
      

object GetProperty(Guid propertyId)






void SetProperty(Guid propertyId, object value)







— , .



static bool IsFocusSupported(CameraSensorLocation sensor)





static bool IsFocusRegionSupported(CameraSensorLocation sensor)





IAsyncOperation FocusAsync()

• IAsyncOperation ResetFocusAsync()



— .



• static IReadOnlyList GetAvailablePreviewResolutions()

• static IReadOnlyList GetAvailableCaptureResolutions()

• IAsyncAction SetPreviewResolutionAsync(Size value)






IAsyncAction SetCaptureResolutionAsync(Size value)







— .



event TypedEventHandler<ICameraCaptureDevice, Object> PreviewFrameAvailable





void GetPreviewBufferArgb(out int[] pixels)





void GetPreviewBufferY(out byte[] pixels)





void GetPreviewBufferYCbCr(out byte[] pixels)







— .



CameraCaptureSequence CreateCaptureSequence(uint numberOfFrames)





IAsyncAction PrepareCaptureSequenceAsync(CameraCaptureSequence sequence)







— . . API . GUID. , .

, ID_CAP_ISV_CAMERA



WMAppManifest.xml . ID_CAP_MEDIALIB_PHOTO



.



Lumia

Nokia Lumia 820 920.





Camera Explorer — , PhotoCaptureDevice



. , .







, Camera Explorer.







Windows Phone DataContext



, Settings



PhotoCaptureDevice



.

PhotoCaptureDevice



DataContext, , , PhotoCaptureDevice



, , MainPage, .



Camera Explorer .

, PhotoCaptureDevice , Camera Explorer. , , . .



DataContext, , .



... class DataContext : INotifyPropertyChanged { ... public static DataContext Singleton { ... } public ObservableCollection<Parameter> Parameters { ... } public PhotoCaptureDevice Device { ... } public MemoryStream ImageStream { ... } }









, PhotoCaptureDevice



. MainPage xaml Canvas



VideoBrush



, .



<phone:PhoneApplicationPage x:Class="CameraExplorer.MainPage" ... > ... <Grid x:Name="LayoutRoot" ... > ... <Grid x:Name="ContentPanel" ... > <Canvas x:Name="VideoCanvas"> <Canvas.Background> <VideoBrush x:Name="videoBrush"/> </Canvas.Background> </Canvas> ... </Grid> </Grid> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar> <shell:ApplicationBarIconButton Text="capture" Click="captureButton_Click" ... /> ... </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> ... </phone:PhoneApplicationPage>







C# MainPage PhotoCaptureDevice



InitializeCamera



, DataContext. , XAML, , .



... public partial class MainPage : PhoneApplicationPage { private CameraExplorer.DataContext _dataContext = CameraExplorer.DataContext.Singleton; ... protected async override void OnNavigatedTo(NavigationEventArgs e) { if (_dataContext.Device == null) { ... await InitializeCamera(CameraSensorLocation.Back); ... } videoBrush.RelativeTransform = new CompositeTransform() { CenterX = 0.5, CenterY = 0.5, Rotation = _dataContext.Device.SensorLocation == CameraSensorLocation.Back ? _dataContext.Device.SensorRotationInDegrees : - _dataContext.Device.SensorRotationInDegrees }; videoBrush.SetSource(_dataContext.Device); ... } 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 void captureButton_Click(object sender, EventArgs e) { if (!_manuallyFocused) { await AutoFocus(); } await Capture(); } private async Task AutoFocus() { if (!_capturing && PhotoCaptureDevice.IsFocusSupported(_dataContext.Device.SensorLocation)) { ... await _dataContext.Device.FocusAsync(); ... _capturing = false; } } private async Task Capture() { if (!_capturing) { _capturing = true; MemoryStream stream = new MemoryStream(); CameraCaptureSequence sequence = _dataContext.Device.CreateCaptureSequence(1); sequence.Frames[0].CaptureStream = stream.AsOutputStream(); await _dataContext.Device.PrepareCaptureSequenceAsync(sequence); await sequence.StartCaptureAsync(); _dataContext.ImageStream = stream; ... } ... } ... }









. Camera Explorer , XAML Image BitmapImage



. , , , void MediaLibrary.SavePictureToCameraRoll(string name, Stream source)



, .



<phone:PhoneApplicationPage x:Class="CameraExplorer.PreviewPage" ... > ... <Grid x:Name="LayoutRoot" ... > ... <Grid x:Name="ContentPanel" ... > <Image x:Name="image" Stretch="UniformToFill"/> </Grid> </Grid> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar> <shell:ApplicationBarIconButton Text="save" Click="saveButton_Click" ... /> </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> ... </phone:PhoneApplicationPage>







... public partial class PreviewPage : PhoneApplicationPage { private CameraExplorer.DataContext _dataContext = CameraExplorer.DataContext.Singleton; private BitmapImage _bitmap = new BitmapImage(); protected override void OnNavigatedTo(NavigationEventArgs e) { ... _bitmap.SetSource(_dataContext.ImageStream); image.Source = _bitmap; ... } private void saveButton_Click(object sender, EventArgs e) { try { _dataContext.ImageStream.Position = 0; MediaLibrary library = new MediaLibrary(); library.SavePictureToCameraRoll("CameraExplorer_" + DateTime.Now.ToString() + ".jpg", _dataContext.ImageStream); } catch (Exception) { ... } ... } }







Camera Explorer , ArrayParameters



RangeParameters



, Parameters



. , , ComboBox



, Slider



Text



. , .

Parameter



, .



... public abstract class Parameter : INotifyPropertyChanged { ... protected Parameter(PhotoCaptureDevice device, string name) { ... } public PhotoCaptureDevice Device { ... } public string Name { ... } public bool Supported { ... } public abstract void Refresh(); ... }







, . _propertyId



, static CameraCapturePropertyRange PhotoCaptureDevice.GetSupportedPropertyRange(CameraSensorLocation sensor, Guid propertyId)



. object PhotoCaptureDevice.GetProperty(Guid propertyId)



. void PhotoCaptureDevice.SetProperty(Guid propertyId, object value)



.



... public abstract class RangeParameter<T> : Parameter { private Guid _propertyId; private T _value; ... protected RangeParameter(PhotoCaptureDevice device, Guid propertyId, string name) : base(device, name) { ... } public override void Refresh() { try { CameraCapturePropertyRange range = PhotoCaptureDevice.GetSupportedPropertyRange( Device.SensorLocation, _propertyId); if (range == null) { Supported = false; } else { Minimum = (T)range.Min; Maximum = (T)range.Max; _value = (T)Device.GetProperty(_propertyId); Supported = true; } } catch (Exception) { Supported = false; } ... } public T Minimum { ... } public T Maximum { ... } public T Value { ... set { if (!_value.Equals(value)) { try { Device.SetProperty(_propertyId, (T)value); _value = value; ... } catch (Exception) { ... } } } } ... }







ExposureCompensationParameter



, Guid RangeParameter



KnownCameraPhotoProperties.ExposureCompensation



, — , . , Int32



, .



... public class ExposureCompensationParameter : RangeParameter<Int32> { public ExposureCompensationParameter(PhotoCaptureDevice device) : base(device, KnownCameraPhotoProperties.ExposureCompensation, "Exposure compensation") { } ... }







Camera Explorer ArrayParameter



. . — void PopulateOptions()



void SetOption(ArrayParameterOption option)



, .



... public class ArrayParameterOption { ... public ArrayParameterOption(dynamic value, string name) { ... } public dynamic Value { ... } public string Name { ... } ... } public abstract class ArrayParameter : Parameter, IReadOnlyCollection<ArrayParameterOption> { private List<ArrayParameterOption> _options = new List<ArrayParameterOption>(); private ArrayParameterOption _selectedOption; ... public ArrayParameter(PhotoCaptureDevice device, string name) : base(device, name) { ... } public override void Refresh() { ... _options.Clear(); _selectedOption = null; try { PopulateOptions(); Supported = _options.Count > 0; } catch (Exception) { Supported = false; } ... } protected List<ArrayParameterOption> Options { ... } public ArrayParameterOption SelectedOption { ... set { if (_selectedOption != value) { ... if (_selectedOption != null)) { SetOption(value); } _selectedOption = value; } } } protected abstract void PopulateOptions(); protected abstract void SetOption(ArrayParameterOption option); ... }







, , , . void PopulateOptions()



, , ArrayParameterOption



SelectedOption



, void SetOption(ArrayParameterOption option)



. , static IReadOnlyList , KnownCameraPhotoProperties.SceneMode



object PhotoCaptureDevice.GetProperty(Guid propertyId)



. void PhotoCaptureDevice.SetProperty(Guid propertyId, object value)



.



... public class SceneModeParameter : ArrayParameter { public SceneModeParameter(PhotoCaptureDevice device) : base(device, KnownCameraPhotoProperties.SceneMode, "Scene mode") { } protected override void PopulateOptions() { IReadOnlyList<object> supportedValues = PhotoCaptureDevice.GetSupportedPropertyValues( Device.SensorLocation, PropertyId); object value = Device.GetProperty(PropertyId); foreach (dynamic i in supportedValues) { CameraSceneMode csm = (CameraSceneMode)i; ArrayParameterOption option = new ArrayParameterOption(csm, csm.ToString()); Options.Add(option); if (i.Equals(value)) { SelectedOption = option; } } } protected override void SetOption(ArrayParameterOption option) { Device.SetProperty(PropertyId, option.Value); } ... }







Tap-to-focus

«». Tap-to-focus , , , . , Tap-to-focus .



Rectangle



Canvas



, :



<Rectangle x:Name="FocusIndicator" Stroke="Red" Opacity="0.7" Width="80" Height="80" StrokeThickness="5" Visibility="Collapsed"/>







, .

Canvas Tap:



public MainPage() { ... VideoCanvas.Tap += new EventHandler<GestureEventArgs>(videoCanvas_Tap); ... }







. API- , VideoCanvas



, , .



, . , , , .



, , , , .



private async void videoCanvas_Tap(object sender, GestureEventArgs e) { System.Windows.Point uiTapPoint = e.GetPosition(VideoCanvas); if (PhotoCaptureDevice.IsFocusRegionSupported(_dataContext.Device.SensorLocation) && _focusSemaphore.WaitOne(0)) { // . Windows.Foundation.Point tapPoint = new Windows.Foundation.Point(uiTapPoint.X, uiTapPoint.Y); double xRatio = VideoCanvas.ActualWidth / _dataContext.Device.PreviewResolution.Width; double yRatio = VideoCanvas.ActualHeight / _dataContext.Device.PreviewResolution.Height; // , Windows.Foundation.Point displayOrigin = new Windows.Foundation.Point( tapPoint.X - _focusRegionSize.Width / 2, tapPoint.Y - _focusRegionSize.Height / 2); // canvas Windows.Foundation.Point viewFinderOrigin = new Windows.Foundation.Point( displayOrigin.X / xRatio, displayOrigin.Y / yRatio); Windows.Foundation.Rect focusrect = new Windows.Foundation.Rect( viewFinderOrigin, _focusRegionSize); // Windows.Foundation.Rect viewPortRect = new Windows.Foundation.Rect( 0, 0, _dataContext.Device.PreviewResolution.Width, _dataContext.Device.PreviewResolution.Height); focusrect.Intersect(viewPortRect); _dataContext.Device.FocusRegion = focusrect; // FocusIndicator.SetValue(Shape.StrokeProperty, _notFocusedBrush); FocusIndicator.SetValue(Canvas.LeftProperty, uiTapPoint.X - _focusRegionSize.Width / 2); FocusIndicator.SetValue(Canvas.TopProperty, uiTapPoint.Y - _focusRegionSize.Height / 2); FocusIndicator.SetValue(Canvas.VisibilityProperty, Visibility.Visible); CameraFocusStatus status = await _dataContext.Device.FocusAsync(); if (status == CameraFocusStatus.Locked) { FocusIndicator.SetValue(Shape.StrokeProperty, _focusedBrush); _manuallyFocused = true; _dataContext.Device.SetProperty( KnownCameraPhotoProperties.LockedAutoFocusParameters, AutoFocusParameters.Exposure & AutoFocusParameters.Focus & AutoFocusParameters.WhiteBalance); } else { _manuallyFocused = false; _dataContext.Device.SetProperty( KnownCameraPhotoProperties.LockedAutoFocusParameters, AutoFocusParameters.None); } _focusSemaphore.Release(); } }







, . FocusAsync



, , . , WaitOne



, , , false



— , .





, «», Lens Picker. «» , . Lens Picker, XML App:



<Extensions> <Extension ExtensionName="Camera_Capture_App" ConsumerId="{5B04B775-356B-4AA0-AAF8-6491FFEA5631]" TaskId="_default" /> </Extensions>







, Lens Picker, . , Lens Picker Assets



. , Lens design guidelines for Windows Phone .



Maps API.
























static IReadOnlyList

• object GetProperty(Guid propertyId)






void SetProperty(Guid propertyId, object value)







— , .



static bool IsFocusSupported(CameraSensorLocation sensor)





static bool IsFocusRegionSupported(CameraSensorLocation sensor)





IAsyncOperation FocusAsync()

• IAsyncOperation ResetFocusAsync()



— .



• static IReadOnlyList GetAvailablePreviewResolutions()

• static IReadOnlyList GetAvailableCaptureResolutions()

• IAsyncAction SetPreviewResolutionAsync(Size value)






IAsyncAction SetCaptureResolutionAsync(Size value)







— .



event TypedEventHandler<ICameraCaptureDevice, Object> PreviewFrameAvailable





void GetPreviewBufferArgb(out int[] pixels)





void GetPreviewBufferY(out byte[] pixels)





void GetPreviewBufferYCbCr(out byte[] pixels)







— .



CameraCaptureSequence CreateCaptureSequence(uint numberOfFrames)





IAsyncAction PrepareCaptureSequenceAsync(CameraCaptureSequence sequence)







— . . API . GUID. , .

, ID_CAP_ISV_CAMERA



WMAppManifest.xml . ID_CAP_MEDIALIB_PHOTO



.



Lumia

Nokia Lumia 820 920.





Camera Explorer — , PhotoCaptureDevice



. , .







, Camera Explorer.







Windows Phone DataContext



, Settings



PhotoCaptureDevice



.

PhotoCaptureDevice



DataContext, , , PhotoCaptureDevice



, , MainPage, .



Camera Explorer .

, PhotoCaptureDevice , Camera Explorer. , , . .



DataContext, , .



... class DataContext : INotifyPropertyChanged { ... public static DataContext Singleton { ... } public ObservableCollection<Parameter> Parameters { ... } public PhotoCaptureDevice Device { ... } public MemoryStream ImageStream { ... } }









, PhotoCaptureDevice



. MainPage xaml Canvas



VideoBrush



, .



<phone:PhoneApplicationPage x:Class="CameraExplorer.MainPage" ... > ... <Grid x:Name="LayoutRoot" ... > ... <Grid x:Name="ContentPanel" ... > <Canvas x:Name="VideoCanvas"> <Canvas.Background> <VideoBrush x:Name="videoBrush"/> </Canvas.Background> </Canvas> ... </Grid> </Grid> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar> <shell:ApplicationBarIconButton Text="capture" Click="captureButton_Click" ... /> ... </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> ... </phone:PhoneApplicationPage>







C# MainPage PhotoCaptureDevice



InitializeCamera



, DataContext. , XAML, , .



... public partial class MainPage : PhoneApplicationPage { private CameraExplorer.DataContext _dataContext = CameraExplorer.DataContext.Singleton; ... protected async override void OnNavigatedTo(NavigationEventArgs e) { if (_dataContext.Device == null) { ... await InitializeCamera(CameraSensorLocation.Back); ... } videoBrush.RelativeTransform = new CompositeTransform() { CenterX = 0.5, CenterY = 0.5, Rotation = _dataContext.Device.SensorLocation == CameraSensorLocation.Back ? _dataContext.Device.SensorRotationInDegrees : - _dataContext.Device.SensorRotationInDegrees }; videoBrush.SetSource(_dataContext.Device); ... } 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 void captureButton_Click(object sender, EventArgs e) { if (!_manuallyFocused) { await AutoFocus(); } await Capture(); } private async Task AutoFocus() { if (!_capturing && PhotoCaptureDevice.IsFocusSupported(_dataContext.Device.SensorLocation)) { ... await _dataContext.Device.FocusAsync(); ... _capturing = false; } } private async Task Capture() { if (!_capturing) { _capturing = true; MemoryStream stream = new MemoryStream(); CameraCaptureSequence sequence = _dataContext.Device.CreateCaptureSequence(1); sequence.Frames[0].CaptureStream = stream.AsOutputStream(); await _dataContext.Device.PrepareCaptureSequenceAsync(sequence); await sequence.StartCaptureAsync(); _dataContext.ImageStream = stream; ... } ... } ... }









. Camera Explorer , XAML Image BitmapImage



. , , , void MediaLibrary.SavePictureToCameraRoll(string name, Stream source)



, .



<phone:PhoneApplicationPage x:Class="CameraExplorer.PreviewPage" ... > ... <Grid x:Name="LayoutRoot" ... > ... <Grid x:Name="ContentPanel" ... > <Image x:Name="image" Stretch="UniformToFill"/> </Grid> </Grid> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar> <shell:ApplicationBarIconButton Text="save" Click="saveButton_Click" ... /> </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> ... </phone:PhoneApplicationPage>







... public partial class PreviewPage : PhoneApplicationPage { private CameraExplorer.DataContext _dataContext = CameraExplorer.DataContext.Singleton; private BitmapImage _bitmap = new BitmapImage(); protected override void OnNavigatedTo(NavigationEventArgs e) { ... _bitmap.SetSource(_dataContext.ImageStream); image.Source = _bitmap; ... } private void saveButton_Click(object sender, EventArgs e) { try { _dataContext.ImageStream.Position = 0; MediaLibrary library = new MediaLibrary(); library.SavePictureToCameraRoll("CameraExplorer_" + DateTime.Now.ToString() + ".jpg", _dataContext.ImageStream); } catch (Exception) { ... } ... } }







Camera Explorer , ArrayParameters



RangeParameters



, Parameters



. , , ComboBox



, Slider



Text



. , .

Parameter



, .



... public abstract class Parameter : INotifyPropertyChanged { ... protected Parameter(PhotoCaptureDevice device, string name) { ... } public PhotoCaptureDevice Device { ... } public string Name { ... } public bool Supported { ... } public abstract void Refresh(); ... }







, . _propertyId



, static CameraCapturePropertyRange PhotoCaptureDevice.GetSupportedPropertyRange(CameraSensorLocation sensor, Guid propertyId)



. object PhotoCaptureDevice.GetProperty(Guid propertyId)



. void PhotoCaptureDevice.SetProperty(Guid propertyId, object value)



.



... public abstract class RangeParameter<T> : Parameter { private Guid _propertyId; private T _value; ... protected RangeParameter(PhotoCaptureDevice device, Guid propertyId, string name) : base(device, name) { ... } public override void Refresh() { try { CameraCapturePropertyRange range = PhotoCaptureDevice.GetSupportedPropertyRange( Device.SensorLocation, _propertyId); if (range == null) { Supported = false; } else { Minimum = (T)range.Min; Maximum = (T)range.Max; _value = (T)Device.GetProperty(_propertyId); Supported = true; } } catch (Exception) { Supported = false; } ... } public T Minimum { ... } public T Maximum { ... } public T Value { ... set { if (!_value.Equals(value)) { try { Device.SetProperty(_propertyId, (T)value); _value = value; ... } catch (Exception) { ... } } } } ... }







ExposureCompensationParameter



, Guid RangeParameter



KnownCameraPhotoProperties.ExposureCompensation



, — , . , Int32



, .



... public class ExposureCompensationParameter : RangeParameter<Int32> { public ExposureCompensationParameter(PhotoCaptureDevice device) : base(device, KnownCameraPhotoProperties.ExposureCompensation, "Exposure compensation") { } ... }







Camera Explorer ArrayParameter



. . — void PopulateOptions()



void SetOption(ArrayParameterOption option)



, .



... public class ArrayParameterOption { ... public ArrayParameterOption(dynamic value, string name) { ... } public dynamic Value { ... } public string Name { ... } ... } public abstract class ArrayParameter : Parameter, IReadOnlyCollection<ArrayParameterOption> { private List<ArrayParameterOption> _options = new List<ArrayParameterOption>(); private ArrayParameterOption _selectedOption; ... public ArrayParameter(PhotoCaptureDevice device, string name) : base(device, name) { ... } public override void Refresh() { ... _options.Clear(); _selectedOption = null; try { PopulateOptions(); Supported = _options.Count > 0; } catch (Exception) { Supported = false; } ... } protected List<ArrayParameterOption> Options { ... } public ArrayParameterOption SelectedOption { ... set { if (_selectedOption != value) { ... if (_selectedOption != null)) { SetOption(value); } _selectedOption = value; } } } protected abstract void PopulateOptions(); protected abstract void SetOption(ArrayParameterOption option); ... }







, , , . void PopulateOptions()



, , ArrayParameterOption



SelectedOption



, void SetOption(ArrayParameterOption option)



. , static IReadOnlyList , KnownCameraPhotoProperties.SceneMode



object PhotoCaptureDevice.GetProperty(Guid propertyId)



. void PhotoCaptureDevice.SetProperty(Guid propertyId, object value)



.



... public class SceneModeParameter : ArrayParameter { public SceneModeParameter(PhotoCaptureDevice device) : base(device, KnownCameraPhotoProperties.SceneMode, "Scene mode") { } protected override void PopulateOptions() { IReadOnlyList<object> supportedValues = PhotoCaptureDevice.GetSupportedPropertyValues( Device.SensorLocation, PropertyId); object value = Device.GetProperty(PropertyId); foreach (dynamic i in supportedValues) { CameraSceneMode csm = (CameraSceneMode)i; ArrayParameterOption option = new ArrayParameterOption(csm, csm.ToString()); Options.Add(option); if (i.Equals(value)) { SelectedOption = option; } } } protected override void SetOption(ArrayParameterOption option) { Device.SetProperty(PropertyId, option.Value); } ... }







Tap-to-focus

«». Tap-to-focus , , , . , Tap-to-focus .



Rectangle



Canvas



, :



<Rectangle x:Name="FocusIndicator" Stroke="Red" Opacity="0.7" Width="80" Height="80" StrokeThickness="5" Visibility="Collapsed"/>







, .

Canvas Tap:



public MainPage() { ... VideoCanvas.Tap += new EventHandler<GestureEventArgs>(videoCanvas_Tap); ... }







. API- , VideoCanvas



, , .



, . , , , .



, , , , .



private async void videoCanvas_Tap(object sender, GestureEventArgs e) { System.Windows.Point uiTapPoint = e.GetPosition(VideoCanvas); if (PhotoCaptureDevice.IsFocusRegionSupported(_dataContext.Device.SensorLocation) && _focusSemaphore.WaitOne(0)) { // . Windows.Foundation.Point tapPoint = new Windows.Foundation.Point(uiTapPoint.X, uiTapPoint.Y); double xRatio = VideoCanvas.ActualWidth / _dataContext.Device.PreviewResolution.Width; double yRatio = VideoCanvas.ActualHeight / _dataContext.Device.PreviewResolution.Height; // , Windows.Foundation.Point displayOrigin = new Windows.Foundation.Point( tapPoint.X - _focusRegionSize.Width / 2, tapPoint.Y - _focusRegionSize.Height / 2); // canvas Windows.Foundation.Point viewFinderOrigin = new Windows.Foundation.Point( displayOrigin.X / xRatio, displayOrigin.Y / yRatio); Windows.Foundation.Rect focusrect = new Windows.Foundation.Rect( viewFinderOrigin, _focusRegionSize); // Windows.Foundation.Rect viewPortRect = new Windows.Foundation.Rect( 0, 0, _dataContext.Device.PreviewResolution.Width, _dataContext.Device.PreviewResolution.Height); focusrect.Intersect(viewPortRect); _dataContext.Device.FocusRegion = focusrect; // FocusIndicator.SetValue(Shape.StrokeProperty, _notFocusedBrush); FocusIndicator.SetValue(Canvas.LeftProperty, uiTapPoint.X - _focusRegionSize.Width / 2); FocusIndicator.SetValue(Canvas.TopProperty, uiTapPoint.Y - _focusRegionSize.Height / 2); FocusIndicator.SetValue(Canvas.VisibilityProperty, Visibility.Visible); CameraFocusStatus status = await _dataContext.Device.FocusAsync(); if (status == CameraFocusStatus.Locked) { FocusIndicator.SetValue(Shape.StrokeProperty, _focusedBrush); _manuallyFocused = true; _dataContext.Device.SetProperty( KnownCameraPhotoProperties.LockedAutoFocusParameters, AutoFocusParameters.Exposure & AutoFocusParameters.Focus & AutoFocusParameters.WhiteBalance); } else { _manuallyFocused = false; _dataContext.Device.SetProperty( KnownCameraPhotoProperties.LockedAutoFocusParameters, AutoFocusParameters.None); } _focusSemaphore.Release(); } }







, . FocusAsync



, , . , WaitOne



, , , false



— , .





, «», Lens Picker. «» , . Lens Picker, XML App:



<Extensions> <Extension ExtensionName="Camera_Capture_App" ConsumerId="{5B04B775-356B-4AA0-AAF8-6491FFEA5631]" TaskId="_default" /> </Extensions>







, Lens Picker, . , Lens Picker Assets



. , Lens design guidelines for Windows Phone .



Maps API.
























 static IReadOnlyList 
      

object GetProperty(Guid propertyId)






void SetProperty(Guid propertyId, object value)







— , .



static bool IsFocusSupported(CameraSensorLocation sensor)





static bool IsFocusRegionSupported(CameraSensorLocation sensor)





IAsyncOperation FocusAsync()

• IAsyncOperation ResetFocusAsync()



— .



• static IReadOnlyList GetAvailablePreviewResolutions()

• static IReadOnlyList GetAvailableCaptureResolutions()

• IAsyncAction SetPreviewResolutionAsync(Size value)






IAsyncAction SetCaptureResolutionAsync(Size value)







— .



event TypedEventHandler<ICameraCaptureDevice, Object> PreviewFrameAvailable





void GetPreviewBufferArgb(out int[] pixels)





void GetPreviewBufferY(out byte[] pixels)





void GetPreviewBufferYCbCr(out byte[] pixels)







— .



CameraCaptureSequence CreateCaptureSequence(uint numberOfFrames)





IAsyncAction PrepareCaptureSequenceAsync(CameraCaptureSequence sequence)







— . . API . GUID. , .

, ID_CAP_ISV_CAMERA



WMAppManifest.xml . ID_CAP_MEDIALIB_PHOTO



.



Lumia

Nokia Lumia 820 920.





Camera Explorer — , PhotoCaptureDevice



. , .







, Camera Explorer.







Windows Phone DataContext



, Settings



PhotoCaptureDevice



.

PhotoCaptureDevice



DataContext, , , PhotoCaptureDevice



, , MainPage, .



Camera Explorer .

, PhotoCaptureDevice , Camera Explorer. , , . .



DataContext, , .



... class DataContext : INotifyPropertyChanged { ... public static DataContext Singleton { ... } public ObservableCollection<Parameter> Parameters { ... } public PhotoCaptureDevice Device { ... } public MemoryStream ImageStream { ... } }









, PhotoCaptureDevice



. MainPage xaml Canvas



VideoBrush



, .



<phone:PhoneApplicationPage x:Class="CameraExplorer.MainPage" ... > ... <Grid x:Name="LayoutRoot" ... > ... <Grid x:Name="ContentPanel" ... > <Canvas x:Name="VideoCanvas"> <Canvas.Background> <VideoBrush x:Name="videoBrush"/> </Canvas.Background> </Canvas> ... </Grid> </Grid> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar> <shell:ApplicationBarIconButton Text="capture" Click="captureButton_Click" ... /> ... </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> ... </phone:PhoneApplicationPage>







C# MainPage PhotoCaptureDevice



InitializeCamera



, DataContext. , XAML, , .



... public partial class MainPage : PhoneApplicationPage { private CameraExplorer.DataContext _dataContext = CameraExplorer.DataContext.Singleton; ... protected async override void OnNavigatedTo(NavigationEventArgs e) { if (_dataContext.Device == null) { ... await InitializeCamera(CameraSensorLocation.Back); ... } videoBrush.RelativeTransform = new CompositeTransform() { CenterX = 0.5, CenterY = 0.5, Rotation = _dataContext.Device.SensorLocation == CameraSensorLocation.Back ? _dataContext.Device.SensorRotationInDegrees : - _dataContext.Device.SensorRotationInDegrees }; videoBrush.SetSource(_dataContext.Device); ... } 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 void captureButton_Click(object sender, EventArgs e) { if (!_manuallyFocused) { await AutoFocus(); } await Capture(); } private async Task AutoFocus() { if (!_capturing && PhotoCaptureDevice.IsFocusSupported(_dataContext.Device.SensorLocation)) { ... await _dataContext.Device.FocusAsync(); ... _capturing = false; } } private async Task Capture() { if (!_capturing) { _capturing = true; MemoryStream stream = new MemoryStream(); CameraCaptureSequence sequence = _dataContext.Device.CreateCaptureSequence(1); sequence.Frames[0].CaptureStream = stream.AsOutputStream(); await _dataContext.Device.PrepareCaptureSequenceAsync(sequence); await sequence.StartCaptureAsync(); _dataContext.ImageStream = stream; ... } ... } ... }









. Camera Explorer , XAML Image BitmapImage



. , , , void MediaLibrary.SavePictureToCameraRoll(string name, Stream source)



, .



<phone:PhoneApplicationPage x:Class="CameraExplorer.PreviewPage" ... > ... <Grid x:Name="LayoutRoot" ... > ... <Grid x:Name="ContentPanel" ... > <Image x:Name="image" Stretch="UniformToFill"/> </Grid> </Grid> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar> <shell:ApplicationBarIconButton Text="save" Click="saveButton_Click" ... /> </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> ... </phone:PhoneApplicationPage>







... public partial class PreviewPage : PhoneApplicationPage { private CameraExplorer.DataContext _dataContext = CameraExplorer.DataContext.Singleton; private BitmapImage _bitmap = new BitmapImage(); protected override void OnNavigatedTo(NavigationEventArgs e) { ... _bitmap.SetSource(_dataContext.ImageStream); image.Source = _bitmap; ... } private void saveButton_Click(object sender, EventArgs e) { try { _dataContext.ImageStream.Position = 0; MediaLibrary library = new MediaLibrary(); library.SavePictureToCameraRoll("CameraExplorer_" + DateTime.Now.ToString() + ".jpg", _dataContext.ImageStream); } catch (Exception) { ... } ... } }







Camera Explorer , ArrayParameters



RangeParameters



, Parameters



. , , ComboBox



, Slider



Text



. , .

Parameter



, .



... public abstract class Parameter : INotifyPropertyChanged { ... protected Parameter(PhotoCaptureDevice device, string name) { ... } public PhotoCaptureDevice Device { ... } public string Name { ... } public bool Supported { ... } public abstract void Refresh(); ... }







, . _propertyId



, static CameraCapturePropertyRange PhotoCaptureDevice.GetSupportedPropertyRange(CameraSensorLocation sensor, Guid propertyId)



. object PhotoCaptureDevice.GetProperty(Guid propertyId)



. void PhotoCaptureDevice.SetProperty(Guid propertyId, object value)



.



... public abstract class RangeParameter<T> : Parameter { private Guid _propertyId; private T _value; ... protected RangeParameter(PhotoCaptureDevice device, Guid propertyId, string name) : base(device, name) { ... } public override void Refresh() { try { CameraCapturePropertyRange range = PhotoCaptureDevice.GetSupportedPropertyRange( Device.SensorLocation, _propertyId); if (range == null) { Supported = false; } else { Minimum = (T)range.Min; Maximum = (T)range.Max; _value = (T)Device.GetProperty(_propertyId); Supported = true; } } catch (Exception) { Supported = false; } ... } public T Minimum { ... } public T Maximum { ... } public T Value { ... set { if (!_value.Equals(value)) { try { Device.SetProperty(_propertyId, (T)value); _value = value; ... } catch (Exception) { ... } } } } ... }







ExposureCompensationParameter



, Guid RangeParameter



KnownCameraPhotoProperties.ExposureCompensation



, — , . , Int32



, .



... public class ExposureCompensationParameter : RangeParameter<Int32> { public ExposureCompensationParameter(PhotoCaptureDevice device) : base(device, KnownCameraPhotoProperties.ExposureCompensation, "Exposure compensation") { } ... }







Camera Explorer ArrayParameter



. . — void PopulateOptions()



void SetOption(ArrayParameterOption option)



, .



... public class ArrayParameterOption { ... public ArrayParameterOption(dynamic value, string name) { ... } public dynamic Value { ... } public string Name { ... } ... } public abstract class ArrayParameter : Parameter, IReadOnlyCollection<ArrayParameterOption> { private List<ArrayParameterOption> _options = new List<ArrayParameterOption>(); private ArrayParameterOption _selectedOption; ... public ArrayParameter(PhotoCaptureDevice device, string name) : base(device, name) { ... } public override void Refresh() { ... _options.Clear(); _selectedOption = null; try { PopulateOptions(); Supported = _options.Count > 0; } catch (Exception) { Supported = false; } ... } protected List<ArrayParameterOption> Options { ... } public ArrayParameterOption SelectedOption { ... set { if (_selectedOption != value) { ... if (_selectedOption != null)) { SetOption(value); } _selectedOption = value; } } } protected abstract void PopulateOptions(); protected abstract void SetOption(ArrayParameterOption option); ... }







, , , . void PopulateOptions()



, , ArrayParameterOption



SelectedOption



, void SetOption(ArrayParameterOption option)



. , static IReadOnlyList , KnownCameraPhotoProperties.SceneMode



object PhotoCaptureDevice.GetProperty(Guid propertyId)



. void PhotoCaptureDevice.SetProperty(Guid propertyId, object value)



.



... public class SceneModeParameter : ArrayParameter { public SceneModeParameter(PhotoCaptureDevice device) : base(device, KnownCameraPhotoProperties.SceneMode, "Scene mode") { } protected override void PopulateOptions() { IReadOnlyList<object> supportedValues = PhotoCaptureDevice.GetSupportedPropertyValues( Device.SensorLocation, PropertyId); object value = Device.GetProperty(PropertyId); foreach (dynamic i in supportedValues) { CameraSceneMode csm = (CameraSceneMode)i; ArrayParameterOption option = new ArrayParameterOption(csm, csm.ToString()); Options.Add(option); if (i.Equals(value)) { SelectedOption = option; } } } protected override void SetOption(ArrayParameterOption option) { Device.SetProperty(PropertyId, option.Value); } ... }







Tap-to-focus

«». Tap-to-focus , , , . , Tap-to-focus .



Rectangle



Canvas



, :



<Rectangle x:Name="FocusIndicator" Stroke="Red" Opacity="0.7" Width="80" Height="80" StrokeThickness="5" Visibility="Collapsed"/>







, .

Canvas Tap:



public MainPage() { ... VideoCanvas.Tap += new EventHandler<GestureEventArgs>(videoCanvas_Tap); ... }







. API- , VideoCanvas



, , .



, . , , , .



, , , , .



private async void videoCanvas_Tap(object sender, GestureEventArgs e) { System.Windows.Point uiTapPoint = e.GetPosition(VideoCanvas); if (PhotoCaptureDevice.IsFocusRegionSupported(_dataContext.Device.SensorLocation) && _focusSemaphore.WaitOne(0)) { // . Windows.Foundation.Point tapPoint = new Windows.Foundation.Point(uiTapPoint.X, uiTapPoint.Y); double xRatio = VideoCanvas.ActualWidth / _dataContext.Device.PreviewResolution.Width; double yRatio = VideoCanvas.ActualHeight / _dataContext.Device.PreviewResolution.Height; // , Windows.Foundation.Point displayOrigin = new Windows.Foundation.Point( tapPoint.X - _focusRegionSize.Width / 2, tapPoint.Y - _focusRegionSize.Height / 2); // canvas Windows.Foundation.Point viewFinderOrigin = new Windows.Foundation.Point( displayOrigin.X / xRatio, displayOrigin.Y / yRatio); Windows.Foundation.Rect focusrect = new Windows.Foundation.Rect( viewFinderOrigin, _focusRegionSize); // Windows.Foundation.Rect viewPortRect = new Windows.Foundation.Rect( 0, 0, _dataContext.Device.PreviewResolution.Width, _dataContext.Device.PreviewResolution.Height); focusrect.Intersect(viewPortRect); _dataContext.Device.FocusRegion = focusrect; // FocusIndicator.SetValue(Shape.StrokeProperty, _notFocusedBrush); FocusIndicator.SetValue(Canvas.LeftProperty, uiTapPoint.X - _focusRegionSize.Width / 2); FocusIndicator.SetValue(Canvas.TopProperty, uiTapPoint.Y - _focusRegionSize.Height / 2); FocusIndicator.SetValue(Canvas.VisibilityProperty, Visibility.Visible); CameraFocusStatus status = await _dataContext.Device.FocusAsync(); if (status == CameraFocusStatus.Locked) { FocusIndicator.SetValue(Shape.StrokeProperty, _focusedBrush); _manuallyFocused = true; _dataContext.Device.SetProperty( KnownCameraPhotoProperties.LockedAutoFocusParameters, AutoFocusParameters.Exposure & AutoFocusParameters.Focus & AutoFocusParameters.WhiteBalance); } else { _manuallyFocused = false; _dataContext.Device.SetProperty( KnownCameraPhotoProperties.LockedAutoFocusParameters, AutoFocusParameters.None); } _focusSemaphore.Release(); } }







, . FocusAsync



, , . , WaitOne



, , , false



— , .





, «», Lens Picker. «» , . Lens Picker, XML App:



<Extensions> <Extension ExtensionName="Camera_Capture_App" ConsumerId="{5B04B775-356B-4AA0-AAF8-6491FFEA5631]" TaskId="_default" /> </Extensions>







, Lens Picker, . , Lens Picker Assets



. , Lens design guidelines for Windows Phone .



Maps API.
























static IReadOnlyList

• object GetProperty(Guid propertyId)






void SetProperty(Guid propertyId, object value)







— , .



static bool IsFocusSupported(CameraSensorLocation sensor)





static bool IsFocusRegionSupported(CameraSensorLocation sensor)





IAsyncOperation FocusAsync()

• IAsyncOperation ResetFocusAsync()



— .



• static IReadOnlyList GetAvailablePreviewResolutions()

• static IReadOnlyList GetAvailableCaptureResolutions()

• IAsyncAction SetPreviewResolutionAsync(Size value)






IAsyncAction SetCaptureResolutionAsync(Size value)







— .



event TypedEventHandler<ICameraCaptureDevice, Object> PreviewFrameAvailable





void GetPreviewBufferArgb(out int[] pixels)





void GetPreviewBufferY(out byte[] pixels)





void GetPreviewBufferYCbCr(out byte[] pixels)







— .



CameraCaptureSequence CreateCaptureSequence(uint numberOfFrames)





IAsyncAction PrepareCaptureSequenceAsync(CameraCaptureSequence sequence)







— . . API . GUID. , .

, ID_CAP_ISV_CAMERA



WMAppManifest.xml . ID_CAP_MEDIALIB_PHOTO



.



Lumia

Nokia Lumia 820 920.





Camera Explorer — , PhotoCaptureDevice



. , .







, Camera Explorer.







Windows Phone DataContext



, Settings



PhotoCaptureDevice



.

PhotoCaptureDevice



DataContext, , , PhotoCaptureDevice



, , MainPage, .



Camera Explorer .

, PhotoCaptureDevice , Camera Explorer. , , . .



DataContext, , .



... class DataContext : INotifyPropertyChanged { ... public static DataContext Singleton { ... } public ObservableCollection<Parameter> Parameters { ... } public PhotoCaptureDevice Device { ... } public MemoryStream ImageStream { ... } }









, PhotoCaptureDevice



. MainPage xaml Canvas



VideoBrush



, .



<phone:PhoneApplicationPage x:Class="CameraExplorer.MainPage" ... > ... <Grid x:Name="LayoutRoot" ... > ... <Grid x:Name="ContentPanel" ... > <Canvas x:Name="VideoCanvas"> <Canvas.Background> <VideoBrush x:Name="videoBrush"/> </Canvas.Background> </Canvas> ... </Grid> </Grid> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar> <shell:ApplicationBarIconButton Text="capture" Click="captureButton_Click" ... /> ... </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> ... </phone:PhoneApplicationPage>







C# MainPage PhotoCaptureDevice



InitializeCamera



, DataContext. , XAML, , .



... public partial class MainPage : PhoneApplicationPage { private CameraExplorer.DataContext _dataContext = CameraExplorer.DataContext.Singleton; ... protected async override void OnNavigatedTo(NavigationEventArgs e) { if (_dataContext.Device == null) { ... await InitializeCamera(CameraSensorLocation.Back); ... } videoBrush.RelativeTransform = new CompositeTransform() { CenterX = 0.5, CenterY = 0.5, Rotation = _dataContext.Device.SensorLocation == CameraSensorLocation.Back ? _dataContext.Device.SensorRotationInDegrees : - _dataContext.Device.SensorRotationInDegrees }; videoBrush.SetSource(_dataContext.Device); ... } 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 void captureButton_Click(object sender, EventArgs e) { if (!_manuallyFocused) { await AutoFocus(); } await Capture(); } private async Task AutoFocus() { if (!_capturing && PhotoCaptureDevice.IsFocusSupported(_dataContext.Device.SensorLocation)) { ... await _dataContext.Device.FocusAsync(); ... _capturing = false; } } private async Task Capture() { if (!_capturing) { _capturing = true; MemoryStream stream = new MemoryStream(); CameraCaptureSequence sequence = _dataContext.Device.CreateCaptureSequence(1); sequence.Frames[0].CaptureStream = stream.AsOutputStream(); await _dataContext.Device.PrepareCaptureSequenceAsync(sequence); await sequence.StartCaptureAsync(); _dataContext.ImageStream = stream; ... } ... } ... }









. Camera Explorer , XAML Image BitmapImage



. , , , void MediaLibrary.SavePictureToCameraRoll(string name, Stream source)



, .



<phone:PhoneApplicationPage x:Class="CameraExplorer.PreviewPage" ... > ... <Grid x:Name="LayoutRoot" ... > ... <Grid x:Name="ContentPanel" ... > <Image x:Name="image" Stretch="UniformToFill"/> </Grid> </Grid> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar> <shell:ApplicationBarIconButton Text="save" Click="saveButton_Click" ... /> </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> ... </phone:PhoneApplicationPage>







... public partial class PreviewPage : PhoneApplicationPage { private CameraExplorer.DataContext _dataContext = CameraExplorer.DataContext.Singleton; private BitmapImage _bitmap = new BitmapImage(); protected override void OnNavigatedTo(NavigationEventArgs e) { ... _bitmap.SetSource(_dataContext.ImageStream); image.Source = _bitmap; ... } private void saveButton_Click(object sender, EventArgs e) { try { _dataContext.ImageStream.Position = 0; MediaLibrary library = new MediaLibrary(); library.SavePictureToCameraRoll("CameraExplorer_" + DateTime.Now.ToString() + ".jpg", _dataContext.ImageStream); } catch (Exception) { ... } ... } }







Camera Explorer , ArrayParameters



RangeParameters



, Parameters



. , , ComboBox



, Slider



Text



. , .

Parameter



, .



... public abstract class Parameter : INotifyPropertyChanged { ... protected Parameter(PhotoCaptureDevice device, string name) { ... } public PhotoCaptureDevice Device { ... } public string Name { ... } public bool Supported { ... } public abstract void Refresh(); ... }







, . _propertyId



, static CameraCapturePropertyRange PhotoCaptureDevice.GetSupportedPropertyRange(CameraSensorLocation sensor, Guid propertyId)



. object PhotoCaptureDevice.GetProperty(Guid propertyId)



. void PhotoCaptureDevice.SetProperty(Guid propertyId, object value)



.



... public abstract class RangeParameter<T> : Parameter { private Guid _propertyId; private T _value; ... protected RangeParameter(PhotoCaptureDevice device, Guid propertyId, string name) : base(device, name) { ... } public override void Refresh() { try { CameraCapturePropertyRange range = PhotoCaptureDevice.GetSupportedPropertyRange( Device.SensorLocation, _propertyId); if (range == null) { Supported = false; } else { Minimum = (T)range.Min; Maximum = (T)range.Max; _value = (T)Device.GetProperty(_propertyId); Supported = true; } } catch (Exception) { Supported = false; } ... } public T Minimum { ... } public T Maximum { ... } public T Value { ... set { if (!_value.Equals(value)) { try { Device.SetProperty(_propertyId, (T)value); _value = value; ... } catch (Exception) { ... } } } } ... }







ExposureCompensationParameter



, Guid RangeParameter



KnownCameraPhotoProperties.ExposureCompensation



, — , . , Int32



, .



... public class ExposureCompensationParameter : RangeParameter<Int32> { public ExposureCompensationParameter(PhotoCaptureDevice device) : base(device, KnownCameraPhotoProperties.ExposureCompensation, "Exposure compensation") { } ... }







Camera Explorer ArrayParameter



. . — void PopulateOptions()



void SetOption(ArrayParameterOption option)



, .



... public class ArrayParameterOption { ... public ArrayParameterOption(dynamic value, string name) { ... } public dynamic Value { ... } public string Name { ... } ... } public abstract class ArrayParameter : Parameter, IReadOnlyCollection<ArrayParameterOption> { private List<ArrayParameterOption> _options = new List<ArrayParameterOption>(); private ArrayParameterOption _selectedOption; ... public ArrayParameter(PhotoCaptureDevice device, string name) : base(device, name) { ... } public override void Refresh() { ... _options.Clear(); _selectedOption = null; try { PopulateOptions(); Supported = _options.Count > 0; } catch (Exception) { Supported = false; } ... } protected List<ArrayParameterOption> Options { ... } public ArrayParameterOption SelectedOption { ... set { if (_selectedOption != value) { ... if (_selectedOption != null)) { SetOption(value); } _selectedOption = value; } } } protected abstract void PopulateOptions(); protected abstract void SetOption(ArrayParameterOption option); ... }







, , , . void PopulateOptions()



, , ArrayParameterOption



SelectedOption



, void SetOption(ArrayParameterOption option)



. , static IReadOnlyList , KnownCameraPhotoProperties.SceneMode



object PhotoCaptureDevice.GetProperty(Guid propertyId)



. void PhotoCaptureDevice.SetProperty(Guid propertyId, object value)



.



... public class SceneModeParameter : ArrayParameter { public SceneModeParameter(PhotoCaptureDevice device) : base(device, KnownCameraPhotoProperties.SceneMode, "Scene mode") { } protected override void PopulateOptions() { IReadOnlyList<object> supportedValues = PhotoCaptureDevice.GetSupportedPropertyValues( Device.SensorLocation, PropertyId); object value = Device.GetProperty(PropertyId); foreach (dynamic i in supportedValues) { CameraSceneMode csm = (CameraSceneMode)i; ArrayParameterOption option = new ArrayParameterOption(csm, csm.ToString()); Options.Add(option); if (i.Equals(value)) { SelectedOption = option; } } } protected override void SetOption(ArrayParameterOption option) { Device.SetProperty(PropertyId, option.Value); } ... }







Tap-to-focus

«». Tap-to-focus , , , . , Tap-to-focus .



Rectangle



Canvas



, :



<Rectangle x:Name="FocusIndicator" Stroke="Red" Opacity="0.7" Width="80" Height="80" StrokeThickness="5" Visibility="Collapsed"/>







, .

Canvas Tap:



public MainPage() { ... VideoCanvas.Tap += new EventHandler<GestureEventArgs>(videoCanvas_Tap); ... }







. API- , VideoCanvas



, , .



, . , , , .



, , , , .



private async void videoCanvas_Tap(object sender, GestureEventArgs e) { System.Windows.Point uiTapPoint = e.GetPosition(VideoCanvas); if (PhotoCaptureDevice.IsFocusRegionSupported(_dataContext.Device.SensorLocation) && _focusSemaphore.WaitOne(0)) { // . Windows.Foundation.Point tapPoint = new Windows.Foundation.Point(uiTapPoint.X, uiTapPoint.Y); double xRatio = VideoCanvas.ActualWidth / _dataContext.Device.PreviewResolution.Width; double yRatio = VideoCanvas.ActualHeight / _dataContext.Device.PreviewResolution.Height; // , Windows.Foundation.Point displayOrigin = new Windows.Foundation.Point( tapPoint.X - _focusRegionSize.Width / 2, tapPoint.Y - _focusRegionSize.Height / 2); // canvas Windows.Foundation.Point viewFinderOrigin = new Windows.Foundation.Point( displayOrigin.X / xRatio, displayOrigin.Y / yRatio); Windows.Foundation.Rect focusrect = new Windows.Foundation.Rect( viewFinderOrigin, _focusRegionSize); // Windows.Foundation.Rect viewPortRect = new Windows.Foundation.Rect( 0, 0, _dataContext.Device.PreviewResolution.Width, _dataContext.Device.PreviewResolution.Height); focusrect.Intersect(viewPortRect); _dataContext.Device.FocusRegion = focusrect; // FocusIndicator.SetValue(Shape.StrokeProperty, _notFocusedBrush); FocusIndicator.SetValue(Canvas.LeftProperty, uiTapPoint.X - _focusRegionSize.Width / 2); FocusIndicator.SetValue(Canvas.TopProperty, uiTapPoint.Y - _focusRegionSize.Height / 2); FocusIndicator.SetValue(Canvas.VisibilityProperty, Visibility.Visible); CameraFocusStatus status = await _dataContext.Device.FocusAsync(); if (status == CameraFocusStatus.Locked) { FocusIndicator.SetValue(Shape.StrokeProperty, _focusedBrush); _manuallyFocused = true; _dataContext.Device.SetProperty( KnownCameraPhotoProperties.LockedAutoFocusParameters, AutoFocusParameters.Exposure & AutoFocusParameters.Focus & AutoFocusParameters.WhiteBalance); } else { _manuallyFocused = false; _dataContext.Device.SetProperty( KnownCameraPhotoProperties.LockedAutoFocusParameters, AutoFocusParameters.None); } _focusSemaphore.Release(); } }







, . FocusAsync



, , . , WaitOne



, , , false



— , .





, «», Lens Picker. «» , . Lens Picker, XML App:



<Extensions> <Extension ExtensionName="Camera_Capture_App" ConsumerId="{5B04B775-356B-4AA0-AAF8-6491FFEA5631]" TaskId="_default" /> </Extensions>







, Lens Picker, . , Lens Picker Assets



. , Lens design guidelines for Windows Phone .



Maps API.
























 static IReadOnlyList 
      

object GetProperty(Guid propertyId)






void SetProperty(Guid propertyId, object value)







— , .



static bool IsFocusSupported(CameraSensorLocation sensor)





static bool IsFocusRegionSupported(CameraSensorLocation sensor)





IAsyncOperation FocusAsync()

• IAsyncOperation ResetFocusAsync()



— .



• static IReadOnlyList GetAvailablePreviewResolutions()

• static IReadOnlyList GetAvailableCaptureResolutions()

• IAsyncAction SetPreviewResolutionAsync(Size value)






IAsyncAction SetCaptureResolutionAsync(Size value)







— .



event TypedEventHandler<ICameraCaptureDevice, Object> PreviewFrameAvailable





void GetPreviewBufferArgb(out int[] pixels)





void GetPreviewBufferY(out byte[] pixels)





void GetPreviewBufferYCbCr(out byte[] pixels)







— .



CameraCaptureSequence CreateCaptureSequence(uint numberOfFrames)





IAsyncAction PrepareCaptureSequenceAsync(CameraCaptureSequence sequence)







— . . API . GUID. , .

, ID_CAP_ISV_CAMERA



WMAppManifest.xml . ID_CAP_MEDIALIB_PHOTO



.



Lumia

Nokia Lumia 820 920.





Camera Explorer — , PhotoCaptureDevice



. , .







, Camera Explorer.







Windows Phone DataContext



, Settings



PhotoCaptureDevice



.

PhotoCaptureDevice



DataContext, , , PhotoCaptureDevice



, , MainPage, .



Camera Explorer .

, PhotoCaptureDevice , Camera Explorer. , , . .



DataContext, , .



... class DataContext : INotifyPropertyChanged { ... public static DataContext Singleton { ... } public ObservableCollection<Parameter> Parameters { ... } public PhotoCaptureDevice Device { ... } public MemoryStream ImageStream { ... } }









, PhotoCaptureDevice



. MainPage xaml Canvas



VideoBrush



, .



<phone:PhoneApplicationPage x:Class="CameraExplorer.MainPage" ... > ... <Grid x:Name="LayoutRoot" ... > ... <Grid x:Name="ContentPanel" ... > <Canvas x:Name="VideoCanvas"> <Canvas.Background> <VideoBrush x:Name="videoBrush"/> </Canvas.Background> </Canvas> ... </Grid> </Grid> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar> <shell:ApplicationBarIconButton Text="capture" Click="captureButton_Click" ... /> ... </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> ... </phone:PhoneApplicationPage>







C# MainPage PhotoCaptureDevice



InitializeCamera



, DataContext. , XAML, , .



... public partial class MainPage : PhoneApplicationPage { private CameraExplorer.DataContext _dataContext = CameraExplorer.DataContext.Singleton; ... protected async override void OnNavigatedTo(NavigationEventArgs e) { if (_dataContext.Device == null) { ... await InitializeCamera(CameraSensorLocation.Back); ... } videoBrush.RelativeTransform = new CompositeTransform() { CenterX = 0.5, CenterY = 0.5, Rotation = _dataContext.Device.SensorLocation == CameraSensorLocation.Back ? _dataContext.Device.SensorRotationInDegrees : - _dataContext.Device.SensorRotationInDegrees }; videoBrush.SetSource(_dataContext.Device); ... } 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 void captureButton_Click(object sender, EventArgs e) { if (!_manuallyFocused) { await AutoFocus(); } await Capture(); } private async Task AutoFocus() { if (!_capturing && PhotoCaptureDevice.IsFocusSupported(_dataContext.Device.SensorLocation)) { ... await _dataContext.Device.FocusAsync(); ... _capturing = false; } } private async Task Capture() { if (!_capturing) { _capturing = true; MemoryStream stream = new MemoryStream(); CameraCaptureSequence sequence = _dataContext.Device.CreateCaptureSequence(1); sequence.Frames[0].CaptureStream = stream.AsOutputStream(); await _dataContext.Device.PrepareCaptureSequenceAsync(sequence); await sequence.StartCaptureAsync(); _dataContext.ImageStream = stream; ... } ... } ... }









. Camera Explorer , XAML Image BitmapImage



. , , , void MediaLibrary.SavePictureToCameraRoll(string name, Stream source)



, .



<phone:PhoneApplicationPage x:Class="CameraExplorer.PreviewPage" ... > ... <Grid x:Name="LayoutRoot" ... > ... <Grid x:Name="ContentPanel" ... > <Image x:Name="image" Stretch="UniformToFill"/> </Grid> </Grid> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar> <shell:ApplicationBarIconButton Text="save" Click="saveButton_Click" ... /> </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> ... </phone:PhoneApplicationPage>







... public partial class PreviewPage : PhoneApplicationPage { private CameraExplorer.DataContext _dataContext = CameraExplorer.DataContext.Singleton; private BitmapImage _bitmap = new BitmapImage(); protected override void OnNavigatedTo(NavigationEventArgs e) { ... _bitmap.SetSource(_dataContext.ImageStream); image.Source = _bitmap; ... } private void saveButton_Click(object sender, EventArgs e) { try { _dataContext.ImageStream.Position = 0; MediaLibrary library = new MediaLibrary(); library.SavePictureToCameraRoll("CameraExplorer_" + DateTime.Now.ToString() + ".jpg", _dataContext.ImageStream); } catch (Exception) { ... } ... } }







Camera Explorer , ArrayParameters



RangeParameters



, Parameters



. , , ComboBox



, Slider



Text



. , .

Parameter



, .



... public abstract class Parameter : INotifyPropertyChanged { ... protected Parameter(PhotoCaptureDevice device, string name) { ... } public PhotoCaptureDevice Device { ... } public string Name { ... } public bool Supported { ... } public abstract void Refresh(); ... }







, . _propertyId



, static CameraCapturePropertyRange PhotoCaptureDevice.GetSupportedPropertyRange(CameraSensorLocation sensor, Guid propertyId)



. object PhotoCaptureDevice.GetProperty(Guid propertyId)



. void PhotoCaptureDevice.SetProperty(Guid propertyId, object value)



.



... public abstract class RangeParameter<T> : Parameter { private Guid _propertyId; private T _value; ... protected RangeParameter(PhotoCaptureDevice device, Guid propertyId, string name) : base(device, name) { ... } public override void Refresh() { try { CameraCapturePropertyRange range = PhotoCaptureDevice.GetSupportedPropertyRange( Device.SensorLocation, _propertyId); if (range == null) { Supported = false; } else { Minimum = (T)range.Min; Maximum = (T)range.Max; _value = (T)Device.GetProperty(_propertyId); Supported = true; } } catch (Exception) { Supported = false; } ... } public T Minimum { ... } public T Maximum { ... } public T Value { ... set { if (!_value.Equals(value)) { try { Device.SetProperty(_propertyId, (T)value); _value = value; ... } catch (Exception) { ... } } } } ... }







ExposureCompensationParameter



, Guid RangeParameter



KnownCameraPhotoProperties.ExposureCompensation



, — , . , Int32



, .



... public class ExposureCompensationParameter : RangeParameter<Int32> { public ExposureCompensationParameter(PhotoCaptureDevice device) : base(device, KnownCameraPhotoProperties.ExposureCompensation, "Exposure compensation") { } ... }







Camera Explorer ArrayParameter



. . — void PopulateOptions()



void SetOption(ArrayParameterOption option)



, .



... public class ArrayParameterOption { ... public ArrayParameterOption(dynamic value, string name) { ... } public dynamic Value { ... } public string Name { ... } ... } public abstract class ArrayParameter : Parameter, IReadOnlyCollection<ArrayParameterOption> { private List<ArrayParameterOption> _options = new List<ArrayParameterOption>(); private ArrayParameterOption _selectedOption; ... public ArrayParameter(PhotoCaptureDevice device, string name) : base(device, name) { ... } public override void Refresh() { ... _options.Clear(); _selectedOption = null; try { PopulateOptions(); Supported = _options.Count > 0; } catch (Exception) { Supported = false; } ... } protected List<ArrayParameterOption> Options { ... } public ArrayParameterOption SelectedOption { ... set { if (_selectedOption != value) { ... if (_selectedOption != null)) { SetOption(value); } _selectedOption = value; } } } protected abstract void PopulateOptions(); protected abstract void SetOption(ArrayParameterOption option); ... }







, , , . void PopulateOptions()



, , ArrayParameterOption



SelectedOption



, void SetOption(ArrayParameterOption option)



. , static IReadOnlyList , KnownCameraPhotoProperties.SceneMode



object PhotoCaptureDevice.GetProperty(Guid propertyId)



. void PhotoCaptureDevice.SetProperty(Guid propertyId, object value)



.



... public class SceneModeParameter : ArrayParameter { public SceneModeParameter(PhotoCaptureDevice device) : base(device, KnownCameraPhotoProperties.SceneMode, "Scene mode") { } protected override void PopulateOptions() { IReadOnlyList<object> supportedValues = PhotoCaptureDevice.GetSupportedPropertyValues( Device.SensorLocation, PropertyId); object value = Device.GetProperty(PropertyId); foreach (dynamic i in supportedValues) { CameraSceneMode csm = (CameraSceneMode)i; ArrayParameterOption option = new ArrayParameterOption(csm, csm.ToString()); Options.Add(option); if (i.Equals(value)) { SelectedOption = option; } } } protected override void SetOption(ArrayParameterOption option) { Device.SetProperty(PropertyId, option.Value); } ... }







Tap-to-focus

«». Tap-to-focus , , , . , Tap-to-focus .



Rectangle



Canvas



, :



<Rectangle x:Name="FocusIndicator" Stroke="Red" Opacity="0.7" Width="80" Height="80" StrokeThickness="5" Visibility="Collapsed"/>







, .

Canvas Tap:



public MainPage() { ... VideoCanvas.Tap += new EventHandler<GestureEventArgs>(videoCanvas_Tap); ... }







. API- , VideoCanvas



, , .



, . , , , .



, , , , .



private async void videoCanvas_Tap(object sender, GestureEventArgs e) { System.Windows.Point uiTapPoint = e.GetPosition(VideoCanvas); if (PhotoCaptureDevice.IsFocusRegionSupported(_dataContext.Device.SensorLocation) && _focusSemaphore.WaitOne(0)) { // . Windows.Foundation.Point tapPoint = new Windows.Foundation.Point(uiTapPoint.X, uiTapPoint.Y); double xRatio = VideoCanvas.ActualWidth / _dataContext.Device.PreviewResolution.Width; double yRatio = VideoCanvas.ActualHeight / _dataContext.Device.PreviewResolution.Height; // , Windows.Foundation.Point displayOrigin = new Windows.Foundation.Point( tapPoint.X - _focusRegionSize.Width / 2, tapPoint.Y - _focusRegionSize.Height / 2); // canvas Windows.Foundation.Point viewFinderOrigin = new Windows.Foundation.Point( displayOrigin.X / xRatio, displayOrigin.Y / yRatio); Windows.Foundation.Rect focusrect = new Windows.Foundation.Rect( viewFinderOrigin, _focusRegionSize); // Windows.Foundation.Rect viewPortRect = new Windows.Foundation.Rect( 0, 0, _dataContext.Device.PreviewResolution.Width, _dataContext.Device.PreviewResolution.Height); focusrect.Intersect(viewPortRect); _dataContext.Device.FocusRegion = focusrect; // FocusIndicator.SetValue(Shape.StrokeProperty, _notFocusedBrush); FocusIndicator.SetValue(Canvas.LeftProperty, uiTapPoint.X - _focusRegionSize.Width / 2); FocusIndicator.SetValue(Canvas.TopProperty, uiTapPoint.Y - _focusRegionSize.Height / 2); FocusIndicator.SetValue(Canvas.VisibilityProperty, Visibility.Visible); CameraFocusStatus status = await _dataContext.Device.FocusAsync(); if (status == CameraFocusStatus.Locked) { FocusIndicator.SetValue(Shape.StrokeProperty, _focusedBrush); _manuallyFocused = true; _dataContext.Device.SetProperty( KnownCameraPhotoProperties.LockedAutoFocusParameters, AutoFocusParameters.Exposure & AutoFocusParameters.Focus & AutoFocusParameters.WhiteBalance); } else { _manuallyFocused = false; _dataContext.Device.SetProperty( KnownCameraPhotoProperties.LockedAutoFocusParameters, AutoFocusParameters.None); } _focusSemaphore.Release(); } }







, . FocusAsync



, , . , WaitOne



, , , false



— , .





, «», Lens Picker. «» , . Lens Picker, XML App:



<Extensions> <Extension ExtensionName="Camera_Capture_App" ConsumerId="{5B04B775-356B-4AA0-AAF8-6491FFEA5631]" TaskId="_default" /> </Extensions>







, Lens Picker, . , Lens Picker Assets



. , Lens design guidelines for Windows Phone .



Maps API.
























static IReadOnlyList

• object GetProperty(Guid propertyId)






void SetProperty(Guid propertyId, object value)







— , .



static bool IsFocusSupported(CameraSensorLocation sensor)





static bool IsFocusRegionSupported(CameraSensorLocation sensor)





IAsyncOperation FocusAsync()

• IAsyncOperation ResetFocusAsync()



— .



• static IReadOnlyList GetAvailablePreviewResolutions()

• static IReadOnlyList GetAvailableCaptureResolutions()

• IAsyncAction SetPreviewResolutionAsync(Size value)






IAsyncAction SetCaptureResolutionAsync(Size value)







— .



event TypedEventHandler<ICameraCaptureDevice, Object> PreviewFrameAvailable





void GetPreviewBufferArgb(out int[] pixels)





void GetPreviewBufferY(out byte[] pixels)





void GetPreviewBufferYCbCr(out byte[] pixels)







— .



CameraCaptureSequence CreateCaptureSequence(uint numberOfFrames)





IAsyncAction PrepareCaptureSequenceAsync(CameraCaptureSequence sequence)







— . . API . GUID. , .

, ID_CAP_ISV_CAMERA



WMAppManifest.xml . ID_CAP_MEDIALIB_PHOTO



.



Lumia

Nokia Lumia 820 920.





Camera Explorer — , PhotoCaptureDevice



. , .







, Camera Explorer.







Windows Phone DataContext



, Settings



PhotoCaptureDevice



.

PhotoCaptureDevice



DataContext, , , PhotoCaptureDevice



, , MainPage, .



Camera Explorer .

, PhotoCaptureDevice , Camera Explorer. , , . .



DataContext, , .



... class DataContext : INotifyPropertyChanged { ... public static DataContext Singleton { ... } public ObservableCollection<Parameter> Parameters { ... } public PhotoCaptureDevice Device { ... } public MemoryStream ImageStream { ... } }









, PhotoCaptureDevice



. MainPage xaml Canvas



VideoBrush



, .



<phone:PhoneApplicationPage x:Class="CameraExplorer.MainPage" ... > ... <Grid x:Name="LayoutRoot" ... > ... <Grid x:Name="ContentPanel" ... > <Canvas x:Name="VideoCanvas"> <Canvas.Background> <VideoBrush x:Name="videoBrush"/> </Canvas.Background> </Canvas> ... </Grid> </Grid> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar> <shell:ApplicationBarIconButton Text="capture" Click="captureButton_Click" ... /> ... </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> ... </phone:PhoneApplicationPage>







C# MainPage PhotoCaptureDevice



InitializeCamera



, DataContext. , XAML, , .



... public partial class MainPage : PhoneApplicationPage { private CameraExplorer.DataContext _dataContext = CameraExplorer.DataContext.Singleton; ... protected async override void OnNavigatedTo(NavigationEventArgs e) { if (_dataContext.Device == null) { ... await InitializeCamera(CameraSensorLocation.Back); ... } videoBrush.RelativeTransform = new CompositeTransform() { CenterX = 0.5, CenterY = 0.5, Rotation = _dataContext.Device.SensorLocation == CameraSensorLocation.Back ? _dataContext.Device.SensorRotationInDegrees : - _dataContext.Device.SensorRotationInDegrees }; videoBrush.SetSource(_dataContext.Device); ... } 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 void captureButton_Click(object sender, EventArgs e) { if (!_manuallyFocused) { await AutoFocus(); } await Capture(); } private async Task AutoFocus() { if (!_capturing && PhotoCaptureDevice.IsFocusSupported(_dataContext.Device.SensorLocation)) { ... await _dataContext.Device.FocusAsync(); ... _capturing = false; } } private async Task Capture() { if (!_capturing) { _capturing = true; MemoryStream stream = new MemoryStream(); CameraCaptureSequence sequence = _dataContext.Device.CreateCaptureSequence(1); sequence.Frames[0].CaptureStream = stream.AsOutputStream(); await _dataContext.Device.PrepareCaptureSequenceAsync(sequence); await sequence.StartCaptureAsync(); _dataContext.ImageStream = stream; ... } ... } ... }









. Camera Explorer , XAML Image BitmapImage



. , , , void MediaLibrary.SavePictureToCameraRoll(string name, Stream source)



, .



<phone:PhoneApplicationPage x:Class="CameraExplorer.PreviewPage" ... > ... <Grid x:Name="LayoutRoot" ... > ... <Grid x:Name="ContentPanel" ... > <Image x:Name="image" Stretch="UniformToFill"/> </Grid> </Grid> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar> <shell:ApplicationBarIconButton Text="save" Click="saveButton_Click" ... /> </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> ... </phone:PhoneApplicationPage>







... public partial class PreviewPage : PhoneApplicationPage { private CameraExplorer.DataContext _dataContext = CameraExplorer.DataContext.Singleton; private BitmapImage _bitmap = new BitmapImage(); protected override void OnNavigatedTo(NavigationEventArgs e) { ... _bitmap.SetSource(_dataContext.ImageStream); image.Source = _bitmap; ... } private void saveButton_Click(object sender, EventArgs e) { try { _dataContext.ImageStream.Position = 0; MediaLibrary library = new MediaLibrary(); library.SavePictureToCameraRoll("CameraExplorer_" + DateTime.Now.ToString() + ".jpg", _dataContext.ImageStream); } catch (Exception) { ... } ... } }







Camera Explorer , ArrayParameters



RangeParameters



, Parameters



. , , ComboBox



, Slider



Text



. , .

Parameter



, .



... public abstract class Parameter : INotifyPropertyChanged { ... protected Parameter(PhotoCaptureDevice device, string name) { ... } public PhotoCaptureDevice Device { ... } public string Name { ... } public bool Supported { ... } public abstract void Refresh(); ... }







, . _propertyId



, static CameraCapturePropertyRange PhotoCaptureDevice.GetSupportedPropertyRange(CameraSensorLocation sensor, Guid propertyId)



. object PhotoCaptureDevice.GetProperty(Guid propertyId)



. void PhotoCaptureDevice.SetProperty(Guid propertyId, object value)



.



... public abstract class RangeParameter<T> : Parameter { private Guid _propertyId; private T _value; ... protected RangeParameter(PhotoCaptureDevice device, Guid propertyId, string name) : base(device, name) { ... } public override void Refresh() { try { CameraCapturePropertyRange range = PhotoCaptureDevice.GetSupportedPropertyRange( Device.SensorLocation, _propertyId); if (range == null) { Supported = false; } else { Minimum = (T)range.Min; Maximum = (T)range.Max; _value = (T)Device.GetProperty(_propertyId); Supported = true; } } catch (Exception) { Supported = false; } ... } public T Minimum { ... } public T Maximum { ... } public T Value { ... set { if (!_value.Equals(value)) { try { Device.SetProperty(_propertyId, (T)value); _value = value; ... } catch (Exception) { ... } } } } ... }







ExposureCompensationParameter



, Guid RangeParameter



KnownCameraPhotoProperties.ExposureCompensation



, — , . , Int32



, .



... public class ExposureCompensationParameter : RangeParameter<Int32> { public ExposureCompensationParameter(PhotoCaptureDevice device) : base(device, KnownCameraPhotoProperties.ExposureCompensation, "Exposure compensation") { } ... }







Camera Explorer ArrayParameter



. . — void PopulateOptions()



void SetOption(ArrayParameterOption option)



, .



... public class ArrayParameterOption { ... public ArrayParameterOption(dynamic value, string name) { ... } public dynamic Value { ... } public string Name { ... } ... } public abstract class ArrayParameter : Parameter, IReadOnlyCollection<ArrayParameterOption> { private List<ArrayParameterOption> _options = new List<ArrayParameterOption>(); private ArrayParameterOption _selectedOption; ... public ArrayParameter(PhotoCaptureDevice device, string name) : base(device, name) { ... } public override void Refresh() { ... _options.Clear(); _selectedOption = null; try { PopulateOptions(); Supported = _options.Count > 0; } catch (Exception) { Supported = false; } ... } protected List<ArrayParameterOption> Options { ... } public ArrayParameterOption SelectedOption { ... set { if (_selectedOption != value) { ... if (_selectedOption != null)) { SetOption(value); } _selectedOption = value; } } } protected abstract void PopulateOptions(); protected abstract void SetOption(ArrayParameterOption option); ... }







, , , . void PopulateOptions()



, , ArrayParameterOption



SelectedOption



, void SetOption(ArrayParameterOption option)



. , static IReadOnlyList , KnownCameraPhotoProperties.SceneMode



object PhotoCaptureDevice.GetProperty(Guid propertyId)



. void PhotoCaptureDevice.SetProperty(Guid propertyId, object value)



.



... public class SceneModeParameter : ArrayParameter { public SceneModeParameter(PhotoCaptureDevice device) : base(device, KnownCameraPhotoProperties.SceneMode, "Scene mode") { } protected override void PopulateOptions() { IReadOnlyList<object> supportedValues = PhotoCaptureDevice.GetSupportedPropertyValues( Device.SensorLocation, PropertyId); object value = Device.GetProperty(PropertyId); foreach (dynamic i in supportedValues) { CameraSceneMode csm = (CameraSceneMode)i; ArrayParameterOption option = new ArrayParameterOption(csm, csm.ToString()); Options.Add(option); if (i.Equals(value)) { SelectedOption = option; } } } protected override void SetOption(ArrayParameterOption option) { Device.SetProperty(PropertyId, option.Value); } ... }







Tap-to-focus

«». Tap-to-focus , , , . , Tap-to-focus .



Rectangle



Canvas



, :



<Rectangle x:Name="FocusIndicator" Stroke="Red" Opacity="0.7" Width="80" Height="80" StrokeThickness="5" Visibility="Collapsed"/>







, .

Canvas Tap:



public MainPage() { ... VideoCanvas.Tap += new EventHandler<GestureEventArgs>(videoCanvas_Tap); ... }







. API- , VideoCanvas



, , .



, . , , , .



, , , , .



private async void videoCanvas_Tap(object sender, GestureEventArgs e) { System.Windows.Point uiTapPoint = e.GetPosition(VideoCanvas); if (PhotoCaptureDevice.IsFocusRegionSupported(_dataContext.Device.SensorLocation) && _focusSemaphore.WaitOne(0)) { // . Windows.Foundation.Point tapPoint = new Windows.Foundation.Point(uiTapPoint.X, uiTapPoint.Y); double xRatio = VideoCanvas.ActualWidth / _dataContext.Device.PreviewResolution.Width; double yRatio = VideoCanvas.ActualHeight / _dataContext.Device.PreviewResolution.Height; // , Windows.Foundation.Point displayOrigin = new Windows.Foundation.Point( tapPoint.X - _focusRegionSize.Width / 2, tapPoint.Y - _focusRegionSize.Height / 2); // canvas Windows.Foundation.Point viewFinderOrigin = new Windows.Foundation.Point( displayOrigin.X / xRatio, displayOrigin.Y / yRatio); Windows.Foundation.Rect focusrect = new Windows.Foundation.Rect( viewFinderOrigin, _focusRegionSize); // Windows.Foundation.Rect viewPortRect = new Windows.Foundation.Rect( 0, 0, _dataContext.Device.PreviewResolution.Width, _dataContext.Device.PreviewResolution.Height); focusrect.Intersect(viewPortRect); _dataContext.Device.FocusRegion = focusrect; // FocusIndicator.SetValue(Shape.StrokeProperty, _notFocusedBrush); FocusIndicator.SetValue(Canvas.LeftProperty, uiTapPoint.X - _focusRegionSize.Width / 2); FocusIndicator.SetValue(Canvas.TopProperty, uiTapPoint.Y - _focusRegionSize.Height / 2); FocusIndicator.SetValue(Canvas.VisibilityProperty, Visibility.Visible); CameraFocusStatus status = await _dataContext.Device.FocusAsync(); if (status == CameraFocusStatus.Locked) { FocusIndicator.SetValue(Shape.StrokeProperty, _focusedBrush); _manuallyFocused = true; _dataContext.Device.SetProperty( KnownCameraPhotoProperties.LockedAutoFocusParameters, AutoFocusParameters.Exposure & AutoFocusParameters.Focus & AutoFocusParameters.WhiteBalance); } else { _manuallyFocused = false; _dataContext.Device.SetProperty( KnownCameraPhotoProperties.LockedAutoFocusParameters, AutoFocusParameters.None); } _focusSemaphore.Release(); } }







, . FocusAsync



, , . , WaitOne



, , , false



— , .





, «», Lens Picker. «» , . Lens Picker, XML App:



<Extensions> <Extension ExtensionName="Camera_Capture_App" ConsumerId="{5B04B775-356B-4AA0-AAF8-6491FFEA5631]" TaskId="_default" /> </Extensions>







, Lens Picker, . , Lens Picker Assets



. , Lens design guidelines for Windows Phone .



Maps API.
























 static IReadOnlyList 
      

object GetProperty(Guid propertyId)






void SetProperty(Guid propertyId, object value)







— , .



static bool IsFocusSupported(CameraSensorLocation sensor)





static bool IsFocusRegionSupported(CameraSensorLocation sensor)





IAsyncOperation FocusAsync()

• IAsyncOperation ResetFocusAsync()



— .



• static IReadOnlyList GetAvailablePreviewResolutions()

• static IReadOnlyList GetAvailableCaptureResolutions()

• IAsyncAction SetPreviewResolutionAsync(Size value)






IAsyncAction SetCaptureResolutionAsync(Size value)







— .



event TypedEventHandler<ICameraCaptureDevice, Object> PreviewFrameAvailable





void GetPreviewBufferArgb(out int[] pixels)





void GetPreviewBufferY(out byte[] pixels)





void GetPreviewBufferYCbCr(out byte[] pixels)







— .



CameraCaptureSequence CreateCaptureSequence(uint numberOfFrames)





IAsyncAction PrepareCaptureSequenceAsync(CameraCaptureSequence sequence)







— . . API . GUID. , .

, ID_CAP_ISV_CAMERA



WMAppManifest.xml . ID_CAP_MEDIALIB_PHOTO



.



Lumia

Nokia Lumia 820 920.





Camera Explorer — , PhotoCaptureDevice



. , .







, Camera Explorer.







Windows Phone DataContext



, Settings



PhotoCaptureDevice



.

PhotoCaptureDevice



DataContext, , , PhotoCaptureDevice



, , MainPage, .



Camera Explorer .

, PhotoCaptureDevice , Camera Explorer. , , . .



DataContext, , .



... class DataContext : INotifyPropertyChanged { ... public static DataContext Singleton { ... } public ObservableCollection<Parameter> Parameters { ... } public PhotoCaptureDevice Device { ... } public MemoryStream ImageStream { ... } }









, PhotoCaptureDevice



. MainPage xaml Canvas



VideoBrush



, .



<phone:PhoneApplicationPage x:Class="CameraExplorer.MainPage" ... > ... <Grid x:Name="LayoutRoot" ... > ... <Grid x:Name="ContentPanel" ... > <Canvas x:Name="VideoCanvas"> <Canvas.Background> <VideoBrush x:Name="videoBrush"/> </Canvas.Background> </Canvas> ... </Grid> </Grid> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar> <shell:ApplicationBarIconButton Text="capture" Click="captureButton_Click" ... /> ... </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> ... </phone:PhoneApplicationPage>







C# MainPage PhotoCaptureDevice



InitializeCamera



, DataContext. , XAML, , .



... public partial class MainPage : PhoneApplicationPage { private CameraExplorer.DataContext _dataContext = CameraExplorer.DataContext.Singleton; ... protected async override void OnNavigatedTo(NavigationEventArgs e) { if (_dataContext.Device == null) { ... await InitializeCamera(CameraSensorLocation.Back); ... } videoBrush.RelativeTransform = new CompositeTransform() { CenterX = 0.5, CenterY = 0.5, Rotation = _dataContext.Device.SensorLocation == CameraSensorLocation.Back ? _dataContext.Device.SensorRotationInDegrees : - _dataContext.Device.SensorRotationInDegrees }; videoBrush.SetSource(_dataContext.Device); ... } 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 void captureButton_Click(object sender, EventArgs e) { if (!_manuallyFocused) { await AutoFocus(); } await Capture(); } private async Task AutoFocus() { if (!_capturing && PhotoCaptureDevice.IsFocusSupported(_dataContext.Device.SensorLocation)) { ... await _dataContext.Device.FocusAsync(); ... _capturing = false; } } private async Task Capture() { if (!_capturing) { _capturing = true; MemoryStream stream = new MemoryStream(); CameraCaptureSequence sequence = _dataContext.Device.CreateCaptureSequence(1); sequence.Frames[0].CaptureStream = stream.AsOutputStream(); await _dataContext.Device.PrepareCaptureSequenceAsync(sequence); await sequence.StartCaptureAsync(); _dataContext.ImageStream = stream; ... } ... } ... }









. Camera Explorer , XAML Image BitmapImage



. , , , void MediaLibrary.SavePictureToCameraRoll(string name, Stream source)



, .



<phone:PhoneApplicationPage x:Class="CameraExplorer.PreviewPage" ... > ... <Grid x:Name="LayoutRoot" ... > ... <Grid x:Name="ContentPanel" ... > <Image x:Name="image" Stretch="UniformToFill"/> </Grid> </Grid> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar> <shell:ApplicationBarIconButton Text="save" Click="saveButton_Click" ... /> </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> ... </phone:PhoneApplicationPage>







... public partial class PreviewPage : PhoneApplicationPage { private CameraExplorer.DataContext _dataContext = CameraExplorer.DataContext.Singleton; private BitmapImage _bitmap = new BitmapImage(); protected override void OnNavigatedTo(NavigationEventArgs e) { ... _bitmap.SetSource(_dataContext.ImageStream); image.Source = _bitmap; ... } private void saveButton_Click(object sender, EventArgs e) { try { _dataContext.ImageStream.Position = 0; MediaLibrary library = new MediaLibrary(); library.SavePictureToCameraRoll("CameraExplorer_" + DateTime.Now.ToString() + ".jpg", _dataContext.ImageStream); } catch (Exception) { ... } ... } }







Camera Explorer , ArrayParameters



RangeParameters



, Parameters



. , , ComboBox



, Slider



Text



. , .

Parameter



, .



... public abstract class Parameter : INotifyPropertyChanged { ... protected Parameter(PhotoCaptureDevice device, string name) { ... } public PhotoCaptureDevice Device { ... } public string Name { ... } public bool Supported { ... } public abstract void Refresh(); ... }







, . _propertyId



, static CameraCapturePropertyRange PhotoCaptureDevice.GetSupportedPropertyRange(CameraSensorLocation sensor, Guid propertyId)



. object PhotoCaptureDevice.GetProperty(Guid propertyId)



. void PhotoCaptureDevice.SetProperty(Guid propertyId, object value)



.



... public abstract class RangeParameter<T> : Parameter { private Guid _propertyId; private T _value; ... protected RangeParameter(PhotoCaptureDevice device, Guid propertyId, string name) : base(device, name) { ... } public override void Refresh() { try { CameraCapturePropertyRange range = PhotoCaptureDevice.GetSupportedPropertyRange( Device.SensorLocation, _propertyId); if (range == null) { Supported = false; } else { Minimum = (T)range.Min; Maximum = (T)range.Max; _value = (T)Device.GetProperty(_propertyId); Supported = true; } } catch (Exception) { Supported = false; } ... } public T Minimum { ... } public T Maximum { ... } public T Value { ... set { if (!_value.Equals(value)) { try { Device.SetProperty(_propertyId, (T)value); _value = value; ... } catch (Exception) { ... } } } } ... }







ExposureCompensationParameter



, Guid RangeParameter



KnownCameraPhotoProperties.ExposureCompensation



, — , . , Int32



, .



... public class ExposureCompensationParameter : RangeParameter<Int32> { public ExposureCompensationParameter(PhotoCaptureDevice device) : base(device, KnownCameraPhotoProperties.ExposureCompensation, "Exposure compensation") { } ... }







Camera Explorer ArrayParameter



. . — void PopulateOptions()



void SetOption(ArrayParameterOption option)



, .



... public class ArrayParameterOption { ... public ArrayParameterOption(dynamic value, string name) { ... } public dynamic Value { ... } public string Name { ... } ... } public abstract class ArrayParameter : Parameter, IReadOnlyCollection<ArrayParameterOption> { private List<ArrayParameterOption> _options = new List<ArrayParameterOption>(); private ArrayParameterOption _selectedOption; ... public ArrayParameter(PhotoCaptureDevice device, string name) : base(device, name) { ... } public override void Refresh() { ... _options.Clear(); _selectedOption = null; try { PopulateOptions(); Supported = _options.Count > 0; } catch (Exception) { Supported = false; } ... } protected List<ArrayParameterOption> Options { ... } public ArrayParameterOption SelectedOption { ... set { if (_selectedOption != value) { ... if (_selectedOption != null)) { SetOption(value); } _selectedOption = value; } } } protected abstract void PopulateOptions(); protected abstract void SetOption(ArrayParameterOption option); ... }







, , , . void PopulateOptions()



, , ArrayParameterOption



SelectedOption



, void SetOption(ArrayParameterOption option)



. , static IReadOnlyList , KnownCameraPhotoProperties.SceneMode



object PhotoCaptureDevice.GetProperty(Guid propertyId)



. void PhotoCaptureDevice.SetProperty(Guid propertyId, object value)



.



... public class SceneModeParameter : ArrayParameter { public SceneModeParameter(PhotoCaptureDevice device) : base(device, KnownCameraPhotoProperties.SceneMode, "Scene mode") { } protected override void PopulateOptions() { IReadOnlyList<object> supportedValues = PhotoCaptureDevice.GetSupportedPropertyValues( Device.SensorLocation, PropertyId); object value = Device.GetProperty(PropertyId); foreach (dynamic i in supportedValues) { CameraSceneMode csm = (CameraSceneMode)i; ArrayParameterOption option = new ArrayParameterOption(csm, csm.ToString()); Options.Add(option); if (i.Equals(value)) { SelectedOption = option; } } } protected override void SetOption(ArrayParameterOption option) { Device.SetProperty(PropertyId, option.Value); } ... }







Tap-to-focus

«». Tap-to-focus , , , . , Tap-to-focus .



Rectangle



Canvas



, :



<Rectangle x:Name="FocusIndicator" Stroke="Red" Opacity="0.7" Width="80" Height="80" StrokeThickness="5" Visibility="Collapsed"/>







, .

Canvas Tap:



public MainPage() { ... VideoCanvas.Tap += new EventHandler<GestureEventArgs>(videoCanvas_Tap); ... }







. API- , VideoCanvas



, , .



, . , , , .



, , , , .



private async void videoCanvas_Tap(object sender, GestureEventArgs e) { System.Windows.Point uiTapPoint = e.GetPosition(VideoCanvas); if (PhotoCaptureDevice.IsFocusRegionSupported(_dataContext.Device.SensorLocation) && _focusSemaphore.WaitOne(0)) { // . Windows.Foundation.Point tapPoint = new Windows.Foundation.Point(uiTapPoint.X, uiTapPoint.Y); double xRatio = VideoCanvas.ActualWidth / _dataContext.Device.PreviewResolution.Width; double yRatio = VideoCanvas.ActualHeight / _dataContext.Device.PreviewResolution.Height; // , Windows.Foundation.Point displayOrigin = new Windows.Foundation.Point( tapPoint.X - _focusRegionSize.Width / 2, tapPoint.Y - _focusRegionSize.Height / 2); // canvas Windows.Foundation.Point viewFinderOrigin = new Windows.Foundation.Point( displayOrigin.X / xRatio, displayOrigin.Y / yRatio); Windows.Foundation.Rect focusrect = new Windows.Foundation.Rect( viewFinderOrigin, _focusRegionSize); // Windows.Foundation.Rect viewPortRect = new Windows.Foundation.Rect( 0, 0, _dataContext.Device.PreviewResolution.Width, _dataContext.Device.PreviewResolution.Height); focusrect.Intersect(viewPortRect); _dataContext.Device.FocusRegion = focusrect; // FocusIndicator.SetValue(Shape.StrokeProperty, _notFocusedBrush); FocusIndicator.SetValue(Canvas.LeftProperty, uiTapPoint.X - _focusRegionSize.Width / 2); FocusIndicator.SetValue(Canvas.TopProperty, uiTapPoint.Y - _focusRegionSize.Height / 2); FocusIndicator.SetValue(Canvas.VisibilityProperty, Visibility.Visible); CameraFocusStatus status = await _dataContext.Device.FocusAsync(); if (status == CameraFocusStatus.Locked) { FocusIndicator.SetValue(Shape.StrokeProperty, _focusedBrush); _manuallyFocused = true; _dataContext.Device.SetProperty( KnownCameraPhotoProperties.LockedAutoFocusParameters, AutoFocusParameters.Exposure & AutoFocusParameters.Focus & AutoFocusParameters.WhiteBalance); } else { _manuallyFocused = false; _dataContext.Device.SetProperty( KnownCameraPhotoProperties.LockedAutoFocusParameters, AutoFocusParameters.None); } _focusSemaphore.Release(); } }







, . FocusAsync



, , . , WaitOne



, , , false



— , .





, «», Lens Picker. «» , . Lens Picker, XML App:



<Extensions> <Extension ExtensionName="Camera_Capture_App" ConsumerId="{5B04B775-356B-4AA0-AAF8-6491FFEA5631]" TaskId="_default" /> </Extensions>







, Lens Picker, . , Lens Picker Assets



. , Lens design guidelines for Windows Phone .



Maps API.
























static IReadOnlyList

• object GetProperty(Guid propertyId)






void SetProperty(Guid propertyId, object value)







— , .



static bool IsFocusSupported(CameraSensorLocation sensor)





static bool IsFocusRegionSupported(CameraSensorLocation sensor)





IAsyncOperation FocusAsync()

• IAsyncOperation ResetFocusAsync()



— .



• static IReadOnlyList GetAvailablePreviewResolutions()

• static IReadOnlyList GetAvailableCaptureResolutions()

• IAsyncAction SetPreviewResolutionAsync(Size value)






IAsyncAction SetCaptureResolutionAsync(Size value)







— .



event TypedEventHandler<ICameraCaptureDevice, Object> PreviewFrameAvailable





void GetPreviewBufferArgb(out int[] pixels)





void GetPreviewBufferY(out byte[] pixels)





void GetPreviewBufferYCbCr(out byte[] pixels)







— .



CameraCaptureSequence CreateCaptureSequence(uint numberOfFrames)





IAsyncAction PrepareCaptureSequenceAsync(CameraCaptureSequence sequence)







— . . API . GUID. , .

, ID_CAP_ISV_CAMERA



WMAppManifest.xml . ID_CAP_MEDIALIB_PHOTO



.



Lumia

Nokia Lumia 820 920.





Camera Explorer — , PhotoCaptureDevice



. , .







, Camera Explorer.







Windows Phone DataContext



, Settings



PhotoCaptureDevice



.

PhotoCaptureDevice



DataContext, , , PhotoCaptureDevice



, , MainPage, .



Camera Explorer .

, PhotoCaptureDevice , Camera Explorer. , , . .



DataContext, , .



... class DataContext : INotifyPropertyChanged { ... public static DataContext Singleton { ... } public ObservableCollection<Parameter> Parameters { ... } public PhotoCaptureDevice Device { ... } public MemoryStream ImageStream { ... } }









, PhotoCaptureDevice



. MainPage xaml Canvas



VideoBrush



, .



<phone:PhoneApplicationPage x:Class="CameraExplorer.MainPage" ... > ... <Grid x:Name="LayoutRoot" ... > ... <Grid x:Name="ContentPanel" ... > <Canvas x:Name="VideoCanvas"> <Canvas.Background> <VideoBrush x:Name="videoBrush"/> </Canvas.Background> </Canvas> ... </Grid> </Grid> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar> <shell:ApplicationBarIconButton Text="capture" Click="captureButton_Click" ... /> ... </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> ... </phone:PhoneApplicationPage>







C# MainPage PhotoCaptureDevice



InitializeCamera



, DataContext. , XAML, , .



... public partial class MainPage : PhoneApplicationPage { private CameraExplorer.DataContext _dataContext = CameraExplorer.DataContext.Singleton; ... protected async override void OnNavigatedTo(NavigationEventArgs e) { if (_dataContext.Device == null) { ... await InitializeCamera(CameraSensorLocation.Back); ... } videoBrush.RelativeTransform = new CompositeTransform() { CenterX = 0.5, CenterY = 0.5, Rotation = _dataContext.Device.SensorLocation == CameraSensorLocation.Back ? _dataContext.Device.SensorRotationInDegrees : - _dataContext.Device.SensorRotationInDegrees }; videoBrush.SetSource(_dataContext.Device); ... } 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 void captureButton_Click(object sender, EventArgs e) { if (!_manuallyFocused) { await AutoFocus(); } await Capture(); } private async Task AutoFocus() { if (!_capturing && PhotoCaptureDevice.IsFocusSupported(_dataContext.Device.SensorLocation)) { ... await _dataContext.Device.FocusAsync(); ... _capturing = false; } } private async Task Capture() { if (!_capturing) { _capturing = true; MemoryStream stream = new MemoryStream(); CameraCaptureSequence sequence = _dataContext.Device.CreateCaptureSequence(1); sequence.Frames[0].CaptureStream = stream.AsOutputStream(); await _dataContext.Device.PrepareCaptureSequenceAsync(sequence); await sequence.StartCaptureAsync(); _dataContext.ImageStream = stream; ... } ... } ... }









. Camera Explorer , XAML Image BitmapImage



. , , , void MediaLibrary.SavePictureToCameraRoll(string name, Stream source)



, .



<phone:PhoneApplicationPage x:Class="CameraExplorer.PreviewPage" ... > ... <Grid x:Name="LayoutRoot" ... > ... <Grid x:Name="ContentPanel" ... > <Image x:Name="image" Stretch="UniformToFill"/> </Grid> </Grid> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar> <shell:ApplicationBarIconButton Text="save" Click="saveButton_Click" ... /> </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> ... </phone:PhoneApplicationPage>







... public partial class PreviewPage : PhoneApplicationPage { private CameraExplorer.DataContext _dataContext = CameraExplorer.DataContext.Singleton; private BitmapImage _bitmap = new BitmapImage(); protected override void OnNavigatedTo(NavigationEventArgs e) { ... _bitmap.SetSource(_dataContext.ImageStream); image.Source = _bitmap; ... } private void saveButton_Click(object sender, EventArgs e) { try { _dataContext.ImageStream.Position = 0; MediaLibrary library = new MediaLibrary(); library.SavePictureToCameraRoll("CameraExplorer_" + DateTime.Now.ToString() + ".jpg", _dataContext.ImageStream); } catch (Exception) { ... } ... } }







Camera Explorer , ArrayParameters



RangeParameters



, Parameters



. , , ComboBox



, Slider



Text



. , .

Parameter



, .



... public abstract class Parameter : INotifyPropertyChanged { ... protected Parameter(PhotoCaptureDevice device, string name) { ... } public PhotoCaptureDevice Device { ... } public string Name { ... } public bool Supported { ... } public abstract void Refresh(); ... }







, . _propertyId



, static CameraCapturePropertyRange PhotoCaptureDevice.GetSupportedPropertyRange(CameraSensorLocation sensor, Guid propertyId)



. object PhotoCaptureDevice.GetProperty(Guid propertyId)



. void PhotoCaptureDevice.SetProperty(Guid propertyId, object value)



.



... public abstract class RangeParameter<T> : Parameter { private Guid _propertyId; private T _value; ... protected RangeParameter(PhotoCaptureDevice device, Guid propertyId, string name) : base(device, name) { ... } public override void Refresh() { try { CameraCapturePropertyRange range = PhotoCaptureDevice.GetSupportedPropertyRange( Device.SensorLocation, _propertyId); if (range == null) { Supported = false; } else { Minimum = (T)range.Min; Maximum = (T)range.Max; _value = (T)Device.GetProperty(_propertyId); Supported = true; } } catch (Exception) { Supported = false; } ... } public T Minimum { ... } public T Maximum { ... } public T Value { ... set { if (!_value.Equals(value)) { try { Device.SetProperty(_propertyId, (T)value); _value = value; ... } catch (Exception) { ... } } } } ... }







ExposureCompensationParameter



, Guid RangeParameter



KnownCameraPhotoProperties.ExposureCompensation



, — , . , Int32



, .



... public class ExposureCompensationParameter : RangeParameter<Int32> { public ExposureCompensationParameter(PhotoCaptureDevice device) : base(device, KnownCameraPhotoProperties.ExposureCompensation, "Exposure compensation") { } ... }







Camera Explorer ArrayParameter



. . — void PopulateOptions()



void SetOption(ArrayParameterOption option)



, .



... public class ArrayParameterOption { ... public ArrayParameterOption(dynamic value, string name) { ... } public dynamic Value { ... } public string Name { ... } ... } public abstract class ArrayParameter : Parameter, IReadOnlyCollection<ArrayParameterOption> { private List<ArrayParameterOption> _options = new List<ArrayParameterOption>(); private ArrayParameterOption _selectedOption; ... public ArrayParameter(PhotoCaptureDevice device, string name) : base(device, name) { ... } public override void Refresh() { ... _options.Clear(); _selectedOption = null; try { PopulateOptions(); Supported = _options.Count > 0; } catch (Exception) { Supported = false; } ... } protected List<ArrayParameterOption> Options { ... } public ArrayParameterOption SelectedOption { ... set { if (_selectedOption != value) { ... if (_selectedOption != null)) { SetOption(value); } _selectedOption = value; } } } protected abstract void PopulateOptions(); protected abstract void SetOption(ArrayParameterOption option); ... }







, , , . void PopulateOptions()



, , ArrayParameterOption



SelectedOption



, void SetOption(ArrayParameterOption option)



. , static IReadOnlyList , KnownCameraPhotoProperties.SceneMode



object PhotoCaptureDevice.GetProperty(Guid propertyId)



. void PhotoCaptureDevice.SetProperty(Guid propertyId, object value)



.



... public class SceneModeParameter : ArrayParameter { public SceneModeParameter(PhotoCaptureDevice device) : base(device, KnownCameraPhotoProperties.SceneMode, "Scene mode") { } protected override void PopulateOptions() { IReadOnlyList<object> supportedValues = PhotoCaptureDevice.GetSupportedPropertyValues( Device.SensorLocation, PropertyId); object value = Device.GetProperty(PropertyId); foreach (dynamic i in supportedValues) { CameraSceneMode csm = (CameraSceneMode)i; ArrayParameterOption option = new ArrayParameterOption(csm, csm.ToString()); Options.Add(option); if (i.Equals(value)) { SelectedOption = option; } } } protected override void SetOption(ArrayParameterOption option) { Device.SetProperty(PropertyId, option.Value); } ... }







Tap-to-focus

«». Tap-to-focus , , , . , Tap-to-focus .



Rectangle



Canvas



, :



<Rectangle x:Name="FocusIndicator" Stroke="Red" Opacity="0.7" Width="80" Height="80" StrokeThickness="5" Visibility="Collapsed"/>







, .

Canvas Tap:



public MainPage() { ... VideoCanvas.Tap += new EventHandler<GestureEventArgs>(videoCanvas_Tap); ... }







. API- , VideoCanvas



, , .



, . , , , .



, , , , .



private async void videoCanvas_Tap(object sender, GestureEventArgs e) { System.Windows.Point uiTapPoint = e.GetPosition(VideoCanvas); if (PhotoCaptureDevice.IsFocusRegionSupported(_dataContext.Device.SensorLocation) && _focusSemaphore.WaitOne(0)) { // . Windows.Foundation.Point tapPoint = new Windows.Foundation.Point(uiTapPoint.X, uiTapPoint.Y); double xRatio = VideoCanvas.ActualWidth / _dataContext.Device.PreviewResolution.Width; double yRatio = VideoCanvas.ActualHeight / _dataContext.Device.PreviewResolution.Height; // , Windows.Foundation.Point displayOrigin = new Windows.Foundation.Point( tapPoint.X - _focusRegionSize.Width / 2, tapPoint.Y - _focusRegionSize.Height / 2); // canvas Windows.Foundation.Point viewFinderOrigin = new Windows.Foundation.Point( displayOrigin.X / xRatio, displayOrigin.Y / yRatio); Windows.Foundation.Rect focusrect = new Windows.Foundation.Rect( viewFinderOrigin, _focusRegionSize); // Windows.Foundation.Rect viewPortRect = new Windows.Foundation.Rect( 0, 0, _dataContext.Device.PreviewResolution.Width, _dataContext.Device.PreviewResolution.Height); focusrect.Intersect(viewPortRect); _dataContext.Device.FocusRegion = focusrect; // FocusIndicator.SetValue(Shape.StrokeProperty, _notFocusedBrush); FocusIndicator.SetValue(Canvas.LeftProperty, uiTapPoint.X - _focusRegionSize.Width / 2); FocusIndicator.SetValue(Canvas.TopProperty, uiTapPoint.Y - _focusRegionSize.Height / 2); FocusIndicator.SetValue(Canvas.VisibilityProperty, Visibility.Visible); CameraFocusStatus status = await _dataContext.Device.FocusAsync(); if (status == CameraFocusStatus.Locked) { FocusIndicator.SetValue(Shape.StrokeProperty, _focusedBrush); _manuallyFocused = true; _dataContext.Device.SetProperty( KnownCameraPhotoProperties.LockedAutoFocusParameters, AutoFocusParameters.Exposure & AutoFocusParameters.Focus & AutoFocusParameters.WhiteBalance); } else { _manuallyFocused = false; _dataContext.Device.SetProperty( KnownCameraPhotoProperties.LockedAutoFocusParameters, AutoFocusParameters.None); } _focusSemaphore.Release(); } }







, . FocusAsync



, , . , WaitOne



, , , false



— , .





, «», Lens Picker. «» , . Lens Picker, XML App:



<Extensions> <Extension ExtensionName="Camera_Capture_App" ConsumerId="{5B04B775-356B-4AA0-AAF8-6491FFEA5631]" TaskId="_default" /> </Extensions>







, Lens Picker, . , Lens Picker Assets



. , Lens design guidelines for Windows Phone .



Maps API.
























 static IReadOnlyList 
      

object GetProperty(Guid propertyId)






void SetProperty(Guid propertyId, object value)







— , .



static bool IsFocusSupported(CameraSensorLocation sensor)





static bool IsFocusRegionSupported(CameraSensorLocation sensor)





IAsyncOperation FocusAsync()

• IAsyncOperation ResetFocusAsync()



— .



• static IReadOnlyList GetAvailablePreviewResolutions()

• static IReadOnlyList GetAvailableCaptureResolutions()

• IAsyncAction SetPreviewResolutionAsync(Size value)






IAsyncAction SetCaptureResolutionAsync(Size value)







— .



event TypedEventHandler<ICameraCaptureDevice, Object> PreviewFrameAvailable





void GetPreviewBufferArgb(out int[] pixels)





void GetPreviewBufferY(out byte[] pixels)





void GetPreviewBufferYCbCr(out byte[] pixels)







— .



CameraCaptureSequence CreateCaptureSequence(uint numberOfFrames)





IAsyncAction PrepareCaptureSequenceAsync(CameraCaptureSequence sequence)







— . . API . GUID. , .

, ID_CAP_ISV_CAMERA



WMAppManifest.xml . ID_CAP_MEDIALIB_PHOTO



.



Lumia

Nokia Lumia 820 920.





Camera Explorer — , PhotoCaptureDevice



. , .







, Camera Explorer.







Windows Phone DataContext



, Settings



PhotoCaptureDevice



.

PhotoCaptureDevice



DataContext, , , PhotoCaptureDevice



, , MainPage, .



Camera Explorer .

, PhotoCaptureDevice , Camera Explorer. , , . .



DataContext, , .



... class DataContext : INotifyPropertyChanged { ... public static DataContext Singleton { ... } public ObservableCollection<Parameter> Parameters { ... } public PhotoCaptureDevice Device { ... } public MemoryStream ImageStream { ... } }









, PhotoCaptureDevice



. MainPage xaml Canvas



VideoBrush



, .



<phone:PhoneApplicationPage x:Class="CameraExplorer.MainPage" ... > ... <Grid x:Name="LayoutRoot" ... > ... <Grid x:Name="ContentPanel" ... > <Canvas x:Name="VideoCanvas"> <Canvas.Background> <VideoBrush x:Name="videoBrush"/> </Canvas.Background> </Canvas> ... </Grid> </Grid> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar> <shell:ApplicationBarIconButton Text="capture" Click="captureButton_Click" ... /> ... </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> ... </phone:PhoneApplicationPage>







C# MainPage PhotoCaptureDevice



InitializeCamera



, DataContext. , XAML, , .



... public partial class MainPage : PhoneApplicationPage { private CameraExplorer.DataContext _dataContext = CameraExplorer.DataContext.Singleton; ... protected async override void OnNavigatedTo(NavigationEventArgs e) { if (_dataContext.Device == null) { ... await InitializeCamera(CameraSensorLocation.Back); ... } videoBrush.RelativeTransform = new CompositeTransform() { CenterX = 0.5, CenterY = 0.5, Rotation = _dataContext.Device.SensorLocation == CameraSensorLocation.Back ? _dataContext.Device.SensorRotationInDegrees : - _dataContext.Device.SensorRotationInDegrees }; videoBrush.SetSource(_dataContext.Device); ... } 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 void captureButton_Click(object sender, EventArgs e) { if (!_manuallyFocused) { await AutoFocus(); } await Capture(); } private async Task AutoFocus() { if (!_capturing && PhotoCaptureDevice.IsFocusSupported(_dataContext.Device.SensorLocation)) { ... await _dataContext.Device.FocusAsync(); ... _capturing = false; } } private async Task Capture() { if (!_capturing) { _capturing = true; MemoryStream stream = new MemoryStream(); CameraCaptureSequence sequence = _dataContext.Device.CreateCaptureSequence(1); sequence.Frames[0].CaptureStream = stream.AsOutputStream(); await _dataContext.Device.PrepareCaptureSequenceAsync(sequence); await sequence.StartCaptureAsync(); _dataContext.ImageStream = stream; ... } ... } ... }









. Camera Explorer , XAML Image BitmapImage



. , , , void MediaLibrary.SavePictureToCameraRoll(string name, Stream source)



, .



<phone:PhoneApplicationPage x:Class="CameraExplorer.PreviewPage" ... > ... <Grid x:Name="LayoutRoot" ... > ... <Grid x:Name="ContentPanel" ... > <Image x:Name="image" Stretch="UniformToFill"/> </Grid> </Grid> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar> <shell:ApplicationBarIconButton Text="save" Click="saveButton_Click" ... /> </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> ... </phone:PhoneApplicationPage>







... public partial class PreviewPage : PhoneApplicationPage { private CameraExplorer.DataContext _dataContext = CameraExplorer.DataContext.Singleton; private BitmapImage _bitmap = new BitmapImage(); protected override void OnNavigatedTo(NavigationEventArgs e) { ... _bitmap.SetSource(_dataContext.ImageStream); image.Source = _bitmap; ... } private void saveButton_Click(object sender, EventArgs e) { try { _dataContext.ImageStream.Position = 0; MediaLibrary library = new MediaLibrary(); library.SavePictureToCameraRoll("CameraExplorer_" + DateTime.Now.ToString() + ".jpg", _dataContext.ImageStream); } catch (Exception) { ... } ... } }







Camera Explorer , ArrayParameters



RangeParameters



, Parameters



. , , ComboBox



, Slider



Text



. , .

Parameter



, .



... public abstract class Parameter : INotifyPropertyChanged { ... protected Parameter(PhotoCaptureDevice device, string name) { ... } public PhotoCaptureDevice Device { ... } public string Name { ... } public bool Supported { ... } public abstract void Refresh(); ... }







, . _propertyId



, static CameraCapturePropertyRange PhotoCaptureDevice.GetSupportedPropertyRange(CameraSensorLocation sensor, Guid propertyId)



. object PhotoCaptureDevice.GetProperty(Guid propertyId)



. void PhotoCaptureDevice.SetProperty(Guid propertyId, object value)



.



... public abstract class RangeParameter<T> : Parameter { private Guid _propertyId; private T _value; ... protected RangeParameter(PhotoCaptureDevice device, Guid propertyId, string name) : base(device, name) { ... } public override void Refresh() { try { CameraCapturePropertyRange range = PhotoCaptureDevice.GetSupportedPropertyRange( Device.SensorLocation, _propertyId); if (range == null) { Supported = false; } else { Minimum = (T)range.Min; Maximum = (T)range.Max; _value = (T)Device.GetProperty(_propertyId); Supported = true; } } catch (Exception) { Supported = false; } ... } public T Minimum { ... } public T Maximum { ... } public T Value { ... set { if (!_value.Equals(value)) { try { Device.SetProperty(_propertyId, (T)value); _value = value; ... } catch (Exception) { ... } } } } ... }







ExposureCompensationParameter



, Guid RangeParameter



KnownCameraPhotoProperties.ExposureCompensation



, — , . , Int32



, .



... public class ExposureCompensationParameter : RangeParameter<Int32> { public ExposureCompensationParameter(PhotoCaptureDevice device) : base(device, KnownCameraPhotoProperties.ExposureCompensation, "Exposure compensation") { } ... }







Camera Explorer ArrayParameter



. . — void PopulateOptions()



void SetOption(ArrayParameterOption option)



, .



... public class ArrayParameterOption { ... public ArrayParameterOption(dynamic value, string name) { ... } public dynamic Value { ... } public string Name { ... } ... } public abstract class ArrayParameter : Parameter, IReadOnlyCollection<ArrayParameterOption> { private List<ArrayParameterOption> _options = new List<ArrayParameterOption>(); private ArrayParameterOption _selectedOption; ... public ArrayParameter(PhotoCaptureDevice device, string name) : base(device, name) { ... } public override void Refresh() { ... _options.Clear(); _selectedOption = null; try { PopulateOptions(); Supported = _options.Count > 0; } catch (Exception) { Supported = false; } ... } protected List<ArrayParameterOption> Options { ... } public ArrayParameterOption SelectedOption { ... set { if (_selectedOption != value) { ... if (_selectedOption != null)) { SetOption(value); } _selectedOption = value; } } } protected abstract void PopulateOptions(); protected abstract void SetOption(ArrayParameterOption option); ... }







, , , . void PopulateOptions()



, , ArrayParameterOption



SelectedOption



, void SetOption(ArrayParameterOption option)



. , static IReadOnlyList , KnownCameraPhotoProperties.SceneMode



object PhotoCaptureDevice.GetProperty(Guid propertyId)



. void PhotoCaptureDevice.SetProperty(Guid propertyId, object value)



.



... public class SceneModeParameter : ArrayParameter { public SceneModeParameter(PhotoCaptureDevice device) : base(device, KnownCameraPhotoProperties.SceneMode, "Scene mode") { } protected override void PopulateOptions() { IReadOnlyList<object> supportedValues = PhotoCaptureDevice.GetSupportedPropertyValues( Device.SensorLocation, PropertyId); object value = Device.GetProperty(PropertyId); foreach (dynamic i in supportedValues) { CameraSceneMode csm = (CameraSceneMode)i; ArrayParameterOption option = new ArrayParameterOption(csm, csm.ToString()); Options.Add(option); if (i.Equals(value)) { SelectedOption = option; } } } protected override void SetOption(ArrayParameterOption option) { Device.SetProperty(PropertyId, option.Value); } ... }







Tap-to-focus

«». Tap-to-focus , , , . , Tap-to-focus .



Rectangle



Canvas



, :



<Rectangle x:Name="FocusIndicator" Stroke="Red" Opacity="0.7" Width="80" Height="80" StrokeThickness="5" Visibility="Collapsed"/>







, .

Canvas Tap:



public MainPage() { ... VideoCanvas.Tap += new EventHandler<GestureEventArgs>(videoCanvas_Tap); ... }







. API- , VideoCanvas



, , .



, . , , , .



, , , , .



private async void videoCanvas_Tap(object sender, GestureEventArgs e) { System.Windows.Point uiTapPoint = e.GetPosition(VideoCanvas); if (PhotoCaptureDevice.IsFocusRegionSupported(_dataContext.Device.SensorLocation) && _focusSemaphore.WaitOne(0)) { // . Windows.Foundation.Point tapPoint = new Windows.Foundation.Point(uiTapPoint.X, uiTapPoint.Y); double xRatio = VideoCanvas.ActualWidth / _dataContext.Device.PreviewResolution.Width; double yRatio = VideoCanvas.ActualHeight / _dataContext.Device.PreviewResolution.Height; // , Windows.Foundation.Point displayOrigin = new Windows.Foundation.Point( tapPoint.X - _focusRegionSize.Width / 2, tapPoint.Y - _focusRegionSize.Height / 2); // canvas Windows.Foundation.Point viewFinderOrigin = new Windows.Foundation.Point( displayOrigin.X / xRatio, displayOrigin.Y / yRatio); Windows.Foundation.Rect focusrect = new Windows.Foundation.Rect( viewFinderOrigin, _focusRegionSize); // Windows.Foundation.Rect viewPortRect = new Windows.Foundation.Rect( 0, 0, _dataContext.Device.PreviewResolution.Width, _dataContext.Device.PreviewResolution.Height); focusrect.Intersect(viewPortRect); _dataContext.Device.FocusRegion = focusrect; // FocusIndicator.SetValue(Shape.StrokeProperty, _notFocusedBrush); FocusIndicator.SetValue(Canvas.LeftProperty, uiTapPoint.X - _focusRegionSize.Width / 2); FocusIndicator.SetValue(Canvas.TopProperty, uiTapPoint.Y - _focusRegionSize.Height / 2); FocusIndicator.SetValue(Canvas.VisibilityProperty, Visibility.Visible); CameraFocusStatus status = await _dataContext.Device.FocusAsync(); if (status == CameraFocusStatus.Locked) { FocusIndicator.SetValue(Shape.StrokeProperty, _focusedBrush); _manuallyFocused = true; _dataContext.Device.SetProperty( KnownCameraPhotoProperties.LockedAutoFocusParameters, AutoFocusParameters.Exposure & AutoFocusParameters.Focus & AutoFocusParameters.WhiteBalance); } else { _manuallyFocused = false; _dataContext.Device.SetProperty( KnownCameraPhotoProperties.LockedAutoFocusParameters, AutoFocusParameters.None); } _focusSemaphore.Release(); } }







, . FocusAsync



, , . , WaitOne



, , , false



— , .





, «», Lens Picker. «» , . Lens Picker, XML App:



<Extensions> <Extension ExtensionName="Camera_Capture_App" ConsumerId="{5B04B775-356B-4AA0-AAF8-6491FFEA5631]" TaskId="_default" /> </Extensions>







, Lens Picker, . , Lens Picker Assets



. , Lens design guidelines for Windows Phone .



Maps API.
























static IReadOnlyList

• object GetProperty(Guid propertyId)






void SetProperty(Guid propertyId, object value)







— , .



static bool IsFocusSupported(CameraSensorLocation sensor)





static bool IsFocusRegionSupported(CameraSensorLocation sensor)





IAsyncOperation FocusAsync()

• IAsyncOperation ResetFocusAsync()



— .



• static IReadOnlyList GetAvailablePreviewResolutions()

• static IReadOnlyList GetAvailableCaptureResolutions()

• IAsyncAction SetPreviewResolutionAsync(Size value)






IAsyncAction SetCaptureResolutionAsync(Size value)







— .



event TypedEventHandler<ICameraCaptureDevice, Object> PreviewFrameAvailable





void GetPreviewBufferArgb(out int[] pixels)





void GetPreviewBufferY(out byte[] pixels)





void GetPreviewBufferYCbCr(out byte[] pixels)







— .



CameraCaptureSequence CreateCaptureSequence(uint numberOfFrames)





IAsyncAction PrepareCaptureSequenceAsync(CameraCaptureSequence sequence)







— . . API . GUID. , .

, ID_CAP_ISV_CAMERA



WMAppManifest.xml . ID_CAP_MEDIALIB_PHOTO



.



Lumia

Nokia Lumia 820 920.





Camera Explorer — , PhotoCaptureDevice



. , .







, Camera Explorer.







Windows Phone DataContext



, Settings



PhotoCaptureDevice



.

PhotoCaptureDevice



DataContext, , , PhotoCaptureDevice



, , MainPage, .



Camera Explorer .

, PhotoCaptureDevice , Camera Explorer. , , . .



DataContext, , .



... class DataContext : INotifyPropertyChanged { ... public static DataContext Singleton { ... } public ObservableCollection<Parameter> Parameters { ... } public PhotoCaptureDevice Device { ... } public MemoryStream ImageStream { ... } }









, PhotoCaptureDevice



. MainPage xaml Canvas



VideoBrush



, .



<phone:PhoneApplicationPage x:Class="CameraExplorer.MainPage" ... > ... <Grid x:Name="LayoutRoot" ... > ... <Grid x:Name="ContentPanel" ... > <Canvas x:Name="VideoCanvas"> <Canvas.Background> <VideoBrush x:Name="videoBrush"/> </Canvas.Background> </Canvas> ... </Grid> </Grid> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar> <shell:ApplicationBarIconButton Text="capture" Click="captureButton_Click" ... /> ... </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> ... </phone:PhoneApplicationPage>







C# MainPage PhotoCaptureDevice



InitializeCamera



, DataContext. , XAML, , .



... public partial class MainPage : PhoneApplicationPage { private CameraExplorer.DataContext _dataContext = CameraExplorer.DataContext.Singleton; ... protected async override void OnNavigatedTo(NavigationEventArgs e) { if (_dataContext.Device == null) { ... await InitializeCamera(CameraSensorLocation.Back); ... } videoBrush.RelativeTransform = new CompositeTransform() { CenterX = 0.5, CenterY = 0.5, Rotation = _dataContext.Device.SensorLocation == CameraSensorLocation.Back ? _dataContext.Device.SensorRotationInDegrees : - _dataContext.Device.SensorRotationInDegrees }; videoBrush.SetSource(_dataContext.Device); ... } 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 void captureButton_Click(object sender, EventArgs e) { if (!_manuallyFocused) { await AutoFocus(); } await Capture(); } private async Task AutoFocus() { if (!_capturing && PhotoCaptureDevice.IsFocusSupported(_dataContext.Device.SensorLocation)) { ... await _dataContext.Device.FocusAsync(); ... _capturing = false; } } private async Task Capture() { if (!_capturing) { _capturing = true; MemoryStream stream = new MemoryStream(); CameraCaptureSequence sequence = _dataContext.Device.CreateCaptureSequence(1); sequence.Frames[0].CaptureStream = stream.AsOutputStream(); await _dataContext.Device.PrepareCaptureSequenceAsync(sequence); await sequence.StartCaptureAsync(); _dataContext.ImageStream = stream; ... } ... } ... }









. Camera Explorer , XAML Image BitmapImage



. , , , void MediaLibrary.SavePictureToCameraRoll(string name, Stream source)



, .



<phone:PhoneApplicationPage x:Class="CameraExplorer.PreviewPage" ... > ... <Grid x:Name="LayoutRoot" ... > ... <Grid x:Name="ContentPanel" ... > <Image x:Name="image" Stretch="UniformToFill"/> </Grid> </Grid> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar> <shell:ApplicationBarIconButton Text="save" Click="saveButton_Click" ... /> </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> ... </phone:PhoneApplicationPage>







... public partial class PreviewPage : PhoneApplicationPage { private CameraExplorer.DataContext _dataContext = CameraExplorer.DataContext.Singleton; private BitmapImage _bitmap = new BitmapImage(); protected override void OnNavigatedTo(NavigationEventArgs e) { ... _bitmap.SetSource(_dataContext.ImageStream); image.Source = _bitmap; ... } private void saveButton_Click(object sender, EventArgs e) { try { _dataContext.ImageStream.Position = 0; MediaLibrary library = new MediaLibrary(); library.SavePictureToCameraRoll("CameraExplorer_" + DateTime.Now.ToString() + ".jpg", _dataContext.ImageStream); } catch (Exception) { ... } ... } }







Camera Explorer , ArrayParameters



RangeParameters



, Parameters



. , , ComboBox



, Slider



Text



. , .

Parameter



, .



... public abstract class Parameter : INotifyPropertyChanged { ... protected Parameter(PhotoCaptureDevice device, string name) { ... } public PhotoCaptureDevice Device { ... } public string Name { ... } public bool Supported { ... } public abstract void Refresh(); ... }







, . _propertyId



, static CameraCapturePropertyRange PhotoCaptureDevice.GetSupportedPropertyRange(CameraSensorLocation sensor, Guid propertyId)



. object PhotoCaptureDevice.GetProperty(Guid propertyId)



. void PhotoCaptureDevice.SetProperty(Guid propertyId, object value)



.



... public abstract class RangeParameter<T> : Parameter { private Guid _propertyId; private T _value; ... protected RangeParameter(PhotoCaptureDevice device, Guid propertyId, string name) : base(device, name) { ... } public override void Refresh() { try { CameraCapturePropertyRange range = PhotoCaptureDevice.GetSupportedPropertyRange( Device.SensorLocation, _propertyId); if (range == null) { Supported = false; } else { Minimum = (T)range.Min; Maximum = (T)range.Max; _value = (T)Device.GetProperty(_propertyId); Supported = true; } } catch (Exception) { Supported = false; } ... } public T Minimum { ... } public T Maximum { ... } public T Value { ... set { if (!_value.Equals(value)) { try { Device.SetProperty(_propertyId, (T)value); _value = value; ... } catch (Exception) { ... } } } } ... }







ExposureCompensationParameter



, Guid RangeParameter



KnownCameraPhotoProperties.ExposureCompensation



, — , . , Int32



, .



... public class ExposureCompensationParameter : RangeParameter<Int32> { public ExposureCompensationParameter(PhotoCaptureDevice device) : base(device, KnownCameraPhotoProperties.ExposureCompensation, "Exposure compensation") { } ... }







Camera Explorer ArrayParameter



. . — void PopulateOptions()



void SetOption(ArrayParameterOption option)



, .



... public class ArrayParameterOption { ... public ArrayParameterOption(dynamic value, string name) { ... } public dynamic Value { ... } public string Name { ... } ... } public abstract class ArrayParameter : Parameter, IReadOnlyCollection<ArrayParameterOption> { private List<ArrayParameterOption> _options = new List<ArrayParameterOption>(); private ArrayParameterOption _selectedOption; ... public ArrayParameter(PhotoCaptureDevice device, string name) : base(device, name) { ... } public override void Refresh() { ... _options.Clear(); _selectedOption = null; try { PopulateOptions(); Supported = _options.Count > 0; } catch (Exception) { Supported = false; } ... } protected List<ArrayParameterOption> Options { ... } public ArrayParameterOption SelectedOption { ... set { if (_selectedOption != value) { ... if (_selectedOption != null)) { SetOption(value); } _selectedOption = value; } } } protected abstract void PopulateOptions(); protected abstract void SetOption(ArrayParameterOption option); ... }







, , , . void PopulateOptions()



, , ArrayParameterOption



SelectedOption



, void SetOption(ArrayParameterOption option)



. , static IReadOnlyList , KnownCameraPhotoProperties.SceneMode



object PhotoCaptureDevice.GetProperty(Guid propertyId)



. void PhotoCaptureDevice.SetProperty(Guid propertyId, object value)



.



... public class SceneModeParameter : ArrayParameter { public SceneModeParameter(PhotoCaptureDevice device) : base(device, KnownCameraPhotoProperties.SceneMode, "Scene mode") { } protected override void PopulateOptions() { IReadOnlyList<object> supportedValues = PhotoCaptureDevice.GetSupportedPropertyValues( Device.SensorLocation, PropertyId); object value = Device.GetProperty(PropertyId); foreach (dynamic i in supportedValues) { CameraSceneMode csm = (CameraSceneMode)i; ArrayParameterOption option = new ArrayParameterOption(csm, csm.ToString()); Options.Add(option); if (i.Equals(value)) { SelectedOption = option; } } } protected override void SetOption(ArrayParameterOption option) { Device.SetProperty(PropertyId, option.Value); } ... }







Tap-to-focus

«». Tap-to-focus , , , . , Tap-to-focus .



Rectangle



Canvas



, :



<Rectangle x:Name="FocusIndicator" Stroke="Red" Opacity="0.7" Width="80" Height="80" StrokeThickness="5" Visibility="Collapsed"/>







, .

Canvas Tap:



public MainPage() { ... VideoCanvas.Tap += new EventHandler<GestureEventArgs>(videoCanvas_Tap); ... }







. API- , VideoCanvas



, , .



, . , , , .



, , , , .



private async void videoCanvas_Tap(object sender, GestureEventArgs e) { System.Windows.Point uiTapPoint = e.GetPosition(VideoCanvas); if (PhotoCaptureDevice.IsFocusRegionSupported(_dataContext.Device.SensorLocation) && _focusSemaphore.WaitOne(0)) { // . Windows.Foundation.Point tapPoint = new Windows.Foundation.Point(uiTapPoint.X, uiTapPoint.Y); double xRatio = VideoCanvas.ActualWidth / _dataContext.Device.PreviewResolution.Width; double yRatio = VideoCanvas.ActualHeight / _dataContext.Device.PreviewResolution.Height; // , Windows.Foundation.Point displayOrigin = new Windows.Foundation.Point( tapPoint.X - _focusRegionSize.Width / 2, tapPoint.Y - _focusRegionSize.Height / 2); // canvas Windows.Foundation.Point viewFinderOrigin = new Windows.Foundation.Point( displayOrigin.X / xRatio, displayOrigin.Y / yRatio); Windows.Foundation.Rect focusrect = new Windows.Foundation.Rect( viewFinderOrigin, _focusRegionSize); // Windows.Foundation.Rect viewPortRect = new Windows.Foundation.Rect( 0, 0, _dataContext.Device.PreviewResolution.Width, _dataContext.Device.PreviewResolution.Height); focusrect.Intersect(viewPortRect); _dataContext.Device.FocusRegion = focusrect; // FocusIndicator.SetValue(Shape.StrokeProperty, _notFocusedBrush); FocusIndicator.SetValue(Canvas.LeftProperty, uiTapPoint.X - _focusRegionSize.Width / 2); FocusIndicator.SetValue(Canvas.TopProperty, uiTapPoint.Y - _focusRegionSize.Height / 2); FocusIndicator.SetValue(Canvas.VisibilityProperty, Visibility.Visible); CameraFocusStatus status = await _dataContext.Device.FocusAsync(); if (status == CameraFocusStatus.Locked) { FocusIndicator.SetValue(Shape.StrokeProperty, _focusedBrush); _manuallyFocused = true; _dataContext.Device.SetProperty( KnownCameraPhotoProperties.LockedAutoFocusParameters, AutoFocusParameters.Exposure & AutoFocusParameters.Focus & AutoFocusParameters.WhiteBalance); } else { _manuallyFocused = false; _dataContext.Device.SetProperty( KnownCameraPhotoProperties.LockedAutoFocusParameters, AutoFocusParameters.None); } _focusSemaphore.Release(); } }







, . FocusAsync



, , . , WaitOne



, , , false



— , .





, «», Lens Picker. «» , . Lens Picker, XML App:



<Extensions> <Extension ExtensionName="Camera_Capture_App" ConsumerId="{5B04B775-356B-4AA0-AAF8-6491FFEA5631]" TaskId="_default" /> </Extensions>







, Lens Picker, . , Lens Picker Assets



. , Lens design guidelines for Windows Phone .



Maps API.
























static IReadOnlyList

• object GetProperty(Guid propertyId)






void SetProperty(Guid propertyId, object value)







— , .



static bool IsFocusSupported(CameraSensorLocation sensor)





static bool IsFocusRegionSupported(CameraSensorLocation sensor)





IAsyncOperation FocusAsync()

• IAsyncOperation ResetFocusAsync()



— .



• static IReadOnlyList GetAvailablePreviewResolutions()

• static IReadOnlyList GetAvailableCaptureResolutions()

• IAsyncAction SetPreviewResolutionAsync(Size value)






IAsyncAction SetCaptureResolutionAsync(Size value)







— .



event TypedEventHandler<ICameraCaptureDevice, Object> PreviewFrameAvailable





void GetPreviewBufferArgb(out int[] pixels)





void GetPreviewBufferY(out byte[] pixels)





void GetPreviewBufferYCbCr(out byte[] pixels)







— .



CameraCaptureSequence CreateCaptureSequence(uint numberOfFrames)





IAsyncAction PrepareCaptureSequenceAsync(CameraCaptureSequence sequence)







— . . API . GUID. , .

, ID_CAP_ISV_CAMERA



WMAppManifest.xml . ID_CAP_MEDIALIB_PHOTO



.



Lumia

Nokia Lumia 820 920.





Camera Explorer — , PhotoCaptureDevice



. , .







, Camera Explorer.







Windows Phone DataContext



, Settings



PhotoCaptureDevice



.

PhotoCaptureDevice



DataContext, , , PhotoCaptureDevice



, , MainPage, .



Camera Explorer .

, PhotoCaptureDevice , Camera Explorer. , , . .



DataContext, , .



... class DataContext : INotifyPropertyChanged { ... public static DataContext Singleton { ... } public ObservableCollection<Parameter> Parameters { ... } public PhotoCaptureDevice Device { ... } public MemoryStream ImageStream { ... } }









, PhotoCaptureDevice



. MainPage xaml Canvas



VideoBrush



, .



<phone:PhoneApplicationPage x:Class="CameraExplorer.MainPage" ... > ... <Grid x:Name="LayoutRoot" ... > ... <Grid x:Name="ContentPanel" ... > <Canvas x:Name="VideoCanvas"> <Canvas.Background> <VideoBrush x:Name="videoBrush"/> </Canvas.Background> </Canvas> ... </Grid> </Grid> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar> <shell:ApplicationBarIconButton Text="capture" Click="captureButton_Click" ... /> ... </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> ... </phone:PhoneApplicationPage>







C# MainPage PhotoCaptureDevice



InitializeCamera



, DataContext. , XAML, , .



... public partial class MainPage : PhoneApplicationPage { private CameraExplorer.DataContext _dataContext = CameraExplorer.DataContext.Singleton; ... protected async override void OnNavigatedTo(NavigationEventArgs e) { if (_dataContext.Device == null) { ... await InitializeCamera(CameraSensorLocation.Back); ... } videoBrush.RelativeTransform = new CompositeTransform() { CenterX = 0.5, CenterY = 0.5, Rotation = _dataContext.Device.SensorLocation == CameraSensorLocation.Back ? _dataContext.Device.SensorRotationInDegrees : - _dataContext.Device.SensorRotationInDegrees }; videoBrush.SetSource(_dataContext.Device); ... } 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 void captureButton_Click(object sender, EventArgs e) { if (!_manuallyFocused) { await AutoFocus(); } await Capture(); } private async Task AutoFocus() { if (!_capturing && PhotoCaptureDevice.IsFocusSupported(_dataContext.Device.SensorLocation)) { ... await _dataContext.Device.FocusAsync(); ... _capturing = false; } } private async Task Capture() { if (!_capturing) { _capturing = true; MemoryStream stream = new MemoryStream(); CameraCaptureSequence sequence = _dataContext.Device.CreateCaptureSequence(1); sequence.Frames[0].CaptureStream = stream.AsOutputStream(); await _dataContext.Device.PrepareCaptureSequenceAsync(sequence); await sequence.StartCaptureAsync(); _dataContext.ImageStream = stream; ... } ... } ... }









. Camera Explorer , XAML Image BitmapImage



. , , , void MediaLibrary.SavePictureToCameraRoll(string name, Stream source)



, .



<phone:PhoneApplicationPage x:Class="CameraExplorer.PreviewPage" ... > ... <Grid x:Name="LayoutRoot" ... > ... <Grid x:Name="ContentPanel" ... > <Image x:Name="image" Stretch="UniformToFill"/> </Grid> </Grid> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar> <shell:ApplicationBarIconButton Text="save" Click="saveButton_Click" ... /> </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> ... </phone:PhoneApplicationPage>







... public partial class PreviewPage : PhoneApplicationPage { private CameraExplorer.DataContext _dataContext = CameraExplorer.DataContext.Singleton; private BitmapImage _bitmap = new BitmapImage(); protected override void OnNavigatedTo(NavigationEventArgs e) { ... _bitmap.SetSource(_dataContext.ImageStream); image.Source = _bitmap; ... } private void saveButton_Click(object sender, EventArgs e) { try { _dataContext.ImageStream.Position = 0; MediaLibrary library = new MediaLibrary(); library.SavePictureToCameraRoll("CameraExplorer_" + DateTime.Now.ToString() + ".jpg", _dataContext.ImageStream); } catch (Exception) { ... } ... } }







Camera Explorer , ArrayParameters



RangeParameters



, Parameters



. , , ComboBox



, Slider



Text



. , .

Parameter



, .



... public abstract class Parameter : INotifyPropertyChanged { ... protected Parameter(PhotoCaptureDevice device, string name) { ... } public PhotoCaptureDevice Device { ... } public string Name { ... } public bool Supported { ... } public abstract void Refresh(); ... }







, . _propertyId



, static CameraCapturePropertyRange PhotoCaptureDevice.GetSupportedPropertyRange(CameraSensorLocation sensor, Guid propertyId)



. object PhotoCaptureDevice.GetProperty(Guid propertyId)



. void PhotoCaptureDevice.SetProperty(Guid propertyId, object value)



.



... public abstract class RangeParameter<T> : Parameter { private Guid _propertyId; private T _value; ... protected RangeParameter(PhotoCaptureDevice device, Guid propertyId, string name) : base(device, name) { ... } public override void Refresh() { try { CameraCapturePropertyRange range = PhotoCaptureDevice.GetSupportedPropertyRange( Device.SensorLocation, _propertyId); if (range == null) { Supported = false; } else { Minimum = (T)range.Min; Maximum = (T)range.Max; _value = (T)Device.GetProperty(_propertyId); Supported = true; } } catch (Exception) { Supported = false; } ... } public T Minimum { ... } public T Maximum { ... } public T Value { ... set { if (!_value.Equals(value)) { try { Device.SetProperty(_propertyId, (T)value); _value = value; ... } catch (Exception) { ... } } } } ... }







ExposureCompensationParameter



, Guid RangeParameter



KnownCameraPhotoProperties.ExposureCompensation



, — , . , Int32



, .



... public class ExposureCompensationParameter : RangeParameter<Int32> { public ExposureCompensationParameter(PhotoCaptureDevice device) : base(device, KnownCameraPhotoProperties.ExposureCompensation, "Exposure compensation") { } ... }







Camera Explorer ArrayParameter



. . — void PopulateOptions()



void SetOption(ArrayParameterOption option)



, .



... public class ArrayParameterOption { ... public ArrayParameterOption(dynamic value, string name) { ... } public dynamic Value { ... } public string Name { ... } ... } public abstract class ArrayParameter : Parameter, IReadOnlyCollection<ArrayParameterOption> { private List<ArrayParameterOption> _options = new List<ArrayParameterOption>(); private ArrayParameterOption _selectedOption; ... public ArrayParameter(PhotoCaptureDevice device, string name) : base(device, name) { ... } public override void Refresh() { ... _options.Clear(); _selectedOption = null; try { PopulateOptions(); Supported = _options.Count > 0; } catch (Exception) { Supported = false; } ... } protected List<ArrayParameterOption> Options { ... } public ArrayParameterOption SelectedOption { ... set { if (_selectedOption != value) { ... if (_selectedOption != null)) { SetOption(value); } _selectedOption = value; } } } protected abstract void PopulateOptions(); protected abstract void SetOption(ArrayParameterOption option); ... }







, , , . void PopulateOptions()



, , ArrayParameterOption



SelectedOption



, void SetOption(ArrayParameterOption option)



. , static IReadOnlyList , KnownCameraPhotoProperties.SceneMode



object PhotoCaptureDevice.GetProperty(Guid propertyId)



. void PhotoCaptureDevice.SetProperty(Guid propertyId, object value)



.



... public class SceneModeParameter : ArrayParameter { public SceneModeParameter(PhotoCaptureDevice device) : base(device, KnownCameraPhotoProperties.SceneMode, "Scene mode") { } protected override void PopulateOptions() { IReadOnlyList<object> supportedValues = PhotoCaptureDevice.GetSupportedPropertyValues( Device.SensorLocation, PropertyId); object value = Device.GetProperty(PropertyId); foreach (dynamic i in supportedValues) { CameraSceneMode csm = (CameraSceneMode)i; ArrayParameterOption option = new ArrayParameterOption(csm, csm.ToString()); Options.Add(option); if (i.Equals(value)) { SelectedOption = option; } } } protected override void SetOption(ArrayParameterOption option) { Device.SetProperty(PropertyId, option.Value); } ... }







Tap-to-focus

«». Tap-to-focus , , , . , Tap-to-focus .



Rectangle



Canvas



, :



<Rectangle x:Name="FocusIndicator" Stroke="Red" Opacity="0.7" Width="80" Height="80" StrokeThickness="5" Visibility="Collapsed"/>







, .

Canvas Tap:



public MainPage() { ... VideoCanvas.Tap += new EventHandler<GestureEventArgs>(videoCanvas_Tap); ... }







. API- , VideoCanvas



, , .



, . , , , .



, , , , .



private async void videoCanvas_Tap(object sender, GestureEventArgs e) { System.Windows.Point uiTapPoint = e.GetPosition(VideoCanvas); if (PhotoCaptureDevice.IsFocusRegionSupported(_dataContext.Device.SensorLocation) && _focusSemaphore.WaitOne(0)) { // . Windows.Foundation.Point tapPoint = new Windows.Foundation.Point(uiTapPoint.X, uiTapPoint.Y); double xRatio = VideoCanvas.ActualWidth / _dataContext.Device.PreviewResolution.Width; double yRatio = VideoCanvas.ActualHeight / _dataContext.Device.PreviewResolution.Height; // , Windows.Foundation.Point displayOrigin = new Windows.Foundation.Point( tapPoint.X - _focusRegionSize.Width / 2, tapPoint.Y - _focusRegionSize.Height / 2); // canvas Windows.Foundation.Point viewFinderOrigin = new Windows.Foundation.Point( displayOrigin.X / xRatio, displayOrigin.Y / yRatio); Windows.Foundation.Rect focusrect = new Windows.Foundation.Rect( viewFinderOrigin, _focusRegionSize); // Windows.Foundation.Rect viewPortRect = new Windows.Foundation.Rect( 0, 0, _dataContext.Device.PreviewResolution.Width, _dataContext.Device.PreviewResolution.Height); focusrect.Intersect(viewPortRect); _dataContext.Device.FocusRegion = focusrect; // FocusIndicator.SetValue(Shape.StrokeProperty, _notFocusedBrush); FocusIndicator.SetValue(Canvas.LeftProperty, uiTapPoint.X - _focusRegionSize.Width / 2); FocusIndicator.SetValue(Canvas.TopProperty, uiTapPoint.Y - _focusRegionSize.Height / 2); FocusIndicator.SetValue(Canvas.VisibilityProperty, Visibility.Visible); CameraFocusStatus status = await _dataContext.Device.FocusAsync(); if (status == CameraFocusStatus.Locked) { FocusIndicator.SetValue(Shape.StrokeProperty, _focusedBrush); _manuallyFocused = true; _dataContext.Device.SetProperty( KnownCameraPhotoProperties.LockedAutoFocusParameters, AutoFocusParameters.Exposure & AutoFocusParameters.Focus & AutoFocusParameters.WhiteBalance); } else { _manuallyFocused = false; _dataContext.Device.SetProperty( KnownCameraPhotoProperties.LockedAutoFocusParameters, AutoFocusParameters.None); } _focusSemaphore.Release(); } }







, . FocusAsync



, , . , WaitOne



, , , false



— , .





, «», Lens Picker. «» , . Lens Picker, XML App:



<Extensions> <Extension ExtensionName="Camera_Capture_App" ConsumerId="{5B04B775-356B-4AA0-AAF8-6491FFEA5631]" TaskId="_default" /> </Extensions>







, Lens Picker, . , Lens Picker Assets



. , Lens design guidelines for Windows Phone .



Maps API.
























static IReadOnlyList

• object GetProperty(Guid propertyId)






void SetProperty(Guid propertyId, object value)







— , .



static bool IsFocusSupported(CameraSensorLocation sensor)





static bool IsFocusRegionSupported(CameraSensorLocation sensor)





IAsyncOperation FocusAsync()

• IAsyncOperation ResetFocusAsync()



— .



• static IReadOnlyList GetAvailablePreviewResolutions()

• static IReadOnlyList GetAvailableCaptureResolutions()

• IAsyncAction SetPreviewResolutionAsync(Size value)






IAsyncAction SetCaptureResolutionAsync(Size value)







— .



event TypedEventHandler<ICameraCaptureDevice, Object> PreviewFrameAvailable





void GetPreviewBufferArgb(out int[] pixels)





void GetPreviewBufferY(out byte[] pixels)





void GetPreviewBufferYCbCr(out byte[] pixels)







— .



CameraCaptureSequence CreateCaptureSequence(uint numberOfFrames)





IAsyncAction PrepareCaptureSequenceAsync(CameraCaptureSequence sequence)







— . . API . GUID. , .

, ID_CAP_ISV_CAMERA



WMAppManifest.xml . ID_CAP_MEDIALIB_PHOTO



.



Lumia

Nokia Lumia 820 920.





Camera Explorer — , PhotoCaptureDevice



. , .







, Camera Explorer.







Windows Phone DataContext



, Settings



PhotoCaptureDevice



.

PhotoCaptureDevice



DataContext, , , PhotoCaptureDevice



, , MainPage, .



Camera Explorer .

, PhotoCaptureDevice , Camera Explorer. , , . .



DataContext, , .



... class DataContext : INotifyPropertyChanged { ... public static DataContext Singleton { ... } public ObservableCollection<Parameter> Parameters { ... } public PhotoCaptureDevice Device { ... } public MemoryStream ImageStream { ... } }









, PhotoCaptureDevice



. MainPage xaml Canvas



VideoBrush



, .



<phone:PhoneApplicationPage x:Class="CameraExplorer.MainPage" ... > ... <Grid x:Name="LayoutRoot" ... > ... <Grid x:Name="ContentPanel" ... > <Canvas x:Name="VideoCanvas"> <Canvas.Background> <VideoBrush x:Name="videoBrush"/> </Canvas.Background> </Canvas> ... </Grid> </Grid> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar> <shell:ApplicationBarIconButton Text="capture" Click="captureButton_Click" ... /> ... </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> ... </phone:PhoneApplicationPage>







C# MainPage PhotoCaptureDevice



InitializeCamera



, DataContext. , XAML, , .



... public partial class MainPage : PhoneApplicationPage { private CameraExplorer.DataContext _dataContext = CameraExplorer.DataContext.Singleton; ... protected async override void OnNavigatedTo(NavigationEventArgs e) { if (_dataContext.Device == null) { ... await InitializeCamera(CameraSensorLocation.Back); ... } videoBrush.RelativeTransform = new CompositeTransform() { CenterX = 0.5, CenterY = 0.5, Rotation = _dataContext.Device.SensorLocation == CameraSensorLocation.Back ? _dataContext.Device.SensorRotationInDegrees : - _dataContext.Device.SensorRotationInDegrees }; videoBrush.SetSource(_dataContext.Device); ... } 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 void captureButton_Click(object sender, EventArgs e) { if (!_manuallyFocused) { await AutoFocus(); } await Capture(); } private async Task AutoFocus() { if (!_capturing && PhotoCaptureDevice.IsFocusSupported(_dataContext.Device.SensorLocation)) { ... await _dataContext.Device.FocusAsync(); ... _capturing = false; } } private async Task Capture() { if (!_capturing) { _capturing = true; MemoryStream stream = new MemoryStream(); CameraCaptureSequence sequence = _dataContext.Device.CreateCaptureSequence(1); sequence.Frames[0].CaptureStream = stream.AsOutputStream(); await _dataContext.Device.PrepareCaptureSequenceAsync(sequence); await sequence.StartCaptureAsync(); _dataContext.ImageStream = stream; ... } ... } ... }









. Camera Explorer , XAML Image BitmapImage



. , , , void MediaLibrary.SavePictureToCameraRoll(string name, Stream source)



, .



<phone:PhoneApplicationPage x:Class="CameraExplorer.PreviewPage" ... > ... <Grid x:Name="LayoutRoot" ... > ... <Grid x:Name="ContentPanel" ... > <Image x:Name="image" Stretch="UniformToFill"/> </Grid> </Grid> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar> <shell:ApplicationBarIconButton Text="save" Click="saveButton_Click" ... /> </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> ... </phone:PhoneApplicationPage>







... public partial class PreviewPage : PhoneApplicationPage { private CameraExplorer.DataContext _dataContext = CameraExplorer.DataContext.Singleton; private BitmapImage _bitmap = new BitmapImage(); protected override void OnNavigatedTo(NavigationEventArgs e) { ... _bitmap.SetSource(_dataContext.ImageStream); image.Source = _bitmap; ... } private void saveButton_Click(object sender, EventArgs e) { try { _dataContext.ImageStream.Position = 0; MediaLibrary library = new MediaLibrary(); library.SavePictureToCameraRoll("CameraExplorer_" + DateTime.Now.ToString() + ".jpg", _dataContext.ImageStream); } catch (Exception) { ... } ... } }







Camera Explorer , ArrayParameters



RangeParameters



, Parameters



. , , ComboBox



, Slider



Text



. , .

Parameter



, .



... public abstract class Parameter : INotifyPropertyChanged { ... protected Parameter(PhotoCaptureDevice device, string name) { ... } public PhotoCaptureDevice Device { ... } public string Name { ... } public bool Supported { ... } public abstract void Refresh(); ... }







, . _propertyId



, static CameraCapturePropertyRange PhotoCaptureDevice.GetSupportedPropertyRange(CameraSensorLocation sensor, Guid propertyId)



. object PhotoCaptureDevice.GetProperty(Guid propertyId)



. void PhotoCaptureDevice.SetProperty(Guid propertyId, object value)



.



... public abstract class RangeParameter<T> : Parameter { private Guid _propertyId; private T _value; ... protected RangeParameter(PhotoCaptureDevice device, Guid propertyId, string name) : base(device, name) { ... } public override void Refresh() { try { CameraCapturePropertyRange range = PhotoCaptureDevice.GetSupportedPropertyRange( Device.SensorLocation, _propertyId); if (range == null) { Supported = false; } else { Minimum = (T)range.Min; Maximum = (T)range.Max; _value = (T)Device.GetProperty(_propertyId); Supported = true; } } catch (Exception) { Supported = false; } ... } public T Minimum { ... } public T Maximum { ... } public T Value { ... set { if (!_value.Equals(value)) { try { Device.SetProperty(_propertyId, (T)value); _value = value; ... } catch (Exception) { ... } } } } ... }







ExposureCompensationParameter



, Guid RangeParameter



KnownCameraPhotoProperties.ExposureCompensation



, — , . , Int32



, .



... public class ExposureCompensationParameter : RangeParameter<Int32> { public ExposureCompensationParameter(PhotoCaptureDevice device) : base(device, KnownCameraPhotoProperties.ExposureCompensation, "Exposure compensation") { } ... }







Camera Explorer ArrayParameter



. . — void PopulateOptions()



void SetOption(ArrayParameterOption option)



, .



... public class ArrayParameterOption { ... public ArrayParameterOption(dynamic value, string name) { ... } public dynamic Value { ... } public string Name { ... } ... } public abstract class ArrayParameter : Parameter, IReadOnlyCollection<ArrayParameterOption> { private List<ArrayParameterOption> _options = new List<ArrayParameterOption>(); private ArrayParameterOption _selectedOption; ... public ArrayParameter(PhotoCaptureDevice device, string name) : base(device, name) { ... } public override void Refresh() { ... _options.Clear(); _selectedOption = null; try { PopulateOptions(); Supported = _options.Count > 0; } catch (Exception) { Supported = false; } ... } protected List<ArrayParameterOption> Options { ... } public ArrayParameterOption SelectedOption { ... set { if (_selectedOption != value) { ... if (_selectedOption != null)) { SetOption(value); } _selectedOption = value; } } } protected abstract void PopulateOptions(); protected abstract void SetOption(ArrayParameterOption option); ... }







, , , . void PopulateOptions()



, , ArrayParameterOption



SelectedOption



, void SetOption(ArrayParameterOption option)



. , static IReadOnlyList , KnownCameraPhotoProperties.SceneMode



object PhotoCaptureDevice.GetProperty(Guid propertyId)



. void PhotoCaptureDevice.SetProperty(Guid propertyId, object value)



.



... public class SceneModeParameter : ArrayParameter { public SceneModeParameter(PhotoCaptureDevice device) : base(device, KnownCameraPhotoProperties.SceneMode, "Scene mode") { } protected override void PopulateOptions() { IReadOnlyList<object> supportedValues = PhotoCaptureDevice.GetSupportedPropertyValues( Device.SensorLocation, PropertyId); object value = Device.GetProperty(PropertyId); foreach (dynamic i in supportedValues) { CameraSceneMode csm = (CameraSceneMode)i; ArrayParameterOption option = new ArrayParameterOption(csm, csm.ToString()); Options.Add(option); if (i.Equals(value)) { SelectedOption = option; } } } protected override void SetOption(ArrayParameterOption option) { Device.SetProperty(PropertyId, option.Value); } ... }







Tap-to-focus

«». Tap-to-focus , , , . , Tap-to-focus .



Rectangle



Canvas



, :



<Rectangle x:Name="FocusIndicator" Stroke="Red" Opacity="0.7" Width="80" Height="80" StrokeThickness="5" Visibility="Collapsed"/>







, .

Canvas Tap:



public MainPage() { ... VideoCanvas.Tap += new EventHandler<GestureEventArgs>(videoCanvas_Tap); ... }







. API- , VideoCanvas



, , .



, . , , , .



, , , , .



private async void videoCanvas_Tap(object sender, GestureEventArgs e) { System.Windows.Point uiTapPoint = e.GetPosition(VideoCanvas); if (PhotoCaptureDevice.IsFocusRegionSupported(_dataContext.Device.SensorLocation) && _focusSemaphore.WaitOne(0)) { // . Windows.Foundation.Point tapPoint = new Windows.Foundation.Point(uiTapPoint.X, uiTapPoint.Y); double xRatio = VideoCanvas.ActualWidth / _dataContext.Device.PreviewResolution.Width; double yRatio = VideoCanvas.ActualHeight / _dataContext.Device.PreviewResolution.Height; // , Windows.Foundation.Point displayOrigin = new Windows.Foundation.Point( tapPoint.X - _focusRegionSize.Width / 2, tapPoint.Y - _focusRegionSize.Height / 2); // canvas Windows.Foundation.Point viewFinderOrigin = new Windows.Foundation.Point( displayOrigin.X / xRatio, displayOrigin.Y / yRatio); Windows.Foundation.Rect focusrect = new Windows.Foundation.Rect( viewFinderOrigin, _focusRegionSize); // Windows.Foundation.Rect viewPortRect = new Windows.Foundation.Rect( 0, 0, _dataContext.Device.PreviewResolution.Width, _dataContext.Device.PreviewResolution.Height); focusrect.Intersect(viewPortRect); _dataContext.Device.FocusRegion = focusrect; // FocusIndicator.SetValue(Shape.StrokeProperty, _notFocusedBrush); FocusIndicator.SetValue(Canvas.LeftProperty, uiTapPoint.X - _focusRegionSize.Width / 2); FocusIndicator.SetValue(Canvas.TopProperty, uiTapPoint.Y - _focusRegionSize.Height / 2); FocusIndicator.SetValue(Canvas.VisibilityProperty, Visibility.Visible); CameraFocusStatus status = await _dataContext.Device.FocusAsync(); if (status == CameraFocusStatus.Locked) { FocusIndicator.SetValue(Shape.StrokeProperty, _focusedBrush); _manuallyFocused = true; _dataContext.Device.SetProperty( KnownCameraPhotoProperties.LockedAutoFocusParameters, AutoFocusParameters.Exposure & AutoFocusParameters.Focus & AutoFocusParameters.WhiteBalance); } else { _manuallyFocused = false; _dataContext.Device.SetProperty( KnownCameraPhotoProperties.LockedAutoFocusParameters, AutoFocusParameters.None); } _focusSemaphore.Release(); } }







, . FocusAsync



, , . , WaitOne



, , , false



— , .





, «», Lens Picker. «» , . Lens Picker, XML App:



<Extensions> <Extension ExtensionName="Camera_Capture_App" ConsumerId="{5B04B775-356B-4AA0-AAF8-6491FFEA5631]" TaskId="_default" /> </Extensions>







, Lens Picker, . , Lens Picker Assets



. , Lens design guidelines for Windows Phone .



Maps API.
























 static IReadOnlyList 
      

object GetProperty(Guid propertyId)






void SetProperty(Guid propertyId, object value)







— , .



static bool IsFocusSupported(CameraSensorLocation sensor)





static bool IsFocusRegionSupported(CameraSensorLocation sensor)





IAsyncOperation FocusAsync()

• IAsyncOperation ResetFocusAsync()



— .



• static IReadOnlyList GetAvailablePreviewResolutions()

• static IReadOnlyList GetAvailableCaptureResolutions()

• IAsyncAction SetPreviewResolutionAsync(Size value)






IAsyncAction SetCaptureResolutionAsync(Size value)







— .



event TypedEventHandler<ICameraCaptureDevice, Object> PreviewFrameAvailable





void GetPreviewBufferArgb(out int[] pixels)





void GetPreviewBufferY(out byte[] pixels)





void GetPreviewBufferYCbCr(out byte[] pixels)







— .



CameraCaptureSequence CreateCaptureSequence(uint numberOfFrames)





IAsyncAction PrepareCaptureSequenceAsync(CameraCaptureSequence sequence)







— . . API . GUID. , .

, ID_CAP_ISV_CAMERA



WMAppManifest.xml . ID_CAP_MEDIALIB_PHOTO



.



Lumia

Nokia Lumia 820 920.





Camera Explorer — , PhotoCaptureDevice



. , .







, Camera Explorer.







Windows Phone DataContext



, Settings



PhotoCaptureDevice



.

PhotoCaptureDevice



DataContext, , , PhotoCaptureDevice



, , MainPage, .



Camera Explorer .

, PhotoCaptureDevice , Camera Explorer. , , . .



DataContext, , .



... class DataContext : INotifyPropertyChanged { ... public static DataContext Singleton { ... } public ObservableCollection<Parameter> Parameters { ... } public PhotoCaptureDevice Device { ... } public MemoryStream ImageStream { ... } }









, PhotoCaptureDevice



. MainPage xaml Canvas



VideoBrush



, .



<phone:PhoneApplicationPage x:Class="CameraExplorer.MainPage" ... > ... <Grid x:Name="LayoutRoot" ... > ... <Grid x:Name="ContentPanel" ... > <Canvas x:Name="VideoCanvas"> <Canvas.Background> <VideoBrush x:Name="videoBrush"/> </Canvas.Background> </Canvas> ... </Grid> </Grid> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar> <shell:ApplicationBarIconButton Text="capture" Click="captureButton_Click" ... /> ... </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> ... </phone:PhoneApplicationPage>







C# MainPage PhotoCaptureDevice



InitializeCamera



, DataContext. , XAML, , .



... public partial class MainPage : PhoneApplicationPage { private CameraExplorer.DataContext _dataContext = CameraExplorer.DataContext.Singleton; ... protected async override void OnNavigatedTo(NavigationEventArgs e) { if (_dataContext.Device == null) { ... await InitializeCamera(CameraSensorLocation.Back); ... } videoBrush.RelativeTransform = new CompositeTransform() { CenterX = 0.5, CenterY = 0.5, Rotation = _dataContext.Device.SensorLocation == CameraSensorLocation.Back ? _dataContext.Device.SensorRotationInDegrees : - _dataContext.Device.SensorRotationInDegrees }; videoBrush.SetSource(_dataContext.Device); ... } 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 void captureButton_Click(object sender, EventArgs e) { if (!_manuallyFocused) { await AutoFocus(); } await Capture(); } private async Task AutoFocus() { if (!_capturing && PhotoCaptureDevice.IsFocusSupported(_dataContext.Device.SensorLocation)) { ... await _dataContext.Device.FocusAsync(); ... _capturing = false; } } private async Task Capture() { if (!_capturing) { _capturing = true; MemoryStream stream = new MemoryStream(); CameraCaptureSequence sequence = _dataContext.Device.CreateCaptureSequence(1); sequence.Frames[0].CaptureStream = stream.AsOutputStream(); await _dataContext.Device.PrepareCaptureSequenceAsync(sequence); await sequence.StartCaptureAsync(); _dataContext.ImageStream = stream; ... } ... } ... }









. Camera Explorer , XAML Image BitmapImage



. , , , void MediaLibrary.SavePictureToCameraRoll(string name, Stream source)



, .



<phone:PhoneApplicationPage x:Class="CameraExplorer.PreviewPage" ... > ... <Grid x:Name="LayoutRoot" ... > ... <Grid x:Name="ContentPanel" ... > <Image x:Name="image" Stretch="UniformToFill"/> </Grid> </Grid> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar> <shell:ApplicationBarIconButton Text="save" Click="saveButton_Click" ... /> </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> ... </phone:PhoneApplicationPage>







... public partial class PreviewPage : PhoneApplicationPage { private CameraExplorer.DataContext _dataContext = CameraExplorer.DataContext.Singleton; private BitmapImage _bitmap = new BitmapImage(); protected override void OnNavigatedTo(NavigationEventArgs e) { ... _bitmap.SetSource(_dataContext.ImageStream); image.Source = _bitmap; ... } private void saveButton_Click(object sender, EventArgs e) { try { _dataContext.ImageStream.Position = 0; MediaLibrary library = new MediaLibrary(); library.SavePictureToCameraRoll("CameraExplorer_" + DateTime.Now.ToString() + ".jpg", _dataContext.ImageStream); } catch (Exception) { ... } ... } }







Camera Explorer , ArrayParameters



RangeParameters



, Parameters



. , , ComboBox



, Slider



Text



. , .

Parameter



, .



... public abstract class Parameter : INotifyPropertyChanged { ... protected Parameter(PhotoCaptureDevice device, string name) { ... } public PhotoCaptureDevice Device { ... } public string Name { ... } public bool Supported { ... } public abstract void Refresh(); ... }







, . _propertyId



, static CameraCapturePropertyRange PhotoCaptureDevice.GetSupportedPropertyRange(CameraSensorLocation sensor, Guid propertyId)



. object PhotoCaptureDevice.GetProperty(Guid propertyId)



. void PhotoCaptureDevice.SetProperty(Guid propertyId, object value)



.



... public abstract class RangeParameter<T> : Parameter { private Guid _propertyId; private T _value; ... protected RangeParameter(PhotoCaptureDevice device, Guid propertyId, string name) : base(device, name) { ... } public override void Refresh() { try { CameraCapturePropertyRange range = PhotoCaptureDevice.GetSupportedPropertyRange( Device.SensorLocation, _propertyId); if (range == null) { Supported = false; } else { Minimum = (T)range.Min; Maximum = (T)range.Max; _value = (T)Device.GetProperty(_propertyId); Supported = true; } } catch (Exception) { Supported = false; } ... } public T Minimum { ... } public T Maximum { ... } public T Value { ... set { if (!_value.Equals(value)) { try { Device.SetProperty(_propertyId, (T)value); _value = value; ... } catch (Exception) { ... } } } } ... }







ExposureCompensationParameter



, Guid RangeParameter



KnownCameraPhotoProperties.ExposureCompensation



, — , . , Int32



, .



... public class ExposureCompensationParameter : RangeParameter<Int32> { public ExposureCompensationParameter(PhotoCaptureDevice device) : base(device, KnownCameraPhotoProperties.ExposureCompensation, "Exposure compensation") { } ... }







Camera Explorer ArrayParameter



. . — void PopulateOptions()



void SetOption(ArrayParameterOption option)



, .



... public class ArrayParameterOption { ... public ArrayParameterOption(dynamic value, string name) { ... } public dynamic Value { ... } public string Name { ... } ... } public abstract class ArrayParameter : Parameter, IReadOnlyCollection<ArrayParameterOption> { private List<ArrayParameterOption> _options = new List<ArrayParameterOption>(); private ArrayParameterOption _selectedOption; ... public ArrayParameter(PhotoCaptureDevice device, string name) : base(device, name) { ... } public override void Refresh() { ... _options.Clear(); _selectedOption = null; try { PopulateOptions(); Supported = _options.Count > 0; } catch (Exception) { Supported = false; } ... } protected List<ArrayParameterOption> Options { ... } public ArrayParameterOption SelectedOption { ... set { if (_selectedOption != value) { ... if (_selectedOption != null)) { SetOption(value); } _selectedOption = value; } } } protected abstract void PopulateOptions(); protected abstract void SetOption(ArrayParameterOption option); ... }







, , , . void PopulateOptions()



, , ArrayParameterOption



SelectedOption



, void SetOption(ArrayParameterOption option)



. , static IReadOnlyList , KnownCameraPhotoProperties.SceneMode



object PhotoCaptureDevice.GetProperty(Guid propertyId)



. void PhotoCaptureDevice.SetProperty(Guid propertyId, object value)



.



... public class SceneModeParameter : ArrayParameter { public SceneModeParameter(PhotoCaptureDevice device) : base(device, KnownCameraPhotoProperties.SceneMode, "Scene mode") { } protected override void PopulateOptions() { IReadOnlyList<object> supportedValues = PhotoCaptureDevice.GetSupportedPropertyValues( Device.SensorLocation, PropertyId); object value = Device.GetProperty(PropertyId); foreach (dynamic i in supportedValues) { CameraSceneMode csm = (CameraSceneMode)i; ArrayParameterOption option = new ArrayParameterOption(csm, csm.ToString()); Options.Add(option); if (i.Equals(value)) { SelectedOption = option; } } } protected override void SetOption(ArrayParameterOption option) { Device.SetProperty(PropertyId, option.Value); } ... }







Tap-to-focus

«». Tap-to-focus , , , . , Tap-to-focus .



Rectangle



Canvas



, :



<Rectangle x:Name="FocusIndicator" Stroke="Red" Opacity="0.7" Width="80" Height="80" StrokeThickness="5" Visibility="Collapsed"/>







, .

Canvas Tap:



public MainPage() { ... VideoCanvas.Tap += new EventHandler<GestureEventArgs>(videoCanvas_Tap); ... }







. API- , VideoCanvas



, , .



, . , , , .



, , , , .



private async void videoCanvas_Tap(object sender, GestureEventArgs e) { System.Windows.Point uiTapPoint = e.GetPosition(VideoCanvas); if (PhotoCaptureDevice.IsFocusRegionSupported(_dataContext.Device.SensorLocation) && _focusSemaphore.WaitOne(0)) { // . Windows.Foundation.Point tapPoint = new Windows.Foundation.Point(uiTapPoint.X, uiTapPoint.Y); double xRatio = VideoCanvas.ActualWidth / _dataContext.Device.PreviewResolution.Width; double yRatio = VideoCanvas.ActualHeight / _dataContext.Device.PreviewResolution.Height; // , Windows.Foundation.Point displayOrigin = new Windows.Foundation.Point( tapPoint.X - _focusRegionSize.Width / 2, tapPoint.Y - _focusRegionSize.Height / 2); // canvas Windows.Foundation.Point viewFinderOrigin = new Windows.Foundation.Point( displayOrigin.X / xRatio, displayOrigin.Y / yRatio); Windows.Foundation.Rect focusrect = new Windows.Foundation.Rect( viewFinderOrigin, _focusRegionSize); // Windows.Foundation.Rect viewPortRect = new Windows.Foundation.Rect( 0, 0, _dataContext.Device.PreviewResolution.Width, _dataContext.Device.PreviewResolution.Height); focusrect.Intersect(viewPortRect); _dataContext.Device.FocusRegion = focusrect; // FocusIndicator.SetValue(Shape.StrokeProperty, _notFocusedBrush); FocusIndicator.SetValue(Canvas.LeftProperty, uiTapPoint.X - _focusRegionSize.Width / 2); FocusIndicator.SetValue(Canvas.TopProperty, uiTapPoint.Y - _focusRegionSize.Height / 2); FocusIndicator.SetValue(Canvas.VisibilityProperty, Visibility.Visible); CameraFocusStatus status = await _dataContext.Device.FocusAsync(); if (status == CameraFocusStatus.Locked) { FocusIndicator.SetValue(Shape.StrokeProperty, _focusedBrush); _manuallyFocused = true; _dataContext.Device.SetProperty( KnownCameraPhotoProperties.LockedAutoFocusParameters, AutoFocusParameters.Exposure & AutoFocusParameters.Focus & AutoFocusParameters.WhiteBalance); } else { _manuallyFocused = false; _dataContext.Device.SetProperty( KnownCameraPhotoProperties.LockedAutoFocusParameters, AutoFocusParameters.None); } _focusSemaphore.Release(); } }







, . FocusAsync



, , . , WaitOne



, , , false



— , .





, «», Lens Picker. «» , . Lens Picker, XML App:



<Extensions> <Extension ExtensionName="Camera_Capture_App" ConsumerId="{5B04B775-356B-4AA0-AAF8-6491FFEA5631]" TaskId="_default" /> </Extensions>







, Lens Picker, . , Lens Picker Assets



. , Lens design guidelines for Windows Phone .



Maps API.
























static IReadOnlyList

• object GetProperty(Guid propertyId)






void SetProperty(Guid propertyId, object value)







— , .



static bool IsFocusSupported(CameraSensorLocation sensor)





static bool IsFocusRegionSupported(CameraSensorLocation sensor)





IAsyncOperation FocusAsync()

• IAsyncOperation ResetFocusAsync()



— .



• static IReadOnlyList GetAvailablePreviewResolutions()

• static IReadOnlyList GetAvailableCaptureResolutions()

• IAsyncAction SetPreviewResolutionAsync(Size value)






IAsyncAction SetCaptureResolutionAsync(Size value)







— .



event TypedEventHandler<ICameraCaptureDevice, Object> PreviewFrameAvailable





void GetPreviewBufferArgb(out int[] pixels)





void GetPreviewBufferY(out byte[] pixels)





void GetPreviewBufferYCbCr(out byte[] pixels)







— .



CameraCaptureSequence CreateCaptureSequence(uint numberOfFrames)





IAsyncAction PrepareCaptureSequenceAsync(CameraCaptureSequence sequence)







— . . API . GUID. , .

, ID_CAP_ISV_CAMERA



WMAppManifest.xml . ID_CAP_MEDIALIB_PHOTO



.



Lumia

Nokia Lumia 820 920.





Camera Explorer — , PhotoCaptureDevice



. , .







, Camera Explorer.







Windows Phone DataContext



, Settings



PhotoCaptureDevice



.

PhotoCaptureDevice



DataContext, , , PhotoCaptureDevice



, , MainPage, .



Camera Explorer .

, PhotoCaptureDevice , Camera Explorer. , , . .



DataContext, , .



... class DataContext : INotifyPropertyChanged { ... public static DataContext Singleton { ... } public ObservableCollection<Parameter> Parameters { ... } public PhotoCaptureDevice Device { ... } public MemoryStream ImageStream { ... } }









, PhotoCaptureDevice



. MainPage xaml Canvas



VideoBrush



, .



<phone:PhoneApplicationPage x:Class="CameraExplorer.MainPage" ... > ... <Grid x:Name="LayoutRoot" ... > ... <Grid x:Name="ContentPanel" ... > <Canvas x:Name="VideoCanvas"> <Canvas.Background> <VideoBrush x:Name="videoBrush"/> </Canvas.Background> </Canvas> ... </Grid> </Grid> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar> <shell:ApplicationBarIconButton Text="capture" Click="captureButton_Click" ... /> ... </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> ... </phone:PhoneApplicationPage>







C# MainPage PhotoCaptureDevice



InitializeCamera



, DataContext. , XAML, , .



... public partial class MainPage : PhoneApplicationPage { private CameraExplorer.DataContext _dataContext = CameraExplorer.DataContext.Singleton; ... protected async override void OnNavigatedTo(NavigationEventArgs e) { if (_dataContext.Device == null) { ... await InitializeCamera(CameraSensorLocation.Back); ... } videoBrush.RelativeTransform = new CompositeTransform() { CenterX = 0.5, CenterY = 0.5, Rotation = _dataContext.Device.SensorLocation == CameraSensorLocation.Back ? _dataContext.Device.SensorRotationInDegrees : - _dataContext.Device.SensorRotationInDegrees }; videoBrush.SetSource(_dataContext.Device); ... } 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 void captureButton_Click(object sender, EventArgs e) { if (!_manuallyFocused) { await AutoFocus(); } await Capture(); } private async Task AutoFocus() { if (!_capturing && PhotoCaptureDevice.IsFocusSupported(_dataContext.Device.SensorLocation)) { ... await _dataContext.Device.FocusAsync(); ... _capturing = false; } } private async Task Capture() { if (!_capturing) { _capturing = true; MemoryStream stream = new MemoryStream(); CameraCaptureSequence sequence = _dataContext.Device.CreateCaptureSequence(1); sequence.Frames[0].CaptureStream = stream.AsOutputStream(); await _dataContext.Device.PrepareCaptureSequenceAsync(sequence); await sequence.StartCaptureAsync(); _dataContext.ImageStream = stream; ... } ... } ... }









. Camera Explorer , XAML Image BitmapImage



. , , , void MediaLibrary.SavePictureToCameraRoll(string name, Stream source)



, .



<phone:PhoneApplicationPage x:Class="CameraExplorer.PreviewPage" ... > ... <Grid x:Name="LayoutRoot" ... > ... <Grid x:Name="ContentPanel" ... > <Image x:Name="image" Stretch="UniformToFill"/> </Grid> </Grid> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar> <shell:ApplicationBarIconButton Text="save" Click="saveButton_Click" ... /> </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> ... </phone:PhoneApplicationPage>







... public partial class PreviewPage : PhoneApplicationPage { private CameraExplorer.DataContext _dataContext = CameraExplorer.DataContext.Singleton; private BitmapImage _bitmap = new BitmapImage(); protected override void OnNavigatedTo(NavigationEventArgs e) { ... _bitmap.SetSource(_dataContext.ImageStream); image.Source = _bitmap; ... } private void saveButton_Click(object sender, EventArgs e) { try { _dataContext.ImageStream.Position = 0; MediaLibrary library = new MediaLibrary(); library.SavePictureToCameraRoll("CameraExplorer_" + DateTime.Now.ToString() + ".jpg", _dataContext.ImageStream); } catch (Exception) { ... } ... } }







Camera Explorer , ArrayParameters



RangeParameters



, Parameters



. , , ComboBox



, Slider



Text



. , .

Parameter



, .



... public abstract class Parameter : INotifyPropertyChanged { ... protected Parameter(PhotoCaptureDevice device, string name) { ... } public PhotoCaptureDevice Device { ... } public string Name { ... } public bool Supported { ... } public abstract void Refresh(); ... }







, . _propertyId



, static CameraCapturePropertyRange PhotoCaptureDevice.GetSupportedPropertyRange(CameraSensorLocation sensor, Guid propertyId)



. object PhotoCaptureDevice.GetProperty(Guid propertyId)



. void PhotoCaptureDevice.SetProperty(Guid propertyId, object value)



.



... public abstract class RangeParameter<T> : Parameter { private Guid _propertyId; private T _value; ... protected RangeParameter(PhotoCaptureDevice device, Guid propertyId, string name) : base(device, name) { ... } public override void Refresh() { try { CameraCapturePropertyRange range = PhotoCaptureDevice.GetSupportedPropertyRange( Device.SensorLocation, _propertyId); if (range == null) { Supported = false; } else { Minimum = (T)range.Min; Maximum = (T)range.Max; _value = (T)Device.GetProperty(_propertyId); Supported = true; } } catch (Exception) { Supported = false; } ... } public T Minimum { ... } public T Maximum { ... } public T Value { ... set { if (!_value.Equals(value)) { try { Device.SetProperty(_propertyId, (T)value); _value = value; ... } catch (Exception) { ... } } } } ... }







ExposureCompensationParameter



, Guid RangeParameter



KnownCameraPhotoProperties.ExposureCompensation



, — , . , Int32



, .



... public class ExposureCompensationParameter : RangeParameter<Int32> { public ExposureCompensationParameter(PhotoCaptureDevice device) : base(device, KnownCameraPhotoProperties.ExposureCompensation, "Exposure compensation") { } ... }







Camera Explorer ArrayParameter



. . — void PopulateOptions()



void SetOption(ArrayParameterOption option)



, .



... public class ArrayParameterOption { ... public ArrayParameterOption(dynamic value, string name) { ... } public dynamic Value { ... } public string Name { ... } ... } public abstract class ArrayParameter : Parameter, IReadOnlyCollection<ArrayParameterOption> { private List<ArrayParameterOption> _options = new List<ArrayParameterOption>(); private ArrayParameterOption _selectedOption; ... public ArrayParameter(PhotoCaptureDevice device, string name) : base(device, name) { ... } public override void Refresh() { ... _options.Clear(); _selectedOption = null; try { PopulateOptions(); Supported = _options.Count > 0; } catch (Exception) { Supported = false; } ... } protected List<ArrayParameterOption> Options { ... } public ArrayParameterOption SelectedOption { ... set { if (_selectedOption != value) { ... if (_selectedOption != null)) { SetOption(value); } _selectedOption = value; } } } protected abstract void PopulateOptions(); protected abstract void SetOption(ArrayParameterOption option); ... }







, , , . void PopulateOptions()



, , ArrayParameterOption



SelectedOption



, void SetOption(ArrayParameterOption option)



. , static IReadOnlyList , KnownCameraPhotoProperties.SceneMode



object PhotoCaptureDevice.GetProperty(Guid propertyId)



. void PhotoCaptureDevice.SetProperty(Guid propertyId, object value)



.



... public class SceneModeParameter : ArrayParameter { public SceneModeParameter(PhotoCaptureDevice device) : base(device, KnownCameraPhotoProperties.SceneMode, "Scene mode") { } protected override void PopulateOptions() { IReadOnlyList<object> supportedValues = PhotoCaptureDevice.GetSupportedPropertyValues( Device.SensorLocation, PropertyId); object value = Device.GetProperty(PropertyId); foreach (dynamic i in supportedValues) { CameraSceneMode csm = (CameraSceneMode)i; ArrayParameterOption option = new ArrayParameterOption(csm, csm.ToString()); Options.Add(option); if (i.Equals(value)) { SelectedOption = option; } } } protected override void SetOption(ArrayParameterOption option) { Device.SetProperty(PropertyId, option.Value); } ... }







Tap-to-focus

«». Tap-to-focus , , , . , Tap-to-focus .



Rectangle



Canvas



, :



<Rectangle x:Name="FocusIndicator" Stroke="Red" Opacity="0.7" Width="80" Height="80" StrokeThickness="5" Visibility="Collapsed"/>







, .

Canvas Tap:



public MainPage() { ... VideoCanvas.Tap += new EventHandler<GestureEventArgs>(videoCanvas_Tap); ... }







. API- , VideoCanvas



, , .



, . , , , .



, , , , .



private async void videoCanvas_Tap(object sender, GestureEventArgs e) { System.Windows.Point uiTapPoint = e.GetPosition(VideoCanvas); if (PhotoCaptureDevice.IsFocusRegionSupported(_dataContext.Device.SensorLocation) && _focusSemaphore.WaitOne(0)) { // . Windows.Foundation.Point tapPoint = new Windows.Foundation.Point(uiTapPoint.X, uiTapPoint.Y); double xRatio = VideoCanvas.ActualWidth / _dataContext.Device.PreviewResolution.Width; double yRatio = VideoCanvas.ActualHeight / _dataContext.Device.PreviewResolution.Height; // , Windows.Foundation.Point displayOrigin = new Windows.Foundation.Point( tapPoint.X - _focusRegionSize.Width / 2, tapPoint.Y - _focusRegionSize.Height / 2); // canvas Windows.Foundation.Point viewFinderOrigin = new Windows.Foundation.Point( displayOrigin.X / xRatio, displayOrigin.Y / yRatio); Windows.Foundation.Rect focusrect = new Windows.Foundation.Rect( viewFinderOrigin, _focusRegionSize); // Windows.Foundation.Rect viewPortRect = new Windows.Foundation.Rect( 0, 0, _dataContext.Device.PreviewResolution.Width, _dataContext.Device.PreviewResolution.Height); focusrect.Intersect(viewPortRect); _dataContext.Device.FocusRegion = focusrect; // FocusIndicator.SetValue(Shape.StrokeProperty, _notFocusedBrush); FocusIndicator.SetValue(Canvas.LeftProperty, uiTapPoint.X - _focusRegionSize.Width / 2); FocusIndicator.SetValue(Canvas.TopProperty, uiTapPoint.Y - _focusRegionSize.Height / 2); FocusIndicator.SetValue(Canvas.VisibilityProperty, Visibility.Visible); CameraFocusStatus status = await _dataContext.Device.FocusAsync(); if (status == CameraFocusStatus.Locked) { FocusIndicator.SetValue(Shape.StrokeProperty, _focusedBrush); _manuallyFocused = true; _dataContext.Device.SetProperty( KnownCameraPhotoProperties.LockedAutoFocusParameters, AutoFocusParameters.Exposure & AutoFocusParameters.Focus & AutoFocusParameters.WhiteBalance); } else { _manuallyFocused = false; _dataContext.Device.SetProperty( KnownCameraPhotoProperties.LockedAutoFocusParameters, AutoFocusParameters.None); } _focusSemaphore.Release(); } }







, . FocusAsync



, , . , WaitOne



, , , false



— , .





, «», Lens Picker. «» , . Lens Picker, XML App:



<Extensions> <Extension ExtensionName="Camera_Capture_App" ConsumerId="{5B04B775-356B-4AA0-AAF8-6491FFEA5631]" TaskId="_default" /> </Extensions>







, Lens Picker, . , Lens Picker Assets



. , Lens design guidelines for Windows Phone .



Maps API.
























 static IReadOnlyList 
      

object GetProperty(Guid propertyId)






void SetProperty(Guid propertyId, object value)







— , .



static bool IsFocusSupported(CameraSensorLocation sensor)





static bool IsFocusRegionSupported(CameraSensorLocation sensor)





IAsyncOperation FocusAsync()

• IAsyncOperation ResetFocusAsync()



— .



• static IReadOnlyList GetAvailablePreviewResolutions()

• static IReadOnlyList GetAvailableCaptureResolutions()

• IAsyncAction SetPreviewResolutionAsync(Size value)






IAsyncAction SetCaptureResolutionAsync(Size value)







— .



event TypedEventHandler<ICameraCaptureDevice, Object> PreviewFrameAvailable





void GetPreviewBufferArgb(out int[] pixels)





void GetPreviewBufferY(out byte[] pixels)





void GetPreviewBufferYCbCr(out byte[] pixels)







— .



CameraCaptureSequence CreateCaptureSequence(uint numberOfFrames)





IAsyncAction PrepareCaptureSequenceAsync(CameraCaptureSequence sequence)







— . . API . GUID. , .

, ID_CAP_ISV_CAMERA



WMAppManifest.xml . ID_CAP_MEDIALIB_PHOTO



.



Lumia

Nokia Lumia 820 920.





Camera Explorer — , PhotoCaptureDevice



. , .







, Camera Explorer.







Windows Phone DataContext



, Settings



PhotoCaptureDevice



.

PhotoCaptureDevice



DataContext, , , PhotoCaptureDevice



, , MainPage, .



Camera Explorer .

, PhotoCaptureDevice , Camera Explorer. , , . .



DataContext, , .



... class DataContext : INotifyPropertyChanged { ... public static DataContext Singleton { ... } public ObservableCollection<Parameter> Parameters { ... } public PhotoCaptureDevice Device { ... } public MemoryStream ImageStream { ... } }









, PhotoCaptureDevice



. MainPage xaml Canvas



VideoBrush



, .



<phone:PhoneApplicationPage x:Class="CameraExplorer.MainPage" ... > ... <Grid x:Name="LayoutRoot" ... > ... <Grid x:Name="ContentPanel" ... > <Canvas x:Name="VideoCanvas"> <Canvas.Background> <VideoBrush x:Name="videoBrush"/> </Canvas.Background> </Canvas> ... </Grid> </Grid> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar> <shell:ApplicationBarIconButton Text="capture" Click="captureButton_Click" ... /> ... </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> ... </phone:PhoneApplicationPage>







C# MainPage PhotoCaptureDevice



InitializeCamera



, DataContext. , XAML, , .



... public partial class MainPage : PhoneApplicationPage { private CameraExplorer.DataContext _dataContext = CameraExplorer.DataContext.Singleton; ... protected async override void OnNavigatedTo(NavigationEventArgs e) { if (_dataContext.Device == null) { ... await InitializeCamera(CameraSensorLocation.Back); ... } videoBrush.RelativeTransform = new CompositeTransform() { CenterX = 0.5, CenterY = 0.5, Rotation = _dataContext.Device.SensorLocation == CameraSensorLocation.Back ? _dataContext.Device.SensorRotationInDegrees : - _dataContext.Device.SensorRotationInDegrees }; videoBrush.SetSource(_dataContext.Device); ... } 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 void captureButton_Click(object sender, EventArgs e) { if (!_manuallyFocused) { await AutoFocus(); } await Capture(); } private async Task AutoFocus() { if (!_capturing && PhotoCaptureDevice.IsFocusSupported(_dataContext.Device.SensorLocation)) { ... await _dataContext.Device.FocusAsync(); ... _capturing = false; } } private async Task Capture() { if (!_capturing) { _capturing = true; MemoryStream stream = new MemoryStream(); CameraCaptureSequence sequence = _dataContext.Device.CreateCaptureSequence(1); sequence.Frames[0].CaptureStream = stream.AsOutputStream(); await _dataContext.Device.PrepareCaptureSequenceAsync(sequence); await sequence.StartCaptureAsync(); _dataContext.ImageStream = stream; ... } ... } ... }









. Camera Explorer , XAML Image BitmapImage



. , , , void MediaLibrary.SavePictureToCameraRoll(string name, Stream source)



, .



<phone:PhoneApplicationPage x:Class="CameraExplorer.PreviewPage" ... > ... <Grid x:Name="LayoutRoot" ... > ... <Grid x:Name="ContentPanel" ... > <Image x:Name="image" Stretch="UniformToFill"/> </Grid> </Grid> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar> <shell:ApplicationBarIconButton Text="save" Click="saveButton_Click" ... /> </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> ... </phone:PhoneApplicationPage>







... public partial class PreviewPage : PhoneApplicationPage { private CameraExplorer.DataContext _dataContext = CameraExplorer.DataContext.Singleton; private BitmapImage _bitmap = new BitmapImage(); protected override void OnNavigatedTo(NavigationEventArgs e) { ... _bitmap.SetSource(_dataContext.ImageStream); image.Source = _bitmap; ... } private void saveButton_Click(object sender, EventArgs e) { try { _dataContext.ImageStream.Position = 0; MediaLibrary library = new MediaLibrary(); library.SavePictureToCameraRoll("CameraExplorer_" + DateTime.Now.ToString() + ".jpg", _dataContext.ImageStream); } catch (Exception) { ... } ... } }







Camera Explorer , ArrayParameters



RangeParameters



, Parameters



. , , ComboBox



, Slider



Text



. , .

Parameter



, .



... public abstract class Parameter : INotifyPropertyChanged { ... protected Parameter(PhotoCaptureDevice device, string name) { ... } public PhotoCaptureDevice Device { ... } public string Name { ... } public bool Supported { ... } public abstract void Refresh(); ... }







, . _propertyId



, static CameraCapturePropertyRange PhotoCaptureDevice.GetSupportedPropertyRange(CameraSensorLocation sensor, Guid propertyId)



. object PhotoCaptureDevice.GetProperty(Guid propertyId)



. void PhotoCaptureDevice.SetProperty(Guid propertyId, object value)



.



... public abstract class RangeParameter<T> : Parameter { private Guid _propertyId; private T _value; ... protected RangeParameter(PhotoCaptureDevice device, Guid propertyId, string name) : base(device, name) { ... } public override void Refresh() { try { CameraCapturePropertyRange range = PhotoCaptureDevice.GetSupportedPropertyRange( Device.SensorLocation, _propertyId); if (range == null) { Supported = false; } else { Minimum = (T)range.Min; Maximum = (T)range.Max; _value = (T)Device.GetProperty(_propertyId); Supported = true; } } catch (Exception) { Supported = false; } ... } public T Minimum { ... } public T Maximum { ... } public T Value { ... set { if (!_value.Equals(value)) { try { Device.SetProperty(_propertyId, (T)value); _value = value; ... } catch (Exception) { ... } } } } ... }







ExposureCompensationParameter



, Guid RangeParameter



KnownCameraPhotoProperties.ExposureCompensation



, — , . , Int32



, .



... public class ExposureCompensationParameter : RangeParameter<Int32> { public ExposureCompensationParameter(PhotoCaptureDevice device) : base(device, KnownCameraPhotoProperties.ExposureCompensation, "Exposure compensation") { } ... }







Camera Explorer ArrayParameter



. . — void PopulateOptions()



void SetOption(ArrayParameterOption option)



, .



... public class ArrayParameterOption { ... public ArrayParameterOption(dynamic value, string name) { ... } public dynamic Value { ... } public string Name { ... } ... } public abstract class ArrayParameter : Parameter, IReadOnlyCollection<ArrayParameterOption> { private List<ArrayParameterOption> _options = new List<ArrayParameterOption>(); private ArrayParameterOption _selectedOption; ... public ArrayParameter(PhotoCaptureDevice device, string name) : base(device, name) { ... } public override void Refresh() { ... _options.Clear(); _selectedOption = null; try { PopulateOptions(); Supported = _options.Count > 0; } catch (Exception) { Supported = false; } ... } protected List<ArrayParameterOption> Options { ... } public ArrayParameterOption SelectedOption { ... set { if (_selectedOption != value) { ... if (_selectedOption != null)) { SetOption(value); } _selectedOption = value; } } } protected abstract void PopulateOptions(); protected abstract void SetOption(ArrayParameterOption option); ... }







, , , . void PopulateOptions()



, , ArrayParameterOption



SelectedOption



, void SetOption(ArrayParameterOption option)



. , static IReadOnlyList , KnownCameraPhotoProperties.SceneMode



object PhotoCaptureDevice.GetProperty(Guid propertyId)



. void PhotoCaptureDevice.SetProperty(Guid propertyId, object value)



.



... public class SceneModeParameter : ArrayParameter { public SceneModeParameter(PhotoCaptureDevice device) : base(device, KnownCameraPhotoProperties.SceneMode, "Scene mode") { } protected override void PopulateOptions() { IReadOnlyList<object> supportedValues = PhotoCaptureDevice.GetSupportedPropertyValues( Device.SensorLocation, PropertyId); object value = Device.GetProperty(PropertyId); foreach (dynamic i in supportedValues) { CameraSceneMode csm = (CameraSceneMode)i; ArrayParameterOption option = new ArrayParameterOption(csm, csm.ToString()); Options.Add(option); if (i.Equals(value)) { SelectedOption = option; } } } protected override void SetOption(ArrayParameterOption option) { Device.SetProperty(PropertyId, option.Value); } ... }







Tap-to-focus

«». Tap-to-focus , , , . , Tap-to-focus .



Rectangle



Canvas



, :



<Rectangle x:Name="FocusIndicator" Stroke="Red" Opacity="0.7" Width="80" Height="80" StrokeThickness="5" Visibility="Collapsed"/>







, .

Canvas Tap:



public MainPage() { ... VideoCanvas.Tap += new EventHandler<GestureEventArgs>(videoCanvas_Tap); ... }







. API- , VideoCanvas



, , .



, . , , , .



, , , , .



private async void videoCanvas_Tap(object sender, GestureEventArgs e) { System.Windows.Point uiTapPoint = e.GetPosition(VideoCanvas); if (PhotoCaptureDevice.IsFocusRegionSupported(_dataContext.Device.SensorLocation) && _focusSemaphore.WaitOne(0)) { // . Windows.Foundation.Point tapPoint = new Windows.Foundation.Point(uiTapPoint.X, uiTapPoint.Y); double xRatio = VideoCanvas.ActualWidth / _dataContext.Device.PreviewResolution.Width; double yRatio = VideoCanvas.ActualHeight / _dataContext.Device.PreviewResolution.Height; // , Windows.Foundation.Point displayOrigin = new Windows.Foundation.Point( tapPoint.X - _focusRegionSize.Width / 2, tapPoint.Y - _focusRegionSize.Height / 2); // canvas Windows.Foundation.Point viewFinderOrigin = new Windows.Foundation.Point( displayOrigin.X / xRatio, displayOrigin.Y / yRatio); Windows.Foundation.Rect focusrect = new Windows.Foundation.Rect( viewFinderOrigin, _focusRegionSize); // Windows.Foundation.Rect viewPortRect = new Windows.Foundation.Rect( 0, 0, _dataContext.Device.PreviewResolution.Width, _dataContext.Device.PreviewResolution.Height); focusrect.Intersect(viewPortRect); _dataContext.Device.FocusRegion = focusrect; // FocusIndicator.SetValue(Shape.StrokeProperty, _notFocusedBrush); FocusIndicator.SetValue(Canvas.LeftProperty, uiTapPoint.X - _focusRegionSize.Width / 2); FocusIndicator.SetValue(Canvas.TopProperty, uiTapPoint.Y - _focusRegionSize.Height / 2); FocusIndicator.SetValue(Canvas.VisibilityProperty, Visibility.Visible); CameraFocusStatus status = await _dataContext.Device.FocusAsync(); if (status == CameraFocusStatus.Locked) { FocusIndicator.SetValue(Shape.StrokeProperty, _focusedBrush); _manuallyFocused = true; _dataContext.Device.SetProperty( KnownCameraPhotoProperties.LockedAutoFocusParameters, AutoFocusParameters.Exposure & AutoFocusParameters.Focus & AutoFocusParameters.WhiteBalance); } else { _manuallyFocused = false; _dataContext.Device.SetProperty( KnownCameraPhotoProperties.LockedAutoFocusParameters, AutoFocusParameters.None); } _focusSemaphore.Release(); } }







, . FocusAsync



, , . , WaitOne



, , , false



— , .





, «», Lens Picker. «» , . Lens Picker, XML App:



<Extensions> <Extension ExtensionName="Camera_Capture_App" ConsumerId="{5B04B775-356B-4AA0-AAF8-6491FFEA5631]" TaskId="_default" /> </Extensions>







, Lens Picker, . , Lens Picker Assets



. , Lens design guidelines for Windows Phone .



Maps API.
























static IReadOnlyList

• object GetProperty(Guid propertyId)






void SetProperty(Guid propertyId, object value)







— , .



static bool IsFocusSupported(CameraSensorLocation sensor)





static bool IsFocusRegionSupported(CameraSensorLocation sensor)





IAsyncOperation FocusAsync()

• IAsyncOperation ResetFocusAsync()



— .



• static IReadOnlyList GetAvailablePreviewResolutions()

• static IReadOnlyList GetAvailableCaptureResolutions()

• IAsyncAction SetPreviewResolutionAsync(Size value)






IAsyncAction SetCaptureResolutionAsync(Size value)







— .



event TypedEventHandler<ICameraCaptureDevice, Object> PreviewFrameAvailable





void GetPreviewBufferArgb(out int[] pixels)





void GetPreviewBufferY(out byte[] pixels)





void GetPreviewBufferYCbCr(out byte[] pixels)







— .



CameraCaptureSequence CreateCaptureSequence(uint numberOfFrames)





IAsyncAction PrepareCaptureSequenceAsync(CameraCaptureSequence sequence)







— . . API . GUID. , .

, ID_CAP_ISV_CAMERA



WMAppManifest.xml . ID_CAP_MEDIALIB_PHOTO



.



Lumia

Nokia Lumia 820 920.





Camera Explorer — , PhotoCaptureDevice



. , .







, Camera Explorer.







Windows Phone DataContext



, Settings



PhotoCaptureDevice



.

PhotoCaptureDevice



DataContext, , , PhotoCaptureDevice



, , MainPage, .



Camera Explorer .

, PhotoCaptureDevice , Camera Explorer. , , . .



DataContext, , .



... class DataContext : INotifyPropertyChanged { ... public static DataContext Singleton { ... } public ObservableCollection<Parameter> Parameters { ... } public PhotoCaptureDevice Device { ... } public MemoryStream ImageStream { ... } }









, PhotoCaptureDevice



. MainPage xaml Canvas



VideoBrush



, .



<phone:PhoneApplicationPage x:Class="CameraExplorer.MainPage" ... > ... <Grid x:Name="LayoutRoot" ... > ... <Grid x:Name="ContentPanel" ... > <Canvas x:Name="VideoCanvas"> <Canvas.Background> <VideoBrush x:Name="videoBrush"/> </Canvas.Background> </Canvas> ... </Grid> </Grid> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar> <shell:ApplicationBarIconButton Text="capture" Click="captureButton_Click" ... /> ... </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> ... </phone:PhoneApplicationPage>







C# MainPage PhotoCaptureDevice



InitializeCamera



, DataContext. , XAML, , .



... public partial class MainPage : PhoneApplicationPage { private CameraExplorer.DataContext _dataContext = CameraExplorer.DataContext.Singleton; ... protected async override void OnNavigatedTo(NavigationEventArgs e) { if (_dataContext.Device == null) { ... await InitializeCamera(CameraSensorLocation.Back); ... } videoBrush.RelativeTransform = new CompositeTransform() { CenterX = 0.5, CenterY = 0.5, Rotation = _dataContext.Device.SensorLocation == CameraSensorLocation.Back ? _dataContext.Device.SensorRotationInDegrees : - _dataContext.Device.SensorRotationInDegrees }; videoBrush.SetSource(_dataContext.Device); ... } 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 void captureButton_Click(object sender, EventArgs e) { if (!_manuallyFocused) { await AutoFocus(); } await Capture(); } private async Task AutoFocus() { if (!_capturing && PhotoCaptureDevice.IsFocusSupported(_dataContext.Device.SensorLocation)) { ... await _dataContext.Device.FocusAsync(); ... _capturing = false; } } private async Task Capture() { if (!_capturing) { _capturing = true; MemoryStream stream = new MemoryStream(); CameraCaptureSequence sequence = _dataContext.Device.CreateCaptureSequence(1); sequence.Frames[0].CaptureStream = stream.AsOutputStream(); await _dataContext.Device.PrepareCaptureSequenceAsync(sequence); await sequence.StartCaptureAsync(); _dataContext.ImageStream = stream; ... } ... } ... }









. Camera Explorer , XAML Image BitmapImage



. , , , void MediaLibrary.SavePictureToCameraRoll(string name, Stream source)



, .



<phone:PhoneApplicationPage x:Class="CameraExplorer.PreviewPage" ... > ... <Grid x:Name="LayoutRoot" ... > ... <Grid x:Name="ContentPanel" ... > <Image x:Name="image" Stretch="UniformToFill"/> </Grid> </Grid> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar> <shell:ApplicationBarIconButton Text="save" Click="saveButton_Click" ... /> </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> ... </phone:PhoneApplicationPage>







... public partial class PreviewPage : PhoneApplicationPage { private CameraExplorer.DataContext _dataContext = CameraExplorer.DataContext.Singleton; private BitmapImage _bitmap = new BitmapImage(); protected override void OnNavigatedTo(NavigationEventArgs e) { ... _bitmap.SetSource(_dataContext.ImageStream); image.Source = _bitmap; ... } private void saveButton_Click(object sender, EventArgs e) { try { _dataContext.ImageStream.Position = 0; MediaLibrary library = new MediaLibrary(); library.SavePictureToCameraRoll("CameraExplorer_" + DateTime.Now.ToString() + ".jpg", _dataContext.ImageStream); } catch (Exception) { ... } ... } }







Camera Explorer , ArrayParameters



RangeParameters



, Parameters



. , , ComboBox



, Slider



Text



. , .

Parameter



, .



... public abstract class Parameter : INotifyPropertyChanged { ... protected Parameter(PhotoCaptureDevice device, string name) { ... } public PhotoCaptureDevice Device { ... } public string Name { ... } public bool Supported { ... } public abstract void Refresh(); ... }







, . _propertyId



, static CameraCapturePropertyRange PhotoCaptureDevice.GetSupportedPropertyRange(CameraSensorLocation sensor, Guid propertyId)



. object PhotoCaptureDevice.GetProperty(Guid propertyId)



. void PhotoCaptureDevice.SetProperty(Guid propertyId, object value)



.



... public abstract class RangeParameter<T> : Parameter { private Guid _propertyId; private T _value; ... protected RangeParameter(PhotoCaptureDevice device, Guid propertyId, string name) : base(device, name) { ... } public override void Refresh() { try { CameraCapturePropertyRange range = PhotoCaptureDevice.GetSupportedPropertyRange( Device.SensorLocation, _propertyId); if (range == null) { Supported = false; } else { Minimum = (T)range.Min; Maximum = (T)range.Max; _value = (T)Device.GetProperty(_propertyId); Supported = true; } } catch (Exception) { Supported = false; } ... } public T Minimum { ... } public T Maximum { ... } public T Value { ... set { if (!_value.Equals(value)) { try { Device.SetProperty(_propertyId, (T)value); _value = value; ... } catch (Exception) { ... } } } } ... }







ExposureCompensationParameter



, Guid RangeParameter



KnownCameraPhotoProperties.ExposureCompensation



, — , . , Int32



, .



... public class ExposureCompensationParameter : RangeParameter<Int32> { public ExposureCompensationParameter(PhotoCaptureDevice device) : base(device, KnownCameraPhotoProperties.ExposureCompensation, "Exposure compensation") { } ... }







Camera Explorer ArrayParameter



. . — void PopulateOptions()



void SetOption(ArrayParameterOption option)



, .



... public class ArrayParameterOption { ... public ArrayParameterOption(dynamic value, string name) { ... } public dynamic Value { ... } public string Name { ... } ... } public abstract class ArrayParameter : Parameter, IReadOnlyCollection<ArrayParameterOption> { private List<ArrayParameterOption> _options = new List<ArrayParameterOption>(); private ArrayParameterOption _selectedOption; ... public ArrayParameter(PhotoCaptureDevice device, string name) : base(device, name) { ... } public override void Refresh() { ... _options.Clear(); _selectedOption = null; try { PopulateOptions(); Supported = _options.Count > 0; } catch (Exception) { Supported = false; } ... } protected List<ArrayParameterOption> Options { ... } public ArrayParameterOption SelectedOption { ... set { if (_selectedOption != value) { ... if (_selectedOption != null)) { SetOption(value); } _selectedOption = value; } } } protected abstract void PopulateOptions(); protected abstract void SetOption(ArrayParameterOption option); ... }







, , , . void PopulateOptions()



, , ArrayParameterOption



SelectedOption



, void SetOption(ArrayParameterOption option)



. , static IReadOnlyList , KnownCameraPhotoProperties.SceneMode



object PhotoCaptureDevice.GetProperty(Guid propertyId)



. void PhotoCaptureDevice.SetProperty(Guid propertyId, object value)



.



... public class SceneModeParameter : ArrayParameter { public SceneModeParameter(PhotoCaptureDevice device) : base(device, KnownCameraPhotoProperties.SceneMode, "Scene mode") { } protected override void PopulateOptions() { IReadOnlyList<object> supportedValues = PhotoCaptureDevice.GetSupportedPropertyValues( Device.SensorLocation, PropertyId); object value = Device.GetProperty(PropertyId); foreach (dynamic i in supportedValues) { CameraSceneMode csm = (CameraSceneMode)i; ArrayParameterOption option = new ArrayParameterOption(csm, csm.ToString()); Options.Add(option); if (i.Equals(value)) { SelectedOption = option; } } } protected override void SetOption(ArrayParameterOption option) { Device.SetProperty(PropertyId, option.Value); } ... }







Tap-to-focus

«». Tap-to-focus , , , . , Tap-to-focus .



Rectangle



Canvas



, :



<Rectangle x:Name="FocusIndicator" Stroke="Red" Opacity="0.7" Width="80" Height="80" StrokeThickness="5" Visibility="Collapsed"/>







, .

Canvas Tap:



public MainPage() { ... VideoCanvas.Tap += new EventHandler<GestureEventArgs>(videoCanvas_Tap); ... }







. API- , VideoCanvas



, , .



, . , , , .



, , , , .



private async void videoCanvas_Tap(object sender, GestureEventArgs e) { System.Windows.Point uiTapPoint = e.GetPosition(VideoCanvas); if (PhotoCaptureDevice.IsFocusRegionSupported(_dataContext.Device.SensorLocation) && _focusSemaphore.WaitOne(0)) { // . Windows.Foundation.Point tapPoint = new Windows.Foundation.Point(uiTapPoint.X, uiTapPoint.Y); double xRatio = VideoCanvas.ActualWidth / _dataContext.Device.PreviewResolution.Width; double yRatio = VideoCanvas.ActualHeight / _dataContext.Device.PreviewResolution.Height; // , Windows.Foundation.Point displayOrigin = new Windows.Foundation.Point( tapPoint.X - _focusRegionSize.Width / 2, tapPoint.Y - _focusRegionSize.Height / 2); // canvas Windows.Foundation.Point viewFinderOrigin = new Windows.Foundation.Point( displayOrigin.X / xRatio, displayOrigin.Y / yRatio); Windows.Foundation.Rect focusrect = new Windows.Foundation.Rect( viewFinderOrigin, _focusRegionSize); // Windows.Foundation.Rect viewPortRect = new Windows.Foundation.Rect( 0, 0, _dataContext.Device.PreviewResolution.Width, _dataContext.Device.PreviewResolution.Height); focusrect.Intersect(viewPortRect); _dataContext.Device.FocusRegion = focusrect; // FocusIndicator.SetValue(Shape.StrokeProperty, _notFocusedBrush); FocusIndicator.SetValue(Canvas.LeftProperty, uiTapPoint.X - _focusRegionSize.Width / 2); FocusIndicator.SetValue(Canvas.TopProperty, uiTapPoint.Y - _focusRegionSize.Height / 2); FocusIndicator.SetValue(Canvas.VisibilityProperty, Visibility.Visible); CameraFocusStatus status = await _dataContext.Device.FocusAsync(); if (status == CameraFocusStatus.Locked) { FocusIndicator.SetValue(Shape.StrokeProperty, _focusedBrush); _manuallyFocused = true; _dataContext.Device.SetProperty( KnownCameraPhotoProperties.LockedAutoFocusParameters, AutoFocusParameters.Exposure & AutoFocusParameters.Focus & AutoFocusParameters.WhiteBalance); } else { _manuallyFocused = false; _dataContext.Device.SetProperty( KnownCameraPhotoProperties.LockedAutoFocusParameters, AutoFocusParameters.None); } _focusSemaphore.Release(); } }







, . FocusAsync



, , . , WaitOne



, , , false



— , .





, «», Lens Picker. «» , . Lens Picker, XML App:



<Extensions> <Extension ExtensionName="Camera_Capture_App" ConsumerId="{5B04B775-356B-4AA0-AAF8-6491FFEA5631]" TaskId="_default" /> </Extensions>







, Lens Picker, . , Lens Picker Assets



. , Lens design guidelines for Windows Phone .



Maps API.
























 static IReadOnlyList 
      

object GetProperty(Guid propertyId)






void SetProperty(Guid propertyId, object value)







— , .



static bool IsFocusSupported(CameraSensorLocation sensor)





static bool IsFocusRegionSupported(CameraSensorLocation sensor)





IAsyncOperation FocusAsync()

• IAsyncOperation ResetFocusAsync()



— .



• static IReadOnlyList GetAvailablePreviewResolutions()

• static IReadOnlyList GetAvailableCaptureResolutions()

• IAsyncAction SetPreviewResolutionAsync(Size value)






IAsyncAction SetCaptureResolutionAsync(Size value)







— .



event TypedEventHandler<ICameraCaptureDevice, Object> PreviewFrameAvailable





void GetPreviewBufferArgb(out int[] pixels)





void GetPreviewBufferY(out byte[] pixels)





void GetPreviewBufferYCbCr(out byte[] pixels)







— .



CameraCaptureSequence CreateCaptureSequence(uint numberOfFrames)





IAsyncAction PrepareCaptureSequenceAsync(CameraCaptureSequence sequence)







— . . API . GUID. , .

, ID_CAP_ISV_CAMERA



WMAppManifest.xml . ID_CAP_MEDIALIB_PHOTO



.



Lumia

Nokia Lumia 820 920.





Camera Explorer — , PhotoCaptureDevice



. , .







, Camera Explorer.







Windows Phone DataContext



, Settings



PhotoCaptureDevice



.

PhotoCaptureDevice



DataContext, , , PhotoCaptureDevice



, , MainPage, .



Camera Explorer .

, PhotoCaptureDevice , Camera Explorer. , , . .



DataContext, , .



... class DataContext : INotifyPropertyChanged { ... public static DataContext Singleton { ... } public ObservableCollection<Parameter> Parameters { ... } public PhotoCaptureDevice Device { ... } public MemoryStream ImageStream { ... } }









, PhotoCaptureDevice



. MainPage xaml Canvas



VideoBrush



, .



<phone:PhoneApplicationPage x:Class="CameraExplorer.MainPage" ... > ... <Grid x:Name="LayoutRoot" ... > ... <Grid x:Name="ContentPanel" ... > <Canvas x:Name="VideoCanvas"> <Canvas.Background> <VideoBrush x:Name="videoBrush"/> </Canvas.Background> </Canvas> ... </Grid> </Grid> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar> <shell:ApplicationBarIconButton Text="capture" Click="captureButton_Click" ... /> ... </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> ... </phone:PhoneApplicationPage>







C# MainPage PhotoCaptureDevice



InitializeCamera



, DataContext. , XAML, , .



... public partial class MainPage : PhoneApplicationPage { private CameraExplorer.DataContext _dataContext = CameraExplorer.DataContext.Singleton; ... protected async override void OnNavigatedTo(NavigationEventArgs e) { if (_dataContext.Device == null) { ... await InitializeCamera(CameraSensorLocation.Back); ... } videoBrush.RelativeTransform = new CompositeTransform() { CenterX = 0.5, CenterY = 0.5, Rotation = _dataContext.Device.SensorLocation == CameraSensorLocation.Back ? _dataContext.Device.SensorRotationInDegrees : - _dataContext.Device.SensorRotationInDegrees }; videoBrush.SetSource(_dataContext.Device); ... } 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 void captureButton_Click(object sender, EventArgs e) { if (!_manuallyFocused) { await AutoFocus(); } await Capture(); } private async Task AutoFocus() { if (!_capturing && PhotoCaptureDevice.IsFocusSupported(_dataContext.Device.SensorLocation)) { ... await _dataContext.Device.FocusAsync(); ... _capturing = false; } } private async Task Capture() { if (!_capturing) { _capturing = true; MemoryStream stream = new MemoryStream(); CameraCaptureSequence sequence = _dataContext.Device.CreateCaptureSequence(1); sequence.Frames[0].CaptureStream = stream.AsOutputStream(); await _dataContext.Device.PrepareCaptureSequenceAsync(sequence); await sequence.StartCaptureAsync(); _dataContext.ImageStream = stream; ... } ... } ... }









. Camera Explorer , XAML Image BitmapImage



. , , , void MediaLibrary.SavePictureToCameraRoll(string name, Stream source)



, .



<phone:PhoneApplicationPage x:Class="CameraExplorer.PreviewPage" ... > ... <Grid x:Name="LayoutRoot" ... > ... <Grid x:Name="ContentPanel" ... > <Image x:Name="image" Stretch="UniformToFill"/> </Grid> </Grid> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar> <shell:ApplicationBarIconButton Text="save" Click="saveButton_Click" ... /> </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> ... </phone:PhoneApplicationPage>







... public partial class PreviewPage : PhoneApplicationPage { private CameraExplorer.DataContext _dataContext = CameraExplorer.DataContext.Singleton; private BitmapImage _bitmap = new BitmapImage(); protected override void OnNavigatedTo(NavigationEventArgs e) { ... _bitmap.SetSource(_dataContext.ImageStream); image.Source = _bitmap; ... } private void saveButton_Click(object sender, EventArgs e) { try { _dataContext.ImageStream.Position = 0; MediaLibrary library = new MediaLibrary(); library.SavePictureToCameraRoll("CameraExplorer_" + DateTime.Now.ToString() + ".jpg", _dataContext.ImageStream); } catch (Exception) { ... } ... } }







Camera Explorer , ArrayParameters



RangeParameters



, Parameters



. , , ComboBox



, Slider



Text



. , .

Parameter



, .



... public abstract class Parameter : INotifyPropertyChanged { ... protected Parameter(PhotoCaptureDevice device, string name) { ... } public PhotoCaptureDevice Device { ... } public string Name { ... } public bool Supported { ... } public abstract void Refresh(); ... }







, . _propertyId



, static CameraCapturePropertyRange PhotoCaptureDevice.GetSupportedPropertyRange(CameraSensorLocation sensor, Guid propertyId)



. object PhotoCaptureDevice.GetProperty(Guid propertyId)



. void PhotoCaptureDevice.SetProperty(Guid propertyId, object value)



.



... public abstract class RangeParameter<T> : Parameter { private Guid _propertyId; private T _value; ... protected RangeParameter(PhotoCaptureDevice device, Guid propertyId, string name) : base(device, name) { ... } public override void Refresh() { try { CameraCapturePropertyRange range = PhotoCaptureDevice.GetSupportedPropertyRange( Device.SensorLocation, _propertyId); if (range == null) { Supported = false; } else { Minimum = (T)range.Min; Maximum = (T)range.Max; _value = (T)Device.GetProperty(_propertyId); Supported = true; } } catch (Exception) { Supported = false; } ... } public T Minimum { ... } public T Maximum { ... } public T Value { ... set { if (!_value.Equals(value)) { try { Device.SetProperty(_propertyId, (T)value); _value = value; ... } catch (Exception) { ... } } } } ... }







ExposureCompensationParameter



, Guid RangeParameter



KnownCameraPhotoProperties.ExposureCompensation



, — , . , Int32



, .



... public class ExposureCompensationParameter : RangeParameter<Int32> { public ExposureCompensationParameter(PhotoCaptureDevice device) : base(device, KnownCameraPhotoProperties.ExposureCompensation, "Exposure compensation") { } ... }







Camera Explorer ArrayParameter



. . — void PopulateOptions()



void SetOption(ArrayParameterOption option)



, .



... public class ArrayParameterOption { ... public ArrayParameterOption(dynamic value, string name) { ... } public dynamic Value { ... } public string Name { ... } ... } public abstract class ArrayParameter : Parameter, IReadOnlyCollection<ArrayParameterOption> { private List<ArrayParameterOption> _options = new List<ArrayParameterOption>(); private ArrayParameterOption _selectedOption; ... public ArrayParameter(PhotoCaptureDevice device, string name) : base(device, name) { ... } public override void Refresh() { ... _options.Clear(); _selectedOption = null; try { PopulateOptions(); Supported = _options.Count > 0; } catch (Exception) { Supported = false; } ... } protected List<ArrayParameterOption> Options { ... } public ArrayParameterOption SelectedOption { ... set { if (_selectedOption != value) { ... if (_selectedOption != null)) { SetOption(value); } _selectedOption = value; } } } protected abstract void PopulateOptions(); protected abstract void SetOption(ArrayParameterOption option); ... }







, , , . void PopulateOptions()



, , ArrayParameterOption



SelectedOption



, void SetOption(ArrayParameterOption option)



. , static IReadOnlyList , KnownCameraPhotoProperties.SceneMode



object PhotoCaptureDevice.GetProperty(Guid propertyId)



. void PhotoCaptureDevice.SetProperty(Guid propertyId, object value)



.



... public class SceneModeParameter : ArrayParameter { public SceneModeParameter(PhotoCaptureDevice device) : base(device, KnownCameraPhotoProperties.SceneMode, "Scene mode") { } protected override void PopulateOptions() { IReadOnlyList<object> supportedValues = PhotoCaptureDevice.GetSupportedPropertyValues( Device.SensorLocation, PropertyId); object value = Device.GetProperty(PropertyId); foreach (dynamic i in supportedValues) { CameraSceneMode csm = (CameraSceneMode)i; ArrayParameterOption option = new ArrayParameterOption(csm, csm.ToString()); Options.Add(option); if (i.Equals(value)) { SelectedOption = option; } } } protected override void SetOption(ArrayParameterOption option) { Device.SetProperty(PropertyId, option.Value); } ... }







Tap-to-focus

«». Tap-to-focus , , , . , Tap-to-focus .



Rectangle



Canvas



, :



<Rectangle x:Name="FocusIndicator" Stroke="Red" Opacity="0.7" Width="80" Height="80" StrokeThickness="5" Visibility="Collapsed"/>







, .

Canvas Tap:



public MainPage() { ... VideoCanvas.Tap += new EventHandler<GestureEventArgs>(videoCanvas_Tap); ... }







. API- , VideoCanvas



, , .



, . , , , .



, , , , .



private async void videoCanvas_Tap(object sender, GestureEventArgs e) { System.Windows.Point uiTapPoint = e.GetPosition(VideoCanvas); if (PhotoCaptureDevice.IsFocusRegionSupported(_dataContext.Device.SensorLocation) && _focusSemaphore.WaitOne(0)) { // . Windows.Foundation.Point tapPoint = new Windows.Foundation.Point(uiTapPoint.X, uiTapPoint.Y); double xRatio = VideoCanvas.ActualWidth / _dataContext.Device.PreviewResolution.Width; double yRatio = VideoCanvas.ActualHeight / _dataContext.Device.PreviewResolution.Height; // , Windows.Foundation.Point displayOrigin = new Windows.Foundation.Point( tapPoint.X - _focusRegionSize.Width / 2, tapPoint.Y - _focusRegionSize.Height / 2); // canvas Windows.Foundation.Point viewFinderOrigin = new Windows.Foundation.Point( displayOrigin.X / xRatio, displayOrigin.Y / yRatio); Windows.Foundation.Rect focusrect = new Windows.Foundation.Rect( viewFinderOrigin, _focusRegionSize); // Windows.Foundation.Rect viewPortRect = new Windows.Foundation.Rect( 0, 0, _dataContext.Device.PreviewResolution.Width, _dataContext.Device.PreviewResolution.Height); focusrect.Intersect(viewPortRect); _dataContext.Device.FocusRegion = focusrect; // FocusIndicator.SetValue(Shape.StrokeProperty, _notFocusedBrush); FocusIndicator.SetValue(Canvas.LeftProperty, uiTapPoint.X - _focusRegionSize.Width / 2); FocusIndicator.SetValue(Canvas.TopProperty, uiTapPoint.Y - _focusRegionSize.Height / 2); FocusIndicator.SetValue(Canvas.VisibilityProperty, Visibility.Visible); CameraFocusStatus status = await _dataContext.Device.FocusAsync(); if (status == CameraFocusStatus.Locked) { FocusIndicator.SetValue(Shape.StrokeProperty, _focusedBrush); _manuallyFocused = true; _dataContext.Device.SetProperty( KnownCameraPhotoProperties.LockedAutoFocusParameters, AutoFocusParameters.Exposure & AutoFocusParameters.Focus & AutoFocusParameters.WhiteBalance); } else { _manuallyFocused = false; _dataContext.Device.SetProperty( KnownCameraPhotoProperties.LockedAutoFocusParameters, AutoFocusParameters.None); } _focusSemaphore.Release(); } }







, . FocusAsync



, , . , WaitOne



, , , false



— , .





, «», Lens Picker. «» , . Lens Picker, XML App:



<Extensions> <Extension ExtensionName="Camera_Capture_App" ConsumerId="{5B04B775-356B-4AA0-AAF8-6491FFEA5631]" TaskId="_default" /> </Extensions>







, Lens Picker, . , Lens Picker Assets



. , Lens design guidelines for Windows Phone .



Maps API.
























static IReadOnlyList

• object GetProperty(Guid propertyId)






void SetProperty(Guid propertyId, object value)







— , .



static bool IsFocusSupported(CameraSensorLocation sensor)





static bool IsFocusRegionSupported(CameraSensorLocation sensor)





IAsyncOperation FocusAsync()

• IAsyncOperation ResetFocusAsync()



— .



• static IReadOnlyList GetAvailablePreviewResolutions()

• static IReadOnlyList GetAvailableCaptureResolutions()

• IAsyncAction SetPreviewResolutionAsync(Size value)






IAsyncAction SetCaptureResolutionAsync(Size value)







— .



event TypedEventHandler<ICameraCaptureDevice, Object> PreviewFrameAvailable





void GetPreviewBufferArgb(out int[] pixels)





void GetPreviewBufferY(out byte[] pixels)





void GetPreviewBufferYCbCr(out byte[] pixels)







— .



CameraCaptureSequence CreateCaptureSequence(uint numberOfFrames)





IAsyncAction PrepareCaptureSequenceAsync(CameraCaptureSequence sequence)







— . . API . GUID. , .

, ID_CAP_ISV_CAMERA



WMAppManifest.xml . ID_CAP_MEDIALIB_PHOTO



.



Lumia

Nokia Lumia 820 920.





Camera Explorer — , PhotoCaptureDevice



. , .







, Camera Explorer.







Windows Phone DataContext



, Settings



PhotoCaptureDevice



.

PhotoCaptureDevice



DataContext, , , PhotoCaptureDevice



, , MainPage, .



Camera Explorer .

, PhotoCaptureDevice , Camera Explorer. , , . .



DataContext, , .



... class DataContext : INotifyPropertyChanged { ... public static DataContext Singleton { ... } public ObservableCollection<Parameter> Parameters { ... } public PhotoCaptureDevice Device { ... } public MemoryStream ImageStream { ... } }









, PhotoCaptureDevice



. MainPage xaml Canvas



VideoBrush



, .



<phone:PhoneApplicationPage x:Class="CameraExplorer.MainPage" ... > ... <Grid x:Name="LayoutRoot" ... > ... <Grid x:Name="ContentPanel" ... > <Canvas x:Name="VideoCanvas"> <Canvas.Background> <VideoBrush x:Name="videoBrush"/> </Canvas.Background> </Canvas> ... </Grid> </Grid> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar> <shell:ApplicationBarIconButton Text="capture" Click="captureButton_Click" ... /> ... </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> ... </phone:PhoneApplicationPage>







C# MainPage PhotoCaptureDevice



InitializeCamera



, DataContext. , XAML, , .



... public partial class MainPage : PhoneApplicationPage { private CameraExplorer.DataContext _dataContext = CameraExplorer.DataContext.Singleton; ... protected async override void OnNavigatedTo(NavigationEventArgs e) { if (_dataContext.Device == null) { ... await InitializeCamera(CameraSensorLocation.Back); ... } videoBrush.RelativeTransform = new CompositeTransform() { CenterX = 0.5, CenterY = 0.5, Rotation = _dataContext.Device.SensorLocation == CameraSensorLocation.Back ? _dataContext.Device.SensorRotationInDegrees : - _dataContext.Device.SensorRotationInDegrees }; videoBrush.SetSource(_dataContext.Device); ... } 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 void captureButton_Click(object sender, EventArgs e) { if (!_manuallyFocused) { await AutoFocus(); } await Capture(); } private async Task AutoFocus() { if (!_capturing && PhotoCaptureDevice.IsFocusSupported(_dataContext.Device.SensorLocation)) { ... await _dataContext.Device.FocusAsync(); ... _capturing = false; } } private async Task Capture() { if (!_capturing) { _capturing = true; MemoryStream stream = new MemoryStream(); CameraCaptureSequence sequence = _dataContext.Device.CreateCaptureSequence(1); sequence.Frames[0].CaptureStream = stream.AsOutputStream(); await _dataContext.Device.PrepareCaptureSequenceAsync(sequence); await sequence.StartCaptureAsync(); _dataContext.ImageStream = stream; ... } ... } ... }









. Camera Explorer , XAML Image BitmapImage



. , , , void MediaLibrary.SavePictureToCameraRoll(string name, Stream source)



, .



<phone:PhoneApplicationPage x:Class="CameraExplorer.PreviewPage" ... > ... <Grid x:Name="LayoutRoot" ... > ... <Grid x:Name="ContentPanel" ... > <Image x:Name="image" Stretch="UniformToFill"/> </Grid> </Grid> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar> <shell:ApplicationBarIconButton Text="save" Click="saveButton_Click" ... /> </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> ... </phone:PhoneApplicationPage>







... public partial class PreviewPage : PhoneApplicationPage { private CameraExplorer.DataContext _dataContext = CameraExplorer.DataContext.Singleton; private BitmapImage _bitmap = new BitmapImage(); protected override void OnNavigatedTo(NavigationEventArgs e) { ... _bitmap.SetSource(_dataContext.ImageStream); image.Source = _bitmap; ... } private void saveButton_Click(object sender, EventArgs e) { try { _dataContext.ImageStream.Position = 0; MediaLibrary library = new MediaLibrary(); library.SavePictureToCameraRoll("CameraExplorer_" + DateTime.Now.ToString() + ".jpg", _dataContext.ImageStream); } catch (Exception) { ... } ... } }







Camera Explorer , ArrayParameters



RangeParameters



, Parameters



. , , ComboBox



, Slider



Text



. , .

Parameter



, .



... public abstract class Parameter : INotifyPropertyChanged { ... protected Parameter(PhotoCaptureDevice device, string name) { ... } public PhotoCaptureDevice Device { ... } public string Name { ... } public bool Supported { ... } public abstract void Refresh(); ... }







, . _propertyId



, static CameraCapturePropertyRange PhotoCaptureDevice.GetSupportedPropertyRange(CameraSensorLocation sensor, Guid propertyId)



. object PhotoCaptureDevice.GetProperty(Guid propertyId)



. void PhotoCaptureDevice.SetProperty(Guid propertyId, object value)



.



... public abstract class RangeParameter<T> : Parameter { private Guid _propertyId; private T _value; ... protected RangeParameter(PhotoCaptureDevice device, Guid propertyId, string name) : base(device, name) { ... } public override void Refresh() { try { CameraCapturePropertyRange range = PhotoCaptureDevice.GetSupportedPropertyRange( Device.SensorLocation, _propertyId); if (range == null) { Supported = false; } else { Minimum = (T)range.Min; Maximum = (T)range.Max; _value = (T)Device.GetProperty(_propertyId); Supported = true; } } catch (Exception) { Supported = false; } ... } public T Minimum { ... } public T Maximum { ... } public T Value { ... set { if (!_value.Equals(value)) { try { Device.SetProperty(_propertyId, (T)value); _value = value; ... } catch (Exception) { ... } } } } ... }







ExposureCompensationParameter



, Guid RangeParameter



KnownCameraPhotoProperties.ExposureCompensation



, — , . , Int32



, .



... public class ExposureCompensationParameter : RangeParameter<Int32> { public ExposureCompensationParameter(PhotoCaptureDevice device) : base(device, KnownCameraPhotoProperties.ExposureCompensation, "Exposure compensation") { } ... }







Camera Explorer ArrayParameter



. . — void PopulateOptions()



void SetOption(ArrayParameterOption option)



, .



... public class ArrayParameterOption { ... public ArrayParameterOption(dynamic value, string name) { ... } public dynamic Value { ... } public string Name { ... } ... } public abstract class ArrayParameter : Parameter, IReadOnlyCollection<ArrayParameterOption> { private List<ArrayParameterOption> _options = new List<ArrayParameterOption>(); private ArrayParameterOption _selectedOption; ... public ArrayParameter(PhotoCaptureDevice device, string name) : base(device, name) { ... } public override void Refresh() { ... _options.Clear(); _selectedOption = null; try { PopulateOptions(); Supported = _options.Count > 0; } catch (Exception) { Supported = false; } ... } protected List<ArrayParameterOption> Options { ... } public ArrayParameterOption SelectedOption { ... set { if (_selectedOption != value) { ... if (_selectedOption != null)) { SetOption(value); } _selectedOption = value; } } } protected abstract void PopulateOptions(); protected abstract void SetOption(ArrayParameterOption option); ... }







, , , . void PopulateOptions()



, , ArrayParameterOption



SelectedOption



, void SetOption(ArrayParameterOption option)



. , static IReadOnlyList , KnownCameraPhotoProperties.SceneMode



object PhotoCaptureDevice.GetProperty(Guid propertyId)



. void PhotoCaptureDevice.SetProperty(Guid propertyId, object value)



.



... public class SceneModeParameter : ArrayParameter { public SceneModeParameter(PhotoCaptureDevice device) : base(device, KnownCameraPhotoProperties.SceneMode, "Scene mode") { } protected override void PopulateOptions() { IReadOnlyList<object> supportedValues = PhotoCaptureDevice.GetSupportedPropertyValues( Device.SensorLocation, PropertyId); object value = Device.GetProperty(PropertyId); foreach (dynamic i in supportedValues) { CameraSceneMode csm = (CameraSceneMode)i; ArrayParameterOption option = new ArrayParameterOption(csm, csm.ToString()); Options.Add(option); if (i.Equals(value)) { SelectedOption = option; } } } protected override void SetOption(ArrayParameterOption option) { Device.SetProperty(PropertyId, option.Value); } ... }







Tap-to-focus

«». Tap-to-focus , , , . , Tap-to-focus .



Rectangle



Canvas



, :



<Rectangle x:Name="FocusIndicator" Stroke="Red" Opacity="0.7" Width="80" Height="80" StrokeThickness="5" Visibility="Collapsed"/>







, .

Canvas Tap:



public MainPage() { ... VideoCanvas.Tap += new EventHandler<GestureEventArgs>(videoCanvas_Tap); ... }







. API- , VideoCanvas



, , .



, . , , , .



, , , , .



private async void videoCanvas_Tap(object sender, GestureEventArgs e) { System.Windows.Point uiTapPoint = e.GetPosition(VideoCanvas); if (PhotoCaptureDevice.IsFocusRegionSupported(_dataContext.Device.SensorLocation) && _focusSemaphore.WaitOne(0)) { // . Windows.Foundation.Point tapPoint = new Windows.Foundation.Point(uiTapPoint.X, uiTapPoint.Y); double xRatio = VideoCanvas.ActualWidth / _dataContext.Device.PreviewResolution.Width; double yRatio = VideoCanvas.ActualHeight / _dataContext.Device.PreviewResolution.Height; // , Windows.Foundation.Point displayOrigin = new Windows.Foundation.Point( tapPoint.X - _focusRegionSize.Width / 2, tapPoint.Y - _focusRegionSize.Height / 2); // canvas Windows.Foundation.Point viewFinderOrigin = new Windows.Foundation.Point( displayOrigin.X / xRatio, displayOrigin.Y / yRatio); Windows.Foundation.Rect focusrect = new Windows.Foundation.Rect( viewFinderOrigin, _focusRegionSize); // Windows.Foundation.Rect viewPortRect = new Windows.Foundation.Rect( 0, 0, _dataContext.Device.PreviewResolution.Width, _dataContext.Device.PreviewResolution.Height); focusrect.Intersect(viewPortRect); _dataContext.Device.FocusRegion = focusrect; // FocusIndicator.SetValue(Shape.StrokeProperty, _notFocusedBrush); FocusIndicator.SetValue(Canvas.LeftProperty, uiTapPoint.X - _focusRegionSize.Width / 2); FocusIndicator.SetValue(Canvas.TopProperty, uiTapPoint.Y - _focusRegionSize.Height / 2); FocusIndicator.SetValue(Canvas.VisibilityProperty, Visibility.Visible); CameraFocusStatus status = await _dataContext.Device.FocusAsync(); if (status == CameraFocusStatus.Locked) { FocusIndicator.SetValue(Shape.StrokeProperty, _focusedBrush); _manuallyFocused = true; _dataContext.Device.SetProperty( KnownCameraPhotoProperties.LockedAutoFocusParameters, AutoFocusParameters.Exposure & AutoFocusParameters.Focus & AutoFocusParameters.WhiteBalance); } else { _manuallyFocused = false; _dataContext.Device.SetProperty( KnownCameraPhotoProperties.LockedAutoFocusParameters, AutoFocusParameters.None); } _focusSemaphore.Release(); } }







, . FocusAsync



, , . , WaitOne



, , , false



— , .





, «», Lens Picker. «» , . Lens Picker, XML App:



<Extensions> <Extension ExtensionName="Camera_Capture_App" ConsumerId="{5B04B775-356B-4AA0-AAF8-6491FFEA5631]" TaskId="_default" /> </Extensions>







, Lens Picker, . , Lens Picker Assets



. , Lens design guidelines for Windows Phone .



Maps API.
























static IReadOnlyList

• object GetProperty(Guid propertyId)






void SetProperty(Guid propertyId, object value)







— , .



static bool IsFocusSupported(CameraSensorLocation sensor)





static bool IsFocusRegionSupported(CameraSensorLocation sensor)





IAsyncOperation FocusAsync()

• IAsyncOperation ResetFocusAsync()



— .



• static IReadOnlyList GetAvailablePreviewResolutions()

• static IReadOnlyList GetAvailableCaptureResolutions()

• IAsyncAction SetPreviewResolutionAsync(Size value)






IAsyncAction SetCaptureResolutionAsync(Size value)







— .



event TypedEventHandler<ICameraCaptureDevice, Object> PreviewFrameAvailable





void GetPreviewBufferArgb(out int[] pixels)





void GetPreviewBufferY(out byte[] pixels)





void GetPreviewBufferYCbCr(out byte[] pixels)







— .



CameraCaptureSequence CreateCaptureSequence(uint numberOfFrames)





IAsyncAction PrepareCaptureSequenceAsync(CameraCaptureSequence sequence)







— . . API . GUID. , .

, ID_CAP_ISV_CAMERA



WMAppManifest.xml . ID_CAP_MEDIALIB_PHOTO



.



Lumia

Nokia Lumia 820 920.





Camera Explorer — , PhotoCaptureDevice



. , .







, Camera Explorer.







Windows Phone DataContext



, Settings



PhotoCaptureDevice



.

PhotoCaptureDevice



DataContext, , , PhotoCaptureDevice



, , MainPage, .



Camera Explorer .

, PhotoCaptureDevice , Camera Explorer. , , . .



DataContext, , .



... class DataContext : INotifyPropertyChanged { ... public static DataContext Singleton { ... } public ObservableCollection<Parameter> Parameters { ... } public PhotoCaptureDevice Device { ... } public MemoryStream ImageStream { ... } }









, PhotoCaptureDevice



. MainPage xaml Canvas



VideoBrush



, .



<phone:PhoneApplicationPage x:Class="CameraExplorer.MainPage" ... > ... <Grid x:Name="LayoutRoot" ... > ... <Grid x:Name="ContentPanel" ... > <Canvas x:Name="VideoCanvas"> <Canvas.Background> <VideoBrush x:Name="videoBrush"/> </Canvas.Background> </Canvas> ... </Grid> </Grid> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar> <shell:ApplicationBarIconButton Text="capture" Click="captureButton_Click" ... /> ... </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> ... </phone:PhoneApplicationPage>







C# MainPage PhotoCaptureDevice



InitializeCamera



, DataContext. , XAML, , .



... public partial class MainPage : PhoneApplicationPage { private CameraExplorer.DataContext _dataContext = CameraExplorer.DataContext.Singleton; ... protected async override void OnNavigatedTo(NavigationEventArgs e) { if (_dataContext.Device == null) { ... await InitializeCamera(CameraSensorLocation.Back); ... } videoBrush.RelativeTransform = new CompositeTransform() { CenterX = 0.5, CenterY = 0.5, Rotation = _dataContext.Device.SensorLocation == CameraSensorLocation.Back ? _dataContext.Device.SensorRotationInDegrees : - _dataContext.Device.SensorRotationInDegrees }; videoBrush.SetSource(_dataContext.Device); ... } 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 void captureButton_Click(object sender, EventArgs e) { if (!_manuallyFocused) { await AutoFocus(); } await Capture(); } private async Task AutoFocus() { if (!_capturing && PhotoCaptureDevice.IsFocusSupported(_dataContext.Device.SensorLocation)) { ... await _dataContext.Device.FocusAsync(); ... _capturing = false; } } private async Task Capture() { if (!_capturing) { _capturing = true; MemoryStream stream = new MemoryStream(); CameraCaptureSequence sequence = _dataContext.Device.CreateCaptureSequence(1); sequence.Frames[0].CaptureStream = stream.AsOutputStream(); await _dataContext.Device.PrepareCaptureSequenceAsync(sequence); await sequence.StartCaptureAsync(); _dataContext.ImageStream = stream; ... } ... } ... }









. Camera Explorer , XAML Image BitmapImage



. , , , void MediaLibrary.SavePictureToCameraRoll(string name, Stream source)



, .



<phone:PhoneApplicationPage x:Class="CameraExplorer.PreviewPage" ... > ... <Grid x:Name="LayoutRoot" ... > ... <Grid x:Name="ContentPanel" ... > <Image x:Name="image" Stretch="UniformToFill"/> </Grid> </Grid> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar> <shell:ApplicationBarIconButton Text="save" Click="saveButton_Click" ... /> </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> ... </phone:PhoneApplicationPage>







... public partial class PreviewPage : PhoneApplicationPage { private CameraExplorer.DataContext _dataContext = CameraExplorer.DataContext.Singleton; private BitmapImage _bitmap = new BitmapImage(); protected override void OnNavigatedTo(NavigationEventArgs e) { ... _bitmap.SetSource(_dataContext.ImageStream); image.Source = _bitmap; ... } private void saveButton_Click(object sender, EventArgs e) { try { _dataContext.ImageStream.Position = 0; MediaLibrary library = new MediaLibrary(); library.SavePictureToCameraRoll("CameraExplorer_" + DateTime.Now.ToString() + ".jpg", _dataContext.ImageStream); } catch (Exception) { ... } ... } }







Camera Explorer , ArrayParameters



RangeParameters



, Parameters



. , , ComboBox



, Slider



Text



. , .

Parameter



, .



... public abstract class Parameter : INotifyPropertyChanged { ... protected Parameter(PhotoCaptureDevice device, string name) { ... } public PhotoCaptureDevice Device { ... } public string Name { ... } public bool Supported { ... } public abstract void Refresh(); ... }







, . _propertyId



, static CameraCapturePropertyRange PhotoCaptureDevice.GetSupportedPropertyRange(CameraSensorLocation sensor, Guid propertyId)



. object PhotoCaptureDevice.GetProperty(Guid propertyId)



. void PhotoCaptureDevice.SetProperty(Guid propertyId, object value)



.



... public abstract class RangeParameter<T> : Parameter { private Guid _propertyId; private T _value; ... protected RangeParameter(PhotoCaptureDevice device, Guid propertyId, string name) : base(device, name) { ... } public override void Refresh() { try { CameraCapturePropertyRange range = PhotoCaptureDevice.GetSupportedPropertyRange( Device.SensorLocation, _propertyId); if (range == null) { Supported = false; } else { Minimum = (T)range.Min; Maximum = (T)range.Max; _value = (T)Device.GetProperty(_propertyId); Supported = true; } } catch (Exception) { Supported = false; } ... } public T Minimum { ... } public T Maximum { ... } public T Value { ... set { if (!_value.Equals(value)) { try { Device.SetProperty(_propertyId, (T)value); _value = value; ... } catch (Exception) { ... } } } } ... }







ExposureCompensationParameter



, Guid RangeParameter



KnownCameraPhotoProperties.ExposureCompensation



, — , . , Int32



, .



... public class ExposureCompensationParameter : RangeParameter<Int32> { public ExposureCompensationParameter(PhotoCaptureDevice device) : base(device, KnownCameraPhotoProperties.ExposureCompensation, "Exposure compensation") { } ... }







Camera Explorer ArrayParameter



. . — void PopulateOptions()



void SetOption(ArrayParameterOption option)



, .



... public class ArrayParameterOption { ... public ArrayParameterOption(dynamic value, string name) { ... } public dynamic Value { ... } public string Name { ... } ... } public abstract class ArrayParameter : Parameter, IReadOnlyCollection<ArrayParameterOption> { private List<ArrayParameterOption> _options = new List<ArrayParameterOption>(); private ArrayParameterOption _selectedOption; ... public ArrayParameter(PhotoCaptureDevice device, string name) : base(device, name) { ... } public override void Refresh() { ... _options.Clear(); _selectedOption = null; try { PopulateOptions(); Supported = _options.Count > 0; } catch (Exception) { Supported = false; } ... } protected List<ArrayParameterOption> Options { ... } public ArrayParameterOption SelectedOption { ... set { if (_selectedOption != value) { ... if (_selectedOption != null)) { SetOption(value); } _selectedOption = value; } } } protected abstract void PopulateOptions(); protected abstract void SetOption(ArrayParameterOption option); ... }







, , , . void PopulateOptions()



, , ArrayParameterOption



SelectedOption



, void SetOption(ArrayParameterOption option)



. , static IReadOnlyList , KnownCameraPhotoProperties.SceneMode



object PhotoCaptureDevice.GetProperty(Guid propertyId)



. void PhotoCaptureDevice.SetProperty(Guid propertyId, object value)



.



... public class SceneModeParameter : ArrayParameter { public SceneModeParameter(PhotoCaptureDevice device) : base(device, KnownCameraPhotoProperties.SceneMode, "Scene mode") { } protected override void PopulateOptions() { IReadOnlyList<object> supportedValues = PhotoCaptureDevice.GetSupportedPropertyValues( Device.SensorLocation, PropertyId); object value = Device.GetProperty(PropertyId); foreach (dynamic i in supportedValues) { CameraSceneMode csm = (CameraSceneMode)i; ArrayParameterOption option = new ArrayParameterOption(csm, csm.ToString()); Options.Add(option); if (i.Equals(value)) { SelectedOption = option; } } } protected override void SetOption(ArrayParameterOption option) { Device.SetProperty(PropertyId, option.Value); } ... }







Tap-to-focus

«». Tap-to-focus , , , . , Tap-to-focus .



Rectangle



Canvas



, :



<Rectangle x:Name="FocusIndicator" Stroke="Red" Opacity="0.7" Width="80" Height="80" StrokeThickness="5" Visibility="Collapsed"/>







, .

Canvas Tap:



public MainPage() { ... VideoCanvas.Tap += new EventHandler<GestureEventArgs>(videoCanvas_Tap); ... }







. API- , VideoCanvas



, , .



, . , , , .



, , , , .



private async void videoCanvas_Tap(object sender, GestureEventArgs e) { System.Windows.Point uiTapPoint = e.GetPosition(VideoCanvas); if (PhotoCaptureDevice.IsFocusRegionSupported(_dataContext.Device.SensorLocation) && _focusSemaphore.WaitOne(0)) { // . Windows.Foundation.Point tapPoint = new Windows.Foundation.Point(uiTapPoint.X, uiTapPoint.Y); double xRatio = VideoCanvas.ActualWidth / _dataContext.Device.PreviewResolution.Width; double yRatio = VideoCanvas.ActualHeight / _dataContext.Device.PreviewResolution.Height; // , Windows.Foundation.Point displayOrigin = new Windows.Foundation.Point( tapPoint.X - _focusRegionSize.Width / 2, tapPoint.Y - _focusRegionSize.Height / 2); // canvas Windows.Foundation.Point viewFinderOrigin = new Windows.Foundation.Point( displayOrigin.X / xRatio, displayOrigin.Y / yRatio); Windows.Foundation.Rect focusrect = new Windows.Foundation.Rect( viewFinderOrigin, _focusRegionSize); // Windows.Foundation.Rect viewPortRect = new Windows.Foundation.Rect( 0, 0, _dataContext.Device.PreviewResolution.Width, _dataContext.Device.PreviewResolution.Height); focusrect.Intersect(viewPortRect); _dataContext.Device.FocusRegion = focusrect; // FocusIndicator.SetValue(Shape.StrokeProperty, _notFocusedBrush); FocusIndicator.SetValue(Canvas.LeftProperty, uiTapPoint.X - _focusRegionSize.Width / 2); FocusIndicator.SetValue(Canvas.TopProperty, uiTapPoint.Y - _focusRegionSize.Height / 2); FocusIndicator.SetValue(Canvas.VisibilityProperty, Visibility.Visible); CameraFocusStatus status = await _dataContext.Device.FocusAsync(); if (status == CameraFocusStatus.Locked) { FocusIndicator.SetValue(Shape.StrokeProperty, _focusedBrush); _manuallyFocused = true; _dataContext.Device.SetProperty( KnownCameraPhotoProperties.LockedAutoFocusParameters, AutoFocusParameters.Exposure & AutoFocusParameters.Focus & AutoFocusParameters.WhiteBalance); } else { _manuallyFocused = false; _dataContext.Device.SetProperty( KnownCameraPhotoProperties.LockedAutoFocusParameters, AutoFocusParameters.None); } _focusSemaphore.Release(); } }







, . FocusAsync



, , . , WaitOne



, , , false



— , .





, «», Lens Picker. «» , . Lens Picker, XML App:



<Extensions> <Extension ExtensionName="Camera_Capture_App" ConsumerId="{5B04B775-356B-4AA0-AAF8-6491FFEA5631]" TaskId="_default" /> </Extensions>







, Lens Picker, . , Lens Picker Assets



. , Lens design guidelines for Windows Phone .



Maps API.
























static IReadOnlyList

• object GetProperty(Guid propertyId)






void SetProperty(Guid propertyId, object value)







— , .



static bool IsFocusSupported(CameraSensorLocation sensor)





static bool IsFocusRegionSupported(CameraSensorLocation sensor)





IAsyncOperation FocusAsync()

• IAsyncOperation ResetFocusAsync()



— .



• static IReadOnlyList GetAvailablePreviewResolutions()

• static IReadOnlyList GetAvailableCaptureResolutions()

• IAsyncAction SetPreviewResolutionAsync(Size value)






IAsyncAction SetCaptureResolutionAsync(Size value)







— .



event TypedEventHandler<ICameraCaptureDevice, Object> PreviewFrameAvailable





void GetPreviewBufferArgb(out int[] pixels)





void GetPreviewBufferY(out byte[] pixels)





void GetPreviewBufferYCbCr(out byte[] pixels)







— .



CameraCaptureSequence CreateCaptureSequence(uint numberOfFrames)





IAsyncAction PrepareCaptureSequenceAsync(CameraCaptureSequence sequence)







— . . API . GUID. , .

, ID_CAP_ISV_CAMERA



WMAppManifest.xml . ID_CAP_MEDIALIB_PHOTO



.



Lumia

Nokia Lumia 820 920.





Camera Explorer — , PhotoCaptureDevice



. , .







, Camera Explorer.







Windows Phone DataContext



, Settings



PhotoCaptureDevice



.

PhotoCaptureDevice



DataContext, , , PhotoCaptureDevice



, , MainPage, .



Camera Explorer .

, PhotoCaptureDevice , Camera Explorer. , , . .



DataContext, , .



... class DataContext : INotifyPropertyChanged { ... public static DataContext Singleton { ... } public ObservableCollection<Parameter> Parameters { ... } public PhotoCaptureDevice Device { ... } public MemoryStream ImageStream { ... } }









, PhotoCaptureDevice



. MainPage xaml Canvas



VideoBrush



, .



<phone:PhoneApplicationPage x:Class="CameraExplorer.MainPage" ... > ... <Grid x:Name="LayoutRoot" ... > ... <Grid x:Name="ContentPanel" ... > <Canvas x:Name="VideoCanvas"> <Canvas.Background> <VideoBrush x:Name="videoBrush"/> </Canvas.Background> </Canvas> ... </Grid> </Grid> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar> <shell:ApplicationBarIconButton Text="capture" Click="captureButton_Click" ... /> ... </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> ... </phone:PhoneApplicationPage>







C# MainPage PhotoCaptureDevice



InitializeCamera



, DataContext. , XAML, , .



... public partial class MainPage : PhoneApplicationPage { private CameraExplorer.DataContext _dataContext = CameraExplorer.DataContext.Singleton; ... protected async override void OnNavigatedTo(NavigationEventArgs e) { if (_dataContext.Device == null) { ... await InitializeCamera(CameraSensorLocation.Back); ... } videoBrush.RelativeTransform = new CompositeTransform() { CenterX = 0.5, CenterY = 0.5, Rotation = _dataContext.Device.SensorLocation == CameraSensorLocation.Back ? _dataContext.Device.SensorRotationInDegrees : - _dataContext.Device.SensorRotationInDegrees }; videoBrush.SetSource(_dataContext.Device); ... } 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 void captureButton_Click(object sender, EventArgs e) { if (!_manuallyFocused) { await AutoFocus(); } await Capture(); } private async Task AutoFocus() { if (!_capturing && PhotoCaptureDevice.IsFocusSupported(_dataContext.Device.SensorLocation)) { ... await _dataContext.Device.FocusAsync(); ... _capturing = false; } } private async Task Capture() { if (!_capturing) { _capturing = true; MemoryStream stream = new MemoryStream(); CameraCaptureSequence sequence = _dataContext.Device.CreateCaptureSequence(1); sequence.Frames[0].CaptureStream = stream.AsOutputStream(); await _dataContext.Device.PrepareCaptureSequenceAsync(sequence); await sequence.StartCaptureAsync(); _dataContext.ImageStream = stream; ... } ... } ... }









. Camera Explorer , XAML Image BitmapImage



. , , , void MediaLibrary.SavePictureToCameraRoll(string name, Stream source)



, .



<phone:PhoneApplicationPage x:Class="CameraExplorer.PreviewPage" ... > ... <Grid x:Name="LayoutRoot" ... > ... <Grid x:Name="ContentPanel" ... > <Image x:Name="image" Stretch="UniformToFill"/> </Grid> </Grid> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar> <shell:ApplicationBarIconButton Text="save" Click="saveButton_Click" ... /> </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> ... </phone:PhoneApplicationPage>







... public partial class PreviewPage : PhoneApplicationPage { private CameraExplorer.DataContext _dataContext = CameraExplorer.DataContext.Singleton; private BitmapImage _bitmap = new BitmapImage(); protected override void OnNavigatedTo(NavigationEventArgs e) { ... _bitmap.SetSource(_dataContext.ImageStream); image.Source = _bitmap; ... } private void saveButton_Click(object sender, EventArgs e) { try { _dataContext.ImageStream.Position = 0; MediaLibrary library = new MediaLibrary(); library.SavePictureToCameraRoll("CameraExplorer_" + DateTime.Now.ToString() + ".jpg", _dataContext.ImageStream); } catch (Exception) { ... } ... } }







Camera Explorer , ArrayParameters



RangeParameters



, Parameters



. , , ComboBox



, Slider



Text



. , .

Parameter



, .



... public abstract class Parameter : INotifyPropertyChanged { ... protected Parameter(PhotoCaptureDevice device, string name) { ... } public PhotoCaptureDevice Device { ... } public string Name { ... } public bool Supported { ... } public abstract void Refresh(); ... }







, . _propertyId



, static CameraCapturePropertyRange PhotoCaptureDevice.GetSupportedPropertyRange(CameraSensorLocation sensor, Guid propertyId)



. object PhotoCaptureDevice.GetProperty(Guid propertyId)



. void PhotoCaptureDevice.SetProperty(Guid propertyId, object value)



.



... public abstract class RangeParameter<T> : Parameter { private Guid _propertyId; private T _value; ... protected RangeParameter(PhotoCaptureDevice device, Guid propertyId, string name) : base(device, name) { ... } public override void Refresh() { try { CameraCapturePropertyRange range = PhotoCaptureDevice.GetSupportedPropertyRange( Device.SensorLocation, _propertyId); if (range == null) { Supported = false; } else { Minimum = (T)range.Min; Maximum = (T)range.Max; _value = (T)Device.GetProperty(_propertyId); Supported = true; } } catch (Exception) { Supported = false; } ... } public T Minimum { ... } public T Maximum { ... } public T Value { ... set { if (!_value.Equals(value)) { try { Device.SetProperty(_propertyId, (T)value); _value = value; ... } catch (Exception) { ... } } } } ... }







ExposureCompensationParameter



, Guid RangeParameter



KnownCameraPhotoProperties.ExposureCompensation



, — , . , Int32



, .



... public class ExposureCompensationParameter : RangeParameter<Int32> { public ExposureCompensationParameter(PhotoCaptureDevice device) : base(device, KnownCameraPhotoProperties.ExposureCompensation, "Exposure compensation") { } ... }







Camera Explorer ArrayParameter



. . — void PopulateOptions()



void SetOption(ArrayParameterOption option)



, .



... public class ArrayParameterOption { ... public ArrayParameterOption(dynamic value, string name) { ... } public dynamic Value { ... } public string Name { ... } ... } public abstract class ArrayParameter : Parameter, IReadOnlyCollection<ArrayParameterOption> { private List<ArrayParameterOption> _options = new List<ArrayParameterOption>(); private ArrayParameterOption _selectedOption; ... public ArrayParameter(PhotoCaptureDevice device, string name) : base(device, name) { ... } public override void Refresh() { ... _options.Clear(); _selectedOption = null; try { PopulateOptions(); Supported = _options.Count > 0; } catch (Exception) { Supported = false; } ... } protected List<ArrayParameterOption> Options { ... } public ArrayParameterOption SelectedOption { ... set { if (_selectedOption != value) { ... if (_selectedOption != null)) { SetOption(value); } _selectedOption = value; } } } protected abstract void PopulateOptions(); protected abstract void SetOption(ArrayParameterOption option); ... }







, , , . void PopulateOptions()



, , ArrayParameterOption



SelectedOption



, void SetOption(ArrayParameterOption option)



. , static IReadOnlyList , KnownCameraPhotoProperties.SceneMode



object PhotoCaptureDevice.GetProperty(Guid propertyId)



. void PhotoCaptureDevice.SetProperty(Guid propertyId, object value)



.



... public class SceneModeParameter : ArrayParameter { public SceneModeParameter(PhotoCaptureDevice device) : base(device, KnownCameraPhotoProperties.SceneMode, "Scene mode") { } protected override void PopulateOptions() { IReadOnlyList<object> supportedValues = PhotoCaptureDevice.GetSupportedPropertyValues( Device.SensorLocation, PropertyId); object value = Device.GetProperty(PropertyId); foreach (dynamic i in supportedValues) { CameraSceneMode csm = (CameraSceneMode)i; ArrayParameterOption option = new ArrayParameterOption(csm, csm.ToString()); Options.Add(option); if (i.Equals(value)) { SelectedOption = option; } } } protected override void SetOption(ArrayParameterOption option) { Device.SetProperty(PropertyId, option.Value); } ... }







Tap-to-focus

«». Tap-to-focus , , , . , Tap-to-focus .



Rectangle



Canvas



, :



<Rectangle x:Name="FocusIndicator" Stroke="Red" Opacity="0.7" Width="80" Height="80" StrokeThickness="5" Visibility="Collapsed"/>







, .

Canvas Tap:



public MainPage() { ... VideoCanvas.Tap += new EventHandler<GestureEventArgs>(videoCanvas_Tap); ... }







. API- , VideoCanvas



, , .



, . , , , .



, , , , .



private async void videoCanvas_Tap(object sender, GestureEventArgs e) { System.Windows.Point uiTapPoint = e.GetPosition(VideoCanvas); if (PhotoCaptureDevice.IsFocusRegionSupported(_dataContext.Device.SensorLocation) && _focusSemaphore.WaitOne(0)) { // . Windows.Foundation.Point tapPoint = new Windows.Foundation.Point(uiTapPoint.X, uiTapPoint.Y); double xRatio = VideoCanvas.ActualWidth / _dataContext.Device.PreviewResolution.Width; double yRatio = VideoCanvas.ActualHeight / _dataContext.Device.PreviewResolution.Height; // , Windows.Foundation.Point displayOrigin = new Windows.Foundation.Point( tapPoint.X - _focusRegionSize.Width / 2, tapPoint.Y - _focusRegionSize.Height / 2); // canvas Windows.Foundation.Point viewFinderOrigin = new Windows.Foundation.Point( displayOrigin.X / xRatio, displayOrigin.Y / yRatio); Windows.Foundation.Rect focusrect = new Windows.Foundation.Rect( viewFinderOrigin, _focusRegionSize); // Windows.Foundation.Rect viewPortRect = new Windows.Foundation.Rect( 0, 0, _dataContext.Device.PreviewResolution.Width, _dataContext.Device.PreviewResolution.Height); focusrect.Intersect(viewPortRect); _dataContext.Device.FocusRegion = focusrect; // FocusIndicator.SetValue(Shape.StrokeProperty, _notFocusedBrush); FocusIndicator.SetValue(Canvas.LeftProperty, uiTapPoint.X - _focusRegionSize.Width / 2); FocusIndicator.SetValue(Canvas.TopProperty, uiTapPoint.Y - _focusRegionSize.Height / 2); FocusIndicator.SetValue(Canvas.VisibilityProperty, Visibility.Visible); CameraFocusStatus status = await _dataContext.Device.FocusAsync(); if (status == CameraFocusStatus.Locked) { FocusIndicator.SetValue(Shape.StrokeProperty, _focusedBrush); _manuallyFocused = true; _dataContext.Device.SetProperty( KnownCameraPhotoProperties.LockedAutoFocusParameters, AutoFocusParameters.Exposure & AutoFocusParameters.Focus & AutoFocusParameters.WhiteBalance); } else { _manuallyFocused = false; _dataContext.Device.SetProperty( KnownCameraPhotoProperties.LockedAutoFocusParameters, AutoFocusParameters.None); } _focusSemaphore.Release(); } }







, . FocusAsync



, , . , WaitOne



, , , false



— , .





, «», Lens Picker. «» , . Lens Picker, XML App:



<Extensions> <Extension ExtensionName="Camera_Capture_App" ConsumerId="{5B04B775-356B-4AA0-AAF8-6491FFEA5631]" TaskId="_default" /> </Extensions>







, Lens Picker, . , Lens Picker Assets



. , Lens design guidelines for Windows Phone .



Maps API.
























 static IReadOnlyList 
      

object GetProperty(Guid propertyId)






void SetProperty(Guid propertyId, object value)







— , .



static bool IsFocusSupported(CameraSensorLocation sensor)





static bool IsFocusRegionSupported(CameraSensorLocation sensor)





IAsyncOperation FocusAsync()

• IAsyncOperation ResetFocusAsync()



— .



• static IReadOnlyList GetAvailablePreviewResolutions()

• static IReadOnlyList GetAvailableCaptureResolutions()

• IAsyncAction SetPreviewResolutionAsync(Size value)






IAsyncAction SetCaptureResolutionAsync(Size value)







— .



event TypedEventHandler<ICameraCaptureDevice, Object> PreviewFrameAvailable





void GetPreviewBufferArgb(out int[] pixels)





void GetPreviewBufferY(out byte[] pixels)





void GetPreviewBufferYCbCr(out byte[] pixels)







— .



CameraCaptureSequence CreateCaptureSequence(uint numberOfFrames)





IAsyncAction PrepareCaptureSequenceAsync(CameraCaptureSequence sequence)







— . . API . GUID. , .

, ID_CAP_ISV_CAMERA



WMAppManifest.xml . ID_CAP_MEDIALIB_PHOTO



.



Lumia

Nokia Lumia 820 920.





Camera Explorer — , PhotoCaptureDevice



. , .







, Camera Explorer.







Windows Phone DataContext



, Settings



PhotoCaptureDevice



.

PhotoCaptureDevice



DataContext, , , PhotoCaptureDevice



, , MainPage, .



Camera Explorer .

, PhotoCaptureDevice , Camera Explorer. , , . .



DataContext, , .



... class DataContext : INotifyPropertyChanged { ... public static DataContext Singleton { ... } public ObservableCollection<Parameter> Parameters { ... } public PhotoCaptureDevice Device { ... } public MemoryStream ImageStream { ... } }









, PhotoCaptureDevice



. MainPage xaml Canvas



VideoBrush



, .



<phone:PhoneApplicationPage x:Class="CameraExplorer.MainPage" ... > ... <Grid x:Name="LayoutRoot" ... > ... <Grid x:Name="ContentPanel" ... > <Canvas x:Name="VideoCanvas"> <Canvas.Background> <VideoBrush x:Name="videoBrush"/> </Canvas.Background> </Canvas> ... </Grid> </Grid> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar> <shell:ApplicationBarIconButton Text="capture" Click="captureButton_Click" ... /> ... </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> ... </phone:PhoneApplicationPage>







C# MainPage PhotoCaptureDevice



InitializeCamera



, DataContext. , XAML, , .



... public partial class MainPage : PhoneApplicationPage { private CameraExplorer.DataContext _dataContext = CameraExplorer.DataContext.Singleton; ... protected async override void OnNavigatedTo(NavigationEventArgs e) { if (_dataContext.Device == null) { ... await InitializeCamera(CameraSensorLocation.Back); ... } videoBrush.RelativeTransform = new CompositeTransform() { CenterX = 0.5, CenterY = 0.5, Rotation = _dataContext.Device.SensorLocation == CameraSensorLocation.Back ? _dataContext.Device.SensorRotationInDegrees : - _dataContext.Device.SensorRotationInDegrees }; videoBrush.SetSource(_dataContext.Device); ... } 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 void captureButton_Click(object sender, EventArgs e) { if (!_manuallyFocused) { await AutoFocus(); } await Capture(); } private async Task AutoFocus() { if (!_capturing && PhotoCaptureDevice.IsFocusSupported(_dataContext.Device.SensorLocation)) { ... await _dataContext.Device.FocusAsync(); ... _capturing = false; } } private async Task Capture() { if (!_capturing) { _capturing = true; MemoryStream stream = new MemoryStream(); CameraCaptureSequence sequence = _dataContext.Device.CreateCaptureSequence(1); sequence.Frames[0].CaptureStream = stream.AsOutputStream(); await _dataContext.Device.PrepareCaptureSequenceAsync(sequence); await sequence.StartCaptureAsync(); _dataContext.ImageStream = stream; ... } ... } ... }









. Camera Explorer , XAML Image BitmapImage



. , , , void MediaLibrary.SavePictureToCameraRoll(string name, Stream source)



, .



<phone:PhoneApplicationPage x:Class="CameraExplorer.PreviewPage" ... > ... <Grid x:Name="LayoutRoot" ... > ... <Grid x:Name="ContentPanel" ... > <Image x:Name="image" Stretch="UniformToFill"/> </Grid> </Grid> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar> <shell:ApplicationBarIconButton Text="save" Click="saveButton_Click" ... /> </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> ... </phone:PhoneApplicationPage>







... public partial class PreviewPage : PhoneApplicationPage { private CameraExplorer.DataContext _dataContext = CameraExplorer.DataContext.Singleton; private BitmapImage _bitmap = new BitmapImage(); protected override void OnNavigatedTo(NavigationEventArgs e) { ... _bitmap.SetSource(_dataContext.ImageStream); image.Source = _bitmap; ... } private void saveButton_Click(object sender, EventArgs e) { try { _dataContext.ImageStream.Position = 0; MediaLibrary library = new MediaLibrary(); library.SavePictureToCameraRoll("CameraExplorer_" + DateTime.Now.ToString() + ".jpg", _dataContext.ImageStream); } catch (Exception) { ... } ... } }







Camera Explorer , ArrayParameters



RangeParameters



, Parameters



. , , ComboBox



, Slider



Text



. , .

Parameter



, .



... public abstract class Parameter : INotifyPropertyChanged { ... protected Parameter(PhotoCaptureDevice device, string name) { ... } public PhotoCaptureDevice Device { ... } public string Name { ... } public bool Supported { ... } public abstract void Refresh(); ... }







, . _propertyId



, static CameraCapturePropertyRange PhotoCaptureDevice.GetSupportedPropertyRange(CameraSensorLocation sensor, Guid propertyId)



. object PhotoCaptureDevice.GetProperty(Guid propertyId)



. void PhotoCaptureDevice.SetProperty(Guid propertyId, object value)



.



... public abstract class RangeParameter<T> : Parameter { private Guid _propertyId; private T _value; ... protected RangeParameter(PhotoCaptureDevice device, Guid propertyId, string name) : base(device, name) { ... } public override void Refresh() { try { CameraCapturePropertyRange range = PhotoCaptureDevice.GetSupportedPropertyRange( Device.SensorLocation, _propertyId); if (range == null) { Supported = false; } else { Minimum = (T)range.Min; Maximum = (T)range.Max; _value = (T)Device.GetProperty(_propertyId); Supported = true; } } catch (Exception) { Supported = false; } ... } public T Minimum { ... } public T Maximum { ... } public T Value { ... set { if (!_value.Equals(value)) { try { Device.SetProperty(_propertyId, (T)value); _value = value; ... } catch (Exception) { ... } } } } ... }







ExposureCompensationParameter



, Guid RangeParameter



KnownCameraPhotoProperties.ExposureCompensation



, — , . , Int32



, .



... public class ExposureCompensationParameter : RangeParameter<Int32> { public ExposureCompensationParameter(PhotoCaptureDevice device) : base(device, KnownCameraPhotoProperties.ExposureCompensation, "Exposure compensation") { } ... }







Camera Explorer ArrayParameter



. . — void PopulateOptions()



void SetOption(ArrayParameterOption option)



, .



... public class ArrayParameterOption { ... public ArrayParameterOption(dynamic value, string name) { ... } public dynamic Value { ... } public string Name { ... } ... } public abstract class ArrayParameter : Parameter, IReadOnlyCollection<ArrayParameterOption> { private List<ArrayParameterOption> _options = new List<ArrayParameterOption>(); private ArrayParameterOption _selectedOption; ... public ArrayParameter(PhotoCaptureDevice device, string name) : base(device, name) { ... } public override void Refresh() { ... _options.Clear(); _selectedOption = null; try { PopulateOptions(); Supported = _options.Count > 0; } catch (Exception) { Supported = false; } ... } protected List<ArrayParameterOption> Options { ... } public ArrayParameterOption SelectedOption { ... set { if (_selectedOption != value) { ... if (_selectedOption != null)) { SetOption(value); } _selectedOption = value; } } } protected abstract void PopulateOptions(); protected abstract void SetOption(ArrayParameterOption option); ... }







, , , . void PopulateOptions()



, , ArrayParameterOption



SelectedOption



, void SetOption(ArrayParameterOption option)



. , static IReadOnlyList , KnownCameraPhotoProperties.SceneMode



object PhotoCaptureDevice.GetProperty(Guid propertyId)



. void PhotoCaptureDevice.SetProperty(Guid propertyId, object value)



.



... public class SceneModeParameter : ArrayParameter { public SceneModeParameter(PhotoCaptureDevice device) : base(device, KnownCameraPhotoProperties.SceneMode, "Scene mode") { } protected override void PopulateOptions() { IReadOnlyList<object> supportedValues = PhotoCaptureDevice.GetSupportedPropertyValues( Device.SensorLocation, PropertyId); object value = Device.GetProperty(PropertyId); foreach (dynamic i in supportedValues) { CameraSceneMode csm = (CameraSceneMode)i; ArrayParameterOption option = new ArrayParameterOption(csm, csm.ToString()); Options.Add(option); if (i.Equals(value)) { SelectedOption = option; } } } protected override void SetOption(ArrayParameterOption option) { Device.SetProperty(PropertyId, option.Value); } ... }







Tap-to-focus

«». Tap-to-focus , , , . , Tap-to-focus .



Rectangle



Canvas



, :



<Rectangle x:Name="FocusIndicator" Stroke="Red" Opacity="0.7" Width="80" Height="80" StrokeThickness="5" Visibility="Collapsed"/>







, .

Canvas Tap:



public MainPage() { ... VideoCanvas.Tap += new EventHandler<GestureEventArgs>(videoCanvas_Tap); ... }







. API- , VideoCanvas



, , .



, . , , , .



, , , , .



private async void videoCanvas_Tap(object sender, GestureEventArgs e) { System.Windows.Point uiTapPoint = e.GetPosition(VideoCanvas); if (PhotoCaptureDevice.IsFocusRegionSupported(_dataContext.Device.SensorLocation) && _focusSemaphore.WaitOne(0)) { // . Windows.Foundation.Point tapPoint = new Windows.Foundation.Point(uiTapPoint.X, uiTapPoint.Y); double xRatio = VideoCanvas.ActualWidth / _dataContext.Device.PreviewResolution.Width; double yRatio = VideoCanvas.ActualHeight / _dataContext.Device.PreviewResolution.Height; // , Windows.Foundation.Point displayOrigin = new Windows.Foundation.Point( tapPoint.X - _focusRegionSize.Width / 2, tapPoint.Y - _focusRegionSize.Height / 2); // canvas Windows.Foundation.Point viewFinderOrigin = new Windows.Foundation.Point( displayOrigin.X / xRatio, displayOrigin.Y / yRatio); Windows.Foundation.Rect focusrect = new Windows.Foundation.Rect( viewFinderOrigin, _focusRegionSize); // Windows.Foundation.Rect viewPortRect = new Windows.Foundation.Rect( 0, 0, _dataContext.Device.PreviewResolution.Width, _dataContext.Device.PreviewResolution.Height); focusrect.Intersect(viewPortRect); _dataContext.Device.FocusRegion = focusrect; // FocusIndicator.SetValue(Shape.StrokeProperty, _notFocusedBrush); FocusIndicator.SetValue(Canvas.LeftProperty, uiTapPoint.X - _focusRegionSize.Width / 2); FocusIndicator.SetValue(Canvas.TopProperty, uiTapPoint.Y - _focusRegionSize.Height / 2); FocusIndicator.SetValue(Canvas.VisibilityProperty, Visibility.Visible); CameraFocusStatus status = await _dataContext.Device.FocusAsync(); if (status == CameraFocusStatus.Locked) { FocusIndicator.SetValue(Shape.StrokeProperty, _focusedBrush); _manuallyFocused = true; _dataContext.Device.SetProperty( KnownCameraPhotoProperties.LockedAutoFocusParameters, AutoFocusParameters.Exposure & AutoFocusParameters.Focus & AutoFocusParameters.WhiteBalance); } else { _manuallyFocused = false; _dataContext.Device.SetProperty( KnownCameraPhotoProperties.LockedAutoFocusParameters, AutoFocusParameters.None); } _focusSemaphore.Release(); } }







, . FocusAsync



, , . , WaitOne



, , , false



— , .





, «», Lens Picker. «» , . Lens Picker, XML App:



<Extensions> <Extension ExtensionName="Camera_Capture_App" ConsumerId="{5B04B775-356B-4AA0-AAF8-6491FFEA5631]" TaskId="_default" /> </Extensions>







, Lens Picker, . , Lens Picker Assets



. , Lens design guidelines for Windows Phone .



Maps API.
























static IReadOnlyList

• object GetProperty(Guid propertyId)






void SetProperty(Guid propertyId, object value)







— , .



static bool IsFocusSupported(CameraSensorLocation sensor)





static bool IsFocusRegionSupported(CameraSensorLocation sensor)





IAsyncOperation FocusAsync()

• IAsyncOperation ResetFocusAsync()



— .



• static IReadOnlyList GetAvailablePreviewResolutions()

• static IReadOnlyList GetAvailableCaptureResolutions()

• IAsyncAction SetPreviewResolutionAsync(Size value)






IAsyncAction SetCaptureResolutionAsync(Size value)







— .



event TypedEventHandler<ICameraCaptureDevice, Object> PreviewFrameAvailable





void GetPreviewBufferArgb(out int[] pixels)





void GetPreviewBufferY(out byte[] pixels)





void GetPreviewBufferYCbCr(out byte[] pixels)







— .



CameraCaptureSequence CreateCaptureSequence(uint numberOfFrames)





IAsyncAction PrepareCaptureSequenceAsync(CameraCaptureSequence sequence)







— . . API . GUID. , .

, ID_CAP_ISV_CAMERA



WMAppManifest.xml . ID_CAP_MEDIALIB_PHOTO



.



Lumia

Nokia Lumia 820 920.





Camera Explorer — , PhotoCaptureDevice



. , .







, Camera Explorer.







Windows Phone DataContext



, Settings



PhotoCaptureDevice



.

PhotoCaptureDevice



DataContext, , , PhotoCaptureDevice



, , MainPage, .



Camera Explorer .

, PhotoCaptureDevice , Camera Explorer. , , . .



DataContext, , .



... class DataContext : INotifyPropertyChanged { ... public static DataContext Singleton { ... } public ObservableCollection<Parameter> Parameters { ... } public PhotoCaptureDevice Device { ... } public MemoryStream ImageStream { ... } }









, PhotoCaptureDevice



. MainPage xaml Canvas



VideoBrush



, .



<phone:PhoneApplicationPage x:Class="CameraExplorer.MainPage" ... > ... <Grid x:Name="LayoutRoot" ... > ... <Grid x:Name="ContentPanel" ... > <Canvas x:Name="VideoCanvas"> <Canvas.Background> <VideoBrush x:Name="videoBrush"/> </Canvas.Background> </Canvas> ... </Grid> </Grid> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar> <shell:ApplicationBarIconButton Text="capture" Click="captureButton_Click" ... /> ... </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> ... </phone:PhoneApplicationPage>







C# MainPage PhotoCaptureDevice



InitializeCamera



, DataContext. , XAML, , .



... public partial class MainPage : PhoneApplicationPage { private CameraExplorer.DataContext _dataContext = CameraExplorer.DataContext.Singleton; ... protected async override void OnNavigatedTo(NavigationEventArgs e) { if (_dataContext.Device == null) { ... await InitializeCamera(CameraSensorLocation.Back); ... } videoBrush.RelativeTransform = new CompositeTransform() { CenterX = 0.5, CenterY = 0.5, Rotation = _dataContext.Device.SensorLocation == CameraSensorLocation.Back ? _dataContext.Device.SensorRotationInDegrees : - _dataContext.Device.SensorRotationInDegrees }; videoBrush.SetSource(_dataContext.Device); ... } 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 void captureButton_Click(object sender, EventArgs e) { if (!_manuallyFocused) { await AutoFocus(); } await Capture(); } private async Task AutoFocus() { if (!_capturing && PhotoCaptureDevice.IsFocusSupported(_dataContext.Device.SensorLocation)) { ... await _dataContext.Device.FocusAsync(); ... _capturing = false; } } private async Task Capture() { if (!_capturing) { _capturing = true; MemoryStream stream = new MemoryStream(); CameraCaptureSequence sequence = _dataContext.Device.CreateCaptureSequence(1); sequence.Frames[0].CaptureStream = stream.AsOutputStream(); await _dataContext.Device.PrepareCaptureSequenceAsync(sequence); await sequence.StartCaptureAsync(); _dataContext.ImageStream = stream; ... } ... } ... }









. Camera Explorer , XAML Image BitmapImage



. , , , void MediaLibrary.SavePictureToCameraRoll(string name, Stream source)



, .



<phone:PhoneApplicationPage x:Class="CameraExplorer.PreviewPage" ... > ... <Grid x:Name="LayoutRoot" ... > ... <Grid x:Name="ContentPanel" ... > <Image x:Name="image" Stretch="UniformToFill"/> </Grid> </Grid> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar> <shell:ApplicationBarIconButton Text="save" Click="saveButton_Click" ... /> </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> ... </phone:PhoneApplicationPage>







... public partial class PreviewPage : PhoneApplicationPage { private CameraExplorer.DataContext _dataContext = CameraExplorer.DataContext.Singleton; private BitmapImage _bitmap = new BitmapImage(); protected override void OnNavigatedTo(NavigationEventArgs e) { ... _bitmap.SetSource(_dataContext.ImageStream); image.Source = _bitmap; ... } private void saveButton_Click(object sender, EventArgs e) { try { _dataContext.ImageStream.Position = 0; MediaLibrary library = new MediaLibrary(); library.SavePictureToCameraRoll("CameraExplorer_" + DateTime.Now.ToString() + ".jpg", _dataContext.ImageStream); } catch (Exception) { ... } ... } }







Camera Explorer , ArrayParameters



RangeParameters



, Parameters



. , , ComboBox



, Slider



Text



. , .

Parameter



, .



... public abstract class Parameter : INotifyPropertyChanged { ... protected Parameter(PhotoCaptureDevice device, string name) { ... } public PhotoCaptureDevice Device { ... } public string Name { ... } public bool Supported { ... } public abstract void Refresh(); ... }







, . _propertyId



, static CameraCapturePropertyRange PhotoCaptureDevice.GetSupportedPropertyRange(CameraSensorLocation sensor, Guid propertyId)



. object PhotoCaptureDevice.GetProperty(Guid propertyId)



. void PhotoCaptureDevice.SetProperty(Guid propertyId, object value)



.



... public abstract class RangeParameter<T> : Parameter { private Guid _propertyId; private T _value; ... protected RangeParameter(PhotoCaptureDevice device, Guid propertyId, string name) : base(device, name) { ... } public override void Refresh() { try { CameraCapturePropertyRange range = PhotoCaptureDevice.GetSupportedPropertyRange( Device.SensorLocation, _propertyId); if (range == null) { Supported = false; } else { Minimum = (T)range.Min; Maximum = (T)range.Max; _value = (T)Device.GetProperty(_propertyId); Supported = true; } } catch (Exception) { Supported = false; } ... } public T Minimum { ... } public T Maximum { ... } public T Value { ... set { if (!_value.Equals(value)) { try { Device.SetProperty(_propertyId, (T)value); _value = value; ... } catch (Exception) { ... } } } } ... }







ExposureCompensationParameter



, Guid RangeParameter



KnownCameraPhotoProperties.ExposureCompensation



, — , . , Int32



, .



... public class ExposureCompensationParameter : RangeParameter<Int32> { public ExposureCompensationParameter(PhotoCaptureDevice device) : base(device, KnownCameraPhotoProperties.ExposureCompensation, "Exposure compensation") { } ... }







Camera Explorer ArrayParameter



. . — void PopulateOptions()



void SetOption(ArrayParameterOption option)



, .



... public class ArrayParameterOption { ... public ArrayParameterOption(dynamic value, string name) { ... } public dynamic Value { ... } public string Name { ... } ... } public abstract class ArrayParameter : Parameter, IReadOnlyCollection<ArrayParameterOption> { private List<ArrayParameterOption> _options = new List<ArrayParameterOption>(); private ArrayParameterOption _selectedOption; ... public ArrayParameter(PhotoCaptureDevice device, string name) : base(device, name) { ... } public override void Refresh() { ... _options.Clear(); _selectedOption = null; try { PopulateOptions(); Supported = _options.Count > 0; } catch (Exception) { Supported = false; } ... } protected List<ArrayParameterOption> Options { ... } public ArrayParameterOption SelectedOption { ... set { if (_selectedOption != value) { ... if (_selectedOption != null)) { SetOption(value); } _selectedOption = value; } } } protected abstract void PopulateOptions(); protected abstract void SetOption(ArrayParameterOption option); ... }







, , , . void PopulateOptions()



, , ArrayParameterOption



SelectedOption



, void SetOption(ArrayParameterOption option)



. , static IReadOnlyList , KnownCameraPhotoProperties.SceneMode



object PhotoCaptureDevice.GetProperty(Guid propertyId)



. void PhotoCaptureDevice.SetProperty(Guid propertyId, object value)



.



... public class SceneModeParameter : ArrayParameter { public SceneModeParameter(PhotoCaptureDevice device) : base(device, KnownCameraPhotoProperties.SceneMode, "Scene mode") { } protected override void PopulateOptions() { IReadOnlyList<object> supportedValues = PhotoCaptureDevice.GetSupportedPropertyValues( Device.SensorLocation, PropertyId); object value = Device.GetProperty(PropertyId); foreach (dynamic i in supportedValues) { CameraSceneMode csm = (CameraSceneMode)i; ArrayParameterOption option = new ArrayParameterOption(csm, csm.ToString()); Options.Add(option); if (i.Equals(value)) { SelectedOption = option; } } } protected override void SetOption(ArrayParameterOption option) { Device.SetProperty(PropertyId, option.Value); } ... }







Tap-to-focus

«». Tap-to-focus , , , . , Tap-to-focus .



Rectangle



Canvas



, :



<Rectangle x:Name="FocusIndicator" Stroke="Red" Opacity="0.7" Width="80" Height="80" StrokeThickness="5" Visibility="Collapsed"/>







, .

Canvas Tap:



public MainPage() { ... VideoCanvas.Tap += new EventHandler<GestureEventArgs>(videoCanvas_Tap); ... }







. API- , VideoCanvas



, , .



, . , , , .



, , , , .



private async void videoCanvas_Tap(object sender, GestureEventArgs e) { System.Windows.Point uiTapPoint = e.GetPosition(VideoCanvas); if (PhotoCaptureDevice.IsFocusRegionSupported(_dataContext.Device.SensorLocation) && _focusSemaphore.WaitOne(0)) { // . Windows.Foundation.Point tapPoint = new Windows.Foundation.Point(uiTapPoint.X, uiTapPoint.Y); double xRatio = VideoCanvas.ActualWidth / _dataContext.Device.PreviewResolution.Width; double yRatio = VideoCanvas.ActualHeight / _dataContext.Device.PreviewResolution.Height; // , Windows.Foundation.Point displayOrigin = new Windows.Foundation.Point( tapPoint.X - _focusRegionSize.Width / 2, tapPoint.Y - _focusRegionSize.Height / 2); // canvas Windows.Foundation.Point viewFinderOrigin = new Windows.Foundation.Point( displayOrigin.X / xRatio, displayOrigin.Y / yRatio); Windows.Foundation.Rect focusrect = new Windows.Foundation.Rect( viewFinderOrigin, _focusRegionSize); // Windows.Foundation.Rect viewPortRect = new Windows.Foundation.Rect( 0, 0, _dataContext.Device.PreviewResolution.Width, _dataContext.Device.PreviewResolution.Height); focusrect.Intersect(viewPortRect); _dataContext.Device.FocusRegion = focusrect; // FocusIndicator.SetValue(Shape.StrokeProperty, _notFocusedBrush); FocusIndicator.SetValue(Canvas.LeftProperty, uiTapPoint.X - _focusRegionSize.Width / 2); FocusIndicator.SetValue(Canvas.TopProperty, uiTapPoint.Y - _focusRegionSize.Height / 2); FocusIndicator.SetValue(Canvas.VisibilityProperty, Visibility.Visible); CameraFocusStatus status = await _dataContext.Device.FocusAsync(); if (status == CameraFocusStatus.Locked) { FocusIndicator.SetValue(Shape.StrokeProperty, _focusedBrush); _manuallyFocused = true; _dataContext.Device.SetProperty( KnownCameraPhotoProperties.LockedAutoFocusParameters, AutoFocusParameters.Exposure & AutoFocusParameters.Focus & AutoFocusParameters.WhiteBalance); } else { _manuallyFocused = false; _dataContext.Device.SetProperty( KnownCameraPhotoProperties.LockedAutoFocusParameters, AutoFocusParameters.None); } _focusSemaphore.Release(); } }







, . FocusAsync



, , . , WaitOne



, , , false



— , .





, «», Lens Picker. «» , . Lens Picker, XML App:



<Extensions> <Extension ExtensionName="Camera_Capture_App" ConsumerId="{5B04B775-356B-4AA0-AAF8-6491FFEA5631]" TaskId="_default" /> </Extensions>







, Lens Picker, . , Lens Picker Assets



. , Lens design guidelines for Windows Phone .



Maps API.



























All Articles