{
  "revision": 0,
  "last_node_id": 139,
  "last_link_id": 0,
  "nodes": [
    {
      "id": 139,
      "type": "75bf8a72-aad8-4f3e-83ee-380e70248240",
      "pos": [
        620,
        900
      ],
      "size": [
        240,
        178
      ],
      "flags": {},
      "order": 1,
      "mode": 0,
      "inputs": [
        {
          "label": "image",
          "localized_name": "images.image0",
          "name": "images.image0",
          "type": "IMAGE",
          "link": null
        }
      ],
      "outputs": [
        {
          "label": "IMAGE",
          "localized_name": "IMAGE0",
          "name": "IMAGE0",
          "type": "IMAGE",
          "links": []
        }
      ],
      "properties": {
        "proxyWidgets": [
          [
            "5",
            "choice"
          ],
          [
            "3",
            "value"
          ],
          [
            "6",
            "value"
          ],
          [
            "7",
            "value"
          ],
          [
            "8",
            "value"
          ],
          [
            "9",
            "value"
          ]
        ]
      },
      "widgets_values": [],
      "title": "Image Levels"
    }
  ],
  "links": [],
  "version": 0.4,
  "definitions": {
    "subgraphs": [
      {
        "id": "75bf8a72-aad8-4f3e-83ee-380e70248240",
        "version": 1,
        "state": {
          "lastGroupId": 0,
          "lastNodeId": 144,
          "lastLinkId": 118,
          "lastRerouteId": 0
        },
        "revision": 0,
        "config": {},
        "name": "Image Levels",
        "inputNode": {
          "id": -10,
          "bounding": [
            3840,
            -3430,
            120,
            60
          ]
        },
        "outputNode": {
          "id": -20,
          "bounding": [
            4950,
            -3430,
            120,
            60
          ]
        },
        "inputs": [
          {
            "id": "b53e5012-fa47-400f-a324-28c74854ccae",
            "name": "images.image0",
            "type": "IMAGE",
            "linkIds": [
              1
            ],
            "localized_name": "images.image0",
            "label": "image",
            "pos": [
              3940,
              -3410
            ]
          }
        ],
        "outputs": [
          {
            "id": "de7f2ffa-155f-41fd-b054-aa4d91ef49ca",
            "name": "IMAGE0",
            "type": "IMAGE",
            "linkIds": [
              8
            ],
            "localized_name": "IMAGE0",
            "label": "IMAGE",
            "pos": [
              4970,
              -3410
            ]
          }
        ],
        "widgets": [],
        "nodes": [
          {
            "id": 5,
            "type": "CustomCombo",
            "pos": [
              4020,
              -3350
            ],
            "size": [
              270,
              198
            ],
            "flags": {},
            "order": 0,
            "mode": 0,
            "inputs": [
              {
                "label": "channel",
                "localized_name": "choice",
                "name": "choice",
                "type": "COMBO",
                "widget": {
                  "name": "choice"
                },
                "link": null
              }
            ],
            "outputs": [
              {
                "localized_name": "STRING",
                "name": "STRING",
                "type": "STRING",
                "links": null
              },
              {
                "localized_name": "INDEX",
                "name": "INDEX",
                "type": "INT",
                "links": [
                  3
                ]
              }
            ],
            "title": "Channel",
            "properties": {
              "Node name for S&R": "CustomCombo"
            },
            "widgets_values": [
              "RGB",
              0,
              "RGB",
              "R",
              "G",
              "B",
              ""
            ]
          },
          {
            "id": 8,
            "type": "PrimitiveFloat",
            "pos": [
              4020,
              -3550
            ],
            "size": [
              270,
              58
            ],
            "flags": {},
            "order": 1,
            "mode": 0,
            "inputs": [
              {
                "label": "output_black",
                "localized_name": "value",
                "name": "value",
                "type": "FLOAT",
                "widget": {
                  "name": "value"
                },
                "link": null
              }
            ],
            "outputs": [
              {
                "localized_name": "FLOAT",
                "name": "FLOAT",
                "type": "FLOAT",
                "links": [
                  6
                ]
              }
            ],
            "title": "Output Black",
            "properties": {
              "Node name for S&R": "PrimitiveFloat",
              "max": 255,
              "min": 0,
              "step": 1,
              "display": "gradientslider",
              "gradient_stops": [
                {
                  "offset": 0,
                  "color": [
                    0,
                    0,
                    0
                  ]
                },
                {
                  "offset": 1,
                  "color": [
                    255,
                    255,
                    255
                  ]
                }
              ]
            },
            "widgets_values": [
              0
            ]
          },
          {
            "id": 3,
            "type": "PrimitiveFloat",
            "pos": [
              4020,
              -3850
            ],
            "size": [
              270,
              58
            ],
            "flags": {},
            "order": 2,
            "mode": 0,
            "inputs": [
              {
                "label": "input_black",
                "localized_name": "value",
                "name": "value",
                "type": "FLOAT",
                "widget": {
                  "name": "value"
                },
                "link": null
              }
            ],
            "outputs": [
              {
                "localized_name": "FLOAT",
                "name": "FLOAT",
                "type": "FLOAT",
                "links": [
                  2
                ]
              }
            ],
            "title": "Input Black",
            "properties": {
              "Node name for S&R": "PrimitiveFloat",
              "min": 0,
              "max": 255,
              "step": 1,
              "display": "gradientslider",
              "gradient_stops": [
                {
                  "offset": 0,
                  "color": [
                    0,
                    0,
                    0
                  ]
                },
                {
                  "offset": 1,
                  "color": [
                    255,
                    255,
                    255
                  ]
                }
              ]
            },
            "widgets_values": [
              0
            ]
          },
          {
            "id": 6,
            "type": "PrimitiveFloat",
            "pos": [
              4020,
              -3750
            ],
            "size": [
              270,
              58
            ],
            "flags": {},
            "order": 3,
            "mode": 0,
            "inputs": [
              {
                "label": "input_white",
                "localized_name": "value",
                "name": "value",
                "type": "FLOAT",
                "widget": {
                  "name": "value"
                },
                "link": null
              }
            ],
            "outputs": [
              {
                "localized_name": "FLOAT",
                "name": "FLOAT",
                "type": "FLOAT",
                "links": [
                  4
                ]
              }
            ],
            "title": "Input White",
            "properties": {
              "Node name for S&R": "PrimitiveFloat",
              "max": 255,
              "min": 0,
              "step": 1,
              "display": "gradientslider",
              "gradient_stops": [
                {
                  "offset": 0,
                  "color": [
                    0,
                    0,
                    0
                  ]
                },
                {
                  "offset": 1,
                  "color": [
                    255,
                    255,
                    255
                  ]
                }
              ]
            },
            "widgets_values": [
              255
            ]
          },
          {
            "id": 7,
            "type": "PrimitiveFloat",
            "pos": [
              4020,
              -3650
            ],
            "size": [
              270,
              58
            ],
            "flags": {},
            "order": 4,
            "mode": 0,
            "inputs": [
              {
                "label": "gamma",
                "localized_name": "value",
                "name": "value",
                "type": "FLOAT",
                "widget": {
                  "name": "value"
                },
                "link": null
              }
            ],
            "outputs": [
              {
                "localized_name": "FLOAT",
                "name": "FLOAT",
                "type": "FLOAT",
                "links": [
                  5
                ]
              }
            ],
            "title": "Gamma",
            "properties": {
              "Node name for S&R": "PrimitiveFloat",
              "max": 10,
              "min": 0,
              "step": 0.01,
              "precision": 2,
              "display": "gradientslider",
              "gradient_stops": [
                {
                  "offset": 0,
                  "color": [
                    0,
                    0,
                    0
                  ]
                },
                {
                  "offset": 0.5,
                  "color": [
                    128,
                    128,
                    128
                  ]
                },
                {
                  "offset": 1,
                  "color": [
                    255,
                    255,
                    255
                  ]
                }
              ]
            },
            "widgets_values": [
              1
            ]
          },
          {
            "id": 9,
            "type": "PrimitiveFloat",
            "pos": [
              4020,
              -3450
            ],
            "size": [
              270,
              58
            ],
            "flags": {},
            "order": 5,
            "mode": 0,
            "inputs": [
              {
                "label": "output_white",
                "localized_name": "value",
                "name": "value",
                "type": "FLOAT",
                "widget": {
                  "name": "value"
                },
                "link": null
              }
            ],
            "outputs": [
              {
                "localized_name": "FLOAT",
                "name": "FLOAT",
                "type": "FLOAT",
                "links": [
                  7
                ]
              }
            ],
            "title": "Output White",
            "properties": {
              "Node name for S&R": "PrimitiveFloat",
              "max": 255,
              "min": 0,
              "step": 1,
              "display": "gradientslider",
              "gradient_stops": [
                {
                  "offset": 0,
                  "color": [
                    0,
                    0,
                    0
                  ]
                },
                {
                  "offset": 1,
                  "color": [
                    255,
                    255,
                    255
                  ]
                }
              ]
            },
            "widgets_values": [
              255
            ]
          },
          {
            "id": 1,
            "type": "GLSLShader",
            "pos": [
              4310,
              -3850
            ],
            "size": [
              580,
              272
            ],
            "flags": {},
            "order": 6,
            "mode": 0,
            "inputs": [
              {
                "label": "image0",
                "localized_name": "images.image0",
                "name": "images.image0",
                "type": "IMAGE",
                "link": 1
              },
              {
                "label": "image1",
                "localized_name": "images.image1",
                "name": "images.image1",
                "shape": 7,
                "type": "IMAGE",
                "link": null
              },
              {
                "label": "u_float0",
                "localized_name": "floats.u_float0",
                "name": "floats.u_float0",
                "shape": 7,
                "type": "FLOAT",
                "link": 2
              },
              {
                "label": "u_float1",
                "localized_name": "floats.u_float1",
                "name": "floats.u_float1",
                "shape": 7,
                "type": "FLOAT",
                "link": 4
              },
              {
                "label": "u_float2",
                "localized_name": "floats.u_float2",
                "name": "floats.u_float2",
                "shape": 7,
                "type": "FLOAT",
                "link": 5
              },
              {
                "label": "u_float3",
                "localized_name": "floats.u_float3",
                "name": "floats.u_float3",
                "shape": 7,
                "type": "FLOAT",
                "link": 6
              },
              {
                "label": "u_float4",
                "localized_name": "floats.u_float4",
                "name": "floats.u_float4",
                "shape": 7,
                "type": "FLOAT",
                "link": 7
              },
              {
                "label": "u_int0",
                "localized_name": "ints.u_int0",
                "name": "ints.u_int0",
                "shape": 7,
                "type": "INT",
                "link": 3
              },
              {
                "label": "u_int1",
                "localized_name": "ints.u_int1",
                "name": "ints.u_int1",
                "shape": 7,
                "type": "INT",
                "link": null
              },
              {
                "localized_name": "fragment_shader",
                "name": "fragment_shader",
                "type": "STRING",
                "widget": {
                  "name": "fragment_shader"
                },
                "link": null
              },
              {
                "localized_name": "size_mode",
                "name": "size_mode",
                "type": "COMFY_DYNAMICCOMBO_V3",
                "widget": {
                  "name": "size_mode"
                },
                "link": null
              }
            ],
            "outputs": [
              {
                "localized_name": "IMAGE0",
                "name": "IMAGE0",
                "type": "IMAGE",
                "links": [
                  8
                ]
              },
              {
                "localized_name": "IMAGE1",
                "name": "IMAGE1",
                "type": "IMAGE",
                "links": null
              },
              {
                "localized_name": "IMAGE2",
                "name": "IMAGE2",
                "type": "IMAGE",
                "links": null
              },
              {
                "localized_name": "IMAGE3",
                "name": "IMAGE3",
                "type": "IMAGE",
                "links": null
              }
            ],
            "properties": {
              "Node name for S&R": "GLSLShader"
            },
            "widgets_values": [
              "#version 300 es\nprecision highp float;\n\n// Levels Adjustment\n// u_int0:   channel      (0=RGB, 1=R, 2=G, 3=B)         default: 0\n// u_float0: input black  (0-255)                        default: 0\n// u_float1: input white  (0-255)                        default: 255\n// u_float2: gamma        (0.01-9.99)                    default: 1.0\n// u_float3: output black (0-255)                        default: 0\n// u_float4: output white (0-255)                        default: 255\n\nuniform sampler2D u_image0;\nuniform int u_int0;\nuniform float u_float0;\nuniform float u_float1;\nuniform float u_float2;\nuniform float u_float3;\nuniform float u_float4;\n\nin vec2 v_texCoord;\nout vec4 fragColor;\n\nvec3 applyLevels(vec3 color, float inBlack, float inWhite, float gamma, float outBlack, float outWhite) {\n    float inRange = max(inWhite - inBlack, 0.0001);\n    vec3 result = clamp((color - inBlack) / inRange, 0.0, 1.0);\n    result = pow(result, vec3(1.0 / gamma));\n    result = mix(vec3(outBlack), vec3(outWhite), result);\n    return result;\n}\n\nfloat applySingleChannel(float value, float inBlack, float inWhite, float gamma, float outBlack, float outWhite) {\n    float inRange = max(inWhite - inBlack, 0.0001);\n    float result = clamp((value - inBlack) / inRange, 0.0, 1.0);\n    result = pow(result, 1.0 / gamma);\n    result = mix(outBlack, outWhite, result);\n    return result;\n}\n\nvoid main() {\n    vec4 texColor = texture(u_image0, v_texCoord);\n    vec3 color = texColor.rgb;\n    \n    float inBlack = u_float0 / 255.0;\n    float inWhite = u_float1 / 255.0;\n    float gamma = u_float2;\n    float outBlack = u_float3 / 255.0;\n    float outWhite = u_float4 / 255.0;\n    \n    vec3 result;\n    \n    if (u_int0 == 0) {\n        result = applyLevels(color, inBlack, inWhite, gamma, outBlack, outWhite);\n    }\n    else if (u_int0 == 1) {\n        result = color;\n        result.r = applySingleChannel(color.r, inBlack, inWhite, gamma, outBlack, outWhite);\n    }\n    else if (u_int0 == 2) {\n        result = color;\n        result.g = applySingleChannel(color.g, inBlack, inWhite, gamma, outBlack, outWhite);\n    }\n    else if (u_int0 == 3) {\n        result = color;\n        result.b = applySingleChannel(color.b, inBlack, inWhite, gamma, outBlack, outWhite);\n    }\n    else {\n        result = color;\n    }\n    \n    fragColor = vec4(result, texColor.a);\n}",
              "from_input"
            ]
          }
        ],
        "groups": [],
        "links": [
          {
            "id": 2,
            "origin_id": 3,
            "origin_slot": 0,
            "target_id": 1,
            "target_slot": 2,
            "type": "FLOAT"
          },
          {
            "id": 4,
            "origin_id": 6,
            "origin_slot": 0,
            "target_id": 1,
            "target_slot": 3,
            "type": "FLOAT"
          },
          {
            "id": 5,
            "origin_id": 7,
            "origin_slot": 0,
            "target_id": 1,
            "target_slot": 4,
            "type": "FLOAT"
          },
          {
            "id": 6,
            "origin_id": 8,
            "origin_slot": 0,
            "target_id": 1,
            "target_slot": 5,
            "type": "FLOAT"
          },
          {
            "id": 7,
            "origin_id": 9,
            "origin_slot": 0,
            "target_id": 1,
            "target_slot": 6,
            "type": "FLOAT"
          },
          {
            "id": 3,
            "origin_id": 5,
            "origin_slot": 1,
            "target_id": 1,
            "target_slot": 7,
            "type": "INT"
          },
          {
            "id": 1,
            "origin_id": -10,
            "origin_slot": 0,
            "target_id": 1,
            "target_slot": 0,
            "type": "IMAGE"
          },
          {
            "id": 8,
            "origin_id": 1,
            "origin_slot": 0,
            "target_id": -20,
            "target_slot": 0,
            "type": "IMAGE"
          }
        ],
        "extra": {
          "workflowRendererVersion": "LG"
        },
        "category": "Image Tools/Color adjust",
        "description": "Adjusts black point, white point, and gamma for tonal range control via GPU shader."
      }
    ]
  },
  "extra": {}
}