ruby_spriter 0.6.5 → 0.6.7
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/CHANGELOG.md +188 -0
- data/README.md +374 -33
- data/lib/ruby_spriter/batch_processor.rb +212 -0
- data/lib/ruby_spriter/cli.rb +369 -6
- data/lib/ruby_spriter/compression_manager.rb +101 -0
- data/lib/ruby_spriter/consolidator.rb +33 -0
- data/lib/ruby_spriter/gimp_processor.rb +6 -3
- data/lib/ruby_spriter/processor.rb +661 -26
- data/lib/ruby_spriter/utils/file_helper.rb +25 -0
- data/lib/ruby_spriter/utils/spritesheet_splitter.rb +86 -0
- data/lib/ruby_spriter/version.rb +2 -2
- data/lib/ruby_spriter/video_processor.rb +7 -7
- data/lib/ruby_spriter.rb +3 -0
- data/spec/ruby_spriter/batch_processor_spec.rb +200 -0
- data/spec/ruby_spriter/cli_spec.rb +750 -0
- data/spec/ruby_spriter/compression_manager_spec.rb +157 -0
- data/spec/ruby_spriter/consolidator_spec.rb +163 -0
- data/spec/ruby_spriter/processor_spec.rb +735 -0
- data/spec/ruby_spriter/utils/file_helper_spec.rb +80 -1
- data/spec/ruby_spriter/utils/spritesheet_splitter_spec.rb +104 -0
- data/spec/ruby_spriter/video_processor_spec.rb +29 -0
- metadata +8 -2
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'open3'
|
|
4
|
+
require 'fileutils'
|
|
5
|
+
|
|
6
|
+
module RubySpriter
|
|
7
|
+
# Manages PNG compression with metadata preservation
|
|
8
|
+
class CompressionManager
|
|
9
|
+
# Compress PNG file using ImageMagick with maximum compression
|
|
10
|
+
# @param input_file [String] Source PNG file
|
|
11
|
+
# @param output_file [String] Destination PNG file
|
|
12
|
+
# @param debug [Boolean] Enable debug output
|
|
13
|
+
def self.compress(input_file, output_file, debug: false)
|
|
14
|
+
Utils::FileHelper.validate_readable!(input_file)
|
|
15
|
+
|
|
16
|
+
cmd = build_compression_command(input_file, output_file)
|
|
17
|
+
|
|
18
|
+
if debug
|
|
19
|
+
Utils::OutputFormatter.indent("DEBUG: Compression command: #{cmd}")
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
stdout, stderr, status = Open3.capture3(cmd)
|
|
23
|
+
|
|
24
|
+
unless status.success?
|
|
25
|
+
raise ProcessingError, "Failed to compress PNG: #{stderr}"
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
Utils::FileHelper.validate_exists!(output_file)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Compress PNG file while preserving embedded metadata
|
|
32
|
+
# @param input_file [String] Source PNG file
|
|
33
|
+
# @param output_file [String] Destination PNG file
|
|
34
|
+
# @param debug [Boolean] Enable debug output
|
|
35
|
+
def self.compress_with_metadata(input_file, output_file, debug: false)
|
|
36
|
+
# Read metadata before compression
|
|
37
|
+
metadata = MetadataManager.read(input_file)
|
|
38
|
+
|
|
39
|
+
# Compress the file
|
|
40
|
+
temp_file = output_file.gsub('.png', '_compress_temp.png')
|
|
41
|
+
compress(input_file, temp_file, debug: debug)
|
|
42
|
+
|
|
43
|
+
# Re-embed metadata if it existed
|
|
44
|
+
if metadata
|
|
45
|
+
MetadataManager.embed(
|
|
46
|
+
temp_file,
|
|
47
|
+
output_file,
|
|
48
|
+
columns: metadata[:columns],
|
|
49
|
+
rows: metadata[:rows],
|
|
50
|
+
frames: metadata[:frames],
|
|
51
|
+
debug: debug
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
# Clean up temp file
|
|
55
|
+
FileUtils.rm_f(temp_file) if File.exist?(temp_file)
|
|
56
|
+
else
|
|
57
|
+
# No metadata, just move temp to output
|
|
58
|
+
FileUtils.mv(temp_file, output_file)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Get compression statistics
|
|
63
|
+
# @param original_file [String] Original file path
|
|
64
|
+
# @param compressed_file [String] Compressed file path
|
|
65
|
+
# @return [Hash] Statistics including sizes and reduction percentage
|
|
66
|
+
def self.compression_stats(original_file, compressed_file)
|
|
67
|
+
original_size = File.size(original_file)
|
|
68
|
+
compressed_size = File.size(compressed_file)
|
|
69
|
+
saved_bytes = original_size - compressed_size
|
|
70
|
+
reduction_percent = (saved_bytes.to_f / original_size * 100.0)
|
|
71
|
+
|
|
72
|
+
{
|
|
73
|
+
original_size: original_size,
|
|
74
|
+
compressed_size: compressed_size,
|
|
75
|
+
saved_bytes: saved_bytes,
|
|
76
|
+
reduction_percent: reduction_percent
|
|
77
|
+
}
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
private_class_method def self.build_compression_command(input_file, output_file)
|
|
81
|
+
magick_cmd = Platform.imagemagick_convert_cmd
|
|
82
|
+
|
|
83
|
+
# Use maximum PNG compression settings:
|
|
84
|
+
# - compression-level=9: Maximum zlib compression
|
|
85
|
+
# - compression-filter=5: Paeth filter (best for most images)
|
|
86
|
+
# - compression-strategy=1: Filtered strategy
|
|
87
|
+
# - quality=95: High quality
|
|
88
|
+
# - strip: Remove all metadata (we'll re-add it later)
|
|
89
|
+
[
|
|
90
|
+
magick_cmd,
|
|
91
|
+
Utils::PathHelper.quote_path(input_file),
|
|
92
|
+
'-strip',
|
|
93
|
+
'-define', 'png:compression-level=9',
|
|
94
|
+
'-define', 'png:compression-filter=5',
|
|
95
|
+
'-define', 'png:compression-strategy=1',
|
|
96
|
+
'-quality', '95',
|
|
97
|
+
Utils::PathHelper.quote_path(output_file)
|
|
98
|
+
].join(' ')
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
@@ -58,6 +58,39 @@ module RubySpriter
|
|
|
58
58
|
}
|
|
59
59
|
end
|
|
60
60
|
|
|
61
|
+
# Find all PNG files with spritesheet metadata in a directory
|
|
62
|
+
# @param directory [String] Directory path to scan
|
|
63
|
+
# @return [Array<String>] Sorted array of spritesheet file paths
|
|
64
|
+
def find_spritesheets_in_directory(directory)
|
|
65
|
+
# Validate directory exists
|
|
66
|
+
unless File.directory?(directory)
|
|
67
|
+
raise ValidationError, "Directory not found: #{directory}"
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Find all PNG files
|
|
71
|
+
pattern = File.join(directory, '*.png')
|
|
72
|
+
png_files = Dir.glob(pattern)
|
|
73
|
+
|
|
74
|
+
# Filter to only files with metadata
|
|
75
|
+
spritesheets = png_files.select do |file|
|
|
76
|
+
metadata = MetadataManager.read(file)
|
|
77
|
+
!metadata.nil?
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Validate we found at least one
|
|
81
|
+
if spritesheets.empty?
|
|
82
|
+
raise ValidationError, "No PNG files with spritesheet metadata found in directory: #{directory}"
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# Validate we have at least 2
|
|
86
|
+
if spritesheets.length < 2
|
|
87
|
+
raise ValidationError, "Found only #{spritesheets.length} spritesheet, need at least 2 for consolidation"
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Sort alphabetically by filename
|
|
91
|
+
spritesheets.sort
|
|
92
|
+
end
|
|
93
|
+
|
|
61
94
|
private
|
|
62
95
|
|
|
63
96
|
def validate_files!(files)
|
|
@@ -68,7 +68,8 @@ module RubySpriter
|
|
|
68
68
|
|
|
69
69
|
def scale_image(input_file)
|
|
70
70
|
percent = options[:scale_percent]
|
|
71
|
-
|
|
71
|
+
desired_output = Utils::FileHelper.output_filename(input_file, "scaled-#{percent}pct")
|
|
72
|
+
output_file = Utils::FileHelper.ensure_unique_output(desired_output, overwrite: options[:overwrite])
|
|
72
73
|
|
|
73
74
|
Utils::OutputFormatter.indent("Scaling to #{percent}%...")
|
|
74
75
|
|
|
@@ -85,7 +86,8 @@ module RubySpriter
|
|
|
85
86
|
|
|
86
87
|
def remove_background(input_file)
|
|
87
88
|
method = options[:fuzzy_select] ? 'fuzzy' : 'global'
|
|
88
|
-
|
|
89
|
+
desired_output = Utils::FileHelper.output_filename(input_file, "nobg-#{method}")
|
|
90
|
+
output_file = Utils::FileHelper.ensure_unique_output(desired_output, overwrite: options[:overwrite])
|
|
89
91
|
|
|
90
92
|
Utils::OutputFormatter.indent("Removing background (#{method} select)...")
|
|
91
93
|
|
|
@@ -621,7 +623,8 @@ module RubySpriter
|
|
|
621
623
|
gain = options[:sharpen_gain] || 0.5
|
|
622
624
|
threshold = options[:sharpen_threshold] || 0.03
|
|
623
625
|
|
|
624
|
-
|
|
626
|
+
desired_output = Utils::FileHelper.output_filename(input_file, "sharpened")
|
|
627
|
+
output_file = Utils::FileHelper.ensure_unique_output(desired_output, overwrite: options[:overwrite])
|
|
625
628
|
|
|
626
629
|
Utils::OutputFormatter.indent("Applying unsharp mask (ImageMagick)...")
|
|
627
630
|
Utils::OutputFormatter.indent(" radius=#{radius}, gain=#{gain}, threshold=#{threshold}")
|