Skip to content

Commit

Permalink
[FileExplorer] Add PDF Thumbnail Provider for Windows Explorer (#13058)
Browse files Browse the repository at this point in the history
* Add PdfPreviewHandler to build dependency of runner

* PDF Thumbnail Provider

* Remove using brackets

* Pdf Thumbnail - Settings and Unit Tests

* Removed resx

* Add PDF Thumbnail Provider binary

* Install Pdf Thumbnail Provider

* Fix pagee spelling error.

* Update Windows dependency to version 10.0.18362.0 because that is the minimal required version of the PowerToys.

* Add Pdf Preview Handler and Pdf Thumbnail Provider
  • Loading branch information
rdeveen committed Sep 14, 2021
1 parent 7e22f26 commit 7ac1e00
Show file tree
Hide file tree
Showing 20 changed files with 487 additions and 9 deletions.
5 changes: 2 additions & 3 deletions .pipelines/pipeline.user.windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,6 @@ restore:
name: 'Restore Tools packages'
command: '.pipelines\restore-tools.cmd'



build:
commands:
# Localize the files before the Build PowerToys step to generate translated resx files from the lcl files
Expand Down Expand Up @@ -113,6 +111,8 @@ build:
- 'modules\FileExplorerPreview\MarkdownPreviewHandler.comhost.dll'
- 'modules\FileExplorerPreview\PdfPreviewHandler.dll'
- 'modules\FileExplorerPreview\PdfPreviewHandler.comhost.dll'
- 'modules\FileExplorerPreview\PdfThumbnailProvider.dll'
- 'modules\FileExplorerPreview\PdfThumbnailProvider.comhost.dll'
- 'modules\FileExplorerPreview\powerpreview.dll'
- 'modules\FileExplorerPreview\PreviewHandlerCommon.dll'
- 'modules\FileExplorerPreview\SvgPreviewHandler.dll'
Expand Down Expand Up @@ -229,7 +229,6 @@ build:
signing_options:
sign_inline: true # This does signing as soon as this command completes


#package:
# commands:
# - !!buildcommand
Expand Down
19 changes: 19 additions & 0 deletions PowerToys.sln
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "runner", "src\runner\runner
{0B593A6C-4143-4337-860E-DB5710FB87DB} = {0B593A6C-4143-4337-860E-DB5710FB87DB}
{E364F67B-BB12-4E91-B639-355866EBCD8B} = {E364F67B-BB12-4E91-B639-355866EBCD8B}
{D940E07F-532C-4FF3-883F-790DA014F19A} = {D940E07F-532C-4FF3-883F-790DA014F19A}
{69E1EE8D-143A-4060-9129-4658ACF14AAF} = {69E1EE8D-143A-4060-9129-4658ACF14AAF}
{DA425894-6E13-404F-8DCB-78584EC0557A} = {DA425894-6E13-404F-8DCB-78584EC0557A}
{2BE46397-4DFA-414C-9BD4-41E4BBF8CB34} = {2BE46397-4DFA-414C-9BD4-41E4BBF8CB34}
{A7D5099E-F0FD-4BF3-8522-5A682759F915} = {A7D5099E-F0FD-4BF3-8522-5A682759F915}
Expand Down Expand Up @@ -362,6 +363,10 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "VideoConferenceProxyFilter"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "VideoConference", "VideoConference", "{470FBAF9-E1F8-4F3E-8786-198A1C81C8A8}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PdfThumbnailProvider", "src\modules\previewpane\PdfThumbnailProvider\PdfThumbnailProvider.csproj", "{11491FD8-F921-48BF-880C-7FEA185B80A1}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnitTests-PdfThumbnailProvider", "src\modules\previewpane\UnitTests-PdfThumbnailProvider\UnitTests-PdfThumbnailProvider.csproj", "{F40C3397-1834-4530-B2D9-8F8B8456BCDF}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Expand Down Expand Up @@ -948,6 +953,18 @@ Global
{AC2857B4-103D-4D6D-9740-926EBF785042}.Release|x64.Build.0 = Release|x64
{AC2857B4-103D-4D6D-9740-926EBF785042}.Release|x86.ActiveCfg = Release|Win32
{AC2857B4-103D-4D6D-9740-926EBF785042}.Release|x86.Build.0 = Release|Win32
{11491FD8-F921-48BF-880C-7FEA185B80A1}.Debug|x64.ActiveCfg = Debug|x64
{11491FD8-F921-48BF-880C-7FEA185B80A1}.Debug|x64.Build.0 = Debug|x64
{11491FD8-F921-48BF-880C-7FEA185B80A1}.Debug|x86.ActiveCfg = Debug|x64
{11491FD8-F921-48BF-880C-7FEA185B80A1}.Release|x64.ActiveCfg = Release|x64
{11491FD8-F921-48BF-880C-7FEA185B80A1}.Release|x64.Build.0 = Release|x64
{11491FD8-F921-48BF-880C-7FEA185B80A1}.Release|x86.ActiveCfg = Release|x64
{F40C3397-1834-4530-B2D9-8F8B8456BCDF}.Debug|x64.ActiveCfg = Debug|x64
{F40C3397-1834-4530-B2D9-8F8B8456BCDF}.Debug|x64.Build.0 = Debug|x64
{F40C3397-1834-4530-B2D9-8F8B8456BCDF}.Debug|x86.ActiveCfg = Debug|x64
{F40C3397-1834-4530-B2D9-8F8B8456BCDF}.Release|x64.ActiveCfg = Release|x64
{F40C3397-1834-4530-B2D9-8F8B8456BCDF}.Release|x64.Build.0 = Release|x64
{F40C3397-1834-4530-B2D9-8F8B8456BCDF}.Release|x86.ActiveCfg = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -1061,6 +1078,8 @@ Global
{5ABA70DE-3A3F-41F6-A1F5-D1F74F54F9BB} = {470FBAF9-E1F8-4F3E-8786-198A1C81C8A8}
{AC2857B4-103D-4D6D-9740-926EBF785042} = {470FBAF9-E1F8-4F3E-8786-198A1C81C8A8}
{470FBAF9-E1F8-4F3E-8786-198A1C81C8A8} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
{11491FD8-F921-48BF-880C-7FEA185B80A1} = {2F305555-C296-497E-AC20-5FA1B237996A}
{F40C3397-1834-4530-B2D9-8F8B8456BCDF} = {2F305555-C296-497E-AC20-5FA1B237996A}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {C3A2F9D1-7930-4EF4-A6FC-7EE0A99821D0}
Expand Down
24 changes: 23 additions & 1 deletion installer/PowerToysSetup/Product.wxs
Original file line number Diff line number Diff line change
Expand Up @@ -511,6 +511,19 @@
<RegistryValue Type="string" Key="InprocServer32\$(var.Version).0" Name="Assembly" Value="PdfPreviewHandler, Version=$(var.Version).0, Culture=neutral" />
<RegistryValue Type="string" Key="InprocServer32\$(var.Version).0" Name="Class" Value="Microsoft.PowerToys.PreviewHandler.Pdf.PdfPreviewHandler" />
</RegistryKey>
<!-- Registry Key for Class Registration of Pdf Thumbnail Provider -->
<RegistryKey Root="HKCR" Key="CLSID\{BCC13D15-9720-4CC4-8371-EA74A274741E}">
<RegistryValue Type="string" Value="Microsoft.PowerToys.ThumbnailHandler.Pdf.PdfThumbnailProvider" />
<RegistryValue Type="string" Name="DisplayName" Value="Pdf Thumbnail Provider" />
<RegistryValue Type="string" Name="AppID" Value="{CF142243-F059-45AF-8842-DBBE9783DB14}" />
<RegistryValue Type="string" Key="Implemented Categories\{62C8FE65-4EBB-45e7-B440-6E39B2CDBF29}" Value=""/>
<RegistryValue Type="string" Key="InprocServer32" Value="[FileExplorerPreviewInstallFolder]PdfThumbnailProvider.comhost.dll" />
<RegistryValue Type="string" Key="InprocServer32" Name="Assembly" Value="PdfThumbnailProvider, Version=$(var.Version).0, Culture=neutral" />
<RegistryValue Type="string" Key="InprocServer32" Name="Class" Value="Microsoft.PowerToys.ThumbnailHandler.Pdf.PdfThumbnailProvider" />
<RegistryValue Type="string" Key="InprocServer32" Name="ThreadingModel" Value="Both" />
<RegistryValue Type="string" Key="InprocServer32\$(var.Version).0" Name="Assembly" Value="PdfThumbnailProvider, Version=$(var.Version).0, Culture=neutral" />
<RegistryValue Type="string" Key="InprocServer32\$(var.Version).0" Name="Class" Value="Microsoft.PowerToys.ThumbnailHandler.Pdf.PdfThumbnailProvider" />
</RegistryKey>
<!-- Registry Key for AppID registration -->
<RegistryKey Root="HKCR" Key="AppID\{CF142243-F059-45AF-8842-DBBE9783DB14}">
<RegistryValue Type="expandable" Name="DllSurrogate" Value="%SystemRoot%\system32\prevhost.exe" />
Expand Down Expand Up @@ -543,6 +556,10 @@
<RegistryKey Root="HKCR" Key=".pdf\shellex">
<RegistryValue Type="string" Key="{8895b1c6-b41f-4c1c-a562-0d564250836f}" Value="{07665729-6243-4746-95b7-79579308d1b2}" />
</RegistryKey>
<!-- Add file type association for Pdf Thumbnail Provider -->
<RegistryKey Root="HKCR" Key=".pdf\shellex">
<RegistryValue Type="string" Key="{E357FCCD-A995-4576-B01F-234630154E96}" Value="{BCC13D15-9720-4CC4-8371-EA74A274741E}" />
</RegistryKey>
<!-- Update Key to use IE11 for prevhost.exe -->
<RegistryKey Root="HKLM" Key="Software\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BROWSER_EMULATION">
<RegistryValue Type="integer" Name="prevhost.exe" Value="11000" />
Expand Down Expand Up @@ -791,7 +808,7 @@
<File Source="$(var.BinX64Dir)modules\FileExplorerPreview\SvgPreviewHandler.comhost.dll" />
<File Source="$(var.BinX64Dir)modules\FileExplorerPreview\SvgPreviewHandler.runtimeconfig.json" />
<File Source="$(var.BinX64Dir)modules\FileExplorerPreview\SvgPreviewHandler.deps.json" />
<!-- File to include dll for Svg Preview Handler -->
<!-- File to include dll for Svg Thumbnail Provider -->
<File Source="$(var.BinX64Dir)modules\FileExplorerPreview\SvgThumbnailProvider.dll" />
<File Source="$(var.BinX64Dir)modules\FileExplorerPreview\SvgThumbnailProvider.comhost.dll" />
<File Source="$(var.BinX64Dir)modules\FileExplorerPreview\SvgThumbnailProvider.runtimeconfig.json" />
Expand All @@ -809,6 +826,11 @@
<File Source="$(var.BinX64Dir)modules\FileExplorerPreview\PdfPreviewHandler.comhost.dll" />
<File Source="$(var.BinX64Dir)modules\FileExplorerPreview\PdfPreviewHandler.runtimeconfig.json" />
<File Source="$(var.BinX64Dir)modules\FileExplorerPreview\PdfPreviewHandler.deps.json" />
<!-- File to include dll for Pdf Thumbnail Provider -->
<File Source="$(var.BinX64Dir)modules\FileExplorerPreview\PdfThumbnailProvider.dll" />
<File Source="$(var.BinX64Dir)modules\FileExplorerPreview\PdfThumbnailProvider.comhost.dll" />
<File Source="$(var.BinX64Dir)modules\FileExplorerPreview\PdfThumbnailProvider.runtimeconfig.json" />
<File Source="$(var.BinX64Dir)modules\FileExplorerPreview\PdfThumbnailProvider.deps.json" />
</Component>
</DirectoryRef>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@

<ItemGroup>
<Reference Include="Windows">
<HintPath>$(MSBuildProgramFiles32)\Windows Kits\10\UnionMetadata\10.0.17134.0\Windows.winmd</HintPath>
<HintPath>$(MSBuildProgramFiles32)\Windows Kits\10\UnionMetadata\10.0.18362.0\Windows.winmd</HintPath>
<IsWinMDFile>true</IsWinMDFile>
</Reference>
</ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Drawing;
using System.IO;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using Common.ComInterlop;
using Common.Utilities;
using Windows.Data.Pdf;
using Windows.Storage.Streams;

namespace Microsoft.PowerToys.ThumbnailHandler.Pdf
{
/// <summary>
/// PDF Thumbnail Provider.
/// </summary>
[Guid("BCC13D15-9720-4CC4-8371-EA74A274741E")]
[ClassInterface(ClassInterfaceType.None)]
[ComVisible(true)]
public class PdfThumbnailProvider : IInitializeWithStream, IThumbnailProvider
{
/// <summary>
/// Gets the stream object to access file.
/// </summary>
public IStream Stream { get; private set; }

/// <summary>
/// The maximum dimension (width or height) thumbnail we will generate.
/// </summary>
private const uint MaxThumbnailSize = 10000;

/// <inheritdoc/>
public void Initialize(IStream pstream, uint grfMode)
{
// Ignore the grfMode always use read mode to access the file.
this.Stream = pstream;
}

/// <inheritdoc/>
public void GetThumbnail(uint cx, out IntPtr phbmp, out WTS_ALPHATYPE pdwAlpha)
{
phbmp = IntPtr.Zero;
pdwAlpha = WTS_ALPHATYPE.WTSAT_UNKNOWN;

if (cx == 0 || cx > MaxThumbnailSize)
{
return;
}

using var dataStream = new ReadonlyStream(this.Stream as IStream);
using var memStream = new MemoryStream();

dataStream.CopyTo(memStream);
memStream.Position = 0;

// AsRandomAccessStream() extension method from System.Runtime.WindowsRuntime
var pdf = PdfDocument.LoadFromStreamAsync(memStream.AsRandomAccessStream()).GetAwaiter().GetResult();

if (pdf.PageCount > 0)
{
using var page = pdf.GetPage(0);

var image = PageToImage(page, cx);

using Bitmap thumbnail = new Bitmap(image);

phbmp = thumbnail.GetHbitmap();
pdwAlpha = WTS_ALPHATYPE.WTSAT_RGB;
}
}

/// <summary>
/// Transform the PdfPage to an Image.
/// </summary>
/// <param name="page">The page to transform to an Image.</param>
/// <param name="height">The height of the page.</param>
/// <returns>An object of type <see cref="Image"/></returns>
private static Image PageToImage(PdfPage page, uint height)
{
Image imageOfPage;

using var stream = new InMemoryRandomAccessStream();

page.RenderToStreamAsync(stream, new PdfPageRenderOptions()
{
DestinationHeight = height,
}).GetAwaiter().GetResult();

imageOfPage = Image.FromStream(stream.AsStream());

return imageOfPage;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<PropertyGroup>
<Platforms>x64</Platforms>
<UseWindowsForms>true</UseWindowsForms>
<ProjectGuid>{11491FD8-F921-48BF-880C-7FEA185B80A1}</ProjectGuid>
<RootNamespace>Microsoft.PowerToys.ThumbnailHandler.Pdf</RootNamespace>
<AssemblyName>PdfThumbnailProvider</AssemblyName>
<AssemblyTitle>PdfThumbnailProvider</AssemblyTitle>
<AssemblyDescription>PowerToys PdfPreviewHandler</AssemblyDescription>
<AssemblyCompany>Microsoft Corporation</AssemblyCompany>
<AssemblyCopyright>Copyright (C) 2020 Microsoft Corporation</AssemblyCopyright>
<AssemblyProduct>PowerToys</AssemblyProduct>
<TargetFramework>netcoreapp3.1</TargetFramework>
<EnableComHosting>true</EnableComHosting>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<Company>Microsoft Corporation</Company>
<Product>PowerToys</Product>
<NeutralLanguage>en-US</NeutralLanguage>
<Description>PowerToys PdfPreviewHandler</Description>
<Copyright>Copyright (C) 2020 Microsoft Corporation</Copyright>
<OutputPath>$(SolutionDir)$(Platform)\$(Configuration)\modules\FileExplorerPreview\</OutputPath>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
</PropertyGroup>

<Import Project="..\..\..\Version.props" />

<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="3.3.0">
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Microsoft.CodeAnalysis.VersionCheckAnalyzer" Version="3.3.0">
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Microsoft.CodeQuality.Analyzers" Version="3.3.0">
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Microsoft.NetCore.Analyzers" Version="3.3.0">
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Microsoft.NetFramework.Analyzers" Version="3.3.0">
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118">
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="System.Runtime.WindowsRuntime" Version="4.7.0" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\..\..\codeAnalysis\GlobalSuppressions.cs" Link="GlobalSuppressions.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\common\ManagedTelemetry\Telemetry\ManagedTelemetry.csproj" />
<ProjectReference Include="..\Common\PreviewHandlerCommon.csproj" />
</ItemGroup>
<ItemGroup>
<AdditionalFiles Include="..\..\..\codeAnalysis\StyleCop.json">
<Link>StyleCop.json</Link>
</AdditionalFiles>
</ItemGroup>

<ItemGroup>
<Reference Include="Windows">
<HintPath>$(MSBuildProgramFiles32)\Windows Kits\10\UnionMetadata\10.0.18362.0\Windows.winmd</HintPath>
<IsWinMDFile>true</IsWinMDFile>
</Reference>
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
using System.Windows.Forms;
using Common.ComInterlop;
using Common.Utilities;
using Microsoft.PowerToys.Telemetry;
using PreviewHandlerCommon;

namespace Microsoft.PowerToys.ThumbnailHandler.Svg
Expand Down
Binary file not shown.

0 comments on commit 7ac1e00

Please sign in to comment.