Class: JekyllImgFlow::Providers::BaseProvider
- Inherits:
-
Object
- Object
- JekyllImgFlow::Providers::BaseProvider
- Defined in:
- lib/jekyll-imgflow/providers/base_provider.rb
Overview
Base provider class - all providers must inherit from this
Constant Summary collapse
- SMARTCROP_POSITIONS =
Valid smartcrop position values
%w[attention entropy center centre].freeze
- COMPASS_TO_SHORT =
Short compass → provider position mapping used by HTTP providers.
{ "northwest" => "tl", "northeast" => "tr", "southwest" => "bl", "southeast" => "br", "center" => "c" }.freeze
- KNOWN_OPERATIONS =
Provider capability methods
%i[crop format opacity optimize quality resize watermark alpha_opacity].freeze
Instance Attribute Summary collapse
-
#config ⇒ Object
Returns the value of attribute config.
Class Method Summary collapse
-
.provider_name ⇒ Object
Provider name for identification (override in subclasses).
- .supports_operation?(operation) ⇒ Boolean
- .unsupported_operations ⇒ Object
Instance Method Summary collapse
- #add_watermark(watermark_path, options = {}) ⇒ Object
-
#alpha_byte_value(opacity) ⇒ Object
Convert a 0..1 opacity float to a 0..255 integer (used by all providers that encode alpha as an 8-bit value).
- #alpha_opacity=(opacity) ⇒ Object
-
#available? ⇒ Boolean
Check if this provider is available (must be implemented by subclasses).
-
#check_http_service(url) ⇒ Object
Helper method for HTTP providers to check service availability.
-
#cli_available?(*commands) ⇒ Boolean
Check whether any of the given CLI commands is available on PATH.
-
#compass_to_short(position) ⇒ Object
Shared compass → short position mapping (tl/tr/bl/br/c).
- #convert_format(format) ⇒ Object
- #crop(ratio_or_width, height_val = nil, x_val = nil, y_val = nil) ⇒ Object
-
#crop_coords(operation, opts) ⇒ Object
Coordinates for a crop operation: ratio crops use calculated values, explicit crops use x/y/width/height options (defaulting x/y to 0).
-
#crop_geometry(operation) ⇒ Object
Normalize a crop operation into a geometry hash.
-
#encode_file_url(file_path) ⇒ Object
Helper method for HTTP providers to construct HTTP URLs from file paths.
-
#execute(input_path, output_path) ⇒ Object
Final execution method - providers must implement this.
-
#find_op(type) ⇒ Object
Operation lookup helpers — used by all providers to avoid repeating
@operations.find { |op| op[:type] == :xxx }. - #format(value) ⇒ Object
-
#initialize(config = {}) ⇒ BaseProvider
constructor
A new instance of BaseProvider.
-
#input_format_ext(input_path) ⇒ Object
Input format extension (lowercased, no dot) for format preservation.
- #op?(type) ⇒ Boolean
- #opacity(value) ⇒ Object
-
#operations ⇒ Object
Get current operations (for testing/debugging).
- #optimize(level = :medium) ⇒ Object
- #quality(value) ⇒ Object
- #quality=(quality) ⇒ Object
-
#relative_file_path(file_path, site) ⇒ Object
Get the relative path from site source using Pathname.
-
#reset_operations ⇒ Object
Reset operations for next processing.
-
#resize(width, height, options = {}) ⇒ Object
Operation collection methods - these should NOT execute immediately.
-
#smartcrop_interestingness(keep) ⇒ Object
Map a smartcrop
keepvalue to the libvips interestingness string used by Sharp and LibVips smartcrop/thumbnail --crop operations. - #supports_operation?(operation) ⇒ Boolean
-
#temp_path(input_path, suffix) ⇒ Object
Generate a temporary file path by replacing the extension of
input_pathwithsuffix(e.g. temp_path("a.jpg", "tmp_base.jpg") → "a.tmp_base.jpg"). - #watermark(watermark_path, options = {}) ⇒ Object
-
#watermark_parts(operation) ⇒ Object
Extract watermark operation parts into a hash.
Constructor Details
#initialize(config = {}) ⇒ BaseProvider
Returns a new instance of BaseProvider.
25 26 27 28 |
# File 'lib/jekyll-imgflow/providers/base_provider.rb', line 25 def initialize(config = {}) @config = config @operations = [] end |
Instance Attribute Details
#config ⇒ Object
Returns the value of attribute config.
23 24 25 |
# File 'lib/jekyll-imgflow/providers/base_provider.rb', line 23 def config @config end |
Class Method Details
.provider_name ⇒ Object
Provider name for identification (override in subclasses)
287 288 289 |
# File 'lib/jekyll-imgflow/providers/base_provider.rb', line 287 def provider_name name.split("::").last.downcase end |
.supports_operation?(operation) ⇒ Boolean
299 300 301 302 303 |
# File 'lib/jekyll-imgflow/providers/base_provider.rb', line 299 def supports_operation?(operation) return false unless KNOWN_OPERATIONS.include?(operation) !unsupported_operations.include?(operation) end |
.unsupported_operations ⇒ Object
295 296 297 |
# File 'lib/jekyll-imgflow/providers/base_provider.rb', line 295 def unsupported_operations [] # Default: no unsupported operations end |
Instance Method Details
#add_watermark(watermark_path, options = {}) ⇒ Object
222 223 224 225 |
# File 'lib/jekyll-imgflow/providers/base_provider.rb', line 222 def add_watermark(watermark_path, = {}) @operations << { type: :watermark, watermark_path: watermark_path, options: } end |
#alpha_byte_value(opacity) ⇒ Object
Convert a 0..1 opacity float to a 0..255 integer (used by all providers that encode alpha as an 8-bit value).
85 86 87 |
# File 'lib/jekyll-imgflow/providers/base_provider.rb', line 85 def alpha_byte_value(opacity) (opacity * 255).round end |
#alpha_opacity=(opacity) ⇒ Object
227 228 229 |
# File 'lib/jekyll-imgflow/providers/base_provider.rb', line 227 def alpha_opacity=(opacity) @operations << { type: :alpha_opacity, opacity: opacity } end |
#available? ⇒ Boolean
Check if this provider is available (must be implemented by subclasses)
116 117 118 119 120 |
# File 'lib/jekyll-imgflow/providers/base_provider.rb', line 116 def available? # Default: not available unless subclass implements actual check # This ensures providers explicitly check their availability false end |
#check_http_service(url) ⇒ Object
Helper method for HTTP providers to check service availability
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 |
# File 'lib/jekyll-imgflow/providers/base_provider.rb', line 123 def check_http_service(url) return false unless url begin require "net/http" require "uri" uri = URI(url) http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = uri.scheme == "https" http.read_timeout = 2 http.open_timeout = 2 request = Net::HTTP::Get.new(uri) http.request(request) # Consider available if we get any response (even 404 means service is running) true rescue StandardError false end end |
#cli_available?(*commands) ⇒ Boolean
Check whether any of the given CLI commands is available on PATH. Used by CLI providers (sharp, libvips, imagemagick).
108 109 110 111 112 113 |
# File 'lib/jekyll-imgflow/providers/base_provider.rb', line 108 def cli_available?(*commands) commands.any? do |cmd| _, _, status = Open3.capture3("which", cmd) status.success? end end |
#compass_to_short(position) ⇒ Object
Shared compass → short position mapping (tl/tr/bl/br/c). HTTP providers (imgproxy, weserv, flyimg) all use this mapping.
74 75 76 |
# File 'lib/jekyll-imgflow/providers/base_provider.rb', line 74 def compass_to_short(position) COMPASS_TO_SHORT[position.to_s] || position.to_s end |
#convert_format(format) ⇒ Object
202 203 204 |
# File 'lib/jekyll-imgflow/providers/base_provider.rb', line 202 def convert_format(format) @operations << { type: :format, format: format } end |
#crop(ratio_or_width, height_val = nil, x_val = nil, y_val = nil) ⇒ Object
187 188 189 190 191 192 193 194 195 196 |
# File 'lib/jekyll-imgflow/providers/base_provider.rb', line 187 def crop(ratio_or_width, height_val = nil, x_val = nil, y_val = nil) if height_val.is_a?(Hash) @operations << { type: :crop, ratio: ratio_or_width, options: height_val } elsif height_val = { width: ratio_or_width, height: height_val, x: x_val, y: y_val } @operations << .merge(type: :crop, ratio: nil, options: ) else @operations << { type: :crop, ratio: ratio_or_width, options: {} } end end |
#crop_coords(operation, opts) ⇒ Object
Coordinates for a crop operation: ratio crops use calculated values, explicit crops use x/y/width/height options (defaulting x/y to 0).
53 54 55 56 57 58 59 60 61 |
# File 'lib/jekyll-imgflow/providers/base_provider.rb', line 53 def crop_coords(operation, opts) if operation[:ratio] { x: opts[:calculated_x], y: opts[:calculated_y], width: opts[:calculated_width], height: opts[:calculated_height] } else { x: opts[:x] || 0, y: opts[:y] || 0, width: opts[:width], height: opts[:height] } end end |
#crop_geometry(operation) ⇒ Object
Normalize a crop operation into a geometry hash. Returns { smartcrop:, keep:, x:, y:, width:, height: } where smartcrop is true when ratio + keep + valid smartcrop position.
43 44 45 46 47 48 49 |
# File 'lib/jekyll-imgflow/providers/base_provider.rb', line 43 def crop_geometry(operation) opts = operation[:options] || {} params = operation[:params] || {} keep = opts[:keep] || params[:keep] || params[:position] smartcrop = operation[:ratio] && keep && SMARTCROP_POSITIONS.include?(keep.to_s) crop_coords(operation, opts).merge(smartcrop: smartcrop, keep: keep) end |
#encode_file_url(file_path) ⇒ Object
Helper method for HTTP providers to construct HTTP URLs from file paths
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 |
# File 'lib/jekyll-imgflow/providers/base_provider.rb', line 147 def encode_file_url(file_path) # If already a URL, return as-is return file_path if file_path.start_with?("http://", "https://") # For HTTP providers, construct proper HTTP URL site = @config.site relative_path = relative_file_path(file_path, site) # URL-encode each path segment to handle spaces and special characters encoded_path = relative_path.split("/").map do |segment| URI.encode_www_form_component(segment) end.join("/") # Construct HTTP URL for the file # Use Jekyll server URL (localhost:4000 by default for development) # In production, this would be the actual site URL from config base_url = site.config["url"] || "http://localhost:4000" baseurl = site.config["baseurl"] || "" "#{base_url}#{baseurl}/#{encoded_path}" end |
#execute(input_path, output_path) ⇒ Object
Final execution method - providers must implement this
240 241 242 |
# File 'lib/jekyll-imgflow/providers/base_provider.rb', line 240 def execute(input_path, output_path) raise NotImplementedError, "Provider must implement execute method" end |
#find_op(type) ⇒ Object
Operation lookup helpers — used by all providers to avoid
repeating @operations.find { |op| op[:type] == :xxx }.
32 33 34 |
# File 'lib/jekyll-imgflow/providers/base_provider.rb', line 32 def find_op(type) @operations.find { |op| op[:type] == type } end |
#format(value) ⇒ Object
210 211 212 |
# File 'lib/jekyll-imgflow/providers/base_provider.rb', line 210 def format(value) convert_format(value) end |
#input_format_ext(input_path) ⇒ Object
Input format extension (lowercased, no dot) for format preservation.
79 80 81 |
# File 'lib/jekyll-imgflow/providers/base_provider.rb', line 79 def input_format_ext(input_path) File.extname(input_path).delete(".").downcase end |
#op?(type) ⇒ Boolean
36 37 38 |
# File 'lib/jekyll-imgflow/providers/base_provider.rb', line 36 def op?(type) @operations.any? { |op| op[:type] == type } end |
#opacity(value) ⇒ Object
218 219 220 |
# File 'lib/jekyll-imgflow/providers/base_provider.rb', line 218 def opacity(value) self.alpha_opacity = value end |
#operations ⇒ Object
Get current operations (for testing/debugging)
250 251 252 |
# File 'lib/jekyll-imgflow/providers/base_provider.rb', line 250 def operations @operations.dup end |
#optimize(level = :medium) ⇒ Object
214 215 216 |
# File 'lib/jekyll-imgflow/providers/base_provider.rb', line 214 def optimize(level = :medium) @operations << { type: :optimize, level: level } end |
#quality(value) ⇒ Object
206 207 208 |
# File 'lib/jekyll-imgflow/providers/base_provider.rb', line 206 def quality(value) self.quality = value end |
#quality=(quality) ⇒ Object
198 199 200 |
# File 'lib/jekyll-imgflow/providers/base_provider.rb', line 198 def quality=(quality) @operations << { type: :quality, quality: quality } end |
#relative_file_path(file_path, site) ⇒ Object
Get the relative path from site source using Pathname
170 171 172 173 174 175 176 177 178 179 |
# File 'lib/jekyll-imgflow/providers/base_provider.rb', line 170 def relative_file_path(file_path, site) file_pathname = Pathname.new(file_path) if file_pathname.absolute? && file_path.to_s.start_with?(site.source) file_pathname.relative_path_from(Pathname.new(site.source)).to_s elsif file_path.start_with?("/") file_path[1..] else file_path end end |
#reset_operations ⇒ Object
Reset operations for next processing
245 246 247 |
# File 'lib/jekyll-imgflow/providers/base_provider.rb', line 245 def reset_operations @operations = [] end |
#resize(width, height, options = {}) ⇒ Object
Operation collection methods - these should NOT execute immediately
182 183 184 185 |
# File 'lib/jekyll-imgflow/providers/base_provider.rb', line 182 def resize(width, height, = {}) @operations << { type: :resize, width: width, height: height, options: } end |
#smartcrop_interestingness(keep) ⇒ Object
Map a smartcrop keep value to the libvips interestingness string
used by Sharp and LibVips smartcrop/thumbnail --crop operations.
98 99 100 101 102 103 104 |
# File 'lib/jekyll-imgflow/providers/base_provider.rb', line 98 def smartcrop_interestingness(keep) case keep.to_s when "entropy" then "entropy" when "center", "centre" then "centre" else "attention" end end |
#supports_operation?(operation) ⇒ Boolean
235 236 237 |
# File 'lib/jekyll-imgflow/providers/base_provider.rb', line 235 def supports_operation?(operation) self.class.supports_operation?(operation) end |
#temp_path(input_path, suffix) ⇒ Object
Generate a temporary file path by replacing the extension of
input_path with suffix (e.g. temp_path("a.jpg", "tmp_base.jpg")
→ "a.tmp_base.jpg").
92 93 94 |
# File 'lib/jekyll-imgflow/providers/base_provider.rb', line 92 def temp_path(input_path, suffix) input_path.gsub(/\.[^.]+$/, ".#{suffix}") end |
#watermark(watermark_path, options = {}) ⇒ Object
231 232 233 |
# File 'lib/jekyll-imgflow/providers/base_provider.rb', line 231 def watermark(watermark_path, = {}) add_watermark(watermark_path, ) end |
#watermark_parts(operation) ⇒ Object
Extract watermark operation parts into a hash.
64 65 66 67 68 69 70 |
# File 'lib/jekyll-imgflow/providers/base_provider.rb', line 64 def watermark_parts(operation) { watermark_path: operation[:watermark_path], position: operation[:options][:position], opacity: operation[:options][:opacity] } end |