Class: JekyllImgFlow::Providers::Imagemagick

Inherits:
BaseProvider show all
Defined in:
lib/jekyll-imgflow/providers/imagemagick.rb

Overview

ImageMagick provider implementation using the standardized tag interface

Constant Summary

Constants inherited from BaseProvider

BaseProvider::SMARTCROP_POSITIONS

Instance Attribute Summary

Attributes inherited from BaseProvider

#config

Instance Method Summary collapse

Methods inherited from BaseProvider

#add_watermark, #alpha_opacity=, #check_http_service, #convert_format, #crop, #encode_file_url, #format, #initialize, #opacity, #operations, #optimize, provider_name, #quality, #quality=, #reset_operations, #resize, #supports_operation?, supports_operation?, unsupported_operations, #watermark

Constructor Details

This class inherits a constructor from JekyllImgFlow::Providers::BaseProvider

Instance Method Details

#available?Boolean

Returns:

  • (Boolean)


11
12
13
14
15
16
# File 'lib/jekyll-imgflow/providers/imagemagick.rb', line 11

def available?
  # Check if magick or convert CLI is available
  _, _, status1 = Open3.capture3("which", "magick")
  _, _, status2 = Open3.capture3("which", "convert")
  status1.success? || status2.success?
end

#build_combined_imagemagick_command(input_path, output_path) ⇒ Object



29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/jekyll-imgflow/providers/imagemagick.rb', line 29

def build_combined_imagemagick_command(input_path, output_path)
  # Start with base command
  command_parts = ["magick", input_path.shellescape]

  # Add all operations
  @operations.each do |operation|
    case operation[:type]
    when :resize
      # Tags now provide complete calculated values
      command_parts << "-resize" << if operation[:height]
                                      "#{operation[:width]}x#{operation[:height]}!"
                                    else
                                      operation[:width].to_s
                                    end

    when :crop
      opts = operation[:options]
      params = operation[:params] || {}

      # Check for keep parameter (ImageMagick doesn't support smartcrop, but we handle it gracefully)
      keep = opts[:keep] || params[:keep] || params[:position]

      if operation[:ratio] && keep && SMARTCROP_POSITIONS.include?(keep.to_s)
        # ImageMagick doesn't support smartcrop, but we handle the keep parameter
        # Use center gravity as a reasonable fallback for smartcrop requests
        crop_width = opts[:calculated_width]
        crop_height = opts[:calculated_height]
        crop_x = opts[:calculated_x]
        crop_y = opts[:calculated_y]

        # Use gravity center for smartcrop-like behavior
        crop_spec = "#{crop_width}x#{crop_height}+#{crop_x}+#{crop_y}"
        command_parts << "-gravity" << "center"
      else
        # Use basic cropping
        if operation[:ratio]
          crop_x = opts[:calculated_x]
          crop_y = opts[:calculated_y]
          crop_width = opts[:calculated_width]
          crop_height = opts[:calculated_height]
        else
          crop_x = opts[:x]
          crop_y = opts[:y]
          crop_width = opts[:width]
          crop_height = opts[:height]
        end
        crop_spec = "#{crop_width}x#{crop_height}+#{crop_x}+#{crop_y}"
      end
      command_parts << "-crop" << crop_spec

    when :quality
      magick_quality = translate_quality_to_imagemagick(operation[:quality])
      command_parts << "-quality" << magick_quality.to_s

    when :format
      # Assume validated input from tags
      # Format is handled by output filename extension
      # Quality is set separately if needed
      unless @operations.any? { |op| op[:type] == :quality }
        default_quality = @config&.quality || raise("No quality configured")
        command_parts << "-quality" << default_quality.to_s
      end

    when :watermark
      watermark_path = operation[:watermark_path]
      position = operation[:options][:position]

      # Translate compass directions to ImageMagick gravity format
      gravity = translate_position(position)

      # Add watermark as composite operation
      command_parts << watermark_path.shellescape
      command_parts << "-gravity" << gravity
      command_parts << "-composite"

    when :alpha_opacity
      opacity = operation[:opacity]
      alpha_value = (opacity * 100).round
      command_parts << "-alpha" << "set"
      command_parts << "-channel" << "A"
      command_parts << "-evaluate" << "multiply" << "#{alpha_value}%"
    end
  end

  # Add output filename
  command_parts << output_path.shellescape

  command_parts.join(" ")
end

#execute(input_path, output_path) ⇒ Object



18
19
20
21
22
23
24
25
26
27
# File 'lib/jekyll-imgflow/providers/imagemagick.rb', line 18

def execute(input_path, output_path)
  return if @operations.empty?

  # Build single ImageMagick command with all operations combined
  command = build_combined_imagemagick_command(input_path, output_path)
  execute_command(command)

  reset_operations
  output_path
end

#translate_position(position) ⇒ Object



119
120
121
122
123
124
125
126
127
128
# File 'lib/jekyll-imgflow/providers/imagemagick.rb', line 119

def translate_position(position)
  case position
  when "northwest" then "NorthWest"
  when "northeast" then "NorthEast"
  when "southwest" then "SouthWest"
  when "southeast" then "SouthEast"
  when "center" then "Center"
  else position
  end
end