rubyvision 0.0.1 → 0.0.2

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.
Files changed (4) hide show
  1. checksums.yaml +4 -4
  2. data/lib/bmp.rb +440 -14
  3. data/lib/image.rb +32 -5
  4. metadata +1 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0edb9ddbd0fc80f58952cda8b11faaf414fd5685ef8e02674f1ea3012fd5b7f6
4
- data.tar.gz: 9d5b60522d9dbb51c1367bf2876669e0dc6ecd1ca7b676cee8282f9407438988
3
+ metadata.gz: 711a7460a9ce2a1d29b05cbef6308f89bcf9c1342569e2bd220dceb5cd9d994f
4
+ data.tar.gz: db8b35869280ccba041ea522e13ce9f8763b035569c0dff917929cb580ffe26d
5
5
  SHA512:
6
- metadata.gz: 6e9fe8189ea617eb509b553cae98323304a511a7c73bfe34133aafd189d1cd92d8bcb1bb2c4634eb753fa933441533bf90065184b60a36e42cf083d80727fa5c
7
- data.tar.gz: 1388b8be8c3801919c5c8379bb103baff8d97062ac8c35e4e3aa8fbb5580670637b416929316be8c4534092f7915b804157c90adf16eb5a3dbff4b8d5a311390
6
+ metadata.gz: e224d265d47f076330244b5c4f82b57eae5f0f6e2b9e9090f591ba19769068c3baaf6d353afdade92f5807c7c8d80b4d0e723d24cbedddce5f362a7c67a7b4a5
7
+ data.tar.gz: ece340328b54864ebf17613c8ec302c88d569c81152599a5a7f92052a62939e77b72eb64c9ba5ebecc9d418225b26173a349eade11eebb3fa87523892c65d5db
data/lib/bmp.rb CHANGED
@@ -1,58 +1,484 @@
1
1
  # Language: Ruby, Level: Level 3
2
-
2
+ # frozen_string_literal: true
3
3
  require 'set'
4
4
 
5
- class Bmp
6
- def initialize(path)
7
-
8
- end
5
+ # This class contains the methods to read bmp files
6
+ # It supports 1,2,4,8,16,24 bits per pixel and RLE compression
9
7
 
10
- def readbmp(path) #returns an image object
8
+ class Bmp
9
+ # getters
11
10
 
11
+ def initialize(path)
12
+ puts "Inside bmp constructor"
13
+ file_descriptor = IO.sysopen(path)
14
+ @raw_data = IO.new(file_descriptor)
15
+ @signature = @raw_data.sysread(2)
16
+ @size = @raw_data.sysread(4).unpack('L')[0] # Because little endian format
17
+ @raw_data.sysseek(10)
18
+ @offset = @raw_data.sysread(4).unpack('L')[0]
19
+ @info_header_size = @raw_data.sysread(4).unpack('L')[0]
20
+ @width = @raw_data.sysread(4).unpack('L')[0]
21
+ @height = @raw_data.sysread(4).unpack('L')[0]
22
+ @planes = @raw_data.sysread(2).unpack('S')[0]
23
+ @bits_per_pixel = @raw_data.sysread(2).unpack('S')[0]
24
+ @numcolors = 2**@bits_per_pixel
25
+ @compression = @raw_data.sysread(4).unpack('L')[0]
26
+ @compressed_size = @raw_data.sysread(4).unpack('L')[0]
27
+ @x_pixels_per_m = @raw_data.sysread(4).unpack('L')[0]
28
+ @y_pixels_per_m = @raw_data.sysread(4).unpack('L')[0]
29
+ @colors_used = @raw_data.sysread(4).unpack('L')[0]
30
+ @num_of_imp_colors = @raw_data.sysread(4).unpack('L')[0]
31
+ read_to_palette if @bits_per_pixel <= 8
32
+ read_masks if @bits_per_pixel >= 16
33
+ puts @raw_data.pos.to_s
12
34
  end
13
35
 
14
36
  def read_to_palette
15
-
37
+ @palette = []
38
+ (1..@colors_used).each do |i|
39
+ b = @raw_data.sysread(1).unpack('C')[0]
40
+ g = @raw_data.sysread(1).unpack('C')[0]
41
+ r = @raw_data.sysread(1).unpack('C')[0]
42
+ temp = @raw_data.sysread(1).unpack('C')
43
+ @palette[i - 1] = [b, g, r]
44
+ #puts "#{r},#{g},#{b}"
45
+ end
46
+ #IO.write("results/palette.txt", @palette.join("\n"))
16
47
  end
17
-
48
+ attr_reader :width
49
+ attr_reader :height
18
50
  def read_masks
19
-
51
+ if @compression != 0
52
+ @redmask = @raw_data.sysread(4).unpack('N')[0]
53
+ @greenmask = @raw_data.sysread(4).unpack('N')[0]
54
+ @bluemask = @raw_data.sysread(4).unpack('N')[0]
55
+ @alphachannel = @raw_data.sysread(4).unpack('N')[0]
56
+ end
20
57
  end
21
58
 
22
59
  def describe
23
-
60
+ puts 'Header Data'
61
+ puts "Signature: #{@signature}"
62
+ puts "Size: #{@size}"
63
+ puts "Offset: #{@offset}"
64
+ puts 'InfoHeader Data'
65
+ puts "Infoheader size: #{@info_header_size}"
66
+ puts "Width: #{@width}"
67
+ puts "Height: #{@height}"
68
+ puts "Planes: #{@planes}"
69
+ puts "Bits per pixel = #{@bits_per_pixel}"
70
+ puts "Compression: #{@compression}"
71
+ if @compression.zero?
72
+ puts 'Compression: None'
73
+ elsif @compression == 1
74
+ puts 'Compression: BI_RLE8 8 bit encoding'
75
+ elsif @compression == 2
76
+ puts 'Compression: BI_RLE4 4 bit encoding'
77
+ elsif @compression == 3
78
+ puts 'Compression: BI_BITFIELDS'
79
+ end
80
+ puts "Compressed image size: #{@compressed_size}"
81
+ puts "Pixel density on x-axis (per m): #{@x_pixels_per_m}"
82
+ puts "Pixel density on y-axis (per m): #{@y_pixels_per_m}"
83
+ puts "Used colors (in color palette): #{@colors_used}"
84
+ puts "Number of important colors: #{@num_of_imp_colors} (0 if all are important)"
24
85
  end
25
86
 
26
87
  def read_to_array
88
+ @raw_data.sysseek(@offset)
89
+ a = Array.new(@height)
27
90
 
91
+ if @bits_per_pixel <= 8
92
+ a = read_from_palette
93
+ elsif @bits_per_pixel > 8
94
+ a = read_from_pixel_array
95
+ # puts "Location of pointer after reading: #{@raw_data.pos}"
96
+ end
97
+
98
+ a
28
99
  end
29
100
 
30
101
  def read_from_palette
102
+ a = Array.new(@height)
103
+ if @bits_per_pixel == 1
104
+ row_length = ((@width / 32).floor * 32 + 32) / 8
105
+ (1..@height).each do |i|
106
+ colors = []
107
+ row_length_data = ''
108
+ (1..row_length).each do
109
+ row_length_data += @raw_data.sysread(1).unpack('C')[0].to_s
110
+ end
111
+ (1..@width).each do |j|
112
+ colors[j - 1] = @palette[row_length_data[j].to_i]
113
+ end
114
+ a[@height - i] = colors
115
+ end
116
+ elsif @bits_per_pixel == 2
117
+ (1..@height).each do |i|
118
+ row_array = []
119
+ row_length = ((@width / 32).floor * 32 + 32) / 8
120
+ count = 0
121
+ (1..row_length).each do |_j|
122
+ break if count > @width
123
+
124
+ byteval = @raw_data.sysread(1).unpack('C')[0]
125
+ fourth = byteval & 3
126
+ byteval >> 2
127
+ third = byteval & 3
128
+ byteval >> 2
129
+ second = byteval & 3
130
+ byteval >> 2
131
+ first = byteval
132
+ row_array.push(@palette[first])
133
+ count += 1
134
+ break if count >= @width
135
+
136
+ row_array.push(@palette[second])
137
+ count += 1
138
+ break if count >= @width
139
+
140
+ row_array.push(@palette[third])
141
+ count += 1
142
+ break if count >= @width
143
+
144
+ row_array.push(@palette[fourth])
145
+ count += 1
146
+ break if count >= @width
147
+ end
148
+ a[@height - i] = row_array
149
+ end
150
+ elsif @bits_per_pixel == 4
151
+ if @compression != 0
152
+ a = decompress_RLE4
153
+ return a
154
+ end
155
+ (1..@height).each do |i|
156
+ row_array = []
157
+ row_length = ((@width * 4 / 32).floor * 32 + 32) / 8
158
+ count = 0
159
+ (1..row_length).each do |_j|
160
+ break if count >= @width
161
+
162
+ byteval = @raw_data.sysread(1).unpack('C')[0]
163
+ second = byteval & 15
164
+ byteval >> 4
165
+ first = byteval
166
+ row_array.push(@palette[first])
167
+ count += 1
168
+ break if count >= @width
31
169
 
170
+ row_array.push(@palette[second])
171
+ count += 1
172
+ end
173
+ a[@height - i] = row_array
174
+ end
175
+ elsif @bits_per_pixel == 8
176
+ if @compression != 0
177
+ a = decompress_RLE8
178
+ return a
179
+ end
180
+ (1..@height).each do |i|
181
+ row_array = Array.new(@width)
182
+ (1..@width).each do |j|
183
+ row_array[j - 1] = @palette[@raw_data.sysread(1).unpack('C')[0]]
184
+ end
185
+ @raw_data.sysread((@width * 3) % 4) # zeros are appended to rows of pixels if the image width is not a multiple of 4, this ignores them.
186
+ a[@height - i] = row_array
187
+ end
188
+ end
189
+ a
32
190
  end
33
191
 
34
192
  def decompress_RLE4
193
+ a = Array.new(height)
194
+ (1..@height).each do |j|
195
+ i = 0
196
+ row_array = []
197
+ len = 0
198
+ loop do
35
199
 
36
- end
200
+ first_byte = @raw_data.sysread(1).unpack('C')[0]
201
+ second_byte = @raw_data.sysread(1).unpack('C')[0]
202
+ if first_byte != 0
203
+ pixel_two = second_byte & 15
204
+ pixel_one = second_byte >> 4
205
+ rolling_array = [pixel_one, pixel_two]
206
+ k = 0
207
+ (1..first_byte).each do
208
+ row_array.push(@palette[rolling_array[k]])
209
+ k = k ^ 1
210
+ len += 1
211
+ end
212
+ elsif second_byte > 2
213
+ sz = (((second_byte + 1)>>1) + 1) & (~1)
214
+ if second_byte%2 == 1
215
+ temp = 0
216
+ (1..sz).each do
217
+ len += 2
218
+ two_pixels = @raw_data.sysread(1).unpack('C')[0]
219
+ pixel_two = two_pixels & 15
220
+ pixel_one = two_pixels >> 4
221
+ if temp<second_byte
222
+ row_array.push(@palette[pixel_one])
223
+ temp += 1
224
+ end
225
+ if temp<second_byte
226
+ row_array.push(@palette[pixel_two])
227
+ temp += 1
228
+ end
229
+ end
230
+ else
231
+ (1..sz).each do
232
+ len += 2
233
+ two_pixels = @raw_data.sysread(1).unpack('C')[0]
234
+ pixel_two = two_pixels & 15
235
+ pixel_one = two_pixels >> 4
236
+ row_array.push(@palette[pixel_one])
237
+ row_array.push(@palette[pixel_two])
238
+ end
239
+ end
240
+ elsif second_byte == 1
241
+ break
242
+ end
243
+ break if len >= @width
37
244
 
245
+ end
246
+ a[@height - j] = row_array
247
+ end
248
+ puts @raw_data.pos.to_s
249
+ return a
250
+ end
38
251
 
39
252
  def decompress_RLE8
253
+ a = Array.new(@height)
254
+ @raw_data.sysseek(@offset)
255
+ (1..@height).each do |j|
256
+ i = 0
257
+ row_array = []
258
+ len = 0
259
+ loop do
260
+
261
+ first_byte = @raw_data.sysread(1).unpack('C')[0]
262
+ second_byte = @raw_data.sysread(1).unpack('C')[0]
263
+ if first_byte != 0
264
+ (1..first_byte).each do
265
+ row_array.push(@palette[second_byte])
266
+ len += 1
267
+ end
268
+ elsif second_byte > 2
269
+ sz = (second_byte+1) & (~1)
270
+
271
+ if second_byte %2 ==1
272
+ (1..(sz-1)).each do
273
+ len += 1
274
+ pixel_val = @raw_data.sysread(1).unpack('C')[0]
275
+ row_array.push(@palette[pixel_val])
276
+ end
277
+ garbage = @raw_data.sysread(1).unpack('C')[0]
278
+ else
279
+ (1..sz).each do
280
+ len += 1
281
+ pixel_val = @raw_data.sysread(1).unpack('C')[0]
282
+ row_array.push(@palette[pixel_val])
283
+ end
284
+ end
285
+ elsif second_byte == 1
286
+ #break
287
+ elsif second_byte == 2
288
+ puts "Error"
289
+ end
290
+ break if len >= @width
40
291
 
292
+ end
293
+ a[@height - j] = row_array
294
+ end
295
+
296
+ return a
41
297
  end
42
298
 
43
299
  def read_from_pixel_array
300
+ a = Array.new(@height)
301
+ if @bits_per_pixel == 16 # works for rgb555 format, not rgb565
302
+ (1..@height).each do |i|
303
+ row_array = Array.new(@width)
304
+ (1..@width).each do |j|
305
+ bindata = @raw_data.sysread(2).unpack('S')[0]
306
+ #bindata = bindata>>1
307
+ b = (bindata<<3) & 0xf8
308
+
309
+ g = (bindata>>2) & 0xf8
310
+ #bindata = bindata >> 6
311
+ r = (bindata>>7) & 0xf8
312
+ row_array[j - 1] = [b, g, r]
313
+ end
314
+ @raw_data.sysread((@width * 3) % 4) # zeros are appended to rows of pixels if the image width is not a multiple of 4, this ignores them.
315
+ a[@height - i] = row_array
316
+ end
44
317
 
318
+ elsif @bits_per_pixel == 24
319
+ (1..@height).each do |i|
320
+ row_array = Array.new(@width)
321
+ (1..@width).each do |j|
322
+ b = @raw_data.sysread(1).unpack('C')[0]
323
+ g = @raw_data.sysread(1).unpack('C')[0]
324
+ r = @raw_data.sysread(1).unpack('C')[0]
325
+ row_array[j - 1] = [b, g, r]
326
+ end
327
+ @raw_data.sysread((@width * 3) % 4) # zeros are appended to rows of pixels if the image width is not a multiple of 4, this ignores them.
328
+ a[@height - i] = row_array
329
+ end
330
+ elsif @bits_per_pixel == 32 # not tested with an image yet, maybe order of colors is wrong
331
+ (1..@height).each do |i|
332
+ row_array = Array.new(@width)
333
+ (1..@width).each do |j|
334
+ b = @raw_data.sysread(1).unpack('C')[0]
335
+ g = @raw_data.sysread(1).unpack('C')[0]
336
+ r = @raw_data.sysread(1).unpack('C')[0]
337
+ alpha = @raw_data.sysread(1).unpack('C')[0]
338
+ row_array[j - 1] = [ b, g, r, alpha] # should be changed based on requirement
339
+ end
340
+ @raw_data.sysread((@width * 3) % 4) # zeros are appended to rows of pixels if the image width is not a multiple of 4, this ignores them.
341
+ a[@height - i] = row_array
342
+ end
343
+ end
344
+ a
45
345
  end
346
+ # will do once the bug is fixed
46
347
 
348
+ def read_to_nmatrix
349
+ result = [] # NMatrix.new([3, 3],dtype: :int64)
350
+ result
351
+ end
47
352
 
353
+ def self.populate_colors(array)
354
+ colors = Hash.new
355
+ height = array.length
356
+ #raise exception if empty array
357
+ width = array[0].length
358
+ index = 0
359
+ #creating a hashmap of unique colors for palette
360
+ (1...height).each do |i|
361
+ (1...width).each do |j|
362
+ #debug
363
+ #if(array[i][j].class.to_s != "Array")
364
+ # puts "******"
365
+ # puts array[i][j]
366
+ # puts i
367
+ # puts j
368
+ # puts "******"
369
+ #end
370
+ if(colors.key?(array[i][j]))
371
+ next
372
+ else
373
+ colors.store(array[i][j], index)
374
+ index += 1
375
+ end
376
+ if(index > 255)
377
+ print "ERROR"
378
+ return
379
+ #raise exception
48
380
 
49
- def populate_colors(array)
50
- #creates palette, useful while writing image
381
+ end
382
+ end
383
+ end
384
+ colors
51
385
  end
52
386
 
53
- def write_to_bmp(name, array, bpp, compression_type)
387
+ def self.write_to_bmp(name, array, bpp, compression_type)
388
+ height = array.length
389
+ #raise exception if empty array
390
+ width = array[0].length
391
+ filestep = ((width*3 + 3) & -(4))
392
+ zeropad = "\0\0\0\0"
393
+ bmp_header_size = 40
394
+
395
+ if(bpp<=8)
396
+ palette_size = 1024
397
+ header_size = 14 + bmp_header_size + palette_size
398
+ ############
399
+ colors = populate_colors(array)
400
+
401
+ (1..colors.length).each do |i|
402
+ puts colors.keys[i-1].length
54
403
 
404
+ end
405
+ ####debug###
406
+ #IO.write("palette2.txt", colors)
407
+ ############
408
+ file_size = height*filestep
409
+
410
+ fileEntity = File.new(name, "w")
411
+ if fileEntity
412
+ size = [file_size+header_size]
413
+ offset = [54+1024]
414
+ x_pixels_per_m = 2000
415
+ y_pixels_per_m = 2000
416
+ fileEntity.syswrite([19778].pack('S')) #signature - "BM"
417
+ fileEntity.syswrite(size.pack('L')) #size
418
+ fileEntity.syswrite([0].pack('L')) #random 4 bytes ###check if accounting for palette
419
+ fileEntity.syswrite(offset.pack('L')) #offset
420
+ fileEntity.syswrite([bmp_header_size].pack('L')) #header size
421
+ fileEntity.syswrite([width].pack('L')) #width
422
+ fileEntity.syswrite([height].pack('L')) #height
423
+ fileEntity.syswrite([1].pack('S')) #planes
424
+ fileEntity.syswrite([bpp].pack('S')) #bits per pixel
425
+ fileEntity.syswrite([compression_type].pack('L')) #compression
426
+ fileEntity.syswrite([0].pack('L')) #compressed size
427
+ fileEntity.syswrite([x_pixels_per_m].pack('L')) #x_pixels_per_m
428
+ fileEntity.syswrite([y_pixels_per_m].pack('L')) #y_pixels_per_m
429
+ fileEntity.syswrite([0].pack('L')) #number of important colors
430
+ fileEntity.syswrite([0].pack('L')) #number of important colors
431
+ (1..colors.length).each do |i| #writes palette
432
+ fileEntity.syswrite([colors.keys[i-1][0]].pack('C')) #b
433
+ fileEntity.syswrite([colors.keys[i-1][1]].pack('C')) #g
434
+ fileEntity.syswrite([colors.keys[i-1][2]].pack('C')) #r
435
+ #fileEntity.syswrite([colors.keys[i-1][3]].pack('C'))
436
+ fileEntity.syswrite([0].pack('C')) #random
437
+ end
438
+ (1..547).each do |i| #writes palette
439
+ fileEntity.syswrite([0].pack('C')) #random
440
+ end
441
+ #starts writing the pixel info
442
+ (1...height).each do |i|
443
+ (1...width).each do |j|
444
+ fileEntity.syswrite([colors[array[height-i][j-1]]].pack('C'))
445
+
446
+ end
447
+ (1..((width*2) % 4)).each do
448
+ fileEntity.syswrite([0].pack('C'))
449
+ end
450
+ end
451
+ fileEntity.syswrite([0].pack('C'))
452
+ fileEntity.syswrite([1].pack('C'))
453
+ end
454
+ print "Successfully created bmp file"
455
+ else
456
+
457
+ end
55
458
 
56
459
  end
57
460
 
58
461
  end
462
+
463
+ #x.printcolors()
464
+
465
+
466
+
467
+ #x = Bmp.new('new8.bmp') # enter local path
468
+ #x.describe
469
+
470
+ ##puts pixels.length
471
+ #puts pixels[0].length
472
+ # prints the array
473
+ #IO.write("results/image.txt", pixels.join("\n"))
474
+ #(1..x.height).each do |i|
475
+ # #puts "#{i}: ****" # Row number
476
+ # (1..x.width).each do |j|
477
+ # #print pixels[i - 1][j - 1] # [B G R]
478
+ # #print " "
479
+ # end
480
+ #puts '****'
481
+ #end
482
+ #x.describe
483
+ #puts pixels.length
484
+ #puts pixels[62].length
@@ -4,19 +4,46 @@
4
4
  require 'bmp'
5
5
  class Image
6
6
  attr_reader :data, :height, :width, :channels
7
- def initialize()
8
- @data = []
9
- @height = 0
10
- @width = 0
11
- @channels = 0
7
+ def initialize(path)
8
+ @data = read(path)
12
9
  end
13
10
 
14
11
  def read(path)
12
+ is_bmp = 1
13
+ if(is_bmp)
14
+ bmp_instance = Bmp.new(path)
15
15
 
16
+ a = bmp_instance.read_to_array
17
+ bmp_instance.describe
18
+ @height = bmp_instance.height
19
+ @width = bmp_instance.width
20
+ #@channels = a[0][0].length
21
+ end
22
+ a
16
23
  end
17
24
 
18
25
  def write(path)
26
+ is_bmp = true
27
+ if(is_bmp)
28
+ a = Bmp.write_to_bmp(path,@data,8,0)
29
+ end
19
30
  end
20
31
 
21
32
 
22
33
  end
34
+
35
+ #DEBug
36
+ #x = Image.new('/home/harsha/imgp/librepo/rubyvision/test/rgb24.bmp')
37
+ #puts x.data.length
38
+ #puts x.data[0].length
39
+ # prints the array
40
+ #IO.write("results/image.txt", pixels.join("\n"))
41
+ #(1..x.height).each do |i|
42
+ # puts "#{i}: ****" # Row number
43
+ # (1..x.width).each do |j|
44
+ # print x.data[i - 1][j - 1] # [B G R]
45
+ # print " "
46
+ # end
47
+ # puts '****'
48
+ #end
49
+ #x.write('/home/harsha/imgp/librepo/rubyvision/temp.bmp')
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubyvision
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Harsha Dixit