Oysiyl commited on
Commit
1318560
·
1 Parent(s): 515964d

updating params

Browse files
Files changed (1) hide show
  1. app.py +152 -115
app.py CHANGED
@@ -22,6 +22,7 @@ hf_hub_download(repo_id="comfyanonymous/ControlNet-v1-1_fp16_safetensors", filen
22
  hf_hub_download(repo_id="Lykon/dreamshaper-7", filename="vae/diffusion_pytorch_model.fp16.safetensors", local_dir="models")
23
  hf_hub_download(repo_id="stabilityai/sd-vae-ft-mse-original", filename="vae-ft-mse-840000-ema-pruned.safetensors", local_dir="models/vae")
24
  hf_hub_download(repo_id="lllyasviel/Annotators", filename="RealESRGAN_x4plus.pth", local_dir="models/upscale_models")
 
25
 
26
  def get_value_at_index(obj: Union[Sequence, Mapping], index: int) -> Any:
27
  """Returns the value at the given index of a sequence or mapping.
@@ -176,7 +177,7 @@ valid_models = [
176
  model_management.load_models_gpu(valid_models)
177
 
178
  @spaces.GPU(duration=30)
179
- def generate_qr_code_unified(prompt: str, text_input: str, input_type: str = "URL", image_size: int = 512, border_size: int = 4, error_correction: str = "Medium (15%)", module_size: int = 12, module_drawer: str = "Square", use_custom_seed: bool = False, seed: int = 0, pipeline: str = "standard", freeu_b1: float = 1.2, freeu_b2: float = 1.3, freeu_s1: float = 1.0, freeu_s2: float = 0.6, enable_sag: bool = True, sag_scale: float = 1.5, sag_blur_sigma: float = 1.5):
180
  # Only manipulate the text if it's a URL input type
181
  qr_text = text_input
182
  if input_type == "URL":
@@ -190,17 +191,17 @@ def generate_qr_code_unified(prompt: str, text_input: str, input_type: str = "UR
190
 
191
  with torch.inference_mode():
192
  if pipeline == "standard":
193
- yield from _pipeline_standard(prompt, qr_text, input_type, image_size, border_size, error_correction, module_size, module_drawer, actual_seed)
194
  else: # artistic
195
- yield from _pipeline_artistic(prompt, qr_text, input_type, image_size, border_size, error_correction, module_size, module_drawer, actual_seed, freeu_b1, freeu_b2, freeu_s1, freeu_s2, enable_sag, sag_scale, sag_blur_sigma)
196
 
197
- def generate_standard_qr(prompt: str, text_input: str, input_type: str = "URL", image_size: int = 512, border_size: int = 4, error_correction: str = "Medium (15%)", module_size: int = 12, module_drawer: str = "Square", use_custom_seed: bool = False, seed: int = 0):
198
  """Wrapper function for standard QR generation"""
199
- yield from generate_qr_code_unified(prompt, text_input, input_type, image_size, border_size, error_correction, module_size, module_drawer, use_custom_seed, seed, pipeline="standard")
200
 
201
- def generate_artistic_qr(prompt: str, text_input: str, input_type: str = "URL", image_size: int = 512, border_size: int = 4, error_correction: str = "Medium (15%)", module_size: int = 12, module_drawer: str = "Square", use_custom_seed: bool = False, seed: int = 0, freeu_b1: float = 1.2, freeu_b2: float = 1.3, freeu_s1: float = 1.0, freeu_s2: float = 0.6, enable_sag: bool = True, sag_scale: float = 1.5, sag_blur_sigma: float = 1.5):
202
  """Wrapper function for artistic QR generation with FreeU and SAG parameters"""
203
- yield from generate_qr_code_unified(prompt, text_input, input_type, image_size, border_size, error_correction, module_size, module_drawer, use_custom_seed, seed, pipeline="artistic", freeu_b1=freeu_b1, freeu_b2=freeu_b2, freeu_s1=freeu_s1, freeu_s2=freeu_s2, enable_sag=enable_sag, sag_scale=sag_scale, sag_blur_sigma=sag_blur_sigma)
204
 
205
  def add_noise_to_border_only(image_tensor, seed: int, border_size: int, image_size: int, module_size: int = 12):
206
  """
@@ -289,7 +290,7 @@ def add_noise_to_border_only(image_tensor, seed: int, border_size: int, image_si
289
  # Convert back to tensor
290
  return torch.from_numpy(img_np).to(image_tensor.device)
291
 
292
- def _pipeline_standard(prompt: str, qr_text: str, input_type: str, image_size: int, border_size: int, error_correction: str, module_size: int, module_drawer: str, seed: int):
293
  emptylatentimage_5 = emptylatentimage.generate(
294
  width=image_size, height=image_size, batch_size=1
295
  )
@@ -433,14 +434,35 @@ def _pipeline_standard(prompt: str, qr_text: str, input_type: str, image_size: i
433
  vae=get_value_at_index(checkpointloadersimple_4, 2),
434
  )
435
 
436
- # 3) Yield the final enhanced image
437
- image_tensor = get_value_at_index(vaedecode_21, 0)
438
- image_np = (image_tensor.cpu().numpy() * 255).astype(np.uint8)
439
- image_np = image_np[0]
440
- pil_image = Image.fromarray(image_np)
441
- yield pil_image, "No errors, all good! Final QR art generated."
442
-
443
- def _pipeline_artistic(prompt: str, qr_text: str, input_type: str, image_size: int, border_size: int, error_correction: str, module_size: int, module_drawer: str, seed: int, freeu_b1: float = 1.2, freeu_b2: float = 1.3, freeu_s1: float = 1.0, freeu_s2: float = 0.6, enable_sag: bool = True, sag_scale: float = 1.5, sag_blur_sigma: float = 1.5):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
444
  # Generate QR code
445
  qr_protocol = "None" if input_type == "Plain Text" else "Https"
446
 
@@ -521,7 +543,7 @@ def _pipeline_artistic(prompt: str, qr_text: str, input_type: str, image_size: i
521
 
522
  # First ControlNet pass (using QR with border cubics)
523
  controlnet_apply = controlnetapplyadvanced.apply_controlnet(
524
- strength=0.45,
525
  start_percent=0,
526
  end_percent=1,
527
  positive=get_value_at_index(positive_prompt, 0),
@@ -540,7 +562,7 @@ def _pipeline_artistic(prompt: str, qr_text: str, input_type: str, image_size: i
540
 
541
  # Second ControlNet pass (using tile processed from QR with border cubics)
542
  controlnet_apply = controlnetapplyadvanced.apply_controlnet(
543
- strength=0.45,
544
  start_percent=0,
545
  end_percent=1,
546
  positive=get_value_at_index(controlnet_apply, 0),
@@ -598,41 +620,18 @@ def _pipeline_artistic(prompt: str, qr_text: str, input_type: str, image_size: i
598
  first_pass_np = (first_pass_tensor.cpu().numpy() * 255).astype(np.uint8)
599
  first_pass_np = first_pass_np[0]
600
  first_pass_pil = Image.fromarray(first_pass_np)
601
- step_msg = "First enhancement pass complete (step 3/5)... upscaling image" if border_size > 0 else "First enhancement pass complete (step 2/4)... upscaling image"
602
  yield first_pass_pil, step_msg
603
 
604
- # Upscale image with model
605
- upscaled = imageupscalewithmodel.upscale(
606
- upscale_model=get_value_at_index(upscalemodelloader_30, 0),
607
- image=get_value_at_index(decoded, 0),
608
- )
609
-
610
- # Resize to target size
611
- resized = imagescale.upscale(
612
- upscale_method="area",
613
- width=image_size*2,
614
- height=image_size*2,
615
- crop="disabled",
616
- image=get_value_at_index(upscaled, 0),
617
- )
618
-
619
- # Show upscaled result
620
- upscaled_tensor = get_value_at_index(resized, 0)
621
- upscaled_np = (upscaled_tensor.cpu().numpy() * 255).astype(np.uint8)
622
- upscaled_np = upscaled_np[0]
623
- upscaled_pil = Image.fromarray(upscaled_np)
624
- step_msg = "Image upscaled (step 4/5)... final refinement pass" if border_size > 0 else "Image upscaled (step 3/4)... final refinement pass"
625
- yield upscaled_pil, step_msg
626
-
627
- # Final ControlNet pass (second pass - upscaled refinement)
628
  controlnet_apply_final = controlnetapplyadvanced.apply_controlnet(
629
- strength=0.7,
630
  start_percent=0,
631
  end_percent=1,
632
  positive=get_value_at_index(positive_prompt, 0),
633
  negative=get_value_at_index(negative_prompt, 0),
634
  control_net=get_value_at_index(tile_controlnet, 0),
635
- image=get_value_at_index(resized, 0),
636
  vae=get_value_at_index(checkpointloadersimple_artistic, 2),
637
  )
638
 
@@ -663,16 +662,40 @@ def _pipeline_artistic(prompt: str, qr_text: str, input_type: str, image_size: i
663
  vae=get_value_at_index(checkpointloadersimple_artistic, 2),
664
  )
665
 
666
- # Convert to PIL Image and return
667
- image_tensor = get_value_at_index(final_decoded, 0)
668
- image_np = (image_tensor.cpu().numpy() * 255).astype(np.uint8)
669
- image_np = image_np[0]
670
- final_image = Image.fromarray(image_np)
671
- step_msg = "No errors, all good! Final artistic QR code generated. (step 5/5)" if border_size > 0 else "No errors, all good! Final artistic QR code generated. (step 4/4)"
672
- yield final_image, step_msg
 
 
 
 
 
 
 
 
673
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
674
 
675
- if __name__ == "__main__":
 
676
 
677
  # Start your Gradio app
678
  with gr.Blocks() as app:
@@ -771,21 +794,6 @@ if __name__ == "__main__":
771
  info="Select the style of the QR code modules (squares). See examples below. Different styles can give your QR code a unique look while maintaining scannability."
772
  )
773
 
774
- # Add seed controls
775
- use_custom_seed = gr.Checkbox(
776
- label="Use Custom Seed",
777
- value=False,
778
- info="Enable to use a specific seed for reproducible results"
779
- )
780
- seed = gr.Slider(
781
- minimum=0,
782
- maximum=2000000,
783
- step=1,
784
- value=0,
785
- label="Seed",
786
- info="Seed value for reproducibility. Same seed with same settings will produce the same result."
787
- )
788
-
789
  # Add style examples with labels
790
  gr.Markdown("### Style Examples:")
791
 
@@ -813,6 +821,28 @@ if __name__ == "__main__":
813
  gr.Markdown("**Horizontal Bars**", show_label=False)
814
  gr.Image("custom_nodes/ComfyQR/img/horizontal-bars.png", width=100, show_label=False, show_download_button=False)
815
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
816
  # The generate button
817
  generate_btn = gr.Button("Generate Standard QR", variant="primary")
818
 
@@ -828,7 +858,7 @@ if __name__ == "__main__":
828
  # When clicking the button, it will trigger the main function
829
  generate_btn.click(
830
  fn=generate_standard_qr,
831
- inputs=[prompt_input, text_input, input_type, image_size, border_size, error_correction, module_size, module_drawer, use_custom_seed, seed],
832
  outputs=[output_image, error_message]
833
  )
834
 
@@ -985,9 +1015,9 @@ if __name__ == "__main__":
985
  minimum=512,
986
  maximum=1024,
987
  step=64,
988
- value=512,
989
  label="Image Size",
990
- info="Base size of the generated image. Final output will be 2x this size (e.g., 5121024) due to the two-step enhancement process. Higher values use more VRAM and take longer to process."
991
  )
992
 
993
  # Add border size slider for artistic QR
@@ -995,7 +1025,7 @@ if __name__ == "__main__":
995
  minimum=0,
996
  maximum=8,
997
  step=1,
998
- value=4,
999
  label="QR Code Border Size",
1000
  info="Number of modules (squares) to use as border around the QR code. Higher values add more whitespace."
1001
  )
@@ -1003,9 +1033,9 @@ if __name__ == "__main__":
1003
  # Add error correction dropdown for artistic QR
1004
  artistic_error_correction = gr.Dropdown(
1005
  choices=["Low (7%)", "Medium (15%)", "Quartile (25%)", "High (30%)"],
1006
- value="Medium (15%)",
1007
  label="Error Correction Level",
1008
- info="Higher error correction makes the QR code more scannable when damaged or obscured, but increases its size and complexity. Medium (15%) is a good starting point for most uses."
1009
  )
1010
 
1011
  # Add module size slider for artistic QR
@@ -1013,9 +1043,9 @@ if __name__ == "__main__":
1013
  minimum=4,
1014
  maximum=16,
1015
  step=1,
1016
- value=12,
1017
  label="QR Module Size",
1018
- info="Pixel width of the smallest QR code unit. Larger values improve readability but require a larger image size. 12 is a good starting point."
1019
  )
1020
 
1021
  # Add module drawer dropdown with style examples for artistic QR
@@ -1026,17 +1056,51 @@ if __name__ == "__main__":
1026
  info="Select the style of the QR code modules (squares). See examples below. Different styles can give your QR code a unique look while maintaining scannability."
1027
  )
1028
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1029
  # Add seed controls for artistic QR
1030
  artistic_use_custom_seed = gr.Checkbox(
1031
  label="Use Custom Seed",
1032
- value=False,
1033
  info="Enable to use a specific seed for reproducible results"
1034
  )
1035
  artistic_seed = gr.Slider(
1036
  minimum=0,
1037
  maximum=2000000,
1038
  step=1,
1039
- value=0,
1040
  label="Seed",
1041
  info="Seed value for reproducibility. Same seed with same settings will produce the same result."
1042
  )
@@ -1047,9 +1111,9 @@ if __name__ == "__main__":
1047
  minimum=1.0,
1048
  maximum=1.6,
1049
  step=0.01,
1050
- value=1.2,
1051
  label="FreeU B1 (Backbone 1)",
1052
- info="Backbone feature enhancement for first layer. Higher values improve detail but may reduce blending. Range: 1.0-1.6, Default: 1.2"
1053
  )
1054
  freeu_b2 = gr.Slider(
1055
  minimum=1.0,
@@ -1063,33 +1127,33 @@ if __name__ == "__main__":
1063
  minimum=0.0,
1064
  maximum=1.5,
1065
  step=0.01,
1066
- value=1.0,
1067
  label="FreeU S1 (Skip 1)",
1068
- info="Skip connection dampening for first layer. Lower values hide QR structure more. Range: 0.0-1.5, Default: 1.0"
1069
  )
1070
  freeu_s2 = gr.Slider(
1071
  minimum=0.0,
1072
  maximum=1.5,
1073
  step=0.01,
1074
- value=0.6,
1075
  label="FreeU S2 (Skip 2)",
1076
- info="Skip connection dampening for second layer. Balances scannability. Range: 0.0-1.5, Default: 0.6"
1077
  )
1078
 
1079
  # SAG (Self-Attention Guidance) Parameters
1080
  gr.Markdown("### SAG (Self-Attention Guidance)")
1081
  enable_sag = gr.Checkbox(
1082
  label="Enable SAG",
1083
- value=False,
1084
  info="Enable Self-Attention Guidance for improved structural coherence and artistic blending"
1085
  )
1086
  sag_scale = gr.Slider(
1087
  minimum=0.0,
1088
  maximum=3.0,
1089
  step=0.1,
1090
- value=1.5,
1091
  label="SAG Scale",
1092
- info="Guidance strength. Higher values provide more structural coherence. Range: 0.0-3.0, Default: 1.5"
1093
  )
1094
  sag_blur_sigma = gr.Slider(
1095
  minimum=0.0,
@@ -1100,33 +1164,6 @@ if __name__ == "__main__":
1100
  info="Blur amount for artistic blending. Higher values create softer, more artistic effects. Range: 0.0-5.0, Default: 1.5"
1101
  )
1102
 
1103
- # Add style examples with labels
1104
- gr.Markdown("### Style Examples:")
1105
-
1106
- # First row of examples
1107
- with gr.Row():
1108
- with gr.Column(scale=1, min_width=0):
1109
- gr.Markdown("**Square**", show_label=False)
1110
- gr.Image("custom_nodes/ComfyQR/img/square.png", width=100, show_label=False, show_download_button=False)
1111
- with gr.Column(scale=1, min_width=0):
1112
- gr.Markdown("**Gapped Square**", show_label=False)
1113
- gr.Image("custom_nodes/ComfyQR/img/gapped_square.png", width=100, show_label=False, show_download_button=False)
1114
- with gr.Column(scale=1, min_width=0):
1115
- gr.Markdown("**Circle**", show_label=False)
1116
- gr.Image("custom_nodes/ComfyQR/img/circle.png", width=100, show_label=False, show_download_button=False)
1117
-
1118
- # Second row of examples
1119
- with gr.Row():
1120
- with gr.Column(scale=1, min_width=0):
1121
- gr.Markdown("**Rounded**", show_label=False)
1122
- gr.Image("custom_nodes/ComfyQR/img/rounded.png", width=100, show_label=False, show_download_button=False)
1123
- with gr.Column(scale=1, min_width=0):
1124
- gr.Markdown("**Vertical Bars**", show_label=False)
1125
- gr.Image("custom_nodes/ComfyQR/img/vertical-bars.png", width=100, show_label=False, show_download_button=False)
1126
- with gr.Column(scale=1, min_width=0):
1127
- gr.Markdown("**Horizontal Bars**", show_label=False)
1128
- gr.Image("custom_nodes/ComfyQR/img/horizontal-bars.png", width=100, show_label=False, show_download_button=False)
1129
-
1130
  # The generate button for artistic QR
1131
  artistic_generate_btn = gr.Button("Generate Artistic QR", variant="primary")
1132
 
@@ -1142,7 +1179,7 @@ if __name__ == "__main__":
1142
  # When clicking the button, it will trigger the artistic function
1143
  artistic_generate_btn.click(
1144
  fn=generate_artistic_qr,
1145
- inputs=[artistic_prompt_input, artistic_text_input, artistic_input_type, artistic_image_size, artistic_border_size, artistic_error_correction, artistic_module_size, artistic_module_drawer, artistic_use_custom_seed, artistic_seed, freeu_b1, freeu_b2, freeu_s1, freeu_s2, enable_sag, sag_scale, sag_blur_sigma],
1146
  outputs=[artistic_output_image, artistic_error_message]
1147
  )
1148
 
 
22
  hf_hub_download(repo_id="Lykon/dreamshaper-7", filename="vae/diffusion_pytorch_model.fp16.safetensors", local_dir="models")
23
  hf_hub_download(repo_id="stabilityai/sd-vae-ft-mse-original", filename="vae-ft-mse-840000-ema-pruned.safetensors", local_dir="models/vae")
24
  hf_hub_download(repo_id="lllyasviel/Annotators", filename="RealESRGAN_x4plus.pth", local_dir="models/upscale_models")
25
+ hf_hub_download(repo_id="lykon/RealESRGAN_x4plus", filename="RealESRGAN_x4plus.pth", local_dir="models/upscale_models")
26
 
27
  def get_value_at_index(obj: Union[Sequence, Mapping], index: int) -> Any:
28
  """Returns the value at the given index of a sequence or mapping.
 
177
  model_management.load_models_gpu(valid_models)
178
 
179
  @spaces.GPU(duration=30)
180
+ def generate_qr_code_unified(prompt: str, text_input: str, input_type: str = "URL", image_size: int = 512, border_size: int = 4, error_correction: str = "Medium (15%)", module_size: int = 12, module_drawer: str = "Square", use_custom_seed: bool = False, seed: int = 0, pipeline: str = "standard", enable_upscale: bool = False, freeu_b1: float = 1.4, freeu_b2: float = 1.3, freeu_s1: float = 0.0, freeu_s2: float = 1.3, enable_sag: bool = True, sag_scale: float = 0.5, sag_blur_sigma: float = 1.5, controlnet_strength_first: float = 0.45, controlnet_strength_final: float = 0.7):
181
  # Only manipulate the text if it's a URL input type
182
  qr_text = text_input
183
  if input_type == "URL":
 
191
 
192
  with torch.inference_mode():
193
  if pipeline == "standard":
194
+ yield from _pipeline_standard(prompt, qr_text, input_type, image_size, border_size, error_correction, module_size, module_drawer, actual_seed, enable_upscale)
195
  else: # artistic
196
+ yield from _pipeline_artistic(prompt, qr_text, input_type, image_size, border_size, error_correction, module_size, module_drawer, actual_seed, enable_upscale, freeu_b1, freeu_b2, freeu_s1, freeu_s2, enable_sag, sag_scale, sag_blur_sigma, controlnet_strength_first, controlnet_strength_final)
197
 
198
+ def generate_standard_qr(prompt: str, text_input: str, input_type: str = "URL", image_size: int = 512, border_size: int = 4, error_correction: str = "Medium (15%)", module_size: int = 12, module_drawer: str = "Square", use_custom_seed: bool = False, seed: int = 0, enable_upscale: bool = False):
199
  """Wrapper function for standard QR generation"""
200
+ yield from generate_qr_code_unified(prompt, text_input, input_type, image_size, border_size, error_correction, module_size, module_drawer, use_custom_seed, seed, pipeline="standard", enable_upscale=enable_upscale)
201
 
202
+ def generate_artistic_qr(prompt: str, text_input: str, input_type: str = "URL", image_size: int = 512, border_size: int = 4, error_correction: str = "Medium (15%)", module_size: int = 12, module_drawer: str = "Square", use_custom_seed: bool = False, seed: int = 0, enable_upscale: bool = True, freeu_b1: float = 1.4, freeu_b2: float = 1.3, freeu_s1: float = 0.0, freeu_s2: float = 1.3, enable_sag: bool = True, sag_scale: float = 0.5, sag_blur_sigma: float = 1.5, controlnet_strength_first: float = 0.45, controlnet_strength_final: float = 0.7):
203
  """Wrapper function for artistic QR generation with FreeU and SAG parameters"""
204
+ yield from generate_qr_code_unified(prompt, text_input, input_type, image_size, border_size, error_correction, module_size, module_drawer, use_custom_seed, seed, pipeline="artistic", enable_upscale=enable_upscale, freeu_b1=freeu_b1, freeu_b2=freeu_b2, freeu_s1=freeu_s1, freeu_s2=freeu_s2, enable_sag=enable_sag, sag_scale=sag_scale, sag_blur_sigma=sag_blur_sigma, controlnet_strength_first=controlnet_strength_first, controlnet_strength_final=controlnet_strength_final)
205
 
206
  def add_noise_to_border_only(image_tensor, seed: int, border_size: int, image_size: int, module_size: int = 12):
207
  """
 
290
  # Convert back to tensor
291
  return torch.from_numpy(img_np).to(image_tensor.device)
292
 
293
+ def _pipeline_standard(prompt: str, qr_text: str, input_type: str, image_size: int, border_size: int, error_correction: str, module_size: int, module_drawer: str, seed: int, enable_upscale: bool = False):
294
  emptylatentimage_5 = emptylatentimage.generate(
295
  width=image_size, height=image_size, batch_size=1
296
  )
 
434
  vae=get_value_at_index(checkpointloadersimple_4, 2),
435
  )
436
 
437
+ # 3) Optionally upscale if enabled
438
+ if enable_upscale:
439
+ # Show pre-upscale result
440
+ pre_upscale_tensor = get_value_at_index(vaedecode_21, 0)
441
+ pre_upscale_np = (pre_upscale_tensor.cpu().numpy() * 255).astype(np.uint8)
442
+ pre_upscale_np = pre_upscale_np[0]
443
+ pre_upscale_pil = Image.fromarray(pre_upscale_np)
444
+ yield pre_upscale_pil, "Enhancement complete (step 3/4)... upscaling image"
445
+
446
+ # Upscale the final image
447
+ upscaled = imageupscalewithmodel.upscale(
448
+ upscale_model=get_value_at_index(upscalemodelloader_30, 0),
449
+ image=get_value_at_index(vaedecode_21, 0),
450
+ )
451
+
452
+ image_tensor = get_value_at_index(upscaled, 0)
453
+ image_np = (image_tensor.cpu().numpy() * 255).astype(np.uint8)
454
+ image_np = image_np[0]
455
+ pil_image = Image.fromarray(image_np)
456
+ yield pil_image, f"No errors, all good! Final QR art generated and upscaled. (step 4/4) | Seed: {seed}"
457
+ else:
458
+ # No upscaling
459
+ image_tensor = get_value_at_index(vaedecode_21, 0)
460
+ image_np = (image_tensor.cpu().numpy() * 255).astype(np.uint8)
461
+ image_np = image_np[0]
462
+ pil_image = Image.fromarray(image_np)
463
+ yield pil_image, f"No errors, all good! Final QR art generated. | Seed: {seed}"
464
+
465
+ def _pipeline_artistic(prompt: str, qr_text: str, input_type: str, image_size: int, border_size: int, error_correction: str, module_size: int, module_drawer: str, seed: int, enable_upscale: bool = True, freeu_b1: float = 1.4, freeu_b2: float = 1.3, freeu_s1: float = 0.0, freeu_s2: float = 1.3, enable_sag: bool = True, sag_scale: float = 0.5, sag_blur_sigma: float = 1.5, controlnet_strength_first: float = 0.45, controlnet_strength_final: float = 0.7):
466
  # Generate QR code
467
  qr_protocol = "None" if input_type == "Plain Text" else "Https"
468
 
 
543
 
544
  # First ControlNet pass (using QR with border cubics)
545
  controlnet_apply = controlnetapplyadvanced.apply_controlnet(
546
+ strength=controlnet_strength_first,
547
  start_percent=0,
548
  end_percent=1,
549
  positive=get_value_at_index(positive_prompt, 0),
 
562
 
563
  # Second ControlNet pass (using tile processed from QR with border cubics)
564
  controlnet_apply = controlnetapplyadvanced.apply_controlnet(
565
+ strength=controlnet_strength_first,
566
  start_percent=0,
567
  end_percent=1,
568
  positive=get_value_at_index(controlnet_apply, 0),
 
620
  first_pass_np = (first_pass_tensor.cpu().numpy() * 255).astype(np.uint8)
621
  first_pass_np = first_pass_np[0]
622
  first_pass_pil = Image.fromarray(first_pass_np)
623
+ step_msg = "First enhancement pass complete (step 3/5)... final refinement pass" if border_size > 0 else "First enhancement pass complete (step 2/4)... final refinement pass"
624
  yield first_pass_pil, step_msg
625
 
626
+ # Final ControlNet pass (second pass - refinement)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
627
  controlnet_apply_final = controlnetapplyadvanced.apply_controlnet(
628
+ strength=controlnet_strength_final,
629
  start_percent=0,
630
  end_percent=1,
631
  positive=get_value_at_index(positive_prompt, 0),
632
  negative=get_value_at_index(negative_prompt, 0),
633
  control_net=get_value_at_index(tile_controlnet, 0),
634
+ image=get_value_at_index(decoded, 0),
635
  vae=get_value_at_index(checkpointloadersimple_artistic, 2),
636
  )
637
 
 
662
  vae=get_value_at_index(checkpointloadersimple_artistic, 2),
663
  )
664
 
665
+ # Optionally upscale if enabled
666
+ if enable_upscale:
667
+ # Show result before upscaling
668
+ pre_upscale_tensor = get_value_at_index(final_decoded, 0)
669
+ pre_upscale_np = (pre_upscale_tensor.cpu().numpy() * 255).astype(np.uint8)
670
+ pre_upscale_np = pre_upscale_np[0]
671
+ pre_upscale_pil = Image.fromarray(pre_upscale_np)
672
+ step_msg = "Final refinement complete (step 4/5)... upscaling image" if border_size > 0 else "Final refinement complete (step 3/4)... upscaling image"
673
+ yield pre_upscale_pil, step_msg
674
+
675
+ # Upscale image with model (after final samples, before returning)
676
+ upscaled = imageupscalewithmodel.upscale(
677
+ upscale_model=get_value_at_index(upscalemodelloader_30, 0),
678
+ image=get_value_at_index(final_decoded, 0),
679
+ )
680
 
681
+ # Convert upscaled image to PIL Image and return
682
+ image_tensor = get_value_at_index(upscaled, 0)
683
+ image_np = (image_tensor.cpu().numpy() * 255).astype(np.uint8)
684
+ image_np = image_np[0]
685
+ final_image = Image.fromarray(image_np)
686
+ step_msg = f"No errors, all good! Final artistic QR code generated and upscaled. (step 5/5) | Seed: {seed}" if border_size > 0 else f"No errors, all good! Final artistic QR code generated and upscaled. (step 4/4) | Seed: {seed}"
687
+ yield final_image, step_msg
688
+ else:
689
+ # No upscaling
690
+ image_tensor = get_value_at_index(final_decoded, 0)
691
+ image_np = (image_tensor.cpu().numpy() * 255).astype(np.uint8)
692
+ image_np = image_np[0]
693
+ final_image = Image.fromarray(image_np)
694
+ step_msg = f"No errors, all good! Final artistic QR code generated. (step 4/4) | Seed: {seed}" if border_size > 0 else f"No errors, all good! Final artistic QR code generated. (step 3/3) | Seed: {seed}"
695
+ yield final_image, step_msg
696
 
697
+
698
+ if __name__ == "__main__" and not os.environ.get('QR_TESTING_MODE'):
699
 
700
  # Start your Gradio app
701
  with gr.Blocks() as app:
 
794
  info="Select the style of the QR code modules (squares). See examples below. Different styles can give your QR code a unique look while maintaining scannability."
795
  )
796
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
797
  # Add style examples with labels
798
  gr.Markdown("### Style Examples:")
799
 
 
821
  gr.Markdown("**Horizontal Bars**", show_label=False)
822
  gr.Image("custom_nodes/ComfyQR/img/horizontal-bars.png", width=100, show_label=False, show_download_button=False)
823
 
824
+ # Add upscale checkbox
825
+ enable_upscale = gr.Checkbox(
826
+ label="Enable Upscaling",
827
+ value=False,
828
+ info="Enable upscaling with RealESRGAN for higher quality output (disabled by default for standard pipeline)"
829
+ )
830
+
831
+ # Add seed controls
832
+ use_custom_seed = gr.Checkbox(
833
+ label="Use Custom Seed",
834
+ value=True,
835
+ info="Enable to use a specific seed for reproducible results"
836
+ )
837
+ seed = gr.Slider(
838
+ minimum=0,
839
+ maximum=2000000,
840
+ step=1,
841
+ value=718313,
842
+ label="Seed",
843
+ info="Seed value for reproducibility. Same seed with same settings will produce the same result."
844
+ )
845
+
846
  # The generate button
847
  generate_btn = gr.Button("Generate Standard QR", variant="primary")
848
 
 
858
  # When clicking the button, it will trigger the main function
859
  generate_btn.click(
860
  fn=generate_standard_qr,
861
+ inputs=[prompt_input, text_input, input_type, image_size, border_size, error_correction, module_size, module_drawer, use_custom_seed, seed, enable_upscale],
862
  outputs=[output_image, error_message]
863
  )
864
 
 
1015
  minimum=512,
1016
  maximum=1024,
1017
  step=64,
1018
+ value=704,
1019
  label="Image Size",
1020
+ info="Base size of the generated image. Final output will be 2x this size (e.g., 7041408) due to the two-step enhancement process. Higher values use more VRAM and take longer to process."
1021
  )
1022
 
1023
  # Add border size slider for artistic QR
 
1025
  minimum=0,
1026
  maximum=8,
1027
  step=1,
1028
+ value=6,
1029
  label="QR Code Border Size",
1030
  info="Number of modules (squares) to use as border around the QR code. Higher values add more whitespace."
1031
  )
 
1033
  # Add error correction dropdown for artistic QR
1034
  artistic_error_correction = gr.Dropdown(
1035
  choices=["Low (7%)", "Medium (15%)", "Quartile (25%)", "High (30%)"],
1036
+ value="High (30%)",
1037
  label="Error Correction Level",
1038
+ info="Higher error correction makes the QR code more scannable when damaged or obscured, but increases its size and complexity. High (30%) is recommended for artistic QR codes."
1039
  )
1040
 
1041
  # Add module size slider for artistic QR
 
1043
  minimum=4,
1044
  maximum=16,
1045
  step=1,
1046
+ value=16,
1047
  label="QR Module Size",
1048
+ info="Pixel width of the smallest QR code unit. Larger values improve readability but require a larger image size. 16 is a good starting point."
1049
  )
1050
 
1051
  # Add module drawer dropdown with style examples for artistic QR
 
1056
  info="Select the style of the QR code modules (squares). See examples below. Different styles can give your QR code a unique look while maintaining scannability."
1057
  )
1058
 
1059
+ # Add style examples with labels
1060
+ gr.Markdown("### Style Examples:")
1061
+
1062
+ # First row of examples
1063
+ with gr.Row():
1064
+ with gr.Column(scale=1, min_width=0):
1065
+ gr.Markdown("**Square**", show_label=False)
1066
+ gr.Image("custom_nodes/ComfyQR/img/square.png", width=100, show_label=False, show_download_button=False)
1067
+ with gr.Column(scale=1, min_width=0):
1068
+ gr.Markdown("**Gapped Square**", show_label=False)
1069
+ gr.Image("custom_nodes/ComfyQR/img/gapped_square.png", width=100, show_label=False, show_download_button=False)
1070
+ with gr.Column(scale=1, min_width=0):
1071
+ gr.Markdown("**Circle**", show_label=False)
1072
+ gr.Image("custom_nodes/ComfyQR/img/circle.png", width=100, show_label=False, show_download_button=False)
1073
+
1074
+ # Second row of examples
1075
+ with gr.Row():
1076
+ with gr.Column(scale=1, min_width=0):
1077
+ gr.Markdown("**Rounded**", show_label=False)
1078
+ gr.Image("custom_nodes/ComfyQR/img/rounded.png", width=100, show_label=False, show_download_button=False)
1079
+ with gr.Column(scale=1, min_width=0):
1080
+ gr.Markdown("**Vertical Bars**", show_label=False)
1081
+ gr.Image("custom_nodes/ComfyQR/img/vertical-bars.png", width=100, show_label=False, show_download_button=False)
1082
+ with gr.Column(scale=1, min_width=0):
1083
+ gr.Markdown("**Horizontal Bars**", show_label=False)
1084
+ gr.Image("custom_nodes/ComfyQR/img/horizontal-bars.png", width=100, show_label=False, show_download_button=False)
1085
+
1086
+ # Add upscale checkbox
1087
+ artistic_enable_upscale = gr.Checkbox(
1088
+ label="Enable Upscaling",
1089
+ value=True,
1090
+ info="Enable upscaling with RealESRGAN for higher quality output (enabled by default for artistic pipeline)"
1091
+ )
1092
+
1093
  # Add seed controls for artistic QR
1094
  artistic_use_custom_seed = gr.Checkbox(
1095
  label="Use Custom Seed",
1096
+ value=True,
1097
  info="Enable to use a specific seed for reproducible results"
1098
  )
1099
  artistic_seed = gr.Slider(
1100
  minimum=0,
1101
  maximum=2000000,
1102
  step=1,
1103
+ value=718313,
1104
  label="Seed",
1105
  info="Seed value for reproducibility. Same seed with same settings will produce the same result."
1106
  )
 
1111
  minimum=1.0,
1112
  maximum=1.6,
1113
  step=0.01,
1114
+ value=1.4,
1115
  label="FreeU B1 (Backbone 1)",
1116
+ info="Backbone feature enhancement for first layer. Higher values improve detail but may reduce blending. Range: 1.0-1.6, Default: 1.4"
1117
  )
1118
  freeu_b2 = gr.Slider(
1119
  minimum=1.0,
 
1127
  minimum=0.0,
1128
  maximum=1.5,
1129
  step=0.01,
1130
+ value=0.0,
1131
  label="FreeU S1 (Skip 1)",
1132
+ info="Skip connection dampening for first layer. Lower values hide QR structure more. Range: 0.0-1.5, Default: 0.0"
1133
  )
1134
  freeu_s2 = gr.Slider(
1135
  minimum=0.0,
1136
  maximum=1.5,
1137
  step=0.01,
1138
+ value=1.3,
1139
  label="FreeU S2 (Skip 2)",
1140
+ info="Skip connection dampening for second layer. Balances scannability. Range: 0.0-1.5, Default: 1.3"
1141
  )
1142
 
1143
  # SAG (Self-Attention Guidance) Parameters
1144
  gr.Markdown("### SAG (Self-Attention Guidance)")
1145
  enable_sag = gr.Checkbox(
1146
  label="Enable SAG",
1147
+ value=True,
1148
  info="Enable Self-Attention Guidance for improved structural coherence and artistic blending"
1149
  )
1150
  sag_scale = gr.Slider(
1151
  minimum=0.0,
1152
  maximum=3.0,
1153
  step=0.1,
1154
+ value=0.5,
1155
  label="SAG Scale",
1156
+ info="Guidance strength. Higher values provide more structural coherence. Range: 0.0-3.0, Default: 0.5"
1157
  )
1158
  sag_blur_sigma = gr.Slider(
1159
  minimum=0.0,
 
1164
  info="Blur amount for artistic blending. Higher values create softer, more artistic effects. Range: 0.0-5.0, Default: 1.5"
1165
  )
1166
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1167
  # The generate button for artistic QR
1168
  artistic_generate_btn = gr.Button("Generate Artistic QR", variant="primary")
1169
 
 
1179
  # When clicking the button, it will trigger the artistic function
1180
  artistic_generate_btn.click(
1181
  fn=generate_artistic_qr,
1182
+ inputs=[artistic_prompt_input, artistic_text_input, artistic_input_type, artistic_image_size, artistic_border_size, artistic_error_correction, artistic_module_size, artistic_module_drawer, artistic_use_custom_seed, artistic_seed, artistic_enable_upscale, freeu_b1, freeu_b2, freeu_s1, freeu_s2, enable_sag, sag_scale, sag_blur_sigma],
1183
  outputs=[artistic_output_image, artistic_error_message]
1184
  )
1185