Module: JXL::Features::Patches

Defined in:
lib/jxl/features/patches.rb

Class Method Summary collapse

Class Method Details

.apply(channels, patches, references, metadata) ⇒ Object



74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/jxl/features/patches.rb', line 74

def apply(channels, patches, references, )
  return channels if patches.nil? || patches.empty?

  patches.each do |patch|
    source = references.fetch(patch.reference.frame).channels
    patch.reference.height.times do |dy|
      patch.reference.width.times do |dx|
        target_index = ((patch.y + dy) * channels[0].width) + patch.x + dx
        source_index = ((patch.reference.y + dy) * source[0].width) + patch.reference.x + dx
        blend_pixel!(channels, source, target_index, source_index, patch.blends, )
      end
    end
  end
  channels
end

.blend_value(old, new, info, background, foreground, metadata, colour_channels: 3, channel: nil) ⇒ Object



106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/jxl/features/patches.rb', line 106

def blend_value(old, new, info, background, foreground, , colour_channels: 3, channel: nil)
  alpha_index = colour_channels + info.alpha_channel
  alpha = foreground[alpha_index] || 1.0
  case info.mode
  when 0 then old
  when 1 then new
  when 2 then old + new
  when 3 then old * (info.clamp ? Num.clamp(new, 0.0, 1.0) : new)
  when 4 then alpha_blend(old, background[alpha_index], new, alpha, , info,
                          alpha: channel == alpha_index)
  when 5 then alpha_blend(new, alpha, old, background[alpha_index], , info,
                          alpha: channel == alpha_index)
  when 6 then channel == alpha_index ? old : old + (blend_alpha(alpha, info) * new)
  when 7
    channel == alpha_index ? new : new + (blend_alpha(background[alpha_index] || 1.0, info) * old)
  end
end

.read(reader, width, height, extra_channels, references) ⇒ Object

Raises:



12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# File 'lib/jxl/features/patches.rb', line 12

def read(reader, width, height, extra_channels, references)
  decoder = Entropy::Decoder.read(reader, 10, distance_multiplier: 0)
  count = decoder.read_uint(0)
  limit = 1024 + (width * height / 4)
  raise ResourceLimitError, "too many patch references" if count > limit

  ref_positions = []
  patches = []
  count.times do
    ref = decoder.read_uint(1)
    source = references[ref]
    raise CorruptError, "invalid patch reference" unless source

    x = decoder.read_uint(3)
    y = decoder.read_uint(3)
    patch_width = decoder.read_uint(2) + 1
    patch_height = decoder.read_uint(2) + 1
    if x + patch_width > source.width || y + patch_height > source.height
      raise CorruptError, "patch exceeds reference frame"
    end

    reference = PatchReference.new(frame: ref, x:, y:, width: patch_width, height: patch_height)
    ref_positions << reference
    read_positions(decoder, patches, reference, width, height, extra_channels, limit)
  end
  decoder.final_state!
  patches.freeze
end