summaryrefslogtreecommitdiff
path: root/platform/winrt
diff options
context:
space:
mode:
Diffstat (limited to 'platform/winrt')
-rw-r--r--platform/winrt/mupdf_cpp/MainPage.xaml.cpp628
-rw-r--r--platform/winrt/mupdf_cpp/MainPage.xaml.h57
-rw-r--r--platform/winrt/mupdf_cpp/PrintPage.cpp165
-rw-r--r--platform/winrt/mupdf_cpp/PrintPage.h57
-rw-r--r--platform/winrt/mupdf_cpp/mupdf_cpp.vcxproj4
-rw-r--r--platform/winrt/mupdf_cpp/mupdf_cpp.vcxproj.filters2
-rw-r--r--platform/winrt/mupdf_cpp/pch.h9
-rw-r--r--platform/winrt/mupdfwinrt/muctx.cpp19
-rw-r--r--platform/winrt/mupdfwinrt/muctx.h5
-rw-r--r--platform/winrt/mupdfwinrt/mudocument.cpp49
-rw-r--r--platform/winrt/mupdfwinrt/mudocument.h2
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);