- GIS
- 遥感
- 数据工程
【免费下载链接】gdal
GDAL is an open source MIT licensed translator library for raster and vector geospatial data formats.
导读
PNG(Portable Network Graphics)是栅格地理数据处理中最常用的无损压缩影像格式之一。GDAL 内置的 PNG 驱动基于 libpng 参考库实现,支持读取与创建灰度、伪彩色、调色板(Paletted)、RGB 与 RGBA 类型,以及 8 位与 16 位采样精度的 PNG 文件。本文以 GDAL 官方文档 doc/source/drivers/raster/png.rst 为骨架,结合 frmts/png/pngdataset.cpp 源码实现与 autotest/gdrivers/png.py 测试用例,系统讲解 PNG 驱动的数据模型、读取行为、创建选项、色彩配置(ICC/伽马/基色)、透明色与背景色处理等核心主题,帮助你完成从"能转 PNG"到"精准控制 PNG 输出质量与元数据"的进阶。
PNG 驱动概览:能力与限制
GDAL 的 PNG 驱动(shortname 为PNG)由 frmts/png/pngdrivercore.cpp 中的PNGDriverSetCommonMetadata()注册,声明如下核心能力:
| 能力项 | 值 | 说明 |
|---|---|---|
| 驱动名称 | PNG | 通过GetGDALDriverManager()注册 |
| 长名称 | Portable Network Graphics | 帮助主题指向drivers/raster/png.html |
| 文件扩展名 | .png | MIME 类型为image/png |
| 创建数据类型 | Byte、UInt16 | 见GDAL_DMD_CREATIONDATATYPES |
| 支持 CreateCopy | 是 | 驱动提供pfnCreateCopy,不支持Create |
| 支持 VirtualIO | 是 | 可读写/vsimem/、/vsistdout/等虚拟文件 |
| 支持地理参考 | 是 | 通过旁挂世界文件(world file)实现 |
驱动通过校验 PNG 文件头签名来识别文件,见 pngdrivercore.cpp 中PNGDriverIdentify()对固定签名{137, 80, 78, 71, 13, 10, 26, 10}的比对。GDAL 内建了 libpng 副本(frmts/png/libpng),因此在默认构建下无需外部依赖即可使用该驱动;构建配置见 frmts/png/CMakeLists.txt,它同时支持链接系统 libpng 与 zlib,并可选择启用 SSE2/NEON 优化。
支持的数据形态
官方文档明确声明,PNG 驱动支持读取和创建以下形态:
- 灰度(Greyscale)、伪彩色、调色板(Paletted)、RGB、RGBA;
- 每采样 8 位与 16 位精度;
- 1、2、4 位低比特深度读取(读取时由 libpng 自动解包为 8 位,并在
IMAGE_STRUCTURE元数据域中记录原始位深NBITS)。
从 pngdataset.cpp 的GetColorInterpretation()可以看出,驱动根据PNG_COLOR_TYPE_*将各波段映射为 GDAL 的颜色解释(GCI_GrayIndex、GCI_PaletteIndex、GCI_RedBand/GreenBand/BlueBand/AlphaBand)。
两大使用限制
文档特别强调 PNG 格式的固有特性:
- PNG 是线性压缩格式:随机读取大 PNG 文件效率极低,因为每次回溯都需要从文件头重新开始解压。这一点在源码中也有印证——pngdataset.cpp 的
LoadScanline()在请求行号小于当前已读行号时会调用Restart()回卷文件重新解压。因此建议按"自上而下"的块访问模式(GSBAP_TOP_TO_BOTTOM,见 pngdataset.h)顺序读取。 - 尺寸上限:受 libpng 约束,GDAL 可创建的 PNG 最大尺寸为 1,000,000 × 1,000,000 像素。
此外,源码头部的 ISSUES 注释还揭示了几个实现层面的已知限制(pngdataset.cpp):CollectMetadata()只能捕获图像数据之前的 TEXT 块;隔行(Interlaced)图像会被整体读入内存;16 位 alpha 值不会缩放为 8 位。
读取 PNG:元数据提取与透明/背景色语义
PNG 驱动读取时会将文件内嵌信息映射为 GDAL 元数据,并自动识别透明信息为 NoData 语义。
TEXT 块 → 数据集元数据
PNG 的tEXt/iTXt文本块会被转换为数据集元数据项,每个块一项(CollectMetadata(),见 pngdataset.cpp)。源码中会先把关键字里的空格、=、:替换为下划线再写入元数据。因此读取时元数据键名与 PNG 关键字可能略有差异。
透明值 → NoData 值
驱动对透明信息的读取遵循以下规则(见 pngdataset.cpp):
| 图像类型 | 行为 |
|---|---|
| 灰度(GRAY) | 读取tRNS块中单一透明值,设为波段 NoData 值 |
| 调色板(PALETTE) | 读取调色板及tRNS透明度数组,完整保留色表的透明索引;若恰好只有一个全透明索引,还会把它作为波段 NoData 值 |
| RGB | 读取tRNS中的透明色,写入NODATA_VALUES元数据(如32639 32639 32639),并分别设为三个波段的 NoData 值 |
背景色(BACKGROUND_COLOR)
自 GDAL 3.12 起(文档标注versionadded:: 3.12),PNG 的bKGD块在读取时会被报告为数据集元数据项BACKGROUND_COLOR:
- 灰度/灰度+Alpha:单个灰度值(如
123); - 调色板:调色板索引值;
- RGB/RGBA:逗号分隔的三个分量(如
123,234,67)。
对应实现见 pngdataset.cpp。测试用例 autotest/gdrivers/png.py 覆盖了 gray、gray_alpha、palette 索引、rgb、rgba 五种背景色场景的读写往返验证。
XMP 元数据
PNG 文件中的 XMP(通常存于iTXt块,关键字为XML:com.adobe.xmp)可被提取,并以原始 XML 内容存放在xml:XMP元数据域。CollectXMPMetadata()(pngdataset.cpp)会独立遍历文件块查找 XMP 内容,并限制其大小不超过 10 MB,且该域只在读取模式(GA_ReadOnly)下按需加载。
世界文件与地理参考
PNG 驱动通过旁挂世界文件提供地理参考。读取时按以下顺序尝试(LoadWorldFile(),见 pngdataset.cpp):
- 默认扩展名世界文件(
.pgw,随GDALReadWorldFile2()自动推断); - 显式
.wld扩展名文件。
官方文档明确支持.pgw、.pngw或.wld三种扩展名。世界文件格式的详细说明见 doc/source/drivers/raster/wld.rst。测试 autotest/gdrivers/png.py 还验证了世界文件中数字使用混合 locale(逗号与点混用)时的正确解析。
位深与块结构
- 1/2/4 位图像读取时由
png_set_packing()解包为 8 位(pngdataset.cpp),原始位深记录在波段IMAGE_STRUCTURE域的NBITS元数据中(pngdataset.cpp)。 - 16 位数据在大端存储的 PNG 中按字节序自动交换(MSB 序转本机序)。
- 默认块大小为整行(
nBlockYSize = 1);在启用整图优化(ENABLE_WHOLE_IMAGE_OPTIMIZATION,依赖 SSE2/NEON)且满足"8 位、非隔行、尺寸 ≤512×512、GDAL_PNG_WHOLE_IMAGE_OPTIM与GDAL_PNG_SINGLE_BLOCK配置为 YES"条件时,整幅图作为单块处理(IsCompatibleOfSingleBlock(),pngdataset.cpp)。测试 autotest/gdrivers/png.py 对 1~4 波段、多种尺寸与配置组合验证了该优化路径的读写一致性。
创建 PNG:CreateCopy 与数据类型约束
PNG 驱动通过CreateCopy()方法创建文件(pfnCreateCopy = PNGDataset::CreateCopy,见 pngdataset.cpp),不支持Create(),因此需要先有一个可读取的原型数据集。官方文档说明:除 16 位无符号整型外,所有像素类型都会被写为 8 位。
波段数与数据类型校验
CreateCopy()开头的校验逻辑(pngdataset.cpp)如下:
- 源波段数必须为 1(灰)、2(灰+Alpha)、3(RGB)或 4(RGBA),否则报错;
- 数据类型必须为
GDT_UInt8或GDT_UInt16,其他类型在严格模式(bStrict=TRUE)下报错退出,非严格模式下警告后降级为 Byte。
颜色类型自动判定
根据源数据集波段数与色表情况自动选择 PNG 颜色类型(pngdataset.cpp):
| 源波段数 | 源波段 1 有色表 | PNG 颜色类型 |
|---|---|---|
| 1 | 无 | PNG_COLOR_TYPE_GRAY(灰度) |
| 1 | 有 | PNG_COLOR_TYPE_PALETTE(调色板) |
| 2 | — | PNG_COLOR_TYPE_GRAY_ALPHA(灰度+Alpha) |
| 3 | — | PNG_COLOR_TYPE_RGB |
| 4 | — | PNG_COLOR_TYPE_RGB_ALPHA |
写入流程
创建过程(pngdataset.cpp)为逐行流式写入:对每一行通过源数据集RasterIO(GF_Read, ...)读取一条扫描线(16 位时做字节序交换),调用png_write_rows()写入;写入期间通过进度回调pfnProgress支持用户中断;最后png_write_end()收尾,并支持@CREATE_ONLY_VISIBLE_AT_CLOSE_TIME选项实现"关闭时才可见"的原子性创建(测试见 autotest/gdrivers/png.py)。
NoData 值在写入时会转换为 PNG 的tRNS块:灰度使用单一灰度透明值;RGB 优先使用源数据集的NODATA_VALUES元数据,否则依次取三个波段的 NoData 值;调色板图像则把 NoData 索引对应的调色板 alpha 置 0([pngdataset.cpp](https://link.gitcode.com/i/39d2e0346db30f91ebaaa3403ba9801e#L2432-L2520, L2711-L2780))。
创建选项详解(Creation Options)
PNG 驱动全部创建选项由 pngdrivercore.cpp 中的CreationOptionList声明,官方文档逐项列出,下面结合源码给出完整说明。
WORLDFILE
- 类型:布尔(YES/NO),默认
NO。 - 作用:强制生成与 PNG 关联的 ESRI 世界文件,扩展名为
.wld。写入实现见 pngdataset.cpp:先取源数据集地理变换,再调用GDALWriteWorldFile()写出同名.wld文件。世界文件格式详见 doc/source/drivers/raster/wld.rst。
ZLEVEL
- 类型:整数,取值范围
[0-9],默认6。 - 作用:设置压缩投入时间。
0最快但不压缩,9最慢但压缩率最高。源码在 pngdataset.cpp 中校验非法值(超出 0-9 直接报Illegal ZLEVEL value并中止创建),然后调用png_set_compression_level()。测试 autotest/gdrivers/png.py 用-1与10验证了报错路径,用0与9验证了合法边界。
文本块创建选项:TITLE / DESCRIPTION / COPYRIGHT / COMMENT
这四个选项分别对应 PNG 预定义关键字(Title、Description、Copyright、Comment),写入tEXt或iTXt块。源码在 pngdataset.cpp 中维护了包含 Title、Author、Description、Copyright、Creation Time、Software、Disclaimer、Warning、Source、Comment 的预定义关键字表,优先取创建选项值,其次(在开启WRITE_METADATA_AS_TEXT时)取源数据集同名元数据。
WRITE_METADATA_AS_TEXT
- 类型:布尔(YES/NO),默认
FALSE。 - 作用:是否将源数据集元数据写入 TEXT 块。开启后,除预定义关键字外的全部源元数据也会逐个写入 TEXT 块(排除
AREA_OR_POINT、NODATA_VALUES,见 pngdataset.cpp)。测试 autotest/gdrivers/png.py 验证了开启该选项后foo、Copyright、Description三类元数据均能写入并读回,且不产生 PAM(.aux.xml)文件。
NBITS
- 类型:整数,取值范围
1, 2, 4(自 GDAL 2.1 起)。 - 作用:强制输出位深。仅对 Byte 灰度波段有效;源码同时支持从源波段
IMAGE_STRUCTURE域的NBITS元数据自动继承位深,并以显式NBITS创建选项优先(pngdataset.cpp)。合法的NBITS值为 1、2、4、8;非法值(如 7)回退为 8 并告警。测试 autotest/gdrivers/png.py 验证了 1 位 TIFF 转 PNG 自动继承、NBITS=2显式指定与NBITS=7非法回退三种情况。
色彩配置创建选项
官方文档指出 COLOR_PROFILE 域中的所有元数据标签均可作为创建选项使用,包括:
SOURCE_ICC_PROFILE:Base64 编码的 ICC 配置文件;SOURCE_ICC_PROFILE_NAME:ICC 配置文件名,sRGB为特殊值;SOURCE_PRIMARIES_RED/GREEN/BLUE:红/绿/蓝基色的 xyY 值,格式为"x,y,1";SOURCE_WHITEPOINT:白点 xyY 值,格式为"x,y,1";PNG_GAMMA:伽马值。
写入逻辑见 pngdataset.cpp:若配置名是sRGB则直接写sRGB块(感知意图采用PNG_sRGB_INTENT_PERCEPTUAL);否则 Base64 解码后写iCCP块;无 ICC 时依次写gAMA、cHRM块(要求白点与三基色同时存在,且每组第 3 个分量必须等于 1.0)。测试 autotest/gdrivers/png_profile.py 验证了通过创建选项与源元数据两种途径写入/读回 ICC 配置文件的往返一致性。
其他通用创建选项
PNG 驱动还支持 GDAL 通用的COPY_SRC_MDD(默认 YES)、SRC_MDD等元数据域复制选项,测试 autotest/gdrivers/png.py 详细验证了默认、禁用、选择域复制三种场景。
色彩配置元数据(COLOR_PROFILE 域)
读取时,PNG 驱动可在COLOR_PROFILE元数据域中提供以下配置信息(LoadICCProfile(),见 pngdataset.cpp):
| 元数据项 | 来源块 | 说明 |
|---|---|---|
SOURCE_ICC_PROFILE | iCCP | Base64 编码的 ICC 配置,存在时其他标签被忽略 |
SOURCE_ICC_PROFILE_NAME | iCCP/sRGB | 配置名;sRGB被识别为特殊值 |
SOURCE_PRIMARIES_RED | cHRM | 红基色 xyY(x,y,1格式) |
SOURCE_PRIMARIES_GREEN | cHRM | 绿基色 xyY |
SOURCE_PRIMARIES_BLUE | cHRM | 蓝基色 xyY |
SOURCE_WHITEPOINT | cHRM | 白点 xyY |
PNG_GAMMA | gAMA | 伽马值 |
重要限制(文档原文强调):这些色彩配置元数据只能用于原始像素数据。如果图像已自动转换为 RGB,则色彩配置信息不可用。读取实现按iCCP→sRGB→gAMA/cHRM的优先级提取,且仅在GA_ReadOnly下按需惰性加载(GetMetadata()/GetMetadataItem()中触发),并刻意避免因此设置 PAM 脏标记(pngdataset.cpp)。
命令行实战:gdal_translate 转 PNG
PNG 驱动虽不支持Create(),但通过gdal_translate(其底层即CreateCopy)可方便地将任意 GDAL 支持的栅格转为 PNG。创建选项在命令行中通过-co传递:
# 基本转换:将 GeoTIFF 转为 PNG,并同时输出世界文件 gdal_translate -of PNG -co WORLDFILE=YES input.tif output.png # 指定压缩级别(0-9) gdal_translate -of PNG -co ZLEVEL=9 input.tif output.png # 写入标题、描述等文本块 gdal_translate -of PNG -co TITLE="My Map" -co DESCRIPTION="示例影像" input.tif output.png # 写入 ICC 配置(Base64 字符串) gdal_translate -of PNG -co SOURCE_ICC_PROFILE="<base64>..." input.tif output.png # 强制 1 位输出(需源为 Byte 单波段) gdal_translate -of PNG -co NBITS=1 input_1bit.tif output.png命令行亦可使用gdal_create(其封装CreateCopy语义)或 Python 绑定:
from osgeo import gdal src = gdal.Open("input.tif") drv = gdal.GetDriverByName("PNG") dst = drv.CreateCopy( "output.png", src, options=["WORLDFILE=YES", "ZLEVEL=9", "TITLE=My Map", "WRITE_METADATA_AS_TEXT=YES"], ) dst = None # 关闭并落盘若需地理参考而不写世界文件,也可使用-a_ullr等选项在转换时附上地理信息,但注意 PNG 本身不存储地理参考,必须依赖旁挂世界文件或 PAM(.aux.xml)元数据。
与 GeoTIFF 的关系及其他说明
官方文档特别指出一个有趣的关联:GeoTIFF 驱动支持带 DEFLATE 压缩的 tiled TIFF,而 DEFLATE 正是 PNG 核心使用的压缩算法。因此,在需要接近 PNG 的无损压缩体验、又要求更灵活的分块随机读取时,可考虑使用 DEFLATE 压缩的 GeoTIFF;PNG 则更适合按行顺序访问的完整无损影像交换场景。
最后,文档标注本驱动实现于 frmts/png/pngdataset.cpp,底层依赖 libpng 参考库;GDAL 仓库内建了 libpng 副本(frmts/png/libpng),并在 frmts/png/filter_sse2_intrinsics.c 中提供了 SSE2/NEON 优化的过滤函数加速路径。如需验证驱动行为,可参考 autotest/gdrivers/png.py 与 autotest/gdrivers/png_profile.py 中完整的读写、元数据、背景色、压缩级别与 ICC 配置测试。
- GIS
- 遥感
- 数据工程
【免费下载链接】gdal
GDAL is an open source MIT licensed translator library for raster and vector geospatial data formats.
相关推荐
GDAL AAIGrid 栅格驱动完全指南:Arc/Info ASCII Grid 读写、数据类型探测与配置选项解析
GDAL AAIGrid 栅格驱动完全指南:Arc/Info ASCII Grid 读写、数据类型探测与配置选项解析 AAIGrid 是 GDAL 内置的栅格驱
GIS遥感数据工程GDAL EHdr 驱动完全指南:读写 ESRI .hdr / BIL 栅格格式
GDAL EHdr 驱动完全指南:读写 ESRI .hdr / BIL 栅格格式 导读 ESRI 的 .hdr Labelled(通常称为 ESRI BIL )
GIS遥感数据工程CANN ops-math Im2col 算子深度解析:滑动窗口图像到列的 NPU 实现与调用指南
CANN ops math Im2col 算子深度解析:滑动窗口图像到列的 NPU 实现与调用指南 Im2col(Image to Column)是卷积类网络在
GIS遥感数据工程
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考