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
118
119
120
121
122
123
124
125
126
127
|
# File 'lib/safe_image/processor.rb', line 38
def thumbnail(input:, output:, width:, height:, format: nil, quality: 85, optimize: false, optimize_mode: :lossless)
input = safe_existing_file!(input)
output = safe_output_path!(output)
width = Integer(width)
height = Integer(height)
quality = Integer(quality)
raise ArgumentError, "width and height must be positive" if width <= 0 || height <= 0
raise ArgumentError, "quality must be 1..100" unless (1..100).cover?(quality)
out_format = (format || output.extname.delete_prefix(".")).downcase
out_format = "jpg" if out_format == "jpeg"
unless SUPPORTED_OUTPUTS.include?(out_format)
raise UnsupportedFormatError, "unsupported output format: #{out_format.inspect}"
end
if @execution == :sandbox || @execution == :sandbox_if_available
if @execution == :sandbox && !Sandbox.available?
raise Error, "sandbox execution requested but Landlock::SafeExec is unavailable"
end
info = Sandbox.thumbnail(
input: input.to_s,
output: output.to_s,
width: width,
height: height,
format: out_format,
quality: quality,
max_pixels: @max_pixels,
backend: @backend,
optimize: optimize,
optimize_mode: optimize_mode
)
if info
return Result.new(
input: input.to_s,
output: output.to_s,
input_format: info.fetch(:input_format),
output_format: info.fetch(:output_format),
width: info.fetch(:width),
height: info.fetch(:height),
filesize: File.size(output),
backend: "sandboxed-#{info.fetch(:backend)}",
duration_ms: info.fetch(:duration_ms),
optimizer: info[:optimizer]
)
end
end
output.dirname.mkpath
info =
if out_format == "jpg" && use_jpegli_for_generated_jpeg?(input)
jpegli_thumbnail(input: input, output: output, width: width, height: height, quality: quality, source_format: input.extname.delete_prefix(".").downcase)
else
case @backend
when :vips
Native.thumbnail(input.to_s, output.to_s, width, height, out_format, quality, @max_pixels)
when :imagemagick, :magick
probe_info = Native.probe(input.to_s)
validate_pixels!(probe_info.fetch(:width), probe_info.fetch(:height))
ImageMagickBackend.thumbnail(
input: input.to_s,
output: output.to_s,
width: width,
height: height,
format: out_format,
quality: quality
)
else
raise ArgumentError, "unknown backend: #{@backend.inspect}"
end
end
opt_info = nil
if optimize
opt_info = Optimizer.optimize(output, mode: optimize_mode, strip_metadata: true, quality: out_format == "jpg" ? quality : nil)
end
Result.new(
input: input.to_s,
output: output.to_s,
input_format: info.fetch(:input_format),
output_format: info.fetch(:output_format),
width: info.fetch(:width),
height: info.fetch(:height),
filesize: File.size(output),
backend: result_backend(info),
duration_ms: info.fetch(:duration_ms),
optimizer: opt_info&.fetch(:tools, nil)
)
end
|