One Hat Cyber Team
Your IP:
216.73.216.30
Server IP:
198.54.114.155
Server:
Linux server71.web-hosting.com 4.18.0-513.18.1.lve.el8.x86_64 #1 SMP Thu Feb 22 12:55:50 UTC 2024 x86_64
Server Software:
LiteSpeed
PHP Version:
5.6.40
Create File
|
Create Folder
Execute
Dir :
~
/
proc
/
self
/
cwd
/
View File Name :
image.tar
src/Exceptions/CouldNotConvert.php 0000644 00000000434 15107356727 0013273 0 ustar 00 <?php namespace Spatie\Image\Exceptions; use Exception; class CouldNotConvert extends Exception { public static function unknownManipulation(string $operationName): self { return new self("Can not convert image. Unknown operation `{$operationName}` used"); } } src/Exceptions/InvalidImageDriver.php 0000644 00000000402 15107356727 0013703 0 ustar 00 <?php namespace Spatie\Image\Exceptions; use Exception; class InvalidImageDriver extends Exception { public static function driver(string $driver): self { return new self("Driver must be `gd` or `imagick`. `{$driver}` provided."); } } src/Exceptions/InvalidTemporaryDirectory.php 0000644 00000000772 15107356727 0015366 0 ustar 00 <?php namespace Spatie\Image\Exceptions; use Exception; class InvalidTemporaryDirectory extends Exception { public static function temporaryDirectoryNotCreatable(string $directory): self { return new self("the temporary directory `{$directory}` does not exist and can not be created"); } public static function temporaryDirectoryNotWritable(string $directory): self { return new self("the temporary directory `{$directory}` does exist but is not writable"); } } src/Exceptions/InvalidManipulation.php 0000644 00000002305 15107356727 0014151 0 ustar 00 <?php namespace Spatie\Image\Exceptions; use Exception; class InvalidManipulation extends Exception { public static function invalidWidth(int $width): self { return new self("Width should be a positive number. `{$width}` given."); } public static function invalidHeight(int $height): self { return new self("Height should be a positive number. `{$height}` given."); } public static function invalidParameter(string $name, $invalidValue, array $validValues): self { $validValues = self::formatValues($validValues); $name = ucfirst($name); return new self("{$name} should be one of {$validValues}. `{$invalidValue}` given."); } public static function valueNotInRange(string $name, $invalidValue, $minValue, $maxValue): self { $name = ucfirst($name); return new self("{$name} should be a number in the range {$minValue} until {$maxValue}. `{$invalidValue}` given."); } protected static function formatValues(array $values): string { $quotedValues = array_map(function (string $value) { return "`{$value}`"; }, $values); return implode(', ', $quotedValues); } } src/Manipulations.php 0000644 00000043135 15107356727 0010712 0 ustar 00 <?php namespace Spatie\Image; use League\Glide\Filesystem\FileNotFoundException; use ReflectionClass; use Spatie\Image\Exceptions\InvalidManipulation; class Manipulations { public const CROP_TOP_LEFT = 'crop-top-left'; public const CROP_TOP = 'crop-top'; public const CROP_TOP_RIGHT = 'crop-top-right'; public const CROP_LEFT = 'crop-left'; public const CROP_CENTER = 'crop-center'; public const CROP_RIGHT = 'crop-right'; public const CROP_BOTTOM_LEFT = 'crop-bottom-left'; public const CROP_BOTTOM = 'crop-bottom'; public const CROP_BOTTOM_RIGHT = 'crop-bottom-right'; public const ORIENTATION_AUTO = 'auto'; public const ORIENTATION_0 = 0; public const ORIENTATION_90 = 90; public const ORIENTATION_180 = 180; public const ORIENTATION_270 = 270; public const FLIP_HORIZONTALLY = 'h'; public const FLIP_VERTICALLY = 'v'; public const FLIP_BOTH = 'both'; public const FIT_CONTAIN = 'contain'; public const FIT_MAX = 'max'; public const FIT_FILL = 'fill'; public const FIT_FILL_MAX = 'fill-max'; public const FIT_STRETCH = 'stretch'; public const FIT_CROP = 'crop'; public const BORDER_OVERLAY = 'overlay'; public const BORDER_SHRINK = 'shrink'; public const BORDER_EXPAND = 'expand'; public const FORMAT_JPG = 'jpg'; public const FORMAT_PJPG = 'pjpg'; public const FORMAT_PNG = 'png'; public const FORMAT_GIF = 'gif'; public const FORMAT_WEBP = 'webp'; public const FORMAT_AVIF = 'avif'; public const FORMAT_TIFF = 'tiff'; public const FILTER_GREYSCALE = 'greyscale'; public const FILTER_SEPIA = 'sepia'; public const UNIT_PIXELS = 'px'; public const UNIT_PERCENT = '%'; public const POSITION_TOP_LEFT = 'top-left'; public const POSITION_TOP = 'top'; public const POSITION_TOP_RIGHT = 'top-right'; public const POSITION_LEFT = 'left'; public const POSITION_CENTER = 'center'; public const POSITION_RIGHT = 'right'; public const POSITION_BOTTOM_LEFT = 'bottom-left'; public const POSITION_BOTTOM = 'bottom'; public const POSITION_BOTTOM_RIGHT = 'bottom-right'; protected ManipulationSequence $manipulationSequence; public function __construct(array $manipulations = []) { if (! $this->hasMultipleConversions($manipulations)) { $manipulations = [$manipulations]; } foreach ($manipulations as $manipulation) { $this->manipulationSequence = new ManipulationSequence($manipulation); } } public static function create(array $manipulations = []): Manipulations { return new self($manipulations); } /** * @throws InvalidManipulation */ public function orientation(string $orientation): static { if (! $this->validateManipulation($orientation, 'orientation')) { throw InvalidManipulation::invalidParameter( 'orientation', $orientation, $this->getValidManipulationOptions('orientation') ); } return $this->addManipulation('orientation', $orientation); } /** * @throws InvalidManipulation */ public function flip(string $orientation): static { if (! $this->validateManipulation($orientation, 'flip')) { throw InvalidManipulation::invalidParameter( 'flip', $orientation, $this->getValidManipulationOptions('flip') ); } return $this->addManipulation('flip', $orientation); } /** * @throws InvalidManipulation */ public function crop(string $cropMethod, int $width, int $height): static { if (! $this->validateManipulation($cropMethod, 'crop')) { throw InvalidManipulation::invalidParameter( 'cropmethod', $cropMethod, $this->getValidManipulationOptions('crop') ); } $this->width($width); $this->height($height); return $this->addManipulation('crop', $cropMethod); } /** * @param int $focalX Crop center X in percent * @param int $focalY Crop center Y in percent * * @throws InvalidManipulation */ public function focalCrop(int $width, int $height, int $focalX, int $focalY, float $zoom = 1): static { if ($zoom < 1 || $zoom > 100) { throw InvalidManipulation::valueNotInRange('zoom', $zoom, 1, 100); } $this->width($width); $this->height($height); return $this->addManipulation('crop', "crop-{$focalX}-{$focalY}-{$zoom}"); } /** * @throws InvalidManipulation */ public function manualCrop(int $width, int $height, int $x, int $y): static { if ($width < 0) { throw InvalidManipulation::invalidWidth($width); } if ($height < 0) { throw InvalidManipulation::invalidWidth($height); } return $this->addManipulation('manualCrop', "{$width},{$height},{$x},{$y}"); } /** * @throws InvalidManipulation */ public function width(int $width): static { if ($width < 0) { throw InvalidManipulation::invalidWidth($width); } return $this->addManipulation('width', (string)$width); } /** * @throws InvalidManipulation */ public function height(int $height): static { if ($height < 0) { throw InvalidManipulation::invalidHeight($height); } return $this->addManipulation('height', (string)$height); } /** * @throws InvalidManipulation */ public function fit(string $fitMethod, ?int $width = null, ?int $height = null): static { if (! $this->validateManipulation($fitMethod, 'fit')) { throw InvalidManipulation::invalidParameter( 'fit', $fitMethod, $this->getValidManipulationOptions('fit') ); } if ($width === null && $height === null) { throw new InvalidManipulation('Width or height or both must be provided'); } if ($width !== null) { $this->width($width); } if ($height !== null) { $this->height($height); } return $this->addManipulation('fit', $fitMethod); } /** * @param int $ratio A value between 1 and 8 * * @throws InvalidManipulation */ public function devicePixelRatio(int $ratio): static { if ($ratio < 1 || $ratio > 8) { throw InvalidManipulation::valueNotInRange('ratio', $ratio, 1, 8); } return $this->addManipulation('devicePixelRatio', (string)$ratio); } /** * @param int $brightness A value between -100 and 100 * * @throws InvalidManipulation */ public function brightness(int $brightness): static { if ($brightness < -100 || $brightness > 100) { throw InvalidManipulation::valueNotInRange('brightness', $brightness, -100, 100); } return $this->addManipulation('brightness', (string)$brightness); } /** * @param float $gamma A value between 0.01 and 9.99 * * @throws InvalidManipulation */ public function gamma(float $gamma): static { if ($gamma < 0.01 || $gamma > 9.99) { throw InvalidManipulation::valueNotInRange('gamma', $gamma, 0.01, 9.00); } return $this->addManipulation('gamma', (string)$gamma); } /** * @param int $contrast A value between -100 and 100 * * @throws InvalidManipulation */ public function contrast(int $contrast): static { if ($contrast < -100 || $contrast > 100) { throw InvalidManipulation::valueNotInRange('contrast', $contrast, -100, 100); } return $this->addManipulation('contrast', (string)$contrast); } /** * @param int $sharpen A value between 0 and 100 * * @throws InvalidManipulation */ public function sharpen(int $sharpen): static { if ($sharpen < 0 || $sharpen > 100) { throw InvalidManipulation::valueNotInRange('sharpen', $sharpen, 0, 100); } return $this->addManipulation('sharpen', (string)$sharpen); } /** * @param int $blur A value between 0 and 100 * * @throws InvalidManipulation */ public function blur(int $blur): static { if ($blur < 0 || $blur > 100) { throw InvalidManipulation::valueNotInRange('blur', $blur, 0, 100); } return $this->addManipulation('blur', (string)$blur); } /** * @param int $pixelate A value between 0 and 1000 * * @throws InvalidManipulation */ public function pixelate(int $pixelate): static { if ($pixelate < 0 || $pixelate > 1000) { throw InvalidManipulation::valueNotInRange('pixelate', $pixelate, 0, 1000); } return $this->addManipulation('pixelate', (string)$pixelate); } /** * @throws InvalidManipulation */ public function greyscale(): static { return $this->filter('greyscale'); } /** * @throws InvalidManipulation */ public function sepia(): static { return $this->filter('sepia'); } public function background(string $colorName): static { return $this->addManipulation('background', $colorName); } /** * @throws InvalidManipulation */ public function border(int $width, string $color, string $borderType = 'overlay'): static { if ($width < 0) { throw InvalidManipulation::invalidWidth($width); } if (! $this->validateManipulation($borderType, 'border')) { throw InvalidManipulation::invalidParameter( 'border', $borderType, $this->getValidManipulationOptions('border') ); } return $this->addManipulation('border', "{$width},{$color},{$borderType}"); } /** * @throws InvalidManipulation */ public function quality(int $quality): static { if ($quality < 0 || $quality > 100) { throw InvalidManipulation::valueNotInRange('quality', $quality, 0, 100); } return $this->addManipulation('quality', (string)$quality); } /** * @throws InvalidManipulation */ public function format(string $format): static { if (! $this->validateManipulation($format, 'format')) { throw InvalidManipulation::invalidParameter( 'format', $format, $this->getValidManipulationOptions('format') ); } return $this->addManipulation('format', $format); } /** * @throws InvalidManipulation */ protected function filter(string $filterName): static { if (! $this->validateManipulation($filterName, 'filter')) { throw InvalidManipulation::invalidParameter( 'filter', $filterName, $this->getValidManipulationOptions('filter') ); } return $this->addManipulation('filter', $filterName); } /** * @throws FileNotFoundException */ public function watermark(string $filePath): static { if (! file_exists($filePath)) { throw new FileNotFoundException($filePath); } $this->addManipulation('watermark', $filePath); return $this; } /** * @param int $width The width of the watermark in pixels (default) or percent. * @param string $unit The unit of the `$width` parameter. Use `Manipulations::UNIT_PERCENT` or `Manipulations::UNIT_PIXELS`. */ public function watermarkWidth(int $width, string $unit = 'px'): static { $width = ($unit === static::UNIT_PERCENT ? $width.'w' : $width); return $this->addManipulation('watermarkWidth', (string)$width); } /** * @param int $height The height of the watermark in pixels (default) or percent. * @param string $unit The unit of the `$height` parameter. Use `Manipulations::UNIT_PERCENT` or `Manipulations::UNIT_PIXELS`. */ public function watermarkHeight(int $height, string $unit = 'px'): static { $height = ($unit === static::UNIT_PERCENT ? $height.'h' : $height); return $this->addManipulation('watermarkHeight', (string)$height); } /** * @param string $fitMethod How is the watermark fitted into the watermarkWidth and watermarkHeight properties. * * @throws InvalidManipulation */ public function watermarkFit(string $fitMethod): static { if (! $this->validateManipulation($fitMethod, 'fit')) { throw InvalidManipulation::invalidParameter( 'watermarkFit', $fitMethod, $this->getValidManipulationOptions('fit') ); } return $this->addManipulation('watermarkFit', $fitMethod); } /** * @param int $xPadding How far is the watermark placed from the left and right edges of the image. * @param int|null $yPadding How far is the watermark placed from the top and bottom edges of the image. * @param string $unit Unit of the padding values. Use `Manipulations::UNIT_PERCENT` or `Manipulations::UNIT_PIXELS`. */ public function watermarkPadding(int $xPadding, int $yPadding = null, string $unit = 'px'): static { $yPadding = $yPadding ?? $xPadding; $xPadding = ($unit === static::UNIT_PERCENT ? $xPadding.'w' : $xPadding); $yPadding = ($unit === static::UNIT_PERCENT ? $yPadding.'h' : $yPadding); $this->addManipulation('watermarkPaddingX', (string)$xPadding); $this->addManipulation('watermarkPaddingY', (string)$yPadding); return $this; } /** * @throws InvalidManipulation */ public function watermarkPosition(string $position): static { if (! $this->validateManipulation($position, 'position')) { throw InvalidManipulation::invalidParameter( 'watermarkPosition', $position, $this->getValidManipulationOptions('position') ); } return $this->addManipulation('watermarkPosition', $position); } /** * Sets the opacity of the watermark. Only works with the `imagick` driver. * * @param int $opacity A value between 0 and 100. * * @throws InvalidManipulation */ public function watermarkOpacity(int $opacity): static { if ($opacity < 0 || $opacity > 100) { throw InvalidManipulation::valueNotInRange('opacity', $opacity, 0, 100); } return $this->addManipulation('watermarkOpacity', (string)$opacity); } /** * Shave off some kilobytes by optimizing the image. */ public function optimize(array $optimizationOptions = []): static { return $this->addManipulation('optimize', json_encode($optimizationOptions)); } public function apply(): static { $this->manipulationSequence->startNewGroup(); return $this; } public function toArray(): array { return $this->manipulationSequence->toArray(); } /** * Checks if the given manipulations has arrays inside or not. */ private function hasMultipleConversions(array $manipulations): bool { foreach ($manipulations as $manipulation) { if (isset($manipulation[0]) && is_array($manipulation[0])) { return true; } } return false; } public function removeManipulation(string $name): void { $this->manipulationSequence->removeManipulation($name); } public function hasManipulation(string $manipulationName): bool { return ! is_null($this->getManipulationArgument($manipulationName)); } public function getManipulationArgument(string $manipulationName) { foreach ($this->manipulationSequence->getGroups() as $manipulationSet) { if (array_key_exists($manipulationName, $manipulationSet)) { return $manipulationSet[$manipulationName]; } } } protected function addManipulation(string $manipulationName, string $manipulationArgument): static { $this->manipulationSequence->addManipulation($manipulationName, $manipulationArgument); return $this; } public function mergeManipulations(self $manipulations): static { $this->manipulationSequence->merge($manipulations->manipulationSequence); return $this; } public function getManipulationSequence(): ManipulationSequence { return $this->manipulationSequence; } protected function validateManipulation(string $value, string $constantNamePrefix): bool { return in_array($value, $this->getValidManipulationOptions($constantNamePrefix)); } protected function getValidManipulationOptions(string $manipulation): array { $options = (new ReflectionClass(static::class))->getConstants(); return array_filter($options, function ($value, $name) use ($manipulation) { return str_starts_with($name, mb_strtoupper($manipulation)); }, ARRAY_FILTER_USE_BOTH); } public function isEmpty(): bool { return $this->manipulationSequence->isEmpty(); } /* * Get the first manipulation with the given name. * * @return mixed */ public function getFirstManipulationArgument(string $manipulationName) { return $this->manipulationSequence->getFirstManipulationArgument($manipulationName); } } src/ManipulationSequence.php 0000644 00000006017 15107356727 0012216 0 ustar 00 <?php namespace Spatie\Image; use ArrayIterator; use IteratorAggregate; class ManipulationSequence implements IteratorAggregate { protected array $groups = []; public function __construct(array $sequenceArray = []) { $this->startNewGroup(); $this->mergeArray($sequenceArray); } public function addManipulation(string $operation, string $argument): static { $lastIndex = count($this->groups) - 1; $this->groups[$lastIndex][$operation] = $argument; return $this; } public function merge(self $sequence): static { $sequenceArray = $sequence->toArray(); $this->mergeArray($sequenceArray); return $this; } public function mergeArray(array $sequenceArray): void { foreach ($sequenceArray as $group) { foreach ($group as $name => $argument) { $this->addManipulation($name, $argument); } if (next($sequenceArray)) { $this->startNewGroup(); } } } public function startNewGroup(): static { $this->groups[] = []; return $this; } public function toArray(): array { return $this->getGroups(); } public function getGroups(): array { return $this->sanitizeManipulationSets($this->groups); } public function getIterator(): ArrayIterator { return new ArrayIterator($this->toArray()); } public function removeManipulation(string $manipulationName): static { foreach ($this->groups as &$group) { if (array_key_exists($manipulationName, $group)) { unset($group[$manipulationName]); } } return $this; } public function isEmpty(): bool { if (count($this->groups) > 1) { return false; } if (count($this->groups[0]) > 0) { return false; } return true; } protected function sanitizeManipulationSets(array $groups): array { return array_values(array_filter($groups, function (array $manipulationSet) { return count($manipulationSet); })); } /* * Determine if the sequences contain a manipulation with the given name. */ public function getFirstManipulationArgument($searchManipulationName) { foreach ($this->groups as $group) { foreach ($group as $name => $argument) { if ($name === $searchManipulationName) { return $argument; } } } } /* * Determine if the sequences contain a manipulation with the given name. */ public function contains($searchManipulationName): bool { foreach ($this->groups as $group) { foreach ($group as $name => $argument) { if ($name === $searchManipulationName) { return true; } } return false; } return false; } } src/Image.php 0000644 00000013226 15107356727 0007107 0 ustar 00 <?php namespace Spatie\Image; use BadMethodCallException; use Intervention\Image\ImageManagerStatic as InterventionImage; use Spatie\Image\Exceptions\InvalidImageDriver; use Spatie\ImageOptimizer\OptimizerChain; use Spatie\ImageOptimizer\OptimizerChainFactory; use Spatie\ImageOptimizer\Optimizers\BaseOptimizer; /** @mixin \Spatie\Image\Manipulations */ class Image { protected Manipulations $manipulations; protected string $imageDriver = 'gd'; protected ?string $temporaryDirectory = null; protected ?OptimizerChain $optimizerChain = null; public function __construct(protected string $pathToImage) { $this->manipulations = new Manipulations(); } public static function load(string $pathToImage): static { return new static($pathToImage); } public function setTemporaryDirectory($tempDir): static { $this->temporaryDirectory = $tempDir; return $this; } public function setOptimizeChain(OptimizerChain $optimizerChain): static { $this->optimizerChain = $optimizerChain; return $this; } /** * @param string $imageDriver * @return $this * @throws InvalidImageDriver */ public function useImageDriver(string $imageDriver): static { if (! in_array($imageDriver, ['gd', 'imagick'])) { throw InvalidImageDriver::driver($imageDriver); } $this->imageDriver = $imageDriver; InterventionImage::configure([ 'driver' => $this->imageDriver, ]); return $this; } public function manipulate(callable | Manipulations $manipulations): static { if (is_callable($manipulations)) { $manipulations($this->manipulations); } if ($manipulations instanceof Manipulations) { $this->manipulations->mergeManipulations($manipulations); } return $this; } public function __call($name, $arguments): static { if (! method_exists($this->manipulations, $name)) { throw new BadMethodCallException("Manipulation `{$name}` does not exist"); } $this->manipulations->$name(...$arguments); return $this; } public function getWidth(): int { return InterventionImage::make($this->pathToImage)->width(); } public function getHeight(): int { return InterventionImage::make($this->pathToImage)->height(); } public function getManipulationSequence(): ManipulationSequence { return $this->manipulations->getManipulationSequence(); } public function save(string $outputPath = ''): void { if ($outputPath === '') { $outputPath = $this->pathToImage; } $this->addFormatManipulation($outputPath); $glideConversion = GlideConversion::create($this->pathToImage)->useImageDriver($this->imageDriver); if (! is_null($this->temporaryDirectory)) { $glideConversion->setTemporaryDirectory($this->temporaryDirectory); } $glideConversion->performManipulations($this->manipulations); $glideConversion->save($outputPath); if ($this->shouldOptimize()) { $optimizerChainConfiguration = $this->manipulations->getFirstManipulationArgument('optimize'); $optimizerChainConfiguration = json_decode($optimizerChainConfiguration, true); $this->performOptimization($outputPath, $optimizerChainConfiguration); } } protected function shouldOptimize(): bool { return ! is_null($this->manipulations->getFirstManipulationArgument('optimize')); } protected function performOptimization($path, array $optimizerChainConfiguration): void { $optimizerChain = $this->optimizerChain ?? OptimizerChainFactory::create(); if (count($optimizerChainConfiguration)) { $existingOptimizers = $optimizerChain->getOptimizers(); $optimizers = array_map(function (array $optimizerOptions, string $optimizerClassName) use ($existingOptimizers) { $optimizer = array_values(array_filter($existingOptimizers, function ($optimizer) use ($optimizerClassName) { return $optimizer::class === $optimizerClassName; })); $optimizer = isset($optimizer[0]) && $optimizer[0] instanceof BaseOptimizer ? $optimizer[0] : new $optimizerClassName(); return $optimizer->setOptions($optimizerOptions)->setBinaryPath($optimizer->binaryPath); }, $optimizerChainConfiguration, array_keys($optimizerChainConfiguration)); $optimizerChain->setOptimizers($optimizers); } $optimizerChain->optimize($path); } protected function addFormatManipulation($outputPath): void { if ($this->manipulations->hasManipulation('format')) { return; } $inputExtension = strtolower(pathinfo($this->pathToImage, PATHINFO_EXTENSION)); $outputExtension = strtolower(pathinfo($outputPath, PATHINFO_EXTENSION)); if ($inputExtension === $outputExtension) { return; } $supportedFormats = [ Manipulations::FORMAT_JPG, Manipulations::FORMAT_PJPG, Manipulations::FORMAT_PNG, Manipulations::FORMAT_GIF, Manipulations::FORMAT_WEBP, Manipulations::FORMAT_AVIF, ]; //gd driver doesn't support TIFF if ($this->imageDriver === 'imagick') { $supportedFormats[] = Manipulations::FORMAT_TIFF; } if (in_array($outputExtension, $supportedFormats)) { $this->manipulations->format($outputExtension); } } } src/GlideConversion.php 0000644 00000013010 15107356727 0011146 0 ustar 00 <?php namespace Spatie\Image; use Exception; use FilesystemIterator; use League\Glide\Server; use League\Glide\ServerFactory; use Spatie\Image\Exceptions\CouldNotConvert; use Spatie\Image\Exceptions\InvalidTemporaryDirectory; final class GlideConversion { private string $imageDriver = 'gd'; private ?string $conversionResult = null; private string $temporaryDirectory; public function __construct(private string $inputImage) { $this->temporaryDirectory = sys_get_temp_dir(); } public static function create(string $inputImage): self { return new self($inputImage); } public function setTemporaryDirectory(string $temporaryDirectory): self { if (! is_dir($temporaryDirectory)) { try { mkdir($temporaryDirectory); } catch (Exception) { throw InvalidTemporaryDirectory::temporaryDirectoryNotCreatable($temporaryDirectory); } } if (! is_writable($temporaryDirectory)) { throw InvalidTemporaryDirectory::temporaryDirectoryNotWritable($temporaryDirectory); } $this->temporaryDirectory = $temporaryDirectory; return $this; } public function getTemporaryDirectory(): string { return $this->temporaryDirectory; } public function useImageDriver(string $imageDriver): self { $this->imageDriver = $imageDriver; return $this; } public function performManipulations(Manipulations $manipulations): GlideConversion { foreach ($manipulations->getManipulationSequence() as $manipulationGroup) { $inputFile = $this->conversionResult ?? $this->inputImage; $watermarkPath = $this->extractWatermarkPath($manipulationGroup); $glideServer = $this->createGlideServer($inputFile, $watermarkPath); $glideServer->setGroupCacheInFolders(false); $manipulatedImage = $this->temporaryDirectory.DIRECTORY_SEPARATOR.$glideServer->makeImage( pathinfo($inputFile, PATHINFO_BASENAME), $this->prepareManipulations($manipulationGroup) ); if ($this->conversionResult) { unlink($this->conversionResult); } $this->conversionResult = $manipulatedImage; } return $this; } /** * Removes the watermark path from the manipulationGroup and returns it. * This way it can be injected into the Glide server as the `watermarks` path. */ private function extractWatermarkPath(&$manipulationGroup) { if (array_key_exists('watermark', $manipulationGroup)) { $watermarkPath = dirname($manipulationGroup['watermark']); $manipulationGroup['watermark'] = basename($manipulationGroup['watermark']); return $watermarkPath; } } private function createGlideServer($inputFile, string $watermarkPath = null): Server { $config = [ 'source' => dirname($inputFile), 'cache' => $this->temporaryDirectory, 'driver' => $this->imageDriver, ]; if ($watermarkPath) { $config['watermarks'] = $watermarkPath; } return ServerFactory::create($config); } public function save(string $outputFile): void { if ($this->conversionResult === '' || $this->conversionResult === null) { copy($this->inputImage, $outputFile); return; } $conversionResultDirectory = pathinfo($this->conversionResult, PATHINFO_DIRNAME); copy($this->conversionResult, $outputFile); unlink($this->conversionResult); if ($conversionResultDirectory !== sys_get_temp_dir() && $this->directoryIsEmpty($conversionResultDirectory)) { rmdir($conversionResultDirectory); } } private function prepareManipulations(array $manipulationGroup): array { $glideManipulations = []; foreach ($manipulationGroup as $name => $argument) { if ($name !== 'optimize') { $glideManipulations[$this->convertToGlideParameter($name)] = $argument; } } return $glideManipulations; } private function convertToGlideParameter(string $manipulationName): string { return match ($manipulationName) { 'width' => 'w', 'height' => 'h', 'blur' => 'blur', 'pixelate' => 'pixel', 'crop' => 'fit', 'manualCrop' => 'crop', 'orientation' => 'or', 'flip' => 'flip', 'fit' => 'fit', 'devicePixelRatio' => 'dpr', 'brightness' => 'bri', 'contrast' => 'con', 'gamma' => 'gam', 'sharpen' => 'sharp', 'filter' => 'filt', 'background' => 'bg', 'border' => 'border', 'quality' => 'q', 'format' => 'fm', 'watermark' => 'mark', 'watermarkWidth' => 'markw', 'watermarkHeight' => 'markh', 'watermarkFit' => 'markfit', 'watermarkPaddingX' => 'markx', 'watermarkPaddingY' => 'marky', 'watermarkPosition' => 'markpos', 'watermarkOpacity' => 'markalpha', default => throw CouldNotConvert::unknownManipulation($manipulationName) }; } private function directoryIsEmpty(string $directory): bool { $iterator = new FilesystemIterator($directory); return ! $iterator->valid(); } } README.md 0000644 00000007254 15107356727 0006050 0 ustar 00 # Manipulate images with an expressive API [](https://packagist.org/packages/spatie/image) [](LICENSE.md) [](https://github.com/spatie/image/actions/workflows/run-tests.yml) [](https://packagist.org/packages/spatie/image) Image manipulation doesn't have to be hard. Here are a few examples on how this package makes it very easy to manipulate images. ```php use Spatie\Image\Image; // modifying the image so it fits in a 100x100 rectangle without altering aspect ratio Image::load($pathToImage) ->width(100) ->height(100) ->save($pathToNewImage); // overwriting the original image with a greyscale version Image::load($pathToImage) ->greyscale() ->save(); // make image darker and save it in low quality Image::load($pathToImage) ->brightness(-30) ->quality(25) ->save(); // rotate the image and sharpen it Image::load($pathToImage) ->orientation(90) ->sharpen(15) ->save(); ``` You'll find more examples in [the full documentation](https://docs.spatie.be/image). Under the hood [Glide](http://glide.thephpleague.com/) by [Jonathan Reinink](https://twitter.com/reinink) is used. ## Support us [<img src="https://github-ads.s3.eu-central-1.amazonaws.com/image.jpg?t=1" width="419px" />](https://spatie.be/github-ad-click/image) We invest a lot of resources into creating [best in class open source packages](https://spatie.be/open-source). You can support us by [buying one of our paid products](https://spatie.be/open-source/support-us). We highly appreciate you sending us a postcard from your hometown, mentioning which of our package(s) you are using. You'll find our address on [our contact page](https://spatie.be/about-us). We publish all received postcards on [our virtual postcard wall](https://spatie.be/open-source/postcards). ## Installation You can install the package via composer: ``` bash composer require spatie/image ``` Please note that since version 1.5.3 this package requires exif extension to be enabled: http://php.net/manual/en/exif.installation.php ## Usage Head over to [the full documentation](https://spatie.be/docs/image). ## Changelog Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently. ## Testing ``` bash composer test ``` ## Contributing Please see [CONTRIBUTING](https://github.com/spatie/.github/blob/main/CONTRIBUTING.md) for details. ## Security If you've found a bug regarding security please mail [security@spatie.be](mailto:security@spatie.be) instead of using the issue tracker. ## Postcardware You're free to use this package, but if it makes it to your production environment we highly appreciate you sending us a postcard from your hometown, mentioning which of our package(s) you are using. Our address is: Spatie, Kruikstraat 22, 2018 Antwerp, Belgium. We publish all received postcards [on our company website](https://spatie.be/en/opensource/postcards). ## Credits - [Freek Van der Herten](https://github.com/freekmurze) - [All Contributors](../../contributors) Under the hood [Glide](http://glide.thephpleague.com/) by [Jonathan Reinink](https://twitter.com/reinink) is used. We've based our documentation and docblocks on text found in [the Glide documentation](http://glide.thephpleague.com/) ## License The MIT License (MIT). Please see [License File](LICENSE.md) for more information. composer.json 0000644 00000002624 15107356727 0007307 0 ustar 00 { "name": "intervention/image", "description": "Image handling and manipulation library with support for Laravel integration", "homepage": "http://image.intervention.io/", "keywords": ["image", "gd", "imagick", "laravel", "watermark", "thumbnail"], "license": "MIT", "authors": [ { "name": "Oliver Vogel", "email": "oliver@intervention.io", "homepage": "https://intervention.io/" } ], "require": { "php": ">=5.4.0", "ext-fileinfo": "*", "guzzlehttp/psr7": "~1.1 || ^2.0" }, "require-dev": { "phpunit/phpunit": "^4.8 || ^5.7 || ^7.5.15", "mockery/mockery": "~0.9.2" }, "suggest": { "ext-gd": "to use GD library based image processing.", "ext-imagick": "to use Imagick based image processing.", "intervention/imagecache": "Caching extension for the Intervention Image library" }, "autoload": { "psr-4": { "Intervention\\Image\\": "src/Intervention/Image" } }, "extra": { "branch-alias": { "dev-master": "2.4-dev" }, "laravel": { "providers": [ "Intervention\\Image\\ImageServiceProvider" ], "aliases": { "Image": "Intervention\\Image\\Facades\\Image" } } }, "minimum-stability": "stable" } LICENSE.md 0000644 00000002102 15107356727 0006160 0 ustar 00 The MIT License (MIT) Copyright (c) Spatie bvba <info@spatie.be> 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. CHANGELOG.md 0000644 00000013650 15107356727 0006377 0 ustar 00 # Changelog All notable changes to `image` will be documented in this file ## 2.2.6 - 2023-05-06 ### What's Changed - Bump dependabot/fetch-metadata from 1.3.5 to 1.3.6 by @dependabot in https://github.com/spatie/image/pull/185 - Bump dependabot/fetch-metadata from 1.3.6 to 1.4.0 by @dependabot in https://github.com/spatie/image/pull/188 - Fit with only width or height by @gdebrauwer in https://github.com/spatie/image/pull/190 ### New Contributors - @dependabot made their first contribution in https://github.com/spatie/image/pull/185 - @gdebrauwer made their first contribution in https://github.com/spatie/image/pull/190 **Full Changelog**: https://github.com/spatie/image/compare/2.2.5...2.2.6 ## 2.2.5 - 2023-01-19 ### What's Changed - Refactor tests to pest by @AyoobMH in https://github.com/spatie/image/pull/176 - Add Dependabot Automation by @patinthehat in https://github.com/spatie/image/pull/177 - Add PHP 8.2 Support by @patinthehat in https://github.com/spatie/image/pull/180 - Update Dependabot Automation by @patinthehat in https://github.com/spatie/image/pull/181 - Add fill-max fit mode by @Tofandel in https://github.com/spatie/image/pull/183 ### New Contributors - @AyoobMH made their first contribution in https://github.com/spatie/image/pull/176 - @patinthehat made their first contribution in https://github.com/spatie/image/pull/177 - @Tofandel made their first contribution in https://github.com/spatie/image/pull/183 **Full Changelog**: https://github.com/spatie/image/compare/2.2.4...2.2.5 ## 2.2.4 - 2022-08-09 ### What's Changed - Add zero orientation support ignoring EXIF by @danielcastrobalbi in https://github.com/spatie/image/pull/171 ### New Contributors - @danielcastrobalbi made their first contribution in https://github.com/spatie/image/pull/171 **Full Changelog**: https://github.com/spatie/image/compare/2.2.3...2.2.4 ## 2.2.3 - 2022-05-21 ## What's Changed - Fix permission issue with temporary directory by @sebastianpopp in https://github.com/spatie/image/pull/163 ## New Contributors - @sebastianpopp made their first contribution in https://github.com/spatie/image/pull/163 **Full Changelog**: https://github.com/spatie/image/compare/2.2.2...2.2.3 ## 2.2.2 - 2022-02-22 - add TIFF support ## 1.11.0 - 2022-02-21 ## What's Changed - Fix docs link by @pascalbaljet in https://github.com/spatie/image/pull/154 - Update .gitattributes by @PaolaRuby in https://github.com/spatie/image/pull/158 - Add TIFF support by @Synchro in https://github.com/spatie/image/pull/159 ## New Contributors - @PaolaRuby made their first contribution in https://github.com/spatie/image/pull/158 **Full Changelog**: https://github.com/spatie/image/compare/2.2.1...1.11.0 ## 2.2.1 - 2021-12-17 ## What's Changed - Use match expression in convertToGlideParameter method by @mohprilaksono in https://github.com/spatie/image/pull/149 - [REF] updated fit docs description by @JeremyRed in https://github.com/spatie/image/pull/150 - Adding compatibility to Symfony 6 by @spackmat in https://github.com/spatie/image/pull/152 ## New Contributors - @mohprilaksono made their first contribution in https://github.com/spatie/image/pull/149 - @JeremyRed made their first contribution in https://github.com/spatie/image/pull/150 - @spackmat made their first contribution in https://github.com/spatie/image/pull/152 **Full Changelog**: https://github.com/spatie/image/compare/2.2.0...2.2.1 ## 2.2.0 - 2021-10-31 - add avif support (#148) ## 2.1.0 - 2021-07-15 - Drop support for PHP 7 - Make codebase more strict with type hinting ## 2.0.0 - 2021-07-15 - Bump league/glide to v2 [#134](https://github.com/spatie/image/pull/134) ## 1.10.4 - 2021-04-07 - Allow spatie/temporary-directory v2 ## 1.10.3 - 2021-03-10 - Bump league/glide to 2.0 [#123](https://github.com/spatie/image/pull/123) ## 1.10.2 - 2020-01-26 - change condition to delete $conversionResultDirectory (#118) ## 1.10.1 - 2020-12-27 - adds zoom option to focalCrop (#112) ## 1.9.0 - 2020-11-13 - allow usage of a custom `OptimizerChain` #110 ## 1.8.1 - 2020-11-12 - revert changes from 1.8.0 ## 1.8.0 - 2020-11-12 - allow usage of a custom `OptimizerChain` (#108) ## 1.7.7 - 2020-11-12 - add support for PHP 8 ## 1.7.6 - 2020-01-26 - change uppercase function to mb_strtoupper instead of strtoupper (#99) ## 1.7.5 - 2019-11-23 - allow symfony 5 components ## 1.7.4 - 2019-08-28 - do not export docs ## 1.7.3 - 2019-08-03 - fix duplicated files (fixes #84) ## 1.7.2 - 2019-05-13 - fixes `optimize()` when used with `apply()` (#78) ## 1.7.1 - 2019-04-17 - change GlideConversion sequence (#76) ## 1.7.0 - 2019-02-22 - add support for `webp` ## 1.6.0 - 2019-01-27 - add `setTemporaryDirectory` ## 1.5.3 - 2019-01-10 - update lower deps ## 1.5.2 - 2018-05-05 - fix exception message ## 1.5.1 - 2018-04-18 - Prevent error when trying to remove `/tmp` ## 1.5.0 - 2018-04-13 - add `flip` ## 1.4.2 - 2018-04-11 - Use the correct driver for getting widths and height of images. ## 1.4.1 - 2018-02-08 - Support symfony ^4.0 - Support phpunit ^7.0 ## 1.4.0 - 2017-12-05 - add `getWidth` and `getHeight` ## 1.3.5 - 2017-12-04 - fix for problems when creating directories in the temporary directory ## 1.3.4 - 2017-07-25 - fix `optimize` docblock ## 1.3.3 - 2017-07-11 - make `optimize` method fluent ## 1.3.2 - 2017-07-05 - swap out underlying optimization package ## 1.3.1 - 2017-07-02 - internally treat `optimize` as a manipulation ## 1.3.0 - 2017-07-02 - add `optimize` method ## 1.2.1 - 2017-06-29 - add methods to determine emptyness to `Manipulations` and `ManipulationSequence` ## 1.2.0 - 2017-04-17 - allow `Manipulations` to be constructed with an array of arrays ## 1.1.3 - 2017-04-07 - improve support for multi-volume systems ## 1.1.2 - 2017-04-04 - remove conversion directory after converting image ## 1.1.1 - 2017-03-17 - avoid processing empty manipulations groups ## 1.1.0 - 2017-02-06 - added support for watermarks ## 1.0.0 - 2017-02-06 - initial release src/Intervention/Image/AbstractDriver.php 0000644 00000006505 15111232401 0014465 0 ustar 00 <?php namespace Intervention\Image; use Intervention\Image\Exception\NotSupportedException; abstract class AbstractDriver { /** * Decoder instance to init images from * * @var \Intervention\Image\AbstractDecoder */ public $decoder; /** * Image encoder instance * * @var \Intervention\Image\AbstractEncoder */ public $encoder; /** * Creates new image instance * * @param int $width * @param int $height * @param string $background * @return \Intervention\Image\Image */ abstract public function newImage($width, $height, $background); /** * Reads given string into color object * * @param string $value * @return AbstractColor */ abstract public function parseColor($value); /** * Checks if core module installation is available * * @return boolean */ abstract protected function coreAvailable(); /** * Returns clone of given core * * @return mixed */ public function cloneCore($core) { return clone $core; } /** * Initiates new image from given input * * @param mixed $data * @return \Intervention\Image\Image */ public function init($data) { return $this->decoder->init($data); } /** * Encodes given image * * @param Image $image * @param string $format * @param int $quality * @return \Intervention\Image\Image */ public function encode($image, $format, $quality) { return $this->encoder->process($image, $format, $quality); } /** * Executes named command on given image * * @param Image $image * @param string $name * @param array $arguments * @return \Intervention\Image\Commands\AbstractCommand */ public function executeCommand($image, $name, $arguments) { $commandName = $this->getCommandClassName($name); $command = new $commandName($arguments); $command->execute($image); return $command; } /** * Returns classname of given command name * * @param string $name * @return string */ private function getCommandClassName($name) { if (extension_loaded('mbstring')) { $name = mb_strtoupper(mb_substr($name, 0, 1)) . mb_substr($name, 1); } else { $name = strtoupper(substr($name, 0, 1)) . substr($name, 1); } $drivername = $this->getDriverName(); $classnameLocal = sprintf('\Intervention\Image\%s\Commands\%sCommand', $drivername, ucfirst($name)); $classnameGlobal = sprintf('\Intervention\Image\Commands\%sCommand', ucfirst($name)); if (class_exists($classnameLocal)) { return $classnameLocal; } elseif (class_exists($classnameGlobal)) { return $classnameGlobal; } throw new NotSupportedException( "Command ({$name}) is not available for driver ({$drivername})." ); } /** * Returns name of current driver instance * * @return string */ public function getDriverName() { $reflect = new \ReflectionClass($this); $namespace = $reflect->getNamespaceName(); return substr(strrchr($namespace, "\\"), 1); } } src/Intervention/Image/AbstractEncoder.php 0000644 00000014272 15111232402 0014612 0 ustar 00 <?php namespace Intervention\Image; use Intervention\Image\Exception\InvalidArgumentException; use Intervention\Image\Exception\NotSupportedException; abstract class AbstractEncoder { /** * Buffer of encode result data * * @var string */ public $result; /** * Image object to encode * * @var Image */ public $image; /** * Output format of encoder instance * * @var string */ public $format; /** * Output quality of encoder instance * * @var int */ public $quality; /** * Processes and returns encoded image as JPEG string * * @return string */ abstract protected function processJpeg(); /** * Processes and returns encoded image as PNG string * * @return string */ abstract protected function processPng(); /** * Processes and returns encoded image as GIF string * * @return string */ abstract protected function processGif(); /** * Processes and returns encoded image as TIFF string * * @return string */ abstract protected function processTiff(); /** * Processes and returns encoded image as BMP string * * @return string */ abstract protected function processBmp(); /** * Processes and returns encoded image as ICO string * * @return string */ abstract protected function processIco(); /** * Processes and returns image as WebP encoded string * * @return string */ abstract protected function processWebp(); /** * Processes and returns image as Avif encoded string * * @return string */ abstract protected function processAvif(); /** * Processes and returns image as Heic encoded string * * @return string */ abstract protected function processHeic(); /** * Process a given image * * @param Image $image * @param string $format * @param int $quality * @return Image */ public function process(Image $image, $format = null, $quality = null) { $this->setImage($image); $this->setFormat($format); $this->setQuality($quality); switch (strtolower($this->format)) { case 'data-url': $this->result = $this->processDataUrl(); break; case 'gif': case 'image/gif': $this->result = $this->processGif(); break; case 'png': case 'image/png': case 'image/x-png': $this->result = $this->processPng(); break; case 'jpg': case 'jpeg': case 'jfif': case 'image/jp2': case 'image/jpg': case 'image/jpeg': case 'image/pjpeg': case 'image/jfif': $this->result = $this->processJpeg(); break; case 'tif': case 'tiff': case 'image/tiff': case 'image/tif': case 'image/x-tif': case 'image/x-tiff': $this->result = $this->processTiff(); break; case 'bmp': case 'ms-bmp': case 'x-bitmap': case 'x-bmp': case 'x-ms-bmp': case 'x-win-bitmap': case 'x-windows-bmp': case 'x-xbitmap': case 'image/ms-bmp': case 'image/x-bitmap': case 'image/x-bmp': case 'image/x-ms-bmp': case 'image/x-win-bitmap': case 'image/x-windows-bmp': case 'image/x-xbitmap': $this->result = $this->processBmp(); break; case 'ico': case 'image/x-ico': case 'image/x-icon': case 'image/vnd.microsoft.icon': $this->result = $this->processIco(); break; case 'psd': case 'image/vnd.adobe.photoshop': $this->result = $this->processPsd(); break; case 'webp': case 'image/webp': case 'image/x-webp': $this->result = $this->processWebp(); break; case 'avif': case 'image/avif': $this->result = $this->processAvif(); break; case 'heic': case 'image/heic': case 'image/heif': $this->result = $this->processHeic(); break; default: throw new NotSupportedException( "Encoding format ({$this->format}) is not supported." ); } $this->setImage(null); return $image->setEncoded($this->result); } /** * Processes and returns encoded image as data-url string * * @return string */ protected function processDataUrl() { $mime = $this->image->mime ? $this->image->mime : 'image/png'; return sprintf('data:%s;base64,%s', $mime, base64_encode($this->process($this->image, $mime, $this->quality)) ); } /** * Sets image to process * * @param Image $image */ protected function setImage($image) { $this->image = $image; } /** * Determines output format * * @param string $format */ protected function setFormat($format = null) { if ($format == '' && $this->image instanceof Image) { $format = $this->image->mime; } $this->format = $format ? $format : 'jpg'; return $this; } /** * Determines output quality * * @param int $quality */ protected function setQuality($quality) { $quality = is_null($quality) ? 90 : $quality; $quality = $quality === 0 ? 1 : $quality; if ($quality < 0 || $quality > 100) { throw new InvalidArgumentException( 'Quality must range from 0 to 100.' ); } $this->quality = intval($quality); return $this; } } src/Intervention/Image/Gd/Driver.php 0000644 00000004347 15111232402 0013336 0 ustar 00 <?php namespace Intervention\Image\Gd; use Intervention\Image\Exception\NotSupportedException; use Intervention\Image\Image; class Driver extends \Intervention\Image\AbstractDriver { /** * Creates new instance of driver * * @param Decoder $decoder * @param Encoder $encoder */ public function __construct(Decoder $decoder = null, Encoder $encoder = null) { if ( ! $this->coreAvailable()) { throw new NotSupportedException( "GD Library extension not available with this PHP installation." ); } $this->decoder = $decoder ? $decoder : new Decoder; $this->encoder = $encoder ? $encoder : new Encoder; } /** * Creates new image instance * * @param int $width * @param int $height * @param mixed $background * @return \Intervention\Image\Image */ public function newImage($width, $height, $background = null) { // create empty resource $core = imagecreatetruecolor($width, $height); $image = new Image(new static, $core); // set background color $background = new Color($background); imagefill($image->getCore(), 0, 0, $background->getInt()); return $image; } /** * Reads given string into color object * * @param string $value * @return AbstractColor */ public function parseColor($value) { return new Color($value); } /** * Checks if core module installation is available * * @return boolean */ protected function coreAvailable() { return (extension_loaded('gd') && function_exists('gd_info')); } /** * Returns clone of given core * * @return mixed */ public function cloneCore($core) { $width = imagesx($core); $height = imagesy($core); $clone = imagecreatetruecolor($width, $height); imagealphablending($clone, false); imagesavealpha($clone, true); $transparency = imagecolorallocatealpha($clone, 0, 0, 0, 127); imagefill($clone, 0, 0, $transparency); imagecopy($clone, $core, 0, 0, 0, 0, $width, $height); return $clone; } } src/Intervention/Image/Gd/Encoder.php 0000644 00000010770 15111232402 0013457 0 ustar 00 <?php namespace Intervention\Image\Gd; use Intervention\Image\Exception\NotSupportedException; class Encoder extends \Intervention\Image\AbstractEncoder { /** * Processes and returns encoded image as JPEG string * * @return string */ protected function processJpeg() { ob_start(); imagejpeg($this->image->getCore(), null, $this->quality); $this->image->mime = image_type_to_mime_type(IMAGETYPE_JPEG); $buffer = ob_get_contents(); ob_end_clean(); return $buffer; } /** * Processes and returns encoded image as PNG string * * @return string */ protected function processPng() { ob_start(); $resource = $this->image->getCore(); imagealphablending($resource, false); imagesavealpha($resource, true); imagepng($resource, null, -1); $this->image->mime = image_type_to_mime_type(IMAGETYPE_PNG); $buffer = ob_get_contents(); ob_end_clean(); return $buffer; } /** * Processes and returns encoded image as GIF string * * @return string */ protected function processGif() { ob_start(); imagegif($this->image->getCore()); $this->image->mime = image_type_to_mime_type(IMAGETYPE_GIF); $buffer = ob_get_contents(); ob_end_clean(); return $buffer; } /** * Processes and returns encoded image as WEBP string * * @return string */ protected function processWebp() { if ( ! function_exists('imagewebp')) { throw new NotSupportedException( "Webp format is not supported by PHP installation." ); } ob_start(); imagepalettetotruecolor($this->image->getCore()); imagealphablending($this->image->getCore(), true); imagesavealpha($this->image->getCore(), true); imagewebp($this->image->getCore(), null, $this->quality); $this->image->mime = defined('IMAGETYPE_WEBP') ? image_type_to_mime_type(IMAGETYPE_WEBP) : 'image/webp'; $buffer = ob_get_contents(); ob_end_clean(); return $buffer; } /** * Processes and returns encoded image as TIFF string * * @return string */ protected function processTiff() { throw new NotSupportedException( "TIFF format is not supported by Gd Driver." ); } /** * Processes and returns encoded image as BMP string * * @return string */ protected function processBmp() { if ( ! function_exists('imagebmp')) { throw new NotSupportedException( "BMP format is not supported by PHP installation." ); } ob_start(); imagebmp($this->image->getCore()); $this->image->mime = defined('IMAGETYPE_BMP') ? image_type_to_mime_type(IMAGETYPE_BMP) : 'image/bmp'; $buffer = ob_get_contents(); ob_end_clean(); return $buffer; } /** * Processes and returns encoded image as ICO string * * @return string */ protected function processIco() { throw new NotSupportedException( "ICO format is not supported by Gd Driver." ); } /** * Processes and returns encoded image as PSD string * * @return string */ protected function processPsd() { throw new NotSupportedException( "PSD format is not supported by Gd Driver." ); } /** * Processes and returns encoded image as AVIF string * * @return string */ protected function processAvif() { if ( ! function_exists('imageavif')) { throw new NotSupportedException( "AVIF format is not supported by PHP installation." ); } ob_start(); $resource = $this->image->getCore(); imagepalettetotruecolor($resource); imagealphablending($resource, true); imagesavealpha($resource, true); imageavif($resource, null, $this->quality); $this->image->mime = defined('IMAGETYPE_AVIF') ? image_type_to_mime_type(IMAGETYPE_AVIF) : 'image/avif'; $buffer = ob_get_contents(); ob_end_clean(); return $buffer; } /** * Processes and returns encoded image as HEIC string * * @return string */ protected function processHeic() { throw new NotSupportedException( "HEIC format is not supported by Gd Driver." ); } } src/Intervention/Image/Gd/Shapes/RectangleShape.php 0000644 00000003456 15111232402 0016213 0 ustar 00 <?php namespace Intervention\Image\Gd\Shapes; use Intervention\Image\AbstractShape; use Intervention\Image\Gd\Color; use Intervention\Image\Image; class RectangleShape extends AbstractShape { /** * X-Coordinate of top-left point * * @var int */ public $x1 = 0; /** * Y-Coordinate of top-left point * * @var int */ public $y1 = 0; /** * X-Coordinate of bottom-right point * * @var int */ public $x2 = 0; /** * Y-Coordinate of bottom-right point * * @var int */ public $y2 = 0; /** * Create new rectangle shape instance * * @param int $x1 * @param int $y1 * @param int $x2 * @param int $y2 */ public function __construct($x1 = null, $y1 = null, $x2 = null, $y2 = null) { $this->x1 = is_numeric($x1) ? intval($x1) : $this->x1; $this->y1 = is_numeric($y1) ? intval($y1) : $this->y1; $this->x2 = is_numeric($x2) ? intval($x2) : $this->x2; $this->y2 = is_numeric($y2) ? intval($y2) : $this->y2; } /** * Draw rectangle to given image at certain position * * @param Image $image * @param int $x * @param int $y * @return boolean */ public function applyToImage(Image $image, $x = 0, $y = 0) { $background = new Color($this->background); imagefilledrectangle($image->getCore(), $this->x1, $this->y1, $this->x2, $this->y2, $background->getInt()); if ($this->hasBorder()) { $border_color = new Color($this->border_color); imagesetthickness($image->getCore(), $this->border_width); imagerectangle($image->getCore(), $this->x1, $this->y1, $this->x2, $this->y2, $border_color->getInt()); } return true; } } src/Intervention/Image/Gd/Shapes/PolygonShape.php 0000644 00000002260 15111232402 0015726 0 ustar 00 <?php namespace Intervention\Image\Gd\Shapes; use Intervention\Image\AbstractShape; use Intervention\Image\Gd\Color; use Intervention\Image\Image; class PolygonShape extends AbstractShape { /** * Array of points of polygon * * @var int */ public $points; /** * Create new polygon instance * * @param array $points */ public function __construct($points) { $this->points = $points; } /** * Draw polygon on given image * * @param Image $image * @param int $x * @param int $y * @return boolean */ public function applyToImage(Image $image, $x = 0, $y = 0) { $background = new Color($this->background); imagefilledpolygon($image->getCore(), $this->points, intval(count($this->points) / 2), $background->getInt()); if ($this->hasBorder()) { $border_color = new Color($this->border_color); imagesetthickness($image->getCore(), $this->border_width); imagepolygon($image->getCore(), $this->points, intval(count($this->points) / 2), $border_color->getInt()); } return true; } } src/Intervention/Image/Gd/Shapes/LineShape.php 0000644 00000003350 15111232402 0015167 0 ustar 00 <?php namespace Intervention\Image\Gd\Shapes; use Intervention\Image\AbstractShape; use Intervention\Image\Gd\Color; use Intervention\Image\Image; class LineShape extends AbstractShape { /** * Starting point x-coordinate of line * * @var int */ public $x = 0; /** * Starting point y-coordinate of line * * @var int */ public $y = 0; /** * Color of line * * @var string */ public $color = '#000000'; /** * Width of line in pixels * * @var int */ public $width = 1; /** * Create new line shape instance * * @param int $x * @param int $y */ public function __construct($x = null, $y = null) { $this->x = is_numeric($x) ? intval($x) : $this->x; $this->y = is_numeric($y) ? intval($y) : $this->y; } /** * Set current line color * * @param string $color * @return void */ public function color($color) { $this->color = $color; } /** * Set current line width in pixels * * @param int $width * @return void */ public function width($width) { throw new \Intervention\Image\Exception\NotSupportedException( "Line width is not supported by GD driver." ); } /** * Draw current instance of line to given endpoint on given image * * @param Image $image * @param int $x * @param int $y * @return boolean */ public function applyToImage(Image $image, $x = 0, $y = 0) { $color = new Color($this->color); imageline($image->getCore(), $x, $y, $this->x, $this->y, $color->getInt()); return true; } } src/Intervention/Image/Gd/Shapes/EllipseShape.php 0000644 00000003416 15111232402 0015700 0 ustar 00 <?php namespace Intervention\Image\Gd\Shapes; use Intervention\Image\AbstractShape; use Intervention\Image\Gd\Color; use Intervention\Image\Image; class EllipseShape extends AbstractShape { /** * Width of ellipse in pixels * * @var int */ public $width = 100; /** * Height of ellipse in pixels * * @var int */ public $height = 100; /** * Create new ellipse instance * * @param int $width * @param int $height */ public function __construct($width = null, $height = null) { $this->width = is_numeric($width) ? intval($width) : $this->width; $this->height = is_numeric($height) ? intval($height) : $this->height; } /** * Draw ellipse instance on given image * * @param Image $image * @param int $x * @param int $y * @return boolean */ public function applyToImage(Image $image, $x = 0, $y = 0) { // parse background color $background = new Color($this->background); if ($this->hasBorder()) { // slightly smaller ellipse to keep 1px bordered edges clean imagefilledellipse($image->getCore(), $x, $y, $this->width-1, $this->height-1, $background->getInt()); $border_color = new Color($this->border_color); imagesetthickness($image->getCore(), $this->border_width); // gd's imageellipse doesn't respect imagesetthickness so i use imagearc with 359.9 degrees here imagearc($image->getCore(), $x, $y, $this->width, $this->height, 0, 359.99, $border_color->getInt()); } else { imagefilledellipse($image->getCore(), $x, $y, $this->width, $this->height, $background->getInt()); } return true; } } src/Intervention/Image/Gd/Shapes/CircleShape.php 0000644 00000001643 15111232402 0015504 0 ustar 00 <?php namespace Intervention\Image\Gd\Shapes; use Intervention\Image\Image; class CircleShape extends EllipseShape { /** * Diameter of circle in pixels * * @var int */ public $diameter = 100; /** * Create new instance of circle * * @param int $diameter */ public function __construct($diameter = null) { $this->width = is_numeric($diameter) ? intval($diameter) : $this->diameter; $this->height = is_numeric($diameter) ? intval($diameter) : $this->diameter; $this->diameter = is_numeric($diameter) ? intval($diameter) : $this->diameter; } /** * Draw current circle on given image * * @param Image $image * @param int $x * @param int $y * @return boolean */ public function applyToImage(Image $image, $x = 0, $y = 0) { return parent::applyToImage($image, $x, $y); } } src/Intervention/Image/Gd/Commands/WidenCommand.php 0000644 00000001433 15111232402 0016202 0 ustar 00 <?php namespace Intervention\Image\Gd\Commands; class WidenCommand extends ResizeCommand { /** * Resize image proportionally to given width * * @param \Intervention\Image\Image $image * @return boolean */ public function execute($image) { $width = $this->argument(0)->type('digit')->required()->value(); $additionalConstraints = $this->argument(1)->type('closure')->value(); $this->arguments[0] = $width; $this->arguments[1] = null; $this->arguments[2] = function ($constraint) use ($additionalConstraints) { $constraint->aspectRatio(); if(is_callable($additionalConstraints)) $additionalConstraints($constraint); }; return parent::execute($image); } } src/Intervention/Image/Gd/Commands/TrimCommand.php 0000644 00000011747 15111232402 0016060 0 ustar 00 <?php namespace Intervention\Image\Gd\Commands; use Intervention\Image\Gd\Color; class TrimCommand extends ResizeCommand { /** * Trims away parts of an image * * @param \Intervention\Image\Image $image * @return boolean */ public function execute($image) { $base = $this->argument(0)->type('string')->value(); $away = $this->argument(1)->value(); $tolerance = $this->argument(2)->type('numeric')->value(0); $feather = $this->argument(3)->type('numeric')->value(0); $width = $image->getWidth(); $height = $image->getHeight(); // default values $checkTransparency = false; // define borders to trim away if (is_null($away)) { $away = ['top', 'right', 'bottom', 'left']; } elseif (is_string($away)) { $away = [$away]; } // lower border names foreach ($away as $key => $value) { $away[$key] = strtolower($value); } // define base color position switch (strtolower($base)) { case 'transparent': case 'trans': $checkTransparency = true; $base_x = 0; $base_y = 0; break; case 'bottom-right': case 'right-bottom': $base_x = $width - 1; $base_y = $height - 1; break; default: case 'top-left': case 'left-top': $base_x = 0; $base_y = 0; break; } // pick base color if ($checkTransparency) { $color = new Color; // color will only be used to compare alpha channel } else { $color = $image->pickColor($base_x, $base_y, 'object'); } $top_x = 0; $top_y = 0; $bottom_x = $width; $bottom_y = $height; // search upper part of image for colors to trim away if (in_array('top', $away)) { for ($y=0; $y < ceil($height/2); $y++) { for ($x=0; $x < $width; $x++) { $checkColor = $image->pickColor($x, $y, 'object'); if ($checkTransparency) { $checkColor->r = $color->r; $checkColor->g = $color->g; $checkColor->b = $color->b; } if ($color->differs($checkColor, $tolerance)) { $top_y = max(0, $y - $feather); break 2; } } } } // search left part of image for colors to trim away if (in_array('left', $away)) { for ($x=0; $x < ceil($width/2); $x++) { for ($y=$top_y; $y < $height; $y++) { $checkColor = $image->pickColor($x, $y, 'object'); if ($checkTransparency) { $checkColor->r = $color->r; $checkColor->g = $color->g; $checkColor->b = $color->b; } if ($color->differs($checkColor, $tolerance)) { $top_x = max(0, $x - $feather); break 2; } } } } // search lower part of image for colors to trim away if (in_array('bottom', $away)) { for ($y=($height-1); $y >= floor($height/2)-1; $y--) { for ($x=$top_x; $x < $width; $x++) { $checkColor = $image->pickColor($x, $y, 'object'); if ($checkTransparency) { $checkColor->r = $color->r; $checkColor->g = $color->g; $checkColor->b = $color->b; } if ($color->differs($checkColor, $tolerance)) { $bottom_y = min($height, $y+1 + $feather); break 2; } } } } // search right part of image for colors to trim away if (in_array('right', $away)) { for ($x=($width-1); $x >= floor($width/2)-1; $x--) { for ($y=$top_y; $y < $bottom_y; $y++) { $checkColor = $image->pickColor($x, $y, 'object'); if ($checkTransparency) { $checkColor->r = $color->r; $checkColor->g = $color->g; $checkColor->b = $color->b; } if ($color->differs($checkColor, $tolerance)) { $bottom_x = min($width, $x+1 + $feather); break 2; } } } } // trim parts of image return $this->modify($image, 0, 0, $top_x, $top_y, ($bottom_x-$top_x), ($bottom_y-$top_y), ($bottom_x-$top_x), ($bottom_y-$top_y)); } } src/Intervention/Image/Gd/Commands/RotateCommand.php 0000644 00000001401 15111232402 0016365 0 ustar 00 <?php namespace Intervention\Image\Gd\Commands; use Intervention\Image\Commands\AbstractCommand; use Intervention\Image\Gd\Color; class RotateCommand extends AbstractCommand { /** * Rotates image counter clockwise * * @param \Intervention\Image\Image $image * @return boolean */ public function execute($image) { $angle = $this->argument(0)->type('numeric')->required()->value(); $color = $this->argument(1)->value(); $color = new Color($color); // restrict rotations beyond 360 degrees, since the end result is the same $angle = fmod($angle, 360); // rotate image $image->setCore(imagerotate($image->getCore(), $angle, $color->getInt())); return true; } } src/Intervention/Image/Gd/Commands/BrightnessCommand.php 0000644 00000000754 15111232402 0017251 0 ustar 00 <?php namespace Intervention\Image\Gd\Commands; use Intervention\Image\Commands\AbstractCommand; class BrightnessCommand extends AbstractCommand { /** * Changes image brightness * * @param \Intervention\Image\Image $image * @return boolean */ public function execute($image) { $level = $this->argument(0)->between(-100, 100)->required()->value(); return imagefilter($image->getCore(), IMG_FILTER_BRIGHTNESS, ($level * 2.55)); } } src/Intervention/Image/Gd/Commands/FlipCommand.php 0000644 00000001642 15111232402 0016030 0 ustar 00 <?php namespace Intervention\Image\Gd\Commands; class FlipCommand extends ResizeCommand { /** * Mirrors an image * * @param \Intervention\Image\Image $image * @return boolean */ public function execute($image) { $mode = $this->argument(0)->value('h'); $size = $image->getSize(); $dst = clone $size; switch (strtolower($mode)) { case 2: case 'v': case 'vert': case 'vertical': $size->pivot->y = $size->height - 1; $size->height = $size->height * (-1); break; default: $size->pivot->x = $size->width - 1; $size->width = $size->width * (-1); break; } return $this->modify($image, 0, 0, $size->pivot->x, $size->pivot->y, $dst->width, $dst->height, $size->width, $size->height); } } src/Intervention/Image/Gd/Commands/SharpenCommand.php 0000644 00000001415 15111232402 0016534 0 ustar 00 <?php namespace Intervention\Image\Gd\Commands; use Intervention\Image\Commands\AbstractCommand; class SharpenCommand extends AbstractCommand { /** * Sharpen image * * @param \Intervention\Image\Image $image * @return boolean */ public function execute($image) { $amount = $this->argument(0)->between(0, 100)->value(10); // build matrix $min = $amount >= 10 ? $amount * -0.01 : 0; $max = $amount * -0.025; $abs = ((4 * $min + 4 * $max) * -1) + 1; $div = 1; $matrix = [ [$min, $max, $min], [$max, $abs, $max], [$min, $max, $min] ]; // apply the matrix return imageconvolution($image->getCore(), $matrix, $div, 0); } } src/Intervention/Image/Gd/Commands/GreyscaleCommand.php 0000644 00000000631 15111232402 0017051 0 ustar 00 <?php namespace Intervention\Image\Gd\Commands; use Intervention\Image\Commands\AbstractCommand; class GreyscaleCommand extends AbstractCommand { /** * Turns an image into a greyscale version * * @param \Intervention\Image\Image $image * @return boolean */ public function execute($image) { return imagefilter($image->getCore(), IMG_FILTER_GRAYSCALE); } } src/Intervention/Image/Gd/Commands/InvertCommand.php 0000644 00000000606 15111232402 0016404 0 ustar 00 <?php namespace Intervention\Image\Gd\Commands; use Intervention\Image\Commands\AbstractCommand; class InvertCommand extends AbstractCommand { /** * Inverts colors of an image * * @param \Intervention\Image\Image $image * @return boolean */ public function execute($image) { return imagefilter($image->getCore(), IMG_FILTER_NEGATE); } } src/Intervention/Image/Gd/Commands/ColorizeCommand.php 0000644 00000001511 15111232402 0016717 0 ustar 00 <?php namespace Intervention\Image\Gd\Commands; use Intervention\Image\Commands\AbstractCommand; class ColorizeCommand extends AbstractCommand { /** * Changes balance of different RGB color channels * * @param \Intervention\Image\Image $image * @return boolean */ public function execute($image) { $red = $this->argument(0)->between(-100, 100)->required()->value(); $green = $this->argument(1)->between(-100, 100)->required()->value(); $blue = $this->argument(2)->between(-100, 100)->required()->value(); // normalize colorize levels $red = round($red * 2.55); $green = round($green * 2.55); $blue = round($blue * 2.55); // apply filter return imagefilter($image->getCore(), IMG_FILTER_COLORIZE, $red, $green, $blue); } } src/Intervention/Image/Gd/Commands/HeightenCommand.php 0000644 00000001441 15111232402 0016666 0 ustar 00 <?php namespace Intervention\Image\Gd\Commands; class HeightenCommand extends ResizeCommand { /** * Resize image proportionally to given height * * @param \Intervention\Image\Image $image * @return boolean */ public function execute($image) { $height = $this->argument(0)->type('digit')->required()->value(); $additionalConstraints = $this->argument(1)->type('closure')->value(); $this->arguments[0] = null; $this->arguments[1] = $height; $this->arguments[2] = function ($constraint) use ($additionalConstraints) { $constraint->aspectRatio(); if(is_callable($additionalConstraints)) $additionalConstraints($constraint); }; return parent::execute($image); } } src/Intervention/Image/Gd/Commands/PixelateCommand.php 0000644 00000000750 15111232402 0016710 0 ustar 00 <?php namespace Intervention\Image\Gd\Commands; use Intervention\Image\Commands\AbstractCommand; class PixelateCommand extends AbstractCommand { /** * Applies a pixelation effect to a given image * * @param \Intervention\Image\Image $image * @return boolean */ public function execute($image) { $size = $this->argument(0)->type('digit')->value(10); return imagefilter($image->getCore(), IMG_FILTER_PIXELATE, $size, true); } } src/Intervention/Image/Gd/Commands/ContrastCommand.php 0000644 00000000747 15111232402 0016740 0 ustar 00 <?php namespace Intervention\Image\Gd\Commands; use Intervention\Image\Commands\AbstractCommand; class ContrastCommand extends AbstractCommand { /** * Changes contrast of image * * @param \Intervention\Image\Image $image * @return boolean */ public function execute($image) { $level = $this->argument(0)->between(-100, 100)->required()->value(); return imagefilter($image->getCore(), IMG_FILTER_CONTRAST, ($level * -1)); } } src/Intervention/Image/Gd/Commands/InsertCommand.php 0000644 00000002154 15111232402 0016401 0 ustar 00 <?php namespace Intervention\Image\Gd\Commands; use Intervention\Image\Commands\AbstractCommand; class InsertCommand extends AbstractCommand { /** * Insert another image into given image * * @param \Intervention\Image\Image $image * @return boolean */ public function execute($image) { $source = $this->argument(0)->required()->value(); $position = $this->argument(1)->type('string')->value(); $x = $this->argument(2)->type('digit')->value(0); $y = $this->argument(3)->type('digit')->value(0); // build watermark $watermark = $image->getDriver()->init($source); // define insertion point $image_size = $image->getSize()->align($position, $x, $y); $watermark_size = $watermark->getSize()->align($position); $target = $image_size->relativePosition($watermark_size); // insert image at position imagealphablending($image->getCore(), true); return imagecopy($image->getCore(), $watermark->getCore(), $target->x, $target->y, 0, 0, $watermark_size->width, $watermark_size->height); } } src/Intervention/Image/Gd/Commands/ResizeCommand.php 0000644 00000004464 15111232402 0016404 0 ustar 00 <?php namespace Intervention\Image\Gd\Commands; use Intervention\Image\Commands\AbstractCommand; class ResizeCommand extends AbstractCommand { /** * Resizes image dimensions * * @param \Intervention\Image\Image $image * @return boolean */ public function execute($image) { $width = $this->argument(0)->value(); $height = $this->argument(1)->value(); $constraints = $this->argument(2)->type('closure')->value(); // resize box $resized = $image->getSize()->resize($width, $height, $constraints); // modify image $this->modify($image, 0, 0, 0, 0, $resized->getWidth(), $resized->getHeight(), $image->getWidth(), $image->getHeight()); return true; } /** * Wrapper function for 'imagecopyresampled' * * @param Image $image * @param int $dst_x * @param int $dst_y * @param int $src_x * @param int $src_y * @param int $dst_w * @param int $dst_h * @param int $src_w * @param int $src_h * @return boolean */ protected function modify($image, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h) { // create new image $modified = imagecreatetruecolor(intval($dst_w), intval($dst_h)); // get current image $resource = $image->getCore(); // preserve transparency $transIndex = imagecolortransparent($resource); if ($transIndex != -1) { $rgba = imagecolorsforindex($modified, $transIndex); $transColor = imagecolorallocatealpha($modified, $rgba['red'], $rgba['green'], $rgba['blue'], 127); imagefill($modified, 0, 0, $transColor); imagecolortransparent($modified, $transColor); } else { imagealphablending($modified, false); imagesavealpha($modified, true); } // copy content from resource $result = imagecopyresampled( $modified, $resource, $dst_x, $dst_y, $src_x, $src_y, intval($dst_w), intval($dst_h), $src_w, $src_h ); // set new content as recource $image->setCore($modified); return $result; } } src/Intervention/Image/Gd/Commands/CropCommand.php 0000644 00000002335 15111232402 0016041 0 ustar 00 <?php namespace Intervention\Image\Gd\Commands; use Intervention\Image\Point; use Intervention\Image\Size; class CropCommand extends ResizeCommand { /** * Crop an image instance * * @param \Intervention\Image\Image $image * @return boolean */ public function execute($image) { $width = $this->argument(0)->type('digit')->required()->value(); $height = $this->argument(1)->type('digit')->required()->value(); $x = $this->argument(2)->type('digit')->value(); $y = $this->argument(3)->type('digit')->value(); if (is_null($width) || is_null($height)) { throw new \Intervention\Image\Exception\InvalidArgumentException( "Width and height of cutout needs to be defined." ); } $cropped = new Size($width, $height); $position = new Point($x, $y); // align boxes if (is_null($x) && is_null($y)) { $position = $image->getSize()->align('center')->relativePosition($cropped->align('center')); } // crop image core return $this->modify($image, 0, 0, $position->x, $position->y, $cropped->width, $cropped->height, $cropped->width, $cropped->height); } } src/Intervention/Image/Gd/Commands/ResizeCanvasCommand.php 0000644 00000005471 15111232402 0017537 0 ustar 00 <?php namespace Intervention\Image\Gd\Commands; use Intervention\Image\Commands\AbstractCommand; class ResizeCanvasCommand extends AbstractCommand { /** * Resizes image boundaries * * @param \Intervention\Image\Image $image * @return boolean */ public function execute($image) { $width = $this->argument(0)->type('digit')->required()->value(); $height = $this->argument(1)->type('digit')->required()->value(); $anchor = $this->argument(2)->value('center'); $relative = $this->argument(3)->type('boolean')->value(false); $bgcolor = $this->argument(4)->value(); $original_width = $image->getWidth(); $original_height = $image->getHeight(); // check of only width or height is set $width = is_null($width) ? $original_width : intval($width); $height = is_null($height) ? $original_height : intval($height); // check on relative width/height if ($relative) { $width = $original_width + $width; $height = $original_height + $height; } // check for negative width/height $width = ($width <= 0) ? $width + $original_width : $width; $height = ($height <= 0) ? $height + $original_height : $height; // create new canvas $canvas = $image->getDriver()->newImage($width, $height, $bgcolor); // set copy position $canvas_size = $canvas->getSize()->align($anchor); $image_size = $image->getSize()->align($anchor); $canvas_pos = $image_size->relativePosition($canvas_size); $image_pos = $canvas_size->relativePosition($image_size); if ($width <= $original_width) { $dst_x = 0; $src_x = $canvas_pos->x; $src_w = $canvas_size->width; } else { $dst_x = $image_pos->x; $src_x = 0; $src_w = $original_width; } if ($height <= $original_height) { $dst_y = 0; $src_y = $canvas_pos->y; $src_h = $canvas_size->height; } else { $dst_y = $image_pos->y; $src_y = 0; $src_h = $original_height; } // make image area transparent to keep transparency // even if background-color is set $transparent = imagecolorallocatealpha($canvas->getCore(), 255, 255, 255, 127); imagealphablending($canvas->getCore(), false); // do not blend / just overwrite imagefilledrectangle($canvas->getCore(), $dst_x, $dst_y, $dst_x + $src_w - 1, $dst_y + $src_h - 1, $transparent); // copy image into new canvas imagecopy($canvas->getCore(), $image->getCore(), $dst_x, $dst_y, $src_x, $src_y, $src_w, $src_h); // set new core to canvas $image->setCore($canvas->getCore()); return true; } } src/Intervention/Image/Gd/Commands/ResetCommand.php 0000644 00000001707 15111232402 0016222 0 ustar 00 <?php namespace Intervention\Image\Gd\Commands; use Intervention\Image\Commands\AbstractCommand; use Intervention\Image\Exception\RuntimeException; class ResetCommand extends AbstractCommand { /** * Resets given image to its backup state * * @param \Intervention\Image\Image $image * @return boolean */ public function execute($image) { $backupName = $this->argument(0)->value(); $backup = $image->getBackup($backupName); if (is_resource($backup) || $backup instanceof \GdImage) { // destroy current resource imagedestroy($image->getCore()); // clone backup $backup = $image->getDriver()->cloneCore($backup); // reset to new resource $image->setCore($backup); return true; } throw new RuntimeException( "Backup not available. Call backup() before reset()." ); } } src/Intervention/Image/Gd/Commands/BlurCommand.php 0000644 00000001035 15111232402 0016036 0 ustar 00 <?php namespace Intervention\Image\Gd\Commands; use Intervention\Image\Commands\AbstractCommand; class BlurCommand extends AbstractCommand { /** * Applies blur effect on image * * @param \Intervention\Image\Image $image * @return boolean */ public function execute($image) { $amount = $this->argument(0)->between(0, 100)->value(1); for ($i=0; $i < intval($amount); $i++) { imagefilter($image->getCore(), IMG_FILTER_GAUSSIAN_BLUR); } return true; } } src/Intervention/Image/Gd/Commands/DestroyCommand.php 0000644 00000001064 15111232402 0016565 0 ustar 00 <?php namespace Intervention\Image\Gd\Commands; use Intervention\Image\Commands\AbstractCommand; class DestroyCommand extends AbstractCommand { /** * Destroys current image core and frees up memory * * @param \Intervention\Image\Image $image * @return boolean */ public function execute($image) { // destroy image core imagedestroy($image->getCore()); // destroy backups foreach ($image->getBackups() as $backup) { imagedestroy($backup); } return true; } } src/Intervention/Image/Gd/Commands/MaskCommand.php 0000644 00000004663 15111232402 0016037 0 ustar 00 <?php namespace Intervention\Image\Gd\Commands; use Intervention\Image\Commands\AbstractCommand; class MaskCommand extends AbstractCommand { /** * Applies an alpha mask to an image * * @param \Intervention\Image\Image $image * @return boolean */ public function execute($image) { $mask_source = $this->argument(0)->value(); $mask_w_alpha = $this->argument(1)->type('bool')->value(false); $image_size = $image->getSize(); // create empty canvas $canvas = $image->getDriver()->newImage($image_size->width, $image_size->height, [0,0,0,0]); // build mask image from source $mask = $image->getDriver()->init($mask_source); $mask_size = $mask->getSize(); // resize mask to size of current image (if necessary) if ($mask_size != $image_size) { $mask->resize($image_size->width, $image_size->height); } imagealphablending($canvas->getCore(), false); if ( ! $mask_w_alpha) { // mask from greyscale image imagefilter($mask->getCore(), IMG_FILTER_GRAYSCALE); } // redraw old image pixel by pixel considering alpha map for ($x=0; $x < $image_size->width; $x++) { for ($y=0; $y < $image_size->height; $y++) { $color = $image->pickColor($x, $y, 'array'); $alpha = $mask->pickColor($x, $y, 'array'); if ($mask_w_alpha) { $alpha = $alpha[3]; // use alpha channel as mask } else { if ($alpha[3] == 0) { // transparent as black $alpha = 0; } else { // $alpha = floatval(round((($alpha[0] + $alpha[1] + $alpha[3]) / 3) / 255, 2)); // image is greyscale, so channel doesn't matter (use red channel) $alpha = floatval(round($alpha[0] / 255, 2)); } } // preserve alpha of original image... if ($color[3] < $alpha) { $alpha = $color[3]; } // replace alpha value $color[3] = $alpha; // redraw pixel $canvas->pixel($color, $x, $y); } } // replace current image with masked instance $image->setCore($canvas->getCore()); return true; } } src/Intervention/Image/Gd/Commands/LimitColorsCommand.php 0000644 00000002533 15111232402 0017376 0 ustar 00 <?php namespace Intervention\Image\Gd\Commands; use Intervention\Image\Commands\AbstractCommand; class LimitColorsCommand extends AbstractCommand { /** * Reduces colors of a given image * * @param \Intervention\Image\Image $image * @return boolean */ public function execute($image) { $count = $this->argument(0)->value(); $matte = $this->argument(1)->value(); // get current image size $size = $image->getSize(); // create empty canvas $resource = imagecreatetruecolor($size->width, $size->height); // define matte if (is_null($matte)) { $matte = imagecolorallocatealpha($resource, 255, 255, 255, 127); } else { $matte = $image->getDriver()->parseColor($matte)->getInt(); } // fill with matte and copy original image imagefill($resource, 0, 0, $matte); // set transparency imagecolortransparent($resource, $matte); // copy original image imagecopy($resource, $image->getCore(), 0, 0, 0, 0, $size->width, $size->height); if (is_numeric($count) && $count <= 256) { // decrease colors imagetruecolortopalette($resource, true, $count); } // set new resource $image->setCore($resource); return true; } } src/Intervention/Image/Gd/Commands/PixelCommand.php 0000644 00000001236 15111232402 0016216 0 ustar 00 <?php namespace Intervention\Image\Gd\Commands; use Intervention\Image\Commands\AbstractCommand; use Intervention\Image\Gd\Color; class PixelCommand extends AbstractCommand { /** * Draws one pixel to a given image * * @param \Intervention\Image\Image $image * @return boolean */ public function execute($image) { $color = $this->argument(0)->required()->value(); $color = new Color($color); $x = $this->argument(1)->type('digit')->required()->value(); $y = $this->argument(2)->type('digit')->required()->value(); return imagesetpixel($image->getCore(), $x, $y, $color->getInt()); } } src/Intervention/Image/Gd/Commands/InterlaceCommand.php 0000644 00000000725 15111232402 0017045 0 ustar 00 <?php namespace Intervention\Image\Gd\Commands; use Intervention\Image\Commands\AbstractCommand; class InterlaceCommand extends AbstractCommand { /** * Toggles interlaced encoding mode * * @param \Intervention\Image\Image $image * @return boolean */ public function execute($image) { $mode = $this->argument(0)->type('bool')->value(true); imageinterlace($image->getCore(), $mode); return true; } } src/Intervention/Image/Gd/Commands/FitCommand.php 0000644 00000002000 15111232402 0015645 0 ustar 00 <?php namespace Intervention\Image\Gd\Commands; use Intervention\Image\Size; class FitCommand extends ResizeCommand { /** * Crops and resized an image at the same time * * @param \Intervention\Image\Image $image * @return boolean */ public function execute($image) { $width = $this->argument(0)->type('digit')->required()->value(); $height = $this->argument(1)->type('digit')->value($width); $constraints = $this->argument(2)->type('closure')->value(); $position = $this->argument(3)->type('string')->value('center'); // calculate size $cropped = $image->getSize()->fit(new Size($width, $height), $position); $resized = clone $cropped; $resized = $resized->resize($width, $height, $constraints); // modify image $this->modify($image, 0, 0, $cropped->pivot->x, $cropped->pivot->y, $resized->getWidth(), $resized->getHeight(), $cropped->getWidth(), $cropped->getHeight()); return true; } } src/Intervention/Image/Gd/Commands/OpacityCommand.php 0000644 00000001372 15111232402 0016546 0 ustar 00 <?php namespace Intervention\Image\Gd\Commands; use Intervention\Image\Commands\AbstractCommand; class OpacityCommand extends AbstractCommand { /** * Defines opacity of an image * * @param \Intervention\Image\Image $image * @return boolean */ public function execute($image) { $transparency = $this->argument(0)->between(0, 100)->required()->value(); // get size of image $size = $image->getSize(); // build temp alpha mask $mask_color = sprintf('rgba(0, 0, 0, %.1F)', $transparency / 100); $mask = $image->getDriver()->newImage($size->width, $size->height, $mask_color); // mask image $image->mask($mask->getCore(), true); return true; } } src/Intervention/Image/Gd/Commands/PickColorCommand.php 0000644 00000001761 15111232402 0017025 0 ustar 00 <?php namespace Intervention\Image\Gd\Commands; use Intervention\Image\Commands\AbstractCommand; use Intervention\Image\Gd\Color; class PickColorCommand extends AbstractCommand { /** * Read color information from a certain position * * @param \Intervention\Image\Image $image * @return boolean */ public function execute($image) { $x = $this->argument(0)->type('digit')->required()->value(); $y = $this->argument(1)->type('digit')->required()->value(); $format = $this->argument(2)->type('string')->value('array'); // pick color $color = imagecolorat($image->getCore(), $x, $y); if ( ! imageistruecolor($image->getCore())) { $color = imagecolorsforindex($image->getCore(), $color); $color['alpha'] = round(1 - $color['alpha'] / 127, 2); } $color = new Color($color); // format to output $this->setOutput($color->format($format)); return true; } } src/Intervention/Image/Gd/Commands/GammaCommand.php 0000644 00000000736 15111232402 0016163 0 ustar 00 <?php namespace Intervention\Image\Gd\Commands; use Intervention\Image\Commands\AbstractCommand; class GammaCommand extends AbstractCommand { /** * Applies gamma correction to a given image * * @param \Intervention\Image\Image $image * @return boolean */ public function execute($image) { $gamma = $this->argument(0)->type('numeric')->required()->value(); return imagegammacorrect($image->getCore(), 1, $gamma); } } src/Intervention/Image/Gd/Commands/FillCommand.php 0000644 00000003724 15111232402 0016027 0 ustar 00 <?php namespace Intervention\Image\Gd\Commands; use Intervention\Image\Commands\AbstractCommand; use Intervention\Image\Gd\Color; use Intervention\Image\Gd\Decoder; class FillCommand extends AbstractCommand { /** * Fills image with color or pattern * * @param \Intervention\Image\Image $image * @return boolean */ public function execute($image) { $filling = $this->argument(0)->value(); $x = $this->argument(1)->type('digit')->value(); $y = $this->argument(2)->type('digit')->value(); $width = $image->getWidth(); $height = $image->getHeight(); $resource = $image->getCore(); try { // set image tile filling $source = new Decoder; $tile = $source->init($filling); imagesettile($image->getCore(), $tile->getCore()); $filling = IMG_COLOR_TILED; } catch (\Intervention\Image\Exception\NotReadableException $e) { // set solid color filling $color = new Color($filling); $filling = $color->getInt(); } imagealphablending($resource, true); if (is_int($x) && is_int($y)) { // resource should be visible through transparency $base = $image->getDriver()->newImage($width, $height)->getCore(); imagecopy($base, $resource, 0, 0, 0, 0, $width, $height); // floodfill if exact position is defined imagefill($resource, $x, $y, $filling); // copy filled original over base imagecopy($base, $resource, 0, 0, 0, 0, $width, $height); // set base as new resource-core $image->setCore($base); imagedestroy($resource); } else { // fill whole image otherwise imagefilledrectangle($resource, 0, 0, $width - 1, $height - 1, $filling); } isset($tile) ? imagedestroy($tile->getCore()) : null; return true; } } src/Intervention/Image/Gd/Commands/BackupCommand.php 0000644 00000001044 15111232402 0016337 0 ustar 00 <?php namespace Intervention\Image\Gd\Commands; use Intervention\Image\Commands\AbstractCommand; class BackupCommand extends AbstractCommand { /** * Saves a backups of current state of image core * * @param \Intervention\Image\Image $image * @return boolean */ public function execute($image) { $backupName = $this->argument(0)->value(); // clone current image resource $clone = clone $image; $image->setBackup($clone->getCore(), $backupName); return true; } } src/Intervention/Image/Gd/Commands/GetSizeCommand.php 0000644 00000001010 15111232402 0016475 0 ustar 00 <?php namespace Intervention\Image\Gd\Commands; use Intervention\Image\Commands\AbstractCommand; use Intervention\Image\Size; class GetSizeCommand extends AbstractCommand { /** * Reads size of given image instance in pixels * * @param \Intervention\Image\Image $image * @return boolean */ public function execute($image) { $this->setOutput(new Size( imagesx($image->getCore()), imagesy($image->getCore()) )); return true; } } src/Intervention/Image/Gd/Font.php 0000644 00000020240 15111232402 0012777 0 ustar 00 <?php namespace Intervention\Image\Gd; use Intervention\Image\Exception\NotSupportedException; use Intervention\Image\Image; class Font extends \Intervention\Image\AbstractFont { /** * Get font size in points * * @return int */ protected function getPointSize() { return intval(ceil($this->size * 0.75)); } /** * Filter function to access internal integer font values * * @return int */ private function getInternalFont() { $internalfont = is_null($this->file) ? 1 : $this->file; $internalfont = is_numeric($internalfont) ? $internalfont : false; if ( ! in_array($internalfont, [1, 2, 3, 4, 5])) { throw new NotSupportedException( sprintf('Internal GD font (%s) not available. Use only 1-5.', $internalfont) ); } return intval($internalfont); } /** * Get width of an internal font character * * @return int */ private function getInternalFontWidth() { return $this->getInternalFont() + 4; } /** * Get height of an internal font character * * @return int */ private function getInternalFontHeight() { switch ($this->getInternalFont()) { case 1: return 8; case 2: return 14; case 3: return 14; case 4: return 16; case 5: return 16; } } /** * Calculates bounding box of current font setting * * @return Array */ public function getBoxSize() { $box = []; if ($this->hasApplicableFontFile()) { // imagettfbbox() converts numeric entities to their respective // character. Preserve any originally double encoded entities to be // represented as is. // eg: &#160; will render   rather than its character. $this->text = preg_replace('/&(#(?:x[a-fA-F0-9]+|[0-9]+);)/', '&\1', $this->text); $this->text = mb_encode_numericentity($this->text, array(0x0080, 0xffff, 0, 0xffff), 'UTF-8'); // get bounding box with angle 0 $box = imagettfbbox($this->getPointSize(), 0, $this->file, $this->text); // rotate points manually if ($this->angle != 0) { $angle = pi() * 2 - $this->angle * pi() * 2 / 360; for ($i=0; $i<4; $i++) { $x = $box[$i * 2]; $y = $box[$i * 2 + 1]; $box[$i * 2] = cos($angle) * $x - sin($angle) * $y; $box[$i * 2 + 1] = sin($angle) * $x + cos($angle) * $y; } } $box['width'] = intval(abs($box[4] - $box[0])); $box['height'] = intval(abs($box[5] - $box[1])); } else { // get current internal font size $width = $this->getInternalFontWidth(); $height = $this->getInternalFontHeight(); if (strlen($this->text) == 0) { // no text -> no boxsize $box['width'] = 0; $box['height'] = 0; } else { // calculate boxsize $box['width'] = strlen($this->text) * $width; $box['height'] = $height; } } return $box; } /** * Draws font to given image at given position * * @param Image $image * @param int $posx * @param int $posy * @return void */ public function applyToImage(Image $image, $posx = 0, $posy = 0) { // parse text color $color = new Color($this->color); if ($this->hasApplicableFontFile()) { if ($this->angle != 0 || is_string($this->align) || is_string($this->valign)) { $box = $this->getBoxSize(); $align = is_null($this->align) ? 'left' : strtolower($this->align); $valign = is_null($this->valign) ? 'bottom' : strtolower($this->valign); // correction on position depending on v/h alignment switch ($align.'-'.$valign) { case 'center-top': $posx = $posx - round(($box[6]+$box[4])/2); $posy = $posy - round(($box[7]+$box[5])/2); break; case 'right-top': $posx = $posx - $box[4]; $posy = $posy - $box[5]; break; case 'left-top': $posx = $posx - $box[6]; $posy = $posy - $box[7]; break; case 'center-center': case 'center-middle': $posx = $posx - round(($box[0]+$box[4])/2); $posy = $posy - round(($box[1]+$box[5])/2); break; case 'right-center': case 'right-middle': $posx = $posx - round(($box[2]+$box[4])/2); $posy = $posy - round(($box[3]+$box[5])/2); break; case 'left-center': case 'left-middle': $posx = $posx - round(($box[0]+$box[6])/2); $posy = $posy - round(($box[1]+$box[7])/2); break; case 'center-bottom': $posx = $posx - round(($box[0]+$box[2])/2); $posy = $posy - round(($box[1]+$box[3])/2); break; case 'right-bottom': $posx = $posx - $box[2]; $posy = $posy - $box[3]; break; case 'left-bottom': $posx = $posx - $box[0]; $posy = $posy - $box[1]; break; } } // enable alphablending for imagettftext imagealphablending($image->getCore(), true); // draw ttf text imagettftext($image->getCore(), $this->getPointSize(), $this->angle, $posx, $posy, $color->getInt(), $this->file, $this->text); } else { // get box size $box = $this->getBoxSize(); $width = $box['width']; $height = $box['height']; // internal font specific position corrections if ($this->getInternalFont() == 1) { $top_correction = 1; $bottom_correction = 2; } elseif ($this->getInternalFont() == 3) { $top_correction = 2; $bottom_correction = 4; } else { $top_correction = 3; $bottom_correction = 4; } // x-position corrections for horizontal alignment switch (strtolower($this->align)) { case 'center': $posx = ceil($posx - ($width / 2)); break; case 'right': $posx = ceil($posx - $width) + 1; break; } // y-position corrections for vertical alignment switch (strtolower($this->valign)) { case 'center': case 'middle': $posy = ceil($posy - ($height / 2)); break; case 'top': $posy = ceil($posy - $top_correction); break; default: case 'bottom': $posy = round($posy - $height + $bottom_correction); break; } // draw text imagestring($image->getCore(), $this->getInternalFont(), $posx, $posy, $this->text, $color->getInt()); } } /** * Set text kerning * * @param string $kerning * @return void */ public function kerning($kerning) { throw new \Intervention\Image\Exception\NotSupportedException( "Kerning is not supported by GD driver." ); } } src/Intervention/Image/Gd/Decoder.php 0000644 00000011510 15111232402 0013436 0 ustar 00 <?php namespace Intervention\Image\Gd; use Intervention\Image\Exception\NotReadableException; use Intervention\Image\Exception\NotSupportedException; use Intervention\Image\Image; class Decoder extends \Intervention\Image\AbstractDecoder { /** * Initiates new image from path in filesystem * * @param string $path * @return \Intervention\Image\Image */ public function initFromPath($path) { if ( ! file_exists($path)) { throw new NotReadableException( "Unable to find file ({$path})." ); } // get mime type of file $mime = finfo_file(finfo_open(FILEINFO_MIME_TYPE), $path); // define core switch (strtolower($mime)) { case 'image/png': case 'image/x-png': $core = @imagecreatefrompng($path); break; case 'image/jpg': case 'image/jpeg': case 'image/pjpeg': $core = @imagecreatefromjpeg($path); if (!$core) { $core= @imagecreatefromstring(file_get_contents($path)); } break; case 'image/gif': $core = @imagecreatefromgif($path); break; case 'image/webp': case 'image/x-webp': if ( ! function_exists('imagecreatefromwebp')) { throw new NotReadableException( "Unsupported image type. GD/PHP installation does not support WebP format." ); } $core = @imagecreatefromwebp($path); break; case 'image/bmp': case 'image/ms-bmp': case 'image/x-bitmap': case 'image/x-bmp': case 'image/x-ms-bmp': case 'image/x-win-bitmap': case 'image/x-windows-bmp': case 'image/x-xbitmap': if (! function_exists('imagecreatefrombmp')) { throw new NotReadableException( "Unsupported image type. GD/PHP installation does not support BMP format." ); } $core = @imagecreatefrombmp($path); break; default: throw new NotReadableException( sprintf("Unsupported image type %s. GD driver is only able to decode JPG, PNG, GIF, BMP or WebP files.", strtolower($mime)) ); } if (empty($core)) { throw new NotReadableException( "Unable to decode image from file ({$path})." ); } $this->gdResourceToTruecolor($core); // build image $image = $this->initFromGdResource($core); $image->mime = $mime; $image->setFileInfoFromPath($path); return $image; } /** * Initiates new image from GD resource * * @param Resource $resource * @return \Intervention\Image\Image */ public function initFromGdResource($resource) { return new Image(new Driver, $resource); } /** * Initiates new image from Imagick object * * @param Imagick $object * @return \Intervention\Image\Image */ public function initFromImagick(\Imagick $object) { throw new NotSupportedException( "Gd driver is unable to init from Imagick object." ); } /** * Initiates new image from binary data * * @param string $data * @return \Intervention\Image\Image */ public function initFromBinary($binary) { $resource = @imagecreatefromstring($binary); if ($resource === false) { throw new NotReadableException( "Unable to init from given binary data." ); } $image = $this->initFromGdResource($resource); $image->mime = finfo_buffer(finfo_open(FILEINFO_MIME_TYPE), $binary); return $image; } /** * Transform GD resource into Truecolor version * * @param resource $resource * @return bool */ public function gdResourceToTruecolor(&$resource) { $width = imagesx($resource); $height = imagesy($resource); // new canvas $canvas = imagecreatetruecolor($width, $height); // fill with transparent color imagealphablending($canvas, false); $transparent = imagecolorallocatealpha($canvas, 255, 255, 255, 127); imagefilledrectangle($canvas, 0, 0, $width, $height, $transparent); imagecolortransparent($canvas, $transparent); imagealphablending($canvas, true); // copy original imagecopy($canvas, $resource, 0, 0, 0, 0, $width, $height); imagedestroy($resource); $resource = $canvas; return true; } } src/Intervention/Image/Gd/Color.php 0000644 00000012267 15111232402 0013161 0 ustar 00 <?php namespace Intervention\Image\Gd; use Intervention\Image\AbstractColor; use Intervention\Image\Exception\NotSupportedException; class Color extends AbstractColor { /** * RGB Red value of current color instance * * @var int */ public $r; /** * RGB Green value of current color instance * * @var int */ public $g; /** * RGB Blue value of current color instance * * @var int */ public $b; /** * RGB Alpha value of current color instance * * @var float */ public $a; /** * Initiates color object from integer * * @param int $value * @return \Intervention\Image\AbstractColor */ public function initFromInteger($value) { $this->a = ($value >> 24) & 0xFF; $this->r = ($value >> 16) & 0xFF; $this->g = ($value >> 8) & 0xFF; $this->b = $value & 0xFF; } /** * Initiates color object from given array * * @param array $value * @return \Intervention\Image\AbstractColor */ public function initFromArray($array) { $array = array_values($array); if (count($array) == 4) { // color array with alpha value list($r, $g, $b, $a) = $array; $this->a = $this->alpha2gd($a); } elseif (count($array) == 3) { // color array without alpha value list($r, $g, $b) = $array; $this->a = 0; } $this->r = $r; $this->g = $g; $this->b = $b; } /** * Initiates color object from given string * * @param string $value * @return \Intervention\Image\AbstractColor */ public function initFromString($value) { if ($color = $this->rgbaFromString($value)) { $this->r = $color[0]; $this->g = $color[1]; $this->b = $color[2]; $this->a = $this->alpha2gd($color[3]); } } /** * Initiates color object from given R, G and B values * * @param int $r * @param int $g * @param int $b * @return \Intervention\Image\AbstractColor */ public function initFromRgb($r, $g, $b) { $this->r = intval($r); $this->g = intval($g); $this->b = intval($b); $this->a = 0; } /** * Initiates color object from given R, G, B and A values * * @param int $r * @param int $g * @param int $b * @param float $a * @return \Intervention\Image\AbstractColor */ public function initFromRgba($r, $g, $b, $a = 1) { $this->r = intval($r); $this->g = intval($g); $this->b = intval($b); $this->a = $this->alpha2gd($a); } /** * Initiates color object from given ImagickPixel object * * @param ImagickPixel $value * @return \Intervention\Image\AbstractColor */ public function initFromObject($value) { throw new NotSupportedException( "GD colors cannot init from ImagickPixel objects." ); } /** * Calculates integer value of current color instance * * @return int */ public function getInt() { return ($this->a << 24) + ($this->r << 16) + ($this->g << 8) + $this->b; } /** * Calculates hexadecimal value of current color instance * * @param string $prefix * @return string */ public function getHex($prefix = '') { return sprintf('%s%02x%02x%02x', $prefix, $this->r, $this->g, $this->b); } /** * Calculates RGB(A) in array format of current color instance * * @return array */ public function getArray() { return [$this->r, $this->g, $this->b, round(1 - $this->a / 127, 2)]; } /** * Calculates RGBA in string format of current color instance * * @return string */ public function getRgba() { return sprintf('rgba(%d, %d, %d, %.2F)', $this->r, $this->g, $this->b, round(1 - $this->a / 127, 2)); } /** * Determines if current color is different from given color * * @param AbstractColor $color * @param int $tolerance * @return boolean */ public function differs(AbstractColor $color, $tolerance = 0) { $color_tolerance = round($tolerance * 2.55); $alpha_tolerance = round($tolerance * 1.27); $delta = [ 'r' => abs($color->r - $this->r), 'g' => abs($color->g - $this->g), 'b' => abs($color->b - $this->b), 'a' => abs($color->a - $this->a) ]; return ( $delta['r'] > $color_tolerance or $delta['g'] > $color_tolerance or $delta['b'] > $color_tolerance or $delta['a'] > $alpha_tolerance ); } /** * Convert rgba alpha (0-1) value to gd value (0-127) * * @param float $input * @return int */ private function alpha2gd($input) { $oldMin = 0; $oldMax = 1; $newMin = 127; $newMax = 0; return ceil(((($input- $oldMin) * ($newMax - $newMin)) / ($oldMax - $oldMin)) + $newMin); } } src/Intervention/Image/ImageServiceProviderLumen.php 0000644 00000001312 15111232402 0016615 0 ustar 00 <?php namespace Intervention\Image; use Illuminate\Support\ServiceProvider; class ImageServiceProviderLumen extends ServiceProvider { /** * Register the service provider. * * @return void */ public function register() { $app = $this->app; // merge default config $this->mergeConfigFrom( __DIR__.'/../../config/config.php', 'image' ); // set configuration $app->configure('image'); // create image $app->singleton('image',function ($app) { return new ImageManager($app['config']->get('image')); }); $app->alias('image', 'Intervention\Image\ImageManager'); } } src/Intervention/Image/AbstractFont.php 0000644 00000011177 15111232403 0014143 0 ustar 00 <?php namespace Intervention\Image; abstract class AbstractFont { /** * Text to be written * * @var String */ public $text; /** * Text size in pixels * * @var int */ public $size = 12; /** * Color of the text * * @var mixed */ public $color = '000000'; /** * Rotation angle of the text * * @var int */ public $angle = 0; /** * Horizontal alignment of the text * * @var String */ public $align; /** * Vertical alignment of the text * * @var String */ public $valign; /** * Space between text characters * * @var float */ public $kerning = 0; /** * Path to TTF or GD library internal font file of the text * * @var mixed */ public $file; /** * Draws font to given image on given position * * @param Image $image * @param int $posx * @param int $posy * @return boolean */ abstract public function applyToImage(Image $image, $posx = 0, $posy = 0); /** * Calculates bounding box of current font setting * * @return array */ abstract public function getBoxSize(); /** * Create a new instance of Font * * @param String $text Text to be written */ public function __construct($text = null) { $this->text = $text; } /** * Set text to be written * * @param String $text * @return self */ public function text($text) { $this->text = $text; return $this; } /** * Get text to be written * * @return String */ public function getText() { return $this->text; } /** * Set font size in pixels * * @param int $size * @return self */ public function size($size) { $this->size = $size; return $this; } /** * Get font size in pixels * * @return int */ public function getSize() { return $this->size; } /** * Set color of text to be written * * @param mixed $color * @return self */ public function color($color) { $this->color = $color; return $this; } /** * Get color of text * * @return mixed */ public function getColor() { return $this->color; } /** * Set rotation angle of text * * @param int $angle * @return self */ public function angle($angle) { $this->angle = $angle; return $this; } /** * Get rotation angle of text * * @return int */ public function getAngle() { return $this->angle; } /** * Set horizontal text alignment * * @param string $align * @return self */ public function align($align) { $this->align = $align; return $this; } /** * Get horizontal text alignment * * @return string */ public function getAlign() { return $this->align; } /** * Set vertical text alignment * * @param string $valign * @return self */ public function valign($valign) { $this->valign = $valign; return $this; } /** * Get vertical text alignment * * @return string */ public function getValign() { return $this->valign; } /** * Set text kerning * * @param string $kerning * @return void */ public function kerning($kerning) { $this->kerning = $kerning; } /** * Get kerning * * @return float */ public function getKerning() { return $this->kerning; } /** * Set path to font file * * @param string $file * @return self */ public function file($file) { $this->file = $file; return $this; } /** * Get path to font file * * @return string */ public function getFile() { return $this->file; } /** * Checks if current font has access to an applicable font file * * @return boolean */ protected function hasApplicableFontFile() { if (is_string($this->file)) { return file_exists($this->file); } return false; } /** * Counts lines of text to be written * * @return int */ public function countLines() { return count(explode(PHP_EOL, $this->text)); } } src/Intervention/Image/File.php 0000644 00000003367 15111232403 0012432 0 ustar 00 <?php namespace Intervention\Image; class File { /** * Mime type * * @var string */ public $mime; /** * Name of directory path * * @var string */ public $dirname; /** * Basename of current file * * @var string */ public $basename; /** * File extension of current file * * @var string */ public $extension; /** * File name of current file * * @var string */ public $filename; /** * Sets all instance properties from given path * * @param string $path */ public function setFileInfoFromPath($path) { $info = pathinfo($path); $this->dirname = array_key_exists('dirname', $info) ? $info['dirname'] : null; $this->basename = array_key_exists('basename', $info) ? $info['basename'] : null; $this->extension = array_key_exists('extension', $info) ? $info['extension'] : null; $this->filename = array_key_exists('filename', $info) ? $info['filename'] : null; if (file_exists($path) && is_file($path)) { $this->mime = finfo_file(finfo_open(FILEINFO_MIME_TYPE), $path); } return $this; } /** * Get file size * * @return mixed */ public function filesize() { $path = $this->basePath(); if (file_exists($path) && is_file($path)) { return filesize($path); } return false; } /** * Get fully qualified path * * @return string */ public function basePath() { if ($this->dirname && $this->basename) { return ($this->dirname .'/'. $this->basename); } return null; } } src/Intervention/Image/Facades/Image.php 0000644 00000001037 15111232403 0014113 0 ustar 00 <?php namespace Intervention\Image\Facades; use Illuminate\Support\Facades\Facade; /** * @method static \Intervention\Image\Image make(mixed $data) * @method static self configure(array $config) * @method static \Intervention\Image\Image canvas(int $width, int $height, mixed $background = null) * @method static \Intervention\Image\Image cache(\Closure $callback, int $lifetime = null, boolean $returnObj = false) */ class Image extends Facade { protected static function getFacadeAccessor() { return 'image'; } } src/Intervention/Image/ImageManagerStatic.php 0000644 00000003770 15111232403 0015236 0 ustar 00 <?php namespace Intervention\Image; use Closure; class ImageManagerStatic { /** * Instance of Intervention\Image\ImageManager * * @var ImageManager */ public static $manager; /** * Creates a new instance * * @param ImageManager $manager */ public function __construct(ImageManager $manager = null) { self::$manager = $manager ? $manager : new ImageManager; } /** * Get or create new ImageManager instance * * @return ImageManager */ public static function getManager() { return self::$manager ? self::$manager : new ImageManager; } /** * Statically create new custom configured image manager * * @param array $config * * @return ImageManager */ public static function configure(array $config = []) { return self::$manager = self::getManager()->configure($config); } /** * Statically initiates an Image instance from different input types * * @param mixed $data * * @return \Intervention\Image\Image * @throws \Intervention\Image\Exception\NotReadableException */ public static function make($data) { return self::getManager()->make($data); } /** * Statically creates an empty image canvas * * @param int $width * @param int $height * @param mixed $background * * @return \Intervention\Image\Image */ public static function canvas($width, $height, $background = null) { return self::getManager()->canvas($width, $height, $background); } /** * Create new cached image and run callback statically * * @param Closure $callback * @param int $lifetime * @param boolean $returnObj * * @return mixed */ public static function cache(Closure $callback, $lifetime = null, $returnObj = false) { return self::getManager()->cache($callback, $lifetime, $returnObj); } } src/Intervention/Image/Commands/CircleCommand.php 0000644 00000001635 15111232403 0016010 0 ustar 00 <?php namespace Intervention\Image\Commands; use Closure; class CircleCommand extends AbstractCommand { /** * Draw a circle centered on given image * * @param \Intervention\Image\image $image * @return boolean */ public function execute($image) { $diameter = $this->argument(0)->type('numeric')->required()->value(); $x = $this->argument(1)->type('numeric')->required()->value(); $y = $this->argument(2)->type('numeric')->required()->value(); $callback = $this->argument(3)->type('closure')->value(); $circle_classname = sprintf('\Intervention\Image\%s\Shapes\CircleShape', $image->getDriver()->getDriverName()); $circle = new $circle_classname($diameter); if ($callback instanceof Closure) { $callback($circle); } $circle->applyToImage($image, $x, $y); return true; } } src/Intervention/Image/Commands/ResponseCommand.php 0000644 00000001060 15111232403 0016375 0 ustar 00 <?php namespace Intervention\Image\Commands; use Intervention\Image\Response; class ResponseCommand extends AbstractCommand { /** * Builds HTTP response from given image * * @param \Intervention\Image\Image $image * @return boolean */ public function execute($image) { $format = $this->argument(0)->value(); $quality = $this->argument(1)->between(0, 100)->value(); $response = new Response($image, $format, $quality); $this->setOutput($response->make()); return true; } } src/Intervention/Image/Commands/PsrResponseCommand.php 0000644 00000002266 15111232403 0017073 0 ustar 00 <?php namespace Intervention\Image\Commands; use GuzzleHttp\Psr7\Response; class PsrResponseCommand extends AbstractCommand { /** * Builds PSR7 compatible response. May replace "response" command in * some future. * * Method will generate binary stream and put it inside PSR-7 * ResponseInterface. Following code can be optimized using native php * streams and more "clean" streaming, however drivers has to be updated * first. * * @param \Intervention\Image\Image $image * @return boolean */ public function execute($image) { $format = $this->argument(0)->value(); $quality = $this->argument(1)->between(0, 100)->value(); //Encoded property will be populated at this moment $stream = $image->stream($format, $quality); $mimetype = finfo_buffer( finfo_open(FILEINFO_MIME_TYPE), $image->getEncoded() ); $this->setOutput(new Response( 200, [ 'Content-Type' => $mimetype, 'Content-Length' => strlen($image->getEncoded()) ], $stream )); return true; } } src/Intervention/Image/Commands/ChecksumCommand.php 0000644 00000001141 15111232403 0016341 0 ustar 00 <?php namespace Intervention\Image\Commands; class ChecksumCommand extends AbstractCommand { /** * Calculates checksum of given image * * @param \Intervention\Image\Image $image * @return boolean */ public function execute($image) { $colors = []; $size = $image->getSize(); for ($x=0; $x <= ($size->width-1); $x++) { for ($y=0; $y <= ($size->height-1); $y++) { $colors[] = $image->pickColor($x, $y, 'array'); } } $this->setOutput(md5(serialize($colors))); return true; } } src/Intervention/Image/Commands/OrientateCommand.php 0000644 00000001677 15111232403 0016547 0 ustar 00 <?php namespace Intervention\Image\Commands; class OrientateCommand extends AbstractCommand { /** * Correct image orientation according to Exif data * * @param \Intervention\Image\Image $image * @return boolean */ public function execute($image) { switch ($image->exif('Orientation')) { case 2: $image->flip(); break; case 3: $image->rotate(180); break; case 4: $image->rotate(180)->flip(); break; case 5: $image->rotate(270)->flip(); break; case 6: $image->rotate(270); break; case 7: $image->rotate(90)->flip(); break; case 8: $image->rotate(90); break; } return true; } } src/Intervention/Image/Commands/AbstractCommand.php 0000644 00000002710 15111232403 0016345 0 ustar 00 <?php namespace Intervention\Image\Commands; use Intervention\Image\Commands\Argument; abstract class AbstractCommand { /** * Arguments of command * * @var array */ public $arguments; /** * Output of command * * @var mixed */ protected $output; /** * Executes current command on given image * * @param \Intervention\Image\Image $image * @return mixed */ abstract public function execute($image); /** * Creates new command instance * * @param array $arguments */ public function __construct($arguments) { $this->arguments = $arguments; } /** * Creates new argument instance from given argument key * * @param int $key * @return \Intervention\Image\Commands\Argument */ public function argument($key) { return new Argument($this, $key); } /** * Returns output data of current command * * @return mixed */ public function getOutput() { return $this->output ? $this->output : null; } /** * Determines if current instance has output data * * @return boolean */ public function hasOutput() { return ! is_null($this->output); } /** * Sets output data of current command * * @param mixed $value */ public function setOutput($value) { $this->output = $value; } } src/Intervention/Image/Commands/RectangleCommand.php 0000644 00000001772 15111232403 0016515 0 ustar 00 <?php namespace Intervention\Image\Commands; use Closure; class RectangleCommand extends AbstractCommand { /** * Draws rectangle on given image * * @param \Intervention\Image\Image $image * @return boolean */ public function execute($image) { $x1 = $this->argument(0)->type('numeric')->required()->value(); $y1 = $this->argument(1)->type('numeric')->required()->value(); $x2 = $this->argument(2)->type('numeric')->required()->value(); $y2 = $this->argument(3)->type('numeric')->required()->value(); $callback = $this->argument(4)->type('closure')->value(); $rectangle_classname = sprintf('\Intervention\Image\%s\Shapes\RectangleShape', $image->getDriver()->getDriverName()); $rectangle = new $rectangle_classname($x1, $y1, $x2, $y2); if ($callback instanceof Closure) { $callback($rectangle); } $rectangle->applyToImage($image, $x1, $y1); return true; } } src/Intervention/Image/Commands/ExifCommand.php 0000644 00000003654 15111232403 0015505 0 ustar 00 <?php namespace Intervention\Image\Commands; use Intervention\Image\Exception\NotReadableException; use Intervention\Image\Exception\NotSupportedException; class ExifCommand extends AbstractCommand { /** * Read Exif data from the given image * * Note: Windows PHP Users - in order to use this method you will need to * enable the mbstring and exif extensions within the php.ini file. * * @param \Intervention\Image\Image $image * @return boolean */ public function execute($image) { if (!function_exists('exif_read_data')) { throw new NotSupportedException( "Reading Exif data is not supported by this PHP installation." ); } $key = $this->argument(0)->value(); // try to read exif data from image file try { if ($image->dirname && $image->basename) { $stream = $image->dirname . '/' . $image->basename; } elseif (version_compare(PHP_VERSION, '7.2.0', '>=')) { // https://www.php.net/manual/en/function.exif-read-data.php#refsect1-function.exif-read-data-changelog $stream = $image->stream()->detach(); } else { // https://bugs.php.net/bug.php?id=65187 $stream = $image->encode('data-url')->encoded; } $data = @exif_read_data($stream); if (!is_null($key) && is_array($data)) { $data = array_key_exists($key, $data) ? $data[$key] : false; } } catch (\Exception $e) { throw new NotReadableException( sprintf( "Cannot read the Exif data from the filename (%s) provided ", $image->dirname . '/' . $image->basename ), $e->getCode(), $e ); } $this->setOutput($data); return true; } } src/Intervention/Image/Commands/TextCommand.php 0000644 00000001477 15111232403 0015537 0 ustar 00 <?php namespace Intervention\Image\Commands; use Closure; class TextCommand extends AbstractCommand { /** * Write text on given image * @param \Intervention\Image\Image $image * @return boolean */ public function execute($image) { $text = $this->argument(0)->required()->value(); $x = $this->argument(1)->type('numeric')->value(0); $y = $this->argument(2)->type('numeric')->value(0); $callback = $this->argument(3)->type('closure')->value(); $fontclassname = sprintf('\Intervention\Image\%s\Font', $image->getDriver()->getDriverName()); $font = new $fontclassname($text); if ($callback instanceof Closure) { $callback($font); } $font->applyToImage($image, $x, $y); return true; } } src/Intervention/Image/Commands/LineCommand.php 0000644 00000001710 15111232403 0015470 0 ustar 00 <?php namespace Intervention\Image\Commands; use Closure; class LineCommand extends AbstractCommand { /** * Draws line on given image * * @param \Intervention\Image\Image $image * @return boolean */ public function execute($image) { $x1 = $this->argument(0)->type('numeric')->required()->value(); $y1 = $this->argument(1)->type('numeric')->required()->value(); $x2 = $this->argument(2)->type('numeric')->required()->value(); $y2 = $this->argument(3)->type('numeric')->required()->value(); $callback = $this->argument(4)->type('closure')->value(); $line_classname = sprintf('\Intervention\Image\%s\Shapes\LineShape', $image->getDriver()->getDriverName()); $line = new $line_classname($x2, $y2); if ($callback instanceof Closure) { $callback($line); } $line->applyToImage($image, $x1, $y1); return true; } } src/Intervention/Image/Commands/PolygonCommand.php 0000644 00000002416 15111232403 0016234 0 ustar 00 <?php namespace Intervention\Image\Commands; use Closure; use Intervention\Image\Exception\InvalidArgumentException; class PolygonCommand extends AbstractCommand { /** * Draw a polygon on given image * * @param \Intervention\Image\image $image * @return boolean */ public function execute($image) { $points = $this->argument(0)->type('array')->required()->value(); $callback = $this->argument(1)->type('closure')->value(); $vertices_count = count($points); // check if number if coordinates is even if ($vertices_count % 2 !== 0) { throw new InvalidArgumentException( "The number of given polygon vertices must be even." ); } if ($vertices_count < 6) { throw new InvalidArgumentException( "You must have at least 3 points in your array." ); } $polygon_classname = sprintf('\Intervention\Image\%s\Shapes\PolygonShape', $image->getDriver()->getDriverName()); $polygon = new $polygon_classname($points); if ($callback instanceof Closure) { $callback($polygon); } $polygon->applyToImage($image); return true; } } src/Intervention/Image/Commands/EllipseCommand.php 0000644 00000001752 15111232403 0016204 0 ustar 00 <?php namespace Intervention\Image\Commands; use Closure; class EllipseCommand extends AbstractCommand { /** * Draws ellipse on given image * * @param \Intervention\Image\Image $image * @return boolean */ public function execute($image) { $width = $this->argument(0)->type('numeric')->required()->value(); $height = $this->argument(1)->type('numeric')->required()->value(); $x = $this->argument(2)->type('numeric')->required()->value(); $y = $this->argument(3)->type('numeric')->required()->value(); $callback = $this->argument(4)->type('closure')->value(); $ellipse_classname = sprintf('\Intervention\Image\%s\Shapes\EllipseShape', $image->getDriver()->getDriverName()); $ellipse = new $ellipse_classname($width, $height); if ($callback instanceof Closure) { $callback($ellipse); } $ellipse->applyToImage($image, $x, $y); return true; } } src/Intervention/Image/Commands/Argument.php 0000644 00000013120 15111232403 0015062 0 ustar 00 <?php namespace Intervention\Image\Commands; use Intervention\Image\Exception\InvalidArgumentException; class Argument { /** * Command with arguments * * @var AbstractCommand */ public $command; /** * Key of argument in array * * @var int */ public $key; /** * Creates new instance from given command and key * * @param AbstractCommand $command * @param int $key */ public function __construct(AbstractCommand $command, $key = 0) { $this->command = $command; $this->key = $key; } /** * Returns name of current arguments command * * @return string */ public function getCommandName() { preg_match("/\\\\([\w]+)Command$/", get_class($this->command), $matches); return isset($matches[1]) ? lcfirst($matches[1]).'()' : 'Method'; } /** * Returns value of current argument * * @param mixed $default * @return mixed */ public function value($default = null) { $arguments = $this->command->arguments; if (is_array($arguments)) { return isset($arguments[$this->key]) ? $arguments[$this->key] : $default; } return $default; } /** * Defines current argument as required * * @return \Intervention\Image\Commands\Argument */ public function required() { if ( ! array_key_exists($this->key, $this->command->arguments)) { throw new InvalidArgumentException( sprintf("Missing argument %d for %s", $this->key + 1, $this->getCommandName()) ); } return $this; } /** * Determines that current argument must be of given type * * @return \Intervention\Image\Commands\Argument */ public function type($type) { $valid = true; $value = $this->value(); if ($value === null) { return $this; } switch (strtolower($type)) { case 'bool': case 'boolean': $valid = \is_bool($value); $message = '%s accepts only boolean values as argument %d.'; break; case 'int': case 'integer': $valid = \is_int($value); $message = '%s accepts only integer values as argument %d.'; break; case 'num': case 'numeric': $valid = is_numeric($value); $message = '%s accepts only numeric values as argument %d.'; break; case 'str': case 'string': $valid = \is_string($value); $message = '%s accepts only string values as argument %d.'; break; case 'array': $valid = \is_array($value); $message = '%s accepts only array as argument %d.'; break; case 'closure': $valid = is_a($value, '\Closure'); $message = '%s accepts only Closure as argument %d.'; break; case 'digit': $valid = $this->isDigit($value); $message = '%s accepts only integer values as argument %d.'; break; } if (! $valid) { $commandName = $this->getCommandName(); $argument = $this->key + 1; if (isset($message)) { $message = sprintf($message, $commandName, $argument); } else { $message = sprintf('Missing argument for %d.', $argument); } throw new InvalidArgumentException( $message ); } return $this; } /** * Determines that current argument value must be numeric between given values * * @return \Intervention\Image\Commands\Argument */ public function between($x, $y) { $value = $this->type('numeric')->value(); if (is_null($value)) { return $this; } $alpha = min($x, $y); $omega = max($x, $y); if ($value < $alpha || $value > $omega) { throw new InvalidArgumentException( sprintf('Argument %d must be between %s and %s.', $this->key, $x, $y) ); } return $this; } /** * Determines that current argument must be over a minimum value * * @return \Intervention\Image\Commands\Argument */ public function min($value) { $v = $this->type('numeric')->value(); if (is_null($v)) { return $this; } if ($v < $value) { throw new InvalidArgumentException( sprintf('Argument %d must be at least %s.', $this->key, $value) ); } return $this; } /** * Determines that current argument must be under a maxiumum value * * @return \Intervention\Image\Commands\Argument */ public function max($value) { $v = $this->type('numeric')->value(); if (is_null($v)) { return $this; } if ($v > $value) { throw new InvalidArgumentException( sprintf('Argument %d may not be greater than %s.', $this->key, $value) ); } return $this; } /** * Checks if value is "PHP" integer (120 but also 120.0) * * @param mixed $value * @return boolean */ private function isDigit($value) { return is_numeric($value) ? intval($value) == $value : false; } } src/Intervention/Image/Commands/IptcCommand.php 0000644 00000006053 15111232403 0015505 0 ustar 00 <?php namespace Intervention\Image\Commands; use Intervention\Image\Exception\NotSupportedException; class IptcCommand extends AbstractCommand { /** * Read Iptc data from the given image * * @param \Intervention\Image\Image $image * @return boolean */ public function execute($image) { if ( ! function_exists('iptcparse')) { throw new NotSupportedException( "Reading Iptc data is not supported by this PHP installation." ); } $key = $this->argument(0)->value(); $info = []; @getimagesize($image->dirname .'/'. $image->basename, $info); $data = []; if (array_key_exists('APP13', $info)) { $iptc = iptcparse($info['APP13']); if (is_array($iptc)) { $data['DocumentTitle'] = isset($iptc["2#005"][0]) ? $iptc["2#005"][0] : null; $data['Urgency'] = isset($iptc["2#010"][0]) ? $iptc["2#010"][0] : null; $data['Category'] = isset($iptc["2#015"][0]) ? $iptc["2#015"][0] : null; $data['Subcategories'] = isset($iptc["2#020"][0]) ? $iptc["2#020"][0] : null; $data['Keywords'] = isset($iptc["2#025"][0]) ? $iptc["2#025"] : null; $data['ReleaseDate'] = isset($iptc["2#030"][0]) ? $iptc["2#030"][0] : null; $data['ReleaseTime'] = isset($iptc["2#035"][0]) ? $iptc["2#035"][0] : null; $data['SpecialInstructions'] = isset($iptc["2#040"][0]) ? $iptc["2#040"][0] : null; $data['CreationDate'] = isset($iptc["2#055"][0]) ? $iptc["2#055"][0] : null; $data['CreationTime'] = isset($iptc["2#060"][0]) ? $iptc["2#060"][0] : null; $data['AuthorByline'] = isset($iptc["2#080"][0]) ? $iptc["2#080"][0] : null; $data['AuthorTitle'] = isset($iptc["2#085"][0]) ? $iptc["2#085"][0] : null; $data['City'] = isset($iptc["2#090"][0]) ? $iptc["2#090"][0] : null; $data['SubLocation'] = isset($iptc["2#092"][0]) ? $iptc["2#092"][0] : null; $data['State'] = isset($iptc["2#095"][0]) ? $iptc["2#095"][0] : null; $data['Country'] = isset($iptc["2#101"][0]) ? $iptc["2#101"][0] : null; $data['OTR'] = isset($iptc["2#103"][0]) ? $iptc["2#103"][0] : null; $data['Headline'] = isset($iptc["2#105"][0]) ? $iptc["2#105"][0] : null; $data['Source'] = isset($iptc["2#110"][0]) ? $iptc["2#110"][0] : null; $data['PhotoSource'] = isset($iptc["2#115"][0]) ? $iptc["2#115"][0] : null; $data['Copyright'] = isset($iptc["2#116"][0]) ? $iptc["2#116"][0] : null; $data['Caption'] = isset($iptc["2#120"][0]) ? $iptc["2#120"][0] : null; $data['CaptionWriter'] = isset($iptc["2#122"][0]) ? $iptc["2#122"][0] : null; } } if (! is_null($key) && is_array($data)) { $data = array_key_exists($key, $data) ? $data[$key] : false; } $this->setOutput($data); return true; } } src/Intervention/Image/Commands/StreamCommand.php 0000644 00000001777 15111232403 0016051 0 ustar 00 <?php namespace Intervention\Image\Commands; class StreamCommand extends AbstractCommand { /** * Builds PSR7 stream based on image data. Method uses Guzzle PSR7 * implementation as easiest choice. * * @param \Intervention\Image\Image $image * @return boolean */ public function execute($image) { $format = $this->argument(0)->value(); $quality = $this->argument(1)->between(0, 100)->value(); $data = $image->encode($format, $quality)->getEncoded(); $this->setOutput($this->getStream($data)); return true; } /** * Create stream from given data * * @param string $data * @return \Psr\Http\Message\StreamInterface */ protected function getStream($data) { if (class_exists(\GuzzleHttp\Psr7\Utils::class)) { return \GuzzleHttp\Psr7\Utils::streamFor($data); // guzzlehttp/psr7 >= 2.0 } return \GuzzleHttp\Psr7\stream_for($data); // guzzlehttp/psr7 < 2.0 } } src/Intervention/Image/Exception/ImageException.php 0000644 00000000175 15111232403 0016404 0 ustar 00 <?php namespace Intervention\Image\Exception; class ImageException extends \RuntimeException { # nothing to override } src/Intervention/Image/Exception/NotFoundException.php 0000644 00000000175 15111232403 0017116 0 ustar 00 <?php namespace Intervention\Image\Exception; class NotFoundException extends ImageException { # nothing to override } src/Intervention/Image/Exception/NotReadableException.php 0000644 00000000200 15111232403 0017527 0 ustar 00 <?php namespace Intervention\Image\Exception; class NotReadableException extends ImageException { # nothing to override } src/Intervention/Image/Exception/NotWritableException.php 0000644 00000000200 15111232403 0017601 0 ustar 00 <?php namespace Intervention\Image\Exception; class NotWritableException extends ImageException { # nothing to override } src/Intervention/Image/Exception/RuntimeException.php 0000644 00000000174 15111232403 0017004 0 ustar 00 <?php namespace Intervention\Image\Exception; class RuntimeException extends ImageException { # nothing to override } src/Intervention/Image/Exception/InvalidArgumentException.php 0000644 00000000204 15111232403 0020444 0 ustar 00 <?php namespace Intervention\Image\Exception; class InvalidArgumentException extends ImageException { # nothing to override } src/Intervention/Image/Exception/MissingDependencyException.php 0000644 00000000206 15111232403 0020765 0 ustar 00 <?php namespace Intervention\Image\Exception; class MissingDependencyException extends ImageException { # nothing to override } src/Intervention/Image/Exception/NotSupportedException.php 0000644 00000000201 15111232403 0020016 0 ustar 00 <?php namespace Intervention\Image\Exception; class NotSupportedException extends ImageException { # nothing to override } src/Intervention/Image/ImageServiceProviderLaravel4.php 0000644 00000010021 15111232403 0017205 0 ustar 00 <?php namespace Intervention\Image; use Illuminate\Support\ServiceProvider; use Illuminate\Http\Response as IlluminateResponse; class ImageServiceProviderLaravel4 extends ServiceProvider { /** * Bootstrap the application events. * * @return void */ public function boot() { $this->package('intervention/image'); // try to create imagecache route only if imagecache is present if (class_exists('Intervention\\Image\\ImageCache')) { $app = $this->app; // load imagecache config $app['config']->package('intervention/imagecache', __DIR__.'/../../../../imagecache/src/config', 'imagecache'); $config = $app['config']; // create dynamic manipulation route if (is_string($config->get('imagecache::route'))) { // add original to route templates $config->set('imagecache::templates.original', null); // setup image manipulator route $app['router']->get($config->get('imagecache::route').'/{template}/{filename}', ['as' => 'imagecache', function ($template, $filename) use ($app, $config) { // disable session cookies for image route $app['config']->set('session.driver', 'array'); // find file foreach ($config->get('imagecache::paths') as $path) { // don't allow '..' in filenames $image_path = $path.'/'.str_replace('..', '', $filename); if (file_exists($image_path) && is_file($image_path)) { break; } else { $image_path = false; } } // abort if file not found if ($image_path === false) { $app->abort(404); } // define template callback $callback = $config->get("imagecache::templates.{$template}"); if (is_callable($callback) || class_exists($callback)) { // image manipulation based on callback $content = $app['image']->cache(function ($image) use ($image_path, $callback) { switch (true) { case is_callable($callback): return $callback($image->make($image_path)); break; case class_exists($callback): return $image->make($image_path)->filter(new $callback); break; } }, $config->get('imagecache::lifetime')); } else { // get original image file contents $content = file_get_contents($image_path); } // define mime type $mime = finfo_buffer(finfo_open(FILEINFO_MIME_TYPE), $content); // return http response return new IlluminateResponse($content, 200, [ 'Content-Type' => $mime, 'Cache-Control' => 'max-age='.($config->get('imagecache::lifetime')*60).', public', 'Etag' => md5($content) ]); }])->where(['template' => join('|', array_keys($config->get('imagecache::templates'))), 'filename' => '[ \w\\.\\/\\-]+']); } } } /** * Register the service provider. * * @return void */ public function register() { $app = $this->app; $app['image'] = $app->share(function ($app) { return new ImageManager($app['config']->get('image::config')); }); $app->alias('image', 'Intervention\Image\ImageManager'); } } src/Intervention/Image/ImageServiceProvider.php 0000644 00000003673 15111232403 0015631 0 ustar 00 <?php namespace Intervention\Image; use Illuminate\Support\ServiceProvider; use Laravel\Lumen\Application as LumenApplication; use Illuminate\Foundation\Application as IlluminateApplication; class ImageServiceProvider extends ServiceProvider { /** * Indicates if loading of the provider is deferred. * * @var bool */ protected $defer = false; /** * Actual provider * * @var \Illuminate\Support\ServiceProvider */ protected $provider; /** * Create a new service provider instance. * * @param \Illuminate\Contracts\Foundation\Application $app * @return void */ public function __construct($app) { parent::__construct($app); $this->provider = $this->getProvider(); } /** * Bootstrap the application events. * * @return void */ public function boot() { if (method_exists($this->provider, 'boot')) { return $this->provider->boot(); } } /** * Register the service provider. * * @return void */ public function register() { return $this->provider->register(); } /** * Return ServiceProvider according to Laravel version * * @return \Intervention\Image\Provider\ProviderInterface */ private function getProvider() { if ($this->app instanceof LumenApplication) { $provider = '\Intervention\Image\ImageServiceProviderLumen'; } elseif (version_compare(IlluminateApplication::VERSION, '5.0', '<')) { $provider = '\Intervention\Image\ImageServiceProviderLaravel4'; } else { $provider = '\Intervention\Image\ImageServiceProviderLaravelRecent'; } return new $provider($this->app); } /** * Get the services provided by the provider. * * @return array */ public function provides() { return ['image']; } } src/Intervention/Image/Imagick/Driver.php 0000644 00000003552 15111232403 0014346 0 ustar 00 <?php namespace Intervention\Image\Imagick; use Intervention\Image\AbstractDriver; use Intervention\Image\Exception\NotSupportedException; use Intervention\Image\Image; class Driver extends AbstractDriver { /** * Creates new instance of driver * * @param Decoder $decoder * @param Encoder $encoder */ public function __construct(Decoder $decoder = null, Encoder $encoder = null) { if ( ! $this->coreAvailable()) { throw new NotSupportedException( "ImageMagick module not available with this PHP installation." ); } $this->decoder = $decoder ? $decoder : new Decoder; $this->encoder = $encoder ? $encoder : new Encoder; } /** * Creates new image instance * * @param int $width * @param int $height * @param mixed $background * @return \Intervention\Image\Image */ public function newImage($width, $height, $background = null) { $background = new Color($background); // create empty core $core = new \Imagick; $core->newImage($width, $height, $background->getPixel(), 'png'); $core->setType(\Imagick::IMGTYPE_UNDEFINED); $core->setImageType(\Imagick::IMGTYPE_UNDEFINED); $core->setColorspace(\Imagick::COLORSPACE_UNDEFINED); // build image $image = new Image(new static, $core); return $image; } /** * Reads given string into color object * * @param string $value * @return AbstractColor */ public function parseColor($value) { return new Color($value); } /** * Checks if core module installation is available * * @return boolean */ protected function coreAvailable() { return (extension_loaded('imagick') && class_exists('Imagick')); } } src/Intervention/Image/Imagick/Encoder.php 0000644 00000015461 15111232403 0014474 0 ustar 00 <?php namespace Intervention\Image\Imagick; use Intervention\Image\AbstractEncoder; use Intervention\Image\Exception\NotSupportedException; class Encoder extends AbstractEncoder { /** * Processes and returns encoded image as JPEG string * * @return string */ protected function processJpeg() { $format = 'jpeg'; $compression = \Imagick::COMPRESSION_JPEG; $imagick = $this->image->getCore(); $imagick->setImageBackgroundColor('white'); $imagick->setBackgroundColor('white'); $imagick = $imagick->mergeImageLayers(\Imagick::LAYERMETHOD_MERGE); $imagick->setFormat($format); $imagick->setImageFormat($format); $imagick->setCompression($compression); $imagick->setImageCompression($compression); $imagick->setCompressionQuality($this->quality); $imagick->setImageCompressionQuality($this->quality); return $imagick->getImagesBlob(); } /** * Processes and returns encoded image as PNG string * * @return string */ protected function processPng() { $format = 'png'; $compression = \Imagick::COMPRESSION_ZIP; $imagick = $this->image->getCore(); $imagick->setFormat($format); $imagick->setImageFormat($format); $imagick->setCompression($compression); $imagick->setImageCompression($compression); $this->image->mime = image_type_to_mime_type(IMAGETYPE_PNG); return $imagick->getImagesBlob(); } /** * Processes and returns encoded image as GIF string * * @return string */ protected function processGif() { $format = 'gif'; $compression = \Imagick::COMPRESSION_LZW; $imagick = $this->image->getCore(); $imagick->setFormat($format); $imagick->setImageFormat($format); $imagick->setCompression($compression); $imagick->setImageCompression($compression); $this->image->mime = image_type_to_mime_type(IMAGETYPE_GIF); return $imagick->getImagesBlob(); } protected function processWebp() { if ( ! \Imagick::queryFormats('WEBP')) { throw new NotSupportedException( "Webp format is not supported by Imagick installation." ); } $format = 'webp'; $compression = \Imagick::COMPRESSION_JPEG; $imagick = $this->image->getCore(); $imagick->setImageBackgroundColor(new \ImagickPixel('transparent')); $imagick = $imagick->mergeImageLayers(\Imagick::LAYERMETHOD_MERGE); $imagick->setFormat($format); $imagick->setImageFormat($format); $imagick->setCompression($compression); $imagick->setImageCompression($compression); $imagick->setImageCompressionQuality($this->quality); return $imagick->getImagesBlob(); } /** * Processes and returns encoded image as TIFF string * * @return string */ protected function processTiff() { $format = 'tiff'; $compression = \Imagick::COMPRESSION_UNDEFINED; $imagick = $this->image->getCore(); $imagick->setFormat($format); $imagick->setImageFormat($format); $imagick->setCompression($compression); $imagick->setImageCompression($compression); $imagick->setCompressionQuality($this->quality); $imagick->setImageCompressionQuality($this->quality); $this->image->mime = image_type_to_mime_type(IMAGETYPE_TIFF_II); return $imagick->getImagesBlob(); } /** * Processes and returns encoded image as BMP string * * @return string */ protected function processBmp() { $format = 'bmp'; $compression = \Imagick::COMPRESSION_UNDEFINED; $imagick = $this->image->getCore(); $imagick->setFormat($format); $imagick->setImageFormat($format); $imagick->setCompression($compression); $imagick->setImageCompression($compression); $this->image->mime = image_type_to_mime_type(IMAGETYPE_BMP); return $imagick->getImagesBlob(); } /** * Processes and returns encoded image as ICO string * * @return string */ protected function processIco() { $format = 'ico'; $compression = \Imagick::COMPRESSION_UNDEFINED; $imagick = $this->image->getCore(); $imagick->setFormat($format); $imagick->setImageFormat($format); $imagick->setCompression($compression); $imagick->setImageCompression($compression); $this->image->mime = image_type_to_mime_type(IMAGETYPE_ICO); return $imagick->getImagesBlob(); } /** * Processes and returns encoded image as PSD string * * @return string */ protected function processPsd() { $format = 'psd'; $compression = \Imagick::COMPRESSION_UNDEFINED; $imagick = $this->image->getCore(); $imagick->setFormat($format); $imagick->setImageFormat($format); $imagick->setCompression($compression); $imagick->setImageCompression($compression); $this->image->mime = image_type_to_mime_type(IMAGETYPE_PSD); return $imagick->getImagesBlob(); } /** * Processes and returns encoded image as AVIF string * * @return string */ protected function processAvif() { if ( ! \Imagick::queryFormats('AVIF')) { throw new NotSupportedException( "AVIF format is not supported by Imagick installation." ); } $format = 'avif'; $compression = \Imagick::COMPRESSION_UNDEFINED; $imagick = $this->image->getCore(); $imagick->setFormat($format); $imagick->setImageFormat($format); $imagick->setCompression($compression); $imagick->setImageCompression($compression); $imagick->setCompressionQuality($this->quality); $imagick->setImageCompressionQuality($this->quality); return $imagick->getImagesBlob(); } /** * Processes and returns encoded image as HEIC string * * @return string */ protected function processHeic() { if ( ! \Imagick::queryFormats('HEIC')) { throw new NotSupportedException( "HEIC format is not supported by Imagick installation." ); } $format = 'heic'; $compression = \Imagick::COMPRESSION_UNDEFINED; $imagick = $this->image->getCore(); $imagick->setFormat($format); $imagick->setImageFormat($format); $imagick->setCompression($compression); $imagick->setImageCompression($compression); $imagick->setCompressionQuality($this->quality); $imagick->setImageCompressionQuality($this->quality); return $imagick->getImagesBlob(); } } src/Intervention/Image/Imagick/Shapes/RectangleShape.php 0000644 00000003625 15111232403 0017224 0 ustar 00 <?php namespace Intervention\Image\Imagick\Shapes; use Intervention\Image\AbstractShape; use Intervention\Image\Image; use Intervention\Image\Imagick\Color; class RectangleShape extends AbstractShape { /** * X-Coordinate of top-left point * * @var int */ public $x1 = 0; /** * Y-Coordinate of top-left point * * @var int */ public $y1 = 0; /** * X-Coordinate of bottom-right point * * @var int */ public $x2 = 0; /** * Y-Coordinate of bottom-right point * * @var int */ public $y2 = 0; /** * Create new rectangle shape instance * * @param int $x1 * @param int $y1 * @param int $x2 * @param int $y2 */ public function __construct($x1 = null, $y1 = null, $x2 = null, $y2 = null) { $this->x1 = is_numeric($x1) ? intval($x1) : $this->x1; $this->y1 = is_numeric($y1) ? intval($y1) : $this->y1; $this->x2 = is_numeric($x2) ? intval($x2) : $this->x2; $this->y2 = is_numeric($y2) ? intval($y2) : $this->y2; } /** * Draw rectangle to given image at certain position * * @param Image $image * @param int $x * @param int $y * @return boolean */ public function applyToImage(Image $image, $x = 0, $y = 0) { $rectangle = new \ImagickDraw; // set background $bgcolor = new Color($this->background); $rectangle->setFillColor($bgcolor->getPixel()); // set border if ($this->hasBorder()) { $border_color = new Color($this->border_color); $rectangle->setStrokeWidth($this->border_width); $rectangle->setStrokeColor($border_color->getPixel()); } $rectangle->rectangle($this->x1, $this->y1, $this->x2, $this->y2); $image->getCore()->drawImage($rectangle); return true; } } src/Intervention/Image/Imagick/Shapes/PolygonShape.php 0000644 00000003351 15111232403 0016743 0 ustar 00 <?php namespace Intervention\Image\Imagick\Shapes; use Intervention\Image\AbstractShape; use Intervention\Image\Image; use Intervention\Image\Imagick\Color; class PolygonShape extends AbstractShape { /** * Array of points of polygon * * @var array */ public $points; /** * Create new polygon instance * * @param array $points */ public function __construct($points) { $this->points = $this->formatPoints($points); } /** * Draw polygon on given image * * @param Image $image * @param int $x * @param int $y * @return boolean */ public function applyToImage(Image $image, $x = 0, $y = 0) { $polygon = new \ImagickDraw; // set background $bgcolor = new Color($this->background); $polygon->setFillColor($bgcolor->getPixel()); // set border if ($this->hasBorder()) { $border_color = new Color($this->border_color); $polygon->setStrokeWidth($this->border_width); $polygon->setStrokeColor($border_color->getPixel()); } $polygon->polygon($this->points); $image->getCore()->drawImage($polygon); return true; } /** * Format polygon points to Imagick format * * @param Array $points * @return Array */ private function formatPoints($points) { $ipoints = []; $count = 1; foreach ($points as $key => $value) { if ($count%2 === 0) { $y = $value; $ipoints[] = ['x' => $x, 'y' => $y]; } else { $x = $value; } $count++; } return $ipoints; } } src/Intervention/Image/Imagick/Shapes/LineShape.php 0000644 00000003425 15111232403 0016205 0 ustar 00 <?php namespace Intervention\Image\Imagick\Shapes; use Intervention\Image\AbstractShape; use Intervention\Image\Image; use Intervention\Image\Imagick\Color; class LineShape extends AbstractShape { /** * Starting point x-coordinate of line * * @var int */ public $x = 0; /** * Starting point y-coordinate of line * * @var int */ public $y = 0; /** * Color of line * * @var string */ public $color = '#000000'; /** * Width of line in pixels * * @var int */ public $width = 1; /** * Create new line shape instance * * @param int $x * @param int $y */ public function __construct($x = null, $y = null) { $this->x = is_numeric($x) ? intval($x) : $this->x; $this->y = is_numeric($y) ? intval($y) : $this->y; } /** * Set current line color * * @param string $color * @return void */ public function color($color) { $this->color = $color; } /** * Set current line width in pixels * * @param int $width * @return void */ public function width($width) { $this->width = $width; } /** * Draw current instance of line to given endpoint on given image * * @param Image $image * @param int $x * @param int $y * @return boolean */ public function applyToImage(Image $image, $x = 0, $y = 0) { $line = new \ImagickDraw; $color = new Color($this->color); $line->setStrokeColor($color->getPixel()); $line->setStrokeWidth($this->width); $line->line($this->x, $this->y, $x, $y); $image->getCore()->drawImage($line); return true; } } src/Intervention/Image/Imagick/Shapes/EllipseShape.php 0000644 00000003023 15111232403 0016705 0 ustar 00 <?php namespace Intervention\Image\Imagick\Shapes; use Intervention\Image\AbstractShape; use Intervention\Image\Image; use Intervention\Image\Imagick\Color; class EllipseShape extends AbstractShape { /** * Width of ellipse in pixels * * @var int */ public $width = 100; /** * Height of ellipse in pixels * * @var int */ public $height = 100; /** * Create new ellipse instance * * @param int $width * @param int $height */ public function __construct($width = null, $height = null) { $this->width = is_numeric($width) ? intval($width) : $this->width; $this->height = is_numeric($height) ? intval($height) : $this->height; } /** * Draw ellipse instance on given image * * @param Image $image * @param int $x * @param int $y * @return boolean */ public function applyToImage(Image $image, $x = 0, $y = 0) { $circle = new \ImagickDraw; // set background $bgcolor = new Color($this->background); $circle->setFillColor($bgcolor->getPixel()); // set border if ($this->hasBorder()) { $border_color = new Color($this->border_color); $circle->setStrokeWidth($this->border_width); $circle->setStrokeColor($border_color->getPixel()); } $circle->ellipse($x, $y, $this->width / 2, $this->height / 2, 0, 360); $image->getCore()->drawImage($circle); return true; } } src/Intervention/Image/Imagick/Shapes/CircleShape.php 0000644 00000001650 15111232403 0016515 0 ustar 00 <?php namespace Intervention\Image\Imagick\Shapes; use Intervention\Image\Image; class CircleShape extends EllipseShape { /** * Diameter of circle in pixels * * @var int */ public $diameter = 100; /** * Create new instance of circle * * @param int $diameter */ public function __construct($diameter = null) { $this->width = is_numeric($diameter) ? intval($diameter) : $this->diameter; $this->height = is_numeric($diameter) ? intval($diameter) : $this->diameter; $this->diameter = is_numeric($diameter) ? intval($diameter) : $this->diameter; } /** * Draw current circle on given image * * @param Image $image * @param int $x * @param int $y * @return boolean */ public function applyToImage(Image $image, $x = 0, $y = 0) { return parent::applyToImage($image, $x, $y); } } src/Intervention/Image/Imagick/Commands/WidenCommand.php 0000644 00000001440 15111232403 0017213 0 ustar 00 <?php namespace Intervention\Image\Imagick\Commands; class WidenCommand extends ResizeCommand { /** * Resize image proportionally to given width * * @param \Intervention\Image\Image $image * @return boolean */ public function execute($image) { $width = $this->argument(0)->type('digit')->required()->value(); $additionalConstraints = $this->argument(1)->type('closure')->value(); $this->arguments[0] = $width; $this->arguments[1] = null; $this->arguments[2] = function ($constraint) use ($additionalConstraints) { $constraint->aspectRatio(); if(is_callable($additionalConstraints)) $additionalConstraints($constraint); }; return parent::execute($image); } } src/Intervention/Image/Imagick/Commands/TrimCommand.php 0000644 00000007125 15111232403 0017066 0 ustar 00 <?php namespace Intervention\Image\Imagick\Commands; use Intervention\Image\Commands\AbstractCommand; use Intervention\Image\Imagick\Color; class TrimCommand extends AbstractCommand { /** * Trims away parts of an image * * @param \Intervention\Image\Image $image * @return boolean */ public function execute($image) { $base = $this->argument(0)->type('string')->value(); $away = $this->argument(1)->value(); $tolerance = $this->argument(2)->type('numeric')->value(0); $feather = $this->argument(3)->type('numeric')->value(0); $width = $image->getWidth(); $height = $image->getHeight(); $checkTransparency = false; // define borders to trim away if (is_null($away)) { $away = ['top', 'right', 'bottom', 'left']; } elseif (is_string($away)) { $away = [$away]; } // lower border names foreach ($away as $key => $value) { $away[$key] = strtolower($value); } // define base color position switch (strtolower($base)) { case 'transparent': case 'trans': $checkTransparency = true; $base_x = 0; $base_y = 0; break; case 'bottom-right': case 'right-bottom': $base_x = $width - 1; $base_y = $height - 1; break; default: case 'top-left': case 'left-top': $base_x = 0; $base_y = 0; break; } // pick base color if ($checkTransparency) { $base_color = new Color; // color will only be used to compare alpha channel } else { $base_color = $image->pickColor($base_x, $base_y, 'object'); } // trim on clone to get only coordinates $trimed = clone $image->getCore(); // add border to trim specific color $trimed->borderImage($base_color->getPixel(), 1, 1); // trim image $trimed->trimImage(65850 / 100 * $tolerance); // get coordinates of trim $imagePage = $trimed->getImagePage(); list($crop_x, $crop_y) = [$imagePage['x']-1, $imagePage['y']-1]; // $trimed->setImagePage(0, 0, 0, 0); list($crop_width, $crop_height) = [$trimed->width, $trimed->height]; // adjust settings if right should not be trimed if ( ! in_array('right', $away)) { $crop_width = $crop_width + ($width - ($width - $crop_x)); } // adjust settings if bottom should not be trimed if ( ! in_array('bottom', $away)) { $crop_height = $crop_height + ($height - ($height - $crop_y)); } // adjust settings if left should not be trimed if ( ! in_array('left', $away)) { $crop_width = $crop_width + $crop_x; $crop_x = 0; } // adjust settings if top should not be trimed if ( ! in_array('top', $away)) { $crop_height = $crop_height + $crop_y; $crop_y = 0; } // add feather $crop_width = min($width, ($crop_width + $feather * 2)); $crop_height = min($height, ($crop_height + $feather * 2)); $crop_x = max(0, ($crop_x - $feather)); $crop_y = max(0, ($crop_y - $feather)); // finally crop based on page $image->getCore()->cropImage($crop_width, $crop_height, $crop_x, $crop_y); $image->getCore()->setImagePage(0,0,0,0); $trimed->destroy(); return true; } } src/Intervention/Image/Imagick/Commands/RotateCommand.php 0000644 00000001403 15111232403 0017402 0 ustar 00 <?php namespace Intervention\Image\Imagick\Commands; use Intervention\Image\Commands\AbstractCommand; use Intervention\Image\Imagick\Color; class RotateCommand extends AbstractCommand { /** * Rotates image counter clockwise * * @param \Intervention\Image\Image $image * @return boolean */ public function execute($image) { $angle = $this->argument(0)->type('numeric')->required()->value(); $color = $this->argument(1)->value(); $color = new Color($color); // restrict rotations beyond 360 degrees, since the end result is the same $angle = fmod($angle, 360); // rotate image $image->getCore()->rotateImage($color->getPixel(), ($angle * -1)); return true; } } src/Intervention/Image/Imagick/Commands/BrightnessCommand.php 0000644 00000000743 15111232403 0020262 0 ustar 00 <?php namespace Intervention\Image\Imagick\Commands; use Intervention\Image\Commands\AbstractCommand; class BrightnessCommand extends AbstractCommand { /** * Changes image brightness * * @param \Intervention\Image\Image $image * @return boolean */ public function execute($image) { $level = $this->argument(0)->between(-100, 100)->required()->value(); return $image->getCore()->modulateImage(100 + $level, 100, 100); } } src/Intervention/Image/Imagick/Commands/FlipCommand.php 0000644 00000001164 15111232403 0017042 0 ustar 00 <?php namespace Intervention\Image\Imagick\Commands; use Intervention\Image\Commands\AbstractCommand; class FlipCommand extends AbstractCommand { /** * Mirrors an image * * @param \Intervention\Image\Image $image * @return boolean */ public function execute($image) { $mode = $this->argument(0)->value('h'); if (in_array(strtolower($mode), [2, 'v', 'vert', 'vertical'])) { // flip vertical return $image->getCore()->flipImage(); } else { // flip horizontal return $image->getCore()->flopImage(); } } } src/Intervention/Image/Imagick/Commands/SharpenCommand.php 0000644 00000000715 15111232403 0017551 0 ustar 00 <?php namespace Intervention\Image\Imagick\Commands; use Intervention\Image\Commands\AbstractCommand; class SharpenCommand extends AbstractCommand { /** * Sharpen image * * @param \Intervention\Image\Image $image * @return boolean */ public function execute($image) { $amount = $this->argument(0)->between(0, 100)->value(10); return $image->getCore()->unsharpMaskImage(1, 1, $amount / 6.25, 0); } } src/Intervention/Image/Imagick/Commands/GreyscaleCommand.php 0000644 00000000627 15111232403 0020071 0 ustar 00 <?php namespace Intervention\Image\Imagick\Commands; use Intervention\Image\Commands\AbstractCommand; class GreyscaleCommand extends AbstractCommand { /** * Turns an image into a greyscale version * * @param \Intervention\Image\Image $image * @return boolean */ public function execute($image) { return $image->getCore()->modulateImage(100, 0, 100); } } src/Intervention/Image/Imagick/Commands/InvertCommand.php 0000644 00000000577 15111232403 0017426 0 ustar 00 <?php namespace Intervention\Image\Imagick\Commands; use Intervention\Image\Commands\AbstractCommand; class InvertCommand extends AbstractCommand { /** * Inverts colors of an image * * @param \Intervention\Image\Image $image * @return boolean */ public function execute($image) { return $image->getCore()->negateImage(false); } } src/Intervention/Image/Imagick/Commands/ColorizeCommand.php 0000644 00000002472 15111232404 0017742 0 ustar 00 <?php namespace Intervention\Image\Imagick\Commands; use Intervention\Image\Commands\AbstractCommand; class ColorizeCommand extends AbstractCommand { /** * Changes balance of different RGB color channels * * @param \Intervention\Image\Image $image * @return boolean */ public function execute($image) { $red = $this->argument(0)->between(-100, 100)->required()->value(); $green = $this->argument(1)->between(-100, 100)->required()->value(); $blue = $this->argument(2)->between(-100, 100)->required()->value(); // normalize colorize levels $red = $this->normalizeLevel($red); $green = $this->normalizeLevel($green); $blue = $this->normalizeLevel($blue); $qrange = $image->getCore()->getQuantumRange(); // apply $image->getCore()->levelImage(0, $red, $qrange['quantumRangeLong'], \Imagick::CHANNEL_RED); $image->getCore()->levelImage(0, $green, $qrange['quantumRangeLong'], \Imagick::CHANNEL_GREEN); $image->getCore()->levelImage(0, $blue, $qrange['quantumRangeLong'], \Imagick::CHANNEL_BLUE); return true; } private function normalizeLevel($level) { if ($level > 0) { return $level/5; } else { return ($level+100)/100; } } } src/Intervention/Image/Imagick/Commands/HeightenCommand.php 0000644 00000001446 15111232404 0017707 0 ustar 00 <?php namespace Intervention\Image\Imagick\Commands; class HeightenCommand extends ResizeCommand { /** * Resize image proportionally to given height * * @param \Intervention\Image\Image $image * @return boolean */ public function execute($image) { $height = $this->argument(0)->type('digit')->required()->value(); $additionalConstraints = $this->argument(1)->type('closure')->value(); $this->arguments[0] = null; $this->arguments[1] = $height; $this->arguments[2] = function ($constraint) use ($additionalConstraints) { $constraint->aspectRatio(); if(is_callable($additionalConstraints)) $additionalConstraints($constraint); }; return parent::execute($image); } } src/Intervention/Image/Imagick/Commands/PixelateCommand.php 0000644 00000001237 15111232404 0017725 0 ustar 00 <?php namespace Intervention\Image\Imagick\Commands; use Intervention\Image\Commands\AbstractCommand; class PixelateCommand extends AbstractCommand { /** * Applies a pixelation effect to a given image * * @param \Intervention\Image\Image $image * @return boolean */ public function execute($image) { $size = $this->argument(0)->type('digit')->value(10); $width = $image->getWidth(); $height = $image->getHeight(); $image->getCore()->scaleImage(max(1, intval($width / $size)), max(1, intval($height / $size))); $image->getCore()->scaleImage($width, $height); return true; } } src/Intervention/Image/Imagick/Commands/ContrastCommand.php 0000644 00000000756 15111232404 0017754 0 ustar 00 <?php namespace Intervention\Image\Imagick\Commands; use Intervention\Image\Commands\AbstractCommand; class ContrastCommand extends AbstractCommand { /** * Changes contrast of image * * @param \Intervention\Image\Image $image * @return boolean */ public function execute($image) { $level = $this->argument(0)->between(-100, 100)->required()->value(); return $image->getCore()->sigmoidalContrastImage($level > 0, $level / 4, 0); } } src/Intervention/Image/Imagick/Commands/InsertCommand.php 0000644 00000002047 15111232404 0017416 0 ustar 00 <?php namespace Intervention\Image\Imagick\Commands; use Intervention\Image\Commands\AbstractCommand; class InsertCommand extends AbstractCommand { /** * Insert another image into given image * * @param \Intervention\Image\Image $image * @return boolean */ public function execute($image) { $source = $this->argument(0)->required()->value(); $position = $this->argument(1)->type('string')->value(); $x = $this->argument(2)->type('digit')->value(0); $y = $this->argument(3)->type('digit')->value(0); // build watermark $watermark = $image->getDriver()->init($source); // define insertion point $image_size = $image->getSize()->align($position, $x, $y); $watermark_size = $watermark->getSize()->align($position); $target = $image_size->relativePosition($watermark_size); // insert image at position return $image->getCore()->compositeImage($watermark->getCore(), \Imagick::COMPOSITE_DEFAULT, $target->x, $target->y); } } src/Intervention/Image/Imagick/Commands/ResizeCommand.php 0000644 00000001320 15111232404 0017404 0 ustar 00 <?php namespace Intervention\Image\Imagick\Commands; use Intervention\Image\Commands\AbstractCommand; class ResizeCommand extends AbstractCommand { /** * Resizes image dimensions * * @param \Intervention\Image\Image $image * @return boolean */ public function execute($image) { $width = $this->argument(0)->value(); $height = $this->argument(1)->value(); $constraints = $this->argument(2)->type('closure')->value(); // resize box $resized = $image->getSize()->resize($width, $height, $constraints); // modify image $image->getCore()->scaleImage($resized->getWidth(), $resized->getHeight()); return true; } } src/Intervention/Image/Imagick/Commands/CropCommand.php 0000644 00000002521 15111232404 0017052 0 ustar 00 <?php namespace Intervention\Image\Imagick\Commands; use Intervention\Image\Commands\AbstractCommand; use Intervention\Image\Exception\InvalidArgumentException; use Intervention\Image\Point; use Intervention\Image\Size; class CropCommand extends AbstractCommand { /** * Crop an image instance * * @param \Intervention\Image\Image $image * @return boolean */ public function execute($image) { $width = $this->argument(0)->type('digit')->required()->value(); $height = $this->argument(1)->type('digit')->required()->value(); $x = $this->argument(2)->type('digit')->value(); $y = $this->argument(3)->type('digit')->value(); if (is_null($width) || is_null($height)) { throw new InvalidArgumentException( "Width and height of cutout needs to be defined." ); } $cropped = new Size($width, $height); $position = new Point($x, $y); // align boxes if (is_null($x) && is_null($y)) { $position = $image->getSize()->align('center')->relativePosition($cropped->align('center')); } // crop image core $image->getCore()->cropImage($cropped->width, $cropped->height, $position->x, $position->y); $image->getCore()->setImagePage(0,0,0,0); return true; } } src/Intervention/Image/Imagick/Commands/ExifCommand.php 0000644 00000002770 15111232404 0017050 0 ustar 00 <?php namespace Intervention\Image\Imagick\Commands; use Intervention\Image\Commands\ExifCommand as BaseCommand; use Intervention\Image\Exception\NotSupportedException; class ExifCommand extends BaseCommand { /** * Prefer extension or not * * @var bool */ private $preferExtension = true; /** * */ public function dontPreferExtension() { $this->preferExtension = false; } /** * Read Exif data from the given image * * @param \Intervention\Image\Image $image * @return boolean */ public function execute($image) { if ($this->preferExtension && function_exists('exif_read_data')) { return parent::execute($image); } $core = $image->getCore(); if ( ! method_exists($core, 'getImageProperties')) { throw new NotSupportedException( "Reading Exif data is not supported by this PHP installation." ); } $requestedKey = $this->argument(0)->value(); if ($requestedKey !== null) { $this->setOutput($core->getImageProperty('exif:' . $requestedKey)); return true; } $exif = []; $properties = $core->getImageProperties(); foreach ($properties as $key => $value) { if (substr($key, 0, 5) !== 'exif:') { continue; } $exif[substr($key, 5)] = $value; } $this->setOutput($exif); return true; } } src/Intervention/Image/Imagick/Commands/ResizeCanvasCommand.php 0000644 00000006145 15111232404 0020552 0 ustar 00 <?php namespace Intervention\Image\Imagick\Commands; use Intervention\Image\Commands\AbstractCommand; class ResizeCanvasCommand extends AbstractCommand { /** * Resizes image boundaries * * @param \Intervention\Image\Image $image * @return boolean */ public function execute($image) { $width = $this->argument(0)->type('digit')->required()->value(); $height = $this->argument(1)->type('digit')->required()->value(); $anchor = $this->argument(2)->value('center'); $relative = $this->argument(3)->type('boolean')->value(false); $bgcolor = $this->argument(4)->value(); $original_width = $image->getWidth(); $original_height = $image->getHeight(); // check of only width or height is set $width = is_null($width) ? $original_width : intval($width); $height = is_null($height) ? $original_height : intval($height); // check on relative width/height if ($relative) { $width = $original_width + $width; $height = $original_height + $height; } // check for negative width/height $width = ($width <= 0) ? $width + $original_width : $width; $height = ($height <= 0) ? $height + $original_height : $height; // create new canvas $canvas = $image->getDriver()->newImage($width, $height, $bgcolor); // set copy position $canvas_size = $canvas->getSize()->align($anchor); $image_size = $image->getSize()->align($anchor); $canvas_pos = $image_size->relativePosition($canvas_size); $image_pos = $canvas_size->relativePosition($image_size); if ($width <= $original_width) { $dst_x = 0; $src_x = $canvas_pos->x; $src_w = $canvas_size->width; } else { $dst_x = $image_pos->x; $src_x = 0; $src_w = $original_width; } if ($height <= $original_height) { $dst_y = 0; $src_y = $canvas_pos->y; $src_h = $canvas_size->height; } else { $dst_y = $image_pos->y; $src_y = 0; $src_h = $original_height; } // make image area transparent to keep transparency // even if background-color is set $rect = new \ImagickDraw; $fill = $canvas->pickColor(0, 0, 'hex'); $fill = $fill == '#ff0000' ? '#00ff00' : '#ff0000'; $rect->setFillColor($fill); $rect->rectangle($dst_x, $dst_y, $dst_x + $src_w - 1, $dst_y + $src_h - 1); $canvas->getCore()->drawImage($rect); $canvas->getCore()->transparentPaintImage($fill, 0, 0, false); $canvas->getCore()->setImageColorspace($image->getCore()->getImageColorspace()); // copy image into new canvas $image->getCore()->cropImage($src_w, $src_h, $src_x, $src_y); $canvas->getCore()->compositeImage($image->getCore(), \Imagick::COMPOSITE_DEFAULT, $dst_x, $dst_y); $canvas->getCore()->setImagePage(0,0,0,0); // set new core to canvas $image->setCore($canvas->getCore()); return true; } } src/Intervention/Image/Imagick/Commands/ResetCommand.php 0000644 00000001627 15111232404 0017237 0 ustar 00 <?php namespace Intervention\Image\Imagick\Commands; use Intervention\Image\Commands\AbstractCommand; use Intervention\Image\Exception\RuntimeException; class ResetCommand extends AbstractCommand { /** * Resets given image to its backup state * * @param \Intervention\Image\Image $image * @return boolean */ public function execute($image) { $backupName = $this->argument(0)->value(); $backup = $image->getBackup($backupName); if ($backup instanceof \Imagick) { // destroy current core $image->getCore()->clear(); // clone backup $backup = clone $backup; // reset to new resource $image->setCore($backup); return true; } throw new RuntimeException( "Backup not available. Call backup({$backupName}) before reset()." ); } } src/Intervention/Image/Imagick/Commands/BlurCommand.php 0000644 00000000724 15111232404 0017056 0 ustar 00 <?php namespace Intervention\Image\Imagick\Commands; use Intervention\Image\Commands\AbstractCommand; class BlurCommand extends AbstractCommand { /** * Applies blur effect on image * * @param \Intervention\Image\Image $image * @return boolean */ public function execute($image) { $amount = $this->argument(0)->between(0, 100)->value(1); return $image->getCore()->blurImage(1 * $amount, 0.5 * $amount); } } src/Intervention/Image/Imagick/Commands/DestroyCommand.php 0000644 00000001057 15111232404 0017603 0 ustar 00 <?php namespace Intervention\Image\Imagick\Commands; use Intervention\Image\Commands\AbstractCommand; class DestroyCommand extends AbstractCommand { /** * Destroys current image core and frees up memory * * @param \Intervention\Image\Image $image * @return boolean */ public function execute($image) { // destroy image core $image->getCore()->clear(); // destroy backups foreach ($image->getBackups() as $backup) { $backup->clear(); } return true; } } src/Intervention/Image/Imagick/Commands/MaskCommand.php 0000644 00000003622 15111232404 0017045 0 ustar 00 <?php namespace Intervention\Image\Imagick\Commands; use Intervention\Image\Commands\AbstractCommand; class MaskCommand extends AbstractCommand { /** * Applies an alpha mask to an image * * @param \Intervention\Image\Image $image * @return boolean */ public function execute($image) { $mask_source = $this->argument(0)->value(); $mask_w_alpha = $this->argument(1)->type('bool')->value(false); // get imagick $imagick = $image->getCore(); // build mask image from source $mask = $image->getDriver()->init($mask_source); // resize mask to size of current image (if necessary) $image_size = $image->getSize(); if ($mask->getSize() != $image_size) { $mask->resize($image_size->width, $image_size->height); } $imagick->setImageMatte(true); if ($mask_w_alpha) { // just mask with alpha map $imagick->compositeImage($mask->getCore(), \Imagick::COMPOSITE_DSTIN, 0, 0); } else { // get alpha channel of original as greyscale image $original_alpha = clone $imagick; $original_alpha->separateImageChannel(\Imagick::CHANNEL_ALPHA); // use red channel from mask ask alpha $mask_alpha = clone $mask->getCore(); $mask_alpha->compositeImage($mask->getCore(), \Imagick::COMPOSITE_DEFAULT, 0, 0); // $mask_alpha->setImageAlphaChannel(\Imagick::ALPHACHANNEL_DEACTIVATE); $mask_alpha->separateImageChannel(\Imagick::CHANNEL_ALL); // combine both alphas from original and mask $original_alpha->compositeImage($mask_alpha, \Imagick::COMPOSITE_COPYOPACITY, 0, 0); // mask the image with the alpha combination $imagick->compositeImage($original_alpha, \Imagick::COMPOSITE_DSTIN, 0, 0); } return true; } } src/Intervention/Image/Imagick/Commands/LimitColorsCommand.php 0000644 00000003401 15111232404 0020405 0 ustar 00 <?php namespace Intervention\Image\Imagick\Commands; use Intervention\Image\Commands\AbstractCommand; class LimitColorsCommand extends AbstractCommand { /** * Reduces colors of a given image * * @param \Intervention\Image\Image $image * @return boolean */ public function execute($image) { $count = $this->argument(0)->value(); $matte = $this->argument(1)->value(); // get current image size $size = $image->getSize(); // build 2 color alpha mask from original alpha $alpha = clone $image->getCore(); $alpha->separateImageChannel(\Imagick::CHANNEL_ALPHA); $alpha->transparentPaintImage('#ffffff', 0, 0, false); $alpha->separateImageChannel(\Imagick::CHANNEL_ALPHA); $alpha->negateImage(false); if ($matte) { // get matte color $mattecolor = $image->getDriver()->parseColor($matte)->getPixel(); // create matte image $canvas = new \Imagick; $canvas->newImage($size->width, $size->height, $mattecolor, 'png'); // lower colors of original and copy to matte $image->getCore()->quantizeImage($count, \Imagick::COLORSPACE_RGB, 0, false, false); $canvas->compositeImage($image->getCore(), \Imagick::COMPOSITE_DEFAULT, 0, 0); // copy new alpha to canvas $canvas->compositeImage($alpha, \Imagick::COMPOSITE_COPYOPACITY, 0, 0); // replace core $image->setCore($canvas); } else { $image->getCore()->quantizeImage($count, \Imagick::COLORSPACE_RGB, 0, false, false); $image->getCore()->compositeImage($alpha, \Imagick::COMPOSITE_COPYOPACITY, 0, 0); } return true; } } src/Intervention/Image/Imagick/Commands/PixelCommand.php 0000644 00000001463 15111232404 0017234 0 ustar 00 <?php namespace Intervention\Image\Imagick\Commands; use Intervention\Image\Commands\AbstractCommand; use Intervention\Image\Imagick\Color; class PixelCommand extends AbstractCommand { /** * Draws one pixel to a given image * * @param \Intervention\Image\Image $image * @return boolean */ public function execute($image) { $color = $this->argument(0)->required()->value(); $color = new Color($color); $x = $this->argument(1)->type('digit')->required()->value(); $y = $this->argument(2)->type('digit')->required()->value(); // prepare pixel $draw = new \ImagickDraw; $draw->setFillColor($color->getPixel()); $draw->point($x, $y); // apply pixel return $image->getCore()->drawImage($draw); } } src/Intervention/Image/Imagick/Commands/InterlaceCommand.php 0000644 00000001151 15111232404 0020053 0 ustar 00 <?php namespace Intervention\Image\Imagick\Commands; use Intervention\Image\Commands\AbstractCommand; class InterlaceCommand extends AbstractCommand { /** * Toggles interlaced encoding mode * * @param \Intervention\Image\Image $image * @return boolean */ public function execute($image) { $mode = $this->argument(0)->type('bool')->value(true); if ($mode) { $mode = \Imagick::INTERLACE_LINE; } else { $mode = \Imagick::INTERLACE_NO; } $image->getCore()->setInterlaceScheme($mode); return true; } } src/Intervention/Image/Imagick/Commands/FitCommand.php 0000644 00000002331 15111232404 0016670 0 ustar 00 <?php namespace Intervention\Image\Imagick\Commands; use Intervention\Image\Commands\AbstractCommand; use Intervention\Image\Size; class FitCommand extends AbstractCommand { /** * Crops and resized an image at the same time * * @param \Intervention\Image\Image $image * @return boolean */ public function execute($image) { $width = $this->argument(0)->type('digit')->required()->value(); $height = $this->argument(1)->type('digit')->value($width); $constraints = $this->argument(2)->type('closure')->value(); $position = $this->argument(3)->type('string')->value('center'); // calculate size $cropped = $image->getSize()->fit(new Size($width, $height), $position); $resized = clone $cropped; $resized = $resized->resize($width, $height, $constraints); // crop image $image->getCore()->cropImage( $cropped->width, $cropped->height, $cropped->pivot->x, $cropped->pivot->y ); // resize image $image->getCore()->scaleImage($resized->getWidth(), $resized->getHeight()); $image->getCore()->setImagePage(0,0,0,0); return true; } } src/Intervention/Image/Imagick/Commands/OpacityCommand.php 0000644 00000001145 15111232404 0017560 0 ustar 00 <?php namespace Intervention\Image\Imagick\Commands; use Intervention\Image\Commands\AbstractCommand; class OpacityCommand extends AbstractCommand { /** * Defines opacity of an image * * @param \Intervention\Image\Image $image * @return boolean */ public function execute($image) { $transparency = $this->argument(0)->between(0, 100)->required()->value(); $transparency = $transparency > 0 ? (100 / $transparency) : 1000; return $image->getCore()->evaluateImage(\Imagick::EVALUATE_DIVIDE, $transparency, \Imagick::CHANNEL_ALPHA); } } src/Intervention/Image/Imagick/Commands/PickColorCommand.php 0000644 00000001436 15111232404 0020040 0 ustar 00 <?php namespace Intervention\Image\Imagick\Commands; use Intervention\Image\Commands\AbstractCommand; use Intervention\Image\Imagick\Color; class PickColorCommand extends AbstractCommand { /** * Read color information from a certain position * * @param \Intervention\Image\Image $image * @return boolean */ public function execute($image) { $x = $this->argument(0)->type('digit')->required()->value(); $y = $this->argument(1)->type('digit')->required()->value(); $format = $this->argument(2)->type('string')->value('array'); // pick color $color = new Color($image->getCore()->getImagePixelColor($x, $y)); // format to output $this->setOutput($color->format($format)); return true; } } src/Intervention/Image/Imagick/Commands/GammaCommand.php 0000644 00000000731 15111232404 0017172 0 ustar 00 <?php namespace Intervention\Image\Imagick\Commands; use Intervention\Image\Commands\AbstractCommand; class GammaCommand extends AbstractCommand { /** * Applies gamma correction to a given image * * @param \Intervention\Image\Image $image * @return boolean */ public function execute($image) { $gamma = $this->argument(0)->type('numeric')->required()->value(); return $image->getCore()->gammaImage($gamma); } } src/Intervention/Image/Imagick/Commands/FillCommand.php 0000644 00000006475 15111232405 0017052 0 ustar 00 <?php namespace Intervention\Image\Imagick\Commands; use Intervention\Image\Commands\AbstractCommand; use Intervention\Image\Exception\NotReadableException; use Intervention\Image\Image; use Intervention\Image\Imagick\Color; use Intervention\Image\Imagick\Decoder; class FillCommand extends AbstractCommand { /** * Fills image with color or pattern * * @param \Intervention\Image\Image $image * @return boolean */ public function execute($image) { $filling = $this->argument(0)->value(); $x = $this->argument(1)->type('digit')->value(); $y = $this->argument(2)->type('digit')->value(); $imagick = $image->getCore(); try { // set image filling $source = new Decoder; $filling = $source->init($filling); } catch (NotReadableException $e) { // set solid color filling $filling = new Color($filling); } // flood fill if coordinates are set if (is_int($x) && is_int($y)) { // flood fill with texture if ($filling instanceof Image) { // create tile $tile = clone $image->getCore(); // mask away color at position $tile->transparentPaintImage($tile->getImagePixelColor($x, $y), 0, 0, false); // create canvas $canvas = clone $image->getCore(); // fill canvas with texture $canvas = $canvas->textureImage($filling->getCore()); // merge canvas and tile $canvas->compositeImage($tile, \Imagick::COMPOSITE_DEFAULT, 0, 0); // replace image core $image->setCore($canvas); // flood fill with color } elseif ($filling instanceof Color) { // create canvas with filling $canvas = new \Imagick; $canvas->newImage($image->getWidth(), $image->getHeight(), $filling->getPixel(), 'png'); // create tile to put on top $tile = clone $image->getCore(); // mask away color at pos. $tile->transparentPaintImage($tile->getImagePixelColor($x, $y), 0, 0, false); // save alpha channel of original image $alpha = clone $image->getCore(); // merge original with canvas and tile $image->getCore()->compositeImage($canvas, \Imagick::COMPOSITE_DEFAULT, 0, 0); $image->getCore()->compositeImage($tile, \Imagick::COMPOSITE_DEFAULT, 0, 0); // restore alpha channel of original image $image->getCore()->compositeImage($alpha, \Imagick::COMPOSITE_COPYOPACITY, 0, 0); } } else { if ($filling instanceof Image) { // fill whole image with texture $image->setCore($image->getCore()->textureImage($filling->getCore())); } elseif ($filling instanceof Color) { // fill whole image with color $draw = new \ImagickDraw(); $draw->setFillColor($filling->getPixel()); $draw->rectangle(0, 0, $image->getWidth(), $image->getHeight()); $image->getCore()->drawImage($draw); } } return true; } } src/Intervention/Image/Imagick/Commands/BackupCommand.php 0000644 00000001051 15111232405 0017352 0 ustar 00 <?php namespace Intervention\Image\Imagick\Commands; use Intervention\Image\Commands\AbstractCommand; class BackupCommand extends AbstractCommand { /** * Saves a backups of current state of image core * * @param \Intervention\Image\Image $image * @return boolean */ public function execute($image) { $backupName = $this->argument(0)->value(); // clone current image resource $clone = clone $image; $image->setBackup($clone->getCore(), $backupName); return true; } } src/Intervention/Image/Imagick/Commands/GetSizeCommand.php 0000644 00000001115 15111232405 0017520 0 ustar 00 <?php namespace Intervention\Image\Imagick\Commands; use Intervention\Image\Commands\AbstractCommand; use Intervention\Image\Size; class GetSizeCommand extends AbstractCommand { /** * Reads size of given image instance in pixels * * @param \Intervention\Image\Image $image * @return boolean */ public function execute($image) { /** @var \Imagick $core */ $core = $image->getCore(); $this->setOutput(new Size( $core->getImageWidth(), $core->getImageHeight() )); return true; } } src/Intervention/Image/Imagick/Font.php 0000644 00000006503 15111232405 0014022 0 ustar 00 <?php namespace Intervention\Image\Imagick; use Intervention\Image\AbstractFont; use Intervention\Image\Exception\RuntimeException; use Intervention\Image\Image; class Font extends AbstractFont { /** * Draws font to given image at given position * * @param Image $image * @param int $posx * @param int $posy * @return void */ public function applyToImage(Image $image, $posx = 0, $posy = 0) { // build draw object $draw = new \ImagickDraw(); $draw->setStrokeAntialias(true); $draw->setTextAntialias(true); // set font file if ($this->hasApplicableFontFile()) { $draw->setFont($this->file); } else { throw new RuntimeException( "Font file must be provided to apply text to image." ); } // parse text color $color = new Color($this->color); $draw->setFontSize($this->size); $draw->setFillColor($color->getPixel()); $draw->setTextKerning($this->kerning); // align horizontal switch (strtolower($this->align)) { case 'center': $align = \Imagick::ALIGN_CENTER; break; case 'right': $align = \Imagick::ALIGN_RIGHT; break; default: $align = \Imagick::ALIGN_LEFT; break; } $draw->setTextAlignment($align); // align vertical if (strtolower($this->valign) != 'bottom') { // corrections on y-position switch (strtolower($this->valign)) { case 'center': case 'middle': // calculate box size $dimensions = $image->getCore()->queryFontMetrics($draw, $this->text); $posy = $posy + $dimensions['textHeight'] * 0.65 / 2; break; case 'top': // calculate box size $dimensions = $image->getCore()->queryFontMetrics($draw, $this->text, false); $posy = $posy + $dimensions['characterHeight']; break; } } // apply to image $image->getCore()->annotateImage($draw, $posx, $posy, $this->angle * (-1), $this->text); } /** * Calculates bounding box of current font setting * * @return array */ public function getBoxSize() { $box = []; // build draw object $draw = new \ImagickDraw(); $draw->setStrokeAntialias(true); $draw->setTextAntialias(true); // set font file if ($this->hasApplicableFontFile()) { $draw->setFont($this->file); } else { throw new RuntimeException( "Font file must be provided to apply text to image." ); } $draw->setFontSize($this->size); $dimensions = (new \Imagick())->queryFontMetrics($draw, $this->text); if (strlen($this->text) == 0) { // no text -> no boxsize $box['width'] = 0; $box['height'] = 0; } else { // get boxsize $box['width'] = intval(abs($dimensions['textWidth'])); $box['height'] = intval(abs($dimensions['textHeight'])); } return $box; } } src/Intervention/Image/Imagick/Decoder.php 0000644 00000006136 15111232405 0014463 0 ustar 00 <?php namespace Intervention\Image\Imagick; use Intervention\Image\AbstractDecoder; use Intervention\Image\Exception\NotReadableException; use Intervention\Image\Exception\NotSupportedException; use Intervention\Image\Image; class Decoder extends AbstractDecoder { /** * Initiates new image from path in filesystem * * @param string $path * @return \Intervention\Image\Image */ public function initFromPath($path) { $core = new \Imagick; try { $core->setBackgroundColor(new \ImagickPixel('transparent')); $core->readImage($path); $core->setImageType(defined('\Imagick::IMGTYPE_TRUECOLORALPHA') ? \Imagick::IMGTYPE_TRUECOLORALPHA : \Imagick::IMGTYPE_TRUECOLORMATTE); } catch (\ImagickException $e) { throw new \Intervention\Image\Exception\NotReadableException( "Unable to read image from path ({$path}).", 0, $e ); } // build image $image = $this->initFromImagick($core); $image->setFileInfoFromPath($path); return $image; } /** * Initiates new image from GD resource * * @param Resource $resource * @return \Intervention\Image\Image */ public function initFromGdResource($resource) { throw new NotSupportedException( 'Imagick driver is unable to init from GD resource.' ); } /** * Initiates new image from Imagick object * * @param Imagick $object * @return \Intervention\Image\Image */ public function initFromImagick(\Imagick $object) { // currently animations are not supported // so all images are turned into static $object = $this->removeAnimation($object); // reset image orientation $object->setImageOrientation(\Imagick::ORIENTATION_UNDEFINED); return new Image(new Driver, $object); } /** * Initiates new image from binary data * * @param string $data * @return \Intervention\Image\Image */ public function initFromBinary($binary) { $core = new \Imagick; try { $core->setBackgroundColor(new \ImagickPixel('transparent')); $core->readImageBlob($binary); } catch (\ImagickException $e) { throw new NotReadableException( "Unable to read image from binary data.", 0, $e ); } // build image $image = $this->initFromImagick($core); $image->mime = finfo_buffer(finfo_open(FILEINFO_MIME_TYPE), $binary); return $image; } /** * Turns object into one frame Imagick object * by removing all frames except first * * @param Imagick $object * @return Imagick */ private function removeAnimation(\Imagick $object) { $imagick = new \Imagick; foreach ($object as $frame) { $imagick->addImage($frame->getImage()); break; } $object->destroy(); return $imagick; } } src/Intervention/Image/Imagick/Color.php 0000644 00000014545 15111232405 0014177 0 ustar 00 <?php namespace Intervention\Image\Imagick; use Intervention\Image\AbstractColor; class Color extends AbstractColor { /** * ImagickPixel containing current color information * * @var \ImagickPixel */ public $pixel; /** * Initiates color object from integer * * @param int $value * @return \Intervention\Image\AbstractColor */ public function initFromInteger($value) { $a = ($value >> 24) & 0xFF; $r = ($value >> 16) & 0xFF; $g = ($value >> 8) & 0xFF; $b = $value & 0xFF; $a = $this->rgb2alpha($a); $this->setPixel($r, $g, $b, $a); } /** * Initiates color object from given array * * @param array $value * @return \Intervention\Image\AbstractColor */ public function initFromArray($array) { $array = array_values($array); if (count($array) == 4) { // color array with alpha value list($r, $g, $b, $a) = $array; } elseif (count($array) == 3) { // color array without alpha value list($r, $g, $b) = $array; $a = 1; } $this->setPixel($r, $g, $b, $a); } /** * Initiates color object from given string * * @param string $value * * @return \Intervention\Image\AbstractColor */ public function initFromString($value) { if ($color = $this->rgbaFromString($value)) { $this->setPixel($color[0], $color[1], $color[2], $color[3]); } } /** * Initiates color object from given ImagickPixel object * * @param ImagickPixel $value * * @return \Intervention\Image\AbstractColor */ public function initFromObject($value) { if (is_a($value, '\ImagickPixel')) { $this->pixel = $value; } } /** * Initiates color object from given R, G and B values * * @param int $r * @param int $g * @param int $b * * @return \Intervention\Image\AbstractColor */ public function initFromRgb($r, $g, $b) { $this->setPixel($r, $g, $b); } /** * Initiates color object from given R, G, B and A values * * @param int $r * @param int $g * @param int $b * @param float $a * * @return \Intervention\Image\AbstractColor */ public function initFromRgba($r, $g, $b, $a) { $this->setPixel($r, $g, $b, $a); } /** * Calculates integer value of current color instance * * @return int */ public function getInt() { $r = $this->getRedValue(); $g = $this->getGreenValue(); $b = $this->getBlueValue(); $a = intval(round($this->getAlphaValue() * 255)); return intval(($a << 24) + ($r << 16) + ($g << 8) + $b); } /** * Calculates hexadecimal value of current color instance * * @param string $prefix * * @return string */ public function getHex($prefix = '') { return sprintf('%s%02x%02x%02x', $prefix, $this->getRedValue(), $this->getGreenValue(), $this->getBlueValue() ); } /** * Calculates RGB(A) in array format of current color instance * * @return array */ public function getArray() { return [ $this->getRedValue(), $this->getGreenValue(), $this->getBlueValue(), $this->getAlphaValue() ]; } /** * Calculates RGBA in string format of current color instance * * @return string */ public function getRgba() { return sprintf('rgba(%d, %d, %d, %.2F)', $this->getRedValue(), $this->getGreenValue(), $this->getBlueValue(), $this->getAlphaValue() ); } /** * Determines if current color is different from given color * * @param AbstractColor $color * @param int $tolerance * @return boolean */ public function differs(AbstractColor $color, $tolerance = 0) { $color_tolerance = round($tolerance * 2.55); $alpha_tolerance = round($tolerance); $delta = [ 'r' => abs($color->getRedValue() - $this->getRedValue()), 'g' => abs($color->getGreenValue() - $this->getGreenValue()), 'b' => abs($color->getBlueValue() - $this->getBlueValue()), 'a' => abs($color->getAlphaValue() - $this->getAlphaValue()) ]; return ( $delta['r'] > $color_tolerance or $delta['g'] > $color_tolerance or $delta['b'] > $color_tolerance or $delta['a'] > $alpha_tolerance ); } /** * Returns RGB red value of current color * * @return int */ public function getRedValue() { return intval(round($this->pixel->getColorValue(\Imagick::COLOR_RED) * 255)); } /** * Returns RGB green value of current color * * @return int */ public function getGreenValue() { return intval(round($this->pixel->getColorValue(\Imagick::COLOR_GREEN) * 255)); } /** * Returns RGB blue value of current color * * @return int */ public function getBlueValue() { return intval(round($this->pixel->getColorValue(\Imagick::COLOR_BLUE) * 255)); } /** * Returns RGB alpha value of current color * * @return float */ public function getAlphaValue() { return round($this->pixel->getColorValue(\Imagick::COLOR_ALPHA), 2); } /** * Initiates ImagickPixel from given RGBA values * * @return \ImagickPixel */ private function setPixel($r, $g, $b, $a = null) { $a = is_null($a) ? 1 : $a; return $this->pixel = new \ImagickPixel( sprintf('rgba(%d, %d, %d, %.2F)', $r, $g, $b, $a) ); } /** * Returns current color as ImagickPixel * * @return \ImagickPixel */ public function getPixel() { return $this->pixel; } /** * Calculates RGBA integer alpha value into float value * * @param int $value * @return float */ private function rgb2alpha($value) { // (255 -> 1.0) / (0 -> 0.0) return (float) round($value/255, 2); } } src/Intervention/Image/ImageServiceProviderLaravelRecent.php 0000644 00000004677 15111232405 0020310 0 ustar 00 <?php namespace Intervention\Image; use Illuminate\Support\ServiceProvider; class ImageServiceProviderLaravelRecent extends ServiceProvider { /** * Determines if Intervention Imagecache is installed * * @return boolean */ private function cacheIsInstalled() { return class_exists('Intervention\\Image\\ImageCache'); } /** * Bootstrap the application events. * * @return void */ public function boot() { $this->publishes([ __DIR__.'/../../config/config.php' => config_path('image.php') ]); // setup intervention/imagecache if package is installed $this->cacheIsInstalled() ? $this->bootstrapImageCache() : null; } /** * Register the service provider. * * @return void */ public function register() { $app = $this->app; // merge default config $this->mergeConfigFrom( __DIR__.'/../../config/config.php', 'image' ); // create image $app->singleton('image', function ($app) { return new ImageManager($this->getImageConfig($app)); }); $app->alias('image', 'Intervention\Image\ImageManager'); } /** * Bootstrap imagecache * * @return void */ protected function bootstrapImageCache() { $app = $this->app; $config = __DIR__.'/../../../../imagecache/src/config/config.php'; $this->publishes([ $config => config_path('imagecache.php') ]); // merge default config $this->mergeConfigFrom( $config, 'imagecache' ); // imagecache route if (is_string(config('imagecache.route'))) { $filename_pattern = '[ \w\\.\\/\\-\\@\(\)\=]+'; // route to access template applied image file $app['router']->get(config('imagecache.route').'/{template}/{filename}', [ 'uses' => 'Intervention\Image\ImageCacheController@getResponse', 'as' => 'imagecache' ])->where(['filename' => $filename_pattern]); } } /** * Return image configuration as array * * @param Application $app * @return array */ private function getImageConfig($app) { $config = $app['config']->get('image'); if (is_null($config)) { return []; } return $config; } } src/Intervention/Image/ImageManager.php 0000644 00000006563 15111232405 0014073 0 ustar 00 <?php namespace Intervention\Image; use Closure; use Intervention\Image\Exception\MissingDependencyException; use Intervention\Image\Exception\NotSupportedException; class ImageManager { /** * Config * * @var array */ public $config = [ 'driver' => 'gd' ]; /** * Creates new instance of Image Manager * * @param array $config */ public function __construct(array $config = []) { $this->checkRequirements(); $this->configure($config); } /** * Overrides configuration settings * * @param array $config * * @return self */ public function configure(array $config = []) { $this->config = array_replace($this->config, $config); return $this; } /** * Initiates an Image instance from different input types * * @param mixed $data * * @return \Intervention\Image\Image */ public function make($data) { return $this->createDriver()->init($data); } /** * Creates an empty image canvas * * @param int $width * @param int $height * @param mixed $background * * @return \Intervention\Image\Image */ public function canvas($width, $height, $background = null) { return $this->createDriver()->newImage($width, $height, $background); } /** * Create new cached image and run callback * (requires additional package intervention/imagecache) * * @param Closure $callback * @param int $lifetime * @param boolean $returnObj * * @return Image */ public function cache(Closure $callback, $lifetime = null, $returnObj = false) { if (class_exists('Intervention\\Image\\ImageCache')) { // create imagecache $imagecache = new ImageCache($this); // run callback if (is_callable($callback)) { $callback($imagecache); } return $imagecache->get($lifetime, $returnObj); } throw new MissingDependencyException( "Please install package intervention/imagecache before running this function." ); } /** * Creates a driver instance according to config settings * * @return \Intervention\Image\AbstractDriver */ private function createDriver() { if (is_string($this->config['driver'])) { $drivername = ucfirst($this->config['driver']); $driverclass = sprintf('Intervention\\Image\\%s\\Driver', $drivername); if (class_exists($driverclass)) { return new $driverclass; } throw new NotSupportedException( "Driver ({$drivername}) could not be instantiated." ); } if ($this->config['driver'] instanceof AbstractDriver) { return $this->config['driver']; } throw new NotSupportedException( "Unknown driver type." ); } /** * Check if all requirements are available * * @return void */ private function checkRequirements() { if ( ! function_exists('finfo_buffer')) { throw new MissingDependencyException( "PHP Fileinfo extension must be installed/enabled to use Intervention Image." ); } } } src/Intervention/Image/Response.php 0000644 00000003600 15111232405 0013341 0 ustar 00 <?php namespace Intervention\Image; use Illuminate\Support\Facades\Response as IlluminateResponse; use Symfony\Component\HttpFoundation\Response as SymfonyResponse; class Response { /** * Image that should be displayed by response * * @var Image */ public $image; /** * Format of displayed image * * @var string */ public $format; /** * Quality of displayed image * * @var int */ public $quality; /** * Creates a new instance of response * * @param Image $image * @param string $format * @param int $quality */ public function __construct(Image $image, $format = null, $quality = null) { $this->image = $image; $this->format = $format ? $format : $image->mime; $this->quality = $quality ? $quality : 90; } /** * Builds response according to settings * * @return mixed */ public function make() { $this->image->encode($this->format, $this->quality); $data = $this->image->getEncoded(); $mime = finfo_buffer(finfo_open(FILEINFO_MIME_TYPE), $data); $length = strlen($data); if (function_exists('app') && is_a($app = app(), 'Illuminate\Foundation\Application')) { $response = IlluminateResponse::make($data); $response->header('Content-Type', $mime); $response->header('Content-Length', $length); } elseif (class_exists('\Symfony\Component\HttpFoundation\Response')) { $response = new SymfonyResponse($data); $response->headers->set('Content-Type', $mime); $response->headers->set('Content-Length', $length); } else { header('Content-Type: ' . $mime); header('Content-Length: ' . $length); $response = $data; } return $response; } } src/Intervention/Image/AbstractColor.php 0000644 00000014405 15111232405 0014312 0 ustar 00 <?php namespace Intervention\Image; use Intervention\Image\Exception\NotReadableException; use Intervention\Image\Exception\NotSupportedException; abstract class AbstractColor { /** * Initiates color object from integer * * @param int $value * @return \Intervention\Image\AbstractColor */ abstract public function initFromInteger($value); /** * Initiates color object from given array * * @param array $value * @return \Intervention\Image\AbstractColor */ abstract public function initFromArray($value); /** * Initiates color object from given string * * @param string $value * @return \Intervention\Image\AbstractColor */ abstract public function initFromString($value); /** * Initiates color object from given ImagickPixel object * * @param ImagickPixel $value * @return \Intervention\Image\AbstractColor */ abstract public function initFromObject($value); /** * Initiates color object from given R, G and B values * * @param int $r * @param int $g * @param int $b * @return \Intervention\Image\AbstractColor */ abstract public function initFromRgb($r, $g, $b); /** * Initiates color object from given R, G, B and A values * * @param int $r * @param int $g * @param int $b * @param float $a * @return \Intervention\Image\AbstractColor */ abstract public function initFromRgba($r, $g, $b, $a); /** * Calculates integer value of current color instance * * @return int */ abstract public function getInt(); /** * Calculates hexadecimal value of current color instance * * @param string $prefix * @return string */ abstract public function getHex($prefix); /** * Calculates RGB(A) in array format of current color instance * * @return array */ abstract public function getArray(); /** * Calculates RGBA in string format of current color instance * * @return string */ abstract public function getRgba(); /** * Determines if current color is different from given color * * @param AbstractColor $color * @param int $tolerance * @return boolean */ abstract public function differs(AbstractColor $color, $tolerance = 0); /** * Creates new instance * * @param mixed $value */ public function __construct($value = null) { $this->parse($value); } /** * Parses given value as color * * @param mixed $value * @return \Intervention\Image\AbstractColor */ public function parse($value) { switch (true) { case is_string($value): $this->initFromString($value); break; case is_int($value): $this->initFromInteger($value); break; case is_array($value): $this->initFromArray($value); break; case is_object($value): $this->initFromObject($value); break; case is_null($value): $this->initFromArray([255, 255, 255, 0]); break; default: throw new NotReadableException( "Color format ({$value}) cannot be read." ); } return $this; } /** * Formats current color instance into given format * * @param string $type * @return mixed */ public function format($type) { switch (strtolower($type)) { case 'rgba': return $this->getRgba(); case 'hex': return $this->getHex('#'); case 'int': case 'integer': return $this->getInt(); case 'array': return $this->getArray(); case 'obj': case 'object': return $this; default: throw new NotSupportedException( "Color format ({$type}) is not supported." ); } } /** * Reads RGBA values from string into array * * @param string $value * @return array */ protected function rgbaFromString($value) { $result = false; // parse color string in hexidecimal format like #cccccc or cccccc or ccc $hexPattern = '/^#?([a-f0-9]{1,2})([a-f0-9]{1,2})([a-f0-9]{1,2})$/i'; // parse color string in format rgb(140, 140, 140) $rgbPattern = '/^rgb ?\(([0-9]{1,3}), ?([0-9]{1,3}), ?([0-9]{1,3})\)$/i'; // parse color string in format rgba(255, 0, 0, 0.5) $rgbaPattern = '/^rgba ?\(([0-9]{1,3}), ?([0-9]{1,3}), ?([0-9]{1,3}), ?([0-9.]{1,4})\)$/i'; if (preg_match($hexPattern, $value, $matches)) { $result = []; $result[0] = strlen($matches[1]) == '1' ? hexdec($matches[1].$matches[1]) : hexdec($matches[1]); $result[1] = strlen($matches[2]) == '1' ? hexdec($matches[2].$matches[2]) : hexdec($matches[2]); $result[2] = strlen($matches[3]) == '1' ? hexdec($matches[3].$matches[3]) : hexdec($matches[3]); $result[3] = 1; } elseif (preg_match($rgbPattern, $value, $matches)) { $result = []; $result[0] = ($matches[1] >= 0 && $matches[1] <= 255) ? intval($matches[1]) : 0; $result[1] = ($matches[2] >= 0 && $matches[2] <= 255) ? intval($matches[2]) : 0; $result[2] = ($matches[3] >= 0 && $matches[3] <= 255) ? intval($matches[3]) : 0; $result[3] = 1; } elseif (preg_match($rgbaPattern, $value, $matches)) { $result = []; $result[0] = ($matches[1] >= 0 && $matches[1] <= 255) ? intval($matches[1]) : 0; $result[1] = ($matches[2] >= 0 && $matches[2] <= 255) ? intval($matches[2]) : 0; $result[2] = ($matches[3] >= 0 && $matches[3] <= 255) ? intval($matches[3]) : 0; $result[3] = ($matches[4] >= 0 && $matches[4] <= 1) ? $matches[4] : 0; } else { throw new NotReadableException( "Unable to read color ({$value})." ); } return $result; } } src/Intervention/Image/Filters/DemoFilter.php 0000644 00000001473 15111232405 0015213 0 ustar 00 <?php namespace Intervention\Image\Filters; use Intervention\Image\Image; class DemoFilter implements FilterInterface { /** * Default size of filter effects */ const DEFAULT_SIZE = 10; /** * Size of filter effects * * @var int */ private $size; /** * Creates new instance of filter * * @param int $size */ public function __construct($size = null) { $this->size = is_numeric($size) ? intval($size) : self::DEFAULT_SIZE; } /** * Applies filter effects to given image * * @param \Intervention\Image\Image $image * @return \Intervention\Image\Image */ public function applyFilter(Image $image) { $image->pixelate($this->size); $image->greyscale(); return $image; } } src/Intervention/Image/Filters/FilterInterface.php 0000644 00000000457 15111232405 0016230 0 ustar 00 <?php namespace Intervention\Image\Filters; use Intervention\Image\Image; interface FilterInterface { /** * Applies filter to given image * * @param \Intervention\Image\Image $image * @return \Intervention\Image\Image */ public function applyFilter(Image $image); } src/Intervention/Image/ImageServiceProviderLeague.php 0000644 00000001432 15111232405 0016745 0 ustar 00 <?php namespace Intervention\Image; use League\Container\ServiceProvider\AbstractServiceProvider; class ImageServiceProviderLeague extends AbstractServiceProvider { /** * @var array $config */ protected $config; /** * @var array $provides */ protected $provides = [ 'Intervention\Image\ImageManager' ]; /** * Constructor. * * @param array $config */ public function __construct($config = []) { $this->config = $config; } /** * Register the server provider. * * @return void */ public function register() { $this->getContainer()->share('Intervention\Image\ImageManager', function () { return new ImageManager($this->config); }); } } src/Intervention/Image/Size.php 0000644 00000022607 15111232405 0012465 0 ustar 00 <?php namespace Intervention\Image; use Closure; use Intervention\Image\Exception\InvalidArgumentException; class Size { /** * Width * * @var int */ public $width; /** * Height * * @var int */ public $height; /** * Pivot point * * @var Point */ public $pivot; /** * Creates a new Size instance * * @param int $width * @param int $height * @param Point $pivot */ public function __construct($width = null, $height = null, Point $pivot = null) { $this->width = is_numeric($width) ? intval($width) : 1; $this->height = is_numeric($height) ? intval($height) : 1; $this->pivot = $pivot ? $pivot : new Point; } /** * Set the width and height absolutely * * @param int $width * @param int $height */ public function set($width, $height) { $this->width = $width; $this->height = $height; } /** * Set current pivot point * * @param Point $point */ public function setPivot(Point $point) { $this->pivot = $point; } /** * Get the current width * * @return int */ public function getWidth() { return intval($this->width); } /** * Get the current height * * @return int */ public function getHeight() { return intval($this->height); } /** * Calculate the current aspect ratio * * @return float */ public function getRatio() { return $this->width / $this->height; } /** * Resize to desired width and/or height * * @param int $width * @param int $height * @param Closure $callback * @return Size */ public function resize($width, $height, Closure $callback = null) { if (is_null($width) && is_null($height)) { throw new InvalidArgumentException( "Width or height needs to be defined." ); } // new size with dominant width $dominant_w_size = clone $this; $dominant_w_size->resizeHeight($height, $callback); $dominant_w_size->resizeWidth($width, $callback); // new size with dominant height $dominant_h_size = clone $this; $dominant_h_size->resizeWidth($width, $callback); $dominant_h_size->resizeHeight($height, $callback); // decide which size to use if ($dominant_h_size->fitsInto(new self($width, $height))) { $this->set($dominant_h_size->width, $dominant_h_size->height); } else { $this->set($dominant_w_size->width, $dominant_w_size->height); } return $this; } /** * Scale size according to given constraints * * @param int $width * @param Closure $callback * @return Size */ private function resizeWidth($width, Closure $callback = null) { $constraint = $this->getConstraint($callback); if ($constraint->isFixed(Constraint::UPSIZE)) { $max_width = $constraint->getSize()->getWidth(); $max_height = $constraint->getSize()->getHeight(); } if (is_numeric($width)) { if ($constraint->isFixed(Constraint::UPSIZE)) { $this->width = ($width > $max_width) ? $max_width : $width; } else { $this->width = $width; } if ($constraint->isFixed(Constraint::ASPECTRATIO)) { $h = max(1, intval(round($this->width / $constraint->getSize()->getRatio()))); if ($constraint->isFixed(Constraint::UPSIZE)) { $this->height = ($h > $max_height) ? $max_height : $h; } else { $this->height = $h; } } } } /** * Scale size according to given constraints * * @param int $height * @param Closure $callback * @return Size */ private function resizeHeight($height, Closure $callback = null) { $constraint = $this->getConstraint($callback); if ($constraint->isFixed(Constraint::UPSIZE)) { $max_width = $constraint->getSize()->getWidth(); $max_height = $constraint->getSize()->getHeight(); } if (is_numeric($height)) { if ($constraint->isFixed(Constraint::UPSIZE)) { $this->height = ($height > $max_height) ? $max_height : $height; } else { $this->height = $height; } if ($constraint->isFixed(Constraint::ASPECTRATIO)) { $w = max(1, intval(round($this->height * $constraint->getSize()->getRatio()))); if ($constraint->isFixed(Constraint::UPSIZE)) { $this->width = ($w > $max_width) ? $max_width : $w; } else { $this->width = $w; } } } } /** * Calculate the relative position to another Size * based on the pivot point settings of both sizes. * * @param Size $size * @return \Intervention\Image\Point */ public function relativePosition(Size $size) { $x = $this->pivot->x - $size->pivot->x; $y = $this->pivot->y - $size->pivot->y; return new Point($x, $y); } /** * Resize given Size to best fitting size of current size. * * @param Size $size * @return \Intervention\Image\Size */ public function fit(Size $size, $position = 'center') { // create size with auto height $auto_height = clone $size; $auto_height->resize($this->width, null, function ($constraint) { $constraint->aspectRatio(); }); // decide which version to use if ($auto_height->fitsInto($this)) { $size = $auto_height; } else { // create size with auto width $auto_width = clone $size; $auto_width->resize(null, $this->height, function ($constraint) { $constraint->aspectRatio(); }); $size = $auto_width; } $this->align($position); $size->align($position); $size->setPivot($this->relativePosition($size)); return $size; } /** * Checks if given size fits into current size * * @param Size $size * @return boolean */ public function fitsInto(Size $size) { return ($this->width <= $size->width) && ($this->height <= $size->height); } /** * Aligns current size's pivot point to given position * and moves point automatically by offset. * * @param string $position * @param int $offset_x * @param int $offset_y * @return \Intervention\Image\Size */ public function align($position, $offset_x = 0, $offset_y = 0) { switch (strtolower($position)) { case 'top': case 'top-center': case 'top-middle': case 'center-top': case 'middle-top': $x = intval($this->width / 2); $y = 0 + $offset_y; break; case 'top-right': case 'right-top': $x = $this->width - $offset_x; $y = 0 + $offset_y; break; case 'left': case 'left-center': case 'left-middle': case 'center-left': case 'middle-left': $x = 0 + $offset_x; $y = intval($this->height / 2); break; case 'right': case 'right-center': case 'right-middle': case 'center-right': case 'middle-right': $x = $this->width - $offset_x; $y = intval($this->height / 2); break; case 'bottom-left': case 'left-bottom': $x = 0 + $offset_x; $y = $this->height - $offset_y; break; case 'bottom': case 'bottom-center': case 'bottom-middle': case 'center-bottom': case 'middle-bottom': $x = intval($this->width / 2); $y = $this->height - $offset_y; break; case 'bottom-right': case 'right-bottom': $x = $this->width - $offset_x; $y = $this->height - $offset_y; break; case 'center': case 'middle': case 'center-center': case 'middle-middle': $x = intval($this->width / 2) + $offset_x; $y = intval($this->height / 2) + $offset_y; break; default: case 'top-left': case 'left-top': $x = 0 + $offset_x; $y = 0 + $offset_y; break; } $this->pivot->setPosition($x, $y); return $this; } /** * Runs constraints on current size * * @param Closure $callback * @return \Intervention\Image\Constraint */ private function getConstraint(Closure $callback = null) { $constraint = new Constraint(clone $this); if (is_callable($callback)) { $callback($constraint); } return $constraint; } } src/Intervention/Image/Point.php 0000644 00000001675 15111232405 0012646 0 ustar 00 <?php namespace Intervention\Image; class Point { /** * X coordinate * * @var int */ public $x; /** * Y coordinate * * @var int */ public $y; /** * Creates a new instance * * @param int $x * @param int $y */ public function __construct($x = null, $y = null) { $this->x = is_numeric($x) ? intval($x) : 0; $this->y = is_numeric($y) ? intval($y) : 0; } /** * Sets X coordinate * * @param int $x */ public function setX($x) { $this->x = intval($x); } /** * Sets Y coordinate * * @param int $y */ public function setY($y) { $this->y = intval($y); } /** * Sets both X and Y coordinate * * @param int $x * @param int $y */ public function setPosition($x, $y) { $this->setX($x); $this->setY($y); } } src/Intervention/Image/Image.php 0000644 00000047575 15111232405 0012610 0 ustar 00 <?php namespace Intervention\Image; use Intervention\Image\Exception\NotWritableException; use Intervention\Image\Exception\RuntimeException; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\StreamInterface; /** * @method \Intervention\Image\Image backup(string $name = 'default') Backups current image state as fallback for reset method under an optional name. Overwrites older state on every call, unless a different name is passed. * @method \Intervention\Image\Image blur(int $amount = 1) Apply a gaussian blur filter with a optional amount on the current image. Use values between 0 and 100. * @method \Intervention\Image\Image brightness(int $level) Changes the brightness of the current image by the given level. Use values between -100 for min. brightness. 0 for no change and +100 for max. brightness. * @method \Intervention\Image\Image cache(\Closure $callback, int $lifetime = null, boolean $returnObj = false) Method to create a new cached image instance from a Closure callback. Pass a lifetime in minutes for the callback and decide whether you want to get an Intervention Image instance as return value or just receive the image stream. * @method \Intervention\Image\Image canvas(int $width, int $height, mixed $bgcolor = null) Factory method to create a new empty image instance with given width and height. You can define a background-color optionally. By default the canvas background is transparent. * @method \Intervention\Image\Image circle(int $diameter, int $x, int $y, \Closure $callback = null) Draw a circle at given x, y, coordinates with given diameter. You can define the appearance of the circle by an optional closure callback. * @method \Intervention\Image\Image colorize(int $red, int $green, int $blue) Change the RGB color values of the current image on the given channels red, green and blue. The input values are normalized so you have to include parameters from 100 for maximum color value. 0 for no change and -100 to take out all the certain color on the image. * @method \Intervention\Image\Image contrast(int $level) Changes the contrast of the current image by the given level. Use values between -100 for min. contrast 0 for no change and +100 for max. contrast. * @method \Intervention\Image\Image crop(int $width, int $height, int $x = null, int $y = null) Cut out a rectangular part of the current image with given width and height. Define optional x,y coordinates to move the top-left corner of the cutout to a certain position. * @method void destroy() Frees memory associated with the current image instance before the PHP script ends. Normally resources are destroyed automatically after the script is finished. * @method \Intervention\Image\Image ellipse(int $width, int $height, int $x, int $y, \Closure $callback = null) Draw a colored ellipse at given x, y, coordinates. You can define width and height and set the appearance of the circle by an optional closure callback. * @method mixed exif(string $key = null) Read Exif meta data from current image. * @method mixed iptc(string $key = null) Read Iptc meta data from current image. * @method \Intervention\Image\Image fill(mixed $filling, int $x = null, int $y = null) Fill current image with given color or another image used as tile for filling. Pass optional x, y coordinates to start at a certain point. * @method \Intervention\Image\Image flip(string $mode = 'h') Mirror the current image horizontally or vertically by specifying the mode. * @method \Intervention\Image\Image fit(int $width, int $height = null, \Closure $callback = null, string $position = 'center') Combine cropping and resizing to format image in a smart way. The method will find the best fitting aspect ratio of your given width and height on the current image automatically, cut it out and resize it to the given dimension. You may pass an optional Closure callback as third parameter, to prevent possible upsizing and a custom position of the cutout as fourth parameter. * @method \Intervention\Image\Image gamma(float $correction) Performs a gamma correction operation on the current image. * @method \Intervention\Image\Image greyscale() Turns image into a greyscale version. * @method \Intervention\Image\Image heighten(int $height, \Closure $callback = null) Resizes the current image to new height, constraining aspect ratio. Pass an optional Closure callback as third parameter, to apply additional constraints like preventing possible upsizing. * @method \Intervention\Image\Image insert(mixed $source, string $position = 'top-left', int $x = 0, int $y = 0) Paste a given image source over the current image with an optional position and a offset coordinate. This method can be used to apply another image as watermark because the transparency values are maintained. * @method \Intervention\Image\Image interlace(boolean $interlace = true) Determine whether an image should be encoded in interlaced or standard mode by toggling interlace mode with a boolean parameter. If an JPEG image is set interlaced the image will be processed as a progressive JPEG. * @method \Intervention\Image\Image invert() Reverses all colors of the current image. * @method \Intervention\Image\Image limitColors(int $count, mixed $matte = null) Method converts the existing colors of the current image into a color table with a given maximum count of colors. The function preserves as much alpha channel information as possible and blends transarent pixels against a optional matte color. * @method \Intervention\Image\Image line(int $x1, int $y1, int $x2, int $y2, \Closure $callback = null) Draw a line from x,y point 1 to x,y point 2 on current image. Define color and/or width of line in an optional Closure callback. * @method \Intervention\Image\Image make(mixed $source) Universal factory method to create a new image instance from source, which can be a filepath, a GD image resource, an Imagick object or a binary image data. * @method \Intervention\Image\Image mask(mixed $source, boolean $mask_with_alpha) Apply a given image source as alpha mask to the current image to change current opacity. Mask will be resized to the current image size. By default a greyscale version of the mask is converted to alpha values, but you can set mask_with_alpha to apply the actual alpha channel. Any transparency values of the current image will be maintained. * @method \Intervention\Image\Image opacity(int $transparency) Set the opacity in percent of the current image ranging from 100% for opaque and 0% for full transparency. * @method \Intervention\Image\Image orientate() This method reads the EXIF image profile setting 'Orientation' and performs a rotation on the image to display the image correctly. * @method mixed pickColor(int $x, int $y, string $format = 'array') Pick a color at point x, y out of current image and return in optional given format. * @method \Intervention\Image\Image pixel(mixed $color, int $x, int $y) Draw a single pixel in given color on x, y position. * @method \Intervention\Image\Image pixelate(int $size) Applies a pixelation effect to the current image with a given size of pixels. * @method \Intervention\Image\Image polygon(array $points, \Closure $callback = null) Draw a colored polygon with given points. You can define the appearance of the polygon by an optional closure callback. * @method \Intervention\Image\Image rectangle(int $x1, int $y1, int $x2, int $y2, \Closure $callback = null) Draw a colored rectangle on current image with top-left corner on x,y point 1 and bottom-right corner at x,y point 2. Define the overall appearance of the shape by passing a Closure callback as an optional parameter. * @method \Intervention\Image\Image reset(string $name = 'default') Resets all of the modifications to a state saved previously by backup under an optional name. * @method \Intervention\Image\Image resize(int $width = null, int $height = null, \Closure $callback = null) Resizes current image based on given width and/or height. To contraint the resize command, pass an optional Closure callback as third parameter. * @method \Intervention\Image\Image resizeCanvas(int $width, int $height, string $anchor = 'center', boolean $relative = false, mixed $bgcolor = null) Resize the boundaries of the current image to given width and height. An anchor can be defined to determine from what point of the image the resizing is going to happen. Set the mode to relative to add or subtract the given width or height to the actual image dimensions. You can also pass a background color for the emerging area of the image. * @method mixed response(string $format = null, int $quality = 90) Sends HTTP response with current image in given format and quality. * @method \Intervention\Image\Image rotate(float $angle, mixed $bgcolor = null) Rotate the current image counter-clockwise by a given angle. Optionally define a background color for the uncovered zone after the rotation. * @method \Intervention\Image\Image sharpen(int $amount = 10) Sharpen current image with an optional amount. Use values between 0 and 100. * @method \Intervention\Image\Image text(string $text, int $x = 0, int $y = 0, \Closure $callback = null) Write a text string to the current image at an optional x,y basepoint position. You can define more details like font-size, font-file and alignment via a callback as the fourth parameter. * @method \Intervention\Image\Image trim(string $base = 'top-left', array $away = array('top', 'bottom', 'left', 'right'), int $tolerance = 0, int $feather = 0) Trim away image space in given color. Define an optional base to pick a color at a certain position and borders that should be trimmed away. You can also set an optional tolerance level, to trim similar colors and add a feathering border around the trimed image. * @method \Intervention\Image\Image widen(int $width, \Closure $callback = null) Resizes the current image to new width, constraining aspect ratio. Pass an optional Closure callback as third parameter, to apply additional constraints like preventing possible upsizing. * @method StreamInterface stream(string $format = null, int $quality = 90) Build PSR-7 compatible StreamInterface with current image in given format and quality. * @method ResponseInterface psrResponse(string $format = null, int $quality = 90) Build PSR-7 compatible ResponseInterface with current image in given format and quality. */ class Image extends File { /** * Instance of current image driver * * @var AbstractDriver */ protected $driver; /** * Image resource/object of current image processor * * @var mixed */ protected $core; /** * Array of Image resource backups of current image processor * * @var array */ protected $backups = []; /** * Last image encoding result * * @var string */ public $encoded = ''; /** * Creates a new Image instance * * @param AbstractDriver $driver * @param mixed $core */ public function __construct(AbstractDriver $driver = null, $core = null) { $this->driver = $driver; $this->core = $core; } /** * Magic method to catch all image calls * usually any AbstractCommand * * @param string $name * @param Array $arguments * @return mixed */ public function __call($name, $arguments) { $command = $this->driver->executeCommand($this, $name, $arguments); return $command->hasOutput() ? $command->getOutput() : $this; } /** * Starts encoding of current image * * @param string $format * @param int $quality * @return \Intervention\Image\Image */ public function encode($format = null, $quality = 90) { return $this->driver->encode($this, $format, $quality); } /** * Saves encoded image in filesystem * * @param string $path * @param int $quality * @param string $format * @return \Intervention\Image\Image */ public function save($path = null, $quality = null, $format = null) { $path = is_null($path) ? $this->basePath() : $path; if (is_null($path)) { throw new NotWritableException( "Can't write to undefined path." ); } if ($format === null) { $format = pathinfo($path, PATHINFO_EXTENSION); } $data = $this->encode($format, $quality); $saved = @file_put_contents($path, $data); if ($saved === false) { throw new NotWritableException( "Can't write image data to path ({$path})" ); } // set new file info $this->setFileInfoFromPath($path); return $this; } /** * Runs a given filter on current image * * @param FiltersFilterInterface $filter * @return \Intervention\Image\Image */ public function filter(Filters\FilterInterface $filter) { return $filter->applyFilter($this); } /** * Returns current image driver * * @return \Intervention\Image\AbstractDriver */ public function getDriver() { return $this->driver; } /** * Sets current image driver * @param AbstractDriver $driver */ public function setDriver(AbstractDriver $driver) { $this->driver = $driver; return $this; } /** * Returns current image resource/obj * * @return mixed */ public function getCore() { return $this->core; } /** * Sets current image resource * * @param mixed $core */ public function setCore($core) { $this->core = $core; return $this; } /** * Returns current image backup * * @param string $name * @return mixed */ public function getBackup($name = null) { $name = is_null($name) ? 'default' : $name; if ( ! $this->backupExists($name)) { throw new RuntimeException( "Backup with name ({$name}) not available. Call backup() before reset()." ); } return $this->backups[$name]; } /** * Returns all backups attached to image * * @return array */ public function getBackups() { return $this->backups; } /** * Sets current image backup * * @param mixed $resource * @param string $name * @return self */ public function setBackup($resource, $name = null) { $name = is_null($name) ? 'default' : $name; $this->backups[$name] = $resource; return $this; } /** * Checks if named backup exists * * @param string $name * @return bool */ private function backupExists($name) { return array_key_exists($name, $this->backups); } /** * Checks if current image is already encoded * * @return boolean */ public function isEncoded() { return ! empty($this->encoded); } /** * Returns encoded image data of current image * * @return string */ public function getEncoded() { return $this->encoded; } /** * Sets encoded image buffer * * @param string $value */ public function setEncoded($value) { $this->encoded = $value; return $this; } /** * Calculates current image width * * @return int */ public function getWidth() { return $this->getSize()->width; } /** * Alias of getWidth() * * @return int */ public function width() { return $this->getWidth(); } /** * Calculates current image height * * @return int */ public function getHeight() { return $this->getSize()->height; } /** * Alias of getHeight * * @return int */ public function height() { return $this->getHeight(); } /** * Reads mime type * * @return string */ public function mime() { return $this->mime; } /** * Returns encoded image data in string conversion * * @return string */ public function __toString() { return $this->encoded; } /** * Cloning an image */ public function __clone() { $this->core = $this->driver->cloneCore($this->core); } } src/Intervention/Image/AbstractDecoder.php 0000644 00000021022 15111232405 0014572 0 ustar 00 <?php namespace Intervention\Image; use GuzzleHttp\Psr7\Stream; use Intervention\Image\Exception\NotReadableException; use Psr\Http\Message\StreamInterface; abstract class AbstractDecoder { /** * Initiates new image from path in filesystem * * @param string $path * @return \Intervention\Image\Image */ abstract public function initFromPath($path); /** * Initiates new image from binary data * * @param string $data * @return \Intervention\Image\Image */ abstract public function initFromBinary($data); /** * Initiates new image from GD resource * * @param Resource $resource * @return \Intervention\Image\Image */ abstract public function initFromGdResource($resource); /** * Initiates new image from Imagick object * * @param \Imagick $object * @return \Intervention\Image\Image */ abstract public function initFromImagick(\Imagick $object); /** * Buffer of input data * * @var mixed */ private $data; /** * Creates new Decoder with data * * @param mixed $data */ public function __construct($data = null) { $this->data = $data; } /** * Init from given URL * * @param string $url * @return \Intervention\Image\Image */ public function initFromUrl($url) { $options = [ 'http' => [ 'method'=>"GET", 'protocol_version'=>1.1, // force use HTTP 1.1 for service mesh environment with envoy 'header'=>"Accept-language: en\r\n". "User-Agent: Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36\r\n" ] ]; $context = stream_context_create($options); if ($data = @file_get_contents($url, false, $context)) { return $this->initFromBinary($data); } throw new NotReadableException( "Unable to init from given url (".$url.")." ); } /** * Init from given stream * * @param StreamInterface|resource $stream * @return \Intervention\Image\Image */ public function initFromStream($stream) { if (!$stream instanceof StreamInterface) { $stream = new Stream($stream); } try { $offset = $stream->tell(); } catch (\RuntimeException $e) { $offset = 0; } $shouldAndCanSeek = $offset !== 0 && $stream->isSeekable(); if ($shouldAndCanSeek) { $stream->rewind(); } try { $data = $stream->getContents(); } catch (\RuntimeException $e) { $data = null; } if ($shouldAndCanSeek) { $stream->seek($offset); } if ($data) { return $this->initFromBinary($data); } throw new NotReadableException( "Unable to init from given stream" ); } /** * Determines if current source data is GD resource * * @return boolean */ public function isGdResource() { if (is_resource($this->data)) { return (get_resource_type($this->data) == 'gd'); } if ($this->data instanceof \GdImage) { return true; } return false; } /** * Determines if current source data is Imagick object * * @return boolean */ public function isImagick() { return is_a($this->data, 'Imagick'); } /** * Determines if current source data is Intervention\Image\Image object * * @return boolean */ public function isInterventionImage() { return is_a($this->data, '\Intervention\Image\Image'); } /** * Determines if current data is SplFileInfo object * * @return boolean */ public function isSplFileInfo() { return is_a($this->data, 'SplFileInfo'); } /** * Determines if current data is Symfony UploadedFile component * * @return boolean */ public function isSymfonyUpload() { return is_a($this->data, 'Symfony\Component\HttpFoundation\File\UploadedFile'); } /** * Determines if current source data is file path * * @return boolean */ public function isFilePath() { if (is_string($this->data)) { try { return is_file($this->data); } catch (\Exception $e) { return false; } } return false; } /** * Determines if current source data is url * * @return boolean */ public function isUrl() { return (bool) filter_var($this->data, FILTER_VALIDATE_URL); } /** * Determines if current source data is a stream resource * * @return boolean */ public function isStream() { if ($this->data instanceof StreamInterface) return true; if (!is_resource($this->data)) return false; if (get_resource_type($this->data) !== 'stream') return false; return true; } /** * Determines if current source data is binary data * * @return boolean */ public function isBinary() { if (is_string($this->data)) { $mime = finfo_buffer(finfo_open(FILEINFO_MIME_TYPE), $this->data); return (substr($mime, 0, 4) != 'text' && $mime != 'application/x-empty'); } return false; } /** * Determines if current source data is data-url * * @return boolean */ public function isDataUrl() { $data = $this->decodeDataUrl($this->data); return is_null($data) ? false : true; } /** * Determines if current source data is base64 encoded * * @return boolean */ public function isBase64() { if (!is_string($this->data)) { return false; } return base64_encode(base64_decode($this->data)) === str_replace(["\n", "\r"], '', $this->data); } /** * Initiates new Image from Intervention\Image\Image * * @param Image $object * @return \Intervention\Image\Image */ public function initFromInterventionImage($object) { return $object; } /** * Parses and decodes binary image data from data-url * * @param string $data_url * @return string */ private function decodeDataUrl($data_url) { if (!is_string($data_url)) { return null; } $pattern = "/^data:(?:image\/[a-zA-Z\-\.]+)(?:charset=\".+\")?;base64,(?P<data>.+)$/"; preg_match($pattern, str_replace(["\n", "\r"], '', $data_url), $matches); if (is_array($matches) && array_key_exists('data', $matches)) { return base64_decode($matches['data']); } return null; } /** * Initiates new image from mixed data * * @param mixed $data * @return \Intervention\Image\Image */ public function init($data) { $this->data = $data; switch (true) { case $this->isGdResource(): return $this->initFromGdResource($this->data); case $this->isImagick(): return $this->initFromImagick($this->data); case $this->isInterventionImage(): return $this->initFromInterventionImage($this->data); case $this->isSplFileInfo(): return $this->initFromPath($this->data->getRealPath()); case $this->isBinary(): return $this->initFromBinary($this->data); case $this->isUrl(): return $this->initFromUrl($this->data); case $this->isStream(): return $this->initFromStream($this->data); case $this->isDataUrl(): return $this->initFromBinary($this->decodeDataUrl($this->data)); case $this->isFilePath(): return $this->initFromPath($this->data); // isBase64 has to be after isFilePath to prevent false positives case $this->isBase64(): return $this->initFromBinary(base64_decode($this->data)); default: throw new NotReadableException("Image source not readable"); } } /** * Decoder object transforms to string source data * * @return string */ public function __toString() { return (string) $this->data; } } src/Intervention/Image/Constraint.php 0000644 00000003112 15111232405 0013665 0 ustar 00 <?php namespace Intervention\Image; class Constraint { /** * Bit value of aspect ratio constraint */ const ASPECTRATIO = 1; /** * Bit value of upsize constraint */ const UPSIZE = 2; /** * Constraint size * * @var \Intervention\Image\Size */ private $size; /** * Integer value of fixed parameters * * @var int */ private $fixed = 0; /** * Create a new constraint based on size * * @param Size $size */ public function __construct(Size $size) { $this->size = $size; } /** * Returns current size of constraint * * @return \Intervention\Image\Size */ public function getSize() { return $this->size; } /** * Fix the given argument in current constraint * * @param int $type * @return void */ public function fix($type) { $this->fixed = ($this->fixed & ~(1 << $type)) | (1 << $type); } /** * Checks if given argument is fixed in current constraint * * @param int $type * @return boolean */ public function isFixed($type) { return (bool) ($this->fixed & (1 << $type)); } /** * Fixes aspect ratio in current constraint * * @return void */ public function aspectRatio() { $this->fix(self::ASPECTRATIO); } /** * Fixes possibility to size up in current constraint * * @return void */ public function upsize() { $this->fix(self::UPSIZE); } } src/Intervention/Image/AbstractShape.php 0000644 00000002526 15111232405 0014275 0 ustar 00 <?php namespace Intervention\Image; abstract class AbstractShape { /** * Background color of shape * * @var string */ public $background; /** * Border color of current shape * * @var string */ public $border_color; /** * Border width of shape * * @var int */ public $border_width = 0; /** * Draws shape to given image on given position * * @param Image $image * @param int $posx * @param int $posy * @return boolean */ abstract public function applyToImage(Image $image, $posx = 0, $posy = 0); /** * Set text to be written * * @param string $text * @return void */ public function background($color) { $this->background = $color; } /** * Set border width and color of current shape * * @param int $width * @param string $color * @return void */ public function border($width, $color = null) { $this->border_width = is_numeric($width) ? intval($width) : 0; $this->border_color = is_null($color) ? '#000000' : $color; } /** * Determines if current shape has border * * @return boolean */ public function hasBorder() { return ($this->border_width >= 1); } } src/config/config.php 0000644 00000000774 15111232405 0010560 0 ustar 00 <?php return [ /* |-------------------------------------------------------------------------- | Image Driver |-------------------------------------------------------------------------- | | Intervention Image supports "GD Library" and "Imagick" to process images | internally. You may choose one of them according to your PHP | configuration. By default PHP's "GD Library" implementation is used. | | Supported: "gd", "imagick" | */ 'driver' => 'gd' ]; LICENSE 0000644 00000002066 15111232405 0005547 0 ustar 00 The MIT License (MIT) Copyright (c) 2014 Oliver Vogel 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. provides.json 0000644 00000000267 15111232405 0007271 0 ustar 00 { "providers": [ "Intervention\\Image\\ImageServiceProvider" ], "aliases": [ { "alias": "Image", "facade": "Intervention\\Image\\Facades\\Image" } ] }