☰
GDAL PNG 栅格驱动完全指南:读写机制、创建选项与色彩配置深度解析
2026/10/12 1:18:50 网站建设 项目流程
  • GIS
  • 遥感
  • 数据工程

【免费下载链接】gdal

GDAL is an open source MIT licensed translator library for raster and vector geospatial data formats.

项目地址:https://gitcode.com/gh_mirrors/gd/gdal
点击查看免费下载

导读

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
文件扩展名.pngMIME 类型为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 格式的固有特性:

  1. PNG 是线性压缩格式:随机读取大 PNG 文件效率极低,因为每次回溯都需要从文件头重新开始解压。这一点在源码中也有印证——pngdataset.cpp 的LoadScanline()在请求行号小于当前已读行号时会调用Restart()回卷文件重新解压。因此建议按"自上而下"的块访问模式(GSBAP_TOP_TO_BOTTOM,见 pngdataset.h)顺序读取。
  2. 尺寸上限:受 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):

  1. 默认扩展名世界文件(.pgw,随GDALReadWorldFile2()自动推断);
  2. 显式.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_PROFILEiCCPBase64 编码的 ICC 配置,存在时其他标签被忽略
SOURCE_ICC_PROFILE_NAMEiCCP/sRGB配置名;sRGB被识别为特殊值
SOURCE_PRIMARIES_REDcHRM红基色 xyY(x,y,1格式)
SOURCE_PRIMARIES_GREENcHRM绿基色 xyY
SOURCE_PRIMARIES_BLUEcHRM蓝基色 xyY
SOURCE_WHITEPOINTcHRM白点 xyY
PNG_GAMMAgAMA伽马值

重要限制(文档原文强调):这些色彩配置元数据只能用于原始像素数据。如果图像已自动转换为 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.

项目地址:https://gitcode.com/gh_mirrors/gd/gdal
点击查看免费下载
上一篇:探秘高效数据处理:ClickHouse Python Driver
下一篇:推荐开源项目:Meteor.js 文件管理库——Ostr.io Files

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询