उन्नत कैमरा एपीआई का व्यावहारिक उपयोग

हाल ही में, हमने एपीआई पर विचार करना शुरू किया , जिसका उत्पादन MWC - 2013 प्रदर्शनी में घोषित किया गया था। आज के लेख में, हम उन्नत कैमरा एपीआई का उपयोग करने के व्यावहारिक उदाहरणों को देखेंगे।




विंडोज फोन 8 उन्नत फोटो कैप्चर एपीआई


विंडोज फोन 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.

Source: https://habr.com/ru/post/In174307/


All Articles