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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bbd5e580104dccc3e1a1123ccc063dde0ae530d7443129bc044e9b73a9c71293
4
- data.tar.gz: 6590f3d4f9491a10aec353701cde1f53a26158ba8c655be0952ea3be0129d500
3
+ metadata.gz: 62efcd05717e96f42f60e21cbc7a569277fed6bb2e56d24d57d3fe11ff37cb1b
4
+ data.tar.gz: 7c8fd4eb2542668dd25abd6b5cccc12818c790cf111f1b2a8e38bbda44527f4d
5
5
  SHA512:
6
- metadata.gz: ac78e76fc92be0e1891012cd1d1fe5b0cb5f388f736f75c2a4a193a294ce339cd1763ce2d1dcc055fa997b6feed20a0fba30d57447695cf8512db229fdcd6306
7
- data.tar.gz: 20efde215a0528fc028980fa8edc3c8d40a3acff446aeb3f3599ca7cbd69a87dcc1eac135a5d844e2746a58651c011f8f64a38b2c35733029d382d5c832fe8a0
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
@@ -5,5 +5,5 @@
5
5
  - [x] limit connections _per IP_
6
6
  - [x] allow 10 (pixel-)actions per client
7
7
  - [ ] extend `pxf generate`
8
- - [ ] add a pre-processor for images
8
+ - [x] add a pre-processor for images
9
9
  - [ ] mention the Gosu gem in the README
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
@@ -8,7 +8,7 @@ end
8
8
 
9
9
  def err(msg)
10
10
  $stderr.puts("pxf: #{msg}")
11
- exit 1
11
+ exit(1)
12
12
  end
13
13
 
14
14
  case ARGV[0]
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 1
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
@@ -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
@@ -24,7 +24,7 @@ module Pixelflut
24
24
  end
25
25
 
26
26
  # def [](x, y)
27
- # @data[(4 * (x + @columns * y)) % @data.size, 4].bytes.map! do |b|
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)) % @data.size
43
+ pos = (4 * (x1 + @columns * y1)) % @to_blob.size
44
44
  pattern = color * (x2 - x1 + 1)
45
45
  (y2 - y1 + 1).times do
46
- @data[pos, pattern.size] = pattern
46
+ @to_blob[pos, pattern.size] = pattern
47
47
  pos += @row_inc
48
48
  end
49
49
  @changes += 1
@@ -1,3 +1,3 @@
1
1
  module Pixelflut
2
- VERSION = '0.0.6'.freeze
2
+ VERSION = '0.0.8'.freeze
3
3
  end
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.6
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-02-04 00:00:00.000000000 Z
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