Como criar automaticamente miniaturas do Windows recursivamente? [duplicado]

6

Estou usando o Windows 8.1 com o Windows Explorer. O cache de imagens ("thumbs.db") é criado quando visito uma pasta que contém vídeos, fotos ou outros arquivos semelhantes. Eu tenho um problema com isso porque eu tenho várias pastas com vídeos grandes e fotos que estão mudando constantemente. Toda vez que abro uma pasta contendo esses arquivos, tenho que esperar alguns segundos até que o cache de miniaturas seja criado.

Uma solução seria desativar o cache de miniaturas. Mas eu gosto de ver miniaturas, então isso não é uma solução para mim. Em vez disso, gostaria de chamar um lote ou outro programa a cada x segundos que cria as miniaturas do Windows recursivamente. Eu poderia abrir as pastas sem demora.

Como posso conseguir isso?

    
por dude 04.01.2015 / 18:10

4 respostas

1

Aqui está um script do PowerShell que eu escrevi e que deve fazer o que você precisa.

Eu peguei a lógica deste tópico: link e transformou-o em um script que você pode executar como uma tarefa agendada no Windows.

Você precisará ter o .net4.0 e o PowerShell 3.0 instalados para usá-lo, caso contrário, você terá erros. Neste ponto, você provavelmente terá .net4.0, mas provavelmente precisará do PowerShell 3.0

Salve o seguinte em um arquivo chamado 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..."
}

Em seguida, execute-o a partir da linha de comando do PowerShell com os seguintes parâmetros:

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

Na realidade, qualquer extensão de arquivo deve funcionar. Ele irá olhar recursivamente através de todos os diretórios. A única desvantagem é apenas um tipo de arquivo de cada vez, mas várias tarefas podem ser executadas usando simplesmente uma extensão de arquivo diferente. Basicamente, o script abre cada arquivo e lê apenas o primeiro byte, o que é suficiente para forçar uma atualização no arquivo thumbs.db.

Editar Eu alterei o script para incluir também a parte de atualização do shell postada acima. Parece estar funcionando no meu sistema, embora eu não tenha milhares de imagens para testar. Isso combina a leitura dos primeiros bytes do arquivo, seguida de uma atualização das miniaturas.

    
por 27.02.2015 / 20:38
2

Posso pensar em dois métodos para acelerar a criação de miniaturas:

  1. Reduza o tamanho da miniatura ( mais informações )
  2. Escreva um programa que periodicamente atualize as miniaturas de novos arquivos

Para o segundo método, eu não sei de um produto que faz isso, então você precisará escrever o seu próprio. Aqui está uma referência útil: Como faço para atualizar a miniatura de um arquivo no Windows Explorer? .

A postagem sugere e inclui a origem de um programa C # que realiza isso lendo o primeiro byte do arquivo. O Windows atualiza a miniatura quando o programa fecha o arquivo.

A resposta aceita simplesmente notifica o Windows de que o arquivo foi alterado uma solução publicada que não precisa ler o arquivo.

Minha versão (não testada) é:

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 { }
}
    
por 27.02.2015 / 10:23
1

Outro fragmento de programa que deve atualizar o cache de miniaturas usando a interface COM IThumbnailCache (C ++). Que eu saiba, não existe nenhuma ferramenta pré-compilada para a tarefa.

O MSDN diz: "Se o parâmetro flags para IThumbnailCache :: GetThumbnail incluir o sinalizador WTS_EXTRACT e a miniatura ainda não estiver em cache, uma miniatura será extraída e colocada no cache"

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();
    }
}
    
por 27.02.2015 / 16:20
-2

O problema é bastante complexo. A melhor coisa a fazer é projetar um aplicativo especificamente para essa finalidade.

Opção 1:

Procure por * .jpg, * .avi, etc e todos eles devem ser armazenados em cache.

Opção 2a:

Crie um script em lote para criar manualmente as miniaturas. Exemplo (adapte-se às suas necessidades):

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

Recursivamente:

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

Opção 2b:

Isto é para arquivos de vídeo, o ffmpeg é a ferramenta.

Exemplo:

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

Para a opção 2, você terá que respeitar o esquema de nomeação de thumbs para que sua saída gerada seja considerada válida.

    
por 27.02.2015 / 10:34