not really known
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

145 lines
5.4 KiB

  1. /* Bucker mode will fill an area with a color */
  2. define([], function() {
  3. function initGui() {
  4. PaintApp.elements.bucketButton = document.getElementById('bucket-button');
  5. PaintApp.paletteModesButtons.push(PaintApp.elements.bucketButton);
  6. PaintApp.elements.bucketButton.addEventListener('click', function() {
  7. PaintApp.paletteRemoveActiveClass();
  8. PaintApp.addActiveClassToElement(PaintApp.elements.bucketButton);
  9. PaintApp.switchMode('Bucket');
  10. });
  11. }
  12. //Floodfill functions
  13. function floodfill(x, y, fillcolor, ctx, width, height, tolerance) {
  14. var img = ctx.getImageData(0, 0, width, height);
  15. var data = img.data;
  16. var length = data.length;
  17. var Q = [];
  18. var i = (x + y * width) * 4;
  19. var e = i,
  20. w = i,
  21. me, mw, w2 = width * 4;
  22. var targetcolor = [
  23. data[i],
  24. data[i + 1],
  25. data[i + 2],
  26. data[i + 3]
  27. ];
  28. var targettotal = data[i] + data[i + 1] + data[i + 2] + data[i + 3];
  29. if (!pixelCompare(i, targetcolor, targettotal, fillcolor, data, length, tolerance)) {
  30. return false;
  31. }
  32. Q.push(i);
  33. while (Q.length) {
  34. i = Q.pop();
  35. if (pixelCompareAndSet(i, targetcolor, targettotal, fillcolor, data, length, tolerance)) {
  36. e = i;
  37. w = i;
  38. mw = parseInt(i / w2) * w2;
  39. me = mw + w2;
  40. while (mw < (w -= 4) && pixelCompareAndSet(w, targetcolor, targettotal, fillcolor, data, length, tolerance));
  41. while (me > (e += 4) && pixelCompareAndSet(e, targetcolor, targettotal, fillcolor, data, length, tolerance));
  42. for (var j = w; j < e; j += 4) {
  43. if (j - w2 >= 0 && pixelCompare(j - w2, targetcolor, targettotal, fillcolor, data, length, tolerance))
  44. Q.push(j - w2);
  45. if (j + w2 < length && pixelCompare(j + w2, targetcolor, targettotal, fillcolor, data, length, tolerance))
  46. Q.push(j + w2);
  47. }
  48. }
  49. }
  50. ctx.putImageData(img, 0, 0);
  51. }
  52. //Floodfill functions
  53. function pixelCompare(i, targetcolor, targettotal, fillcolor, data, length, tolerance) {
  54. if (i < 0 || i >= length)
  55. return false;
  56. if (data[i + 3] === 0)
  57. return true;
  58. if (targetcolor[3] === fillcolor.a && targetcolor[0] === fillcolor.r && targetcolor[1] === fillcolor.g && targetcolor[2] === fillcolor.b)
  59. return false;
  60. if (targetcolor[3] === data[i + 3] && targetcolor[0] === data[i] && targetcolor[1] === data[i + 1] && targetcolor[2] === data[i + 2])
  61. return true;
  62. if (Math.abs(targetcolor[3] - data[i + 3]) <= 255 - tolerance && Math.abs(targetcolor[0] - data[i]) <= tolerance && Math.abs(targetcolor[1] - data[i + 1]) <= tolerance && Math.abs(targetcolor[2] - data[i + 2]) <= tolerance)
  63. return true;
  64. return false;
  65. }
  66. //Floodfill functions
  67. function pixelCompareAndSet(i, targetcolor, targettotal, fillcolor, data, length, tolerance) {
  68. if (pixelCompare(i, targetcolor, targettotal, fillcolor, data, length, tolerance)) {
  69. data[i] = fillcolor.r;
  70. data[i + 1] = fillcolor.g;
  71. data[i + 2] = fillcolor.b;
  72. data[i + 3] = 255;
  73. return true;
  74. }
  75. return false;
  76. }
  77. var Bucket = {
  78. initGui: initGui,
  79. lock: false,
  80. onMouseDown: function(event) {
  81. if (PaintApp.modes.Bucket.lock) {
  82. return;
  83. }
  84. var ctx = PaintApp.elements.canvas.getContext('2d');
  85. /* Transformation of the color used inside the palette to match with the bucket fill functions prototypes */
  86. var colorFillStrings = PaintApp.data.color.fill.slice(4, -1).split(',');
  87. var colorFill = [
  88. parseInt(colorFillStrings[0]),
  89. parseInt(colorFillStrings[1]),
  90. parseInt(colorFillStrings[2]),
  91. 0
  92. ];
  93. var colorHex = colorFill.map(function(x) {
  94. x = parseInt(x).toString(16);
  95. return x.length == 1 ? '0' + x : x;
  96. });
  97. var fillColor = {
  98. a: 1,
  99. r: parseInt(colorFill[0]),
  100. g: parseInt(colorFill[1]),
  101. b: parseInt(colorFill[2])
  102. };
  103. /* Getting the clicked point */
  104. var p = ctx.getImageData(event.point.x * window.devicePixelRatio, event.point.y * window.devicePixelRatio, 1, 1).data;
  105. /* If the color of the point is too close to the required color we stop the process */
  106. /* We can't do a strict equality because browsers will auto change a few colors and we cannot prevent it... */
  107. if (Math.abs(p[0] - fillColor.r) <= 10 && Math.abs(p[1] - fillColor.g) <= 10 && Math.abs(p[2] - fillColor.b) <= 10) {
  108. PaintApp.modes.Bucket.lock = false;
  109. return;
  110. }
  111. /* Proceed with the bucket fill */
  112. floodfill(parseInt(event.point.x * window.devicePixelRatio), parseInt(event.point.y * window.devicePixelRatio), fillColor, ctx, ctx.canvas.width, ctx.canvas.height, 5);
  113. PaintApp.saveCanvas();
  114. PaintApp.modes.Bucket.lock = false;
  115. /* If inside a shared activity, send the new image to everyone */
  116. if (PaintApp.data.isShared) {
  117. try {
  118. PaintApp.collaboration.sendMessage({
  119. action: 'toDataURL',
  120. data: {
  121. width: PaintApp.elements.canvas.width / window.devicePixelRatio,
  122. height: PaintApp.elements.canvas.height / window.devicePixelRatio,
  123. src: PaintApp.collaboration.compress(PaintApp.elements.canvas.toDataURL())
  124. }
  125. })
  126. } catch (e) {}
  127. }
  128. },
  129. onMouseDrag: function(event) {},
  130. onMouseUp: function(event) {}
  131. };
  132. return Bucket;
  133. });