fix image censoring

This commit is contained in:
zotlabs 2019-07-31 21:46:19 -07:00
parent 0de97b2fc0
commit 57a2fe9dd6
6 changed files with 158 additions and 157 deletions

View file

@ -584,13 +584,13 @@ class Connedit extends Controller {
'info' => (intval($contact['abook_ignored']) ? t('This connection is ignored!') : ''),
),
// 'censor' => array(
// 'label' => (intval($contact['abook_censor']) ? t('Uncensor') : t('Censor')),
// 'url' => z_root() . '/connedit/' . $contact['abook_id'] . '/censor',
// 'sel' => (intval($contact['abook_censor']) ? 'active' : ''),
// 'title' => t('Censor (or Uncensor) images from this connection'),
// 'info' => (intval($contact['abook_censor']) ? t('This connection is censored!') : ''),
// ),
'censor' => array(
'label' => (intval($contact['abook_censor']) ? t('Uncensor') : t('Censor')),
'url' => z_root() . '/connedit/' . $contact['abook_id'] . '/censor',
'sel' => (intval($contact['abook_censor']) ? 'active' : ''),
'title' => t('Censor (or Uncensor) images from this connection'),
'info' => (intval($contact['abook_censor']) ? t('This connection is censored!') : ''),
),
'archive' => array(
'label' => (intval($contact['abook_archived']) ? t('Unarchive') : t('Archive')),

View file

@ -1375,52 +1375,56 @@ function bbcode($Text, $options = []) {
// Images
$data_censored = (($censored) ? ' data-censored ' : '');;
// [img]pathtoimage[/img]
if (strpos($Text,'[/img]') !== false) {
$Text = preg_replace("/\[img\](.*?)\[\/img\]/ism", '<img ' . $data_censored . 'style="max-width: 100%;" src="$1" alt="' . t('Image/photo') . '" />', $Text);
$Text = preg_replace("/\[img\](.*?)\[\/img\]/ism", '<img style="max-width: 100%;" src="$1" alt="' . t('Image/photo') . '" />', $Text);
}
if (strpos($Text,'[/zmg]') !== false) {
$Text = preg_replace("/\[zmg\](.*?)\[\/zmg\]/ism", '<img ' . $data_censored . 'class="zrl" style="max-width: 100%;" src="$1" alt="' . t('Image/photo') . '" />', $Text);
$Text = preg_replace("/\[zmg\](.*?)\[\/zmg\]/ism", '<img class="zrl" style="max-width: 100%;" src="$1" alt="' . t('Image/photo') . '" />', $Text);
}
// [img float={left, right}]pathtoimage[/img]
if (strpos($Text,'[/img]') !== false) {
$Text = preg_replace("/\[img float=left\](.*?)\[\/img\]/ism", '<img ' . $data_censored . 'style="max-width: 100%;" src="$1" style="float: left;" alt="' . t('Image/photo') . '" />', $Text);
$Text = preg_replace("/\[img float=left\](.*?)\[\/img\]/ism", '<img style="max-width: 100%;" src="$1" style="float: left;" alt="' . t('Image/photo') . '" />', $Text);
}
if (strpos($Text,'[/img]') !== false) {
$Text = preg_replace("/\[img float=right\](.*?)\[\/img\]/ism", '<img ' . $data_censored . 'style="max-width: 100%;" src="$1" style="float: right;" alt="' . t('Image/photo') . '" />', $Text);
$Text = preg_replace("/\[img float=right\](.*?)\[\/img\]/ism", '<img style="max-width: 100%;" src="$1" style="float: right;" alt="' . t('Image/photo') . '" />', $Text);
}
if (strpos($Text,'[/zmg]') !== false) {
$Text = preg_replace("/\[zmg float=left\](.*?)\[\/zmg\]/ism", '<img ' . $data_censored . 'style="max-width: 100%;" class="zrl" src="$1" style="float: left;" alt="' . t('Image/photo') . '" />', $Text);
$Text = preg_replace("/\[zmg float=left\](.*?)\[\/zmg\]/ism", '<img style="max-width: 100%;" class="zrl" src="$1" style="float: left;" alt="' . t('Image/photo') . '" />', $Text);
}
if (strpos($Text,'[/zmg]') !== false) {
$Text = preg_replace("/\[zmg float=right\](.*?)\[\/zmg\]/ism", '<img ' . $data_censored . 'style="max-width: 100%;" class="zrl" src="$1" style="float: right;" alt="' . t('Image/photo') . '" />', $Text);
$Text = preg_replace("/\[zmg float=right\](.*?)\[\/zmg\]/ism", '<img style="max-width: 100%;" class="zrl" src="$1" style="float: right;" alt="' . t('Image/photo') . '" />', $Text);
}
// [img=widthxheight]pathtoimage[/img]
if (strpos($Text,'[/img]') !== false) {
$Text = preg_replace("/\[img\=([0-9]*)x([0-9]*)\](.*?)\[\/img\]/ism", '<img ' . $data_censored . 'src="$3" style="width: 100%; max-width: $1px;" alt="' . t('Image/photo') . '" />', $Text);
$Text = preg_replace("/\[img\=([0-9]*)x([0-9]*)\](.*?)\[\/img\]/ism", '<img src="$3" style="width: 100%; max-width: $1px;" alt="' . t('Image/photo') . '" />', $Text);
}
if (strpos($Text,'[/zmg]') !== false) {
$Text = preg_replace("/\[zmg\=([0-9]*)x([0-9]*)\](.*?)\[\/zmg\]/ism", '<img ' . $data_censored . 'class="zrl" src="$3" style="width: 100%; max-width: $1px;" alt="' . t('Image/photo') . '" />', $Text);
$Text = preg_replace("/\[zmg\=([0-9]*)x([0-9]*)\](.*?)\[\/zmg\]/ism", '<img class="zrl" src="$3" style="width: 100%; max-width: $1px;" alt="' . t('Image/photo') . '" />', $Text);
}
// [img=widthxheight float={left, right}]pathtoimage[/img]
if (strpos($Text,'[/img]') !== false) {
$Text = preg_replace("/\[img\=([0-9]*)x([0-9]*) float=left\](.*?)\[\/img\]/ism", '<img ' . $data_censored . 'src="$3" style="width: 100%; max-width: $1px; float: left;" alt="' . t('Image/photo') . '" />', $Text);
$Text = preg_replace("/\[img\=([0-9]*)x([0-9]*) float=left\](.*?)\[\/img\]/ism", '<img src="$3" style="width: 100%; max-width: $1px; float: left;" alt="' . t('Image/photo') . '" />', $Text);
}
if (strpos($Text,'[/img]') !== false) {
$Text = preg_replace("/\[img\=([0-9]*)x([0-9]*) float=right\](.*?)\[\/img\]/ism", '<img ' . $data_censored . 'src="$3" style="width: 100%; max-width: $1px; float: right;" alt="' . t('Image/photo') . '" />', $Text);
$Text = preg_replace("/\[img\=([0-9]*)x([0-9]*) float=right\](.*?)\[\/img\]/ism", '<img src="$3" style="width: 100%; max-width: $1px; float: right;" alt="' . t('Image/photo') . '" />', $Text);
}
if (strpos($Text,'[/zmg]') !== false) {
$Text = preg_replace("/\[zmg\=([0-9]*)x([0-9]*) float=left\](.*?)\[\/zmg\]/ism", '<img ' . $data_censored . 'class="zrl" src="$3" style="width: 100%; max-width: $1px; float: left;" alt="' . t('Image/photo') . '" />', $Text);
$Text = preg_replace("/\[zmg\=([0-9]*)x([0-9]*) float=left\](.*?)\[\/zmg\]/ism", '<img class="zrl" src="$3" style="width: 100%; max-width: $1px; float: left;" alt="' . t('Image/photo') . '" />', $Text);
}
if (strpos($Text,'[/zmg]') !== false) {
$Text = preg_replace("/\[zmg\=([0-9]*)x([0-9]*) float=right\](.*?)\[\/zmg\]/ism", '<img ' . $data_censored . 'class="zrl" src="$3" style="width: 100%; max-width: $1px; float: right;" alt="' . t('Image/photo') . '" />', $Text);
$Text = preg_replace("/\[zmg\=([0-9]*)x([0-9]*) float=right\](.*?)\[\/zmg\]/ism", '<img class="zrl" src="$3" style="width: 100%; max-width: $1px; float: right;" alt="' . t('Image/photo') . '" />', $Text);
}
if($censored) {
$Text = separate_img_links($Text);
$Text = preg_replace("/\<img(.*?)src=\"(.*?)\"(.*?)\>/ism",'<a href="#" onclick="\\$.colorbox({ \'href\': \'$2\' }); return false;">$2</a>',$Text);
}
// style (sanitized)
if (strpos($Text,'[/style]') !== false) {
$Text = preg_replace_callback("(\[style=(.*?)\](.*?)\[\/style\])ism", "bb_sanitize_style", $Text);

View file

@ -91,7 +91,7 @@ function nav($template = 'default') {
$nav['settings'] = array('settings', t('Settings'),"", t('Account/Channel Settings'),'settings_nav_btn');
// $nav['safe'] = array('safe', t('Safe Mode'), ((intval($_SESSION['unsafe'])) ? t('(is off)') : t('(is on)')) , t('Connection image filtering'),'safe_nav_btn');
$nav['safe'] = array('safe', t('Safe Mode'), ((intval($_SESSION['unsafe'])) ? t('(is off)') : t('(is on)')) , t('Image filtering'),'safe_nav_btn');
if($chans && count($chans) > 1 && feature_enabled(local_channel(),'nav_channel_select'))

View file

@ -1488,11 +1488,9 @@ function prepare_body(&$item,$attach = false,$opts = false) {
call_hooks('prepare_body_init', $item);
$pixelation = floatval(get_pconfig($item['uid'],'system','content_pixelation',0.05));
$censored = ((($item['author']['abook_censor'] || $item['owner']['abook_censor']) && (! intval($_SESSION['unsafe'])))
? ' data-censored '
: ''
$censored = ((($item['author']['abook_censor'] || $item['owner']['abook_censor'] || $item['author']['xchan_selfcensored'] || $item['owner']['xchan_selfcensored'] || $item['author']['xchan_censored'] || $item['owner']['xchan_censored']) && (! intval($_SESSION['unsafe'])))
? true
: false
);
if ($censored) {
@ -1507,20 +1505,20 @@ function prepare_body(&$item,$attach = false,$opts = false) {
$is_photo = ((($item['verb'] === ACTIVITY_POST) && ($item['obj_type'] === ACTIVITY_OBJ_PHOTO)) ? true : false);
if($is_photo) {
if($is_photo && ! $censored) {
$object = json_decode($item['obj'],true);
if(array_key_exists('url',$object) && is_array($object['url']) && array_key_exists(0,$object['url'])) {
// if original photo width is <= 640px prepend it to item body
if(array_key_exists('width',$object['url'][0]) && $object['url'][0]['width'] <= 640) {
$s .= '<div class="inline-photo-item-wrapper"><a href="' . zid(rawurldecode($object['id'])) . '" target="_blank" rel="nofollow noopener" ><img $censored class="inline-photo-item" style="max-width:' . $object['url'][0]['width'] . 'px; width:100%; height:auto;" src="' . zid(rawurldecode($object['url'][0]['href'])) . '"></a></div>' . $s;
$item['body'] = '[zmg]' . $object['url'][0]['href'] . '[/zmg]' . "\n\n" . $item['body'];
}
// if original photo width is > 640px make it a cover photo
if(array_key_exists('width',$object['url'][0]) && $object['url'][0]['width'] > 640) {
$scale = ((($object['url'][1]['width'] == 1024) || ($object['url'][1]['height'] == 1024)) ? 1 : 0);
$photo = '<a href="' . zid(rawurldecode($object['id'])) . '" target="_blank" rel="nofollow noopener"><img $censored style="max-width:' . $object['url'][$scale]['width'] . 'px; width:100%; height:auto;" src="' . zid(rawurldecode($object['url'][$scale]['href'])) . '"></a>';
$photo = '<a href="' . zid(rawurldecode($object['id'])) . '" target="_blank" rel="nofollow noopener"><img style="max-width:' . $object['url'][$scale]['width'] . 'px; width:100%; height:auto;" src="' . zid(rawurldecode($object['url'][$scale]['href'])) . '"></a>';
}
}
}
@ -1537,10 +1535,6 @@ function prepare_body(&$item,$attach = false,$opts = false) {
}
}
// if ($censored) {
// $s = separate_img_links($s);
// //$s = str_replace('<img ', '<img ' . $censored, $s);
// }
$event = (($item['obj_type'] === ACTIVITY_OBJ_EVENT) ? format_event_obj($item['obj']) : false);

View file

@ -2,123 +2,132 @@
* pixelate.js
* 43081j
* Pixelate images with ease
* v0.5
* License: MIT
*/
(function (window, $) {
var pixelate = function() {
var defaults = {
value: 0.05,
reveal: true,
revealonclick: false
};
var options = arguments[0] || {};
var element = this;
var elementParent = element.parentNode;
if (typeof options !== 'object') {
options = { value: parseInt(arguments[0]) };
}
options = (function() {
var opts = {};
for (var k in defaults) {
if (element.hasAttribute('data-' + k)) {
opts[k] = element.getAttribute('data-' + k);
continue;
}
if (k in options) {
opts[k] = options[k];
continue;
}
opts[k] = defaults[k];
}
return opts;
})();
var imgWidth = element.width;
var imgHeight = element.height;
var revealed = false;
var canv = document.createElement('canvas');
canv.width = imgWidth;
canv.height = imgHeight;
var ctx = canv.getContext('2d');
// ctx.mozImageSmoothingEnabled = false;
ctx.webkitImageSmoothingEnabled = false;
ctx.imageSmoothingEnabled = false;
var width = imgWidth * options.value;
var height = imgHeight * options.value;
ctx.drawImage(element, 0, 0, width, height);
ctx.drawImage(canv, 0, 0, width, height, 0, 0, canv.width, canv.height);
element.style.display = 'none';
elementParent.insertBefore(canv, element);
if (options.revealonclick !== false && options.revealonclick !== 'false') {
/*
* Reveal on click
*/
canv.addEventListener('click', function () {
revealed = !revealed;
if (revealed) {
ctx.drawImage(element, 0, 0, imgWidth, imgHeight);
} else {
ctx.drawImage(element, 0, 0, width, height);
ctx.drawImage(canv, 0, 0, width, height, 0, 0, canv.width, canv.height);
}
});
}
if (options.reveal !== false && options.reveal !== 'false') {
/*
* Reveal on hover
*/
canv.addEventListener('mouseenter', function () {
if (revealed) {
return;
}
ctx.drawImage(element, 0, 0, imgWidth, imgHeight);
});
canv.addEventListener('mouseleave', function () {
if (revealed) {
return;
}
ctx.drawImage(element, 0, 0, width, height);
ctx.drawImage(canv, 0, 0, width, height, 0, 0, canv.width, canv.height);
});
}
};
if (typeof $ === 'function') {
$.fn.extend({
pixelate: function() {
var args = arguments;
return this.each(function () {
pixelate.apply(this, args);
});
}
});
}
document.addEventListener('DOMContentLoaded', function () {
var img = document.querySelectorAll('img[data-pixelate]');
for (var i = 0; i < img.length; i++) {
img[i].addEventListener('load', function () {
pixelate.apply(this);
});
}
});
(function(window, $) {
var pixelate = function(args) {
// Parameters
var defaults = {
value: 0.05, // pixelation "density" (1 = no pixelation, 0 = all pixelated into 1 pixel)
reveal: true, // reveal on hover
revealonclick: false // reveal on click
};
// Get the current object (img)
var element = this, //arguments[0],
elementParent = element.parentNode;
// Input arguments
var input_options = args || {};
if(typeof input_options !== 'object') {
input_options = { value: parseInt(arguments[1]) };
}
// Function/object that will merge and store all options (priority to html attributes, then to user-specified arguments, then to defaults
options = (function() {
var opts = {};
for(var k in defaults) {
// HTML attribute
if(element.hasAttribute('data-' + k)) {
opts[k] = element.getAttribute('data-' + k);
// User-specified argument
} else if (k in input_options) {
opts[k] = input_options[k];
// Defaults (fallback if there is nothing else)
} else {
opts[k] = defaults[k];
}
}
return opts;
})();
// Get image size
var display = element.style.display;
var imgWidth = element.width;
var imgHeight = element.height;
var revealed = false;
// Create two canvas (one temporary to downscale, and one final to upscale)
var canvtmp = document.createElement('canvas'); // temporary downscaling canvas
canvtmp.width = imgWidth;
canvtmp.height = imgHeight;
var canvpix = document.createElement('canvas'); // final upscaling canvas
canvpix.width = imgWidth;
canvpix.height = imgHeight;
var contexttmp = canvtmp.getContext('2d');
// contexttmp.mozImageSmoothingEnabled = false;
contexttmp.webkitImageSmoothingEnabled = false;
contexttmp.imageSmoothingEnabled = false;
var contextpix = canvpix.getContext('2d');
// contextpix.mozImageSmoothingEnabled = false;
contextpix.webkitImageSmoothingEnabled = false;
contextpix.imageSmoothingEnabled = false;
// Compute the downsampling width and height
var width = imgWidth * options.value,
height = imgHeight * options.value;
// Downsampling (reduce image size, to create the pixels)
contextpix.clearRect(0, 0, canvpix.width, canvpix.height); // clear temporary canvas to avoid overlapping multiple times the same downsampled image, blurrying the contours
contexttmp.drawImage(element, 0, 0, width, height);
// Upsample back to original size (using another canvas to avoid issues with transparent images, which will leave the temporary canvas as a small icon in the upper left corner)
contextpix.clearRect(0, 0, canvpix.width, canvpix.height); // clear the canvas to avoid overlapping multiple times same image (particularly when using reveal option)
contextpix.drawImage(canvtmp, 0, 0, width, height, 0, 0, canvpix.width, canvpix.height);
// Reinsert image back in place (we hide the old and place a new one instead)
element.style.display = 'none';
elementParent.insertBefore(canvpix, element);
// Manage user interaction: reveal on hover or on click
if(options.revealonclick !== false && options.revealonclick !== 'false') {
/*
* Reveal on click
*/
canvpix.addEventListener('click', function(e) {
revealed = !revealed;
if(revealed) {
// On reveal, show the original image
contextpix.clearRect(0, 0, canvpix.width, canvpix.height); // clear
contextpix.drawImage(element, 0, 0, imgWidth, imgHeight);
} else {
// On unreveal, recompute the pixelation
contexttmp.clearRect(0, 0, canvpix.width, canvpix.height); // clear
contexttmp.drawImage(element, 0, 0, width, height); // downsample using temporary canvas
contextpix.clearRect(0, 0, canvpix.width, canvpix.height); // clear
contextpix.drawImage(canvtmp, 0, 0, width, height, 0, 0, canvpix.width, canvpix.height); // upsample
}
});
}
if(options.reveal !== false && options.reveal !== 'false') {
/*
* Reveal on hover
*/
canvpix.addEventListener('mouseenter', function(e) {
if(revealed) return;
// On reveal, show the original image
contextpix.clearRect(0, 0, canvpix.width, canvpix.height); // clear
contextpix.drawImage(element, 0, 0, imgWidth, imgHeight);
});
canvpix.addEventListener('mouseleave', function(e) {
if(revealed) return;
// On unreveal, recompute the pixelation
contexttmp.clearRect(0, 0, canvpix.width, canvpix.height); // clear
contexttmp.drawImage(element, 0, 0, width, height); // downsample using temporary canvas
contextpix.clearRect(0, 0, canvpix.width, canvpix.height); // clear
contextpix.drawImage(canvtmp, 0, 0, width, height, 0, 0, canvpix.width, canvpix.height); // upsample
});
}
};
// Add prototype function to all objects (so that we can call img.pixelate())
window.HTMLImageElement.prototype.pixelate = pixelate;
if(typeof $ === 'function') {
$.fn.extend({
pixelate: function() {
return this.each(function() {
pixelate.apply(this, arguments);
});
}
});
}
// Add HTML attribute callback
document.addEventListener('DOMContentLoaded', function(e) {
var img = document.querySelectorAll('img[data-pixelate]');
for(var i = 0; i < img.length; i++) {
img[i].addEventListener('load', function() {
this.pixelate();
});
};
});
})(window, typeof jQuery === 'undefined' ? null : jQuery);

View file

@ -807,11 +807,6 @@ function updateConvItems(mode,data) {
collapseHeight();
}
// pixelate any images from censored connections
// This has way too many bugs currently.
// $('img[data-censored]').pixelate({ value: 0.05, reveal: true });
// auto-scroll to a particular comment in a thread (designated by mid) when in single-thread mode
// use the same method to generate the submid as we use in ThreadItem,
@ -885,7 +880,6 @@ function collapseHeight() {
console.log('collapsed above viewport count: ' + i);
$(window).scrollTop(sval);
}
}