rbimg 0.1.3 → 0.1.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +1 -1
- data/Gemfile.lock +4 -4
- data/README.md +30 -5
- data/TODO.md +7 -0
- data/lib/image_types/png.rb +240 -26
- data/lib/rbimg.rb +1 -0
- data/lib/rbimg/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 866ea03a52665264e1685f5c058c86d757bd172302eb81a3ce0eeeb92f6b16e0
|
4
|
+
data.tar.gz: 34f65d90480aa2b55f49e0931dea21edaeb990b8ed46fc44e77b4cf144746277
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 32f94fd46bc3f7a63671364a3284efcd014e8801079a5453b1371554a8030965f45b63c09342cc103f5fc5bda981dc90eb2b2570d0d9b812a1284bc2e1889063
|
7
|
+
data.tar.gz: 630f3b9e6e68425badbb430c61e870b6d9a4ff0da74595ef27a1cfabdd54a7fa03d2646f0a03d4abbff48e38eda6dd104ce6893d8f3d610f83bddc2756fd5da0
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
rbimg (0.1.
|
4
|
+
rbimg (0.1.4)
|
5
5
|
byteman (~> 0.1.0)
|
6
6
|
|
7
7
|
GEM
|
8
8
|
remote: https://rubygems.org/
|
9
9
|
specs:
|
10
|
-
byteman (0.1.
|
10
|
+
byteman (0.1.1)
|
11
11
|
coderay (1.1.3)
|
12
|
-
diff-lcs (1.4.
|
12
|
+
diff-lcs (1.4.4)
|
13
13
|
gspec (0.1.3)
|
14
14
|
method_source (1.0.0)
|
15
15
|
pry (0.13.1)
|
@@ -34,7 +34,7 @@ PLATFORMS
|
|
34
34
|
ruby
|
35
35
|
|
36
36
|
DEPENDENCIES
|
37
|
-
byteman (~> 0.1.
|
37
|
+
byteman (~> 0.1.1)
|
38
38
|
gspec (~> 0.1.3)
|
39
39
|
pry (~> 0.13.1)
|
40
40
|
rake (~> 12.0)
|
data/README.md
CHANGED
@@ -4,7 +4,15 @@ Allows simple creation and reading of images (currently only PNG images).
|
|
4
4
|
|
5
5
|
Supports all required chunk types (IHDR, PLTE, IDAT, IEND)
|
6
6
|
|
7
|
-
|
7
|
+
All filtering methods for individual scanlines are supported for reading PNG images, but it will always write with a filtering method of 0 (so re-writing may give you a different format than the original image)
|
8
|
+
|
9
|
+
All bit depths for PNG images are supported. See PNG documentation or source code for specifics (ArgumentError thrown if an incorrect bit depth is used for a specific color type)
|
10
|
+
|
11
|
+
All PNG color types are supported: greyscale, greyscale with alpha, rgb, rgba, and palette. All with their respective bit_depth sizes.
|
12
|
+
|
13
|
+
As of now this gem will be able to retrieve the correct pixel information for all PNG images except for those with an interlace method other than 0, which, as far as I can tell, are most PNG images.
|
14
|
+
|
15
|
+
Non-required chunk types are not currently supported.
|
8
16
|
|
9
17
|
This gem is primarily for simple manipulation of images using pixel data.
|
10
18
|
|
@@ -67,7 +75,7 @@ end
|
|
67
75
|
png = Rbimg::PNG.new(pixels: pixels.flatten, type: :greyscale_alpha, width: 300, height: 500)
|
68
76
|
png.write(path: './greyscale_alpha')
|
69
77
|
```
|
70
|
-
Write a greyscale image from the
|
78
|
+
Write a greyscale image from the MNIST dataset:
|
71
79
|
|
72
80
|
```ruby
|
73
81
|
img_data = File.read("./data/t10k-images-idx3-ubyte").bytes
|
@@ -77,7 +85,7 @@ num_rows = img_data[8...12]
|
|
77
85
|
num_cols = img_data[12...16]
|
78
86
|
pixels = img_data[16...(16 + 784)]
|
79
87
|
png = Rbimg::PNG.new(pixels: pixels, type: :greyscale, width: 28, height: 28)
|
80
|
-
png.write(path: '
|
88
|
+
png.write(path: 'mnist_test')
|
81
89
|
```
|
82
90
|
|
83
91
|
Read a PNG image and get the pixel array from a path
|
@@ -95,6 +103,22 @@ png = Rbimg::PNG.read(data: data)
|
|
95
103
|
puts png.pixels
|
96
104
|
```
|
97
105
|
|
106
|
+
Write a 16-bit-depth rgba image with random colors and alpha:
|
107
|
+
|
108
|
+
```ruby
|
109
|
+
height = 140
|
110
|
+
width = 123
|
111
|
+
r = Random.new
|
112
|
+
pixels = Array.new(3 * width * height) do |i|
|
113
|
+
r.rand(2 ** 16)
|
114
|
+
end
|
115
|
+
|
116
|
+
png = Rbimg::PNG.new(pixels: pixels, type: :rgb, width: width, height: height, bit_depth: 16)
|
117
|
+
png.write(path: "./rgba_16bit")
|
118
|
+
```
|
119
|
+
|
120
|
+
Combine images in rows or columns:
|
121
|
+
|
98
122
|
|
99
123
|
|
100
124
|
## Installation
|
@@ -113,9 +137,7 @@ Or install it yourself as:
|
|
113
137
|
|
114
138
|
$ gem install rbimg
|
115
139
|
|
116
|
-
## Usage
|
117
140
|
|
118
|
-
TODO: Write usage instructions here
|
119
141
|
|
120
142
|
## Development
|
121
143
|
|
@@ -125,6 +147,9 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
|
|
125
147
|
|
126
148
|
## Contributing
|
127
149
|
|
150
|
+
The feature that will make this gem fully-functional for all PNG images is the implementation of interlaced PNGs. Any help is welcomed. This gem was developed using the documentation found and libpng.org/png/spec/1.2
|
151
|
+
Information about interlaced PNGs can be found there.
|
152
|
+
|
128
153
|
Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/rbimg. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/[USERNAME]/rbimg/blob/master/CODE_OF_CONDUCT.md).
|
129
154
|
|
130
155
|
|
data/TODO.md
ADDED
data/lib/image_types/png.rb
CHANGED
@@ -15,17 +15,109 @@ class Rbimg::PNG
|
|
15
15
|
rgba: 6
|
16
16
|
}
|
17
17
|
|
18
|
+
def self.combine(*images, divider: nil, as: :row)
|
19
|
+
raise ArgumentError.new("as: must be :row or :col") if as != :row && as != :col
|
20
|
+
raise ArgumentError.new("Images and divider must all be an Rbimg::PNG") if !images.all?{|i| i.is_a?(Rbimg::PNG)}
|
21
|
+
type = images.first.type
|
22
|
+
height = images.first.height
|
23
|
+
width = images.first.width
|
24
|
+
bit_depth = images.first.bit_depth
|
25
|
+
|
26
|
+
color_type = COLOR_TYPES[type]
|
27
|
+
|
28
|
+
logical_pixel_width = width * Rbimg::PNG.pixel_size_for(color_type: color_type)
|
29
|
+
|
30
|
+
if divider
|
31
|
+
width_multiplier = logical_pixel_width / width
|
32
|
+
divider_width = divider.width * width_multiplier
|
33
|
+
if as == :row
|
34
|
+
raise ArgumentError.new("divider must have the same height as images if aligning as a row") if divider.height != height
|
35
|
+
elsif as == :col
|
36
|
+
raise ArgumentError.new("divider must have the same width as images if aligning as a column") if divider.width != width
|
37
|
+
end
|
38
|
+
raise ArgumentError.new("divider must have the same type and bit_depth as images") if divider.type != type || divider.bit_depth != bit_depth
|
39
|
+
end
|
40
|
+
|
41
|
+
images.each do |i|
|
42
|
+
if i.type != type || i.height != height || i.width != width || i.bit_depth != bit_depth
|
43
|
+
raise ArgumentError.new("Currently all images must have the same type, height, width, and bit_depth to be combined")
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
|
48
|
+
if as == :row
|
49
|
+
new_width = images.length * width
|
50
|
+
new_height = height
|
51
|
+
|
52
|
+
if divider
|
53
|
+
new_width += (divider.width * (images.length - 1))
|
54
|
+
end
|
55
|
+
|
56
|
+
new_pixels = height.times.map do |row|
|
57
|
+
row_start = row * logical_pixel_width
|
58
|
+
divider_row_start = row * divider_width if divider
|
59
|
+
images.map do |img|
|
60
|
+
row_pixels = img.pixels[row_start...(row_start + logical_pixel_width)]
|
61
|
+
((img == images.last) || divider.nil?) ? row_pixels : row_pixels + divider.pixels[divider_row_start...(divider_row_start + divider_width)]
|
62
|
+
end
|
63
|
+
end.flatten
|
64
|
+
|
65
|
+
else
|
66
|
+
new_width = width
|
67
|
+
new_height = images.length * height
|
68
|
+
if divider
|
69
|
+
new_height += (divider.height * (images.length - 1))
|
70
|
+
end
|
71
|
+
|
72
|
+
new_pixels = images.map do |img|
|
73
|
+
img_pixels = img.pixels
|
74
|
+
if divider && img != images.last
|
75
|
+
img_pixels + divider.pixels
|
76
|
+
else
|
77
|
+
img_pixels
|
78
|
+
end
|
79
|
+
end.flatten
|
80
|
+
end
|
81
|
+
|
82
|
+
begin
|
83
|
+
new_img = Rbimg::PNG.new(pixels: new_pixels, type: type, width: new_width, height: new_height, bit_depth: bit_depth)
|
84
|
+
rescue
|
85
|
+
binding.pry
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
89
|
+
|
90
|
+
def self.pixel_size_for(color_type:)
|
91
|
+
case color_type
|
92
|
+
when 0
|
93
|
+
1
|
94
|
+
when 2
|
95
|
+
3
|
96
|
+
when 3
|
97
|
+
1
|
98
|
+
when 4
|
99
|
+
2
|
100
|
+
when 6
|
101
|
+
4
|
102
|
+
else
|
103
|
+
raise ArgumentError.new("#{color_type} is not a valid color type. Must be 0,2,3,4, or 6")
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
18
107
|
def self.read(path: nil, data: nil)
|
19
108
|
|
20
109
|
raise ArgumentError.new(".read must be initialized with a path or a datastream") if (path.nil? && data.nil?) || (!path.nil? && !data.nil?)
|
21
110
|
raise ArgumentError.new("data must be an array of byte integers or a byte string") if data && !data.is_a?(Array) && !data.is_a?(String)
|
22
111
|
raise ArgumentError.new("data must be an array of byte integers or a byte string") if data && data.is_a?(Array) && !data.first.is_a?(Integer)
|
112
|
+
path += ".png" if path && !path.end_with?('.png')
|
23
113
|
begin
|
114
|
+
|
24
115
|
if path
|
25
116
|
data = File.read(path).bytes
|
26
117
|
else
|
27
118
|
data = data.bytes if data.is_a?(String)
|
28
119
|
end
|
120
|
+
|
29
121
|
chunk_start = 8
|
30
122
|
chunks = []
|
31
123
|
loop do
|
@@ -46,6 +138,7 @@ class Rbimg::PNG
|
|
46
138
|
end
|
47
139
|
|
48
140
|
chunk_start = chunk_end
|
141
|
+
#TODO: Make sure last chunk is IEND
|
49
142
|
break if chunk_end >= data.length - 1
|
50
143
|
|
51
144
|
end
|
@@ -57,40 +150,125 @@ class Rbimg::PNG
|
|
57
150
|
compression_method = chunks.first[:compression_method]
|
58
151
|
filter_method = chunks.first[:filter_method]
|
59
152
|
interlace_method = chunks.first[:interlace_method]
|
153
|
+
|
60
154
|
all_idats = chunks.filter{ |c| c.is_a?(Hash) && c[:type] == "IDAT" }
|
61
|
-
compressed_pixels = all_idats.reduce([]){ |mem, idat| mem + idat[:compressed_pixels] }
|
155
|
+
compressed_pixels = all_idats.reduce([]) { |mem, idat| mem + idat[:compressed_pixels] }
|
62
156
|
pixels_and_filter = Zlib::Inflate.inflate(compressed_pixels.pack("C*")).unpack("C*")
|
157
|
+
|
63
158
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
159
|
+
logical_pixel_width = Rbimg::PNG.pixel_size_for(color_type: color_type) * width
|
160
|
+
|
161
|
+
pixel_width = (logical_pixel_width * (bit_depth / 8.0)).ceil
|
162
|
+
|
163
|
+
|
164
|
+
scanline_filters = Array.new(height, nil)
|
165
|
+
pixels = Array.new(pixels_and_filter.length - height, nil)
|
166
|
+
|
167
|
+
pixels_and_filter.each.with_index do |pixel,i|
|
168
|
+
scanline = i / (pixel_width + 1)
|
169
|
+
pixel_number = (i % (pixel_width + 1)) - 1
|
170
|
+
pixel_loc = scanline * pixel_width + pixel_number
|
171
|
+
if (pixel_number == -1)
|
172
|
+
scanline_filters[scanline] = pixel
|
173
|
+
else
|
174
|
+
case scanline_filters[scanline]
|
175
|
+
when 0
|
176
|
+
pixels[pixel_loc] = pixel
|
177
|
+
when 1
|
178
|
+
x = pixel_number
|
179
|
+
bpp = (pixel_width / width) * (bit_depth / 8.0).ceil
|
180
|
+
prev_raw = x - bpp < 0 ? 0 : pixels[pixel_loc - bpp]
|
181
|
+
new_pixel = (pixel + prev_raw) % 256
|
182
|
+
pixels[pixel_loc] = new_pixel
|
183
|
+
when 2
|
184
|
+
x = pixel_number
|
185
|
+
prev_raw = scanline == 0 ? 0 : pixels[pixel_loc - pixel_width]
|
186
|
+
new_pixel = (pixel + prev_raw) % 256
|
187
|
+
pixels[pixel_loc] = new_pixel
|
188
|
+
when 3
|
189
|
+
x = pixel_number
|
190
|
+
bpp = (pixel_width / width) * (bit_depth / 8.0).ceil
|
191
|
+
left_pix = x - bpp < 0 ? 0 : pixels[pixel_loc - bpp]
|
192
|
+
above_pix = scanline == 0 ? 0 : pixels[pixel_loc - pixel_width]
|
193
|
+
new_pixel = (pixel + ((left_pix + above_pix) / 2).floor) % 256
|
194
|
+
pixels[pixel_loc] = new_pixel
|
195
|
+
when 4
|
196
|
+
x = pixel_number
|
197
|
+
bpp = (pixel_width / width) * (bit_depth / 8.0).ceil
|
198
|
+
|
199
|
+
paeth_predictor = Proc.new do |left, above, upper_left|
|
200
|
+
p = left + above - upper_left
|
201
|
+
pa = (p - left).abs
|
202
|
+
pb = (p - above).abs
|
203
|
+
pc = (p - upper_left).abs
|
204
|
+
if pa <= pb && pa <= pc
|
205
|
+
left
|
206
|
+
elsif pb <= pc
|
207
|
+
above
|
208
|
+
else
|
209
|
+
upper_left
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
left_pix = x - bpp < 0 ? 0 : pixels[pixel_loc - bpp]
|
214
|
+
above_pix = scanline == 0 ? 0 : pixels[pixel_loc - pixel_width]
|
215
|
+
upper_left_pix = scanline == 0 ? 0 : x - bpp < 0 ? 0 : pixels[pixel_loc - pixel_width - bpp]
|
216
|
+
pp_out = paeth_predictor[left_pix, above_pix, upper_left_pix]
|
217
|
+
new_pixel = (pixel + pp_out) % 256
|
218
|
+
pixels[pixel_loc] = new_pixel
|
219
|
+
else
|
220
|
+
raise Rbimg::FormatError.new("Incorrect Filtering type used on this PNG file")
|
221
|
+
end
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
|
226
|
+
|
227
|
+
|
228
|
+
if bit_depth != 8
|
229
|
+
corrected_pixels = Array.new(logical_pixel_width * height, nil)
|
230
|
+
height.times do |row_num|
|
231
|
+
row_start = row_num * pixel_width
|
232
|
+
row_end = row_start + pixel_width
|
233
|
+
row_data = pixels[row_start...row_end]
|
234
|
+
binary_data = Byteman.buf2int(row_data).to_s(2)
|
235
|
+
pad_size = ((logical_pixel_width * bit_depth) / 8.0).ceil * 8
|
236
|
+
binary_data = Byteman.pad(num: binary_data, len: pad_size, type: :bits)
|
237
|
+
corrected_row_start = row_num * logical_pixel_width
|
238
|
+
logical_pixel_width.times do |pixel_num_in_row|
|
239
|
+
binary_segment_start = pixel_num_in_row * bit_depth
|
240
|
+
binary_segment_end = binary_segment_start + bit_depth
|
241
|
+
binary_segment = binary_data[binary_segment_start...binary_segment_end]
|
242
|
+
logical_pixel_value = binary_segment.to_i(2)
|
243
|
+
corrected_pixel_location = corrected_row_start + pixel_num_in_row
|
244
|
+
corrected_pixels[corrected_pixel_location] = logical_pixel_value
|
245
|
+
end
|
246
|
+
end
|
75
247
|
else
|
76
|
-
|
248
|
+
corrected_pixels = pixels
|
77
249
|
end
|
78
|
-
|
79
|
-
args = {pixels:
|
250
|
+
|
251
|
+
args = {pixels: corrected_pixels, type: color_type, width: width, height: height, bit_depth: bit_depth}
|
80
252
|
plte = chunks.find{|c| c[:type] == "PLTE" unless c.is_a?(Array)}
|
81
253
|
args[:palette] = plte[:chunk_data] if plte
|
82
254
|
new(**args)
|
83
|
-
rescue
|
84
|
-
raise
|
255
|
+
rescue Errno::ENOENT => e
|
256
|
+
raise ArgumentError.new("Invalid path #{path}")
|
257
|
+
rescue => e
|
258
|
+
raise e if e.is_a?(Rbimg::FormatError)
|
259
|
+
raise Rbimg::FormatError.new("This PNG file is not in the correct format or has been corrupted :)")
|
85
260
|
end
|
86
261
|
end
|
87
262
|
|
263
|
+
|
88
264
|
|
89
265
|
attr_reader :pixels, :width, :height, :bit_depth, :compression_method, :filter_method, :interlace_method
|
90
|
-
|
91
|
-
def initialize(pixels: nil, type: nil, width: , height: , bit_depth: 8, compression_method: 0, filter_method: 0, interlace_method: 0, palette: nil)
|
266
|
+
attr_reader :pixel_size
|
267
|
+
def initialize(pixels: nil, type: nil, width: nil, height: nil, bit_depth: 8, compression_method: 0, filter_method: 0, interlace_method: 0, palette: nil)
|
92
268
|
@pixels, @width, @height, @compression_method, @filter_method, @interlace_method = pixels, width, height, compression_method, filter_method, interlace_method
|
93
269
|
@bit_depth = bit_depth
|
270
|
+
type = :greyscale if type.nil?
|
271
|
+
|
94
272
|
@type = type.is_a?(Integer) ? type : COLOR_TYPES[type]
|
95
273
|
raise ArgumentError.new("#{type} is not a valid color type. Please use one of: #{COLOR_TYPES.keys}") if type.nil?
|
96
274
|
raise ArgumentError.new("Palettes are not compatible with color types 0 and 4") if palette && (@type == 0 || @type == 4)
|
@@ -117,8 +295,25 @@ class Rbimg::PNG
|
|
117
295
|
]
|
118
296
|
@chunks.insert(1, Chunk.PLTE(palette)) if !palette.nil?
|
119
297
|
|
298
|
+
@pixel_size = Rbimg::PNG.pixel_size_for(color_type: @type)
|
299
|
+
|
300
|
+
end
|
301
|
+
|
302
|
+
def pixel(num)
|
303
|
+
start = num * @pixel_size
|
304
|
+
pend = start + @pixel_size
|
305
|
+
pixels[start...pend]
|
120
306
|
end
|
121
307
|
|
308
|
+
def row(rownum)
|
309
|
+
return nil if rownum > self.height
|
310
|
+
pix_width = pixel_size * width
|
311
|
+
start = rownum * pix_width
|
312
|
+
pend = start + pix_width
|
313
|
+
pixels[start...pend]
|
314
|
+
end
|
315
|
+
|
316
|
+
|
122
317
|
def type
|
123
318
|
COLOR_TYPES.each do |k,v|
|
124
319
|
return k if v == @type
|
@@ -134,6 +329,8 @@ class Rbimg::PNG
|
|
134
329
|
File.write(path + postscript, bytes)
|
135
330
|
end
|
136
331
|
|
332
|
+
|
333
|
+
|
137
334
|
private
|
138
335
|
|
139
336
|
def all_data
|
@@ -196,7 +393,7 @@ class Rbimg::PNG
|
|
196
393
|
test_length(width)
|
197
394
|
test_length(height)
|
198
395
|
raise ArgumentError.new('Color code types must be 0, 2, 3, 4, or 6') if ![0,2,3,4,6].include?(color_type)
|
199
|
-
raise ArgumentError.new(
|
396
|
+
raise ArgumentError.new("Bit depth must be related to color_type as such: color_value => bit_depth_options: #{bit_depth_rules}") if !bit_depth_rules[color_type].include?(bit_depth)
|
200
397
|
|
201
398
|
|
202
399
|
wbytes = Byteman.pad(len: 4, num: Byteman.int2buf(width))
|
@@ -247,21 +444,35 @@ class Rbimg::PNG
|
|
247
444
|
|
248
445
|
case bit_depth
|
249
446
|
when 1
|
250
|
-
|
447
|
+
raise ArgumentError.new("If bit depth is 1, all pixel values must be a 1 or 0") if bit_strm.any?{ |b| b != 0 && b != 1 }
|
448
|
+
bits = bit_strm.join('') + ("0" * ((-1 * bit_strm.length % 8) % 8 ))
|
449
|
+
Byteman.hex(0) + Byteman.pad(num: Byteman.hex(bits.to_i(2)), len: bits.length / 8)
|
251
450
|
when 2
|
252
|
-
|
253
|
-
|
254
|
-
|
451
|
+
bits = bit_strm.map do |b|
|
452
|
+
raise ArgumentError.new("If bit depth is 2, all pixel values must be between 0 and 3") if !b.between?(0,3)
|
453
|
+
Byteman.pad(num: b, len: 2, type: :bits)
|
454
|
+
end.join('')
|
455
|
+
padded_bits = bits + ("0" * ((-1 * bit_strm.length * 2) % 8) % 8)
|
456
|
+
Byteman.hex(0) + Byteman.pad(num: Byteman.hex(padded_bits.to_i(2)), len: padded_bits.length / 8)
|
457
|
+
when 4
|
458
|
+
bits = bit_strm.map do |b|
|
459
|
+
raise ArgumentError.new("If bit depth is 4, all pixel values must be between 0 and 15") if !b.between?(0,15)
|
460
|
+
Byteman.pad(num: b, len: 4, type: :bits)
|
461
|
+
end.join('')
|
462
|
+
padded_bits = bits + ("0" * ((-1 * bit_strm.length * 4) % 8) % 8)
|
463
|
+
Byteman.hex(0) + Byteman.pad(num: Byteman.hex(padded_bits.to_i(2)), len: padded_bits.length / 8)
|
255
464
|
when 8
|
465
|
+
raise ArgumentError.new("If bit depth is 8, all pixel values must be between 0 and 255") if bit_strm.any?{|b| !b.between?(0,255)}
|
256
466
|
([0] + bit_strm).pack("C*")
|
257
467
|
when 16
|
258
|
-
(
|
468
|
+
raise ArgumentError.new("If bit depth is 16, all pixel values must be between 0 and 65535") if bit_strm.any?{|b| !b.between?(0,65535)}
|
469
|
+
Byteman.hex(0) + bit_strm.map{|b| Byteman.pad(num: Byteman.hex(b), len: 2)}.join('')
|
259
470
|
else
|
260
471
|
ArgumentError.new("bit_depth can only be 1,2,4,8, or 16 bits")
|
261
472
|
end
|
262
473
|
|
263
474
|
end
|
264
|
-
|
475
|
+
|
265
476
|
z = Zlib::Deflate.new(Zlib::BEST_COMPRESSION, Zlib::MAX_WBITS, Zlib::MAX_MEM_LEVEL, Zlib::RLE)
|
266
477
|
zstrm = z.deflate(scanlines.join(''), Zlib::FINISH)
|
267
478
|
z.close
|
@@ -317,4 +528,7 @@ class Rbimg::PNG
|
|
317
528
|
|
318
529
|
end
|
319
530
|
|
531
|
+
|
532
|
+
|
533
|
+
|
320
534
|
end
|
data/lib/rbimg.rb
CHANGED
data/lib/rbimg/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rbimg
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- micahshute
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-07-
|
11
|
+
date: 2020-07-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: byteman
|
@@ -42,6 +42,7 @@ files:
|
|
42
42
|
- LICENSE.txt
|
43
43
|
- README.md
|
44
44
|
- Rakefile
|
45
|
+
- TODO.md
|
45
46
|
- bin/console
|
46
47
|
- bin/setup
|
47
48
|
- lib/errors/crc_error.rb
|