Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
jDanek committed Nov 7, 2023
0 parents commit 59e9bdb
Show file tree
Hide file tree
Showing 9 changed files with 352 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
* text=auto eol=lf
/.gitattributes export-ignore
/.gitignore export-ignore
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2023 Jirka Daněk

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
30 changes: 30 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
Watermark
#########

Watermarks for uploaded images.

.. contents::

Requirements
************

- SunLight CMS 8

Installation
************

::

Copy the folder 'plugins' and its contents to the root directory

or

::

Installation via administration: 'Administration > Plugins > Upload new plugins'

Configuration
*************

The path to the watermark file can be found in the plugin settings. The default path is `upload/watermark.png`
39 changes: 39 additions & 0 deletions watermark/class/ConfigAction.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php

namespace SunlightExtend\Watermark;

use Sunlight\Plugin\Action\ConfigAction as BaseConfigAction;
use Sunlight\Util\Form;

class ConfigAction extends BaseConfigAction
{
protected function getFields(): array
{
$config = $this->plugin->getConfig();
$positions = Watermark::getPositions();

return [
'watermark_file' => [
'label' => _lang('watermark.config.watermark_file'),
'input' => '<input type="text" name="config[watermark_file]" ' . Form::restorePostValue('config[watermark_file]', $config['watermark_file']) . ' class="inputmedium">',
'type' => 'text',
],
'watermark_position' => [
'label' => _lang('watermark.config.watermark_position'),
'input' => _buffer(function () use ($config, $positions) { ?>
<select name="config[watermark_position]" class="inputmedium">
<?php foreach ($positions as $position) : ?>
<option value="<?= $position ?>"<?= $config['watermark_position'] == $position ? ' selected' : '' ?>><?= _lang('watermark.config.pos.' . $position) ?></option>
<?php endforeach; ?>
</select>
<?php }),
'type' => 'text',
],
'resize_large_watermark' => [
'label' => _lang('watermark.config.resize_large_watermark'),
'input' => '<input type="checkbox" name="config[resize_large_watermark]" ' . Form::restorePostValue('config[resize_large_watermark]', $config['resize_large_watermark']) . '>',
'type' => 'checkbox',
]
];
}
}
181 changes: 181 additions & 0 deletions watermark/class/Watermark.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
<?php

namespace SunlightExtend\Watermark;

use Sunlight\Image\Image;

class Watermark
{
public const POS_TOP_CENTER = 'top-center';
public const POS_TOP_LEFT = 'top-left';
public const POS_TOP_RIGHT = 'top-right';
public const POS_CENTER = 'center';
public const POS_CENTER_LEFT = 'center-left';
public const POS_CENTER_RIGHT = 'center-right';
public const POS_BOTTOM_CENTER = 'bottom-center';
public const POS_BOTTOM_LEFT = 'bottom-left';
public const POS_BOTTOM_RIGHT = 'bottom-right';

/** @var Image */
private $source;
/** @var Image */
private $watermark;
/** @var bool */
private $resizeLargeWatermark = false;

public function __construct(Image $source, Image $watermark)
{
$this->source = $source;
$this->watermark = $watermark;
}

public static function getPositions(): array
{
return [
self::POS_TOP_CENTER,
self::POS_TOP_LEFT,
self::POS_TOP_RIGHT,
self::POS_CENTER,
self::POS_CENTER_LEFT,
self::POS_CENTER_RIGHT,
self::POS_BOTTOM_CENTER,
self::POS_BOTTOM_LEFT,
self::POS_BOTTOM_RIGHT,
];
}

private function getPositionCoordinate(Image $source, Image $watermark, string $position): array
{
// default
$positionX = 0;
$positionY = 0;

switch ($position) {
case self::POS_TOP_CENTER:
$positionX = ($source->width / 2) - ($watermark->width / 2);
// $positionY = 0;
break;
case self::POS_TOP_RIGHT:
$positionX = $source->width - $watermark->width;
// $positionY = 0;
break;
case self::POS_CENTER:
$positionX = ($source->width / 2) - ($watermark->width / 2);
$positionY = ($source->height / 2) - ($watermark->height / 2);
break;
case self::POS_CENTER_LEFT:
// $positionX = 0;
$positionY = ($source->height / 2) - ($watermark->height / 2);
break;
case self::POS_CENTER_RIGHT:
$positionX = $source->width - $watermark->width;
$positionY = ($source->height / 2) - ($watermark->height / 2);
break;
case self::POS_BOTTOM_CENTER:
$positionX = ($source->width / 2) - ($watermark->width / 2);
$positionY = $source->height - $watermark->height;
break;
case self::POS_BOTTOM_LEFT:
// $positionX = 0;
$positionY = $source->height - $watermark->height;
break;
case self::POS_BOTTOM_RIGHT:
$positionX = ($source->width - $watermark->width) - 5;
$positionY = ($source->height - $watermark->height) - 5;
break;
case self::POS_TOP_LEFT:
default:
// $positionX = 0;
// $positionY = 0;
break;
}

return ['x' => (int)$positionX, 'y' => (int)$positionY];
}

public function setResizeLargeWatermark(bool $resizeLargeWatermark): void
{
$this->resizeLargeWatermark = $resizeLargeWatermark;
}

/**
* Supported parameters:
*
* - top-center - position of the watermark at the top centre
* - top-left - position of the watermark at the top left
* - top-right - position of the watermark at the top right
* - center - position of the watermark centered
* - center-left - position of the watermark at the center left
* - center-right - position of the watermark at the center right
* - bottom-center - position of the watermark at the bottom center
* - bottom-left - position of the watermark at the bottom left
* - bottom-right - position of the watermark at the bottom right
*/
public function apply(string $position = self::POS_CENTER): void
{
imagealphablending($this->source->resource, true);
imagesavealpha($this->source->resource, true);

$watermark = $this->resizeLargeWatermark();

$watermarkPositions = $this->getPositionCoordinate(
$this->source,
$watermark,
$position
);

// image merge
imagecopy(
$this->source->resource,
$watermark->resource,
$watermarkPositions['x'],
$watermarkPositions['y'],
0,
0,
$watermark->width,
$watermark->height
);
}

/**
* Reduce the watermark to one third of the original image
* @return Image
*/
private function resizeLargeWatermark(): Image
{
$sourceWidth = $this->source->width;
$sourceHeight = $this->source->height;
$watermarkWidth = $this->watermark->width;
$watermarkHeight = $this->watermark->height;

// compare the dimensions and shrink the watermark if it is larger
if (
$this->resizeLargeWatermark
&& ($watermarkWidth > $sourceWidth || $watermarkHeight > $sourceHeight)
) {
// determine whether the watermark is portrait or landscape
if ($watermarkWidth > $watermarkHeight) {
$newWidth = (int)($sourceWidth / 3);
$newHeight = (int)($watermarkHeight * ($newWidth / $watermarkWidth));
} else {
$newHeight = (int)($sourceHeight / 3);
$newWidth = (int)($watermarkWidth * ($newHeight / $watermarkHeight));
}

// create a new watermark with a modified size
$newWatermark = imagecreatetruecolor($newWidth, $newHeight);

// transparent color
imagesavealpha($newWatermark, true);
$transparentColor = imagecolorallocatealpha($newWatermark, 0, 0, 0, 127);
imagefill($newWatermark, 0, 0, $transparentColor);

// resize
imagecopyresampled($newWatermark, $this->watermark->resource, 0, 0, 0, 0, $newWidth, $newHeight, $watermarkWidth, $watermarkHeight);

return new Image($newWatermark, $newWidth, $newHeight);
}
// return original watermark
return $this->watermark;
}
}
20 changes: 20 additions & 0 deletions watermark/event/watermark.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

use Sunlight\Image\ImageLoader;
use SunlightExtend\Watermark\Watermark;

return function (array $args) {
if ($args['options']['resize']['w'] >= 500 && $args['options']['resize']['h'] >= 100) {

$watermarkFile = SL_ROOT . $this->getConfig()['watermark_file'];
if (!file_exists($watermarkFile)) {
return;
}

$watermark = new Watermark($args['image'], ImageLoader::load($watermarkFile));
if ($this->getConfig()['resize_large_watermark']) {
$watermark->setResizeLargeWatermark(true);
}
$watermark->apply($this->getConfig()['watermark_position']);
}
};
16 changes: 16 additions & 0 deletions watermark/lang/cs.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

return [
'config.watermark_file' => 'Cesta k souboru vodoznaku',
'config.watermark_position' => 'Pozice',
'config.resize_large_watermark' => 'Zmenšit vodoznak<br><small>pokud je vetší než originální obrázek</small>',
'config.pos.top-center' => 'Nahoře uprostřed',
'config.pos.top-left' => 'Nahoře vlevo',
'config.pos.top-right' => 'Nahoře vpravo',
'config.pos.center' => 'Uprostřed',
'config.pos.center-left' => 'Uprostřed vlevo',
'config.pos.center-right' => 'Uprostřed vpravo',
'config.pos.bottom-center' => 'Dole uprostřed',
'config.pos.bottom-left' => 'Dole vlevo',
'config.pos.bottom-right' => 'Dole vpravo',
];
16 changes: 16 additions & 0 deletions watermark/lang/en.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

return [
'config.watermark_file' => 'Watermark file path',
'config.watermark_position' => 'Watermark position',
'config.resize_large_watermark' => 'Shrink the watermark<br><small>if the watermark is larger than the original image</small>',
'config.pos.top-center' => 'Top center',
'config.pos.top-left' => 'Top left',
'config.pos.top-right' => 'Top right',
'config.pos.center' => 'Center',
'config.pos.center-left' => 'Center left',
'config.pos.center-right' => 'Center right',
'config.pos.bottom-center' => 'Bottom center',
'config.pos.bottom-left' => 'Bottom left',
'config.pos.bottom-right' => 'Bottom right',
];
26 changes: 26 additions & 0 deletions watermark/plugin.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"$schema": "../../../system/schema/extend.json",
"name": "Watermark",
"description": "Watermarks for uploaded images",
"version": "1.0.0",
"authors": [
{"name": "Friends of Sunlight CMS", "url": "https://github.com/friends-of-sunlight-cms/"}
],
"environment": {
"system": "^8.0"
},
"config_defaults": {
"watermark_file": "upload/watermark.png",
"watermark_position": "center",
"resize_large_watermark": true
},
"actions": {
"config": "ConfigAction"
},
"langs": {
"watermark": "lang"
},
"events": [
{"event": "image.process.after", "script": "event/watermark.php"}
]
}

0 comments on commit 59e9bdb

Please sign in to comment.