pixelflut 0.2.1 → 1.0.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/README.md +14 -13
- data/bin/pxf +119 -55
- data/lib/pixelflut/sender.rb +18 -16
- data/lib/pixelflut/version.rb +1 -1
- data/lib/pixelflut.rb +79 -37
- metadata +5 -53
- data/.gitignore +0 -3
- data/bin/pxf-info +0 -32
- data/gems.rb +0 -3
- data/lib/pixelflut/image.rb +0 -32
- data/pixelflut.gemspec +0 -34
- data/rakefile.rb +0 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b91c341d7ba55f35b968b3a35c31cb4e676b2055c2f86bd6a94e3f5a4847c788
|
4
|
+
data.tar.gz: 700e3fae41c985852236339eca7381f05d383e55c74e9948b2f7935b2f7bf69e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 68bbebdd53d083cf10e6bc5c76a18b81ac43347f929166d61493a4e8a54b07263f7ae18c1b23eb5c26317a8d02a33aea18f26740c0cb3f9f387338bb4322a2f5
|
7
|
+
data.tar.gz: c045bd205847f450c924c2e0f2485737af956f6f419e99b78dadd7b8ab101972f0b251bd09eb62bd39024f60c4f00b34830ccf367a718e71395d037696f735ea
|
data/README.md
CHANGED
@@ -12,8 +12,8 @@ This gem is an open experiment. You are welcome to fork or create pull requests
|
|
12
12
|
|
13
13
|
Use [Bundler](http://gembundler.com/) to install the gem:
|
14
14
|
|
15
|
-
```
|
16
|
-
|
15
|
+
```sh
|
16
|
+
gem install pixelflut
|
17
17
|
```
|
18
18
|
|
19
19
|
Now the `pxf` command offers the complete functionality.
|
@@ -22,18 +22,19 @@ Now the `pxf` command offers the complete functionality.
|
|
22
22
|
|
23
23
|
You'll find some help on the command line:
|
24
24
|
|
25
|
-
```
|
25
|
+
```
|
26
26
|
$ pxf
|
27
|
-
Usage: pxf [
|
27
|
+
Usage: pxf [options] <image>
|
28
28
|
|
29
29
|
Options:
|
30
|
-
|
31
|
-
-p, --port
|
32
|
-
-c, --connections
|
33
|
-
-
|
34
|
-
-
|
35
|
-
-
|
36
|
-
-
|
37
|
-
-
|
38
|
-
-
|
30
|
+
--host <address> target host address (default 127.0.0.1)
|
31
|
+
-p, --port <port> target port (default 1337)
|
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
|
+
-m, --mode <mode> select pixel encoding (TEXT | BIN)
|
36
|
+
-t, --threads use threads instead of processes
|
37
|
+
-h, --help print this help
|
38
|
+
-v, --version print version information
|
39
|
+
|
39
40
|
```
|
data/bin/pxf
CHANGED
@@ -1,69 +1,133 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
4
|
+
$stdout.sync = $stderr.sync = true
|
5
|
+
$name = Process.setproctitle(File.basename(Process.argv0))
|
6
|
+
|
7
|
+
if ARGV.index('-h') || ARGV.index('--help')
|
8
|
+
puts <<~HELP
|
9
|
+
Usage: #{$name} [options] <png_image>
|
10
|
+
|
11
|
+
Options:
|
12
|
+
--host <address> target host address (default 127.0.0.1)
|
13
|
+
-p, --port <port> target port (default 1234)
|
14
|
+
-c, --connections <count> count of connections (default 4)
|
15
|
+
-m, --mode <mode> select pixel encoding (TEXT | BIN)
|
16
|
+
-t, --threads use threads instead of processes
|
17
|
+
-x, --transpose-x <x> transpose image <x> pixels
|
18
|
+
-y, --transpose-y <y> transpose image <y> pixels
|
19
|
+
-h, --help print this help
|
20
|
+
-v, --version print version information
|
21
|
+
HELP
|
22
|
+
exit
|
14
23
|
end
|
15
24
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
next unless fork
|
21
|
-
Process.setproctitle(name(format("#{name}-%02d", i + 1)))
|
22
|
-
data = data[i].join
|
23
|
-
GC.start
|
24
|
-
GC.disable
|
25
|
-
Pixelflut::Sender.send(opts.address, data) { print('.') }
|
26
|
-
end
|
27
|
-
rescue SocketError => e
|
28
|
-
error(3, e)
|
29
|
-
rescue LoadError => e
|
30
|
-
error(4, e)
|
31
|
-
rescue Errno::ECONNREFUSED
|
32
|
-
error(2, 'unable to connect')
|
33
|
-
rescue Errno::EPIPE
|
34
|
-
error(2, 'connection lost')
|
25
|
+
if ARGV.index('-v') || ARGV.index('--version')
|
26
|
+
require_relative('../lib/pixelflut/version')
|
27
|
+
puts("#{$name} - Pixelflut v#{Pixelflut::VERSION}")
|
28
|
+
exit
|
35
29
|
end
|
36
30
|
|
37
|
-
def
|
38
|
-
|
39
|
-
|
40
|
-
Pixelflut.junks(lines, bytes: opts.bytes)
|
31
|
+
def die!(msg, code: 1)
|
32
|
+
$stderr.puts("#{$name}: #{msg}")
|
33
|
+
exit(code)
|
41
34
|
end
|
42
35
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
36
|
+
die!('argument missing') if ARGV.empty?
|
37
|
+
|
38
|
+
require_relative('../lib/pixelflut')
|
39
|
+
|
40
|
+
module Configuration
|
41
|
+
class << self
|
42
|
+
attr_reader :use_threads
|
43
|
+
|
44
|
+
def address
|
45
|
+
require_relative('../lib/pixelflut/sender')
|
46
|
+
Pixelflut::Sender.as_address(@host || '127.0.0.1', @port || 1234)
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def invalid(value, name)
|
52
|
+
die!("value for #{name} missing") if value.nil?
|
53
|
+
die!("invalid value for #{name} - '#{value}'")
|
54
|
+
end
|
55
|
+
|
56
|
+
def as_str(value, name)
|
57
|
+
value.nil? || value.empty? ? invalid(value, name) : value
|
58
|
+
end
|
59
|
+
|
60
|
+
def as_uint(value, name)
|
61
|
+
(ret = value.to_i).positive? ? ret : invalid(value, name)
|
62
|
+
end
|
63
|
+
|
64
|
+
def as_mode(value, name)
|
65
|
+
%w[text bin].include?(v = value.downcase) ? v : invalid(value, name)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
until ARGV.empty?
|
70
|
+
case arg = ARGV.shift
|
71
|
+
when '--host'
|
72
|
+
@host = as_str(ARGV.shift, 'host')
|
73
|
+
when '-p', '--port'
|
74
|
+
@port = as_uint(ARGV.shift, 'port')
|
75
|
+
when '-c', '--connections'
|
76
|
+
Pixelflut.count = as_uint(ARGV.shift, 'connections')
|
77
|
+
die!("too many connections - #{Pixelflut.count}") if Pixelflut.count > 255
|
78
|
+
when '-m', '--mode', '--pixel'
|
79
|
+
Pixelflut.mode = as_mode(ARGV.shift, 'mode')
|
80
|
+
when '-t', '--use-threads'
|
81
|
+
@use_threads = true
|
82
|
+
when '-x', '--transpose-x'
|
83
|
+
Pixelflut.delta_x = ARGV.shift.to_i
|
84
|
+
when '-y', '--transpose-y'
|
85
|
+
Pixelflut.delta_y = ARGV.shift.to_i
|
86
|
+
else
|
87
|
+
die!("invalid option - #{arg}") if Pixelflut.file_name
|
88
|
+
Pixelflut.file_name = arg
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
die!('<image> missing') unless Pixelflut.file_name
|
47
93
|
end
|
48
94
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
95
|
+
def use_processes(address, data)
|
96
|
+
puts("#{$name}: start #{data.size} processes for #{data.sum(&:size)} bytes")
|
97
|
+
data.size.times do |i|
|
98
|
+
next unless fork
|
99
|
+
data = data[i]
|
100
|
+
GC.start
|
101
|
+
$name = Process.setproctitle("#{$name}-#{'0' if i < 9}#{i + 1}")
|
102
|
+
Pixelflut::Sender.send(address, data) do |size|
|
103
|
+
puts("#{$name}: #{size} bytes")
|
53
104
|
end
|
54
|
-
end
|
55
|
-
Pixelflut::Sender.address(
|
56
|
-
args['ADDRESS'] || '127.0.0.1',
|
57
|
-
(args['PORT'] || 1234).to_i
|
58
|
-
),
|
59
|
-
(args['CONN'] || 4).to_i,
|
60
|
-
args['BYTES'].to_i,
|
61
|
-
args['X'].to_i,
|
62
|
-
args['Y'].to_i,
|
63
|
-
{ 'RGBA' => :rgba, 'RGB' => :rgb }[args['MODE']] || :rgbx,
|
64
|
-
args.key?('SCALE') ? args['SCALE'].to_f : nil,
|
65
|
-
args['IMAGE']
|
66
|
-
)
|
105
|
+
end
|
67
106
|
end
|
68
107
|
|
69
|
-
|
108
|
+
def use_threads(address, data)
|
109
|
+
puts("#{$name}: start #{data.size} threads for #{data.sum(&:size)} bytes")
|
110
|
+
Thread.report_on_exception = false
|
111
|
+
data.map! { |slice| Thread.start { Pixelflut::Sender.send(address, slice) } }
|
112
|
+
GC.start
|
113
|
+
data.each(&:join)
|
114
|
+
end
|
115
|
+
|
116
|
+
begin
|
117
|
+
if Configuration.use_threads
|
118
|
+
use_threads(Configuration.address, Pixelflut.data)
|
119
|
+
else
|
120
|
+
use_processes(Configuration.address, Pixelflut.data)
|
121
|
+
end
|
122
|
+
rescue Errno::ECONNREFUSED
|
123
|
+
die!('unable to connect', code: 2)
|
124
|
+
rescue Errno::EPIPE
|
125
|
+
die!('connection lost', code: 2)
|
126
|
+
rescue SocketError => e
|
127
|
+
die!(e, code: 3)
|
128
|
+
rescue LoadError => e
|
129
|
+
die!(e, code: 4)
|
130
|
+
rescue Interrupt
|
131
|
+
print("\b\b") if $stdout.tty?
|
132
|
+
die!('aborted', code: 130)
|
133
|
+
end
|
data/lib/pixelflut/sender.rb
CHANGED
@@ -1,29 +1,31 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Pixelflut
|
4
4
|
module Sender
|
5
|
-
def self.
|
6
|
-
|
5
|
+
def self.as_address(host, port)
|
6
|
+
require('socket') unless defined?(Addrinfo)
|
7
|
+
info = Addrinfo.tcp(host, port)
|
8
|
+
Address.new(
|
9
|
+
Socket.pack_sockaddr_in(info.ip_port, info.ip_address),
|
10
|
+
info.ipv6? ? :INET6 : :INET
|
11
|
+
)
|
7
12
|
end
|
8
13
|
|
9
14
|
def self.send(address, data)
|
10
15
|
socket = create_socket(address)
|
11
|
-
yield(
|
12
|
-
|
16
|
+
yield(data.bytesize) if block_given?
|
17
|
+
socket.write(data) while true
|
13
18
|
end
|
14
19
|
|
15
20
|
def self.create_socket(address)
|
16
|
-
Socket
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
socket.do_not_reverse_lookup = true
|
23
|
-
socket.connect(
|
24
|
-
Socket.pack_sockaddr_in(address.ip_port, address.ip_address)
|
25
|
-
)
|
26
|
-
end
|
21
|
+
socket = Socket.new(address.type, :STREAM)
|
22
|
+
socket.connect(address.sockaddr_in)
|
23
|
+
socket.setsockopt(:TCP, :NODELAY, 1)
|
24
|
+
socket.setsockopt(:SOCKET, :KEEPALIVE, 0)
|
25
|
+
socket.sync = socket.do_not_reverse_lookup = true
|
26
|
+
socket
|
27
27
|
end
|
28
|
+
|
29
|
+
Address = Struct.new(:sockaddr_in, :type)
|
28
30
|
end
|
29
31
|
end
|
data/lib/pixelflut/version.rb
CHANGED
data/lib/pixelflut.rb
CHANGED
@@ -1,57 +1,99 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative 'pixelflut/image'
|
4
|
-
require_relative 'pixelflut/sender'
|
5
|
-
|
6
3
|
module Pixelflut
|
7
4
|
class << self
|
8
|
-
|
9
|
-
|
5
|
+
attr_accessor :file_name, :count, :mode, :delta_x, :delta_y
|
6
|
+
|
7
|
+
def data
|
8
|
+
sliced(convert(*load).shuffle!, @count).map!(&:join)
|
10
9
|
end
|
11
10
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
11
|
+
private
|
12
|
+
|
13
|
+
def load
|
14
|
+
require('chunky_png') unless defined?(ChunkyPNG)
|
15
|
+
image = ChunkyPNG::Canvas.from_file(@file_name)
|
16
|
+
[image.width, image.height, image.pixels.pack("N#{image.pixels.size}")]
|
17
|
+
rescue Errno::ENOENT => e
|
18
|
+
raise(LoadError, e.message, cause: e)
|
16
19
|
end
|
17
20
|
|
18
|
-
def
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
21
|
+
# def load_rmagick
|
22
|
+
# require('rmagick') unless defined?(Magick)
|
23
|
+
# image = Magick::Image.read(@file_name).first
|
24
|
+
# image.scale!(@scale) if @scale
|
25
|
+
# [
|
26
|
+
# image.columns,
|
27
|
+
# image.rows,
|
28
|
+
# image.export_pixels_to_str(0, 0, image.columns, image.rows, 'rgba')
|
29
|
+
# ]
|
30
|
+
# rescue Magick::ImageMagickError => e
|
31
|
+
# raise(LoadError, e.message, cause: e)
|
32
|
+
# end
|
33
|
+
|
34
|
+
def sliced(array, number)
|
35
|
+
division = array.size / number
|
36
|
+
modulo = array.size % number
|
37
|
+
pos = 0
|
38
|
+
Array.new(number) do |index|
|
39
|
+
length = division + (modulo > 0 && modulo > index ? 1 : 0)
|
40
|
+
slice = array.slice(pos, length)
|
41
|
+
pos += length
|
42
|
+
slice
|
24
43
|
end
|
25
|
-
ret
|
26
44
|
end
|
27
|
-
alias packages junks # backward compatibility
|
28
|
-
|
29
|
-
private
|
30
45
|
|
31
|
-
def
|
32
|
-
|
33
|
-
|
34
|
-
|
46
|
+
def convert(width, height, blob)
|
47
|
+
if @mode == 'bin'
|
48
|
+
to_bin_format(width, height, blob)
|
49
|
+
else
|
50
|
+
to_text_format(width, height, blob)
|
51
|
+
end
|
35
52
|
end
|
36
53
|
|
37
|
-
def
|
38
|
-
|
54
|
+
def to_text_format(width, height, blob)
|
55
|
+
ret = []
|
56
|
+
pos = -1
|
57
|
+
height.times do |y|
|
58
|
+
width.times do |x|
|
59
|
+
next if (a = blob.getbyte(pos += 4)) == 0
|
60
|
+
ret << format(
|
61
|
+
(
|
62
|
+
if a == 255
|
63
|
+
"PX %d %d %02x%02x%02x\n"
|
64
|
+
else
|
65
|
+
"PX %d %d %02x%02x%02x%02x\n"
|
66
|
+
end
|
67
|
+
),
|
68
|
+
x + @delta_x,
|
69
|
+
y + @delta_y,
|
70
|
+
blob.getbyte(pos - 3),
|
71
|
+
blob.getbyte(pos - 2),
|
72
|
+
blob.getbyte(pos - 1),
|
73
|
+
a
|
74
|
+
)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
ret
|
39
78
|
end
|
40
79
|
|
41
|
-
def
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
1,
|
51
|
-
px.alpha >= 65_535 ? 6 : 8
|
52
|
-
]
|
80
|
+
def to_bin_format(width, height, blob)
|
81
|
+
ret = []
|
82
|
+
pos = 0
|
83
|
+
height.times do |y|
|
84
|
+
width.times do |x|
|
85
|
+
if blob[pos + 3] != "\x0"
|
86
|
+
ret << "PB#{[x + @delta_x, y + @delta_y].pack('v2')}#{blob[pos, 4]}"
|
87
|
+
end
|
88
|
+
pos += 4
|
53
89
|
end
|
54
90
|
end
|
91
|
+
ret
|
55
92
|
end
|
56
93
|
end
|
94
|
+
|
95
|
+
@count = ENV['TC'].to_i
|
96
|
+
@count = 4 unless @count.positive?
|
97
|
+
@mode = 'text'
|
98
|
+
@delta_x = @delta_y = 0
|
57
99
|
end
|
metadata
CHANGED
@@ -1,17 +1,17 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pixelflut
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mike Blumtritt
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-12-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: chunky_png
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
@@ -24,48 +24,6 @@ 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.4.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.4.0
|
41
|
-
- !ruby/object:Gem::Dependency
|
42
|
-
name: bundler
|
43
|
-
requirement: !ruby/object:Gem::Requirement
|
44
|
-
requirements:
|
45
|
-
- - ">="
|
46
|
-
- !ruby/object:Gem::Version
|
47
|
-
version: '0'
|
48
|
-
type: :development
|
49
|
-
prerelease: false
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
51
|
-
requirements:
|
52
|
-
- - ">="
|
53
|
-
- !ruby/object:Gem::Version
|
54
|
-
version: '0'
|
55
|
-
- !ruby/object:Gem::Dependency
|
56
|
-
name: rake
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
58
|
-
requirements:
|
59
|
-
- - ">="
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
version: '0'
|
62
|
-
type: :development
|
63
|
-
prerelease: false
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
65
|
-
requirements:
|
66
|
-
- - ">="
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
version: '0'
|
69
27
|
description: |
|
70
28
|
Based on the idea of a simple server protocol to collaborate on a shared
|
71
29
|
canvas named [Pixelflut](https://cccgoe.de/wiki/Pixelflut) this gem
|
@@ -73,27 +31,21 @@ description: |
|
|
73
31
|
email:
|
74
32
|
executables:
|
75
33
|
- pxf
|
76
|
-
- pxf-info
|
77
34
|
extensions: []
|
78
35
|
extra_rdoc_files:
|
79
36
|
- README.md
|
80
37
|
files:
|
81
|
-
- ".gitignore"
|
82
38
|
- README.md
|
83
39
|
- bin/pxf
|
84
|
-
- bin/pxf-info
|
85
|
-
- gems.rb
|
86
40
|
- lib/pixelflut.rb
|
87
|
-
- lib/pixelflut/image.rb
|
88
41
|
- lib/pixelflut/sender.rb
|
89
42
|
- lib/pixelflut/version.rb
|
90
|
-
- pixelflut.gemspec
|
91
|
-
- rakefile.rb
|
92
43
|
homepage: https://github.com/mblumtritt/pixelflut
|
93
44
|
licenses: []
|
94
45
|
metadata:
|
95
46
|
source_code_uri: https://github.com/mblumtritt/pixelflut
|
96
47
|
bug_tracker_uri: https://github.com/mblumtritt/pixelflut/issues
|
48
|
+
rubygems_mfa_required: 'true'
|
97
49
|
post_install_message:
|
98
50
|
rdoc_options: []
|
99
51
|
require_paths:
|
@@ -109,7 +61,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
109
61
|
- !ruby/object:Gem::Version
|
110
62
|
version: '0'
|
111
63
|
requirements: []
|
112
|
-
rubygems_version: 3.
|
64
|
+
rubygems_version: 3.4.22
|
113
65
|
signing_key:
|
114
66
|
specification_version: 4
|
115
67
|
summary: A fast Pixelflut client written in Ruby.
|
data/.gitignore
DELETED
data/bin/pxf-info
DELETED
@@ -1,32 +0,0 @@
|
|
1
|
-
#! /bin/sh
|
2
|
-
|
3
|
-
set -e
|
4
|
-
|
5
|
-
if [ "$1" = '--help' ]
|
6
|
-
then
|
7
|
-
echo "Usage: ${0##*/} [-p|--port PORT] ADDRESS
|
8
|
-
|
9
|
-
Requests screen size of Pixelflut server at ADDRESS.
|
10
|
-
"
|
11
|
-
exit 0
|
12
|
-
fi
|
13
|
-
|
14
|
-
PORT="1234"
|
15
|
-
ADDRESS=""
|
16
|
-
|
17
|
-
while [ $# -gt 0 ]
|
18
|
-
do
|
19
|
-
key="$1"
|
20
|
-
case $key in
|
21
|
-
-p|--port)
|
22
|
-
PORT="$2"
|
23
|
-
shift; shift
|
24
|
-
;;
|
25
|
-
*)
|
26
|
-
ADDRESS="$key"
|
27
|
-
shift
|
28
|
-
;;
|
29
|
-
esac
|
30
|
-
done
|
31
|
-
|
32
|
-
echo "SIZE\nQUIT\n" | nc "$ADDRESS" "$PORT"
|
data/gems.rb
DELETED
data/lib/pixelflut/image.rb
DELETED
@@ -1,32 +0,0 @@
|
|
1
|
-
require 'rmagick'
|
2
|
-
|
3
|
-
module Pixelflut
|
4
|
-
class Image
|
5
|
-
def initialize(file_name)
|
6
|
-
@image = Magick::ImageList.new(file_name)[0]
|
7
|
-
rescue Magick::ImageMagickError => e
|
8
|
-
raise(LoadError, e.message, cause: e)
|
9
|
-
end
|
10
|
-
|
11
|
-
def width
|
12
|
-
@image.columns
|
13
|
-
end
|
14
|
-
|
15
|
-
def height
|
16
|
-
@image.rows
|
17
|
-
end
|
18
|
-
|
19
|
-
def resize_to(width, height = nil)
|
20
|
-
@image.resize_to_fit!(width, height)
|
21
|
-
end
|
22
|
-
|
23
|
-
def scale(factor)
|
24
|
-
@image.scale!(factor)
|
25
|
-
end
|
26
|
-
|
27
|
-
def each_pixel
|
28
|
-
return to_enum(__method__) unless block_given?
|
29
|
-
@image.each_pixel { |px, x, y| 0 != px.alpha and yield(x, y, px) }
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
data/pixelflut.gemspec
DELETED
@@ -1,34 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative 'lib/pixelflut/version'
|
4
|
-
|
5
|
-
Gem::Specification.new do |spec|
|
6
|
-
spec.name = 'pixelflut'
|
7
|
-
spec.version = Pixelflut::VERSION
|
8
|
-
spec.author = 'Mike Blumtritt'
|
9
|
-
|
10
|
-
spec.required_ruby_version = '>= 2.7.2'
|
11
|
-
|
12
|
-
spec.summary = 'A fast Pixelflut client written in Ruby.'
|
13
|
-
spec.description = <<~DESCRIPTION
|
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.
|
17
|
-
DESCRIPTION
|
18
|
-
spec.homepage = 'https://github.com/mblumtritt/pixelflut'
|
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'
|
23
|
-
|
24
|
-
spec.add_runtime_dependency 'rmagick'
|
25
|
-
spec.add_runtime_dependency 'mini-cli', '>= 0.4.0'
|
26
|
-
spec.add_development_dependency 'bundler'
|
27
|
-
spec.add_development_dependency 'rake'
|
28
|
-
|
29
|
-
spec.bindir = 'bin'
|
30
|
-
spec.executables = %w[pxf pxf-info]
|
31
|
-
|
32
|
-
spec.files = Dir.chdir(__dir__) { `git ls-files -z`.split(0.chr) }
|
33
|
-
spec.extra_rdoc_files = %w[README.md]
|
34
|
-
end
|