ruby_spriter 0.6.7 → 0.7.0.1
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/.rspec +3 -3
- data/CHANGELOG.md +1035 -405
- data/Gemfile +17 -17
- data/LICENSE +21 -21
- data/README.md +183 -902
- data/bin/ruby_spriter +20 -20
- data/lib/ruby_spriter/background_sampler.rb +140 -0
- data/lib/ruby_spriter/batch_processor.rb +268 -212
- data/lib/ruby_spriter/cell_cleanup_config.rb +21 -0
- data/lib/ruby_spriter/cell_cleanup_gimp_script.rb +123 -0
- data/lib/ruby_spriter/cell_cleanup_processor.rb +230 -0
- data/lib/ruby_spriter/cli.rb +676 -612
- data/lib/ruby_spriter/compression_manager.rb +101 -101
- data/lib/ruby_spriter/consolidator.rb +179 -179
- data/lib/ruby_spriter/dependency_checker.rb +224 -174
- data/lib/ruby_spriter/ghost_edge_cleaner.rb +164 -0
- data/lib/ruby_spriter/gimp_processor.rb +1188 -667
- data/lib/ruby_spriter/metadata_manager.rb +117 -116
- data/lib/ruby_spriter/platform.rb +137 -82
- data/lib/ruby_spriter/processor.rb +1230 -886
- data/lib/ruby_spriter/smoke_detector.rb +223 -0
- data/lib/ruby_spriter/threshold_stepper.rb +227 -0
- data/lib/ruby_spriter/utils/file_helper.rb +82 -82
- data/lib/ruby_spriter/utils/image_helper.rb +16 -0
- data/lib/ruby_spriter/utils/output_formatter.rb +65 -65
- data/lib/ruby_spriter/utils/path_helper.rb +59 -59
- data/lib/ruby_spriter/utils/spritesheet_splitter.rb +86 -86
- data/lib/ruby_spriter/version.rb +6 -7
- data/lib/ruby_spriter/video_processor.rb +357 -139
- data/lib/ruby_spriter.rb +38 -34
- data/ruby_spriter.gemspec +44 -42
- data/spec/fixtures/centered_sprite_with_inner_bg.png +0 -0
- data/spec/fixtures/centered_sprite_with_inner_bg_inner_removed.png +0 -0
- data/spec/fixtures/centered_sprite_with_inner_bg_threshold_stepped.png +0 -0
- data/spec/fixtures/complex_background_sprite.png +0 -0
- data/spec/fixtures/death - bloodborne rekconing.mp4 +0 -0
- data/spec/fixtures/death - bloodborne rekconing_spritesheet-nobg-global.png +0 -0
- data/spec/fixtures/death - bloodborne rekconing_spritesheet.png +0 -0
- data/spec/fixtures/death - bloodborne rekconing_spritesheet_20251110_185027_431-nobg-global.png +0 -0
- data/spec/fixtures/death - bloodborne rekconing_spritesheet_20251110_185027_431.png +0 -0
- data/spec/fixtures/death - bloodborne rekconing_spritesheet_20251110_185125_738-nobg-global.png +0 -0
- data/spec/fixtures/death - bloodborne rekconing_spritesheet_20251110_185125_738.png +0 -0
- data/spec/fixtures/has_inner_bg.png +0 -0
- data/spec/fixtures/has_small_inner_bg.png +0 -0
- data/spec/fixtures/smoke_effect_sprite.png +0 -0
- data/spec/fixtures/spritesheet_with_metadata.png +0 -0
- data/spec/fixtures/test_sprite.png +0 -0
- data/spec/fixtures/test_sprite_smoke_processed.png +0 -0
- data/spec/fixtures/test_video_spritesheet.png +0 -0
- data/spec/fixtures/transparent_bg_sprite.png +0 -0
- data/spec/fixtures/walk_north_sprite-sheet.png +0 -0
- data/spec/integration/no_fuzzy_mode_spec.rb +100 -0
- data/spec/ruby_spriter/batch_processor_spec.rb +509 -200
- data/spec/ruby_spriter/cli_spec.rb +2026 -1892
- data/spec/ruby_spriter/compression_manager_spec.rb +157 -157
- data/spec/ruby_spriter/consolidator_spec.rb +538 -538
- data/spec/ruby_spriter/gimp_processor_spec.rb +523 -425
- data/spec/ruby_spriter/platform_spec.rb +92 -82
- data/spec/ruby_spriter/processor_spec.rb +911 -735
- data/spec/ruby_spriter/utils/file_helper_spec.rb +150 -150
- data/spec/ruby_spriter/utils/path_helper_spec.rb +78 -78
- data/spec/ruby_spriter/utils/spritesheet_splitter_spec.rb +104 -104
- data/spec/ruby_spriter/video_processor_spec.rb +346 -29
- data/spec/spec_helper.rb +41 -41
- data/spec/tmp/cli_test_output.png +0 -0
- data/spec/tmp/cli_test_output_20251105_114647_395.png +0 -0
- data/spec/tmp/combined_test.png +0 -0
- data/spec/tmp/compat_test.png +0 -0
- data/spec/tmp/compat_test_20251030_174233_361.png +0 -0
- data/spec/tmp/final_all_features.png +0 -0
- data/spec/tmp/final_test_all_features.png +0 -0
- data/spec/tmp/full_pipeline_test.png +0 -0
- data/spec/tmp/inner_test.png +0 -0
- data/spec/tmp/integration_test.png +0 -0
- data/spec/tmp/validation_test.png +0 -0
- data/spec/unit/background_sampler_spec.rb +132 -0
- data/spec/unit/cell_cleanup_config_spec.rb +32 -0
- data/spec/unit/cell_cleanup_gimp_script_spec.rb +59 -0
- data/spec/unit/cell_cleanup_processor_spec.rb +261 -0
- data/spec/unit/ghost_edge_cleaner_spec.rb +223 -0
- data/spec/unit/gimp_processor_single_point_selection_spec.rb +81 -0
- data/spec/unit/smoke_detector_spec.rb +246 -0
- data/spec/unit/threshold_stepper_spec.rb +195 -0
- metadata +56 -10
|
@@ -1,65 +1,65 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module RubySpriter
|
|
4
|
-
module Utils
|
|
5
|
-
# Console output formatting utilities
|
|
6
|
-
class OutputFormatter
|
|
7
|
-
ICONS = {
|
|
8
|
-
success: '✅',
|
|
9
|
-
error: '❌',
|
|
10
|
-
warning: '⚠️',
|
|
11
|
-
info: 'ℹ️',
|
|
12
|
-
clean: '🧹',
|
|
13
|
-
note: '📝'
|
|
14
|
-
}.freeze
|
|
15
|
-
|
|
16
|
-
class << self
|
|
17
|
-
# Print section header
|
|
18
|
-
# @param title [String] Section title
|
|
19
|
-
# @param width [Integer] Header width
|
|
20
|
-
def header(title, width = 60)
|
|
21
|
-
puts "\n" + "=" * width
|
|
22
|
-
puts title
|
|
23
|
-
puts "=" * width + "\n"
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
# Print success message
|
|
27
|
-
# @param message [String] Message to print
|
|
28
|
-
def success(message)
|
|
29
|
-
puts "#{ICONS[:success]} #{message}"
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
# Print error message
|
|
33
|
-
# @param message [String] Message to print
|
|
34
|
-
def error(message)
|
|
35
|
-
puts "#{ICONS[:error]} #{message}"
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
# Print warning message
|
|
39
|
-
# @param message [String] Message to print
|
|
40
|
-
def warning(message)
|
|
41
|
-
puts "#{ICONS[:warning]} #{message}"
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
# Print info message
|
|
45
|
-
# @param message [String] Message to print
|
|
46
|
-
def info(message)
|
|
47
|
-
puts "#{ICONS[:info]} #{message}"
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
# Print note message
|
|
51
|
-
# @param message [String] Message to print
|
|
52
|
-
def note(message)
|
|
53
|
-
puts "#{ICONS[:note]} #{message}"
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
# Print indented message
|
|
57
|
-
# @param message [String] Message to print
|
|
58
|
-
# @param indent [Integer] Number of spaces to indent
|
|
59
|
-
def indent(message, indent = 6)
|
|
60
|
-
puts " " * indent + message
|
|
61
|
-
end
|
|
62
|
-
end
|
|
63
|
-
end
|
|
64
|
-
end
|
|
65
|
-
end
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RubySpriter
|
|
4
|
+
module Utils
|
|
5
|
+
# Console output formatting utilities
|
|
6
|
+
class OutputFormatter
|
|
7
|
+
ICONS = {
|
|
8
|
+
success: '✅',
|
|
9
|
+
error: '❌',
|
|
10
|
+
warning: '⚠️',
|
|
11
|
+
info: 'ℹ️',
|
|
12
|
+
clean: '🧹',
|
|
13
|
+
note: '📝'
|
|
14
|
+
}.freeze
|
|
15
|
+
|
|
16
|
+
class << self
|
|
17
|
+
# Print section header
|
|
18
|
+
# @param title [String] Section title
|
|
19
|
+
# @param width [Integer] Header width
|
|
20
|
+
def header(title, width = 60)
|
|
21
|
+
puts "\n" + "=" * width
|
|
22
|
+
puts title
|
|
23
|
+
puts "=" * width + "\n"
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Print success message
|
|
27
|
+
# @param message [String] Message to print
|
|
28
|
+
def success(message)
|
|
29
|
+
puts "#{ICONS[:success]} #{message}"
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Print error message
|
|
33
|
+
# @param message [String] Message to print
|
|
34
|
+
def error(message)
|
|
35
|
+
puts "#{ICONS[:error]} #{message}"
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Print warning message
|
|
39
|
+
# @param message [String] Message to print
|
|
40
|
+
def warning(message)
|
|
41
|
+
puts "#{ICONS[:warning]} #{message}"
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Print info message
|
|
45
|
+
# @param message [String] Message to print
|
|
46
|
+
def info(message)
|
|
47
|
+
puts "#{ICONS[:info]} #{message}"
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Print note message
|
|
51
|
+
# @param message [String] Message to print
|
|
52
|
+
def note(message)
|
|
53
|
+
puts "#{ICONS[:note]} #{message}"
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Print indented message
|
|
57
|
+
# @param message [String] Message to print
|
|
58
|
+
# @param indent [Integer] Number of spaces to indent
|
|
59
|
+
def indent(message, indent = 6)
|
|
60
|
+
puts " " * indent + message
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
@@ -1,59 +1,59 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module RubySpriter
|
|
4
|
-
module Utils
|
|
5
|
-
# Cross-platform path handling utilities
|
|
6
|
-
class PathHelper
|
|
7
|
-
class << self
|
|
8
|
-
# Quote a file path for shell execution
|
|
9
|
-
# @param path [String] The path to quote
|
|
10
|
-
# @return [String] Properly quoted path
|
|
11
|
-
def quote_path(path)
|
|
12
|
-
if Platform.windows?
|
|
13
|
-
"\"#{path}\""
|
|
14
|
-
else
|
|
15
|
-
# Need 4 backslashes because gsub interprets backslashes in replacement string
|
|
16
|
-
"'#{path.gsub("'", "\\\\'")}'"
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
# Quote a command argument for shell execution
|
|
21
|
-
# @param arg [String] The argument to quote
|
|
22
|
-
# @return [String] Properly quoted argument
|
|
23
|
-
def quote_arg(arg)
|
|
24
|
-
if Platform.windows?
|
|
25
|
-
"\"#{arg}\""
|
|
26
|
-
else
|
|
27
|
-
# Need 4 backslashes because gsub interprets backslashes in replacement string
|
|
28
|
-
"'#{arg.gsub("'", "\\\\'")}'"
|
|
29
|
-
end
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
# Normalize path for Python scripts (GIMP)
|
|
33
|
-
# @param path [String] The path to normalize
|
|
34
|
-
# @return [String] Normalized path with forward slashes
|
|
35
|
-
def normalize_for_python(path)
|
|
36
|
-
abs_path = File.absolute_path(path)
|
|
37
|
-
|
|
38
|
-
if Platform.windows?
|
|
39
|
-
# Use forward slashes for Python raw strings
|
|
40
|
-
abs_path.gsub('\\', '/')
|
|
41
|
-
else
|
|
42
|
-
abs_path
|
|
43
|
-
end
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
# Convert path to native format
|
|
47
|
-
# @param path [String] The path to convert
|
|
48
|
-
# @return [String] Path with platform-appropriate separators
|
|
49
|
-
def to_native(path)
|
|
50
|
-
if Platform.windows?
|
|
51
|
-
path.gsub('/', '\\')
|
|
52
|
-
else
|
|
53
|
-
path.gsub('\\', '/')
|
|
54
|
-
end
|
|
55
|
-
end
|
|
56
|
-
end
|
|
57
|
-
end
|
|
58
|
-
end
|
|
59
|
-
end
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RubySpriter
|
|
4
|
+
module Utils
|
|
5
|
+
# Cross-platform path handling utilities
|
|
6
|
+
class PathHelper
|
|
7
|
+
class << self
|
|
8
|
+
# Quote a file path for shell execution
|
|
9
|
+
# @param path [String] The path to quote
|
|
10
|
+
# @return [String] Properly quoted path
|
|
11
|
+
def quote_path(path)
|
|
12
|
+
if Platform.windows?
|
|
13
|
+
"\"#{path}\""
|
|
14
|
+
else
|
|
15
|
+
# Need 4 backslashes because gsub interprets backslashes in replacement string
|
|
16
|
+
"'#{path.gsub("'", "\\\\'")}'"
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Quote a command argument for shell execution
|
|
21
|
+
# @param arg [String] The argument to quote
|
|
22
|
+
# @return [String] Properly quoted argument
|
|
23
|
+
def quote_arg(arg)
|
|
24
|
+
if Platform.windows?
|
|
25
|
+
"\"#{arg}\""
|
|
26
|
+
else
|
|
27
|
+
# Need 4 backslashes because gsub interprets backslashes in replacement string
|
|
28
|
+
"'#{arg.gsub("'", "\\\\'")}'"
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Normalize path for Python scripts (GIMP)
|
|
33
|
+
# @param path [String] The path to normalize
|
|
34
|
+
# @return [String] Normalized path with forward slashes
|
|
35
|
+
def normalize_for_python(path)
|
|
36
|
+
abs_path = File.absolute_path(path)
|
|
37
|
+
|
|
38
|
+
if Platform.windows?
|
|
39
|
+
# Use forward slashes for Python raw strings
|
|
40
|
+
abs_path.gsub('\\', '/')
|
|
41
|
+
else
|
|
42
|
+
abs_path
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Convert path to native format
|
|
47
|
+
# @param path [String] The path to convert
|
|
48
|
+
# @return [String] Path with platform-appropriate separators
|
|
49
|
+
def to_native(path)
|
|
50
|
+
if Platform.windows?
|
|
51
|
+
path.gsub('/', '\\')
|
|
52
|
+
else
|
|
53
|
+
path.gsub('\\', '/')
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
@@ -1,86 +1,86 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'open3'
|
|
4
|
-
require 'fileutils'
|
|
5
|
-
|
|
6
|
-
module RubySpriter
|
|
7
|
-
module Utils
|
|
8
|
-
# Splits a spritesheet into individual frame images
|
|
9
|
-
class SpritesheetSplitter
|
|
10
|
-
# Split spritesheet into individual frames
|
|
11
|
-
# @param spritesheet_file [String] Path to spritesheet PNG
|
|
12
|
-
# @param output_dir [String] Directory to save individual frames
|
|
13
|
-
# @param columns [Integer] Number of columns in grid
|
|
14
|
-
# @param rows [Integer] Number of rows in grid
|
|
15
|
-
# @param frames [Integer] Total number of frames to extract
|
|
16
|
-
def split_into_frames(spritesheet_file, output_dir, columns, rows, frames)
|
|
17
|
-
FileUtils.mkdir_p(output_dir)
|
|
18
|
-
|
|
19
|
-
OutputFormatter.header("Extracting Frames")
|
|
20
|
-
OutputFormatter.indent("Splitting spritesheet into #{frames} frames to disk...")
|
|
21
|
-
OutputFormatter.indent("Output directory: #{output_dir}")
|
|
22
|
-
|
|
23
|
-
# Get spritesheet dimensions
|
|
24
|
-
dimensions = get_image_dimensions(spritesheet_file)
|
|
25
|
-
tile_width = dimensions[:width] / columns
|
|
26
|
-
tile_height = dimensions[:height] / rows
|
|
27
|
-
|
|
28
|
-
# Extract each frame
|
|
29
|
-
spritesheet_basename = File.basename(spritesheet_file, '.*')
|
|
30
|
-
|
|
31
|
-
frames.times do |i|
|
|
32
|
-
frame_number = i + 1
|
|
33
|
-
row = i / columns
|
|
34
|
-
col = i % columns
|
|
35
|
-
|
|
36
|
-
x_offset = col * tile_width
|
|
37
|
-
y_offset = row * tile_height
|
|
38
|
-
|
|
39
|
-
frame_filename = "FR#{format('%03d', frame_number)}_#{spritesheet_basename}.png"
|
|
40
|
-
frame_path = File.join(output_dir, frame_filename)
|
|
41
|
-
|
|
42
|
-
extract_tile(spritesheet_file, frame_path, tile_width, tile_height, x_offset, y_offset)
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
OutputFormatter.indent("✅ Frames extracted successfully\n")
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
private
|
|
49
|
-
|
|
50
|
-
def get_image_dimensions(image_file)
|
|
51
|
-
cmd = [
|
|
52
|
-
'magick',
|
|
53
|
-
'identify',
|
|
54
|
-
'-format', '%wx%h',
|
|
55
|
-
PathHelper.quote_path(image_file)
|
|
56
|
-
].join(' ')
|
|
57
|
-
|
|
58
|
-
stdout, stderr, status = Open3.capture3(cmd)
|
|
59
|
-
|
|
60
|
-
unless status.success?
|
|
61
|
-
raise ProcessingError, "Could not get image dimensions: #{stderr}"
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
width, height = stdout.strip.split('x').map(&:to_i)
|
|
65
|
-
{ width: width, height: height }
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
def extract_tile(source_file, output_file, width, height, x_offset, y_offset)
|
|
69
|
-
cmd = [
|
|
70
|
-
'magick',
|
|
71
|
-
'convert',
|
|
72
|
-
PathHelper.quote_path(source_file),
|
|
73
|
-
'-crop', "#{width}x#{height}+#{x_offset}+#{y_offset}",
|
|
74
|
-
'+repage',
|
|
75
|
-
PathHelper.quote_path(output_file)
|
|
76
|
-
].join(' ')
|
|
77
|
-
|
|
78
|
-
stdout, stderr, status = Open3.capture3(cmd)
|
|
79
|
-
|
|
80
|
-
unless status.success?
|
|
81
|
-
raise ProcessingError, "Could not extract frame: #{stderr}"
|
|
82
|
-
end
|
|
83
|
-
end
|
|
84
|
-
end
|
|
85
|
-
end
|
|
86
|
-
end
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'open3'
|
|
4
|
+
require 'fileutils'
|
|
5
|
+
|
|
6
|
+
module RubySpriter
|
|
7
|
+
module Utils
|
|
8
|
+
# Splits a spritesheet into individual frame images
|
|
9
|
+
class SpritesheetSplitter
|
|
10
|
+
# Split spritesheet into individual frames
|
|
11
|
+
# @param spritesheet_file [String] Path to spritesheet PNG
|
|
12
|
+
# @param output_dir [String] Directory to save individual frames
|
|
13
|
+
# @param columns [Integer] Number of columns in grid
|
|
14
|
+
# @param rows [Integer] Number of rows in grid
|
|
15
|
+
# @param frames [Integer] Total number of frames to extract
|
|
16
|
+
def split_into_frames(spritesheet_file, output_dir, columns, rows, frames)
|
|
17
|
+
FileUtils.mkdir_p(output_dir)
|
|
18
|
+
|
|
19
|
+
OutputFormatter.header("Extracting Frames")
|
|
20
|
+
OutputFormatter.indent("Splitting spritesheet into #{frames} frames to disk...")
|
|
21
|
+
OutputFormatter.indent("Output directory: #{output_dir}")
|
|
22
|
+
|
|
23
|
+
# Get spritesheet dimensions
|
|
24
|
+
dimensions = get_image_dimensions(spritesheet_file)
|
|
25
|
+
tile_width = dimensions[:width] / columns
|
|
26
|
+
tile_height = dimensions[:height] / rows
|
|
27
|
+
|
|
28
|
+
# Extract each frame
|
|
29
|
+
spritesheet_basename = File.basename(spritesheet_file, '.*')
|
|
30
|
+
|
|
31
|
+
frames.times do |i|
|
|
32
|
+
frame_number = i + 1
|
|
33
|
+
row = i / columns
|
|
34
|
+
col = i % columns
|
|
35
|
+
|
|
36
|
+
x_offset = col * tile_width
|
|
37
|
+
y_offset = row * tile_height
|
|
38
|
+
|
|
39
|
+
frame_filename = "FR#{format('%03d', frame_number)}_#{spritesheet_basename}.png"
|
|
40
|
+
frame_path = File.join(output_dir, frame_filename)
|
|
41
|
+
|
|
42
|
+
extract_tile(spritesheet_file, frame_path, tile_width, tile_height, x_offset, y_offset)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
OutputFormatter.indent("✅ Frames extracted successfully\n")
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
private
|
|
49
|
+
|
|
50
|
+
def get_image_dimensions(image_file)
|
|
51
|
+
cmd = [
|
|
52
|
+
'magick',
|
|
53
|
+
'identify',
|
|
54
|
+
'-format', '%wx%h',
|
|
55
|
+
PathHelper.quote_path(image_file)
|
|
56
|
+
].join(' ')
|
|
57
|
+
|
|
58
|
+
stdout, stderr, status = Open3.capture3(cmd)
|
|
59
|
+
|
|
60
|
+
unless status.success?
|
|
61
|
+
raise ProcessingError, "Could not get image dimensions: #{stderr}"
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
width, height = stdout.strip.split('x').map(&:to_i)
|
|
65
|
+
{ width: width, height: height }
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def extract_tile(source_file, output_file, width, height, x_offset, y_offset)
|
|
69
|
+
cmd = [
|
|
70
|
+
'magick',
|
|
71
|
+
'convert',
|
|
72
|
+
PathHelper.quote_path(source_file),
|
|
73
|
+
'-crop', "#{width}x#{height}+#{x_offset}+#{y_offset}",
|
|
74
|
+
'+repage',
|
|
75
|
+
PathHelper.quote_path(output_file)
|
|
76
|
+
].join(' ')
|
|
77
|
+
|
|
78
|
+
stdout, stderr, status = Open3.capture3(cmd)
|
|
79
|
+
|
|
80
|
+
unless status.success?
|
|
81
|
+
raise ProcessingError, "Could not extract frame: #{stderr}"
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
data/lib/ruby_spriter/version.rb
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module RubySpriter
|
|
4
|
-
VERSION = '0.
|
|
5
|
-
VERSION_DATE = '2025-
|
|
6
|
-
|
|
7
|
-
end
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RubySpriter
|
|
4
|
+
VERSION = '0.7.0.1'
|
|
5
|
+
VERSION_DATE = '2025-11-06'
|
|
6
|
+
end
|