WebCollage/src/Assembler/Superpose.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.
}
}