pixelflut 0.2.2 → 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 +99 -118
- data/lib/pixelflut/sender.rb +17 -17
- data/lib/pixelflut/version.rb +1 -1
- data/lib/pixelflut.rb +79 -40
- metadata +5 -7
- data/bin/pxf-info +0 -32
- data/lib/pixelflut/image.rb +0 -34
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
@@ -2,151 +2,132 @@
|
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
$stdout.sync = $stderr.sync = true
|
5
|
-
|
5
|
+
$name = Process.setproctitle(File.basename(Process.argv0))
|
6
6
|
|
7
7
|
if ARGV.index('-h') || ARGV.index('--help')
|
8
8
|
puts <<~HELP
|
9
|
-
Usage: #{$name}
|
9
|
+
Usage: #{$name} [options] <png_image>
|
10
10
|
|
11
11
|
Options:
|
12
|
-
--host <address> target host address
|
12
|
+
--host <address> target host address (default 127.0.0.1)
|
13
13
|
-p, --port <port> target port (default 1234)
|
14
14
|
-c, --connections <count> count of connections (default 4)
|
15
|
-
-
|
15
|
+
-m, --mode <mode> select pixel encoding (TEXT | BIN)
|
16
|
+
-t, --threads use threads instead of processes
|
16
17
|
-x, --transpose-x <x> transpose image <x> pixels
|
17
18
|
-y, --transpose-y <y> transpose image <y> pixels
|
18
|
-
-s, --scale <scale> scale image by factor
|
19
|
-
-m, --pixel <mode> select pixel coding (RGBX | RGBA | RGB)
|
20
19
|
-h, --help print this help
|
20
|
+
-v, --version print version information
|
21
21
|
HELP
|
22
22
|
exit
|
23
23
|
end
|
24
24
|
|
25
|
-
|
26
|
-
|
25
|
+
if ARGV.index('-v') || ARGV.index('--version')
|
26
|
+
require_relative('../lib/pixelflut/version')
|
27
|
+
puts("#{$name} - Pixelflut v#{Pixelflut::VERSION}")
|
28
|
+
exit
|
29
|
+
end
|
30
|
+
|
31
|
+
def die!(msg, code: 1)
|
32
|
+
$stderr.puts("#{$name}: #{msg}")
|
27
33
|
exit(code)
|
28
34
|
end
|
29
35
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
@bytes = as_uint(argv.shift, 'bytes')
|
61
|
-
when '-x', '--transpose-x'
|
62
|
-
@trans_x = argv.shift.to_i
|
63
|
-
when '-y', '--transpose-y'
|
64
|
-
@trans_y = argv.shift.to_i
|
65
|
-
when '-s', '--scale'
|
66
|
-
@scale = as_float(argv.shift, 'scale')
|
67
|
-
when '-m', '--pixel'
|
68
|
-
@mode = as_mode(argv.shift, 'mode')
|
69
|
-
else
|
70
|
-
raise(ArgumentError, "Invalid option - #{arg}") if @image
|
71
|
-
@image = arg
|
72
|
-
end
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
def address
|
77
|
-
Pixelflut::Sender.address(@address, @port)
|
78
|
-
end
|
79
|
-
|
80
|
-
def options
|
81
|
-
{ source: @image, x: @trans_x, y: @trans_y, scale: @scale, mode: @mode }
|
82
|
-
end
|
83
|
-
|
84
|
-
private
|
85
|
-
|
86
|
-
def invalid(value, name)
|
87
|
-
raise(ArgumentError, "Value for #{name} missing") if value.nil?
|
88
|
-
raise(ArgumentError, "Invalid value for #{name} - '#{value}'")
|
89
|
-
end
|
90
|
-
|
91
|
-
def as_uint(value, name)
|
92
|
-
ret = value.to_i
|
93
|
-
ret.positive? ? ret : invalid(value, name)
|
94
|
-
end
|
95
|
-
|
96
|
-
def as_str(value, name)
|
97
|
-
value.nil? || value.empty? ? invalid(value, name) : value
|
98
|
-
end
|
99
|
-
|
100
|
-
def as_float(value, name)
|
101
|
-
ret = value.to_f
|
102
|
-
ret.positive? ? ret : invalid(value, name)
|
103
|
-
end
|
104
|
-
|
105
|
-
def as_mode(value, name)
|
106
|
-
case value.downcase
|
107
|
-
when 'rgbx'
|
108
|
-
:rgbx
|
109
|
-
when 'rgba'
|
110
|
-
:rgba
|
111
|
-
when 'rgb'
|
112
|
-
:rgb
|
113
|
-
else
|
114
|
-
invalid(value, name)
|
115
|
-
end
|
116
|
-
end
|
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)
|
117
66
|
end
|
118
|
-
|
67
|
+
end
|
119
68
|
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
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
|
124
90
|
end
|
125
|
-
|
91
|
+
|
92
|
+
die!('<image> missing') unless Pixelflut.file_name
|
126
93
|
end
|
127
94
|
|
128
|
-
|
129
|
-
|
130
|
-
require_relative('../lib/pixelflut')
|
131
|
-
data = create_junks
|
132
|
-
error("Too many subprocesses - #{data.size}") if data.size > 256
|
133
|
-
print("spawn #{data.size}")
|
95
|
+
def use_processes(address, data)
|
96
|
+
puts("#{$name}: start #{data.size} processes for #{data.sum(&:size)} bytes")
|
134
97
|
data.size.times do |i|
|
135
98
|
next unless fork
|
136
|
-
|
137
|
-
data = data[i].join
|
99
|
+
data = data[i]
|
138
100
|
GC.start
|
139
|
-
|
140
|
-
Pixelflut::Sender.send(
|
101
|
+
$name = Process.setproctitle("#{$name}-#{'0' if i < 9}#{i + 1}")
|
102
|
+
Pixelflut::Sender.send(address, data) do |size|
|
103
|
+
puts("#{$name}: #{size} bytes")
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
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)
|
141
121
|
end
|
142
|
-
rescue ArgumentError => e
|
143
|
-
error(e)
|
144
|
-
rescue LoadError => e
|
145
|
-
error(e, code: 4)
|
146
122
|
rescue Errno::ECONNREFUSED
|
147
|
-
|
123
|
+
die!('unable to connect', code: 2)
|
148
124
|
rescue Errno::EPIPE
|
149
|
-
|
125
|
+
die!('connection lost', code: 2)
|
150
126
|
rescue SocketError => e
|
151
|
-
|
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)
|
152
133
|
end
|
data/lib/pixelflut/sender.rb
CHANGED
@@ -1,31 +1,31 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'socket'
|
4
|
-
|
5
3
|
module Pixelflut
|
6
4
|
module Sender
|
7
|
-
def self.
|
8
|
-
|
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
|
+
)
|
9
12
|
end
|
10
13
|
|
11
14
|
def self.send(address, data)
|
12
15
|
socket = create_socket(address)
|
13
|
-
yield(
|
14
|
-
|
16
|
+
yield(data.bytesize) if block_given?
|
17
|
+
socket.write(data) while true
|
15
18
|
end
|
16
19
|
|
17
20
|
def self.create_socket(address)
|
18
|
-
Socket
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
socket.do_not_reverse_lookup = true
|
25
|
-
socket.connect(
|
26
|
-
Socket.pack_sockaddr_in(address.ip_port, address.ip_address)
|
27
|
-
)
|
28
|
-
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
|
29
27
|
end
|
28
|
+
|
29
|
+
Address = Struct.new(:sockaddr_in, :type)
|
30
30
|
end
|
31
31
|
end
|
data/lib/pixelflut/version.rb
CHANGED
data/lib/pixelflut.rb
CHANGED
@@ -1,60 +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
|
-
|
16
|
-
|
17
|
-
|
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)
|
18
19
|
end
|
19
20
|
|
20
|
-
def
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
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
|
26
43
|
end
|
27
|
-
ret
|
28
44
|
end
|
29
45
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
.map! { |x, y, px| "PX #{x + dx} #{y + dy} #{yield(px)}\n" }
|
37
|
-
.shuffle!
|
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
|
38
52
|
end
|
39
53
|
|
40
|
-
def
|
41
|
-
|
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
|
42
78
|
end
|
43
79
|
|
44
|
-
def
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
1,
|
54
|
-
px.alpha >= 65_535 ? 6 : 8
|
55
|
-
]
|
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
|
56
89
|
end
|
57
90
|
end
|
91
|
+
ret
|
58
92
|
end
|
59
93
|
end
|
94
|
+
|
95
|
+
@count = ENV['TC'].to_i
|
96
|
+
@count = 4 unless @count.positive?
|
97
|
+
@mode = 'text'
|
98
|
+
@delta_x = @delta_y = 0
|
60
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
|
- - ">="
|
@@ -31,16 +31,13 @@ description: |
|
|
31
31
|
email:
|
32
32
|
executables:
|
33
33
|
- pxf
|
34
|
-
- pxf-info
|
35
34
|
extensions: []
|
36
35
|
extra_rdoc_files:
|
37
36
|
- README.md
|
38
37
|
files:
|
39
38
|
- README.md
|
40
39
|
- bin/pxf
|
41
|
-
- bin/pxf-info
|
42
40
|
- lib/pixelflut.rb
|
43
|
-
- lib/pixelflut/image.rb
|
44
41
|
- lib/pixelflut/sender.rb
|
45
42
|
- lib/pixelflut/version.rb
|
46
43
|
homepage: https://github.com/mblumtritt/pixelflut
|
@@ -48,6 +45,7 @@ licenses: []
|
|
48
45
|
metadata:
|
49
46
|
source_code_uri: https://github.com/mblumtritt/pixelflut
|
50
47
|
bug_tracker_uri: https://github.com/mblumtritt/pixelflut/issues
|
48
|
+
rubygems_mfa_required: 'true'
|
51
49
|
post_install_message:
|
52
50
|
rdoc_options: []
|
53
51
|
require_paths:
|
@@ -63,7 +61,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
63
61
|
- !ruby/object:Gem::Version
|
64
62
|
version: '0'
|
65
63
|
requirements: []
|
66
|
-
rubygems_version: 3.
|
64
|
+
rubygems_version: 3.4.22
|
67
65
|
signing_key:
|
68
66
|
specification_version: 4
|
69
67
|
summary: A fast Pixelflut client written in Ruby.
|
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/lib/pixelflut/image.rb
DELETED
@@ -1,34 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'rmagick'
|
4
|
-
|
5
|
-
module Pixelflut
|
6
|
-
class Image
|
7
|
-
def initialize(file_name)
|
8
|
-
@image = Magick::ImageList.new(file_name).first
|
9
|
-
rescue Magick::ImageMagickError => e
|
10
|
-
raise(LoadError, e.message, cause: e)
|
11
|
-
end
|
12
|
-
|
13
|
-
def width
|
14
|
-
@image.columns
|
15
|
-
end
|
16
|
-
|
17
|
-
def height
|
18
|
-
@image.rows
|
19
|
-
end
|
20
|
-
|
21
|
-
def resize_to(width, height = nil)
|
22
|
-
@image.resize_to_fit!(width, height)
|
23
|
-
end
|
24
|
-
|
25
|
-
def scale(factor)
|
26
|
-
@image.scale!(factor)
|
27
|
-
end
|
28
|
-
|
29
|
-
def each_pixel
|
30
|
-
return to_enum(__method__) unless block_given?
|
31
|
-
@image.each_pixel { |px, x, y| 0 != px.alpha and yield(x, y, px) }
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|