Class: Retouch::CLI

Inherits:
Object
  • Object
show all
Defined in:
lib/retouch/cli.rb,
sig/retouch.rbs

Constant Summary collapse

OPERATIONS =
%w[
  resize thumbnail crop flip flop rotate pad extend border trim
  grayscale invert brightness contrast gamma saturate tint opacity quantize
  blur sharpen pixelate overlay watermark text rect arrow
  montage append spritesheet animate diff
].freeze
MULTI_IMAGE_OPERATIONS =
%w[montage append spritesheet animate diff].freeze
OPERATION_USAGE =
{
  "resize" => "GEOMETRY [--filter nearest|bilinear|bicubic|lanczos3] [--gravity POSITION]",
  "thumbnail" => "GEOMETRY [--filter FILTER]",
  "crop" => "GEOMETRY [--gravity POSITION]",
  "rotate" => "DEGREES [--background COLOR]",
  "pad" => "PIXELS [--color COLOR]",
  "extend" => "WIDTH HEIGHT [--color COLOR] [--gravity POSITION]",
  "border" => "PIXELS [COLOR]",
  "trim" => "[--color COLOR] [--fuzz 0..255]",
  "brightness" => "-255..255",
  "contrast" => "FACTOR",
  "gamma" => "GAMMA",
  "saturate" => "FACTOR",
  "tint" => "COLOR [--amount 0..1]",
  "opacity" => "0..1",
  "quantize" => "[--colors 2..256] [--dither none|ordered|floyd-steinberg]",
  "blur" => "SIGMA",
  "sharpen" => "SIGMA [--amount FACTOR]",
  "pixelate" => "BLOCK_SIZE",
  "overlay" => "IMAGE [--x X] [--y Y] [--gravity POSITION] [--opacity 0..1] [--mode MODE]",
  "watermark" => "IMAGE [composite options]",
  "text" => "TEXT [--at POSITION] [--size PIXELS] [--font FILE] [--background COLOR]",
  "rect" => "X Y WIDTH HEIGHT [COLOR] [--fill]",
  "arrow" => "X1 Y1 X2 Y2 [COLOR] [--width PIXELS] [--head PIXELS]",
  "montage" => "[--cols N] [--gap PIXELS] [--background COLOR] [--label]",
  "append" => "[--direction vertical|horizontal] [--gap PIXELS]",
  "spritesheet" => "[--max-width PIXELS] [--gap PIXELS]",
  "animate" => "(--fps RATE | --delay SECONDS) [--no-loop]",
  "diff" => "[--threshold 0..255] [--color COLOR]"
}.freeze

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(argv, out:, err:) ⇒ CLI

Returns a new instance of CLI.

Raises:

  • (ArgumentError)


53
54
55
56
57
58
59
60
61
# File 'lib/retouch/cli.rb', line 53

def initialize(argv, out:, err:)
  @args = argv.dup
  @out = out
  @err = err
  @options = { level: 6, jobs: 1, loop: true }
  read_global_options
  raise ArgumentError, "PNG level must be between 0 and 9" unless @options[:level].between?(0, 9)
  raise ArgumentError, "jobs must be positive" unless @options[:jobs].positive?
end

Class Method Details

.run(argv, out: $stdout, err: $stderr) ⇒ Integer

Parameters:

  • argv (Array[String])
  • out: (Object) (defaults to: $stdout)
  • err: (Object) (defaults to: $stderr)

Returns:

  • (Integer)


46
47
48
49
50
51
# File 'lib/retouch/cli.rb', line 46

def self.run(argv, out: $stdout, err: $stderr)
  new(argv, out:, err:).run
rescue ArgumentError, OptionParser::ParseError => e
  err.puts("retouch: #{e.message}")
  2
end

Instance Method Details

#run ⇒ Object



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
# File 'lib/retouch/cli.rb', line 63

def run
  return help if @options[:help] || @args.empty?
  return info_command if @args.first == "info"
  return help(@args[1]) if @args.first == "help"

  operation_at = @args.index { |token| OPERATIONS.include?(token) }
  return fail_usage("missing operation") unless operation_at

  inputs = @args.shift(operation_at)
  return fail_usage("at least one input file is required") if inputs.empty?
  return fail_usage("an output path with -o is required") unless @options[:output]

  operation = @args.first
  parsed = parse_cli_operations(@args)
  return 2 unless parsed

  if MULTI_IMAGE_OPERATIONS.include?(operation)
    return fail_usage("#{operation} must be the only operation in its command") unless parsed.one?

    multi_image_command(inputs, operation, parsed.fetch(0))
  else
    image_command(inputs, parsed)
  end
rescue StandardError => e
  @err.puts("retouch: #{e.message}")
  @err.puts(e.backtrace.first) if @options[:verbose]
  1
end