Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optimize large image loading #43

Merged
merged 1 commit into from
Jul 30, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion WinQuickLook/Handlers/AnimatedGifPreviewHandler.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.IO;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media.Imaging;
Expand All @@ -24,7 +25,7 @@ public bool CanOpen(string fileName)
return bitmap.Frames.Count > 1;
}

public (FrameworkElement, Size, string) GetViewer(string fileName)
public async Task<(FrameworkElement, Size, string)> GetViewerAsync(string fileName)
{
var bitmap = BitmapDecoder.Create(new Uri(fileName), BitmapCreateOptions.DelayCreation, BitmapCacheOption.OnDemand);

Expand Down
3 changes: 2 additions & 1 deletion WinQuickLook/Handlers/AudioPreviewHandler.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using System.Windows;

using WinQuickLook.Controls;
Expand All @@ -17,7 +18,7 @@ public bool CanOpen(string fileName)
return _supportFormats.Contains(extension);
}

public (FrameworkElement, Size, string) GetViewer(string fileName)
public async Task<(FrameworkElement, Size, string)> GetViewerAsync(string fileName)
{
var requestSize = new Size(400, 400);

Expand Down
3 changes: 2 additions & 1 deletion WinQuickLook/Handlers/ComInteropPreviewHandler.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.IO;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Forms.Integration;

Expand All @@ -20,7 +21,7 @@ public bool CanOpen(string fileName)
return PreviewHandlerHost.GetPreviewHandlerCLSID(fileName) != Guid.Empty;
}

public (FrameworkElement, Size, string) GetViewer(string fileName)
public async Task<(FrameworkElement, Size, string)> GetViewerAsync(string fileName)
{
var requestSize = new Size
{
Expand Down
3 changes: 2 additions & 1 deletion WinQuickLook/Handlers/GenericPreviewHandler.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.IO;
using System.Threading.Tasks;
using System.Windows;

using WinQuickLook.Controls;
Expand All @@ -13,7 +14,7 @@ public bool CanOpen(string fileName)
return true;
}

public (FrameworkElement, Size, string) GetViewer(string fileName)
public async Task<(FrameworkElement, Size, string)> GetViewerAsync(string fileName)
{
var requestSize = new Size(500, 280);

Expand Down
3 changes: 2 additions & 1 deletion WinQuickLook/Handlers/HtmlPreviewHandler.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;

Expand All @@ -17,7 +18,7 @@ public bool CanOpen(string fileName)
return _supportFormats.Contains(extension);
}

public (FrameworkElement, Size, string) GetViewer(string fileName)
public async Task<(FrameworkElement, Size, string)> GetViewerAsync(string fileName)
{
var requestSize = new Size
{
Expand Down
5 changes: 3 additions & 2 deletions WinQuickLook/Handlers/IPreviewHandler.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
using System.Windows;
using System.Threading.Tasks;
using System.Windows;

namespace WinQuickLook.Handlers
{
public interface IPreviewHandler
{
bool CanOpen(string fileName);

(FrameworkElement, Size, string) GetViewer(string fileName);
Task<(FrameworkElement, Size, string)> GetViewerAsync(string fileName);
}
}
46 changes: 31 additions & 15 deletions WinQuickLook/Handlers/ImagePreviewHandler.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.IO;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
Expand All @@ -22,7 +23,7 @@ public bool CanOpen(string fileName)
{
using var stream = File.OpenRead(fileName);

BitmapDecoder.Create(stream, BitmapCreateOptions.DelayCreation, BitmapCacheOption.OnDemand);
BitmapDecoder.Create(stream, BitmapCreateOptions.DelayCreation, BitmapCacheOption.None);

return true;
}
Expand All @@ -32,9 +33,9 @@ public bool CanOpen(string fileName)
}
}

public (FrameworkElement, Size, string) GetViewer(string fileName)
public async Task<(FrameworkElement, Size, string)> GetViewerAsync(string fileName)
{
var bitmap = GetImage(fileName);
var (bitmap, originalSize) = GetImage(fileName);

var requestSize = new Size
{
Expand All @@ -46,36 +47,51 @@ public bool CanOpen(string fileName)

image.BeginInit();
image.Stretch = Stretch.Uniform;
image.StretchDirection = StretchDirection.DownOnly;
image.StretchDirection = StretchDirection.Both;
image.Source = bitmap;
image.EndInit();

return (image, requestSize, $"{bitmap.PixelWidth}x{bitmap.PixelHeight} - {WinExplorerHelper.GetFileSize(fileName)}");
return (image, requestSize, $"{originalSize.Width}x{originalSize.Height} - {WinExplorerHelper.GetFileSize(fileName)}");
}

private static BitmapSource GetImage(string fileName)
private static (BitmapSource, Size) GetImage(string fileName)
{
var (scaledSize, originalSize) = GetScaledImageSize(fileName, 1200);

var bitmap = new BitmapImage();

bitmap.BeginInit();
bitmap.CacheOption = BitmapCacheOption.OnLoad;
bitmap.CreateOptions = BitmapCreateOptions.None;
bitmap.CacheOption = BitmapCacheOption.None;
bitmap.DecodePixelWidth = (int)scaledSize.Width;
bitmap.DecodePixelHeight = (int)scaledSize.Height;
bitmap.UriSource = new Uri(fileName, UriKind.Absolute);
bitmap.EndInit();

bitmap.Freeze();

if (Math.Abs(bitmap.DpiX - 96.0) < 0.1 && Math.Abs(bitmap.DpiY - 96.0) < 0.1)
{
return bitmap;
}
return (bitmap, originalSize);
}

private static (Size, Size) GetScaledImageSize(string fileName, int maxSize)
{
using var stream = File.OpenRead(fileName);

int stride = bitmap.PixelWidth * 4;
var pixels = new byte[stride * bitmap.PixelHeight];
var decoder = BitmapDecoder.Create(stream, BitmapCreateOptions.DelayCreation, BitmapCacheOption.None);

bitmap.CopyPixels(pixels, stride, 0);
var width = decoder.Frames[0].PixelWidth;
var height = decoder.Frames[0].PixelHeight;

var originalSize = new Size(width, height);

if (width > maxSize || height > maxSize)
{
var scaleFactor = (double)maxSize / Math.Max(width, height);

return (new Size(width * scaleFactor, height * scaleFactor), originalSize);
}

return BitmapSource.Create(bitmap.PixelWidth, bitmap.PixelHeight, 96.0, 96.0, bitmap.Format, bitmap.Palette, pixels, stride);
return (originalSize, originalSize);
}
}
}
3 changes: 2 additions & 1 deletion WinQuickLook/Handlers/InternetShortcutPreviewHandler.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;

Expand All @@ -15,7 +16,7 @@ public bool CanOpen(string fileName)
return _supportFormats.Contains(extension);
}

public (FrameworkElement, Size, string) GetViewer(string fileName)
public async Task<(FrameworkElement, Size, string)> GetViewerAsync(string fileName)
{
var content = File.ReadAllLines(fileName);

Expand Down
3 changes: 2 additions & 1 deletion WinQuickLook/Handlers/PdfPreviewHandler.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.IO;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Forms.Integration;

Expand All @@ -18,7 +19,7 @@ public bool CanOpen(string fileName)
return extension == ".pdf";
}

public (FrameworkElement, Size, string) GetViewer(string fileName)
public async Task<(FrameworkElement, Size, string)> GetViewerAsync(string fileName)
{
var pdfViewer = new PdfViewer();

Expand Down
3 changes: 2 additions & 1 deletion WinQuickLook/Handlers/SyntaxHighlightPreviewHandler.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.IO;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media;

Expand Down Expand Up @@ -26,7 +27,7 @@ public bool CanOpen(string fileName)
return HighlightingManager.Instance.GetDefinitionByExtension(Path.GetExtension(fileName)) != null;
}

public (FrameworkElement, Size, string) GetViewer(string fileName)
public async Task<(FrameworkElement, Size, string)> GetViewerAsync(string fileName)
{
var requestSize = new Size
{
Expand Down
3 changes: 2 additions & 1 deletion WinQuickLook/Handlers/TextPreviewHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
Expand All @@ -21,7 +22,7 @@ public bool CanOpen(string fileName)
return _supportFormats.Contains(extension);
}

public (FrameworkElement, Size, string) GetViewer(string fileName)
public async Task<(FrameworkElement, Size, string)> GetViewerAsync(string fileName)
{
var contents = File.ReadAllBytes(fileName);
var encoding = DetectEncoding(contents);
Expand Down
3 changes: 2 additions & 1 deletion WinQuickLook/Handlers/VideoPreviewHandler.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using System.Windows;

using WinQuickLook.Controls;
Expand All @@ -17,7 +18,7 @@ public bool CanOpen(string fileName)
return _supportFormats.Contains(extension);
}

public (FrameworkElement, Size, string) GetViewer(string fileName)
public async Task<(FrameworkElement, Size, string)> GetViewerAsync(string fileName)
{
var requestSize = new Size
{
Expand Down
4 changes: 2 additions & 2 deletions WinQuickLook/QuickLookWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -71,14 +71,14 @@ public bool HideIfVisible()
return true;
}

public void Open(string fileName)
public async void Open(string fileName)
{
CleanupHost();

_fileName = fileName;
_handler = _handlers.First(x => x.CanOpen(fileName));

var (element, requestSize, metadata) = _handler.GetViewer(fileName);
var (element, requestSize, metadata) = await _handler.GetViewerAsync(fileName);

PreviewHost = element;

Expand Down