summaryrefslogtreecommitdiff
path: root/platform/winrt/mupdf_cpp
diff options
context:
space:
mode:
authorMichael Vrhel <michael.vrhel@artifex.com>2014-01-08 22:42:10 -0800
committerMichael Vrhel <michael.vrhel@artifex.com>2014-01-09 14:25:57 -0800
commitcd84c92e68a7a3131895c469294235159ffab4dd (patch)
treec2f3b00708a583e8b6666f2131aab026b7f108e5 /platform/winrt/mupdf_cpp
parent5249664dd8178e985b4ef47af6e1772b4c7665e7 (diff)
downloadmupdf-cd84c92e68a7a3131895c469294235159ffab4dd.tar.xz
Add tiling into the DirectX printing code.
The tiling in x and y is needed to ensure that we can print at high resolutions with devices that have smaller bit map sizes (e.g. the surface). Banding only in the y dimension like we often do is not sufficient. Also fix an open with file association bug that must of occurred with the transition to 8.1 And update WinRT solution for recent changes in mupdf code. This includes the addition of a few new files and the document type registration.
Diffstat (limited to 'platform/winrt/mupdf_cpp')
-rw-r--r--platform/winrt/mupdf_cpp/App.xaml.cpp22
-rw-r--r--platform/winrt/mupdf_cpp/MainPage.xaml.cpp221
-rw-r--r--platform/winrt/mupdf_cpp/MainPage.xaml.h4
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);