class EmbedXMP::WebP

WebP images

Constants

VP8F_HEAD
VP8L_HEAD
VP8X_HEAD
VP8X_XMP_FLAG
WEBP_HEAD
XMPS_HEAD

Public Instance Methods

file_header() click to toggle source
Calls superclass method EmbedXMP::RIFF#file_header
# File lib/embed_xmp/webp.rb, line 27
def file_header
  riff_id, file_length, form_type = super

  raise 'NoWEBPHeader' if WEBP_HEAD != form_type

  [riff_id, file_length, form_type]
end
join_sidecar(sidecar_file, xpacked: false) click to toggle source

Join an XMP sidecar into the image file.

# File lib/embed_xmp/webp.rb, line 20
def join_sidecar(sidecar_file, xpacked: false)
  remove_xmp

  xmp_data = read_io_or_string(sidecar_file)
  upsert_xmp_chunk(create_xmp_chunk(xmp_data, xpacked))
end

Private Instance Methods

create_xmp_chunk(xmp_data, xpacked) click to toggle source

rubocop: enable Metrics/MethodLength

# File lib/embed_xmp/webp.rb, line 58
def create_xmp_chunk(xmp_data, xpacked)
  data = EmbedXMP::XMP
         .new(xmp_data, writable: true, xpacked: xpacked)
         .to_s.gsub("\0", ' ').b

  # pad with a potentially useful space char instead of NULL at end
  if data.length.odd?
    data[EmbedXMP::XMP::XPACKET_END_W] =
      " #{EmbedXMP::XMP::XPACKET_END_W}"
  end

  new_chunk(XMPS_HEAD, data)
end
dimensions_from_image_chunk(chunk_id, vp8_data) click to toggle source
# File lib/embed_xmp/webp.rb, line 95
def dimensions_from_image_chunk(chunk_id, vp8_data)
  case chunk_id
  when VP8F_HEAD
    dimensions_from_vp8(vp8_data[0, 10])
  when VP8L_HEAD
    dimensions_from_vp8_lossless(vp8_data[0, 10])
  end
end
dimensions_from_vp8(vp8_data) click to toggle source
# File lib/embed_xmp/webp.rb, line 79
def dimensions_from_vp8(vp8_data)
  width, height = vp8_data[6, 4]
                  .unpack('vv')
                  .map { |v| (v & 0b00111111_11111111) - 1 }
  [width, height]
end
dimensions_from_vp8_lossless(vp8_data) click to toggle source
# File lib/embed_xmp/webp.rb, line 86
def dimensions_from_vp8_lossless(vp8_data)
  b1, b2, b3, b4 = vp8_data[1, 4].unpack('c' * 4)

  width = ((b2 & 0b0011_1111) << 8) | b1
  height = ((b4 & 0b0011_1111) << 8) |
           ((b2 & 0b1100_0000) >> 6) | (b3 << 2)
  [width, height]
end
remove_xmp() click to toggle source

rubocop: disable Metrics/MethodLength

# File lib/embed_xmp/webp.rb, line 38
def remove_xmp
  offset = 12
  while offset < @image_data.length
    chunk_id, length, = chunk(offset)

    break if chunk_id.nil?

    if XMPS_HEAD == chunk_id
      remove_chunk(offset)
      toggle_xmp_feature(xmp: false)
      break if offset + length >= @image_data.length

      next
    end

    offset += length
  end
end
toggle_xmp_feature(xmp: true) click to toggle source
# File lib/embed_xmp/webp.rb, line 118
def toggle_xmp_feature(xmp: true)
  chunk_id, _, data = chunk(12)

  if VP8X_HEAD != chunk_id
    upgrade_to_extended_format
    return toggle_xmp_feature(xmp: xmp)
  end

  data[0] = (data.unpack1('c').to_i |  VP8X_XMP_FLAG).chr if xmp
  data[0] = (data.unpack1('c').to_i & ~VP8X_XMP_FLAG).chr unless xmp

  replace_chunk(12, chunk_id, data)
end
upgrade_to_extended_format() click to toggle source
# File lib/embed_xmp/webp.rb, line 104
def upgrade_to_extended_format
  chunk_id, _, data = chunk(12)

  width, height = dimensions_from_image_chunk(chunk_id, data)

  vp8x_data = [VP8X_XMP_FLAG, 0, 0, 0,
               width,  width  >> 8, 0,
               height, height >> 8, 0].pack('c' * 10)

  chunk = new_chunk(VP8X_HEAD, vp8x_data)

  insert_into_file(12, chunk)
end
upsert_xmp_chunk(xmp_chunk) click to toggle source
# File lib/embed_xmp/webp.rb, line 72
def upsert_xmp_chunk(xmp_chunk)
  remove_xmp
  @image_data += xmp_chunk
  update_file_length_header
  toggle_xmp_feature(xmp: true)
end