177 lines
6.5 KiB
PHP
177 lines
6.5 KiB
PHP
<?php
|
|
|
|
namespace Shikiryu\WebGobbler\Assembler;
|
|
|
|
use Imagick;
|
|
use Shikiryu\WebGobbler\Assembler;
|
|
|
|
class Superpose extends Assembler
|
|
{
|
|
/**
|
|
* @var Imagick
|
|
*/
|
|
private $current_image;
|
|
|
|
/**
|
|
* @param string $file
|
|
*
|
|
* @return void
|
|
* @throws \ImagickException
|
|
* @throws \Exception
|
|
*/
|
|
public function saveTo($file)
|
|
{
|
|
$image_to_superpose = new \Imagick($this->pool->getImage());
|
|
$image_x = $image_to_superpose->getImageWidth();
|
|
$image_y = $image_to_superpose->getImageHeight();
|
|
if ($image_x < 32 || $image_y < 32) {
|
|
throw new \Exception('Image too small.');
|
|
}
|
|
|
|
$this->current_image = $image_to_superpose;
|
|
|
|
$nb_images = $this->config->get('assembler.superpose.min_num_images', 5);
|
|
for ($i = 0; $i < $nb_images; $i++) {
|
|
$this->current_image = $this->superpose();
|
|
}
|
|
$this->current_image->writeImage($file);
|
|
}
|
|
|
|
public function superpose()
|
|
{
|
|
return $this->superposeOneImage($this->current_image, new \Imagick($this->pool->getImage()));
|
|
}
|
|
|
|
/**
|
|
* Superposes one image in the current image.
|
|
* This method must only be called by the assembler_superpose thread !
|
|
*
|
|
* @param \Imagick $current_image
|
|
* @param \Imagick $image_to_superpose
|
|
*
|
|
* @return \Imagick
|
|
* @throws \Exception
|
|
*/
|
|
private function superposeOneImage($current_image, $image_to_superpose)
|
|
{
|
|
if ($this->config->get('assembler.superpose.variante', 0) === 1) {
|
|
$current_image->brightnessContrastImage(0.99, 1);
|
|
}
|
|
if ($image_to_superpose->getColorspace() !== \Imagick::COLORSPACE_RGB) {
|
|
$image_to_superpose->setColorspace(\Imagick::COLORSPACE_RGB);
|
|
}
|
|
|
|
# If the image is bigger than current image, scale it down to 1/2 of final picture dimensions
|
|
# (while keeping its ratio)
|
|
$image_x = $image_to_superpose->getImageWidth();
|
|
$image_y = $image_to_superpose->getImageHeight();
|
|
if ($image_x > $this->config->get('assembler.sizex') || $image_y > $this->config->get('assembler.sizey')) {
|
|
try {
|
|
$image_to_superpose->scaleImage($this->config->get('assembler.sizex') / 2, $this->config->get('assembler.sizey') / 2, true);
|
|
} catch (\ImagickException $e) {
|
|
}
|
|
}
|
|
|
|
# Scale down/up image if required.
|
|
/*scaleValue = self.CONFIG["assembler.superpose.scale"]
|
|
if str(scaleValue) != "1.0":
|
|
try:
|
|
imageToSuperpose.thumbnail((int(float(imagex)*scaleValue),int(float(imagey)*scaleValue)),Image.ANTIALIAS)
|
|
except TypeError: #TypeError: unsubscriptable object ; Spurious exception in PIL. :-(
|
|
raise BadImage
|
|
(imagex,imagey) = imageToSuperpose.size*/
|
|
|
|
# Compensate for poorly-contrasted images on the web
|
|
/*try:
|
|
imageToSuperpose = ImageOps.autocontrast(imageToSuperpose)
|
|
except TypeError: # Aaron tells me that this exception occurs with PNG images.
|
|
raise BadImage*/
|
|
|
|
# Some image are too white.
|
|
# For example, the photo of a coin on a white background.
|
|
# These picture degrad the quality of the final image.
|
|
# We try to dectect them by summing the value of the pixels
|
|
# on the borders.
|
|
# If the image is considered "white", we invert it.
|
|
/*pixelcount = 1 # 1 to prevent divide by zero error.
|
|
valuecount = 0
|
|
try:
|
|
for x in range(0,imagex,20):
|
|
(r,g,b) = imageToSuperpose.getpixel((x,5))
|
|
valuecount += r+g+b
|
|
(r,g,b) = imageToSuperpose.getpixel((x,imagey-5))
|
|
valuecount += r+g+b
|
|
pixelcount += 2
|
|
for y in range(0,imagey,20):
|
|
(r,g,b) = imageToSuperpose.getpixel((5,y))
|
|
valuecount += r+g+b
|
|
(r,g,b) = imageToSuperpose.getpixel((imagex-5,y))
|
|
valuecount += r+g+b
|
|
pixelcount += 2
|
|
except TypeError: #unsubscriptable object Arrggghh... not again !
|
|
raise BadImage # Aggrrreeeuuuu...
|
|
|
|
# If the average r+g+b of the border pixels exceed this value,
|
|
# we consider the image is too white, and we invert it.
|
|
if (100*(valuecount/(255*3))/pixelcount)>60: # Cut at 60%. (100% is RGB=(255,255,255))
|
|
imageToSuperpose = ImageOps.invert(imageToSuperpose)*/
|
|
|
|
$paste_coords_x = random_int(-$image_x, $this->config->get('assembler.sizex'));
|
|
$paste_coords_y = random_int(-$image_y, $this->config->get('assembler.sizey'));
|
|
|
|
# Darken image borders
|
|
$image_to_superpose = $this->darkenImageBorder($image_to_superpose, 30);
|
|
|
|
if ($this->config->get('assembler.superpose.randomrotation', false)) {
|
|
$image_to_superpose->rotateImage('none', random_int(0, 359));
|
|
$image_to_superpose = $this->darkenImageBorder($image_to_superpose, 30);
|
|
}
|
|
|
|
// mask_image = ImageOps.autocontrast(imageToSuperpose.convert('L'))
|
|
|
|
// if (self.CONFIG["assembler.superpose.variante"]==1) and (random.randint(0,100)<5): # Invert the transparency of 5% of the images (Except if we are in variante 1 mode)
|
|
// mask_image = ImageOps.invert(mask_image)
|
|
$current_image->compositeImage($image_to_superpose, \Imagick::COMPOSITE_DEFAULT, $paste_coords_x, $paste_coords_y);
|
|
|
|
if ($this->config->get('assembler.superpose.variante') === 0) {
|
|
$current_image->equalizeImage();
|
|
} else {
|
|
$current_image->autoLevelImage();
|
|
}
|
|
|
|
return $current_image;
|
|
}
|
|
|
|
/**
|
|
* @param \Imagick $image
|
|
* @param int|null $border_size
|
|
*
|
|
* @return \Imagick
|
|
*/
|
|
private function darkenImageBorder(Imagick $image, $border_size = null)
|
|
{
|
|
if (null === $border_size) {
|
|
$border_size = $this->config->get('assembler.superpose.bordersmooth');
|
|
}
|
|
|
|
$image_x = $image->getImageWidth();
|
|
$image_y = $image->getImageHeight();
|
|
|
|
for ($i = 0; $i < $border_size; $i++) {
|
|
$draw = new \ImagickDraw();
|
|
$draw->setStrokeOpacity(($border_size-$i)/$border_size);
|
|
$draw->setStrokeWidth(1);
|
|
$draw->setStrokeColor('black');
|
|
$draw->setFillColor('none');
|
|
$draw->rectangle($i, $i, $image_x - $i, $image_y - $i);
|
|
$image->drawImage($draw);
|
|
}
|
|
|
|
return $image;
|
|
}
|
|
|
|
public function display()
|
|
{
|
|
// TODO: Implement display() method.
|
|
}
|
|
} |