> ## Documentation Index
> Fetch the complete documentation index at: https://clickhouse.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

> PNG 图像输出格式文档

# PNG

| 输入 | 输出 | 别名 |
| -- | -- | -- |
| ✗  | ✔  | ✗  |

<div id="description">
  ## 描述
</div>

将查询结果渲染为 PNG 图像。这可用作内置的可视化工具。

输出图像的大小由设置
[`output_format_image_width`](/docs/zh/reference/settings/formats/output-format#output_format_image_width) 和
[`output_format_image_height`](/docs/zh/reference/settings/formats/output-format#output_format_image_height)
固定 (两者默认值均为 1024) 。结果未覆盖到的像素会填充为黑色
(在 `RGB` 和灰度图模式下) ，或透明黑色 (在 `RGBA` 模式下) 。

颜色模式会根据结果的列名和类型自动确定：

| 列                  | 模式                                 |
| ------------------ | ---------------------------------- |
| `r`, `g`, `b`      | 8 位 RGB                            |
| `r`, `g`, `b`, `a` | 8 位 RGBA                           |
| 整数类型的 `v`          | 8 位灰度图                             |
| `Float*` 类型的 `v`   | 8 位灰度图 (`[0, 1]` 中的值 → `[0, 255]`) |
| `Bool` 类型的 `v`     | 二值 (渲染为 8 位灰度图：`0` 或 `255`)        |

列名按不区分大小写方式匹配。如果无法明确
判定颜色模式 (例如列名未知、`v` 与 `r`/`g`/`b`/`a` 混用，或 `r`/`g`/`b` 中缺少某一列) ，
查询会抛出异常。

对于像素通道，整数值会被限制在 `[0, 255]` 范围内，而浮点值
会被限制在 `[0, 1]` 范围内，然后再缩放到 `[0, 255]`。

图像中每条记录的位置由以下两种模式之一决定：

* **隐式** (默认模式——即不存在 `x` 和 `y` 时) 。每条记录对应
  一个像素；像素按扫描线顺序填充：从左到右、从上到下。
* **显式** (当存在 `x` 和 `y` 列，且两者均为整数类型时) 。
  `x` 和 `y` 列给出像素坐标。坐标超出
  图像范围的记录会被静默忽略。如果多个记录具有相同坐标，
  则以最后一条记录为准 (画家算法) 。

<div id="example-usage">
  ## 使用示例
</div>

<div id="implicit-rgb">
  ### 隐式坐标 (每个像素一行) ，RGB
</div>

```sql theme={null}
SELECT
    toUInt8(x * 25) AS r,
    toUInt8(y * 25) AS g,
    toUInt8((x + y) * 12) AS b
FROM
(
    SELECT number % 10 AS x, intDiv(number, 10) AS y FROM numbers(100)
)
INTO OUTFILE 'gradient.png'
FORMAT PNG
SETTINGS output_format_image_width = 10, output_format_image_height = 10;
```

<div id="explicit-grayscale">
  ### 显式坐标，灰度图
</div>

```sql theme={null}
SELECT
    toInt32(x) AS x,
    toInt32(y) AS y,
    toUInt8(intensity) AS v
FROM points
INTO OUTFILE 'points.png'
FORMAT PNG
SETTINGS output_format_image_width = 512, output_format_image_height = 512;
```

<div id="animation">
  ## 动画
</div>

如果结果中存在整数类型的 `t` 列，该格式会生成动画 PNG (`APNG`) ，而不是
静态图像。记录会根据 `t` 的值分组成帧，`t` 表示帧的相对时间偏移。每一帧都是独立图像：每帧开始时画布均为空，在
隐式坐标模式下，光标也会从左上角重新开始。`t` 列可与
任一坐标模式结合使用。

`t` 的单位由
[`output_format_image_time_multiplier_seconds`](/docs/zh/reference/settings/formats/output-format#output_format_image_time_multiplier_seconds)
和
[`output_format_image_time_divisor_seconds`](/docs/zh/reference/settings/formats/output-format#output_format_image_time_divisor_seconds)确定：
一个 `t` 单位等于
`output_format_image_time_multiplier_seconds / output_format_image_time_divisor_seconds`
秒。使用默认值 (`1` 和 `60`) 时，一个 `t` 单位为 1/60 秒。

一帧会一直显示到下一帧开始，因此其耗时为两个连续
`t` 值之差。最后一帧的显示时间与前一帧相同。动画会无限循环。

```sql theme={null}
SELECT
    number % 60 AS t,
    toInt32(intDiv(number, 60) % 64) AS x,
    toInt32((number * 7) % 64) AS y,
    toUInt8(255) AS v
FROM numbers(60 * 64)
INTO OUTFILE 'animation.png'
FORMAT PNG
SETTINGS output_format_image_width = 64, output_format_image_height = 64;
```

<div id="streaming-animation">
  ### 流式输出帧
</div>

默认情况下，所有帧都会收集到内存中，并在查询结束时写出；系统会为 `t` 的每个不同值保留一个图像
缓冲区，且 `t` 可以按任意顺序到达。

设置
[`output_format_image_streaming_animation`](/docs/zh/reference/settings/formats/output-format#output_format_image_streaming_animation)
会在检测到下一个 `t` 值时立即写出当前帧。内存中只保留一个图像缓冲区，并且在查询仍在运行时，
帧就会输出，因此查看器可以在帧生成时显示它们。相应地：

* `t` 必须是非递减的；否则查询会抛出异常。必要时请添加 `ORDER BY t`。
* 写入请求头时尚无法得知帧数，因此 `acTL` 块声明的是上限，
  而非确切数量。浏览器可以播放这类文件，但信任声明数量的解码器
  (例如 `Pillow` 和一些命令行 `APNG` 工具) 会在最后一个实际帧之后报告错误。
  单帧动画是例外：写入该帧时，整个结果已经读取完毕，
  因此会精确声明数量，且输出符合规范。

由于内联终端图像协议会将整个数据流作为单个载荷传输，帧无法
提前到达终端，因此此设置在该场景下仅影响内存使用量。发送前会将确切帧数
修补到缓冲的载荷中，因此有关上限的注意事项不适用。

动画仅在 `iterm` 终端模式下显示。`sixel` 协议完全无法表示
动画，而 Kitty 图形协议只能通过单独的逐帧命令流实现动画，
无法通过动画数据流实现，因此只会显示第一帧；这两种模式都会拒绝包含
`t` 列的结果。

<div id="terminal-mode">
  ## 在终端中显示图像
</div>

默认情况下，`PNG` 格式会输出原始图像字节。通过设置
[`output_format_image_terminal_mode`](/docs/zh/reference/settings/formats/output-format#output_format_image_terminal_mode)
可使该格式改为使用内联图像协议，直接在终端中渲染图像：

| 值        | 行为                                                                  |
| -------- | ------------------------------------------------------------------- |
| \`\` (空) | 输出原始图像字节 (默认值) 。                                                    |
| `iterm`  | 使用 iTerm2 内联图像协议。                                                   |
| `kitty`  | 使用 Kitty 图形协议。无法显示动画。                                               |
| `sixel`  | 使用 Sixel 协议。图像会被缩减为固定的 6×6×6 调色板；如果存在 alpha 通道，则会将其合成到黑色背景上。        |
| `auto`   | 如果输出是终端，则检测其支持的协议，并使用 `iterm`、`kitty` 或 `sixel` (按此顺序) ；否则输出原始图像字节。 |

```sql theme={null}
SELECT toUInt8(x * 25) AS r, toUInt8(y * 25) AS g, toUInt8((x + y) * 12) AS b
FROM (SELECT number % 10 AS x, intDiv(number, 10) AS y FROM numbers(100))
FORMAT PNG
SETTINGS output_format_image_width = 10, output_format_image_height = 10, output_format_image_terminal_mode = 'auto';
```

<div id="format-settings">
  ## 格式 设置
</div>

| Setting                                       | 描述                     | 默认值      |
| --------------------------------------------- | ---------------------- | -------- |
| `output_format_image_width`                   | 输出图像的宽度 (以像素为单位) 。     | `1024`   |
| `output_format_image_height`                  | 输出图像的高度 (以像素为单位) 。     | `1024`   |
| `output_format_image_terminal_mode`           | 内联终端图像协议 (见上文) 。       | \`\` (空) |
| `output_format_image_time_multiplier_seconds` | `t` 列时间单位的分子，以秒为单位。    | `1`      |
| `output_format_image_time_divisor_seconds`    | `t` 列时间单位的分母，以秒为单位。    | `60`     |
| `output_format_image_streaming_animation`     | `t` 推进后立即写入每个帧 (见上文) 。 | `0`      |
