如何自动递归创建 Windows 缩略图?

如何自动递归创建 Windows 缩略图?

我使用的是 Windows 8.1 和 Windows 资源管理器。当我访问包含视频、照片或其他此类文件的文件夹时,会创建图像缓存(“thumbs.db”)。我遇到了这个问题,因为我有多个文件夹,里面有不断变化且很大的视频和照片。每次打开包含这些文件的文件夹时,我都必须等待几秒钟,直到创建缩略图缓存。

一种解决方法是禁用缩略图缓存。但我喜欢看缩略图,所以这对我来说不是一个解决方案。相反,我想每隔 x 秒调用一个批处理或另一个程序,以递归方式创建 Windows 缩略图。然后我就可以毫不延迟地打开文件夹。

我怎样才能做到这一点?

答案1

这是我编写的 PowerShell 脚本,它可以完成您的需要。

我从这个帖子中得出了逻辑:https://stackoverflow.com/questions/3555799/how-do-i-refresh-a-files-thumbnail-in-windows-explorer,并将其制作成脚本,可以在windows中作为计划任务运行。

您需要安装 .net4.0 和 PowerShell 3.0 才能使用它,否则会出现错误。此时您可能已经拥有 .net4.0,但您可能需要PowerShell 3.0

将以下内容保存到名为 thumb_generate.ps1 的文件中

param ([string]$path,[string]$ext)
function Refresh-Explorer 
{  
   $code = @'  
   [System.Runtime.InteropServices.DllImport("Shell32.dll")]   
   public static extern Int32 SHParseDisplayName([MarshalAs(UnmanagedType.LPWStr)] String pszName, IntPtr pbc, out IntPtr ppidl, UInt32 sfgaoIn, out UInt32 psfgaoOut);

   [System.Runtime.InteropServices.DllImport("Shell32.dll")]   
   private static extern int SHChangeNotify(int eventId, int flags, IntPtr item1, IntPtr item2);

   [System.Runtime.InteropServices.DllImport("Shell32.dll")]   
   private static extern int ILFree(IntPtr pidl);    

   public static void Refresh(string path)  {
    uint iAttribute;
    IntPtr pidl;
    SHParseDisplayName(path, IntPtr.Zero, out pidl, 0, out iAttribute);  
    SHChangeNotify(0x00002000, 0x1000, IntPtr.Zero, IntPtr.Zero); 
    ILFree(pidl); 
}  
'@  

    Add-Type -MemberDefinition $code -Namespace MyWinAPI -Name Explorer   
    [MyWinAPI.Explorer]::Refresh($path)  
} 

cls
if([System.String]::IsNullOrEmpty($path))
{
   Write-Host "Path cannot be empty."
   Write-Host "Example:  .\thumb_generate.ps1 -path ""C:\"" -ext ""jpg"""
   return
}
if([System.String]::IsNullOrEmpty($path))
{
   Write-Host "Extension cannot be empty."
   Write-Host "Example:  .\thumb_generate.ps1 -path ""C:\"" -ext ""jpg"""
   return
}

$fileExtension = "*." + $ext
Write-Host -ForegroundColor Green "---Thumbnail generation for Windows 7/8---"
Write-Host -ForegroundColor Green "----PowerShell 3.0 & .Net 4.0 required----"
Write-Host "Path: "  $path
Write-Host "Extension: " $fileExtension
Write-Host 
if (Test-Path $path) 
{
   Write-Host "Path Exists, begin generation thumbnails"

   $images = [System.IO.Directory]::EnumerateFiles($path,$fileExtension,"AllDirectories")
   Foreach($image in $images)
   {
       try
       {
          $file = New-Object System.IO.FileInfo($image)
          Write-Host $file.FullName
          $fStream = $file.Open([System.IO.FileMode]::Open,[System.IO.FileAccess]::Read,[System.IO.FileShare]::None)

          $firstbyte = New-Object Byte[] 1
          $result = $fStream.Read($firstbyte,0,1)
       }
       catch
       {
          Write-Host -ForegroundColor Red "An error occured on file: " + $file.FullName
       }
       $fStream.Close();
   }
    Refresh-Explorer
}
else
{
  "Path Doesn't Exist, Exiting..."
}

然后使用以下参数从 PowerShell 命令行执行它:

.\thumb_generate.ps1 -path "C:\PathToImages\"  -ext "jpg"

实际上,任何文件扩展名都可以。它将递归地查看所有目录。一个缺点是一次只能处理一种文件类型,但可以运行多个仅使用不同文件扩展名的作业。基本上,脚本打开每个文件并只读取第一个字节,这足以强制更新 thumbs.db 文件。

编辑我修改了脚本,使其也包含上面发布的 shell 更新部分。虽然我没有数千张图片可以测试,但它似乎在我的系统上工作正常。这结合了读取文件的前几个字节,然后强制刷新缩略图。

答案2

我能想到两种加速缩略图创建的方法:

  1. 缩小缩略图的尺寸(更多信息
  2. 编写一个程序定期刷新新文件的缩略图

对于第二种方法,我不知道有哪个产品可以做到这一点,所以你需要自己编写一个。这是一个有用的参考: 如何在 Windows 资源管理器中刷新文件的缩略图?

这篇文章建议并包含一个 C# 程序的源代码,该程序通过读取文件的第一个字节来实现此目的。当程序关闭文件时,Windows 会刷新缩略图。

接受的答案更简单地通知 Windows 文件已更改发布解决方案不需要读取文件。

我的版本(未经测试)是:

public static void refreshThumbnail(string path)
{
    try
    {
        uint iAttribute;
        IntPtr pidl;
        SHParseDisplayName(path, IntPtr.Zero, out pidl, 0, out iAttribute);
        SHChangeNotify(
            (uint)ShellChangeNotificationEvents.SHCNE_UPDATEITEM,
            (uint)ShellChangeNotificationFlags.SHCNF_FLUSH,
            pidl,
            IntPtr.Zero);
        ILFree(pidl);

    }
    catch { }
}

答案3

另一个程序片段应该使用 IThumbnailCache COM 接口 (C++) 刷新缩略图缓存。据我所知,没有任何预编译工具可以完成此任务。

MSDN 表示:“如果 IThumbnailCache::GetThumbnail 的标志参数包含标志 WTS_EXTRACT,并且缩略图尚未缓存,则会提取缩略图并将其放置在缓存中”

CoInitialize(NULL);

IThumbnailCache *cache;
HRESULT hr = CoCreateInstance(CLSID_LocalThumbnailCache, NULL, CLSCTX_INPROC, IID_PPV_ARGS(&cache));
if (SUCCEEDED(hr))
{
    <loop over files>
    {
        cache->GetThumbnail(<shell item for file>, <required size>, WTS_EXTRACT, NULL, NULL, NULL);
        cache->Release();
    }
}

答案4

这个问题相当复杂。最好的办法是专门为此设计一个应用程序。

选项1:

搜索*.jpg、*.avi 等,它们都应该被缓存。

选项 2a:

创建批处理脚本来手动创建缩略图。示例(根据您的需要调整):

mkdir thumbjunk
for f in *.jpg
do convert $f -thumbnail 100x80 thumbjunk/$f.gif

递归地:

find * -prune -name '*.jpg' \
-exec convert '{}' -thumbnail 100x80 thumbjunk/'{}'.gif 

选项 2b:

这是用于视频文件的,ffmpeg 是工具。

例子:

ffmpeg -ss 00:01:00 -i testavi.avi -vf 'select=not(mod(n\,1000)),scale=320:240,tile=2x3' testavi.png

对于选项 2,您必须遵守缩略图命名方案,以便生成的输出被视为有效。

相关内容