pnglitch 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.
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