Advertisement
Guest User

canvas

a guest
Oct 21st, 2014
180
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.09 KB | None | 0 0
  1. var when = require('when');
  2. /*
  3. * MIT License
  4. * You may use this code as long as you retain this notice. Use at your own risk! :)
  5. * https://github.com/danschumann/limby-resize
  6. * 0.0.4
  7. */
  8. var canvasResize = function(original, canvas) {
  9.  
  10. var
  11. w1 = original.width,
  12. h1 = original.height,
  13. w2 = canvas.width,
  14. h2 = canvas.height,
  15. img = original.getContext("2d").getImageData(0, 0, w1, h1),
  16. img2 = canvas.getContext("2d").getImageData(0, 0, w2, h2);
  17.  
  18. if (w2 > w1 || h2 > h1) {
  19. canvas.getContext('2d').drawImage(original, 0, 0, w2, h2);
  20. return;
  21. };
  22.  
  23.  
  24. var data = img.data;
  25. // we don't use this much, as working with doubles isn't great
  26. var _data2 = img2.data;
  27.  
  28. // We enforce float type for every entity in the array
  29. // this prevents weird faded lines when things get rounded off
  30. var data2 = Array(_data2.length);
  31. for (var i = 0; i < _data2.length; i++){
  32. data2[i] = 0.0;
  33. }
  34.  
  35. // We track alphas, since we need to use alphas to correct colors later on
  36. var alphas = Array(_data2.length >> 2);
  37. for (var i = 0; i < _data2.length >> 2; i++){
  38. alphas[i] = 1;
  39. }
  40.  
  41. // when resizing down, this will be decimal
  42. var xScale = w2 / w1;
  43. var yScale = h2 / h1;
  44.  
  45. // For every pixel in the original, we tally it up in the new one
  46. var nextY = function(y1){
  47. for (var x1 = 0; x1 < w1; x1++) {
  48.  
  49. var
  50.  
  51. // the original pixel is split between two pixels in the output, we do an extra step
  52. extraX = false,
  53. extraY = false,
  54.  
  55. // the output pixel
  56. targetX = Math.floor(x1 * xScale),
  57. targetY = Math.floor(y1 * yScale),
  58.  
  59. // The percentage of this pixel going to the output pixel
  60. xFactor = xScale,
  61. yFactor = yScale,
  62.  
  63. // The percentage of this pixel going to the right neighbor or bottom neighbor
  64. bottomFactor = 0,
  65. rightFactor = 0,
  66.  
  67. // positions of pixels in the array
  68. offset = (y1 * w1 + x1) * 4,
  69. targetOffset = (targetY * w2 + targetX) * 4;
  70.  
  71. // Right side goes into another pixel
  72. if (targetX < Math.floor((x1 + 1) * xScale)) {
  73.  
  74. rightFactor = (((x1 + 1) * xScale) % 1);
  75. xFactor -= rightFactor;
  76.  
  77. extraX = true;
  78.  
  79. }
  80.  
  81. // Bottom side goes into another pixel
  82. if (targetY < Math.floor((y1 + 1) * yScale)) {
  83.  
  84. bottomFactor = (((y1 + 1) * yScale) % 1);
  85. yFactor -= bottomFactor;
  86.  
  87. extraY = true;
  88.  
  89. }
  90.  
  91. var a;
  92.  
  93. a = (data[offset + 3] / 255);
  94.  
  95. alphaOffset = targetOffset / 4;
  96.  
  97. if (extraX) {
  98.  
  99. // Since we're not adding the color of invisible pixels, we multiply by a
  100. data2[targetOffset + 4] += data[offset] * rightFactor * yFactor * a;
  101. data2[targetOffset + 5] += data[offset + 1] * rightFactor * yFactor * a;
  102. data2[targetOffset + 6] += data[offset + 2] * rightFactor * yFactor * a;
  103.  
  104. data2[targetOffset + 7] += data[offset + 3] * rightFactor * yFactor;
  105.  
  106. // if we left out the color of invisible pixels(fully or partly)
  107. // the entire average we end up with will no longer be out of 255
  108. // so we subtract the percentage from the alpha ( originally 1 )
  109. // so that we can reverse this effect by dividing by the amount.
  110. // ( if one pixel is black and invisible, and the other is white and visible,
  111. // the white pixel will weight itself at 50% because it does not know the other pixel is invisible
  112. // so the total(color) for the new pixel would be 128(gray), but it should be all white.
  113. // the alpha will be the correct 128, combinging alphas, but we need to preserve the color
  114. // of the visible pixels )
  115. alphas[alphaOffset + 1] -= (1 - a) * rightFactor * yFactor;
  116. }
  117.  
  118. if (extraY) {
  119. data2[targetOffset + w2 * 4] += data[offset] * xFactor * bottomFactor * a;
  120. data2[targetOffset + w2 * 4 + 1] += data[offset + 1] * xFactor * bottomFactor * a;
  121. data2[targetOffset + w2 * 4 + 2] += data[offset + 2] * xFactor * bottomFactor * a;
  122.  
  123. data2[targetOffset + w2 * 4 + 3] += data[offset + 3] * xFactor * bottomFactor;
  124.  
  125. alphas[alphaOffset + w2] -= (1 - a) * xFactor * bottomFactor;
  126. }
  127.  
  128. if (extraX && extraY) {
  129. data2[targetOffset + w2 * 4 + 4] += data[offset] * rightFactor * bottomFactor * a;
  130. data2[targetOffset + w2 * 4 + 5] += data[offset + 1] * rightFactor * bottomFactor * a;
  131. data2[targetOffset + w2 * 4 + 6] += data[offset + 2] * rightFactor * bottomFactor * a;
  132.  
  133. data2[targetOffset + w2 * 4 + 7] += data[offset + 3] * rightFactor * bottomFactor;
  134.  
  135. alphas[alphaOffset + w2 + 1] -= (1 - a) * rightFactor * bottomFactor;
  136. }
  137.  
  138. data2[targetOffset] += data[offset] * xFactor * yFactor * a;
  139. data2[targetOffset + 1] += data[offset + 1] * xFactor * yFactor * a;
  140. data2[targetOffset + 2] += data[offset + 2] * xFactor * yFactor * a;
  141.  
  142. data2[targetOffset + 3] += data[offset + 3] * xFactor * yFactor;
  143.  
  144. alphas[alphaOffset] -= (1 - a) * xFactor * yFactor;
  145. };
  146.  
  147. if (y1++ < h1)
  148. setTimeout(nextY.bind(this, y1), 0); // this allows other processes to tick
  149. else
  150. done();
  151.  
  152. };
  153.  
  154. nextY(0);
  155.  
  156. var done = function(){
  157.  
  158. // fully distribute the color of pixels that are partially full because their neighbor is transparent
  159. for (var i = 0; i < (_data2.length >> 2); i++){
  160. if (alphas[i] && alphas[i] < 1) {
  161. data2[(i<<2)] /= alphas[i]; // r
  162. data2[(i<<2) + 1] /= alphas[i]; // g
  163. data2[(i<<2) + 2] /= alphas[i]; // b
  164. }
  165. }
  166.  
  167. // re populate the actual imgData
  168. for (var i = 0; i < data2.length; i++){
  169. _data2[i] = Math.round(data2[i]);
  170. }
  171.  
  172. var context = canvas.getContext("2d")
  173. context.putImageData(img2, 0, 0);
  174. deferred.resolve();
  175.  
  176. };
  177.  
  178. var deferred = when.defer();
  179. return deferred.promise
  180.  
  181. };
  182.  
  183. // Allow for use with browser or node.js
  184. if ('undefined' !== typeof window) {
  185. window.canvasResize = canvasResize;
  186. } else {
  187. module.exports = canvasResize;
  188. };
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement