diff options
Diffstat (limited to 'platform/winrt/mupdf_cpp')
-rw-r--r-- | platform/winrt/mupdf_cpp/App.xaml.cpp | 22 | ||||
-rw-r--r-- | platform/winrt/mupdf_cpp/MainPage.xaml.cpp | 221 | ||||
-rw-r--r-- | platform/winrt/mupdf_cpp/MainPage.xaml.h | 4 |
3 files changed, 183 insertions, 64 deletions
diff --git a/platform/winrt/mupdf_cpp/App.xaml.cpp b/platform/winrt/mupdf_cpp/App.xaml.cpp index d0b9d8c7..4bb9614c 100644 --- a/platform/winrt/mupdf_cpp/App.xaml.cpp +++ b/platform/winrt/mupdf_cpp/App.xaml.cpp @@ -95,17 +95,23 @@ void App::OnLaunched(Windows::ApplicationModel::Activation::LaunchActivatedEvent } } -// Handle file activations. +/* Handle case where we do a association file opening and the app is already + running */ void App::OnFileActivated(Windows::ApplicationModel::Activation::FileActivatedEventArgs^ args) { - auto rootFrame = ref new Frame(); - TypeName pageType = { "mupdf_cpp.MainPage", TypeKind::Custom }; - rootFrame->Navigate(pageType, args); - Window::Current->Content = rootFrame; - auto rootPage = safe_cast<MainPage^>(rootFrame->Content); - rootPage->FileEvent = args; - rootPage->ProtocolEvent = nullptr; + auto rootFrame = dynamic_cast<Frame^>(Window::Current->Content); + if (rootFrame->Content == nullptr) + { + if (!rootFrame->Navigate(TypeName(MainPage::typeid))) + { + throw ref new FailureException("Failed to create initial page"); + } + } + auto p = dynamic_cast<MainPage^>(rootFrame->Content); + p->FileEvent = args; + p->ProtocolEvent = nullptr; + p->FromFile(); Window::Current->Activate(); } diff --git a/platform/winrt/mupdf_cpp/MainPage.xaml.cpp b/platform/winrt/mupdf_cpp/MainPage.xaml.cpp index c3c8c576..fa717084 100644 --- a/platform/winrt/mupdf_cpp/MainPage.xaml.cpp +++ b/platform/winrt/mupdf_cpp/MainPage.xaml.cpp @@ -149,7 +149,8 @@ void MainPage::SetUpDirectX() m_d2d_factory->CreateDevice(dxgi_device.Get(), &m_d2d_device); } -/* Used during launch of application from file */ +/* Used during launch of application from file when application was not + already running */ void MainPage::Page_Loaded(Object^ sender, RoutedEventArgs^ e) { MainPage^ rootPage = dynamic_cast<MainPage^>(sender); @@ -166,6 +167,23 @@ void MainPage::Page_Loaded(Object^ sender, RoutedEventArgs^ e) } } +/* Used during launch of application from file when application was already + running */ +void MainPage::FromFile() +{ + if (this->FileEvent != nullptr) + { + /* Launched with an "open with", or as default app */ + if (this->FileEvent->Files->Size > 0) + { + IStorageItem ^file = this->FileEvent->Files->GetAt(0); + StorageFile ^sfile = safe_cast<StorageFile^>(file); + + OpenDocumentPrep(sfile); + } + } +} + /// <summary> /// Invoked when this page is about to be displayed in a Frame. /// </summary> @@ -351,10 +369,10 @@ void MainPage::ReplaceImage(int page_num, InMemoryRandomAccessStream^ ras, } int MainPage::ComputePageSize(spatial_info_t spatial_info, int page_num, - Point *point) + Point *render_size, float *scale_factor) { Point screenSize; - Point pageSize; + Point renpageSize; Point size; try @@ -376,10 +394,12 @@ int MainPage::ComputePageSize(spatial_info_t spatial_info, int page_num, float hscale = screenSize.X / size.X; float vscale = screenSize.Y / size.Y; float scale = min(hscale, vscale); - pageSize.X = (float) (size.X * scale * spatial_info.scale_factor); - pageSize.Y = (float) (size.Y * scale * spatial_info.scale_factor); + renpageSize.X = (float)(size.X * scale * spatial_info.scale_factor); + renpageSize.Y = (float)(size.Y * scale * spatial_info.scale_factor); + + *scale_factor = (float) (scale * spatial_info.scale_factor); + *render_size = renpageSize; - *point = pageSize; return S_ISOK; } @@ -618,6 +638,7 @@ void MainPage::RenderThumbs() Point ras_size; Array<unsigned char>^ bmp_data; int code; + float scale_factor; /* The renderings run on a background thread */ assert(IsBackgroundThread()); @@ -625,10 +646,11 @@ void MainPage::RenderThumbs() for (int k = 0; k < num_pages; k++) { - if (ComputePageSize(spatial_info_local, k, &ras_size) == S_ISOK) + if (ComputePageSize(spatial_info_local, k, &ras_size, &scale_factor) == S_ISOK) { code = mu_doc->RenderPageBitmapSync(k, (int)ras_size.X, - (int)ras_size.Y, false, true, &bmp_data); + (int)ras_size.Y, scale_factor, false, true, false, { 0, 0 }, + { ras_size.X, ras_size.Y }, &bmp_data); DocumentPage^ doc_page = ref new DocumentPage(); doc_page->Height = (int)(ras_size.Y / SCALE_THUMB); @@ -809,9 +831,11 @@ void MainPage::InitialRender() if (m_num_pages > k ) { Point ras_size; - if (ComputePageSize(spatial_info, k, &ras_size) == S_ISOK) + float scale_factor; + + if (ComputePageSize(spatial_info, k, &ras_size, &scale_factor) == S_ISOK) { - auto render_task = create_task(mu_doc->RenderPageAsync(k, (int) ras_size.X, (int) ras_size.Y, true)); + auto render_task = create_task(mu_doc->RenderPageAsync(k, (int)ras_size.X, (int)ras_size.Y, true, scale_factor)); render_task.then([this, k, ras_size](InMemoryRandomAccessStream^ ras) { if (ras != nullptr) @@ -857,10 +881,11 @@ void MainPage::RenderRange(int curr_page) doc->PageZoom != m_doczoom) { Point ras_size; - if (ComputePageSize(spatial_info, k, &ras_size) == S_ISOK) + float scale_factor; + if (ComputePageSize(spatial_info, k, &ras_size, &scale_factor) == S_ISOK) { double zoom = m_doczoom; - auto render_task = create_task(mu_doc->RenderPageAsync(k, (int) ras_size.X, (int) ras_size.Y, true)); + auto render_task = create_task(mu_doc->RenderPageAsync(k, (int)ras_size.X, (int)ras_size.Y, true, scale_factor)); render_task.then([this, k, ras_size, zoom, curr_page](InMemoryRandomAccessStream^ ras) { if (ras != nullptr) @@ -1627,10 +1652,11 @@ void MainPage::ScrollChanged(Platform::Object^ sender, /* Render at new resolution. */ spatial_info_t spatial_info = InitSpatial(m_doczoom); Point ras_size; - if (ComputePageSize(spatial_info, page, &ras_size) == S_ISOK) + float scale_factor; + if (ComputePageSize(spatial_info, page, &ras_size, &scale_factor) == S_ISOK) { doc_page->PageZoom = m_doczoom; - auto render_task = create_task(mu_doc->RenderPageAsync(page, (int) ras_size.X, (int) ras_size.Y, true)); + auto render_task = create_task(mu_doc->RenderPageAsync(page, (int)ras_size.X, (int)ras_size.Y, true, scale_factor)); render_task.then([this, page, ras_size, scrollviewer](InMemoryRandomAccessStream^ ras) { if (ras != nullptr) @@ -2078,7 +2104,7 @@ void MainPage::DrawPreviewSurface(float width, float height, float scale_in, 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)); + D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE)); // Create surface bitmap on which page content is drawn. ComPtr<ID2D1Bitmap1> d2d_surfacebitmap; @@ -2092,8 +2118,9 @@ void MainPage::DrawPreviewSurface(float width, float height, float scale_in, spatial_info.size.X = width; spatial_info.size.Y = height; Point ras_size; + float scale_factor; - if (ComputePageSize(spatial_info, ren_page_num, &ras_size) != S_ISOK) + if (ComputePageSize(spatial_info, ren_page_num, &ras_size, &scale_factor) != S_ISOK) return; ras_size.X = ceil(ras_size.X); @@ -2101,22 +2128,22 @@ void MainPage::DrawPreviewSurface(float width, float height, float scale_in, Array<unsigned char>^ bmp_data; int code = mu_doc->RenderPageBitmapSync(ren_page_num, (int) ras_size.X, - (int) ras_size.Y, true, false, - &bmp_data); + (int)ras_size.Y, scale_factor, true, false, false, { 0, 0 }, + { ras_size.X, ras_size.Y }, &bmp_data); if (bmp_data == nullptr) return; D2D1_SIZE_U bit_map_rect; bit_map_rect.width = (UINT32) (ras_size.X); bit_map_rect.height = (UINT32) (ras_size.Y); - D2D1_BITMAP_PROPERTIES1 bitmap_properties2 = + D2D1_BITMAP_PROPERTIES1 bitmap_prop = D2D1::BitmapProperties1(D2D1_BITMAP_OPTIONS_NONE, - D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED)); + D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE)); ID2D1Bitmap1 *bit_map; ThrowIfFailed(d2d_context->CreateBitmap(bit_map_rect, &(bmp_data[0]), (UINT32) (ras_size.X * 4), - &bitmap_properties2, &bit_map)); + &bitmap_prop, &bit_map)); D2D1_SIZE_F size = bit_map->GetSize(); /* Handle centering */ @@ -2141,12 +2168,19 @@ HRESULT MainPage::ClosePrintControl() return (m_d2d_printcontrol == nullptr) ? S_OK : m_d2d_printcontrol->Close(); } +/* To support high resolution printing, we tile renderings at the maxbitmap size + allowed with DirectX for this particular device. e.g the low end surface + will have a smaller maxbitmap size compared to a laptop or desktop. */ 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; + bool tile = false; + Point tile_count; + D2D1_SIZE_U bit_map_rect; + Array<unsigned char>^ bmp_data; if (index_page_num == 0) { @@ -2157,7 +2191,7 @@ void MainPage::PrintPage(uint32 page_num, D2D1_RECT_F image_area, D2D1_SIZE_F pa })); } - /* Windoze seems to hand me a bogus dpi */ + /* Windoze seems to hand me a bogus dpi. Need to follow up on this */ device_dpi = 96; if (m_ppage_num_list.size() > 0) @@ -2170,65 +2204,124 @@ void MainPage::PrintPage(uint32 page_num, D2D1_RECT_F image_area, D2D1_SIZE_F pa ComPtr<ID2D1DeviceContext> d2d_context; ThrowIfFailed(m_d2d_device->CreateDeviceContext(D2D1_DEVICE_CONTEXT_OPTIONS_NONE, &d2d_context)); + + /* This should let us work in pixel dimensions but after much testing + it clearly has some issues. May investigate this further later. */ + //d2d_context->SetUnitMode(D2D1_UNIT_MODE_PIXELS); 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 */ + /* Width and height here are at 96 dpi */ float width = image_area.right - image_area.left; float height = image_area.bottom - image_area.top; + /* MuPDF native resolution is 72dpi */ 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.X = (width / device_dpi) * (m_printresolution); spatial_info.size.Y = (height /device_dpi) * (m_printresolution); Point ras_size; - if (ComputePageSize(spatial_info, ren_page_num, &ras_size) != S_ISOK) + float scale_factor; + + if (ComputePageSize(spatial_info, ren_page_num, &ras_size, &scale_factor) != S_ISOK) return; 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, (int) ras_size.X, - (int) ras_size.Y, true, false, - &bmp_data); - if (bmp_data == nullptr) - return; - D2D1_SIZE_U bit_map_rect; - bit_map_rect.width = (UINT32) (ras_size.X); - bit_map_rect.height = (UINT32) (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]), - (UINT32)(ras_size.X * 4), &bitmap_properties2, &bit_map)); - D2D1_SIZE_F size = bit_map->GetSize(); + /* Determine if we need to do any tiling */ + int tile_size = d2d_context->GetMaximumBitmapSize(); + tile_count.Y = 1; + if (ras_size.X > tile_size) + { + tile = true; + tile_count.X = (float) ceil((float) ras_size.X / (float) tile_size); + bit_map_rect.width = (UINT32) (tile_size); + } + else + { + tile_count.X = 1; + bit_map_rect.width = (UINT32) (ras_size.X); + } + if (ras_size.Y > tile_size) + { + tile = true; + tile_count.Y = (float) ceil((float) ras_size.Y / (float) tile_size); + bit_map_rect.height = (UINT32) (tile_size); + } + else + { + tile_count.Y = 1; + bit_map_rect.height = (UINT32) (ras_size.Y); + } - /* Handle centering */ + /* Adjust for centering in media page */ float y_offset = 0; float x_offset = 0; - if (m_centerprint) + if (m_centerprint) { - /* Offsets need to be provided in the device dpi */ - y_offset = (float) ((page_area.height - (size.height * device_dpi / m_printresolution)) / 2.0); - x_offset = (float) ((page_area.width - (size.width * device_dpi / m_printresolution)) / 2.0); + y_offset = (float)round(((page_area.height - (ras_size.Y) * device_dpi / m_printresolution) / 2.0)); + x_offset = (float)round(((page_area.width - (ras_size.X) * 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; + D2D1_BITMAP_PROPERTIES1 bitmap_prop = + D2D1::BitmapProperties1(D2D1_BITMAP_OPTIONS_NONE, + D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE), + (float) m_printresolution, (float) m_printresolution); + + ID2D1Bitmap1 *bit_map = NULL; + Point top_left, top_left_dip; + Point bottom_right, bottom_right_dip; + + /* Initialize X location */ + top_left.X = 0; + bottom_right.X = (float) bit_map_rect.width; d2d_context->BeginDraw(); - d2d_context->DrawBitmap(bit_map, D2D1::RectF(x_offset, y_offset, - image_width + x_offset, image_height + y_offset)); + /* Useful for debugging */ + //d2d_context->Clear(D2D1::ColorF(D2D1::ColorF::Coral)); + int total_tile = (int) (tile_count.X * tile_count.Y); + + for (int x = 0; x < tile_count.X; x++) + { + /* Reset Y location */ + top_left.Y = 0; + bottom_right.Y = (float) bit_map_rect.height; + + for (int y = 0; y < tile_count.Y; y++) + { + int code = mu_doc->RenderPageBitmapSync(ren_page_num, (int)bit_map_rect.width, + (int)bit_map_rect.height, scale_factor, true, false, tile, top_left, + bottom_right, &bmp_data); + if (bmp_data == nullptr || code != 0) + break; + + ThrowIfFailed(d2d_context->CreateBitmap(bit_map_rect, &(bmp_data[0]), + (UINT32)(bit_map_rect.width * 4), &bitmap_prop, &bit_map)); + + // This is where D2D1_UNIT_MODE_PIXELS fails to work. Essentially, + // DirectX ends up clipping based upon the origin still in DIPS + // instead of actual pixel positions. + top_left_dip.X = (float)((double) top_left.X * (double)device_dpi / (double)m_printresolution + x_offset - 0.5); + top_left_dip.Y = (float)((double)top_left.Y * (double)device_dpi / (double)m_printresolution + y_offset - 0.5); + bottom_right_dip.X = (float)((double)bottom_right.X * (double)device_dpi / (double)m_printresolution + x_offset + 0.5); + bottom_right_dip.Y = (float)((double)bottom_right.Y * (double)device_dpi / (double)m_printresolution + y_offset + 0.5); + d2d_context->DrawBitmap(bit_map, D2D1::RectF(top_left_dip.X, top_left_dip.Y, + bottom_right_dip.X, bottom_right_dip.Y)); + bit_map->Release(); + + /* Increment Y location */ + top_left.Y += (float) bit_map_rect.height; + bottom_right.Y += (float) bit_map_rect.height; + PrintProgressTile(total_tile); + } + /* Increment X location */ + top_left.X += (float) bit_map_rect.width; + bottom_right.X += (float) bit_map_rect.width; + } ThrowIfFailed(d2d_context->EndDraw()); ThrowIfFailed(clist->Close()); ThrowIfFailed(m_d2d_printcontrol->AddPage(clist.Get(), page_area, print_ticket)); - bit_map->Release(); } void MainPage::RefreshPreview() @@ -2260,6 +2353,23 @@ void MainPage::PrintProgress(PrintTask^ sender, PrintTaskProgressingEventArgs^ a })); } +void MainPage::PrintProgressTile(int total_tiles) +{ + assert(IsBackgroundThread()); + double step_size = 100.0 / ((double)GetPrintPageCount() * (double)total_tiles); + /* Update the progress bar if it is still active. The tiling of each + page can be slow on the surface if the resolution is high, hence + the need for this feedback */ + this->Dispatcher->RunAsync(CoreDispatcherPriority::Low, + ref new DispatchedHandler([this, step_size]() + { + if (this->xaml_PrintStack->Visibility != Windows::UI::Xaml::Visibility::Collapsed) + { + xaml_PrintProgress->Value += step_size; + } + })); +} + void MainPage::PrintCompleted(PrintTask^ sender, PrintTaskCompletedEventArgs^ args) { assert(IsBackgroundThread()); @@ -2268,6 +2378,7 @@ void MainPage::PrintCompleted(PrintTask^ sender, PrintTaskCompletedEventArgs^ ar ref new DispatchedHandler([this]() { xaml_PrintStack->Visibility = Windows::UI::Xaml::Visibility::Collapsed; + xaml_PrintProgress->Value = 0; })); } diff --git a/platform/winrt/mupdf_cpp/MainPage.xaml.h b/platform/winrt/mupdf_cpp/MainPage.xaml.h index c7b5e88b..1cf8dd97 100644 --- a/platform/winrt/mupdf_cpp/MainPage.xaml.h +++ b/platform/winrt/mupdf_cpp/MainPage.xaml.h @@ -152,6 +152,7 @@ namespace mupdf_cpp void set(Windows::ApplicationModel::Activation::FileActivatedEventArgs^ value) { _fileEventArgs = value; } } void NotifyUser(String^ strMessage, int type); + void FromFile(); /* For association cases when we are already running */ protected: virtual void OnNavigatedTo(Windows::UI::Xaml::Navigation::NavigationEventArgs^ e) override; @@ -264,7 +265,7 @@ namespace mupdf_cpp void UpdateAppBarButtonViewState(); void ExitInvokedHandler(Windows::UI::Popups::IUICommand^ command); void OKInvokedHandler(Windows::UI::Popups::IUICommand^ command); - int ComputePageSize(spatial_info_t spatial_info, int page_num, Point *Point); + int ComputePageSize(spatial_info_t spatial_info, int page_num, Point *ren_size, float *scale_factor); void ScrollChanged(Platform::Object^ sender, Windows::UI::Xaml::Controls::ScrollViewerViewChangedEventArgs^ e); void LinkTapped(Platform::Object^ sender, Windows::UI::Xaml::Input::TappedRoutedEventArgs^ e); void SearchProgress(IAsyncOperationWithProgress<int, double>^ operation, double status); @@ -309,6 +310,7 @@ namespace mupdf_cpp int GetPrintPageCount(); void SetPrintTarget(void *print_struct); void PrintProgress(PrintTask^ sender, PrintTaskProgressingEventArgs^ args); + void PrintProgressTile(int total_tiles); void PrintCompleted(PrintTask^ sender, PrintTaskCompletedEventArgs^ args); private: void Testing(Platform::Object^ sender, Windows::UI::Xaml::Input::ManipulationCompletedRoutedEventArgs^ e); |