This commit is contained in:
justumen
2024-12-17 14:38:57 +01:00
parent eabe9f2e10
commit 50ee5779c0
1695 changed files with 20285 additions and 18 deletions

115
API_StableDiffusion.py Normal file
View File

@@ -0,0 +1,115 @@
import os
import time
import requests
from PIL import Image
import numpy as np
import torch
import base64
class APIGenerateStability:
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"api_key": ("STRING", {
"multiline": False,
"default": ""
}),
"prompt": ("STRING", {
"multiline": True,
"default": "A beautiful landscape"
}),
},
"optional": {
"negative_prompt": ("STRING", {
"multiline": True,
"default": ""
}),
"aspect_ratio": (["16:9", "1:1", "21:9", "2:3", "3:2", "4:5", "5:4", "9:16", "9:21"], {
"default": "1:1"
}),
"seed": ("INT", {
"default": 0,
"min": 0,
"max": 4294967294
}),
"output_format": (["jpeg", "png", "webp"], {
"default": "png"
}),
"strength": ("FLOAT", {
"default": 1.0,
"min": 0.0,
"max": 1.0,
"step": 0.01
}),
}
}
RETURN_TYPES = ("IMAGE",)
FUNCTION = "generate"
CATEGORY = "Bjornulf"
def get_next_number(self):
save_dir = "output/API/Stability"
os.makedirs(save_dir, exist_ok=True)
files = [f for f in os.listdir(save_dir) if f.endswith(('.webp', '.png', '.jpeg'))]
if not files:
return 1
numbers = [int(f.split('.')[0]) for f in files]
return max(numbers) + 1
def generate(self, api_key, prompt, negative_prompt="", aspect_ratio="1:1",
seed=0, output_format="png", strength=1.0):
headers = {
"Authorization": f"Bearer {api_key}",
"Accept": "image/*"
}
# Prepare the form data
form_data = {
"prompt": prompt,
"output_format": output_format,
"aspect_ratio": aspect_ratio
}
# Add optional parameters if they're provided
if negative_prompt:
form_data["negative_prompt"] = negative_prompt
if seed != 0:
form_data["seed"] = seed
if strength != 1.0:
form_data["strength"] = strength
# Include a placeholder in the 'files' argument to trigger multipart/form-data
files = {"placeholder": ("filename", b"")}
# Make the API request
response = requests.post(
"https://api.stability.ai/v2beta/stable-image/generate/ultra",
headers=headers,
files=files,
data=form_data
)
if response.status_code == 200:
next_num = self.get_next_number()
filename = f"{next_num:03d}.{output_format}"
filepath = os.path.join("output/API/Stability", filename)
# Save the image
with open(filepath, 'wb') as file:
file.write(response.content)
# Load and process the image for ComfyUI
img = Image.open(filepath)
if img.mode != 'RGB':
img = img.convert('RGB')
# Convert to tensor format expected by ComfyUI
img_tensor = torch.from_numpy(np.array(img).astype(np.float32) / 255.0)
img_tensor = img_tensor.unsqueeze(0)
return (img_tensor,)
else:
raise Exception(str(response.json()))

1657
API_civitai.py Normal file

File diff suppressed because it is too large Load Diff

269
API_falAI.py Normal file
View File

@@ -0,0 +1,269 @@
import os
import time
import requests
from PIL import Image
import numpy as np
import torch
import fal_client
from io import BytesIO
import json
import threading
import asyncio
class APIGenerateFalAI:
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"api_token": ("STRING", {
"multiline": False,
"default": "",
"display": "Fal.ai API Token"
}),
"model": (["fal-ai/flux-pro/v1.1-ultra", "fal-ai/recraft-v3", "fal-ai/flux-general/image-to-image"], {
"default": "fal-ai/flux-pro/v1.1-ultra"
}),
"prompt": ("STRING", {
"multiline": True,
"default": "A blackhole in space"
}),
"number_of_images": ("INT", {
"default": 1,
"min": 1,
"max": 10,
"step": 1
}),
"seed": ("INT", {
"default": -1,
"min": -1,
"max": 2147483647
}),
"timeout": ("INT", {
"default": 300,
"min": 60,
"max": 1800,
"step": 60,
"display": "Timeout (seconds)"
}),
}
}
RETURN_TYPES = ("IMAGE", "STRING",)
RETURN_NAMES = ("image", "generation_info",)
FUNCTION = "generate"
CATEGORY = "FalAI"
def __init__(self):
self.output_dir = "output/API/FalAI"
self.metadata_dir = "output/API/FalAI/metadata"
os.makedirs(self.output_dir, exist_ok=True)
os.makedirs(self.metadata_dir, exist_ok=True)
self._interrupt_event = threading.Event()
def get_next_number(self):
save_dir = "output/API/FalAI"
os.makedirs(save_dir, exist_ok=True)
files = [f for f in os.listdir(save_dir) if f.endswith('.png')]
if not files:
return 1
numbers = [int(f.split('.')[0]) for f in files]
return max(numbers) + 1
def create_filename(self, number):
# Simply format the number with leading zeros
return f"{number:03d}.png"
def save_image_and_metadata(self, img, generation_info, number):
# Create simple filename
filename = self.create_filename(number)
filepath = os.path.join(self.output_dir, filename)
# Save image
img.save(filepath)
# Create metadata filename based on the image filename
metadata_filename = f"{number:03d}_metadata.json"
metadata_filepath = os.path.join(self.metadata_dir, metadata_filename)
# Save metadata
with open(metadata_filepath, 'w', encoding='utf-8') as f:
json.dump(generation_info, f, indent=4, ensure_ascii=False)
return filepath, metadata_filepath
async def generate_single_image_async(self, input_data, api_token, model):
try:
# Set the environment variable for the API token
os.environ['FAL_KEY'] = api_token
# Submit request and get request ID
handler = await fal_client.submit_async(
model,
arguments=input_data
)
request_id = handler.request_id
print(f"Request ID: {request_id}")
# Wait for the result
result = await fal_client.result_async(model, request_id)
if not result or 'images' not in result or not result['images']:
raise ValueError(f"No valid result received. Result: {result}")
# Get image URL and download image
image_url = result['images'][0]['url']
image_response = requests.get(image_url)
if image_response.status_code != 200:
raise ConnectionError(f"Failed to download image: Status code {image_response.status_code}")
# Process image
img = Image.open(BytesIO(image_response.content))
if img.mode != 'RGB':
img = img.convert('RGB')
# Save metadata and image
number = self.get_next_number()
generation_info = {
"timestamp": time.strftime("%Y-%m-%d %H:%M:%S"),
"parameters": input_data,
"result": result,
"request_id": request_id
}
image_path, metadata_path = self.save_image_and_metadata(img, generation_info, number)
print(f"Saved image to: {image_path}")
print(f"Saved metadata to: {metadata_path}")
img_tensor = torch.from_numpy(np.array(img).astype(np.float32) / 255.0)
img_tensor = img_tensor.unsqueeze(0)
return img_tensor, generation_info
except Exception as e:
print(f"Generation error: {str(e)}")
raise Exception(f"Error generating image: {str(e)}")
def generate(self, api_token, model, prompt, number_of_images=1, seed=-1, timeout=300):
if not api_token:
raise ValueError("API token is required")
self._interrupt_event.clear()
empty_image = torch.zeros((1, 1024, 1024, 3)) # Default size
try:
images = []
infos = []
failed_jobs = []
# Create new event loop
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
async def process_all_images():
tasks = []
for i in range(number_of_images):
if self._interrupt_event.is_set():
break
# Create input data for each image
input_data = {"prompt": prompt}
# If seed is provided, increment it for each image
# If seed is -1, generate a random seed for each image
if seed != -1:
current_seed = seed + i
else:
current_seed = np.random.randint(0, 2147483647)
input_data["seed"] = current_seed
tasks.append(self.generate_single_image_async(input_data, api_token, model))
return await asyncio.gather(*tasks, return_exceptions=True)
try:
results = loop.run_until_complete(process_all_images())
finally:
loop.close()
for result in results:
if isinstance(result, Exception):
failed_jobs.append({
'error': str(result)
})
else:
img_tensor, generation_info = result
images.append(img_tensor)
infos.append(generation_info)
if not images:
generation_info = {
"error": "All generation jobs failed",
"timestamp": time.strftime("%Y-%m-%d %H:%M:%S"),
"failed_jobs": failed_jobs
}
return (empty_image, json.dumps(generation_info, indent=2))
combined_tensor = torch.cat(images, dim=0)
combined_info = {
"successful_generations": len(images),
"total_requested": number_of_images,
"generation_parameters": {
"prompt": prompt,
"initial_seed": seed
},
"individual_results": infos,
"failed_jobs": failed_jobs if failed_jobs else None
}
return (combined_tensor, json.dumps(combined_info, indent=2))
except Exception as e:
generation_info = {
"error": f"Fal.ai generation failed: {str(e)}",
"timestamp": time.strftime("%Y-%m-%d %H:%M:%S")
}
return (empty_image, json.dumps(generation_info, indent=2))
def recover_image_by_request_id(self, request_id, api_token, model):
try:
# Set the environment variable for the API token
os.environ['FAL_KEY'] = api_token
result = fal_client.result(model, request_id)
if not result or 'images' not in result or not result['images']:
raise ValueError(f"No valid result for request ID {request_id}")
image_url = result['images'][0]['url']
image_response = requests.get(image_url)
if image_response.status_code != 200:
raise ConnectionError(f"Failed to download image: Status code {image_response.status_code}")
img = Image.open(BytesIO(image_response.content))
if img.mode != 'RGB':
img = img.convert('RGB')
number = self.get_next_number()
generation_info = {
"timestamp": time.strftime("%Y-%m-%d %H:%M:%S"),
"result": result,
"request_id": request_id
}
image_path, metadata_path = self.save_image_and_metadata(img, generation_info, number)
img_tensor = torch.from_numpy(np.array(img).astype(np.float32) / 255.0)
img_tensor = img_tensor.unsqueeze(0)
return img_tensor, generation_info
except Exception as e:
raise Exception(f"Error recovering image: {str(e)}")
@classmethod
def IS_CHANGED(cls, **kwargs):
return float("NaN")
def interrupt(self):
print("Interrupting Fal.ai generation...")
self._interrupt_event.set()

185
API_flux.py Normal file
View File

@@ -0,0 +1,185 @@
import os
import time
import requests
from PIL import Image
import numpy as np
import torch
class APIGenerateFlux:
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"api_key": ("STRING", {
"multiline": False,
"default": "1ae1f1cc-de28-4682-bc4c-6ac2fdff79cc"
}),
"prompt": ("STRING", {
"multiline": True,
"default": "A beautiful landscape"
}),
"model": (["flux-pro-1.1-ultra", "flux-pro-1.1", "flux-pro", "flux-dev"], {
"default": "flux-pro-1.1-ultra"
}),
"aspect_ratio": (["16:9", "1:1", "4:3", "3:2", "21:9", "9:21"], {
"default": "16:9"
}),
"width": ("INT", {
"default": 2752,
"min": 256,
"max": 2752,
"step": 32
}),
"height": ("INT", {
"default": 1536,
"min": 256,
"max": 1536,
"step": 32
}),
"output_format": (["png", "jpeg"], {
"default": "png"
}),
},
"optional": {
"seed": ("INT", {
"default": 0,
"min": 0,
"max": 0xffffffffffffffff
}),
"safety_tolerance": ("INT", {
"default": 6,
"min": 0,
"max": 6
}),
"raw": ("BOOLEAN", {
"default": False
}),
"image_prompt_strength": ("FLOAT", {
"default": 0.1,
"min": 0.0,
"max": 1.0,
"step": 0.01
}),
"steps": ("INT", {
"default": 50,
"min": 15,
"max": 50
}),
"guidance": ("FLOAT", {
"default": 2.5,
"min": 1.0,
"max": 100.0,
"step": 0.1
}),
"prompt_upsampling": ("BOOLEAN", {
"default": False
}),
}
}
RETURN_TYPES = ("IMAGE",)
FUNCTION = "generate"
CATEGORY = "BFL API"
def get_next_number(self):
save_dir = "output/API/BlackForestLabs"
os.makedirs(save_dir, exist_ok=True)
files = [f for f in os.listdir(save_dir) if f.endswith('.png')]
if not files:
return 1
numbers = [int(f.split('.')[0]) for f in files]
return max(numbers) + 1
def generate(self, api_key, prompt, model, aspect_ratio, output_format,
seed=0, safety_tolerance=2, raw=False, image_prompt_strength=0.1,
width=1024, height=768, steps=50, guidance=30.0,
prompt_upsampling=False):
headers = {
'accept': 'application/json',
'x-key': api_key,
'Content-Type': 'application/json'
}
# Base payload
payload = {
'prompt': prompt,
'output_format': output_format,
'safety_tolerance': safety_tolerance,
}
# Add model-specific parameters
if model == "flux-pro-1.1-ultra":
payload.update({
'aspect_ratio': aspect_ratio,
'raw': raw,
'image_prompt_strength': image_prompt_strength
})
if seed != 0:
payload['seed'] = seed
else: # Other models
payload.update({
'width': width,
'height': height,
'steps': steps,
'guidance': guidance,
'prompt_upsampling': prompt_upsampling
})
if seed != 0:
payload['seed'] = seed
# Make API request
response = requests.post(
f'https://api.bfl.ml/v1/{model}',
headers=headers,
json=payload
)
if response.status_code != 200:
raise Exception(f"API request failed: {response.text}")
request_id = response.json()['id']
# Poll for results
while True:
time.sleep(0.5)
result = requests.get(
f"https://api.bfl.ml/v1/get_result?id={request_id}",
headers=headers
)
if result.status_code != 200:
raise Exception(f"Failed to get results: {result.text}")
data = result.json()
status = data['status']
if status == "Ready":
image_url = data['result']['sample']
# Download and process image
image_response = requests.get(image_url)
if image_response.status_code == 200:
next_num = self.get_next_number()
filename = f"{next_num:03d}.png"
filepath = os.path.join("output/API/BlackForestLabs", filename)
with open(filepath, 'wb') as f:
f.write(image_response.content)
img = Image.open(filepath)
if img.mode != 'RGB':
img = img.convert('RGB')
img_tensor = torch.from_numpy(np.array(img).astype(np.float32) / 255.0)
img_tensor = img_tensor.unsqueeze(0)
return (img_tensor,)
else:
raise Exception("Failed to download image")
elif status in ["Content Moderated", "Request Moderated"]:
raise Exception(f"{status}. Process stopped.")
print(f"Status: {status}")

363
README.md
View File

@@ -1,11 +1,11 @@
# 🔗 Comfyui : Bjornulf_custom_nodes v0.61 🔗
# 🔗 Comfyui : Bjornulf_custom_nodes v0.62 🔗
A list of 79 custom nodes for Comfyui : Display, manipulate, and edit text, images, videos, loras and more.
A list of 110 custom nodes for Comfyui : Display, manipulate, create and edit text, images, videos, loras, generate characters and more.
You can manage looping operations, generate randomized content, trigger logical conditions, pause and manually control your workflows and even work with external AI tools, like Ollama or Text To Speech.
# Coffee : ☕☕☕☕☕ 5/5
❤️❤️❤️ <https://ko-fi.com/bjornulf> ❤️❤️❤️
Support me and my work : ❤️❤️❤️ <https://ko-fi.com/bjornulf> ❤️❤️❤️
# ☘ This project is part of my AI trio. ☘
@@ -37,6 +37,25 @@ You can manage looping operations, generate randomized content, trigger logical
`68.` [✨➜📝 Anything to Text](#68----anything-to-text)
`75.` [📝➜📝 Replace text](#75----replace-text)
## 🔥 Text Generator 🔥
`81.` [🔥📝 Text Generator 📝🔥](#8)
`82.` [👩‍🦰📝 Text Generator (Character Female)](#8)
`83.` [👨‍🦰📝 Text Generator (Character Male)](#8)
`84.` [👾📝 Text Generator (Character Creature)](#8)
`85.` [💃🕺📝 Text Generator (Character Pose)](#8)
`86.` [🔧👨‍🔧📝 Text Generator (Object for Character)](#8)
`87.` [🌄📝 Text Generator (Scene)](#8)
`88.` [🎨📝 Text Generator (Style)](#8)
`89.` [👗 Text Generator (Outfit Female)](#8)
`90.` [👚 Text Generator (Outfit Male)](#8)
`91.` [♻🔥📝 List Looper (Text Generator)](#8)
`92.` [♻🌄📝 List Looper (Text Generator Scenes)](#8)
`93.` [♻🎨📝 List Looper (Text Generator Styles)](#8)
`94.` [♻💃🕺📝 List Looper (Text Generator Poses)](#8)
`95.` [♻👨‍🦰👩‍🦰👾 List Looper (Text Generator Characters)](#8)
`96.` [♻👚 List Looper (Text Generator Outfits Male)](#8)
`97.` [♻👗 List Looper (Text Generator Outfits Female)](#8)
## ♻ Loop ♻
`6.` [♻ Loop](#6----loop)
`7.` [♻ Loop Texts](#7----loop-texts)
@@ -51,9 +70,16 @@ You can manage looping operations, generate randomized content, trigger logical
`39.` [♻ Loop (✒🗔 Advanced Write Text + 🅰️ variables)](#39----loop--advanced-write-text)
`42.` [♻ Loop (Model+Clip+Vae) - aka Checkpoint / Model](#42----loop-modelclipvae---aka-checkpoint--model)
`53.` [♻ Loop Load checkpoint (Model Selector)](#53----loop-load-checkpoint-model-selector)
`54.` [♻ Loop Lora Selector](#54----loop-lora-selector)
`54.` [👑 Loop Lora Selector](#54----loop-lora-selector)
`56.` [♻📝 Loop Sequential (Integer)](#56----loop-sequential-integer)
`57.` [♻📝 Loop Sequential (input Lines)](#57----loop-sequential-input-lines)
`90.` [♻🔥📝 List Looper (Text Generator)](#8)
`91.` [♻🌄📝 List Looper (Text Generator Scenes)](#8)
`92.` [♻🎨📝 List Looper (Text Generator Styles)](#8)
`93.` [♻💃🕺📝 List Looper (Text Generator Poses)](#8)
`94.` [♻👨‍🦰👩‍🦰📝 List Looper (Text Generator Characters)](#8)
`95.` [♻👚 List Looper (Text Generator Outfits Male)](#8)
`96.` [♻👗 List Looper (Text Generator Outfits Female)](#8)
## 🎲 Randomization 🎲
`3.` [✒🗔 Advanced Write Text (+ 🎲 random selection and 🅰️ variables)](#3----advanced-write-text---random-selection-and-🅰%EF%B8%8F-variables)
@@ -64,7 +90,7 @@ You can manage looping operations, generate randomized content, trigger logical
`40.` [🎲 Random (Model+Clip+Vae) - aka Checkpoint / Model](#40----random-modelclipvae---aka-checkpoint--model)
`41.` [🎲 Random Load checkpoint (Model Selector)](#41----random-load-checkpoint-model-selector)
`48.` [🔀🎲 Text scrambler (🧑 Character)](#48----text-scrambler--character)
`55.` [🎲 Random Lora Selector](#55----random-lora-selector)
`55.` [🎲👑 Random Lora Selector](#55----random-lora-selector)
## 🖼💾 Image Save 💾🖼
`16.` [💾🖼💬 Save image for Bjornulf LobeChat](#16----save-image-for-bjornulf-lobechat-for-my-custom-lobe-chat)
@@ -94,6 +120,7 @@ You can manage looping operations, generate randomized content, trigger logical
`61.` [🖼🖼 Merge Images/Videos 📹📹 (Vertically)](#61----merge-imagesvideos--vertically)
`62.` [🦙👁 Ollama Vision](#62----ollama-vision)
`70.` [📏 Resize Image Percentage](#70----resize-image-percentage)
`80.` [🩷 Empty Latent Selector](#)
## 🚀 Load checkpoints 🚀
`40.` [🎲 Random (Model+Clip+Vae) - aka Checkpoint / Model](#40----random-modelclipvae---aka-checkpoint--model)
@@ -103,7 +130,24 @@ You can manage looping operations, generate randomized content, trigger logical
## 🚀 Load loras 🚀
`54.` [♻ Loop Lora Selector](#54----loop-lora-selector)
`55.` [🎲 Random Lora Selector](#55----random-lora-selector)
`55.` [🎲 Random Lora@ Selector](#55----random-lora-selector)
## ☁ Image Creation : API / cloud / remote ☁
`106.` [☁🎨 API Image Generator (FalAI) ☁](#10)
`107.` [☁🎨 API Image Generator (CivitAI) ☁](#10)
`108.` [☁👑 Add Lora (API ONLY - CivitAI) 👑☁](#10)
`109.` [☁🎨 API Image Generator (Black Forest Labs - Flux) ☁](#10)
`110.` [☁🎨 API Image Generator (Stability - Stable Diffusion) ☁](#10)
## 📥 Take from CivitAI 📥
`98.` [📥 Load checkpoint SD1.5 (+Download from CivitAi)](#10)
`99.` [📥 Load checkpoint SDXL (+Download from CivitAi)](#10)
`100.` [📥 Load checkpoint Pony (+Download from CivitAi)](#10)
`101.` [📥 Load checkpoint FLUX Dev (+Download from CivitAi)](#10)
`102.` [📥 Load checkpoint FLUX Schnell (+Download from CivitAi)](#10)
`103.` [📥👑 Load Lora SD1.5 (+Download from CivitAi)](#10)
`104.` [📥👑 Load Lora SDXL (+Download from CivitAi)](#10)
`105.` [📥👑 Load Lora Pony (+Download from CivitAi)](#10)
## 📹 Video 📹
`20.` [📹 Video Ping Pong](#20----video-ping-pong)
@@ -155,7 +199,7 @@ My referal link for Runpod : <https://runpod.io?ref=tkowk7g5> (If you use that i
If you want to use my nodes and comfyui in the cloud (and can install more stuff), I'm managing an optimized ready-to-use template on runpod : <https://runpod.io/console/deploy?template=r32dtr35u1&ref=tkowk7g5>
Template name : `bjornulf-comfyui-allin-workspace`, can be operational in ~3 minutes. (Depending on your pod, setup and download of extra models or whatever not included.)
You need to create and select a network volume before using that, size is up to you, i have 50Gb Storage because i use cloud only for Flux or lora training on a 4090. (~0.7$/hour)
⚠️ When pod is ready, you need to open a terminal in browser (After clicking on `connect` from your pod) and use this to launch ComfyUI manually : `cd /workspace/ComfyUI && python main.py --listen 0.0.0.0 --port 3000` (Much better to control it with a terminal, check logs, etc...)
⚠️ When pod is ready, you need to open a terminal in browser (After clicking on `connect` from your pod) and use this to launch ComfyUI manually : `cd /workspace/ComfyUI && python main.py --listen 0.0.0.0 --port 3000` or the alias `start_-_comfy` (Much better to control it with a terminal, check logs, etc...)
After that you can just click on the `Connect to port 3000` button.
As file manager, you can use the included `JupyterLab` on port 8888.
If you have any issues with it, please let me know.
@@ -190,6 +234,8 @@ cd /workspace/ComfyUI/output && tar -czvf /workspace/output.tar.gz .
Then you can download it from the file manager JupyterLab.
If you want to start the XTTS server, just use the alias `start_xtts`.
If you have any issues with this template from Runpod, please let me know, I'm here to help. 😊
# 🏗 Dependencies (nothing to do for runpod ☁)
@@ -298,6 +344,7 @@ cd /where/you/installed/ComfyUI && python main.py
- **0.59**: A lot of Javascript fixing to avoid resizing and better properties mangement / recoveries
- **0.60**: Revert changes from ollama_talk (implement _user mode later / another node)
- **0.61**: Add/modify a bunch of Ffmpeg / video nodes. With a global configuration system and toggle python-ffmpeg / system.
- **0.62**: MASSIVE update, Text Generator nodes. (15 nodes), API nodes generate (civitai / black forest labs / fal.ai), API civit ai download models nodes, lora
# 📝 Nodes descriptions
@@ -307,6 +354,9 @@ cd /where/you/installed/ComfyUI && python main.py
The show node will only display text, or a list of several texts. (read only node)
3 types are managed : Green is for STRING type, Orange is for FLOAT type and blue is for INT type. I put colors so I/you don't try to edit them. 🤣
Update 0.61 : You now also have 4 other nodes to display format specific values : INT, FLOAT, STRING and JSON (STRING)
These are convenient because these are automatically recommended on drag and drop.
![Show Text](screenshots/show.png)
## 2 - ✒ Write Text
@@ -1227,4 +1277,301 @@ Convert a video, can use FFMPEG_CONFIG_JSON.
Take a list of videos (one per line) and concatenate them. (One after the other in the same video.)
Can use FFMPEG_CONFIG_JSON. (From node 76 / 77)
![concat video list](screenshots/concat_video_list.png)
![concat video list](screenshots/concat_video_list.png)
#### 80 - 🩷 Empty Latent Selector
**Description:**
Tired of setting up latent space manually ?
Select one from my custom list of formats.
Just connect that to your KSampler.
![empty_latent](screenshots/empty_latent.png)
#### 81 - 🔥📝 Text Generator 📝🔥
**Description:**
Main node to generate content, doesn't really do much by itself, just `camera angle` and `multicharacter action`. (For example : `... eat picnic, view from above.`)
BUT, you can connect others `Text Generator Nodes` to it.
⚠️ Warning for "Text Generator" : This node is JUST writing text, text is then interpreted by a checkpoint (SD1.5, SDXL, Flux...) to generate an image.
Some models are very bad at doing some things, so DON'T EXPECT for everything you do to work properly all the time with every checkpoints or loras. (This node was made with FLUX in mind.)
Below is a Tutorial on how to use all my `Text Generator nodes`. I did that small tutorial in 8 steps:
Step 1 : You use the main Text Generator node, it will write general details about the image (here `camera_angle` and `shot_type`) - For now I just combine the text to a simple "write text" that will send `swamp monster` :
![textgen](screenshots/textgen.png)
Step 2 : Add a specific style to your image :
![textgen_style](screenshots/textgen_style.png)
Step 3 : Add scene/background to your image :
![textgen_scene](screenshots/textgen_scene.png)
Step 4 : Add a character to the scene using a character node, instead of the Write text Node.
I will remove the "swamp monster" from the "write text node" and use my Character Node instead, I will use it to create an agressive dragon with lighting powers :
![textgen_char](screenshots/textgen_char.png)
Step 5 : Character nodes (Male/Female and creatures) can contain more than one character. (But they will share the same characteristics)
Below I removed the dragon and I created 2 "Character male" fighting by using the `multi_char_action` from the main node. (You can set it to CUSTOM and write your own action too.)
![textgen_2chars](screenshots/textgen_2chars.png)
Step 5 : Let's try to add a location for the character, I want to put it on the left of the image. Here is a failure with the SDXL model I have been using all along :
![textgen_charposition_FAIL_sdxl](screenshots/textgen_charposition_FAIL_sdxl.png)
Step 6 : Switch to FLUX to test the `location_on_image` feature (which is working) :
![textgen_location_on_image_flux](screenshots/textgen_location_on_image_flux.png)
Step 7 : Switch to API black Forest Lab with FLUX Ultra, using my API custom node 109.
If you want several characters with different characteristics (like `location_on_image` or whatever), you can chain several Character Nodes together by connecting them to each other.
You can see below that I asked for 2 tiny dragons on the left and a zombie on the right.
![textgen_Complex_ULTRA](screenshots/textgen_Complex_ULTRA.png)
Step 8 : And to end this tutorial, I will disable the Zombie, I will add an outfit (here a `floral armor`), I will also add a `pose` node for the character and also connect this pose node to an `object` node. (They will together make the character `hold a book` and put his `hand on chin`)
![textgen_final](screenshots/textgen_final.png)
#### 82 - 👩‍🦰📝 Text Generator (Character Female)
**Description:**
Generate text related to female characters.
Need to be connected to "Text Generator" main node.
⚠️ For "Text Generator" tutorial see node 81.
#### 83 - 👨‍🦰📝 Text Generator (Character Male)
**Description:**
Generate text related to male characters.
⚠️ For "Text Generator" tutorial see node 81.
#### 84 - 👾📝 Text Generator (Character Creature)
**Description:**
Generate text related to creatures. (characters)
⚠️ For "Text Generator" tutorial see node 81.
#### 85 - 💃🕺📝 Text Generator (Character Pose)
**Description:**
Generate text related to the pose of characters.
⚠️ For "Text Generator" tutorial see node 81.
#### 86 - 🔧👨‍🔧📝 Text Generator (Object for Character)
**Description:**
Generate text related to an object connected to a pose, that is connected to a character.
⚠️ For "Text Generator" tutorial see node 81.
#### 87 - 🌄📝 Text Generator (Scene)
**Description:**
Generate text related to a specific scene, connects directly to the main text generator.
⚠️ For "Text Generator" tutorial see node 81.
#### 88 - 🎨📝 Text Generator (Style)
**Description:**
Generate text related to a specific style, connects directly to the main text generator.
⚠️ For "Text Generator" tutorial see node 81.
#### 89 - 👗 Text Generator (Outfit Female)
**Description:**
Generate text related to a specific female outfit.
⚠️ For "Text Generator" tutorial see node 81.
#### 90 - 👚 Text Generator (Outfit Male)
**Description:**
Generate text related to a specific male outfit.
⚠️ For "Text Generator" tutorial see node 81.
#### 91 - ♻🔥📝 List Looper (Text Generator)
**Description:**
Loop made to loop over elements for the main node text generator.
All the `List Looper` nodes have the same logic, you should be able to use them all the same way.
Here is an example with node 92 (list looper scenes), looping over all the different `weather_condition` :
![listlooper_USE](screenshots/listlooper_USE.png)
⚠️ Note, if you want to Loop over the elements `One by One`, Not all-in one, DO NOT use this `list looper nodes` !!
You can just convert the element you want as input and double click to create a new node that you can set to "increment".
Example, here you can see that the value was "incremented", aka changed to the next from the list, the next run will then have the next value from the list (and so on) :
![listlooper_notUSE](screenshots/listlooper_notUSE.png)
#### 92 - ♻🌄📝 List Looper (Text Generator Scenes)
**Description:**
Loop made to loop over elements for the node scenes.
⚠️ For "List Looper" tutorial see node 91.
#### 93 - ♻🎨📝 List Looper (Text Generator Styles)
**Description:**
Loop made to loop over elements for the node style.
⚠️ For "List Looper" tutorial see node 91.
#### 94 - ♻💃🕺📝 List Looper (Text Generator Poses)
**Description:**
Loop made to loop over elements for the node poses.
⚠️ For "List Looper" tutorial see node 91.
#### 95 - ♻👨‍🦰👩‍🦰👾 List Looper (Text Generator Characters)
**Description:**
Loop made to loop over elements for the node charceter (male/female/creature).
⚠️ For "List Looper" tutorial see node 91.
#### 96 - ♻👚 List Looper (Text Generator Outfits Male)
**Description:**
Loop made to loop over elements for the node for male outfits.
⚠️ For "List Looper" tutorial see node 91.
#### 97 - ♻👗 List Looper (Text Generator Outfits Female)
**Description:**
Loop made to loop over elements for the node for female outfits.
⚠️ For "List Looper" tutorial see node 91.
#### 98 - 📥 Load checkpoint SD1.5 (+Download from CivitAi)
**Description:**
This is the same as a basic "Load checkpoint" node, but the list is from civitai (not your local folder).
It will also download the file from civitai if you don't have it on your computer yet. (You need an api token from your account. - Find yours on civitai.com settings. -)
This is the `sd1.5` version, it will download the models in : `ComfyUI/models/checkpoints/Bjornulf_civitAI/sd1.5`
After downloading, you can keep using this node as is to load your checkpoint, or use the downloaded model from a basic "Load checkpoint" node.
![civitai_load_sd15](screenshots/civitai_load_sd15.png)
#### 99 - 📥 Load checkpoint SDXL (+Download from CivitAi)
**Description:**
This is the same as a basic "Load checkpoint" node, but the list is from civitai (not your local folder).
It will also download the file from civitai if you don't have it on your computer yet. (You need an api token from your account. - Find yours on civitai.com settings. -)
This is the `sdxl_1.0` version, it will download the models in : `ComfyUI/models/checkpoints/Bjornulf_civitAI/sdxl_1.0`
After downloading, you can keep using this node as is to load your checkpoint, or use the downloaded model from a basic "Load checkpoint" node.
![civitai_load_sdxl](screenshots/civitai_load_sdxl.png)
#### 100 - 📥 Load checkpoint Pony (+Download from CivitAi)
**Description:**
This is the same as a basic "Load checkpoint" node, but the list is from civitai (not your local folder).
It will also download the file from civitai if you don't have it on your computer yet. (You need an api token from your account. - Find yours on civitai.com settings. -)
This is the `pony` version, it will download the models in : `ComfyUI/models/checkpoints/Bjornulf_civitAI/pony`
After downloading, you can keep using this node as is to load your checkpoint, or use the downloaded model from a basic "Load checkpoint" node.
![civitai_load_pony](screenshots/civitai_load_pony.png)
#### 101 - 📥 Load checkpoint FLUX Dev (+Download from CivitAi)
**Description:**
This is the same as a basic "Load checkpoint" node, but the list is from civitai (not your local folder).
It will also download the file from civitai if you don't have it on your computer yet. (You need an api token from your account. - Find yours on civitai.com settings. -)
This is the `flux_d` version, it will download the models in : `ComfyUI/models/checkpoints/Bjornulf_civitAI/flux_d`
After downloading, you can keep using this node as is to load your checkpoint, or use the downloaded model from a basic "Load checkpoint" node.
🚧 Work in progress, need to manually clean up list, diffusers, etc.. ? 🚧
#### 102 - 📥 Load checkpoint FLUX Schnell (+Download from CivitAi)
**Description:**
This is the same as a basic "Load checkpoint" node, but the list is from civitai (not your local folder).
It will also download the file from civitai if you don't have it on your computer yet. (You need an api token from your account. - Find yours on civitai.com settings. -)
This is the `flux_s` version, it will download the models in : `ComfyUI/models/checkpoints/Bjornulf_civitAI/flux_s`
After downloading, you can keep using this node as is to load your checkpoint, or use the downloaded model from a basic "Load checkpoint" node.
🚧 Work in progress, need to manually clean up list, diffusers, etc.. ? 🚧
#### 103 - 📥👑 Load Lora SD1.5 (+Download from CivitAi)
**Description:**
This is the same as a basic "Load lora" node, but the list is from civitai (not your local folder).
It will also download the file from civitai if you don't have it on your computer yet. (You need an api token from your account. - Find yours on civitai.com settings. -)
This is the `sd_1.5` version, it will download the lora in : `ComfyUI/models/loras/Bjornulf_civitAI/sd_1.5`
After downloading, you can keep using this node as is to load your lora, or use the downloaded lora from a basic "Load lora" node.
Below is an example with Lora "Colorize" :
![civitai_lora_sd15](screenshots/civitai_lora_sd15.png)
#### 104 - 📥👑 Load Lora SDXL (+Download from CivitAi)
**Description:**
This is the same as a basic "Load lora" node, but the list is from civitai (not your local folder).
It will also download the file from civitai if you don't have it on your computer yet. (You need an api token from your account. - Find yours on civitai.com settings. -)
This is the `sdxl_1.0` version, it will download the lora in : `ComfyUI/models/loras/Bjornulf_civitAI/sdxl_1.0`
After downloading, you can keep using this node as is to load your lora, or use the downloaded lora from a basic "Load lora" node.
Below is an example with Lora "Better faces" :
![civitai_lora_sdxl](screenshots/civitai_lora_sdxl.png)
#### 105 - 📥👑 Load Lora Pony (+Download from CivitAi)
**Description:**
This is the same as a basic "Load lora" node, but the list is from civitai (not your local folder).
It will also download the file from civitai if you don't have it on your computer yet. (You need an api token from your account. - Find yours on civitai.com settings. -)
This is the `pony` version, it will download the lora in : `ComfyUI/models/loras/Bjornulf_civitAI/pony`
After downloading, you can keep using this node as is to load your lora, or use the downloaded lora from a basic "Load lora" node.
![civitai_lora_pony](screenshots/civitai_lora_pony.png)
#### 106 - ☁🎨 API Image Generator (FalAI) 🎨☁
**Description:**
Generate images with only a token.
This is the `fal.ai` version and will save the image in `ComfyUI/output/API/CivitAI/`
![api falai](screenshots/api_falai.png)
#### 107 - ☁🎨 API Image Generator (CivitAI) 🎨☁
**Description:**
Generate images with only a token.
This is the `civit.ai` version and will save the image in `ComfyUI/output/API/CivitAI/`
⚠️ Warning : Civitai isn't the best reliable API, sometimes it doesn't answer, or take long time to answer, some urn don't answer as well as others, etc...
Use it at your own risks, I do not recommend running anything "costly" using their API, like Flux Ultra, etc... (Use the website instead with blue buzz)
API requests (like from this node) are using yellow buzz.
![api civitai](screenshots/api_civitai.png)
#### 108 - ☁👑 Add Lora (API ONLY - CivitAI) 👑☁
**Description:**
Use lora with the API, below is an example to see clearly with the same seed the different with/without/lora.
![api civitai lora](screenshots/api_civitai_lora.png)
#### 109 - ☁🎨 API Image Generator (Black Forest Labs - Flux) 🎨☁
**Description:**
Generate an image with the Black Forest Labs API. (flux)
![api black forest](screenshots/api_black_forest.png)
#### 110 - ☁🎨 API Image Generator (Stability - Stable Diffusion) 🎨☁
**Description:**
Generate an image with the Stability API. (sd3)
![api stability](screenshots/api_stability.png)

5
TODO Normal file
View File

@@ -0,0 +1,5 @@
- Combine Loop + text random ?
- Allow all ffmpeg code to use FFMPEG_CONFIG_JSON
- video preview, allow list of IMAGES as a video ?
Add options to video preview : autoplay, audio toggle
- try to make all in one face fix...

View File

@@ -80,8 +80,49 @@ from .text_to_anything import TextToAnything
from .anything_to_text import AnythingToText
from .add_line_numbers import AddLineNumbers
from .ffmpeg_convert import ConvertVideo
# from .hiresfix import HiResFix
# from .show_images import ImageBlend
from .text_generator import TextGenerator, TextGeneratorScene, TextGeneratorStyle, TextGeneratorCharacterFemale, TextGeneratorCharacterMale, TextGeneratorOutfitMale, TextGeneratorOutfitFemale, ListLooper, ListLooperScene, ListLooperStyle, ListLooperCharacter, ListLooperOutfitFemale, ListLooperOutfitMale, TextGeneratorCharacterPose, TextGeneratorCharacterObject, TextGeneratorCharacterCreature
from .API_flux import APIGenerateFlux
from .API_StableDiffusion import APIGenerateStability
from .API_civitai import APIGenerateCivitAI, APIGenerateCivitAIAddLORA, CivitAIModelSelectorPony, CivitAIModelSelectorSD15, CivitAIModelSelectorSDXL, CivitAIModelSelectorFLUX_S, CivitAIModelSelectorFLUX_D, CivitAILoraSelectorSD15, CivitAILoraSelectorSDXL, CivitAILoraSelectorPONY
from .API_falAI import APIGenerateFalAI
from .latent_resolution_selector import LatentResolutionSelector
NODE_CLASS_MAPPINGS = {
"Bjornulf_LatentResolutionSelector": LatentResolutionSelector,
"Bjornulf_APIGenerateFlux": APIGenerateFlux,
"Bjornulf_APIGenerateFalAI": APIGenerateFalAI,
"Bjornulf_APIGenerateStability": APIGenerateStability,
"Bjornulf_APIGenerateCivitAI": APIGenerateCivitAI,
"Bjornulf_CivitAIModelSelectorPony": CivitAIModelSelectorPony,
"Bjornulf_CivitAIModelSelectorSD15": CivitAIModelSelectorSD15,
"Bjornulf_CivitAIModelSelectorSDXL": CivitAIModelSelectorSDXL,
"Bjornulf_CivitAIModelSelectorFLUX_S": CivitAIModelSelectorFLUX_S,
"Bjornulf_CivitAIModelSelectorFLUX_D": CivitAIModelSelectorFLUX_D,
"Bjornulf_CivitAILoraSelectorSD15": CivitAILoraSelectorSD15,
"Bjornulf_CivitAILoraSelectorSDXL": CivitAILoraSelectorSDXL,
"Bjornulf_CivitAILoraSelectorPONY": CivitAILoraSelectorPONY,
# "Bjornulf_CivitAILoraSelector": CivitAILoraSelector,
"Bjornulf_APIGenerateCivitAIAddLORA": APIGenerateCivitAIAddLORA,
"Bjornulf_TextGenerator": TextGenerator,
"Bjornulf_TextGeneratorCharacterPose": TextGeneratorCharacterPose,
"Bjornulf_TextGeneratorCharacterObject": TextGeneratorCharacterObject,
"Bjornulf_TextGeneratorScene": TextGeneratorScene,
"Bjornulf_TextGeneratorStyle": TextGeneratorStyle,
"Bjornulf_TextGeneratorCharacterFemale": TextGeneratorCharacterFemale,
"Bjornulf_TextGeneratorCharacterMale": TextGeneratorCharacterMale,
"Bjornulf_TextGeneratorCharacterCreature": TextGeneratorCharacterCreature,
"Bjornulf_TextGeneratorOutfitFemale": TextGeneratorOutfitFemale,
"Bjornulf_TextGeneratorOutfitMale": TextGeneratorOutfitMale,
"Bjornulf_ListLooper": ListLooper,
"Bjornulf_ListLooperScene": ListLooperScene,
"Bjornulf_ListLooperStyle": ListLooperStyle,
"Bjornulf_ListLooperCharacter": ListLooperCharacter,
"Bjornulf_ListLooperOutfitMale": ListLooperOutfitMale,
"Bjornulf_ListLooperOutfitFemale": ListLooperOutfitFemale,
# "Bjornulf_HiResFix": HiResFix,
# "Bjornulf_ImageBlend": ImageBlend,
"Bjornulf_ShowInt": ShowInt,
"Bjornulf_TextReplace" : TextReplace,
"Bjornulf_ShowFloat": ShowFloat,
@@ -166,7 +207,42 @@ NODE_CLASS_MAPPINGS = {
}
NODE_DISPLAY_NAME_MAPPINGS = {
"Bjornulf_ShowInt": "👁 Show (Int)",
# "Bjornulf_HiResFix": "HiResFix",
# "Bjornulf_ImageBlend": "🎨 Image Blend",
# "Bjornulf_APIHiResCivitAI": "🎨➜🎨 API Image hires fix (CivitAI)",
# "Bjornulf_CivitAILoraSelector": "lora Civit",
"Bjornulf_LatentResolutionSelector": "🩷 Empty Latent Selector",
"Bjornulf_CivitAIModelSelectorSD15": "📥 Load checkpoint SD1.5 (+Download from CivitAi)",
"Bjornulf_CivitAIModelSelectorSDXL": "📥 Load checkpoint SDXL (+Download from CivitAi)",
"Bjornulf_CivitAIModelSelectorPony": "📥 Load checkpoint Pony (+Download from CivitAi)",
"Bjornulf_CivitAIModelSelectorFLUX_D": "📥 Load checkpoint FLUX Dev (+Download from CivitAi)",
"Bjornulf_CivitAIModelSelectorFLUX_S": "📥 Load checkpoint FLUX Schnell (+Download from CivitAi)",
"Bjornulf_CivitAILoraSelectorSD15": "📥👑 Load Lora SD1.5 (+Download from CivitAi)",
"Bjornulf_CivitAILoraSelectorSDXL": "📥👑 Load Lora SDXL (+Download from CivitAi)",
"Bjornulf_CivitAILoraSelectorPONY": "📥👑 Load Lora Pony (+Download from CivitAi)",
"Bjornulf_APIGenerateFalAI": "☁🎨 API Image Generator (FalAI) 🎨☁",
"Bjornulf_APIGenerateCivitAI": "☁🎨 API Image Generator (CivitAI) 🎨☁",
"Bjornulf_APIGenerateCivitAIAddLORA": "☁👑 Add Lora (API ONLY - CivitAI) 👑☁",
"Bjornulf_APIGenerateFlux": "☁🎨 API Image Generator (Black Forest Labs - Flux) 🎨☁",
"Bjornulf_APIGenerateStability": "☁🎨 API Image Generator (Stability - Stable Diffusion) 🎨☁",
"Bjornulf_TextGenerator": "🔥📝 Text Generator 📝🔥",
"Bjornulf_TextGeneratorCharacterFemale": "👩‍🦰📝 Text Generator (Character Female)",
"Bjornulf_TextGeneratorCharacterMale": "👨‍🦰📝 Text Generator (Character Male)",
"Bjornulf_TextGeneratorCharacterPose": "💃🕺📝 Text Generator (Character Pose)",
"Bjornulf_TextGeneratorCharacterObject": "🔧👨‍🔧📝 Text Generator (Object for Character)",
"Bjornulf_TextGeneratorCharacterCreature": "👾📝 Text Generator (Character Creature)",
"Bjornulf_TextGeneratorScene": "🌄📝 Text Generator (Scene)",
"Bjornulf_TextGeneratorStyle": "🎨📝 Text Generator (Style)",
"Bjornulf_TextGeneratorOutfitFemale": "👗 Text Generator (Outfit Female)",
"Bjornulf_TextGeneratorOutfitMale": "👚 Text Generator (Outfit Male)",
"Bjornulf_ListLooper": "♻🔥📝 List Looper (Text Generator)",
"Bjornulf_ListLooperScene": "♻🌄📝 List Looper (Text Generator Scenes)",
"Bjornulf_ListLooperStyle": "♻🎨📝 List Looper (Text Generator Styles)",
"Bjornulf_ListLooperPose": "♻💃🕺📝 List Looper (Text Generator Poses)",
"Bjornulf_ListLooperCharacter": "♻👨‍🦰👩‍🦰👾 List Looper (Text Generator Characters)",
"Bjornulf_ListLooperOutfitMale": "♻👚 List Looper (Text Generator Outfits Male)",
"Bjornulf_ListLooperOutfitFemale": "♻👗 List Looper (Text Generator Outfits Female)",
"Bjornulf_ShowInt": "👁 Show (Int)",
"Bjornulf_ShowFloat": "👁 Show (Float)",
"Bjornulf_ShowJson": "👁 Show (JSON)",
"Bjornulf_ShowStringText": "👁 Show (String/Text)",
@@ -192,12 +268,12 @@ NODE_DISPLAY_NAME_MAPPINGS = {
"Bjornulf_ConcatVideosFromList": "📹🔗 Concat Videos from list",
"Bjornulf_LoopLinesSequential": "♻📝 Loop Sequential (input Lines)",
"Bjornulf_LoopIntegerSequential": "♻📝 Loop Sequential (Integer)",
"Bjornulf_LoopLoraSelector": "♻ Loop Lora Selector",
"Bjornulf_RandomLoraSelector": "🎲 Random Lora Selector",
"Bjornulf_LoopLoraSelector": "👑 Loop Lora Selector",
"Bjornulf_RandomLoraSelector": "🎲👑 Random Lora Selector",
"Bjornulf_LoopModelSelector": "♻ Loop Load checkpoint (Model Selector)",
"Bjornulf_VideoPreview": "📹👁 Video Preview",
"Bjornulf_ImagesListToVideo": "🖼➜📹 Images to Video path (tmp video)",
"Bjornulf_VideoToImagesList": "📹➜🖼 Video Path to Images",
"Bjornulf_VideoToImagesList": "📹➜🖼 Video Path to Images (Load video)",
"Bjornulf_AudioVideoSync": "🔊📹 Audio Video Sync",
"Bjornulf_ScramblerCharacter": "🔀🎲 Text scrambler (🧑 Character)",
"Bjornulf_WriteTextAdvanced": "✒🗔 Advanced Write Text",

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 491 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 457 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 424 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 393 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 505 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Some files were not shown because too many files have changed in this diff Show More