Windows 10 1511 Release - May 2016 Update
This commit is contained in:
Коммит
9e7fa281b4
|
@ -74,6 +74,8 @@ ipch/
|
|||
*.opensdf
|
||||
*.sdf
|
||||
*.cachefile
|
||||
*.VC.db
|
||||
*.VC.VC.opendb
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
|
|
|
@ -392,6 +392,14 @@ For additional Windows samples, see [Windows on GitHub](http://microsoft.github.
|
|||
</tr>
|
||||
</table>
|
||||
|
||||
### Holographic
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td><a href="Samples/HolographicSpatialMapping">Holographic spatial mapping</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
### Identity, security, and encryption
|
||||
|
||||
<table>
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
switch (pageSections) {
|
||||
case "1":
|
||||
// Animate the whole page together
|
||||
enterPage = WinJS.UI.Animation.enterPage([scenarioHeader, input, output], null);
|
||||
enterPage = WinJS.UI.Animation.enterPage([[scenarioHeader, input, output]], null);
|
||||
break;
|
||||
case "2":
|
||||
// Stagger the header and body
|
||||
|
|
|
@ -172,8 +172,6 @@ namespace BackgroundAudioTask
|
|||
BackgroundMediaPlayer.MessageReceivedFromForeground -= BackgroundMediaPlayer_MessageReceivedFromForeground;
|
||||
smtc.ButtonPressed -= smtc_ButtonPressed;
|
||||
smtc.PropertyChanged -= smtc_PropertyChanged;
|
||||
|
||||
BackgroundMediaPlayer.Shutdown(); // shutdown media pipeline
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
|
|
@ -34,7 +34,7 @@ Array<Scenario>^ MainPage::scenariosInner = ref new Array<Scenario>
|
|||
{
|
||||
// The format here is the following:
|
||||
// { "Description for the sample", "Fully quaified name for the class that implements the scenario" }
|
||||
{ "Background task", "SDKTemplate.SampleBackgroundTask" },
|
||||
{ "Background task", "SDKTemplate.SampleBackgroundTask" },
|
||||
{ "Background task with a condition", "SDKTemplate.SampleBackgroundTaskWithCondition" },
|
||||
{ "Servicing complete task", "SDKTemplate.ServicingCompleteTask" },
|
||||
{ "Background task with time trigger", "SDKTemplate.TimeTriggeredTask" },
|
||||
|
@ -102,7 +102,7 @@ BackgroundTaskRegistration^ BackgroundTaskSample::RegisterBackgroundTask(String^
|
|||
|
||||
auto task = builder->Register();
|
||||
|
||||
UpdateBackgroundTaskStatus(name, true);
|
||||
UpdateBackgroundTaskRegistrationStatus(name, true);
|
||||
|
||||
//
|
||||
// Remove previous completion status from local settings.
|
||||
|
@ -142,17 +142,17 @@ void BackgroundTaskSample::UnregisterBackgroundTasks(String^ name)
|
|||
{
|
||||
auto cur = iter->Current->Value;
|
||||
|
||||
if(cur->Name == name)
|
||||
if (cur->Name == name)
|
||||
{
|
||||
cur->Unregister(true);
|
||||
UpdateBackgroundTaskStatus(name, false);
|
||||
UpdateBackgroundTaskRegistrationStatus(name, false);
|
||||
}
|
||||
|
||||
hascur = iter->MoveNext();
|
||||
}
|
||||
}
|
||||
|
||||
void BackgroundTaskSample::UpdateBackgroundTaskStatus(String^ name, bool registered)
|
||||
void BackgroundTaskSample::UpdateBackgroundTaskRegistrationStatus(String^ name, bool registered)
|
||||
{
|
||||
if (name == SampleBackgroundTaskName)
|
||||
{
|
||||
|
|
|
@ -61,7 +61,7 @@ namespace SDKTemplate
|
|||
static BackgroundTaskRegistration^ RegisterBackgroundTask(String^ taskEntryPoint, String^ name, IBackgroundTrigger^ trigger, IBackgroundCondition^ condition);
|
||||
static bool TaskRequiresBackgroundAccess(String^ name);
|
||||
static void UnregisterBackgroundTasks(String^ name);
|
||||
static void UpdateBackgroundTaskStatus(String^ name, bool registered);
|
||||
static void UpdateBackgroundTaskRegistrationStatus(String^ name, bool registered);
|
||||
|
||||
static String^ SampleBackgroundTaskProgress;
|
||||
static bool SampleBackgroundTaskRegistered;
|
||||
|
|
|
@ -44,20 +44,15 @@ void SampleBackgroundTask::OnNavigatedTo(NavigationEventArgs^ e)
|
|||
//
|
||||
// Attach progress and completed handlers to any existing tasks.
|
||||
//
|
||||
auto iter = BackgroundTaskRegistration::AllTasks->First();
|
||||
auto hascur = iter->HasCurrent;
|
||||
while (hascur)
|
||||
for (auto pair : BackgroundTaskRegistration::AllTasks)
|
||||
{
|
||||
auto cur = iter->Current->Value;
|
||||
|
||||
if (cur->Name == SampleBackgroundTaskName)
|
||||
auto task = pair->Value;
|
||||
if (task->Name == SampleBackgroundTaskName)
|
||||
{
|
||||
BackgroundTaskSample::UpdateBackgroundTaskStatus(cur->Name, true);
|
||||
AttachProgressAndCompletedHandlers(cur);
|
||||
BackgroundTaskSample::UpdateBackgroundTaskRegistrationStatus(task->Name, true);
|
||||
AttachProgressAndCompletedHandlers(task);
|
||||
break;
|
||||
}
|
||||
|
||||
hascur = iter->MoveNext();
|
||||
}
|
||||
|
||||
UpdateUI();
|
||||
|
@ -69,19 +64,8 @@ void SampleBackgroundTask::OnNavigatedTo(NavigationEventArgs^ e)
|
|||
/// <param name="task">The task to attach progress and completed handlers to.</param>
|
||||
void SampleBackgroundTask::AttachProgressAndCompletedHandlers(IBackgroundTaskRegistration^ task)
|
||||
{
|
||||
auto progress = [this](BackgroundTaskRegistration^ task, BackgroundTaskProgressEventArgs^ args)
|
||||
{
|
||||
auto progress = "Progress: " + args->Progress + "%";
|
||||
BackgroundTaskSample::SampleBackgroundTaskProgress = progress;
|
||||
UpdateUI();
|
||||
};
|
||||
task->Progress += ref new BackgroundTaskProgressEventHandler(progress);
|
||||
|
||||
auto completed = [this](BackgroundTaskRegistration^ task, BackgroundTaskCompletedEventArgs^ args)
|
||||
{
|
||||
UpdateUI();
|
||||
};
|
||||
task->Completed += ref new BackgroundTaskCompletedEventHandler(completed);
|
||||
task->Progress += ref new BackgroundTaskProgressEventHandler(this, &SampleBackgroundTask::OnProgress);
|
||||
task->Completed += ref new BackgroundTaskCompletedEventHandler(this, &SampleBackgroundTask::OnCompleted);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -110,6 +94,31 @@ void SampleBackgroundTask::UnregisterBackgroundTask(Platform::Object^ sender, Wi
|
|||
UpdateUI();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle background task progress.
|
||||
/// </summary>
|
||||
/// <param name="task">The task that is reporting progress.</param>
|
||||
/// <param name="args">Arguments of the progress report.</param>
|
||||
void SampleBackgroundTask::OnProgress(BackgroundTaskRegistration^ task, BackgroundTaskProgressEventArgs^ args)
|
||||
{
|
||||
Dispatcher->RunAsync(CoreDispatcherPriority::Normal, ref new DispatchedHandler([this, args]()
|
||||
{
|
||||
auto progress = "Progress: " + args->Progress + "%";
|
||||
BackgroundTaskSample::SampleBackgroundTaskProgress = progress;
|
||||
UpdateUI();
|
||||
}));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle background task completion.
|
||||
/// </summary>
|
||||
/// <param name="task">The task that is reporting completion.</param>
|
||||
/// <param name="args">Arguments of the completion report.</param>
|
||||
void SampleBackgroundTask::OnCompleted(BackgroundTaskRegistration^ task, BackgroundTaskCompletedEventArgs^ args)
|
||||
{
|
||||
UpdateUI();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update the scenario UI.
|
||||
/// </summary>
|
||||
|
|
|
@ -38,6 +38,8 @@ namespace SDKTemplate
|
|||
void AttachProgressAndCompletedHandlers(Windows::ApplicationModel::Background::IBackgroundTaskRegistration^ task);
|
||||
void RegisterBackgroundTask(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
|
||||
void UnregisterBackgroundTask(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
|
||||
void OnProgress(Windows::ApplicationModel::Background::BackgroundTaskRegistration^ task, Windows::ApplicationModel::Background::BackgroundTaskProgressEventArgs^ args);
|
||||
void OnCompleted(Windows::ApplicationModel::Background::BackgroundTaskRegistration^ task, Windows::ApplicationModel::Background::BackgroundTaskCompletedEventArgs^ args);
|
||||
void UpdateUI();
|
||||
};
|
||||
}
|
||||
|
|
|
@ -44,20 +44,15 @@ void SampleBackgroundTaskWithCondition::OnNavigatedTo(NavigationEventArgs^ e)
|
|||
//
|
||||
// Attach progress and completed handlers to any existing tasks.
|
||||
//
|
||||
auto iter = BackgroundTaskRegistration::AllTasks->First();
|
||||
auto hascur = iter->HasCurrent;
|
||||
while (hascur)
|
||||
for (auto pair : BackgroundTaskRegistration::AllTasks)
|
||||
{
|
||||
auto cur = iter->Current->Value;
|
||||
|
||||
if (cur->Name == SampleBackgroundTaskWithConditionName)
|
||||
auto task = pair->Value;
|
||||
if (task->Name == SampleBackgroundTaskWithConditionName)
|
||||
{
|
||||
BackgroundTaskSample::UpdateBackgroundTaskStatus(cur->Name, true);
|
||||
AttachProgressAndCompletedHandlers(cur);
|
||||
BackgroundTaskSample::UpdateBackgroundTaskRegistrationStatus(task->Name, true);
|
||||
AttachProgressAndCompletedHandlers(task);
|
||||
break;
|
||||
}
|
||||
|
||||
hascur = iter->MoveNext();
|
||||
}
|
||||
|
||||
UpdateUI();
|
||||
|
@ -69,19 +64,8 @@ void SampleBackgroundTaskWithCondition::OnNavigatedTo(NavigationEventArgs^ e)
|
|||
/// <param name="task">The task to attach progress and completed handlers to.</param>
|
||||
void SampleBackgroundTaskWithCondition::AttachProgressAndCompletedHandlers(IBackgroundTaskRegistration^ task)
|
||||
{
|
||||
auto progress = [this](BackgroundTaskRegistration^ task, BackgroundTaskProgressEventArgs^ args)
|
||||
{
|
||||
auto progress = "Progress: " + args->Progress + "%";
|
||||
BackgroundTaskSample::SampleBackgroundTaskWithConditionProgress = progress;
|
||||
UpdateUI();
|
||||
};
|
||||
task->Progress += ref new BackgroundTaskProgressEventHandler(progress);
|
||||
|
||||
auto completed = [this](BackgroundTaskRegistration^ task, BackgroundTaskCompletedEventArgs^ args)
|
||||
{
|
||||
UpdateUI();
|
||||
};
|
||||
task->Completed += ref new BackgroundTaskCompletedEventHandler(completed);
|
||||
task->Progress += ref new BackgroundTaskProgressEventHandler(this, &SampleBackgroundTaskWithCondition::OnProgress);
|
||||
task->Completed += ref new BackgroundTaskCompletedEventHandler(this, &SampleBackgroundTaskWithCondition::OnCompleted);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -110,6 +94,31 @@ void SampleBackgroundTaskWithCondition::UnregisterBackgroundTask(Platform::Objec
|
|||
UpdateUI();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle background task progress.
|
||||
/// </summary>
|
||||
/// <param name="task">The task that is reporting progress.</param>
|
||||
/// <param name="args">Arguments of the progress report.</param>
|
||||
void SampleBackgroundTaskWithCondition::OnProgress(BackgroundTaskRegistration^ task, BackgroundTaskProgressEventArgs^ args)
|
||||
{
|
||||
Dispatcher->RunAsync(CoreDispatcherPriority::Normal, ref new DispatchedHandler([this, args]()
|
||||
{
|
||||
auto progress = "Progress: " + args->Progress + "%";
|
||||
BackgroundTaskSample::SampleBackgroundTaskWithConditionProgress = progress;
|
||||
UpdateUI();
|
||||
}));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle background task completion.
|
||||
/// </summary>
|
||||
/// <param name="task">The task that is reporting completion.</param>
|
||||
/// <param name="args">Arguments of the completion report.</param>
|
||||
void SampleBackgroundTaskWithCondition::OnCompleted(BackgroundTaskRegistration^ task, BackgroundTaskCompletedEventArgs^ args)
|
||||
{
|
||||
UpdateUI();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update the scenario UI.
|
||||
/// </summary>
|
||||
|
|
|
@ -38,6 +38,8 @@ namespace SDKTemplate
|
|||
void AttachProgressAndCompletedHandlers(Windows::ApplicationModel::Background::IBackgroundTaskRegistration^ task);
|
||||
void RegisterBackgroundTask(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
|
||||
void UnregisterBackgroundTask(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
|
||||
void OnProgress(Windows::ApplicationModel::Background::BackgroundTaskRegistration^ task, Windows::ApplicationModel::Background::BackgroundTaskProgressEventArgs^ args);
|
||||
void OnCompleted(Windows::ApplicationModel::Background::BackgroundTaskRegistration^ task, Windows::ApplicationModel::Background::BackgroundTaskCompletedEventArgs^ args);
|
||||
void UpdateUI();
|
||||
};
|
||||
}
|
||||
|
|
|
@ -44,20 +44,15 @@ void ServicingCompleteTask::OnNavigatedTo(NavigationEventArgs^ e)
|
|||
//
|
||||
// Attach progress and completed handlers to any existing tasks.
|
||||
//
|
||||
auto iter = BackgroundTaskRegistration::AllTasks->First();
|
||||
auto hascur = iter->HasCurrent;
|
||||
while (hascur)
|
||||
for (auto pair : BackgroundTaskRegistration::AllTasks)
|
||||
{
|
||||
auto cur = iter->Current->Value;
|
||||
|
||||
if (cur->Name == ServicingCompleteTaskName)
|
||||
auto task = pair->Value;
|
||||
if (task->Name == ServicingCompleteTaskName)
|
||||
{
|
||||
BackgroundTaskSample::UpdateBackgroundTaskStatus(cur->Name, true);
|
||||
AttachProgressAndCompletedHandlers(cur);
|
||||
BackgroundTaskSample::UpdateBackgroundTaskRegistrationStatus(task->Name, true);
|
||||
AttachProgressAndCompletedHandlers(task);
|
||||
break;
|
||||
}
|
||||
|
||||
hascur = iter->MoveNext();
|
||||
}
|
||||
|
||||
UpdateUI();
|
||||
|
@ -69,19 +64,8 @@ void ServicingCompleteTask::OnNavigatedTo(NavigationEventArgs^ e)
|
|||
/// <param name="task">The task to attach progress and completed handlers to.</param>
|
||||
void ServicingCompleteTask::AttachProgressAndCompletedHandlers(IBackgroundTaskRegistration^ task)
|
||||
{
|
||||
auto progress = [this](BackgroundTaskRegistration^ task, BackgroundTaskProgressEventArgs^ args)
|
||||
{
|
||||
auto progress = "Progress: " + args->Progress + "%";
|
||||
BackgroundTaskSample::ServicingCompleteTaskProgress = progress;
|
||||
UpdateUI();
|
||||
};
|
||||
task->Progress += ref new BackgroundTaskProgressEventHandler(progress);
|
||||
|
||||
auto completed = [this](BackgroundTaskRegistration^ task, BackgroundTaskCompletedEventArgs^ args)
|
||||
{
|
||||
UpdateUI();
|
||||
};
|
||||
task->Completed += ref new BackgroundTaskCompletedEventHandler(completed);
|
||||
task->Progress += ref new BackgroundTaskProgressEventHandler(this, &ServicingCompleteTask::OnProgress);
|
||||
task->Completed += ref new BackgroundTaskCompletedEventHandler(this, &ServicingCompleteTask::OnCompleted);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -111,6 +95,31 @@ void ServicingCompleteTask::UnregisterBackgroundTask(Platform::Object^ sender, W
|
|||
UpdateUI();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle background task progress.
|
||||
/// </summary>
|
||||
/// <param name="task">The task that is reporting progress.</param>
|
||||
/// <param name="args">Arguments of the progress report.</param>
|
||||
void ServicingCompleteTask::OnProgress(BackgroundTaskRegistration^ task, BackgroundTaskProgressEventArgs^ args)
|
||||
{
|
||||
Dispatcher->RunAsync(CoreDispatcherPriority::Normal, ref new DispatchedHandler([this, args]()
|
||||
{
|
||||
auto progress = "Progress: " + args->Progress + "%";
|
||||
BackgroundTaskSample::ServicingCompleteTaskProgress = progress;
|
||||
UpdateUI();
|
||||
}));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle background task completion.
|
||||
/// </summary>
|
||||
/// <param name="task">The task that is reporting completion.</param>
|
||||
/// <param name="args">Arguments of the completion report.</param>
|
||||
void ServicingCompleteTask::OnCompleted(BackgroundTaskRegistration^ task, BackgroundTaskCompletedEventArgs^ args)
|
||||
{
|
||||
UpdateUI();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update the scenario UI.
|
||||
/// </summary>
|
||||
|
|
|
@ -38,6 +38,8 @@ namespace SDKTemplate
|
|||
void AttachProgressAndCompletedHandlers(Windows::ApplicationModel::Background::IBackgroundTaskRegistration^ task);
|
||||
void RegisterBackgroundTask(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
|
||||
void UnregisterBackgroundTask(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
|
||||
void OnProgress(Windows::ApplicationModel::Background::BackgroundTaskRegistration^ task, Windows::ApplicationModel::Background::BackgroundTaskProgressEventArgs^ args);
|
||||
void OnCompleted(Windows::ApplicationModel::Background::BackgroundTaskRegistration^ task, Windows::ApplicationModel::Background::BackgroundTaskCompletedEventArgs^ args);
|
||||
void UpdateUI();
|
||||
};
|
||||
}
|
||||
|
|
|
@ -44,20 +44,15 @@ void TimeTriggeredTask::OnNavigatedTo(NavigationEventArgs^ e)
|
|||
//
|
||||
// Attach progress and completed handlers to any existing tasks.
|
||||
//
|
||||
auto iter = BackgroundTaskRegistration::AllTasks->First();
|
||||
auto hascur = iter->HasCurrent;
|
||||
while (hascur)
|
||||
for (auto pair : BackgroundTaskRegistration::AllTasks)
|
||||
{
|
||||
auto cur = iter->Current->Value;
|
||||
|
||||
if (cur->Name == TimeTriggeredTaskName)
|
||||
auto task = pair->Value;
|
||||
if (task->Name == TimeTriggeredTaskName)
|
||||
{
|
||||
BackgroundTaskSample::UpdateBackgroundTaskStatus(cur->Name, true);
|
||||
AttachProgressAndCompletedHandlers(cur);
|
||||
BackgroundTaskSample::UpdateBackgroundTaskRegistrationStatus(task->Name, true);
|
||||
AttachProgressAndCompletedHandlers(task);
|
||||
break;
|
||||
}
|
||||
|
||||
hascur = iter->MoveNext();
|
||||
}
|
||||
|
||||
UpdateUI();
|
||||
|
@ -69,19 +64,8 @@ void TimeTriggeredTask::OnNavigatedTo(NavigationEventArgs^ e)
|
|||
/// <param name="task">The task to attach progress and completed handlers to.</param>
|
||||
void TimeTriggeredTask::AttachProgressAndCompletedHandlers(IBackgroundTaskRegistration^ task)
|
||||
{
|
||||
auto progress = [this](BackgroundTaskRegistration^ task, BackgroundTaskProgressEventArgs^ args)
|
||||
{
|
||||
auto progress = "Progress: " + args->Progress + "%";
|
||||
BackgroundTaskSample::TimeTriggeredTaskProgress = progress;
|
||||
UpdateUI();
|
||||
};
|
||||
task->Progress += ref new BackgroundTaskProgressEventHandler(progress);
|
||||
|
||||
auto completed = [this](BackgroundTaskRegistration^ task, BackgroundTaskCompletedEventArgs^ args)
|
||||
{
|
||||
UpdateUI();
|
||||
};
|
||||
task->Completed += ref new BackgroundTaskCompletedEventHandler(completed);
|
||||
task->Progress += ref new BackgroundTaskProgressEventHandler(this, &TimeTriggeredTask::OnProgress);
|
||||
task->Completed += ref new BackgroundTaskCompletedEventHandler(this, &TimeTriggeredTask::OnCompleted);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -110,6 +94,31 @@ void TimeTriggeredTask::UnregisterBackgroundTask(Platform::Object^ sender, Windo
|
|||
UpdateUI();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle background task progress.
|
||||
/// </summary>
|
||||
/// <param name="task">The task that is reporting progress.</param>
|
||||
/// <param name="args">Arguments of the progress report.</param>
|
||||
void TimeTriggeredTask::OnProgress(BackgroundTaskRegistration^ task, BackgroundTaskProgressEventArgs^ args)
|
||||
{
|
||||
Dispatcher->RunAsync(CoreDispatcherPriority::Normal, ref new DispatchedHandler([this, args]()
|
||||
{
|
||||
auto progress = "Progress: " + args->Progress + "%";
|
||||
BackgroundTaskSample::TimeTriggeredTaskProgress = progress;
|
||||
UpdateUI();
|
||||
}));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle background task completion.
|
||||
/// </summary>
|
||||
/// <param name="task">The task that is reporting completion.</param>
|
||||
/// <param name="args">Arguments of the completion report.</param>
|
||||
void TimeTriggeredTask::OnCompleted(BackgroundTaskRegistration^ task, BackgroundTaskCompletedEventArgs^ args)
|
||||
{
|
||||
UpdateUI();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update the scenario UI.
|
||||
/// </summary>
|
||||
|
|
|
@ -38,6 +38,8 @@ namespace SDKTemplate
|
|||
void AttachProgressAndCompletedHandlers(Windows::ApplicationModel::Background::IBackgroundTaskRegistration^ task);
|
||||
void RegisterBackgroundTask(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
|
||||
void UnregisterBackgroundTask(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
|
||||
void OnProgress(Windows::ApplicationModel::Background::BackgroundTaskRegistration^ task, Windows::ApplicationModel::Background::BackgroundTaskProgressEventArgs^ args);
|
||||
void OnCompleted(Windows::ApplicationModel::Background::BackgroundTaskRegistration^ task, Windows::ApplicationModel::Background::BackgroundTaskCompletedEventArgs^ args);
|
||||
void UpdateUI();
|
||||
};
|
||||
}
|
||||
|
|
|
@ -44,20 +44,15 @@ void ApplicationTriggerTask::OnNavigatedTo(NavigationEventArgs^ e)
|
|||
//
|
||||
// Attach progress and completed handlers to any existing tasks.
|
||||
//
|
||||
auto iter = BackgroundTaskRegistration::AllTasks->First();
|
||||
auto hascur = iter->HasCurrent;
|
||||
while (hascur)
|
||||
for (auto pair : BackgroundTaskRegistration::AllTasks)
|
||||
{
|
||||
auto cur = iter->Current->Value;
|
||||
|
||||
if (cur->Name == ApplicationTriggerTaskName)
|
||||
auto task = pair->Value;
|
||||
if (task->Name == ApplicationTriggerTaskName)
|
||||
{
|
||||
BackgroundTaskSample::UpdateBackgroundTaskStatus(cur->Name, true);
|
||||
AttachProgressAndCompletedHandlers(cur);
|
||||
BackgroundTaskSample::UpdateBackgroundTaskRegistrationStatus(task->Name, true);
|
||||
AttachProgressAndCompletedHandlers(task);
|
||||
break;
|
||||
}
|
||||
|
||||
hascur = iter->MoveNext();
|
||||
}
|
||||
|
||||
trigger = ref new ApplicationTrigger();
|
||||
|
@ -70,19 +65,8 @@ void ApplicationTriggerTask::OnNavigatedTo(NavigationEventArgs^ e)
|
|||
/// <param name="task">The task to attach progress and completed handlers to.</param>
|
||||
void ApplicationTriggerTask::AttachProgressAndCompletedHandlers(IBackgroundTaskRegistration^ task)
|
||||
{
|
||||
auto progress = [this](BackgroundTaskRegistration^ task, BackgroundTaskProgressEventArgs^ args)
|
||||
{
|
||||
auto progress = "Progress: " + args->Progress + "%";
|
||||
BackgroundTaskSample::ApplicationTriggerTaskProgress = progress;
|
||||
UpdateUI();
|
||||
};
|
||||
task->Progress += ref new BackgroundTaskProgressEventHandler(progress);
|
||||
|
||||
auto completed = [this](BackgroundTaskRegistration^ task, BackgroundTaskCompletedEventArgs^ args)
|
||||
{
|
||||
UpdateUI();
|
||||
};
|
||||
task->Completed += ref new BackgroundTaskCompletedEventHandler(completed);
|
||||
task->Progress += ref new BackgroundTaskProgressEventHandler(this, &ApplicationTriggerTask::OnProgress);
|
||||
task->Completed += ref new BackgroundTaskCompletedEventHandler(this, &ApplicationTriggerTask::OnCompleted);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -135,6 +119,31 @@ void ApplicationTriggerTask::SignalBackgroundTask(Platform::Object^ sender, Wind
|
|||
UpdateUI();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle background task progress.
|
||||
/// </summary>
|
||||
/// <param name="task">The task that is reporting progress.</param>
|
||||
/// <param name="args">Arguments of the progress report.</param>
|
||||
void ApplicationTriggerTask::OnProgress(BackgroundTaskRegistration^ task, BackgroundTaskProgressEventArgs^ args)
|
||||
{
|
||||
Dispatcher->RunAsync(CoreDispatcherPriority::Normal, ref new DispatchedHandler([this, args]()
|
||||
{
|
||||
auto progress = "Progress: " + args->Progress + "%";
|
||||
BackgroundTaskSample::ApplicationTriggerTaskProgress = progress;
|
||||
UpdateUI();
|
||||
}));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle background task completion.
|
||||
/// </summary>
|
||||
/// <param name="task">The task that is reporting completion.</param>
|
||||
/// <param name="args">Arguments of the completion report.</param>
|
||||
void ApplicationTriggerTask::OnCompleted(BackgroundTaskRegistration^ task, BackgroundTaskCompletedEventArgs^ args)
|
||||
{
|
||||
UpdateUI();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update the scenario UI.
|
||||
/// </summary>
|
||||
|
|
|
@ -41,6 +41,8 @@ namespace SDKTemplate
|
|||
void RegisterBackgroundTask(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
|
||||
void UnregisterBackgroundTask(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
|
||||
void SignalBackgroundTask(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
|
||||
void OnProgress(Windows::ApplicationModel::Background::BackgroundTaskRegistration^ task, Windows::ApplicationModel::Background::BackgroundTaskProgressEventArgs^ args);
|
||||
void OnCompleted(Windows::ApplicationModel::Background::BackgroundTaskRegistration^ task, Windows::ApplicationModel::Background::BackgroundTaskCompletedEventArgs^ args);
|
||||
void UpdateUI();
|
||||
};
|
||||
}
|
||||
|
|
|
@ -13,17 +13,10 @@
|
|||
#include "SampleBackgroundTask.h"
|
||||
|
||||
using namespace Tasks;
|
||||
using namespace Windows::ApplicationModel::Background;
|
||||
using namespace Windows::Foundation;
|
||||
using namespace Windows::Storage;
|
||||
|
||||
SampleBackgroundTask::SampleBackgroundTask() :
|
||||
CancelReason(BackgroundTaskCancellationReason::Abort), CancelRequested(false), TaskDeferral(nullptr), PeriodicTimer(nullptr), Progress(0), TaskInstance(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
SampleBackgroundTask::~SampleBackgroundTask()
|
||||
{
|
||||
}
|
||||
using namespace Windows::System::Threading;
|
||||
|
||||
void SampleBackgroundTask::Run(IBackgroundTaskInstance^ taskInstance)
|
||||
{
|
||||
|
@ -60,11 +53,12 @@ void SampleBackgroundTask::Run(IBackgroundTaskInstance^ taskInstance)
|
|||
PeriodicTimer->Cancel();
|
||||
|
||||
//
|
||||
// Write to LocalSettings to indicate that this background task ran.
|
||||
// Record that this background task ran.
|
||||
//
|
||||
auto settings = ApplicationData::Current->LocalSettings;
|
||||
auto taskStatus = (Progress < 100) ? "Canceled with reason: " + CancelReason.ToString() : "Completed";
|
||||
auto key = TaskInstance->Task->Name;
|
||||
settings->Values->Insert(key, (Progress < 100) ? "Canceled with reason: " + CancelReason.ToString() : "Completed");
|
||||
auto settings = ApplicationData::Current->LocalSettings;
|
||||
settings->Values->Insert(key, taskStatus);
|
||||
|
||||
//
|
||||
// Indicate that the background task has completed.
|
||||
|
|
|
@ -10,32 +10,22 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "pch.h"
|
||||
#include <agile.h>
|
||||
|
||||
using namespace Windows::ApplicationModel::Background;
|
||||
using namespace Windows::System::Threading;
|
||||
|
||||
namespace Tasks
|
||||
{
|
||||
[Windows::Foundation::Metadata::WebHostHidden]
|
||||
public ref class SampleBackgroundTask sealed : public IBackgroundTask
|
||||
public ref class SampleBackgroundTask sealed : public Windows::ApplicationModel::Background::IBackgroundTask
|
||||
{
|
||||
|
||||
public:
|
||||
SampleBackgroundTask();
|
||||
|
||||
virtual void Run(IBackgroundTaskInstance^ taskInstance);
|
||||
void OnCanceled(IBackgroundTaskInstance^ taskInstance, BackgroundTaskCancellationReason reason);
|
||||
virtual void Run(Windows::ApplicationModel::Background::IBackgroundTaskInstance^ taskInstance);
|
||||
void OnCanceled(Windows::ApplicationModel::Background::IBackgroundTaskInstance^ taskInstance, Windows::ApplicationModel::Background::BackgroundTaskCancellationReason reason);
|
||||
|
||||
private:
|
||||
~SampleBackgroundTask();
|
||||
|
||||
BackgroundTaskCancellationReason CancelReason;
|
||||
volatile bool CancelRequested;
|
||||
Platform::Agile<Windows::ApplicationModel::Background::BackgroundTaskDeferral> TaskDeferral;
|
||||
ThreadPoolTimer^ PeriodicTimer;
|
||||
unsigned int Progress;
|
||||
IBackgroundTaskInstance^ TaskInstance;
|
||||
Windows::ApplicationModel::Background::BackgroundTaskCancellationReason CancelReason = Windows::ApplicationModel::Background::BackgroundTaskCancellationReason::Abort;
|
||||
volatile bool CancelRequested = false;
|
||||
Platform::Agile<Windows::ApplicationModel::Background::BackgroundTaskDeferral> TaskDeferral = nullptr;
|
||||
Windows::System::Threading::ThreadPoolTimer^ PeriodicTimer = nullptr;
|
||||
unsigned int Progress = 0;
|
||||
Windows::ApplicationModel::Background::IBackgroundTaskInstance^ TaskInstance = nullptr;
|
||||
};
|
||||
}
|
|
@ -74,11 +74,12 @@ namespace SDKTemplate
|
|||
/// <param name="name">A name for the background task.</param>
|
||||
/// <param name="trigger">The trigger for the background task.</param>
|
||||
/// <param name="condition">An optional conditional event that must be true for the task to fire.</param>
|
||||
public static async Task<BackgroundTaskRegistration> RegisterBackgroundTask(String taskEntryPoint, String name, IBackgroundTrigger trigger, IBackgroundCondition condition)
|
||||
public static BackgroundTaskRegistration RegisterBackgroundTask(String taskEntryPoint, String name, IBackgroundTrigger trigger, IBackgroundCondition condition)
|
||||
{
|
||||
if (TaskRequiresBackgroundAccess(name))
|
||||
{
|
||||
await BackgroundExecutionManager.RequestAccessAsync();
|
||||
// If the user denies access, the task will not run.
|
||||
var requestTask = BackgroundExecutionManager.RequestAccessAsync();
|
||||
}
|
||||
|
||||
var builder = new BackgroundTaskBuilder();
|
||||
|
@ -100,10 +101,10 @@ namespace SDKTemplate
|
|||
|
||||
BackgroundTaskRegistration task = builder.Register();
|
||||
|
||||
UpdateBackgroundTaskStatus(name, true);
|
||||
UpdateBackgroundTaskRegistrationStatus(name, true);
|
||||
|
||||
//
|
||||
// Remove previous completion status from local settings.
|
||||
// Remove previous completion status.
|
||||
//
|
||||
var settings = ApplicationData.Current.LocalSettings;
|
||||
settings.Values.Remove(name);
|
||||
|
@ -129,7 +130,7 @@ namespace SDKTemplate
|
|||
}
|
||||
}
|
||||
|
||||
UpdateBackgroundTaskStatus(name, false);
|
||||
UpdateBackgroundTaskRegistrationStatus(name, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -137,7 +138,7 @@ namespace SDKTemplate
|
|||
/// </summary>
|
||||
/// <param name="name">Name of background task to store registration status for.</param>
|
||||
/// <param name="registered">TRUE if registered, FALSE if unregistered.</param>
|
||||
public static void UpdateBackgroundTaskStatus(String name, bool registered)
|
||||
public static void UpdateBackgroundTaskRegistrationStatus(String name, bool registered)
|
||||
{
|
||||
switch (name)
|
||||
{
|
||||
|
@ -188,10 +189,11 @@ namespace SDKTemplate
|
|||
|
||||
var status = registered ? "Registered" : "Unregistered";
|
||||
|
||||
object taskStatus;
|
||||
var settings = ApplicationData.Current.LocalSettings;
|
||||
if (settings.Values.ContainsKey(name))
|
||||
if (settings.Values.TryGetValue(name, out taskStatus))
|
||||
{
|
||||
status += " - " + settings.Values[name].ToString();
|
||||
status += " - " + taskStatus.ToString();
|
||||
}
|
||||
|
||||
return status;
|
||||
|
|
|
@ -48,7 +48,7 @@ namespace SDKTemplate
|
|||
if (task.Value.Name == BackgroundTaskSample.SampleBackgroundTaskName)
|
||||
{
|
||||
AttachProgressAndCompletedHandlers(task.Value);
|
||||
BackgroundTaskSample.UpdateBackgroundTaskStatus(BackgroundTaskSample.SampleBackgroundTaskName, true);
|
||||
BackgroundTaskSample.UpdateBackgroundTaskRegistrationStatus(BackgroundTaskSample.SampleBackgroundTaskName, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -61,14 +61,13 @@ namespace SDKTemplate
|
|||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private async void RegisterBackgroundTask(object sender, RoutedEventArgs e)
|
||||
private void RegisterBackgroundTask(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var task = BackgroundTaskSample.RegisterBackgroundTask(BackgroundTaskSample.SampleBackgroundTaskEntryPoint,
|
||||
BackgroundTaskSample.SampleBackgroundTaskName,
|
||||
new SystemTrigger(SystemTriggerType.TimeZoneChange, false),
|
||||
null);
|
||||
await task;
|
||||
AttachProgressAndCompletedHandlers(task.Result);
|
||||
AttachProgressAndCompletedHandlers(task);
|
||||
UpdateUI();
|
||||
}
|
||||
|
||||
|
@ -100,9 +99,12 @@ namespace SDKTemplate
|
|||
/// <param name="e">Arguments of the progress report.</param>
|
||||
private void OnProgress(IBackgroundTaskRegistration task, BackgroundTaskProgressEventArgs args)
|
||||
{
|
||||
var progress = "Progress: " + args.Progress + "%";
|
||||
BackgroundTaskSample.SampleBackgroundTaskProgress = progress;
|
||||
UpdateUI();
|
||||
var ignored = Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
|
||||
{
|
||||
var progress = "Progress: " + args.Progress + "%";
|
||||
BackgroundTaskSample.SampleBackgroundTaskProgress = progress;
|
||||
UpdateUI();
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -49,7 +49,7 @@ namespace SDKTemplate
|
|||
if (task.Value.Name == BackgroundTaskSample.SampleBackgroundTaskWithConditionName)
|
||||
{
|
||||
AttachProgressAndCompletedHandlers(task.Value);
|
||||
BackgroundTaskSample.UpdateBackgroundTaskStatus(BackgroundTaskSample.SampleBackgroundTaskWithConditionName, true);
|
||||
BackgroundTaskSample.UpdateBackgroundTaskRegistrationStatus(BackgroundTaskSample.SampleBackgroundTaskWithConditionName, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -62,14 +62,13 @@ namespace SDKTemplate
|
|||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private async void RegisterBackgroundTask(object sender, RoutedEventArgs e)
|
||||
private void RegisterBackgroundTask(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var task = BackgroundTaskSample.RegisterBackgroundTask(BackgroundTaskSample.SampleBackgroundTaskEntryPoint,
|
||||
BackgroundTaskSample.SampleBackgroundTaskWithConditionName,
|
||||
new SystemTrigger(SystemTriggerType.TimeZoneChange, false),
|
||||
new SystemCondition(SystemConditionType.InternetAvailable));
|
||||
await task;
|
||||
AttachProgressAndCompletedHandlers(task.Result);
|
||||
AttachProgressAndCompletedHandlers(task);
|
||||
UpdateUI();
|
||||
}
|
||||
|
||||
|
@ -101,9 +100,12 @@ namespace SDKTemplate
|
|||
/// <param name="e">Arguments of the progress report.</param>
|
||||
private void OnProgress(IBackgroundTaskRegistration task, BackgroundTaskProgressEventArgs args)
|
||||
{
|
||||
var progress = "Progress: " + args.Progress + "%";
|
||||
BackgroundTaskSample.SampleBackgroundTaskWithConditionProgress = progress;
|
||||
UpdateUI();
|
||||
var ignored = Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
|
||||
{
|
||||
var progress = "Progress: " + args.Progress + "%";
|
||||
BackgroundTaskSample.SampleBackgroundTaskWithConditionProgress = progress;
|
||||
UpdateUI();
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -48,7 +48,7 @@ namespace SDKTemplate
|
|||
if (task.Value.Name == BackgroundTaskSample.ServicingCompleteTaskName)
|
||||
{
|
||||
AttachProgressAndCompletedHandlers(task.Value);
|
||||
BackgroundTaskSample.UpdateBackgroundTaskStatus(BackgroundTaskSample.ServicingCompleteTaskName, true);
|
||||
BackgroundTaskSample.UpdateBackgroundTaskRegistrationStatus(BackgroundTaskSample.ServicingCompleteTaskName, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -61,14 +61,13 @@ namespace SDKTemplate
|
|||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private async void RegisterBackgroundTask(object sender, RoutedEventArgs e)
|
||||
private void RegisterBackgroundTask(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var task = BackgroundTaskSample.RegisterBackgroundTask(BackgroundTaskSample.ServicingCompleteTaskEntryPoint,
|
||||
BackgroundTaskSample.ServicingCompleteTaskName,
|
||||
new SystemTrigger(SystemTriggerType.ServicingComplete, false),
|
||||
null);
|
||||
await task;
|
||||
AttachProgressAndCompletedHandlers(task.Result);
|
||||
AttachProgressAndCompletedHandlers(task);
|
||||
UpdateUI();
|
||||
}
|
||||
|
||||
|
@ -100,9 +99,12 @@ namespace SDKTemplate
|
|||
/// <param name="e">Arguments of the progress report.</param>
|
||||
private void OnProgress(IBackgroundTaskRegistration task, BackgroundTaskProgressEventArgs args)
|
||||
{
|
||||
var progress = "Progress: " + args.Progress + "%";
|
||||
BackgroundTaskSample.ServicingCompleteTaskProgress = progress;
|
||||
UpdateUI();
|
||||
var ignored = Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
|
||||
{
|
||||
var progress = "Progress: " + args.Progress + "%";
|
||||
BackgroundTaskSample.ServicingCompleteTaskProgress = progress;
|
||||
UpdateUI();
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -48,7 +48,7 @@ namespace SDKTemplate
|
|||
if (task.Value.Name == BackgroundTaskSample.TimeTriggeredTaskName)
|
||||
{
|
||||
AttachProgressAndCompletedHandlers(task.Value);
|
||||
BackgroundTaskSample.UpdateBackgroundTaskStatus(BackgroundTaskSample.TimeTriggeredTaskName, true);
|
||||
BackgroundTaskSample.UpdateBackgroundTaskRegistrationStatus(BackgroundTaskSample.TimeTriggeredTaskName, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -61,14 +61,13 @@ namespace SDKTemplate
|
|||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private async void RegisterBackgroundTask(object sender, RoutedEventArgs e)
|
||||
private void RegisterBackgroundTask(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var task = BackgroundTaskSample.RegisterBackgroundTask(BackgroundTaskSample.SampleBackgroundTaskEntryPoint,
|
||||
BackgroundTaskSample.TimeTriggeredTaskName,
|
||||
new TimeTrigger(15, false),
|
||||
null);
|
||||
await task;
|
||||
AttachProgressAndCompletedHandlers(task.Result);
|
||||
AttachProgressAndCompletedHandlers(task);
|
||||
UpdateUI();
|
||||
}
|
||||
|
||||
|
@ -100,9 +99,12 @@ namespace SDKTemplate
|
|||
/// <param name="e">Arguments of the progress report.</param>
|
||||
private void OnProgress(IBackgroundTaskRegistration task, BackgroundTaskProgressEventArgs args)
|
||||
{
|
||||
var progress = "Progress: " + args.Progress + "%";
|
||||
BackgroundTaskSample.TimeTriggeredTaskProgress = progress;
|
||||
UpdateUI();
|
||||
var ignored = Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
|
||||
{
|
||||
var progress = "Progress: " + args.Progress + "%";
|
||||
BackgroundTaskSample.TimeTriggeredTaskProgress = progress;
|
||||
UpdateUI();
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -51,7 +51,7 @@ namespace SDKTemplate
|
|||
if (task.Value.Name == BackgroundTaskSample.ApplicationTriggerTaskName)
|
||||
{
|
||||
AttachProgressAndCompletedHandlers(task.Value);
|
||||
BackgroundTaskSample.UpdateBackgroundTaskStatus(BackgroundTaskSample.ApplicationTriggerTaskName, true);
|
||||
BackgroundTaskSample.UpdateBackgroundTaskRegistrationStatus(BackgroundTaskSample.ApplicationTriggerTaskName, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -65,14 +65,13 @@ namespace SDKTemplate
|
|||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private async void RegisterBackgroundTask(object sender, RoutedEventArgs e)
|
||||
private void RegisterBackgroundTask(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var task = BackgroundTaskSample.RegisterBackgroundTask(BackgroundTaskSample.SampleBackgroundTaskEntryPoint,
|
||||
BackgroundTaskSample.ApplicationTriggerTaskName,
|
||||
trigger,
|
||||
null);
|
||||
await task;
|
||||
AttachProgressAndCompletedHandlers(task.Result);
|
||||
AttachProgressAndCompletedHandlers(task);
|
||||
UpdateUI();
|
||||
}
|
||||
|
||||
|
@ -122,9 +121,12 @@ namespace SDKTemplate
|
|||
/// <param name="e">Arguments of the progress report.</param>
|
||||
private void OnProgress(IBackgroundTaskRegistration task, BackgroundTaskProgressEventArgs args)
|
||||
{
|
||||
var progress = "Progress: " + args.Progress + "%";
|
||||
BackgroundTaskSample.ApplicationTriggerTaskProgress = progress;
|
||||
UpdateUI();
|
||||
var ignored = Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
|
||||
{
|
||||
var progress = "Progress: " + args.Progress + "%";
|
||||
BackgroundTaskSample.ApplicationTriggerTaskProgress = progress;
|
||||
UpdateUI();
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -91,13 +91,14 @@ namespace Tasks
|
|||
{
|
||||
_periodicTimer.Cancel();
|
||||
|
||||
var settings = ApplicationData.Current.LocalSettings;
|
||||
var key = _taskInstance.Task.Name;
|
||||
|
||||
//
|
||||
// Write to LocalSettings to indicate that this background task ran.
|
||||
// Record that this background task ran.
|
||||
//
|
||||
settings.Values[key] = (_progress < 100) ? "Canceled with reason: " + _cancelReason.ToString() : "Completed";
|
||||
String taskStatus = (_progress < 100) ? "Canceled with reason: " + _cancelReason.ToString() : "Completed";
|
||||
var settings = ApplicationData.Current.LocalSettings;
|
||||
settings.Values[key] = taskStatus;
|
||||
Debug.WriteLine("Background " + _taskInstance.Task.Name + settings.Values[key]);
|
||||
|
||||
//
|
||||
|
|
|
@ -81,9 +81,10 @@ Namespace Global.SDKTemplate
|
|||
''' <param name="name">A name for the background task.</param>
|
||||
''' <param name="trigger">The trigger for the background task.</param>
|
||||
''' <param name="condition">An optional conditional event that must be true for the task to fire.</param>
|
||||
Public Shared Async Function RegisterBackgroundTask(taskEntryPoint As String, name As String, trigger As IBackgroundTrigger, condition As IBackgroundCondition) As Task(Of BackgroundTaskRegistration)
|
||||
Public Shared Function RegisterBackgroundTask(taskEntryPoint As String, name As String, trigger As IBackgroundTrigger, condition As IBackgroundCondition) As BackgroundTaskRegistration
|
||||
If TaskRequiresBackgroundAccess(name) Then
|
||||
Await BackgroundExecutionManager.RequestAccessAsync()
|
||||
' If the user denies access, the task will not run.
|
||||
Dim requestTask = BackgroundExecutionManager.RequestAccessAsync()
|
||||
End If
|
||||
|
||||
Dim builder = New BackgroundTaskBuilder()
|
||||
|
@ -96,9 +97,9 @@ Namespace Global.SDKTemplate
|
|||
End If
|
||||
|
||||
Dim task As BackgroundTaskRegistration = builder.Register()
|
||||
UpdateBackgroundTaskStatus(name, True)
|
||||
UpdateBackgroundTaskRegistrationStatus(name, True)
|
||||
'
|
||||
' Remove previous completion status from local settings.
|
||||
' Remove previous completion status.
|
||||
'
|
||||
Dim settings = ApplicationData.Current.LocalSettings
|
||||
settings.Values.Remove(name)
|
||||
|
@ -116,7 +117,7 @@ Namespace Global.SDKTemplate
|
|||
End If
|
||||
Next
|
||||
|
||||
UpdateBackgroundTaskStatus(name, False)
|
||||
UpdateBackgroundTaskRegistrationStatus(name, False)
|
||||
End Sub
|
||||
|
||||
''' <summary>
|
||||
|
@ -124,7 +125,7 @@ Namespace Global.SDKTemplate
|
|||
''' </summary>
|
||||
''' <param name="name">Name of background task to store registration status for.</param>
|
||||
''' <param name="registered">TRUE if registered, FALSE if unregistered.</param>
|
||||
Public Shared Sub UpdateBackgroundTaskStatus(name As String, registered As Boolean)
|
||||
Public Shared Sub UpdateBackgroundTaskRegistrationStatus(name As String, registered As Boolean)
|
||||
Select name
|
||||
Case SampleBackgroundTaskName
|
||||
SampleBackgroundTaskRegistered = registered
|
||||
|
@ -160,9 +161,10 @@ Namespace Global.SDKTemplate
|
|||
End Select
|
||||
|
||||
Dim status = If(registered, "Registered", "Unregistered")
|
||||
Dim taskStatus As Object = Nothing
|
||||
Dim settings = ApplicationData.Current.LocalSettings
|
||||
If settings.Values.ContainsKey(name) Then
|
||||
status &= " - " & settings.Values(name).ToString()
|
||||
If settings.Values.TryGetValue(name, taskStatus) Then
|
||||
status &= " - " & taskStatus.ToString()
|
||||
End If
|
||||
|
||||
Return status
|
||||
|
@ -173,7 +175,7 @@ Namespace Global.SDKTemplate
|
|||
''' </summary>
|
||||
''' <param name="name">Name of background task to query background access requirement.</param>
|
||||
Public Shared Function TaskRequiresBackgroundAccess(name As String) As Boolean
|
||||
If(name = TimeTriggeredTaskName) OrElse (name = ApplicationTriggerTaskName) Then
|
||||
If (name = TimeTriggeredTaskName) OrElse (name = ApplicationTriggerTaskName) Then
|
||||
Return True
|
||||
Else
|
||||
Return False
|
||||
|
|
|
@ -42,7 +42,7 @@ Namespace Global.SDKTemplate
|
|||
For Each task In BackgroundTaskRegistration.AllTasks
|
||||
If task.Value.Name = BackgroundTaskSample.SampleBackgroundTaskName Then
|
||||
AttachProgressAndCompletedHandlers(task.Value)
|
||||
BackgroundTaskSample.UpdateBackgroundTaskStatus(BackgroundTaskSample.SampleBackgroundTaskName, True)
|
||||
BackgroundTaskSample.UpdateBackgroundTaskRegistrationStatus(BackgroundTaskSample.SampleBackgroundTaskName, True)
|
||||
Exit For
|
||||
End If
|
||||
Next
|
||||
|
@ -55,10 +55,9 @@ Namespace Global.SDKTemplate
|
|||
''' </summary>
|
||||
''' <param name="sender"></param>
|
||||
''' <param name="e"></param>
|
||||
Private Async Sub RegisterBackgroundTask(sender As Object, e As RoutedEventArgs)
|
||||
Private Sub RegisterBackgroundTask(sender As Object, e As RoutedEventArgs)
|
||||
Dim task = BackgroundTaskSample.RegisterBackgroundTask(BackgroundTaskSample.SampleBackgroundTaskEntryPoint, BackgroundTaskSample.SampleBackgroundTaskName, New SystemTrigger(SystemTriggerType.TimeZoneChange, False), Nothing)
|
||||
Await task
|
||||
AttachProgressAndCompletedHandlers(task.Result)
|
||||
AttachProgressAndCompletedHandlers(task)
|
||||
UpdateUI()
|
||||
End Sub
|
||||
|
||||
|
@ -87,9 +86,11 @@ Namespace Global.SDKTemplate
|
|||
''' <param name="task">The task that is reporting progress.</param>
|
||||
''' <param name="e">Arguments of the progress report.</param>
|
||||
Private Sub OnProgress(task As IBackgroundTaskRegistration, args As BackgroundTaskProgressEventArgs)
|
||||
Dim progress = "Progress: " & args.Progress & "%"
|
||||
BackgroundTaskSample.SampleBackgroundTaskProgress = progress
|
||||
UpdateUI()
|
||||
Dim ignored = Dispatcher.RunAsync(CoreDispatcherPriority.Normal, Sub()
|
||||
Dim progress = "Progress: " & args.Progress & "%"
|
||||
BackgroundTaskSample.SampleBackgroundTaskProgress = progress
|
||||
UpdateUI()
|
||||
End Sub)
|
||||
End Sub
|
||||
|
||||
''' <summary>
|
||||
|
|
|
@ -40,7 +40,7 @@ Namespace Global.SDKTemplate
|
|||
For Each task In BackgroundTaskRegistration.AllTasks
|
||||
If task.Value.Name = BackgroundTaskSample.SampleBackgroundTaskWithConditionName Then
|
||||
AttachProgressAndCompletedHandlers(task.Value)
|
||||
BackgroundTaskSample.UpdateBackgroundTaskStatus(BackgroundTaskSample.SampleBackgroundTaskWithConditionName, True)
|
||||
BackgroundTaskSample.UpdateBackgroundTaskRegistrationStatus(BackgroundTaskSample.SampleBackgroundTaskWithConditionName, True)
|
||||
Exit For
|
||||
End If
|
||||
Next
|
||||
|
@ -53,10 +53,9 @@ Namespace Global.SDKTemplate
|
|||
''' </summary>
|
||||
''' <param name="sender"></param>
|
||||
''' <param name="e"></param>
|
||||
Private Async Sub RegisterBackgroundTask(sender As Object, e As RoutedEventArgs)
|
||||
Private Sub RegisterBackgroundTask(sender As Object, e As RoutedEventArgs)
|
||||
Dim task = BackgroundTaskSample.RegisterBackgroundTask(BackgroundTaskSample.SampleBackgroundTaskEntryPoint, BackgroundTaskSample.SampleBackgroundTaskWithConditionName, New SystemTrigger(SystemTriggerType.TimeZoneChange, False), New SystemCondition(SystemConditionType.InternetAvailable))
|
||||
Await task
|
||||
AttachProgressAndCompletedHandlers(task.Result)
|
||||
AttachProgressAndCompletedHandlers(task)
|
||||
UpdateUI()
|
||||
End Sub
|
||||
|
||||
|
@ -85,9 +84,11 @@ Namespace Global.SDKTemplate
|
|||
''' <param name="task">The task that is reporting progress.</param>
|
||||
''' <param name="e">Arguments of the progress report.</param>
|
||||
Private Sub OnProgress(task As IBackgroundTaskRegistration, args As BackgroundTaskProgressEventArgs)
|
||||
Dim progress = "Progress: " & args.Progress & "%"
|
||||
BackgroundTaskSample.SampleBackgroundTaskWithConditionProgress = progress
|
||||
UpdateUI()
|
||||
Dim ignored = Dispatcher.RunAsync(CoreDispatcherPriority.Normal, Sub()
|
||||
Dim progress = "Progress: " & args.Progress & "%"
|
||||
BackgroundTaskSample.SampleBackgroundTaskWithConditionProgress = progress
|
||||
UpdateUI()
|
||||
End Sub)
|
||||
End Sub
|
||||
|
||||
''' <summary>
|
||||
|
|
|
@ -40,7 +40,7 @@ Namespace Global.SDKTemplate
|
|||
For Each task In BackgroundTaskRegistration.AllTasks
|
||||
If task.Value.Name = BackgroundTaskSample.ServicingCompleteTaskName Then
|
||||
AttachProgressAndCompletedHandlers(task.Value)
|
||||
BackgroundTaskSample.UpdateBackgroundTaskStatus(BackgroundTaskSample.ServicingCompleteTaskName, True)
|
||||
BackgroundTaskSample.UpdateBackgroundTaskRegistrationStatus(BackgroundTaskSample.ServicingCompleteTaskName, True)
|
||||
Exit For
|
||||
End If
|
||||
Next
|
||||
|
@ -53,10 +53,9 @@ Namespace Global.SDKTemplate
|
|||
''' </summary>
|
||||
''' <param name="sender"></param>
|
||||
''' <param name="e"></param>
|
||||
Private Async Sub RegisterBackgroundTask(sender As Object, e As RoutedEventArgs)
|
||||
Private Sub RegisterBackgroundTask(sender As Object, e As RoutedEventArgs)
|
||||
Dim task = BackgroundTaskSample.RegisterBackgroundTask(BackgroundTaskSample.ServicingCompleteTaskEntryPoint, BackgroundTaskSample.ServicingCompleteTaskName, New SystemTrigger(SystemTriggerType.ServicingComplete, False), Nothing)
|
||||
Await task
|
||||
AttachProgressAndCompletedHandlers(task.Result)
|
||||
AttachProgressAndCompletedHandlers(task)
|
||||
UpdateUI()
|
||||
End Sub
|
||||
|
||||
|
@ -85,9 +84,11 @@ Namespace Global.SDKTemplate
|
|||
''' <param name="task">The task that is reporting progress.</param>
|
||||
''' <param name="e">Arguments of the progress report.</param>
|
||||
Private Sub OnProgress(task As IBackgroundTaskRegistration, args As BackgroundTaskProgressEventArgs)
|
||||
Dim progress = "Progress: " & args.Progress & "%"
|
||||
BackgroundTaskSample.ServicingCompleteTaskProgress = progress
|
||||
UpdateUI()
|
||||
Dim ignored = Dispatcher.RunAsync(CoreDispatcherPriority.Normal, Sub()
|
||||
Dim progress = "Progress: " & args.Progress & "%"
|
||||
BackgroundTaskSample.ServicingCompleteTaskProgress = progress
|
||||
UpdateUI()
|
||||
End Sub)
|
||||
End Sub
|
||||
|
||||
''' <summary>
|
||||
|
|
|
@ -40,7 +40,7 @@ Namespace Global.SDKTemplate
|
|||
For Each task In BackgroundTaskRegistration.AllTasks
|
||||
If task.Value.Name = BackgroundTaskSample.TimeTriggeredTaskName Then
|
||||
AttachProgressAndCompletedHandlers(task.Value)
|
||||
BackgroundTaskSample.UpdateBackgroundTaskStatus(BackgroundTaskSample.TimeTriggeredTaskName, True)
|
||||
BackgroundTaskSample.UpdateBackgroundTaskRegistrationStatus(BackgroundTaskSample.TimeTriggeredTaskName, True)
|
||||
Exit For
|
||||
End If
|
||||
Next
|
||||
|
@ -53,10 +53,9 @@ Namespace Global.SDKTemplate
|
|||
''' </summary>
|
||||
''' <param name="sender"></param>
|
||||
''' <param name="e"></param>
|
||||
Private Async Sub RegisterBackgroundTask(sender As Object, e As RoutedEventArgs)
|
||||
Private Sub RegisterBackgroundTask(sender As Object, e As RoutedEventArgs)
|
||||
Dim task = BackgroundTaskSample.RegisterBackgroundTask(BackgroundTaskSample.SampleBackgroundTaskEntryPoint, BackgroundTaskSample.TimeTriggeredTaskName, New TimeTrigger(15, False), Nothing)
|
||||
Await task
|
||||
AttachProgressAndCompletedHandlers(task.Result)
|
||||
AttachProgressAndCompletedHandlers(task)
|
||||
UpdateUI()
|
||||
End Sub
|
||||
|
||||
|
@ -85,9 +84,11 @@ Namespace Global.SDKTemplate
|
|||
''' <param name="task">The task that is reporting progress.</param>
|
||||
''' <param name="e">Arguments of the progress report.</param>
|
||||
Private Sub OnProgress(task As IBackgroundTaskRegistration, args As BackgroundTaskProgressEventArgs)
|
||||
Dim progress = "Progress: " & args.Progress & "%"
|
||||
BackgroundTaskSample.TimeTriggeredTaskProgress = progress
|
||||
UpdateUI()
|
||||
Dim ignored = Dispatcher.RunAsync(CoreDispatcherPriority.Normal, Sub()
|
||||
Dim progress = "Progress: " & args.Progress & "%"
|
||||
BackgroundTaskSample.TimeTriggeredTaskProgress = progress
|
||||
UpdateUI()
|
||||
End Sub)
|
||||
End Sub
|
||||
|
||||
''' <summary>
|
||||
|
|
|
@ -42,7 +42,7 @@ Namespace Global.SDKTemplate
|
|||
For Each task In BackgroundTaskRegistration.AllTasks
|
||||
If task.Value.Name = BackgroundTaskSample.ApplicationTriggerTaskName Then
|
||||
AttachProgressAndCompletedHandlers(task.Value)
|
||||
BackgroundTaskSample.UpdateBackgroundTaskStatus(BackgroundTaskSample.ApplicationTriggerTaskName, True)
|
||||
BackgroundTaskSample.UpdateBackgroundTaskRegistrationStatus(BackgroundTaskSample.ApplicationTriggerTaskName, True)
|
||||
Exit For
|
||||
End If
|
||||
Next
|
||||
|
@ -56,10 +56,9 @@ Namespace Global.SDKTemplate
|
|||
''' </summary>
|
||||
''' <param name="sender"></param>
|
||||
''' <param name="e"></param>
|
||||
Private Async Sub RegisterBackgroundTask(sender As Object, e As RoutedEventArgs)
|
||||
Private Sub RegisterBackgroundTask(sender As Object, e As RoutedEventArgs)
|
||||
Dim task = BackgroundTaskSample.RegisterBackgroundTask(BackgroundTaskSample.SampleBackgroundTaskEntryPoint, BackgroundTaskSample.ApplicationTriggerTaskName, trigger, Nothing)
|
||||
Await task
|
||||
AttachProgressAndCompletedHandlers(task.Result)
|
||||
AttachProgressAndCompletedHandlers(task)
|
||||
UpdateUI()
|
||||
End Sub
|
||||
|
||||
|
@ -104,9 +103,11 @@ Namespace Global.SDKTemplate
|
|||
''' <param name="task">The task that is reporting progress.</param>
|
||||
''' <param name="e">Arguments of the progress report.</param>
|
||||
Private Sub OnProgress(task As IBackgroundTaskRegistration, args As BackgroundTaskProgressEventArgs)
|
||||
Dim progress = "Progress: " & args.Progress & "%"
|
||||
BackgroundTaskSample.ApplicationTriggerTaskProgress = progress
|
||||
UpdateUI()
|
||||
Dim ignored = Dispatcher.RunAsync(CoreDispatcherPriority.Normal, Sub()
|
||||
Dim progress = "Progress: " & args.Progress & "%"
|
||||
BackgroundTaskSample.ApplicationTriggerTaskProgress = progress
|
||||
UpdateUI()
|
||||
End Sub)
|
||||
End Sub
|
||||
|
||||
''' <summary>
|
||||
|
|
|
@ -72,10 +72,11 @@ Namespace Global.Tasks
|
|||
_taskInstance.Progress = _progress
|
||||
Else
|
||||
_periodicTimer.Cancel()
|
||||
Dim settings = ApplicationData.Current.LocalSettings
|
||||
Dim status As String = If((_progress < 100), "Canceled with reason: " & _cancelReason.ToString(), "Completed")
|
||||
Dim key = _taskInstance.Task.Name
|
||||
settings.Values(key) = If((_progress < 100), "Canceled with reason: " & _cancelReason.ToString(), "Completed")
|
||||
Debug.WriteLine("Background " & _taskInstance.Task.Name & settings.Values(key))
|
||||
Dim settings = ApplicationData.Current.LocalSettings
|
||||
settings.Values(key) = status
|
||||
Debug.WriteLine("Background " & _taskInstance.Task.Name & status)
|
||||
_deferral.Complete()
|
||||
End If
|
||||
End Sub
|
||||
|
|
|
@ -5,17 +5,18 @@
|
|||
|
||||
# Barcode scanner sample
|
||||
|
||||
This sample shows how to create a barcode scanner, claim it for exclusive use, enable it to receive data, and read a barcode. This sample uses [**Windows.Devices.PointOfService**](http://msdn.microsoft.com/library/windows/apps/dn298071) API.
|
||||
This sample shows how to obtain a barcode scanner,
|
||||
claim it for exclusive use, enable it to receive data, and read a barcode.
|
||||
|
||||
Specifically, this sample shows how to:
|
||||
|
||||
1. **Create the barcode scanner**
|
||||
1. **Obtain the barcode scanner**
|
||||
|
||||
Uses the [**BarcodeScanner.GetDefaultAsync**](http://msdn.microsoft.com/library/windows/apps/dn263790) to get the first available barcode scanner.
|
||||
Uses [**BarcodeScanner.GetDefaultAsync**](http://msdn.microsoft.com/library/windows/apps/dn263790) to get the first available barcode scanner.
|
||||
|
||||
2. **Claim the barcode scanner for exclusive use**
|
||||
|
||||
Uses the [**ClaimScannerAsync**](http://msdn.microsoft.com/library/windows/apps/dn297696) to claim the device.
|
||||
Uses [**ClaimScannerAsync**](http://msdn.microsoft.com/library/windows/apps/dn297696) to claim the device.
|
||||
|
||||
3. **Add event handlers**
|
||||
|
||||
|
@ -41,13 +42,9 @@ To obtain information about Microsoft Visual Studio 2015 and the tools for devel
|
|||
|
||||
## Related topics
|
||||
|
||||
### Samples
|
||||
|
||||
[Barcode Scanner sample](/Samples/BarcodeScanner)
|
||||
|
||||
### Reference
|
||||
|
||||
[Windows.Devices.PointOfService](http://msdn.microsoft.com/library/windows/apps/dn298071)
|
||||
[Windows.Devices.PointOfService namespace](http://msdn.microsoft.com/library/windows/apps/dn298071)
|
||||
|
||||
[USB HID POS Scanner specification](http://go.microsoft.com/fwlink/p/?linkid=309230)
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest"
|
||||
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
|
||||
xmlns:mobile="http://schemas.microsoft.com/appx/manifest/mobile/windows10"
|
||||
IgnorableNamespaces="uap mp"
|
||||
IgnorableNamespaces="uap mp mobile"
|
||||
>
|
||||
<Identity Name="Microsoft.SDKSamples.CallerID.CS" Publisher="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US" Version="1.0.0.0"/>
|
||||
<mp:PhoneIdentity PhoneProductId="2ae61f23-a2f1-48d1-8f76-57a630592a18" PhonePublisherId="00000000-0000-0000-0000-000000000000"/>
|
||||
|
|
|
@ -47,6 +47,7 @@ MainPage::MainPage()
|
|||
, _displayOrientation(DisplayOrientations::Portrait)
|
||||
, _displayRequest(ref new Windows::System::Display::DisplayRequest())
|
||||
, RotationKey({ 0xC380465D, 0x2271, 0x428C,{ 0x9B, 0x83, 0xEC, 0xEA, 0x3B, 0x4A, 0x85, 0xC1 } })
|
||||
, _captureFolder(nullptr)
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
|
@ -334,14 +335,17 @@ task<void> MainPage::TakePhotoAsync()
|
|||
return create_task(_mediaCapture->CapturePhotoToStreamAsync(Windows::Media::MediaProperties::ImageEncodingProperties::CreateJpeg(), inputStream))
|
||||
.then([this, inputStream]()
|
||||
{
|
||||
WriteLine("Photo taken!");
|
||||
return create_task(_captureFolder->CreateFileAsync("SimplePhoto.jpg", CreationCollisionOption::GenerateUniqueName));
|
||||
}).then([this, inputStream](StorageFile^ file)
|
||||
{
|
||||
WriteLine("Photo taken! Saving to " + file->Path);
|
||||
|
||||
// Done taking a photo, so re-enable the button
|
||||
VideoButton->IsEnabled = true;
|
||||
VideoButton->Opacity = 1;
|
||||
|
||||
auto photoOrientation = ConvertOrientationToPhotoOrientation(GetCameraOrientation());
|
||||
return ReencodeAndSavePhotoAsync(inputStream, photoOrientation);
|
||||
return ReencodeAndSavePhotoAsync(inputStream, file, photoOrientation);
|
||||
}).then([this](task<void> previousTask)
|
||||
{
|
||||
try
|
||||
|
@ -362,7 +366,7 @@ task<void> MainPage::TakePhotoAsync()
|
|||
/// <returns></returns>
|
||||
task<void> MainPage::StartRecordingAsync()
|
||||
{
|
||||
return create_task(KnownFolders::PicturesLibrary->CreateFileAsync("SimpleVideo.mp4", CreationCollisionOption::GenerateUniqueName))
|
||||
return create_task(_captureFolder->CreateFileAsync("SimpleVideo.mp4", CreationCollisionOption::GenerateUniqueName))
|
||||
.then([this](StorageFile^ file)
|
||||
{
|
||||
// Calculate rotation angle, taking mirroring into account if necessary
|
||||
|
@ -370,12 +374,11 @@ task<void> MainPage::StartRecordingAsync()
|
|||
auto encodingProfile = MediaProperties::MediaEncodingProfile::CreateMp4(MediaProperties::VideoEncodingQuality::Auto);
|
||||
encodingProfile->Video->Properties->Insert(RotationKey, rotationAngle);
|
||||
|
||||
WriteLine("Starting recording...");
|
||||
return create_task(_mediaCapture->StartRecordToStorageFileAsync(encodingProfile, file))
|
||||
.then([this]()
|
||||
.then([this, file]()
|
||||
{
|
||||
_isRecording = true;
|
||||
WriteLine("Started recording!");
|
||||
WriteLine("Started recording to " + file->Path);
|
||||
});
|
||||
}).then([this](task<void> previousTask)
|
||||
{
|
||||
|
@ -444,22 +447,21 @@ task<DeviceInformation^> MainPage::FindCameraDeviceByPanelAsync(Windows::Devices
|
|||
/// Applies the given orientation to a photo stream and saves it as a StorageFile
|
||||
/// </summary>
|
||||
/// <param name="stream">The photo stream</param>
|
||||
/// <param name="file">The StorageFile in which the photo stream will be saved</param>
|
||||
/// <param name="photoOrientation">The orientation metadata to apply to the photo</param>
|
||||
/// <returns></returns>
|
||||
task<void> MainPage::ReencodeAndSavePhotoAsync(Streams::IRandomAccessStream^ stream, FileProperties::PhotoOrientation photoOrientation)
|
||||
task<void> MainPage::ReencodeAndSavePhotoAsync(Streams::IRandomAccessStream^ stream, StorageFile^ file, FileProperties::PhotoOrientation photoOrientation)
|
||||
{
|
||||
// Using this state variable to pass multiple values through our task chain
|
||||
ReencodeState^ state = ref new ReencodeState();
|
||||
state->_file = file;
|
||||
state->_orientation = photoOrientation;
|
||||
|
||||
return create_task(BitmapDecoder::CreateAsync(stream))
|
||||
.then([state](BitmapDecoder^ decoder)
|
||||
{
|
||||
state->_decoder = decoder;
|
||||
return create_task(KnownFolders::PicturesLibrary->CreateFileAsync("SimplePhoto.jpg", CreationCollisionOption::GenerateUniqueName));
|
||||
}).then([](StorageFile^ file)
|
||||
{
|
||||
return create_task(file->OpenAsync(FileAccessMode::ReadWrite));
|
||||
return create_task(state->_file->OpenAsync(FileAccessMode::ReadWrite));
|
||||
}).then([state](Streams::IRandomAccessStream^ outputStream)
|
||||
{
|
||||
return create_task(BitmapEncoder::CreateForTranscodingAsync(outputStream, state->_decoder));
|
||||
|
@ -528,6 +530,17 @@ task<void> MainPage::SetupUiAsync()
|
|||
_deviceOrientation = _orientationSensor->GetCurrentOrientation();
|
||||
}
|
||||
|
||||
create_task(StorageLibrary::GetLibraryAsync(KnownLibraryId::Pictures))
|
||||
.then([this](StorageLibrary^ picturesLibrary)
|
||||
{
|
||||
_captureFolder = picturesLibrary->SaveFolder;
|
||||
if (_captureFolder == nullptr)
|
||||
{
|
||||
// In this case fall back to the local app storage since the Pictures Library is not available
|
||||
_captureFolder = ApplicationData::Current->LocalFolder;
|
||||
}
|
||||
});
|
||||
|
||||
// Hide the status bar
|
||||
if (Windows::Foundation::Metadata::ApiInformation::IsTypePresent("Windows.UI.ViewManagement.StatusBar"))
|
||||
{
|
||||
|
@ -1006,12 +1019,12 @@ void MainPage::DisplayInformation_OrientationChanged(DisplayInformation^ sender,
|
|||
}));
|
||||
}
|
||||
|
||||
void MainPage::PhotoButton_Tapped(Object^, Windows::UI::Xaml::RoutedEventArgs^)
|
||||
void MainPage::PhotoButton_Click(Object^, Windows::UI::Xaml::RoutedEventArgs^)
|
||||
{
|
||||
TakePhotoAsync();
|
||||
}
|
||||
|
||||
void MainPage::VideoButton_Tapped(Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
|
||||
void MainPage::VideoButton_Click(Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
|
||||
{
|
||||
task<void> taskToExecute;
|
||||
if (!_isRecording)
|
||||
|
@ -1030,7 +1043,7 @@ void MainPage::VideoButton_Tapped(Object^ sender, Windows::UI::Xaml::RoutedEvent
|
|||
});
|
||||
}
|
||||
|
||||
void MainPage::FaceDetectionButton_Tapped(Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
|
||||
void MainPage::FaceDetectionButton_Click(Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
|
||||
{
|
||||
task<void> taskToExecute;
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ namespace FaceDetection
|
|||
internal:
|
||||
Windows::Graphics::Imaging::BitmapDecoder^ _decoder;
|
||||
Windows::Graphics::Imaging::BitmapEncoder^ _encoder;
|
||||
Windows::Storage::StorageFile^ _file;
|
||||
Windows::Storage::FileProperties::PhotoOrientation _orientation;
|
||||
};
|
||||
|
||||
|
@ -54,6 +55,9 @@ namespace FaceDetection
|
|||
// Reference: http://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh868174.aspx
|
||||
const GUID RotationKey;
|
||||
|
||||
// Folder in which the captures will be stored (availability check performed in SetupUiAsync)
|
||||
Windows::Storage::StorageFolder^ _captureFolder;
|
||||
|
||||
// Event tokens
|
||||
Windows::Foundation::EventRegistrationToken _applicationSuspendingEventToken;
|
||||
Windows::Foundation::EventRegistrationToken _applicationResumingEventToken;
|
||||
|
@ -79,7 +83,7 @@ namespace FaceDetection
|
|||
|
||||
// Helpers
|
||||
Concurrency::task<Windows::Devices::Enumeration::DeviceInformation^> FindCameraDeviceByPanelAsync(Windows::Devices::Enumeration::Panel panel);
|
||||
Concurrency::task<void> ReencodeAndSavePhotoAsync(Windows::Storage::Streams::IRandomAccessStream^ stream, Windows::Storage::FileProperties::PhotoOrientation photoOrientation);
|
||||
Concurrency::task<void> ReencodeAndSavePhotoAsync(Windows::Storage::Streams::IRandomAccessStream^ stream, Windows::Storage::StorageFile^ file, Windows::Storage::FileProperties::PhotoOrientation photoOrientation);
|
||||
void UpdateCaptureControls();
|
||||
Concurrency::task<void> SetupUiAsync();
|
||||
Concurrency::task<void> CleanupUiAsync();
|
||||
|
@ -106,10 +110,10 @@ namespace FaceDetection
|
|||
void Application_Suspending(Object^ sender, Windows::ApplicationModel::SuspendingEventArgs^ e);
|
||||
void Application_Resuming(Object^ sender, Object^ args);
|
||||
void DisplayInformation_OrientationChanged(Windows::Graphics::Display::DisplayInformation^ sender, Object^ args);
|
||||
void PhotoButton_Tapped(Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
|
||||
void VideoButton_Tapped(Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
|
||||
void PhotoButton_Click(Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
|
||||
void VideoButton_Click(Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
|
||||
void SystemMediaControls_PropertyChanged(Windows::Media::SystemMediaTransportControls^ sender, Windows::Media::SystemMediaTransportControlsPropertyChangedEventArgs^ args);
|
||||
void FaceDetectionButton_Tapped(Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
|
||||
void FaceDetectionButton_Click(Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
|
||||
void OrientationSensor_OrientationChanged(Windows::Devices::Sensors::SimpleOrientationSensor^, Windows::Devices::Sensors::SimpleOrientationSensorOrientationChangedEventArgs^);
|
||||
void HardwareButtons_CameraPressed(Platform::Object^, Windows::Phone::UI::Input::CameraEventArgs^);
|
||||
|
||||
|
|
|
@ -55,6 +55,9 @@ namespace FaceDetection
|
|||
// Reference: http://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh868174.aspx
|
||||
private static readonly Guid RotationKey = new Guid("C380465D-2271-428C-9B83-ECEA3B4A85C1");
|
||||
|
||||
// Folder in which the captures will be stored (initialized in SetupUiAsync)
|
||||
private StorageFolder _captureFolder = null;
|
||||
|
||||
// Prevent the screen from sleeping while the camera is running
|
||||
private readonly DisplayRequest _displayRequest = new DisplayRequest();
|
||||
|
||||
|
@ -198,12 +201,12 @@ namespace FaceDetection
|
|||
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => UpdateButtonOrientation());
|
||||
}
|
||||
|
||||
private async void PhotoButton_Tapped(object sender, TappedRoutedEventArgs e)
|
||||
private async void PhotoButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
await TakePhotoAsync();
|
||||
}
|
||||
|
||||
private async void VideoButton_Tapped(object sender, TappedRoutedEventArgs e)
|
||||
private async void VideoButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (!_isRecording)
|
||||
{
|
||||
|
@ -218,7 +221,7 @@ namespace FaceDetection
|
|||
UpdateCaptureControls();
|
||||
}
|
||||
|
||||
private async void FaceDetectionButton_Tapped(object sender, TappedRoutedEventArgs e)
|
||||
private async void FaceDetectionButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (_faceDetectionEffect == null || !_faceDetectionEffect.Enabled)
|
||||
{
|
||||
|
@ -456,7 +459,7 @@ namespace FaceDetection
|
|||
/// <returns></returns>
|
||||
private async Task TakePhotoAsync()
|
||||
{
|
||||
// While taking a photo, keep the video button enabled only if the camera supports simultaneosly taking pictures and recording video
|
||||
// While taking a photo, keep the video button enabled only if the camera supports simultaneously taking pictures and recording video
|
||||
VideoButton.IsEnabled = _mediaCapture.MediaCaptureSettings.ConcurrentRecordAndPhotoSupported;
|
||||
|
||||
// Make the button invisible if it's disabled, so it's obvious it cannot be interacted with
|
||||
|
@ -464,20 +467,25 @@ namespace FaceDetection
|
|||
|
||||
var stream = new InMemoryRandomAccessStream();
|
||||
|
||||
Debug.WriteLine("Taking photo...");
|
||||
await _mediaCapture.CapturePhotoToStreamAsync(ImageEncodingProperties.CreateJpeg(), stream);
|
||||
|
||||
try
|
||||
{
|
||||
Debug.WriteLine("Taking photo...");
|
||||
await _mediaCapture.CapturePhotoToStreamAsync(ImageEncodingProperties.CreateJpeg(), stream);
|
||||
Debug.WriteLine("Photo taken!");
|
||||
var file = await _captureFolder.CreateFileAsync("SimplePhoto.jpg", CreationCollisionOption.GenerateUniqueName);
|
||||
|
||||
Debug.WriteLine("Photo taken! Saving to " + file.Path);
|
||||
|
||||
var photoOrientation = ConvertOrientationToPhotoOrientation(GetCameraOrientation());
|
||||
|
||||
await ReencodeAndSavePhotoAsync(stream, photoOrientation);
|
||||
await ReencodeAndSavePhotoAsync(stream, file, photoOrientation);
|
||||
|
||||
Debug.WriteLine("Photo saved!");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// File I/O errors are reported as exceptions
|
||||
Debug.WriteLine("Exception when taking a photo: {0}", ex.ToString());
|
||||
Debug.WriteLine("Exception when taking a photo: " + ex.ToString());
|
||||
}
|
||||
|
||||
// Done taking a photo, so re-enable the button
|
||||
|
@ -494,7 +502,7 @@ namespace FaceDetection
|
|||
try
|
||||
{
|
||||
// Create storage file in Pictures Library
|
||||
var videoFile = await KnownFolders.PicturesLibrary.CreateFileAsync("SimpleVideo.mp4", CreationCollisionOption.GenerateUniqueName);
|
||||
var videoFile = await _captureFolder.CreateFileAsync("SimpleVideo.mp4", CreationCollisionOption.GenerateUniqueName);
|
||||
|
||||
var encodingProfile = MediaEncodingProfile.CreateMp4(VideoEncodingQuality.Auto);
|
||||
|
||||
|
@ -502,7 +510,7 @@ namespace FaceDetection
|
|||
var rotationAngle = 360 - ConvertDeviceOrientationToDegrees(GetCameraOrientation());
|
||||
encodingProfile.Video.Properties.Add(RotationKey, PropertyValue.CreateInt32(rotationAngle));
|
||||
|
||||
Debug.WriteLine("Starting recording...");
|
||||
Debug.WriteLine("Starting recording to " + videoFile.Path);
|
||||
|
||||
await _mediaCapture.StartRecordToStorageFileAsync(encodingProfile, videoFile);
|
||||
_isRecording = true;
|
||||
|
@ -512,7 +520,7 @@ namespace FaceDetection
|
|||
catch (Exception ex)
|
||||
{
|
||||
// File I/O errors are reported as exceptions
|
||||
Debug.WriteLine("Exception when starting video recording: {0}", ex.ToString());
|
||||
Debug.WriteLine("Exception when starting video recording: " + ex.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -599,6 +607,10 @@ namespace FaceDetection
|
|||
}
|
||||
|
||||
RegisterEventHandlers();
|
||||
|
||||
var picturesLibrary = await StorageLibrary.GetLibraryAsync(KnownLibraryId.Pictures);
|
||||
// Fall back to the local app storage if the Pictures Library is not available
|
||||
_captureFolder = picturesLibrary.SaveFolder ?? ApplicationData.Current.LocalFolder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -713,16 +725,15 @@ namespace FaceDetection
|
|||
/// Applies the given orientation to a photo stream and saves it as a StorageFile
|
||||
/// </summary>
|
||||
/// <param name="stream">The photo stream</param>
|
||||
/// <param name="file">The StorageFile in which the photo stream will be saved</param>
|
||||
/// <param name="photoOrientation">The orientation metadata to apply to the photo</param>
|
||||
/// <returns></returns>
|
||||
private static async Task ReencodeAndSavePhotoAsync(IRandomAccessStream stream, PhotoOrientation photoOrientation)
|
||||
private static async Task ReencodeAndSavePhotoAsync(IRandomAccessStream stream, StorageFile file, PhotoOrientation photoOrientation)
|
||||
{
|
||||
using (var inputStream = stream)
|
||||
{
|
||||
var decoder = await BitmapDecoder.CreateAsync(inputStream);
|
||||
|
||||
var file = await KnownFolders.PicturesLibrary.CreateFileAsync("SimplePhoto.jpeg", CreationCollisionOption.GenerateUniqueName);
|
||||
|
||||
using (var outputStream = await file.OpenAsync(FileAccessMode.ReadWrite))
|
||||
{
|
||||
var encoder = await BitmapEncoder.CreateForTranscodingAsync(outputStream, decoder);
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
<mp:PhoneIdentity PhoneProductId="d73539b4-c2ee-4d29-bc00-4bfd38e96567" PhonePublisherId="00000000-0000-0000-0000-000000000000"/>
|
||||
|
||||
<Properties>
|
||||
<DisplayName>CameraFaceDetection</DisplayName>
|
||||
<DisplayName>CameraFaceDetection JS Sample</DisplayName>
|
||||
<PublisherDisplayName>Microsoft Corporation</PublisherDisplayName>
|
||||
<Logo>images\storelogo-sdk.png</Logo>
|
||||
</Properties>
|
||||
|
|
|
@ -20,6 +20,9 @@
|
|||
var Media = Windows.Media;
|
||||
var SimpleOrientation = Windows.Devices.Sensors.SimpleOrientation;
|
||||
var SimpleOrientationSensor = Windows.Devices.Sensors.SimpleOrientationSensor;
|
||||
var StorageLibrary = Windows.Storage.StorageLibrary;
|
||||
var KnownLibraryId = Windows.Storage.KnownLibraryId;
|
||||
var ApplicationData = Windows.Storage.ApplicationData;
|
||||
|
||||
// Receive notifications about rotation of the device and UI and apply any necessary rotation to the preview stream and UI controls
|
||||
var oOrientationSensor = SimpleOrientationSensor.getDefault(),
|
||||
|
@ -49,6 +52,9 @@
|
|||
// Reference: http://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh868174.aspx
|
||||
var RotationKey = "C380465D-2271-428C-9B83-ECEA3B4A85C1";
|
||||
|
||||
// Folder in which the captures will be stored (initialized in SetupUiAsync)
|
||||
var oCaptureFolder;
|
||||
|
||||
// Initialization
|
||||
var app = WinJS.Application;
|
||||
var activation = Windows.ApplicationModel.Activation;
|
||||
|
@ -312,13 +318,18 @@
|
|||
console.log("Taking photo...");
|
||||
return oMediaCapture.capturePhotoToStreamAsync(Windows.Media.MediaProperties.ImageEncodingProperties.createJpeg(), inputStream)
|
||||
.then(function () {
|
||||
console.log("Photo taken!");
|
||||
return oCaptureFolder.createFileAsync("SimplePhoto.jpg", Windows.Storage.CreationCollisionOption.generateUniqueName);
|
||||
})
|
||||
.then(function (file) {
|
||||
console.log("Photo taken! Saving to " + file.path);
|
||||
|
||||
// Done taking a photo, so re-enable the button
|
||||
videoButton.isDisabled = false;
|
||||
|
||||
var photoOrientation = convertOrientationToPhotoOrientation(getCameraOrientation());
|
||||
return reencodeAndSavePhotoAsync(inputStream, photoOrientation);
|
||||
return reencodeAndSavePhotoAsync(inputStream, file, photoOrientation);
|
||||
}).then(function () {
|
||||
console.log("Photo saved!");
|
||||
}, function (error) {
|
||||
console.log(error.message);
|
||||
}).done();
|
||||
|
@ -329,14 +340,14 @@
|
|||
/// </summary>
|
||||
/// <returns></returns>
|
||||
function startRecordingAsync() {
|
||||
return Windows.Storage.KnownFolders.picturesLibrary.createFileAsync("SimpleVideo.mp4", Windows.Storage.CreationCollisionOption.generateUniqueName)
|
||||
return oCaptureFolder.createFileAsync("SimpleVideo.mp4", Windows.Storage.CreationCollisionOption.generateUniqueName)
|
||||
.then(function (file) {
|
||||
// Calculate rotation angle, taking mirroring into account if necessary
|
||||
var rotationAngle = 360 - convertDeviceOrientationToDegrees(getCameraOrientation());
|
||||
var encodingProfile = Windows.Media.MediaProperties.MediaEncodingProfile.createMp4(Windows.Media.MediaProperties.VideoEncodingQuality.auto);
|
||||
encodingProfile.video.properties.insert(RotationKey, rotationAngle);
|
||||
|
||||
console.log("Starting recording...");
|
||||
console.log("Starting recording to " + file.path);
|
||||
return oMediaCapture.startRecordToStorageFileAsync(encodingProfile, file)
|
||||
.then(function () {
|
||||
isRecording = true;
|
||||
|
@ -390,7 +401,7 @@
|
|||
/// <param name="stream">The photo stream</param>
|
||||
/// <param name="photoOrientation">The orientation metadata to apply to the photo</param>
|
||||
/// <returns></returns>
|
||||
function reencodeAndSavePhotoAsync(inputStream, orientation) {
|
||||
function reencodeAndSavePhotoAsync(inputStream, file, orientation) {
|
||||
var Imaging = Windows.Graphics.Imaging;
|
||||
var bitmapDecoder = null,
|
||||
bitmapEncoder = null,
|
||||
|
@ -399,8 +410,6 @@
|
|||
return Imaging.BitmapDecoder.createAsync(inputStream)
|
||||
.then(function (decoder) {
|
||||
bitmapDecoder = decoder;
|
||||
return Windows.Storage.KnownFolders.picturesLibrary.createFileAsync("SimplePhoto.jpg", Windows.Storage.CreationCollisionOption.generateUniqueName);
|
||||
}).then(function (file) {
|
||||
return file.openAsync(Windows.Storage.FileAccessMode.readWrite);
|
||||
}).then(function (outStream) {
|
||||
outputStream = outStream;
|
||||
|
@ -468,13 +477,19 @@
|
|||
oDeviceOrientation = oOrientationSensor.getCurrentOrientation();
|
||||
}
|
||||
|
||||
// Hide the status bar
|
||||
if (Windows.Foundation.Metadata.ApiInformation.isTypePresent("Windows.UI.ViewManagement.StatusBar")) {
|
||||
return Windows.UI.ViewManagement.StatusBar.getForCurrentView().hideAsync();
|
||||
}
|
||||
else {
|
||||
return WinJS.Promise.as();
|
||||
}
|
||||
return StorageLibrary.getLibraryAsync(KnownLibraryId.pictures)
|
||||
.then(function (picturesLibrary) {
|
||||
// Fall back to the local app storage if the Pictures Library is not available
|
||||
oCaptureFolder = picturesLibrary.saveFolder || ApplicationData.current.localFolder;
|
||||
|
||||
// Hide the status bar
|
||||
if (Windows.Foundation.Metadata.ApiInformation.isTypePresent("Windows.UI.ViewManagement.StatusBar")) {
|
||||
return Windows.UI.ViewManagement.StatusBar.getForCurrentView().hideAsync();
|
||||
}
|
||||
else {
|
||||
return WinJS.Promise.as();
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -54,13 +54,13 @@
|
|||
|
||||
<!-- Capture + Record buttons -->
|
||||
<StackPanel HorizontalAlignment="Right" VerticalAlignment="Center">
|
||||
<Button Name="PhotoButton" Tapped="PhotoButton_Tapped" IsEnabled="False">
|
||||
<Button Name="PhotoButton" Click="PhotoButton_Click" IsEnabled="False">
|
||||
<Viewbox>
|
||||
<SymbolIcon Symbol="Camera"/>
|
||||
</Viewbox>
|
||||
</Button>
|
||||
|
||||
<Button Name="VideoButton" Tapped="VideoButton_Tapped" IsEnabled="False">
|
||||
<Button Name="VideoButton" Click="VideoButton_Click" IsEnabled="False">
|
||||
<Grid>
|
||||
<Ellipse x:Name="StartRecordingIcon" Fill="Red" Width="20" Height="20"/>
|
||||
<Rectangle x:Name="StopRecordingIcon" Fill="White" Width="20" Height="20" Visibility="Collapsed"/>
|
||||
|
@ -69,7 +69,7 @@
|
|||
</StackPanel>
|
||||
|
||||
<!--Button to enable / disable face detection-->
|
||||
<Button Name="FaceDetectionButton" Tapped="FaceDetectionButton_Tapped" IsEnabled="False">
|
||||
<Button Name="FaceDetectionButton" Click="FaceDetectionButton_Click" IsEnabled="False">
|
||||
<Viewbox>
|
||||
<Grid>
|
||||
<SymbolIcon Name="FaceDetectionDisabledIcon" Symbol="Contact" Visibility="Visible"/>
|
||||
|
|
|
@ -57,6 +57,9 @@ Namespace Global.FaceDetection
|
|||
' Reference: http://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh868174.aspx
|
||||
Private Shared ReadOnly RotationKey As Guid = New Guid("C380465D-2271-428C-9B83-ECEA3B4A85C1")
|
||||
|
||||
' Folder in which the captures will be stored (initialized in SetupUiAsync)
|
||||
Private _captureFolder As StorageFolder = Nothing
|
||||
|
||||
' Prevent the screen from sleeping while the camera is running
|
||||
Private ReadOnly _displayRequest As DisplayRequest = New DisplayRequest()
|
||||
|
||||
|
@ -161,11 +164,11 @@ Namespace Global.FaceDetection
|
|||
Await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, Sub() UpdateButtonOrientation())
|
||||
End Sub
|
||||
|
||||
Private Async Sub PhotoButton_Tapped(sender As Object, e As TappedRoutedEventArgs)
|
||||
Private Async Sub PhotoButton_Click(sender As Object, e As RoutedEventArgs)
|
||||
Await TakePhotoAsync()
|
||||
End Sub
|
||||
|
||||
Private Async Sub VideoButton_Tapped(sender As Object, e As TappedRoutedEventArgs)
|
||||
Private Async Sub VideoButton_Click(sender As Object, e As RoutedEventArgs)
|
||||
If Not _isRecording Then
|
||||
Await StartRecordingAsync()
|
||||
Else
|
||||
|
@ -175,7 +178,7 @@ Namespace Global.FaceDetection
|
|||
UpdateCaptureControls()
|
||||
End Sub
|
||||
|
||||
Private Async Sub FaceDetectionButton_Tapped(sender As Object, e As TappedRoutedEventArgs)
|
||||
Private Async Sub FaceDetectionButton_Click(sender As Object, e As RoutedEventArgs)
|
||||
If _faceDetectionEffect Is Nothing OrElse Not _faceDetectionEffect.Enabled Then
|
||||
FacesCanvas.Children.Clear()
|
||||
Await CreateFaceDetectionEffectAsync()
|
||||
|
@ -331,14 +334,15 @@ Namespace Global.FaceDetection
|
|||
VideoButton.IsEnabled = _mediaCapture.MediaCaptureSettings.ConcurrentRecordAndPhotoSupported
|
||||
VideoButton.Opacity = If(VideoButton.IsEnabled, 1, 0)
|
||||
Dim stream = New InMemoryRandomAccessStream()
|
||||
Debug.WriteLine("Taking photo...")
|
||||
Await _mediaCapture.CapturePhotoToStreamAsync(ImageEncodingProperties.CreateJpeg(), stream)
|
||||
Try
|
||||
Debug.WriteLine("Taking photo...")
|
||||
Await _mediaCapture.CapturePhotoToStreamAsync(ImageEncodingProperties.CreateJpeg(), stream)
|
||||
Debug.WriteLine("Photo taken!")
|
||||
Dim file = Await _captureFolder.CreateFileAsync("SimplePhoto.jpg", CreationCollisionOption.GenerateUniqueName)
|
||||
Debug.WriteLine("Photo taken! Saving to " & file.Path)
|
||||
Dim photoOrientation = ConvertOrientationToPhotoOrientation(GetCameraOrientation())
|
||||
Await ReencodeAndSavePhotoAsync(stream, photoOrientation)
|
||||
Await ReencodeAndSavePhotoAsync(stream, file, photoOrientation)
|
||||
Catch ex As Exception
|
||||
Debug.WriteLine("Exception when taking a photo: {0}", ex.ToString())
|
||||
Debug.WriteLine("Exception when taking a photo: " & ex.ToString())
|
||||
End Try
|
||||
|
||||
VideoButton.IsEnabled = True
|
||||
|
@ -352,17 +356,17 @@ Namespace Global.FaceDetection
|
|||
Private Async Function StartRecordingAsync() As Task
|
||||
Try
|
||||
' Create storage file in Pictures Library
|
||||
Dim videoFile = Await KnownFolders.PicturesLibrary.CreateFileAsync("SimpleVideo.mp4", CreationCollisionOption.GenerateUniqueName)
|
||||
Dim videoFile = Await _captureFolder.CreateFileAsync("SimpleVideo.mp4", CreationCollisionOption.GenerateUniqueName)
|
||||
Dim encodingProfile = MediaEncodingProfile.CreateMp4(VideoEncodingQuality.Auto)
|
||||
' Calculate rotation angle, taking mirroring into account if necessary
|
||||
Dim rotationAngle = 360 - ConvertDeviceOrientationToDegrees(GetCameraOrientation())
|
||||
encodingProfile.Video.Properties.Add(RotationKey, PropertyValue.CreateInt32(rotationAngle))
|
||||
Debug.WriteLine("Starting recording...")
|
||||
Debug.WriteLine("Starting recording to " & videoFile.Path)
|
||||
Await _mediaCapture.StartRecordToStorageFileAsync(encodingProfile, videoFile)
|
||||
_isRecording = True
|
||||
Debug.WriteLine("Started recording!")
|
||||
Catch ex As Exception
|
||||
Debug.WriteLine("Exception when starting video recording: {0}", ex.ToString())
|
||||
Debug.WriteLine("Exception when starting video recording: " & ex.ToString())
|
||||
End Try
|
||||
End Function
|
||||
|
||||
|
@ -427,6 +431,10 @@ Namespace Global.FaceDetection
|
|||
End If
|
||||
|
||||
RegisterEventHandlers()
|
||||
|
||||
Dim picturesLibrary = Await StorageLibrary.GetLibraryAsync(KnownLibraryId.Pictures)
|
||||
' Fall back to the local app storage if the Pictures Library is not available
|
||||
_captureFolder = If(picturesLibrary.SaveFolder, ApplicationData.Current.LocalFolder)
|
||||
End Function
|
||||
|
||||
''' <summary>
|
||||
|
@ -510,12 +518,12 @@ Namespace Global.FaceDetection
|
|||
''' Applies the given orientation to a photo stream and saves it as a StorageFile
|
||||
''' </summary>
|
||||
''' <param name="stream">The photo stream</param>
|
||||
''' <param name="file">The StorageFile in which the photo stream will be saved</param>
|
||||
''' <param name="photoOrientation">The orientation metadata to apply to the photo</param>
|
||||
''' <returns></returns>
|
||||
Private Shared Async Function ReencodeAndSavePhotoAsync(stream As IRandomAccessStream, photoOrientation As PhotoOrientation) As Task
|
||||
Private Shared Async Function ReencodeAndSavePhotoAsync(stream As IRandomAccessStream, file As StorageFile, photoOrientation As PhotoOrientation) As Task
|
||||
Using inputStream = stream
|
||||
Dim decoder = Await BitmapDecoder.CreateAsync(inputStream)
|
||||
Dim file = Await KnownFolders.PicturesLibrary.CreateFileAsync("SimplePhoto.jpeg", CreationCollisionOption.GenerateUniqueName)
|
||||
Using outputStream = Await file.OpenAsync(FileAccessMode.ReadWrite)
|
||||
Dim encoder = Await BitmapEncoder.CreateForTranscodingAsync(outputStream, decoder)
|
||||
Dim properties = New BitmapPropertySet From {{"System.Photo.Orientation", New BitmapTypedValue(photoOrientation, PropertyType.UInt16)}}
|
||||
|
|
|
@ -42,6 +42,7 @@ MainPage::MainPage()
|
|||
, _displayOrientation(DisplayOrientations::Portrait)
|
||||
, _displayRequest(ref new Windows::System::Display::DisplayRequest())
|
||||
, RotationKey({ 0xC380465D, 0x2271, 0x428C,{ 0x9B, 0x83, 0xEC, 0xEA, 0x3B, 0x4A, 0x85, 0xC1 } })
|
||||
, _captureFolder(nullptr)
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
|
@ -127,6 +128,18 @@ task<void> MainPage::InitializeCameraAsync()
|
|||
WriteLine("The app was denied access to the camera");
|
||||
}
|
||||
});
|
||||
}).then([this]()
|
||||
{
|
||||
create_task(StorageLibrary::GetLibraryAsync(KnownLibraryId::Pictures))
|
||||
.then([this](StorageLibrary^ picturesLibrary)
|
||||
{
|
||||
_captureFolder = picturesLibrary->SaveFolder;
|
||||
if (_captureFolder == nullptr)
|
||||
{
|
||||
// In this case fall back to the local app storage since the Pictures Library is not available
|
||||
_captureFolder = ApplicationData::Current->LocalFolder;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -352,7 +365,7 @@ task<void> MainPage::GetPreviewFrameAsD3DSurfaceAsync()
|
|||
/// <returns></returns>
|
||||
task<void> MainPage::SaveSoftwareBitmapAsync(SoftwareBitmap^ bitmap)
|
||||
{
|
||||
return create_task(KnownFolders::PicturesLibrary->CreateFileAsync("PreviewFrame.jpg", CreationCollisionOption::GenerateUniqueName))
|
||||
return create_task(_captureFolder->CreateFileAsync("PreviewFrame.jpg", CreationCollisionOption::GenerateUniqueName))
|
||||
.then([bitmap](StorageFile^ file)
|
||||
{
|
||||
return create_task(file->OpenAsync(FileAccessMode::ReadWrite));
|
||||
|
@ -581,7 +594,7 @@ void MainPage::DisplayInformation_OrientationChanged(DisplayInformation^ sender,
|
|||
}
|
||||
}
|
||||
|
||||
void MainPage::GetPreviewFrameButton_Tapped(Object^, RoutedEventArgs^)
|
||||
void MainPage::GetPreviewFrameButton_Click(Object^, RoutedEventArgs^)
|
||||
{
|
||||
// If preview is not running, no preview frames can be acquired
|
||||
if (!_isPreviewing) return;
|
||||
|
|
|
@ -41,6 +41,9 @@ namespace CameraGetPreviewFrame
|
|||
// Reference: http://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh868174.aspx
|
||||
const GUID RotationKey;
|
||||
|
||||
// Folder in which the captures will be stored (availability check performed in InitializeCameraAsync)
|
||||
Windows::Storage::StorageFolder^ _captureFolder;
|
||||
|
||||
// Event tokens
|
||||
Windows::Foundation::EventRegistrationToken _applicationSuspendingEventToken;
|
||||
Windows::Foundation::EventRegistrationToken _applicationResumingEventToken;
|
||||
|
@ -70,7 +73,7 @@ namespace CameraGetPreviewFrame
|
|||
void Application_Resuming(Object^ sender, Object^ args);
|
||||
void DisplayInformation_OrientationChanged(Windows::Graphics::Display::DisplayInformation^ sender, Object^ args);
|
||||
void SystemMediaControls_PropertyChanged(Windows::Media::SystemMediaTransportControls^ sender, Windows::Media::SystemMediaTransportControlsPropertyChangedEventArgs^ args);
|
||||
void GetPreviewFrameButton_Tapped(Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
|
||||
void GetPreviewFrameButton_Click(Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
|
||||
void MediaCapture_Failed(Windows::Media::Capture::MediaCapture ^currentCaptureObject, Windows::Media::Capture::MediaCaptureFailedEventArgs^ errorEventArgs);
|
||||
|
||||
protected:
|
||||
|
|
|
@ -50,6 +50,9 @@ namespace CameraGetPreviewFrame
|
|||
// Reference: http://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh868174.aspx
|
||||
private static readonly Guid RotationKey = new Guid("C380465D-2271-428C-9B83-ECEA3B4A85C1");
|
||||
|
||||
// Folder in which the captures will be stored (initialized in InitializeCameraAsync)
|
||||
private StorageFolder _captureFolder = null;
|
||||
|
||||
// Prevent the screen from sleeping while the camera is running
|
||||
private readonly DisplayRequest _displayRequest = new DisplayRequest();
|
||||
|
||||
|
@ -173,7 +176,7 @@ namespace CameraGetPreviewFrame
|
|||
}
|
||||
}
|
||||
|
||||
private async void GetPreviewFrameButton_Tapped(object sender, TappedRoutedEventArgs e)
|
||||
private async void GetPreviewFrameButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// If preview is not running, no preview frames can be acquired
|
||||
if (!_isPreviewing) return;
|
||||
|
@ -259,6 +262,10 @@ namespace CameraGetPreviewFrame
|
|||
}
|
||||
|
||||
await StartPreviewAsync();
|
||||
|
||||
var picturesLibrary = await StorageLibrary.GetLibraryAsync(KnownLibraryId.Pictures);
|
||||
// Fall back to the local app storage if the Pictures Library is not available
|
||||
_captureFolder = picturesLibrary.SaveFolder ?? ApplicationData.Current.LocalFolder;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -381,7 +388,11 @@ namespace CameraGetPreviewFrame
|
|||
// Save the frame (as is, no rotation is being applied)
|
||||
if (SaveFrameCheckBox.IsChecked == true)
|
||||
{
|
||||
await SaveSoftwareBitmapAsync(previewFrame);
|
||||
var file = await _captureFolder.CreateFileAsync("PreviewFrame.jpg", CreationCollisionOption.GenerateUniqueName);
|
||||
|
||||
Debug.WriteLine("Saving preview frame to " + file.Path);
|
||||
|
||||
await SaveSoftwareBitmapAsync(previewFrame, file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -491,13 +502,12 @@ namespace CameraGetPreviewFrame
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Saves a SoftwareBitmap to the Pictures library with the specified name
|
||||
/// Saves a SoftwareBitmap with the specified name
|
||||
/// </summary>
|
||||
/// <param name="bitmap"></param>
|
||||
/// <returns></returns>
|
||||
private static async Task SaveSoftwareBitmapAsync(SoftwareBitmap bitmap)
|
||||
private static async Task SaveSoftwareBitmapAsync(SoftwareBitmap bitmap, StorageFile file)
|
||||
{
|
||||
var file = await KnownFolders.PicturesLibrary.CreateFileAsync("PreviewFrame.jpg", CreationCollisionOption.GenerateUniqueName);
|
||||
using (var outputStream = await file.OpenAsync(FileAccessMode.ReadWrite))
|
||||
{
|
||||
var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.JpegEncoderId, outputStream);
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
<mp:PhoneIdentity PhoneProductId="dcdc78d0-a1e6-44b7-b9cb-aa569a827aa0" PhonePublisherId="00000000-0000-0000-0000-000000000000"/>
|
||||
|
||||
<Properties>
|
||||
<DisplayName>CameraGetPreviewFrame</DisplayName>
|
||||
<DisplayName>CameraGetPreviewFrame JS Sample</DisplayName>
|
||||
<PublisherDisplayName>Microsoft Corporation</PublisherDisplayName>
|
||||
<Logo>images\storelogo-sdk.png</Logo>
|
||||
</Properties>
|
||||
|
|
|
@ -18,10 +18,13 @@
|
|||
var DisplayOrientations = Windows.Graphics.Display.DisplayOrientations;
|
||||
var Imaging = Windows.Graphics.Imaging;
|
||||
var Media = Windows.Media;
|
||||
var StorageLibrary = Windows.Storage.StorageLibrary;
|
||||
var KnownLibraryId = Windows.Storage.KnownLibraryId;
|
||||
var ApplicationData = Windows.Storage.ApplicationData;
|
||||
|
||||
// Receive notifications about rotation of the device and UI and apply any necessary rotation to the preview stream and UI controls
|
||||
var oDisplayInformation = Windows.Graphics.Display.DisplayInformation.getForCurrentView(),
|
||||
oDisplayOrientation = DisplayOrientations.portrait;
|
||||
oDisplayOrientation = DisplayOrientations.landscape;
|
||||
|
||||
// Prevent the screen from sleeping while the camera is running
|
||||
var oDisplayRequest = new Windows.System.Display.DisplayRequest();
|
||||
|
@ -42,6 +45,9 @@
|
|||
// Reference: http://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh868174.aspx
|
||||
var RotationKey = "C380465D-2271-428C-9B83-ECEA3B4A85C1";
|
||||
|
||||
// Folder in which the captures will be stored (initialized in SetupUiAsync)
|
||||
var oCaptureFolder;
|
||||
|
||||
// Initialization
|
||||
var app = WinJS.Application;
|
||||
var activation = Windows.ApplicationModel.Activation;
|
||||
|
@ -49,7 +55,7 @@
|
|||
if (args.detail.kind === activation.ActivationKind.launch) {
|
||||
if (args.detail.previousExecutionState !== activation.ApplicationExecutionState.terminated) {
|
||||
document.getElementById("getPreviewFrameButton").addEventListener("click", getPreviewFrameButton_tapped);
|
||||
previewFrameImage.src = null;
|
||||
previewFrameImage.src = "";
|
||||
}
|
||||
|
||||
oDisplayInformation.addEventListener("orientationchanged", displayInformation_orientationChanged);
|
||||
|
@ -122,6 +128,11 @@
|
|||
}).then(function () {
|
||||
isInitialized = true;
|
||||
return startPreviewAsync();
|
||||
}).then(function () {
|
||||
return StorageLibrary.getLibraryAsync(KnownLibraryId.pictures)
|
||||
}).then(function (picturesLibrary) {
|
||||
// Fall back to the local app storage if the Pictures Library is not available
|
||||
oCaptureFolder = picturesLibrary.saveFolder || ApplicationData.current.localFolder;
|
||||
}).done();
|
||||
}
|
||||
|
||||
|
@ -216,7 +227,7 @@
|
|||
// Cleanup the UI
|
||||
var previewVidTag = document.getElementById("cameraPreview");
|
||||
previewVidTag.pause();
|
||||
previewVidTag.src = null;
|
||||
previewVidTag.src = "";
|
||||
|
||||
// Allow the device screen to sleep now that the preview is stopped
|
||||
oDisplayRequest.requestRelease();
|
||||
|
@ -248,7 +259,10 @@
|
|||
|
||||
// Save and show the frame (as is, no rotation is being applied)
|
||||
if (saveShowFrameCheckBox.checked === true) {
|
||||
return saveAndShowSoftwareBitmapAsync(frameBitmap);
|
||||
return oCaptureFolder.createFileAsync("PreviewFrame.jpg", Windows.Storage.CreationCollisionOption.generateUniqueName)
|
||||
.then(function (file) {
|
||||
return saveAndShowSoftwareBitmapAsync(frameBitmap, file);
|
||||
})
|
||||
}
|
||||
else {
|
||||
return WinJS.Promise.as();
|
||||
|
@ -284,7 +298,7 @@
|
|||
}
|
||||
|
||||
// Clear the image
|
||||
previewFrameImage.src = null;
|
||||
previewFrameImage.src = "";
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -293,23 +307,22 @@
|
|||
/// </summary>
|
||||
/// <param name="bitmap"></param>
|
||||
/// <returns></returns>
|
||||
function saveAndShowSoftwareBitmapAsync(bitmap) {
|
||||
var oFile = null;
|
||||
return Windows.Storage.ApplicationData.current.localFolder.createFileAsync("PreviewFrame.jpg", Windows.Storage.CreationCollisionOption.generateUniqueName)
|
||||
.then(function (file) {
|
||||
oFile = file;
|
||||
return file.openAsync(Windows.Storage.FileAccessMode.readWrite);
|
||||
}).then(function (outputStream) {
|
||||
return Imaging.BitmapEncoder.createAsync(Imaging.BitmapEncoder.jpegEncoderId, outputStream);
|
||||
function saveAndShowSoftwareBitmapAsync(bitmap, file) {
|
||||
var imageStream = null;
|
||||
return file.openAsync(Windows.Storage.FileAccessMode.readWrite)
|
||||
.then(function (outputStream) {
|
||||
imageStream = outputStream;
|
||||
return Imaging.BitmapEncoder.createAsync(Imaging.BitmapEncoder.jpegEncoderId, imageStream);
|
||||
}).then(function (encoder) {
|
||||
// Grab the data from the SoftwareBitmap
|
||||
encoder.setSoftwareBitmap(bitmap);
|
||||
return encoder.flushAsync();
|
||||
}).done(function () {
|
||||
}).then(function () {
|
||||
var imageBlob = window.MSApp.createBlobFromRandomAccessStream("image/jpg", imageStream);
|
||||
// Finally display the image at the correct orientation
|
||||
previewFrameImage.src = oFile.path;
|
||||
previewFrameImage.src = URL.createObjectURL(imageBlob, { oneTimeOnly: true });
|
||||
previewFrameImage.style.transform = "rotate(" + convertDisplayOrientationToDegrees(oDisplayOrientation) + "deg)";
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -36,13 +36,13 @@
|
|||
<CaptureElement Name="PreviewControl" Stretch="Uniform" Grid.Column="0"/>
|
||||
|
||||
<!--Captured preview frame image-->
|
||||
<Image Name="PreviewFrameImage" Grid.Column="1"/>
|
||||
<Image Name="PreviewFrameImage" Grid.Column="1"/>
|
||||
</Grid>
|
||||
|
||||
<!--User input-->
|
||||
<StackPanel Grid.Row="1">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Button Name="GetPreviewFrameButton" Content="GetPreviewFrameAsync" Tapped="GetPreviewFrameButton_Tapped" Margin="10" IsEnabled="False"/>
|
||||
<Button Name="GetPreviewFrameButton" Content="GetPreviewFrameAsync" Click="GetPreviewFrameButton_Click" Margin="10" IsEnabled="False"/>
|
||||
<TextBlock Name="FrameInfoTextBlock" VerticalAlignment="Center"/>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
|
|
|
@ -49,6 +49,7 @@ MainPage::MainPage()
|
|||
, _displayOrientation(DisplayOrientations::Portrait)
|
||||
, _displayRequest(ref new Windows::System::Display::DisplayRequest())
|
||||
, RotationKey({ 0xC380465D, 0x2271, 0x428C,{ 0x9B, 0x83, 0xEC, 0xEA, 0x3B, 0x4A, 0x85, 0xC1 } })
|
||||
, _captureFolder(nullptr)
|
||||
{
|
||||
this->InitializeComponent();
|
||||
|
||||
|
@ -410,13 +411,15 @@ task<void> MainPage::TakeNormalPhotoAsync()
|
|||
return create_task(_mediaCapture->CapturePhotoToStreamAsync(Windows::Media::MediaProperties::ImageEncodingProperties::CreateJpeg(), inputStream))
|
||||
.then([this, inputStream]()
|
||||
{
|
||||
WriteLine("Photo taken!");
|
||||
|
||||
// Create file based off the current time
|
||||
auto fileName = L"SimplePhoto_" + GetTimeStr() + L".jpg";
|
||||
return create_task(_captureFolder->CreateFileAsync(fileName, CreationCollisionOption::GenerateUniqueName));
|
||||
}).then([this, inputStream](StorageFile^ file)
|
||||
{
|
||||
WriteLine("Photo taken! Saving to " + file->Path);
|
||||
|
||||
auto photoOrientation = ConvertOrientationToPhotoOrientation(GetCameraOrientation());
|
||||
|
||||
return ReencodeAndSavePhotoAsync(inputStream, fileName, photoOrientation);
|
||||
return ReencodeAndSavePhotoAsync(inputStream, file, photoOrientation);
|
||||
}).then([this](task<void> previousTask)
|
||||
{
|
||||
try
|
||||
|
@ -450,8 +453,12 @@ task<void> MainPage::TakeHdrPhotoAsync()
|
|||
return create_task(_advancedCapture->CaptureAsync(context))
|
||||
.then([this, context](Capture::AdvancedCapturedPhoto^ photo)
|
||||
{
|
||||
WriteLine("HDR photo taken!");
|
||||
return ReencodeAndSavePhotoAsync(photo->Frame, context->_captureFileName, context->_captureOrientation);
|
||||
context->_photo = photo;
|
||||
return create_task(_captureFolder->CreateFileAsync(context->_captureFileName, CreationCollisionOption::GenerateUniqueName));
|
||||
}).then([this, context](StorageFile^ file)
|
||||
{
|
||||
WriteLine("HDR photo taken! Saving to " + file->Path);
|
||||
return ReencodeAndSavePhotoAsync(context->_photo->Frame, file, context->_captureOrientation);
|
||||
}).then([this](task<void> previousTask)
|
||||
{
|
||||
try
|
||||
|
@ -505,20 +512,18 @@ task<DeviceInformation^> MainPage::FindCameraDeviceByPanelAsync(Windows::Devices
|
|||
/// <param name="stream">The photo stream</param>
|
||||
/// <param name="photoOrientation">The orientation metadata to apply to the photo</param>
|
||||
/// <returns></returns>
|
||||
task<void> MainPage::ReencodeAndSavePhotoAsync(Streams::IRandomAccessStream^ stream, String^ fileName, FileProperties::PhotoOrientation photoOrientation)
|
||||
task<void> MainPage::ReencodeAndSavePhotoAsync(Streams::IRandomAccessStream^ stream, StorageFile^ file, FileProperties::PhotoOrientation photoOrientation)
|
||||
{
|
||||
// Using this state variable to pass multiple values through our task chain
|
||||
ReencodeState^ state = ref new ReencodeState();
|
||||
state->_file = file;
|
||||
state->_orientation = photoOrientation;
|
||||
|
||||
return create_task(BitmapDecoder::CreateAsync(stream))
|
||||
.then([state, fileName](BitmapDecoder^ decoder)
|
||||
.then([state](BitmapDecoder^ decoder)
|
||||
{
|
||||
state->_decoder = decoder;
|
||||
return create_task(KnownFolders::PicturesLibrary->CreateFileAsync(fileName, CreationCollisionOption::GenerateUniqueName));
|
||||
}).then([](StorageFile^ file)
|
||||
{
|
||||
return create_task(file->OpenAsync(FileAccessMode::ReadWrite));
|
||||
return create_task(state->_file->OpenAsync(FileAccessMode::ReadWrite));
|
||||
}).then([state](Streams::IRandomAccessStream^ outputStream)
|
||||
{
|
||||
return create_task(BitmapEncoder::CreateForTranscodingAsync(outputStream, state->_decoder));
|
||||
|
@ -569,6 +574,17 @@ task<void> MainPage::SetupUiAsync()
|
|||
_deviceOrientation = _orientationSensor->GetCurrentOrientation();
|
||||
}
|
||||
|
||||
create_task(StorageLibrary::GetLibraryAsync(KnownLibraryId::Pictures))
|
||||
.then([this](StorageLibrary^ picturesLibrary)
|
||||
{
|
||||
_captureFolder = picturesLibrary->SaveFolder;
|
||||
if (_captureFolder == nullptr)
|
||||
{
|
||||
// In this case fall back to the local app storage since the Pictures Library is not available
|
||||
_captureFolder = ApplicationData::Current->LocalFolder;
|
||||
}
|
||||
});
|
||||
|
||||
// Hide the status bar
|
||||
if (Windows::Foundation::Metadata::ApiInformation::IsTypePresent("Windows.UI.ViewManagement.StatusBar"))
|
||||
{
|
||||
|
@ -920,7 +936,7 @@ void MainPage::SceneAnalysisEffect_SceneAnalyzed(Core::SceneAnalysisEffect^ send
|
|||
}));
|
||||
}
|
||||
|
||||
void MainPage::PhotoButton_Tapped(Object^, Windows::UI::Xaml::RoutedEventArgs^)
|
||||
void MainPage::PhotoButton_Click(Object^, Windows::UI::Xaml::RoutedEventArgs^)
|
||||
{
|
||||
TakePhotoInCurrentModeAsync();
|
||||
}
|
||||
|
@ -1004,15 +1020,18 @@ void MainPage::AdvancedCapture_OptionalReferencePhotoCaptured(Capture::AdvancedP
|
|||
{
|
||||
// Retrieve the context (i.e. what capture does this belong to?)
|
||||
auto context = static_cast<AdvancedCaptureContext^>(args->Context);
|
||||
|
||||
WriteLine("AdvancedCapture_OptionalReferencePhotoCaptured for " + context->_captureFileName);
|
||||
|
||||
// Remove "_HDR" from the name of the capture to create the name of the reference
|
||||
// Remove "_HDR" from the name of the capture to create the name of the reference photo (this is the non-HDR capture)
|
||||
std::wstringstream fileName;
|
||||
fileName << context->_captureFileName->Data();
|
||||
StringReplace(fileName.str(), std::wstring(L"_HDR"), std::wstring(L""));
|
||||
|
||||
ReencodeAndSavePhotoAsync(args->Frame, ref new String(fileName.str().c_str()), context->_captureOrientation);
|
||||
create_task(_captureFolder->CreateFileAsync(ref new String(fileName.str().c_str()), CreationCollisionOption::GenerateUniqueName))
|
||||
.then([this, args, context](StorageFile^ file)
|
||||
{
|
||||
ReencodeAndSavePhotoAsync(args->Frame, file, context->_captureOrientation);
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -20,6 +20,7 @@ namespace CameraHdr
|
|||
internal:
|
||||
Windows::Graphics::Imaging::BitmapDecoder^ _decoder;
|
||||
Windows::Graphics::Imaging::BitmapEncoder^ _encoder;
|
||||
Windows::Storage::StorageFile^ _file;
|
||||
Windows::Storage::FileProperties::PhotoOrientation _orientation;
|
||||
};
|
||||
|
||||
|
@ -31,6 +32,7 @@ namespace CameraHdr
|
|||
internal:
|
||||
Platform::String^ _captureFileName;
|
||||
Windows::Storage::FileProperties::PhotoOrientation _captureOrientation;
|
||||
Windows::Media::Capture::AdvancedCapturedPhoto^ _photo;
|
||||
};
|
||||
|
||||
public ref class MainPage sealed
|
||||
|
@ -46,6 +48,9 @@ namespace CameraHdr
|
|||
// Reference: http://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh868174.aspx
|
||||
const GUID RotationKey;
|
||||
|
||||
// Folder in which the captures will be stored (availability check performed in SetupUiAsync)
|
||||
Windows::Storage::StorageFolder^ _captureFolder;
|
||||
|
||||
// Prevent the screen from sleeping while the camera is running
|
||||
Windows::System::Display::DisplayRequest^ _displayRequest;
|
||||
|
||||
|
@ -97,7 +102,7 @@ namespace CameraHdr
|
|||
|
||||
// Helpers
|
||||
Concurrency::task<Windows::Devices::Enumeration::DeviceInformation^> FindCameraDeviceByPanelAsync(Windows::Devices::Enumeration::Panel panel);
|
||||
Concurrency::task<void> ReencodeAndSavePhotoAsync(Windows::Storage::Streams::IRandomAccessStream^ stream, Platform::String^ fileName, Windows::Storage::FileProperties::PhotoOrientation photoOrientation);
|
||||
Concurrency::task<void> ReencodeAndSavePhotoAsync(Windows::Storage::Streams::IRandomAccessStream^ stream, Windows::Storage::StorageFile^ file, Windows::Storage::FileProperties::PhotoOrientation photoOrientation);
|
||||
void UpdateUi();
|
||||
Concurrency::task<void> SetupUiAsync();
|
||||
Concurrency::task<void> CleanupUiAsync();
|
||||
|
@ -121,7 +126,7 @@ namespace CameraHdr
|
|||
void Application_Resuming(Object^ sender, Object^ args);
|
||||
void DisplayInformation_OrientationChanged(Windows::Graphics::Display::DisplayInformation^ sender, Object^ args);
|
||||
void SceneAnalysisEffect_SceneAnalyzed(Windows::Media::Core::SceneAnalysisEffect^ sender, Windows::Media::Core::SceneAnalyzedEventArgs^ args);
|
||||
void PhotoButton_Tapped(Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
|
||||
void PhotoButton_Click(Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
|
||||
void SystemMediaControls_PropertyChanged(Windows::Media::SystemMediaTransportControls^ sender, Windows::Media::SystemMediaTransportControlsPropertyChangedEventArgs^ args);
|
||||
void HdrToggleButton_Checked(Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
|
||||
void OrientationSensor_OrientationChanged(Windows::Devices::Sensors::SimpleOrientationSensor^, Windows::Devices::Sensors::SimpleOrientationSensorOrientationChangedEventArgs^);
|
||||
|
|
|
@ -52,6 +52,9 @@ namespace CameraHdr
|
|||
// Reference: http://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh868174.aspx
|
||||
private static readonly Guid RotationKey = new Guid("C380465D-2271-428C-9B83-ECEA3B4A85C1");
|
||||
|
||||
// Folder in which the captures will be stored (initialized in SetupUiAsync)
|
||||
private StorageFolder _captureFolder = null;
|
||||
|
||||
// Prevent the screen from sleeping while the camera is running
|
||||
private readonly DisplayRequest _displayRequest = new DisplayRequest();
|
||||
|
||||
|
@ -256,14 +259,15 @@ namespace CameraHdr
|
|||
// Retrieve the context (i.e. what capture does this belong to?)
|
||||
var context = args.Context as AdvancedCaptureContext;
|
||||
|
||||
Debug.WriteLine("AdvancedCapture_OptionalReferencePhotoCaptured for {0}", context.CaptureFileName);
|
||||
|
||||
// Remove "_HDR" from the name of the capture to create the name of the reference
|
||||
// Remove "_HDR" from the name of the capture to create the name of the reference photo (this is the non-HDR capture)
|
||||
var referenceName = context.CaptureFileName.Replace("_HDR", "");
|
||||
|
||||
var file = await _captureFolder.CreateFileAsync(referenceName, CreationCollisionOption.GenerateUniqueName);
|
||||
Debug.WriteLine("AdvancedCapture_OptionalReferencePhotoCaptured for " + context.CaptureFileName + ". Saving to " + file.Path);
|
||||
|
||||
using (var frame = args.Frame)
|
||||
{
|
||||
await ReencodeAndSavePhotoAsync(frame, referenceName, context.CaptureOrientation);
|
||||
await ReencodeAndSavePhotoAsync(frame, file, context.CaptureOrientation);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -278,7 +282,7 @@ namespace CameraHdr
|
|||
Debug.WriteLine("AdvancedCapture_AllPhotosCaptured");
|
||||
}
|
||||
|
||||
private async void PhotoButton_Tapped(object sender, TappedRoutedEventArgs e)
|
||||
private async void PhotoButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
await TakePhotoInCurrentModeAsync();
|
||||
}
|
||||
|
@ -555,21 +559,21 @@ namespace CameraHdr
|
|||
{
|
||||
Debug.WriteLine("Taking photo...");
|
||||
|
||||
// Generate a filename based on the current time
|
||||
// Read the current orientation of the camera and the capture time
|
||||
var photoOrientation = ConvertOrientationToPhotoOrientation(GetCameraOrientation());
|
||||
var fileName = String.Format("SimplePhoto_{0}.jpg", DateTime.Now.ToString("HHmmss"));
|
||||
|
||||
// Get the orientation of the camera at the time of capture
|
||||
var photoOrientation = ConvertOrientationToPhotoOrientation(GetCameraOrientation());
|
||||
|
||||
await _mediaCapture.CapturePhotoToStreamAsync(ImageEncodingProperties.CreateJpeg(), stream);
|
||||
Debug.WriteLine("Photo taken!");
|
||||
|
||||
await ReencodeAndSavePhotoAsync(stream, fileName, photoOrientation);
|
||||
var file = await _captureFolder.CreateFileAsync(fileName, CreationCollisionOption.GenerateUniqueName);
|
||||
Debug.WriteLine("Photo taken! Saving to " + file.Path);
|
||||
|
||||
await ReencodeAndSavePhotoAsync(stream, file, photoOrientation);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// File I/O errors are reported as exceptions
|
||||
Debug.WriteLine("Exception when taking a photo: {0}", ex.ToString());
|
||||
Debug.WriteLine("Exception when taking a photo: " + ex.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -591,17 +595,19 @@ namespace CameraHdr
|
|||
|
||||
// Start capture, and pass the context object
|
||||
var capture = await _advancedCapture.CaptureAsync(context);
|
||||
Debug.WriteLine("HDR photo taken! {0}", fileName);
|
||||
|
||||
using (var frame = capture.Frame)
|
||||
{
|
||||
await ReencodeAndSavePhotoAsync(frame, fileName, photoOrientation);
|
||||
var file = await _captureFolder.CreateFileAsync(fileName, CreationCollisionOption.GenerateUniqueName);
|
||||
Debug.WriteLine("HDR photo taken! Saving to " + file.Path);
|
||||
|
||||
await ReencodeAndSavePhotoAsync(frame, file, photoOrientation);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// File I/O errors are reported as exceptions
|
||||
Debug.WriteLine("Exception when taking an HDR photo: {0}", ex.ToString());
|
||||
Debug.WriteLine("Exception when taking an HDR photo: " + ex.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -672,6 +678,10 @@ namespace CameraHdr
|
|||
}
|
||||
|
||||
RegisterEventHandlers();
|
||||
|
||||
var picturesLibrary = await StorageLibrary.GetLibraryAsync(KnownLibraryId.Pictures);
|
||||
// Fall back to the local app storage if the Pictures Library is not available
|
||||
_captureFolder = picturesLibrary.SaveFolder ?? ApplicationData.Current.LocalFolder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -771,24 +781,22 @@ namespace CameraHdr
|
|||
/// Applies the given orientation to a photo stream and saves it as a StorageFile
|
||||
/// </summary>
|
||||
/// <param name="stream">The photo stream</param>
|
||||
/// <param name="file">The StorageFile in which the photo stream will be saved</param>
|
||||
/// <param name="photoOrientation">The orientation metadata to apply to the photo</param>
|
||||
/// <returns></returns>
|
||||
private static async Task ReencodeAndSavePhotoAsync(IRandomAccessStream stream, string fileName, PhotoOrientation photoOrientation = PhotoOrientation.Normal)
|
||||
private static async Task ReencodeAndSavePhotoAsync(IRandomAccessStream stream, StorageFile file, PhotoOrientation photoOrientation)
|
||||
{
|
||||
using (var inputStream = stream)
|
||||
{
|
||||
var decoder = await BitmapDecoder.CreateAsync(inputStream);
|
||||
|
||||
var file = await KnownFolders.PicturesLibrary.CreateFileAsync(fileName, CreationCollisionOption.GenerateUniqueName);
|
||||
|
||||
using (var outputStream = await file.OpenAsync(FileAccessMode.ReadWrite))
|
||||
{
|
||||
var encoder = await BitmapEncoder.CreateForTranscodingAsync(outputStream, decoder);
|
||||
|
||||
// Set the orientation of the capture
|
||||
var properties = new BitmapPropertySet { { "System.Photo.Orientation", new BitmapTypedValue(photoOrientation, PropertyType.UInt16) } };
|
||||
await encoder.BitmapProperties.SetPropertiesAsync(properties);
|
||||
|
||||
var properties = new BitmapPropertySet { { "System.Photo.Orientation", new BitmapTypedValue(photoOrientation, PropertyType.UInt16) } };
|
||||
|
||||
await encoder.BitmapProperties.SetPropertiesAsync(properties);
|
||||
await encoder.FlushAsync();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,9 @@
|
|||
var Media = Windows.Media;
|
||||
var SimpleOrientation = Windows.Devices.Sensors.SimpleOrientation;
|
||||
var SimpleOrientationSensor = Windows.Devices.Sensors.SimpleOrientationSensor;
|
||||
var StorageLibrary = Windows.Storage.StorageLibrary;
|
||||
var KnownLibraryId = Windows.Storage.KnownLibraryId;
|
||||
var ApplicationData = Windows.Storage.ApplicationData;
|
||||
|
||||
// Receive notifications about rotation of the device and UI and apply any necessary rotation to the preview stream and UI controls
|
||||
var oOrientationSensor = SimpleOrientationSensor.getDefault(),
|
||||
|
@ -57,6 +60,9 @@
|
|||
// Reference: http://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh868174.aspx
|
||||
var RotationKey = "C380465D-2271-428C-9B83-ECEA3B4A85C1";
|
||||
|
||||
// Folder in which the captures will be stored (initialized in SetupUiAsync)
|
||||
var oCaptureFolder;
|
||||
|
||||
// Initialization
|
||||
var app = WinJS.Application;
|
||||
var activation = Windows.ApplicationModel.Activation;
|
||||
|
@ -391,16 +397,18 @@
|
|||
console.log("Taking photo...");
|
||||
|
||||
return oMediaCapture.capturePhotoToStreamAsync(Windows.Media.MediaProperties.ImageEncodingProperties.createJpeg(), inputStream)
|
||||
.then(function() {
|
||||
console.log("Photo taken!");
|
||||
|
||||
.then(function () {
|
||||
var fileName = "SimplePhoto_" + getTimeStr() + ".jpg";
|
||||
return oCaptureFolder.createFileAsync(fileName, Windows.Storage.CreationCollisionOption.GenerateUniqueName)
|
||||
}).then(function(file){
|
||||
console.log("Photo taken! Saving to " + file.path);
|
||||
var photoOrientation = convertOrientationToPhotoOrientation(getCameraOrientation());
|
||||
return reencodeAndSavePhotoAsync(inputStream, fileName, photoOrientation);
|
||||
return reencodeAndSavePhotoAsync(inputStream, file, photoOrientation);
|
||||
});
|
||||
}
|
||||
|
||||
function takeHdrPhotoAsync() {
|
||||
var captureFile = null;
|
||||
// Take the picture
|
||||
console.log("Taking photo...");
|
||||
|
||||
|
@ -409,10 +417,14 @@
|
|||
context.insert("fileName", "SimplePhoto_" + getTimeStr() + "_HDR.jpg");
|
||||
context.insert("orientation", convertOrientationToPhotoOrientation(getCameraOrientation()));
|
||||
|
||||
return oAdvancedCapture.captureAsync(context)
|
||||
return oCaptureFolder.createFileAsync(fileName, Windows.Storage.CreationCollisionOption.GenerateUniqueName)
|
||||
.then(function (file) {
|
||||
captureFile = file;
|
||||
return oAdvancedCapture.captureAsync(context)
|
||||
})
|
||||
.then(function(advancedCapturedPhoto) {
|
||||
console.log("HDR photo taken!");
|
||||
return reencodeAndSavePhotoAsync(advancedCapturedPhoto.frame, context.fileName, context.orientation);
|
||||
console.log("HDR photo taken! Saving to " + captureFile.path);
|
||||
return reencodeAndSavePhotoAsync(advancedCapturedPhoto.frame, captureFile, context.orientation);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -448,7 +460,7 @@
|
|||
/// <param name="stream">The photo stream</param>
|
||||
/// <param name="photoOrientation">The orientation metadata to apply to the photo</param>
|
||||
/// <returns></returns>
|
||||
function reencodeAndSavePhotoAsync(inputStream, fileName, orientation) {
|
||||
function reencodeAndSavePhotoAsync(inputStream, file, orientation) {
|
||||
var Imaging = Windows.Graphics.Imaging;
|
||||
var bitmapDecoder = null,
|
||||
bitmapEncoder = null,
|
||||
|
@ -457,8 +469,6 @@
|
|||
return Imaging.BitmapDecoder.createAsync(inputStream)
|
||||
.then(function (decoder) {
|
||||
bitmapDecoder = decoder;
|
||||
return Windows.Storage.KnownFolders.picturesLibrary.createFileAsync(fileName, Windows.Storage.CreationCollisionOption.generateUniqueName);
|
||||
}).then(function (file) {
|
||||
return file.openAsync(Windows.Storage.FileAccessMode.readWrite);
|
||||
}).then(function (outStream) {
|
||||
outputStream = outStream;
|
||||
|
@ -508,14 +518,19 @@
|
|||
if (oOrientationSensor != null) {
|
||||
oDeviceOrientation = oOrientationSensor.getCurrentOrientation();
|
||||
}
|
||||
return StorageLibrary.getLibraryAsync(KnownLibraryId.pictures)
|
||||
.then(function (picturesLibrary) {
|
||||
// Fall back to the local app storage if the Pictures Library is not available
|
||||
oCaptureFolder = picturesLibrary.saveFolder || ApplicationData.current.localFolder;
|
||||
|
||||
// Hide the status bar
|
||||
if (Windows.Foundation.Metadata.ApiInformation.isTypePresent("Windows.UI.ViewManagement.StatusBar")) {
|
||||
return Windows.UI.ViewManagement.StatusBar.getForCurrentView().hideAsync();
|
||||
}
|
||||
else {
|
||||
return WinJS.Promise.as();
|
||||
}
|
||||
// Hide the status bar
|
||||
if (Windows.Foundation.Metadata.ApiInformation.isTypePresent("Windows.UI.ViewManagement.StatusBar")) {
|
||||
return Windows.UI.ViewManagement.StatusBar.getForCurrentView().hideAsync();
|
||||
}
|
||||
else {
|
||||
return WinJS.Promise.as();
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -755,12 +770,14 @@
|
|||
// Retrieve the context (i.e. what capture does this belong to?)
|
||||
var context = args.context;
|
||||
|
||||
console.log("AdvancedCapture_OptionalReferencePhotoCaptured for " + context.fileName);
|
||||
// Remove "_HDR" from the name of the capture to create the name of the reference (this is the non-HDR capture)
|
||||
var fileName = context.fileName.replace("_HDR", "");
|
||||
|
||||
// Remove "_HDR" from the name of the capture to create the name of the reference
|
||||
context.fileName = context.fileName.replace("_HDR", "");
|
||||
|
||||
reencodeAndSavePhotoAsync(args.frame, context.fileName, context.orientation);
|
||||
return oCaptureFolder.createFileAsync(fileName, Windows.Storage.CreationCollisionOption.GenerateUniqueName)
|
||||
.then(function (file) {
|
||||
console.log("AdvancedCapture_OptionalReferencePhotoCaptured for " + context.fileName + ". Saving to " + file.path);
|
||||
return reencodeAndSavePhotoAsync(args.frame, file, context.orientation);
|
||||
})
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
<mp:PhoneIdentity PhoneProductId="dede2df4-b097-4464-bb96-66a644f32d55" PhonePublisherId="00000000-0000-0000-0000-000000000000"/>
|
||||
|
||||
<Properties>
|
||||
<DisplayName>CameraHDR</DisplayName>
|
||||
<DisplayName>CameraHDR JS Sample</DisplayName>
|
||||
<PublisherDisplayName>Microsoft Corporation</PublisherDisplayName>
|
||||
<Logo>images\storelogo-sdk.png</Logo>
|
||||
</Properties>
|
||||
|
|
|
@ -66,7 +66,7 @@
|
|||
</Viewbox>
|
||||
</ToggleButton>
|
||||
|
||||
<Button Name="PhotoButton" Tapped="PhotoButton_Tapped" IsEnabled="False">
|
||||
<Button Name="PhotoButton" Click="PhotoButton_Click" IsEnabled="False">
|
||||
<Viewbox MaxWidth="40" MaxHeight="40">
|
||||
<SymbolIcon Symbol="Camera"/>
|
||||
</Viewbox>
|
||||
|
|
|
@ -54,6 +54,9 @@ Namespace Global.CameraHdr
|
|||
' Reference: http://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh868174.aspx
|
||||
Private Shared ReadOnly RotationKey As Guid = New Guid("C380465D-2271-428C-9B83-ECEA3B4A85C1")
|
||||
|
||||
' Folder in which the captures will be stored (initialized in SetupUiAsync)
|
||||
Private _captureFolder As StorageFolder = Nothing
|
||||
|
||||
' Prevent the screen from sleeping while the camera is running
|
||||
Private ReadOnly _displayRequest As DisplayRequest = New DisplayRequest()
|
||||
|
||||
|
@ -208,11 +211,12 @@ Namespace Global.CameraHdr
|
|||
Private Async Sub AdvancedCapture_OptionalReferencePhotoCaptured(sender As AdvancedPhotoCapture, args As OptionalReferencePhotoCapturedEventArgs)
|
||||
' Retrieve the context (i.e. what capture does this belong to?)
|
||||
Dim context = TryCast(args.Context, AdvancedCaptureContext)
|
||||
Debug.WriteLine("AdvancedCapture_OptionalReferencePhotoCaptured for {0}", context.CaptureFileName)
|
||||
' Remove "_HDR" from the name of the capture to create the name of the reference
|
||||
Dim referenceName = context.CaptureFileName.Replace("_HDR", "")
|
||||
Dim file = Await _captureFolder.CreateFileAsync(referenceName, CreationCollisionOption.GenerateUniqueName)
|
||||
Debug.WriteLine("AdvancedCapture_OptionalReferencePhotoCaptured for " & context.CaptureFileName & ". Saving to " & file.Path)
|
||||
Using frame = args.Frame
|
||||
Await ReencodeAndSavePhotoAsync(frame, referenceName, context.CaptureOrientation)
|
||||
Await ReencodeAndSavePhotoAsync(frame, file, context.CaptureOrientation)
|
||||
End Using
|
||||
End Sub
|
||||
|
||||
|
@ -226,7 +230,7 @@ Namespace Global.CameraHdr
|
|||
Debug.WriteLine("AdvancedCapture_AllPhotosCaptured")
|
||||
End Sub
|
||||
|
||||
Private Async Sub PhotoButton_Tapped(sender As Object, e As TappedRoutedEventArgs)
|
||||
Private Async Sub PhotoButton_Click(sender As Object, e As RoutedEventArgs)
|
||||
Await TakePhotoInCurrentModeAsync()
|
||||
End Sub
|
||||
|
||||
|
@ -416,15 +420,15 @@ Namespace Global.CameraHdr
|
|||
Dim stream = New InMemoryRandomAccessStream()
|
||||
Try
|
||||
Debug.WriteLine("Taking photo...")
|
||||
' Generate a filename based on the current time
|
||||
Dim fileName = String.Format("SimplePhoto_{0}.jpg", DateTime.Now.ToString("HHmmss"))
|
||||
' Get the orientation of the camera at the time of capture
|
||||
' Read the current orientation of the camera and the capture time
|
||||
Dim photoOrientation = ConvertOrientationToPhotoOrientation(GetCameraOrientation())
|
||||
Dim fileName = String.Format("SimplePhoto_{0}_HDR.jpg", DateTime.Now.ToString("HHmmss"))
|
||||
Await _mediaCapture.CapturePhotoToStreamAsync(ImageEncodingProperties.CreateJpeg(), stream)
|
||||
Debug.WriteLine("Photo taken!")
|
||||
Await ReencodeAndSavePhotoAsync(stream, fileName, photoOrientation)
|
||||
Dim file = Await _captureFolder.CreateFileAsync(fileName, CreationCollisionOption.GenerateUniqueName)
|
||||
Debug.WriteLine("Photo taken! Saving to " & file.Path)
|
||||
Await ReencodeAndSavePhotoAsync(stream, file, photoOrientation)
|
||||
Catch ex As Exception
|
||||
Debug.WriteLine("Exception when taking a photo: {0}", ex.ToString())
|
||||
Debug.WriteLine("Exception when taking a photo: " & ex.ToString())
|
||||
End Try
|
||||
End Function
|
||||
|
||||
|
@ -442,12 +446,13 @@ Namespace Global.CameraHdr
|
|||
Dim context = New AdvancedCaptureContext() With {.CaptureFileName = fileName, .CaptureOrientation = photoOrientation}
|
||||
' Start capture, and pass the context object
|
||||
Dim capture = Await _advancedCapture.CaptureAsync(context)
|
||||
Debug.WriteLine("HDR photo taken! {0}", fileName)
|
||||
Using frame = capture.Frame
|
||||
Await ReencodeAndSavePhotoAsync(frame, fileName, photoOrientation)
|
||||
Dim file = Await _captureFolder.CreateFileAsync(fileName, CreationCollisionOption.GenerateUniqueName)
|
||||
Debug.WriteLine("HDR photo taken! Saving to " & file.Path)
|
||||
Await ReencodeAndSavePhotoAsync(frame, file, photoOrientation)
|
||||
End Using
|
||||
Catch ex As Exception
|
||||
Debug.WriteLine("Exception when taking an HDR photo: {0}", ex.ToString())
|
||||
Debug.WriteLine("Exception when taking an HDR photo: " & ex.ToString())
|
||||
End Try
|
||||
End Function
|
||||
|
||||
|
@ -500,6 +505,10 @@ Namespace Global.CameraHdr
|
|||
End If
|
||||
|
||||
RegisterEventHandlers()
|
||||
|
||||
Dim picturesLibrary = Await StorageLibrary.GetLibraryAsync(KnownLibraryId.Pictures)
|
||||
' Fall back to the local app storage if the Pictures Library is not available
|
||||
_captureFolder = If(picturesLibrary.SaveFolder, ApplicationData.Current.LocalFolder)
|
||||
End Function
|
||||
|
||||
''' <summary>
|
||||
|
@ -575,15 +584,14 @@ Namespace Global.CameraHdr
|
|||
''' Applies the given orientation to a photo stream and saves it as a StorageFile
|
||||
''' </summary>
|
||||
''' <param name="stream">The photo stream</param>
|
||||
''' <param name="file">The StorageFile in which the photo stream will be saved</param>
|
||||
''' <param name="photoOrientation">The orientation metadata to apply to the photo</param>
|
||||
''' <returns></returns>
|
||||
Private Shared Async Function ReencodeAndSavePhotoAsync(stream As IRandomAccessStream, fileName As String, Optional photoOrientation As PhotoOrientation = PhotoOrientation.Normal) As Task
|
||||
Private Shared Async Function ReencodeAndSavePhotoAsync(stream As IRandomAccessStream, file As StorageFile, photoOrientation As PhotoOrientation) As Task
|
||||
Using inputStream = stream
|
||||
Dim decoder = Await BitmapDecoder.CreateAsync(inputStream)
|
||||
Dim file = Await KnownFolders.PicturesLibrary.CreateFileAsync(fileName, CreationCollisionOption.GenerateUniqueName)
|
||||
Using outputStream = Await file.OpenAsync(FileAccessMode.ReadWrite)
|
||||
Dim encoder = Await BitmapEncoder.CreateForTranscodingAsync(outputStream, decoder)
|
||||
' Set the orientation of the capture
|
||||
Dim properties = New BitmapPropertySet From {{"System.Photo.Orientation", New BitmapTypedValue(photoOrientation, PropertyType.UInt16)}}
|
||||
Await encoder.BitmapProperties.SetPropertiesAsync(properties)
|
||||
Await encoder.FlushAsync()
|
||||
|
|
|
@ -67,13 +67,13 @@
|
|||
</Style>
|
||||
</StackPanel.Resources>
|
||||
|
||||
<Button Name="PhotoButton" Tapped="PhotoButton_Tapped" IsEnabled="False">
|
||||
<Button Name="PhotoButton" Click="PhotoButton_Click" IsEnabled="False">
|
||||
<Viewbox MaxHeight="40" MaxWidth="40">
|
||||
<SymbolIcon Symbol="Camera"/>
|
||||
</Viewbox>
|
||||
</Button>
|
||||
|
||||
<Button Name="VideoButton" Tapped="VideoButton_Tapped" IsEnabled="False">
|
||||
<Button Name="VideoButton" Click="VideoButton_Click" IsEnabled="False">
|
||||
<Grid>
|
||||
<Ellipse x:Name="StartRecordingIcon" Fill="Red" Width="20" Height="20"/>
|
||||
<Rectangle x:Name="StopRecordingIcon" Fill="White" Width="20" Height="20" Visibility="Collapsed"/>
|
||||
|
@ -102,13 +102,13 @@
|
|||
</TransitionCollection>
|
||||
</StackPanel.ChildrenTransitions>
|
||||
|
||||
<Button Name="FlashButton" Content="Flash" Tapped="ManualControlButton_Tapped"/>
|
||||
<Button Name="ZoomButton" Content="Zoom" Tapped="ManualControlButton_Tapped"/>
|
||||
<Button Name="FocusButton" Content="Focus" Tapped="ManualControlButton_Tapped"/>
|
||||
<Button Name="WbButton" Content="WB" Tapped="ManualControlButton_Tapped"/>
|
||||
<Button Name="IsoButton" Content="ISO" Tapped="ManualControlButton_Tapped"/>
|
||||
<Button Name="ShutterButton" Content="Shutter" Tapped="ManualControlButton_Tapped"/>
|
||||
<Button Name="EvButton" Content="EV" Tapped="ManualControlButton_Tapped"/>
|
||||
<Button Name="FlashButton" Content="Flash" Click="ManualControlButton_Click"/>
|
||||
<Button Name="ZoomButton" Content="Zoom" Click="ManualControlButton_Click"/>
|
||||
<Button Name="FocusButton" Content="Focus" Click="ManualControlButton_Click"/>
|
||||
<Button Name="WbButton" Content="WB" Click="ManualControlButton_Click"/>
|
||||
<Button Name="IsoButton" Content="ISO" Click="ManualControlButton_Click"/>
|
||||
<Button Name="ShutterButton" Content="Shutter" Click="ManualControlButton_Click"/>
|
||||
<Button Name="EvButton" Content="EV" Click="ManualControlButton_Click"/>
|
||||
</StackPanel>
|
||||
|
||||
<!--Grid that hosts all of the manual controls for the selected camera control-->
|
||||
|
|
|
@ -54,6 +54,9 @@ namespace CameraManualControls
|
|||
// Reference: http://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh868174.aspx
|
||||
private static readonly Guid RotationKey = new Guid("C380465D-2271-428C-9B83-ECEA3B4A85C1");
|
||||
|
||||
// Folder in which the captures will be stored (initialized in SetupUiAsync)
|
||||
private StorageFolder _captureFolder = null;
|
||||
|
||||
// Prevent the screen from sleeping while the camera is running
|
||||
private readonly DisplayRequest _displayRequest = new DisplayRequest();
|
||||
|
||||
|
@ -205,12 +208,12 @@ namespace CameraManualControls
|
|||
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => UpdateButtonOrientation());
|
||||
}
|
||||
|
||||
private async void PhotoButton_Tapped(object sender, TappedRoutedEventArgs e)
|
||||
private async void PhotoButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
await TakePhotoAsync();
|
||||
}
|
||||
|
||||
private async void VideoButton_Tapped(object sender, TappedRoutedEventArgs e)
|
||||
private async void VideoButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (!_isRecording)
|
||||
{
|
||||
|
@ -433,20 +436,25 @@ namespace CameraManualControls
|
|||
|
||||
var stream = new InMemoryRandomAccessStream();
|
||||
|
||||
Debug.WriteLine("Taking photo...");
|
||||
await _mediaCapture.CapturePhotoToStreamAsync(ImageEncodingProperties.CreateJpeg(), stream);
|
||||
|
||||
try
|
||||
{
|
||||
Debug.WriteLine("Taking photo...");
|
||||
await _mediaCapture.CapturePhotoToStreamAsync(ImageEncodingProperties.CreateJpeg(), stream);
|
||||
Debug.WriteLine("Photo taken!");
|
||||
var file = await _captureFolder.CreateFileAsync("SimplePhoto.jpg", CreationCollisionOption.GenerateUniqueName);
|
||||
|
||||
Debug.WriteLine("Photo taken! Saving to " + file.Path);
|
||||
|
||||
var photoOrientation = ConvertOrientationToPhotoOrientation(GetCameraOrientation());
|
||||
|
||||
await ReencodeAndSavePhotoAsync(stream, photoOrientation);
|
||||
await ReencodeAndSavePhotoAsync(stream, file, photoOrientation);
|
||||
|
||||
Debug.WriteLine("Photo saved!");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// File I/O errors are reported as exceptions
|
||||
Debug.WriteLine("Exception when taking a photo: {0}", ex.ToString());
|
||||
Debug.WriteLine("Exception when taking a photo: " + ex.ToString());
|
||||
}
|
||||
|
||||
// Done taking a photo, so re-enable the button
|
||||
|
@ -463,7 +471,7 @@ namespace CameraManualControls
|
|||
try
|
||||
{
|
||||
// Create storage file in Pictures Library
|
||||
var videoFile = await KnownFolders.PicturesLibrary.CreateFileAsync("SimpleVideo.mp4", CreationCollisionOption.GenerateUniqueName);
|
||||
var videoFile = await _captureFolder.CreateFileAsync("SimpleVideo.mp4", CreationCollisionOption.GenerateUniqueName);
|
||||
|
||||
var encodingProfile = MediaEncodingProfile.CreateMp4(VideoEncodingQuality.Auto);
|
||||
|
||||
|
@ -471,7 +479,7 @@ namespace CameraManualControls
|
|||
var rotationAngle = 360 - ConvertDeviceOrientationToDegrees(GetCameraOrientation());
|
||||
encodingProfile.Video.Properties.Add(RotationKey, PropertyValue.CreateInt32(rotationAngle));
|
||||
|
||||
Debug.WriteLine("Starting recording...");
|
||||
Debug.WriteLine("Starting recording to " + videoFile.Path);
|
||||
|
||||
await _mediaCapture.StartRecordToStorageFileAsync(encodingProfile, videoFile);
|
||||
_isRecording = true;
|
||||
|
@ -481,7 +489,7 @@ namespace CameraManualControls
|
|||
catch (Exception ex)
|
||||
{
|
||||
// File I/O errors are reported as exceptions
|
||||
Debug.WriteLine("Exception when starting video recording: {0}", ex.ToString());
|
||||
Debug.WriteLine("Exception when starting video recording: " + ex.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -560,6 +568,10 @@ namespace CameraManualControls
|
|||
}
|
||||
|
||||
RegisterEventHandlers();
|
||||
|
||||
var picturesLibrary = await StorageLibrary.GetLibraryAsync(KnownLibraryId.Pictures);
|
||||
// Fall back to the local app storage if the Pictures Library is not available
|
||||
_captureFolder = picturesLibrary.SaveFolder ?? ApplicationData.Current.LocalFolder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -680,16 +692,15 @@ namespace CameraManualControls
|
|||
/// Applies the given orientation to a photo stream and saves it as a StorageFile
|
||||
/// </summary>
|
||||
/// <param name="stream">The photo stream</param>
|
||||
/// <param name="file">The StorageFile in which the photo stream will be saved</param>
|
||||
/// <param name="photoOrientation">The orientation metadata to apply to the photo</param>
|
||||
/// <returns></returns>
|
||||
private static async Task ReencodeAndSavePhotoAsync(IRandomAccessStream stream, PhotoOrientation photoOrientation)
|
||||
private static async Task ReencodeAndSavePhotoAsync(IRandomAccessStream stream, StorageFile file, PhotoOrientation photoOrientation)
|
||||
{
|
||||
using (var inputStream = stream)
|
||||
{
|
||||
var decoder = await BitmapDecoder.CreateAsync(inputStream);
|
||||
|
||||
var file = await KnownFolders.PicturesLibrary.CreateFileAsync("SimplePhoto.jpeg", CreationCollisionOption.GenerateUniqueName);
|
||||
|
||||
using (var outputStream = await file.OpenAsync(FileAccessMode.ReadWrite))
|
||||
{
|
||||
var encoder = await BitmapEncoder.CreateForTranscodingAsync(outputStream, decoder);
|
||||
|
@ -928,7 +939,7 @@ namespace CameraManualControls
|
|||
|
||||
}
|
||||
|
||||
private void ManualControlButton_Tapped(object sender, TappedRoutedEventArgs e)
|
||||
private void ManualControlButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// Toggle single control mode
|
||||
SetSingleControl(_singleControlMode ? null : sender);
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
<mp:PhoneIdentity PhoneProductId="2a15042f-e258-4b7e-9260-62ceea6b5305" PhonePublisherId="00000000-0000-0000-0000-000000000000"/>
|
||||
|
||||
<Properties>
|
||||
<DisplayName>CameraProfile</DisplayName>
|
||||
<DisplayName>CameraProfile JS Sample</DisplayName>
|
||||
<PublisherDisplayName>Microsoft Corporation</PublisherDisplayName>
|
||||
<Logo>images\storelogo-sdk.png</Logo>
|
||||
</Properties>
|
||||
|
|
|
@ -114,7 +114,7 @@ task<void> Scenario1_PreviewSettings::CleanupCameraAsync()
|
|||
/// Initializes the camera and populates the UI
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
void Scenario1_PreviewSettings::InitializeCameraButton_Tapped(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^)
|
||||
void Scenario1_PreviewSettings::InitializeCameraButton_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^)
|
||||
{
|
||||
Button^ button = static_cast<Button^>(sender);
|
||||
button->IsEnabled = false;
|
||||
|
|
|
@ -36,7 +36,7 @@ namespace SDKTemplate
|
|||
Concurrency::task<void> InitializeCameraAsync();
|
||||
Concurrency::task<void> CleanupCameraAsync();
|
||||
|
||||
void InitializeCameraButton_Tapped(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
|
||||
void InitializeCameraButton_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
|
||||
void ComboBoxSettings_Changed(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
|
||||
|
||||
void PopulateSettingsComboBox();
|
||||
|
|
|
@ -40,6 +40,7 @@ Scenario2_PhotoSettings::Scenario2_PhotoSettings()
|
|||
: _rootPage(MainPage::Current)
|
||||
, _mediaCapture(nullptr)
|
||||
, _isPreviewing(false)
|
||||
, _captureFolder(nullptr)
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
@ -68,6 +69,17 @@ task<void> Scenario2_PhotoSettings::InitializeCameraAsync()
|
|||
{
|
||||
PreviewControl->Source = _mediaCapture.Get();
|
||||
return create_task(_mediaCapture->StartPreviewAsync());
|
||||
}).then([this]()
|
||||
{
|
||||
return create_task(StorageLibrary::GetLibraryAsync(KnownLibraryId::Pictures));
|
||||
}).then([this](StorageLibrary^ picturesLibrary)
|
||||
{
|
||||
_captureFolder = picturesLibrary->SaveFolder;
|
||||
if (_captureFolder == nullptr)
|
||||
{
|
||||
// In this case fall back to the local app storage since the Pictures Library is not available
|
||||
_captureFolder = ApplicationData::Current->LocalFolder;
|
||||
}
|
||||
}).then([this](task<void> previousTask)
|
||||
{
|
||||
try
|
||||
|
@ -114,7 +126,7 @@ task<void> Scenario2_PhotoSettings::CleanupCameraAsync()
|
|||
/// Initializes the camera and populates the UI
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
void Scenario2_PhotoSettings::InitializeCameraButton_Tapped(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^)
|
||||
void Scenario2_PhotoSettings::InitializeCameraButton_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^)
|
||||
{
|
||||
Button^ button = static_cast<Button^>(sender);
|
||||
button->IsEnabled = false;
|
||||
|
@ -137,14 +149,14 @@ void Scenario2_PhotoSettings::InitializeCameraButton_Tapped(Platform::Object^ se
|
|||
/// <summary>
|
||||
/// Takes a photo to and saves to a StorageFile
|
||||
/// </summary>
|
||||
void Scenario2_PhotoSettings::PhotoButton_Tapped(Platform::Object^, Windows::UI::Xaml::RoutedEventArgs^)
|
||||
void Scenario2_PhotoSettings::PhotoButton_Click(Platform::Object^, Windows::UI::Xaml::RoutedEventArgs^)
|
||||
{
|
||||
if (_isPreviewing)
|
||||
{
|
||||
// Disable the photo button while taking a photo
|
||||
PhotoButton->IsEnabled = false;
|
||||
|
||||
create_task(KnownFolders::PicturesLibrary->CreateFileAsync("SimplePhoto.jpg", CreationCollisionOption::GenerateUniqueName))
|
||||
create_task(_captureFolder->CreateFileAsync("SimplePhoto.jpg", CreationCollisionOption::GenerateUniqueName))
|
||||
.then([this](StorageFile^ file)
|
||||
{
|
||||
return create_task(_mediaCapture->CapturePhotoToStorageFileAsync(ImageEncodingProperties::CreateJpeg(), file))
|
||||
|
|
|
@ -33,11 +33,14 @@ namespace SDKTemplate
|
|||
|
||||
bool _isPreviewing;
|
||||
|
||||
// Folder in which the captures will be stored
|
||||
Windows::Storage::StorageFolder^ _captureFolder;
|
||||
|
||||
Concurrency::task<void> InitializeCameraAsync();
|
||||
Concurrency::task<void> CleanupCameraAsync();
|
||||
|
||||
void InitializeCameraButton_Tapped(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
|
||||
void PhotoButton_Tapped(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
|
||||
void InitializeCameraButton_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
|
||||
void PhotoButton_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
|
||||
|
||||
void PreviewSettings_Changed(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
|
||||
void PhotoSettings_Changed(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
|
||||
|
|
|
@ -42,6 +42,7 @@ Scenario3_AspectRatio::Scenario3_AspectRatio()
|
|||
, _mediaCapture(nullptr)
|
||||
, _isPreviewing(false)
|
||||
, _isRecording(false)
|
||||
, _captureFolder(nullptr)
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
@ -70,6 +71,17 @@ task<void> Scenario3_AspectRatio::InitializeCameraAsync()
|
|||
{
|
||||
PreviewControl->Source = _mediaCapture.Get();
|
||||
return create_task(_mediaCapture->StartPreviewAsync());
|
||||
}).then([this]()
|
||||
{
|
||||
return create_task(StorageLibrary::GetLibraryAsync(KnownLibraryId::Pictures));
|
||||
}).then([this](StorageLibrary^ picturesLibrary)
|
||||
{
|
||||
_captureFolder = picturesLibrary->SaveFolder;
|
||||
if (_captureFolder == nullptr)
|
||||
{
|
||||
// In this case fall back to the local app storage since the Pictures Library is not available
|
||||
_captureFolder = ApplicationData::Current->LocalFolder;
|
||||
}
|
||||
}).then([this](task<void> previousTask)
|
||||
{
|
||||
try
|
||||
|
@ -119,7 +131,7 @@ task<void> Scenario3_AspectRatio::CleanupCameraAsync()
|
|||
/// Initializes the camera and populates the UI
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
void Scenario3_AspectRatio::InitializeCameraButton_Tapped(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^)
|
||||
void Scenario3_AspectRatio::InitializeCameraButton_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^)
|
||||
{
|
||||
Button^ button = static_cast<Button^>(sender);
|
||||
button->IsEnabled = false;
|
||||
|
@ -141,14 +153,14 @@ void Scenario3_AspectRatio::InitializeCameraButton_Tapped(Platform::Object^ send
|
|||
/// <summary>
|
||||
/// Records an MP4 video to a StorageFile
|
||||
/// </summary>
|
||||
void Scenario3_AspectRatio::VideoButton_Tapped(Platform::Object^, Windows::UI::Xaml::RoutedEventArgs^)
|
||||
void Scenario3_AspectRatio::VideoButton_Click(Platform::Object^, Windows::UI::Xaml::RoutedEventArgs^)
|
||||
{
|
||||
if (_isPreviewing)
|
||||
{
|
||||
if (!_isRecording)
|
||||
{
|
||||
// Create a storage file and begin recording
|
||||
create_task(KnownFolders::VideosLibrary->CreateFileAsync("SimpleVideo.mp4", CreationCollisionOption::GenerateUniqueName))
|
||||
create_task(_captureFolder->CreateFileAsync("SimpleVideo.mp4", CreationCollisionOption::GenerateUniqueName))
|
||||
.then([this](StorageFile^ file)
|
||||
{
|
||||
return create_task(_mediaCapture->StartRecordToStorageFileAsync(MediaEncodingProfile::CreateMp4(VideoEncodingQuality::Auto), file))
|
||||
|
|
|
@ -34,11 +34,14 @@ namespace SDKTemplate
|
|||
bool _isPreviewing;
|
||||
bool _isRecording;
|
||||
|
||||
// Folder in which the captures will be stored
|
||||
Windows::Storage::StorageFolder^ _captureFolder;
|
||||
|
||||
Concurrency::task<void> InitializeCameraAsync();
|
||||
Concurrency::task<void> CleanupCameraAsync();
|
||||
|
||||
void InitializeCameraButton_Tapped(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
|
||||
void VideoButton_Tapped(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
|
||||
void InitializeCameraButton_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
|
||||
void VideoButton_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
|
||||
|
||||
void PreviewSettings_Changed(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
|
||||
void VideoSettings_Changed(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
|
||||
|
|
|
@ -49,7 +49,7 @@ namespace SDKTemplate
|
|||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private async void InitializeCameraButton_Tapped(object sender, Windows.UI.Xaml.Input.TappedRoutedEventArgs e)
|
||||
private async void InitializeCameraButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var button = sender as Button;
|
||||
|
||||
|
|
|
@ -35,6 +35,9 @@ namespace SDKTemplate
|
|||
// Object to manage access to camera devices
|
||||
private MediaCapturePreviewer _previewer = null;
|
||||
|
||||
// Folder in which the captures will be stored (initialized in InitializeCameraButton_Click)
|
||||
private StorageFolder _captureFolder = null;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Scenario2_PhotoSettings"/> class.
|
||||
/// </summary>
|
||||
|
@ -67,7 +70,7 @@ namespace SDKTemplate
|
|||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private async void InitializeCameraButton_Tapped(object sender, Windows.UI.Xaml.Input.TappedRoutedEventArgs e)
|
||||
private async void InitializeCameraButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var button = sender as Button;
|
||||
|
||||
|
@ -87,6 +90,10 @@ namespace SDKTemplate
|
|||
PopulateComboBox(MediaStreamType.Photo, PhotoSettings, false);
|
||||
PhotoButton.IsEnabled = true;
|
||||
}
|
||||
|
||||
var picturesLibrary = await StorageLibrary.GetLibraryAsync(KnownLibraryId.Pictures);
|
||||
// Fall back to the local app storage if the Pictures Library is not available
|
||||
_captureFolder = picturesLibrary.SaveFolder ?? ApplicationData.Current.LocalFolder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -124,7 +131,7 @@ namespace SDKTemplate
|
|||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private async void PhotoButton_Tapped(object sender, Windows.UI.Xaml.Input.TappedRoutedEventArgs e)
|
||||
private async void PhotoButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (_previewer.IsPreviewing)
|
||||
{
|
||||
|
@ -136,7 +143,7 @@ namespace SDKTemplate
|
|||
try
|
||||
{
|
||||
// Take and save the photo
|
||||
var file = await KnownFolders.PicturesLibrary.CreateFileAsync("SimplePhoto.jpeg", CreationCollisionOption.GenerateUniqueName);
|
||||
var file = await _captureFolder.CreateFileAsync("SimplePhoto.jpg", CreationCollisionOption.GenerateUniqueName);
|
||||
await _previewer.MediaCapture.CapturePhotoToStorageFileAsync(ImageEncodingProperties.CreateJpeg(), file);
|
||||
rootPage.NotifyUser("Photo taken, saved to: " + file.Path, NotifyType.StatusMessage);
|
||||
}
|
||||
|
|
|
@ -33,6 +33,9 @@ namespace SDKTemplate
|
|||
// Object to manage access to camera devices
|
||||
private MediaCapturePreviewer _previewer = null;
|
||||
|
||||
// Folder in which the captures will be stored (initialized in InitializeCameraButton_Click)
|
||||
private StorageFolder _captureFolder = null;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Scenario1_PreviewSettings"/> class.
|
||||
/// </summary>
|
||||
|
@ -65,7 +68,7 @@ namespace SDKTemplate
|
|||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private async void InitializeCameraButton_Tapped(object sender, Windows.UI.Xaml.Input.TappedRoutedEventArgs e)
|
||||
private async void InitializeCameraButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var button = sender as Button;
|
||||
|
||||
|
@ -91,6 +94,10 @@ namespace SDKTemplate
|
|||
VideoButton.IsEnabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
var picturesLibrary = await StorageLibrary.GetLibraryAsync(KnownLibraryId.Pictures);
|
||||
// Fall back to the local app storage if the Pictures Library is not available
|
||||
_captureFolder = picturesLibrary.SaveFolder ?? ApplicationData.Current.LocalFolder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -132,7 +139,7 @@ namespace SDKTemplate
|
|||
/// <summary>
|
||||
/// Records an MP4 video to a StorageFile
|
||||
/// </summary>
|
||||
private async void VideoButton_Tapped(object sender, Windows.UI.Xaml.Input.TappedRoutedEventArgs e)
|
||||
private async void VideoButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (_previewer.IsPreviewing)
|
||||
{
|
||||
|
@ -141,7 +148,7 @@ namespace SDKTemplate
|
|||
try
|
||||
{
|
||||
// Create storage file in Video Library
|
||||
var videoFile = await KnownFolders.VideosLibrary.CreateFileAsync("SimpleVideo.mp4", CreationCollisionOption.GenerateUniqueName);
|
||||
var videoFile = await _captureFolder.CreateFileAsync("SimpleVideo.mp4", CreationCollisionOption.GenerateUniqueName);
|
||||
var encodingProfile = MediaEncodingProfile.CreateMp4(VideoEncodingQuality.Auto);
|
||||
|
||||
await _previewer.MediaCapture.StartRecordToStorageFileAsync(encodingProfile, videoFile);
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<Identity Name="Microsoft.SDKSamples.CameraResolution.JS" Version="1.0.0.0" Publisher="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US" />
|
||||
<mp:PhoneIdentity PhoneProductId="97c9deff-bfd1-434f-9da0-aee0febba635" PhonePublisherId="00000000-0000-0000-0000-000000000000" />
|
||||
<Properties>
|
||||
<DisplayName>CameraProfile</DisplayName>
|
||||
<DisplayName>CameraProfile JS Sample</DisplayName>
|
||||
<PublisherDisplayName>Microsoft Corporation</PublisherDisplayName>
|
||||
<Logo>images\storelogo-sdk.png</Logo>
|
||||
</Properties>
|
||||
|
|
|
@ -30,10 +30,10 @@
|
|||
</div>
|
||||
<div id="scenarioContent">
|
||||
<select id="previewSettings" class="win-dropdown">
|
||||
<option selected="selected" value"">Preview Settings</option>
|
||||
<option selected="selected" value="">Preview Settings</option>
|
||||
</select>
|
||||
<select id="photoSettings" class="win-dropdown">
|
||||
<option selected="selected" value"">Photo Settings</option>
|
||||
<option selected="selected" value="">Photo Settings</option>
|
||||
</select>
|
||||
<button id="photoButton" class="win-button" disabled>Take Photo</button>
|
||||
</div>
|
||||
|
|
|
@ -84,7 +84,7 @@
|
|||
if (cameraSettings.value == "")
|
||||
return;
|
||||
|
||||
oMediaCapture.videoDeviceController.setMediaStreamPropertiesAsync(Capture.MediaStreamType.videoPreview, allProperties[cameraSettings.value]);
|
||||
mediaCapture.videoDeviceController.setMediaStreamPropertiesAsync(Capture.MediaStreamType.videoPreview, allProperties[cameraSettings.value]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,9 @@
|
|||
"use strict";
|
||||
|
||||
var Capture = Windows.Media.Capture;
|
||||
var StorageLibrary = Windows.Storage.StorageLibrary;
|
||||
var KnownLibraryId = Windows.Storage.KnownLibraryId;
|
||||
var ApplicationData = Windows.Storage.ApplicationData;
|
||||
|
||||
var mediaCapture = null,
|
||||
previewProperties = [],
|
||||
|
@ -20,6 +23,9 @@
|
|||
|
||||
var isPreviewing = false;
|
||||
|
||||
// Folder in which the captures will be stored (initialized in SetupUiAsync)
|
||||
var captureFolder;
|
||||
|
||||
var page = WinJS.UI.Pages.define("/html/Scenario2_PhotoSettings.html", {
|
||||
ready: function (element, options) {
|
||||
document.getElementById("initCameraBtn").addEventListener("click", initCameraBtn_click, false);
|
||||
|
@ -71,7 +77,12 @@
|
|||
/// Initializes the camera and populates the UI
|
||||
/// </summary>
|
||||
function initCameraBtn_click() {
|
||||
initializeCameraAsync()
|
||||
return StorageLibrary.getLibraryAsync(KnownLibraryId.pictures)
|
||||
.then(function (picturesLibrary) {
|
||||
// Fall back to the local app storage if the Pictures Library is not available
|
||||
captureFolder = picturesLibrary.saveFolder || ApplicationData.current.localFolder;
|
||||
return initializeCameraAsync();
|
||||
})
|
||||
.then(function () {
|
||||
initCameraBtn.style.visibility = "hidden";
|
||||
checkIfStreamsAreIdentical();
|
||||
|
@ -117,7 +128,7 @@
|
|||
|
||||
var Storage = Windows.Storage;
|
||||
|
||||
Storage.KnownFolders.picturesLibrary.createFileAsync("SimplePhoto.jpg", Storage.CreationCollisionOption.generateUniqueName)
|
||||
captureFolder.createFileAsync("SimplePhoto.jpg", Storage.CreationCollisionOption.generateUniqueName)
|
||||
.then(function (file) {
|
||||
return mediaCapture.capturePhotoToStorageFileAsync(Windows.Media.MediaProperties.ImageEncodingProperties.createJpeg(), file)
|
||||
.then(function () {
|
||||
|
|
|
@ -14,6 +14,10 @@
|
|||
|
||||
var Capture = Windows.Media.Capture;
|
||||
var MediaProperties = Windows.Media.MediaProperties;
|
||||
var StorageLibrary = Windows.Storage.StorageLibrary;
|
||||
var KnownLibraryId = Windows.Storage.KnownLibraryId;
|
||||
var ApplicationData = Windows.Storage.ApplicationData;
|
||||
|
||||
|
||||
var mediaCapture = null,
|
||||
previewProperties = [],
|
||||
|
@ -22,6 +26,9 @@
|
|||
var isPreviewing = false;
|
||||
var isRecording = false;
|
||||
|
||||
// Folder in which the captures will be stored (availability check performed in SetupUiAsync)
|
||||
var captureFolder = Windows.Storage.KnownFolders.videosLibrary;
|
||||
|
||||
var page = WinJS.UI.Pages.define("/html/Scenario3_AspectRatio.html", {
|
||||
ready: function (element, options) {
|
||||
document.getElementById("initCameraBtn").addEventListener("click", initCameraBtn_click, false);
|
||||
|
@ -83,11 +90,16 @@
|
|||
/// Initializes the camera and populates the UI
|
||||
/// </summary>
|
||||
function initCameraBtn_click() {
|
||||
initializeCameraAsync()
|
||||
return StorageLibrary.getLibraryAsync(KnownLibraryId.pictures)
|
||||
.then(function (picturesLibrary) {
|
||||
// Fall back to the local app storage if the Pictures Library is not available
|
||||
captureFolder = picturesLibrary.saveFolder || ApplicationData.current.localFolder;
|
||||
return initializeCameraAsync();
|
||||
})
|
||||
.then(function () {
|
||||
initCameraBtn.style.visibility = "hidden";
|
||||
checkIfStreamsAreIdentical();
|
||||
populateComboBoxes();
|
||||
populateComboBox();
|
||||
videoButton.disabled = false;
|
||||
});
|
||||
}
|
||||
|
@ -100,7 +112,7 @@
|
|||
// The first element is just text
|
||||
if (previewSettings.value == "")
|
||||
return;
|
||||
|
||||
console.log(previewSettings.value)
|
||||
mediaCapture.videoDeviceController.setMediaStreamPropertiesAsync(Capture.MediaStreamType.videoPreview, previewProperties[previewSettings.value]);
|
||||
|
||||
// The preview just changed, update the video combo box
|
||||
|
@ -116,7 +128,6 @@
|
|||
// The first element is just text
|
||||
if (videoSettings.value == "")
|
||||
return;
|
||||
|
||||
mediaCapture.videoDeviceController.setMediaStreamPropertiesAsync(Capture.MediaStreamType.videoRecord, videoProperties[videoSettings.value]);
|
||||
}
|
||||
}
|
||||
|
@ -131,7 +142,7 @@
|
|||
var file = null;
|
||||
|
||||
// Create a storage file and begin recording
|
||||
Storage.KnownFolders.videosLibrary.createFileAsync("SimpleVideo.mp4", Storage.CreationCollisionOption.generateUniqueName)
|
||||
captureFolder.createFileAsync("SimpleVideo.mp4", Storage.CreationCollisionOption.generateUniqueName)
|
||||
.then(function (videoFile) {
|
||||
file = videoFile;
|
||||
var encodingProfile = MediaProperties.MediaEncodingProfile.createMp4(MediaProperties.VideoEncodingQuality.auto);
|
||||
|
@ -185,7 +196,7 @@
|
|||
/// <summary>
|
||||
/// Populates the combo boxes with preview settings and matching ratio settings for the video stream
|
||||
/// </summary>
|
||||
function populateComboBoxes() {
|
||||
function populateComboBox() {
|
||||
// Query all properties preview properties of the device
|
||||
previewProperties = mediaCapture.videoDeviceController.getAvailableMediaStreamProperties(Capture.MediaStreamType.videoPreview);
|
||||
|
||||
|
@ -194,8 +205,6 @@
|
|||
var streamResolution = new streamResolutionHelper(properties);
|
||||
addOptionToComboBox(previewSettings, streamResolution.getFriendlyName(true), index);
|
||||
});
|
||||
|
||||
MatchPreviewAspectRatio();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -216,10 +225,10 @@
|
|||
// Get all formats that have the same-ish aspect ratio as the preview and create new entries in the UI
|
||||
// Allow for some tolerance in the aspect ratio comparison
|
||||
const ASPECT_RATIO_TOLERANCE = 0.015;
|
||||
videoProperties.forEach(function (properties) {
|
||||
videoProperties.forEach(function (properties, index) {
|
||||
var streamHelper = new streamResolutionHelper(properties);
|
||||
if (Math.abs(streamHelper.aspectRatio() - previewProperties.aspectRatio()) < ASPECT_RATIO_TOLERANCE) {
|
||||
addOptionToComboBox(videoSettings, streamHelper.getFriendlyName(true));
|
||||
addOptionToComboBox(videoSettings, streamHelper.getFriendlyName(true), index);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -32,12 +32,11 @@
|
|||
</TextBlock>
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Grid.Row="1" HorizontalAlignment="Left" VerticalAlignment="Top">
|
||||
<ComboBox Name="CameraSettings" PlaceholderText="Preview Settings" SelectionChanged="ComboBoxSettings_Changed" Width="auto"/>
|
||||
</StackPanel>
|
||||
<ComboBox Name="CameraSettings" PlaceholderText="Preview Settings" SelectionChanged="ComboBoxSettings_Changed"
|
||||
Grid.Row="1" HorizontalAlignment="Left" VerticalAlignment="Top" Width="Auto"/>
|
||||
|
||||
<Button Grid.Row="2" Content="Initialize Camera" Tapped="InitializeCameraButton_Tapped"
|
||||
HorizontalAlignment="Center" VerticalAlignment="Center"></Button>
|
||||
<Button Grid.Row="2" Content="Initialize Camera" Click="InitializeCameraButton_Click" HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||
|
||||
<Viewbox Grid.Row="2">
|
||||
<!--Camera preview-->
|
||||
<CaptureElement Name="PreviewControl" Stretch="Uniform" Visibility="Collapsed"/>
|
||||
|
|
|
@ -35,12 +35,11 @@
|
|||
<StackPanel Grid.Row="1" Orientation="Horizontal" HorizontalAlignment="Left" VerticalAlignment="Top">
|
||||
<ComboBox Name="PreviewSettings" PlaceholderText="Preview Settings" SelectionChanged="PreviewSettings_Changed" Width="auto"/>
|
||||
<ComboBox Name="PhotoSettings" PlaceholderText="Photo Settings" SelectionChanged="PhotoSettings_Changed" Width="auto"/>
|
||||
<Button Name="PhotoButton" Tapped="PhotoButton_Tapped" IsEnabled="False">Take Photo</Button>
|
||||
<Button Name="PhotoButton" Click="PhotoButton_Click" IsEnabled="False">Take Photo</Button>
|
||||
</StackPanel>
|
||||
|
||||
<Button Grid.Row="2" Content="Initialize Camera" Tapped="InitializeCameraButton_Tapped"
|
||||
HorizontalAlignment="Center" VerticalAlignment="Center">
|
||||
</Button>
|
||||
<Button Grid.Row="2" Content="Initialize Camera" Click="InitializeCameraButton_Click" HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||
|
||||
<Viewbox Grid.Row="2">
|
||||
<!--Camera preview-->
|
||||
<CaptureElement Name="PreviewControl" Stretch="Uniform" Visibility="Collapsed"/>
|
||||
|
|
|
@ -35,10 +35,10 @@
|
|||
<StackPanel Grid.Row="1" Orientation="Horizontal" HorizontalAlignment="Left" VerticalAlignment="Top">
|
||||
<ComboBox Name="PreviewSettings" PlaceholderText="Preview Settings" SelectionChanged="PreviewSettings_Changed" Width="auto"/>
|
||||
<ComboBox Name="VideoSettings" PlaceholderText="Video Settings" SelectionChanged="VideoSettings_Changed" Width="auto"/>
|
||||
<Button Name="VideoButton" Tapped="VideoButton_Tapped" IsEnabled="False">Record Video</Button>
|
||||
<Button Name="VideoButton" Click="VideoButton_Click" IsEnabled="False">Record Video</Button>
|
||||
</StackPanel>
|
||||
|
||||
<Button Grid.Row="2" Content="Initialize Camera" Tapped="InitializeCameraButton_Tapped"
|
||||
<Button Grid.Row="2" Content="Initialize Camera" Click="InitializeCameraButton_Click"
|
||||
HorizontalAlignment="Center" VerticalAlignment="Center">
|
||||
</Button>
|
||||
<Viewbox Grid.Row="2">
|
||||
|
|
|
@ -44,6 +44,7 @@ MainPage::MainPage()
|
|||
, _displayOrientation(DisplayOrientations::Portrait)
|
||||
, _displayRequest(ref new Windows::System::Display::DisplayRequest())
|
||||
, RotationKey({ 0xC380465D, 0x2271, 0x428C,{ 0x9B, 0x83, 0xEC, 0xEA, 0x3B, 0x4A, 0x85, 0xC1 } })
|
||||
, _captureFolder(nullptr)
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
|
@ -268,14 +269,17 @@ task<void> MainPage::TakePhotoAsync()
|
|||
return create_task(_mediaCapture->CapturePhotoToStreamAsync(Windows::Media::MediaProperties::ImageEncodingProperties::CreateJpeg(), inputStream))
|
||||
.then([this, inputStream]()
|
||||
{
|
||||
WriteLine("Photo taken!");
|
||||
return create_task(_captureFolder->CreateFileAsync("SimplePhoto.jpg", CreationCollisionOption::GenerateUniqueName));
|
||||
}).then([this, inputStream](StorageFile^ file)
|
||||
{
|
||||
WriteLine("Photo taken! Saving to " + file->Path);
|
||||
|
||||
// Done taking a photo, so re-enable the button
|
||||
VideoButton->IsEnabled = true;
|
||||
VideoButton->Opacity = 1;
|
||||
|
||||
auto photoOrientation = ConvertOrientationToPhotoOrientation(GetCameraOrientation());
|
||||
return ReencodeAndSavePhotoAsync(inputStream, photoOrientation);
|
||||
return ReencodeAndSavePhotoAsync(inputStream, file, photoOrientation);
|
||||
}).then([this](task<void> previousTask)
|
||||
{
|
||||
try
|
||||
|
@ -296,7 +300,7 @@ task<void> MainPage::TakePhotoAsync()
|
|||
/// <returns></returns>
|
||||
task<void> MainPage::StartRecordingAsync()
|
||||
{
|
||||
return create_task(KnownFolders::PicturesLibrary->CreateFileAsync("SimpleVideo.mp4", CreationCollisionOption::GenerateUniqueName))
|
||||
return create_task(_captureFolder->CreateFileAsync("SimpleVideo.mp4", CreationCollisionOption::GenerateUniqueName))
|
||||
.then([this](StorageFile^ file)
|
||||
{
|
||||
// Calculate rotation angle, taking mirroring into account if necessary
|
||||
|
@ -304,12 +308,11 @@ task<void> MainPage::StartRecordingAsync()
|
|||
auto encodingProfile = MediaProperties::MediaEncodingProfile::CreateMp4(MediaProperties::VideoEncodingQuality::Auto);
|
||||
encodingProfile->Video->Properties->Insert(RotationKey, rotationAngle);
|
||||
|
||||
WriteLine("Starting recording...");
|
||||
return create_task(_mediaCapture->StartRecordToStorageFileAsync(encodingProfile, file))
|
||||
.then([this]()
|
||||
.then([this, file]()
|
||||
{
|
||||
_isRecording = true;
|
||||
WriteLine("Started recording!");
|
||||
WriteLine("Started recording to " + file->Path);
|
||||
});
|
||||
}).then([this](task<void> previousTask)
|
||||
{
|
||||
|
@ -378,22 +381,21 @@ task<DeviceInformation^> MainPage::FindCameraDeviceByPanelAsync(Windows::Devices
|
|||
/// Applies the given orientation to a photo stream and saves it as a StorageFile
|
||||
/// </summary>
|
||||
/// <param name="stream">The photo stream</param>
|
||||
/// <param name="file">The StorageFile in which the photo stream will be saved</param>
|
||||
/// <param name="photoOrientation">The orientation metadata to apply to the photo</param>
|
||||
/// <returns></returns>
|
||||
task<void> MainPage::ReencodeAndSavePhotoAsync(Streams::IRandomAccessStream^ stream, FileProperties::PhotoOrientation photoOrientation)
|
||||
task<void> MainPage::ReencodeAndSavePhotoAsync(Streams::IRandomAccessStream^ stream, StorageFile^ file, FileProperties::PhotoOrientation photoOrientation)
|
||||
{
|
||||
// Using this state variable to pass multiple values through our task chain
|
||||
ReencodeState^ state = ref new ReencodeState();
|
||||
state->_file = file;
|
||||
state->_orientation = photoOrientation;
|
||||
|
||||
return create_task(BitmapDecoder::CreateAsync(stream))
|
||||
.then([state](BitmapDecoder^ decoder)
|
||||
{
|
||||
state->_decoder = decoder;
|
||||
return create_task(KnownFolders::PicturesLibrary->CreateFileAsync("SimplePhoto.jpg", CreationCollisionOption::GenerateUniqueName));
|
||||
}).then([](StorageFile^ file)
|
||||
{
|
||||
return create_task(file->OpenAsync(FileAccessMode::ReadWrite));
|
||||
return create_task(state->_file->OpenAsync(FileAccessMode::ReadWrite));
|
||||
}).then([state](Streams::IRandomAccessStream^ outputStream)
|
||||
{
|
||||
return create_task(BitmapEncoder::CreateForTranscodingAsync(outputStream, state->_decoder));
|
||||
|
@ -451,6 +453,17 @@ task<void> MainPage::SetupUiAsync()
|
|||
_deviceOrientation = _orientationSensor->GetCurrentOrientation();
|
||||
}
|
||||
|
||||
create_task(StorageLibrary::GetLibraryAsync(KnownLibraryId::Pictures))
|
||||
.then([this](StorageLibrary^ picturesLibrary)
|
||||
{
|
||||
_captureFolder = picturesLibrary->SaveFolder;
|
||||
if (_captureFolder == nullptr)
|
||||
{
|
||||
// In this case fall back to the local app storage since the Pictures Library is not available
|
||||
_captureFolder = ApplicationData::Current->LocalFolder;
|
||||
}
|
||||
});
|
||||
|
||||
// Hide the status bar
|
||||
if (Windows::Foundation::Metadata::ApiInformation::IsTypePresent("Windows.UI.ViewManagement.StatusBar"))
|
||||
{
|
||||
|
@ -747,12 +760,12 @@ void MainPage::DisplayInformation_OrientationChanged(DisplayInformation^ sender,
|
|||
}));
|
||||
}
|
||||
|
||||
void MainPage::PhotoButton_Tapped(Object^, Windows::UI::Xaml::RoutedEventArgs^)
|
||||
void MainPage::PhotoButton_Click(Object^, Windows::UI::Xaml::RoutedEventArgs^)
|
||||
{
|
||||
TakePhotoAsync();
|
||||
}
|
||||
|
||||
void MainPage::VideoButton_Tapped(Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
|
||||
void MainPage::VideoButton_Click(Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
|
||||
{
|
||||
task<void> taskToExecute;
|
||||
if (!_isRecording)
|
||||
|
|
|
@ -20,6 +20,7 @@ namespace CameraStarterKit
|
|||
internal:
|
||||
Windows::Graphics::Imaging::BitmapDecoder^ _decoder;
|
||||
Windows::Graphics::Imaging::BitmapEncoder^ _encoder;
|
||||
Windows::Storage::StorageFile^ _file;
|
||||
Windows::Storage::FileProperties::PhotoOrientation _orientation;
|
||||
};
|
||||
|
||||
|
@ -52,6 +53,9 @@ namespace CameraStarterKit
|
|||
// Reference: http://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh868174.aspx
|
||||
const GUID RotationKey;
|
||||
|
||||
// Folder in which the captures will be stored (availability check performed in SetupUiAsync)
|
||||
Windows::Storage::StorageFolder^ _captureFolder;
|
||||
|
||||
// Event tokens
|
||||
Windows::Foundation::EventRegistrationToken _applicationSuspendingEventToken;
|
||||
Windows::Foundation::EventRegistrationToken _applicationResumingEventToken;
|
||||
|
@ -74,7 +78,7 @@ namespace CameraStarterKit
|
|||
|
||||
// Helpers
|
||||
Concurrency::task<Windows::Devices::Enumeration::DeviceInformation^> FindCameraDeviceByPanelAsync(Windows::Devices::Enumeration::Panel panel);
|
||||
Concurrency::task<void> ReencodeAndSavePhotoAsync(Windows::Storage::Streams::IRandomAccessStream^ stream, Windows::Storage::FileProperties::PhotoOrientation photoOrientation);
|
||||
Concurrency::task<void> ReencodeAndSavePhotoAsync(Windows::Storage::Streams::IRandomAccessStream^ stream, Windows::Storage::StorageFile^ file, Windows::Storage::FileProperties::PhotoOrientation photoOrientation);
|
||||
void UpdateCaptureControls();
|
||||
Concurrency::task<void> SetupUiAsync();
|
||||
Concurrency::task<void> CleanupUiAsync();
|
||||
|
@ -95,8 +99,8 @@ namespace CameraStarterKit
|
|||
void Application_Suspending(Object^ sender, Windows::ApplicationModel::SuspendingEventArgs^ e);
|
||||
void Application_Resuming(Object^ sender, Object^ args);
|
||||
void DisplayInformation_OrientationChanged(Windows::Graphics::Display::DisplayInformation^ sender, Object^ args);
|
||||
void PhotoButton_Tapped(Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
|
||||
void VideoButton_Tapped(Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
|
||||
void PhotoButton_Click(Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
|
||||
void VideoButton_Click(Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
|
||||
void SystemMediaControls_PropertyChanged(Windows::Media::SystemMediaTransportControls^ sender, Windows::Media::SystemMediaTransportControlsPropertyChangedEventArgs^ args);
|
||||
void OrientationSensor_OrientationChanged(Windows::Devices::Sensors::SimpleOrientationSensor^, Windows::Devices::Sensors::SimpleOrientationSensorOrientationChangedEventArgs^);
|
||||
void HardwareButtons_CameraPressed(Platform::Object^, Windows::Phone::UI::Input::CameraEventArgs^);
|
||||
|
|
|
@ -50,6 +50,9 @@ namespace CameraStarterKit
|
|||
// Reference: http://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh868174.aspx
|
||||
private static readonly Guid RotationKey = new Guid("C380465D-2271-428C-9B83-ECEA3B4A85C1");
|
||||
|
||||
// Folder in which the captures will be stored (initialized in SetupUiAsync)
|
||||
private StorageFolder _captureFolder = null;
|
||||
|
||||
// Prevent the screen from sleeping while the camera is running
|
||||
private readonly DisplayRequest _displayRequest = new DisplayRequest();
|
||||
|
||||
|
@ -191,12 +194,12 @@ namespace CameraStarterKit
|
|||
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => UpdateButtonOrientation());
|
||||
}
|
||||
|
||||
private async void PhotoButton_Tapped(object sender, TappedRoutedEventArgs e)
|
||||
private async void PhotoButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
await TakePhotoAsync();
|
||||
}
|
||||
|
||||
private async void VideoButton_Tapped(object sender, TappedRoutedEventArgs e)
|
||||
private async void VideoButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (!_isRecording)
|
||||
{
|
||||
|
@ -385,20 +388,25 @@ namespace CameraStarterKit
|
|||
|
||||
var stream = new InMemoryRandomAccessStream();
|
||||
|
||||
Debug.WriteLine("Taking photo...");
|
||||
await _mediaCapture.CapturePhotoToStreamAsync(ImageEncodingProperties.CreateJpeg(), stream);
|
||||
|
||||
try
|
||||
{
|
||||
Debug.WriteLine("Taking photo...");
|
||||
await _mediaCapture.CapturePhotoToStreamAsync(ImageEncodingProperties.CreateJpeg(), stream);
|
||||
Debug.WriteLine("Photo taken!");
|
||||
var file = await _captureFolder.CreateFileAsync("SimplePhoto.jpg", CreationCollisionOption.GenerateUniqueName);
|
||||
|
||||
Debug.WriteLine("Photo taken! Saving to " + file.Path);
|
||||
|
||||
var photoOrientation = ConvertOrientationToPhotoOrientation(GetCameraOrientation());
|
||||
|
||||
await ReencodeAndSavePhotoAsync(stream, photoOrientation);
|
||||
await ReencodeAndSavePhotoAsync(stream, file, photoOrientation);
|
||||
|
||||
Debug.WriteLine("Photo saved!");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// File I/O errors are reported as exceptions
|
||||
Debug.WriteLine("Exception when taking a photo: {0}", ex.ToString());
|
||||
Debug.WriteLine("Exception when taking a photo: " + ex.ToString());
|
||||
}
|
||||
|
||||
// Done taking a photo, so re-enable the button
|
||||
|
@ -415,7 +423,7 @@ namespace CameraStarterKit
|
|||
try
|
||||
{
|
||||
// Create storage file in Pictures Library
|
||||
var videoFile = await KnownFolders.PicturesLibrary.CreateFileAsync("SimpleVideo.mp4", CreationCollisionOption.GenerateUniqueName);
|
||||
var videoFile = await _captureFolder.CreateFileAsync("SimpleVideo.mp4", CreationCollisionOption.GenerateUniqueName);
|
||||
|
||||
var encodingProfile = MediaEncodingProfile.CreateMp4(VideoEncodingQuality.Auto);
|
||||
|
||||
|
@ -423,7 +431,7 @@ namespace CameraStarterKit
|
|||
var rotationAngle = 360 - ConvertDeviceOrientationToDegrees(GetCameraOrientation());
|
||||
encodingProfile.Video.Properties.Add(RotationKey, PropertyValue.CreateInt32(rotationAngle));
|
||||
|
||||
Debug.WriteLine("Starting recording...");
|
||||
Debug.WriteLine("Starting recording to " + videoFile.Path);
|
||||
|
||||
await _mediaCapture.StartRecordToStorageFileAsync(encodingProfile, videoFile);
|
||||
_isRecording = true;
|
||||
|
@ -433,7 +441,7 @@ namespace CameraStarterKit
|
|||
catch (Exception ex)
|
||||
{
|
||||
// File I/O errors are reported as exceptions
|
||||
Debug.WriteLine("Exception when starting video recording: {0}", ex.ToString());
|
||||
Debug.WriteLine("Exception when starting video recording: " + ex.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -515,6 +523,10 @@ namespace CameraStarterKit
|
|||
}
|
||||
|
||||
RegisterEventHandlers();
|
||||
|
||||
var picturesLibrary = await StorageLibrary.GetLibraryAsync(KnownLibraryId.Pictures);
|
||||
// Fall back to the local app storage if the Pictures Library is not available
|
||||
_captureFolder = picturesLibrary.SaveFolder ?? ApplicationData.Current.LocalFolder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -621,16 +633,15 @@ namespace CameraStarterKit
|
|||
/// Applies the given orientation to a photo stream and saves it as a StorageFile
|
||||
/// </summary>
|
||||
/// <param name="stream">The photo stream</param>
|
||||
/// <param name="file">The StorageFile in which the photo stream will be saved</param>
|
||||
/// <param name="photoOrientation">The orientation metadata to apply to the photo</param>
|
||||
/// <returns></returns>
|
||||
private static async Task ReencodeAndSavePhotoAsync(IRandomAccessStream stream, PhotoOrientation photoOrientation)
|
||||
private static async Task ReencodeAndSavePhotoAsync(IRandomAccessStream stream, StorageFile file, PhotoOrientation photoOrientation)
|
||||
{
|
||||
using (var inputStream = stream)
|
||||
{
|
||||
var decoder = await BitmapDecoder.CreateAsync(inputStream);
|
||||
|
||||
var file = await KnownFolders.PicturesLibrary.CreateFileAsync("SimplePhoto.jpeg", CreationCollisionOption.GenerateUniqueName);
|
||||
|
||||
using (var outputStream = await file.OpenAsync(FileAccessMode.ReadWrite))
|
||||
{
|
||||
var encoder = await BitmapEncoder.CreateForTranscodingAsync(outputStream, decoder);
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
<mp:PhoneIdentity PhoneProductId="d1e912c9-777b-4ead-9fe2-c797d7eebae2" PhonePublisherId="00000000-0000-0000-0000-000000000000"/>
|
||||
|
||||
<Properties>
|
||||
<DisplayName>CameraStarterKit</DisplayName>
|
||||
<DisplayName>CameraStarterKit JS Sample</DisplayName>
|
||||
<PublisherDisplayName>Microsoft Corporation</PublisherDisplayName>
|
||||
<Logo>images\storelogo-sdk.png</Logo>
|
||||
</Properties>
|
||||
|
|
|
@ -20,6 +20,9 @@
|
|||
var Media = Windows.Media;
|
||||
var SimpleOrientation = Windows.Devices.Sensors.SimpleOrientation;
|
||||
var SimpleOrientationSensor = Windows.Devices.Sensors.SimpleOrientationSensor;
|
||||
var StorageLibrary = Windows.Storage.StorageLibrary;
|
||||
var KnownLibraryId = Windows.Storage.KnownLibraryId;
|
||||
var ApplicationData = Windows.Storage.ApplicationData;
|
||||
|
||||
// Receive notifications about rotation of the device and UI and apply any necessary rotation to the preview stream and UI controls
|
||||
var oOrientationSensor = SimpleOrientationSensor.getDefault(),
|
||||
|
@ -47,6 +50,9 @@
|
|||
// Reference: http://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh868174.aspx
|
||||
var RotationKey = "C380465D-2271-428C-9B83-ECEA3B4A85C1";
|
||||
|
||||
// Folder in which the captures will be stored (initialized in SetupUiAsync)
|
||||
var oCaptureFolder;
|
||||
|
||||
// Initialization
|
||||
var app = WinJS.Application;
|
||||
var activation = Windows.ApplicationModel.Activation;
|
||||
|
@ -250,13 +256,18 @@
|
|||
console.log("Taking photo...");
|
||||
return oMediaCapture.capturePhotoToStreamAsync(Windows.Media.MediaProperties.ImageEncodingProperties.createJpeg(), inputStream)
|
||||
.then(function () {
|
||||
console.log("Photo taken!");
|
||||
return oCaptureFolder.createFileAsync("SimplePhoto.jpg", Windows.Storage.CreationCollisionOption.generateUniqueName);
|
||||
})
|
||||
.then(function (file) {
|
||||
console.log("Photo taken! Saving to " + file.path);
|
||||
|
||||
// Done taking a photo, so re-enable the button
|
||||
videoButton.disabled = false;
|
||||
|
||||
var photoOrientation = convertOrientationToPhotoOrientation(getCameraOrientation());
|
||||
return reencodeAndSavePhotoAsync(inputStream, photoOrientation);
|
||||
return reencodeAndSavePhotoAsync(inputStream, file, photoOrientation);
|
||||
}).then(function () {
|
||||
console.log("Photo saved!");
|
||||
}, function (error) {
|
||||
console.log(error.message);
|
||||
}).done();
|
||||
|
@ -267,14 +278,14 @@
|
|||
/// </summary>
|
||||
/// <returns></returns>
|
||||
function startRecordingAsync() {
|
||||
return Windows.Storage.KnownFolders.picturesLibrary.createFileAsync("SimpleVideo.mp4", Windows.Storage.CreationCollisionOption.generateUniqueName)
|
||||
return oCaptureFolder.createFileAsync("SimpleVideo.mp4", Windows.Storage.CreationCollisionOption.generateUniqueName)
|
||||
.then(function (file) {
|
||||
// Calculate rotation angle, taking mirroring into account if necessary
|
||||
var rotationAngle = 360 - convertDeviceOrientationToDegrees(getCameraOrientation());
|
||||
var encodingProfile = Windows.Media.MediaProperties.MediaEncodingProfile.createMp4(Windows.Media.MediaProperties.VideoEncodingQuality.auto);
|
||||
encodingProfile.video.properties.insert(RotationKey, rotationAngle);
|
||||
|
||||
console.log("Starting recording...");
|
||||
console.log("Starting recording to " + file.path);
|
||||
return oMediaCapture.startRecordToStorageFileAsync(encodingProfile, file)
|
||||
.then(function () {
|
||||
isRecording = true;
|
||||
|
@ -328,7 +339,7 @@
|
|||
/// <param name="stream">The photo stream</param>
|
||||
/// <param name="photoOrientation">The orientation metadata to apply to the photo</param>
|
||||
/// <returns></returns>
|
||||
function reencodeAndSavePhotoAsync(inputStream, orientation) {
|
||||
function reencodeAndSavePhotoAsync(inputStream, file, orientation) {
|
||||
var Imaging = Windows.Graphics.Imaging;
|
||||
var bitmapDecoder = null,
|
||||
bitmapEncoder = null,
|
||||
|
@ -337,8 +348,6 @@
|
|||
return Imaging.BitmapDecoder.createAsync(inputStream)
|
||||
.then(function (decoder) {
|
||||
bitmapDecoder = decoder;
|
||||
return Windows.Storage.KnownFolders.picturesLibrary.createFileAsync("SimplePhoto.jpg", Windows.Storage.CreationCollisionOption.generateUniqueName);
|
||||
}).then(function (file) {
|
||||
return file.openAsync(Windows.Storage.FileAccessMode.readWrite);
|
||||
}).then(function (outStream) {
|
||||
outputStream = outStream;
|
||||
|
@ -396,13 +405,19 @@
|
|||
oDeviceOrientation = oOrientationSensor.getCurrentOrientation();
|
||||
}
|
||||
|
||||
// Hide the status bar
|
||||
if (Windows.Foundation.Metadata.ApiInformation.isTypePresent("Windows.UI.ViewManagement.StatusBar")) {
|
||||
return Windows.UI.ViewManagement.StatusBar.getForCurrentView().hideAsync();
|
||||
}
|
||||
else {
|
||||
return WinJS.Promise.as();
|
||||
}
|
||||
return StorageLibrary.getLibraryAsync(KnownLibraryId.pictures)
|
||||
.then(function (picturesLibrary) {
|
||||
// Fall back to the local app storage if the Pictures Library is not available
|
||||
oCaptureFolder = picturesLibrary.saveFolder || ApplicationData.current.localFolder;
|
||||
|
||||
// Hide the status bar
|
||||
if (Windows.Foundation.Metadata.ApiInformation.isTypePresent("Windows.UI.ViewManagement.StatusBar")) {
|
||||
return Windows.UI.ViewManagement.StatusBar.getForCurrentView().hideAsync();
|
||||
}
|
||||
else {
|
||||
return WinJS.Promise.as();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -43,13 +43,13 @@
|
|||
</Style>
|
||||
</StackPanel.Resources>
|
||||
|
||||
<Button Name="PhotoButton" Tapped="PhotoButton_Tapped" IsEnabled="False">
|
||||
<Button Name="PhotoButton" Click="PhotoButton_Click" IsEnabled="False">
|
||||
<Viewbox MaxHeight="40" MaxWidth="40">
|
||||
<SymbolIcon Symbol="Camera"/>
|
||||
</Viewbox>
|
||||
</Button>
|
||||
|
||||
<Button Name="VideoButton" Tapped="VideoButton_Tapped" IsEnabled="False">
|
||||
<Button Name="VideoButton" Click="VideoButton_Click" IsEnabled="False">
|
||||
<Grid>
|
||||
<Ellipse x:Name="StartRecordingIcon" Fill="Red" Width="20" Height="20"/>
|
||||
<Rectangle x:Name="StopRecordingIcon" Fill="White" Width="20" Height="20" Visibility="Collapsed"/>
|
||||
|
|
|
@ -52,6 +52,9 @@ Namespace Global.CameraStarterKit
|
|||
' Reference: http://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh868174.aspx
|
||||
Private Shared ReadOnly RotationKey As Guid = New Guid("C380465D-2271-428C-9B83-ECEA3B4A85C1")
|
||||
|
||||
' Folder in which the captures will be stored (initialized in SetupUiAsync)
|
||||
Private _captureFolder As StorageFolder = Nothing
|
||||
|
||||
' Prevent the screen from sleeping while the camera is running
|
||||
Private ReadOnly _displayRequest As DisplayRequest = New DisplayRequest()
|
||||
|
||||
|
@ -154,11 +157,11 @@ Namespace Global.CameraStarterKit
|
|||
Await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, Sub() UpdateButtonOrientation())
|
||||
End Sub
|
||||
|
||||
Private Async Sub PhotoButton_Tapped(sender As Object, e As TappedRoutedEventArgs)
|
||||
Private Async Sub PhotoButton_Click(sender As Object, e As RoutedEventArgs)
|
||||
Await TakePhotoAsync()
|
||||
End Sub
|
||||
|
||||
Private Async Sub VideoButton_Tapped(sender As Object, e As TappedRoutedEventArgs)
|
||||
Private Async Sub VideoButton_Click(sender As Object, e As RoutedEventArgs)
|
||||
If Not _isRecording Then
|
||||
Await StartRecordingAsync()
|
||||
Else
|
||||
|
@ -282,14 +285,15 @@ Namespace Global.CameraStarterKit
|
|||
VideoButton.IsEnabled = _mediaCapture.MediaCaptureSettings.ConcurrentRecordAndPhotoSupported
|
||||
VideoButton.Opacity = If(VideoButton.IsEnabled, 1, 0)
|
||||
Dim stream = New InMemoryRandomAccessStream()
|
||||
Debug.WriteLine("Taking photo...")
|
||||
Await _mediaCapture.CapturePhotoToStreamAsync(ImageEncodingProperties.CreateJpeg(), stream)
|
||||
Try
|
||||
Debug.WriteLine("Taking photo...")
|
||||
Await _mediaCapture.CapturePhotoToStreamAsync(ImageEncodingProperties.CreateJpeg(), stream)
|
||||
Debug.WriteLine("Photo taken!")
|
||||
Dim file = Await _captureFolder.CreateFileAsync("SimplePhoto.jpg", CreationCollisionOption.GenerateUniqueName)
|
||||
Debug.WriteLine("Photo taken! Saving to " & file.Path)
|
||||
Dim photoOrientation = ConvertOrientationToPhotoOrientation(GetCameraOrientation())
|
||||
Await ReencodeAndSavePhotoAsync(stream, photoOrientation)
|
||||
Await ReencodeAndSavePhotoAsync(stream, file, photoOrientation)
|
||||
Catch ex As Exception
|
||||
Debug.WriteLine("Exception when taking a photo: {0}", ex.ToString())
|
||||
Debug.WriteLine("Exception when taking a photo: " & ex.ToString())
|
||||
End Try
|
||||
|
||||
VideoButton.IsEnabled = True
|
||||
|
@ -303,17 +307,17 @@ Namespace Global.CameraStarterKit
|
|||
Private Async Function StartRecordingAsync() As Task
|
||||
Try
|
||||
' Create storage file in Pictures Library
|
||||
Dim videoFile = Await KnownFolders.PicturesLibrary.CreateFileAsync("SimpleVideo.mp4", CreationCollisionOption.GenerateUniqueName)
|
||||
Dim videoFile = Await _captureFolder.CreateFileAsync("SimpleVideo.mp4", CreationCollisionOption.GenerateUniqueName)
|
||||
Dim encodingProfile = MediaEncodingProfile.CreateMp4(VideoEncodingQuality.Auto)
|
||||
' Calculate rotation angle, taking mirroring into account if necessary
|
||||
Dim rotationAngle = 360 - ConvertDeviceOrientationToDegrees(GetCameraOrientation())
|
||||
encodingProfile.Video.Properties.Add(RotationKey, PropertyValue.CreateInt32(rotationAngle))
|
||||
Debug.WriteLine("Starting recording...")
|
||||
Debug.WriteLine("Starting recording to " & videoFile.Path)
|
||||
Await _mediaCapture.StartRecordToStorageFileAsync(encodingProfile, videoFile)
|
||||
_isRecording = True
|
||||
Debug.WriteLine("Started recording!")
|
||||
Catch ex As Exception
|
||||
Debug.WriteLine("Exception when starting video recording: {0}", ex.ToString())
|
||||
Debug.WriteLine("Exception when starting video recording: " & ex.ToString())
|
||||
End Try
|
||||
End Function
|
||||
|
||||
|
@ -374,6 +378,10 @@ Namespace Global.CameraStarterKit
|
|||
End If
|
||||
|
||||
RegisterEventHandlers()
|
||||
|
||||
Dim picturesLibrary = Await StorageLibrary.GetLibraryAsync(KnownLibraryId.Pictures)
|
||||
' Fall back to the local app storage if the Pictures Library is not available
|
||||
_captureFolder = If(picturesLibrary.SaveFolder, ApplicationData.Current.LocalFolder)
|
||||
End Function
|
||||
|
||||
''' <summary>
|
||||
|
@ -453,12 +461,12 @@ Namespace Global.CameraStarterKit
|
|||
''' Applies the given orientation to a photo stream and saves it as a StorageFile
|
||||
''' </summary>
|
||||
''' <param name="stream">The photo stream</param>
|
||||
''' <param name="file">The StorageFile in which the photo stream will be saved</param>
|
||||
''' <param name="photoOrientation">The orientation metadata to apply to the photo</param>
|
||||
''' <returns></returns>
|
||||
Private Shared Async Function ReencodeAndSavePhotoAsync(stream As IRandomAccessStream, photoOrientation As PhotoOrientation) As Task
|
||||
Private Shared Async Function ReencodeAndSavePhotoAsync(stream As IRandomAccessStream, file As StorageFile, photoOrientation As PhotoOrientation) As Task
|
||||
Using inputStream = stream
|
||||
Dim decoder = Await BitmapDecoder.CreateAsync(inputStream)
|
||||
Dim file = Await KnownFolders.PicturesLibrary.CreateFileAsync("SimplePhoto.jpeg", CreationCollisionOption.GenerateUniqueName)
|
||||
Using outputStream = Await file.OpenAsync(FileAccessMode.ReadWrite)
|
||||
Dim encoder = Await BitmapEncoder.CreateForTranscodingAsync(outputStream, decoder)
|
||||
Dim properties = New BitmapPropertySet From {{"System.Photo.Orientation", New BitmapTypedValue(photoOrientation, PropertyType.UInt16)}}
|
||||
|
|
|
@ -48,6 +48,7 @@ MainPage::MainPage()
|
|||
, _videoStabilizationEffect(nullptr)
|
||||
, _inputPropertiesBackup(nullptr)
|
||||
, _outputPropertiesBackup(nullptr)
|
||||
, _captureFolder(nullptr)
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
|
@ -416,7 +417,7 @@ task<void> MainPage::CleanUpVideoStabilizationEffectAsync()
|
|||
task<void> MainPage::StartRecordingAsync()
|
||||
{
|
||||
// Create storage file in Pictures Library
|
||||
return create_task(KnownFolders::PicturesLibrary->CreateFileAsync("SimpleVideo.mp4", CreationCollisionOption::GenerateUniqueName))
|
||||
return create_task(_captureFolder->CreateFileAsync("SimpleVideo.mp4", CreationCollisionOption::GenerateUniqueName))
|
||||
.then([this](StorageFile^ file)
|
||||
{
|
||||
// Calculate rotation angle, taking mirroring into account if necessary
|
||||
|
@ -425,12 +426,11 @@ task<void> MainPage::StartRecordingAsync()
|
|||
// Add it to the encoding profile, or edit the value if the GUID was already a part of the properties
|
||||
_encodingProfile->Video->Properties->Insert(RotationKey, rotationAngle);
|
||||
|
||||
WriteLine("Starting recording...");
|
||||
return create_task(_mediaCapture->StartRecordToStorageFileAsync(_encodingProfile, file))
|
||||
.then([this]()
|
||||
.then([this, file]()
|
||||
{
|
||||
_isRecording = true;
|
||||
WriteLine("Started recording!");
|
||||
WriteLine("Started recording to: " + file->Path);
|
||||
});
|
||||
}).then([this](task<void> previousTask)
|
||||
{
|
||||
|
@ -556,6 +556,17 @@ task<void> MainPage::SetupUiAsync()
|
|||
_deviceOrientation = _orientationSensor->GetCurrentOrientation();
|
||||
}
|
||||
|
||||
create_task(StorageLibrary::GetLibraryAsync(KnownLibraryId::Pictures))
|
||||
.then([this](StorageLibrary^ picturesLibrary)
|
||||
{
|
||||
_captureFolder = picturesLibrary->SaveFolder;
|
||||
if (_captureFolder == nullptr)
|
||||
{
|
||||
// In this case fall back to the local app storage since the Pictures Library is not available
|
||||
_captureFolder = ApplicationData::Current->LocalFolder;
|
||||
}
|
||||
});
|
||||
|
||||
// Hide the status bar
|
||||
if (Windows::Foundation::Metadata::ApiInformation::IsTypePresent("Windows.UI.ViewManagement.StatusBar"))
|
||||
{
|
||||
|
@ -845,7 +856,7 @@ void MainPage::DisplayInformation_OrientationChanged(DisplayInformation^ sender,
|
|||
}));
|
||||
}
|
||||
|
||||
void MainPage::VsToggleButton_Tapped(Object^, Windows::UI::Xaml::RoutedEventArgs^)
|
||||
void MainPage::VsToggleButton_Click(Object^, Windows::UI::Xaml::RoutedEventArgs^)
|
||||
{
|
||||
// Note that for the most part, this button is disabled during recording, except when VS is turned off automatically
|
||||
task<void> taskToExecute;
|
||||
|
@ -884,7 +895,7 @@ void MainPage::VsToggleButton_Tapped(Object^, Windows::UI::Xaml::RoutedEventArgs
|
|||
});
|
||||
}
|
||||
|
||||
void MainPage::VideoButton_Tapped(Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
|
||||
void MainPage::VideoButton_Click(Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
|
||||
{
|
||||
task<void> taskToExecute;
|
||||
if (!_isRecording)
|
||||
|
|
|
@ -45,6 +45,9 @@ namespace CameraVideoStabilization
|
|||
// Reference: http://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh868174.aspx
|
||||
const GUID RotationKey;
|
||||
|
||||
// Folder in which the captures will be stored (availability check performed in SetupUiAsync)
|
||||
Windows::Storage::StorageFolder^ _captureFolder;
|
||||
|
||||
Windows::Media::Core::VideoStabilizationEffect^ _videoStabilizationEffect;
|
||||
Windows::Media::MediaProperties::VideoEncodingProperties^ _inputPropertiesBackup;
|
||||
Windows::Media::MediaProperties::VideoEncodingProperties^ _outputPropertiesBackup;
|
||||
|
@ -94,8 +97,8 @@ namespace CameraVideoStabilization
|
|||
void Application_Suspending(Object^ sender, Windows::ApplicationModel::SuspendingEventArgs^ e);
|
||||
void Application_Resuming(Object^ sender, Object^ args);
|
||||
void DisplayInformation_OrientationChanged(Windows::Graphics::Display::DisplayInformation^ sender, Object^ args);
|
||||
void VsToggleButton_Tapped(Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
|
||||
void VideoButton_Tapped(Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
|
||||
void VsToggleButton_Click(Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
|
||||
void VideoButton_Click(Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
|
||||
void SystemMediaControls_PropertyChanged(Windows::Media::SystemMediaTransportControls^ sender, Windows::Media::SystemMediaTransportControlsPropertyChangedEventArgs^ args);
|
||||
void VideoStabilizationEffect_EnabledChanged(Windows::Media::Core::VideoStabilizationEffect^ sender, Windows::Media::Core::VideoStabilizationEffectEnabledChangedEventArgs^ args);
|
||||
void OrientationSensor_OrientationChanged(Windows::Devices::Sensors::SimpleOrientationSensor^, Windows::Devices::Sensors::SimpleOrientationSensorOrientationChangedEventArgs^);
|
||||
|
|
|
@ -50,6 +50,9 @@ namespace CameraVideoStabilization
|
|||
// Reference: http://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh868174.aspx
|
||||
private static readonly Guid RotationKey = new Guid("C380465D-2271-428C-9B83-ECEA3B4A85C1");
|
||||
|
||||
// Folder in which the captures will be stored (initialized in SetupUiAsync)
|
||||
private StorageFolder _captureFolder = null;
|
||||
|
||||
// Prevent the screen from sleeping while the camera is running
|
||||
private readonly DisplayRequest _displayRequest = new DisplayRequest();
|
||||
|
||||
|
@ -196,7 +199,7 @@ namespace CameraVideoStabilization
|
|||
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => UpdateButtonOrientation());
|
||||
}
|
||||
|
||||
private async void VsToggleButton_Tapped(object sender, RoutedEventArgs e)
|
||||
private async void VsToggleButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// Note that for the most part, this button is disabled during recording, except when VS is turned off automatically
|
||||
|
||||
|
@ -227,7 +230,7 @@ namespace CameraVideoStabilization
|
|||
UpdateCaptureControls();
|
||||
}
|
||||
|
||||
private async void VideoButton_Tapped(object sender, TappedRoutedEventArgs e)
|
||||
private async void VideoButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (!_isRecording)
|
||||
{
|
||||
|
@ -544,7 +547,7 @@ namespace CameraVideoStabilization
|
|||
try
|
||||
{
|
||||
// Create storage file in Pictures Library
|
||||
var videoFile = await KnownFolders.PicturesLibrary.CreateFileAsync("SimpleVideo.mp4", CreationCollisionOption.GenerateUniqueName);
|
||||
var videoFile = await _captureFolder.CreateFileAsync("SimpleVideo.mp4", CreationCollisionOption.GenerateUniqueName);
|
||||
|
||||
// Calculate rotation angle, taking mirroring into account if necessary
|
||||
var rotationAngle = 360 - ConvertDeviceOrientationToDegrees(GetCameraOrientation());
|
||||
|
@ -552,7 +555,7 @@ namespace CameraVideoStabilization
|
|||
// Add it to the encoding profile, or edit the value if the GUID was already a part of the properties
|
||||
_encodingProfile.Video.Properties[RotationKey] = PropertyValue.CreateInt32(rotationAngle);
|
||||
|
||||
Debug.WriteLine("Starting recording...");
|
||||
Debug.WriteLine("Starting recording to " + videoFile.Path);
|
||||
|
||||
await _mediaCapture.StartRecordToStorageFileAsync(_encodingProfile, videoFile);
|
||||
_isRecording = true;
|
||||
|
@ -562,7 +565,7 @@ namespace CameraVideoStabilization
|
|||
catch (Exception ex)
|
||||
{
|
||||
// File I/O errors are reported as exceptions
|
||||
Debug.WriteLine("Exception when starting video recording: {0}", ex.ToString());
|
||||
Debug.WriteLine("Exception when starting video recording: " + ex.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -594,7 +597,7 @@ namespace CameraVideoStabilization
|
|||
catch (Exception ex)
|
||||
{
|
||||
// File I/O errors are reported as exceptions
|
||||
Debug.WriteLine("Exception when stopping video recording: {0}", ex.ToString());
|
||||
Debug.WriteLine("Exception when stopping video recording: " + ex.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -668,6 +671,10 @@ namespace CameraVideoStabilization
|
|||
}
|
||||
|
||||
RegisterEventHandlers();
|
||||
|
||||
var picturesLibrary = await StorageLibrary.GetLibraryAsync(KnownLibraryId.Pictures);
|
||||
// Fall back to the local app storage if the Pictures Library is not available
|
||||
_captureFolder = picturesLibrary.SaveFolder ?? ApplicationData.Current.LocalFolder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -766,7 +773,6 @@ namespace CameraVideoStabilization
|
|||
return desiredDevice ?? allVideoDevices.FirstOrDefault();
|
||||
}
|
||||
|
||||
|
||||
#endregion Helper functions
|
||||
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
<mp:PhoneIdentity PhoneProductId="5fbda83f-d3b6-4577-a1fe-768211883cd4" PhonePublisherId="00000000-0000-0000-0000-000000000000"/>
|
||||
|
||||
<Properties>
|
||||
<DisplayName>CameraVideoStabilization</DisplayName>
|
||||
<DisplayName>CameraVideoStabilization JS Sample</DisplayName>
|
||||
<PublisherDisplayName>Microsoft Corporation</PublisherDisplayName>
|
||||
<Logo>images\storelogo-sdk.png</Logo>
|
||||
</Properties>
|
||||
|
|
|
@ -23,6 +23,9 @@
|
|||
var Media = Windows.Media;
|
||||
var SimpleOrientation = Windows.Devices.Sensors.SimpleOrientation;
|
||||
var SimpleOrientationSensor = Windows.Devices.Sensors.SimpleOrientationSensor;
|
||||
var StorageLibrary = Windows.Storage.StorageLibrary;
|
||||
var KnownLibraryId = Windows.Storage.KnownLibraryId;
|
||||
var ApplicationData = Windows.Storage.ApplicationData;
|
||||
|
||||
// Receive notifications about rotation of the device and UI and apply any necessary rotation to the preview stream and UI controls
|
||||
var oOrientationSensor = SimpleOrientationSensor.getDefault(),
|
||||
|
@ -56,6 +59,9 @@
|
|||
// Reference: http://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh868174.aspx
|
||||
var RotationKey = "C380465D-2271-428C-9B83-ECEA3B4A85C1";
|
||||
|
||||
// Folder in which the captures will be stored (initialized in SetupUiAsync)
|
||||
var oCaptureFolder;
|
||||
|
||||
// Initialization
|
||||
var app = WinJS.Application;
|
||||
var activation = Windows.ApplicationModel.Activation;
|
||||
|
@ -392,14 +398,14 @@
|
|||
/// </summary>
|
||||
/// <returns></returns>
|
||||
function startRecordingAsync() {
|
||||
return Windows.Storage.KnownFolders.picturesLibrary.createFileAsync("SimpleVideo.mp4", Windows.Storage.CreationCollisionOption.generateUniqueName)
|
||||
return oCaptureFolder.createFileAsync("SimpleVideo.mp4", Windows.Storage.CreationCollisionOption.generateUniqueName)
|
||||
.then(function (file) {
|
||||
// Calculate rotation angle, taking mirroring into account if necessary
|
||||
var rotationAngle = 360 - convertDeviceOrientationToDegrees(getCameraOrientation());
|
||||
var encodingProfile = Windows.Media.MediaProperties.MediaEncodingProfile.createMp4(Windows.Media.MediaProperties.VideoEncodingQuality.auto);
|
||||
encodingProfile.video.properties.insert(RotationKey, rotationAngle);
|
||||
|
||||
console.log("Starting recording...");
|
||||
console.log("Starting recording to " + file.path);
|
||||
return oMediaCapture.startRecordToStorageFileAsync(encodingProfile, file)
|
||||
.then(function () {
|
||||
isRecording = true;
|
||||
|
@ -460,7 +466,7 @@
|
|||
/// <param name="stream">The photo stream</param>
|
||||
/// <param name="photoOrientation">The orientation metadata to apply to the photo</param>
|
||||
/// <returns></returns>
|
||||
function reencodeAndSavePhotoAsync(inputStream, orientation) {
|
||||
function reencodeAndSavePhotoAsync(inputStream, file, orientation) {
|
||||
var Imaging = Windows.Graphics.Imaging;
|
||||
var bitmapDecoder = null,
|
||||
bitmapEncoder = null,
|
||||
|
@ -469,8 +475,6 @@
|
|||
return Imaging.BitmapDecoder.createAsync(inputStream)
|
||||
.then(function (decoder) {
|
||||
bitmapDecoder = decoder;
|
||||
return Windows.Storage.KnownFolders.picturesLibrary.createFileAsync("SimplePhoto.jpg", Windows.Storage.CreationCollisionOption.generateUniqueName);
|
||||
}).then(function (file) {
|
||||
return file.openAsync(Windows.Storage.FileAccessMode.readWrite);
|
||||
}).then(function (outStream) {
|
||||
outputStream = outStream;
|
||||
|
@ -480,7 +484,7 @@
|
|||
var properties = new Imaging.BitmapPropertySet();
|
||||
properties.insert("System.Photo.Orientation", new Imaging.BitmapTypedValue(orientation, Windows.Foundation.PropertyType.uint16));
|
||||
return bitmapEncoder.bitmapProperties.setPropertiesAsync(properties)
|
||||
}).then(function() {
|
||||
}).then(function () {
|
||||
return bitmapEncoder.flushAsync();
|
||||
}).then(function () {
|
||||
inputStream.close();
|
||||
|
@ -558,13 +562,19 @@
|
|||
oDeviceOrientation = oOrientationSensor.getCurrentOrientation();
|
||||
}
|
||||
|
||||
// Hide the status bar
|
||||
if (Windows.Foundation.Metadata.ApiInformation.isTypePresent("Windows.UI.ViewManagement.StatusBar")) {
|
||||
return Windows.UI.ViewManagement.StatusBar.getForCurrentView().hideAsync();
|
||||
}
|
||||
else {
|
||||
return WinJS.Promise.as();
|
||||
}
|
||||
return StorageLibrary.getLibraryAsync(KnownLibraryId.pictures)
|
||||
.then(function (picturesLibrary) {
|
||||
// Fall back to the local app storage if the Pictures Library is not available
|
||||
oCaptureFolder = picturesLibrary.saveFolder || ApplicationData.current.localFolder;
|
||||
|
||||
// Hide the status bar
|
||||
if (Windows.Foundation.Metadata.ApiInformation.isTypePresent("Windows.UI.ViewManagement.StatusBar")) {
|
||||
return Windows.UI.ViewManagement.StatusBar.getForCurrentView().hideAsync();
|
||||
}
|
||||
else {
|
||||
return WinJS.Promise.as();
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -44,7 +44,7 @@
|
|||
<StackPanel HorizontalAlignment="Right" VerticalAlignment="Center">
|
||||
|
||||
<!--VS Toggle button-->
|
||||
<Button Name="VsToggleButton" Tapped="VsToggleButton_Tapped" IsEnabled="False">
|
||||
<Button Name="VsToggleButton" Click="VsToggleButton_Click" IsEnabled="False">
|
||||
<Viewbox MaxHeight="40" MaxWidth="40">
|
||||
<Grid>
|
||||
<!--Off icon-->
|
||||
|
@ -66,7 +66,7 @@
|
|||
</Button>
|
||||
|
||||
<!--Video record button-->
|
||||
<Button Name="VideoButton" Tapped="VideoButton_Tapped" IsEnabled="False">
|
||||
<Button Name="VideoButton" Click="VideoButton_Click" IsEnabled="False">
|
||||
<Grid>
|
||||
<Ellipse Name="StartRecordingIcon" Fill="Red" Width="20" Height="20"/>
|
||||
<Rectangle Name="StopRecordingIcon" Fill="White" Width="20" Height="20" Visibility="Collapsed"/>
|
||||
|
|
|
@ -51,6 +51,9 @@ Namespace Global.CameraVideoStabilization
|
|||
' Reference: http://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh868174.aspx
|
||||
Private Shared ReadOnly RotationKey As Guid = New Guid("C380465D-2271-428C-9B83-ECEA3B4A85C1")
|
||||
|
||||
' Folder in which the captures will be stored (initialized in SetupUiAsync)
|
||||
Private _captureFolder As StorageFolder = Nothing
|
||||
|
||||
' Prevent the screen from sleeping while the camera is running
|
||||
Private ReadOnly _displayRequest As DisplayRequest = New DisplayRequest()
|
||||
|
||||
|
@ -161,7 +164,7 @@ Namespace Global.CameraVideoStabilization
|
|||
Await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, Sub() UpdateButtonOrientation())
|
||||
End Sub
|
||||
|
||||
Private Async Sub VsToggleButton_Tapped(sender As Object, e As RoutedEventArgs)
|
||||
Private Async Sub VsToggleButton_Click(sender As Object, e As RoutedEventArgs)
|
||||
If Not _isRecording Then
|
||||
If _videoStabilizationEffect Is Nothing Then
|
||||
Await CreateVideoStabilizationEffectAsync()
|
||||
|
@ -175,7 +178,7 @@ Namespace Global.CameraVideoStabilization
|
|||
UpdateCaptureControls()
|
||||
End Sub
|
||||
|
||||
Private Async Sub VideoButton_Tapped(sender As Object, e As TappedRoutedEventArgs)
|
||||
Private Async Sub VideoButton_Click(sender As Object, e As RoutedEventArgs)
|
||||
If Not _isRecording Then
|
||||
Await StartRecordingAsync()
|
||||
Else
|
||||
|
@ -372,16 +375,16 @@ Namespace Global.CameraVideoStabilization
|
|||
Private Async Function StartRecordingAsync() As Task
|
||||
Try
|
||||
' Create storage file in Pictures Library
|
||||
Dim videoFile = Await KnownFolders.PicturesLibrary.CreateFileAsync("SimpleVideo.mp4", CreationCollisionOption.GenerateUniqueName)
|
||||
Dim videoFile = Await _captureFolder.CreateFileAsync("SimpleVideo.mp4", CreationCollisionOption.GenerateUniqueName)
|
||||
' Calculate rotation angle, taking mirroring into account if necessary
|
||||
Dim rotationAngle = 360 - ConvertDeviceOrientationToDegrees(GetCameraOrientation())
|
||||
_encodingProfile.Video.Properties(RotationKey) = PropertyValue.CreateInt32(rotationAngle)
|
||||
Debug.WriteLine("Starting recording...")
|
||||
Debug.WriteLine("Starting recording to " & videoFile.Path)
|
||||
Await _mediaCapture.StartRecordToStorageFileAsync(_encodingProfile, videoFile)
|
||||
_isRecording = True
|
||||
Debug.WriteLine("Started recording to: " & videoFile.Path)
|
||||
Debug.WriteLine("Started recording!")
|
||||
Catch ex As Exception
|
||||
Debug.WriteLine("Exception when starting video recording: {0}", ex.ToString())
|
||||
Debug.WriteLine("Exception when starting video recording: " & ex.ToString())
|
||||
End Try
|
||||
End Function
|
||||
|
||||
|
@ -454,6 +457,10 @@ Namespace Global.CameraVideoStabilization
|
|||
End If
|
||||
|
||||
RegisterEventHandlers()
|
||||
|
||||
Dim picturesLibrary = Await StorageLibrary.GetLibraryAsync(KnownLibraryId.Pictures)
|
||||
' Fall back to the local app storage if the Pictures Library is not available
|
||||
_captureFolder = If(picturesLibrary.SaveFolder, ApplicationData.Current.LocalFolder)
|
||||
End Function
|
||||
|
||||
''' <summary>
|
||||
|
|
|
@ -53,14 +53,15 @@ void MainPage::NotifyUserFileNotExist()
|
|||
NotifyUser("The file '" + Filename + "' does not exist. Use scenario one to create this file.", NotifyType::ErrorMessage);
|
||||
}
|
||||
|
||||
void MainPage::HandleFileNotFoundException(Platform::COMException^ e)
|
||||
// I/O errors are reported as exceptions.
|
||||
void MainPage::HandleIoException(Platform::COMException^ e, Platform::String^ description)
|
||||
{
|
||||
if (e->HResult == 0x80070002) // Catch FileNotExistException
|
||||
if (e->HResult == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
|
||||
{
|
||||
NotifyUserFileNotExist();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw e;
|
||||
NotifyUser(description + ": " + e->Message, NotifyType::ErrorMessage);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -74,7 +74,7 @@ namespace SDKTemplate
|
|||
void Initialize();
|
||||
void ValidateFile();
|
||||
void NotifyUserFileNotExist();
|
||||
void HandleFileNotFoundException(Platform::COMException^ e);
|
||||
void HandleIoException(Platform::COMException^ e, Platform::String^ description);
|
||||
|
||||
private:
|
||||
static Platform::Array<Scenario>^ scenariosInner;
|
||||
|
|
|
@ -44,7 +44,7 @@ void Scenario10::DeleteFileButton_Click(Object^ sender, RoutedEventArgs^ e)
|
|||
}
|
||||
catch (COMException^ ex)
|
||||
{
|
||||
rootPage->HandleFileNotFoundException(ex);
|
||||
rootPage->HandleIoException(ex, "Error deleting file '" + fileName + "'");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
using namespace SDKTemplate;
|
||||
|
||||
using namespace concurrency;
|
||||
using namespace Platform;
|
||||
using namespace Windows::Storage;
|
||||
using namespace Windows::UI::Xaml;
|
||||
|
||||
|
@ -28,11 +29,19 @@ Scenario1::Scenario1() : rootPage(MainPage::Current)
|
|||
void Scenario1::CreateFileButton_Click(Object^ sender, RoutedEventArgs^ e)
|
||||
{
|
||||
create_task(KnownFolders::GetFolderForUserAsync(nullptr /* current user */, KnownFolderId::PicturesLibrary)).then([this](StorageFolder^ picturesFolder)
|
||||
{
|
||||
return picturesFolder->CreateFileAsync(rootPage->Filename, CreationCollisionOption::ReplaceExisting);
|
||||
}).then([this](StorageFile^ file)
|
||||
}).then([this](task<StorageFile^> task)
|
||||
{
|
||||
rootPage->SampleFile = file;
|
||||
rootPage->NotifyUser("The file '" + file->Name + "' was created.", NotifyType::StatusMessage);
|
||||
try
|
||||
{
|
||||
StorageFile^ file = task.get();
|
||||
rootPage->SampleFile = file;
|
||||
rootPage->NotifyUser("The file '" + file->Name + "' was created.", NotifyType::StatusMessage);
|
||||
}
|
||||
catch (Exception^ e)
|
||||
{
|
||||
// I/O errors are reported as exceptions.
|
||||
rootPage->NotifyUser("Error creating file '" + MainPage::Filename + "': " + e->Message, NotifyType::ErrorMessage);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@ void Scenario3::WriteTextButton_Click(Object^ sender, RoutedEventArgs^ e)
|
|||
}
|
||||
catch (COMException^ ex)
|
||||
{
|
||||
rootPage->HandleFileNotFoundException(ex);
|
||||
rootPage->HandleIoException(ex, "Error writing to '" + file->Name + "'");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -74,7 +74,7 @@ void Scenario3::ReadTextButton_Click(Object^ sender, RoutedEventArgs^ e)
|
|||
}
|
||||
catch(COMException^ ex)
|
||||
{
|
||||
rootPage->HandleFileNotFoundException(ex);
|
||||
rootPage->HandleIoException(ex, "Error reading from '" + file->Name + "'");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -56,7 +56,7 @@ void Scenario4::WriteBytesButton_Click(Object^ sender, RoutedEventArgs^ e)
|
|||
}
|
||||
catch (COMException^ ex)
|
||||
{
|
||||
rootPage->HandleFileNotFoundException(ex);
|
||||
rootPage->HandleIoException(ex, "Error writing to '" + file->Name + "'");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -88,7 +88,7 @@ void Scenario4::ReadBytesButton_Click(Object^ sender, RoutedEventArgs^ e)
|
|||
}
|
||||
catch (COMException^ ex)
|
||||
{
|
||||
rootPage->HandleFileNotFoundException(ex);
|
||||
rootPage->HandleIoException(ex, "Error reading from '" + file->Name + "'");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -57,7 +57,7 @@ void Scenario5::WriteToStreamButton_Click(Object^ sender, RoutedEventArgs^ e)
|
|||
}
|
||||
catch (COMException^ ex)
|
||||
{
|
||||
rootPage->HandleFileNotFoundException(ex);
|
||||
rootPage->HandleIoException(ex, "Error writing to '" + file->Name + "'");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -101,7 +101,7 @@ void Scenario5::ReadFromStreamButton_Click(Object^ sender, RoutedEventArgs^ e)
|
|||
}
|
||||
catch (COMException^ ex)
|
||||
{
|
||||
rootPage->HandleFileNotFoundException(ex);
|
||||
rootPage->HandleIoException(ex, "Error reading from '" + file->Name + "'");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -47,22 +47,13 @@ void Scenario6::ShowPropertiesButton_Click(Object^ sender, RoutedEventArgs^ e)
|
|||
*outputText += "\nFile type: " + file->FileType;
|
||||
|
||||
// Get basic properties
|
||||
create_task(file->GetBasicPropertiesAsync()).then([this, outputText](task<BasicProperties^> task)
|
||||
create_task(file->GetBasicPropertiesAsync()).then([this, file, outputText](BasicProperties^ basicProperties)
|
||||
{
|
||||
try
|
||||
{
|
||||
BasicProperties^ basicProperties = task.get();
|
||||
*outputText += "\nFile size: " + basicProperties->Size.ToString() + " bytes";
|
||||
*outputText += "\nFile size: " + basicProperties->Size.ToString() + " bytes";
|
||||
|
||||
String^ dateModifiedString = dateFormat->Format(basicProperties->DateModified) + " " + timeFormat->Format(basicProperties->DateModified);
|
||||
*outputText += "\nDate modified: " + dateModifiedString;
|
||||
|
||||
String^ dateModifiedString = dateFormat->Format(basicProperties->DateModified) + " " + timeFormat->Format(basicProperties->DateModified);
|
||||
*outputText += "\nDate modified: " + dateModifiedString;
|
||||
}
|
||||
catch (COMException^ ex)
|
||||
{
|
||||
rootPage->HandleFileNotFoundException(ex);
|
||||
}
|
||||
}).then([this, file]()
|
||||
{
|
||||
// Get extra properties
|
||||
auto propertiesName = ref new Vector<String^>();
|
||||
propertiesName->Append(dateAccessedProperty);
|
||||
|
@ -83,6 +74,16 @@ void Scenario6::ShowPropertiesButton_Click(Object^ sender, RoutedEventArgs^ e)
|
|||
}
|
||||
|
||||
rootPage->NotifyUser(*outputText, NotifyType::StatusMessage);
|
||||
}).then([this, file](task<void> task)
|
||||
{
|
||||
try
|
||||
{
|
||||
task.get();
|
||||
}
|
||||
catch (COMException^ ex)
|
||||
{
|
||||
rootPage->HandleIoException(ex, "Error retrieving properties for '" + file->Name + "'");
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
|
|
|
@ -42,11 +42,26 @@ void Scenario7::AddToListButton_Click(Object^ sender, RoutedEventArgs^ e)
|
|||
rootPage->MruToken = StorageApplicationPermissions::MostRecentlyUsedList->Add(file, file->Name, visibility);
|
||||
rootPage->NotifyUser("The file '" + file->Name + "' was added to the MRU list and a token was stored.", NotifyType::StatusMessage);
|
||||
}
|
||||
else if (FALRadioButton->IsChecked->Value)
|
||||
else
|
||||
{
|
||||
// Add the file to the MRU
|
||||
rootPage->FalToken = StorageApplicationPermissions::FutureAccessList->Add(file, file->Name);
|
||||
rootPage->NotifyUser("The file '" + file->Name + "' was added to the FAL list and a token was stored.", NotifyType::StatusMessage);
|
||||
// Add the file to the FAL
|
||||
try
|
||||
{
|
||||
rootPage->FalToken = StorageApplicationPermissions::FutureAccessList->Add(file, file->Name);
|
||||
rootPage->NotifyUser("The file '" + file->Name + "' was added to the FAL list and a token was stored.", NotifyType::StatusMessage);
|
||||
}
|
||||
catch (COMException^ ex)
|
||||
{
|
||||
if (ex->HResult == FA_E_MAX_PERSISTED_ITEMS_REACHED)
|
||||
{
|
||||
// A real program would call Remove() to create room in the FAL.
|
||||
rootPage->NotifyUser("The file '" + file->Name + "' was not added to the FAL list because the FAL list is full.", NotifyType::ErrorMessage);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -57,115 +72,94 @@ void Scenario7::AddToListButton_Click(Object^ sender, RoutedEventArgs^ e)
|
|||
|
||||
void Scenario7::ShowListButton_Click(Object^ sender, RoutedEventArgs^ e)
|
||||
{
|
||||
StorageFile^ file = rootPage->SampleFile;
|
||||
if (file != nullptr)
|
||||
AccessListEntryView^ entries = nullptr;
|
||||
String^ listName;
|
||||
|
||||
if (MRURadioButton->IsChecked->Value)
|
||||
{
|
||||
String^ outputText;
|
||||
NotifyType statusOrError = NotifyType::StatusMessage;
|
||||
if (MRURadioButton->IsChecked->Value)
|
||||
{
|
||||
AccessListEntryView^ entries = StorageApplicationPermissions::MostRecentlyUsedList->Entries;
|
||||
if (entries->Size > 0)
|
||||
{
|
||||
outputText = "The MRU list contains the following item(s):";
|
||||
std::for_each(begin(entries), end(entries), [this, &outputText](const AccessListEntry& entry)
|
||||
{
|
||||
outputText += "\n" + entry.Metadata; // Application previously chose to store sampleFile->Name in this field
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
outputText = "The MRU list is empty, please select 'Most Recently Used' list and click 'Add to List' to add a file to the MRU list.";
|
||||
statusOrError = NotifyType::ErrorMessage;
|
||||
}
|
||||
}
|
||||
else if (FALRadioButton->IsChecked->Value)
|
||||
{
|
||||
AccessListEntryView^ entries = StorageApplicationPermissions::FutureAccessList->Entries;
|
||||
if (entries->Size > 0)
|
||||
{
|
||||
outputText = "The FAL list contains the following item(s):";
|
||||
std::for_each(begin(entries), end(entries), [this, &outputText](const AccessListEntry& entry)
|
||||
{
|
||||
outputText += "\n" + entry.Metadata; // Application previously chose to store sampleFile->Name in this field
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
outputText = "The FAL list is empty, please select 'Future Access List' list and click 'Add to List' to add a file to the FAL list.";
|
||||
statusOrError = NotifyType::ErrorMessage;
|
||||
}
|
||||
}
|
||||
rootPage->NotifyUser(outputText, statusOrError);
|
||||
listName = "MRU";
|
||||
entries = StorageApplicationPermissions::MostRecentlyUsedList->Entries;
|
||||
}
|
||||
else
|
||||
{
|
||||
rootPage->NotifyUserFileNotExist();
|
||||
listName = "FAL";
|
||||
entries = StorageApplicationPermissions::FutureAccessList->Entries;
|
||||
}
|
||||
|
||||
if (entries->Size > 0)
|
||||
{
|
||||
String^ outputText = "The " + listName + " + list contains the following item(s):";
|
||||
for (const AccessListEntry& entry : entries)
|
||||
{
|
||||
outputText += "\n" + entry.Metadata; // Application previously chose to store sampleFile->Name in this field
|
||||
}
|
||||
rootPage->NotifyUser(outputText, NotifyType::StatusMessage);
|
||||
}
|
||||
else
|
||||
{
|
||||
rootPage->NotifyUser("The " + listName + " list is empty.", NotifyType::ErrorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
void Scenario7::OpenFromListButton_Click(Object^ sender, RoutedEventArgs^ e)
|
||||
{
|
||||
StorageFile^ file = rootPage->SampleFile;
|
||||
if (file != nullptr)
|
||||
task<StorageFile^> fileTask = task_from_result<StorageFile^>(nullptr);
|
||||
|
||||
if (MRURadioButton->IsChecked->Value)
|
||||
{
|
||||
if (MRURadioButton->IsChecked->Value)
|
||||
if (rootPage->MruToken != nullptr)
|
||||
{
|
||||
if (rootPage->MruToken != nullptr)
|
||||
// Open the file via the token that was stored when adding this file into the MRU list
|
||||
fileTask = create_task(StorageApplicationPermissions::MostRecentlyUsedList->GetFileAsync(rootPage->MruToken)).then([this](task<StorageFile^> task)
|
||||
{
|
||||
// Open the file via the token that was stored when adding this file into the MRU list
|
||||
create_task(StorageApplicationPermissions::MostRecentlyUsedList->GetFileAsync(rootPage->MruToken)).then([this](task<StorageFile^> task)
|
||||
StorageFile^ file = nullptr;
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
StorageFile^ file = task.get();
|
||||
// Read the file
|
||||
create_task(FileIO::ReadTextAsync(file)).then([this, file](String^ fileContent)
|
||||
{
|
||||
rootPage->NotifyUser("The file '" + file->Name + "' was opened by a stored token from the MRU list, it contains the following text:\n" + fileContent, NotifyType::StatusMessage);
|
||||
});
|
||||
}
|
||||
catch (COMException^ ex)
|
||||
{
|
||||
rootPage->HandleFileNotFoundException(ex);
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
rootPage->NotifyUser("The MRU list is empty, please select 'Most Recently Used' list and click 'Add to List' to add a file to the MRU list.", NotifyType::ErrorMessage);
|
||||
}
|
||||
file = task.get();
|
||||
}
|
||||
catch (InvalidArgumentException^)
|
||||
{
|
||||
// When the MRU becomes full, older entries are automatically deleted.
|
||||
rootPage->NotifyUser("The token is no longer valid.", NotifyType::ErrorMessage);
|
||||
}
|
||||
return file;
|
||||
});
|
||||
}
|
||||
else if (FALRadioButton->IsChecked->Value)
|
||||
else
|
||||
{
|
||||
if (rootPage->FalToken != nullptr)
|
||||
{
|
||||
// Open the file via the token that was stored when adding this file into the FAL list
|
||||
create_task(StorageApplicationPermissions::FutureAccessList->GetFileAsync(rootPage->FalToken)).then([this](task<StorageFile^> task)
|
||||
{
|
||||
try
|
||||
{
|
||||
StorageFile^ file = task.get();
|
||||
// Read the file
|
||||
create_task(FileIO::ReadTextAsync(file)).then([this, file](String^ fileContent)
|
||||
{
|
||||
rootPage->NotifyUser("The file '" + file->Name + "' was opened by a stored token from the FAL list, it contains the following text:\n" + fileContent, NotifyType::StatusMessage);
|
||||
});
|
||||
}
|
||||
catch (COMException^ ex)
|
||||
{
|
||||
rootPage->HandleFileNotFoundException(ex);
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
rootPage->NotifyUser("The FAL list is empty, please select 'Future Access List' list and click 'Add to List' to add a file to the FAL list.", NotifyType::ErrorMessage);
|
||||
}
|
||||
rootPage->NotifyUser("This operation requires a token. Add file to the MRU list first.", NotifyType::ErrorMessage);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rootPage->NotifyUserFileNotExist();
|
||||
if (rootPage->FalToken != nullptr)
|
||||
{
|
||||
// Open the file via the token that was stored when adding this file into the FAL list
|
||||
fileTask = create_task(StorageApplicationPermissions::FutureAccessList->GetFileAsync(rootPage->FalToken));
|
||||
}
|
||||
else
|
||||
{
|
||||
rootPage->NotifyUser("This operation requires a token. Add file to the FAL list first.", NotifyType::ErrorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
fileTask.then([this](StorageFile^ file)
|
||||
{
|
||||
if (file != nullptr)
|
||||
{
|
||||
create_task(FileIO::ReadTextAsync(file)).then([this, file](task<String^> task)
|
||||
{
|
||||
try
|
||||
{
|
||||
String^ fileContent = task.get();
|
||||
rootPage->NotifyUser("The file '" + file->Name + "' was opened by a stored token. It contains the following text:\n" + fileContent, NotifyType::StatusMessage);
|
||||
}
|
||||
catch (COMException^ ex)
|
||||
{
|
||||
// I/O errors are reported as exceptions.
|
||||
rootPage->HandleIoException(ex, "Error reading file opened from list");
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@ void Scenario8::CopyFileButton_Click(Object^ sender, RoutedEventArgs^ e)
|
|||
}
|
||||
catch (COMException^ ex)
|
||||
{
|
||||
rootPage->HandleFileNotFoundException(ex);
|
||||
rootPage->HandleIoException(ex, "Error copying file '" + file->Name + "'");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -54,7 +54,7 @@ void Scenario9::CompareFilesButton_Click(Object^ sender, RoutedEventArgs^ e)
|
|||
}
|
||||
catch (COMException^ ex)
|
||||
{
|
||||
rootPage->HandleFileNotFoundException(ex);
|
||||
rootPage->HandleIoException(ex, "Error determining whether two files are the same");
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
|
@ -53,6 +53,11 @@ namespace SDKTemplate
|
|||
{
|
||||
rootPage.NotifyUserFileNotExist();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// I/O errors are reported as exceptions.
|
||||
rootPage.NotifyUser(String.Format("Error deleting file '{0}': {1}", file.Name, ex.Message), NotifyType.ErrorMessage);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче