├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── composer.json ├── config └── stable-diffusion.php ├── database ├── factories │ └── ModelFactory.php └── migrations │ └── create_stable_diffusion_results_table.php.stub ├── pint.json └── src ├── Models └── StableDiffusionResult.php ├── Prompt.php ├── StableDiffusion.php ├── StableDiffusionServiceProvider.php └── Traits ├── HasAuthors.php ├── HasCanvases.php ├── HasFinishingTouches.php └── HasPaintingStyles.php /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to `Laravel-StableDiffusion` will be documented in this file. 4 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) RuliLG 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Stable Diffusion integration with Replicate and Laravel 2 | 3 | [![Latest Version on Packagist](https://img.shields.io/packagist/v/rulilg/laravel-stable-diffusion.svg?style=flat-square)](https://packagist.org/packages/rulilg/laravel-stable-diffusion) 4 | [![GitHub Code Style Action Status](https://img.shields.io/github/workflow/status/rulilg/laravel-stable-diffusion/Fix%20PHP%20code%20style%20issues?label=code%20style)](https://github.com/rulilg/laravel-stable-diffusion/actions?query=workflow%3A"Fix+PHP+code+style+issues"+branch%3Amain) 5 | [![Total Downloads](https://img.shields.io/packagist/dt/rulilg/laravel-stable-diffusion.svg?style=flat-square)](https://packagist.org/packages/rulilg/laravel-stable-diffusion) 6 | 7 | Laravel wrapper around the Replicate API to use Stable Diffusion to generate text2img. 8 | 9 | - 🎨 Built-in prompt helper to create better images 10 | - 🚀 Store the results in your database 11 | - 🎇 Generate multiple images in the same API call 12 | 13 | ## Installation 14 | 15 | You can install the package via composer: 16 | 17 | ```bash 18 | composer require rulilg/laravel-stable-diffusion 19 | ``` 20 | 21 | You can publish and run the migrations with: 22 | 23 | ```bash 24 | php artisan vendor:publish --tag="stable-diffusion-migrations" 25 | php artisan migrate 26 | ``` 27 | 28 | You can publish the config file with: 29 | 30 | ```bash 31 | php artisan vendor:publish --tag="stable-diffusion-config" 32 | ``` 33 | 34 | This is the contents of the published config file: 35 | 36 | ```php 37 | return [ 38 | 'url' => env('REPLICATE_URL', 'https://api.replicate.com/v1/predictions'), 39 | 'token' => env('REPLICATE_TOKEN'), 40 | 'version' => env('REPLICATE_STABLEDIFFUSION_VERSION', 'a9758cbfbd5f3c2094457d996681af52552901775aa2d6dd0b17fd15df959bef'), 41 | ]; 42 | 43 | ``` 44 | 45 | Register in [Replicate](https://replicate.com/) and store your token in the `REPLICATE_TOKEN` .env variable. 46 | 47 | Optionally, you can publish the views using 48 | 49 | ```bash 50 | php artisan vendor:publish --tag="laravel-stable-diffusion-views" 51 | ``` 52 | 53 | ## Usage 54 | 55 | It's important to understand that the image generation process is **async**. We need first to send a request to Replicate and, after a few seconds, we can fetch the results back. 56 | 57 | This is the code we need to generate an image. This will return a `StableDiffusionResult` model. 58 | 59 | ```php 60 | use RuliLG\StableDiffusion\StableDiffusion; 61 | use RuliLG\StableDiffusion\Prompt; 62 | 63 | StableDiffusion::make() 64 | ->withPrompt( 65 | Prompt::make() 66 | ->with('a panda sitting on the streets of New York after a long day of walking') 67 | ->photograph() 68 | ->resolution8k() 69 | ->trendingOnArtStation() 70 | ->highlyDetailed() 71 | ->dramaticLighting() 72 | ->octaneRender() 73 | ) 74 | ->generate(4); 75 | ``` 76 | 77 | After the `generate()` method is called, an API request to Replicate is sent so they can start processing the prompt. This will generate a record in our database with a `status="starting"` value, and the ID returned by Replicate. 78 | 79 | To retrieve the results back from Replicate, we need to run the following code: 80 | 81 | ```php 82 | use RuliLG\StableDiffusion\StableDiffusion; 83 | 84 | // we get the Replicate ID and fetch the results back. 85 | // This method will automatically update the record with the new information 86 | $freshResults = StableDiffusion::get($result->replicate_id); 87 | if ($freshResults->is_successful) { 88 | dd($freshResults->output); // List of URLs with the images 89 | } 90 | ``` 91 | 92 | If the results were already fetched, then no API request will be made, so we can safely call this method every time. 93 | 94 | ### The StableDiffusionResult model 95 | 96 | After a request to Replicate is made, a new record is inserted in your database with the following information: 97 | 98 | Column | Description 99 | ----- | ----- 100 | replicate_id | ID from Replicate, which we can use to retrieve the results back 101 | user_prompt | Prompt passed to the `Prompt::make()->with()` method 102 | full_prompt | Prompt generated with all the modifiers 103 | url | Internal URL to fetch the results back from Replicate 104 | status | Status. Can be one of: `starting`, `processing`, `succeeded`, `failed` or `cancelled`. This library doesn't support cancelling requests. 105 | output | Array of URLs containing the images 106 | error | Error description if needed (i.e. no NSFW content is allowed) 107 | predict_time | Time spent by Replicate processing your image, which you will be charged for 108 | 109 | Additionally, the model has the following attributes to know the status of the prediction: 110 | 111 | - `$result->is_successful` 112 | - `$result->is_failed` 113 | - `$result->is_starting` 114 | - `$result->is_processing` 115 | 116 | Also, as results have to be manually updated through the `StableDiffusion::get($id)` method, we can also fetch the results that are not in a finished status: 117 | 118 | ```php 119 | use RuliLG\StableDiffusion\Models\StableDiffusionResult; 120 | use RuliLG\StableDiffusion\StableDiffusion; 121 | 122 | $results = StableDiffusionResult::unfinished()->get(); 123 | foreach ($results as $result) { 124 | StableDiffusion::get($result->replicate_id); 125 | } 126 | ``` 127 | 128 | ## Generating prompts 129 | 130 | There are several styles already built-in: 131 | 132 | Method | Prompt modification 133 | ---- | ---- 134 | `realistic()` | {prompt}, realistic 135 | `hyperrealistic()` | {prompt}, hyperrealistic 136 | `conceptArt()` | {prompt}, concept art 137 | `abstractArt()` | {prompt}, abstract art 138 | `oilPainting()` | {prompt}, oil painting 139 | `watercolor()` | {prompt}, watercolor 140 | `acrylic()` | {prompt}, acrylic 141 | `pencilDrawing()` | {prompt}, pencil drawing 142 | `digitalPainting()` | {prompt}, digital painting 143 | `penDrawing()` | {prompt}, pen drawing 144 | `charcoalDrawing()` | {prompt}, charcoal drawing 145 | `byPicasso()` | {prompt}, by Pablo Picasso 146 | `byVanGogh()` | {prompt}, by Vincent Van Gogh 147 | `byRembrandt()` | {prompt}, by Rembrandt 148 | `byMunch()` | {prompt}, by Edvard Munch 149 | `byKlimt()` | {prompt}, by Paul Klimt 150 | `byKandinsky()` | {prompt}, by Jackson Pollock 151 | `byMonet()` | {prompt}, by Claude Monet 152 | `byDali()` | {prompt}, by Salvador Dali 153 | `byDegas()` | {prompt}, by Edgar Degas 154 | `byKahlo()` | {prompt}, by Frida Kahlo 155 | `byCezanne()` | {prompt}, by Pablo Cezanne 156 | `photograph()` | a photo of {prompt} 157 | `highlyDetailed()` | {prompt}, highly detailed 158 | `surrealism()` | {prompt}, surrealism 159 | `trendingOnArtStation()` | {prompt}, trending on art station 160 | `triadicColorScheme()` | {prompt}, triadic color scheme 161 | `smooth()` | {prompt}, smooth 162 | `sharpFocus()` | {prompt}, sharp focus 163 | `matte()` | {prompt}, matte 164 | `elegant()` | {prompt}, elegant 165 | `theMostBeautifulImageEverSeen()` | {prompt}, the most beautiful image ever seen 166 | `illustration()` | {prompt}, illustration 167 | `digitalPaint()` | {prompt}, digital paint 168 | `dark()` | {prompt}, dark 169 | `gloomy()` | {prompt}, gloomy 170 | `octaneRender()` | {prompt}, octane render 171 | `resolution8k()` | {prompt}, 8k 172 | `resolution4k()` | {prompt}, 4k 173 | `washedColors()` | {prompt}, washed colors 174 | `sharp()` | {prompt}, sharp 175 | `dramaticLighting()` | {prompt}, dramatic lighting 176 | `beautiful()` | {prompt}, beautiful 177 | `postProcessing()` | {prompt}, post processing 178 | `pictureOfTheDay()` | {prompt}, picture of the day 179 | `ambientLighting()` | {prompt}, ambient lighting 180 | `epicComposition()` | {prompt}, epic composition 181 | 182 | Additionally, you can add custom styles with the following methods: 183 | 184 | - `as(string $canvas)`: to add a string at the beginning (i.e. "a photograph of") 185 | - `paintingStyle(string $style)`: to add a painting style (i.e. realistic, hiperrealistic, etc.) 186 | - `by(string $author)`: to instruct the system to paint it with the style of a certain author 187 | - `effect(string $effect)`: to add a finishing touch to the prompt. You can add as many as you want. 188 | 189 | To learn more on how to build prompts for Stable Diffusion, please [enter this link](https://beta.dreamstudio.ai/prompt-guide). 190 | 191 | ## Borah Digital Labs 192 | [Borah Digital Labs](https://borah.digital/) crafts web applications, open-source packages, and offers a team of full-stack solvers ready to tackle your next project. We have built a series of projects: 193 | 194 | - [CodeDocumentation](https://codedocumentation.app/): Automatic code documentation platform 195 | - [AutomaticDocs](https://automaticdocs.app/): One-time documentation for your projects 196 | - [Talkzy](https://talkzy.app/): A tool to summarize meetings 197 | - Compass: An agent-driven tool to help manage companies more efficiently 198 | - [Prompt Token Counter](https://prompttokencounter.com/): Simple tool to count tokens in prompts 199 | - [Sabor en la Oficina](https://saborenlaoficina.es/): Website + catering management platform 200 | 201 | We like to use Laravel for most of our projects and we love to tackle big, complicated problems. Feel free to reach out and we can have a virtual coffee! 202 | 203 | ## License 204 | 205 | The MIT License (MIT). Please see [License File](LICENSE.md) for more information. 206 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rulilg/laravel-stable-diffusion", 3 | "description": "Stable Diffusion integration with Replicate and Laravel", 4 | "keywords": [ 5 | "RuliLG", 6 | "laravel", 7 | "stable diffusion", 8 | "laravel-stable-diffusion" 9 | ], 10 | "homepage": "https://github.com/rulilg/laravel-stable-diffusion", 11 | "license": "MIT", 12 | "authors": [ 13 | { 14 | "name": "Raúl López", 15 | "email": "raul@calimasolutions.com", 16 | "role": "Developer" 17 | } 18 | ], 19 | "require": { 20 | "php": "^8.1 || ^8.2", 21 | "spatie/laravel-package-tools": "^1.13.0", 22 | "illuminate/contracts": "^9.0 || ^10.0" 23 | }, 24 | "require-dev": { 25 | "laravel/pint": "^1.0", 26 | "nunomaduro/collision": "^6.0 || ^7.0", 27 | "nunomaduro/larastan": "^2.0.1", 28 | "orchestra/testbench": "^7.0", 29 | "pestphp/pest": "^1.21 || ^2.6", 30 | "pestphp/pest-plugin-laravel": "^1.1 || ^2.0", 31 | "phpstan/extension-installer": "^1.1", 32 | "phpstan/phpstan-deprecation-rules": "^1.0", 33 | "phpstan/phpstan-phpunit": "^1.0", 34 | "phpunit/phpunit": "^9.5" 35 | }, 36 | "autoload": { 37 | "psr-4": { 38 | "RuliLG\\StableDiffusion\\": "src" 39 | } 40 | }, 41 | "autoload-dev": { 42 | "psr-4": { 43 | "RuliLG\\StableDiffusion\\Tests\\": "tests" 44 | } 45 | }, 46 | "scripts": { 47 | "analyse": "vendor/bin/phpstan analyse", 48 | "test": "vendor/bin/pest", 49 | "test-coverage": "vendor/bin/pest --coverage", 50 | "format": "vendor/bin/pint" 51 | }, 52 | "config": { 53 | "sort-packages": true 54 | }, 55 | "extra": { 56 | "laravel": { 57 | "providers": [ 58 | "RuliLG\\StableDiffusion\\StableDiffusionServiceProvider" 59 | ], 60 | "aliases": { 61 | "StableDiffusion": "RuliLG\\StableDiffusion\\Facades\\StableDiffusion" 62 | } 63 | } 64 | }, 65 | "minimum-stability": "dev", 66 | "prefer-stable": true 67 | } 68 | -------------------------------------------------------------------------------- /config/stable-diffusion.php: -------------------------------------------------------------------------------- 1 | env('REPLICATE_URL', 'https://api.replicate.com/v1/predictions'), 5 | 'token' => env('REPLICATE_TOKEN'), 6 | 'version' => env('REPLICATE_STABLEDIFFUSION_VERSION', 'a9758cbfbd5f3c2094457d996681af52552901775aa2d6dd0b17fd15df959bef'), 7 | ]; 8 | -------------------------------------------------------------------------------- /database/factories/ModelFactory.php: -------------------------------------------------------------------------------- 1 | id(); 13 | $table->string('replicate_id')->unique(); 14 | $table->string('user_prompt'); 15 | $table->string('full_prompt'); 16 | $table->string('url'); 17 | $table->string('status', 30)->index(); 18 | $table->json('output')->nullable(); 19 | $table->mediumText('error')->nullable(); 20 | $table->float('predict_time')->nullable(); 21 | $table->timestamps(); 22 | }); 23 | } 24 | }; 25 | -------------------------------------------------------------------------------- /pint.json: -------------------------------------------------------------------------------- 1 | { 2 | "exclude": [ 3 | "build" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /src/Models/StableDiffusionResult.php: -------------------------------------------------------------------------------- 1 | 'array', 18 | ]; 19 | 20 | public function scopeUnfinished($query) 21 | { 22 | return $query->whereIn('status', ['starting', 'processing']); 23 | } 24 | 25 | public function isSuccessful(): Attribute 26 | { 27 | return Attribute::make( 28 | get: fn () => $this->status === 'succeeded', 29 | ); 30 | } 31 | 32 | public function isStarting(): Attribute 33 | { 34 | return Attribute::make( 35 | get: fn () => $this->status === 'starting', 36 | ); 37 | } 38 | 39 | public function isProcessing(): Attribute 40 | { 41 | return Attribute::make( 42 | get: fn () => $this->status === 'processing', 43 | ); 44 | } 45 | 46 | public function isFailed(): Attribute 47 | { 48 | return Attribute::make( 49 | get: fn () => $this->status === 'failed', 50 | ); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/Prompt.php: -------------------------------------------------------------------------------- 1 | prompt = $prompt; 33 | 34 | return $this; 35 | } 36 | 37 | public function toString(): string 38 | { 39 | $prompt = $this->prompt; 40 | if ($this->author) { 41 | $prompt .= ', made by '.$this->author; 42 | } 43 | 44 | if ($this->canvas) { 45 | $prompt = $this->canvas.' of '.$prompt; 46 | } 47 | 48 | if ($this->paintingStyle) { 49 | $prompt .= ', '.$this->paintingStyle; 50 | } 51 | 52 | if (! empty($this->finishingTouches)) { 53 | $prompt .= ', '.implode(', ', array_values(array_unique($this->finishingTouches))); 54 | } 55 | 56 | return $prompt; 57 | } 58 | 59 | public function userPrompt(): string 60 | { 61 | return $this->prompt; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/StableDiffusion.php: -------------------------------------------------------------------------------- 1 | first(); 26 | assert($result !== null, 'Unknown id'); 27 | 28 | $idleStatuses = ['starting', 'processing']; 29 | if (! in_array($result->status, $idleStatuses)) { 30 | return $result; 31 | } 32 | 33 | $response = self::make() 34 | ->client() 35 | ->get($result->url) 36 | ->json(); 37 | 38 | $result->update([ 39 | 'status' => Arr::get($response, 'status', $result->status), 40 | 'output' => Arr::get($response, 'output'), 41 | 'error' => Arr::get($response, 'error'), 42 | 'predict_time' => Arr::get($response, 'metrics.predict_time'), 43 | ]); 44 | 45 | return $result; 46 | } 47 | 48 | public function withPrompt(Prompt $prompt) 49 | { 50 | $this->prompt = $prompt; 51 | 52 | return $this; 53 | } 54 | 55 | public function width(int $width) 56 | { 57 | assert($width > 0, 'Width must be greater than 0'); 58 | if ($width <= 768) { 59 | assert($width <= 768 && $this->width <= 1024, 'Width must be lower than 768 and height lower than 1024'); 60 | } else { 61 | assert($width <= 1024 && $this->width <= 768, 'Width must be lower than 1024 and height lower than 768'); 62 | } 63 | 64 | $this->width = $width; 65 | 66 | return $this; 67 | } 68 | 69 | public function height(int $height) 70 | { 71 | assert($height > 0, 'Height must be greater than 0'); 72 | if ($height <= 768) { 73 | assert($height <= 768 && $this->width <= 1024, 'Height must be lower than 768 and width lower than 1024'); 74 | } else { 75 | assert($height <= 1024 && $this->width <= 768, 'Height must be lower than 1024 and width lower than 768'); 76 | } 77 | 78 | $this->height = $height; 79 | 80 | return $this; 81 | } 82 | 83 | public function generate(int $numberOfImages): StableDiffusionResult 84 | { 85 | assert($this->prompt !== null, 'You must provide a prompt'); 86 | assert($numberOfImages > 0, 'You must provide a number greater than 0'); 87 | 88 | $response = $this->client() 89 | ->post(config('stable-diffusion.url'), [ 90 | 'version' => config('stable-diffusion.version'), 91 | 'input' => [ 92 | 'prompt' => $this->prompt->toString(), 93 | 'num_outputs' => $numberOfImages, 94 | ], 95 | ]) 96 | ->json(); 97 | 98 | $result = StableDiffusionResult::create([ 99 | 'replicate_id' => $response['id'], 100 | 'user_prompt' => $this->prompt->userPrompt(), 101 | 'full_prompt' => $this->prompt->toString(), 102 | 'url' => $response['urls']['get'], 103 | 'status' => $response['status'], 104 | 'output' => $response['output'], 105 | 'error' => $response['error'], 106 | 'predict_time' => null, 107 | ]); 108 | 109 | return $result; 110 | } 111 | 112 | private function client(): PendingRequest 113 | { 114 | return Http::withHeaders([ 115 | 'Authorization' => 'Token '.config('stable-diffusion.token'), 116 | ]) 117 | ->asJson() 118 | ->acceptJson(); 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /src/StableDiffusionServiceProvider.php: -------------------------------------------------------------------------------- 1 | name('laravel-stable-diffusion') 19 | ->hasConfigFile() 20 | ->hasMigration('create_stable_diffusion_results_table'); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/Traits/HasAuthors.php: -------------------------------------------------------------------------------- 1 | author = $author; 10 | 11 | return $this; 12 | } 13 | 14 | public function byPicasso(): static 15 | { 16 | return $this->by('Pablo Picasso'); 17 | } 18 | 19 | public function byVanGogh(): static 20 | { 21 | return $this->by('Vincent Van Gogh'); 22 | } 23 | 24 | public function byRembrandt(): static 25 | { 26 | return $this->by('Rembrandt'); 27 | } 28 | 29 | public function byMunch(): static 30 | { 31 | return $this->by('Edvard Munch'); 32 | } 33 | 34 | public function byKlimt(): static 35 | { 36 | return $this->by('Paul Klimt'); 37 | } 38 | 39 | public function byKandinsky(): static 40 | { 41 | return $this->by('Jackson Pollock'); 42 | } 43 | 44 | public function byMonet(): static 45 | { 46 | return $this->by('Claude Monet'); 47 | } 48 | 49 | public function byDali(): static 50 | { 51 | return $this->by('Salvador Dali'); 52 | } 53 | 54 | public function byDegas(): static 55 | { 56 | return $this->by('Edgar Degas'); 57 | } 58 | 59 | public function byKahlo(): static 60 | { 61 | return $this->by('Frida Kahlo'); 62 | } 63 | 64 | public function byCezanne(): static 65 | { 66 | return $this->by('Pablo Cezanne'); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/Traits/HasCanvases.php: -------------------------------------------------------------------------------- 1 | canvas = $canvas; 10 | 11 | return $this; 12 | } 13 | 14 | public function photograph(): self 15 | { 16 | return $this->as('a photo'); 17 | } 18 | 19 | public function paperSheet(): self 20 | { 21 | return $this->as('a paper sheet'); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/Traits/HasFinishingTouches.php: -------------------------------------------------------------------------------- 1 | finishingTouches[] = $effect; 10 | 11 | return $this; 12 | } 13 | 14 | public function highlyDetailed(): static 15 | { 16 | return $this->effect('highly detailed'); 17 | } 18 | 19 | public function surrealism(): static 20 | { 21 | return $this->effect('surrealism'); 22 | } 23 | 24 | public function trendingOnArtStation(): static 25 | { 26 | return $this->effect('trending on art station'); 27 | } 28 | 29 | public function triadicColorScheme(): static 30 | { 31 | return $this->effect('triadic color scheme'); 32 | } 33 | 34 | public function smooth(): static 35 | { 36 | return $this->effect('smooth'); 37 | } 38 | 39 | public function sharpFocus(): static 40 | { 41 | return $this->effect('sharp focus'); 42 | } 43 | 44 | public function matte(): static 45 | { 46 | return $this->effect('matte'); 47 | } 48 | 49 | public function elegant(): static 50 | { 51 | return $this->effect('elegant'); 52 | } 53 | 54 | public function theMostBeautifulImageEverSeen(): static 55 | { 56 | return $this->effect('the most beautiful image ever seen'); 57 | } 58 | 59 | public function illustration(): static 60 | { 61 | return $this->effect('illustration'); 62 | } 63 | 64 | public function digitalPaint(): static 65 | { 66 | return $this->effect('digital paint'); 67 | } 68 | 69 | public function dark(): static 70 | { 71 | return $this->effect('dark'); 72 | } 73 | 74 | public function gloomy(): static 75 | { 76 | return $this->effect('gloomy'); 77 | } 78 | 79 | public function octaneRender(): static 80 | { 81 | return $this->effect('octane render'); 82 | } 83 | 84 | public function resolution8k(): static 85 | { 86 | return $this->effect('8k'); 87 | } 88 | 89 | public function resolution4k(): static 90 | { 91 | return $this->effect('4k'); 92 | } 93 | 94 | public function washedColors(): static 95 | { 96 | return $this->effect('washed colors'); 97 | } 98 | 99 | public function sharp(): static 100 | { 101 | return $this->effect('sharp'); 102 | } 103 | 104 | public function dramaticLighting(): static 105 | { 106 | return $this->effect('dramatic lighting'); 107 | } 108 | 109 | public function beautiful(): static 110 | { 111 | return $this->effect('beautiful'); 112 | } 113 | 114 | public function postProcessing(): static 115 | { 116 | return $this->effect('post processing'); 117 | } 118 | 119 | public function pictureOfTheDay(): static 120 | { 121 | return $this->effect('picture of the day'); 122 | } 123 | 124 | public function ambientLighting(): static 125 | { 126 | return $this->effect('ambient lighting'); 127 | } 128 | 129 | public function epicComposition(): static 130 | { 131 | return $this->effect('epic composition'); 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /src/Traits/HasPaintingStyles.php: -------------------------------------------------------------------------------- 1 | paintingStyle = $style; 10 | 11 | return $this; 12 | } 13 | 14 | public function realistic(): static 15 | { 16 | return $this->paintingStyle('realistic'); 17 | } 18 | 19 | public function hyperrealistic(): static 20 | { 21 | return $this->paintingStyle('hyperrealistic'); 22 | } 23 | 24 | public function conceptArt(): static 25 | { 26 | return $this->paintingStyle('concept art'); 27 | } 28 | 29 | public function abstractArt(): static 30 | { 31 | return $this->paintingStyle('abstract art'); 32 | } 33 | 34 | public function oilPainting(): static 35 | { 36 | return $this->paintingStyle('oil painting'); 37 | } 38 | 39 | public function watercolor(): static 40 | { 41 | return $this->paintingStyle('watercolor'); 42 | } 43 | 44 | public function acrylic(): static 45 | { 46 | return $this->paintingStyle('acrylic'); 47 | } 48 | 49 | public function pencilDrawing(): static 50 | { 51 | return $this->paintingStyle('pencil drawing'); 52 | } 53 | 54 | public function digitalPainting(): static 55 | { 56 | return $this->paintingStyle('digital painting'); 57 | } 58 | 59 | public function penDrawing(): static 60 | { 61 | return $this->paintingStyle('pen drawing'); 62 | } 63 | 64 | public function charcoalDrawing(): static 65 | { 66 | return $this->paintingStyle('charcoal drawing'); 67 | } 68 | } 69 | --------------------------------------------------------------------------------