You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WebP图片宽高存储字节位置咨询及Gradle插件解析方案问询

WebP图片宽高的字节位置及Gradle解析实现

WebP文件结构与宽高存储位置

WebP基于RIFF容器格式,先确认文件头部:前12字节固定为RIFF(0-3字节)+ 文件大小(4-7字节,小端序)+ WEBP(8-11字节)。之后的块(Chunk)决定了宽高的存储位置,分三种类型:

1. 有损WebP(VP8块)

  • 找到标识为VP8 (注意末尾带空格,12-15字节)的块
  • 跳过4字节的块大小(16-19字节)
  • 从20字节开始的4字节是VP8帧头核心段:
    • 高度:取第20字节的低2位(作为高2位),拼接第21字节的完整8位,公式:((byte20 & 0x3) << 8) | (byte21 & 0xFF)
    • 宽度:取第22字节的低2位(作为高2位),拼接第23字节的完整8位,公式:((byte22 & 0x3) << 8) | (byte23 & 0xFF)

2. 无损WebP(VP8L块)

  • 找到标识为VP8L(12-15字节)的块
  • 跳过4字节的块大小(16-19字节)
  • 从20字节开始的VP8L头部中,宽高各占14位(小端位存储),常规场景下可简化解析:
    • 宽度:第20字节的低6位 + 第21字节的8位,公式:((byte20 & 0x3F) << 8) | (byte21 & 0xFF)
    • 高度:第22字节的低6位 + 第23字节的8位,公式:((byte22 & 0x3F) << 8) | (byte23 & 0xFF)
      (如果宽高超过14位最大值,需要继续读取后续字节补充位,不过绝大多数图片不会触发这种情况)

3. 扩展WebP(VP8X块,带透明/动画)

  • 找到标识为VP8X(12-15字节)的块
  • 跳过4字节的块大小(16-19字节)
  • 从20字节开始的7字节中,宽高存储在21-23(宽度)、24-26(高度)字节:
    • 宽度:21-23字节按小端序拼接成24位整数后加1,公式:((byte21 & 0xFF) | ((byte22 & 0xFF) << 8) | ((byte23 & 0xFF) << 16)) + 1
    • 高度:24-26字节按小端序拼接成24位整数后加1,公式:((byte24 & 0xFF) | ((byte25 & 0xFF) << 8) | ((byte26 & 0xFF) << 16)) + 1

Gradle插件中解析宽高的实现思路

在Gradle插件里,通过读取文件字节流定位对应位置即可,以下是Groovy实现的核心代码片段:

def getWebpDimension(File webpFile) {
    FileInputStream fis = null
    try {
        fis = new FileInputStream(webpFile)
        // 验证WebP文件头
        byte[] riffHeader = new byte[12]
        if (fis.read(riffHeader) != 12 || !new String(riffHeader[8..11]).equals("WEBP")) {
            return null
        }

        byte[] chunkId = new byte[4]
        byte[] chunkSizeBytes = new byte[4]
        while (fis.read(chunkId) == 4) {
            fis.read(chunkSizeBytes)
            int chunkSize = ByteBuffer.wrap(chunkSizeBytes).order(ByteOrder.LITTLE_ENDIAN).getInt()
            String chunkName = new String(chunkId)

            switch (chunkName) {
                case "VP8 ":
                    // 解析有损WebP宽高
                    byte[] vp8FrameHeader = new byte[4]
                    fis.read(vp8FrameHeader)
                    int height = ((vp8FrameHeader[0] & 0x3) << 8) | (vp8FrameHeader[1] & 0xFF)
                    int width = ((vp8FrameHeader[2] & 0x3) << 8) | (vp8FrameHeader[3] & 0xFF)
                    return [width: width, height: height]
                case "VP8L":
                    // 解析无损WebP宽高
                    byte[] vp8lHeader = new byte[4]
                    fis.read(vp8lHeader)
                    int wpWidth = ((vp8lHeader[0] & 0x3F) << 8) | (vp8lHeader[1] & 0xFF)
                    int wpHeight = ((vp8lHeader[2] & 0x3F) << 8) | (vp8lHeader[3] & 0xFF)
                    return [width: wpWidth, height: wpHeight]
                case "VP8X":
                    // 解析扩展WebP宽高
                    byte[] vp8xHeader = new byte[7]
                    fis.read(vp8xHeader)
                    int xWidth = ((vp8xHeader[1] & 0xFF) | ((vp8xHeader[2] & 0xFF) << 8) | ((vp8xHeader[3] & 0xFF) << 16)) + 1
                    int xHeight = ((vp8xHeader[4] & 0xFF) | ((vp8xHeader[5] & 0xFF) << 8) | ((vp8xHeader[6] & 0xFF) << 16)) + 1
                    return [width: xWidth, height: xHeight]
                default:
                    // 跳过无关块
                    fis.skip(chunkSize)
            }
        }
    } catch (IOException e) {
        e.printStackTrace()
    } finally {
        fis?.close()
    }
    return null
}

注意事项

  • Java/Groovy中的byte是有符号类型,解析时必须用& 0xFF转为无符号整数,避免位运算错误
  • 需处理文件读取的异常情况(如文件不存在、读取中断等)
  • 若要兼容极端大尺寸的无损WebP,需要补充后续字节的位解析逻辑

内容的提问来源于stack exchange,提问作者ke le

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 05:05:43