├── .github └── workflows │ └── publish.yml ├── LICENSE ├── Nodes_Demo ├── LatentTOPixel.png └── PixelCal.png ├── README.md ├── __init__.py ├── nodes.py └── pyproject.toml /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish to Comfy registry 2 | on: 3 | workflow_dispatch: 4 | push: 5 | branches: 6 | - main 7 | - master 8 | paths: 9 | - "pyproject.toml" 10 | 11 | permissions: 12 | issues: write 13 | 14 | jobs: 15 | publish-node: 16 | name: Publish Custom Node to registry 17 | runs-on: ubuntu-latest 18 | if: ${{ github.repository_owner == 'Ling-APE' }} 19 | steps: 20 | - name: Check out code 21 | uses: actions/checkout@v4 22 | - name: Publish Custom Node 23 | uses: Comfy-Org/publish-node-action@v1 24 | with: 25 | ## Add your own personal access token to your Github Repository secrets and reference it here. 26 | personal_access_token: ${{ secrets.REGISTRY_ACCESS_TOKEN }} 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Ling-APE 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 | -------------------------------------------------------------------------------- /Nodes_Demo/LatentTOPixel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ling-APE/ComfyUI-PixelResolutionCalculator/8de61faaba8486f6eea1de3a2b08cf813da8a31c/Nodes_Demo/LatentTOPixel.png -------------------------------------------------------------------------------- /Nodes_Demo/PixelCal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ling-APE/ComfyUI-PixelResolutionCalculator/8de61faaba8486f6eea1de3a2b08cf813da8a31c/Nodes_Demo/PixelCal.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ComfyUI-PixelResolutionCalculator 2 | 3 | This node is used in the [All-in-one Flux Dev workflow](https://github.com/Ling-APE/ComfyUI-All-in-One-FluxDev-Workflow) I made. 4 | 5 | There is two nodes: 6 | * PixelResolutionCalculator 7 | 8 | ![node1](Nodes_Demo/PixelCal.png) 9 | * LatentSizeToPixelSize 10 | 11 | ![node1](Nodes_Demo/LatentTOPixel.png) 12 | 13 | 14 | ## PixelResolutionCalculator 15 | The pixel resolution calculator is just a simple node that generate the closest "latent friendly" pixel resolution from your mega pixel and aspect ratio of choice. Took inspiration from the ImageScaleToTotalPixels node I saw from the original Flux demo workflow, since with flux everyone seems to talk about it with pixel resolution instead of width and height pixel count like SDXL. 16 | ## LatentSizeToPixelSize 17 | LatentSizeToPixelSize convert a laten samlpe input to width and height pixel count. 18 | -------------------------------------------------------------------------------- /__init__.py: -------------------------------------------------------------------------------- 1 | from .nodes import PixelResolutionCalculator, LatentSizeToPixelSize #import NODE_CLASS_MAPPINGS, NODE_DISPLAY_NAME_MAPPINGS 2 | 3 | #__all__ = ["NODE_CLASS_MAPPINGS", "NODE_DISPLAY_NAME_MAPPINGS"] 4 | 5 | NODE_CLASS_MAPPINGS = { 6 | "PixelResolutionCalculator": PixelResolutionCalculator, 7 | "LatentSizeToPixelSize": LatentSizeToPixelSize, 8 | 9 | } 10 | 11 | NODE_DISPLAY_NAME_MAPPING = { 12 | "PixelResolutionCalculator": "Pixel Resolution Calculator", 13 | "LatentSizeToPixelSize": "Latent Size to Pixel Size" 14 | } 15 | 16 | __all__ = ["NODE_CLASS_MAPPINGS", "NODE_DISPLAY_NAME_MAPPINGS"] -------------------------------------------------------------------------------- /nodes.py: -------------------------------------------------------------------------------- 1 | import math 2 | import torch 3 | 4 | # Pixel Resolution Calculator 5 | 6 | class PixelResolutionCalculator: 7 | def __init__(self): 8 | pass 9 | 10 | @classmethod 11 | def INPUT_TYPES(cls): 12 | return { 13 | "required": { 14 | "megapixels": ("FLOAT", {"default": 2.0, "min": 0.1, "max": 100.0}), 15 | "aspect_ratio_width": ("INT", {"default": 3, "min": 1, "max": 100}), 16 | "aspect_ratio_height": ("INT", {"default": 4, "min": 1, "max": 100}), 17 | "divided_by": ("INT", {"default": 8, "min": 1, "max": 100}), 18 | }, 19 | } 20 | 21 | RETURN_TYPES = ("INT", "INT") 22 | RETURN_NAMES = ("width", "height") 23 | 24 | FUNCTION = "calculate_resolution" 25 | CATEGORY = "image" 26 | 27 | def calculate_resolution(self, megapixels, aspect_ratio_width, aspect_ratio_height, divided_by): 28 | total_pixels = megapixels * 1e6 29 | gcd_value = math.gcd(aspect_ratio_width, aspect_ratio_height) 30 | width_ratio = aspect_ratio_width // gcd_value 31 | height_ratio = aspect_ratio_height // gcd_value 32 | multiplier = (total_pixels / (width_ratio * height_ratio)) ** 0.5 33 | width = int(width_ratio * multiplier) 34 | height = int(height_ratio * multiplier) 35 | 36 | # Round width and height to the nearest multiple of divided_by 37 | width = width - (width % divided_by) 38 | height = height - (height % divided_by) 39 | 40 | return width, height 41 | 42 | # Latent Size to Pixel Size 43 | 44 | class LatentSizeToPixelSize: 45 | @classmethod 46 | def INPUT_TYPES(cls): 47 | return { 48 | "required": { 49 | "samples": ("LATENT",), 50 | "latent_block_size": ("INT", {"default": 8, "min": 1, "max": 100}) 51 | } 52 | } 53 | 54 | RETURN_TYPES = ("INT", "INT") 55 | RETURN_NAMES = ("pixel_width", "pixel_height") 56 | 57 | FUNCTION = "latent_to_pixel_size" 58 | CATEGORY = "image" 59 | 60 | def latent_to_pixel_size(self, samples, latent_block_size): 61 | size_dict = {} 62 | i = 0 63 | for tensor in samples['samples'][0]: 64 | if not isinstance(tensor, torch.Tensor): 65 | print("Error: Input should be a torch.Tensor") 66 | return None 67 | shape = tensor.shape 68 | tensor_height = shape[-2] 69 | tensor_width = shape[-1] 70 | size_dict.update({i:[tensor_width, tensor_height]}) 71 | pixel_width = size_dict[0][0] * latent_block_size 72 | pixel_height = size_dict[0][1] * latent_block_size 73 | 74 | return (pixel_width, pixel_height) 75 | 76 | 77 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "comfyui-pixelresolutioncalculator" 3 | description = "Simple resuluition calculator to convert pixel resolution and aspect ratio to laten friendlt pixel width and height size." 4 | version = "1.0.0" 5 | license = {file = "LICENSE"} 6 | 7 | [project.urls] 8 | Repository = "https://github.com/Ling-APE/ComfyUI-PixelResolutionCalculator" 9 | # Used by Comfy Registry https://comfyregistry.org 10 | 11 | [tool.comfy] 12 | PublisherId = "" 13 | DisplayName = "ComfyUI-PixelResolutionCalculator" 14 | Icon = "" 15 | --------------------------------------------------------------------------------