convert2ascii 0.1.1 → 0.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7ba7bbea3873db90bd7d9d7806f9861bd409489789b85d2a6598fd117fb7f7d2
4
- data.tar.gz: e2e931cac272e36341bfbd6554634dfcc25401a58e7c6f2c8bc79c5b9127a8f9
3
+ metadata.gz: aa45c05c40f8dbd46f9bae8e89b7e83123f38ac7ae413051db32e5a0e8562d08
4
+ data.tar.gz: f0c0fca60c7dd724b66e226975784fe0d834683533ad734dc349ab4d8b288925
5
5
  SHA512:
6
- metadata.gz: eeaf96c3b3e0699785dc0706ccffed9acea4fcf6500d53862a98509d1047416621db0d27100d59f9c7b00fa94dac6a5e99dd71cdd48f5f183830152b06a5380c
7
- data.tar.gz: f952e61a0e3c47d97390edef85f4400e3467761186cac528ba4e349a4931caae4b5c5d3284062fe871f761a2cef41903e377ea84d8f3aababfcd97ad6e74728e
6
+ metadata.gz: 906c707016273c0988157544eddef58f562fe02b767a626a4124f3dd0e389b91521bfc2685c426cdac716f1a581c8990da0d11e502c73b7595a19c9aefa12074
7
+ data.tar.gz: 3ef8a737f983d57966516fb980836f6e4da64dd45c6dc0dafa15ad05951e36d89d8cdd83b7cf49a4a2c8507270e53500091dd0a304af3742625985a3f3f8b6b6
data/README.md CHANGED
@@ -23,15 +23,17 @@ you can use it in your code and make your own ascii art !
23
23
  * MacOS 15.2 ✅
24
24
  * Ubuntu 24.04 ✅
25
25
  * Windows 11 ❌
26
-
26
+ * Docker ✅
27
27
 
28
28
  ## Example
29
29
 
30
+ * Black Myth: Wukong
31
+
30
32
  ![example](./example/wukong.jpg)
31
33
 
32
- ![neo](./example/neo.gif)
34
+ * The Matrix: Neo
33
35
 
34
- ![example2](./example/doulai.jpg)
36
+ ![neo](./example/neo.gif)
35
37
 
36
38
  ## Prerequisites
37
39
 
@@ -47,6 +49,14 @@ you can use it in your code and make your own ascii art !
47
49
 
48
50
  > `$(pwd)` can be changed to your local path. Here, use your working path.
49
51
 
52
+ ```bash
53
+ # image
54
+ image2ascii -i </path/to/image>
55
+
56
+ # video
57
+ video2ascii -i </path/to/video.mp4>
58
+ ```
59
+
50
60
 
51
61
  ## Install
52
62
 
@@ -1,36 +1,34 @@
1
- require "async"
2
- require "async/barrier"
3
- require "async/semaphore"
1
+ require "parallel"
4
2
  require "etc"
3
+ require "rainbow"
5
4
 
6
5
  module Convert2Ascii
7
6
  class MultiTasker
8
7
  def initialize(proc_tasks)
9
8
  @proc_tasks = proc_tasks
10
9
  @count = set_threads_count
10
+ @finished = []
11
+ @time_start = nil
11
12
  end
12
13
 
13
14
  def set_threads_count
14
15
  cpu_threads = (Etc.nprocessors || 1)
15
- cpu_threads = cpu_threads > 4 ? cpu_threads - 1 : cpu_threads
16
+ cpu_threads = cpu_threads > 4 ? cpu_threads - 2 : 1
16
17
  cpu_threads
17
18
  end
18
19
 
19
- def run
20
- barrier = Async::Barrier.new
21
-
22
- Sync do
23
- # Only 10 tasks are created at a time:
24
- semaphore = Async::Semaphore.new(@count, parent: barrier)
20
+ def progress(index)
21
+ @finished << index
22
+ print(Rainbow("\rprocessing... #{sprintf("%.2f", (1.0 * @finished.length / @proc_tasks.length) * 100)} % (time: #{sprintf("%.2f", Time.now - @time_start)} s)").green)
23
+ end
25
24
 
26
- @proc_tasks.map do |proc_task|
27
- semaphore.async do
28
- proc_task.call
29
- end
30
- end.map(&:wait)
31
- ensure
32
- barrier.stop
25
+ def run
26
+ @time_start = Time.now
27
+ results = Parallel.map(@proc_tasks, in_processes: @count, finish: ->(item, index, result) { progress(index) }, finish_in_order: true) do |task|
28
+ task && task.call
33
29
  end
30
+
31
+ results
34
32
  end
35
33
  end
36
34
  end
@@ -2,12 +2,15 @@ require "rainbow"
2
2
  require_relative "./terminal"
3
3
 
4
4
  module Convert2Ascii
5
- class TerminalPlayer
5
+ class TerminalPlayerError < StandardError
6
+ end
6
7
 
8
+ class TerminalPlayer
7
9
  SAFE_SLOW_DELTA = 0.9 # seconds
8
10
  SAFE_FAST_DELTA = 0.2 # seconds
9
11
 
10
12
  attr_accessor :play_loop, :step_duration, :debug
13
+
11
14
  def initialize(**args)
12
15
  @debug = false
13
16
  @audio = args[:audio]
@@ -20,6 +23,13 @@ module Convert2Ascii
20
23
  @backspace_adjust = "\033[A" * (@frames.length + 1)
21
24
 
22
25
  regist_hook
26
+ check_params
27
+ end
28
+
29
+ def check_params
30
+ if @frames.length <= 0
31
+ raise TerminalPlayerError, "\n[Error] frame's length must be >= 0 "
32
+ end
23
33
  end
24
34
 
25
35
  def play
@@ -76,7 +86,7 @@ module Convert2Ascii
76
86
  end
77
87
 
78
88
  def debug_log(var_name)
79
- puts Rainbow('-- debug ----').yellow
89
+ puts Rainbow("-- debug ----").yellow
80
90
  puts "class:"
81
91
  p var_name.class
82
92
  puts "value:"
@@ -84,7 +94,6 @@ module Convert2Ascii
84
94
  end
85
95
 
86
96
  def full_screen(content)
87
-
88
97
  if !content
89
98
  return content
90
99
  end
@@ -1,3 +1,3 @@
1
1
  module Convert2Ascii
2
- VERSION = "0.1.1"
2
+ VERSION = "0.2.1"
3
3
  end
@@ -8,7 +8,7 @@ require_relative "./image2ascii"
8
8
  require_relative "./terminal-player"
9
9
  require_relative "./multi-tasker"
10
10
  require_relative "./check_package"
11
- require_relative './version'
11
+ require_relative "./version"
12
12
 
13
13
  module Convert2Ascii
14
14
  class Video2AsciiError < StandardError
@@ -17,14 +17,14 @@ module Convert2Ascii
17
17
  class Video2Ascii
18
18
  DEFAULT_STEP_DURATION = 0.04
19
19
 
20
-
21
20
  attr_accessor :uri, :width, :threads_count, :output, :step_duration
21
+
22
22
  def initialize(**args)
23
23
  @uri = args[:uri]
24
24
  @step_duration = args[:step_duration] || DEFAULT_STEP_DURATION
25
25
  @threads_count = set_threads_count
26
26
 
27
- @tmpdir = nil
27
+ @tmpdir = File.join(Dir.home, ".convert2ascii")
28
28
  @output = Dir.pwd
29
29
 
30
30
  # image2ascii attrs
@@ -34,7 +34,6 @@ module Convert2Ascii
34
34
  @color_block = args[:color_block] || false
35
35
 
36
36
  check_packages
37
- regist_hooks
38
37
  end
39
38
 
40
39
  def generate(**args)
@@ -43,34 +42,36 @@ module Convert2Ascii
43
42
  @color = args[:color] || @color # full
44
43
  @color_block = args[:color_block] || @color_block
45
44
 
46
- @tmpdir = Dir.mktmpdir
45
+ remove_tmpdir
46
+ Dir.mkdir(@tmpdir)
47
47
  @audio = get_audio_from_video(@tmpdir)
48
48
  screenshots_from_video(@tmpdir)
49
49
  convert_all_images(@tmpdir)
50
50
  @frames_path = order_frames_path
51
51
 
52
- self
53
- end
54
-
55
-
56
- def save(output_dir)
57
- system("rm -rf #{@tmpdir}/*.jpg")
58
- system("rm -rf #{output_dir} && mkdir #{output_dir}")
59
- system("cp -r #{@tmpdir}/* #{output_dir}")
60
-
61
52
  # save config
62
- File.open("#{output_dir}/meta.json", "w") do |f|
53
+ File.open("#{@tmpdir}/meta.json", "w") do |f|
63
54
  config = {
64
55
  step_duration: @step_duration,
65
- audio: @audio ? File.basename(@audio) : nil,
66
- frames_count: @frames_path.length
56
+ audio: @audio ? File.basename(@audio) : nil,
57
+ frames_count: @frames_path.length,
67
58
  }
68
59
  json_data = JSON.generate(config, pretty: true)
69
60
  f.puts json_data
70
61
  end
71
62
 
63
+ self
64
+ end
65
+
66
+ def save(output_dir)
67
+ system("rm -rf #{@tmpdir}/*.jpg")
68
+ system("rm -rf #{output_dir} && mkdir #{output_dir}")
69
+ system("cp -r #{@tmpdir}/* #{output_dir}")
70
+
72
71
  puts ""
73
72
  puts Rainbow("[info] save success!").green
73
+ ensure
74
+ after_clean
74
75
  end
75
76
 
76
77
  def order_frames_path
@@ -79,7 +80,7 @@ module Convert2Ascii
79
80
  get_name_order(a) <=> get_name_order(b)
80
81
  end
81
82
 
82
- @frames_path = frames_path
83
+ @frames_path = frames_path
83
84
  end
84
85
 
85
86
  def play(**args)
@@ -88,14 +89,21 @@ module Convert2Ascii
88
89
  frames = @frames_path.map { |f| File.open(f).read }
89
90
 
90
91
  player_args = {
91
- frames: ,
92
+ frames:,
92
93
  audio: @audio,
93
94
  play_loop:,
94
95
  step_duration:,
95
96
  }
97
+
96
98
  TerminalPlayer.new(**player_args).play
97
99
 
98
100
  return true
101
+ ensure
102
+ after_clean
103
+ end
104
+
105
+ def after_clean
106
+ remove_tmpdir
99
107
  end
100
108
 
101
109
  private
@@ -105,12 +113,10 @@ module Convert2Ascii
105
113
  CheckFFmpeg.new.check
106
114
  end
107
115
 
108
- def regist_hooks
109
- at_exit {
110
- if @tmpdir
111
- FileUtils.remove_entry @tmpdir
112
- end
113
- }
116
+ def remove_tmpdir
117
+ if File.directory? @tmpdir
118
+ FileUtils.remove_entry @tmpdir
119
+ end
114
120
  end
115
121
 
116
122
  def set_threads_count
@@ -156,7 +162,7 @@ module Convert2Ascii
156
162
  width: @width,
157
163
  style: @style,
158
164
  color: @color,
159
- color_block: @color_block
165
+ color_block: @color_block,
160
166
  }
161
167
  Image2Ascii.new(uri: image).generate(**config).ascii_string
162
168
  end
@@ -169,10 +175,7 @@ module Convert2Ascii
169
175
 
170
176
  def convert_all_images(save_dir)
171
177
  images = Dir.glob("#{save_dir}/*.jpg")
172
-
173
- processed_count = 0
174
178
  tasks = []
175
- time_start = Time.now
176
179
  images.each_with_index do |image, i|
177
180
  tasks << lambda {
178
181
  begin
@@ -181,9 +184,6 @@ module Convert2Ascii
181
184
  File.open("#{@tmpdir}/#{basename}.txt", "w") do |f|
182
185
  f.puts ascii_string
183
186
  end
184
-
185
- processed_count += 1
186
- print(Rainbow("\rprocessing... #{sprintf("%.2f", (1.0 * processed_count / images.length) * 100)} % (time: #{sprintf("%.2f", Time.now - time_start)} s)").green)
187
187
  rescue => error
188
188
  puts "-------"
189
189
  puts Rainbow("\n[Error] convert_to_ascii -> image: #{image} | i: #{i}").red
@@ -194,6 +194,5 @@ module Convert2Ascii
194
194
 
195
195
  MultiTasker.new(tasks).run
196
196
  end
197
-
198
197
  end
199
198
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: convert2ascii
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mark24
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2025-01-12 00:00:00.000000000 Z
10
+ date: 2025-01-13 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: rmagick
@@ -38,19 +38,19 @@ dependencies:
38
38
  - !ruby/object:Gem::Version
39
39
  version: 3.1.1
40
40
  - !ruby/object:Gem::Dependency
41
- name: async
41
+ name: parallel
42
42
  requirement: !ruby/object:Gem::Requirement
43
43
  requirements:
44
44
  - - "~>"
45
45
  - !ruby/object:Gem::Version
46
- version: '2.21'
46
+ version: '1.26'
47
47
  type: :runtime
48
48
  prerelease: false
49
49
  version_requirements: !ruby/object:Gem::Requirement
50
50
  requirements:
51
51
  - - "~>"
52
52
  - !ruby/object:Gem::Version
53
- version: '2.21'
53
+ version: '1.26'
54
54
  description: This gem can help you convert image or video became ASCII art in your
55
55
  terminal.
56
56
  email: