pixelflut 0.0.6 → 0.0.8
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 +31 -0
- data/TODO.md +1 -1
- data/bin/pxf-convert +54 -0
- data/bin/pxf-help +1 -1
- data/bin/pxf-server +2 -3
- data/lib/pixelflut/converter.rb +52 -0
- data/lib/pixelflut/server.rb +2 -108
- data/lib/pixelflut/server/configuration.rb +26 -0
- data/lib/pixelflut/server/connection.rb +96 -0
- data/lib/pixelflut/text_image.rb +3 -3
- data/lib/pixelflut/version.rb +1 -1
- data/pixelflut.gemspec +0 -0
- metadata +7 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 62efcd05717e96f42f60e21cbc7a569277fed6bb2e56d24d57d3fe11ff37cb1b
|
4
|
+
data.tar.gz: 7c8fd4eb2542668dd25abd6b5cccc12818c790cf111f1b2a8e38bbda44527f4d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 94241373ff17f9e0cbbc1b1b2e51f55db1da4beb032c18f4985590e6c50a1ba1bd9313fc7858caa9be76f84593b8fc7374337226afc72641a1c40f767b7fa66a
|
7
|
+
data.tar.gz: 00f6b49748585411187665ef9c2c3a519ca77641c7a3c7aa281b65f37a0c5b8fea7e53df82b49b58cc88401b72698f551b6752915c9d7177c9de5d2b1be9f3f3
|
data/README.md
CHANGED
@@ -29,6 +29,7 @@ $ pxf
|
|
29
29
|
usage: pxf command [options]
|
30
30
|
|
31
31
|
valid commands:
|
32
|
+
convert Convert given IMAGE file to Pixelflut format.
|
32
33
|
generate Execute given generator FILEs.
|
33
34
|
help Print help for given COMMAND.
|
34
35
|
server Start Pixelflut server.
|
@@ -54,3 +55,33 @@ With these options you can configure the server:
|
|
54
55
|
-h, --height HEIGHT set canvas height (default: 600)
|
55
56
|
-f, --[no-]fullscreen run in fullscreen mode
|
56
57
|
```
|
58
|
+
|
59
|
+
### Convert an image
|
60
|
+
|
61
|
+
There is a conversion command which can be used to convert a given image to the Pixelflut text format:
|
62
|
+
|
63
|
+
```bash
|
64
|
+
$ pxf convert image.png
|
65
|
+
```
|
66
|
+
|
67
|
+
The result can directly send to a running server (sample assumes the server runs on localhost port 1234):
|
68
|
+
|
69
|
+
```bash
|
70
|
+
$ pxf convert image.png | netcat localhost 1234
|
71
|
+
```
|
72
|
+
|
73
|
+
The converter can help you to resize and positioning the image and the servers canvas. These options are avail:
|
74
|
+
|
75
|
+
```
|
76
|
+
-x, --transpose-x X transpose image X pixels
|
77
|
+
-y, --transpose-y Y transpose image Y pixels
|
78
|
+
-w, --width WIDTH resize the image to given WIDTH
|
79
|
+
-h, --height HEIGHT resize the image to given HEIGHT
|
80
|
+
```
|
81
|
+
|
82
|
+
It maybe faster to pre-process your image(s) and send later:
|
83
|
+
|
84
|
+
```bash
|
85
|
+
$ pxf convert -x 50 -y 100 --width 640 image.png > image.px
|
86
|
+
$ cat image.px | netcat localhost 1234
|
87
|
+
```
|
data/TODO.md
CHANGED
data/bin/pxf-convert
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
def options(cfg)
|
5
|
+
require 'optparse'
|
6
|
+
OptionParser.new do |opts|
|
7
|
+
opts.summary_indent = ' '
|
8
|
+
opts.banner = 'usage: pxf convert [options] IMAGE'
|
9
|
+
opts.separator(nil)
|
10
|
+
opts.separator('valid options:')
|
11
|
+
opts.on('-x', '--transpose-x X', Integer, 'transpose image X pixels'){ |v| cfg[:x_offset] = v }
|
12
|
+
opts.on('-y', '--transpose-y Y', Integer, 'transpose image Y pixels'){ |v| cfg[:y_offset] = v }
|
13
|
+
opts.on('-w', '--width WIDTH', Integer, 'resize the image to given WIDTH'){ |v| cfg[:width] = v }
|
14
|
+
opts.on('-h', '--height HEIGHT', Integer, 'resize the image to given HEIGHT'){ |v| cfg[:height] = v }
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def help(short)
|
19
|
+
puts(options(nil), nil) unless short
|
20
|
+
puts('Convert given IMAGE file to Pixelflut format.')
|
21
|
+
exit
|
22
|
+
end
|
23
|
+
|
24
|
+
def err(msg, code = 1)
|
25
|
+
$stderr.puts("pxf: #{msg}")
|
26
|
+
exit(code)
|
27
|
+
end
|
28
|
+
|
29
|
+
def create_options
|
30
|
+
cfg = {}
|
31
|
+
options(cfg).parse!
|
32
|
+
cfg
|
33
|
+
rescue OptionParser::ParseError => e
|
34
|
+
err(e)
|
35
|
+
end
|
36
|
+
|
37
|
+
help(false) if '--help' == ARGV[0]
|
38
|
+
help(true) if '--short-help' == ARGV[0]
|
39
|
+
err('too few arguments') if ARGV.empty?
|
40
|
+
options = create_options
|
41
|
+
require File.realdirpath('../../lib/pixelflut/converter.rb', __FILE__)
|
42
|
+
begin
|
43
|
+
ARGV.each do |file_name|
|
44
|
+
cvt = Pixelflut::Converter.new(file_name)
|
45
|
+
cvt.x_offset = options[:x_offset] if options[:x_offset]
|
46
|
+
cvt.y_offset = options[:y_offset] if options[:y_offset]
|
47
|
+
cvt.resize_to(options[:width], options[:height]) if options[:width]
|
48
|
+
cvt.each_line{ |line| puts(line) }
|
49
|
+
end
|
50
|
+
rescue Pixelflut::Converter::Error => e
|
51
|
+
err(e.message, 2)
|
52
|
+
rescue Interrupt
|
53
|
+
exit
|
54
|
+
end
|
data/bin/pxf-help
CHANGED
data/bin/pxf-server
CHANGED
@@ -20,7 +20,7 @@ def options(cfg)
|
|
20
20
|
opts.on('-r', '--read_buffer SIZE', Integer, 'set read buffer size (default: 1024)') do |v|
|
21
21
|
cfg.server.read_buffer_size = v
|
22
22
|
end
|
23
|
-
opts.on('-l', '--peer-limit NUMBER', Integer, 'limit number connections per peer (default: 8)') do |v|
|
23
|
+
opts.on('-l', '--peer-limit NUMBER', Integer, 'limit number of connections per peer (default: 8)') do |v|
|
24
24
|
cfg.server.peer_limit = v
|
25
25
|
end
|
26
26
|
opts.on('-c', '--command-limit NUMBER', Integer, 'limit of continious processed commands (default: 10)') do |v|
|
@@ -53,11 +53,10 @@ def create_configuration
|
|
53
53
|
cfg
|
54
54
|
rescue OptionParser::ParseError => e
|
55
55
|
$stderr.puts("pxf: #{e}")
|
56
|
-
exit
|
56
|
+
exit(1)
|
57
57
|
end
|
58
58
|
|
59
59
|
begin
|
60
|
-
require 'optparse'
|
61
60
|
require File.realdirpath('../../lib/pixelflut.rb', __FILE__)
|
62
61
|
Pixelflut::App.run(create_configuration)
|
63
62
|
rescue Interrupt
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Pixelflut
|
4
|
+
class Converter
|
5
|
+
Error = Class.new(RuntimeError)
|
6
|
+
|
7
|
+
attr_accessor :x_offset, :y_offset
|
8
|
+
|
9
|
+
def initialize(file_name)
|
10
|
+
load_rmagick
|
11
|
+
@images = load_image(file_name)
|
12
|
+
@x_offset = @y_offset = 0
|
13
|
+
end
|
14
|
+
|
15
|
+
def resize_to(width, height = nil)
|
16
|
+
@images.each{ |image| image.resize_to_fit!(width, height) }
|
17
|
+
end
|
18
|
+
|
19
|
+
def each_pixel
|
20
|
+
return to_enum(__method__) unless block_given?
|
21
|
+
@images.each do |image|
|
22
|
+
image.each_pixel do |color, x, y|
|
23
|
+
yield(
|
24
|
+
x + @x_offset,
|
25
|
+
y + @y_offset,
|
26
|
+
color.to_color(Magick::AllCompliance, true, 8, true)[1, 8]
|
27
|
+
) unless 0xffff == color.opacity
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def each_line
|
33
|
+
return to_enum(__method__) unless block_given?
|
34
|
+
each_pixel{ |x, y, rgba| yield "PX #{x} #{y} #{rgba}" }
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def load_image(file_name)
|
40
|
+
Magick::ImageList.new(file_name)
|
41
|
+
rescue Magick::ImageMagickError => e
|
42
|
+
raise(Error, e.message)
|
43
|
+
end
|
44
|
+
|
45
|
+
def load_rmagick
|
46
|
+
require 'rmagick'
|
47
|
+
rescue LoadError
|
48
|
+
raise(Error, 'unable to load gem - "RMagick" not installed')
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
end
|
data/lib/pixelflut/server.rb
CHANGED
@@ -1,30 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'socket'
|
4
|
+
require_relative 'server/connection'
|
5
|
+
require_relative 'server/configuration'
|
4
6
|
|
5
7
|
module Pixelflut
|
6
8
|
class Server
|
7
|
-
Configuration = Struct.new(
|
8
|
-
:host,
|
9
|
-
:port,
|
10
|
-
:keep_alive_time,
|
11
|
-
:read_buffer_size,
|
12
|
-
:command_limit,
|
13
|
-
:peer_limit
|
14
|
-
) do
|
15
|
-
def self.default
|
16
|
-
new(nil, 1234, 1, 1024, 10, 8)
|
17
|
-
end
|
18
|
-
|
19
|
-
def to_s
|
20
|
-
"bind: #{host}:#{port}"\
|
21
|
-
", keep-alive-time: #{keep_alive_time}"\
|
22
|
-
", read-buffer-size: #{read_buffer_size}"\
|
23
|
-
", command-limit: #{command_limit}"\
|
24
|
-
", peer-limit: #{peer_limit}"
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
9
|
attr_reader :config
|
29
10
|
|
30
11
|
def initialize(canvas, config = Configuration.default)
|
@@ -73,92 +54,5 @@ module Pixelflut
|
|
73
54
|
@socket = @config.host ? TCPServer.new(@config.host, @config.port) : TCPServer.new(@config.port)
|
74
55
|
@socket.listen(255)
|
75
56
|
end
|
76
|
-
|
77
|
-
class Connection
|
78
|
-
Configuration = Struct.new(
|
79
|
-
:keep_alive_time,
|
80
|
-
:read_buffer_size,
|
81
|
-
:command_limit,
|
82
|
-
:canvas,
|
83
|
-
:size_result,
|
84
|
-
:on_end,
|
85
|
-
keyword_init: true
|
86
|
-
)
|
87
|
-
|
88
|
-
attr_reader :peeraddr
|
89
|
-
|
90
|
-
def initialize(socket, peeraddr, config)
|
91
|
-
@socket, @peeraddr, @config = socket, peeraddr, config
|
92
|
-
@last_tm, @buffer = Time.now.to_f, ''
|
93
|
-
end
|
94
|
-
|
95
|
-
def close(_reason)
|
96
|
-
socket, @socket = @socket, nil
|
97
|
-
return unless socket
|
98
|
-
socket.close
|
99
|
-
@config.on_end.call(self)
|
100
|
-
false
|
101
|
-
end
|
102
|
-
|
103
|
-
def update
|
104
|
-
index = @buffer.index("\n")
|
105
|
-
return process_loop(index) if index
|
106
|
-
read_size = @config.read_buffer_size - @buffer.size
|
107
|
-
return close(:buffer_exceeded) if read_size <= 0
|
108
|
-
str = @socket.recv_nonblock(read_size, exception: false)
|
109
|
-
now = Time.now.to_f
|
110
|
-
return (now - @last_tm > @config.keep_alive_time ? close(:timeout) : nil) if Symbol === str
|
111
|
-
return close(:closed_by_peer) if 0 == str.size
|
112
|
-
@buffer += str
|
113
|
-
@last_tm = now
|
114
|
-
end
|
115
|
-
|
116
|
-
private
|
117
|
-
|
118
|
-
def next_command(index)
|
119
|
-
@buffer = @buffer[index, @buffer.size - index]
|
120
|
-
@last_tm = Time.now.to_f
|
121
|
-
true
|
122
|
-
end
|
123
|
-
|
124
|
-
def command_size(index)
|
125
|
-
@socket.sendmsg_nonblock(@config.size_result)
|
126
|
-
next_command(index)
|
127
|
-
end
|
128
|
-
|
129
|
-
def command_px(command, index)
|
130
|
-
_, x, y, color = command.split(' ', 4)
|
131
|
-
return close(:color_expected) unless color
|
132
|
-
@config.canvas[x.to_i, y.to_i] = color
|
133
|
-
next_command(index)
|
134
|
-
end
|
135
|
-
|
136
|
-
def command_rc(command, index)
|
137
|
-
_, x1, y1, x2, y2, color = command.split(' ', 6)
|
138
|
-
return close(:color_expected) unless color
|
139
|
-
@config.canvas.draw_rect(x1.to_i, y1.to_i, x2.to_i, y2.to_i, color)
|
140
|
-
next_command(index)
|
141
|
-
end
|
142
|
-
|
143
|
-
def process_loop(index)
|
144
|
-
command_count = @config.command_limit
|
145
|
-
while process_buffer(index)
|
146
|
-
index = @buffer.index("\n") or return
|
147
|
-
command_count -= 1
|
148
|
-
break if command_count <= 0
|
149
|
-
end
|
150
|
-
end
|
151
|
-
|
152
|
-
def process_buffer(index)
|
153
|
-
return close(:max_command_size_exceeded) if index > 31 # 'RC 9999 9999 9999 9999 RRGGBBAA'.size
|
154
|
-
command = @buffer[0, index]
|
155
|
-
index += 1
|
156
|
-
return command_px(command, index) if command.start_with?('PX ')
|
157
|
-
return command_rc(command, index) if command.start_with?('RC ')
|
158
|
-
return close(:quit) if command == 'QUIT'
|
159
|
-
return command_size(index) if command == 'SIZE'
|
160
|
-
close(:bad_command)
|
161
|
-
end
|
162
|
-
end
|
163
57
|
end
|
164
58
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Pixelflut
|
4
|
+
class Server
|
5
|
+
Configuration = Struct.new(
|
6
|
+
:host,
|
7
|
+
:port,
|
8
|
+
:keep_alive_time,
|
9
|
+
:read_buffer_size,
|
10
|
+
:command_limit,
|
11
|
+
:peer_limit
|
12
|
+
) do
|
13
|
+
def self.default
|
14
|
+
new(nil, 1234, 1, 1024, 10, 8)
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_s
|
18
|
+
"bind: #{host}:#{port}"\
|
19
|
+
", keep-alive-time: #{keep_alive_time}"\
|
20
|
+
", read-buffer-size: #{read_buffer_size}"\
|
21
|
+
", command-limit: #{command_limit}"\
|
22
|
+
", peer-limit: #{peer_limit}"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Pixelflut
|
4
|
+
class Server
|
5
|
+
class Connection
|
6
|
+
Configuration = Struct.new(
|
7
|
+
:keep_alive_time,
|
8
|
+
:read_buffer_size,
|
9
|
+
:command_limit,
|
10
|
+
:canvas,
|
11
|
+
:size_result,
|
12
|
+
:on_end,
|
13
|
+
keyword_init: true
|
14
|
+
)
|
15
|
+
|
16
|
+
attr_reader :peeraddr
|
17
|
+
|
18
|
+
def initialize(socket, peeraddr, config)
|
19
|
+
@socket, @peeraddr, @config = socket, peeraddr, config
|
20
|
+
@last_tm, @buffer = Time.now.to_f, ''
|
21
|
+
end
|
22
|
+
|
23
|
+
def close(_reason)
|
24
|
+
socket, @socket = @socket, nil
|
25
|
+
return unless socket
|
26
|
+
socket.close
|
27
|
+
@config.on_end.call(self)
|
28
|
+
false
|
29
|
+
end
|
30
|
+
|
31
|
+
def update
|
32
|
+
index = @buffer.index("\n")
|
33
|
+
return process_loop(index) if index
|
34
|
+
read_size = @config.read_buffer_size - @buffer.size
|
35
|
+
return close(:buffer_exceeded) if read_size <= 0
|
36
|
+
str = @socket.recv_nonblock(read_size, exception: false)
|
37
|
+
now = Time.now.to_f
|
38
|
+
return (now - @last_tm > @config.keep_alive_time ? close(:timeout) : nil) if Symbol === str
|
39
|
+
return close(:closed_by_peer) if 0 == str.size
|
40
|
+
@buffer += str
|
41
|
+
@last_tm = now
|
42
|
+
rescue Errno::ECONNRESET
|
43
|
+
close(:closed_by_peer)
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def next_command(index)
|
49
|
+
@buffer = @buffer[index, @buffer.size - index]
|
50
|
+
@last_tm = Time.now.to_f
|
51
|
+
true
|
52
|
+
end
|
53
|
+
|
54
|
+
def command_size(index)
|
55
|
+
@socket.sendmsg_nonblock(@config.size_result)
|
56
|
+
next_command(index)
|
57
|
+
end
|
58
|
+
|
59
|
+
def command_px(command, index)
|
60
|
+
_, x, y, color = command.split(' ', 4)
|
61
|
+
return close(:color_expected) unless color
|
62
|
+
@config.canvas[x.to_i, y.to_i] = color
|
63
|
+
next_command(index)
|
64
|
+
end
|
65
|
+
|
66
|
+
def command_rc(command, index)
|
67
|
+
_, x1, y1, x2, y2, color = command.split(' ', 6)
|
68
|
+
return close(:color_expected) unless color
|
69
|
+
@config.canvas.draw_rect(x1.to_i, y1.to_i, x2.to_i, y2.to_i, color)
|
70
|
+
next_command(index)
|
71
|
+
end
|
72
|
+
|
73
|
+
def process_loop(index)
|
74
|
+
command_count = @config.command_limit
|
75
|
+
while process_buffer(index)
|
76
|
+
index = @buffer.index("\n") or return
|
77
|
+
command_count -= 1
|
78
|
+
break if command_count <= 0
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def process_buffer(index)
|
83
|
+
return close(:max_command_size_exceeded) if index > 31 # 'RC 9999 9999 9999 9999 RRGGBBAA'.size
|
84
|
+
command = @buffer[0, index]
|
85
|
+
index += 1
|
86
|
+
return command_px(command, index) if command.start_with?('PX ')
|
87
|
+
return command_rc(command, index) if command.start_with?('RC ')
|
88
|
+
return close(:quit) if command == 'QUIT'
|
89
|
+
return command_size(index) if command == 'SIZE'
|
90
|
+
close(:bad_command)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
private_constant(:Connection)
|
95
|
+
end
|
96
|
+
end
|
data/lib/pixelflut/text_image.rb
CHANGED
@@ -24,7 +24,7 @@ module Pixelflut
|
|
24
24
|
end
|
25
25
|
|
26
26
|
# def [](x, y)
|
27
|
-
#
|
27
|
+
# @@to_blob[(4 * (x + @columns * y)) % @data.size, 4].bytes.map! do |b|
|
28
28
|
# b = b.to_s(16)
|
29
29
|
# b = '0' + b if b.size == 1
|
30
30
|
# b
|
@@ -40,10 +40,10 @@ module Pixelflut
|
|
40
40
|
x1, x2 = x2, x1 if x1 > x2
|
41
41
|
y1, y2 = y2, y1 if y1 > y2
|
42
42
|
color = as_color(rrggbbaa)
|
43
|
-
pos = (4 * (x1 + @columns * y1)) % @
|
43
|
+
pos = (4 * (x1 + @columns * y1)) % @to_blob.size
|
44
44
|
pattern = color * (x2 - x1 + 1)
|
45
45
|
(y2 - y1 + 1).times do
|
46
|
-
@
|
46
|
+
@to_blob[pos, pattern.size] = pattern
|
47
47
|
pos += @row_inc
|
48
48
|
end
|
49
49
|
@changes += 1
|
data/lib/pixelflut/version.rb
CHANGED
data/pixelflut.gemspec
CHANGED
Binary file
|
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.0.
|
4
|
+
version: 0.0.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mike Blumtritt
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-03-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: gosu
|
@@ -60,6 +60,7 @@ executables:
|
|
60
60
|
- pxf
|
61
61
|
- pxf-generate
|
62
62
|
- pxf-server
|
63
|
+
- pxf-convert
|
63
64
|
- pxf-help
|
64
65
|
- pxf-version
|
65
66
|
extensions: []
|
@@ -70,6 +71,7 @@ files:
|
|
70
71
|
- README.md
|
71
72
|
- TODO.md
|
72
73
|
- bin/pxf
|
74
|
+
- bin/pxf-convert
|
73
75
|
- bin/pxf-generate
|
74
76
|
- bin/pxf-help
|
75
77
|
- bin/pxf-server
|
@@ -82,7 +84,10 @@ files:
|
|
82
84
|
- lib/pixelflut/canvas/buffered.rb
|
83
85
|
- lib/pixelflut/canvas/color.rb
|
84
86
|
- lib/pixelflut/canvas/streamed.rb
|
87
|
+
- lib/pixelflut/converter.rb
|
85
88
|
- lib/pixelflut/server.rb
|
89
|
+
- lib/pixelflut/server/configuration.rb
|
90
|
+
- lib/pixelflut/server/connection.rb
|
86
91
|
- lib/pixelflut/text_image.rb
|
87
92
|
- lib/pixelflut/version.rb
|
88
93
|
- pixelflut.gemspec
|