pnglitch 0.0.1 → 0.0.2

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
  SHA1:
3
- metadata.gz: 5ef1538aec8847d189241145512fe084c43eca6d
4
- data.tar.gz: 010aa625e9d831f09bac45ea3c6ca88ef9f83545
3
+ metadata.gz: 44d05884a52a43971ee2d6e6f0c0dd79450f7435
4
+ data.tar.gz: 07e160fdf0a363ac043b94c52e76d9446d7ac66f
5
5
  SHA512:
6
- metadata.gz: b356a88db6db41d9729dacd936277b2ffeed2af5714f2c3884821e0654c71071bc379d848e6415473ea4aeea1b5a0cf2a83c100b6820cf211003ae3e4c3fcfd1
7
- data.tar.gz: ec2db449bb83b8574b2f42a0073540995552c8732a9a453f5c6019382b1bc722a2fe183b1b6ba976290932f7b3935296becbf43467d4d071191fea619f60be85
6
+ metadata.gz: 73efdd4e1fb833a268a12b35b39359db9225f0c5a1f0c332ae2b35b3559d317210498fd387f5c1f89fe5ad71105bbd77bc77d173faf0db6e974da488720b43f1
7
+ data.tar.gz: 4f413a38b0e60ac3362ebeea3b0a0a27860fe985084d4dcff6a67e8f446e49536b979b289a6241f3351c3d424f5e471f140a41240d21429f7210e8a247db6a2f
data/.travis.yml CHANGED
@@ -1,4 +1,4 @@
1
1
  language: ruby
2
2
  rvm:
3
3
  - 2.0.0
4
- - 2.1.4
4
+ - 2.2.2
data/LICENSE.txt CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2014 ucnv
1
+ Copyright (c) 2014-2015 ucnv
2
2
 
3
3
  MIT License
4
4
 
data/bin/pnglitch CHANGED
@@ -41,9 +41,7 @@ begin
41
41
  infile, outfile = ARGV
42
42
  PNGlitch.open infile do |png|
43
43
  unless filter.nil?
44
- png.each_scanline do |line|
45
- line.change_filter filter
46
- end
44
+ png.change_all_filters filter
47
45
  end
48
46
  png.glitch do |data|
49
47
  data.gsub /\d/, 'x'
data/lib/pnglitch/base.rb CHANGED
@@ -7,7 +7,7 @@ module PNGlitch
7
7
  class Base
8
8
 
9
9
  attr_reader :width, :height, :sample_size, :is_compressed_data_modified
10
- attr_accessor :head_data, :tail_data, :compressed_data, :filtered_data
10
+ attr_accessor :head_data, :tail_data, :compressed_data, :filtered_data, :idat_chunk_size
11
11
 
12
12
  #
13
13
  # Instanciate the class with the passed +file+
@@ -16,8 +16,8 @@ module PNGlitch
16
16
  path = Pathname.new file
17
17
  @head_data = StringIO.new
18
18
  @tail_data = StringIO.new
19
- @compressed_data = Tempfile.new 'compressed', :encoding => 'ascii-8bit'
20
- @filtered_data = Tempfile.new 'filtered', :encoding => 'ascii-8bit'
19
+ @compressed_data = Tempfile.new 'compressed', encoding: 'ascii-8bit'
20
+ @filtered_data = Tempfile.new 'filtered', encoding: 'ascii-8bit'
21
21
  @idat_chunk_size = nil
22
22
 
23
23
  open(path, 'rb') do |io|
@@ -37,6 +37,7 @@ module PNGlitch
37
37
  }
38
38
  @width = ihdr[:width]
39
39
  @height = ihdr[:height]
40
+ @interlace = ihdr[:interlace_method]
40
41
  @sample_size = {0 => 1, 2 => 3, 3 => 1, 4 => 2, 6 => 4}[ihdr[:color_type]]
41
42
  io.pos -= 13
42
43
  end
@@ -95,10 +96,10 @@ module PNGlitch
95
96
  def filter_types
96
97
  types = []
97
98
  wrap_with_rewind(@filtered_data) do
98
- until @filtered_data.eof? do
99
+ scanline_positions.each do |pos|
100
+ @filtered_data.pos = pos
99
101
  byte = @filtered_data.read 1
100
102
  types << byte.unpack('C').first
101
- @filtered_data.pos += @width * @sample_size
102
103
  end
103
104
  end
104
105
  types
@@ -156,9 +157,6 @@ module PNGlitch
156
157
  #
157
158
  # To set a glitched result, return the modified value in the block.
158
159
  #
159
- # It will raise an error when the data goes over the limit. In such case, please treat
160
- # the data as IO through +glitch_after_compress_as_io+ instead.
161
- #
162
160
  # Once the compressed data is glitched, PNGlitch will warn about modifications to
163
161
  # filtered (decompressed) data because this method does not decompress the glitched
164
162
  # compressed data again. It means that calling +glitch+ after +glitch_after_compress+
@@ -189,26 +187,32 @@ module PNGlitch
189
187
  end
190
188
 
191
189
  #
192
- # (Re-)computes the filtering methods to each scanlines.
193
- #
194
- # On each scanline, it will compute them and apply the results as the filtered data.
190
+ # (Re-)computes the filtering methods on each scanline.
195
191
  #
196
192
  def apply_filters prev_filters = nil, filter_codecs = nil
197
193
  prev_filters = filter_types if prev_filters.nil?
198
194
  filter_codecs = [] if filter_codecs.nil?
199
195
  current_filters = []
200
196
  prev = nil
201
- line_size = @width * @sample_size
197
+ line_sizes = []
198
+ scanline_positions.push(@filtered_data.size).inject do |m, n|
199
+ line_sizes << n - m - 1
200
+ n
201
+ end
202
202
  wrap_with_rewind(@filtered_data) do
203
203
  # decode all scanlines
204
204
  prev_filters.each_with_index do |type, i|
205
205
  byte = @filtered_data.read 1
206
206
  current_filters << byte.unpack('C').first
207
+ line_size = line_sizes[i]
207
208
  line = @filtered_data.read line_size
208
209
  filter = Filter.new type, @sample_size
209
210
  if filter_codecs[i] && filter_codecs[i][:decoder]
210
211
  filter.decoder = filter_codecs[i][:decoder]
211
212
  end
213
+ if !prev.nil? && @interlace_pass_count.include?(i + 1) # make sure prev to be nil if interlace pass is changed
214
+ prev = nil
215
+ end
212
216
  decoded = filter.decode line, prev
213
217
  @filtered_data.pos -= line_size
214
218
  @filtered_data << decoded
@@ -216,24 +220,29 @@ module PNGlitch
216
220
  end
217
221
  # encode all
218
222
  filter_codecs.reverse!
223
+ line_sizes.reverse!
219
224
  data_amount = @filtered_data.pos # should be eof
225
+ ref = data_amount
220
226
  current_filters.reverse_each.with_index do |type, i|
221
- pos = data_amount - ((1 + line_size) * i)
222
- posa = pos - line_size
223
- @filtered_data.pos = posa
227
+ line_size = line_sizes[i]
228
+ ref -= line_size + 1
229
+ @filtered_data.pos = ref + 1
224
230
  line = @filtered_data.read line_size
225
- posb = pos - (1 + line_size) - line_size
226
231
  prev = nil
227
- unless posb < 0
228
- @filtered_data.pos = posb
232
+ if !line_sizes[i + 1].nil?
233
+ @filtered_data.pos = ref - line_size
229
234
  prev = @filtered_data.read line_size
230
235
  end
236
+ # make sure prev to be nil if interlace pass is changed
237
+ if @interlace_pass_count.include?(current_filters.size - i)
238
+ prev = nil
239
+ end
231
240
  filter = Filter.new type, @sample_size
232
241
  if filter_codecs[i] && filter_codecs[i][:encoder]
233
242
  filter.encoder = filter_codecs[i][:encoder]
234
243
  end
235
244
  encoded = filter.encode line, prev
236
- @filtered_data.pos = posa
245
+ @filtered_data.pos = ref + 1
237
246
  @filtered_data << encoded
238
247
  end
239
248
  end
@@ -269,7 +278,7 @@ module PNGlitch
269
278
  #
270
279
  # Process each scanlines.
271
280
  #
272
- # It takes a block with a parameter. The parameter is an instance of
281
+ # It takes a block with a parameter. The parameter must be an instance of
273
282
  # PNGlitch::Scanline and it provides ways to edit the filter type and the data
274
283
  # of the scanlines. Normally it iterates the number of the PNG image height.
275
284
  #
@@ -280,7 +289,7 @@ module PNGlitch
280
289
  # end
281
290
  #
282
291
  # pnglicth.each_scanline do |line|
283
- # line.change_filter 3 # change all filter to 3, data will get re-filtering (it's not be a glitch)
292
+ # line.change_filter 3 # change all filter to 3, data will get re-filtering (it won't be a glitch)
284
293
  # end
285
294
  #
286
295
  # pnglicth.each_scanline do |line|
@@ -293,7 +302,7 @@ module PNGlitch
293
302
  #
294
303
  # -----
295
304
  #
296
- # Please note that +each_scanline+ will apply the filters after the loop. It means
305
+ # Please note that +each_scanline+ will apply the filters *after* the loop. It means
297
306
  # a following example doesn't work as expected.
298
307
  #
299
308
  # pnglicth.each_scanline do |line|
@@ -312,32 +321,24 @@ module PNGlitch
312
321
  #
313
322
  def each_scanline # :yield: scanline
314
323
  return enum_for :each_scanline unless block_given?
315
-
316
324
  prev_filters = self.filter_types
317
325
  is_refilter_needed = false
318
326
  filter_codecs = []
319
327
  wrap_with_rewind(@filtered_data) do
320
- pos = 0
321
328
  at = 0
322
- until @filtered_data.eof? do
323
- scanline = Scanline.new @filtered_data, pos, @width, @sample_size, at
329
+ scanline_positions.push(@filtered_data.size).inject do |pos, delimit|
330
+ scanline = Scanline.new @filtered_data, pos, (delimit - pos - 1), at
324
331
  yield scanline
325
- unless scanline.prev_filter_type.nil?
326
- is_refilter_needed = true
327
- else
328
- prev_filters[at] = scanline.filter_type # forget the prev filter when "graft"
329
- end
330
- filter_codecs << scanline.filter_codec
331
- if !filter_codecs.last[:encoder].nil? || !filter_codecs.last[:decoder].nil?
332
+ if fabricate_scanline(scanline, prev_filters, filter_codecs)
332
333
  is_refilter_needed = true
333
334
  end
334
335
  at += 1
335
- pos += @width * @sample_size + 1
336
- @filtered_data.pos = pos
336
+ delimit
337
337
  end
338
338
  end
339
339
  apply_filters(prev_filters, filter_codecs) if is_refilter_needed
340
340
  compress
341
+ self
341
342
  end
342
343
 
343
344
  #
@@ -348,36 +349,61 @@ module PNGlitch
348
349
  def scanline_at index_or_range
349
350
  base = self
350
351
  prev_filters = self.filter_types
351
- filter_codecs = nil
352
+ filter_codecs = Array.new(prev_filters.size)
352
353
  scanlines = []
353
354
  index_or_range = self.filter_types.size - 1 if index_or_range == -1
354
355
  range = index_or_range.is_a?(Range) ? index_or_range : [index_or_range]
355
- pos = 0
356
- self.filter_types.each.with_index do |filter, at|
356
+
357
+ at = 0
358
+ scanline_positions.push(@filtered_data.size).inject do |pos, delimit|
357
359
  if range.include? at
358
- s = Scanline.new(@filtered_data, pos, @width, @sample_size, at) do |scanline|
359
- is_refilter_needed = false
360
- unless scanline.prev_filter_type.nil?
361
- is_refilter_needed = true
362
- else
363
- prev_filters[at] = scanline.filter_type
360
+ s = Scanline.new(@filtered_data, pos, (delimit - pos - 1), at) do |scanline|
361
+ if base.fabricate_scanline(scanline, prev_filters, filter_codecs)
362
+ base.apply_filters(prev_filters, filter_codecs)
364
363
  end
365
- codec = scanline.filter_codec
366
- if !codec[:encoder].nil? || !codec[:decoder].nil?
367
- filter_codecs = Array.new(prev_filters.size) if filter_codecs.nil?
368
- filter_codecs[at] = codec
369
- is_refilter_needed = true
370
- end
371
- base.apply_filters(prev_filters, filter_codecs) if is_refilter_needed
372
364
  base.compress
373
365
  end
374
366
  scanlines << s
375
367
  end
376
- pos += @width * @sample_size + 1
368
+ at += 1
369
+ delimit
377
370
  end
378
371
  scanlines.size <= 1 ? scanlines.first : scanlines
379
372
  end
380
373
 
374
+ def fabricate_scanline scanline, prev_filters, filter_codecs # :nodoc:
375
+ at = scanline.index
376
+ is_refilter_needed = false
377
+ unless scanline.prev_filter_type.nil?
378
+ is_refilter_needed = true
379
+ else
380
+ prev_filters[at] = scanline.filter_type
381
+ end
382
+ codec = filter_codecs[at] = scanline.filter_codec
383
+ if !codec[:encoder].nil? || !codec[:decoder].nil?
384
+ is_refilter_needed = true
385
+ end
386
+ is_refilter_needed
387
+ end
388
+
389
+ #
390
+ # Changes filter type values to passed +filter_type+ in all scanlines
391
+ #
392
+ def change_all_filters filter_type
393
+ each_scanline do |line|
394
+ line.change_filter filter_type
395
+ end
396
+ compress
397
+ self
398
+ end
399
+
400
+ #
401
+ # Checks if it is interlaced.
402
+ #
403
+ def interlaced?
404
+ @interlace == 1
405
+ end
406
+
381
407
  #
382
408
  # Rewrites the width value.
383
409
  #
@@ -394,6 +420,7 @@ module PNGlitch
394
420
  end
395
421
  end
396
422
  @head_data.rewind
423
+ w
397
424
  end
398
425
 
399
426
  #
@@ -414,27 +441,27 @@ module PNGlitch
414
441
  end
415
442
  end
416
443
  @head_data.rewind
444
+ h
417
445
  end
418
446
 
419
447
  #
420
448
  # Save to the +file+.
421
449
  #
422
450
  def save file
423
- @head_data.rewind
424
- @tail_data.rewind
425
- @compressed_data.rewind
426
- open(file, 'w') do |io|
427
- io << @head_data.read
428
- chunk_size = @idat_chunk_size || @compressed_data.size
429
- type = 'IDAT'
430
- until @compressed_data.eof? do
431
- data = @compressed_data.read(chunk_size)
432
- io << [data.size].pack('N')
433
- io << type
434
- io << data
435
- io << [Zlib.crc32(data, Zlib.crc32(type))].pack('N')
451
+ wrap_with_rewind(@head_data, @tail_data, @compressed_data) do
452
+ open(file, 'w') do |io|
453
+ io << @head_data.read
454
+ chunk_size = @idat_chunk_size || @compressed_data.size
455
+ type = 'IDAT'
456
+ until @compressed_data.eof? do
457
+ data = @compressed_data.read(chunk_size)
458
+ io << [data.size].pack('N')
459
+ io << type
460
+ io << data
461
+ io << [Zlib.crc32(data, Zlib.crc32(type))].pack('N')
462
+ end
463
+ io << @tail_data.read
436
464
  end
437
- io << @tail_data.read
438
465
  end
439
466
  self
440
467
  end
@@ -460,6 +487,64 @@ module PNGlitch
460
487
  end
461
488
  end
462
489
 
490
+ # Calculate positions of scanlines
491
+ def scanline_positions
492
+ scanline_pos = [0]
493
+ amount = @filtered_data.size
494
+ @interlace_pass_count = []
495
+ if self.interlaced?
496
+ # Adam7
497
+ # Pass 1
498
+ v = 1 + (@width / 8.0).ceil * @sample_size
499
+ (@height / 8.0).ceil.times do
500
+ scanline_pos << scanline_pos.last + v
501
+ end
502
+ @interlace_pass_count << scanline_pos.size
503
+ # Pass 2
504
+ v = 1 + ((@width - 4) / 8.0).ceil * @sample_size
505
+ (@height / 8.0).ceil.times do
506
+ scanline_pos << scanline_pos.last + v
507
+ end
508
+ @interlace_pass_count << scanline_pos.size
509
+ # Pass 3
510
+ v = 1 + (@width / 4.0).ceil * @sample_size
511
+ ((@height - 4) / 8.0).ceil.times do
512
+ scanline_pos << scanline_pos.last + v
513
+ end
514
+ @interlace_pass_count << scanline_pos.size
515
+ # Pass 4
516
+ v = 1 + ((@width - 2) / 4.0).ceil * @sample_size
517
+ (@height / 4.0).ceil.times do
518
+ scanline_pos << scanline_pos.last + v
519
+ end
520
+ @interlace_pass_count << scanline_pos.size
521
+ # Pass 5
522
+ v = 1 + (@width / 2.0).ceil * @sample_size
523
+ ((@height - 2) / 4.0).ceil.times do
524
+ scanline_pos << scanline_pos.last + v
525
+ end
526
+ @interlace_pass_count << scanline_pos.size
527
+ # Pass 6
528
+ v = 1 + ((@width - 1) / 2.0).ceil * @sample_size
529
+ (@height / 2.0).ceil.times do
530
+ scanline_pos << scanline_pos.last + v
531
+ end
532
+ @interlace_pass_count << scanline_pos.size
533
+ # Pass 7
534
+ v = 1 + @width * @sample_size
535
+ ((@height - 1) / 2.0).ceil.times do
536
+ scanline_pos << scanline_pos.last + v
537
+ end
538
+ scanline_pos.pop # no need to keep last position
539
+ end
540
+ loop do
541
+ v = scanline_pos.last + (1 + @width * @sample_size)
542
+ break if v >= amount
543
+ scanline_pos << v
544
+ end
545
+ scanline_pos
546
+ end
547
+
463
548
  # Makes warning
464
549
  def warn_if_compressed_data_modified # :nodoc:
465
550
  if @is_compressed_data_modified
@@ -469,7 +554,7 @@ module PNGlitch
469
554
  With this operation, your changes on the compressed data will be reverted.
470
555
  Note that a modification to the compressed data does not reflect to the
471
556
  filtered (decompressed) data.
472
- It\'s happened around #{trace.last.to_s}
557
+ It's happened around #{trace.last.to_s}
473
558
  EOL
474
559
  message = ["\e[33m", message, "\e[0m"].join if STDOUT.tty? # color yellow
475
560
  warn ["\n", message, "\n"].join
@@ -10,6 +10,8 @@ module PNGlitch
10
10
  AVERAGE = 3
11
11
  PAETH = 4
12
12
 
13
+ @@types = Filter.constants.sort_by {|c| const_get c }.collect(&:downcase)
14
+
13
15
  #
14
16
  # Guesses and retuens the filter type as a number.
15
17
  #
@@ -17,10 +19,10 @@ module PNGlitch
17
19
  type = nil
18
20
  if filter_type.is_a?(Numeric) && filter_type.between?(NONE, PAETH)
19
21
  type = filter_type.to_i
20
- elsif filter_type.to_s =~ /[0-4]/
22
+ elsif filter_type.is_a?(String) && filter_type =~ /^[0-4]$/
21
23
  type = filter_type.to_i
22
24
  else
23
- type = ['n', 's', 'u', 'a', 'p'].index(filter_type.to_s[0])
25
+ type = @@types.collect{|c| c.to_s[0] }.index(filter_type.to_s[0].downcase)
24
26
  end
25
27
  type
26
28
  end
@@ -28,10 +30,10 @@ module PNGlitch
28
30
  attr_reader :filter_type
29
31
  attr_accessor :encoder, :decoder
30
32
 
31
- def initialize filter_type, pixel_size
32
- @filter_type = Filter.guess filter_type || 0
33
- @filter_type_name = [:none, :sub, :up, :average, :paeth][@filter_type]
34
- @pixel_size = pixel_size
33
+ def initialize filter_type, sample_size
34
+ @filter_type = Filter.guess(filter_type) || 0
35
+ @filter_type_name = @@types[@filter_type]
36
+ @sample_size = sample_size
35
37
  @encoder = self.method ('encode_%s' % @filter_type_name.to_s).to_sym
36
38
  @decoder = self.method ('decode_%s' % @filter_type_name.to_s).to_sym
37
39
  end
@@ -40,14 +42,14 @@ module PNGlitch
40
42
  # Filter with a specified filter type.
41
43
  #
42
44
  def encode data, prev_data = nil
43
- @encoder.call data, prev_data
45
+ @encoder.call data.dup, prev_data
44
46
  end
45
47
 
46
48
  #
47
49
  # Reconstruct with a specified filter type.
48
50
  #
49
51
  def decode data, prev_data = nil
50
- @decoder.call data, prev_data
52
+ @decoder.call data.dup, prev_data
51
53
  end
52
54
 
53
55
  private
@@ -56,40 +58,74 @@ module PNGlitch
56
58
  data
57
59
  end
58
60
 
61
+ def decode_none data, prev # :nodoc:
62
+ data
63
+ end
64
+
59
65
  def encode_sub data, prev # :nodoc:
60
66
  # Filt(x) = Orig(x) - Orig(a)
61
- d = data.dup
62
- d.size.times.reverse_each do |i|
63
- next if i < @pixel_size
64
- x = d.getbyte i
65
- a = d.getbyte i - @pixel_size
66
- d.setbyte i, (x - a) & 0xff
67
+ data.size.times.reverse_each do |i|
68
+ next if i < @sample_size
69
+ x = data.getbyte i
70
+ a = data.getbyte i - @sample_size
71
+ data.setbyte i, (x - a) & 0xff
67
72
  end
68
- d
73
+ data
74
+ end
75
+
76
+ def decode_sub data, prev # :nodoc:
77
+ # Recon(x) = Filt(x) + Recon(a)
78
+ data.size.times do |i|
79
+ next if i < @sample_size
80
+ x = data.getbyte i
81
+ a = data.getbyte i - @sample_size
82
+ data.setbyte i, (x + a) & 0xff
83
+ end
84
+ data
69
85
  end
70
86
 
71
87
  def encode_up data, prev # :nodoc:
72
88
  # Filt(x) = Orig(x) - Orig(b)
73
89
  return data if prev.nil?
74
- d = data.dup
75
- d.size.times.reverse_each do |i|
76
- x = d.getbyte i
90
+ data.size.times.reverse_each do |i|
91
+ x = data.getbyte i
92
+ b = prev.getbyte i
93
+ data.setbyte i, (x - b) & 0xff
94
+ end
95
+ data
96
+ end
97
+
98
+ def decode_up data, prev # :nodoc:
99
+ # Recon(x) = Filt(x) + Recon(b)
100
+ return data if prev.nil?
101
+ data.size.times do |i|
102
+ x = data.getbyte i
77
103
  b = prev.getbyte i
78
- d.setbyte i, (x - b) & 0xff
104
+ data.setbyte i, (x + b) & 0xff
79
105
  end
80
- d
106
+ data
107
+ end
108
+
109
+ def decode_average data, prev # :nodoc:
110
+ # Recon(x) = Filt(x) + floor((Recon(a) + Recon(b)) / 2)
111
+ data.size.times do |i|
112
+ x = data.getbyte i
113
+ a = i >= @sample_size ? data.getbyte(i - @sample_size) : 0
114
+ b = !prev.nil? ? prev.getbyte(i) : 0
115
+ data.setbyte i, (x + ((a + b) / 2)) & 0xff
116
+ end
117
+ data
81
118
  end
82
119
 
83
120
  def encode_average data, prev # :nodoc:
84
121
  # Filt(x) = Orig(x) - floor((Orig(a) + Orig(b)) / 2)
85
- d = data.dup
86
- d.size.times.reverse_each do |i|
87
- x = d.getbyte i
88
- a = i >= @pixel_size ? d.getbyte(i - @pixel_size) : 0
122
+ data.size.times.reverse_each do |i|
123
+ x = data.getbyte i
124
+ a = i >= @sample_size ? data.getbyte(i - @sample_size) : 0
89
125
  b = !prev.nil? ? prev.getbyte(i) : 0
90
- d.setbyte i, (x - ((a + b) / 2)) & 0xff
126
+ data.setbyte i, (x - ((a + b) / 2)) & 0xff
91
127
  end
92
- d
128
+ data
93
129
  end
94
130
 
95
131
  def encode_paeth data, prev # :nodoc:
@@ -104,82 +140,40 @@ module PNGlitch
104
140
  # else if pb <= pc then Pr = b
105
141
  # else Pr = c
106
142
  # return Pr
107
- d = data.dup
108
- d.size.times.reverse_each do |i|
109
- x = d.getbyte i
110
- is_a_exist = i >= @pixel_size
143
+ data.size.times.reverse_each do |i|
144
+ x = data.getbyte i
145
+ is_a_exist = i >= @sample_size
111
146
  is_b_exist = !prev.nil?
112
- a = is_a_exist ? d.getbyte(i - @pixel_size) : 0
147
+ a = is_a_exist ? data.getbyte(i - @sample_size) : 0
113
148
  b = is_b_exist ? prev.getbyte(i) : 0
114
- c = is_a_exist && is_b_exist ? prev.getbyte(i - @pixel_size) : 0
149
+ c = is_a_exist && is_b_exist ? prev.getbyte(i - @sample_size) : 0
115
150
  p = a + b - c
116
151
  pa = (p - a).abs
117
152
  pb = (p - b).abs
118
153
  pc = (p - c).abs
119
154
  pr = pa <= pb && pa <= pc ? a : pb <= pc ? b : c
120
- d.setbyte i, (x - pr) & 0xff
155
+ data.setbyte i, (x - pr) & 0xff
121
156
  end
122
- d
123
- end
124
-
125
- def decode_none data, prev # :nodoc:
126
157
  data
127
158
  end
128
159
 
129
- def decode_sub data, prev # :nodoc:
130
- # Recon(x) = Filt(x) + Recon(a)
131
- d = data.dup
132
- d.size.times do |i|
133
- next if i < @pixel_size
134
- x = d.getbyte i
135
- a = d.getbyte i - @pixel_size
136
- d.setbyte i, (x + a) & 0xff
137
- end
138
- d
139
- end
140
-
141
- def decode_up data, prev # :nodoc:
142
- # Recon(x) = Filt(x) + Recon(b)
143
- return data if prev.nil?
144
- d = data.dup
145
- d.size.times do |i|
146
- x = d.getbyte i
147
- b = prev.getbyte i
148
- d.setbyte i, (x + b) & 0xff
149
- end
150
- d
151
- end
152
-
153
- def decode_average data, prev # :nodoc:
154
- # Recon(x) = Filt(x) + floor((Recon(a) + Recon(b)) / 2)
155
- d = data.dup
156
- d.size.times do |i|
157
- x = d.getbyte i
158
- a = i >= @pixel_size ? d.getbyte(i - @pixel_size) : 0
159
- b = !prev.nil? ? prev.getbyte(i) : 0
160
- d.setbyte i, (x + ((a + b) / 2)) & 0xff
161
- end
162
- d
163
- end
164
-
165
160
  def decode_paeth data, prev # :nodoc:
166
161
  # Recon(x) = Filt(x) + PaethPredictor(Recon(a), Recon(b), Recon(c))
167
- d = data.dup
168
- d.size.times do |i|
169
- x = d.getbyte i
170
- is_a_exist = i >= @pixel_size
162
+ data.size.times do |i|
163
+ x = data.getbyte i
164
+ is_a_exist = i >= @sample_size
171
165
  is_b_exist = !prev.nil?
172
- a = is_a_exist ? d.getbyte(i - @pixel_size) : 0
166
+ a = is_a_exist ? data.getbyte(i - @sample_size) : 0
173
167
  b = is_b_exist ? prev.getbyte(i) : 0
174
- c = is_a_exist && is_b_exist ? prev.getbyte(i - @pixel_size) : 0
168
+ c = is_a_exist && is_b_exist ? prev.getbyte(i - @sample_size) : 0
175
169
  p = a + b - c
176
170
  pa = (p - a).abs
177
171
  pb = (p - b).abs
178
172
  pc = (p - c).abs
179
173
  pr = (pa <= pb && pa <= pc) ? a : (pb <= pc ? b : c)
180
- d.setbyte i, (x + pr) & 0xff
174
+ data.setbyte i, (x + pr) & 0xff
181
175
  end
182
- d
176
+ data
183
177
  end
184
178
  end
185
179
  end
@@ -11,12 +11,11 @@ module PNGlitch
11
11
  #
12
12
  # Instanciate.
13
13
  #
14
- def initialize io, start_at, width, sample_size, at
14
+ def initialize io, start_at, data_size, at
15
15
  @index = at
16
16
  @io = io
17
17
  @start_at = start_at
18
- @data_size = width * sample_size
19
- @sample_size = sample_size
18
+ @data_size = data_size
20
19
 
21
20
  pos = @io.pos
22
21
  @io.pos = @start_at
@@ -86,7 +85,7 @@ module PNGlitch
86
85
  def change_filter new_filter
87
86
  @prev_filter_type = @filter_type
88
87
  @filter_type = new_filter
89
- save
88
+ self.save
90
89
  end
91
90
 
92
91
  #
@@ -111,7 +110,6 @@ module PNGlitch
111
110
  # the specified filter type value. It takes a Proc object or a block.
112
111
  #
113
112
  def register_filter_decoder decoder = nil, &block
114
- @filter_decoder = decoder
115
113
  if !decoder.nil? && decoder.is_a?(Proc)
116
114
  @filter_codec[:decoder] = decoder
117
115
  elsif block_given?
@@ -120,14 +118,13 @@ module PNGlitch
120
118
  save
121
119
  end
122
120
 
123
-
124
121
  #
125
122
  # Save the changes.
126
123
  #
127
124
  def save
128
125
  pos = @io.pos
129
126
  @io.pos = @start_at
130
- @io << [@filter_type].pack('C')
127
+ @io << [Filter.guess(@filter_type)].pack('C')
131
128
  @io << self.data.slice(0, @data_size).ljust(@data_size, "\0")
132
129
  @io.pos = pos
133
130
  @callback.call(self) unless @callback.nil?
data/lib/pnglitch.rb CHANGED
@@ -20,7 +20,7 @@ require 'pnglitch/base'
20
20
  # = Usage
21
21
  #
22
22
  # == Simple glitch
23
- #
23
+ #
24
24
  # png = PNGlitch.open '/path/to/your/image.png'
25
25
  # png.glitch do |data|
26
26
  # data.gsub /\d/, 'x'
@@ -39,7 +39,7 @@ require 'pnglitch/base'
39
39
  #
40
40
  # The +glitch+ method treats the decompressed data into one String instance. It will be
41
41
  # very convenient, but please note that it could take a huge size of memory. For example,
42
- # a normal PNG image in 3264 x 2448 pixels makes over 23 MB of decompressed data.
42
+ # a normal PNG image in 4000 x 3000 pixels makes over 48 MB of decompressed data.
43
43
  # In case that the memory usage becomes a concern, it can be written to use IO instead of
44
44
  # String.
45
45
  #
@@ -64,8 +64,8 @@ require 'pnglitch/base'
64
64
  # png.save '/path/to/broken/image.png'
65
65
  # end
66
66
  #
67
- # Depe:nding a viewer application, the result of the first example using +glitch+ can
68
- # detected as unopenable file, because of breaking the filter type bytes (Most applications
67
+ # Depending a viewer application, the result of the first example using +glitch+ can be
68
+ # detected as unopenable, because of breaking the filter type bytes (Most applications
69
69
  # will ignore it, but I found the library in java.awt get failed). The operation with
70
70
  # +each_scanline+ will be more careful for memory usage and the file itself.
71
71
  # It is a polite way, but is slower than the rude +glitch+.
@@ -89,33 +89,34 @@ require 'pnglitch/base'
89
89
  # end
90
90
  #
91
91
  # Filter is a tiny function for optimizing PNG compression. It can be set different types
92
- # with each scanline. The five filter types are defined in the spec, are named +None+, +Up+,
93
- # +Sub+, +Average+ and +Paeth+ (+None+ means no filter, this filter type makes "raw" data).
94
- # Internally five digits (0-4) become the references.
92
+ # with each scanline. The five filter types are defined in the spec, are named +None+,
93
+ # +Sub+, +Up+, +Average+ and +Paeth+ (+None+ means no filter, this filter type makes "raw"
94
+ # data). Internally five digits (0-4) correspond them.
95
95
  #
96
96
  # The filter types must be the most important factor behind the representation of glitch
97
- # results. Each filter has different effect.
97
+ # results. Each filter type has different effect.
98
98
  #
99
- # Generally in PNG file, scanlines has a variety of filter types on each. As in a
99
+ # Generally in PNG file, scanlines has a variety of filter types on each, as in a
100
100
  # convertion by image processing applications (like Photoshop or ImageMagick) they try to
101
- # apply proper filter types with each scanlines.
101
+ # apply a proper filter type with each scanline.
102
102
  #
103
103
  # You can check the values like:
104
104
  #
105
105
  # puts png.filter_types
106
106
  #
107
- # With +each_scanline+, we can reach the filters particularly.
107
+ # With +each_scanline+, we can reach the filter types particularly.
108
108
  #
109
109
  # png.each_scanline do |scanline|
110
+ # puts scanline.filter_type
110
111
  # scanline.change_filter 3
111
112
  # end
112
113
  #
113
114
  # The example above puts all filter types in 3 (type +Average+). +change_filter+ will
114
115
  # apply new filter type values correctly. It computes filters and makes the PNG well
115
- # formatted, and any glitch won't get happened. It also means the output image would have
116
- # completely looks the same as the input one.
116
+ # formatted, and any glitch won't get happened. It also means the output image should
117
+ # completely look the same as the input one.
117
118
  #
118
- # However glitches might reveal the difference of filter types.
119
+ # However glitches will reveal the difference of the filter types.
119
120
  #
120
121
  # PNGlitch.open(infile) do |png|
121
122
  # png.each_scanline do |scanline|
@@ -139,10 +140,10 @@ require 'pnglitch/base'
139
140
  #
140
141
  # With the results of the example above, obviously we can recognize the filter types make
141
142
  # a big difference. The filter is distinct and interesting thing in PNG glitching.
142
- # To put all filter type in a same value before glitching, we could see the signature
143
- # taste of each filter type. (Note that +change_filter+ will be a little bit slow, image
144
- # processing libraries like ImageMagick also have the option to put all filter type in
145
- # same ones and they will process faster.)
143
+ # To put all filter type in a same value before glitching, we would see the signature
144
+ # taste of each filter type. (Note that +change_filter+ may be a little bit slow, image
145
+ # processing libraries like ImageMagick also have an option to put all filter type in
146
+ # same ones and they may process faster.)
146
147
  #
147
148
  # This library provides a simple method to change the filter type so that generating all
148
149
  # possible effects in PNG glitch.
@@ -159,13 +160,12 @@ require 'pnglitch/base'
159
160
  #
160
161
  # png.each_scanline do |scanline|
161
162
  # scanline.register_filter_encoder do |data, prev|
162
- # d = data.dup
163
- # d.size.times.reverse_each do |i|
164
- # x = d.getbyte(i)
163
+ # data.size.times.reverse_each do |i|
164
+ # x = data.getbyte(i)
165
165
  # v = prev ? prev.getbyte((i - 5).abs) : 0
166
- # d.setbyte(i, (x - v) & 0xff)
166
+ # data.setbyte(i, (x - v) & 0xff)
167
167
  # end
168
- # d
168
+ # data
169
169
  # end
170
170
  # end
171
171
  #
@@ -178,7 +178,7 @@ require 'pnglitch/base'
178
178
  # +----------+ +---------------+ +-----------------+ +----------------+
179
179
  #
180
180
  # It shows that there are two states between raw data and a result file, and it means there
181
- # are two states possible to glitch. This library provides to choose of the state to glitch.
181
+ # are two states possible to glitch. This library provides to choose of the state to glitch.
182
182
  #
183
183
  # All examples cited thus far are operations to "filtered data". On the other hand, PNGlitch
184
184
  # can touch the "compressed data" through +glitch_after_compress+ method:
@@ -189,10 +189,10 @@ require 'pnglitch/base'
189
189
  # end
190
190
  #
191
191
  # Glitch against the compressed data makes slightly different pictures from other results.
192
- # But sometimes this scratch would break the compression and make the file unopenable.
192
+ # But sometimes this scratch could break the compression and make the file unopenable.
193
193
  #
194
194
  module PNGlitch
195
- VERSION = '0.0.1'
195
+ VERSION = '0.0.2'
196
196
 
197
197
  class << self
198
198
 
@@ -222,10 +222,11 @@ module PNGlitch
222
222
  # the amount of pixels).
223
223
  # To avoid the attack known as "zip bomb", PNGlitch will throw an error when
224
224
  # decompressed data goes over twice the expected size. If it's sure that the passed
225
- # file is safe, the upper limit of decompressed data size can be set in +open+'s option.
225
+ # file is safe, the upper limit of decompressed data size can be set in +open+'s option
226
+ # in bytes.
226
227
  # Like:
227
228
  #
228
- # PNGlitch.open(infile, limit_of_decompressed_data_size: 1 * 1024 ** 3)
229
+ # PNGlitch.open(infile, limit_of_decompressed_data_size: 1024 ** 3)
229
230
  #
230
231
  def open file, options = {}
231
232
  base = Base.new file, options[:limit_of_decompressed_data_size]
data/pnglitch.gemspec CHANGED
@@ -8,8 +8,8 @@ Gem::Specification.new do |spec|
8
8
  spec.version = PNGlitch::VERSION
9
9
  spec.authors = ["ucnv"]
10
10
  spec.email = ["ucnvvv@gmail.com"]
11
- spec.summary = %q{A Ruby library to glitch PNG images.}
12
- spec.description = <<-EOL.gsub(/^\s*/, '')
11
+ spec.description = %q{A Ruby library to glitch PNG images.}
12
+ spec.summary = <<-EOL.gsub(/^\s*/, '')
13
13
  PNGlitch is a Ruby library to destroy your PNG images.
14
14
  With normal data-bending technique, a glitch against PNG will easily fail
15
15
  because of the checksum function. We provide a fail-proof destruction for it.
Binary file
File without changes
Binary file
@@ -23,4 +23,10 @@ describe PNGlitch::Filter do
23
23
  end
24
24
  end
25
25
 
26
+ describe '.guess' do
27
+ it 'should detect wrong value as nil' do
28
+ v = PNGlitch::Filter.guess 34
29
+ expect(v).to be_nil
30
+ end
31
+ end
26
32
  end
@@ -49,6 +49,7 @@ describe PNGlitch do
49
49
  end
50
50
  }.not_to raise_error
51
51
  expect(types.size).to eq h
52
+ expect(outfile).to exist
52
53
  end
53
54
 
54
55
  it 'should return a value of last call in the block' do
@@ -68,9 +69,17 @@ describe PNGlitch do
68
69
  end
69
70
  end
70
71
 
71
- context('when decompressed data is unexpected size') do
72
- it 'should raise error' do
73
- bomb = infile.dirname.join('bomb.png')
72
+ context 'when decompressed data is unexpected size' do
73
+ it 'should not raise error for too small size' do
74
+ bomb = infile.dirname.join('ina.png')
75
+ expect {
76
+ png = PNGlitch.open bomb
77
+ png.close
78
+ }.to_not raise_error
79
+ end
80
+
81
+ it 'should raise error for too large size' do
82
+ bomb = infile.dirname.join('inb.png')
74
83
  expect {
75
84
  png = PNGlitch.open bomb
76
85
  png.close
@@ -78,15 +87,16 @@ describe PNGlitch do
78
87
  end
79
88
 
80
89
  it 'can avoid the error' do
81
- bomb = infile.dirname.join('bomb.png')
90
+ bomb = infile.dirname.join('inb.png')
82
91
  expect {
83
92
  png = PNGlitch.open bomb, limit_of_decompressed_data_size: 100 * 1024 ** 2
84
93
  png.close
85
94
  }.not_to raise_error
86
95
  end
96
+
87
97
  end
88
98
 
89
- context('when it is not PNG file') do
99
+ context 'when it is not PNG file' do
90
100
  it 'should raise error' do
91
101
  file = infile.dirname.join('filter_none')
92
102
  expect {
@@ -95,6 +105,20 @@ describe PNGlitch do
95
105
  }.to raise_error PNGlitch::FormatError
96
106
  end
97
107
  end
108
+
109
+ context 'with interlaced image' do
110
+ it 'should check it' do
111
+ a = PNGlitch.open infile do |p|
112
+ p.interlaced?
113
+ end
114
+ interlace = infile.dirname.join('inc.png')
115
+ b = PNGlitch.open interlace do |p|
116
+ p.interlaced?
117
+ end
118
+ expect(a).to be false
119
+ expect(b).to be true
120
+ end
121
+ end
98
122
  end
99
123
 
100
124
  describe '.output' do
@@ -155,6 +179,19 @@ describe PNGlitch do
155
179
  end
156
180
  end
157
181
 
182
+ describe '.apply_filters' do
183
+ it 'should ignore wrong filter types' do
184
+ PNGlitch.open infile do |p|
185
+ io = p.filtered_data
186
+ io.rewind
187
+ io << [100].pack('C')
188
+ expect {
189
+ p.apply_filters
190
+ }.not_to raise_error
191
+ end
192
+ end
193
+ end
194
+
158
195
  describe '.glitch' do
159
196
  it 'makes a result that is readable as PNG' do
160
197
  png = PNGlitch.open infile
@@ -290,6 +327,15 @@ describe PNGlitch do
290
327
  end
291
328
 
292
329
  describe '.filter_types' do
330
+ it 'should be in range between 0 and 4' do
331
+ png = PNGlitch.open infile
332
+ types = png.filter_types
333
+ png.close
334
+ types.each do |t|
335
+ expect(t).to be_between(0, 4)
336
+ end
337
+ end
338
+
293
339
  it 'should be same size of image height' do
294
340
  png = PNGlitch.open infile
295
341
  types = png.filter_types
@@ -297,6 +343,19 @@ describe PNGlitch do
297
343
  png.close
298
344
  expect(types.size).to eq height
299
345
  end
346
+
347
+ context 'with interlaced PNG' do
348
+ it 'should be in range between 0 and 4' do
349
+ png = PNGlitch.open infile.dirname.join('inc.png')
350
+ types = png.filter_types
351
+ png.close
352
+ types.each do |t|
353
+ expect(t).to be_between(0, 4)
354
+ end
355
+ end
356
+
357
+ end
358
+
300
359
  end
301
360
 
302
361
  describe '.each_scanline' do
@@ -365,6 +424,36 @@ describe PNGlitch do
365
424
  end
366
425
  end
367
426
 
427
+ it 'can change filter type with the name' do
428
+ t1 = PNGlitch.open infile do |p|
429
+ p.each_scanline do |l|
430
+ l.change_filter PNGlitch::Filter::PAETH
431
+ end
432
+ p.filter_types
433
+ end
434
+ t2 = PNGlitch.open infile do |p|
435
+ p.each_scanline do |l|
436
+ l.change_filter :paeth
437
+ end
438
+ p.filter_types
439
+ end
440
+ t3 = PNGlitch.open infile do |p|
441
+ p.each_scanline do |l|
442
+ l.change_filter :sub
443
+ end
444
+ p.filter_types
445
+ end
446
+ t4 = PNGlitch.open infile do |p|
447
+ p.each_scanline do |l|
448
+ l.graft 'Paeth'
449
+ end
450
+ p.filter_types
451
+ end
452
+ expect(t2).to be == t1
453
+ expect(t3).not_to be == t1
454
+ expect(t4).to be == t1
455
+ end
456
+
368
457
  it 'can apply custom filter method' do
369
458
  lines = []
370
459
  sample_size = nil
@@ -381,17 +470,16 @@ describe PNGlitch do
381
470
  end
382
471
 
383
472
  enc = lambda do |data, prev|
384
- d = data.dup
385
- d.size.times.reverse_each do |i|
386
- x = d.getbyte i
387
- a = i >= sample_size ? d.getbyte(i - sample_size - 1) : 0
473
+ data.size.times.reverse_each do |i|
474
+ x = data.getbyte i
475
+ a = i >= sample_size ? data.getbyte(i - sample_size - 1) : 0
388
476
  b = !prev.nil? ? prev.getbyte(i - 1) : 0
389
- d.setbyte i, (x - ((a + b) / 2)) & 0xff
477
+ data.setbyte i, (x - ((a + b) / 2)) & 0xff
390
478
  end
391
- d
479
+ data
392
480
  end
393
481
  decoded = PNGlitch::Filter.new(original_filter, sample_size).decode(lines[1], lines[0])
394
- encoded = enc.call(decoded, lines[0])
482
+ encoded = enc.call(decoded.dup, lines[0])
395
483
 
396
484
  PNGlitch.open infile do |png|
397
485
  png.each_scanline.with_index do |s, i|
@@ -408,16 +496,15 @@ describe PNGlitch do
408
496
  # ==================================
409
497
 
410
498
  dec = lambda do |data, prev|
411
- d = data.dup
412
- d.size.times do |i|
413
- x = d.getbyte i
414
- a = i >= sample_size ? d.getbyte(i - sample_size - 2) : 0
499
+ data.size.times do |i|
500
+ x = data.getbyte i
501
+ a = i >= sample_size ? data.getbyte(i - sample_size - 2) : 0
415
502
  b = !prev.nil? ? prev.getbyte(i - 1) : 0
416
- d.setbyte i, (x + ((a + b) / 2)) & 0xff
503
+ data.setbyte i, (x + ((a + b) / 2)) & 0xff
417
504
  end
418
- d
505
+ data
419
506
  end
420
- decoded = dec.call(lines[1], lines[0])
507
+ decoded = dec.call(lines[1].dup, lines[0])
421
508
  encoded = PNGlitch::Filter.new(original_filter, sample_size).encode(decoded, lines[0])
422
509
 
423
510
  PNGlitch.open infile do |png|
@@ -434,8 +521,8 @@ describe PNGlitch do
434
521
 
435
522
  # ==================================
436
523
 
437
- decoded = dec.call(lines[1], lines[0])
438
- encoded = enc.call(decoded, lines[0])
524
+ decoded = dec.call(lines[1].dup, lines[0])
525
+ encoded = enc.call(decoded.dup, lines[0])
439
526
 
440
527
  PNGlitch.open infile do |png|
441
528
  png.each_scanline.with_index do |s, i|
@@ -503,6 +590,22 @@ describe PNGlitch do
503
590
  expect(b).not_to eq(a)
504
591
  end
505
592
  end
593
+
594
+ context 'with an interlaced image' do
595
+ it 'can recognize correct filter types' do
596
+ img = infile.dirname.join('inc.png')
597
+ PNGlitch.open img do |p|
598
+ p.each_scanline do |line|
599
+ expect(line.filter_type).to be_between(0, 4)
600
+ end
601
+ p.change_all_filters 4
602
+ p.each_scanline do |line|
603
+ expect(line.filter_type).to be == 4
604
+ end
605
+ p.save outfile.dirname.join('i.png')
606
+ end
607
+ end
608
+ end
506
609
  end
507
610
 
508
611
  describe '.scanline_at' do
@@ -542,17 +645,16 @@ describe PNGlitch do
542
645
  end
543
646
 
544
647
  enc = lambda do |data, prev|
545
- d = data.dup
546
- d.size.times.reverse_each do |i|
547
- x = d.getbyte i
548
- a = i >= sample_size ? d.getbyte(i - sample_size - 1) : 0
648
+ data.size.times.reverse_each do |i|
649
+ x = data.getbyte i
650
+ a = i >= sample_size ? data.getbyte(i - sample_size - 1) : 0
549
651
  b = !prev.nil? ? prev.getbyte(i - 2) : 0
550
- d.setbyte i, (x - ((a + b) / 2)) & 0xff
652
+ data.setbyte i, (x - ((a + b) / 2)) & 0xff
551
653
  end
552
- d
654
+ data
553
655
  end
554
656
  decoded = PNGlitch::Filter.new(original_filter, sample_size).decode(lines[1], lines[0])
555
- encoded = enc.call(decoded, lines[0])
657
+ encoded = enc.call(decoded.dup, lines[0])
556
658
 
557
659
  PNGlitch.open infile do |png|
558
660
  l = png.scanline_at 100
@@ -582,10 +684,27 @@ describe PNGlitch do
582
684
  end
583
685
  end
584
686
 
687
+ describe '.change_all_filters' do
688
+ it 'can change filter types with single method' do
689
+ v = rand(4)
690
+ PNGlitch.open infile do |p|
691
+ p.change_all_filters v
692
+ p.save outfile
693
+ end
694
+ PNGlitch.open outfile do |p|
695
+ p.each_scanline do |l|
696
+ expect(l.filter_type).to be == v
697
+ end
698
+ end
699
+
700
+
701
+ end
702
+ end
703
+
585
704
  describe '.width and .height' do
586
705
  it 'destroy the dimension of the image' do
587
706
  w, h = ()
588
- out = outdir.join('t.png') #outfile
707
+ out = outfile
589
708
  PNGlitch.open infile do |p|
590
709
  w = p.width
591
710
  h = p.height
@@ -600,4 +719,36 @@ describe PNGlitch do
600
719
  end
601
720
  end
602
721
 
722
+ describe '.idat_chunk_size' do
723
+ it 'should be controllable' do
724
+ amount = nil
725
+ out1 = outdir.join 'a.png'
726
+ out2 = outdir.join 'b.png'
727
+ PNGlitch.open infile do |p|
728
+ amount = p.compressed_data.size
729
+ p.idat_chunk_size = 1024
730
+ p.output out1
731
+ end
732
+ PNGlitch.open out1 do |p|
733
+ expect(p.idat_chunk_size).to be == 1024
734
+ end
735
+ idat_size = open(out1, 'rb') do |f|
736
+ f.read.scan(/IDAT/).size
737
+ end
738
+ expect(idat_size).to be == (amount.to_f / 1024).ceil
739
+
740
+ PNGlitch.open infile do |p|
741
+ p.idat_chunk_size = nil
742
+ p.output out2
743
+ end
744
+ PNGlitch.open out2 do |p|
745
+ expect(p.idat_chunk_size).to be nil
746
+ end
747
+ idat_size = open(out2, 'rb') do |f|
748
+ f.read.scan(/IDAT/).size
749
+ end
750
+ expect(idat_size).to be == 1
751
+ end
752
+ end
753
+
603
754
  end
metadata CHANGED
@@ -1,62 +1,58 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pnglitch
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
  - ucnv
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-11-06 00:00:00.000000000 Z
11
+ date: 2015-04-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ~>
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
19
  version: '1.7'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ~>
24
+ - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '1.7'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ~>
31
+ - - "~>"
32
32
  - !ruby/object:Gem::Version
33
33
  version: '10.0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - ~>
38
+ - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '10.0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rspec
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - '>='
45
+ - - ">="
46
46
  - !ruby/object:Gem::Version
47
47
  version: '0'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - '>='
52
+ - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
- description: |
56
- PNGlitch is a Ruby library to destroy your PNG images.
57
- With normal data-bending technique, a glitch against PNG will easily fail
58
- because of the checksum function. We provide a fail-proof destruction for it.
59
- Using this library you will see beautiful and various PNG artifacts.
55
+ description: A Ruby library to glitch PNG images.
60
56
  email:
61
57
  - ucnvvv@gmail.com
62
58
  executables:
@@ -64,9 +60,9 @@ executables:
64
60
  extensions: []
65
61
  extra_rdoc_files: []
66
62
  files:
67
- - .gitignore
68
- - .rspec
69
- - .travis.yml
63
+ - ".gitignore"
64
+ - ".rspec"
65
+ - ".travis.yml"
70
66
  - Gemfile
71
67
  - LICENSE.txt
72
68
  - README.md
@@ -78,13 +74,15 @@ files:
78
74
  - lib/pnglitch/filter.rb
79
75
  - lib/pnglitch/scanline.rb
80
76
  - pnglitch.gemspec
81
- - spec/fixtures/bomb.png
82
77
  - spec/fixtures/filter_average
83
78
  - spec/fixtures/filter_none
84
79
  - spec/fixtures/filter_paeth
85
80
  - spec/fixtures/filter_sub
86
81
  - spec/fixtures/filter_up
87
82
  - spec/fixtures/in.png
83
+ - spec/fixtures/ina.png
84
+ - spec/fixtures/inb.png
85
+ - spec/fixtures/inc.png
88
86
  - spec/pnglitch_filter_spec.rb
89
87
  - spec/pnglitch_spec.rb
90
88
  - spec/spec_helper.rb
@@ -98,28 +96,33 @@ require_paths:
98
96
  - lib
99
97
  required_ruby_version: !ruby/object:Gem::Requirement
100
98
  requirements:
101
- - - '>='
99
+ - - ">="
102
100
  - !ruby/object:Gem::Version
103
101
  version: 2.0.0
104
102
  required_rubygems_version: !ruby/object:Gem::Requirement
105
103
  requirements:
106
- - - '>='
104
+ - - ">="
107
105
  - !ruby/object:Gem::Version
108
106
  version: '0'
109
107
  requirements: []
110
108
  rubyforge_project:
111
- rubygems_version: 2.0.14
109
+ rubygems_version: 2.4.5
112
110
  signing_key:
113
111
  specification_version: 4
114
- summary: A Ruby library to glitch PNG images.
112
+ summary: PNGlitch is a Ruby library to destroy your PNG images. With normal data-bending
113
+ technique, a glitch against PNG will easily fail because of the checksum function.
114
+ We provide a fail-proof destruction for it. Using this library you will see beautiful
115
+ and various PNG artifacts.
115
116
  test_files:
116
- - spec/fixtures/bomb.png
117
117
  - spec/fixtures/filter_average
118
118
  - spec/fixtures/filter_none
119
119
  - spec/fixtures/filter_paeth
120
120
  - spec/fixtures/filter_sub
121
121
  - spec/fixtures/filter_up
122
122
  - spec/fixtures/in.png
123
+ - spec/fixtures/ina.png
124
+ - spec/fixtures/inb.png
125
+ - spec/fixtures/inc.png
123
126
  - spec/pnglitch_filter_spec.rb
124
127
  - spec/pnglitch_spec.rb
125
128
  - spec/spec_helper.rb