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.
@@ -62,10 +62,89 @@ RSpec.describe RubySpriter::Utils::FileHelper do
62
62
  it 'validates file exists and is readable' do
63
63
  file = File.join(@test_dir, 'test.txt')
64
64
  File.write(file, 'test')
65
-
65
+
66
66
  expect {
67
67
  described_class.validate_readable!(file)
68
68
  }.not_to raise_error
69
69
  end
70
70
  end
71
+
72
+ describe '.unique_filename' do
73
+ it 'returns original filename when file does not exist' do
74
+ result = described_class.unique_filename('/path/to/output.png')
75
+ expect(result).to eq('/path/to/output.png')
76
+ end
77
+
78
+ it 'adds timestamp when file exists' do
79
+ file = File.join(@test_dir, 'existing.png')
80
+ File.write(file, 'test')
81
+
82
+ result = described_class.unique_filename(file)
83
+ expect(result).to match(/existing_\d{8}_\d{6}_\d{3}\.png$/)
84
+ expect(result).not_to eq(file)
85
+ end
86
+
87
+ it 'handles files with multiple dots in name' do
88
+ file = File.join(@test_dir, 'my.sprite.sheet.png')
89
+ File.write(file, 'test')
90
+
91
+ result = described_class.unique_filename(file)
92
+ expect(result).to match(/my\.sprite\.sheet_\d{8}_\d{6}_\d{3}\.png$/)
93
+ end
94
+
95
+ it 'preserves directory path' do
96
+ file = File.join(@test_dir, 'subdir', 'output.png')
97
+ FileUtils.mkdir_p(File.dirname(file))
98
+ File.write(file, 'test')
99
+
100
+ result = described_class.unique_filename(file)
101
+ expect(result).to start_with(File.join(@test_dir, 'subdir'))
102
+ end
103
+
104
+ it 'generates different filenames for consecutive calls' do
105
+ file = File.join(@test_dir, 'test.png')
106
+ File.write(file, 'test')
107
+
108
+ result1 = described_class.unique_filename(file)
109
+ sleep(0.01) # Small delay to ensure different timestamps
110
+ result2 = described_class.unique_filename(file)
111
+
112
+ expect(result1).not_to eq(result2)
113
+ end
114
+ end
115
+
116
+ describe '.ensure_unique_output' do
117
+ it 'returns original path when overwrite is true' do
118
+ file = File.join(@test_dir, 'output.png')
119
+ File.write(file, 'test')
120
+
121
+ result = described_class.ensure_unique_output(file, overwrite: true)
122
+ expect(result).to eq(file)
123
+ end
124
+
125
+ it 'returns original path when file does not exist and overwrite is false' do
126
+ file = File.join(@test_dir, 'new_output.png')
127
+
128
+ result = described_class.ensure_unique_output(file, overwrite: false)
129
+ expect(result).to eq(file)
130
+ end
131
+
132
+ it 'returns unique filename when file exists and overwrite is false' do
133
+ file = File.join(@test_dir, 'existing_output.png')
134
+ File.write(file, 'test')
135
+
136
+ result = described_class.ensure_unique_output(file, overwrite: false)
137
+ expect(result).to match(/existing_output_\d{8}_\d{6}_\d{3}\.png$/)
138
+ expect(result).not_to eq(file)
139
+ end
140
+
141
+ it 'defaults to overwrite false when not specified' do
142
+ file = File.join(@test_dir, 'default_test.png')
143
+ File.write(file, 'test')
144
+
145
+ result = described_class.ensure_unique_output(file)
146
+ expect(result).not_to eq(file)
147
+ expect(result).to match(/default_test_\d{8}_\d{6}_\d{3}\.png$/)
148
+ end
149
+ end
71
150
  end
@@ -0,0 +1,104 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe RubySpriter::Utils::SpritesheetSplitter do
6
+ describe '#split_into_frames' do
7
+ let(:spritesheet_file) { 'spritesheet.png' }
8
+ let(:output_dir) { '/tmp/frames' }
9
+ let(:columns) { 4 }
10
+ let(:rows) { 4 }
11
+ let(:frames) { 16 }
12
+ let(:tile_width) { 100 }
13
+ let(:tile_height) { 100 }
14
+
15
+ let(:splitter) { described_class.new }
16
+
17
+ before do
18
+ allow(FileUtils).to receive(:mkdir_p)
19
+ allow(File).to receive(:exist?).and_return(true)
20
+ allow(Open3).to receive(:capture3).and_return(['', '', instance_double(Process::Status, success?: true)])
21
+
22
+ # Mock ImageMagick identify to return dimensions
23
+ allow(Open3).to receive(:capture3).with(/identify/).and_return(
24
+ ["400x400\n", '', instance_double(Process::Status, success?: true)]
25
+ )
26
+ end
27
+
28
+ it 'creates output directory for frames' do
29
+ expect(FileUtils).to receive(:mkdir_p).with(output_dir)
30
+
31
+ splitter.split_into_frames(spritesheet_file, output_dir, columns, rows, frames)
32
+ end
33
+
34
+ it 'extracts each frame with FR prefix and zero-padded numbers' do
35
+ # Expect ImageMagick convert commands for each frame
36
+ expect(Open3).to receive(:capture3).with(/identify/).once.and_return(
37
+ ["400x400\n", '', instance_double(Process::Status, success?: true)]
38
+ )
39
+
40
+ (1..frames).each do |i|
41
+ expect(Open3).to receive(:capture3).with(/convert.*FR#{format('%03d', i)}_/).and_return(
42
+ ['', '', instance_double(Process::Status, success?: true)]
43
+ )
44
+ end
45
+
46
+ splitter.split_into_frames(spritesheet_file, output_dir, columns, rows, frames)
47
+ end
48
+
49
+ it 'calculates tile dimensions from spritesheet size and grid' do
50
+ # For 400x400 image with 4x4 grid, tiles should be 100x100
51
+ expect(Open3).to receive(:capture3).with(/identify/).and_return(
52
+ ["400x400\n", '', instance_double(Process::Status, success?: true)]
53
+ )
54
+
55
+ # Check that crop parameters use 100x100
56
+ expect(Open3).to receive(:capture3).with(/100x100\+0\+0/).and_return(
57
+ ['', '', instance_double(Process::Status, success?: true)]
58
+ )
59
+
60
+ allow(Open3).to receive(:capture3).and_return(['', '', instance_double(Process::Status, success?: true)])
61
+
62
+ splitter.split_into_frames(spritesheet_file, output_dir, columns, rows, 1)
63
+ end
64
+
65
+ it 'includes spritesheet basename in frame output names' do
66
+ basename = File.basename(spritesheet_file, '.*')
67
+
68
+ # Mock identify first
69
+ allow(Open3).to receive(:capture3).with(/identify/).and_return(
70
+ ["400x400\n", '', instance_double(Process::Status, success?: true)]
71
+ )
72
+
73
+ # Expect convert with frame filename
74
+ expect(Open3).to receive(:capture3).with(/FR001_#{basename}\.png/).and_return(
75
+ ['', '', instance_double(Process::Status, success?: true)]
76
+ )
77
+
78
+ splitter.split_into_frames(spritesheet_file, output_dir, columns, rows, 1)
79
+ end
80
+
81
+ it 'raises ProcessingError when ImageMagick fails' do
82
+ allow(Open3).to receive(:capture3).with(/identify/).and_return(
83
+ ["400x400\n", '', instance_double(Process::Status, success?: true)]
84
+ )
85
+
86
+ allow(Open3).to receive(:capture3).with(/convert/).and_return(
87
+ ['', 'Error message', instance_double(Process::Status, success?: false)]
88
+ )
89
+
90
+ expect {
91
+ splitter.split_into_frames(spritesheet_file, output_dir, columns, rows, 1)
92
+ }.to raise_error(RubySpriter::ProcessingError, /Could not extract frame/)
93
+ end
94
+
95
+ it 'displays progress information' do
96
+ expect(RubySpriter::Utils::OutputFormatter).to receive(:header).with(/Extracting Frames/)
97
+ expect(RubySpriter::Utils::OutputFormatter).to receive(:indent).with(/Splitting spritesheet into #{frames} frames/)
98
+ expect(RubySpriter::Utils::OutputFormatter).to receive(:indent).with(/Output directory:/)
99
+ expect(RubySpriter::Utils::OutputFormatter).to receive(:indent).with(/Frames extracted successfully/)
100
+
101
+ splitter.split_into_frames(spritesheet_file, output_dir, columns, rows, frames)
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe RubySpriter::VideoProcessor do
6
+ describe '#create_spritesheet' do
7
+ let(:video_file) { 'test_video.mp4' }
8
+ let(:output_file) { 'spritesheet.png' }
9
+ let(:processor) { described_class.new(frame_count: 16, columns: 4) }
10
+
11
+ before do
12
+ allow(RubySpriter::Utils::FileHelper).to receive(:validate_readable!)
13
+ allow(File).to receive(:size).and_return(1000)
14
+ allow(File).to receive(:exist?).and_return(true)
15
+ allow(File).to receive(:delete)
16
+ allow(RubySpriter::MetadataManager).to receive(:embed)
17
+ allow(Open3).to receive(:capture3).and_return(['2.0', '', instance_double(Process::Status, success?: true)])
18
+ end
19
+
20
+ it 'creates spritesheet from video file' do
21
+ result = processor.create_spritesheet(video_file, output_file)
22
+
23
+ expect(result[:output_file]).to eq(output_file)
24
+ expect(result[:columns]).to eq(4)
25
+ expect(result[:rows]).to eq(4)
26
+ expect(result[:frames]).to eq(16)
27
+ end
28
+ end
29
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby_spriter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.5
4
+ version: 0.6.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - scooter-indie
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-10-23 00:00:00.000000000 Z
11
+ date: 2025-10-24 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: |
14
14
  Ruby Spriter is a cross-platform tool for creating spritesheets from video files
@@ -28,7 +28,9 @@ files:
28
28
  - README.md
29
29
  - bin/ruby_spriter
30
30
  - lib/ruby_spriter.rb
31
+ - lib/ruby_spriter/batch_processor.rb
31
32
  - lib/ruby_spriter/cli.rb
33
+ - lib/ruby_spriter/compression_manager.rb
32
34
  - lib/ruby_spriter/consolidator.rb
33
35
  - lib/ruby_spriter/dependency_checker.rb
34
36
  - lib/ruby_spriter/gimp_processor.rb
@@ -38,6 +40,7 @@ files:
38
40
  - lib/ruby_spriter/utils/file_helper.rb
39
41
  - lib/ruby_spriter/utils/output_formatter.rb
40
42
  - lib/ruby_spriter/utils/path_helper.rb
43
+ - lib/ruby_spriter/utils/spritesheet_splitter.rb
41
44
  - lib/ruby_spriter/version.rb
42
45
  - lib/ruby_spriter/video_processor.rb
43
46
  - ruby_spriter.gemspec
@@ -47,7 +50,9 @@ files:
47
50
  - spec/fixtures/spritesheet_6x2.png
48
51
  - spec/fixtures/spritesheet_with_metadata.png
49
52
  - spec/fixtures/test_video.mp4
53
+ - spec/ruby_spriter/batch_processor_spec.rb
50
54
  - spec/ruby_spriter/cli_spec.rb
55
+ - spec/ruby_spriter/compression_manager_spec.rb
51
56
  - spec/ruby_spriter/consolidator_spec.rb
52
57
  - spec/ruby_spriter/dependency_checker_spec.rb
53
58
  - spec/ruby_spriter/gimp_processor_spec.rb
@@ -57,6 +62,7 @@ files:
57
62
  - spec/ruby_spriter/utils/file_helper_spec.rb
58
63
  - spec/ruby_spriter/utils/output_formatter_spec.rb
59
64
  - spec/ruby_spriter/utils/path_helper_spec.rb
65
+ - spec/ruby_spriter/utils/spritesheet_splitter_spec.rb
60
66
  - spec/ruby_spriter/video_processor_spec.rb
61
67
  - spec/spec_helper.rb
62
68
  homepage: https://github.com/scooter-indie/ruby-spriter