diff options
Diffstat (limited to 'platform/winrt')
-rw-r--r-- | platform/winrt/mupdf_cpp/MainPage.xaml.cpp | 628 | ||||
-rw-r--r-- | platform/winrt/mupdf_cpp/MainPage.xaml.h | 57 | ||||
-rw-r--r-- | platform/winrt/mupdf_cpp/PrintPage.cpp | 165 | ||||
-rw-r--r-- | platform/winrt/mupdf_cpp/PrintPage.h | 57 | ||||
-rw-r--r-- | platform/winrt/mupdf_cpp/mupdf_cpp.vcxproj | 4 | ||||
-rw-r--r-- | platform/winrt/mupdf_cpp/mupdf_cpp.vcxproj.filters | 2 | ||||
-rw-r--r-- | platform/winrt/mupdf_cpp/pch.h | 9 | ||||
-rw-r--r-- | platform/winrt/mupdfwinrt/muctx.cpp | 19 | ||||
-rw-r--r-- | platform/winrt/mupdfwinrt/muctx.h | 5 | ||||
-rw-r--r-- | platform/winrt/mupdfwinrt/mudocument.cpp | 49 | ||||
-rw-r--r-- | platform/winrt/mupdfwinrt/mudocument.h | 2 |
11 files changed, 654 insertions, 343 deletions
diff --git a/platform/winrt/mupdf_cpp/MainPage.xaml.cpp b/platform/winrt/mupdf_cpp/MainPage.xaml.cpp index 36becdaa..9ef47e76 100644 --- a/platform/winrt/mupdf_cpp/MainPage.xaml.cpp +++ b/platform/winrt/mupdf_cpp/MainPage.xaml.cpp @@ -92,11 +92,12 @@ MainPage::MainPage() m_linkcolor="#40AC7225"; mu_doc = nullptr; m_docPages = ref new Platform::Collections::Vector<DocumentPage^>(); - m_printpages = ref new Platform::Collections::Vector<DocumentPage^>(); m_thumbnails = ref new Platform::Collections::Vector<DocumentPage^>(); m_page_link_list = ref new Platform::Collections::Vector<IVector<RectList^>^>(); m_text_list = ref new Platform::Collections::Vector<RectList^>(); m_linkset = ref new Platform::Collections::Vector<int>(); + + SetUpDirectX(); RegisterForPrinting(); CleanUp(); RecordMainThread(); @@ -104,6 +105,44 @@ MainPage::MainPage() _pageLoadedHandlerToken = Loaded += ref new RoutedEventHandler(this, &MainPage::Page_Loaded); } +/* You need a Direct3D device to create a Direct2D device. This gets stuff + set up for Direct2D printing support */ +void MainPage::SetUpDirectX() +{ + UINT creation_flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT; + ComPtr<IDXGIDevice> dxgi_device; + D2D1_FACTORY_OPTIONS options; + ZeroMemory(&options, sizeof(D2D1_FACTORY_OPTIONS)); + D3D_FEATURE_LEVEL feature_levels[] = + { + D3D_FEATURE_LEVEL_11_1, + D3D_FEATURE_LEVEL_11_0, + D3D_FEATURE_LEVEL_10_1, + D3D_FEATURE_LEVEL_10_0, + D3D_FEATURE_LEVEL_9_3, + D3D_FEATURE_LEVEL_9_2, + D3D_FEATURE_LEVEL_9_1 + }; + ComPtr<ID3D11Device> device; + ComPtr<ID3D11DeviceContext> context; + +#if defined(_DEBUG) + options.debugLevel = D2D1_DEBUG_LEVEL_INFORMATION; +#endif + + ThrowIfFailed(D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, 0, + creation_flags, feature_levels, ARRAYSIZE(feature_levels), + D3D11_SDK_VERSION, &device, &m_featureLevel, &context)); + ThrowIfFailed(device.As(&m_d3d_device)); + ThrowIfFailed(context.As(&m_d3d_context)); + ThrowIfFailed(m_d3d_device.As(&dxgi_device)); + ThrowIfFailed(D2D1CreateFactory(D2D1_FACTORY_TYPE_MULTI_THREADED, + __uuidof(ID2D1Factory1), &options, &m_d2d_factory)); + ThrowIfFailed(CoCreateInstance(CLSID_WICImagingFactory, nullptr, + CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&m_wic_factory))); + m_d2d_factory->CreateDevice(dxgi_device.Get(), &m_d2d_device); +} + /* Used during launch of application from file */ void MainPage::Page_Loaded(Object^ sender, RoutedEventArgs^ e) { @@ -215,6 +254,17 @@ void MainPage::Picker(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventAr if (!EnsureUnsnapped()) return; + /* If we are actively rendering a document to the print thread then notify the + user that they will need to wait */ + if (m_print_active) + { + int total_pages = GetPrintPageCount(); + auto str1 = "Cannot open new file. Currently rendering page " + + m_curr_print_count + " of " + total_pages + " for print queue"; + NotifyUser(str1, StatusMessage); + return; + } + FileOpenPicker^ openPicker = ref new FileOpenPicker(); openPicker->ViewMode = PickerViewMode::List; openPicker->SuggestedStartLocation = PickerLocationId::DocumentsLibrary; @@ -408,7 +458,7 @@ void MainPage::CreateBlank(int width, int height) DataWriterStoreOperation^ result = dw->StoreAsync(); /* Block on the Async call */ - while(result->Status != AsyncStatus::Completed) { + while(result->Status != Windows::Foundation::AsyncStatus::Completed) { } /* And store in a the image brush */ bmp->SetSource(ras); @@ -438,8 +488,6 @@ void MainPage::CleanUp() m_docPages->Clear(); if (m_thumbnails != nullptr && m_thumbnails->Size > 0) m_thumbnails->Clear(); - if (m_printpages != nullptr && m_printpages->Size > 0) - m_printpages->Clear(); /* With the ref counting this should not leak */ if (m_page_link_list != nullptr && m_page_link_list->Size > 0) m_page_link_list->Clear(); @@ -474,6 +522,8 @@ void MainPage::CleanUp() m_rectlist_page = -1; m_Progress = 0.0; m_doczoom = 1.0; + m_print_active = false; + m_curr_print_count = 1; this->xaml_PageSlider->Minimum = m_slider_min; this->xaml_PageSlider->Maximum = m_slider_max; @@ -676,7 +726,6 @@ void MainPage::InitialRender() doc_page->LinkBox = nullptr; m_docPages->Append(doc_page); m_thumbnails->Append(doc_page); - m_printpages->Append(doc_page); /* Create empty lists for our links and specify that they have not been computed for these pages */ Vector<RectList^>^ temp_link = ref new Vector<RectList^>(); @@ -1556,95 +1605,79 @@ bool MainPage::IsNotStandardView() xaml_WebView->Visibility == Windows::UI::Xaml::Visibility::Visible); } -/* The following code is for print support. This is just a simple demonstration of - printing with MuPDF in the Windows 8 environment */ +/* The following code is for print support. */ void MainPage::RegisterForPrinting() { - m_printdoc = ref new PrintDocument(); - m_printdoc_source = m_printdoc->DocumentSource; - m_printdoc->Paginate += - ref new Windows::UI::Xaml::Printing::PaginateEventHandler(this, &MainPage::CreatePrintPreviewPages); - m_printdoc->GetPreviewPage += - ref new Windows::UI::Xaml::Printing::GetPreviewPageEventHandler(this, &MainPage::GetPrintPreviewPages); - m_printdoc->AddPages += - ref new Windows::UI::Xaml::Printing::AddPagesEventHandler(this, &MainPage::AddPrintPages); - - PrintManager^ printMan = PrintManager::GetForCurrentView(); - m_printTaskRequestedEventToken = - printMan->PrintTaskRequested += - ref new TypedEventHandler<PrintManager^, PrintTaskRequestedEventArgs^>(this, &MainPage::PrintTaskRequested); -} - -void MainPage::UnregisterForPrinting() -{ - // Remove the handler for printing initialization. - PrintManager^ printMan = PrintManager::GetForCurrentView(); - printMan->PrintTaskRequested -= m_printTaskRequestedEventToken; -} - -void MainPage::PrintTaskRequested(PrintManager^ sender, PrintTaskRequestedEventArgs^ e) -{ - auto printTaskRef = std::make_shared<PrintTask^>(nullptr); - *printTaskRef = e->Request->CreatePrintTask("MuPDF Printing", - ref new PrintTaskSourceRequestedHandler([this, printTaskRef](PrintTaskSourceRequestedArgs^ args) - { - PrintTask^ printTask = *printTaskRef; - PrintTaskOptionDetails^ printDetailedOptions = - PrintTaskOptionDetails::GetFromPrintTaskOptions(printTask->Options); - - // Some standard printer options - printDetailedOptions->DisplayedOptions->Clear(); - printDetailedOptions->DisplayedOptions->Append(Windows::Graphics::Printing::StandardPrintTaskOptions::MediaSize); - printDetailedOptions->DisplayedOptions->Append(Windows::Graphics::Printing::StandardPrintTaskOptions::Copies); - - // Our custom options - PrintCustomItemListOptionDetails^ resolution = - printDetailedOptions->CreateItemListOption("resolution", "Render Resolution"); - resolution->AddItem("sres72", "72 dpi"); - resolution->AddItem("sres150", "150 dpi"); - resolution->AddItem("sres300", "300 dpi"); - resolution->AddItem("sres600", "600 dpi"); - resolution->TrySetValue("sres600"); - m_printresolution = 600; - printDetailedOptions->DisplayedOptions->Append("resolution"); - - PrintCustomItemListOptionDetails^ scaling = printDetailedOptions->CreateItemListOption("scaling", "Scaling"); - scaling->AddItem("sScaleToFit", "Scale To Fit"); - scaling->AddItem("sCrop", "Crop"); - // Add the custom option to the option list. - printDetailedOptions->DisplayedOptions->Append("scaling"); - scaling->TrySetValue("sScaleToFit"); - m_printcrop = false; - printTask->Options->MediaSize = PrintMediaSize::NorthAmericaLetter; - - PrintCustomItemListOptionDetails^ pageFormat = printDetailedOptions->CreateItemListOption(L"PageRange", L"Page Range"); - pageFormat->AddItem(L"PrintAll", L"Print all"); - pageFormat->AddItem(L"PrintRange", L"Print Range"); - printDetailedOptions->DisplayedOptions->Append(L"PageRange"); - PrintCustomTextOptionDetails^ pageRangeEdit = printDetailedOptions->CreateTextOption(L"PageRangeEdit", L"Range"); - - printDetailedOptions->OptionChanged += - ref new TypedEventHandler<PrintTaskOptionDetails^, PrintTaskOptionChangedEventArgs^>(this, &MainPage::PrintOptionsChanged); - - // Invoked when the print job is completed. - printTask->Completed += ref new TypedEventHandler<PrintTask^, PrintTaskCompletedEventArgs^>( - [=](PrintTask^ sender, PrintTaskCompletedEventArgs^ e) - { - auto callback = ref new Windows::UI::Core::DispatchedHandler( - [=]() - { - ClearPrintCollection(); - m_printpagedesc = PrintPageDesc(); - if (e->Completion == Windows::Graphics::Printing::PrintTaskCompletion::Failed) - { - NotifyUser("Sorry, printing failed", StatusMessage); - } - }); - Dispatcher->RunAsync(Windows::UI::Core::CoreDispatcherPriority::Normal, callback); - }); - // Set the document source. - args->SetSource(PrintDocumentSource); - })); + m_print_manager = Windows::Graphics::Printing::PrintManager::GetForCurrentView(); + m_print_manager->PrintTaskRequested += + ref new TypedEventHandler<PrintManager^, PrintTaskRequestedEventArgs^>(this, &MainPage::SetPrintTask); +} + +void MainPage::SetPrintTask(PrintManager^ sender, PrintTaskRequestedEventArgs^ args) +{ + PrintTaskSourceRequestedHandler^ source_handler = + ref new PrintTaskSourceRequestedHandler([this](PrintTaskSourceRequestedArgs^ args)-> void{ + Microsoft::WRL::ComPtr<PrintPages> document_source; + ThrowIfFailed(Microsoft::WRL::MakeAndInitialize<PrintPages>(&document_source, reinterpret_cast<IUnknown*>(this))); + IPrintDocumentSource^ objSource(reinterpret_cast<IPrintDocumentSource^>(document_source.Get())); + args->SetSource(objSource); + }); + + PrintTask^ print_task = + args->Request->CreatePrintTask(L"MuPDF WinRT Print", source_handler); + + /* Call backs so that we know when we are all done with the printing */ + print_task->Progressing += + ref new TypedEventHandler<PrintTask^, PrintTaskProgressingEventArgs^>(this, &MainPage::PrintProgress); + print_task->Completed += + ref new TypedEventHandler<PrintTask^, PrintTaskCompletedEventArgs^>(this, &MainPage::PrintCompleted); + m_print_active = true; + m_curr_print_count = 0; + + PrintTaskOptionDetails^ printDetailedOptions = + PrintTaskOptionDetails::GetFromPrintTaskOptions(print_task->Options); + + // Some standard printer options + printDetailedOptions->DisplayedOptions->Clear(); + printDetailedOptions->DisplayedOptions->Append(Windows::Graphics::Printing::StandardPrintTaskOptions::MediaSize); + printDetailedOptions->DisplayedOptions->Append(Windows::Graphics::Printing::StandardPrintTaskOptions::Copies); + + // Our custom options + PrintCustomItemListOptionDetails^ resolution = + printDetailedOptions->CreateItemListOption("resolution", "Render Resolution"); + resolution->AddItem("sres96", "96dpi"); + resolution->AddItem("sres150", "150 dpi"); + resolution->AddItem("sres300", "300 dpi"); + resolution->AddItem("sres600", "600 dpi"); + resolution->TrySetValue("sres600"); + m_printresolution = 600; + printDetailedOptions->DisplayedOptions->Append("resolution"); + + PrintCustomItemListOptionDetails^ location = printDetailedOptions->CreateItemListOption("location", "Location"); + location->AddItem("sCenter", "Center"); + location->AddItem("sTopleft", "Top Left"); + // Add the custom option to the option list. + printDetailedOptions->DisplayedOptions->Append("location"); + location->TrySetValue("sCenter"); + m_centerprint = true; + print_task->Options->MediaSize = PrintMediaSize::NorthAmericaLetter; + + PrintCustomItemListOptionDetails^ pageFormat = printDetailedOptions->CreateItemListOption(L"PageRange", L"Page Range"); + pageFormat->AddItem(L"PrintAll", L"Print all"); + pageFormat->AddItem(L"PrintRange", L"Print Range"); + printDetailedOptions->DisplayedOptions->Append(L"PageRange"); + PrintCustomTextOptionDetails^ pageRangeEdit = printDetailedOptions->CreateTextOption(L"PageRangeEdit", L"Range"); + + printDetailedOptions->OptionChanged += + ref new TypedEventHandler<PrintTaskOptionDetails^, PrintTaskOptionChangedEventArgs^>(this, &MainPage::PrintOptionsChanged); +} + +int MainPage::GetPrintPageCount() +{ + if (m_ppage_num_list.size() > 0) + return m_ppage_num_list.size(); + else + return m_num_pages; } void MainPage::PrintOptionsChanged(PrintTaskOptionDetails^ sender, PrintTaskOptionChangedEventArgs^ args) @@ -1661,9 +1694,9 @@ void MainPage::PrintOptionsChanged(PrintTaskOptionDetails^ sender, PrintTaskOpti IPrintOptionDetails^ resolution = sender->Options->Lookup(optionId); String^ resolutionValue = safe_cast<String^>(resolution->Value); - if (resolutionValue == "sres72") + if (resolutionValue == "sres96") { - m_printresolution = 72; + m_printresolution = 96; } else if (resolutionValue == "sres150") { @@ -1680,18 +1713,18 @@ void MainPage::PrintOptionsChanged(PrintTaskOptionDetails^ sender, PrintTaskOpti } /* Need to update preview with a change of this one */ - if (optionId == "scaling") + if (optionId == "location") { IPrintOptionDetails^ scaling = sender->Options->Lookup(optionId); String^ scaleValue = safe_cast<String^>(scaling->Value); - if (scaleValue == "sScaleToFit") + if (scaleValue == "sCenter") { - m_printcrop = false; + m_centerprint = true; } - if (scaleValue == "sCrop") + if (scaleValue == "sTopleft") { - m_printcrop = true; + m_centerprint = false; } force_reset = true; } @@ -1821,241 +1854,204 @@ void MainPage::RemovePageRangeEdit(PrintTaskOptionDetails^ printTaskOptionDetail } } -void MainPage::ClearPrintCollection() +void MainPage::CreatePrintControl(_In_ IPrintDocumentPackageTarget* docPackageTarget, + _In_ D2D1_PRINT_CONTROL_PROPERTIES* printControlProperties) { - m_printlock.lock(); - for (int k = 0; k < m_num_pages; k++) - { - auto thumb_page = this->m_thumbnails->GetAt(k); - this->m_printpages->SetAt(k, thumb_page); - } - m_printlock.unlock(); + m_d2d_printcontrol = nullptr; + ThrowIfFailed(m_d2d_device->CreatePrintControl(m_wic_factory.Get(), docPackageTarget, + printControlProperties, &m_d2d_printcontrol)); } -/* Just use the thumbnail images for now */ -void MainPage::CreatePrintPreviewPages(Object^ sender, PaginateEventArgs^ e) +void MainPage::DrawPreviewSurface(float width, float height, float scale_in, + D2D1_RECT_F contentBox, uint32 page_num, + IPrintPreviewDxgiPackageTarget* previewTarget) { - InterlockedIncrement64(&m_requestCount); - PrintPageDesc ppageDescription; - PrintTaskOptionDetails^ printDetailedOptions = - PrintTaskOptionDetails::GetFromPrintTaskOptions(e->PrintTaskOptions); - PrintPageDescription DeviceDescription = - e->PrintTaskOptions->GetPageDescription(0); - - /* This has the media dimension */ - ppageDescription.pagesize = DeviceDescription.PageSize; - - ppageDescription.resolution.Width = DeviceDescription.DpiX; - ppageDescription.resolution.Height = DeviceDescription.DpiY; - - ppageDescription.margin.Width = (std::max)(DeviceDescription.ImageableRect.Left, - DeviceDescription.ImageableRect.Right - - DeviceDescription.PageSize.Width); - - ppageDescription.margin.Height = (std::max)(DeviceDescription.ImageableRect.Top, - DeviceDescription.ImageableRect.Bottom - - DeviceDescription.PageSize.Height); - - ppageDescription.printpagesize.Width = DeviceDescription.PageSize.Width - - ppageDescription.margin.Width * 2; - ppageDescription.printpagesize.Height = DeviceDescription.PageSize.Height - - ppageDescription.margin.Height * 2; - - ClearPrintCollection(); - PrintDocument^ printDocument = safe_cast<PrintDocument^>(sender); - m_printpagedesc = ppageDescription; + int dpi = 96; + int index_page_num = page_num - 1; + int ren_page_num = index_page_num; if (m_ppage_num_list.size() > 0) - { - printDocument->SetPreviewPageCount(m_ppage_num_list.size(), - PreviewPageCountType::Intermediate); - } - else - { - printDocument->SetPreviewPageCount(m_num_pages, - PreviewPageCountType::Intermediate); - } -} - -/* Set the page with the new raster information */ -void MainPage::UpdatePreview(int page_num, InMemoryRandomAccessStream^ ras, - Point ras_size, Page_Content_t content_type, double zoom_in) -{ - assert(IsMainThread()); + ren_page_num = m_ppage_num_list[page_num - 1] - 1; + + /* This goes on in a background thread. Hence is non-blocking for UI */ + assert(IsBackgroundThread()); + + /* Set up all the DirectX stuff */ + CD3D11_TEXTURE2D_DESC textureDesc(DXGI_FORMAT_B8G8R8A8_UNORM, + static_cast<uint32>(ceil(width * dpi / 96)), + static_cast<uint32>(ceil(height * dpi / 96)), + 1, 1, D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE); + ComPtr<ID3D11Texture2D> texture; + ThrowIfFailed(m_d3d_device->CreateTexture2D(&textureDesc, nullptr, &texture)); + ComPtr<IDXGISurface> dxgi_surface; + ThrowIfFailed(texture.As<IDXGISurface>(&dxgi_surface)); + + // Create a new D2D device context for rendering the preview surface. D2D + // device contexts are stateful, and hence a unique device context must be + // used on each thread. + ComPtr<ID2D1DeviceContext> d2d_context; + ThrowIfFailed(m_d2d_device->CreateDeviceContext(D2D1_DEVICE_CONTEXT_OPTIONS_NONE, + &d2d_context)); + // Update DPI for preview surface as well. + d2d_context->SetDpi(96, 96); + + D2D1_BITMAP_PROPERTIES1 bitmap_properties = + D2D1::BitmapProperties1(D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW, + D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED)); + + // Create surface bitmap on which page content is drawn. + ComPtr<ID2D1Bitmap1> d2d_surfacebitmap; + ThrowIfFailed(d2d_context->CreateBitmapFromDxgiSurface(dxgi_surface.Get(), + &bitmap_properties, &d2d_surfacebitmap)); + d2d_context->SetTarget(d2d_surfacebitmap.Get()); + + /* Figure out all the sizing */ + spatial_info_t spatial_info; + spatial_info.scale_factor = 1.0; + spatial_info.size.X = width; + spatial_info.size.Y = height; + Point ras_size = ComputePageSize(spatial_info, ren_page_num); + ras_size.X = ceil(ras_size.X); + ras_size.Y = ceil(ras_size.Y); + + Array<unsigned char>^ bmp_data; + int code = mu_doc->RenderPageBitmapSync(ren_page_num, ras_size.X, ras_size.Y, + true, &bmp_data); + D2D1_SIZE_U bit_map_rect; + bit_map_rect.width = ras_size.X; + bit_map_rect.height = ras_size.Y; + + D2D1_BITMAP_PROPERTIES1 bitmap_properties2 = + D2D1::BitmapProperties1(D2D1_BITMAP_OPTIONS_NONE, + D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED)); + + ID2D1Bitmap1 *bit_map; + ThrowIfFailed(d2d_context->CreateBitmap(bit_map_rect, &(bmp_data[0]), + ras_size.X * 4, &bitmap_properties2, + &bit_map)); + D2D1_SIZE_F size = bit_map->GetSize(); + + /* Handle centering */ + float y_offset = 0; + float x_offset = 0; + if (m_centerprint) + { + y_offset = (height - size.height) / 2.0; + x_offset = (width - size.width) / 2.0; + } + + d2d_context->BeginDraw(); + d2d_context->DrawBitmap(bit_map, D2D1::RectF(x_offset, y_offset, + size.width + x_offset, size.height + y_offset)); + ThrowIfFailed(d2d_context->EndDraw()); + ThrowIfFailed(previewTarget->DrawPage(page_num, dxgi_surface.Get(), dpi, dpi)); +} + +HRESULT MainPage::ClosePrintControl() +{ + return (m_d2d_printcontrol == nullptr) ? S_OK : m_d2d_printcontrol->Close(); +} + +void MainPage::PrintPage(uint32 page_num, D2D1_RECT_F image_area, D2D1_SIZE_F page_area, + float device_dpi, IStream* print_ticket) +{ + int dpi = m_printresolution; + int index_page_num = page_num - 1; + int ren_page_num = index_page_num; - WriteableBitmap ^bmp = ref new WriteableBitmap(ras_size.X, ras_size.Y); - bmp->SetSource(ras); + /* Windoze seems to hand me a bogus dpi */ + device_dpi = 96; - DocumentPage^ doc_page = ref new DocumentPage(); - doc_page->Image = bmp; - - doc_page->Height = ras_size.Y; - doc_page->Width = ras_size.X; - doc_page->Content = content_type; - doc_page->Zoom = zoom_in; - this->m_printpages->SetAt(page_num, doc_page); + if (m_ppage_num_list.size() > 0) + ren_page_num = m_ppage_num_list[page_num - 1] - 1; + + /* This goes on in a background thread. Hence is non-blocking for UI */ + assert(IsBackgroundThread()); + + /* Print command list set up */ + ComPtr<ID2D1DeviceContext> d2d_context; + ThrowIfFailed(m_d2d_device->CreateDeviceContext(D2D1_DEVICE_CONTEXT_OPTIONS_NONE, + &d2d_context)); + ComPtr<ID2D1CommandList> clist; + ThrowIfFailed(d2d_context->CreateCommandList(&clist)); + d2d_context->SetTarget(clist.Get()); + + /* Figure out all the sizing. Width and height here are for device_dpi */ + float width = image_area.right - image_area.left; + float height = image_area.bottom - image_area.top; + + spatial_info_t spatial_info; + spatial_info.scale_factor = 1.0; + /* width and height are based upon device dpi (96) and MuPDF native + resolution is 72dpi */ + spatial_info.size.X = (width /device_dpi) * (m_printresolution); + spatial_info.size.Y = (height /device_dpi) * (m_printresolution); + Point ras_size = ComputePageSize(spatial_info, ren_page_num); + ras_size.X = ceil(ras_size.X); + ras_size.Y = ceil(ras_size.Y); + + Array<unsigned char>^ bmp_data; + int code = mu_doc->RenderPageBitmapSync(ren_page_num, ras_size.X, ras_size.Y, + true, &bmp_data); + D2D1_SIZE_U bit_map_rect; + bit_map_rect.width = ras_size.X; + bit_map_rect.height = ras_size.Y; + + D2D1_BITMAP_PROPERTIES1 bitmap_properties2 = + D2D1::BitmapProperties1(D2D1_BITMAP_OPTIONS_NONE, + D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED)); + + ID2D1Bitmap1 *bit_map; + ThrowIfFailed(d2d_context->CreateBitmap(bit_map_rect, &(bmp_data[0]), + ras_size.X * 4, &bitmap_properties2, + &bit_map)); + D2D1_SIZE_F size = bit_map->GetSize(); + + /* Handle centering */ + float y_offset = 0; + float x_offset = 0; + if (m_centerprint) + { + /* Offsets need to be provided in the device dpi */ + y_offset = (page_area.height - (size.height * device_dpi / m_printresolution)) / 2.0; + x_offset = (page_area.width - (size.width * device_dpi / m_printresolution)) / 2.0; + } + + float image_height = (bit_map_rect.height / m_printresolution) * device_dpi; + float image_width = (bit_map_rect.width / m_printresolution) * device_dpi; + + d2d_context->BeginDraw(); + d2d_context->DrawBitmap(bit_map, D2D1::RectF(x_offset, y_offset, + image_width + x_offset, image_height + y_offset)); + ThrowIfFailed(d2d_context->EndDraw()); + ThrowIfFailed(clist->Close()); + ThrowIfFailed(m_d2d_printcontrol->AddPage(clist.Get(), page_area, print_ticket)); } -void MainPage::CleanUpPreview(int page_num) +void MainPage::RefreshPreview() { - for (int k = page_num - 1; k <= page_num + 1; k++) - { - if (k >= 0 && k < this->m_num_pages && k != page_num) - { - auto doc = this->m_printpages->GetAt(k); - if (doc->Content == THUMBNAIL) return; - - if (this->m_thumbnails->Size > k) - { - auto thumb_page = this->m_thumbnails->GetAt(k); - this->m_printpages->SetAt(k, thumb_page); - } - } - } + PrintPages *p_struct = (PrintPages*) m_print_struct; + p_struct->ResetPreview(); } -void MainPage::RefreshPreview() +/* This reference is needed so that we can reset preview when changes occur on options */ +void MainPage::SetPrintTarget(void *print_struct) { - auto callback = - ref new Windows::UI::Core::DispatchedHandler([this]() - { - m_printdoc->InvalidatePreview(); - }); - Dispatcher->RunAsync(Windows::UI::Core::CoreDispatcherPriority::Normal, callback); + m_print_struct = print_struct; } -void MainPage::GetPrintPreviewPages(Object^ sender, GetPreviewPageEventArgs^ e) +/* These are called by the print thread and as such we cannot do UI updates + directly. However we can keep a monitor of what is going on so that if + someone tries to open a new document while we are printing some monster doc, + we can let them know that they need to wait. */ +void MainPage::PrintProgress(PrintTask^ sender, PrintTaskProgressingEventArgs^ args) { - PrintDocument^ printDocument = safe_cast<PrintDocument^>(sender); - - LONGLONG requestNumber = 0; - InterlockedExchange64(&requestNumber, m_requestCount); - int index_page_num = e->PageNumber; - int ren_page_num = index_page_num; - - if (m_ppage_num_list.size() > 0) - { - ren_page_num = m_ppage_num_list[index_page_num - 1]; - } - auto doc_curr = this->m_printpages->GetAt(ren_page_num - 1); - if (doc_curr->Content == PRINT_PREVIEW) - { - auto bitmap = doc_curr->Image; - Image^ image = ref new Image(); - image->Source = bitmap; - image->HorizontalAlignment = Windows::UI::Xaml::HorizontalAlignment::Center; - image->VerticalAlignment = Windows::UI::Xaml::VerticalAlignment::Center; - image->Stretch = Stretch::UniformToFill; - image->Width = bitmap->PixelWidth; - image->Height = bitmap->PixelHeight; - printDocument->SetPreviewPage(index_page_num, image); - } - else - { - /* Determine the scale to fit case or crop */ - spatial_info_t spatial_info = InitSpatial(1.0); - int pagNum = ren_page_num - 1; - Point ras_size = ComputePageSize(spatial_info, pagNum); - float scale = 1.0; - - if (!(this->m_printcrop)) - { - float scaleY = m_printpagedesc.printpagesize.Height / ras_size.Y; - float scaleX = m_printpagedesc.printpagesize.Width / ras_size.X; - scale = (std::min)(scaleY, scaleX); - } - auto render_task = - create_task(mu_doc->RenderPageAsync(pagNum, ras_size.X, ras_size.Y, true)); - render_task.then([=] (InMemoryRandomAccessStream^ ras) - { - UpdatePreview(pagNum, ras, ras_size, PRINT_PREVIEW, scale); - auto doc_curr = this->m_printpages->GetAt(pagNum); - auto bitmap = doc_curr->Image; - Image^ image = ref new Image(); - image->Source = bitmap; - image->HorizontalAlignment = Windows::UI::Xaml::HorizontalAlignment::Center; - image->VerticalAlignment = Windows::UI::Xaml::VerticalAlignment::Center; - image->Stretch = Stretch::UniformToFill; - image->Width = bitmap->PixelWidth * scale; - image->Height = bitmap->PixelHeight * scale; - printDocument->SetPreviewPage(index_page_num, image); - }, task_continuation_context::use_current()); - } - this->CleanUpPreview(ren_page_num - 1); + assert(IsBackgroundThread()); + this->m_curr_print_count = args->DocumentPageCount; } -void MainPage::AddPrintPages(Object^ sender, AddPagesEventArgs^ e) +void MainPage::PrintCompleted(PrintTask^ sender, PrintTaskCompletedEventArgs^ args) { - PrintDocument^ printDocument = safe_cast<PrintDocument^>(sender); - - /* We create a list of tasks to create the pages for printing. Once all the - pages are created then we can go ahead and start adding them for printing */ - std::vector<concurrency::task<void>> createPageTasks; - double res_scale = ((double) m_printresolution / 72.0); - int page_count = m_num_pages; - - if (m_ppage_num_list.size() > 0) - page_count = m_ppage_num_list.size(); - - for(int i = 0; i < page_count; ++i) - { - m_printlock.lock(); - - int page_num = i; - if (m_ppage_num_list.size() > 0) - page_num = m_ppage_num_list[i] - 1; - - auto doc_curr = this->m_printpages->GetAt(page_num); - if (doc_curr->Content != FULL_RESOLUTION) - { - spatial_info_t spatial_info = InitSpatial(res_scale); - Point ras_size = ComputePageSize(spatial_info, page_num); - float scale = 1.0; - - if (!(this->m_printcrop)) - { - spatial_info = InitSpatial(1.0); - ras_size = ComputePageSize(spatial_info, page_num); - float scaleY = m_printpagedesc.printpagesize.Height / ras_size.Y; - float scaleX = m_printpagedesc.printpagesize.Width / ras_size.X; - scale = (std::min)(scaleY, scaleX); - spatial_info = InitSpatial(res_scale * scale); - ras_size = ComputePageSize(spatial_info, page_num); - } - auto render_task = - create_task(mu_doc->RenderPageAsync(page_num, ras_size.X, ras_size.Y, true)); - createPageTasks.push_back(render_task.then([=] (InMemoryRandomAccessStream^ ras) - { - UpdatePreview(page_num, ras, ras_size, FULL_RESOLUTION, 1.0); - }, task_continuation_context::use_current())); - } - m_printlock.unlock(); - } - - /* When all the tasks have finished then go ahead and add them to the print - document */ - concurrency::when_all(createPageTasks.begin(), createPageTasks.end()). then([=] - { - for (int i = 0; i < page_count; i++) - { - int page_num = i; - if (m_ppage_num_list.size() > 0) - page_num = m_ppage_num_list[i] - 1; - auto doc_curr = this->m_printpages->GetAt(page_num); - auto bitmap = doc_curr->Image; - Image^ image = ref new Image(); - image->Source = bitmap; - image->HorizontalAlignment = Windows::UI::Xaml::HorizontalAlignment::Center; - image->VerticalAlignment = Windows::UI::Xaml::VerticalAlignment::Center; - image->Stretch = Stretch::UniformToFill; - image->Width = bitmap->PixelWidth / res_scale; - image->Height = bitmap->PixelHeight / res_scale; - printDocument->AddPage(image); - } - /* All pages provided. */ - printDocument->AddPagesComplete(); - /* Reset the current page description as soon as possible since the - PrintTask.Completed event might fire later */ - m_printpagedesc = PrintPageDesc(); - }); + assert(IsBackgroundThread()); + m_print_active = false; } diff --git a/platform/winrt/mupdf_cpp/MainPage.xaml.h b/platform/winrt/mupdf_cpp/MainPage.xaml.h index 49f0cd75..f229123e 100644 --- a/platform/winrt/mupdf_cpp/MainPage.xaml.h +++ b/platform/winrt/mupdf_cpp/MainPage.xaml.h @@ -13,6 +13,7 @@ #include <assert.h> #include "DocumentPage.h" #include "status.h" +#include "PrintPage.h" using namespace Platform; using namespace Concurrency; @@ -62,7 +63,6 @@ typedef struct spatial_info_s namespace mupdf_cpp { - class PageRangeException { private: @@ -116,6 +116,15 @@ namespace mupdf_cpp /// </summary> public ref class MainPage sealed { + + inline void ThrowIfFailed(HRESULT hr) + { + if (FAILED(hr)) + { + throw Platform::Exception::CreateException(hr); + } + } + public: MainPage(); @@ -150,8 +159,8 @@ namespace mupdf_cpp Vector<IVector<RectList^>^>^ m_page_link_list; Vector<int>^ m_linkset; Vector<RectList^>^ m_text_list; - int m_rectlist_page; mudocument^ mu_doc; + int m_rectlist_page; bool m_file_open; int m_currpage; int m_searchpage; @@ -178,17 +187,26 @@ namespace mupdf_cpp double m_doczoom; /* Print related */ - Vector<DocumentPage^>^ m_printpages; - concurrency::critical_section m_printlock; - EventRegistrationToken m_printTaskRequestedEventToken; PrintDocument^ m_printdoc; IPrintDocumentSource^ m_printdoc_source; - LONGLONG m_requestCount; PrintPageDesc m_printpagedesc; int m_printresolution; - bool m_printcrop; + bool m_centerprint; bool m_pageRangeEditVisible; std::vector<int> m_ppage_num_list; + int m_curr_print_count; + bool m_print_active; + + /* DirectX Print Control */ + PrintManager ^m_print_manager; + Microsoft::WRL::ComPtr<ID3D11Device> m_d3d_device; + Microsoft::WRL::ComPtr<ID3D11DeviceContext> m_d3d_context; + Microsoft::WRL::ComPtr<ID2D1PrintControl> m_d2d_printcontrol; + Microsoft::WRL::ComPtr<ID2D1Device> m_d2d_device; + Microsoft::WRL::ComPtr<IWICImagingFactory2> m_wic_factory; + Microsoft::WRL::ComPtr<ID2D1Factory1> m_d2d_factory; + D3D_FEATURE_LEVEL m_featureLevel; + void *m_print_struct; void ReplaceImage(int page_num, InMemoryRandomAccessStream^ ras, Point ras_size, double zoom); void Picker(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); @@ -257,19 +275,26 @@ namespace mupdf_cpp /* Print Related */ void RegisterForPrinting(); - void UnregisterForPrinting(); - void PrintTaskRequested(PrintManager^ sender, PrintTaskRequestedEventArgs^ e); - void ClearPrintCollection(); - void CreatePrintPreviewPages(Object^ sender, PaginateEventArgs^ e); - void GetPrintPreviewPages(Object^ sender, GetPreviewPageEventArgs^ e); - void UpdatePreview(int page_num, InMemoryRandomAccessStream^ ras, - Point ras_size, Page_Content_t content_type, double zoom_in); - void CleanUpPreview(int new_page); - void AddPrintPages(Object^ sender, AddPagesEventArgs^ e); void PrintOptionsChanged(PrintTaskOptionDetails^ sender, PrintTaskOptionChangedEventArgs^ args); void RefreshPreview(); void RemovePageRangeEdit(PrintTaskOptionDetails^ printTaskOptionDetails); void SplitString(String^ string, wchar_t delimiter, std::vector<std::wstring>& words); void GetPagesInRange(String^ pageRange); + void SetPrintTask( PrintManager^, PrintTaskRequestedEventArgs^ args); + void SetUpDirectX(); + + internal: + void CreatePrintControl(IPrintDocumentPackageTarget* docPackageTarget, + D2D1_PRINT_CONTROL_PROPERTIES* printControlProperties); + void PrintPage(uint32 page_num, D2D1_RECT_F image_area, D2D1_SIZE_F page_area, + float device_dpi, IStream* print_ticket); + HRESULT ClosePrintControl(); + void DrawPreviewSurface(float width, float height, float scale, + D2D1_RECT_F contentBox, uint32 desiredJobPage, + IPrintPreviewDxgiPackageTarget* previewTarget); + int GetPrintPageCount(); + void SetPrintTarget(void *print_struct); + void PrintProgress(PrintTask^ sender, PrintTaskProgressingEventArgs^ args); + void PrintCompleted(PrintTask^ sender, PrintTaskCompletedEventArgs^ args); }; } diff --git a/platform/winrt/mupdf_cpp/PrintPage.cpp b/platform/winrt/mupdf_cpp/PrintPage.cpp new file mode 100644 index 00000000..5e14f191 --- /dev/null +++ b/platform/winrt/mupdf_cpp/PrintPage.cpp @@ -0,0 +1,165 @@ +#include "pch.h" +#include "PrintPage.h" + +using namespace Microsoft::WRL; +using namespace Windows::Graphics::Printing; + +#pragma region IDocumentPageSource Methods + +/* This is the interface to the print thread calls */ +IFACEMETHODIMP +PrintPages::GetPreviewPageCollection(IPrintDocumentPackageTarget* doc_target, + IPrintPreviewPageCollection** doc_collection) +{ + HRESULT hr = (doc_target != nullptr) ? S_OK : E_INVALIDARG; + + if (SUCCEEDED(hr)) + { + hr = doc_target->GetPackageTarget(ID_PREVIEWPACKAGETARGET_DXGI, + IID_PPV_ARGS(&m_dxgi_previewtarget)); + } + ComPtr<IPrintPreviewPageCollection> page_collection; + if (SUCCEEDED(hr)) + { + ComPtr<PrintPages> docSource(this); + hr = docSource.As<IPrintPreviewPageCollection>(&page_collection); + } + if (SUCCEEDED(hr)) + hr = page_collection.CopyTo(doc_collection); + + if (SUCCEEDED(hr)) + this->m_renderer->SetPrintTarget((void*) this); + return hr; +} + +IFACEMETHODIMP +PrintPages::MakeDocument(IInspectable* doc_options, IPrintDocumentPackageTarget* doc_target) +{ + if (doc_options == nullptr || doc_target == nullptr) + return E_INVALIDARG; + + PrintTaskOptions^ option = reinterpret_cast<PrintTaskOptions^>(doc_options); + PrintPageDescription page_desc = option->GetPageDescription(1); + + D2D1_PRINT_CONTROL_PROPERTIES print_properties; + + print_properties.rasterDPI = (float)(min(page_desc.DpiX, page_desc.DpiY)); + print_properties.colorSpace = D2D1_COLOR_SPACE_SRGB; + print_properties.fontSubset = D2D1_PRINT_FONT_SUBSET_MODE_DEFAULT; + + HRESULT hr = S_OK; + + try + { + m_renderer->CreatePrintControl(doc_target, &print_properties); + + D2D1_RECT_F imageableRect = D2D1::RectF(page_desc.ImageableRect.X, + page_desc.ImageableRect.Y, + page_desc.ImageableRect.X + page_desc.ImageableRect.Width, + page_desc.ImageableRect.Y + page_desc.ImageableRect.Height); + + D2D1_SIZE_F pageSize = D2D1::SizeF(page_desc.PageSize.Width, page_desc.PageSize.Height); + m_totalpages = m_renderer->GetPrintPageCount(); + + for (uint32 page_num = 1; page_num <= m_totalpages; ++page_num) + m_renderer->PrintPage(page_num, imageableRect, pageSize, page_desc.DpiX, nullptr); + } + catch (Platform::Exception^ e) + { + hr = e->HResult; + } + + HRESULT hrClose = m_renderer->ClosePrintControl(); + if (SUCCEEDED(hr)) + { + hr = hrClose; + } + return hr; +} + +#pragma endregion IDocumentPageSource Methods + +#pragma region IPrintPreviewPageCollection Methods + +IFACEMETHODIMP +PrintPages::Paginate(uint32 current_jobpage, IInspectable* doc_options) +{ + HRESULT hr = (doc_options != nullptr) ? S_OK : E_INVALIDARG; + + if (SUCCEEDED(hr)) + { + PrintTaskOptions^ option = reinterpret_cast<PrintTaskOptions^>(doc_options); + PrintPageDescription page_desc = option->GetPageDescription(current_jobpage); + + hr = m_dxgi_previewtarget->InvalidatePreview(); + m_totalpages = m_renderer->GetPrintPageCount(); + + if (SUCCEEDED(hr)) + hr = m_dxgi_previewtarget->SetJobPageCount(PageCountType::FinalPageCount, m_totalpages); + + if (SUCCEEDED(hr)) + { + m_width = page_desc.PageSize.Width; + m_height = page_desc.PageSize.Height; + m_imageable_rect = D2D1::RectF(page_desc.ImageableRect.X, page_desc.ImageableRect.Y, + page_desc.ImageableRect.X + page_desc.ImageableRect.Width, + page_desc.ImageableRect.Y + page_desc.ImageableRect.Height); + m_paginate_called = true; + } + } + return hr; +} + +float +PrintPages::TransformedPageSize(float desired_width, float desired_height, + Windows::Foundation::Size* preview_size) +{ + float scale = 1.0f; + + if (desired_width > 0 && desired_height > 0) + { + preview_size->Width = desired_width; + preview_size->Height = desired_height; + scale = m_width / desired_width; + } + else + { + preview_size->Width = 0; + preview_size->Height = 0; + } + return scale; +} + +void +PrintPages::ResetPreview() +{ + m_dxgi_previewtarget->InvalidatePreview(); +} + +IFACEMETHODIMP +PrintPages::MakePage(uint32 desired_jobpage, float width, float height) +{ + HRESULT hr = (width > 0 && height > 0) ? S_OK : E_INVALIDARG; + + if (desired_jobpage == JOB_PAGE_APPLICATION_DEFINED && m_paginate_called) + desired_jobpage = 1; + + if (SUCCEEDED(hr) && m_paginate_called) + { + Windows::Foundation::Size preview_size; + float scale = TransformedPageSize(width, height, &preview_size); + + try + { + m_renderer->DrawPreviewSurface(preview_size.Width, preview_size.Height, + scale, m_imageable_rect, desired_jobpage, + m_dxgi_previewtarget.Get()); + } + catch (Platform::Exception^ e) + { + hr = e->HResult; + } + } + return hr; +} +#pragma region IPrintPreviewPageCollection Methods diff --git a/platform/winrt/mupdf_cpp/PrintPage.h b/platform/winrt/mupdf_cpp/PrintPage.h new file mode 100644 index 00000000..725a5a43 --- /dev/null +++ b/platform/winrt/mupdf_cpp/PrintPage.h @@ -0,0 +1,57 @@ +#pragma once +#include <windows.graphics.printing.h> +#include <printpreview.h> +#include <documentsource.h> +#include "MainPage.xaml.h" + +using namespace Microsoft::WRL; +using namespace mupdf_cpp; + +/* This is the interface to the print thread calls */ +class PrintPages : public Microsoft::WRL::RuntimeClass<Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::WinRtClassicComMix>, + ABI::Windows::Graphics::Printing::IPrintDocumentSource, + IPrintDocumentPageSource, + IPrintPreviewPageCollection> +{ +private: + InspectableClass(L"Windows.Graphics.Printing.IPrintDocumentSource", BaseTrust); + +public: + HRESULT RuntimeClassInitialize(IUnknown* pageRenderer) + { + HRESULT hr = (pageRenderer != nullptr) ? S_OK : E_INVALIDARG; + + if (SUCCEEDED(hr)) + { + m_paginate_called = false; + m_totalpages = 1; + m_height = 0.f; + m_width = 0.f; + m_renderer = reinterpret_cast<MainPage^>(pageRenderer); + } + return hr; + } + IFACEMETHODIMP GetPreviewPageCollection(IPrintDocumentPackageTarget* doc_target, + IPrintPreviewPageCollection** doc_collection); + IFACEMETHODIMP MakeDocument(IInspectable* doc_options, + IPrintDocumentPackageTarget* doc_target); + IFACEMETHODIMP Paginate(uint32 current_jobpage, IInspectable* doc_options); + IFACEMETHODIMP MakePage(uint32 desired_jobpage, float width, float height); + void ResetPreview(); + +private: + float TransformedPageSize(float desired_width, float desired_height, + Windows::Foundation::Size* preview_size); + uint32 m_totalpages; + bool m_paginate_called; + float m_height; + float m_width; + D2D1_RECT_F m_imageable_rect; + MainPage^ m_renderer; + + Microsoft::WRL::ComPtr<IPrintPreviewDxgiPackageTarget> m_dxgi_previewtarget; + + void DrawPreviewSurface(float width, float height, float scale_in, + D2D1_RECT_F contentBox, uint32 page_num, + IPrintPreviewDxgiPackageTarget* previewTarget); +}; diff --git a/platform/winrt/mupdf_cpp/mupdf_cpp.vcxproj b/platform/winrt/mupdf_cpp/mupdf_cpp.vcxproj index eeeb7634..baa51c03 100644 --- a/platform/winrt/mupdf_cpp/mupdf_cpp.vcxproj +++ b/platform/winrt/mupdf_cpp/mupdf_cpp.vcxproj @@ -173,7 +173,7 @@ <AdditionalIncludeDirectories>../../include/;../mupdfwinrt/;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> </ClCompile> <Link> - <AdditionalDependencies>kernel32.lib;%(AdditionalDependencies);../$(Platform)/$(Configuration)/libmupdf_winRT.lib;../$(Platform)/$(Configuration)/libthirdparty_winRT.lib;../$(Platform)/$(Configuration)/libmupdf-nov8_winRT.lib;../$(Platform)/$(Configuration)/mupdfwinrt.lib</AdditionalDependencies> + <AdditionalDependencies>D3D11.lib;D2d1.lib;kernel32.lib;%(AdditionalDependencies);../$(Platform)/$(Configuration)/libmupdf_winRT.lib;../$(Platform)/$(Configuration)/libthirdparty_winRT.lib;../$(Platform)/$(Configuration)/libmupdf-nov8_winRT.lib;../$(Platform)/$(Configuration)/mupdfwinrt.lib</AdditionalDependencies> <AdditionalOptions>/APPCONTAINER %(AdditionalOptions)</AdditionalOptions> </Link> </ItemDefinitionGroup> @@ -192,6 +192,7 @@ </ItemDefinitionGroup> <ItemGroup> <ClInclude Include="..\mupdfwinrt\status.h" /> + <ClInclude Include="PrintPage.h" /> <ClInclude Include="DocumentPage.h" /> <ClInclude Include="pch.h" /> <ClInclude Include="App.xaml.h"> @@ -224,6 +225,7 @@ <ClCompile Include="App.xaml.cpp"> <DependentUpon>App.xaml</DependentUpon> </ClCompile> + <ClCompile Include="PrintPage.cpp" /> <ClCompile Include="DocumentPage.cpp" /> <ClCompile Include="MainPage.xaml.cpp"> <DependentUpon>MainPage.xaml</DependentUpon> diff --git a/platform/winrt/mupdf_cpp/mupdf_cpp.vcxproj.filters b/platform/winrt/mupdf_cpp/mupdf_cpp.vcxproj.filters index c1791b26..0a387642 100644 --- a/platform/winrt/mupdf_cpp/mupdf_cpp.vcxproj.filters +++ b/platform/winrt/mupdf_cpp/mupdf_cpp.vcxproj.filters @@ -20,6 +20,7 @@ <ClCompile Include="pch.cpp" /> <ClCompile Include="DocumentPage.cpp" /> <ClCompile Include="RectList.cpp" /> + <ClCompile Include="PrintPage.cpp" /> </ItemGroup> <ItemGroup> <ClInclude Include="pch.h" /> @@ -28,6 +29,7 @@ <ClInclude Include="DocumentPage.h" /> <ClInclude Include="RectList.h" /> <ClInclude Include="..\mupdfwinrt\status.h" /> + <ClInclude Include="PrintPage.h" /> </ItemGroup> <ItemGroup> <AppxManifest Include="Package.appxmanifest" /> diff --git a/platform/winrt/mupdf_cpp/pch.h b/platform/winrt/mupdf_cpp/pch.h index fadf910d..b23c6b70 100644 --- a/platform/winrt/mupdf_cpp/pch.h +++ b/platform/winrt/mupdf_cpp/pch.h @@ -7,3 +7,12 @@ #include <collection.h> #include "App.xaml.h" +/* DirectX requirements */ +#include <wrl.h> +#include <wrl\client.h> +#include <dxgi.h> +#include <dxgi1_2.h> +#include <D2d1_1.h> +#include <D3D11.h> +#include <PrintPreview.h> +#include <Wincodec.h> diff --git a/platform/winrt/mupdfwinrt/muctx.cpp b/platform/winrt/mupdfwinrt/muctx.cpp index 98aa7fc6..73c44b05 100644 --- a/platform/winrt/mupdfwinrt/muctx.cpp +++ b/platform/winrt/mupdfwinrt/muctx.cpp @@ -434,7 +434,8 @@ fz_display_list * muctx::CreateDisplayList(int page_num, int *width, int *height /* Render display list bmp_data buffer. No lock needed for this operation */ status_t muctx::RenderPageMT(void *dlist, int page_width, int page_height, - unsigned char *bmp_data, int bmp_width, int bmp_height) + unsigned char *bmp_data, int bmp_width, int bmp_height, + bool flipy) { fz_device *dev = NULL; fz_pixmap *pix = NULL; @@ -453,8 +454,11 @@ status_t muctx::RenderPageMT(void *dlist, int page_width, int page_height, /* Figure out scale factors so that we get the desired size */ pctm = fz_scale(pctm, (float) bmp_width / page_width, (float) bmp_height / page_height); /* Flip on Y */ - ctm.f = bmp_height; - ctm.d = -ctm.d; + if (flipy) + { + ctm.f = bmp_height; + ctm.d = -ctm.d; + } pix = fz_new_pixmap_with_data(ctx_clone, fz_device_bgr(ctx_clone), bmp_width, bmp_height, bmp_data); fz_clear_pixmap_with_value(ctx_clone, pix, 255); @@ -479,7 +483,7 @@ status_t muctx::RenderPageMT(void *dlist, int page_width, int page_height, /* Render page_num to size width by height into bmp_data buffer. Lock needed. */ status_t muctx::RenderPage(int page_num, unsigned char *bmp_data, int bmp_width, - int bmp_height) + int bmp_height, bool flipy) { fz_device *dev = NULL; fz_pixmap *pix = NULL; @@ -500,8 +504,11 @@ status_t muctx::RenderPage(int page_num, unsigned char *bmp_data, int bmp_width, pctm = fz_scale(pctm, (float) bmp_width / page_size.X, (float) bmp_height / page_size.Y); /* Flip on Y */ - ctm.f = bmp_height; - ctm.d = -ctm.d; + if (flipy) + { + ctm.f = bmp_height; + ctm.d = -ctm.d; + } pix = fz_new_pixmap_with_data(mu_ctx, fz_device_bgr(mu_ctx), bmp_width, bmp_height, bmp_data); fz_clear_pixmap_with_value(mu_ctx, pix, 255); diff --git a/platform/winrt/mupdfwinrt/muctx.h b/platform/winrt/mupdfwinrt/muctx.h index cfaa1cae..33f6acc5 100644 --- a/platform/winrt/mupdfwinrt/muctx.h +++ b/platform/winrt/mupdfwinrt/muctx.h @@ -86,9 +86,10 @@ public: int GetPageCount(); status_t InitializeContext(); status_t RenderPage(int page_num, unsigned char *bmp_data, int bmp_width, - int bmp_height); + int bmp_height, bool flipy); status_t RenderPageMT(void *dlist, int page_width, int page_height, - unsigned char *bmp_data, int bmp_width, int bmp_height); + unsigned char *bmp_data, int bmp_width, int bmp_height, + bool flipy); fz_display_list* CreateDisplayList(int page_num, int *width, int *height); Point MeasurePage(int page_num); Point MeasurePage(fz_page *page); diff --git a/platform/winrt/mupdfwinrt/mudocument.cpp b/platform/winrt/mupdfwinrt/mudocument.cpp index 7c90ba18..d4855dd9 100644 --- a/platform/winrt/mupdfwinrt/mudocument.cpp +++ b/platform/winrt/mupdfwinrt/mudocument.cpp @@ -167,6 +167,50 @@ Windows::Foundation::IAsyncOperationWithProgress<int, double>^ }); } +/* Pack the page into a bitmap. This is used in the DirectX code for printing + not in the xaml related code. */ +int mudocument::RenderPageBitmapSync(int page_num, int bmp_width, int bmp_height, + bool use_dlist, Array<unsigned char>^* bit_map) +{ + status_t code; + /* Allocate space for bmp */ + Array<unsigned char>^ bmp_data = + ref new Array<unsigned char>(bmp_height * 4 * bmp_width); + + if (use_dlist) + { + void *dlist; + int page_height; + int page_width; + + mutex_lock.lock(); + /* This lock will keep out issues in mupdf as well as race conditions + in the page cache */ + dlist = (void*) mu_object.CreateDisplayList(page_num, &page_width, + &page_height); + /* Rendering of display list can occur with other threads so unlock */ + mutex_lock.unlock(); + code = mu_object.RenderPageMT(dlist, page_width, page_height, + &(bmp_data[0]), bmp_width, bmp_height, + false); + } + else + { + /* Rendering in immediate mode. Keep lock in place */ + mutex_lock.lock(); + code = mu_object.RenderPage(page_num, &(bmp_data[0]), bmp_width, + bmp_height, false); + mutex_lock.unlock(); + } + if (code != S_ISOK) + { + throw ref new FailureException("Page Rendering Failed"); + } + + *bit_map = bmp_data; + return (int) code; +} + /* Pack the page into a bmp stream */ Windows::Foundation::IAsyncOperation<InMemoryRandomAccessStream^>^ mudocument::RenderPageAsync(int page_num, int bmp_width, int bmp_height, @@ -200,14 +244,15 @@ Windows::Foundation::IAsyncOperation<InMemoryRandomAccessStream^>^ /* Rendering of display list can occur with other threads so unlock */ mutex_lock.unlock(); code = mu_object.RenderPageMT(dlist, page_width, page_height, - &(bmp_data[0]), bmp_width, bmp_height); + &(bmp_data[0]), bmp_width, bmp_height, + true); } else { /* Rendering in immediate mode. Keep lock in place */ mutex_lock.lock(); code = mu_object.RenderPage(page_num, &(bmp_data[0]), bmp_width, - bmp_height); + bmp_height, true); mutex_lock.unlock(); } if (code != S_ISOK) diff --git a/platform/winrt/mupdfwinrt/mudocument.h b/platform/winrt/mupdfwinrt/mudocument.h index eebe1fbe..c3356337 100644 --- a/platform/winrt/mupdfwinrt/mudocument.h +++ b/platform/winrt/mupdfwinrt/mudocument.h @@ -34,6 +34,8 @@ namespace mupdfwinrt Point GetPageSize(int page_num); Windows::Foundation::IAsyncOperation<InMemoryRandomAccessStream^>^ RenderPageAsync(int page_num, int width, int height, bool use_dlist); + int RenderPageBitmapSync(int page_num, int bmp_width, int bmp_height, + bool use_dlist, Array<unsigned char>^* bit_map); Windows::Foundation::IAsyncOperationWithProgress<int, double>^ SearchDocumentWithProgressAsync(String^ textToFind, int dir, int start_page, int num_pages); |