eyes_core 3.0.7 → 3.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/ext/eyes_core/eyes_core.c +128 -2
- data/ext/eyes_core/eyes_core.h +4 -0
- data/lib/applitools/chunky_png/resampling.rb +11 -109
- data/lib/applitools/core/screenshot.rb +9 -0
- data/lib/applitools/utils/image_utils.rb +4 -2
- data/lib/applitools/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 734dda49eb71281c85770bc8e075346b303417f8
|
4
|
+
data.tar.gz: '08dfc01e914c3c9d42958d018dba34a8a3305060'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3365239f1bf1f1843936585a9c25bc7c2804d5ee72ff3928e32e242d0cff34447af492545298a1c13f0e819668016eb4ea5730cec7b6dd1a5f46575e8c6c9195
|
7
|
+
data.tar.gz: 5292266eaf979ff3caad6b05cb937fa64e9eb25f0e67378625f26ca4450da4460563615c5601564468ddfff0c5767f98602b6dd827293bc418448e0bfa8de1e5
|
data/ext/eyes_core/eyes_core.c
CHANGED
@@ -5,12 +5,13 @@ void Init_eyes_core() {
|
|
5
5
|
VALUE Resampling = rb_define_module_under(Applitools, "ResamplingFast");
|
6
6
|
rb_define_method(Resampling, "interpolate_cubic", c_interpolate_cubic, 1);
|
7
7
|
rb_define_method(Resampling, "merge_pixels", c_merge_pixels, 1);
|
8
|
+
rb_define_method(Resampling, "bicubic_points2", c_bicubic_points, 3);
|
9
|
+
rb_define_method(Resampling, "scale_points2", scale_points2, 4);
|
8
10
|
};
|
9
11
|
|
10
12
|
|
11
13
|
VALUE c_interpolate_cubic(VALUE self, VALUE data) {
|
12
14
|
double t = NUM2DBL(rb_ary_entry(data, 1));
|
13
|
-
BYTE new_r, new_g, new_b, new_a;
|
14
15
|
VALUE p0, p1, p2, p3;
|
15
16
|
|
16
17
|
p0 = NUM2UINT(rb_ary_entry(data, 2));
|
@@ -18,13 +19,19 @@ VALUE c_interpolate_cubic(VALUE self, VALUE data) {
|
|
18
19
|
p2 = NUM2UINT(rb_ary_entry(data, 4));
|
19
20
|
p3 = NUM2UINT(rb_ary_entry(data, 5));
|
20
21
|
|
22
|
+
return raw_interpolate_cubic(self, t, p0, p1, p2, p3);
|
23
|
+
};
|
24
|
+
|
25
|
+
VALUE raw_interpolate_cubic(VALUE self, double t, VALUE p0, VALUE p1, VALUE p2, VALUE p3) {
|
26
|
+
BYTE new_r, new_g, new_b, new_a;
|
27
|
+
|
21
28
|
new_r = interpolate_char(t, R_BYTE(p0), R_BYTE(p1), R_BYTE(p2), R_BYTE(p3));
|
22
29
|
new_g = interpolate_char(t, G_BYTE(p0), G_BYTE(p1), G_BYTE(p2), G_BYTE(p3));
|
23
30
|
new_b = interpolate_char(t, B_BYTE(p0), B_BYTE(p1), B_BYTE(p2), B_BYTE(p3));
|
24
31
|
new_a = interpolate_char(t, A_BYTE(p0), A_BYTE(p1), A_BYTE(p2), A_BYTE(p3));
|
25
32
|
|
26
33
|
return UINT2NUM(BUILD_PIXEL(new_r, new_g, new_b, new_a));
|
27
|
-
}
|
34
|
+
}
|
28
35
|
|
29
36
|
BYTE interpolate_char(double t, BYTE c0, BYTE c1, BYTE c2, BYTE c3) {
|
30
37
|
double a, b, c, d, res;
|
@@ -78,3 +85,122 @@ VALUE c_merge_pixels(VALUE self, VALUE pixels) {
|
|
78
85
|
new_a = (BYTE)(acum_a/(size - 1) + 0.5);
|
79
86
|
return UINT2NUM(BUILD_PIXEL(new_r, new_g, new_b, new_a));
|
80
87
|
}
|
88
|
+
|
89
|
+
VALUE raw_merge_pixels(VALUE merge_pixels[], unsigned int size) {
|
90
|
+
unsigned int i, real_colors, acum_r, acum_g, acum_b, acum_a;
|
91
|
+
BYTE new_r, new_g, new_b, new_a;
|
92
|
+
PIXEL pix;
|
93
|
+
|
94
|
+
acum_r = 0;
|
95
|
+
acum_g = 0;
|
96
|
+
acum_b = 0;
|
97
|
+
acum_a = 0;
|
98
|
+
|
99
|
+
new_r = 0;
|
100
|
+
new_g = 0;
|
101
|
+
new_b = 0;
|
102
|
+
new_a = 0;
|
103
|
+
|
104
|
+
real_colors = 0;
|
105
|
+
|
106
|
+
for(i=0; i < size; i++) {
|
107
|
+
pix = NUM2UINT(merge_pixels[i]);
|
108
|
+
if(A_BYTE(pix) != 0) {
|
109
|
+
acum_r += R_BYTE(pix);
|
110
|
+
acum_g += G_BYTE(pix);
|
111
|
+
acum_b += B_BYTE(pix);
|
112
|
+
acum_a += A_BYTE(pix);
|
113
|
+
real_colors += 1;
|
114
|
+
}
|
115
|
+
}
|
116
|
+
|
117
|
+
if(real_colors > 0) {
|
118
|
+
new_r = (BYTE)(acum_r/real_colors + 0.5);
|
119
|
+
new_g = (BYTE)(acum_g/real_colors + 0.5);
|
120
|
+
new_b = (BYTE)(acum_b/real_colors + 0.5);
|
121
|
+
}
|
122
|
+
new_a = (BYTE)(acum_a/(size - 1) + 0.5);
|
123
|
+
return UINT2NUM(BUILD_PIXEL(new_r, new_g, new_b, new_a));
|
124
|
+
}
|
125
|
+
|
126
|
+
VALUE c_bicubic_points(VALUE self, VALUE src_dimension, VALUE dst_dimension, VALUE direction) {
|
127
|
+
unsigned long y_bounds, pixels_size, c_src_dimension, c_dst_dimension, index, index_y;
|
128
|
+
double step;
|
129
|
+
VALUE result_array;
|
130
|
+
|
131
|
+
unsigned long steps [NUM2UINT(dst_dimension)];
|
132
|
+
double residues [NUM2UINT(dst_dimension)];
|
133
|
+
VALUE line_bounds;
|
134
|
+
|
135
|
+
c_src_dimension = NUM2UINT(src_dimension);
|
136
|
+
c_dst_dimension = NUM2UINT(dst_dimension);
|
137
|
+
|
138
|
+
step = (double)(c_src_dimension - 1) / c_dst_dimension;
|
139
|
+
|
140
|
+
if (RTEST(direction)) {
|
141
|
+
y_bounds = NUM2UINT(rb_funcall(self, rb_intern("width"), 0, NULL));
|
142
|
+
} else {
|
143
|
+
y_bounds = NUM2UINT(rb_funcall(self, rb_intern("height"), 0, NULL));
|
144
|
+
};
|
145
|
+
|
146
|
+
pixels_size = y_bounds * c_dst_dimension;
|
147
|
+
result_array = rb_ary_new2(pixels_size);
|
148
|
+
|
149
|
+
for (unsigned long i=0; i < c_dst_dimension; i++) {
|
150
|
+
steps[i] = (unsigned long)i*step;
|
151
|
+
residues[i] = i*step - steps[i];
|
152
|
+
};
|
153
|
+
|
154
|
+
for (unsigned long y=0; y < y_bounds; y++) {
|
155
|
+
line_bounds = rb_funcall(self, rb_intern("line_with_bounds"), 3, UINT2NUM(y), src_dimension, direction);
|
156
|
+
|
157
|
+
index_y = c_dst_dimension * y;
|
158
|
+
for (unsigned long x=0; x < c_dst_dimension; x++) {
|
159
|
+
if (RTEST(direction)) {
|
160
|
+
index = y_bounds * x + y;
|
161
|
+
} else {
|
162
|
+
index = index_y + x;
|
163
|
+
}
|
164
|
+
rb_ary_store(result_array, index, raw_interpolate_cubic(self, residues[x],
|
165
|
+
NUM2UINT(rb_ary_entry(line_bounds, steps[x])),
|
166
|
+
NUM2UINT(rb_ary_entry(line_bounds, steps[x] + 1)),
|
167
|
+
NUM2UINT(rb_ary_entry(line_bounds, steps[x] + 2)),
|
168
|
+
NUM2UINT(rb_ary_entry(line_bounds, steps[x] + 3)))
|
169
|
+
);
|
170
|
+
}
|
171
|
+
}
|
172
|
+
|
173
|
+
return result_array;
|
174
|
+
}
|
175
|
+
|
176
|
+
VALUE scale_points2(VALUE self, VALUE dst_width, VALUE dst_height, VALUE w_m, VALUE h_m) {
|
177
|
+
unsigned long c_dst_height, c_dst_width, y_pos, x_pos, index;
|
178
|
+
unsigned int c_w_m, c_h_m, buffer_index, buffer_size;
|
179
|
+
VALUE pixels_to_merge [NUM2UINT(w_m) * NUM2UINT(h_m)];
|
180
|
+
VALUE result;
|
181
|
+
|
182
|
+
c_dst_height = NUM2UINT(dst_height);
|
183
|
+
c_dst_width = NUM2UINT(dst_width);
|
184
|
+
|
185
|
+
c_w_m = NUM2UINT(w_m);
|
186
|
+
c_h_m = NUM2UINT(h_m);
|
187
|
+
|
188
|
+
result = rb_ary_new2(c_dst_width * c_dst_height);
|
189
|
+
buffer_size = c_h_m * c_w_m;
|
190
|
+
|
191
|
+
for (unsigned long i = 0; i < c_dst_height; i++) {
|
192
|
+
for (unsigned long j = 0; j < c_dst_width; j++) {
|
193
|
+
buffer_index = 0;
|
194
|
+
for (unsigned int y = 0; y < c_h_m; y++) {
|
195
|
+
y_pos = i * c_h_m + y;
|
196
|
+
for (unsigned int x = 0; x < c_w_m; x++) {
|
197
|
+
x_pos = j * c_w_m + x;
|
198
|
+
pixels_to_merge[buffer_index++] = rb_funcall(self, rb_intern("get_pixel"), 2, UINT2NUM(x_pos), UINT2NUM(y_pos));
|
199
|
+
}
|
200
|
+
}
|
201
|
+
index = i * c_dst_width + j;
|
202
|
+
rb_ary_store(result, index, raw_merge_pixels(pixels_to_merge, buffer_size));
|
203
|
+
}
|
204
|
+
}
|
205
|
+
return result;
|
206
|
+
}
|
data/ext/eyes_core/eyes_core.h
CHANGED
@@ -18,7 +18,11 @@ typedef unsigned char BYTE; // Bytes use 8 bits unsigned integers
|
|
18
18
|
void Init_resampling();
|
19
19
|
|
20
20
|
VALUE c_interpolate_cubic(VALUE,VALUE);
|
21
|
+
VALUE raw_interpolate_cubic(VALUE, double, VALUE, VALUE, VALUE, VALUE);
|
22
|
+
VALUE scale_points2(VALUE, VALUE, VALUE, VALUE, VALUE);
|
21
23
|
VALUE c_merge_pixels(VALUE, VALUE);
|
24
|
+
VALUE raw_merge_pixels(VALUE[], unsigned int);
|
25
|
+
VALUE c_bicubic_points(VALUE, VALUE, VALUE, VALUE);
|
22
26
|
BYTE interpolate_char(double, BYTE, BYTE, BYTE, BYTE);
|
23
27
|
|
24
28
|
#endif
|
@@ -7,31 +7,15 @@ module Applitools::ChunkyPNG
|
|
7
7
|
dst_width2 = dst_width * w_m
|
8
8
|
dst_height2 = dst_height * h_m
|
9
9
|
|
10
|
-
|
11
|
-
pixels = Array.new(points.size)
|
12
|
-
|
13
|
-
points.each do |interpolation_data|
|
14
|
-
pixels[interpolation_data[0]] = interpolate_cubic(interpolation_data)
|
15
|
-
end
|
10
|
+
pixels = bicubic_x_points(dst_width2)
|
16
11
|
replace_canvas!(dst_width2, height, pixels)
|
17
12
|
|
18
|
-
|
19
|
-
pixels = Array.new(points.size)
|
20
|
-
|
21
|
-
points.each do |interpolation_data|
|
22
|
-
pixels[interpolation_data[0]] = interpolate_cubic(interpolation_data)
|
23
|
-
end
|
13
|
+
pixels = bicubic_y_points(dst_height2)
|
24
14
|
replace_canvas!(dst_width2, dst_height2, pixels)
|
25
15
|
|
26
16
|
return self unless w_m * h_m > 1
|
27
17
|
|
28
|
-
|
29
|
-
pixels = Array.new(points.size)
|
30
|
-
|
31
|
-
points.each do |merge_data|
|
32
|
-
pixels[merge_data[0]] = merge_pixels(merge_data)
|
33
|
-
end
|
34
|
-
|
18
|
+
pixels = scale_points2(dst_width, dst_height, w_m, h_m);
|
35
19
|
replace_canvas!(dst_width, dst_height, pixels)
|
36
20
|
end
|
37
21
|
|
@@ -40,101 +24,19 @@ module Applitools::ChunkyPNG
|
|
40
24
|
end
|
41
25
|
|
42
26
|
def bicubic_x_points(dst_width)
|
43
|
-
|
27
|
+
bicubic_points2(width, dst_width, false)
|
44
28
|
end
|
45
29
|
|
46
30
|
def bicubic_y_points(dst_height)
|
47
|
-
|
48
|
-
end
|
49
|
-
|
50
|
-
def bicubic_points(src_dimension, dst_dimension, direction, y_start_position = 0)
|
51
|
-
step = (src_dimension - 1).to_f / dst_dimension
|
52
|
-
y_bounds = direction ? width : height
|
53
|
-
raise ArgumentError.new 'Start position value is invalid!' unless y_start_position < y_bounds
|
54
|
-
pixels_size = (y_bounds - y_start_position) * dst_dimension
|
55
|
-
|
56
|
-
steps = Array.new(dst_dimension)
|
57
|
-
residues = Array.new(dst_dimension)
|
58
|
-
|
59
|
-
(0..dst_dimension - 1).each do |i|
|
60
|
-
steps[i] = (i * step).to_i
|
61
|
-
residues[i] = i * step - steps[i]
|
62
|
-
end
|
63
|
-
Enumerator.new(pixels_size) do |enum|
|
64
|
-
(y_start_position..y_bounds - 1).each do |y|
|
65
|
-
line = (direction ? column(y) : row(y))
|
66
|
-
|
67
|
-
line_with_bounds = [imaginable_point(line[0], line[1])] + line + [
|
68
|
-
imaginable_point(line[src_dimension - 2], line[src_dimension - 3]),
|
69
|
-
imaginable_point(line[src_dimension - 1], line[src_dimension - 2])
|
70
|
-
]
|
71
|
-
|
72
|
-
index_y = dst_dimension * y
|
73
|
-
(0..dst_dimension - 1).each do |x|
|
74
|
-
index = direction ? y_bounds * x + y : index_y + x
|
75
|
-
enum << ([index, residues[x]] + line_with_bounds.last(src_dimension + 3 - steps[x]).first(4))
|
76
|
-
end
|
77
|
-
end
|
78
|
-
end
|
31
|
+
bicubic_points2(height, dst_height, true)
|
79
32
|
end
|
80
33
|
|
81
|
-
def
|
82
|
-
|
83
|
-
|
84
|
-
(
|
85
|
-
|
86
|
-
|
87
|
-
y_pos = i * h_m + y
|
88
|
-
(0..w_m - 1).each do |x|
|
89
|
-
x_pos = j * w_m + x
|
90
|
-
pixels_to_merge << get_pixel(x_pos, y_pos)
|
91
|
-
end
|
92
|
-
end
|
93
|
-
index = i * dst_width + j
|
94
|
-
enum << ([index] + pixels_to_merge)
|
95
|
-
end
|
96
|
-
end
|
97
|
-
end
|
98
|
-
end
|
99
|
-
|
100
|
-
def merge_pixels(merge_data)
|
101
|
-
pixels = merge_data[1..merge_data.size]
|
102
|
-
merged_data = pixels.each_with_object(r: 0, g: 0, b: 0, a: 0, real_colors: 0) do |pixel, result|
|
103
|
-
unless ChunkyPNG::Color.fully_transparent?(pixel)
|
104
|
-
result[:real_colors] += 1
|
105
|
-
[:r, :g, :b].each do |ch|
|
106
|
-
result[ch] += ChunkyPNG::Color.send(ch, pixel)
|
107
|
-
end
|
108
|
-
end
|
109
|
-
result[:a] += ChunkyPNG::Color.a(pixel)
|
110
|
-
result
|
111
|
-
end
|
112
|
-
|
113
|
-
r = merged_data[:real_colors] > 0 ? merged_data[:r] / merged_data[:real_colors] : 0
|
114
|
-
g = merged_data[:real_colors] > 0 ? merged_data[:g] / merged_data[:real_colors] : 0
|
115
|
-
b = merged_data[:real_colors] > 0 ? merged_data[:b] / merged_data[:real_colors] : 0
|
116
|
-
a = merged_data[:a] / pixels.size
|
117
|
-
|
118
|
-
ChunkyPNG::Color.rgba(r, g, b, a)
|
119
|
-
end
|
120
|
-
|
121
|
-
def interpolate_cubic(data)
|
122
|
-
result = {}
|
123
|
-
t = data[1]
|
124
|
-
[:r, :g, :b, :a].each do |chan|
|
125
|
-
c0 = ChunkyPNG::Color.send(chan, data[2])
|
126
|
-
c1 = ChunkyPNG::Color.send(chan, data[3])
|
127
|
-
c2 = ChunkyPNG::Color.send(chan, data[4])
|
128
|
-
c3 = ChunkyPNG::Color.send(chan, data[5])
|
129
|
-
|
130
|
-
a = -0.5 * c0 + 1.5 * c1 - 1.5 * c2 + 0.5 * c3
|
131
|
-
b = c0 - 2.5 * c1 + 2 * c2 - 0.5 * c3
|
132
|
-
c = 0.5 * c2 - 0.5 * c0
|
133
|
-
d = c1
|
134
|
-
|
135
|
-
result[chan] = [0, [255, (a * t**3 + b * t**2 + c * t + d).to_i].min].max
|
136
|
-
end
|
137
|
-
ChunkyPNG::Color.rgba(result[:r], result[:g], result[:b], result[:a])
|
34
|
+
def line_with_bounds(y, src_dimension, direction)
|
35
|
+
line = (direction ? column(y) : row(y))
|
36
|
+
[imaginable_point(line[0], line[1])] + line + [
|
37
|
+
imaginable_point(line[src_dimension - 2], line[src_dimension - 3]),
|
38
|
+
imaginable_point(line[src_dimension - 1], line[src_dimension - 2])
|
39
|
+
]
|
138
40
|
end
|
139
41
|
|
140
42
|
def imaginable_point(point1, point2)
|
@@ -13,6 +13,13 @@ module Applitools
|
|
13
13
|
@datastream = ::ChunkyPNG::Datastream.from_string image
|
14
14
|
end
|
15
15
|
|
16
|
+
def update!(image)
|
17
|
+
Applitools::ArgumentGuard.not_nil(image, 'image')
|
18
|
+
Applitools::ArgumentGuard.is_a?(image, 'image', ::ChunkyPNG::Image)
|
19
|
+
@datastream = image.to_datastream
|
20
|
+
self
|
21
|
+
end
|
22
|
+
|
16
23
|
def to_blob
|
17
24
|
@datastream.to_blob
|
18
25
|
end
|
@@ -21,6 +28,8 @@ module Applitools
|
|
21
28
|
restore
|
22
29
|
end
|
23
30
|
|
31
|
+
alias image __getobj__
|
32
|
+
|
24
33
|
def header
|
25
34
|
@datastream.header_chunk
|
26
35
|
end
|
@@ -84,7 +84,9 @@ module Applitools::Utils
|
|
84
84
|
image_ratio = image.width.to_f / image.height.to_f
|
85
85
|
scale_width = (image.width * scale_ratio).ceil
|
86
86
|
scale_height = (scale_width / image_ratio).ceil
|
87
|
-
|
87
|
+
buffered_image = image.image
|
88
|
+
resize_image!(buffered_image, scale_width, scale_height)
|
89
|
+
image.update!(buffered_image)
|
88
90
|
end
|
89
91
|
|
90
92
|
def scale(image, scale_ratio)
|
@@ -95,7 +97,7 @@ module Applitools::Utils
|
|
95
97
|
Applitools::ArgumentGuard.not_nil(new_width, 'new_width')
|
96
98
|
Applitools::ArgumentGuard.not_nil(new_height, 'new_height')
|
97
99
|
Applitools::ArgumentGuard.not_nil(image, 'image')
|
98
|
-
Applitools::ArgumentGuard.is_a?(image, 'image',
|
100
|
+
Applitools::ArgumentGuard.is_a?(image, 'image', ::ChunkyPNG::Image)
|
99
101
|
|
100
102
|
raise Applitools::EyesIllegalArgument.new "Invalid width: #{new_width}" if new_width <= 0
|
101
103
|
raise Applitools::EyesIllegalArgument.new "Invalid height: #{new_height}" if new_height <= 0
|
data/lib/applitools/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: eyes_core
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.0.
|
4
|
+
version: 3.0.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Applitools Team
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-03-
|
11
|
+
date: 2017-03-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: oily_png
|