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