Module: Okmain::Sampler

Defined in:
lib/okmain/sampler.rb

Constant Summary collapse

MAX_SAMPLE_SIZE =
250_000

Class Method Summary collapse

Class Method Details

.compute_block_size(total) ⇒ Object



54
55
56
57
58
59
60
61
62
# File 'lib/okmain/sampler.rb', line 54

def compute_block_size(total)
  return 1 if total <= MAX_SAMPLE_SIZE

  bs = Math.sqrt(total.to_f / MAX_SAMPLE_SIZE).ceil
  # Round up to multiple of 4
  remainder = bs % 4
  bs += (4 - remainder) if remainder != 0
  bs
end

.sample(input) ⇒ Object

Returns [pixels, width, height] where pixels is an Array of [L, a, b] triples.



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
40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/okmain/sampler.rb', line 12

def sample(input)
  image = if input.is_a?(Vips::Image)
            input
          else
            Vips::Image.new_from_file(input.to_s, access: :sequential)
          end

  # Flatten alpha to white background
  image = image.flatten(background: [255, 255, 255]) if image.has_alpha?

  # Convert to scRGB (linear float) for accurate block averaging
  image = image.colourspace(:scrgb)

  total = image.width * image.height
  block_size = compute_block_size(total)

  if block_size > 1
    image = image.shrink(block_size, block_size)
  end

  width = image.width
  height = image.height

  # Extract float pixel data [r, g, b] in linear space
  floats = image.write_to_memory.unpack("f*")
  bands = image.bands
  pixel_count = width * height

  pixels = Array.new(pixel_count)
  i = 0
  while i < pixel_count
    offset = i * bands
    r = floats[offset]
    g = floats[offset + 1]
    b = floats[offset + 2]
    pixels[i] = Oklab.linear_rgb_to_oklab(r, g, b)
    i += 1
  end

  [pixels, width, height]
end