Colourful LOR

Improve LOR with colourful pixel art!

目前为 2018-12-26 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name Colourful LOR
  3. // @namespace com.bodqhrohro.lor.colourful
  4. // @description Improve LOR with colourful pixel art!
  5. // @include https://www.linux.org.ru/*
  6. // @version 1
  7. // @grant none
  8. // ==/UserScript==
  9.  
  10.  
  11. (function() {
  12. var forthMap = {
  13. 3: 8,
  14. 4: 3,
  15. 5: 6,
  16. 6: 9,
  17. 7: 13,
  18. 8: 4,
  19. 9: 5,
  20. 10: 7,
  21. 11: 12,
  22. 12: 10,
  23. 13: 11
  24. }
  25. var backMap = {
  26. 3: 4,
  27. 4: 8,
  28. 5: 9,
  29. 6: 5,
  30. 7: 10,
  31. 8: 3,
  32. 9: 6,
  33. 10: 12,
  34. 11: 13,
  35. 12: 11,
  36. 13: 7
  37. }
  38. var braileRegex = /^[⠀-⣿]+$/m
  39. var PIXEL_SCALE = 8
  40.  
  41. var reduceByte = function(byte) {
  42. byte = (byte>>3) & 15
  43. return byte < 3 || byte > 13 ? byte : forthMap[byte]
  44. }
  45.  
  46. var enduceByte = function(byte) {
  47. byte = byte < 3 || byte > 13 ? byte : backMap[byte]
  48. return byte << 3
  49. }
  50.  
  51. var bytesToBraile = function(byte1, byte2) {
  52. byte1 = reduceByte(byte1)
  53. byte2 = reduceByte(byte2)
  54. return String.fromCharCode(0x2800 + ((byte2&8)<<4) + ((byte1&8)<<3) + ((byte2&7)<<3) + (byte1&7))
  55. }
  56. var braileToBytes = function(symbol) {
  57. symbol = symbol.charCodeAt(0) - 0x2800
  58. byte1 = (symbol&7) + ((symbol&64)>>3)
  59. byte2 = ((symbol&56)>>3) + ((symbol&128)>>4)
  60.  
  61. return [
  62. enduceByte(byte1),
  63. enduceByte(byte2)
  64. ]
  65. }
  66.  
  67. var insertText = function(textarea, text) {
  68. var startPos = textarea.selectionStart
  69. var endPos = textarea.selectionEnd
  70. textarea.value = textarea.value.substring(0, startPos) +
  71. '\n\n' + text + '\n\n' +
  72. textarea.value.substring(endPos, textarea.value.length)
  73. textarea.selectionStart = startPos + text.length
  74. textarea.selectionEnd = startPos + text.length
  75. }
  76. var encodeImage = function(img) {
  77. var canvas = document.createElement('canvas')
  78. var ctx = canvas.getContext('2d')
  79. ctx.drawImage(img, 0, 0)
  80. var imageData = ctx.getImageData(0, 0, img.width, img.height).data
  81. var text = ''
  82. var bytesWidth = img.width * 4
  83. var r, g, b, a;
  84. for (var i = 0; i < imageData.length; i += 4) {
  85. r = imageData[i];
  86. g = imageData[i+1];
  87. b = imageData[i+2];
  88. a = imageData[i+3];
  89. // alpha subcarrier
  90. a &= 128
  91. a >>= 4
  92. a |= (r & 128) >> 1
  93. a |= (g & 128) >> 2
  94. a |= (b & 128) >> 3
  95.  
  96. if (!(i % bytesWidth)) {
  97. text += '[br]\n'
  98. }
  99. text += bytesToBraile(r, g)
  100. text += bytesToBraile(b, a)
  101. }
  102. return text
  103. }
  104.  
  105. var assignFileInputs = function(textarea) {
  106. var fileInput = document.createElement('input')
  107. fileInput.type = 'file'
  108.  
  109. textarea.parentNode.insertBefore(fileInput, textarea.nextSibling)
  110. fileInput.addEventListener('change', function() {
  111. if (!FileReader || !this.files.length) {
  112. return ''
  113. }
  114.  
  115. var fileReader = new FileReader()
  116. fileReader.onload = function() {
  117. var img = document.createElement('img')
  118. document.body.appendChild(img)
  119. img.style.display = 'none'
  120. img.src = fileReader.result
  121. img.onload = function() {
  122. var text = encodeImage(img)
  123. insertText(textarea, text)
  124. img.parentNode.removeChild(img)
  125. }
  126. }
  127. fileReader.readAsDataURL(this.files[0])
  128. })
  129. // description
  130. var description = document.createElement('div')
  131. description.innerHTML = 'Картинка для Colourful:'
  132. textarea.parentNode.insertBefore(description, fileInput)
  133. }
  134. var decodeImage = function(p) {
  135. var canvas = document.createElement('canvas')
  136. var ctx = canvas.getContext('2d')
  137.  
  138. lines = p.innerText.split('\n').filter(function(line) { return line !== ''; })
  139.  
  140. canvas.width = Math.max.apply(null, Array.prototype.map.call(lines, function(line) {
  141. return line.length / 2;
  142. })) * PIXEL_SCALE
  143. canvas.height = lines.length * PIXEL_SCALE
  144. lines.forEach(function(line, lineIndex) {
  145. for (var i = 0; i < line.length; i += 2) {
  146. var rg = line[i]
  147. var ba = line[i+1]
  148. rg = braileToBytes(rg)
  149. ba = braileToBytes(ba)
  150.  
  151. var r = rg[0]
  152. var g = rg[1]
  153. var b = ba[0]
  154. var a = ba[1]
  155. ctx.beginPath()
  156. ctx.rect(i * PIXEL_SCALE / 2, lineIndex * PIXEL_SCALE, PIXEL_SCALE, PIXEL_SCALE)
  157. ctx.fillStyle = 'rgba(' + [r, g, b, a].join(',') + ')'
  158. ctx.fill()
  159. }
  160. })
  161.  
  162. p.innerHTML = ''
  163. p.appendChild(canvas)
  164. }
  165.  
  166. var decodeImages = function(message) {
  167. var ps = message.querySelectorAll('p')
  168. if (ps && ps.length) {
  169. Array.prototype.forEach.call(ps, function(p) {
  170. if (braileRegex.test(p.innerText)) {
  171. decodeImage(p)
  172. }
  173. })
  174. }
  175. }
  176.  
  177. window.addEventListener('load', function() {
  178. // encode
  179. var textareas = document.getElementsByTagName('textarea')
  180. if (textareas && textareas.length) {
  181. Array.prototype.forEach.call(textareas, assignFileInputs)
  182. }
  183.  
  184. //decode
  185. var messages = document.querySelectorAll('.msg_body')
  186. if (messages && messages.length) {
  187. Array.prototype.forEach.call(messages, decodeImages)
  188. }
  189. })
  190. })()