rbimg 0.1.3 → 0.1.4
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/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
|