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 +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
|