/** * {@inheritdoc} */ public function load(ImageInterface $image, array $options = array()) { $background = $image->palette()->color(isset($options['color']) ? $options['color'] : '#fff', isset($options['transparency']) ? $options['transparency'] : null); $topLeft = new Point(0, 0); $size = $image->getSize(); if (isset($options['size'])) { list($width, $height) = $options['size']; $position = isset($options['position']) ? $options['position'] : 'center'; switch ($position) { case 'topleft': $x = 0; $y = 0; break; case 'top': $x = ($width - $image->getSize()->getWidth()) / 2; $y = 0; break; case 'topright': $x = $width - $image->getSize()->getWidth(); $y = 0; break; case 'left': $x = 0; $y = ($height - $image->getSize()->getHeight()) / 2; break; case 'center': $x = ($width - $image->getSize()->getWidth()) / 2; $y = ($height - $image->getSize()->getHeight()) / 2; break; case 'right': $x = $width - $image->getSize()->getWidth(); $y = ($height - $image->getSize()->getHeight()) / 2; break; case 'bottomleft': $x = 0; $y = $height - $image->getSize()->getHeight(); break; case 'bottom': $x = ($width - $image->getSize()->getWidth()) / 2; $y = $height - $image->getSize()->getHeight(); break; case 'bottomright': $x = $width - $image->getSize()->getWidth(); $y = $height - $image->getSize()->getHeight(); break; default: throw new \InvalidArgumentException("Unexpected position '{$position}'"); break; } $size = new Box($width, $height); $topLeft = new Point($x, $y); } $canvas = $this->imagine->create($size, $background); return $canvas->paste($image, $topLeft); }
/** * {@inheritdoc} */ public function generate($toFile = null) { $fontSize = max(min($this->dimension->getWidth() / strlen($this->text) * 1.15, $this->dimension->getHeight() * 0.5), 5); $palette = new RGB(); $image = $this->imagine->create(new Box($this->dimension->getWidth(), $this->dimension->getHeight()), $palette->color($this->backgroundColor->getColor())); $font = ImagineFactory::createFontInstance($this->instanceType, __DIR__ . '/resource/mplus.ttf', $fontSize, $palette->color($this->stringColor->getColor())); $textProperties = $font->box($this->text); $image->draw()->text($this->text, $font, new Point(($this->dimension->getWidth() - $textProperties->getWidth()) / 2, ($this->dimension->getHeight() - $textProperties->getHeight()) / 2)); if ($toFile !== null) { $image->save($toFile); } return new Result($image, $toFile); }
/** * {@inheritdoc} */ public function load(ImageInterface $image, array $options = array()) { $background = new Color(isset($options['color']) ? $options['color'] : '#fff', isset($options['transparency']) ? $options['transparency'] : 0); $topLeft = new Point(0, 0); $size = $image->getSize(); if (isset($options['size'])) { list($width, $height) = $options['size']; $size = new Box($width, $height); $topLeft = new Point(($width - $image->getSize()->getWidth()) / 2, ($height - $image->getSize()->getHeight()) / 2); } $canvas = $this->imagine->create($size, $background); return $canvas->paste($image, $topLeft); }
/** * {@inheritDoc} */ public function apply(ImageInterface $image) { if ($this->size) { list($width, $height) = $this->size; $size = new Box($width, $height); $topLeft = new Point(($width - $image->getSize()->getWidth()) / 2, ($height - $image->getSize()->getHeight()) / 2); } else { $topLeft = new Point(0, 0); $size = $image->getSize(); } $background = $image->palette()->color($this->color); $canvas = $this->imagine->create($size, $background); return $canvas->paste($image, $topLeft); }
protected function doRotate($x, $y, $angle) { list($currentImage, $point) = $this->getCurrentClip(); $size = $currentImage->getSize(); $y = $size->getHeight() - $y; $pointsToRotate = array(new Point(0, 0), new Point($size->getWidth(), 0), new Point($size->getWidth(), $size->getHeight()), new Point(0, $size->getHeight())); $xs = array(); $ys = array(); $rotatePoint = new Point($x, $y); foreach ($pointsToRotate as $pointToRotate) { $rotatedPoint = $this->rotatePoint($angle, $pointToRotate, $rotatePoint); $xs[] = $rotatedPoint->getX(); $ys[] = $rotatedPoint->getY(); } $firstPoint = new Point(min($xs), min($ys)); $diagonalPoint = new Point(max($xs), max($ys)); $middlePoint = new Point(($diagonalPoint->getX() - $firstPoint->getX()) / 2, ($diagonalPoint->getY() - $firstPoint->getY()) / 2); $width = $diagonalPoint->getX() - $firstPoint->getX(); $height = $diagonalPoint->getY() - $firstPoint->getY(); $image = $this->imagine->create($size); $angleInDegrees = rad2deg($angle); $clipPoint = new Point(0, 0); $rotatePoint = new Point(-$middlePoint->getX() + $x, -$middlePoint->getY() + $y); $this->state['clips'][] = array($image, $clipPoint, $angleInDegrees, $rotatePoint); }
/** * Re-sizes the image. If $height is not specified, it will default to $width, creating a square. * * @param int $targetWidth * @param int|null $targetHeight * * @return Image */ public function resize($targetWidth, $targetHeight = null) { $this->normalizeDimensions($targetWidth, $targetHeight); if ($this->_isAnimatedGif) { $this->_image->layers()->coalesce(); // Create a new image instance to avoid object references messing up our dimensions. $newSize = new \Imagine\Image\Box($targetWidth, $targetHeight); $gif = $this->_instance->create($newSize); $gif->layers()->remove(0); foreach ($this->_image->layers() as $layer) { $resizedLayer = $layer->resize($newSize, $this->_getResizeFilter()); $gif->layers()->add($resizedLayer); // Let's update dateUpdated in case this is going to take awhile. if ($index = craft()->assetTransforms->getActiveTransformIndexModel()) { craft()->assetTransforms->storeTransformIndexData($index); } } $this->_image = $gif; } else { if (craft()->images->isImagick()) { $this->_image->smartResize(new \Imagine\Image\Box($targetWidth, $targetHeight), (bool) craft()->config->get('preserveImageColorProfiles'), $this->_quality); } else { $this->_image->resize(new \Imagine\Image\Box($targetWidth, $targetHeight), $this->_getResizeFilter()); } } return $this; }
/** * Re-sizes the image. If $height is not specified, it will default to $width, creating a square. * * @param int $targetWidth * @param int|null $targetHeight * * @return Image */ public function resize($targetWidth, $targetHeight = null) { $this->_normalizeDimensions($targetWidth, $targetHeight); if ($this->_isAnimatedGif) { // Create a new image instance to avoid object references messing up our dimensions. $newSize = new \Imagine\Image\Box($targetWidth, $targetHeight); $gif = $this->_instance->create($newSize); $gif->layers()->remove(0); foreach ($this->_image->layers() as $layer) { $resizedLayer = $layer->resize($newSize, $this->_getResizeFilter()); $gif->layers()->add($resizedLayer); } $this->_image = $gif; } else { $this->_image->resize(new \Imagine\Image\Box($targetWidth, $targetHeight), $this->_getResizeFilter()); } return $this; }
/** * Generate the static map image and add blips to it if any are found * * @return ImageInterface The resulting image * * @return void */ public function generate() { $box = Geo::calculateBox($this->size, $this->centerPoint); $this->resultImage = $this->imagine->create($box['base']); $jj = 0; $xStart = $box['tiles']['start']->getX(); $xStop = $box['tiles']['stop']->getX(); $yStart = $box['tiles']['start']->getY(); $yStop = $box['tiles']['stop']->getY(); for ($i = $yStart - 1; $i < $yStop; $i++) { $ii = 0; for ($j = $xStart - 1; $j < $xStop; $j++) { $this->addTile($this->tiles->getTile($j, $i), new Point($ii * Geo::TILE_SIZE, $jj * Geo::TILE_SIZE)); $ii++; } $jj++; } $this->loader->run(); $this->resultImage->crop($box['crop'], $this->size); foreach ($this->blips as $blip) { $this->drawBlip($blip); } $this->loader->run(); return $this->resultImage; }
/** * Creates an image object * * @param array|\Imagine\Image\ImageInterface $source * @throws \InvalidArgumentException On unsupported source type * @return \Imagine\Image\ImageInterface */ public function create($source) { if ($source instanceof ImageInterface) { return $source; } if (isset($source['file'])) { return $this->imagine->open($source['file']); } if (isset($source['data'])) { return $this->imagine->load($source['data']); } if (isset($source['resource'])) { return $this->imagine->read($source['resource']); } if (isset($source['width']) && isset($source['height'])) { return $this->imagine->create(new Box($source['width'], $source['height'])); } throw new InvalidArgumentException(); }
public function getImagineImage(ImagineInterface $imagine, FontCollection $fontCollection, $width, $height) { $fontPath = $fontCollection->getFontById($this->font)->getPath(); if ($this->getAbsoluteSize() !== null) { $fontSize = $this->getAbsoluteSize(); } elseif ($this->getRelativeSize() !== null) { $fontSize = (int) $this->getRelativeSize() / 100 * $height; } else { throw new \LogicException('Either relative or absolute watermark size must be set!'); } if (true || !class_exists('ImagickDraw')) { // Fall back to ugly image. $palette = new \Imagine\Image\Palette\RGB(); $font = $imagine->font($fontPath, $fontSize, $palette->color('#000')); $box = $font->box($this->getText()); $watermarkImage = $imagine->create($box, $palette->color('#FFF')); $watermarkImage->draw()->text($this->text, $font, new \Imagine\Image\Point(0, 0)); } else { // CURRENTLY DISABLED. // Use nicer Imagick implementation. // Untested! // @todo Test and implement it! $draw = new \ImagickDraw(); $draw->setFont($fontPath); $draw->setFontSize($fontSize); $draw->setStrokeAntialias(true); //try with and without $draw->setTextAntialias(true); //try with and without $draw->setFillColor('#fff'); $textOnly = new \Imagick(); $textOnly->newImage(1400, 400, "transparent"); //transparent canvas $textOnly->annotateImage($draw, 0, 0, 0, $this->text); //Create stroke $draw->setFillColor('#000'); //same as stroke color $draw->setStrokeColor('#000'); $draw->setStrokeWidth(8); $strokeImage = new \Imagick(); $strokeImage->newImage(1400, 400, "transparent"); $strokeImage->annotateImage($draw, 0, 0, 0, $this->text); //Composite text over stroke $strokeImage->compositeImage($textOnly, \Imagick::COMPOSITE_OVER, 0, 0, \Imagick::CHANNEL_ALPHA); $strokeImage->trimImage(0); //cut transparent border $watermarkImage = $imagine->load($strokeImage->getImageBlob()); //$strokeImage->resizeImage(300,0, \Imagick::FILTER_CATROM, 0.9, false); //resize to final size } return $watermarkImage; }
public function apply(ImageInterface &$image, ImagineInterface $imagine) { $box = $image->getSize(); // x and y is the center of the crop $x = Helper::percentValue($this->_x, $boxw = $box->getWidth()); $y = Helper::percentValue($this->_y, $boxh = $box->getHeight()); $w = Helper::percentValue($this->_width, $boxw); $h = Helper::percentValue($this->_height, $boxh); if ($this->_ratio) { switch ($this->_ratio) { case self::COVER: Helper::scaleSize($w, $h, $box); $w = $h = min($w, $h); break; case self::CONTAIN: Helper::scaleSize($w, $h, $box); $max = max($w, $h); $img = $imagine->create(new Box($max, $max), new Color(0, 100)); $img->paste($image, new Point(($max - $boxw) * 0.5, ($max - $boxh) * 0.5)); $image = $img; return; default: // custom ratio $this->fitByRatio($w, $h, $w && $h ? $w / $h : 0); if (!$w || !$h) { throw new \RuntimeException('Invalid ratio supplied'); } break; } } else { Helper::scaleSize($w, $h, $box); } $halfw = $w / 2; $halfh = $h / 2; if ($x + $halfw > $boxw) { $x = $boxw - $halfw; } if ($y + $halfh > $boxh) { $y = $boxh - $halfh; } if ($x < $halfw) { $x = $halfw; } if ($y < $halfh) { $y = $halfh; } $image->crop(new Point($x - $w / 2, $y - $h / 2), new Box($w, $h)); }
/** * Re-sizes the image. If $height is not specified, it will default to $width, creating a square. * * @param int $targetWidth * @param int|null $targetHeight * * @return Image */ public function resize($targetWidth, $targetHeight = null) { $this->normalizeDimensions($targetWidth, $targetHeight); if ($this->_isAnimatedGif) { // Create a new image instance to avoid object references messing up our dimensions. $newSize = new \Imagine\Image\Box($targetWidth, $targetHeight); $gif = $this->_instance->create($newSize); $gif->layers()->remove(0); foreach ($this->_image->layers() as $layer) { $resizedLayer = $layer->resize($newSize, $this->_getResizeFilter()); $gif->layers()->add($resizedLayer); } $this->_image = $gif; } else { if (craft()->images->isImagick()) { $this->_image->smartResize(new \Imagine\Image\Box($targetWidth, $targetHeight), (bool) craft()->config->get('preserveImageColorProfiles'), $this->_quality); } else { $this->_image->resize(new \Imagine\Image\Box($targetWidth, $targetHeight), $this->_getResizeFilter()); } } return $this; }
/** * Process image resizing, with borders or cropping. If $dest_width and $dest_height * are both null, no resize is performed. * * @param ImagineInterface $imagine the Imagine instance * @param ImageInterface $image the image to process * @param int $dest_width the required width * @param int $dest_height the required height * @param int $resize_mode the resize mode (crop / bands / keep image ratio)p * @param string $bg_color the bg_color used for bands * @param bool $allow_zoom if true, image may be zoomed to matchrequired size. If false, image is not zoomed. * @return ImageInterface the resized image. */ protected function applyResize(ImagineInterface $imagine, ImageInterface $image, $dest_width, $dest_height, $resize_mode, $bg_color, $allow_zoom = false) { if (!(is_null($dest_width) && is_null($dest_height))) { $width_orig = $image->getSize()->getWidth(); $height_orig = $image->getSize()->getHeight(); $ratio = $width_orig / $height_orig; if (is_null($dest_width)) { $dest_width = $dest_height * $ratio; } if (is_null($dest_height)) { $dest_height = $dest_width / $ratio; } if (is_null($resize_mode)) { $resize_mode = self::KEEP_IMAGE_RATIO; } $width_diff = $dest_width / $width_orig; $height_diff = $dest_height / $height_orig; $delta_x = $delta_y = $border_width = $border_height = 0; if ($width_diff > 1 && $height_diff > 1) { $resize_width = $width_orig; $resize_height = $height_orig; // When cropping, be sure to always generate an image which is // no smaller than the required size, zooming it if required. if ($resize_mode == self::EXACT_RATIO_WITH_CROP) { if ($allow_zoom) { if ($width_diff > $height_diff) { $resize_width = $dest_width; $resize_height = intval($height_orig * $dest_width / $width_orig); $delta_y = ($resize_height - $dest_height) / 2; } else { $resize_height = $dest_height; $resize_width = intval($width_orig * $resize_height / $height_orig); $delta_x = ($resize_width - $dest_width) / 2; } } else { // No zoom : final image may be smaller than the required size. $dest_width = $resize_width; $dest_height = $resize_height; } } } elseif ($width_diff > $height_diff) { // Image height > image width $resize_height = $dest_height; $resize_width = intval($width_orig * $resize_height / $height_orig); if ($resize_mode == self::EXACT_RATIO_WITH_CROP) { $resize_width = $dest_width; $resize_height = intval($height_orig * $dest_width / $width_orig); $delta_y = ($resize_height - $dest_height) / 2; } elseif ($resize_mode != self::EXACT_RATIO_WITH_BORDERS) { $dest_width = $resize_width; } } else { // Image width > image height $resize_width = $dest_width; $resize_height = intval($height_orig * $dest_width / $width_orig); if ($resize_mode == self::EXACT_RATIO_WITH_CROP) { $resize_height = $dest_height; $resize_width = intval($width_orig * $resize_height / $height_orig); $delta_x = ($resize_width - $dest_width) / 2; } elseif ($resize_mode != self::EXACT_RATIO_WITH_BORDERS) { $dest_height = $resize_height; } } $image->resize(new Box($resize_width, $resize_height)); if ($resize_mode == self::EXACT_RATIO_WITH_BORDERS) { $border_width = intval(($dest_width - $resize_width) / 2); $border_height = intval(($dest_height - $resize_height) / 2); $canvas = new Box($dest_width, $dest_height); return $imagine->create($canvas, $bg_color)->paste($image, new Point($border_width, $border_height)); } elseif ($resize_mode == self::EXACT_RATIO_WITH_CROP) { $image->crop(new Point($delta_x, $delta_y), new Box($dest_width, $dest_height)); } } return $image; }
/** * @param string $inFilename * @param Image $spec * @param string $outFilename */ public function convert($inFilename, Specification $spec, $outFilename) { $image = $this->imagine->open($inFilename); $options = array(); if ($spec->getFormat()) { $options['format'] = $spec->getFormat(); } if ($spec->getQuality()) { if (!empty($options['format']) && $options['format'] === 'png') { $options['png_compression_level'] = floor($spec->getQuality() / 10); $options['png_compression_filter'] = $spec->getQuality() % 10; } elseif (!empty($options['format']) && $options['format'] === 'jpg') { $options['jpeg_quality'] = $spec->getQuality(); } } if ($spec->getColorspace()) { $image->strip(); switch ($spec->getColorspace()) { case 'cmyk': $image->usePalette(new CMYK()); break; case 'grayscale': $image->usePalette(new Grayscale()); break; default: $image->usePalette(new RGB()); } } if ($spec->getScale()) { if ($spec->getScale() === 'up') { // only scale up } elseif ($spec->getScale() === 'down') { // only scale down } } $method = $spec->getResizeMode(); if ($method === Image::RESIZE_METHOD_WIDTH) { $specSize = $image->getSize()->widen($spec->getWidth()); $image->resize($specSize); } elseif ($method === Image::RESIZE_METHOD_HEIGHT) { $specSize = $image->getSize()->heighten($spec->getHeight()); $image->resize($specSize); } elseif ($method === Image::RESIZE_METHOD_EXACT) { $specSize = new Box($spec->getWidth(), $spec->getHeight()); $image->resize($specSize); } elseif ($method === Image::RESIZE_METHOD_FIT) { $specSize = new Box($spec->getWidth(), $spec->getHeight()); $image = $image->thumbnail($specSize, ImageInterface::THUMBNAIL_INSET); } elseif ($method === Image::RESIZE_METHOD_EXACT_FIT) { $specSize = new Box($spec->getWidth(), $spec->getHeight()); $layer = $image->thumbnail($specSize, ImageInterface::THUMBNAIL_INSET); $layerSize = $layer->getSize(); $palette = new RGB(); if ($spec->getBackgroundColor()) { $color = $palette->color($spec->getBackgroundColor(), 100); } else { $color = $palette->color('#fff', 0); } $image = $this->imagine->create($specSize, $color); $image->paste($layer, new Point(floor(($specSize->getWidth() - $layerSize->getWidth()) / 2), floor(($specSize->getHeight() - $layerSize->getHeight()) / 2))); } elseif ($method === Image::RESIZE_METHOD_CROP) { $specSize = new Box($spec->getWidth(), $spec->getHeight()); $imageSize = $image->getSize(); if (!$specSize->contains($imageSize)) { $ratios = array($specSize->getWidth() / $imageSize->getWidth(), $specSize->getHeight() / $imageSize->getHeight()); $ratio = max($ratios); if (!$imageSize->contains($specSize)) { $imageSize = new Box(min($imageSize->getWidth(), $specSize->getWidth()), min($imageSize->getHeight(), $specSize->getHeight())); } else { $imageSize = $imageSize->scale($ratio); $image->resize($imageSize); } if ($spec->getCenterX() && $spec->getCenterY()) { $point = new Point($spec->getCenterX(), $spec->getCenterY()); } else { $point = new Point(max(0, round(($imageSize->getWidth() - $specSize->getWidth()) / 2)), max(0, round(($imageSize->getHeight() - $specSize->getHeight()) / 2))); } $image->crop($point, $specSize); } } $image->save($outFilename, $options); }
/** * (non-PHPdoc) * @see Imagine\Filter\FilterInterface::apply() */ public function apply(ImageInterface $image) { $canvas = $this->imagine->create($this->size, $this->background); $canvas->paste($image, $this->placement); return $canvas; }
protected function setUp() { $this->imagine = new Imagine(); $this->gcImage = $this->imagine->create(new Box(self::GC_WIDTH, self::GC_HEIGHT), new Color(self::GC_COLOR)); $this->gc = new GraphicsContext($this->imagine, $this->gcImage); }
/** * Process image resizing, with borders or cropping. If $dest_width and $dest_height * are both null, no resize is performed. * * @param ImagineInterface $imagine the Imagine instance * @param ImageInterface $image the image to process * @param int $dest_width the required width * @param int $dest_height the required height * @param int $resize_mode the resize mode (crop / bands / keep image ratio)p * @param string $bg_color the bg_color used for bands * @return ImageInterface the resized image. */ protected function applyResize(ImagineInterface $imagine, ImageInterface $image, $dest_width, $dest_height, $resize_mode, $bg_color) { if (!(is_null($dest_width) && is_null($dest_height))) { $width_orig = $image->getSize()->getWidth(); $height_orig = $image->getSize()->getHeight(); if (is_null($dest_width)) { $dest_width = $width_orig; } if (is_null($dest_height)) { $dest_height = $height_orig; } if (is_null($resize_mode)) { $resize_mode = self::KEEP_IMAGE_RATIO; } $width_diff = $dest_width / $width_orig; $height_diff = $dest_height / $height_orig; $delta_x = $delta_y = $border_width = $border_height = 0; if ($width_diff > 1 && $height_diff > 1) { $next_width = $width_orig; $next_height = $height_orig; $dest_width = $resize_mode == self::EXACT_RATIO_WITH_BORDERS ? $dest_width : $next_width; $dest_height = $resize_mode == self::EXACT_RATIO_WITH_BORDERS ? $dest_height : $next_height; } elseif ($width_diff > $height_diff) { // Image height > image width $next_height = $dest_height; $next_width = intval($width_orig * $next_height / $height_orig); if ($resize_mode == self::EXACT_RATIO_WITH_CROP) { $next_width = $dest_width; $next_height = intval($height_orig * $dest_width / $width_orig); $delta_y = ($next_height - $dest_height) / 2; } elseif ($resize_mode != self::EXACT_RATIO_WITH_BORDERS) { $dest_width = $next_width; } } else { // Image width > image height $next_width = $dest_width; $next_height = intval($height_orig * $dest_width / $width_orig); if ($resize_mode == self::EXACT_RATIO_WITH_CROP) { $next_height = $dest_height; $next_width = intval($width_orig * $next_height / $height_orig); $delta_x = ($next_width - $dest_width) / 2; } elseif ($resize_mode != self::EXACT_RATIO_WITH_BORDERS) { $dest_height = $next_height; } } $image->resize(new Box($next_width, $next_height)); if ($resize_mode == self::EXACT_RATIO_WITH_BORDERS) { $border_width = intval(($dest_width - $next_width) / 2); $border_height = intval(($dest_height - $next_height) / 2); $canvas = new Box($dest_width, $dest_height); return $imagine->create($canvas, $bg_color)->paste($image, new Point($border_width, $border_height)); } elseif ($resize_mode == self::EXACT_RATIO_WITH_CROP) { $image->crop(new Point($delta_x, $delta_y), new Box($dest_width, $dest_height)); } } return $image; }
/** * @param array $images * @param string $uniqueId * @param int [optional] $width * @param int [optional] $height * @param int [optional] $limit * @return string | false */ public function create($images, $uniqueId, $width = null, $height = null, $limit = 5) { if (count($images) < 1) { return false; } if ($this->hasCached($uniqueId) === true) { return $this->getHttpPath($uniqueId); } if (count($images) < $limit) { $limit = count($images); } $getMax = function ($key) { return function ($images, $item) use($key) { $processed = []; if (is_array($images)) { foreach ($images as $image) { if ($item->{$key} < $image->{$key}) { $processed[] = $image; } } } else { return $images; } return count($processed) ? $processed : $item->{$key}; }; }; $maxWidth = array_reduce($images, $getMax('width'), $images); $maxHeight = array_reduce($images, $getMax('height'), $images); if ($width == null && $height === null) { $sqrt = sqrt($limit); $width = ceil(sqrt($limit)) * $maxWidth; $height = round($sqrt) * $maxHeight; } else { if ($width != null && $height === null) { $height = ceil($limit / ceil($width / $maxWidth)) * $maxHeight; } else { if ($width == null && $height != null) { $width = ceil($limit / ceil($height / $maxHeight)) * $maxWidth; } else { $height = ceil($height / $maxHeight) * $maxHeight; $width = ceil($width / $maxWidth) * $maxWidth; } } } $collage = $this->imageService->create(new Image\Box($width, $height)); $x = 0; $y = 0; foreach ($images as $image) { $photo = $this->imageService->open($image->url); // paste photo at current position $collage->paste($photo, new Image\Point($x, $y)); // move position by 30px to the right $x += $maxWidth; if ($x >= $width) { // we reached the right border of our collage, so advance to the // next row and reset our column to the left. $y += $maxHeight; $x = 0; } if ($y >= $height) { break; // done } } try { $collage->save($this->getFilePath($uniqueId)); return $this->getHttpPath($uniqueId); } catch (\Exception $ex) { return false; } }