{"id":16440620,"url":"https://github.com/darrynten/pslayers","last_synced_at":"2025-03-16T17:36:25.734Z","repository":{"id":52421955,"uuid":"82737297","full_name":"darrynten/pslayers","owner":"darrynten","description":"PHP Imagick Layers","archived":false,"fork":false,"pushed_at":"2021-04-29T19:13:41.000Z","size":2122,"stargazers_count":56,"open_issues_count":6,"forks_count":6,"subscribers_count":10,"default_branch":"dev","last_synced_at":"2024-06-17T03:20:50.691Z","etag":null,"topics":["composition","filters","imagemagick","imagick","layers","library","photoshop","php","php7"],"latest_commit_sha":null,"homepage":null,"language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/darrynten.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-02-21T23:18:42.000Z","updated_at":"2024-02-12T19:33:23.000Z","dependencies_parsed_at":"2022-09-16T15:10:23.730Z","dependency_job_id":null,"html_url":"https://github.com/darrynten/pslayers","commit_stats":null,"previous_names":[],"tags_count":12,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/darrynten%2Fpslayers","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/darrynten%2Fpslayers/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/darrynten%2Fpslayers/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/darrynten%2Fpslayers/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/darrynten","download_url":"https://codeload.github.com/darrynten/pslayers/tar.gz/refs/heads/dev","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":219861926,"owners_count":16555980,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["composition","filters","imagemagick","imagick","layers","library","photoshop","php","php7"],"created_at":"2024-10-11T09:12:35.159Z","updated_at":"2024-10-11T09:12:35.239Z","avatar_url":"https://github.com/darrynten.png","language":"PHP","readme":"# pslayers\n\n![Travis Build Status](https://travis-ci.org/darrynten/pslayers.svg?branch=master)\n![StyleCI Status](https://styleci.io/repos/82737297/shield?branch=master)\n[![codecov](https://codecov.io/gh/darrynten/pslayers/branch/master/graph/badge.svg)](https://codecov.io/gh/darrynten/pslayers)\n![Packagist Version](https://img.shields.io/packagist/v/darrynten/pslayers.svg)\n![MIT License](https://img.shields.io/github/license/darrynten/pslayers.svg)\n\nPowerful and fully featured PHP library that features photoshop-style\nimage layering, compositing, filtering, blending and masking.\n\nUses Imagick and PHP 7+\n\n## Introduction\n\nWe needed to give [buzzbot.ai](https://buzzbot.ai) a way to express\nherself visually, so we gave her photoshop-level image management and\nmanipulation capabilities.\n\nThis is the core package that our bots use during their Generation\nphases. As such it has been designed from the ground up to be simple\nto use, but to also allow for maximum flexibility.\n\nThe core function of this package is to provide an easy way to layer\nimages and then composite them together.\n\nWe're pre-releasing this as it does everything we need it to, but we're\nbusy with other stuff, and as you know incomplete and released is better\n(and quicker) than complete and released. And we need it on packagist :)\n\n### Basic Usage\n\n```php\n$init = [\n    'id' =\u003e 12,\n    'width' =\u003e 100,\n    'height' =\u003e 100,\n];\n\n$pslayers = new Pslayers($init);\n```\n\n#### Single Layer\n\n```php\n// Bare minimum for a blank layer\n$layerConfig = [\n    'id' =\u003e 14,\n    'width' =\u003e 100,\n    'height' =\u003e 100,\n];\n\n$layer = new BlankLayer($layerConfig);\n\n// getting\n$width = $layer-\u003ewidth(); // $width = 100\n\n// setting\n$layer-\u003ewidth(200); // $width = 200\n```\n\n##### Standard base getters and setters\n\nIt was very silly to do var/get/set all with the same name. This is on the\ntodo list to refactor out.\n\n```\n$layer-\u003ewidth();\n$layer-\u003eheight();\n$layer-\u003epositionX();\n$layer-\u003epositionY();\n$layer-\u003eopacity(); // number between 0 and 1\n$layer-\u003ecomposite(); // see notes below\n```\n\n##### Getting details of the layer\n\nAll layer classes implement an interface which forces the method\n`getLayerDetailsArray()` which returns an array representation of the\nlayer, which differs from layer to layer.\n\nThere is a helper method that fetches the JSON representation of this\nwhich is called `getLayerDetailsJson()` and all types of layers have\nthis method available on them.\n\n##### Setting the Composite\n\nComposite is the Composite Operator Constants, which is Imagick integer\nconstants.\n\nYou pass then in with `Imagick::COMPOSITE_DEFAULT` or whichever composite\noperator you want to apply on your layer.\n\nCurrently only 1 composite, it is not possible to combine composites yet.\n\n```php\n$layer-\u003ecomposite(Imagick::COMPOSITE_LIGHTEN);\n```\n\nThis composite will be applied when the stack is rendered.\n\n#### Collections of Layers\n\n```php\n// Make a layer\n$layer = new BlankLayer($config);\n\n// Add to your Pslayers object\n$pslayer-\u003elayers-\u003eaddLayerToCollection($layer);\n\n// Add with foced z-index (destructive, see notes below)\n$pslayer-\u003elayers-\u003eaddLayerToCollection($layer, 2);\n```\n\n##### Programmatic Collections\n\nYou can make and manipulate your own collections if you like\n\n```php\n// Make a collection\n$collection = new LayerCollection();\n\n// Add a layer to a collection\n$collection-\u003eaddLayerToCollection($layer);\n\n// Add a layer with a forced z index (destructive, see notes below)\n$collection-\u003eaddLayerToCollection($layer, 1);\n```\n\n#### Rendering\n\nYou can call the render method on your collection which will render\nup from index 0\n\n```\n$pslayers-\u003eaddLayerToCollection($layer1);\n$pslayers-\u003eaddLayerToCollection($layer2);\n$pslayers-\u003eaddLayerToCollection($layer3);\n\n$pslayers-\u003erender();\n```\n\n#### Layer Types\n\nMore info on the standard layer types\n\n##### Blank Layer\n\nDetailed above, this is the most basic but most powerful of layers. It has\nunlimited potential.\n\nYou can interact with its `canvas` attribute, which is a fully functional\nImagick class.\n\nGo crazy!\n\n##### Text Layer\n\nAllows addition and manipulation of text\n\nAdds some additional text-specific properties\n\n```php\n$layer = new TextLayer($config);\n\n$layer-\u003etext('text');\n$layer-\u003efont('/path/to/font');\n$layer-\u003efontFamily('Times');\n$layer-\u003efontSize(16);\n$layer-\u003efontWeight(400);\n$layer-\u003efontStretch(\\Imagick::STRETCH_ANY);\n$layer-\u003efontSize(\\Imagick::STYLE_NORMAL);\n$layer-\u003eunderColour('#FFF');\n$layer-\u003efillColour('rgba(255, 128, 0, 0.5)');\n$layer-\u003efillOpacity(0.1);\n$layer-\u003estrokeColour('hsl(200, 20, 50)');\n$layer-\u003estrokeWidth(2);\n$layer-\u003estrokeOpacity(1.0);\n```\n\n##### Image Layer\n\nThis *only* works with the `imageUrl` config option at this time.\n\nYou can still set the image directly or use a BlankLayer and set your\nimage on that canvas.\n\nThis will be fixed.\n\n##### Gradient Layer\n\nCurrently only a start-to-finish top-to-bottom solid-to-solid gradient\nlayer. This will be expanded upon.\n\n```php\n$layer = new GradientLayer($config);\n\n$layer-\u003estartColour('#FFFFFF');\n$layer-\u003eendColour('#000000');\n```\n\nThere is no start or end or direction yet\n\n#### Radial Gradient Layer\n\n```php\n$layer = new RadialGradientLayer($config);\n\n$layer-\u003estartColour('#FFFFFF');\n$layer-\u003eendColour('#000000');\n```\n\nLike its cousin it's also not 100% implemented, but it provides the most\nbasic of radial gradient that Imagick has to offer.\n\n##### Solid Layer\n\nThis is just a solid colour layer\n\n```php\n$layer = new SolidLayer($config);\n\n$layer-\u003ecolour('#FFFFFF');\n```\n\n##### Pattern Layer\n\nA layer that tiles a standard Imagick pattern. You can add optional\nscaling and scale filtering values.\n\nThis is *not* a tiling layer, this uses standard, low res, built in\npatterns that come with Imagick.\n\n```php\n$layer = new PatternLayer($config);\n\n$layer-\u003epattern('bricks');\n$layer-\u003escale(2);\n$layer-\u003escaleFilter(Imagick::FILTER_BICUBIC);\n```\n\n##### Plasma Layer\n\nGenerates the standard Imagick `plasma:` style Psuedoimage.\n\n```php\n$layer = new PlasmaLayer($config);\n```\n\n##### Group Layer\n\nThis is basically a layer that contains another collection of layers\nthat can each have their own compositing trees, so you can have greater\ncontrol over your layer composition and manipulation.\n\n```php\n$layer = new GroupLayer($config);\n\n$newTextLayer = new TextLayer($config);\n$newGradientLayer = new GradientLayer($config);\n\n$layer-\u003egroup-\u003eaddLayerToCollection($newGradientLayer, 1);\n$layer-\u003egroup-\u003eaddLayerToCollection($newTextLayer, 2);\n\n$layer-\u003erender();\n```\n\nThis needs to get its render triggered when appropriate\n\n## Compositing\n\nA big part of the power of this comes from the compositing that is\navailable.\n\nYou can add a composite mode to any layer and during render it will be\napplied.\n\nNote that while you can apply multiple filters to layers, you can\nonly apply a single composite. If you want to achieve multiple composite\nmixes at once you can achieve this by making a group layer with copies\nof the same layer in there and composite each copy the way you want.\n\nSupported composite modes\n\n* Add - The image + the image below\n* Atop - The result is the same shape as image, with composite image obscuring image where the image shapes overlap\n* Blend - Blends the image\n* Bump Map - The same as multiply, except the source is converted to grayscale first.\n* Colour Burn - Darkens the destination image to reflect the source image\n* Colour Dodge - Brightens the destination image to reflect the source image\n* Colourise - Colorizes the target image using the composite image\n* Copy - Copies the source image on the target image\n* Copy Black - Copies black from the source to target\n* Copy Blue - Copies blue from the source to target\n* Copy Cyan - Copies cyan from the source to target\n* Copy Green - Copies green from the source to target\n* Copy Magenta - Copies magenta from the source to target\n* Copy Opacity - Copies opacity from the source to target\n* Copy Red - Copies red from the source to target\n* Copy Yellow - Copies yellow from the source to target\n* Darken - Darkens the target image\n* Destination Atop - The part of the destination lying inside of the source is composited over the source and replaces the destination\n* Destination In - The parts inside the source replace the target\n* Destination Out - The parts outside the source replace the target\n* Destination Over - Target replaces the source\n* Difference - Subtracts the darker of the two constituent colors from the lighter\n* Displace - Shifts target image pixels as defined by the source\n* Dissolve - Dissolves the source in to the target\n* Exclusion - Produces an effect similar to that of Difference, but appears as lower contrast\n* Hard Light - Multiplies or screens the colors, dependent on the source color value\n* Hue - Modifies the hue of the target as defined by source\n* Composite In - Composites source into the target\n* Lighten - Lightens the target as defined by source\n* Luminise - Luminizes the target as defined by source\n* Minus - Subtracts the source from the target\n* Modulate - Modulates the target brightness, saturation and hue as defined by source\n* Multiply - Multiplies the target to the source\n* Composite Out - Composites outer parts of the source on the target\n* Composite Over - Composites source over the target\n* Overlay - Overlays the source on the target\n* Plus - Adds the source to the target\n* Replace - Replaces the target with the source\n* Saturate - Saturates the target as defined by the source\n* Screen - The source and destination are complemented and then multiplied and then replace the destination\n* Soft Light - Darkens or lightens the colors, dependent on the source\n* Source Atop - The part of the source lying inside of the destination is composited onto the destination\n* Source In - The part of the source lying inside of the destination replaces the destination\n* Source Out - The part of the source lying outside of the destination replaces the destination\n* Source Over - The source replaces the destination\n* Subtract - Subtract the colors in the source image from the destination image\n* Threshold - The source is composited on the target as defined by source threshold\n* XOR - The part of the source that lies outside of the destination is combined with the part of the destination that lies outside of the source\n\n## TODO before v1 release\n\n* refactor out var/get/set all using same name\n* z-index management\n* all paramaters below\n* all blend/mix modes below\n* all documentation below\n\n### Exaxt PS Layer Blend Modes for Reference\n\n* Brightness\n* Contrast\n* Saturation\n* Tint\n* Hue\n\n#### Darken\n\n* Darken\n* Multiply\n* Colour Burn\n* Linear Burn\n* Darker Colour\n\n#### Lighten\n\n* Lighten\n* Screen\n* Colour Dodge\n* Linear Dodge (Add)\n* Lighter Colour\n\n#### Contrast\n\n* Overlay\n* Soft Light\n* Hard Light\n* Vivid Light\n* Linear Light\n* Pin Light\n* Hard Mix\n\n#### Inversion\n\n* Difference\n* Exclusion\n\n#### Cancelleation\n\n* Subtract\n* Divide\n\n#### Component\n\n* Hue\n* Saturation\n* Colour\n* Luminosity\n\n## Mask\n\n# NOT IMPLEMENTED\n\n* Gradiant Mask\n* Transparency Mask\n\n## Filters\n\nThere is support for filters\n\nYou can combine filters on a layer in a similar way to how you combine\nlayers together in a collection - the z-index is the array index, and the\nrender is run up the index.\n\n### Standard Filters\n\nThese are the base filters included with pslayers.\n\nWe have designed them to be easily extensible and creatable, and will\nhappily accept new filters into the core library should they be up to\nscratch. Contributions are welcome.\n\n##### Blur\n\nBasic blur filter\n\n```php\n$blurFilter = new BlurFilter([\n    'id' =\u003e 'blur',\n    'radius' =\u003e 5,                      // required\n    'sigma' =\u003e 2,                       // required\n    'channel' =\u003e \\Imagik::CHANNEL_ALL,  // optional\n]);\n\n$blankLayer = new BlankLayer([\n    'id' =\u003e 'blank',\n    'filters' =\u003e [\n        $blurFilter,\n        // You can combine filters\n    ]\n])\n```\n\n### Fred's Filters Filter Pack\n\n\u003e We've included this by default, but you need to ask Fred if you're\nwanting to use them for anything other than personal use.\n\nThese are wrapped up versions of the infamous Fred's Imagick scripts that\nhave been implemented as safely and securely as we possibly could.\n\nIn order to keep things consistent we do not support any default values\nwith any of these filters.\n\nWe have not implemented all the filters, but there is a solid base there\nthat should make it easy for anyone to quickly add one of his filters.\n\nThis also means that you can wrap up any bash script you like, but please,\nuse this wisely. We will only accept any contributions along these lines\nafter careful vetting.\n\n### Implemented Fred Filter and Usage\n\n#### Stained Glass\n\nGives a stained glass effect.\n\n[Docs](http://www.fmwconcepts.com/imagemagick/stainedglass/index.php)\n\n```php\n$filter = new StainedGlassFilter([\n    'id' =\u003e 1,\n    'kind' =\u003e 'random',\n    'size' =\u003e 50,\n    'offset' =\u003e 0,\n    'ncolors' =\u003e 8,\n    'bright' =\u003e 100,\n    'ecolor' =\u003e 'black',\n    'thick' =\u003e 0,\n    'rseed' =\u003e rand(),\n]);\n\n// And then add to a layer\n\n$plasmaLayer = new PlasmaLayer([\n    'id' =\u003e 'master-layer-plasma-layer',\n    'width' =\u003e $width,\n    'height' =\u003e $height,\n    'opacity' =\u003e 0.8,\n    'positionX' =\u003e 0,\n    'positionY' =\u003e 0,\n    'composite' =\u003e Imagick::COMPOSITE_DARKEN,\n    'filters' =\u003e [\n        $stainedGlassFilter,\n    ],\n]);\n```\n\n#### Dice\n\nDices up the images\n\n[Docs](http://www.fmwconcepts.com/imagemagick/dice/index.php)\n\n```php\n$diceFilter = new DiceFilter([\n    'id' =\u003e 'master-layer-dice-filter',\n    'size' =\u003e 100,\n    'percent' =\u003e 100,\n    'center' =\u003e '10,10',\n    'radii' =\u003e '0,0',\n    'rounding' =\u003e '0,0',\n]);\n```\n\n#### Other Freds Filters\n\nNot all filters have been added. If you add a filter please do contribute\nit back to this project via a PR.\n\nYou can extend `FredBaseFilter` and follow the style within one of the\nother templates.\n\nAs an example we will run through the creation of the\n[stained glass filter](http://www.fmwconcepts.com/imagemagick/stainedglass/index.php) - you can follow along in the source for this\nfilter.\n\nThe usage instructions show the switches\n\n```\nUSAGE: stainedglass [-k kind] [-s size] [-o offset] [-n ncolors] [-b bright] [-e ecolor] [-t thick] [-r rseed] [-a] infile outfile\nUSAGE: stainedglass [-h or -help]\n\n-k .... kind ....... kind of stainedglass cell shape; choices are: square \n.................... (or s), hexagon (or h), random (or r); default=random\n-s .... size ....... size of cell; integer\u003e0; default=16 \n-o .... offset ..... random offset amount; integer\u003e=0; default=6; \n.................... only applies to kind=random\n-n .... ncolors .... number of desired reduced colors for the output; \n.................... integer\u003e0; default is no color reduction\n-b .... bright ..... brightness value in percent for output image; \n.................... integer\u003e=0; default=100\n-e .... ecolor ..... color for edge or border around each cell; any valid \n.................... IM color; default=black\n-t .... thick ...... thickness for edge or border around each cell; \n.................... integer\u003e=0; default=1; zero means no edge or border\n-r .... rseed ...... random number seed value; integer\u003e=0; if seed provided, \n.................... then image will reproduce; default is no seed, so that \n.................... each image will be randomly different; only applies \n.................... to kind=random\n-a ................. use average color of cell rather than color at center \n.................... of cell; default is center color\n```\n\nYou will use those in the creation of the class.\n\nAt the very least you need the following\n\n```php\nnamespace DarrynTen\\Pslayers\\Filters\\Filter\\Fred\\StainedGlass;\n\nuse DarrynTen\\Pslayers\\Filters\\Filter\\Fred\\FredBaseFilter;\n```\n\nalthough you will see in the file that there is very strict validation\nhappening in all of these classes, but we will not be worrying about that\nright now for the sake of this tutorial.\n\nNext we set the extend the included base filter and set the command.\n\nThis is the command that one would run if using these filters in the\ncommand line.\n\n```php\nclass StainedGlassFilter extends FredBaseFilter\n{\n    protected $command = 'stainedglass';\n```\n\nWe then make a mapping of all the switches\n\n```php\n    protected $switchMap = [\n        'kind' =\u003e 'k',\n        'size' =\u003e 's',\n        'offset' =\u003e 'o',\n        'ncolors' =\u003e 'n',\n        'bright' =\u003e 'b',\n        'ecolor' =\u003e 'e',\n        'thick' =\u003e 't',\n        'rseed' =\u003e 'r',\n    ];\n```\n\nThese will get mapped out to the command when the `render()` method that\nis inside the base class is called.\n\nYou will notice that there is no support for the `-a` switch, as it\noperates sort-of like a boolean, but we have not added this type of\n\"anonymous\" switch (a switch that does not provide a value).\n\nPlease feel free to update the base filter to support this.\n\nWe then make `protected` variables for each entry in the switch map that\nwill be used by the base class when constructing.\n\n```php\n    protected $kind;\n    protected $size;\n    protected $offset;\n    protected $ncolors;\n    protected $bright;\n    protected $ecolor;\n    protected $thick;\n    protected $rseed;\n```\n\nEvery single one of these must be the exact name as per the switch map\nyou defined above. This is very important. It is also important that you\nmap to the short version of the switch.\n\nThen you make a constructor\n\n```php\n    public function __construct(array $config)\n    {\n        // Do your validation here, before you construct the parent\n\n        parent::__construct($config);\n    }\n```\n\nAnd then you're done. That's the entirety of creating a mapping to one of\nthe filters. All the magic happens in the base fred filter :)\n\nRemember though, we have not included any validation or doc blocks in the\nabove example, which *must* be included for a new filter to be accepted\ninto the project. It is also important to throw exceptions for any\nvalidation errors (don't return `false`, you must `throw`).\n\n## Acknowledgements\n\n* [Dmitry Semenov](https://github.com/mxnr), as always.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdarrynten%2Fpslayers","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdarrynten%2Fpslayers","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdarrynten%2Fpslayers/lists"}