shutterbug 0.2.5 → 0.4.3

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.
Files changed (41) hide show
  1. checksums.yaml +8 -8
  2. data/.travis.yml +3 -3
  3. data/README.md +6 -0
  4. data/bower.json +1 -1
  5. data/demo/The_Scream.jpg +0 -0
  6. data/demo/canvas_example.html +36 -0
  7. data/demo/index.html +1 -0
  8. data/lib/shutterbug.rb +1 -1
  9. data/lib/shutterbug/cache_manager.rb +2 -2
  10. data/lib/shutterbug/configuration.rb +4 -8
  11. data/lib/shutterbug/handlers.rb +5 -4
  12. data/lib/shutterbug/handlers/convert_handler.rb +38 -16
  13. data/lib/shutterbug/handlers/direct_upload_handler.rb +30 -0
  14. data/lib/shutterbug/handlers/file_handler.rb +30 -0
  15. data/lib/shutterbug/handlers/js_file_handler.rb +13 -10
  16. data/lib/shutterbug/handlers/shutterbug.js +123 -32
  17. data/lib/shutterbug/phantom_job.rb +11 -10
  18. data/lib/shutterbug/rackapp.rb +15 -18
  19. data/lib/shutterbug/rasterize.js +4 -4
  20. data/lib/shutterbug/storage.rb +1 -1
  21. data/lib/shutterbug/storage/file_storage.rb +21 -8
  22. data/lib/shutterbug/storage/s3_storage.rb +26 -31
  23. data/shutterbug.gemspec +0 -1
  24. data/spec/shared_examples_for_handlers.rb +13 -9
  25. data/spec/shared_examples_for_storage.rb +14 -10
  26. data/spec/shutterbug/configuration_spec.rb +1 -11
  27. data/spec/shutterbug/convert_handler_spec.rb +5 -4
  28. data/spec/shutterbug/direct_upload_handler_spec.rb +7 -0
  29. data/spec/shutterbug/file_handler_spec.rb +7 -0
  30. data/spec/shutterbug/file_storage_spec.rb +2 -1
  31. data/spec/shutterbug/js_file_handler_spec.rb +2 -1
  32. data/spec/shutterbug/rackapp_spec.rb +14 -28
  33. data/spec/shutterbug/s3_storage_spec.rb +1 -1
  34. metadata +10 -12
  35. data/lib/shutterbug/handlers/file_handlers.rb +0 -9
  36. data/lib/shutterbug/handlers/file_handlers/base.rb +0 -39
  37. data/lib/shutterbug/handlers/file_handlers/html_file.rb +0 -22
  38. data/lib/shutterbug/handlers/file_handlers/png_file.rb +0 -23
  39. data/spec/shared_examples_for_file_handlers.rb +0 -16
  40. data/spec/shutterbug/html_file_handler_spec.rb +0 -10
  41. data/spec/shutterbug/png_file_handler_spec.rb +0 -10
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- NjVmZDdiYjY0NmUzYzc1YzNlN2QwMGI5MmEwOTk1MzNjNWZkNjM2NA==
4
+ MjY4NTQ1OTA1ZjFjZmFjZGUzNjVhMWZmNjc4ODM4N2VjZTVkMDFiYQ==
5
5
  data.tar.gz: !binary |-
6
- N2I1N2ZlYzM5ZjAzOGNkMTA2ZGY4ZTE0N2VlYTQ3NmUyNjUzMzk5MQ==
6
+ NzhmMTc5NGEzNzIzYjNjM2M1ZmIzM2U3NGJlMDhjYTgyYzRjNDZhNg==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- MmNjZWJlMmI1ZTI1OWJkMzc5MWVhZjhiZWQxYTk0MjNlMTIzNWMzYjk5YzI2
10
- ZDdkOTExNmQ0NzBkYzFkN2UxOWY4MTAxNTJmMjY3YTc0OWZkNGUzOWYwMDY5
11
- NTY5Zjc4YmUzNTEzZjllZmE2NDE1YTFmZjllNTllMTc0YmYzY2I=
9
+ NmJkMjRiYjMyYjZhZjAyZmUyYTUxOTc3ZThiNjZlMWVkNWUwMjFmYTNlNTBi
10
+ MjcyM2EyZTE5MWZmNjgxMDdlM2UxZDRjOWRjYWI1NjFlMmUzNzExMWM4ZjRk
11
+ YmU5YWI5Y2YxY2MyYTkyOTE2YzdhMDAwZDBjYWE4M2RkZDliY2U=
12
12
  data.tar.gz: !binary |-
13
- M2E0OTFkZTlkN2ZmNmU1NjdiZjlmYzY5ZjE4YmI0NjRmYzQ2ZDU4MjgyMWQ4
14
- ZDhjY2QzNmMxNjM0YjVjMzc1M2MzMWYzNDA1NjUwODdhZGQyNGE2NzM4YTg5
15
- YmZkZmI3MWQwYTQyODgxOTYyNmRiMGU5Yzc0YTVjNTQwYTMzMTQ=
13
+ ZDFmZmM5ZjZiZjVjYjI4ODk0OTdlZmQxZmRiZmY5OTVlNjhmYTAzZjE4MzYz
14
+ ZWU1OTk4YjhkMmMwNjcxNmNhOWVhYzNjMzZkZGMyMWNhMTA2YjMzMjJiZDVh
15
+ ZWRlMzE0YzcyZmRjNTUyZGZlNzA5NTFlM2VhYzYwMzU2NmYxMmM=
data/.travis.yml CHANGED
@@ -1,9 +1,9 @@
1
1
  language: ruby
2
2
  rvm:
3
- - "1.9.2"
3
+ # - "1.9.2"
4
4
  - "1.9.3"
5
5
  - "2.0.0"
6
- - jruby-19mode # JRuby in 1.9 mode
7
- - rbx-19mode
6
+ # - jruby-19mode # JRuby in 1.9 mode
7
+ # - rbx-19mode
8
8
  # uncomment this line if your project needs to run something other than `rake`:
9
9
  # script: bundle exec rspec spec
data/README.md CHANGED
@@ -179,6 +179,12 @@ And a Procfile which looks like this:
179
179
 
180
180
  ## Changes ##
181
181
 
182
+ * December 4, 2014 – v 0.4.3
183
+ * Added support of various image formats and quality settings.
184
+
185
+ * December 2, 2014 – v 0.3.0
186
+ * Improved canvas snapshot - data is uploaded directly to S3 from the browser (no PhantomJS rendering).
187
+
182
188
  * November 12, 2014 – v 0.2.5
183
189
  * Added setFailureCallback to shutterbug.js for gracefully handling ajax failures in some custom way.
184
190
  * Updated CORS configuration in config.ru to allow [:options] requests.
data/bower.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shutterbug",
3
- "version": "0.2.5",
3
+ "version": "0.4.3",
4
4
  "homepage": "https://github.com/concord-consortium/shutterbug",
5
5
  "authors": [
6
6
  "Noah Paessel <npaessel@concord.org>"
Binary file
@@ -0,0 +1,36 @@
1
+ <!doctype html>
2
+ <html>
3
+ <head>
4
+ <title>demo</title>
5
+ <script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script>
6
+ <script type="text/javascript" src="/shutterbug/shutterbug.js"></script>
7
+ <link rel="stylesheet" type="text/css" href="main.css">
8
+ </head>
9
+
10
+ <body>
11
+ <div>
12
+ <canvas id="src" width="350" height="350"></canvas>
13
+ </div>
14
+ <button class="shutterbug" data-dst="#dst">Snapshot</button>
15
+ <div id="dst"></div>
16
+ </body>
17
+ <script type="text/javascript">
18
+ $(document).ready(function(e) {
19
+ var img = new Image();
20
+ img.onload = function () {
21
+ var ctx = $("canvas")[0].getContext("2d");
22
+ ctx.fillStyle = "green";
23
+ ctx.fillRect(0, 0, 350, 350);
24
+ ctx.fillStyle = "orange";
25
+ ctx.fillRect(10, 10, 330, 330);
26
+ ctx.drawImage(img, 20, 20, 310, 310);
27
+ };
28
+ img.src = "The_Scream.jpg";
29
+
30
+ var bug = new Shutterbug("#src", "#dst", null, null, null, {format: "jpeg", quality: 0.75});
31
+ $("button.shutterbug").click(function(e) {
32
+ bug.getDomSnapshot();
33
+ });
34
+ });
35
+ </script>
36
+ </html>
data/demo/index.html CHANGED
@@ -14,6 +14,7 @@
14
14
  <li>Very <a href="simple_example.html">simple</a> example.</li>
15
15
  <li><a href="iframe_example.html">IFrame</a> example.</li>
16
16
  <li><a href="nested_iframe_example.html">Nested IFrames</a> example.</li>
17
+ <li><a href="canvas_example.html">Canvas</a> example.</li>
17
18
  </ul>
18
19
  </body>
19
20
  </html>
data/lib/shutterbug.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  module Shutterbug
2
- VERSION = "0.2.5"
2
+ VERSION = "0.4.3"
3
3
  autoload :Rackapp, "shutterbug/rackapp"
4
4
  autoload :Configuration, "shutterbug/configuration"
5
5
  autoload :Storage, "shutterbug/storage"
@@ -1,6 +1,6 @@
1
1
  module Shutterbug
2
2
  module CacheManager
3
- autoload :NoCache, "shutterbug/cache_manager/no_cache"
4
- autoload :CacheEntry, "shutterbug/cache_manager/cache_entry"
3
+ autoload :NoCache, "shutterbug/cache_manager/no_cache"
4
+ autoload :CacheEntry, "shutterbug/cache_manager/cache_entry"
5
5
  end
6
6
  end
@@ -1,7 +1,7 @@
1
1
  require 'tmpdir'
2
+
2
3
  module Shutterbug
3
4
  class Configuration
4
-
5
5
  attr_accessor :uri_prefix
6
6
  attr_accessor :path_prefix
7
7
  attr_accessor :resource_dir
@@ -27,19 +27,15 @@ module Shutterbug
27
27
  end
28
28
 
29
29
  def fs_path_for(filename)
30
- File.join(resource_dir,"phantom_#{filename}")
30
+ File.join(resource_dir, "phantom_#{filename}")
31
31
  end
32
32
 
33
33
  def url_prefix
34
34
  "#{uri_prefix}#{path_prefix}"
35
35
  end
36
36
 
37
- def convert_path
38
- "#{url_prefix}/make_snapshot"
39
- end
40
-
41
37
  def base_url(req)
42
- req.POST()['base_url'] || req.referrer || "#{req.scheme}://#{req.host_with_port}"
38
+ req.POST()['base_url'] || req.referrer || "#{req.scheme}://#{req.host_with_port}"
43
39
  end
44
40
 
45
41
  def storage
@@ -50,4 +46,4 @@ module Shutterbug
50
46
  return (self.s3_bin && self.s3_key && self.s3_secret)
51
47
  end
52
48
  end
53
- end
49
+ end
@@ -1,7 +1,8 @@
1
- require "shutterbug/handlers/file_handlers"
2
1
  module Shutterbug
3
2
  module Handlers
4
- autoload :ConvertHandler, "shutterbug/handlers/convert_handler"
5
- autoload :JsFileHandler, "shutterbug/handlers/js_file_handler"
3
+ autoload :ConvertHandler, "shutterbug/handlers/convert_handler"
4
+ autoload :DirectUploadHandler, "shutterbug/handlers/direct_upload_handler"
5
+ autoload :JsFileHandler, "shutterbug/handlers/js_file_handler"
6
+ autoload :FileHandler, "shutterbug/handlers/file_handler"
6
7
  end
7
- end
8
+ end
@@ -1,38 +1,60 @@
1
1
  require 'stringio'
2
+
2
3
  module Shutterbug
3
4
  module Handlers
4
5
  class ConvertHandler
5
6
 
6
- def initialize(_config = Configuration.instance)
7
- @config = _config
7
+ def self.config
8
+ Configuration.instance
8
9
  end
9
10
 
10
- def regex
11
- /#{@config.path_prefix}\/make_snapshot/
11
+ def self.regex
12
+ /#{self.config.path_prefix}\/make_snapshot/
12
13
  end
13
14
 
14
15
  def handle(helper, req, env)
15
16
  response_text = convert(req).image_tag
16
- helper.good_response(response_text,'text/plain')
17
+ helper.response(response_text, 'text/plain')
18
+ end
19
+
20
+ def convert_quality(val, format)
21
+ # Client sends quality between 0 and 1 (similar to .toDataURL() second argument).
22
+ # This conversion tries to ensure that the size of the final image is similar to
23
+ # .toDataURL() output with given quality settings.
24
+ val = val.to_f
25
+ case format
26
+ when "png"
27
+ val *= 10
28
+ when "jpeg"
29
+ val *= 100
30
+ else
31
+ val *= 100
32
+ end
33
+ # PhantomJS expects integer.
34
+ val.to_i
17
35
  end
18
36
 
19
37
  def convert(req)
20
- html = req.POST()['content'] || ""
21
- width = req.POST()['width'] || 1000
22
- height = req.POST()['height'] || 700
23
- css = req.POST()['css'] || ""
24
- job = PhantomJob.new(@config.base_url(req), html, css, width, height)
25
- unless (cache_entry = @config.cache_manager.find(job.cache_key))
38
+ html = req.POST()['content'] || ""
39
+ width = req.POST()['width'] || 1000
40
+ height = req.POST()['height'] || 700
41
+ css = req.POST()['css'] || ""
42
+ format = req.POST()['format'] || "png"
43
+ quality = req.POST()['quality'] || 1
44
+ quality = convert_quality(quality, format)
45
+ config = self.class.config
46
+ job = PhantomJob.new(config.base_url(req), html, css, width, height, format, quality)
47
+ unless (cache_entry = config.cache_manager.find(job.cache_key))
26
48
  job.rasterize
27
49
  html_entry = Shutterbug::CacheManager::CacheEntry.new(job.html_file)
28
- png_entry = Shutterbug::CacheManager::CacheEntry.new(job.png_file)
29
- html_entry.preview_url = png_entry.preview_url
30
- @config.cache_manager.add_entry(html_entry)
31
- cache_entry = @config.cache_manager.add_entry(png_entry)
50
+ image_entry = Shutterbug::CacheManager::CacheEntry.new(job.image_file)
51
+ html_entry.preview_url = image_entry.preview_url
52
+ config.cache_manager.add_entry(html_entry)
53
+ cache_entry = config.cache_manager.add_entry(image_entry)
32
54
  end
33
55
  # return the image tag
34
56
  return cache_entry
35
57
  end
36
58
  end
37
59
  end
38
- end
60
+ end
@@ -0,0 +1,30 @@
1
+ require 'securerandom'
2
+
3
+ # This handler can be used for fast, client-side upload of images (or canvas) directly to storage.
4
+ # When client is taking snapshot of image or canvas, we don't need to use PhantomJS.
5
+ module Shutterbug
6
+ module Handlers
7
+ class DirectUploadHandler
8
+
9
+ def self.regex
10
+ /#{Configuration.instance.path_prefix}\/img_upload_url/
11
+ end
12
+
13
+ # Returns put_url and get_url for a new file that should be uploaded by the client.
14
+ # Of course get_url will work after file is uploaded.
15
+ def handle(helper, req, env)
16
+ format = req.GET()['format'] || 'png'
17
+
18
+ object_name = "img-#{SecureRandom.uuid}.#{format}"
19
+ storage = Configuration.instance.storage
20
+ unless storage.respond_to? :put_url
21
+ return helper.response('direct upload not available', 'text/plain', 400)
22
+ end
23
+ helper.response({
24
+ put_url: storage.put_url(object_name),
25
+ get_url: storage.get_url(object_name),
26
+ }.to_json, 'application/json')
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,30 @@
1
+ module Shutterbug
2
+ module Handlers
3
+ class FileHandler
4
+
5
+ # relative url
6
+ def self.path_prefix
7
+ "#{Configuration.instance.path_prefix}/get_file"
8
+ end
9
+
10
+ # absolute url
11
+ def self.uri_prefix
12
+ "#{Configuration.instance.uri_prefix}#{self.path_prefix}"
13
+ end
14
+
15
+ def self.regex
16
+ filename_matcher = "(([^\/|\.]+)\.?([^\/]+))?"
17
+ /#{self.path_prefix}\/#{filename_matcher}/
18
+ end
19
+
20
+ def handle(helper, req, env)
21
+ filename = self.class.regex.match(req.path)[1]
22
+ if File.extname(filename) == ''
23
+ filename += '.html'
24
+ end
25
+ file = Configuration.instance.storage.new(filename)
26
+ helper.response(file.get_content, file.mime_type)
27
+ end
28
+ end
29
+ end
30
+ end
@@ -2,26 +2,29 @@ module Shutterbug
2
2
  module Handlers
3
3
  class JsFileHandler
4
4
 
5
+ def self.config
6
+ Configuration.instance
7
+ end
8
+
5
9
  def self.js_path
6
- "#{Configuration.instance.url_prefix}/shutterbug.js"
10
+ "#{self.config.url_prefix}/shutterbug.js"
7
11
  end
8
12
 
9
- def regex
10
- /#{@config.path_prefix}\/shutterbug.js/
13
+ def self.regex
14
+ /#{self.config.path_prefix}\/shutterbug.js/
11
15
  end
12
16
 
13
- def js_file
14
- File.join(File.dirname(__FILE__),"shutterbug.js")
17
+ def initialize
18
+ @javascript = File.read(js_file).gsub(/URL_PREFIX/, self.class.config.url_prefix)
15
19
  end
16
20
 
17
- def initialize(_config=Configuration.instance())
18
- @config = _config
19
- @javascript = File.read(js_file).gsub(/CONVERT_PATH/,@config.convert_path)
21
+ def js_file
22
+ File.join(File.dirname(__FILE__), "shutterbug.js")
20
23
  end
21
24
 
22
25
  def handle(helper, req, env)
23
- helper.good_response(@javascript, 'application/javascript')
26
+ helper.response(@javascript, 'application/javascript')
24
27
  end
25
28
  end
26
29
  end
27
- end
30
+ end
@@ -1,9 +1,12 @@
1
1
  /*global $ */
2
- (function(){
3
- var $ = window.$;
2
+ (function() {
3
+ var $ = window.jQuery;
4
4
 
5
5
  var MAX_TIMEOUT = 1500;
6
6
 
7
+ // IE9 doesn't implement this.
8
+ var BIN_DATA_SUPPORTED = typeof(window.Blob) === "function" && typeof(window.Uint8Array) === "function";
9
+
7
10
  var getBaseUrl = function() {
8
11
  var base = window.location.href;
9
12
  return base;
@@ -50,7 +53,7 @@
50
53
  // - element descentands are iframes - .find('iframe')
51
54
  var $iframes = $element.find('iframe').addBack("iframe");
52
55
  this._iframeContentRequests = [];
53
-
56
+
54
57
  $iframes.each(function(i, iframeElem) {
55
58
  var message = {
56
59
  type: 'htmlFragRequest',
@@ -65,7 +68,7 @@
65
68
  var requestDeffered = new $.Deferred();
66
69
  self._iframeContentRequests[i] = requestDeffered;
67
70
  setTimeout(function() {
68
- // It handles a situation in which iframe doesn't support Shutterbug.
71
+ // It handles a situation in which iframe doesn't support Shutterbug.
69
72
  // When we doesn't receive answer for some time, assume that we can't
70
73
  // render this particular iframe (provide null as iframe description).
71
74
  if (requestDeffered.state() !== "resolved") {
@@ -101,19 +104,22 @@
101
104
  });
102
105
  }
103
106
 
104
- var replacementImgs = $element.find('canvas').map( function(count,elem) {
107
+ // .addBack('canvas') handles case when the element itself is a canvas.
108
+ var replacementImgs = $element.find('canvas').addBack('canvas').map(function(i, elem) {
109
+ // Use png here, as it supports transparency and canvas can be layered on top of other elements.
105
110
  var dataUrl = elem.toDataURL('image/png');
106
- var img = cloneDomItem($(elem),"<img>");
111
+ var img = cloneDomItem($(elem), "<img>");
107
112
  img.attr('src', dataUrl);
108
113
  return img;
109
114
  });
110
115
 
111
- element.find('canvas').each(function(i,elm) {
112
- var backgroundDiv = cloneDomItem($(elm),"<div>");
113
- // Add a backing (background) dom element for BG canvas property
114
- $(elm).replaceWith(replacementImgs[i]);
115
- backgroundDiv.insertBefore($(elm));
116
- });
116
+ if (element.is('canvas')) {
117
+ element = replacementImgs[0];
118
+ } else {
119
+ element.find('canvas').each(function(i, elem) {
120
+ $(elem).replaceWith(replacementImgs[i]);
121
+ });
122
+ }
117
123
 
118
124
  element.css({
119
125
  'top':0,
@@ -150,34 +156,110 @@
150
156
  var counter = $("<span>");
151
157
  counter.html(time);
152
158
  $(self.imgDst).html("creating snapshot: ").append(counter);
153
- var timer = setInterval(function(t) {
159
+ this.timer = setInterval(function(t) {
154
160
  time = time + 1;
155
161
  counter.html(time);
156
162
  }, 1000);
163
+ var tagName = $(this.element).prop("tagName");
164
+ switch(tagName) {
165
+ case "CANVAS":
166
+ this.canvasSnapshot();
167
+ break;
168
+ default:
169
+ this.basicSnapshot();
170
+ break;
171
+ }
172
+ };
173
+
174
+ var canvasSnapshot = function() {
175
+ if (!BIN_DATA_SUPPORTED) {
176
+ return this.basicSnapshot();
177
+ }
178
+ var self = this;
179
+ $.ajax({
180
+ type: 'GET',
181
+ url: 'URL_PREFIX/img_upload_url?format=' + this.imageFormat
182
+ }).done(function(data) {
183
+ self.directUpload(data);
184
+ }).fail(function() {
185
+ // Use basic snapshot as a fallback.
186
+ // Direct upload is not supported on server side (e.g. due to used storage).
187
+ self.basicSnapshot();
188
+ });
189
+ };
190
+
191
+ function directUpload(options) {
192
+ var $canvas = $(this.element);
193
+ var dataURL = $canvas[0].toDataURL('image/' + this.imageFormat, this.imageQuality)
194
+ var blob = dataURLtoBlob(dataURL);
195
+ var self = this;
196
+ $.ajax({
197
+ type: 'PUT',
198
+ url: options.put_url,
199
+ data: blob,
200
+ processData: false,
201
+ contentType: false
202
+ }).done(function(data) {
203
+ self.success('<img src=' + options.get_url + '>');
204
+ }).fail(function(jqXHR, textStatus, errorThrown) {
205
+ self.fail(jqXHR, textStatus, errorThrown)
206
+ });
207
+ }
208
+
209
+ function dataURLtoBlob(dataURL) {
210
+ // Convert base64/URLEncoded data component to raw binary data held in a string.
211
+ if (dataURL.split(',')[0].indexOf('base64') === -1) {
212
+ throw new Error('expected base64 data');
213
+ }
214
+ var byteString = atob(dataURL.split(',')[1]);
215
+ // Separate out the mime component.
216
+ var mimeString = dataURL.split(',')[0].split(':')[1].split(';')[0];
217
+ // Write the bytes of the string to a typed array.
218
+ var ia = new Uint8Array(byteString.length);
219
+ for (var i = 0; i < byteString.length; i++) {
220
+ ia[i] = byteString.charCodeAt(i);
221
+ }
222
+ return new Blob([ia], {type: mimeString});
223
+ }
224
+
225
+ var basicSnapshot = function() {
226
+ var self = this;
157
227
  // Ask for HTML fragment and render it on server.
158
- this.getHtmlFragment(function(html) {
228
+ this.getHtmlFragment(function(html_data) {
229
+ html_data.format = self.imageFormat;
230
+ html_data.quality = self.imageQuality;
159
231
  $.ajax({
160
- url: "CONVERT_PATH",
232
+ url: "URL_PREFIX/make_snapshot",
161
233
  type: "POST",
162
- data: html
234
+ data: html_data
163
235
  }).success(function(msg) {
164
- if(self.imgDst) {
165
- $(self.imgDst).html(msg);
166
- }
167
- if (self.callback) {
168
- self.callback(msg);
169
- }
170
- clearInterval(timer);
236
+ self.success(msg)
171
237
  }).fail(function(jqXHR, textStatus, errorThrown) {
172
- $(self.imgDst).html("snapshot failed");
173
- if (self.failCallback) {
174
- self.failCallback(jqXHR, textStatus, errorThrown);
175
- }
176
- clearInterval(timer);
238
+ self.fail(jqXHR, textStatus, errorThrown);
177
239
  });
178
240
  });
179
241
  };
180
242
 
243
+ var success = function(imageTag) {
244
+ if (this.imgDst) {
245
+ $(this.imgDst).html(imageTag);
246
+ }
247
+ if (this.callback) {
248
+ this.callback(imageTag);
249
+ }
250
+ clearInterval(this.timer);
251
+ }
252
+
253
+ var fail = function(jqXHR, textStatus, errorThrown) {
254
+ if (this.imgDst) {
255
+ $(this.imgDst).html("snapshot failed");
256
+ }
257
+ if (this.failCallback) {
258
+ this.failCallback(jqXHR, textStatus, errorThrown);
259
+ }
260
+ clearInterval(this.timer);
261
+ }
262
+
181
263
  var requestHtmlFrag = function() {
182
264
  var destination = $(this.element)[0].contentWindow;
183
265
  var message = {
@@ -188,7 +270,7 @@
188
270
  };
189
271
 
190
272
  var htmlSnap = function() {
191
- this.getHtmlFragment(function callback(fragment){
273
+ this.getHtmlFragment(function callback(fragment) {
192
274
  // FIXME btoa is not intended to encode text it is for for 8bit per char strings
193
275
  // so if you send it a UTF8 string with a special char in it, it will fail
194
276
  // this SO has a note about handling this:
@@ -219,7 +301,7 @@
219
301
  };
220
302
 
221
303
  // TODO: Construct using opts instead of positional arguments.
222
- window.Shutterbug = function(selector, imgDst, callback, id, jQuery) {
304
+ window.Shutterbug = function(selector, imgDst, callback, id, jQuery, opt) {
223
305
  if (typeof(jQuery) != "undefined" && jQuery != null) {
224
306
  $ = jQuery;
225
307
  }
@@ -229,12 +311,21 @@
229
311
  $ = window.$;
230
312
  }
231
313
 
314
+ opt = opt || {};
315
+
232
316
  var shutterbugInstance = {
233
317
  element: selector,
234
318
  imgDst: imgDst,
235
319
  callback: callback,
236
320
  id: id,
321
+ imageFormat: opt.format || "png",
322
+ imageQuality: opt.quality || 1,
237
323
  getDomSnapshot: getDomSnapshot,
324
+ basicSnapshot: basicSnapshot,
325
+ canvasSnapshot: canvasSnapshot,
326
+ directUpload: directUpload,
327
+ success: success,
328
+ fail: fail,
238
329
  getHtmlFragment: getHtmlFragment,
239
330
  requestHtmlFrag: requestHtmlFrag,
240
331
  htmlSnap: htmlSnap,
@@ -260,8 +351,8 @@
260
351
 
261
352
  var htmlFragRequestListen = function(message) {
262
353
  var send_response = function(data) {
263
- // Update timeout. When we receive a request from parent, we have to finish nested iframes
264
- // rendering in that time. Otherwise parent rendering will timeout.
354
+ // Update timeout. When we receive a request from parent, we have to finish nested iframes
355
+ // rendering in that time. Otherwise parent rendering will timeout.
265
356
  // Backward compatibility: Shutterbug v0.1.x don't send iframeReqTimeout.
266
357
  shutterbugInstance.iframeReqTimeout = data.iframeReqTimeout != null ? data.iframeReqTimeout : MAX_TIMEOUT;
267
358
  shutterbugInstance.getHtmlFragment(function(html) {