mirror of
https://github.com/alchemy-fr/Phraseanet.git
synced 2025-10-15 14:03:27 +00:00
PHRAS-3822 Prod : Improve Image WaterMarking (#4266)
* admin improve watermark * unused * allow to use collection wm image to wm a subdef (set <watermark>coll_wm</watermark> in structure) * [skip ci] upload a wm for subdef (WIP to be continued ?) * allow to use a record as wm image (document) to wmark subdefs * cleanup --------- Co-authored-by: jygaulier <gaulier@alchemy.fr>
This commit is contained in:
@@ -24,6 +24,7 @@ class Image extends Provider
|
|||||||
const OPTION_ICODEC = 'icodec';
|
const OPTION_ICODEC = 'icodec';
|
||||||
const OPTION_WATERMARK = 'watermark';
|
const OPTION_WATERMARK = 'watermark';
|
||||||
const OPTION_WATERMARKTEXT = 'watermarktext';
|
const OPTION_WATERMARKTEXT = 'watermarktext';
|
||||||
|
const OPTION_WATERMARKRID = 'watermarkrid';
|
||||||
|
|
||||||
protected $options = [];
|
protected $options = [];
|
||||||
|
|
||||||
@@ -37,8 +38,9 @@ class Image extends Provider
|
|||||||
$this->registerOption(new OptionType\Boolean($this->translator->trans('Flatten layers'), self::OPTION_FLATTEN, false));
|
$this->registerOption(new OptionType\Boolean($this->translator->trans('Flatten layers'), self::OPTION_FLATTEN, false));
|
||||||
$this->registerOption(new OptionType\Range($this->translator->trans('Quality'), self::OPTION_QUALITY, 0, 100, 75));
|
$this->registerOption(new OptionType\Range($this->translator->trans('Quality'), self::OPTION_QUALITY, 0, 100, 75));
|
||||||
$this->registerOption(new OptionType\Enum('Image Codec', self::OPTION_ICODEC, array('jpeg', 'png', 'tiff'), 'jpeg'));
|
$this->registerOption(new OptionType\Enum('Image Codec', self::OPTION_ICODEC, array('jpeg', 'png', 'tiff'), 'jpeg'));
|
||||||
$this->registerOption(new OptionType\Boolean($this->translator->trans('Watermark'), self::OPTION_WATERMARK, false));
|
$this->registerOption(new OptionType\EnumButton($this->translator->trans('Watermark'), self::OPTION_WATERMARK, array('no' => 'no', 'yes' => 'yes'), 'no'));
|
||||||
$this->registerOption(new OptionType\Text($this->translator->trans('Watermark text'), self::OPTION_WATERMARKTEXT, ''));
|
$this->registerOption(new OptionType\Text($this->translator->trans('Watermark text'), self::OPTION_WATERMARKTEXT, ''));
|
||||||
|
$this->registerOption(new OptionType\Text($this->translator->trans('Watermark Record_id'), self::OPTION_WATERMARKRID, ''));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getType()
|
public function getType()
|
||||||
|
20
lib/Alchemy/Phrasea/Media/Subdef/OptionType/EnumButton.php
Normal file
20
lib/Alchemy/Phrasea/Media/Subdef/OptionType/EnumButton.php
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of Phraseanet
|
||||||
|
*
|
||||||
|
* (c) 2005-2016 Alchemy
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Alchemy\Phrasea\Media\Subdef\OptionType;
|
||||||
|
|
||||||
|
class EnumButton extends Enum
|
||||||
|
{
|
||||||
|
public function getType()
|
||||||
|
{
|
||||||
|
return self::TYPE_ENUM_BUTTON;
|
||||||
|
}
|
||||||
|
}
|
@@ -18,6 +18,7 @@ interface OptionType
|
|||||||
const TYPE_BOOLEAN = 'Boolean';
|
const TYPE_BOOLEAN = 'Boolean';
|
||||||
const TYPE_MULTI = 'Multi';
|
const TYPE_MULTI = 'Multi';
|
||||||
const TYPE_TEXT = 'Text';
|
const TYPE_TEXT = 'Text';
|
||||||
|
const TYPE_ENUM_BUTTON = 'EnumButton';
|
||||||
|
|
||||||
public function getDisplayName();
|
public function getDisplayName();
|
||||||
|
|
||||||
|
@@ -23,10 +23,12 @@ use Alchemy\Phrasea\Filesystem\FilesystemService;
|
|||||||
use Alchemy\Phrasea\Media\Subdef\OptionType\Boolean;
|
use Alchemy\Phrasea\Media\Subdef\OptionType\Boolean;
|
||||||
use Alchemy\Phrasea\Media\Subdef\OptionType\Text;
|
use Alchemy\Phrasea\Media\Subdef\OptionType\Text;
|
||||||
use Alchemy\Phrasea\Media\Subdef\Specification\PdfSpecification;
|
use Alchemy\Phrasea\Media\Subdef\Specification\PdfSpecification;
|
||||||
|
use databox_subdef;
|
||||||
use Exception;
|
use Exception;
|
||||||
use Imagine\Image\ImagineInterface;
|
use Imagine\Image\ImagineInterface;
|
||||||
use Imagine\Image\Palette\RGB;
|
use Imagine\Image\Palette\RGB;
|
||||||
use Imagine\Image\Point;
|
use Imagine\Image\Point;
|
||||||
|
use Imagine\Imagick\Imagine;
|
||||||
use MediaAlchemyst\Alchemyst;
|
use MediaAlchemyst\Alchemyst;
|
||||||
use MediaAlchemyst\Exception\ExceptionInterface as MediaAlchemystException;
|
use MediaAlchemyst\Exception\ExceptionInterface as MediaAlchemystException;
|
||||||
use MediaAlchemyst\Exception\FileNotFoundException;
|
use MediaAlchemyst\Exception\FileNotFoundException;
|
||||||
@@ -234,7 +236,7 @@ class SubdefGenerator
|
|||||||
return $this->logger;
|
return $this->logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function generateSubdef(\record_adapter $record, \databox_subdef $subdef_class, $pathdest)
|
private function generateSubdef(\record_adapter $record, databox_subdef $subdef_class, $pathdest)
|
||||||
{
|
{
|
||||||
$start = microtime(true);
|
$start = microtime(true);
|
||||||
$destFile = null;
|
$destFile = null;
|
||||||
@@ -296,12 +298,31 @@ class SubdefGenerator
|
|||||||
$image = $subdef_class->getSubdefType();
|
$image = $subdef_class->getSubdefType();
|
||||||
/** @var Boolean $wm */
|
/** @var Boolean $wm */
|
||||||
$wm = $image->getOption(Subdef\Image::OPTION_WATERMARK);
|
$wm = $image->getOption(Subdef\Image::OPTION_WATERMARK);
|
||||||
if($wm->getValue()) {
|
if($wm->getValue() === 'yes') { // bc to "text" mode
|
||||||
|
|
||||||
// we must watermark the file
|
// we must watermark the file
|
||||||
/** @var Text $wmt */
|
$wm_text = null;
|
||||||
$wmt = $image->getOption(Subdef\Image::OPTION_WATERMARKTEXT);
|
$wm_image = null;
|
||||||
$this->wartermarkImageFile($pathdest, $wmt->getValue());
|
|
||||||
|
/** @var Text $opt */
|
||||||
|
|
||||||
|
$opt = $image->getOption(Subdef\Image::OPTION_WATERMARKTEXT);
|
||||||
|
if($opt && ($t = trim($opt->getValue())) !== '') {
|
||||||
|
$wm_text = $t;
|
||||||
|
}
|
||||||
|
|
||||||
|
$opt = $image->getOption(Subdef\Image::OPTION_WATERMARKRID);
|
||||||
|
if($opt && ($rid = trim($opt->getValue())) !== '') {
|
||||||
|
try {
|
||||||
|
$wm_image = $subdef_class->getDatabox()->get_record($rid)->get_subdef('document')->getRealPath();
|
||||||
|
}
|
||||||
|
catch (\Exception $e) {
|
||||||
|
$this->logger->error(sprintf('Getting wm image (record %d) failed with message %s', $rid, $e->getMessage()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!is_null($wm_text) || !is_null($wm_image)) {
|
||||||
|
$this->wartermarkImageFile($pathdest, $wm_text, $wm_image);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -324,13 +345,16 @@ class SubdefGenerator
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function wartermarkImageFile(string $filepath, string $watermarkText)
|
/**
|
||||||
|
* @param string $filepath
|
||||||
|
* @param string|null $watermarkText
|
||||||
|
* @param string|null $watermarkImage
|
||||||
|
*/
|
||||||
|
private function wartermarkImageFile(string $filepath, $watermarkText, $watermarkImage)
|
||||||
{
|
{
|
||||||
static $palette;
|
static $palette;
|
||||||
|
|
||||||
if (null === $palette) {
|
/** @var Imagine $imagine */
|
||||||
$palette = new RGB();
|
|
||||||
}
|
|
||||||
$imagine = $this->getImagine();
|
$imagine = $this->getImagine();
|
||||||
|
|
||||||
$in_image = $imagine->open($filepath);
|
$in_image = $imagine->open($filepath);
|
||||||
@@ -338,6 +362,32 @@ class SubdefGenerator
|
|||||||
$in_w = $in_size->getWidth();
|
$in_w = $in_size->getWidth();
|
||||||
$in_h = $in_size->getHeight();
|
$in_h = $in_size->getHeight();
|
||||||
|
|
||||||
|
$in_image_changed = false;
|
||||||
|
|
||||||
|
if ($watermarkImage !== null && file_exists($watermarkImage)) {
|
||||||
|
$wm_image = $imagine->open($watermarkImage);
|
||||||
|
$wm_size = $wm_image->getSize();
|
||||||
|
$wm_w = $wm_size->getWidth();
|
||||||
|
$wm_h = $wm_size->getHeight();
|
||||||
|
|
||||||
|
if (($wm_w / $wm_h) > ($in_w / $in_h)) {
|
||||||
|
$wm_size = $wm_size->widen($in_w);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$wm_size = $wm_size->heighten($in_h);
|
||||||
|
}
|
||||||
|
$wm_image->resize($wm_size);
|
||||||
|
|
||||||
|
$in_image->paste($wm_image, new Point(($in_w - $wm_size->getWidth()) >> 1, ($in_h - $wm_size->getHeight()) >> 1));
|
||||||
|
|
||||||
|
$in_image_changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if($watermarkText !== null) {
|
||||||
|
if (null === $palette) {
|
||||||
|
$palette = new RGB();
|
||||||
|
}
|
||||||
|
|
||||||
$draw = $in_image->draw();
|
$draw = $in_image->draw();
|
||||||
$black = $palette->color("000000");
|
$black = $palette->color("000000");
|
||||||
$white = $palette->color("FFFFFF");
|
$white = $palette->color("FFFFFF");
|
||||||
@@ -370,11 +420,22 @@ class SubdefGenerator
|
|||||||
$draw->text($watermarkText, $fonts[$i], new Point($x0 - $i, $y - $i));
|
$draw->text($watermarkText, $fonts[$i], new Point($x0 - $i, $y - $i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
$in_image_changed = true;
|
||||||
$in_image->save($filepath);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function generateSubdefFromFile($pathSrc, \databox_subdef $subdef_class, $pathdest)
|
if($in_image_changed) {
|
||||||
|
$in_image->save($filepath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used only by api V3 subdef generator service
|
||||||
|
*
|
||||||
|
* @param $pathSrc
|
||||||
|
* @param databox_subdef $subdef_class
|
||||||
|
* @param $pathdest
|
||||||
|
*/
|
||||||
|
public function generateSubdefFromFile($pathSrc, databox_subdef $subdef_class, $pathdest)
|
||||||
{
|
{
|
||||||
$start = microtime(true);
|
$start = microtime(true);
|
||||||
$destFile = null;
|
$destFile = null;
|
||||||
@@ -428,12 +489,32 @@ class SubdefGenerator
|
|||||||
$image = $subdef_class->getSubdefType();
|
$image = $subdef_class->getSubdefType();
|
||||||
/** @var Boolean $wm */
|
/** @var Boolean $wm */
|
||||||
$wm = $image->getOption(Subdef\Image::OPTION_WATERMARK);
|
$wm = $image->getOption(Subdef\Image::OPTION_WATERMARK);
|
||||||
if($wm->getValue()) {
|
|
||||||
|
|
||||||
|
if($wm->getValue() === 'yes') { // bc to "text" mode
|
||||||
// we must watermark the file
|
// we must watermark the file
|
||||||
/** @var Text $wmt */
|
$wm_text = null;
|
||||||
$wmt = $image->getOption(Subdef\Image::OPTION_WATERMARKTEXT);
|
$wm_image = null;
|
||||||
$this->wartermarkImageFile($pathdest, $wmt->getValue());
|
|
||||||
|
/** @var Text $opt */
|
||||||
|
|
||||||
|
$opt = $image->getOption(Subdef\Image::OPTION_WATERMARKTEXT);
|
||||||
|
if($opt && ($t = trim($opt->getValue())) !== '') {
|
||||||
|
$wm_text = $t;
|
||||||
|
}
|
||||||
|
|
||||||
|
$opt = $image->getOption(Subdef\Image::OPTION_WATERMARKRID);
|
||||||
|
if($opt && ($rid = trim($opt->getValue())) !== '') {
|
||||||
|
try {
|
||||||
|
$wm_image = $subdef_class->getDatabox()->get_record($rid)->get_subdef('document')->getRealPath();
|
||||||
|
}
|
||||||
|
catch (\Exception $e) {
|
||||||
|
$this->logger->error(sprintf('Getting wm image (record %d) failed with message %s', $rid, $e->getMessage()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!is_null($wm_text) || !is_null($wm_image)) {
|
||||||
|
$this->wartermarkImageFile($pathdest, $wm_text, $wm_image);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -22,6 +22,9 @@ use Symfony\Component\Translation\TranslatorInterface;
|
|||||||
|
|
||||||
class databox_subdef
|
class databox_subdef
|
||||||
{
|
{
|
||||||
|
/** @var databox|null */
|
||||||
|
private $databox;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The class type of the subdef
|
* The class type of the subdef
|
||||||
* Is null or one of the CLASS_* constants
|
* Is null or one of the CLASS_* constants
|
||||||
@@ -67,8 +70,9 @@ class databox_subdef
|
|||||||
*
|
*
|
||||||
* @return databox_subdef
|
* @return databox_subdef
|
||||||
*/
|
*/
|
||||||
public function __construct(SubdefType $type, SimpleXMLElement $sd, TranslatorInterface $translator)
|
public function __construct(SubdefType $type, SimpleXMLElement $sd, TranslatorInterface $translator, databox $databox = null)
|
||||||
{
|
{
|
||||||
|
$this->databox = $databox;
|
||||||
$this->subdef_group = $type;
|
$this->subdef_group = $type;
|
||||||
$this->class = (string)$sd->attributes()->class;
|
$this->class = (string)$sd->attributes()->class;
|
||||||
$this->translator = $translator;
|
$this->translator = $translator;
|
||||||
@@ -113,6 +117,12 @@ class databox_subdef
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getDatabox()
|
||||||
|
{
|
||||||
|
return $this->databox;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build Image Subdef object depending the SimpleXMLElement
|
* Build Image Subdef object depending the SimpleXMLElement
|
||||||
*
|
*
|
||||||
@@ -141,11 +151,14 @@ class databox_subdef
|
|||||||
$image->setOptionValue(Image::OPTION_FLATTEN, p4field::isyes($sd->flatten));
|
$image->setOptionValue(Image::OPTION_FLATTEN, p4field::isyes($sd->flatten));
|
||||||
}
|
}
|
||||||
if ($sd->watermark) {
|
if ($sd->watermark) {
|
||||||
$image->setOptionValue(Image::OPTION_WATERMARK, p4field::isyes($sd->watermark));
|
$image->setOptionValue(Image::OPTION_WATERMARK, (string) $sd->watermark);
|
||||||
}
|
}
|
||||||
if ($sd->watermarktext) {
|
if ($sd->watermarktext) {
|
||||||
$image->setOptionValue(Image::OPTION_WATERMARKTEXT, $sd->watermarktext);
|
$image->setOptionValue(Image::OPTION_WATERMARKTEXT, $sd->watermarktext);
|
||||||
}
|
}
|
||||||
|
if ($sd->watermarkrid) {
|
||||||
|
$image->setOptionValue(Image::OPTION_WATERMARKRID, $sd->watermarkrid);
|
||||||
|
}
|
||||||
return $image;
|
return $image;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
|
@@ -107,7 +107,7 @@ class databox_subdefsStructure implements IteratorAggregate, Countable
|
|||||||
$group = $this->getSubdefGroup($subdefgroup_name);
|
$group = $this->getSubdefGroup($subdefgroup_name);
|
||||||
|
|
||||||
foreach ($subdefs as $sd) {
|
foreach ($subdefs as $sd) {
|
||||||
$group->addSubdef(new databox_subdef($group->getType(), $sd, $this->translator));
|
$group->addSubdef(new databox_subdef($group->getType(), $sd, $this->translator, $this->databox));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -62,7 +62,6 @@
|
|||||||
$("#slidervalue" + section + name + defType + fieldname).val(value);
|
$("#slidervalue" + section + name + defType + fieldname).val(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function populate_values(section, name) {
|
function populate_values(section, name) {
|
||||||
|
|
||||||
var config = JSON.parse('{{ config |json_encode|raw }}'),
|
var config = JSON.parse('{{ config |json_encode|raw }}'),
|
||||||
@@ -620,6 +619,13 @@
|
|||||||
{% if selected %}checked="checked"{% endif %}/>{{ pot_value }}
|
{% if selected %}checked="checked"{% endif %}/>{{ pot_value }}
|
||||||
</label>
|
</label>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
{% elseif option.getType() == constant('\\Alchemy\\Phrasea\\Media\\Subdef\\OptionType\\OptionType::TYPE_ENUM_BUTTON') %}
|
||||||
|
<div style="padding: 5px 0px;">
|
||||||
|
{% for label, pot_value in option.getAvailableValues() %}
|
||||||
|
<input name="{{ varname }}" type="radio" value="{{ pot_value }}"
|
||||||
|
{% if pot_value == option.getValue() %}checked="checked"{% endif %} /> {{ label }}
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
|
Reference in New Issue
Block a user