Module: SafeImage::Native

Defined in:
lib/safe_image/native.rb

Overview

The libvips backend boundary. All libvips work is executed by the bundled safe_image_vips_helper process; the Ruby process never dlopens libvips. This module keeps the old Native call shape for the higher-level backend code while doing only argument normalization and response shaping in Ruby.

Class Method Summary collapse

Class Method Details

.available?Boolean

Returns:

  • (Boolean)


12
# File 'lib/safe_image/native.rb', line 12

def available? = NativeHelper.available?

.convert(input, output, format, quality, max_pixels) ⇒ Object



86
87
88
89
90
91
92
# File 'lib/safe_image/native.rb', line 86

def convert(input, output, format, quality, max_pixels)
  quality = Integer(quality)
  validate_quality!(quality)
  input = String(input)
  input_format!(input)
  NativeHelper.convert(input, String(output), output_format!(format), quality, checked_max_pixels(max_pixels))
end

.crop_north(input, output, width, height, format, quality, max_pixels) ⇒ Object

Raises:

  • (ArgumentError)


66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/safe_image/native.rb', line 66

def crop_north(input, output, width, height, format, quality, max_pixels)
  width = Integer(width)
  height = Integer(height)
  quality = Integer(quality)
  raise ArgumentError, "width and height must be positive" if width <= 0 || height <= 0
  validate_quality!(quality)

  input = String(input)
  input_format!(input)
  NativeHelper.crop_north(
    input,
    String(output),
    width,
    height,
    output_format!(format),
    quality,
    checked_max_pixels(max_pixels)
  )
end

.dominant_color(path, max_pixels) ⇒ Object



94
95
96
97
98
99
# File 'lib/safe_image/native.rb', line 94

def dominant_color(path, max_pixels)
  path = String(path)
  input_format!(path)
  hex = NativeHelper.dominant_color(path, checked_max_pixels(max_pixels))
  hex.scan(/../).map { |component| component.to_i(16) }
end

.letter_avatar(output, size, red, green, blue, markup, font, fontfile) ⇒ Object

Renders a letter avatar through the helper. Markup has already been escaped by VipsBackend; font tokens and font files come from its allowlist.

Raises:

  • (ArgumentError)


134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
# File 'lib/safe_image/native.rb', line 134

def letter_avatar(output, size, red, green, blue, markup, font, fontfile)
  size = Integer(size)
  channels = [Integer(red), Integer(green), Integer(blue)]
  raise ArgumentError, "size must be 1..4096" unless (1..4096).cover?(size)
  unless channels.all? { |value| (0..255).cover?(value) }
    raise ArgumentError, "background channels must be 0..255"
  end

  NativeHelper.letter_avatar(
    String(output),
    size,
    channels[0],
    channels[1],
    channels[2],
    String(markup),
    String(font),
    String(fontfile)
  )
  true
end

.orientation(path, max_pixels) ⇒ Object



107
108
109
110
111
# File 'lib/safe_image/native.rb', line 107

def orientation(path, max_pixels)
  path = String(path)
  input_format!(path)
  NativeHelper.orientation(path, checked_max_pixels(max_pixels))
end

.pages(path, max_pixels) ⇒ Object



101
102
103
104
105
# File 'lib/safe_image/native.rb', line 101

def pages(path, max_pixels)
  path = String(path)
  input_format!(path)
  NativeHelper.pages(path, checked_max_pixels(max_pixels))
end

.png_from_rgba(bytes, width, height, output) ⇒ Object

Encodes a raw RGBA buffer (top-down rows) as PNG. Used by the pure-Ruby ICO decoder; the raw bytes are staged to a tempfile and consumed by the helper so libvips remains out of the Ruby process.

Raises:

  • (ArgumentError)


116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# File 'lib/safe_image/native.rb', line 116

def png_from_rgba(bytes, width, height, output)
  bytes = String(bytes)
  width = Integer(width)
  height = Integer(height)
  raise ArgumentError, "width and height must be positive" if width <= 0 || height <= 0
  raise LimitError, "rgba buffer dimensions exceed 4096x4096" if width > 4096 || height > 4096
  raise ArgumentError, "rgba buffer must be width*height*4 bytes" if bytes.bytesize != width * height * 4

  Tempfile.create(%w[safe-image-rgba .rgba], binmode: true) do |raw|
    raw.write(bytes)
    raw.close
    NativeHelper.png_from_rgba(raw.path, width, height, String(output))
  end
  true
end

.probe(path, max_pixels = nil) ⇒ Object



14
15
16
17
18
19
20
21
22
23
24
# File 'lib/safe_image/native.rb', line 14

def probe(path, max_pixels = nil)
  path = String(path)
  input_format!(path)
  info = NativeHelper.probe(path, checked_max_pixels(max_pixels))
  {
    format: info.fetch(:input_format),
    width: info.fetch(:width),
    height: info.fetch(:height),
    duration_ms: info.fetch(:duration_ms)
  }
end

.resize(input, output, scale, format, quality, max_pixels) ⇒ Object



46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/safe_image/native.rb', line 46

def resize(input, output, scale, format, quality, max_pixels)
  scale = Float(scale)
  quality = Integer(quality)
  unless scale.finite? && scale.positive? && scale <= 100.0
    raise ArgumentError, "scale must be finite and in 0..100"
  end
  validate_quality!(quality)

  input = String(input)
  input_format!(input)
  NativeHelper.resize(
    input,
    String(output),
    scale,
    output_format!(format),
    quality,
    checked_max_pixels(max_pixels)
  )
end

.thumbnail(input, output, width, height, format, quality, max_pixels) ⇒ Object

Raises:

  • (ArgumentError)


26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# File 'lib/safe_image/native.rb', line 26

def thumbnail(input, output, width, height, format, quality, max_pixels)
  width = Integer(width)
  height = Integer(height)
  quality = Integer(quality)
  raise ArgumentError, "width and height must be positive" if width <= 0 || height <= 0
  validate_quality!(quality)

  input = String(input)
  input_format!(input)
  NativeHelper.thumbnail(
    input,
    String(output),
    width,
    height,
    output_format!(format),
    quality,
    checked_max_pixels(max_pixels)
  )
end