ruby_spriter 0.6.5

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.
Files changed (40) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +3 -0
  3. data/CHANGELOG.md +217 -0
  4. data/Gemfile +17 -0
  5. data/LICENSE +21 -0
  6. data/README.md +561 -0
  7. data/bin/ruby_spriter +20 -0
  8. data/lib/ruby_spriter/cli.rb +249 -0
  9. data/lib/ruby_spriter/consolidator.rb +146 -0
  10. data/lib/ruby_spriter/dependency_checker.rb +174 -0
  11. data/lib/ruby_spriter/gimp_processor.rb +664 -0
  12. data/lib/ruby_spriter/metadata_manager.rb +116 -0
  13. data/lib/ruby_spriter/platform.rb +82 -0
  14. data/lib/ruby_spriter/processor.rb +251 -0
  15. data/lib/ruby_spriter/utils/file_helper.rb +57 -0
  16. data/lib/ruby_spriter/utils/output_formatter.rb +65 -0
  17. data/lib/ruby_spriter/utils/path_helper.rb +59 -0
  18. data/lib/ruby_spriter/version.rb +7 -0
  19. data/lib/ruby_spriter/video_processor.rb +139 -0
  20. data/lib/ruby_spriter.rb +31 -0
  21. data/ruby_spriter.gemspec +42 -0
  22. data/spec/fixtures/image_without_metadata.png +0 -0
  23. data/spec/fixtures/spritesheet_4x2.png +0 -0
  24. data/spec/fixtures/spritesheet_4x4.png +0 -0
  25. data/spec/fixtures/spritesheet_6x2.png +0 -0
  26. data/spec/fixtures/spritesheet_with_metadata.png +0 -0
  27. data/spec/fixtures/test_video.mp4 +0 -0
  28. data/spec/ruby_spriter/cli_spec.rb +1142 -0
  29. data/spec/ruby_spriter/consolidator_spec.rb +375 -0
  30. data/spec/ruby_spriter/dependency_checker_spec.rb +0 -0
  31. data/spec/ruby_spriter/gimp_processor_spec.rb +425 -0
  32. data/spec/ruby_spriter/metadata_manager_spec.rb +0 -0
  33. data/spec/ruby_spriter/platform_spec.rb +82 -0
  34. data/spec/ruby_spriter/processor_spec.rb +0 -0
  35. data/spec/ruby_spriter/utils/file_helper_spec.rb +71 -0
  36. data/spec/ruby_spriter/utils/output_formatter_spec.rb +0 -0
  37. data/spec/ruby_spriter/utils/path_helper_spec.rb +78 -0
  38. data/spec/ruby_spriter/video_processor_spec.rb +0 -0
  39. data/spec/spec_helper.rb +41 -0
  40. metadata +88 -0
@@ -0,0 +1,139 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'open3'
4
+
5
+ module RubySpriter
6
+ # Processes video files with FFmpeg
7
+ class VideoProcessor
8
+ attr_reader :options
9
+
10
+ def initialize(options = {})
11
+ @options = options
12
+ end
13
+
14
+ # Create spritesheet from video file
15
+ # @param video_file [String] Path to video file
16
+ # @param output_file [String] Path to output spritesheet
17
+ # @return [Hash] Processing results
18
+ def create_spritesheet(video_file, output_file)
19
+ Utils::FileHelper.validate_readable!(video_file)
20
+
21
+ Utils::OutputFormatter.header("Video Analysis")
22
+ duration = get_duration(video_file)
23
+ Utils::OutputFormatter.indent("Duration: #{duration.round(2)} seconds\n")
24
+
25
+ columns = options[:columns] || 4
26
+ frame_count = options[:frame_count] || 16
27
+ rows = (frame_count.to_f / columns).ceil
28
+
29
+ Utils::OutputFormatter.header("Creating Spritesheet")
30
+
31
+ temp_file = output_file.sub('.png', '_temp.png')
32
+
33
+ create_with_ffmpeg(video_file, temp_file, duration, columns, rows, frame_count)
34
+
35
+ # Embed metadata
36
+ MetadataManager.embed(
37
+ temp_file,
38
+ output_file,
39
+ columns: columns,
40
+ rows: rows,
41
+ frames: frame_count,
42
+ debug: options[:debug]
43
+ )
44
+
45
+ # Clean up temp file
46
+ File.delete(temp_file) if File.exist?(temp_file)
47
+
48
+ file_size = File.size(output_file)
49
+
50
+ # Display results with Godot instructions
51
+ display_spritesheet_results(output_file, file_size, columns, rows, frame_count)
52
+
53
+ {
54
+ output_file: output_file,
55
+ columns: columns,
56
+ rows: rows,
57
+ frames: frame_count,
58
+ size: file_size
59
+ }
60
+ end
61
+
62
+ # Get video duration in seconds
63
+ # @param video_file [String] Path to video file
64
+ # @return [Float] Duration in seconds
65
+ def get_duration(video_file)
66
+ cmd = [
67
+ 'ffprobe',
68
+ '-v', 'error',
69
+ '-show_entries', 'format=duration',
70
+ '-of', 'default=noprint_wrappers=1:nokey=1',
71
+ Utils::PathHelper.quote_path(video_file)
72
+ ].join(' ')
73
+
74
+ stdout, stderr, status = Open3.capture3(cmd)
75
+
76
+ unless status.success?
77
+ raise ProcessingError, "Could not determine video duration: #{stderr}"
78
+ end
79
+
80
+ stdout.strip.to_f
81
+ end
82
+
83
+ private
84
+
85
+ def create_with_ffmpeg(video_file, output_file, duration, columns, rows, frame_count)
86
+ fps = (frame_count / duration.to_f).round(6)
87
+ max_width = options[:max_width] || 320
88
+
89
+ Utils::OutputFormatter.indent("Layout: #{columns}×#{rows} grid (#{frame_count} frames)")
90
+ Utils::OutputFormatter.indent("Frame rate: #{fps} fps")
91
+ Utils::OutputFormatter.indent("Max frame width: #{max_width}px")
92
+ Utils::OutputFormatter.indent("Building spritesheet...")
93
+
94
+ filter_complex = [
95
+ "fps=#{fps}",
96
+ "scale=#{max_width}:-1:flags=lanczos",
97
+ "tile=#{columns}x#{rows}"
98
+ ].join(',')
99
+
100
+ cmd = build_ffmpeg_command(video_file, output_file, filter_complex)
101
+
102
+ if options[:debug]
103
+ Utils::OutputFormatter.indent("DEBUG: ffmpeg command:")
104
+ Utils::OutputFormatter.indent(cmd)
105
+ end
106
+
107
+ stdout, stderr, status = Open3.capture3(cmd)
108
+
109
+ unless status.success?
110
+ raise ProcessingError, "FFmpeg failed: #{stderr}"
111
+ end
112
+
113
+ Utils::FileHelper.validate_exists!(output_file)
114
+ end
115
+
116
+ def build_ffmpeg_command(video_file, output_file, filter_complex)
117
+ [
118
+ 'ffmpeg',
119
+ '-i', Utils::PathHelper.quote_path(video_file),
120
+ '-filter_complex', Utils::PathHelper.quote_arg(filter_complex),
121
+ '-frames:v', '1',
122
+ '-y',
123
+ Utils::PathHelper.quote_path(output_file),
124
+ '-hide_banner',
125
+ options[:debug] ? '-loglevel info' : '-loglevel error'
126
+ ].join(' ')
127
+ end
128
+
129
+ def display_spritesheet_results(output_file, file_size, columns, rows, frame_count)
130
+ Utils::OutputFormatter.success("Spritesheet created: #{output_file}")
131
+ Utils::OutputFormatter.indent("Size: #{Utils::FileHelper.format_size(file_size)}")
132
+ Utils::OutputFormatter.note("Metadata embedded: #{columns}×#{rows} grid (#{frame_count} frames)")
133
+
134
+ puts "\n 📊 Godot AnimatedSprite2D Settings:"
135
+ Utils::OutputFormatter.indent("HFrames = #{columns}")
136
+ Utils::OutputFormatter.indent("VFrames = #{rows}\n")
137
+ end
138
+ end
139
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Main module for Ruby Spriter
4
+ module RubySpriter
5
+ class Error < StandardError; end
6
+ class DependencyError < Error; end
7
+ class ProcessingError < Error; end
8
+ class ValidationError < Error; end
9
+ end
10
+
11
+ # Load version first
12
+ require_relative 'ruby_spriter/version'
13
+
14
+ # Load utilities (no dependencies)
15
+ require_relative 'ruby_spriter/utils/path_helper'
16
+ require_relative 'ruby_spriter/utils/file_helper'
17
+ require_relative 'ruby_spriter/utils/output_formatter'
18
+
19
+ # Load core components
20
+ require_relative 'ruby_spriter/platform'
21
+ require_relative 'ruby_spriter/dependency_checker'
22
+ require_relative 'ruby_spriter/metadata_manager'
23
+
24
+ # Load processors
25
+ require_relative 'ruby_spriter/video_processor'
26
+ require_relative 'ruby_spriter/gimp_processor'
27
+ require_relative 'ruby_spriter/consolidator'
28
+
29
+ # Load orchestration
30
+ require_relative 'ruby_spriter/processor'
31
+ require_relative 'ruby_spriter/cli'
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'lib/ruby_spriter/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'ruby_spriter'
7
+ spec.version = RubySpriter::VERSION
8
+ spec.authors = ['scooter-indie']
9
+ spec.email = ['scooter-indie@users.noreply.github.com']
10
+
11
+ spec.summary = 'MP4 to Spritesheet converter with GIMP image processing'
12
+ spec.description = <<~DESC
13
+ Ruby Spriter is a cross-platform tool for creating spritesheets from video files
14
+ and processing them with GIMP. Features include background removal, scaling,
15
+ consolidation, and metadata management.
16
+ DESC
17
+ spec.homepage = 'https://github.com/scooter-indie/ruby-spriter'
18
+ spec.license = 'MIT'
19
+ spec.required_ruby_version = '>= 2.7.0'
20
+
21
+ spec.metadata['homepage_uri'] = spec.homepage
22
+ spec.metadata['source_code_uri'] = 'https://github.com/scooter-indie/ruby-spriter'
23
+ spec.metadata['changelog_uri'] = 'https://github.com/scooter-indie/ruby-spriter/blob/main/CHANGELOG.md'
24
+
25
+ # Specify which files should be added to the gem when it is released.
26
+ spec.files = Dir.glob('{bin,lib,spec}/**/*') + %w[
27
+ README.md
28
+ CHANGELOG.md
29
+ LICENSE
30
+ Gemfile
31
+ ruby_spriter.gemspec
32
+ .rspec
33
+ ]
34
+
35
+ spec.bindir = 'bin'
36
+ spec.executables = ['ruby_spriter']
37
+ spec.require_paths = ['lib']
38
+
39
+ # Runtime dependencies (none - uses only standard library + external tools)
40
+
41
+ # Development dependencies are in Gemfile
42
+ end
Binary file
Binary file
Binary file
Binary file