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 +4 -4
- data/.gitignore +0 -1
- data/README.md +11 -11
- data/bin/pxf +48 -73
- data/gems.rb +1 -1
- data/lib/pixelflut.rb +48 -10
- data/lib/pixelflut/image.rb +1 -1
- data/lib/pixelflut/sender.rb +16 -15
- data/lib/pixelflut/version.rb +3 -1
- data/pixelflut.gemspec +14 -19
- data/rakefile.rb +5 -3
- metadata +26 -12
- data/lib/pixelflut/convert.rb +0 -31
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d060b7c6e1888c61141aa6f24fae4e2255f4335d8e63ff8dcf1a8710f6d749a4
|
4
|
+
data.tar.gz: 81cb2846a78285887dab175ab3cb45bc9dcb4d9b0cf7d01add3d607431d537c5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d30c42ab6b714404eff2f5dfb3c861c96010266086a497ba2684acb7e6c8ca2b3d79999e41fc10b44fb89a62c1375ed0b68b6da74afa79dfe40cc775c0031d47
|
7
|
+
data.tar.gz: 58ab45066aeff1c2b1162ff225ba24498a966a7a75caae0219f849695c1cf7d1b997ddbfba605ed118ffea2c9a72a222e666525b2936a618c6563b083b8f4208
|
data/.gitignore
CHANGED
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 [
|
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 [
|
27
|
+
Usage: pxf [OPTIONS] IMAGE
|
28
28
|
|
29
29
|
Options:
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
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
|
-
|
5
|
-
|
6
|
-
|
7
|
-
require 'optparse'
|
8
|
-
require_relative '../lib/pixelflut'
|
4
|
+
require 'mini-cli'
|
5
|
+
include MiniCli
|
9
6
|
|
10
|
-
|
11
|
-
|
12
|
-
|
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
|
-
|
16
|
-
|
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
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
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.
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
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
|
-
|
65
|
-
|
66
|
-
address = Pixelflut::Sender.address(
|
67
|
-
data =
|
68
|
-
|
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(
|
47
|
+
Process.setproctitle(name(format("#{name}-%02d", i + 1)))
|
78
48
|
data = data[i].join
|
79
|
-
|
80
|
-
|
49
|
+
GC.start
|
50
|
+
GC.disable
|
51
|
+
Pixelflut::Sender.send(address, data) { print('.') }
|
81
52
|
end
|
82
53
|
rescue SocketError => e
|
83
|
-
|
54
|
+
error(3, e)
|
84
55
|
rescue LoadError => e
|
85
|
-
|
56
|
+
error(4, e)
|
86
57
|
rescue Errno::ECONNREFUSED
|
87
|
-
|
58
|
+
error(2, 'unable to connect')
|
88
59
|
rescue Errno::EPIPE
|
89
|
-
|
90
|
-
|
91
|
-
|
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
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
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
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
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
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
|
data/lib/pixelflut/image.rb
CHANGED
data/lib/pixelflut/sender.rb
CHANGED
@@ -2,27 +2,28 @@ require 'socket'
|
|
2
2
|
|
3
3
|
module Pixelflut
|
4
4
|
module Sender
|
5
|
-
|
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
|
-
|
11
|
+
yield(socket) if block_given?
|
12
|
+
loop { socket.write(data) }
|
14
13
|
end
|
15
14
|
|
16
|
-
def create_socket(address)
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
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
|
data/lib/pixelflut/version.rb
CHANGED
data/pixelflut.gemspec
CHANGED
@@ -2,38 +2,33 @@
|
|
2
2
|
|
3
3
|
require_relative 'lib/pixelflut/version'
|
4
4
|
|
5
|
-
|
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
|
11
|
-
[
|
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
|
-
|
17
|
-
|
18
|
-
|
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
|
-
|
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
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.
|
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:
|
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
|
57
|
-
[
|
58
|
-
|
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.
|
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:
|
110
|
+
version: '0'
|
97
111
|
requirements: []
|
98
|
-
rubygems_version: 3.
|
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: []
|
data/lib/pixelflut/convert.rb
DELETED
@@ -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
|