WebP: format specification

File extension

webp

KS implementation details

License: CC0-1.0
Minimal Kaitai Struct required: 0.11

References

This page hosts a formal specification of WebP using Kaitai Struct. This specification can be automatically translated into a variety of programming languages to get a parsing library.

Block diagram

Format specification in Kaitai Struct YAML

meta:
  id: webp
  title: WebP
  file-extension: webp
  xref:
    justsolve: WebP
    loc: fdd000577
    mime: image/webp
    pronom:
      - fmt/566 # WebP Lossy ('VP8 ')
      - fmt/567 # WebP Lossless ('VP8L')
      - fmt/568 # WebP Extended ('VP8X')
    rfc: 9649
    wikidata: Q62617958
  license: CC0-1.0
  ks-version: '0.11'
  encoding: UTF-8
  endian: le
  bit-endian: be
doc-ref: https://developers.google.com/speed/webp/docs/riff_container
seq:
  - id: magic
    contents: "RIFF"
  - id: len_data
    type: u4
  - id: webp
    contents: "WEBP"
  - id: payload
    size: len_data - webp._sizeof
    type: chunks
types:
  chunks:
    seq:
      - id: chunks
        type: chunk
        repeat: eos
  chunk:
    -webide-representation: '{name}'
    seq:
      - id: name
        type: u4
        enum: chunk_names
        valid:
          in-enum: true
      - id: len_data
        type: u4
      - id: data
        size: len_data
        type:
          switch-on: name
          cases:
            chunk_names::alph: alph
            chunk_names::anim: anim
            chunk_names::anmf: anmf
            chunk_names::vp8: vp8
            chunk_names::vp8l: vp8l
            chunk_names::vp8x: vp8x
            chunk_names::xmp: xmp
            chunk_names::xmp_var: xmp
      - id: padding
        contents: [0x00]
        if: len_data % 2 != 0
  vp8:
    meta:
      bit-endian: le
    doc-ref: https://www.rfc-editor.org/rfc/rfc6386#section-9.1
    seq:
      - id: frame_type
        type: b1
        valid: false # the VP8 chunk always holds a key frame
      - id: version
        type: b3
        valid:
          # See https://github.com/webmproject/libwebp/blob/4fa21912338357f89e4fd51cf2368325b59e9bd9/src/dec/vp8_dec.c#L305-L308 (Git tag "v1.6.0")
          max: 3 # only versions 0-3 are defined
      - id: show_frame
        type: b1
      - id: len_first_partition
        type: b19
      - id: start_code
        contents: [0x9d, 0x01, 0x2a]
      - id: width
        type: b14
      - id: horizontal_scale
        type: b2
      - id: height
        type: b14
      - id: vertical_scale
        type: b2
      - id: data
        size-eos: true
  vp8l:
    meta:
      bit-endian: le
    doc-ref: https://developers.google.com/speed/webp/docs/webp_lossless_bitstream_specification
    seq:
      - id: signature
        type: u1
        valid: 0x2f
      - id: image_width_minus_1
        type: b14
      - id: image_height_minus_1
        type: b14
      - id: alpha_is_used
        type: b1
        doc: |
          A hint only - it should not impact decoding. It should be `false` when
          all alpha values are 255 in the picture, and `true` otherwise.
      - id: version_number
        type: b3
        valid: 0
      - id: data
        size-eos: true
    instances:
      image_width:
        value: image_width_minus_1 + 1
      image_height:
        value: image_height_minus_1 + 1
  vp8x:
    seq:
      - id: reserved1
        type: b2
        valid: 0
      - id: icc_profile
        type: b1
      - id: alpha
        type: b1
      - id: exif
        type: b1
      - id: xmp
        type: b1
      - id: animation
        type: b1
      - id: reserved2
        type: b1
        valid: false
      - id: reserved3
        type: b24
        valid: 0
      - id: canvas_width_minus_1
        type: b24le
      - id: canvas_height_minus_1
        type: b24le
        valid:
          # From <https://developers.google.com/speed/webp/docs/riff_container#extended_file_format>:
          #
          # > The product of Canvas Width and Canvas Height MUST be at most
          # > `2^32 - 1`.
          max: (0xffff_ffff / canvas_width) - 1
    instances:
      canvas_width:
        value: canvas_width_minus_1 + 1
      canvas_height:
        value: canvas_height_minus_1 + 1
  alph:
    seq:
      - id: reserved
        type: b2
        valid: 0
      - id: preprocessing
        type: b2
        enum: preprocessing
        valid:
          in-enum: true
      - id: filtering
        type: b2
        enum: filtering_method
      - id: compression
        type: b2
        enum: compression_method
        valid:
          in-enum: true
      - id: data
        size-eos: true
  anim:
    doc-ref: https://developers.google.com/speed/webp/docs/riff_container#animation
    seq:
      - id: background_color
        type: bg_color
      - id: loop_count
        type: u2
    types:
      bg_color:
        -webide-representation: 'rgba({red:dec}, {green:dec}, {blue:dec}, {alpha:dec})'
        seq:
          - id: blue
            type: u1
          - id: green
            type: u1
          - id: red
            type: u1
          - id: alpha
            type: u1
  anmf:
    seq:
      - id: frame_x_div_2
        type: b24le
      - id: frame_y_div_2
        type: b24le
      - id: frame_width_minus_1
        type: b24le
      - id: frame_height_minus_1
        type: b24le
      - id: duration
        type: b24le
      - id: reserved
        type: b6
        valid: 0
      - id: blending_method
        type: b1
      - id: disposal_method
        type: b1
      - id: data
        size-eos: true
    instances:
      frame_x:
        value: frame_x_div_2 * 2
      frame_y:
        value: frame_y_div_2 * 2
      frame_width:
        value: frame_width_minus_1 + 1
      frame_height:
        value: frame_height_minus_1 + 1
  xmp:
    seq:
      - id: data
        size-eos: true
        type: str
        encoding: UTF-8
enums:
  chunk_names:
    0x48504c41: alph # 'ALPH'
    0x4d494e41: anim # 'ANIM'
    0x464d4e41: anmf # 'ANMF'
    0x46495845: exif # 'EXIF'
    0x4d475246: frgm # 'FRGM'
    0x50434349: iccp # 'ICCP'
    0x4c385056: vp8l # 'VP8L'
    0x20385056: vp8  # 'VP8 '
    0x58385056: vp8x # 'VP8X'
    0x20504d58: xmp  # 'XMP '
    # some files, for example in YTMusic.apk in some Android devices
    # have a different padding byte for the XMP FourCC.
    0x00504d58: xmp_var # 'XMP\0'
  filtering_method:
    0: none
    1: horizontal
    2: vertical
    3: gradient
  compression_method:
    0: none
    1: webp_lossless
  preprocessing:
    0: none
    1: level_reduction