diff --git a/app/js/common/blurhash.js b/app/js/common/blurhash.js new file mode 100644 index 00000000..4616a51e --- /dev/null +++ b/app/js/common/blurhash.js @@ -0,0 +1,119 @@ +var digitCharacters = [ + "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", + "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", + "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", + "U", "V", "W", "X", "Y", "Z", "a", "b", "c", "d", + "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", + "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", + "y", "z", "#", "$", "%", "*", "+", ",", "-", ".", + ":", ";", "=", "?", "@", "[", "]", "^", "_", "{", + "|", "}", "~", +]; +function decode83(str) { + var value = 0; + for (var i = 0; i < str.length; i++) { + var c = str[i]; + var digit = digitCharacters.indexOf(c); + value = value * 83 + digit; + } + return value; +} +function linearTosRGB(value) { + var v = Math.max(0, Math.min(1, value)); + if (v <= 0.0031308) { + return Math.round(v * 12.92 * 255 + 0.5); + } + else { + return Math.round((1.055 * Math.pow(v, 1 / 2.4) - 0.055) * 255 + 0.5); + } +} +function sRGBToLinear(value) { + var v = value / 255; + if (v <= 0.04045) { + return v / 12.92; + } + else { + return Math.pow((v + 0.055) / 1.055, 2.4); + } +} +function decodeDC(value) { + var intR = value >> 16; + var intG = (value >> 8) & 255; + var intB = value & 255; + return [sRGBToLinear(intR), sRGBToLinear(intG), sRGBToLinear(intB)]; +}; +function sign(n) { return (n < 0 ? -1 : 1); } +function signPow(val, exp) { return sign(val) * Math.pow(Math.abs(val), exp); } +function decodeDC2(value, maximumValue) { + var quantR = Math.floor(value / (19 * 19)); + var quantG = Math.floor(value / 19) % 19; + var quantB = value % 19; + var rgb = [ + signPow((quantR - 9) / 9, 2.0) * maximumValue, + signPow((quantG - 9) / 9, 2.0) * maximumValue, + signPow((quantB - 9) / 9, 2.0) * maximumValue, + ]; + return rgb; +}; +function decodeblur(blurhash, width, height, punch) { + punch = punch | 1; + if (blurhash.length < 6) { + console.error('too short blurhash'); + return null; + } + var sizeFlag = decode83(blurhash[0]); + var numY = Math.floor(sizeFlag / 9) + 1; + var numX = (sizeFlag % 9) + 1; + var quantisedMaximumValue = decode83(blurhash[1]); + var maximumValue = (quantisedMaximumValue + 1) / 166; + if (blurhash.length !== 4 + 2 * numX * numY) { + console.error('blurhash length mismatch', blurhash.length, 4 + 2 * numX * numY); + return null; + } + var colors = new Array(numX * numY); + for (var i = 0; i < colors.length; i++) { + if (i === 0) { + var value = decode83(blurhash.substring(2, 6)); + colors[i] = decodeDC(value); + } + else { + var value = decode83(blurhash.substring(4 + i * 2, 6 + i * 2)); + colors[i] = decodeDC2(value, maximumValue * punch); + } + } + var bytesPerRow = width * 4; + var pixels = new Uint8ClampedArray(bytesPerRow * height); + for (var y = 0; y < height; y++) { + for (var x = 0; x < width; x++) { + var r = 0; + var g = 0; + var b = 0; + for (var j = 0; j < numY; j++) { + for (var i = 0; i < numX; i++) { + var basis = Math.cos(Math.PI * x * i / width) * Math.cos(Math.PI * y * j / height); + var color = colors[i + j * numX]; + r += color[0] * basis; + g += color[1] * basis; + b += color[2] * basis; + } + } + var intR = linearTosRGB(r); + var intG = linearTosRGB(g); + var intB = linearTosRGB(b); + pixels[4 * x + 0 + y * bytesPerRow] = intR; + pixels[4 * x + 1 + y * bytesPerRow] = intG; + pixels[4 * x + 2 + y * bytesPerRow] = intB; + pixels[4 * x + 3 + y * bytesPerRow] = 255; // alpha + } + } + return pixels; +} +function parseBlur(blur) { + var canvas = document.getElementById('canvas'); + var ctx = canvas.getContext('2d'); + var pixels = decodeblur(blur, 32, 32) + const imageData = new ImageData(pixels, 32, 32); + + ctx.putImageData(imageData, 0, 0); + return canvas.toDataURL() +} \ No newline at end of file diff --git a/app/js/tl/parse.js b/app/js/tl/parse.js index a41406eb..a9e7e4c2 100644 --- a/app/js/tl/parse.js +++ b/app/js/tl/parse.js @@ -580,16 +580,25 @@ function parse(obj, mix, acct_id, tlid, popup, mutefilter, type) { var purl = media.preview_url; media_ids=media_ids+media.id+","; var url = media.url; + var nsfwmes="" if (toot.sensitive && nsfw) { var sense = "sensitive" + var blur=media.blurhash + if(blur){ + nsfwmes='NSFW media' + purl=parseBlur(blur) + var sense="" + } } else { var sense = "" + var blur=null } - viewer = viewer + ''; + ' toot-img pointer" style="width:calc(' + cwdt + '% - 1px); height:'+imh+';">'+nsfwmes; + }); media_ids = media_ids.slice(0, -1) ; } else { diff --git a/app/js/ui/settings.js b/app/js/ui/settings.js index 62bc14fa..780dffab 100644 --- a/app/js/ui/settings.js +++ b/app/js/ui/settings.js @@ -668,3 +668,4 @@ oksload(); npprovider(); ctLoad() }; + diff --git a/app/package.json b/app/package.json index ad278db0..9786ab22 100644 --- a/app/package.json +++ b/app/package.json @@ -1,6 +1,6 @@ { "name": "thedesk", - "version": "18.3.2", + "version": "18.3.3", "description": "TheDesk is a Mastodon client for PC.", "repository": "https://github.com/cutls/TheDesk", "main": "main.js", @@ -88,8 +88,7 @@ "linux": { "icon": "build/icons", "target": [ - "zip", - "snap" + "zip" ], "category": "Network" }, diff --git a/app/view/en/acct.html b/app/view/en/acct.html index c3a3c1ff..efdbe7df 100644 --- a/app/view/en/acct.html +++ b/app/view/en/acct.html @@ -1,5 +1,5 @@ - +
アップデートがあります
+Get latest TheDesk
→