本节将介绍如何使用照相设备进行拍照,并保存照片。
1. MediaCapture
winRT中使用MediaCapture类进型拍照和录制视频相关操作。具体该类的介绍参考https://msdn.microsoft.com/zh-cn/library/windows/apps/windows.media.capture.mediacapture.aspx。通过Mediacapture获取照相资源,由于照相资源在系统中是唯一的,所以我们必须在退出拍照页面和应用挂起时释放资源,否则在应用挂起时开启别的应用(如照相机)会出现资源被占用的情况而死机。具体流程如下:
1) 一般手机都有前置, 后置摄像头,具体使用哪个摄像头会根据应用的要求而不相同。所以首先,我们要根据需求来决定使用哪个摄像头. 如获取后置摄像头:
task<DeviceInformation^> PhotoCapturePage::GetCamera(Windows::Devices::Enumeration::Panel camera)
{
return create_task(DeviceInformation::FindAllAsync(DeviceClass::VideoCapture))
.then([camera](DeviceInformationCollection^ devices)->DeviceInformation^
{
DeviceInformation^ device = nullptr;
for (unsigned int i = 0; i < devices->Size; i++)
{
device = devices->GetAt(i);
if (device->EnclosureLocation != nullptr
&& device->EnclosureLocation->Panel == camera)
break;
}
return device;
});
}
2)接下来我们获取照相资源,并初始化:
task<void> PhotoCapturePage::InitPreview(Windows::Devices::Enumeration::DeviceInformation^ device)
{
MediaCaptureInitializationSettings^ settings = ref new MediaCaptureInitializationSettings();
settings->StreamingCaptureMode = StreamingCaptureMode::Video;
settings->PhotoCaptureSource = PhotoCaptureSource::Photo;
settings->AudioDeviceId = "";
settings->VideoDeviceId = device->Id;
return create_task(mediaCaptureMgr->InitializeAsync(settings));
}
3)初始化之后,就可以开始预览:
</pre><pre name="code" class="cpp">concurrency::task<void> PhotoCapturePage::StartPreview()
{
previewElement->Source = mediaCaptureMgr.Get();
mediaCaptureMgr->SetPreviewRotation(VideoRotation::Clockwise90Degrees);
return create_task(mediaCaptureMgr->StartPreviewAsync());
}
</pre>在预览时,我们需要将预览的内容呈现给用户,所以在xaml中定于CaptureElement用来显示预览内容:<p></p><p></p><pre name="code" class="cpp"><pre name="code" class="html"><CaptureElement x:Name="previewElement" Stretch="UniformToFill" Grid.RowSpan="3" Canvas.ZIndex="1"/>
那么我们何时申请照相资源,何时释放它呢?我们考虑进入一个页面依次触发的事件:OnNavigateTo->LoadState. 退出页面时:OnNavigateFrom->SaveState。所以我们可以在进入页面的事件中使用照相资源,在退出时释放。考虑到应用的挂起和恢复,挂起时触发事件OnNavigateFrom->SaveState, 恢复时OnResume. 在OnResume时也要重新申请资源。所以我们可以在LoadState事件中调用ScenarioInit():
void PhotoCapturePage::ScenarioInit()
{
mediaCaptureMgr = ref new MediaCapture();
isPreviewing = false;
previewElement->Source = nullptr;
GetCamera(Windows::Devices::Enumeration::Panel::Back)
.then([this](DeviceInformation^ device)
{
return InitPreview(device);
}).then([this]()
{
//return SetFocus();
})
.then([this](void)
{
if (mediaCaptureMgr->VideoDeviceController->FocusControl->Supported)
{
mediaCaptureMgr->VideoDeviceController->FlashControl->Enabled = false;
mediaCaptureMgr->VideoDeviceController->FlashControl->Auto = true;
}
return StartPreview();
}).then([this]()
{
return SetFocus();
//isPreviewing = true;
}).then([this]()
{
isPreviewing = true;
});
}
在SaveState,和Onresume事件中调用CleanMediaCapture():
concurrency::task<void> PhotoCapturePage::CleanMediaCapture()
{
task<void> op([](){});
if (mediaCaptureMgr.Get() != nullptr)
{
if (isPreviewing)
{
try
{
op = create_task(mediaCaptureMgr->StopPreviewAsync())
.then([this](void)
{
if (previewElement != nullptr)
previewElement->Source = nullptr;
// delete(mediaCaptureMgr.Get());
mediaCaptureMgr = nullptr;
isPreviewing = false;
});
}
catch (Exception^ e)
{
}
}
else {
//delete(mediaCaptureMgr.Get());
mediaCaptureMgr = nullptr;
isPreviewing = false;
}
}
return op;
}
2. 拍照并保存
void PhotoCapturePage::CapturePhoto()
{
ImageEncodingProperties^ format = ImageEncodingProperties::CreateJpeg();
inputStream = ref new InMemoryRandomAccessStream();
outputStream = ref new InMemoryRandomAccessStream();
try
{
create_task(mediaCaptureMgr->CapturePhotoToStreamAsync(format, inputStream))
.then([this]()
{
return BitmapDecoder::CreateAsync(inputStream);
}).then([=](BitmapDecoder^ decoder)
{
return BitmapEncoder::CreateForTranscodingAsync(outputStream, decoder);
}).then([=](BitmapEncoder^ encoder)
{
encoder->BitmapTransform->Rotation = BitmapRotation::Clockwise90Degrees;
return encoder->FlushAsync();
}).then([=]()
{
// Save the image
String^ fileName = CreateFileName();
photoFolder = KnownFolders::PicturesLibrary;
return photoFolder->CreateFileAsync(fileName, CreationCollisionOption::ReplaceExisting);
}).then([=](StorageFile^ file)
{
photoStorageFile = file;
// Store stream in file
return photoStorageFile->OpenAsync(FileAccessMode::ReadWrite);
}).then([=](IRandomAccessStream^ stream)
{
outputStream->Seek(0);
stream->Seek(0);
stream->Size = 0;
return RandomAccessStream::CopyAndCloseAsync(outputStream, stream);
}).then([=](long long result)
{
captureNum++;
captureNumTB->Text = captureNum.ToString();
vFileNames->Append(photoStorageFile->Name);
});
}
catch (Exception^ e)
{
}
}