fast_resize 1.0.2 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/VERSION +1 -1
- data/bindings/ruby/ext/fastresize/extconf.rb +79 -105
- data/bindings/ruby/lib/fastresize/platform.rb +102 -56
- data/bindings/ruby/lib/fastresize/version.rb +1 -1
- data/bindings/ruby/lib/fastresize.rb +321 -6
- data/bindings/ruby/prebuilt/linux-aarch64/bin/fast_resize +0 -0
- data/bindings/ruby/prebuilt/linux-aarch64.tar.gz +0 -0
- data/bindings/ruby/prebuilt/linux-x86_64/bin/fast_resize +0 -0
- data/bindings/ruby/prebuilt/linux-x86_64/lib/libfastresize.a +0 -0
- data/bindings/ruby/prebuilt/linux-x86_64.tar.gz +0 -0
- data/bindings/ruby/prebuilt/macos-arm64/bin/fast_resize +0 -0
- data/bindings/ruby/prebuilt/macos-arm64/lib/libfastresize.a +0 -0
- data/bindings/ruby/prebuilt/macos-arm64.tar.gz +0 -0
- data/bindings/ruby/prebuilt/macos-x86_64/bin/fast_resize +0 -0
- data/bindings/ruby/prebuilt/macos-x86_64/lib/libfastresize.a +0 -0
- data/bindings/ruby/prebuilt/macos-x86_64.tar.gz +0 -0
- metadata +4 -22
- data/CMakeLists.txt +0 -311
- data/bindings/ruby/ext/fastresize/fastresize_ext.cpp +0 -377
- data/include/fastresize.h +0 -189
- data/include/stb_image.h +0 -7988
- data/include/stb_image_resize2.h +0 -10651
- data/include/stb_image_write.h +0 -1724
- data/src/cli.cpp +0 -540
- data/src/decoder.cpp +0 -647
- data/src/encoder.cpp +0 -376
- data/src/fastresize.cpp +0 -445
- data/src/internal.h +0 -108
- data/src/pipeline.cpp +0 -284
- data/src/pipeline.h +0 -175
- data/src/resizer.cpp +0 -199
- data/src/simd_resize.cpp +0 -384
- data/src/simd_resize.h +0 -72
- data/src/simd_utils.h +0 -127
- data/src/thread_pool.cpp +0 -232
|
@@ -1,13 +1,328 @@
|
|
|
1
|
-
|
|
1
|
+
# FastResize - The Fastest Image Resizing Library On The Planet
|
|
2
|
+
# Copyright (C) 2025 Tran Huu Canh (0xTh3OKrypt) and FastResize Contributors
|
|
3
|
+
#
|
|
4
|
+
# Resize 1,000 images in 2 seconds. Up to 2.9x faster than libvips,
|
|
5
|
+
# 3.1x faster than imageflow. Uses 3-4x less RAM than alternatives.
|
|
6
|
+
#
|
|
7
|
+
# Author: Tran Huu Canh (0xTh3OKrypt)
|
|
8
|
+
# Email: tranhuucanh39@gmail.com
|
|
9
|
+
# Homepage: https://github.com/tranhuucanh/fast_resize
|
|
10
|
+
#
|
|
11
|
+
# BSD 3-Clause License
|
|
12
|
+
#
|
|
13
|
+
# Redistribution and use in source and binary forms, with or without
|
|
14
|
+
# modification, are permitted provided that the following conditions are met:
|
|
15
|
+
#
|
|
16
|
+
# 1. Redistributions of source code must retain the above copyright notice,
|
|
17
|
+
# this list of conditions and the following disclaimer.
|
|
18
|
+
#
|
|
19
|
+
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
20
|
+
# this list of conditions and the following disclaimer in the documentation
|
|
21
|
+
# and/or other materials provided with the distribution.
|
|
22
|
+
#
|
|
23
|
+
# 3. Neither the name of the copyright holder nor the names of its
|
|
24
|
+
# contributors may be used to endorse or promote products derived from
|
|
25
|
+
# this software without specific prior written permission.
|
|
26
|
+
#
|
|
27
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
28
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
29
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
30
|
+
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
|
31
|
+
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
32
|
+
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
33
|
+
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
34
|
+
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
35
|
+
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
36
|
+
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
|
37
|
+
# THE POSSIBILITY OF SUCH DAMAGE.
|
|
2
38
|
|
|
3
|
-
|
|
4
|
-
|
|
39
|
+
require_relative "fastresize/version"
|
|
40
|
+
require_relative "fastresize/platform"
|
|
5
41
|
|
|
42
|
+
module FastResize
|
|
6
43
|
class Error < StandardError; end
|
|
7
44
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
45
|
+
# Get library version
|
|
46
|
+
#
|
|
47
|
+
# @return [String] Version string
|
|
48
|
+
def self.version
|
|
49
|
+
cli_path = Platform.find_binary
|
|
50
|
+
output = `#{cli_path} --version 2>&1`.strip
|
|
51
|
+
output.sub('FastResize v', '')
|
|
52
|
+
rescue => e
|
|
53
|
+
VERSION
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Get image information
|
|
57
|
+
#
|
|
58
|
+
# @param path [String] Path to the image file
|
|
59
|
+
# @return [Hash] Image info with :width, :height, :channels, :format
|
|
60
|
+
#
|
|
61
|
+
# @example
|
|
62
|
+
# FastResize.image_info("photo.jpg")
|
|
63
|
+
# # => { width: 1920, height: 1080, channels: 3, format: "JPEG" }
|
|
64
|
+
def self.image_info(path)
|
|
65
|
+
raise Error, "Image path cannot be empty" if path.nil? || path.empty?
|
|
66
|
+
raise Error, "Image file not found: #{path}" unless File.exist?(path)
|
|
67
|
+
|
|
68
|
+
cli_path = Platform.find_binary
|
|
69
|
+
output = `#{cli_path} info '#{path}' 2>&1`
|
|
70
|
+
raise Error, "Failed to get image info: #{output}" unless $?.success?
|
|
71
|
+
|
|
72
|
+
info = {}
|
|
73
|
+
output.each_line do |line|
|
|
74
|
+
case line
|
|
75
|
+
when /Format:\s*(\S+)/
|
|
76
|
+
info[:format] = $1
|
|
77
|
+
when /Size:\s*(\d+)x(\d+)/
|
|
78
|
+
info[:width] = $1.to_i
|
|
79
|
+
info[:height] = $2.to_i
|
|
80
|
+
when /Channels:\s*(\d+)/
|
|
81
|
+
info[:channels] = $1.to_i
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
info
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# Resize a single image
|
|
89
|
+
#
|
|
90
|
+
# @param input_path [String] Path to input image
|
|
91
|
+
# @param output_path [String] Path to save resized image
|
|
92
|
+
# @param options [Hash] Resize options
|
|
93
|
+
# @option options [Integer] :width Target width in pixels
|
|
94
|
+
# @option options [Integer] :height Target height in pixels
|
|
95
|
+
# @option options [Float] :scale Scale factor (e.g., 0.5 = 50%, 2.0 = 200%)
|
|
96
|
+
# @option options [Integer] :quality JPEG/WebP quality 1-100 (default: 85)
|
|
97
|
+
# @option options [Symbol] :filter Resize filter: :mitchell, :catmull_rom, :box, :triangle
|
|
98
|
+
# @option options [Boolean] :keep_aspect_ratio Maintain aspect ratio (default: true)
|
|
99
|
+
# @option options [Boolean] :overwrite Overwrite input file (default: false)
|
|
100
|
+
# @return [Boolean] true if successful
|
|
101
|
+
#
|
|
102
|
+
# @example Basic resize by width
|
|
103
|
+
# FastResize.resize("input.jpg", "output.jpg", width: 800)
|
|
104
|
+
#
|
|
105
|
+
# @example Resize to exact dimensions
|
|
106
|
+
# FastResize.resize("input.jpg", "output.jpg", width: 800, height: 600)
|
|
107
|
+
#
|
|
108
|
+
# @example Scale to 50%
|
|
109
|
+
# FastResize.resize("input.jpg", "output.jpg", scale: 0.5)
|
|
110
|
+
#
|
|
111
|
+
# @example With quality and filter
|
|
112
|
+
# FastResize.resize("input.jpg", "output.jpg",
|
|
113
|
+
# width: 800,
|
|
114
|
+
# quality: 95,
|
|
115
|
+
# filter: :catmull_rom
|
|
116
|
+
# )
|
|
117
|
+
def self.resize(input_path, output_path, options = {})
|
|
118
|
+
raise Error, "Input path cannot be empty" if input_path.nil? || input_path.empty?
|
|
119
|
+
raise Error, "Output path cannot be empty" if output_path.nil? || output_path.empty?
|
|
120
|
+
raise Error, "Input file not found: #{input_path}" unless File.exist?(input_path)
|
|
121
|
+
|
|
122
|
+
cli_path = Platform.find_binary
|
|
123
|
+
args = build_resize_args(input_path, output_path, options)
|
|
124
|
+
|
|
125
|
+
result = system(cli_path, *args, out: File::NULL, err: File::NULL)
|
|
126
|
+
raise Error, "Failed to resize image" unless result
|
|
127
|
+
|
|
128
|
+
true
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# Resize with format conversion
|
|
132
|
+
#
|
|
133
|
+
# @param input_path [String] Path to input image
|
|
134
|
+
# @param output_path [String] Path to save resized image
|
|
135
|
+
# @param format [String] Output format: 'jpg', 'png', 'webp'
|
|
136
|
+
# @param options [Hash] Resize options (same as resize)
|
|
137
|
+
# @return [Boolean] true if successful
|
|
138
|
+
#
|
|
139
|
+
# @example Convert to WebP
|
|
140
|
+
# FastResize.resize_with_format("input.jpg", "output.webp", "webp", width: 800)
|
|
141
|
+
def self.resize_with_format(input_path, output_path, format, options = {})
|
|
142
|
+
raise Error, "Input path cannot be empty" if input_path.nil? || input_path.empty?
|
|
143
|
+
raise Error, "Output path cannot be empty" if output_path.nil? || output_path.empty?
|
|
144
|
+
raise Error, "Format cannot be empty" if format.nil? || format.empty?
|
|
145
|
+
raise Error, "Input file not found: #{input_path}" unless File.exist?(input_path)
|
|
146
|
+
|
|
147
|
+
# The CLI handles format based on output extension
|
|
148
|
+
# Ensure output path has the correct extension
|
|
149
|
+
ext = File.extname(output_path).downcase
|
|
150
|
+
expected_ext = ".#{format.downcase}"
|
|
151
|
+
|
|
152
|
+
if ext != expected_ext
|
|
153
|
+
output_path = output_path.sub(/\.[^.]+$/, expected_ext)
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
resize(input_path, output_path, options)
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
# Batch resize images to a directory with same options
|
|
160
|
+
#
|
|
161
|
+
# @param input_paths [Array<String>] Array of input image paths
|
|
162
|
+
# @param output_dir [String] Output directory
|
|
163
|
+
# @param options [Hash] Resize options plus batch options
|
|
164
|
+
# @option options [Integer] :threads Number of threads (default: auto)
|
|
165
|
+
# @option options [Boolean] :stop_on_error Stop on first error (default: false)
|
|
166
|
+
# @option options [Boolean] :max_speed Enable pipeline mode (default: false)
|
|
167
|
+
# @return [Hash] Result with :total, :success, :failed, :errors
|
|
168
|
+
#
|
|
169
|
+
# @example Batch resize
|
|
170
|
+
# files = Dir["photos/*.jpg"]
|
|
171
|
+
# result = FastResize.batch_resize(files, "thumbnails/", width: 300)
|
|
172
|
+
# # => { total: 100, success: 100, failed: 0, errors: [] }
|
|
173
|
+
def self.batch_resize(input_paths, output_dir, options = {})
|
|
174
|
+
raise Error, "Input paths cannot be empty" if input_paths.nil? || input_paths.empty?
|
|
175
|
+
raise Error, "Output directory cannot be empty" if output_dir.nil? || output_dir.empty?
|
|
176
|
+
|
|
177
|
+
# Create output directory if it doesn't exist
|
|
178
|
+
require 'fileutils'
|
|
179
|
+
FileUtils.mkdir_p(output_dir)
|
|
180
|
+
|
|
181
|
+
cli_path = Platform.find_binary
|
|
182
|
+
|
|
183
|
+
# Create temp file with input paths for batch mode
|
|
184
|
+
require 'tempfile'
|
|
185
|
+
temp_dir = Tempfile.new(['fastresize_batch', ''])
|
|
186
|
+
temp_dir_path = temp_dir.path
|
|
187
|
+
temp_dir.close
|
|
188
|
+
temp_dir.unlink
|
|
189
|
+
|
|
190
|
+
# Copy input files to temp directory (simulate batch input)
|
|
191
|
+
# Actually, use the batch command directly
|
|
192
|
+
args = ['batch']
|
|
193
|
+
args += build_batch_args(options)
|
|
194
|
+
|
|
195
|
+
# Get the input directory from the first file
|
|
196
|
+
input_dir = File.dirname(input_paths.first)
|
|
197
|
+
args << input_dir
|
|
198
|
+
args << output_dir
|
|
199
|
+
|
|
200
|
+
output = `#{cli_path} #{args.map { |a| "'#{a}'" }.join(' ')} 2>&1`
|
|
201
|
+
success = $?.success?
|
|
202
|
+
|
|
203
|
+
# Parse output
|
|
204
|
+
result = {
|
|
205
|
+
total: input_paths.length,
|
|
206
|
+
success: 0,
|
|
207
|
+
failed: 0,
|
|
208
|
+
errors: []
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
if success
|
|
212
|
+
# Parse success/failed from output
|
|
213
|
+
if output =~ /(\d+) success/
|
|
214
|
+
result[:success] = $1.to_i
|
|
215
|
+
end
|
|
216
|
+
if output =~ /(\d+) failed/
|
|
217
|
+
result[:failed] = $1.to_i
|
|
218
|
+
end
|
|
219
|
+
else
|
|
220
|
+
result[:failed] = input_paths.length
|
|
221
|
+
result[:errors] << output.strip
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
result
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
# Batch resize with custom options per image
|
|
228
|
+
#
|
|
229
|
+
# @param items [Array<Hash>] Array of items, each with :input, :output, and resize options
|
|
230
|
+
# @param options [Hash] Batch options (:threads, :stop_on_error, :max_speed)
|
|
231
|
+
# @return [Hash] Result with :total, :success, :failed, :errors
|
|
232
|
+
#
|
|
233
|
+
# @example Custom batch resize
|
|
234
|
+
# items = [
|
|
235
|
+
# { input: "photo1.jpg", output: "thumb1.jpg", width: 300 },
|
|
236
|
+
# { input: "photo2.jpg", output: "thumb2.jpg", width: 400, quality: 90 }
|
|
237
|
+
# ]
|
|
238
|
+
# result = FastResize.batch_resize_custom(items)
|
|
239
|
+
def self.batch_resize_custom(items, options = {})
|
|
240
|
+
raise Error, "Items cannot be empty" if items.nil? || items.empty?
|
|
241
|
+
|
|
242
|
+
result = {
|
|
243
|
+
total: items.length,
|
|
244
|
+
success: 0,
|
|
245
|
+
failed: 0,
|
|
246
|
+
errors: []
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
items.each do |item|
|
|
250
|
+
input = item[:input]
|
|
251
|
+
output = item[:output]
|
|
252
|
+
item_options = item.reject { |k, _| [:input, :output].include?(k) }
|
|
253
|
+
|
|
254
|
+
begin
|
|
255
|
+
resize(input, output, item_options)
|
|
256
|
+
result[:success] += 1
|
|
257
|
+
rescue Error => e
|
|
258
|
+
result[:failed] += 1
|
|
259
|
+
result[:errors] << "#{input}: #{e.message}"
|
|
260
|
+
break if options[:stop_on_error]
|
|
261
|
+
end
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
result
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
private
|
|
268
|
+
|
|
269
|
+
# Build CLI arguments for single resize
|
|
270
|
+
def self.build_resize_args(input_path, output_path, options)
|
|
271
|
+
args = [input_path, output_path]
|
|
272
|
+
|
|
273
|
+
if options[:scale]
|
|
274
|
+
# Scale factor: 0.5 = 50%, 2.0 = 200%
|
|
275
|
+
args += ['-s', options[:scale].to_s]
|
|
276
|
+
elsif options[:width] && options[:height]
|
|
277
|
+
args += ['-w', options[:width].to_s]
|
|
278
|
+
args += ['-h', options[:height].to_s]
|
|
279
|
+
elsif options[:width]
|
|
280
|
+
args += ['-w', options[:width].to_s]
|
|
281
|
+
elsif options[:height]
|
|
282
|
+
args += ['-h', options[:height].to_s]
|
|
11
283
|
end
|
|
284
|
+
|
|
285
|
+
args += ['-q', options[:quality].to_s] if options[:quality]
|
|
286
|
+
|
|
287
|
+
if options[:filter]
|
|
288
|
+
filter_name = options[:filter].to_s.gsub('_', '-')
|
|
289
|
+
args += ['-f', filter_name]
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
args << '--no-aspect-ratio' if options[:keep_aspect_ratio] == false
|
|
293
|
+
args << '-o' if options[:overwrite]
|
|
294
|
+
|
|
295
|
+
args
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
# Build CLI arguments for batch operations
|
|
299
|
+
def self.build_batch_args(options)
|
|
300
|
+
args = []
|
|
301
|
+
|
|
302
|
+
if options[:scale]
|
|
303
|
+
# Scale factor: 0.5 = 50%, 2.0 = 200%
|
|
304
|
+
args += ['-s', options[:scale].to_s]
|
|
305
|
+
elsif options[:width] && options[:height]
|
|
306
|
+
args += ['-w', options[:width].to_s]
|
|
307
|
+
args += ['-h', options[:height].to_s]
|
|
308
|
+
elsif options[:width]
|
|
309
|
+
args += ['-w', options[:width].to_s]
|
|
310
|
+
elsif options[:height]
|
|
311
|
+
args += ['-h', options[:height].to_s]
|
|
312
|
+
end
|
|
313
|
+
|
|
314
|
+
args += ['-q', options[:quality].to_s] if options[:quality]
|
|
315
|
+
|
|
316
|
+
if options[:filter]
|
|
317
|
+
filter_name = options[:filter].to_s.gsub('_', '-')
|
|
318
|
+
args += ['-f', filter_name]
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
args << '--no-aspect-ratio' if options[:keep_aspect_ratio] == false
|
|
322
|
+
args += ['-t', options[:threads].to_s] if options[:threads]
|
|
323
|
+
args << '--stop-on-error' if options[:stop_on_error]
|
|
324
|
+
args << '--max-speed' if options[:max_speed]
|
|
325
|
+
|
|
326
|
+
args
|
|
12
327
|
end
|
|
13
328
|
end
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: fast_resize
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.0.
|
|
4
|
+
version: 1.0.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Tran Huu Canh (0xTh3OKrypt)
|
|
@@ -75,12 +75,10 @@ extensions:
|
|
|
75
75
|
- bindings/ruby/ext/fastresize/extconf.rb
|
|
76
76
|
extra_rdoc_files: []
|
|
77
77
|
files:
|
|
78
|
-
- CMakeLists.txt
|
|
79
78
|
- LICENSE
|
|
80
79
|
- README.md
|
|
81
80
|
- VERSION
|
|
82
81
|
- bindings/ruby/ext/fastresize/extconf.rb
|
|
83
|
-
- bindings/ruby/ext/fastresize/fastresize_ext.cpp
|
|
84
82
|
- bindings/ruby/lib/fastresize.rb
|
|
85
83
|
- bindings/ruby/lib/fastresize/platform.rb
|
|
86
84
|
- bindings/ruby/lib/fastresize/version.rb
|
|
@@ -112,30 +110,14 @@ files:
|
|
|
112
110
|
- bindings/ruby/prebuilt/macos-x86_64/include/stb_image_resize2.h
|
|
113
111
|
- bindings/ruby/prebuilt/macos-x86_64/include/stb_image_write.h
|
|
114
112
|
- bindings/ruby/prebuilt/macos-x86_64/lib/libfastresize.a
|
|
115
|
-
- include/fastresize.h
|
|
116
|
-
- include/stb_image.h
|
|
117
|
-
- include/stb_image_resize2.h
|
|
118
|
-
- include/stb_image_write.h
|
|
119
|
-
- src/cli.cpp
|
|
120
|
-
- src/decoder.cpp
|
|
121
|
-
- src/encoder.cpp
|
|
122
|
-
- src/fastresize.cpp
|
|
123
|
-
- src/internal.h
|
|
124
|
-
- src/pipeline.cpp
|
|
125
|
-
- src/pipeline.h
|
|
126
|
-
- src/resizer.cpp
|
|
127
|
-
- src/simd_resize.cpp
|
|
128
|
-
- src/simd_resize.h
|
|
129
|
-
- src/simd_utils.h
|
|
130
|
-
- src/thread_pool.cpp
|
|
131
113
|
homepage: https://github.com/tranhuucanh/fast_resize
|
|
132
114
|
licenses:
|
|
133
115
|
- BSD-3-Clause
|
|
134
116
|
metadata:
|
|
135
|
-
|
|
136
|
-
changelog_uri: https://github.com/tranhuucanh/fast_resize/blob/master/CHANGELOG.md
|
|
137
|
-
documentation_uri: https://github.com/tranhuucanh/fast_resize
|
|
117
|
+
homepage_uri: https://github.com/tranhuucanh/fast_resize
|
|
138
118
|
source_code_uri: https://github.com/tranhuucanh/fast_resize
|
|
119
|
+
changelog_uri: https://github.com/tranhuucanh/fast_resize/blob/master/CHANGELOG.md
|
|
120
|
+
bug_tracker_uri: https://github.com/tranhuucanh/fast_resize/issues
|
|
139
121
|
post_install_message:
|
|
140
122
|
rdoc_options: []
|
|
141
123
|
require_paths:
|