fix Exif rotation in ImageViewer; WIP on archive viewer

This commit is contained in:
Paddy Xu
2017-04-28 00:08:26 +03:00
parent 7dcb0e615b
commit a5442faa12
17 changed files with 495 additions and 273 deletions

View File

@@ -0,0 +1,85 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Windows;
using SharpCompress.Archives.SevenZip;
using SharpCompress.Common;
using SharpCompress.Readers;
namespace QuickLook.Plugin.ArchiveViewer
{
public class Plugin : IViewer
{
public int Priority => 0;
public bool CanHandle(string path)
{
if (Directory.Exists(path))
return false;
using (var s = File.OpenRead(path))
{
// The 7Zip format doesn't allow for reading as a forward-only stream so
// 7Zip is only supported through the Archive API.
if (SevenZipArchive.IsSevenZipFile(s))
return true;
s.Seek(0, SeekOrigin.Begin);
try
{
ReaderFactory.Open(s);
}
catch (InvalidOperationException)
{
return false;
}
}
return true;
}
public void Prepare(string path, ViewContentContainer container)
{
container.PreferedSize = new Size {Width = 800, Height = 600};
}
public void View(string path, ViewContentContainer container)
{
var files = new List<IEntry>();
if (SevenZipArchive.IsSevenZipFile(path))
GetItemsFromSevenZip(path, files);
else
GetItemsFromIReader(path, files);
}
public void Close()
{
throw new NotImplementedException();
}
private void GetItemsFromSevenZip(string path, List<IEntry> files)
{
using (var s = File.OpenRead(path))
{
using (var reader = SevenZipArchive.Open(s))
{
foreach (var entry in reader.Entries)
files.Add(entry);
}
}
}
private void GetItemsFromIReader(string path, List<IEntry> files)
{
using (var s = File.OpenRead(path))
{
using (var reader = ReaderFactory.Open(s))
{
while (reader.MoveToNextEntry())
files.Add(reader.Entry);
}
}
}
}
}

View File

@@ -0,0 +1,35 @@
using System.Reflection;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("QuickLook.Plugin.ArchiveViewer")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("QuickLook.Plugin.ArchiveViewer")]
[assembly: AssemblyCopyright("Copyright © 2017")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("de2e3bc5-6ab2-4420-a160-48c7a7506c1c")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@@ -0,0 +1,66 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{DE2E3BC5-6AB2-4420-A160-48C7A7506C1C}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>QuickLook.Plugin.ArchiveViewer</RootNamespace>
<AssemblyName>QuickLook.Plugin.ArchiveViewer</AssemblyName>
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>..\Build\Debug\Plugins\QuickLook.Plugin.ArchiveViewer\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<PlatformTarget>x86</PlatformTarget>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>..\Build\Release\Plugins\QuickLook.Plugin.ArchiveViewer\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<PlatformTarget>x86</PlatformTarget>
</PropertyGroup>
<ItemGroup>
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
<Reference Include="SharpCompress, Version=0.15.2.0, Culture=neutral, PublicKeyToken=afb0a02973931d96, processorArchitecture=MSIL">
<HintPath>..\packages\SharpCompress.0.15.2\lib\net45\SharpCompress.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xaml" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
<Reference Include="WindowsBase" />
</ItemGroup>
<ItemGroup>
<Compile Include="Plugin.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\QuickLook\QuickLook.csproj">
<Project>{8b4a9ce5-67b5-4a94-81cb-3771f688fdeb}</Project>
<Name>QuickLook</Name>
<Private>False</Private>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="SharpCompress" version="0.15.2" targetFramework="net452" />
</packages>

View File

@@ -0,0 +1,53 @@
using System.IO;
using System.Windows;
using System.Windows.Media.Imaging;
namespace QuickLook.Plugin.ImageViewer
{
internal static class ImageFileHelper
{
internal static Size GetImageSize(string path)
{
var ori = GetOrientationFromExif(path);
using (var stream = File.OpenRead(path))
{
var decoder = BitmapDecoder.Create(stream, BitmapCreateOptions.None, BitmapCacheOption.None);
var frame = decoder.Frames[0];
if (ori == ExifOrientation.Rotate90CW || ori == ExifOrientation.Rotate270CW)
return new Size {Width = frame.PixelHeight, Height = frame.PixelWidth};
return new Size {Width = frame.PixelWidth, Height = frame.PixelHeight};
}
}
internal static ExifOrientation GetOrientationFromExif(string path)
{
using (var stream = File.OpenRead(path))
{
var decoder = BitmapDecoder.Create(stream, BitmapCreateOptions.None, BitmapCacheOption.None);
var frame = decoder.Frames[0];
var orientation = ((BitmapMetadata) frame.Metadata).GetQuery(@"/app1/{ushort=0}/{ushort=274}");
if (orientation == null)
return ExifOrientation.Horizontal;
return (ExifOrientation) (ushort) orientation;
}
}
internal enum ExifOrientation
{
Horizontal = 1,
MirrorHorizontal = 2,
Rotate180 = 3,
MirrorVertical = 4,
MirrorHorizontal270CW = 5,
Rotate90CW = 6,
MirrorHorizontal90CW = 7,
Rotate270CW = 8
}
}
}

View File

@@ -1,4 +1,5 @@
using System; using System;
using System.IO;
using System.Windows; using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
using System.Windows.Input; using System.Windows.Input;
@@ -20,7 +21,22 @@ namespace QuickLook.Plugin.ImageViewer
{ {
InitializeComponent(); InitializeComponent();
viewPanelImage.Source = new BitmapImage(new Uri(path)); var ori = ImageFileHelper.GetOrientationFromExif(path);
var bitmap = new BitmapImage();
using (var fs = File.OpenRead(path))
{
bitmap.BeginInit();
bitmap.StreamSource = fs;
bitmap.CacheOption = BitmapCacheOption.OnLoad;
bitmap.Rotation = ori == ImageFileHelper.ExifOrientation.Rotate90CW
? Rotation.Rotate90
: ori == ImageFileHelper.ExifOrientation.Rotate270CW
? Rotation.Rotate270
: Rotation.Rotate0;
bitmap.EndInit();
}
viewPanelImage.Source = bitmap;
Loaded += (sender, e) => { ZoomToFit(); }; Loaded += (sender, e) => { ZoomToFit(); };

View File

@@ -1,16 +1,14 @@
using System; using System.IO;
using System.IO;
using System.Windows; using System.Windows;
using System.Windows.Media.Imaging;
namespace QuickLook.Plugin.ImageViewer namespace QuickLook.Plugin.ImageViewer
{ {
public class Plugin : IViewer public class Plugin : IViewer
{ {
private Size _imageSize;
private ImagePanel _ip; private ImagePanel _ip;
private BitmapDecoder decoder;
public int Priority { get; } public int Priority => 9999;
public bool CanHandle(string path) public bool CanHandle(string path)
{ {
@@ -37,10 +35,9 @@ namespace QuickLook.Plugin.ImageViewer
public void Prepare(string path, ViewContentContainer container) public void Prepare(string path, ViewContentContainer container)
{ {
decoder = BitmapDecoder.Create(new Uri(path), BitmapCreateOptions.None, BitmapCacheOption.None); _imageSize = ImageFileHelper.GetImageSize(path);
var frame = decoder.Frames[0];
container.SetPreferedSizeFit(new Size {Width = frame.Width, Height = frame.Height}, 0.6); container.SetPreferedSizeFit(_imageSize, 0.8);
} }
public void View(string path, ViewContentContainer container) public void View(string path, ViewContentContainer container)
@@ -48,7 +45,7 @@ namespace QuickLook.Plugin.ImageViewer
_ip = new ImagePanel(path); _ip = new ImagePanel(path);
container.SetContent(_ip); container.SetContent(_ip);
container.Title = $"{Path.GetFileName(path)}"; container.Title = $"{Path.GetFileName(path)} ({_imageSize.Width} × {_imageSize.Height})";
} }
public void Close() public void Close()

View File

@@ -49,6 +49,7 @@
</Reference> </Reference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="ImageFileHelper.cs" />
<Compile Include="ImagePanel.xaml.cs"> <Compile Include="ImagePanel.xaml.cs">
<DependentUpon>ImagePanel.xaml</DependentUpon> <DependentUpon>ImagePanel.xaml</DependentUpon>
</Compile> </Compile>

View File

@@ -14,6 +14,10 @@ namespace QuickLook.Plugin.LastResort
public static BitmapSource ToBitmapSource(this Bitmap source) public static BitmapSource ToBitmapSource(this Bitmap source)
{ {
// BitmapSource.Create throws an exception when the image is scanned backward.
// The Clone() will make it back scanning forward.
source = (Bitmap) source.Clone();
var ip = source.GetHbitmap(); var ip = source.GetHbitmap();
BitmapSource bs = null; BitmapSource bs = null;
try try

View File

@@ -1,256 +0,0 @@
using System;
using System.Drawing;
using System.IO;
using System.Runtime.InteropServices;
// ReSharper disable InconsistentNaming
namespace QuickLook.Plugin.LastResort
{
public static class IconHelper
{
public enum IconSizeEnum
{
SmallIcon16 = SHGFI_SMALLICON,
MediumIcon32 = SHGFI_LARGEICON,
LargeIcon48 = SHIL_EXTRALARGE,
ExtraLargeIcon = SHIL_JUMBO
}
private const int SHGFI_SMALLICON = 0x1;
private const int SHGFI_LARGEICON = 0x0;
private const int SHIL_JUMBO = 0x4;
private const int SHIL_EXTRALARGE = 0x2;
private const int WM_CLOSE = 0x0010;
[DllImport("user32")]
private static extern
IntPtr SendMessage(
IntPtr handle,
int Msg,
IntPtr wParam,
IntPtr lParam);
[DllImport("shell32.dll")]
private static extern int SHGetImageList(
int iImageList,
ref Guid riid,
out IImageList ppv);
[DllImport("Shell32.dll")]
private static extern int SHGetFileInfo(
string pszPath,
int dwFileAttributes,
ref SHFILEINFO psfi,
int cbFileInfo,
uint uFlags);
[DllImport("user32")]
private static extern int DestroyIcon(
IntPtr hIcon);
public static Bitmap GetBitmapFromFolderPath(
string filepath, IconSizeEnum iconsize)
{
var hIcon = GetIconHandleFromFolderPath(filepath, iconsize);
return getBitmapFromIconHandle(hIcon);
}
public static Bitmap GetBitmapFromFilePath(
string filepath, IconSizeEnum iconsize)
{
var hIcon = GetIconHandleFromFilePath(filepath, iconsize);
return getBitmapFromIconHandle(hIcon);
}
public static Bitmap GetBitmapFromPath(
string filepath, IconSizeEnum iconsize)
{
var hIcon = IntPtr.Zero;
if (Directory.Exists(filepath))
{
hIcon = GetIconHandleFromFolderPath(filepath, iconsize);
}
else
{
if (File.Exists(filepath))
hIcon = GetIconHandleFromFilePath(filepath, iconsize);
}
return getBitmapFromIconHandle(hIcon);
}
private static Bitmap getBitmapFromIconHandle(IntPtr hIcon)
{
if (hIcon == IntPtr.Zero) throw new FileNotFoundException();
var myIcon = Icon.FromHandle(hIcon);
var bitmap = myIcon.ToBitmap();
myIcon.Dispose();
DestroyIcon(hIcon);
SendMessage(hIcon, WM_CLOSE, IntPtr.Zero, IntPtr.Zero);
return bitmap;
}
private static IntPtr GetIconHandleFromFilePath(string filepath, IconSizeEnum iconsize)
{
var shinfo = new SHFILEINFO();
const uint SHGFI_SYSICONINDEX = 0x4000;
const int FILE_ATTRIBUTE_NORMAL = 0x80;
var flags = SHGFI_SYSICONINDEX;
return getIconHandleFromFilePathWithFlags(filepath, iconsize, ref shinfo, FILE_ATTRIBUTE_NORMAL, flags);
}
private static IntPtr GetIconHandleFromFolderPath(string folderpath, IconSizeEnum iconsize)
{
var shinfo = new SHFILEINFO();
const uint SHGFI_ICON = 0x000000100;
const uint SHGFI_USEFILEATTRIBUTES = 0x000000010;
const int FILE_ATTRIBUTE_DIRECTORY = 0x00000010;
var flags = SHGFI_ICON | SHGFI_USEFILEATTRIBUTES;
return getIconHandleFromFilePathWithFlags(folderpath, iconsize, ref shinfo, FILE_ATTRIBUTE_DIRECTORY,
flags);
}
private static IntPtr getIconHandleFromFilePathWithFlags(
string filepath, IconSizeEnum iconsize,
ref SHFILEINFO shinfo, int fileAttributeFlag, uint flags)
{
const int ILD_TRANSPARENT = 1;
var retval = SHGetFileInfo(filepath, fileAttributeFlag, ref shinfo, Marshal.SizeOf(shinfo), flags);
if (retval == 0) throw new FileNotFoundException();
var iconIndex = shinfo.iIcon;
var iImageListGuid = new Guid("46EB5926-582E-4017-9FDF-E8998DAA0950");
IImageList iml;
var hres = SHGetImageList((int) iconsize, ref iImageListGuid, out iml);
var hIcon = IntPtr.Zero;
hres = iml.GetIcon(iconIndex, ILD_TRANSPARENT, ref hIcon);
return hIcon;
}
}
[ComImport]
[Guid("46EB5926-582E-4017-9FDF-E8998DAA0950")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IImageList
{
[PreserveSig]
int Add(
IntPtr hbmImage,
IntPtr hbmMask,
ref int pi);
[PreserveSig]
int ReplaceIcon(
int i,
IntPtr hicon,
ref int pi);
[PreserveSig]
int SetOverlayImage(
int iImage,
int iOverlay);
[PreserveSig]
int Replace(
int i,
IntPtr hbmImage,
IntPtr hbmMask);
[PreserveSig]
int AddMasked(
IntPtr hbmImage,
int crMask,
ref int pi);
[PreserveSig]
int Draw(
ref IMAGELISTDRAWPARAMS pimldp);
[PreserveSig]
int Remove(
int i);
[PreserveSig]
int GetIcon(
int i,
int flags,
ref IntPtr picon);
}
[StructLayout(LayoutKind.Sequential)]
public struct IMAGEINFO
{
public IntPtr hbmImage;
public IntPtr hbmMask;
public int Unused1;
public int Unused2;
public RECT rcImage;
}
public struct IMAGELISTDRAWPARAMS
{
public int cbSize;
public IntPtr himl;
public int i;
public IntPtr hdcDst;
public int x;
public int y;
public int cx;
public int cy;
public int xBitmap;
public int yBitmap;
public int rgbBk;
public int rgbFg;
public int fStyle;
public int dwRop;
public int fState;
public int Frame;
public int crEffect;
}
[StructLayout(LayoutKind.Sequential)]
public struct POINT
{
private readonly int X;
private readonly int Y;
public POINT(int x, int y)
{
X = x;
Y = y;
}
public POINT(Point pt) : this(pt.X, pt.Y)
{
}
public static implicit operator Point(POINT p)
{
return new Point(p.X, p.Y);
}
public static implicit operator POINT(Point p)
{
return new POINT(p.X, p.Y);
}
}
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
public struct SHFILEINFO
{
public IntPtr hIcon;
public int iIcon;
public uint dwAttributes;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 254)] public string szDisplayName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] public string szTypeName;
}
}

View File

@@ -10,7 +10,7 @@
<ColumnDefinition Width="150" /> <ColumnDefinition Width="150" />
<ColumnDefinition Width="65*" /> <ColumnDefinition Width="65*" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<Image x:Name="image" Grid.Column="0" Height="128" Width="128" Stretch="Fill" /> <Image x:Name="image" Grid.Column="0" Height="128" Width="128" Stretch="None" />
<Grid Grid.Column="1"> <Grid Grid.Column="1">
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="20*" /> <ColumnDefinition Width="20*" />

View File

@@ -24,9 +24,13 @@ namespace QuickLook.Plugin.LastResort
public void DisplayInfo(string path) public void DisplayInfo(string path)
{ {
var icon = IconHelper.GetBitmapFromPath(path, IconHelper.IconSizeEnum.ExtraLargeIcon).ToBitmapSource(); var icon =
WindowsThumbnailProvider.GetThumbnail(path, 256, 256,
ThumbnailOptions.ScaleUp);
image.Source = icon; image.Source = icon.ToBitmapSource();
icon.Dispose();
var name = Path.GetFileName(path); var name = Path.GetFileName(path);
filename.Content = string.IsNullOrEmpty(name) ? path : name; filename.Content = string.IsNullOrEmpty(name) ? path : name;

View File

@@ -54,7 +54,7 @@
</Compile> </Compile>
<Compile Include="Plugin.cs" /> <Compile Include="Plugin.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="IconHelper.cs" /> <Compile Include="WindowsThumbnailProvider.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\QuickLook\QuickLook.csproj"> <ProjectReference Include="..\QuickLook\QuickLook.csproj">

View File

@@ -0,0 +1,203 @@
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Runtime.InteropServices;
namespace QuickLook.Plugin.LastResort
{
[Flags]
internal enum ThumbnailOptions
{
None = 0x00,
BiggerSizeOk = 0x01,
InMemoryOnly = 0x02,
IconOnly = 0x04,
ThumbnailOnly = 0x08,
InCacheOnly = 0x10,
IconBackground = 0x80,
ScaleUp = 0x100
}
internal static class WindowsThumbnailProvider
{
private const string IShellItem2Guid = "7E9FB0D3-919F-4307-AB2E-9B1860310C93";
[DllImport("shell32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern int SHCreateItemFromParsingName(
[MarshalAs(UnmanagedType.LPWStr)] string path,
// The following parameter is not used - binding context.
IntPtr pbc,
ref Guid riid,
[MarshalAs(UnmanagedType.Interface)] out IShellItem shellItem);
[DllImport("gdi32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool DeleteObject(IntPtr hObject);
public static Bitmap GetThumbnail(string fileName, int width, int height, ThumbnailOptions options)
{
var hBitmap = GetHBitmap(Path.GetFullPath(fileName), width, height, options);
try
{
// return a System.Drawing.Bitmap from the hBitmap
return GetBitmapFromHBitmap(hBitmap);
}
finally
{
// delete HBitmap to avoid memory leaks
DeleteObject(hBitmap);
}
}
internal static Bitmap GetBitmapFromHBitmap(IntPtr nativeHBitmap)
{
var bmp = Image.FromHbitmap(nativeHBitmap);
if (Image.GetPixelFormatSize(bmp.PixelFormat) < 32)
return bmp;
return CreateAlphaBitmap(bmp, PixelFormat.Format32bppArgb);
}
internal static Bitmap CreateAlphaBitmap(Bitmap srcBitmap, PixelFormat targetPixelFormat)
{
var result = new Bitmap(srcBitmap.Width, srcBitmap.Height, targetPixelFormat);
var bmpBounds = new Rectangle(0, 0, srcBitmap.Width, srcBitmap.Height);
var srcData = srcBitmap.LockBits(bmpBounds, ImageLockMode.ReadOnly, srcBitmap.PixelFormat);
var isAlplaBitmap = false;
try
{
for (var y = 0; y <= srcData.Height - 1; y++)
for (var x = 0; x <= srcData.Width - 1; x++)
{
var pixelColor = Color.FromArgb(
Marshal.ReadInt32(srcData.Scan0, srcData.Stride * y + 4 * x));
if ((pixelColor.A > 0) & (pixelColor.A < 255))
isAlplaBitmap = true;
result.SetPixel(x, y, pixelColor);
}
}
finally
{
srcBitmap.UnlockBits(srcData);
}
if (isAlplaBitmap)
return result;
return srcBitmap;
}
private static IntPtr GetHBitmap(string fileName, int width, int height, ThumbnailOptions options)
{
IShellItem nativeShellItem;
var shellItem2Guid = new Guid(IShellItem2Guid);
var retCode = SHCreateItemFromParsingName(fileName, IntPtr.Zero, ref shellItem2Guid, out nativeShellItem);
if (retCode != 0)
throw Marshal.GetExceptionForHR(retCode);
var nativeSize = new NativeSize();
nativeSize.Width = width;
nativeSize.Height = height;
IntPtr hBitmap;
var hr = ((IShellItemImageFactory) nativeShellItem).GetImage(nativeSize, options, out hBitmap);
Marshal.ReleaseComObject(nativeShellItem);
if (hr == HResult.Ok) return hBitmap;
throw Marshal.GetExceptionForHR((int) hr);
}
[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("43826d1e-e718-42ee-bc55-a1e261c37bfe")]
internal interface IShellItem
{
void BindToHandler(IntPtr pbc,
[MarshalAs(UnmanagedType.LPStruct)] Guid bhid,
[MarshalAs(UnmanagedType.LPStruct)] Guid riid,
out IntPtr ppv);
void GetParent(out IShellItem ppsi);
void GetDisplayName(SIGDN sigdnName, out IntPtr ppszName);
void GetAttributes(uint sfgaoMask, out uint psfgaoAttribs);
void Compare(IShellItem psi, uint hint, out int piOrder);
}
internal enum SIGDN : uint
{
NORMALDISPLAY = 0,
PARENTRELATIVEPARSING = 0x80018001,
PARENTRELATIVEFORADDRESSBAR = 0x8001c001,
DESKTOPABSOLUTEPARSING = 0x80028000,
PARENTRELATIVEEDITING = 0x80031001,
DESKTOPABSOLUTEEDITING = 0x8004c000,
FILESYSPATH = 0x80058000,
URL = 0x80068000
}
internal enum HResult
{
Ok = 0x0000,
False = 0x0001,
InvalidArguments = unchecked((int) 0x80070057),
OutOfMemory = unchecked((int) 0x8007000E),
NoInterface = unchecked((int) 0x80004002),
Fail = unchecked((int) 0x80004005),
ElementNotFound = unchecked((int) 0x80070490),
TypeElementNotFound = unchecked((int) 0x8002802B),
NoObject = unchecked((int) 0x800401E5),
Win32ErrorCanceled = 1223,
Canceled = unchecked((int) 0x800704C7),
ResourceInUse = unchecked((int) 0x800700AA),
AccessDenied = unchecked((int) 0x80030005)
}
[ComImport]
[Guid("bcc18b79-ba16-442f-80c4-8a59c30c463b")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IShellItemImageFactory
{
[PreserveSig]
HResult GetImage(
[In] [MarshalAs(UnmanagedType.Struct)] NativeSize size,
[In] ThumbnailOptions flags,
[Out] out IntPtr phbm);
}
[StructLayout(LayoutKind.Sequential)]
internal struct NativeSize
{
private int width;
private int height;
public int Width
{
set => width = value;
}
public int Height
{
set => height = value;
}
}
[StructLayout(LayoutKind.Sequential)]
public struct RGBQUAD
{
public byte rgbBlue;
public byte rgbGreen;
public byte rgbRed;
public byte rgbReserved;
}
}
}

View File

@@ -15,7 +15,6 @@ namespace QuickLook.Plugin.TextViewer
if (Directory.Exists(path)) if (Directory.Exists(path))
return false; return false;
// ReSharper disable once InconsistentNaming
const long MAX_SIZE = 20 * 1024 * 1024; const long MAX_SIZE = 20 * 1024 * 1024;
// if there is a possible highlighting scheme (by file extension), treat it as a plain text file // if there is a possible highlighting scheme (by file extension), treat it as a plain text file

View File

@@ -18,6 +18,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QuickLook.Plugin.TextViewer
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QuickLook.Plugin.ImageViewer", "QuickLook.Plugin.ImageViewer\QuickLook.Plugin.ImageViewer.csproj", "{FE5A5111-9607-4721-A7BE-422754002ED8}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QuickLook.Plugin.ImageViewer", "QuickLook.Plugin.ImageViewer\QuickLook.Plugin.ImageViewer.csproj", "{FE5A5111-9607-4721-A7BE-422754002ED8}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QuickLook.Plugin.ArchiveViewer", "QuickLook.Plugin.ArchiveViewer\QuickLook.Plugin.ArchiveViewer.csproj", "{DE2E3BC5-6AB2-4420-A160-48C7A7506C1C}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@@ -72,6 +74,14 @@ Global
{FE5A5111-9607-4721-A7BE-422754002ED8}.Release|Any CPU.Build.0 = Release|Any CPU {FE5A5111-9607-4721-A7BE-422754002ED8}.Release|Any CPU.Build.0 = Release|Any CPU
{FE5A5111-9607-4721-A7BE-422754002ED8}.Release|x86.ActiveCfg = Release|Any CPU {FE5A5111-9607-4721-A7BE-422754002ED8}.Release|x86.ActiveCfg = Release|Any CPU
{FE5A5111-9607-4721-A7BE-422754002ED8}.Release|x86.Build.0 = Release|Any CPU {FE5A5111-9607-4721-A7BE-422754002ED8}.Release|x86.Build.0 = Release|Any CPU
{DE2E3BC5-6AB2-4420-A160-48C7A7506C1C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DE2E3BC5-6AB2-4420-A160-48C7A7506C1C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DE2E3BC5-6AB2-4420-A160-48C7A7506C1C}.Debug|x86.ActiveCfg = Debug|Any CPU
{DE2E3BC5-6AB2-4420-A160-48C7A7506C1C}.Debug|x86.Build.0 = Debug|Any CPU
{DE2E3BC5-6AB2-4420-A160-48C7A7506C1C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DE2E3BC5-6AB2-4420-A160-48C7A7506C1C}.Release|Any CPU.Build.0 = Release|Any CPU
{DE2E3BC5-6AB2-4420-A160-48C7A7506C1C}.Release|x86.ActiveCfg = Release|Any CPU
{DE2E3BC5-6AB2-4420-A160-48C7A7506C1C}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE

View File

@@ -12,8 +12,8 @@
Topmost="True" d:DesignWidth="624" d:DesignHeight="700" Topmost="True" d:DesignWidth="624" d:DesignHeight="700"
MinWidth="275" MinHeight="150" MinWidth="275" MinHeight="150"
WindowStartupLocation="CenterScreen" WindowStartupLocation="CenterScreen"
x:ClassModifier="internal" Focusable="False" x:ClassModifier="internal" Focusable="False"
ShowActivated="False" ShowInTaskbar="False" WindowStyle="None" ShowActivated="False" ShowInTaskbar="False" WindowStyle="None"
ResizeMode="CanResizeWithGrip" AllowsTransparency="True"> ResizeMode="CanResizeWithGrip" AllowsTransparency="True">
<Window.Background> <Window.Background>
<SolidColorBrush Color="#DFFFFFFF" /> <SolidColorBrush Color="#DFFFFFFF" />