pixelflut 0.1.5 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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