├── .github
└── workflows
│ └── publish.yml
├── .gitignore
├── LICENSE
├── README.md
├── __init__.py
├── pyproject.toml
├── resharpen.py
└── samples
├── -0.5.jpg
├── 0.0.jpg
└── 0.5.jpg
/.github/workflows/publish.yml:
--------------------------------------------------------------------------------
1 | name: Publish to Comfy registry
2 | on:
3 | workflow_dispatch:
4 | push:
5 | branches:
6 | - main
7 | paths:
8 | - "pyproject.toml"
9 |
10 | jobs:
11 | publish-node:
12 | name: Publish Custom Node to registry
13 | runs-on: ubuntu-latest
14 | # Skip forked repository
15 | if: github.event.repository.fork == false
16 | steps:
17 | - name: Check out code
18 | uses: actions/checkout@v4
19 | - name: Publish Custom Node
20 | uses: Comfy-Org/publish-node-action@main
21 | with:
22 | personal_access_token: ${{ secrets.REGISTRY_ACCESS_TOKEN }}
23 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | __pycache__
2 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2024 Haoming
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 all
13 | 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 THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ComfyUI ReSharpen
2 | This is an Extension for [ComfyUI](https://github.com/comfyanonymous/ComfyUI), which allows you to increase or decrease the amount of details generated during the Stable Diffusion pipeline.
3 |
4 | > **ie.** This is not just a postprocessing filter
5 |
6 | ## How to Use
7 | - Attach the **ReSharpen** node between `Empty Latent` and your `Sampler` node of choice
8 | - Adjust the **details** slider:
9 | - **Positive** values cause the images to be noisy
10 | - **Negative** values cause the images to be blurry
11 |
12 | > Values too large or small may cause the result to become distorted!
13 |
14 | ### Important:
15 | - `Ancestral` samplers *(**eg.** `Euler a`)* do **not** work.
16 | - The effect is "global," meaning if you want to disable it during other parts of the workflow *(**eg.** during `Hires. Fix`)*, you need to add another **ReSharpen** node and set the `details` to `0` again.
17 |
18 | ## Examples
19 |
20 |
21 |
22 |
23 | Sharpness |
24 | -0.5 |
25 | 0.0 |
26 | 0.5 |
27 |
28 |
29 |
30 |
31 | Result |
32 |  |
33 |  |
34 |  |
35 |
36 |
37 |
38 |
39 |
40 |
41 | - [How does it work?](https://github.com/Haoming02/sd-webui-resharpen/blob/main/README.md#how-does-it-work)
42 |
--------------------------------------------------------------------------------
/__init__.py:
--------------------------------------------------------------------------------
1 | from .resharpen import ReSharpen, disable_resharpen
2 | from functools import wraps
3 | from typing import Callable
4 | import execution
5 |
6 | NODE_CLASS_MAPPINGS = {"Resharpen": ReSharpen}
7 | NODE_DISPLAY_NAME_MAPPINGS = {"Resharpen": "ReSharpen"}
8 |
9 |
10 | def find_node(prompt: dict) -> bool:
11 | """Find any ReSharpen Node"""
12 |
13 | return any(v.get("class_type") == "Resharpen" for v in prompt.values())
14 |
15 |
16 | original_validate: Callable = execution.validate_prompt
17 |
18 |
19 | @wraps(original_validate)
20 | def hijack_validate(prompt: dict) -> Callable:
21 |
22 | if not find_node(prompt):
23 | disable_resharpen()
24 |
25 | return original_validate(prompt)
26 |
27 |
28 | execution.validate_prompt = hijack_validate
29 |
--------------------------------------------------------------------------------
/pyproject.toml:
--------------------------------------------------------------------------------
1 | [project]
2 | name = "comfyui-resharpen"
3 | description = "Manipulate the details of generations"
4 | version = "1.1.1"
5 | license = { text = "MIT License" }
6 | dependencies = []
7 |
8 | [project.urls]
9 | Repository = "https://github.com/Haoming02/comfyui-resharpen"
10 |
11 | [tool.comfy]
12 | PublisherId = "haoming02"
13 | DisplayName = "ReSharpen"
14 | Icon = ""
15 |
--------------------------------------------------------------------------------
/resharpen.py:
--------------------------------------------------------------------------------
1 | from functools import wraps
2 | from typing import Callable
3 | import latent_preview
4 | import torch
5 |
6 |
7 | ORIGINAL_PREP: Callable = latent_preview.prepare_callback
8 |
9 | RESHARPEN_STRENGTH: float = 0.0
10 | LATENT_CACHE: torch.Tensor = None
11 |
12 |
13 | def disable_resharpen():
14 | """Reset the ReSharpen Strength"""
15 | global RESHARPEN_STRENGTH
16 | RESHARPEN_STRENGTH = 0.0
17 |
18 |
19 | def hijack(PREP) -> Callable:
20 |
21 | @wraps(PREP)
22 | def prep_callback(*args, **kwargs):
23 | global LATENT_CACHE
24 | LATENT_CACHE = None
25 |
26 | original_callback: Callable = PREP(*args, **kwargs)
27 | if not RESHARPEN_STRENGTH:
28 | return original_callback
29 |
30 | print("[ReSharpen] Enabled~")
31 |
32 | @torch.inference_mode()
33 | @wraps(original_callback)
34 | def hijack_callback(step, x0, x, total_steps):
35 | if not RESHARPEN_STRENGTH:
36 | return original_callback(step, x0, x, total_steps)
37 |
38 | global LATENT_CACHE
39 | if LATENT_CACHE is not None:
40 | delta = x.detach().clone() - LATENT_CACHE
41 | x += delta * RESHARPEN_STRENGTH
42 |
43 | LATENT_CACHE = x.detach().clone()
44 | return original_callback(step, x0, x, total_steps)
45 |
46 | return hijack_callback
47 |
48 | return prep_callback
49 |
50 |
51 | latent_preview.prepare_callback = hijack(ORIGINAL_PREP)
52 |
53 |
54 | class ReSharpen:
55 | @classmethod
56 | def INPUT_TYPES(s):
57 | return {
58 | "required": {
59 | "latent": ("LATENT",),
60 | "details": (
61 | "FLOAT",
62 | {"default": 0.0, "min": -2.0, "max": 2.0, "step": 0.1},
63 | ),
64 | }
65 | }
66 |
67 | RETURN_TYPES = ("LATENT",)
68 | FUNCTION = "hook"
69 | CATEGORY = "latent"
70 |
71 | def hook(self, latent, details: float):
72 |
73 | global RESHARPEN_STRENGTH
74 | RESHARPEN_STRENGTH = details / -10.0
75 |
76 | return (latent,)
77 |
--------------------------------------------------------------------------------
/samples/-0.5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Haoming02/comfyui-resharpen/4f29c1c853b77bc069a5e23d99df151ebd47a17d/samples/-0.5.jpg
--------------------------------------------------------------------------------
/samples/0.0.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Haoming02/comfyui-resharpen/4f29c1c853b77bc069a5e23d99df151ebd47a17d/samples/0.0.jpg
--------------------------------------------------------------------------------
/samples/0.5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Haoming02/comfyui-resharpen/4f29c1c853b77bc069a5e23d99df151ebd47a17d/samples/0.5.jpg
--------------------------------------------------------------------------------