compaa 0.1.1 → 0.2.0

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.
@@ -1,15 +1,15 @@
1
1
  !!!
2
2
  %head
3
- %script{src: '/assets/underscore.js'}
4
- %script{src: '/assets/jquery-2.0.0.js'}
3
+ %script{src: '/assets/context_blender.js'}
4
+ %script{src: '/assets/blender.js'}
5
5
  %script{src: '/assets/compaa.js'}
6
6
  %link{rel: 'stylesheet', href: '/assets/bootstrap.css'}
7
7
  :javascript
8
8
  var compaa;
9
- $(function() {
9
+ document.addEventListener('DOMContentLoaded', function() {
10
10
  compaa = Object.create(Compaa);
11
11
  compaa.init();
12
- });
12
+ }, false);
13
13
 
14
14
  %body
15
15
  %canvas#difference
@@ -37,9 +37,12 @@ module Compaa
37
37
 
38
38
  def get
39
39
  case @request.path
40
- when '/' then index
41
- when '/artifacts.json' then artifacts_json
42
- else four_oh_four
40
+ when '/' then index
41
+ when '/artifacts.json' then artifacts_json
42
+ when '/compaa.js' then compaa_js
43
+ when '/blender.js' then blender_js
44
+ when '/context_blender.js' then context_blender_js
45
+ else four_oh_four
43
46
  end
44
47
  end
45
48
 
@@ -1,3 +1,3 @@
1
1
  module Compaa
2
- VERSION = '0.1.1'
2
+ VERSION = '0.2.0'
3
3
  end
@@ -1,22 +1,31 @@
1
- require 'sinatra'
1
+ require 'sinatra/base'
2
2
  require 'json'
3
3
  require 'rack/cors'
4
4
 
5
- use Rack::Cors do
6
- allow do
7
- origins '*'
8
- resource '/*', :headers => :any, :methods => [:get, :post]
5
+ class MockCompaa < Sinatra::Base
6
+ set :port, 4567
7
+ disable :logging
8
+
9
+ use Rack::Cors do
10
+ allow do
11
+ origins '*'
12
+ resource '/*', :headers => :any, :methods => [:get, :post]
13
+ end
14
+ end
15
+
16
+ get '/artifacts.json' do
17
+ content_type 'application/json'
18
+ {
19
+ artifacts: %w(
20
+ artifacts/reference_screenshots/one.png
21
+ artifacts/reference_screenshots/two.png
22
+ artifacts/reference_screenshots/three.png
23
+ artifacts/reference_screenshots/four.png
24
+ )
25
+ }.to_json
9
26
  end
10
27
  end
11
28
 
12
- get '/artifacts.json' do
13
- content_type 'application/json'
14
- {
15
- artifacts: %w(
16
- artifacts/reference_screenshots/one.png
17
- artifacts/reference_screenshots/two.png
18
- artifacts/reference_screenshots/three.png
19
- artifacts/reference_screenshots/four.png
20
- )
21
- }.to_json
29
+ Thread.new do
30
+ MockCompaa.run!
22
31
  end
@@ -71,7 +71,7 @@ describe Compaa::GeneratedImage do
71
71
  difference_path =
72
72
  File.join %w[artifacts differences_in_screenshots_this_run dir file.png_difference.gif]
73
73
 
74
- mock_file_manager.expect :rm, true, [difference_path]
74
+ mock_file_manager.expect :rm, true, [difference_path, { force: true }]
75
75
 
76
76
  subject.delete_difference_image
77
77
 
@@ -1,5 +1,5 @@
1
1
  require 'spec_helper'
2
- require 'capybara/poltergeist'
2
+ require 'capybara'
3
3
 
4
4
  Dir.chdir 'tmp/homemove' do
5
5
  Capybara.app = Compaa::RackApp.new
@@ -0,0 +1,26 @@
1
+ describe("blender", function() {
2
+ describe("makeItBlend()", function() {
3
+ it("produces a difference image", function() {
4
+ var imageOne = new Image(),
5
+ imageTwo = new Image(),
6
+ expectedImage = new Image(),
7
+ actual;
8
+
9
+ this.addMatchers(imagediff.jasmine);
10
+
11
+ expectedImage.src = '/spec/javascripts/support/expected.png';
12
+ imageOne.src = '/spec/javascripts/support/generated.png';
13
+ imageTwo.src = '/spec/javascripts/support/reference.png';
14
+
15
+ waitsFor(function() {
16
+ return imageOne.complete && imageTwo.complete && expectedImage.complete;
17
+ });
18
+
19
+ runs(function() {
20
+ window.blender.makeItBlend(imageOne, imageTwo, function(blended) {
21
+ expect(blended).toImageDiffEqual(expectedImage);
22
+ });
23
+ });
24
+ });
25
+ });
26
+ });
@@ -0,0 +1,382 @@
1
+ // js-imagediff 1.0.3
2
+ // (c) 2011-2012 Carl Sutherland, Humble Software
3
+ // Distributed under the MIT License
4
+ // For original source and documentation visit:
5
+ // http://www.github.com/HumbleSoftware/js-imagediff
6
+
7
+ (function (name, definition) {
8
+ var root = this;
9
+ if (typeof module !== 'undefined') {
10
+ var Canvas = require('canvas');
11
+ module.exports = definition(root, name, Canvas);
12
+ } else if (typeof define === 'function' && typeof define.amd === 'object') {
13
+ define(definition);
14
+ } else {
15
+ root[name] = definition(root, name);
16
+ }
17
+ })('imagediff', function (root, name, Canvas) {
18
+
19
+ var
20
+ TYPE_ARRAY = /\[object Array\]/i,
21
+ TYPE_CANVAS = /\[object (Canvas|HTMLCanvasElement)\]/i,
22
+ TYPE_CONTEXT = /\[object CanvasRenderingContext2D\]/i,
23
+ TYPE_IMAGE = /\[object (Image|HTMLImageElement)\]/i,
24
+ TYPE_IMAGE_DATA = /\[object ImageData\]/i,
25
+
26
+ UNDEFINED = 'undefined',
27
+
28
+ canvas = getCanvas(),
29
+ context = canvas.getContext('2d'),
30
+ previous = root[name],
31
+ imagediff, jasmine;
32
+
33
+ // Creation
34
+ function getCanvas (width, height) {
35
+ var
36
+ canvas = Canvas ?
37
+ new Canvas() :
38
+ document.createElement('canvas');
39
+ if (width) canvas.width = width;
40
+ if (height) canvas.height = height;
41
+ return canvas;
42
+ }
43
+ function getImageData (width, height) {
44
+ canvas.width = width;
45
+ canvas.height = height;
46
+ context.clearRect(0, 0, width, height);
47
+ return context.createImageData(width, height);
48
+ }
49
+
50
+
51
+ // Type Checking
52
+ function isImage (object) {
53
+ return isType(object, TYPE_IMAGE);
54
+ }
55
+ function isCanvas (object) {
56
+ return isType(object, TYPE_CANVAS);
57
+ }
58
+ function isContext (object) {
59
+ return isType(object, TYPE_CONTEXT);
60
+ }
61
+ function isImageData (object) {
62
+ return !!(object &&
63
+ isType(object, TYPE_IMAGE_DATA) &&
64
+ typeof(object.width) !== UNDEFINED &&
65
+ typeof(object.height) !== UNDEFINED &&
66
+ typeof(object.data) !== UNDEFINED);
67
+ }
68
+ function isImageType (object) {
69
+ return (
70
+ isImage(object) ||
71
+ isCanvas(object) ||
72
+ isContext(object) ||
73
+ isImageData(object)
74
+ );
75
+ }
76
+ function isType (object, type) {
77
+ return typeof (object) === 'object' && !!Object.prototype.toString.apply(object).match(type);
78
+ }
79
+
80
+
81
+ // Type Conversion
82
+ function copyImageData (imageData) {
83
+ var
84
+ height = imageData.height,
85
+ width = imageData.width,
86
+ data = imageData.data,
87
+ newImageData, newData, i;
88
+
89
+ canvas.width = width;
90
+ canvas.height = height;
91
+ newImageData = context.getImageData(0, 0, width, height);
92
+ newData = newImageData.data;
93
+
94
+ for (i = imageData.data.length; i--;) {
95
+ newData[i] = data[i];
96
+ }
97
+
98
+ return newImageData;
99
+ }
100
+ function toImageData (object) {
101
+ if (isImage(object)) { return toImageDataFromImage(object); }
102
+ if (isCanvas(object)) { return toImageDataFromCanvas(object); }
103
+ if (isContext(object)) { return toImageDataFromContext(object); }
104
+ if (isImageData(object)) { return object; }
105
+ }
106
+ function toImageDataFromImage (image) {
107
+ var
108
+ height = image.height,
109
+ width = image.width;
110
+ canvas.width = width;
111
+ canvas.height = height;
112
+ context.clearRect(0, 0, width, height);
113
+ context.drawImage(image, 0, 0);
114
+ return context.getImageData(0, 0, width, height);
115
+ }
116
+ function toImageDataFromCanvas (canvas) {
117
+ var
118
+ height = canvas.height,
119
+ width = canvas.width,
120
+ context = canvas.getContext('2d');
121
+ return context.getImageData(0, 0, width, height);
122
+ }
123
+ function toImageDataFromContext (context) {
124
+ var
125
+ canvas = context.canvas,
126
+ height = canvas.height,
127
+ width = canvas.width;
128
+ return context.getImageData(0, 0, width, height);
129
+ }
130
+ function toCanvas (object) {
131
+ var
132
+ data = toImageData(object),
133
+ canvas = getCanvas(data.width, data.height),
134
+ context = canvas.getContext('2d');
135
+
136
+ context.putImageData(data, 0, 0);
137
+ return canvas;
138
+ }
139
+
140
+
141
+ // ImageData Equality Operators
142
+ function equalWidth (a, b) {
143
+ return a.width === b.width;
144
+ }
145
+ function equalHeight (a, b) {
146
+ return a.height === b.height;
147
+ }
148
+ function equalDimensions (a, b) {
149
+ return equalHeight(a, b) && equalWidth(a, b);
150
+ }
151
+ function equal (a, b, tolerance) {
152
+
153
+ var
154
+ aData = a.data,
155
+ bData = b.data,
156
+ length = aData.length,
157
+ i;
158
+
159
+ tolerance = tolerance || 0;
160
+
161
+ if (!equalDimensions(a, b)) return false;
162
+ for (i = length; i--;) if (aData[i] !== bData[i] && Math.abs(aData[i] - bData[i]) > tolerance) return false;
163
+
164
+ return true;
165
+ }
166
+
167
+
168
+ // Diff
169
+ function diff (a, b) {
170
+ return (equalDimensions(a, b) ? diffEqual : diffUnequal)(a, b);
171
+ }
172
+ function diffEqual (a, b) {
173
+
174
+ var
175
+ height = a.height,
176
+ width = a.width,
177
+ c = getImageData(width, height), // c = a - b
178
+ aData = a.data,
179
+ bData = b.data,
180
+ cData = c.data,
181
+ length = cData.length,
182
+ row, column,
183
+ i, j, k, v;
184
+
185
+ for (i = 0; i < length; i += 4) {
186
+ cData[i] = Math.abs(aData[i] - bData[i]);
187
+ cData[i+1] = Math.abs(aData[i+1] - bData[i+1]);
188
+ cData[i+2] = Math.abs(aData[i+2] - bData[i+2]);
189
+ cData[i+3] = Math.abs(255 - aData[i+3] - bData[i+3]);
190
+ }
191
+
192
+ return c;
193
+ }
194
+ function diffUnequal (a, b) {
195
+
196
+ var
197
+ height = Math.max(a.height, b.height),
198
+ width = Math.max(a.width, b.width),
199
+ c = getImageData(width, height), // c = a - b
200
+ aData = a.data,
201
+ bData = b.data,
202
+ cData = c.data,
203
+ rowOffset,
204
+ columnOffset,
205
+ row, column,
206
+ i, j, k, v;
207
+
208
+
209
+ for (i = cData.length - 1; i > 0; i = i - 4) {
210
+ cData[i] = 255;
211
+ }
212
+
213
+ // Add First Image
214
+ offsets(a);
215
+ for (row = a.height; row--;){
216
+ for (column = a.width; column--;) {
217
+ i = 4 * ((row + rowOffset) * width + (column + columnOffset));
218
+ j = 4 * (row * a.width + column);
219
+ cData[i+0] = aData[j+0]; // r
220
+ cData[i+1] = aData[j+1]; // g
221
+ cData[i+2] = aData[j+2]; // b
222
+ // cData[i+3] = aData[j+3]; // a
223
+ }
224
+ }
225
+
226
+ // Subtract Second Image
227
+ offsets(b);
228
+ for (row = b.height; row--;){
229
+ for (column = b.width; column--;) {
230
+ i = 4 * ((row + rowOffset) * width + (column + columnOffset));
231
+ j = 4 * (row * b.width + column);
232
+ cData[i+0] = Math.abs(cData[i+0] - bData[j+0]); // r
233
+ cData[i+1] = Math.abs(cData[i+1] - bData[j+1]); // g
234
+ cData[i+2] = Math.abs(cData[i+2] - bData[j+2]); // b
235
+ }
236
+ }
237
+
238
+ // Helpers
239
+ function offsets (imageData) {
240
+ rowOffset = Math.floor((height - imageData.height) / 2);
241
+ columnOffset = Math.floor((width - imageData.width) / 2);
242
+ }
243
+
244
+ return c;
245
+ }
246
+
247
+
248
+ // Validation
249
+ function checkType () {
250
+ var i;
251
+ for (i = 0; i < arguments.length; i++) {
252
+ if (!isImageType(arguments[i])) {
253
+ throw {
254
+ name : 'ImageTypeError',
255
+ message : 'Submitted object was not an image.'
256
+ };
257
+ }
258
+ }
259
+ }
260
+
261
+
262
+ // Jasmine Matchers
263
+ function get (element, content) {
264
+ element = document.createElement(element);
265
+ if (element && content) {
266
+ element.innerHTML = content;
267
+ }
268
+ return element;
269
+ }
270
+
271
+ jasmine = {
272
+
273
+ toBeImageData : function () {
274
+ return imagediff.isImageData(this.actual);
275
+ },
276
+
277
+ toImageDiffEqual : function (expected, tolerance) {
278
+
279
+ if (typeof (document) !== UNDEFINED) {
280
+ this.message = function () {
281
+ var
282
+ div = get('div'),
283
+ a = get('div', '<div>Actual:</div>'),
284
+ b = get('div', '<div>Expected:</div>'),
285
+ c = get('div', '<div>Diff:</div>'),
286
+ diff = imagediff.diff(this.actual, expected),
287
+ canvas = getCanvas(),
288
+ context;
289
+
290
+ canvas.height = diff.height;
291
+ canvas.width = diff.width;
292
+
293
+ div.style.overflow = 'hidden';
294
+ a.style.float = 'left';
295
+ b.style.float = 'left';
296
+ c.style.float = 'left';
297
+
298
+ context = canvas.getContext('2d');
299
+ context.putImageData(diff, 0, 0);
300
+
301
+ a.appendChild(toCanvas(this.actual));
302
+ b.appendChild(toCanvas(expected));
303
+ c.appendChild(canvas);
304
+
305
+ div.appendChild(a);
306
+ div.appendChild(b);
307
+ div.appendChild(c);
308
+
309
+ return [
310
+ div,
311
+ "Expected not to be equal."
312
+ ];
313
+ };
314
+ }
315
+
316
+ return imagediff.equal(this.actual, expected, tolerance);
317
+ }
318
+ };
319
+
320
+
321
+ // Image Output
322
+ function imageDataToPNG (imageData, outputFile, callback) {
323
+
324
+ var
325
+ canvas = toCanvas(imageData),
326
+ base64Data,
327
+ decodedImage;
328
+
329
+ callback = callback || Function;
330
+
331
+ base64Data = canvas.toDataURL().replace(/^data:image\/\w+;base64,/,"");
332
+ decodedImage = new Buffer(base64Data, 'base64');
333
+ require('fs').writeFile(outputFile, decodedImage, callback);
334
+ }
335
+
336
+
337
+ // Definition
338
+ imagediff = {
339
+
340
+ createCanvas : getCanvas,
341
+ createImageData : getImageData,
342
+
343
+ isImage : isImage,
344
+ isCanvas : isCanvas,
345
+ isContext : isContext,
346
+ isImageData : isImageData,
347
+ isImageType : isImageType,
348
+
349
+ toImageData : function (object) {
350
+ checkType(object);
351
+ if (isImageData(object)) { return copyImageData(object); }
352
+ return toImageData(object);
353
+ },
354
+
355
+ equal : function (a, b, tolerance) {
356
+ checkType(a, b);
357
+ a = toImageData(a);
358
+ b = toImageData(b);
359
+ return equal(a, b, tolerance);
360
+ },
361
+ diff : function (a, b) {
362
+ checkType(a, b);
363
+ a = toImageData(a);
364
+ b = toImageData(b);
365
+ return diff(a, b);
366
+ },
367
+
368
+ jasmine : jasmine,
369
+
370
+ // Compatibility
371
+ noConflict : function () {
372
+ root[name] = previous;
373
+ return imagediff;
374
+ }
375
+ };
376
+
377
+ if (typeof module !== 'undefined') {
378
+ imagediff.imageDataToPNG = imageDataToPNG;
379
+ }
380
+
381
+ return imagediff;
382
+ });