#缩略图 #图像 #shell #freedesktop #linux #文件路径 #文件格式

bin+lib allmytoes

根据 freedesktop.org 规范提供缩略图

11 个版本 (4 个破坏性更新)

0.4.0 2024 年 5 月 5 日
0.2.0 2023 年 12 月 17 日
0.1.0 2023 年 10 月 23 日
0.0.5 2023 年 6 月 26 日
0.0.1 2022 年 7 月 20 日

#127 in 图像

Download history 150/week @ 2024-05-02 18/week @ 2024-05-09 97/week @ 2024-05-16 127/week @ 2024-05-23 109/week @ 2024-05-30 118/week @ 2024-06-06 144/week @ 2024-06-13 133/week @ 2024-06-20 124/week @ 2024-06-27 191/week @ 2024-07-04 109/week @ 2024-07-11 156/week @ 2024-07-18 137/week @ 2024-07-25 115/week @ 2024-08-01 156/week @ 2024-08-08 107/week @ 2024-08-15

每月 538 次下载

GPL-3.0-or-later

690KB
2.5K SLoC

Rust 1.5K SLoC // 0.0% comments Python 628 SLoC // 0.1% comments Gherkin (Cucumber) 378 SLoC // 0.1% comments Shell 52 SLoC // 0.2% comments

所有脚趾

通过使用 freedesktop-specified 缩略图数据库(也称为 XDG 标准)提供缩略图。

缩略图通过一个共同的缓存与其他程序共享。

只有在尚未创建缩略图或原始文件已更改时,才会创建缩略图。

所有脚趾可以为许多图像格式创建缩略图。(参见“解码”支持的 image crate。)

此外,所有脚趾还可以使用其他程序创建其他类型文件的缩略图,以创建基本图像。(参见 Provider 部分。)

所有脚趾既是用于 shell 和脚本的交互式程序,也是 Rust 库。在代码或结构化数据中简称为“AMT”(或“amt”)。

[[目录]]

用法

使用文件作为参数调用 allmytoes。程序会将缩略图的路径打印到 stdout

> allmytoes some_image.jpg
/home/me/.cache/thumbnails/large/b7931d1d6e0439c1a6e2e6b02c5b21a6.png

如果缩略图已经存在,所有脚趾将仅返回现有缩略图文件的路径。如果不存在,所有脚趾将首先创建图像的缩略图。

缩略图大小

最新的 freedesktop.org 规范(0.9.0)定义了四种不同的缩略图大小:普通、大、超大和超超大,最大边长分别为 128 像素、256 像素、512 像素和 1024 像素。

默认情况下,所有脚趾返回 (256 像素)缩略图的路径。可以通过使用 -s--size)选项并给出一个值来选择要返回的大小,该值从 {nlxxx} 中选择。

例如,要获取一个超超大缩略图,调用方式如下

> allmytoes -sxx some_image.jpg
/home/me/.cache/thumbnails/xx-large/ad0779df58de36f038bdc4040a322bfe.png

小输入图像

如果输入图像小于请求的缩略图大小,缩略图将具有与输入图像相同的尺寸。缩略图永远不会比原始图像更大。

如果请求的大小还没有缩略图,AllMyToes将检查输入图像是否小于请求的缩略图大小。如果是这样,AllMyToes将确定覆盖输入图像尺寸的最小缩略图大小(大于或等于输入图像)。如果这个“可行”的缩略图大小与请求的缩略图大小不同,AllMyToes将使用这个更小的、“可行”的缩略图大小从头开始工作。AllMyToes这样做是为了避免为小图像创建不必要的、重复的缩略图。

这意味着对于小的输入图像,返回的缩略图路径可能不会对应于请求的缩略图大小,因为创建和保留(较大)请求大小的缩略图将浪费计算时间和磁盘空间。

如果出于某种原因必须获取请求大小的缩略图的路径,可以使用-F--force-size)选项。但是,只有当有真正充分的理由时才这样做。

显示详细信息

使用--extensive(或-e)选项调用AllMyToes会在打印缩略图路径之外打印更多信息。提供的信息包括:

  • 缩略图的路径
  • 用于XDG缩略图名称的输入文件的URI散列
  • 存储在缩略图中的所有元数据(键值对),作为“tEXt”条目

这无关紧要,无论是缩略图已经存在还是刚刚由AllMyToes创建。

所有数据都按键值对列表打印,每个元组一行。键与值之间用“:”分隔。显示缩略图文件元数据的键值对前面有冒号,并按字母顺序打印。

示例

$ allmytoes --extensive some_image.jpg 
Thumb path: /home/dude/.cache/thumbnails/large/c000276b8378a33e16e3fac005eebc02.png
Thumb hash: c000276b8378a33e16e3fac005eebc02
:Software: allmytoes
:Software::Version: 0.1.0
:Thumb::Image::Dimensions: 4608x3456
:Thumb::Image::Height: 3456
:Thumb::Image::Reorientation: Rotated 180 degrees, not flipped
:Thumb::Image::Width: 4608
:Thumb::MTime: 1693737198
:Thumb::Mimetype: image/jpeg
:Thumb::Size: 7777807
:Thumb::URI: file:///path/to/some_image.jpg

缩略图中可用的元数据当然取决于创建缩略图的软件。因此,以冒号(:)开头的行可能会有所不同。

日志记录

默认情况下,AllMyToes会将警告和错误打印到stderr。可以通过环境变量RUST_LOG设置不同的日志级别。例如,做

export RUST_LOG=trace

以获取所有日志条目,直到最详细的“跟踪”级别。

提供者

如果定义了“提供者”,AllMyToes可以为非图像文件创建缩略图。提供者是一个shell命令或脚本来为特定的一组MIME类型提供图像。

AllMyToes支持一些文件格式

格式 依赖关系
PDF (evince-thumbnailermagick)和(exiftoolpdfinfogs)
Postscript (evince-thumbnailermagick)和(exiftoolgs)
SVG inkscapemagick
各种视频格式 ffmpeg(可选ffprobe & magick & bc用于更复杂的缩略图)和(ffprobe或(mediainfobc)或(exiftoolbc))

确切的MIME类型和提供者定义可以在/conf/provider.yaml中找到。

定义提供者

用户可以在YAML文件中使用自己的提供者配置以添加对更多MIME类型的支持或实现更复杂的缩略图。

要这样做,请将 /conf/provider.yaml 复制到 ~/.config/allmytoes/provider.yaml(如果 $XDG_CONFIG_HOME 已定义,则也可以使用 $XDG_CONFIG_HOME)并对其进行修改。您还可以使用 -p--provider-config-file)选项显式选择其他提供者配置。

❗请注意,提供者功能相对较新,在稳定之前,提供者配置的格式可能会发生变化。

提供者配置YAML文件在顶层包含一个字典列表。每个列表条目定义了一个提供者,用于一种或多种MIME类型。对于每个条目,有两个必需键和两个可选键。

必需 简短描述
mimes 列表,包含由提供者定义处理的MIME类型
commands 列表,提供缩略图的命令,从上到下处理,直到成功为止
meta 字典,将缩略图元数据键映射到提供它们的命令列表
revision 用于跟踪提供者定义版本的整数

mimes

MIME类型列表定义了提供者将执行哪些MIME类型。MIME类型指定为 <type>/<subtype>,例如 video/x-matroska。如果为无法找到提供者的文件调用AllMyToes,则将在错误消息中打印MIME类型。找到提供者的MIME类型将在调试消息中打印,并在缩略图本身中作为元数据标记。 (如果您使用 --extensive-e)选项,则可以查看。)

commmands

每个提供者条目必须有一个命令列表。命令是shell命令(或脚本),它们接受输入文件并将图像返回给AllMyToes。AllMyToes接受该图像并从中创建符合XDG规范的缩略图。命令通过将其复制到定义的位置来提供该图像。

mimes 列表中的某个MIME类型与输入文件匹配时,AllMyToes将执行 commands 列表中的第一个命令。如果该命令成功(退出代码 0),AllMyToes将停止并使用该命令提供的缩略图。

如果命令未成功(退出代码 0),AllMyToes将尝试下一个命令,依此类推。

这允许使用不同的程序来提供缩略图。如果用户没有使用第一个命令的程序,另一个计算缩略图的方法可能有效。如果命令返回 0 但仍不提供有效的缩略图,AllMyToes将返回错误。

命令通过将其复制到临时目录中的某个路径来提供缩略图,该路径随后将被AllMyToes删除。

命令需要某些信息才能完成其工作,例如输入文件和将缩略图复制到的路径。因此,命令可以使用某些变量。

变量 内容
%(file)s 输入文件的完整路径
%(size)s 理想情况下较长边应具有的像素大小。
%(输出文件名)s 缩略图应复制的临时文件的路径
%(临时目录)s 包含%(outfile)的临时目录,并且在创建缩略图期间可能需要的其他临时文件也可以使用

如果创建的图像(在%(outfile)处)的大小大于%(size),AllMyToes将相应地缩小图像。AllMyToes还会执行其他必要的转换,例如将图像转换为每通道8位的RGBA PNG图像并添加所有必要的元数据块。因此,命令可以提供任何支持的图像格式的缩略图。AllMyToes还会确保将图像转换为符合freedesktop.org规范的缩略图。

meta

freedesktop.org缩略图具有“元数据块”,以键值对形式的元数据属性。(参见元数据块的解释。)提供者也可以提供这样的元数据条目。其中一些甚至被标准推荐Thumb::Document::Pages用于面向纸张的文档,以及Thumb::Movie::Length用于视频文件的总秒数)。

提供者规范中的meta键包含一个字典,将元数据键映射到命令列表。对于每个键,执行命令列表,从上到下,直到其中一个命令成功退出并返回0。必须通过stdout返回元数据块的价值。

在当前实现中,如果元数据块的任何命令都不成功,则缩略图生成将失败。元数据块的命令可以使用与图像创建命令相同的变量。

元数据块的规范是可选的。

revision

修订键旨在作为提供者的“版本”。它是可选的,目前除了作为元数据块添加到缩略图之外,没有其他效果。

这个想法是将来可以使用这个修订号重新创建缩略图,如果有一个提供者具有更高的修订号。

关于命令的注意事项

对于commands键中的图像命令以及meta键下的命令,都应该考虑一些事情。

首先,命令可以是多行shell脚本,只需在YAML文件中使用多行字符串即可。以下为SVG提供者的示例,说明了多行命令可能的样子

- mimes:
  - image/svg+xml
  commands:
    - |
      which inkscape || exit 1
      w=$(inkscape -W "%(file)s" | sed 's/\..*//')
      h=$(inkscape -H "%(file)s" | sed 's/\..*//')
      test $w -gt $h && size_arg="-w %(size)s" || size_arg="-h %(size)s"
      inkscape --export-area-page --export-type=png $size_arg -o "%(tmpdir)s/outfile.png" "%(file)s" && \
        mv "%(tmpdir)s/outfile.png" "%(outfile)s"
    - |
      convert -background none -resize %(size)sx%(size)s "%(file)s" "%(tmpdir)s/outfile.png" && \
        mv "%(tmpdir)s/outfile.png" "%(outfile)s"

其次,命令应该是POSIX shell兼容的,例如不要依赖于BASH。这保证了提供者命令将在大多数机器和账户上工作。

第三,如果某些环境先决条件没有满足,命令应该以返回码> 0失败。请记住,无论早期命令是否失败,命令的管道将退出最后一个命令的返回码。

因此,使用 && 将程序链起来或使用 || exit 1 来扩展程序调用,以便正确地使提供程序命令失败,这是一个好主意。例如,可以使用 which <program> || exit 1 来测试管道中使用的所需程序的可用性。

还要记住要 引用输入文件(例如 "%(file)s"),因为路径可能包含空格。不应在 %(outfile)s(以及 %(tmpdir)s)中包含任何空格,但引用它们也无妨。

示例

让我们看一个示例,并指定一个为 PDF postscript 文件提供缩略图的提供程序。两者都可以使用相同的命令转换为缩略图,这就是为什么可以将两者处理在一个提供程序中。

请注意,AllMyToes 的实际默认配置使用不同的提供程序定义来实现更具体的元块命令。这个定义仅作为示例。

PDF 文件的 MIME 类型为 application/pdf,postscript 文件的 MIME 类型为 application/postscript

- mimes: [application/pdf, application/postscript]
  commands:
    - evince-thumbnailer -s %(size)s "%(file)s" %(outfile)s
    - convert -thumbnail %(size)sx%(size)s -background white %(file)s[0] PNG:%(outfile)s
  meta:
    'Thumb::Document::Pages':
      - |
        which exiftool || exit 1
        exiftool "%(file)s" | awk '/^Page Count/ {print $4}' | sed 's/[^0-9]*//g'
      - | 
        which gs || exit 1
        gs -o /dev/null -sDEVICE=bbox "%(file)s" 2>&1 | grep HiResBoundingBox | wc -l
  revision: 1

首先,定义此提供程序将使用的 MIME 类型。

commands 部分首先尝试使用 evince-thumbnailer%(outfile)s 中创建缩略图。如果 evince-thumbnailer 存在,则提供图像的任务已完成,不会执行第二个命令。

如果 evince-thumbnailer 不可用,第一个命令将失败,AllMyToes 将执行第二个命令,该命令使用 ImageMagick 的 convert。如果 convert 也不可用,则缩略图创建失败,AllMyToes 将返回错误。

首先尝试 evince-thumbnailer,因为它更快,我们更喜欢使用它。

如果两个命令中的任何一个成功,AllMyToes 将评估 meta 部分。在这个例子中,我们只有一个具有元键 Thumb::Document::Pages 的元块。此元块也有两个命令,同样,如果第一个命令失败,AllMyToes 将仅执行第二个命令。

第一个命令依赖于 exiftool,第二个命令依赖于 Ghostscript(gs)。因为它们都用于管道中,所以我们首先检查它们是否存在,如果不存在则退出并返回 1。示例展示了如何将多行脚本用作命令。

两个元数据命令都返回值作为输出到 stdoutThumb::Document::Pages 元数据块的值。

有关更多示例,请参阅 默认提供程序配置

这有什么用?

我的个人动机是使用缩略图来预览终端文件管理器中的图像,如 joshutoranger 中的图像。但是,AllMyToes在任何需要以脚本环境显示尺寸受限图像的情况下都可能很有用,例如作为桌面通知中的图标,或在基于终端的应用程序中的其他图像叠加,或桌面小部件;在这些情况下,加载全尺寸图像会消耗不必要的的时间和CPU资源。

安装

Linux X86-64 二进制文件(实验性)

发布页面下载最新版本的二进制文件。使下载的文件可执行(chmod +x allmytoes)并将其放置在您的PATH目录中(例如mv allmytoes ~/local/bin)。

通过cargo的最新发布版

cargo install allmytoes

通过cargo获取最新版本

cargo install --git https://gitlab.com/allmytoes/allmytoes.git

从仓库克隆

git clone https://gitlab.com/allmytoes/allmytoes.git
cd allmytoes
cargo build --release

生成的二进制文件将在target/release/allmytoes

一些规格

  • Freedesktop.org 缩略图规范:AllMyToes努力遵守freedesktop.org 缩略图规范。现在应该实现了标准的所有相关部分。
  • AllMyToes不会创建缓存目录($XDG_CACHE_HOME~/.cache)。如果缓存目录不存在,AllMyToes将以错误终止。(以后可能会改变。)
  • 如果不存在,AllMyToes将在缓存目录下创建缩略图目录和特定大小的子目录。
  • AllMyToes只接受常规文件和常规文件的符号链接作为输入。将来可能会支持目录。没有计划支持其他文件类型

缩略图元数据块

缩略图 - 所有都是PNG格式 - 具有一定的元数据条目,每个条目都是一个PNG“tEXt”,具有键和值。freedesktop.org 缩略图标准描述了一些必需的和一些可选的键。(见标准中的“缩略图创建部分”)。AllMyToes实现了所有这些。以下表格列出了AllMyToes创建的所有元数据条目。

XDG 标准 描述
Thumb::URI 必需 缩略图源文件的URI。
Thumb::MTime 必需 缩略图源文件的mtime。(功能上必需。)
Software 可选 创建缩略图的软件的名称。也被PNG标准描述。
这始终设置为allmytoes
Software::Version - 创建缩略图的AllMyToes的版本。
AMT::ProviderRevision - 对于来自提供者(非图像源)的缩略图,根据配置提供的提供者修订版。
Thumb::Size 可选 缩略图源文件的大小,以字节为单位。
Thumb::Mimetype 可选 缩略图源文件的mimetype。
Thumb::Image::Width 可选 源图像的宽度,以像素为单位。
Thumb::Image::Height 可选 源图像的高度,以像素为单位。
Thumb::Image::Dimensions - 一个字符串 <宽度>x<高度>,描述了缩略图源图像的尺寸。
Thumb::Image::重定向 - 对创建缩略图时进行的旋转和翻转的文本描述,基于缩略图源图像的EXIF数据。
仅当缩略图的来源是包含Orientation标志的EXIF数据的图像格式时。
Thumb::文档::页数 可选 页数(仅适用于PDF和PostScript文件)。
Thumb::电影::长度 可选 视频长度(秒,仅适用于视频文件)。

† 仅适用于图像输入文件

路线图

计划的主要里程碑

  • 遵守 freedesktop.org 规范的强制要求,并具有基本健壮性(见 %1)。然后 AllMyToes 将升级到 0.1.0 版本。
  • 通过配置提供预览的其他程序支持非图像文件格式(视频、字体、文档等)。(#13)
  • 支持 共享仓库
  • 根据配置的路径模式支持其他缩略图仓库位置。(不属于 freedesktop.org 标准。)

另请参阅 我的开发板

测试

一些东西通过标准 Rust 单元测试进行测试。可以使用 cargo test 运行这些测试。

大多数 AllMyToes 功能通过 BDD 测试框架进行端到端测试,该框架是 Python Behave。这些测试使用文件系统上的真实图像和一个 allmytoes 调试构建,作为子进程启动。

BDD 测试位于 test 子目录中。测试定义作为 feature-文件位于 test/features 中。

运行 BDD 测试

拥有 Python >= 3.10 环境和所需的依赖项。例如,使用 virtualenv,然后运行 pip install -r test/requirements.txt

拥有 AllMyToes 的 调试 构建。 target/debug/allmytoes 将是受测试的二进制文件。

然后,要运行测试,请使用 cd 进入 test 目录并运行 behave

关于缺少的测试/未测试事物的说明

  • XDG_CACHE_HOME 的评估
  • 对错误和缺失的文件扩展名进行 MIME 类型探测(如果 CI 失败,请检查是否在使用的 docker img 上安装了 MIME-db)
  • --force-creation
  • 当输入文件不可读时返回错误,无论是否存在有效的缩略图。
  • 更新现有但过时的缩略图
  • 在不存在、不可读、无法解码的输入文件上出错
  • 拒绝处理既不是常规文件也不是常规文件符号链接的文件
  • 所有 tEXt 元数据(mtime 和 URI 是隐式测试的,当然)
  • #61

您可能更喜欢使用此替代方案

  • Tumbler 是一个功能更丰富且更为成熟的用于同一目的的工具,但需要作为服务运行,并使用 DBUS 进行通信。

    我没有使用 Tumbler,因为我想要为我的脚本拥有更简单的东西。

AllMyToes 作为 Rust 库

AllMyToes 可以作为一个 Rust 库来获取给定图片的缩略图。您可以在 crates.io 上找到这个软件包。

AllMyToes 具有非常简洁的接口。有一个用于配置的 struct(AMT),它还提供了一个获取缩略图的功能(get)。然后,有一个枚举类型用于指定缩略图大小(ThumbSize),一个用于结果的 struct(Thumb),以及一个用于可能的错误类型的枚举(ToeErrorType)。

示例

use std::path::Path;
use allmytoes::{AMTConfiguration, AMT, ThumbSize};

fn main() {
    // The configuration for allmytoes
    // Usually, the defaults are fine.
    let configuration = AMTConfiguration::default();

    // An instance of allmytoes that can be used to provide thumbnails
    let amt = AMT::new(&configuration);

    // The file for which we want a thumbnail as a `std::path::Path`.
    let input_file = Path::new("/tmp/image.jpg");
    
    // The size of the thumbnail we want
    let thumb_size = ThumbSize::Large;

    // Get a thumbnail
    match amt.get(
        input_file,
        thumb_size,
    ) {
        Ok(thumb) => {
            println!("The thumb is here: {}", thumb.path)
        }
        Err(error) => println!(
            "Error '{:?}' occurred when trying to provide the thumb. ({})",
            error,
            error.msg(),
        ),
    }
}

许可协议:GPL 3

AllMyToes 是免费软件:您可以在自由软件基金会发布的 GNU 通用公共许可证的条款下重新分发和/或修改它,许可证版本为 3,或者(根据您的选择)许可证的任何后续版本。

AllMyToes 的分发旨在使其有用,但没有任何保证;甚至没有关于其商售性或适用于特定目的的隐含保证。有关详细信息,请参阅 GNU 通用公共许可证。

您应已收到 GNU 通用公共许可证的副本。如果没有,请参阅 https://gnu.ac.cn/licenses/

依赖关系

~12–19MB
~272K SLoC