Colourful LOR

Improve LOR with colourful pixel art!

Dovrai installare un'estensione come Tampermonkey, Greasemonkey o Violentmonkey per installare questo script.

You will need to install an extension such as Tampermonkey to install this script.

Dovrai installare un'estensione come Tampermonkey o Violentmonkey per installare questo script.

Dovrai installare un'estensione come Tampermonkey o Userscripts per installare questo script.

Dovrai installare un'estensione come ad esempio Tampermonkey per installare questo script.

Dovrai installare un gestore di script utente per installare questo script.

(Ho già un gestore di script utente, lasciamelo installare!)

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

(Ho già un gestore di stile utente, lasciamelo installare!)

// ==UserScript==
// @name        Colourful LOR
// @namespace   com.bodqhrohro.lor.colourful
// @description Improve LOR with colourful pixel art!
// @include     https://www.linux.org.ru/*
// @version     1
// @grant       none
// ==/UserScript==


(function() {
  var forthMap = {
    3: 8,
    4: 3,
    5: 6,
    6: 9,
    7: 13,
    8: 4,
    9: 5,
    10: 7,
    11: 12,
    12: 10,
    13: 11
  }
  
  var backMap = {
    3: 4,
    4: 8,
    5: 9,
    6: 5,
    7: 10,
    8: 3,
    9: 6,
    10: 12,
    11: 13,
    12: 11,
    13: 7
  }
  
  var braileRegex = /^[⠀-⣿]+$/m
  
  var PIXEL_SCALE = 8

  var reduceByte = function(byte) {
    byte = (byte>>3) & 15
    return byte < 3 || byte > 13 ? byte : forthMap[byte]
  }

  var enduceByte = function(byte) {
    byte = byte < 3 || byte > 13 ? byte : backMap[byte]
    return byte << 3
  }

  var bytesToBraile = function(byte1, byte2) {
    byte1 = reduceByte(byte1)
    byte2 = reduceByte(byte2)
    return String.fromCharCode(0x2800 + ((byte2&8)<<4) + ((byte1&8)<<3) + ((byte2&7)<<3) + (byte1&7))
  }
  
  var braileToBytes = function(symbol) {
    symbol = symbol.charCodeAt(0) - 0x2800
    byte1 = (symbol&7) + ((symbol&64)>>3)
    byte2 = ((symbol&56)>>3) + ((symbol&128)>>4)

    return [
      enduceByte(byte1),
      enduceByte(byte2)
    ]
  }

  var insertText = function(textarea, text) {
      var startPos = textarea.selectionStart
      var endPos = textarea.selectionEnd
      textarea.value = textarea.value.substring(0, startPos) +
        '\n\n' + text + '\n\n' +
        textarea.value.substring(endPos, textarea.value.length)
      textarea.selectionStart = startPos + text.length
      textarea.selectionEnd = startPos + text.length
  }
  
  var encodeImage = function(img) {
    var canvas = document.createElement('canvas')
    var ctx = canvas.getContext('2d')
    
    ctx.drawImage(img, 0, 0)
    var imageData = ctx.getImageData(0, 0, img.width, img.height).data
    
    var text = ''
    var bytesWidth = img.width * 4
    var r, g, b, a;
    for (var i = 0; i < imageData.length; i += 4) {
      r = imageData[i];
      g = imageData[i+1];
      b = imageData[i+2];
      a = imageData[i+3];
      
      // alpha subcarrier
      a &= 128
      a >>= 4
      a |= (r & 128) >> 1
      a |= (g & 128) >> 2
      a |= (b & 128) >> 3

      if (!(i % bytesWidth)) {
        text += '[br]\n'
      }
      text += bytesToBraile(r, g)
      text += bytesToBraile(b, a)
    }
    return text
  }

  var assignFileInputs = function(textarea) {
    var fileInput = document.createElement('input')
    fileInput.type = 'file'

    textarea.parentNode.insertBefore(fileInput, textarea.nextSibling)
    fileInput.addEventListener('change', function() {
      if (!FileReader || !this.files.length) {
        return ''
      }

      var fileReader = new FileReader()
      fileReader.onload = function() {
        var img = document.createElement('img')
        document.body.appendChild(img)
        img.style.display = 'none'
        img.src = fileReader.result
        img.onload = function() {
          var text = encodeImage(img)
          insertText(textarea, text)
          img.parentNode.removeChild(img)
        }
      }
      fileReader.readAsDataURL(this.files[0])
    })
    
    // description
    var description = document.createElement('div')
    description.innerHTML = 'Картинка для Colourful:'
    textarea.parentNode.insertBefore(description, fileInput)
  }
  
  var decodeImage = function(p) {
    var canvas = document.createElement('canvas')
    var ctx = canvas.getContext('2d')

    lines = p.innerText.split('\n').filter(function(line) { return line !== ''; })

    canvas.width = Math.max.apply(null, Array.prototype.map.call(lines, function(line) {
      return line.length / 2;
    })) * PIXEL_SCALE
    canvas.height = lines.length * PIXEL_SCALE
    
    lines.forEach(function(line, lineIndex) {
      for (var i = 0; i < line.length; i += 2) {
        var rg = line[i]
        var ba = line[i+1]
        
        rg = braileToBytes(rg)
        ba = braileToBytes(ba)

        var r = rg[0]
        var g = rg[1]
        var b = ba[0]
        var a = ba[1]

        r += (a & 64) << 1
        g += (a & 32) << 2
        b += (a & 16) << 3
        a = (a & 8) ? 255 : 0
        
        ctx.beginPath()
        ctx.rect(i * PIXEL_SCALE / 2, lineIndex * PIXEL_SCALE, PIXEL_SCALE, PIXEL_SCALE)
        ctx.fillStyle = 'rgba(' + [r, g, b, a].join(',') + ')'
        ctx.fill()
      }
    })

    p.innerHTML = ''
    p.appendChild(canvas)
  }

  var decodeImages = function(message) {
    var ps = message.querySelectorAll('p')
    if (ps && ps.length) {
      Array.prototype.forEach.call(ps, function(p) {
        if (braileRegex.test(p.innerText)) {
          decodeImage(p)
        }
      })
    }
  }

  window.addEventListener('load', function() {
    // encode
    var textareas = document.getElementsByTagName('textarea')
    if (textareas && textareas.length) {
      Array.prototype.forEach.call(textareas, assignFileInputs)
    }

    //decode
    var messages = document.querySelectorAll('.msg_body')
    if (messages && messages.length) {
      Array.prototype.forEach.call(messages, decodeImages)
    }
  })
})()