123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231 |
- #! /usr/bin/perl
- # Copyright (C) 2017 Alex Schroeder <alex@gnu.org>
- # This program is free software: you can redistribute it and/or modify it under
- # the terms of the GNU General Public License as published by the Free Software
- # Foundation, either version 3 of the License, or (at your option) any later
- # version.
- #
- # This program is distributed in the hope that it will be useful, but WITHOUT
- # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
- #
- # You should have received a copy of the GNU General Public License along with
- # this program. If not, see <http://www.gnu.org/licenses/>.
- use strict;
- use v5.10;
- AddModuleDescription('paste-image.pl', 'Paste Files to Upload');
- our (@MyInitVariables, $ScriptName, $HtmlHeaders, $MaxPost, $CommentsPattern,
- $QuestionaskerSecretKey);
- our ($PasteImageOnBrowse);
- $PasteImageOnBrowse = 0;
- push(@MyInitVariables, \&PasteImageScript);
- # Resampling based on the following:
- # https://stackoverflow.com/a/19223362/534893
- # https://github.com/viliusle/Hermite-resize
- sub PasteImageScript {
- my $id = GetId();
- return unless $id;
- OpenPage($id);
- my $username = GetParam('username', '');
- my $templatePage = "Image_{n}_for_$id";
- my $templateText = "Image {n}";
- my $question = $QuestionaskerSecretKey || 'question';
- if ((GetParam('action', 'browse') eq 'edit'
- or GetParam('action', 'browse') eq 'new'
- or $CommentsPattern and $id =~ /$CommentsPattern/
- or $PasteImageOnBrowse and GetParam('action', 'browse') eq 'browse')
- and $HtmlHeaders !~ /PasteImage/) {
- $HtmlHeaders .= << "EOT";
- <script type="text/javascript">
- if (!HTMLTextAreaElement.prototype.insertAtCaret) {
- HTMLTextAreaElement.prototype.insertAtPoint = function (text) {
- text = text || '';
- if (this.selectionStart || this.selectionStart === 0) {
- // Others
- var startPos = this.selectionStart;
- var endPos = this.selectionEnd;
- this.value = this.value.substring(0, startPos) +
- text +
- this.value.substring(endPos, this.value.length);
- this.selectionStart = startPos + text.length;
- this.selectionEnd = startPos + text.length;
- } else {
- this.value += text;
- }
- };
- };
- var PasteImage = {
- init: function() {
- let e = document.getElementById('text') || document.getElementById('aftertext');
- if (e)
- e.addEventListener('paste', PasteImage.handler);
- },
- handler: function(e) {
- // Chrome
- if (e.clipboardData) {
- let items = e.clipboardData.items;
- for (var i = 0; i < items.length; i++) {
- if (items[i].type.indexOf("image") !== -1) {
- let blob = items[i].getAsFile();
- let reader = new window.FileReader();
- reader.onloadend = function() {
- let dataUrl = reader.result;
- let n = 1;
- while (n++ < 4 && $MaxPost > 0 && dataUrl.length > $MaxPost)
- dataUrl = PasteImage.shrink(dataUrl);
- PasteImage.process(dataUrl, "$templatePage", "$templateText", 1);
- }
- reader.readAsDataURL(blob);
- }
- }
- }
- },
- shrink: function(dataUrl) {
- let image = new Image;
- image.src = dataUrl;
- let canvas = document.createElement("canvas");
- canvas.width = image.width;
- canvas.height = image.height;
- let ctx = canvas.getContext("2d");
- ctx.drawImage(image, 0, 0);
- let width_source = canvas.width;
- let height_source = canvas.height;
- let width = Math.round(width_source * 0.5);
- let height = Math.round(height_source * 0.5);
- let ratio_w = width_source / width;
- let ratio_h = height_source / height;
- let ratio_w_half = Math.ceil(ratio_w / 2);
- let ratio_h_half = Math.ceil(ratio_h / 2);
- let img = ctx.getImageData(0, 0, width_source, height_source);
- let img2 = ctx.createImageData(width, height);
- let data = img.data;
- let data2 = img2.data;
- for (let j = 0; j < height; j++) {
- for (let i = 0; i < width; i++) {
- let x2 = (i + j * width) * 4;
- let weight = 0;
- let weights = 0;
- let weights_alpha = 0;
- let gx_r = 0;
- let gx_g = 0;
- let gx_b = 0;
- let gx_a = 0;
- let center_y = (j + 0.5) * ratio_h;
- let yy_start = Math.floor(j * ratio_h);
- let yy_stop = Math.ceil((j + 1) * ratio_h);
- for (let yy = yy_start; yy < yy_stop; yy++) {
- let dy = Math.abs(center_y - (yy + 0.5)) / ratio_h_half;
- let center_x = (i + 0.5) * ratio_w;
- let w0 = dy * dy; //pre-calc part of w
- let xx_start = Math.floor(i * ratio_w);
- let xx_stop = Math.ceil((i + 1) * ratio_w);
- for (let xx = xx_start; xx < xx_stop; xx++) {
- let dx = Math.abs(center_x - (xx + 0.5)) / ratio_w_half;
- let w = Math.sqrt(w0 + dx * dx);
- if (w >= 1) {
- //pixel too far
- continue;
- }
- //hermite filter
- weight = 2 * w * w * w - 3 * w * w + 1;
- let pos_x = 4 * (xx + yy * width_source);
- //alpha
- gx_a += weight * data[pos_x + 3];
- weights_alpha += weight;
- //colors
- if (data[pos_x + 3] < 255)
- weight = weight * data[pos_x + 3] / 250;
- gx_r += weight * data[pos_x];
- gx_g += weight * data[pos_x + 1];
- gx_b += weight * data[pos_x + 2];
- weights += weight;
- }
- }
- data2[x2] = gx_r / weights;
- data2[x2 + 1] = gx_g / weights;
- data2[x2 + 2] = gx_b / weights;
- data2[x2 + 3] = gx_a / weights_alpha;
- }
- }
- canvas.width = width;
- canvas.height = height;
- ctx.putImageData(img2, 0, 0);
- let png = canvas.toDataURL();
- let jpg = canvas.toDataURL('image/jpeg');
- return png <= jpg ? png : jpg;
- },
- process: function(dataUrl, templatePage, templateText, n) {
- let name = templatePage.replace('{n}', n);
- let text = templateText.replace('{n}', n);
- let xhr = new XMLHttpRequest();
- xhr.open("HEAD", "$ScriptName/" + name, true);
- xhr.onreadystatechange = function() {
- if (xhr.readyState == 4) {
- if (xhr.status == 200) {
- PasteImage.process(dataUrl, templatePage, templateText, n+1);
- } else if (xhr.status == 404) {
- PasteImage.post(dataUrl, name, text);
- } else {
- let re = /<h1>(.*)<\\/h1>/g;
- let match = re.exec(xhr.responseText);
- alert(match[1]);
- }
- }
- };
- xhr.send(null);
- },
- post: function(dataUrl, name, text) {
- let xhr = new XMLHttpRequest();
- xhr.open("POST", "$ScriptName", true);
- xhr.onreadystatechange = function() {
- if (xhr.readyState == 4) {
- if (xhr.status == 200) {
- let e = document.getElementById('text') || document.getElementById('aftertext');
- e.insertAtPoint("[[image:" + name + "|" + text + "]]");
- } else {
- let re = /<h1>(.*)<\\/h1>/g;
- let match = re.exec(xhr.responseText);
- alert(match[1]);
- }
- }
- }
- let mimeType = dataUrl.split(',')[0].split(':')[1].split(';')[0];
- let content = encodeURIComponent(dataUrl.split(',')[1]);
- let params = "title=" + encodeURIComponent(name);
- params += "&summary=" + encodeURIComponent(name);
- params += "&username=" + encodeURIComponent("$username");
- params += "&recent_edit=on";
- params += "&$question=1";
- params += "&text=#FILE " + mimeType + "%0A" + content;
- xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
- xhr.send(params);
- },
- };
- window.addEventListener('load', PasteImage.init);
- </script>
- EOT
- }
- }
|