pixelflut 0.1.5 → 0.2.0

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: 289cd742f8feabae71182b94738bf9b21246bf1f3afae4a4b2bc1c5b1be87d4c
4
- data.tar.gz: 2ba98d609131de67a2be99f55681087b45eeaf4deb6bf488b393894c1b31c6c9
3
+ metadata.gz: d060b7c6e1888c61141aa6f24fae4e2255f4335d8e63ff8dcf1a8710f6d749a4
4
+ data.tar.gz: 81cb2846a78285887dab175ab3cb45bc9dcb4d9b0cf7d01add3d607431d537c5
5
5
  SHA512:
6
- metadata.gz: 9a8b53a0309a0c52a8898bab91f9c1ba95bb1622f733fee1236914b036dabae5ad2b375a55b6bb5c5cb3d1d9ba33f9d200cde650d014232e193f598ce8d3de8f
7
- data.tar.gz: ba1480300f12b1fae6dba2fcec945537b519dd04fabffd345288a5b3c2c1f1c8e5ae6d9115314663772feeaa6d74c8b8198c8d905f6c8c8e0fab51c27a8594e2
6
+ metadata.gz: d30c42ab6b714404eff2f5dfb3c861c96010266086a497ba2684acb7e6c8ca2b3d79999e41fc10b44fb89a62c1375ed0b68b6da74afa79dfe40cc775c0031d47
7
+ data.tar.gz: 58ab45066aeff1c2b1162ff225ba24498a966a7a75caae0219f849695c1cf7d1b997ddbfba605ed118ffea2c9a72a222e666525b2936a618c6563b083b8f4208
data/.gitignore CHANGED
@@ -1,4 +1,3 @@
1
- _local/
2
1
  tmp/
3
2
  pkg/
4
3
  gems.locked
data/README.md CHANGED
@@ -4,7 +4,7 @@ A Pixelflut client written in Ruby.
4
4
 
5
5
  ## Description
6
6
 
7
- Based on the idea of a simple server protocol to collaborate on a shared canvas named [Pixel Flut](https://cccgoe.de/wiki/Pixelflut) this gem implements a Ruby version of a client.
7
+ Based on the idea of a simple server protocol to collaborate on a shared canvas named [Pixelflut](https://cccgoe.de/wiki/Pixelflut) this gem implements a Ruby version of a client.
8
8
 
9
9
  This gem is an open experiment. You are welcome to fork or create pull requests to find the fastest solution!
10
10
 
@@ -24,16 +24,16 @@ You'll find some help on the command line:
24
24
 
25
25
  ```bash
26
26
  $ pxf
27
- Usage: pxf [options] IMAGE
27
+ Usage: pxf [OPTIONS] IMAGE
28
28
 
29
29
  Options:
30
- --host ADDRESS target host address
31
- -p, --port NUMBER target port (default 1234)
32
- -c, --connections COUNT count of connections (default 4)
33
- -x, --transpose-x X transpose image X pixels
34
- -y, --transpose-y Y transpose image Y pixels
35
- -s, --scale FACTOR scale image by FACTOR
36
-
37
- -h, --help print this help
38
- -v, --version print version information
30
+ --host ADDRESS target host address
31
+ -p, --port PORT target port (default 1234)
32
+ -c, --connections CONN count of connections (default 4)
33
+ -b, --bytes BYTES send junks of BYTES size
34
+ -x, --transpose-x X transpose image X pixels
35
+ -y, --transpose-y Y transpose image Y pixels
36
+ -s, --scale SCALE scale image by SCALE factor
37
+ -m, --pixel MODE select pixel coding (RGBX | RGBA | RGB)
38
+ -h, --help print this help
39
39
  ```
data/bin/pxf CHANGED
@@ -1,92 +1,67 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
3
 
4
- Process.setproctitle($name = 'pxf')
5
- $stderr.sync = $stdout.sync = true
6
-
7
- require 'optparse'
8
- require_relative '../lib/pixelflut'
4
+ require 'mini-cli'
5
+ include MiniCli
9
6
 
10
- def err(msg, code = 1)
11
- $stderr.puts("#{$name}: #{msg}")
12
- exit(code)
7
+ help <<~end, 'IMAGE'
8
+ --host ADDRESS target host address
9
+ -p, --port PORT target port (default 1234)
10
+ -c, --connections CONN count of connections (default 4)
11
+ -b, --bytes BYTES send junks of BYTES size
12
+ -x, --transpose-x X transpose image X pixels
13
+ -y, --transpose-y Y transpose image Y pixels
14
+ -s, --scale SCALE scale image by SCALE factor
15
+ -m, --pixel MODE select pixel coding (RGBX | RGBA | RGB)
16
+ -h, --help print this help
13
17
  end
14
18
 
15
- OPTS =
16
- Struct
17
- .new(:host, :port, :count, :x, :y, :mode, :scale, :image)
18
- .new('127.0.0.1', 1234, 4, 0, 0, :rgbx)
19
+ Process.setproctitle(name)
20
+ $stderr.sync = $stdout.sync = true
19
21
 
20
- def parse(args)
21
- OptionParser.new do |parser|
22
- parser.summary_indent = ' '
23
- parser.banner = 'Usage: pxf [options] IMAGE'
24
- parser.separator(nil)
25
- parser.separator('Options:')
26
- parser.on(
27
- '--host ADDRESS', 'target host address'
28
- ){ |v| OPTS.host = v }
29
- parser.on(
30
- '-p', '--port NUMBER', Integer, 'target port (default 1234)'
31
- ){ |v| OPTS.port = v }
32
- parser.on(
33
- '-c', '--connections COUNT', Integer, 'count of connections (default 4)'
34
- ){ |v| OPTS.count = v }
35
- parser.on(
36
- '-x', '--transpose-x X', Integer, 'transpose image X pixels'
37
- ){ |v| OPTS.x = v }
38
- parser.on(
39
- '-y', '--transpose-y Y', Integer, 'transpose image Y pixels'
40
- ){ |v| OPTS.y = v }
41
- parser.on(
42
- '-s', '--scale FACTOR', OptionParser::DecimalNumeric, 'scale image by FACTOR'
43
- ){ |v| OPTS.scale = v }
44
- parser.on(
45
- '-m', '--pixel MODE',
46
- {'RGBX' => :rgbx, 'RGBA' => :rgba, 'RGB' => :rgb},
47
- 'select pixel coding (RGBX | RGBA | RGB)'
48
- ){ |v| OPTS.mode = v }
49
- parser.separator(nil)
50
- parser.on('-h', '--help', 'print this help') do
51
- exit(!puts(parser))
52
- end
53
- parser.on('-v', '--version', 'print version information') do
54
- require_relative '../lib/pixelflut/version'
55
- exit(!puts("pxf-#{Pixelflut::VERSION}"))
22
+ parse_argv do |args|
23
+ Struct.new(:host, :port, :count, :bytes, :x, :y, :mode, :scale, :source) do
24
+ def to_h
25
+ { source: source, x: x, y: y, scale: scale, mode: mode }
56
26
  end
57
- end.parse!(args)
58
- OPTS.image = args.first or err('image name expected')
59
- OPTS
60
- rescue OptionParser::ParseError => e
61
- err(e)
27
+ end.new(
28
+ args['ADDRESS'] || '127.0.0.1',
29
+ (args['PORT'] || 1234).to_i,
30
+ (args['CONN'] || 4).to_i,
31
+ args['BYTES'].to_i,
32
+ args['X'].to_i,
33
+ args['Y'].to_i,
34
+ { 'RGBA' => :rgba, 'RGB' => :rgb }[args['MODE']] || :rgbx,
35
+ args.key?('SCALE') ? args['SCALE'].to_f : nil,
36
+ args['IMAGE']
37
+ )
62
38
  end
63
39
 
64
- begin
65
- parse(ARGV)
66
- address = Pixelflut::Sender.address(OPTS.host, OPTS.port)
67
- data = Pixelflut.sliced(
68
- source: OPTS.image,
69
- count: OPTS.count,
70
- x: OPTS.x,
71
- y: OPTS.y,
72
- scale: OPTS.scale,
73
- mode: OPTS.mode
74
- )
40
+ main do |opts|
41
+ require_relative '../lib/pixelflut'
42
+ address = Pixelflut::Sender.address(opts.host, opts.port)
43
+ data = create_data(opts)
44
+ print("spawn #{data.size}")
75
45
  data.size.times do |i|
76
46
  next unless fork
77
- Process.setproctitle($name = format('pxf-%02d', i + 1))
47
+ Process.setproctitle(name(format("#{name}-%02d", i + 1)))
78
48
  data = data[i].join
79
- puts("#{$name}: run - #{data.bytesize} bytes")
80
- Pixelflut::Sender.send(address, data)
49
+ GC.start
50
+ GC.disable
51
+ Pixelflut::Sender.send(address, data) { print('.') }
81
52
  end
82
53
  rescue SocketError => e
83
- err(e, 3)
54
+ error(3, e)
84
55
  rescue LoadError => e
85
- err(e, 4)
56
+ error(4, e)
86
57
  rescue Errno::ECONNREFUSED
87
- err('unable to connect', 2)
58
+ error(2, 'unable to connect')
88
59
  rescue Errno::EPIPE
89
- err('connection lost', 2)
90
- rescue Interrupt
91
- err('interrupted', 130)
60
+ error(2, 'connection lost')
61
+ end
62
+
63
+ def create_data(opts)
64
+ data = Pixelflut.convert(**opts.to_h)
65
+ return Pixelflut.slices(data, count: opts.count) if opts.bytes.zero?
66
+ Pixelflut.packages(data, bytes: opts.bytes)
92
67
  end
data/gems.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- source('https://rubygems.org'){ gemspec }
3
+ source('https://rubygems.org') { gemspec }
data/lib/pixelflut.rb CHANGED
@@ -1,19 +1,57 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative 'pixelflut/image'
4
- require_relative 'pixelflut/convert'
5
4
  require_relative 'pixelflut/sender'
6
5
 
7
6
  module Pixelflut
8
- def self.converted(source, x = 0, y = 0, scale = nil)
9
- image = Image.new(source)
10
- image.scale(scale) if scale
11
- Convert.each_line(image, x, y)
12
- end
7
+ class << self
8
+ def convert(source:, x: 0, y: 0, scale: nil, mode: :rgbx)
9
+ _convert(as_image(source, scale), x, y, &as_cvt(mode))
10
+ end
11
+
12
+ def slices(lines, count: 4)
13
+ Array.new(count) { [] }.tap do |ret|
14
+ lines.each_with_index { |line, idx| ret[idx % count] << line }
15
+ end
16
+ end
17
+
18
+ def packages(lines, bytes:)
19
+ ret = [current = []]
20
+ size = 0
21
+ lines.each do |line|
22
+ next current << line if (size += line.bytesize) < bytes
23
+ ret << (current = [line])
24
+ size = line.bytesize
25
+ end
26
+ ret
27
+ end
28
+
29
+ private
30
+
31
+ def _convert(image, dx, dy)
32
+ image.each_pixel.to_a.map! do |x, y, px|
33
+ "PX #{x + dx} #{y + dy} #{yield(px)}\n"
34
+ end.shuffle!
35
+ end
36
+
37
+ def as_image(source, scale)
38
+ Image.new(source).tap { |image| image.scale(scale) if scale }
39
+ end
13
40
 
14
- def self.sliced(source:, count: 4, x: 0, y: 0, scale: nil, mode: :rgbx)
15
- image = Image.new(source)
16
- image.scale(scale) if scale
17
- Convert.random_slices(image, x, y, mode, count)
41
+ def as_cvt(mode)
42
+ case mode
43
+ when :rgb
44
+ lambda { |px| px.to_color(Magick::AllCompliance, false, 8, true)[1, 6] }
45
+ when :rgba
46
+ lambda { |px| px.to_color(Magick::AllCompliance, true, 8, true)[1, 8] }
47
+ else
48
+ lambda do |px|
49
+ px.to_color(Magick::AllCompliance, false, 8, true)[
50
+ 1,
51
+ px.alpha >= 65_535 ? 6 : 8
52
+ ]
53
+ end
54
+ end
55
+ end
18
56
  end
19
57
  end
@@ -26,7 +26,7 @@ module Pixelflut
26
26
 
27
27
  def each_pixel
28
28
  return to_enum(__method__) unless block_given?
29
- @image.each_pixel{ |px, x, y| 0 != px.alpha and yield(x, y, px) }
29
+ @image.each_pixel { |px, x, y| 0 != px.alpha and yield(x, y, px) }
30
30
  end
31
31
  end
32
32
  end
@@ -2,27 +2,28 @@ require 'socket'
2
2
 
3
3
  module Pixelflut
4
4
  module Sender
5
- module_function
6
-
7
- def address(host, port)
5
+ def self.address(host, port)
8
6
  Addrinfo.tcp(host, port)
9
7
  end
10
8
 
11
- def send(address, data)
9
+ def self.send(address, data)
12
10
  socket = create_socket(address)
13
- loop{ socket.write(data) }
11
+ yield(socket) if block_given?
12
+ loop { socket.write(data) }
14
13
  end
15
14
 
16
- def create_socket(address)
17
- socket = Socket.new(address.ipv6? ? :INET6 : :INET, :STREAM)
18
- # socket.sync = true
19
- # socket.setsockopt(:TCP, :NODELAY, 1)
20
- socket.setsockopt(:SOCKET, :KEEPALIVE, 0)
21
- socket.do_not_reverse_lookup = true
22
- socket.connect(
23
- Socket.pack_sockaddr_in(address.ip_port, address.ip_address)
24
- )
25
- socket
15
+ def self.create_socket(address)
16
+ Socket
17
+ .new(address.ipv6? ? :INET6 : :INET, :STREAM)
18
+ .tap do |socket|
19
+ socket.sync = false
20
+ socket.setsockopt(:TCP, :NODELAY, 0)
21
+ socket.setsockopt(:SOCKET, :KEEPALIVE, 0)
22
+ socket.do_not_reverse_lookup = true
23
+ socket.connect(
24
+ Socket.pack_sockaddr_in(address.ip_port, address.ip_address)
25
+ )
26
+ end
26
27
  end
27
28
  end
28
29
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Pixelflut
2
- VERSION = '0.1.5'.freeze
4
+ VERSION = '0.2.0'
3
5
  end
data/pixelflut.gemspec CHANGED
@@ -2,38 +2,33 @@
2
2
 
3
3
  require_relative 'lib/pixelflut/version'
4
4
 
5
- GemSpec = Gem::Specification.new do |spec|
5
+ Gem::Specification.new do |spec|
6
6
  spec.name = 'pixelflut'
7
7
  spec.version = Pixelflut::VERSION
8
+ spec.author = 'Mike Blumtritt'
9
+
10
+ spec.required_ruby_version = '>= 2.7.2'
11
+
8
12
  spec.summary = 'A fast Pixelflut client written in Ruby.'
9
13
  spec.description = <<~DESCRIPTION
10
- Based on the idea of a simple server protocol to collaborate on a shared canvas named
11
- [Pixel Flut](https://cccgoe.de/wiki/Pixelflut) this gem implements a fast Ruby client version.
14
+ Based on the idea of a simple server protocol to collaborate on a shared
15
+ canvas named [Pixelflut](https://cccgoe.de/wiki/Pixelflut) this gem
16
+ implements a fast Ruby client version.
12
17
  DESCRIPTION
13
- spec.author = 'Mike Blumtritt'
14
- spec.email = 'mike.blumtritt@pm.me'
15
18
  spec.homepage = 'https://github.com/mblumtritt/pixelflut'
16
- spec.metadata = {
17
- 'source_code_uri' => 'https://github.com/mblumtritt/pixelflut',
18
- 'bug_tracker_uri' => 'https://github.com/mblumtritt/pixelflut/issues'
19
- }
20
- spec.rubyforge_project = spec.name
19
+
20
+ spec.metadata['source_code_uri'] = 'https://github.com/mblumtritt/pixelflut'
21
+ spec.metadata['bug_tracker_uri'] =
22
+ 'https://github.com/mblumtritt/pixelflut/issues'
21
23
 
22
24
  spec.add_runtime_dependency 'rmagick'
25
+ spec.add_runtime_dependency 'mini-cli'
23
26
  spec.add_development_dependency 'bundler'
24
27
  spec.add_development_dependency 'rake'
25
28
 
26
- spec.platform = Gem::Platform::RUBY
27
- spec.required_rubygems_version = Gem::Requirement.new('>= 1.3.6')
28
- spec.required_ruby_version = '>= 2.5.0'
29
-
30
- spec.require_paths = %w[lib]
31
29
  spec.bindir = 'bin'
32
30
  spec.executables = %w[pxf pxf-info]
33
31
 
34
- all_files = %x(git ls-files -z).split(0.chr)
35
- spec.test_files = all_files.grep(%r{^(spec|test)/})
36
- spec.files = all_files - spec.test_files
37
-
32
+ spec.files = Dir.chdir(__dir__) { `git ls-files -z`.split(0.chr) }
38
33
  spec.extra_rdoc_files = %w[README.md]
39
34
  end
data/rakefile.rb CHANGED
@@ -1,5 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'bundler/gem_tasks'
2
4
 
3
- task :default do
4
- exec 'rake --tasks'
5
- end
5
+ $stdout.sync = $stderr.sync = true
6
+
7
+ task(:default) { exec 'rake --tasks' }
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pixelflut
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.5
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mike Blumtritt
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-11-28 00:00:00.000000000 Z
11
+ date: 2021-03-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rmagick
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: mini-cli
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: bundler
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -53,9 +67,10 @@ dependencies:
53
67
  - !ruby/object:Gem::Version
54
68
  version: '0'
55
69
  description: |
56
- Based on the idea of a simple server protocol to collaborate on a shared canvas named
57
- [Pixel Flut](https://cccgoe.de/wiki/Pixelflut) this gem implements a fast Ruby client version.
58
- email: mike.blumtritt@pm.me
70
+ Based on the idea of a simple server protocol to collaborate on a shared
71
+ canvas named [Pixelflut](https://cccgoe.de/wiki/Pixelflut) this gem
72
+ implements a fast Ruby client version.
73
+ email:
59
74
  executables:
60
75
  - pxf
61
76
  - pxf-info
@@ -69,7 +84,6 @@ files:
69
84
  - bin/pxf-info
70
85
  - gems.rb
71
86
  - lib/pixelflut.rb
72
- - lib/pixelflut/convert.rb
73
87
  - lib/pixelflut/image.rb
74
88
  - lib/pixelflut/sender.rb
75
89
  - lib/pixelflut/version.rb
@@ -80,7 +94,7 @@ licenses: []
80
94
  metadata:
81
95
  source_code_uri: https://github.com/mblumtritt/pixelflut
82
96
  bug_tracker_uri: https://github.com/mblumtritt/pixelflut/issues
83
- post_install_message:
97
+ post_install_message:
84
98
  rdoc_options: []
85
99
  require_paths:
86
100
  - lib
@@ -88,15 +102,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
88
102
  requirements:
89
103
  - - ">="
90
104
  - !ruby/object:Gem::Version
91
- version: 2.5.0
105
+ version: 2.7.2
92
106
  required_rubygems_version: !ruby/object:Gem::Requirement
93
107
  requirements:
94
108
  - - ">="
95
109
  - !ruby/object:Gem::Version
96
- version: 1.3.6
110
+ version: '0'
97
111
  requirements: []
98
- rubygems_version: 3.0.6
99
- signing_key:
112
+ rubygems_version: 3.2.9
113
+ signing_key:
100
114
  specification_version: 4
101
115
  summary: A fast Pixelflut client written in Ruby.
102
116
  test_files: []
@@ -1,31 +0,0 @@
1
- require 'rmagick'
2
-
3
- module Pixelflut
4
- module Convert
5
- def self.random_slices(image, dx, dy, mode, count)
6
- mode = MODE.fetch(mode) if Symbol === mode
7
- ret, idx = Array.new(count){ [] }, 0
8
- image.each_pixel.to_a.shuffle!.each do |x, y, px|
9
- ret[idx % count] << "PX #{x + dx} #{y + dy} #{mode.call(px)}\n"
10
- idx += 1
11
- end
12
- ret
13
- end
14
-
15
- MODE = {
16
- rgb: lambda do |pixel|
17
- pixel.to_color(Magick::AllCompliance, false, 8, true)[1, 6]
18
- end,
19
- rgba: lambda do |pixel|
20
- pixel.to_color(Magick::AllCompliance, true, 8, true)[1, 8]
21
- end,
22
- rgbx: lambda do |pixel|
23
- if pixel.alpha >= 65535
24
- pixel.to_color(Magick::AllCompliance, false, 8, true)[1, 6]
25
- else
26
- pixel.to_color(Magick::AllCompliance, true, 8, true)[1, 8]
27
- end
28
- end
29
- }.freeze
30
- end
31
- end