axon 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gemtest +0 -0
- data/CHANGELOG.rdoc +3 -0
- data/README.rdoc +104 -0
- data/Rakefile +30 -0
- data/TODO.rdoc +12 -0
- data/ext/axon/axon.c +20 -0
- data/ext/axon/bilinear_interpolation.c +115 -0
- data/ext/axon/extconf.rb +21 -0
- data/ext/axon/iccjpeg.c +248 -0
- data/ext/axon/iccjpeg.h +73 -0
- data/ext/axon/interpolation.h +7 -0
- data/ext/axon/jpeg_common.c +118 -0
- data/ext/axon/jpeg_common.h +37 -0
- data/ext/axon/jpeg_native_writer.c +248 -0
- data/ext/axon/jpeg_reader.c +774 -0
- data/ext/axon/nearest_neighbor_interpolation.c +50 -0
- data/ext/axon/png_common.c +21 -0
- data/ext/axon/png_common.h +18 -0
- data/ext/axon/png_native_writer.c +166 -0
- data/ext/axon/png_reader.c +381 -0
- data/lib/axon/axon.so +0 -0
- data/lib/axon/bilinear_scaler.rb +60 -0
- data/lib/axon/cropper.rb +35 -0
- data/lib/axon/fit.rb +67 -0
- data/lib/axon/jpeg_writer.rb +41 -0
- data/lib/axon/nearest_neighbor_scaler.rb +39 -0
- data/lib/axon/png_writer.rb +35 -0
- data/lib/axon/scaler.rb +41 -0
- data/lib/axon/solid.rb +23 -0
- data/lib/axon.rb +45 -0
- data/test/_test_readme.rb +34 -0
- data/test/helper.rb +17 -0
- data/test/reader_tests.rb +115 -0
- data/test/stress_tests.rb +71 -0
- data/test/test_bilinear_scaler.rb +9 -0
- data/test/test_cropper.rb +9 -0
- data/test/test_exif.rb +39 -0
- data/test/test_generator.rb +10 -0
- data/test/test_icc.rb +18 -0
- data/test/test_jpeg.rb +9 -0
- data/test/test_jpeg_reader.rb +109 -0
- data/test/test_jpeg_writer.rb +26 -0
- data/test/test_nearest_neighbor_scaler.rb +13 -0
- data/test/test_png.rb +9 -0
- data/test/test_png_reader.rb +15 -0
- data/test/test_png_writer.rb +13 -0
- data/test/writer_tests.rb +179 -0
- metadata +148 -0
data/lib/axon/cropper.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
module Axon
|
2
|
+
class Cropper
|
3
|
+
include Enumerable
|
4
|
+
include Image
|
5
|
+
|
6
|
+
attr_reader :image, :width, :height, :components, :color_model
|
7
|
+
|
8
|
+
def initialize(image, width, height, x_offset=nil, y_offset=nil)
|
9
|
+
@image = image
|
10
|
+
@width = width
|
11
|
+
@height = height
|
12
|
+
@x_offset = x_offset || 0
|
13
|
+
@y_offset = y_offset || 0
|
14
|
+
@components = image.components
|
15
|
+
@color_model = image.color_model
|
16
|
+
end
|
17
|
+
|
18
|
+
def each
|
19
|
+
sl_width = @width * @components
|
20
|
+
sl_offset = @x_offset * @components
|
21
|
+
|
22
|
+
@image.each_with_index do |orig_sl, i|
|
23
|
+
next if i < @y_offset
|
24
|
+
yield orig_sl[sl_offset, sl_width]
|
25
|
+
break if i == @height - 1
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
module Image
|
31
|
+
def crop(*args)
|
32
|
+
Cropper.new(self, *args)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
data/lib/axon/fit.rb
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
module Axon
|
2
|
+
class Fit
|
3
|
+
include Image
|
4
|
+
include Enumerable
|
5
|
+
|
6
|
+
def initialize(source, width, height)
|
7
|
+
@source, @fit_width, @fit_height = source, width, height
|
8
|
+
end
|
9
|
+
|
10
|
+
def components
|
11
|
+
@source.components
|
12
|
+
end
|
13
|
+
|
14
|
+
def color_model
|
15
|
+
@source.color_model
|
16
|
+
end
|
17
|
+
|
18
|
+
def width
|
19
|
+
@source.width * calc_fit_ratio
|
20
|
+
end
|
21
|
+
|
22
|
+
def height
|
23
|
+
@source.height * calc_fit_ratio
|
24
|
+
end
|
25
|
+
|
26
|
+
def each
|
27
|
+
r = calc_fit_ratio
|
28
|
+
|
29
|
+
if r > 1
|
30
|
+
scaler = NearestNeighborScaler.new(@source, r)
|
31
|
+
scaler.each{ |*a| yield(*a) }
|
32
|
+
elsif r < 1
|
33
|
+
if r <= 0.5 && @source.kind_of?(JPEGReader)
|
34
|
+
@source.scale_denom = calc_jpeg_pre_shrink(r)
|
35
|
+
r = calc_fit_ratio
|
36
|
+
end
|
37
|
+
scaler = BilinearScaler.new(@source, r)
|
38
|
+
scaler.each{ |*a| yield(*a) }
|
39
|
+
else
|
40
|
+
@source.each{ |*a| yield(*a) }
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def calc_fit_ratio
|
47
|
+
width_ratio = @fit_width.to_f / @source.width
|
48
|
+
height_ratio = @fit_height.to_f / @source.height
|
49
|
+
[width_ratio, height_ratio].min
|
50
|
+
end
|
51
|
+
|
52
|
+
def calc_jpeg_pre_shrink(r)
|
53
|
+
case (1/r)
|
54
|
+
when (0...2) then nil
|
55
|
+
when (2...4) then 2
|
56
|
+
when (4...8) then 4
|
57
|
+
else 8
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
module Image
|
63
|
+
def fit(*args)
|
64
|
+
Fit.new(self, *args)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'stringio'
|
2
|
+
|
3
|
+
module Axon
|
4
|
+
class JPEGWriter
|
5
|
+
include JPEGNativeWriter
|
6
|
+
|
7
|
+
attr_accessor :quality, :icc_profile, :exif
|
8
|
+
attr_reader :io, :bufsize, :image
|
9
|
+
|
10
|
+
def initialize(image)
|
11
|
+
@image = image
|
12
|
+
@quality = nil
|
13
|
+
@icc_profile = nil
|
14
|
+
@exif = nil
|
15
|
+
end
|
16
|
+
|
17
|
+
def write(io, bufsize = nil)
|
18
|
+
@bufsize = bufsize || 512
|
19
|
+
@io = io
|
20
|
+
jpeg_native_write
|
21
|
+
end
|
22
|
+
|
23
|
+
def data
|
24
|
+
s = StringIO.new
|
25
|
+
s.set_encoding 'BINARY' if s.respond_to?(:set_encoding)
|
26
|
+
|
27
|
+
write(s)
|
28
|
+
s.string
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
module Image
|
33
|
+
def to_jpeg(*args)
|
34
|
+
JPEGWriter.new self, *args
|
35
|
+
end
|
36
|
+
|
37
|
+
def write_jpeg(io)
|
38
|
+
JPEGWriter.new(self).write(io)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Axon
|
2
|
+
class NearestNeighborScaler < Scaler
|
3
|
+
include NearestNeighborScaling
|
4
|
+
include Image
|
5
|
+
include Enumerable
|
6
|
+
|
7
|
+
def each
|
8
|
+
dest_y = 0
|
9
|
+
sample_y = 0
|
10
|
+
|
11
|
+
@image.each_with_index do |scanline, orig_y|
|
12
|
+
while sample_y == orig_y
|
13
|
+
yield interpolate_scanline(scanline)
|
14
|
+
dest_y += 1
|
15
|
+
sample_y = (dest_y / @height_ratio).to_i
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def _interpolate_scanline(scanline)
|
23
|
+
dest_sl = ''
|
24
|
+
|
25
|
+
scanline.size.times do |dest_x|
|
26
|
+
sample_x = (dest_x / @width_ratio).to_i
|
27
|
+
dest_sl << scanline[sample_x * components, components]
|
28
|
+
end
|
29
|
+
|
30
|
+
return dest_sl
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
module Image
|
35
|
+
def scale_nearest_neighbor(*args)
|
36
|
+
NearestNeighborScaler.new(self, *args)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'stringio'
|
2
|
+
|
3
|
+
module Axon
|
4
|
+
class PNGWriter
|
5
|
+
include PNGNativeWriter
|
6
|
+
|
7
|
+
attr_reader :image
|
8
|
+
|
9
|
+
def initialize(image)
|
10
|
+
@image = image
|
11
|
+
end
|
12
|
+
|
13
|
+
def write(io)
|
14
|
+
png_native_write(io)
|
15
|
+
end
|
16
|
+
|
17
|
+
def data
|
18
|
+
s = StringIO.new
|
19
|
+
s.set_encoding 'BINARY' if s.respond_to?(:set_encoding)
|
20
|
+
|
21
|
+
write(s)
|
22
|
+
s.string
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
module Image
|
27
|
+
def to_png
|
28
|
+
PNGWriter.new self
|
29
|
+
end
|
30
|
+
|
31
|
+
def write_png(io)
|
32
|
+
PNGWriter.new(self).write(io)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
data/lib/axon/scaler.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
module Axon
|
2
|
+
class Scaler
|
3
|
+
attr_reader :width, :height
|
4
|
+
|
5
|
+
def initialize(image, *args)
|
6
|
+
@image = image
|
7
|
+
|
8
|
+
if args.size == 1
|
9
|
+
init_ratio(args[0])
|
10
|
+
elsif args.size == 2
|
11
|
+
init_dims(args[0], args[1])
|
12
|
+
else
|
13
|
+
raise ArgumentError, "Must give one or two arguments"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def components
|
18
|
+
@image.components
|
19
|
+
end
|
20
|
+
|
21
|
+
def color_model
|
22
|
+
@image.color_model
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def init_ratio(ratio)
|
28
|
+
@width_ratio = @height_ratio = ratio.to_f
|
29
|
+
@width = (@image.width * ratio).floor
|
30
|
+
@height = (@image.height * ratio).floor
|
31
|
+
end
|
32
|
+
|
33
|
+
def init_dims(width, height)
|
34
|
+
@width_ratio = width.to_f / @image.width
|
35
|
+
@width = width
|
36
|
+
|
37
|
+
@height_ratio = height.to_f / @image.height
|
38
|
+
@height = height
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/lib/axon/solid.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
module Axon
|
2
|
+
class Solid
|
3
|
+
include Image
|
4
|
+
include Enumerable
|
5
|
+
attr_reader :width, :height, :color_model, :components
|
6
|
+
|
7
|
+
def initialize(width, height, color=nil, color_model=nil)
|
8
|
+
@width, @height = width, height
|
9
|
+
@color = color || "\x00\x00\x00"
|
10
|
+
@color_model = color_model || :RGB
|
11
|
+
@components = @color.size
|
12
|
+
end
|
13
|
+
|
14
|
+
def each
|
15
|
+
sl = @color * width
|
16
|
+
height.times { yield sl }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
module Image
|
21
|
+
# empty
|
22
|
+
end
|
23
|
+
end
|
data/lib/axon.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'axon/axon'
|
2
|
+
|
3
|
+
require 'axon/solid'
|
4
|
+
require 'axon/cropper'
|
5
|
+
require 'axon/scaler'
|
6
|
+
require 'axon/nearest_neighbor_scaler'
|
7
|
+
require 'axon/bilinear_scaler'
|
8
|
+
require 'axon/fit'
|
9
|
+
|
10
|
+
require 'axon/jpeg_writer'
|
11
|
+
require 'axon/png_writer'
|
12
|
+
|
13
|
+
module Axon
|
14
|
+
VERSION = '0.0.1'
|
15
|
+
|
16
|
+
def self.JPEG(thing, markers=nil)
|
17
|
+
if thing.respond_to? :read
|
18
|
+
io = thing
|
19
|
+
rewind_after_scanlines = false
|
20
|
+
elsif thing[0, 1] == "\xFF"
|
21
|
+
io = StringIO.new(thing)
|
22
|
+
rewind_after_scanlines = true
|
23
|
+
else
|
24
|
+
io = File.open(thing)
|
25
|
+
rewind_after_scanlines = true
|
26
|
+
end
|
27
|
+
|
28
|
+
JPEGReader.new(io, markers, rewind_after_scanlines)
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.PNG(thing)
|
32
|
+
if thing.respond_to? :read
|
33
|
+
io = thing
|
34
|
+
rewind_after_scanlines = false
|
35
|
+
elsif thing[0, 1] == "\x89"
|
36
|
+
io = StringIO.new(thing)
|
37
|
+
rewind_after_scanlines = true
|
38
|
+
else
|
39
|
+
io = File.open(thing)
|
40
|
+
rewind_after_scanlines = true
|
41
|
+
end
|
42
|
+
|
43
|
+
PNGReader.new(io)
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
module Axon
|
4
|
+
class TestReader < AxonTestCase
|
5
|
+
def setup
|
6
|
+
data = Solid.new(100, 200, "\x0A\x14\x69").to_jpeg.data
|
7
|
+
@io_in = StringIO.new(data)
|
8
|
+
@io_out = StringIO.new
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_short_chained_example
|
12
|
+
|
13
|
+
# Short, chained example. Reads a JPEG from io_in and writes scaled png to
|
14
|
+
# io_out.
|
15
|
+
Axon.JPEG(@io_in).fit(100, 100).write_png(@io_out)
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_longer_example
|
19
|
+
# Even longer example, reads the JPEG header, looks at properties and header
|
20
|
+
# values, sets decompression options, scales the image, sets compression
|
21
|
+
# options, and writes a JPEG.
|
22
|
+
image = Axon.JPEG(@io_in, [:APP2])
|
23
|
+
|
24
|
+
puts image.width
|
25
|
+
puts image.height
|
26
|
+
puts image[:APP2]
|
27
|
+
image.scale_denom = 4
|
28
|
+
|
29
|
+
jpeg = image.fit(100, 100).to_jpeg
|
30
|
+
jpeg.quality = 88
|
31
|
+
jpeg.write(@io_out)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/test/helper.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'axon'
|
3
|
+
require 'stringio'
|
4
|
+
require 'reader_tests'
|
5
|
+
require 'writer_tests'
|
6
|
+
|
7
|
+
module Axon
|
8
|
+
class AxonTestCase < MiniTest::Unit::TestCase
|
9
|
+
|
10
|
+
# Generate a solid velvet JPEG
|
11
|
+
def setup
|
12
|
+
@velvet = "\x0A\x14\x69"
|
13
|
+
@image = Solid.new 10, 15, @velvet
|
14
|
+
@io_out = StringIO.new
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
module Axon
|
2
|
+
module ReaderTests
|
3
|
+
def test_read_image_from_io
|
4
|
+
assert_equal 10, @reader.width
|
5
|
+
assert_equal 15, @reader.height
|
6
|
+
end
|
7
|
+
|
8
|
+
def test_read_image_from_string
|
9
|
+
assert_equal 10, @reader.width
|
10
|
+
assert_equal 15, @reader.height
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_num_components
|
14
|
+
assert_equal 3, @reader.components
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_color_model
|
18
|
+
assert_equal :RGB, @reader.color_model
|
19
|
+
end
|
20
|
+
|
21
|
+
class DoubleIO < StringIO
|
22
|
+
def read(*args)
|
23
|
+
s = super
|
24
|
+
s[0..20] * 100
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_io_returns_too_much
|
29
|
+
f = DoubleIO.new @data
|
30
|
+
assert_raises(RuntimeError) { @readerclass.new f }
|
31
|
+
end
|
32
|
+
|
33
|
+
class NilIO
|
34
|
+
def read(*args); end
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_io_returns_nil
|
38
|
+
assert_raises(RuntimeError) { @readerclass.new NilIO.new }
|
39
|
+
end
|
40
|
+
|
41
|
+
class RaiseIO
|
42
|
+
def read(*args)
|
43
|
+
raise 'heck'
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_io_raises_exception
|
48
|
+
assert_raises(RuntimeError) { @readerclass.new RaiseIO.new }
|
49
|
+
end
|
50
|
+
|
51
|
+
class EmptyStringIO
|
52
|
+
def read(*args)
|
53
|
+
""
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_empty_string_io
|
58
|
+
assert_raises(RuntimeError) { @readerclass.new EmptyStringIO.new }
|
59
|
+
end
|
60
|
+
|
61
|
+
class ThatsNotAStringIO
|
62
|
+
def read(*args)
|
63
|
+
:this_should_be_a_string
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def test_not_a_string_io
|
68
|
+
assert_raises(TypeError) { @readerclass.new ThatsNotAStringIO.new }
|
69
|
+
end
|
70
|
+
|
71
|
+
def test_each
|
72
|
+
size = @reader.width * @reader.components
|
73
|
+
|
74
|
+
@reader.each do |scan_line|
|
75
|
+
assert_equal size, scan_line.size
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def test_no_shenanigans_during_each
|
80
|
+
@reader.each do |sl|
|
81
|
+
assert_raises(RuntimeError) { @reader.each{} }
|
82
|
+
break
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
class OneExceptionIO < StringIO
|
87
|
+
def initialize(*args)
|
88
|
+
@raised_exception = false
|
89
|
+
super
|
90
|
+
end
|
91
|
+
|
92
|
+
def read(*args)
|
93
|
+
unless @raised_exception
|
94
|
+
@raised_exception = true
|
95
|
+
raise 'heck'
|
96
|
+
end
|
97
|
+
super
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def test_recovers_from_initial_io_exception
|
102
|
+
io = OneExceptionIO.new @data
|
103
|
+
r = @readerclass.allocate
|
104
|
+
assert_raises(RuntimeError) { r.send(:initialize, io) }
|
105
|
+
r.send(:initialize, io)
|
106
|
+
r.each{ }
|
107
|
+
end
|
108
|
+
|
109
|
+
def test_multiple_each_calls
|
110
|
+
@reader.each{ }
|
111
|
+
@io_in.rewind
|
112
|
+
@reader.each{ }
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
module Axon
|
4
|
+
class TestStressCases < AxonTestCase
|
5
|
+
def setup
|
6
|
+
@velvet = "\x0A\x14\x69"
|
7
|
+
@image = Generator::Solid.new 1000, 1500, @velvet
|
8
|
+
@jpeg_data = @image.to_jpeg.data
|
9
|
+
@readerclass = JPEGReader
|
10
|
+
end
|
11
|
+
|
12
|
+
class RandomRaiseIO
|
13
|
+
def initialize(source)
|
14
|
+
@io = StringIO.new source
|
15
|
+
@die_at = rand(source.size)
|
16
|
+
end
|
17
|
+
|
18
|
+
def read
|
19
|
+
if @die_at < 2
|
20
|
+
raise 'random death!'
|
21
|
+
end
|
22
|
+
|
23
|
+
read_size = rand @die_at
|
24
|
+
@die_at -= read_size
|
25
|
+
@io.read(read_size)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_io_raises_after_random_sized_reads
|
30
|
+
loop do
|
31
|
+
f = RandomRaiseIO.new(@jpeg_data)
|
32
|
+
r = @readerclass.new(f) rescue puts("new failed")
|
33
|
+
r.each{} rescue puts('each_sl failed')
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class CustomIO < StringIO
|
38
|
+
def initialize(str, sequence)
|
39
|
+
super str
|
40
|
+
@sequence = sequence
|
41
|
+
end
|
42
|
+
|
43
|
+
def read
|
44
|
+
if !@sequence || @sequence.empty?
|
45
|
+
raise "random death!"
|
46
|
+
@sequence = nil
|
47
|
+
end
|
48
|
+
super(@sequence.shift)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_custom_io_error
|
53
|
+
loop do
|
54
|
+
f = CustomIO.new(@jpeg_data, [114, 64, 8, 200, 200, 30, 350])
|
55
|
+
|
56
|
+
r = @readerclass.new(f)
|
57
|
+
r.each{ } rescue nil
|
58
|
+
f = CustomIO.new(@jpeg_data, [101, 0])
|
59
|
+
r = @readerclass.new(f) rescue nil
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_io_returns_nil_after_random_sized_reads
|
64
|
+
loop do
|
65
|
+
f = SometimesNilIO.new(@data)
|
66
|
+
r = @readerclass.new(f)
|
67
|
+
r.each{}
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
data/test/test_exif.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
module Axon
|
4
|
+
class TestExif < AxonTestCase
|
5
|
+
def test_exif_roundtrip
|
6
|
+
random_data = ""
|
7
|
+
(100).times do
|
8
|
+
random_data << [rand].pack('d') # 800 bytes random data
|
9
|
+
end
|
10
|
+
|
11
|
+
writer = @image.to_jpeg
|
12
|
+
writer.exif = random_data
|
13
|
+
|
14
|
+
image_with_exif = Axon.JPEG(writer.data)
|
15
|
+
assert_equal random_data, image_with_exif.exif
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_exif_with_icc_roundtrip
|
19
|
+
random_icc_data = ""
|
20
|
+
(2**16).times do # a little larger than one jpeg segment
|
21
|
+
random_icc_data << [rand].pack('d') # 8 bytes random data
|
22
|
+
end
|
23
|
+
|
24
|
+
random_exif_data = ""
|
25
|
+
(100).times do
|
26
|
+
random_exif_data << [rand].pack('d') # 800 bytes random data
|
27
|
+
end
|
28
|
+
|
29
|
+
writer = @image.to_jpeg
|
30
|
+
writer.icc_profile = random_icc_data
|
31
|
+
writer.exif = random_exif_data
|
32
|
+
|
33
|
+
image_with_exif_and_icc = Axon.JPEG(writer.data)
|
34
|
+
|
35
|
+
assert_equal random_exif_data, image_with_exif_and_icc.exif
|
36
|
+
assert_equal random_icc_data, image_with_exif_and_icc.icc_profile
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/test/test_icc.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
module Axon
|
4
|
+
class TestICC < AxonTestCase
|
5
|
+
def test_large_icc_roundtrip
|
6
|
+
random_data = ""
|
7
|
+
(2**16).times do # a little larger than one jpeg segment
|
8
|
+
random_data << [rand].pack('d') # 8 bytes random data
|
9
|
+
end
|
10
|
+
|
11
|
+
writer = @image.to_jpeg
|
12
|
+
writer.icc_profile = random_data
|
13
|
+
|
14
|
+
image_with_icc = Axon.JPEG(writer.data)
|
15
|
+
assert_equal random_data, image_with_icc.icc_profile
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|