手写识别,是指将在手写设备上书写时产生的有序轨迹信息化转化为汉字内码的过程,实际上是手写轨迹的坐标序列到汉字的内码的一个映射过程,是人机交互最自然、最方便的手段之一。
随着智能手机、掌上电脑等移动信息工具的普及,手写识别技术也进入了规模应用时代。
手写识别能够使用户按照最自然、最方便的输入方式进行文字输入,易学易用,可取代键盘或者鼠标。用于手写输入的设备有许多种,比如电磁感应手写板、压感式手写板、触摸屏、触控板、超声波笔等。
手写识别属于文字识别和模式识别范畴,文字识别从识别过程来说分成脱机识别(off-line)和联机识别(on-line)两大类,从识别对象来说又分成手写体识别和印刷体识别两大类,我们常说的手写识别是指联机手写体识别。
下面我们来亲自实践下Windows8下面的笔迹文档开发.
详细请见代码分析
#include "pch.h" #include <ppltasks.h> #include "simpleInk.h" /////////////////////////////////////////////////////////////////////////////// // simpleInk实施 simpleInk::simpleInk( _In_ Windows::UI::Core::CoreWindow^ window, _In_ Windows::ApplicationModel::Core::CoreApplicationView^ applicationView) : _applicationView(applicationView), _points(nullptr), _curPointIndex(0), _pointerId(-1) { Initialize(window, Windows::Graphics::Display::DisplayProperties::LogicalDpi); // 设置激活处理程序 _tokenViewActivated = _applicationView->Activated::add( ref new Windows::Foundation::TypedEventHandler< Windows::ApplicationModel::Core::CoreApplicationView^, Windows::ApplicationModel::Activation::IActivatedEventArgs^>( this, &simpleInk::OnViewActivated)); // 设置窗口的事件处理程序 m_window->PointerCursor = ref new Windows::UI::Core::CoreCursor( Windows::UI::Core::CoreCursorType::Arrow, 0); _tokenWindowActivated = m_window->Activated::add( ref new Windows::Foundation::TypedEventHandler< Windows::UI::Core::CoreWindow^, Windows::UI::Core::WindowActivatedEventArgs^>( this, &simpleInk::OnWindowActivated)); _tokenWindowSizeChanged = m_window->SizeChanged::add( ref new Windows::Foundation::TypedEventHandler< Windows::UI::Core::CoreWindow^, Windows::UI::Core::WindowSizeChangedEventArgs^>( this, &simpleInk::OnWindowSizeChanged)); _tokenCharacterReceived = m_window->CharacterReceived::add( ref new Windows::Foundation::TypedEventHandler< Windows::UI::Core::CoreWindow^, Windows::UI::Core::CharacterReceivedEventArgs^>( this, &simpleInk::OnCharacterReceived)); _tokenPointerPressed = m_window->PointerPressed::add( ref new Windows::Foundation::TypedEventHandler< Windows::UI::Core::CoreWindow^, Windows::UI::Core::PointerEventArgs^>( this, &simpleInk::OnPointerPressed)); _tokenPointerMoved = m_window->PointerMoved::add( ref new Windows::Foundation::TypedEventHandler< Windows::UI::Core::CoreWindow^, Windows::UI::Core::PointerEventArgs^>( this, &simpleInk::OnPointerMoved)); _tokenPointerReleased = m_window->PointerReleased::add( ref new Windows::Foundation::TypedEventHandler< Windows::UI::Core::CoreWindow^, Windows::UI::Core::PointerEventArgs^>( this, &simpleInk::OnPointerReleased)); _recognitionText = ""; _strokeBuilder = ref new Windows::UI::Input::Inking::InkStrokeBuilder(); _strokeContainer = ref new Windows::UI::Input::Inking::InkStrokeContainer(); _recognizerContainer = ref new Windows::UI::Input::Inking::InkRecognizerContainer(); // 检测识别引擎并将第一个为默认 _recognizerId = 0; _recognizer = _recognizerContainer->GetRecognizers()->GetAt(_recognizerId); _recognizerContainer->SetDefaultRecognizer(_recognizer); _drawingAttributes = ref new Windows::UI::Input::Inking::InkDrawingAttributes(); _drawingAttributes->Color = Windows::UI::Colors::Black; _drawingAttributes->PenTip = Windows::UI::Input::Inking::PenTipShape::Circle; Windows::Foundation::Size size; size.Width = 3.0f; _drawingAttributes->Size = size; _drawingAttributes->IgnorePressure = true; _drawingAttributes->FitToCurve = true; _strokeBuilder->SetDefaultDrawingAttributes(_drawingAttributes); CreateBrush(_drawingAttributes->Color, &_currentBrush); } simpleInk::~simpleInk() { // Remove all the window event handlers m_window->Activated::remove(_tokenWindowActivated); m_window->SizeChanged::remove(_tokenWindowSizeChanged); m_window->CharacterReceived::remove(_tokenCharacterReceived); m_window->PointerPressed::remove(_tokenPointerPressed); m_window->PointerMoved::remove(_tokenPointerMoved); m_window->PointerReleased::remove(_tokenPointerReleased); m_window->PointerWheelChanged::remove(_tokenPointerWheelChanged); // 删除所有窗口的事件处理程序 _applicationView->Activated::remove(_tokenViewActivated); // 除视图激活处理程序 m_d2dContext->SetTarget(nullptr); m_d2dContext = nullptr; m_d2dDevice = nullptr; m_d2dFactory = nullptr; m_d2dTargetBitmap = nullptr; m_d3dContext = nullptr; m_d3dDevice = nullptr; m_depthStencilView = nullptr; m_dwriteFactory = nullptr; m_renderTargetView = nullptr; m_swapChain = nullptr; m_wicFactory = nullptr; _blackBrush = nullptr; _currentBrush = nullptr; _eventTextFormat = nullptr; _points = nullptr; _recognitionText = nullptr; _strokeBuilder = nullptr; _strokeContainer = nullptr; _recognizerContainer = nullptr; _recognizer = nullptr; _drawingAttributes = nullptr; } void simpleInk::Run() { // 激活窗口,以便将可见。 m_window->Activate(); // 处理所有的事件,如果存在 m_window->Dispatcher->ProcessEvents(Windows::UI::Core::CoreProcessEventsOption::ProcessUntilQuit); } // // 视图激活处理程序中的应用 // void simpleInk::OnViewActivated(_In_ Windows::ApplicationModel::Core::CoreApplicationView^, _In_ Windows::ApplicationModel::Activation::IActivatedEventArgs^) { m_window->Activate(); } // // 事件处理程序 // void simpleInk::OnWindowActivated(_In_ Windows::UI::Core::CoreWindow^, _In_ Windows::UI::Core::WindowActivatedEventArgs^) { RenderOnAllBuffers(); } void simpleInk::OnWindowSizeChanged(_In_ Windows::UI::Core::CoreWindow^, _In_ Windows::UI::Core::WindowSizeChangedEventArgs^) { UpdateForWindowSizeChange(); RenderOnAllBuffers(); } void simpleInk::OnCharacterReceived(_In_ Windows::UI::Core::CoreWindow^, _In_ Windows::UI::Core::CharacterReceivedEventArgs^ args) { switch (args->KeyCode) { case 3: // ctrl+c 复制处理程序 OnCopyToClipboard(); break; case 20: // ctrl+t, 复制文字处理程序 OnCopyTextToClipboard(); break; case 22: // ctrl+v, 粘贴处理程序 OnPasteFromClipboard(); break; case 19: // ctrl+s, 保存处理程序 OnSave(); break; case 15: // ctrl+o,公开处理程序 OnLoad(); break; case 1: // ctrl+a, 选择所有的处理程序 OnSelectAll(); break; case 8: //退格,删除处理程序 OnDelete(); break; case 4: // crtl+d, 更改绘图属性 OnChangeDrawingAttributes(); break; case 18: // crtl+r, 改变识别引擎 OnChangeRecognizer(); break; case 32: // space, 识别 OnRecognize(); break; } } void simpleInk::OnPointerPressed(_In_ Windows::UI::Core::CoreWindow^, _In_ Windows::UI::Core::PointerEventArgs^ args) { Windows::UI::Input::PointerPoint^ pointerPoint = args->CurrentPoint; //确保没有指针已经是墨(我们允许在一个时间只有一个“积极的”指针) //确保指针在墨模式(笔,没有按钮,或鼠标左键下) if (_pointerId == -1 && PointerIsInking(pointerPoint)) { // 笔迹书写第一点 _strokeBuilder->BeginStroke(pointerPoint); // 初始化变量用来保持轨道线呈现在不同的缓冲区. // 欲了解更多信息的地方是在头文件中声明_points看到评论e. _points = ref new Platform::Array<Windows::UI::Input::PointerPoint^>(NUM_BUFFERS + 1); _curPointIndex = 0; _points[_curPointIndex] = pointerPoint; _pointerId = pointerPoint->PointerId; // save pointer id so that no other pointer can ink until this one it is released } } void simpleInk::OnPointerMoved(_In_ Windows::UI::Core::CoreWindow^, _In_ Windows::UI::Core::PointerEventArgs^ args) { Windows::UI::Input::PointerPoint^ pointerPoint = args->CurrentPoint; // 确保开始书写 if (_pointerId == (int) pointerPoint->PointerId) { // 取中间点 Windows::Foundation::Collections::IVector<Windows::UI::Input::PointerPoint^>^ pointerPoints = args->GetIntermediatePoints(); // 更新笔迹 for (unsigned int i = 0; i < pointerPoints->Size; i++) { _strokeBuilder->AppendToStroke(pointerPoints->GetAt(i)); } // 实时渲染 // 保存新的起点,并呈现新线,以及线提供的其他缓冲区。 _curPointIndex = (_curPointIndex + 1) % _points->Length; _points[_curPointIndex] = pointerPoint; for (unsigned int i = 1; i < _points->Length; i++) { unsigned int si = (i + _curPointIndex) % _points->Length; unsigned int ei = (si + 1) % _points->Length; if (nullptr != _points[si] && nullptr != _points[ei]) { RenderLine(_points[si]->Position, _points[ei]->Position); } } Present(); } } void simpleInk::OnPointerReleased(_In_ Windows::UI::Core::CoreWindow^, _In_ Windows::UI::Core::PointerEventArgs^ args) { Windows::UI::Input::PointerPoint^ pointerPoint = args->CurrentPoint; // 确保该事件属于指针 if (_pointerId == (int) pointerPoint->PointerId) { //这是最后一点 Windows::UI::Input::Inking::InkStroke^ stroke = _strokeBuilder->EndStroke(pointerPoint); //添加笔迹容器 _strokeContainer->AddStroke(stroke); // 准备好了,没有实时渲染的需要,重新渲染整个场景 RenderOnAllBuffers(); // 改变未来中风的颜色和宽度 OnChangeDrawingAttributes(); _points = nullptr; // 退出实时模式 _pointerId = -1; //退出时删除对象 } } void simpleInk::OnCopyToClipboard() { Windows::Foundation::Collections::IVectorView<Windows::UI::Input::Inking::IInkStroke^>^ inkStrokes = _strokeContainer->GetStrokes(); bool someSelected = false; for(unsigned int i = 0; i < inkStrokes->Size; i++) { if (inkStrokes->GetAt(i)->Selected) { someSelected = true; break; } } if (someSelected) { _strokeContainer->CopySelectedToClipboard(); } else { for(unsigned int i = 0; i < inkStrokes->Size; i++) { inkStrokes->GetAt(i)->Selected = true; } _strokeContainer->CopySelectedToClipboard(); for(unsigned int i = 0; i < inkStrokes->Size; i++) { inkStrokes->GetAt(i)->Selected = false; } } } void simpleInk::OnCopyTextToClipboard() { Windows::ApplicationModel::DataTransfer::DataPackage^ dataPackage = ref new Windows::ApplicationModel::DataTransfer::DataPackage(); dataPackage->SetText(_recognitionText); Windows::ApplicationModel::DataTransfer::Clipboard::SetContent(dataPackage); } void simpleInk::OnPasteFromClipboard() { bool canPaste = _strokeContainer->CanPasteFromClipboard(); if (canPaste) { Windows::Foundation::Point position; position.X = 100.0f; position.Y = 100.0f; _strokeContainer->PasteFromClipboard(position); RenderOnAllBuffers(); } else { } } void simpleInk::OnSave() { Windows::Storage::Pickers::FileSavePicker^ savePicker = ref new Windows::Storage::Pickers::FileSavePicker(); savePicker->SuggestedStartLocation = Windows::Storage::Pickers::PickerLocationId::PicturesLibrary; auto extension = ref new Platform::Collections::Vector<Platform::String^>; extension->Append(".gif"); savePicker->FileTypeChoices->Insert("Gif with embedded ISF", extension); savePicker->DefaultFileExtension = ".gif"; concurrency::task<Windows::Storage::StorageFile^> savePickerTask(savePicker->PickSaveFileAsync()); savePickerTask.then([this] (Windows::Storage::StorageFile^ file) { if (nullptr != file) { concurrency::task<Windows::Storage::Streams::IRandomAccessStream^> openFileTask(file->OpenAsync(Windows::Storage::FileAccessMode::ReadWrite)); openFileTask.then([this] (Windows::Storage::Streams::IRandomAccessStream^ stream) { concurrency::task<unsigned int> saveTask(_strokeContainer->SaveAsync(stream)); saveTask.then([stream] (unsigned int) { concurrency::task<bool> flushTask(stream->FlushAsync()); flushTask.then([] (bool) { // done! }); }); }); } }); } void simpleInk::OnLoad() { Windows::Storage::Pickers::FileOpenPicker^ openPicker = ref new Windows::Storage::Pickers::FileOpenPicker(); openPicker->SuggestedStartLocation = Windows::Storage::Pickers::PickerLocationId::PicturesLibrary; openPicker->FileTypeFilter->Append(".gif"); concurrency::task<Windows::Storage::StorageFile^> openPickerTask(openPicker->PickSingleFileAsync()); openPickerTask.then([this] (Windows::Storage::StorageFile^ file) { if (nullptr != file) { concurrency::task<Windows::Storage::Streams::IRandomAccessStream^> openFileTask(file->OpenAsync(Windows::Storage::FileAccessMode::Read)); openFileTask.then([this] (Windows::Storage::Streams::IRandomAccessStream^ stream) { concurrency::task<void> loadTask(_strokeContainer->LoadAsync(stream)); loadTask.then([this] (void) { RenderOnAllBuffers(); }); }); } }); } void simpleInk::OnSelectAll() { Windows::Foundation::Collections::IVectorView<Windows::UI::Input::Inking::IInkStroke^>^ inkStrokes = _strokeContainer->GetStrokes(); for(unsigned int i = 0; i < inkStrokes->Size; i++) { inkStrokes->GetAt(i)->Selected = true; } RenderOnAllBuffers(); } void simpleInk::OnDelete() { Windows::Foundation::Collections::IVectorView<Windows::UI::Input::Inking::IInkStroke^>^ inkStrokes = _strokeContainer->GetStrokes(); bool someSelected = false; for(unsigned int i = 0; i < inkStrokes->Size; i++) { if (inkStrokes->GetAt(i)->Selected) { someSelected = true; break; } } if (someSelected) { _strokeContainer->DeleteSelected(); } else { for(unsigned int i = 0; i < inkStrokes->Size; i++) { inkStrokes->GetAt(i)->Selected = true; } _strokeContainer->DeleteSelected(); } RenderOnAllBuffers(); } void simpleInk::OnChangeDrawingAttributes() { _drawingAttributes->Color = Windows::UI::ColorHelper::FromArgb(255, rand() & 0xf0, rand() & 0xf0, rand() & 0xf0); Windows::Foundation::Size size; size.Width = (rand() & 0x07) * 1.0f + 1.0f; _drawingAttributes->Size = size; _strokeBuilder->SetDefaultDrawingAttributes(_drawingAttributes); CreateBrush(_drawingAttributes->Color, &_currentBrush); } void simpleInk::OnChangeRecognizer() { _recognizerId++; if (_recognizerId >= _recognizerContainer->GetRecognizers()->Size) { _recognizerId = 0; } _recognizerContainer->SetDefaultRecognizer(_recognizerContainer->GetRecognizers()->GetAt(_recognizerId)); RenderOnAllBuffers(); } void simpleInk::OnRecognize() { _recognitionText = ""; Windows::Foundation::Collections::IVectorView<Windows::UI::Input::Inking::IInkStroke^>^ inkStrokes = _strokeContainer->GetStrokes(); if (0 == inkStrokes->Size) { RenderOnAllBuffers(); return; } Windows::UI::Input::Inking::InkRecognitionTarget target = Windows::UI::Input::Inking::InkRecognitionTarget::All; for(unsigned int i = 0; i < inkStrokes->Size; i++) { if (inkStrokes->GetAt(i)->Selected) { target = Windows::UI::Input::Inking::InkRecognitionTarget::Selected; break; } } concurrency::task<Windows::Foundation::Collections::IVectorView<Windows::UI::Input::Inking::IInkRecognitionResult^>^> recognizeTask(_recognizerContainer->RecognizeAsync(_strokeContainer, target)); recognizeTask.then([this] (Windows::Foundation::Collections::IVectorView<Windows::UI::Input::Inking::IInkRecognitionResult^>^ recognitionResults) { _strokeContainer->UpdateRecognitionResults(recognitionResults); Windows::Foundation::Collections::IVectorView<Windows::UI::Input::Inking::IInkRecognitionResult^>^ updatedRecognitionResults = _strokeContainer->GetRecognitionResults(); for(unsigned int i = 0; i < updatedRecognitionResults->Size; i++) { Windows::UI::Input::Inking::IInkRecognitionResult^ recognitionResult = updatedRecognitionResults->GetAt(i); Windows::Foundation::Collections::IVectorView<Platform::String^>^ textCandidates = recognitionResult->GetTextCandidates(); Platform::String^ topCandidate = textCandidates->GetAt(0); _recognitionText += topCandidate + " "; } RenderOnAllBuffers(); }); } void simpleInk::RenderLine(Windows::Foundation::Point from, Windows::Foundation::Point to) { m_d2dContext->BeginDraw(); m_d2dContext->SetTransform(D2D1::Matrix3x2F::Identity()); float width = _drawingAttributes->Size.Width; m_d2dContext->DrawLine(D2D1::Point2F(from.X, from.Y), D2D1::Point2F(to.X, to.Y), _currentBrush.Get(), width, (ID2D1StrokeStyle *) 0); HRESULT hr = m_d2dContext->EndDraw(); if (hr == D2DERR_RECREATE_TARGET) { m_d2dContext->SetTarget(nullptr); m_d2dTargetBitmap = nullptr; CreateWindowSizeDependentResources(); } else { DX::ThrowIfFailed(hr); } } void simpleInk::ConvertStrokeToGeometry(_In_ Windows::UI::Input::Inking::IInkStroke^ stroke, _Outptr_ ID2D1PathGeometry** geometry) { DX::ThrowIfFailed(m_d2dFactory->CreatePathGeometry(geometry)); Microsoft::WRL::ComPtr<ID2D1GeometrySink> sink; DX::ThrowIfFailed((*geometry)->Open(&sink)); sink->SetSegmentFlags(D2D1_PATH_SEGMENT_FORCE_ROUND_LINE_JOIN); sink->SetFillMode(D2D1_FILL_MODE_ALTERNATE); Windows::Foundation::Collections::IVectorView<Windows::UI::Input::Inking::IInkStrokeRenderingSegment^>^ renderingSegments = stroke->GetRenderingSegments(); Windows::UI::Input::Inking::IInkStrokeRenderingSegment^ firstSegment = renderingSegments->GetAt(0); Windows::Foundation::Point first = firstSegment->Position; sink->BeginFigure(D2D1::Point2F(first.X, first.Y), D2D1_FIGURE_BEGIN_FILLED); for (unsigned int j = 1; j < renderingSegments->Size; j++) { Windows::UI::Input::Inking::IInkStrokeRenderingSegment^ renderingSegment = renderingSegments->GetAt(j); sink->AddBezier( D2D1::BezierSegment( D2D1::Point2F(renderingSegment->BezierControlPoint1.X, renderingSegment->BezierControlPoint1.Y), D2D1::Point2F(renderingSegment->BezierControlPoint2.X, renderingSegment->BezierControlPoint2.Y), D2D1::Point2F(renderingSegment->Position.X, renderingSegment->Position.Y) ) ); } sink->EndFigure(D2D1_FIGURE_END_OPEN); DX::ThrowIfFailed(sink->Close()); } void simpleInk::OnRender() { // drawing m_d2dContext->BeginDraw(); m_d2dContext->SetTransform(D2D1::Matrix3x2F::Identity()); m_d2dContext->Clear(D2D1::ColorF(D2D1::ColorF::White)); // render all strokes Windows::Foundation::Collections::IVectorView<Windows::UI::Input::Inking::IInkStroke^>^ inkStrokes = _strokeContainer->GetStrokes(); for(unsigned int i = 0; i < inkStrokes->Size; i++) { Windows::UI::Input::Inking::IInkStroke^ stroke = inkStrokes->GetAt(i); Microsoft::WRL::ComPtr<ID2D1PathGeometry> strokeGeometry; ConvertStrokeToGeometry(stroke, &strokeGeometry); float width = stroke->DrawingAttributes->Size.Width; int color = RGB(stroke->DrawingAttributes->Color.R, stroke->DrawingAttributes->Color.G, stroke->DrawingAttributes->Color.B); Microsoft::WRL::ComPtr<ID2D1SolidColorBrush> currentBrush; DX::ThrowIfFailed(m_d2dContext->CreateSolidColorBrush(D2D1::ColorF(color), ¤tBrush)); m_d2dContext->DrawGeometry(strokeGeometry.Get(), currentBrush.Get(), width, (ID2D1StrokeStyle *) 0); } D2D1_RECT_F recoTextRect = {0, 50, 1000, 500}; m_d2dContext->DrawText(_recognitionText->Begin(), _recognitionText->Length(), _eventTextFormat.Get(), &recoTextRect, _blackBrush.Get()); D2D1_RECT_F recoNameRect = {0, 0, 1000, 500}; Platform::String^ name = _recognizerContainer->GetRecognizers()->GetAt(_recognizerId)->Name; m_d2dContext->DrawText(name->Begin(), name->Length(), _eventTextFormat.Get(), &recoNameRect, _blackBrush.Get()); HRESULT hr = m_d2dContext->EndDraw(); if (hr == D2DERR_RECREATE_TARGET) { m_d2dContext->SetTarget(nullptr); m_d2dTargetBitmap = nullptr; CreateWindowSizeDependentResources(); } else { DX::ThrowIfFailed(hr); } Present(); } void simpleInk::RenderOnAllBuffers() { for (unsigned int i = 0; i < NUM_BUFFERS; i++) { OnRender(); } } void simpleInk::CreateBrush(_In_ Windows::UI::Color color, _Outptr_ ID2D1SolidColorBrush** brush) { int iColor = RGB(color.R, color.G, color.B); *brush = nullptr; DX::ThrowIfFailed( m_d2dContext->CreateSolidColorBrush( D2D1::ColorF(iColor), brush ) ); } void simpleInk::CreateDeviceResources() { DirectXBase::CreateDeviceResources(); DX::ThrowIfFailed( m_dwriteFactory->CreateTextFormat(L"Verdana", NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, 20.0f, L"", &_eventTextFormat)); _eventTextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_LEADING); _eventTextFormat->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_NEAR); CreateBrush(Windows::UI::Colors::Black, &_blackBrush); } void simpleInk::CreateWindowSizeDependentResources() { m_windowBounds = m_window->Bounds; // If the swap chain already exists, resize it. if(m_swapChain != nullptr) { DX::ThrowIfFailed( m_swapChain->ResizeBuffers(NUM_BUFFERS, 0, 0, DXGI_FORMAT_B8G8R8A8_UNORM, 0) ); } // Otherwise, create a new one. else { // Allocate a descriptor. DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {0}; swapChainDesc.Width = 0; swapChainDesc.Height = 0; swapChainDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; swapChainDesc.Stereo = false; swapChainDesc.SampleDesc.Count = 1; swapChainDesc.SampleDesc.Quality = 0; swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; swapChainDesc.BufferCount = NUM_BUFFERS; swapChainDesc.Scaling = DXGI_SCALING_NONE; swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; swapChainDesc.Flags = 0; Microsoft::WRL::ComPtr<IDXGIDevice1> dxgiDevice; DX::ThrowIfFailed( m_d3dDevice.As(&dxgiDevice) ); Microsoft::WRL::ComPtr<IDXGIAdapter> dxgiAdapter; DX::ThrowIfFailed( dxgiDevice->GetAdapter(&dxgiAdapter) ); Microsoft::WRL::ComPtr<IDXGIFactory2> dxgiFactory; DX::ThrowIfFailed( dxgiAdapter->GetParent( __uuidof(IDXGIFactory2), &dxgiFactory ) ); DX::ThrowIfFailed( dxgiFactory->CreateSwapChainForCoreWindow( m_d3dDevice.Get(), reinterpret_cast<IUnknown*>(m_window), &swapChainDesc, nullptr, &m_swapChain ) ); DX::ThrowIfFailed( dxgiDevice->SetMaximumFrameLatency(MAX_FRAME_LATENCY) ); } Microsoft::WRL::ComPtr<ID3D11Texture2D> backBuffer; DX::ThrowIfFailed( m_swapChain->GetBuffer( 0, __uuidof(ID3D11Texture2D), &backBuffer ) ); DX::ThrowIfFailed( m_d3dDevice->CreateRenderTargetView( backBuffer.Get(), nullptr, &m_renderTargetView ) ); D3D11_TEXTURE2D_DESC backBufferDesc = {0}; backBuffer->GetDesc(&backBufferDesc); m_renderTargetSize.Width = static_cast<float>(backBufferDesc.Width); m_renderTargetSize.Height = static_cast<float>(backBufferDesc.Height); CD3D11_TEXTURE2D_DESC depthStencilDesc( DXGI_FORMAT_D24_UNORM_S8_UINT, backBufferDesc.Width, backBufferDesc.Height, 1, 1, D3D11_BIND_DEPTH_STENCIL ); Microsoft::WRL::ComPtr<ID3D11Texture2D> depthStencil; DX::ThrowIfFailed( m_d3dDevice->CreateTexture2D( &depthStencilDesc, nullptr, &depthStencil ) ); DX::ThrowIfFailed( m_d3dDevice->CreateDepthStencilView( depthStencil.Get(), &CD3D11_DEPTH_STENCIL_VIEW_DESC(D3D11_DSV_DIMENSION_TEXTURE2D), &m_depthStencilView ) ); CD3D11_VIEWPORT viewport( 0.0f, 0.0f, static_cast<float>(backBufferDesc.Width), static_cast<float>(backBufferDesc.Height) ); m_d3dContext->RSSetViewports(1, &viewport); D2D1_BITMAP_PROPERTIES1 bitmapProperties = D2D1::BitmapProperties1( D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW, D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED), m_dpi, m_dpi ); Microsoft::WRL::ComPtr<IDXGISurface> dxgiBackBuffer; DX::ThrowIfFailed( m_swapChain->GetBuffer( 0, __uuidof(IDXGISurface), &dxgiBackBuffer ) ); DX::ThrowIfFailed( m_d2dContext->CreateBitmapFromDxgiSurface( dxgiBackBuffer.Get(), &bitmapProperties, &m_d2dTargetBitmap ) ); m_d2dContext->SetTarget(m_d2dTargetBitmap.Get()); m_d2dContext->SetTextAntialiasMode(D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE); } void simpleInk::Present() { // 设置写字的参数 DXGI_PRESENT_PARAMETERS parameters = {0}; parameters.DirtyRectsCount = 0; parameters.pDirtyRects = nullptr; parameters.pScrollRect = nullptr; parameters.pScrollOffset = nullptr; // 设置窗口句柄 HRESULT hr = m_swapChain->Present1(0, 0, ¶meters); // 如果设备没有准备好,将返回失败 if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET) { Initialize(m_window, m_dpi); } else { DX::ThrowIfFailed(hr); } } /////////////////////////////////////////////////////////////////////////////// // 视图框架 simpleInkFrameworkView::simpleInkFrameworkView() : _activationEntryPoint(ActivationEntryPoint::Unknown), _window(nullptr), _applicationView(nullptr) { } void simpleInkFrameworkView::Initialize(_In_ Windows::ApplicationModel::Core::CoreApplicationView^ applicationView) { // 初始化程序视图 _applicationView = applicationView; } void simpleInkFrameworkView::SetWindow(_In_ Windows::UI::Core::CoreWindow^ window) { // 设置窗口句柄 _window = window; } void simpleInkFrameworkView::Load(Platform::String^ entryPoint) { if (entryPoint == "simpleInk.App") { _activationEntryPoint = ActivationEntryPoint::simpleInk; } } void simpleInkFrameworkView::Run() { if (_activationEntryPoint == ActivationEntryPoint::simpleInk) { simpleInk^ view = ref new simpleInk(_window, _applicationView); view->Run(); } else { DX::ThrowIfFailed(E_UNEXPECTED); } } void simpleInkFrameworkView::Uninitialize() { } Windows::ApplicationModel::Core::IFrameworkView^ simpleInkFrameworkViewSource::CreateView() { return ref new simpleInkFrameworkView(); } /////////////////////////////////////////////////////////////////////////////// // 程序入口 // 程序初始化 [Platform::MTAThread] int main(Platform::Array<Platform::String^>^) { auto frameworkViewSource = ref new simpleInkFrameworkViewSource(); return Windows::ApplicationModel::Core::CoreApplication::Run(frameworkViewSource); }
我们亲自来实践运行看效果
识别效果
赶紧下载VS11体验吧
http://www.microsoft.com/click/services/Redirect2.ashx?CR_CC=200098144