This commit is contained in:
KLL535
2025-01-21 23:52:00 +03:00
committed by GitHub
parent b1bcd41677
commit 1ced9f5283
10 changed files with 685 additions and 0 deletions
+1
View File
@@ -0,0 +1 @@
# v1.0.0
+21
View File
@@ -0,0 +1,21 @@
MIT License/X11 License
Copyright (c) 2025 KLL535
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+7
View File
@@ -0,0 +1,7 @@
from .nodes.nodes import NODE_CLASS_MAPPINGS, NODE_DISPLAY_NAME_MAPPINGS
WEB_DIRECTORY = "./js"
__all__ = ['NODE_CLASS_MAPPINGS','NODE_DISPLAY_NAME_MAPPINGS','WEB_DIRECTORY']
print("\033[34mComfyUI_simpleButcher Node Suite: \033[92mLoaded\033[0m")
+29
View File
@@ -0,0 +1,29 @@
import { app } from "../../scripts/app.js";
import { api } from "../../scripts/api.js";
app.registerExtension({
name: "Simple Load Line From Text File",
async beforeRegisterNodeDef(nodeType, nodeData, app) {
if (nodeData.name === "Simple Load Line From Text File") {
const origOnNodeCreated = nodeType.prototype.onNodeCreated;
nodeType.prototype.onNodeCreated = function() {
const r = origOnNodeCreated ? origOnNodeCreated.apply(this) : undefined;
let counter = 0;
function find_count(w) {
return w.name === "count"
}
const count = this.widgets.find(find_count);
count.type = "converted-widget"; // hidden
function do_counter() {
return counter++;
}
count.serializeValue = do_counter;
function reset_counter() {
counter = 0;
}
api.addEventListener("promptQueued", reset_counter); // reset
return r;
}
}
}
})
+606
View File
@@ -0,0 +1,606 @@
import random
import glob
import numpy as np
import torch
import os
import sys
import re
import json
import hashlib
import comfy.sd
import folder_paths
import requests
import piexif
from safetensors import safe_open
from collections import deque
from datetime import datetime
from PIL import Image
from PIL.PngImagePlugin import PngInfo
from typing import Dict
LORA_PATH = folder_paths.folder_names_and_paths["loras"][0][0]
class AnyType(str):
def __ne__(self, __value: object) -> bool:
return False
any = AnyType("*")
################################
class SimpleLoadLineFromTextFile:
def __init__(self):
self.batch_counter = 0
self.line_counter = 0
self.random_list = []
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"start": ("INT", {"default": 0, "min": 0, "step": 1, "tooltip": "Start position for increment or decrement methods"}),
"load_file": ("BOOLEAN", {"default": True, "tooltip": "if True, load center of prompt from file"}),
"file_path": ("STRING", {"default": "", "tooltip": "Path to the file from which the lines for the central part of the prompt will be taken"}),
"next": (["increment", "decrement", "random", "random no repetitions"], {"default":"increment", "tooltip": "Option for enumerating lines, in case of randomness the start parameter is ignored"}),
"count": ("INT", {"default": 0, "min": 0, "step": 1}),
},
"optional": {
"prefix": ("STRING", {"multiline": True, "default": "", "tooltip": "Add text to the beginning of the prompt", "forceInput": True}),
"postfix": ("STRING", {"multiline": True, "default": "", "tooltip": "Add text to the ending of the prompt", "forceInput": True}),
}
}
RETURN_TYPES = ("STRING","INT","INT","INT")
RETURN_NAMES = ("text","batch_counter","line_counter","lines")
FUNCTION = "read_text_file"
CATEGORY = "📚 SimpleButcher"
DESCRIPTION = "Simple prompt loader from a text file to automate the batch process. Can be combined with each other and create total randomness text and lora that is taken from your text and lora templates"
def read_text_file(self, start = 0, load_file = False, file_path = "", next = "increment", prefix = "", postfix = "", count = 0):
if count == 0:
self.batch_counter = 0
self.line_counter = start
print(f"\033[93mClear counter\033[0m")
self.batch_counter = self.batch_counter + 1
lines2 = []
line_count = 0
if file_path != "":
if load_file == True:
file_path = os.path.expandvars(file_path)
if not os.path.isfile(file_path):
raise FileNotFoundError(f"The file at path '{file_path}' does not exist.")
with open(file_path, 'r', encoding='utf-8') as file:
lines = file.readlines()
for line in lines:
line = line.replace("\r","")
line = line.strip()
if line != "":
lines2.append(line)
line_count = len(lines2)
text = ""
if prefix != "":
text = prefix + " "
current_line = 0
if line_count > 0:
if next == "random no repetitions":
if count == 0:
# generate random numbers
print(f"\033[93mRandomize\033[0m")
self.random_list = list(range(0, line_count))
random.shuffle(self.random_list)
self.line_counter = self.random_list[self.batch_counter % len(self.random_list)]
elif next == "random":
self.line_counter = random.randint(0, line_count-1)
self.line_counter = self.line_counter % line_count
text = text + lines2[self.line_counter]
current_line = self.line_counter
console_text = f"[\033[95mBatch: {self.batch_counter}\033[0m -> \033[92mLine: {str(current_line)}/{str(line_count)}\033[0m]"
print(f"{console_text}")
if next == "increment":
self.line_counter = self.line_counter+1
elif next == "decrement":
self.line_counter = self.line_counter-1
if self.line_counter < 0:
self.line_counter = line_count-1
else:
console_text = f"[\033[95mBatch: {self.batch_counter}\033[0m]"
print(f"{console_text}")
if postfix != "":
text = text + " " + postfix
text = text.replace("\r","")
text = text.replace("\n"," ")
text = text.replace("<"," <")
text = text.replace(" "," ")
return (text,self.batch_counter,current_line,line_count)
################################
class SimpleExtractLoraFromText:
@classmethod
def INPUT_TYPES(cls):
return {"required": {
"text": ("STRING", {"multiline": True, "default": "", "tooltip": "Text with mixed lora and prompt", "forceInput": True}),
}
}
RETURN_TYPES = ("STRING","STRING")
RETURN_NAMES = ("lora_text","prompt")
FUNCTION = "extract_lora"
CATEGORY = "📚 SimpleButcher"
DESCRIPTION = "If the text contains lore, written in Forge style: <lora:name:1.0> or <lora:name:unet=1.0:te=0.75>, this node splits the text into prompts and lore separately"
def extract_lora(self, text):
text_prompt = text
text_loras = re.findall(r'<lora:[^>]*>', text)
text_lora = ' '.join(text_loras)
text_lora = text_lora.strip()
text_lora = text_lora.replace(" "," ")
text_lora2 = text_lora.replace('\n',' ')
#text_prompt = ' '.join(s for s in text.split() if not (s.startswith("<") and s.endswith(">")))
#text_prompt = ' '.join(word for word in text.split() if not re.search('<.*?>', word))
text_prompt = re.sub('<.*?>', '', text)
text_prompt = text_prompt.replace(",,",",")
text_prompt = text_prompt.replace(" ,",",")
text_prompt = text_prompt.replace(",",", ")
text_prompt = text_prompt.replace(" "," ")
text_prompt = text_prompt.strip()
text_prompt = text_prompt.strip(",")
text_prompt = text_prompt.strip()
return (text_lora,text_prompt)
################################
class SimpleLoraLoader:
def __init__(self):
self.loaded_lora = []
self.cache_size = 0
@classmethod
def INPUT_TYPES(cls):
return {"required": {
"model": ("MODEL", {"tooltip": "The diffusion model the LoRA will be applied to"}),
"clip": ("CLIP", {"tooltip": "The CLIP model the LoRA will be applied to"}),
"lora_text": ("STRING", {"multiline": False, "default": "", "tooltip": "Multiple LoRAs discriptions in Forge style: <lora:name:1.0> or <lora:name:unet=1.0:te=0.75>", "forceInput": True}),
},
"optional": {
"multiple_strength_unet": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.05, "tooltip": "Multiple of unet strength"}),
"multiple_strength_clip": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.05, "tooltip": "Multiple of clip strength"}),
"limit_strength_unet": ("FLOAT", {"default": 2.0, "min": -10.0, "max": 10.0, "step": 0.05, "tooltip": "Max of unet strength"}),
"limit_strength_clip": ("FLOAT", {"default": 2.0, "min": -10.0, "max": 10.0, "step": 0.05, "tooltip": "Max of clip strength"}),
}
}
RETURN_TYPES = ("MODEL","CLIP","STRING","STRING")
RETURN_NAMES = ("model","clip","civitai_lora","civitai_lora_hash")
FUNCTION = "lora_loader"
CATEGORY = "📚 SimpleButcher"
DESCRIPTION = "Multiple LoRAs loader, understands discriptions in Forge style: <lora:name:1.0> or <lora:name:unet=1.0:te=0.75>. Understands both file names and internal lore names (Forge style). Once creates a lora_name.json dictionary and places it in the lora folder to speed up. Once creates a lora templates to __txt folder. In case of lora update just delete these files and press F5 in confy-ui."
def file_sha256(self, filename):
hasher = hashlib.sha256()
with open(filename, 'rb') as f:
while True:
data = f.read(65536) # Read in 64k chunks
if not data:
break
hasher.update(data)
return hasher.hexdigest()
def load_lora_name(self):
directory = LORA_PATH
json_path = os.path.join(directory,"lora_name.json")
name_lines = []
json_lines = []
console_text = f"[\033[94mLora File:\033[0m]"
print(f"{console_text}")
for root, dirs, files in os.walk(directory):
for file in files:
if file.endswith(".safetensors"):
full_filepath = os.path.join(root, file)
filepath = full_filepath.replace(directory+"\\", "")
lora_name1 = os.path.splitext(file)[0]
lora_name2 = "None"
with safe_open(full_filepath, framework="pt", device="cpu") as f:
if f.metadata() != None:
if "ss_output_name" in f.metadata():
lora_name2 = f.metadata()["ss_output_name"]
if lora_name2 == "lora":
lora_name2 = "None"
if lora_name2 == "":
lora_name2 = "None"
#elif "modelspec.title" in f.metadata():
# lora_name2 = f.metadata()["modelspec.title"]
hash_value = self.file_sha256(full_filepath)
hash_value_10_chars = hash_value[:10]
subdirectory = os.path.dirname(filepath)
if subdirectory == "":
subdirectory = "root"
subdirectory = subdirectory.replace("\\","_")
if lora_name2 == "None":
console_text = f"[\033[95m{hash_value_10_chars}\033[0m] {filepath} -> \033[91m{lora_name2}\033[0m"
name_lines.append([subdirectory,"<lora:"+lora_name1+":1.0>"])
else:
console_text = f"[\033[95m{hash_value_10_chars}\033[0m] {filepath} -> \033[92m{lora_name2}\033[0m"
name_lines.append([subdirectory,"<lora:"+lora_name2+":1.0>"])
print(f"{console_text}")
json_lines.append([filepath,lora_name1,lora_name2,hash_value_10_chars])
console_text = "End"
console_text = f"[\033[94m{console_text}\033[0m]"
print(f"{console_text}")
with open(json_path, 'w') as file:
json.dump(json_lines, file)
txt_path = directory + "\\__txt"
if not os.path.exists(txt_path):
os.makedirs(txt_path, exist_ok=True)
data_dict = {}
for name, value in name_lines:
if name not in data_dict:
data_dict[name] = []
data_dict[name].append(value)
for name, values in data_dict.items():
with open(txt_path+f"\\Lora in {name}.txt", "w", encoding="utf-8") as file:
for value in values:
file.write(f"{value}\n")
return ()
def lora_loader(self, model, clip, lora_text, multiple_strength_unet = 1.0, multiple_strength_clip = 1.0, limit_strength_unet = 2.0, limit_strength_clip = 2.0):
json_path = os.path.join(LORA_PATH,"lora_name.json")
if not os.path.isfile(json_path):
self.load_lora_name()
dic = []
if os.path.isfile(json_path):
with open(json_path, 'r') as file:
data = json.load(file)
dic = [tuple(item) for item in data]
loras = re.findall(r'<lora:[^>]*>', lora_text)
civitai_lora = ""
civitai_lora_hash = ""
#print(f"Cache size = {len(self.loaded_lora)}")
for item in self.loaded_lora:
item[2] = False
for lora in loras:
lora = lora.replace("<lora:","")
lora = lora.replace(">","")
parts = lora.split(":", 1)
lora_prompt_name = parts[0]
lora_path = ""
lora_hash = ""
for item in dic: # find filename
if item[1] == lora_prompt_name:
lora_path = item[0]
lora_hash = item[3]
break
if lora_path == "":
for item in dic: # or find lora name
if item[2] == lora_prompt_name:
lora_path = item[0]
lora_hash = item[3]
break
if lora_path == "":
console_text = "-Lora: "+lora_prompt_name
console_text = f"[\033[91m{console_text}\033[0m]"
print(f"{console_text}")
continue
##########################
##### parce strength #####
strength_model = 1.0
strength_clip = 1.0
if len(parts) == 2:
lora_parameter = parts[1]
parts = lora_parameter.split(":")
if len(parts) == 1:
try:
strength_model = float(lora_parameter)
strength_model = round(strength_model, 2)
except:
strength_model = 1.0
strength_clip = strength_model
else:
for part in parts:
parts2 = part.split("=")
if parts2[0] == "unet":
try:
strength_model = float(parts2[1])
strength_model = round(strength_model, 2)
except:
strength_model = 1.0
elif parts2[0] == "te":
try:
strength_clip = float(parts2[1])
strength_clip = round(strength_clip, 2)
except:
strength_clip = 1.0
if multiple_strength_unet != 1.0:
strength_model = round(strength_model * multiple_strength_unet, 2)
if multiple_strength_clip != 1.0:
strength_clip = round(strength_clip * multiple_strength_clip, 2)
if strength_model > limit_strength_unet:
strength_model = limit_strength_unet
if strength_clip > limit_strength_clip:
strength_clip = limit_strength_clip
##### parce strength #####
##########################
strength_model_str = "{:.2f}".format(strength_model)
strength_clip_str = "{:.2f}".format(strength_clip)
if strength_model == strength_clip:
civitai_lora = civitai_lora + "<lora:" + lora_prompt_name + ":" + strength_model_str + "> "
else:
civitai_lora = civitai_lora + "<lora:" + lora_prompt_name + ":unet=" + strength_model_str + ":te=" + strength_clip_str + "> "
civitai_lora_hash = civitai_lora_hash + lora_prompt_name + ": " + lora_hash + ", "
lora = None
postfix = ""
for item in self.loaded_lora:
if item[0] == lora_path:
lora = item[1]
item[2] = True
postfix = " cache"
if lora == None:
full_path = folder_paths.get_full_path_or_raise("loras", lora_path)
lora = comfy.utils.load_torch_file(full_path, safe_load=True)
self.loaded_lora.append([lora_path,lora,True])
postfix = " load"
model,clip = comfy.sd.load_lora_for_models(model, clip, lora, strength_model, strength_clip)
if strength_model == strength_clip:
console_text = f"[\033[94m+Lora: {lora_path}:\033[92m{strength_model_str}\033[0m]{postfix}"
print(f"{console_text}")
else:
console_text = f"[\033[94m+Lora: {lora_path}:\033[92m{strength_model_str}:{strength_clip_str}\033[0m]{postfix}"
print(f"{console_text}")
##### Empty catch #####
for i in range(len(self.loaded_lora)-1, -1, -1): #reverse order
if not self.loaded_lora[i][2]:
temp = self.loaded_lora[i][1]
del self.loaded_lora[i]
del temp
civitai_lora_hash = civitai_lora_hash.rstrip(", ")
civitai_lora = civitai_lora.strip()
return (model,clip,civitai_lora,civitai_lora_hash)
################################
class SimpleImageSaver:
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"images": ("IMAGE", { "tooltip": "image(s) to save", "forceInput": True}),
"prompt": ("STRING", {"default": "", "multiline": False, "tooltip": "STRING", "forceInput": True}),
"output_path": ("STRING", {"default": "", "multiline": False, "tooltip": "Path where images will be saved"}),
"SEED": ("INT", {"default": '0', "tooltip": "INT", "forceInput": True}),
"modelname": ("STRING", {"default": '', "multiline": False, "tooltip": "STRING, use Checkpoint Loader with Name (Image Saver) node", "forceInput": True}),
},
"optional": {
"steps": ("INT", {"default": 0, "tooltip": "INT", "forceInput": True}),
"sampler": (any, {"default": None, "tooltip": "ANY, use Sampler Selector (Image Saver) node", "forceInput": True}),
"schedule": (any, {"default": None, "tooltip": "ANY, use Scheduler Selector (Image Saver) node", "forceInput": True}),
"CFG_scale": ("FLOAT", {"default": 0.0, "tooltip": "FLOAT", "forceInput": True}),
"distilled_CFG_scale": ("FLOAT", {"default": 0.0, "tooltip": "FLOAT", "forceInput": True}),
"width": ("INT", {"default": 0, "tooltip": "INT", "forceInput": True}),
"height": ("INT", {"default": 0, "tooltip": "INT", "forceInput": True}),
"beta_schedule_alpha": ("FLOAT", {"default": 0.0, "tooltip": "FLOAT", "forceInput": True}),
"beta_schedule_beta": ("FLOAT", {"default": 0.0, "tooltip": "FLOAT", "forceInput": True}),
"civitai_lora": ("STRING", {"default": '', "multiline": False, "tooltip": "STRING, Loras name from Simple Lora Loader node", "forceInput": True}),
"civitai_lora_hash": ("STRING", {"default": '', "multiline": False, "tooltip": "STRING, Loras hash from Simple Lora Loader node", "forceInput": True}),
"negative": ("STRING", {"default": '', "multiline": False, "tooltip": "STRING, Negative prompt", "forceInput": True}),
}
}
RETURN_TYPES = ("STRING",)
RETURN_NAMES = ("metadata_text",)
FUNCTION = "image_saver"
CATEGORY = "📚 SimpleButcher"
DESCRIPTION = "SimpleImageSaver"
OUTPUT_NODE = True
DESCRIPTION = "Image Saver with metadata in Forge style. Loras name and hash could be obtained from Simple Lora Loader node. Сreated subfolders with date, output files contain a sequence number and seed, as Forge does."
def find_free_number(self, path):
i = -1
for filename in os.listdir(path):
if os.path.isfile(os.path.join(path, filename)):
new = -1
try:
new = int(filename[:5])
except:
new = -1
if new > i:
i = new
return i+1
def get_sha256(self, file_path: str):
file_no_ext = os.path.splitext(file_path)[0]
hash_file = file_no_ext + ".sha256"
if os.path.exists(hash_file):
try:
with open(hash_file, "r") as f:
return f.read().strip()
except OSError as e:
print(f"ComfyUI-Image-Saver: Error reading existing hash file: {e}")
sha256_hash = hashlib.sha256()
with open(file_path, "rb") as f:
for byte_block in iter(lambda: f.read(4096), b""):
sha256_hash.update(byte_block)
try:
with open(hash_file, "w") as f:
f.write(sha256_hash.hexdigest())
except OSError as e:
print(f"ComfyUI-Image-Saver: Error writing hash to {hash_file}: {e}")
return sha256_hash.hexdigest()
def image_saver(self, images, prompt, output_path, SEED, modelname, steps=0, sampler=None, schedule=None, CFG_scale=0.0, distilled_CFG_scale=0.0, width=0, height=0, beta_schedule_alpha=0.0, beta_schedule_beta=0.0, civitai_lora="", civitai_lora_hash="",negative=""):
metadata_text = ""
now = datetime.now()
date = now.strftime("%Y-%m-%d")
output_path = output_path.strip()
if output_path == '':
return ()
output_path = os.path.join(output_path, date)
if not os.path.exists(output_path):
os.makedirs(output_path, exist_ok=True)
for image in images:
i = 255. * image.cpu().numpy()
img = Image.fromarray(np.clip(i, 0, 255).astype(np.uint8))
free_number = self.find_free_number(output_path)
if free_number > 99999:
print(f"\033[91mToo many files\033[0m")
return ()
seed_text = str(SEED)
####################
##### metadata #####
metadata_text = prompt
if civitai_lora != "":
metadata_text = metadata_text + ' ' + civitai_lora
metadata_text = metadata_text + '\n'
if negative != "":
metadata_text = metadata_text + "Negative prompt: "+ negative + '\n'
if steps != 0:
metadata_text = metadata_text + "Steps: "+str(steps)+", "
if sampler != None:
metadata_text = metadata_text + "Sampler: "+str(sampler)+", "
if schedule != None:
metadata_text = metadata_text + "Schedule type: "+str(schedule)+", "
if CFG_scale != 0.0:
metadata_text = metadata_text + "CFG scale: "+str(CFG_scale)+", "
if distilled_CFG_scale != 0.0:
metadata_text = metadata_text + "Distilled CFG Scale: "+str(distilled_CFG_scale)+", "
metadata_text = metadata_text + "Seed: "+seed_text+", "
if width != 0:
if height != 0:
metadata_text = metadata_text + "Size: " + str(width) + "x" + str(height) + ", "
ckpt_path = folder_paths.get_full_path("checkpoints", modelname)
if not ckpt_path:
ckpt_path = folder_paths.get_full_path("diffusion_models", modelname)
if ckpt_path:
modelhash = self.get_sha256(ckpt_path)[:10]
else:
modelhash = ""
metadata_text = metadata_text + "Model hash: "+modelhash+", "
modelname = os.path.basename(modelname)
modelname = os.path.splitext(modelname)[0]
metadata_text = metadata_text + "Model: "+modelname+", "
if beta_schedule_alpha != 0.0:
metadata_text = metadata_text + "Beta schedule alpha: "+str(beta_schedule_alpha)+", "
if beta_schedule_beta != 0.0:
metadata_text = metadata_text + "Beta schedule beta: "+str(beta_schedule_beta)+", "
if civitai_lora_hash != "":
metadata_text = metadata_text + "Lora hashes: \"" + civitai_lora_hash + "\", "
metadata_text = metadata_text + "Version: ComfyUI"
##### metadata #####
####################
metadata = PngInfo()
metadata.add_text("parameters", metadata_text)
filename = f"{free_number:05d}-{seed_text}.png"
img.save(os.path.join(output_path, filename), pnginfo=metadata, optimize=False)
return (metadata_text,)
################################
NODE_CLASS_MAPPINGS = {
"Simple Load Line From Text File": SimpleLoadLineFromTextFile,
"Simple Extract Lora From Text": SimpleExtractLoraFromText,
"Simple Lora Loader": SimpleLoraLoader,
"Simple Image Saver (as Forge)": SimpleImageSaver
}
NODE_DISPLAY_NAME_MAPPINGS = {
"Simple Load Line From Text File": "Simple Load Line From Text File 📚",
"Simple Extract Lora From Text": "Simple Extract Lora From Text 📚",
"Simple Lora Loader": "Simple Lora Loader 📚",
"Simple Image Saver (as Forge)": "Simple Image Saver (as Forge) 📚",
}
+2
View File
@@ -0,0 +1,2 @@
piexif
File diff suppressed because one or more lines are too long
+9
View File
@@ -0,0 +1,9 @@
<lora:BeautyInEvilFlux:1> hkevil,
<lora:flux.1_lora_flyway_Epic-detail_v2:1>
<lora:RetroAnimeFluxV1:1>
<lora:Studio_Ghibli_Flux:1> ghiblistyle,
<lora:dreadmirth-style-art:1> dreadmirthart,
<lora:RM_Animefy_v1.0M:1>
<lora:Illustration_Style_IV:1>
<lora:ImpressionismFlux:1> ArsMJStyle, impressionism,
<lora:FluxDFaeTasticDetails:1>
+9
View File
@@ -0,0 +1,9 @@
A quiet, reclusive individual who prefers solitude to large crowds; an introverted homebody who finds comfort in the familiar surroundings of their own space, shunning social gatherings and instead enjoying solitary pursuits such as reading, writing, or hobbies that allow for deep focus and introspection. This person is content with their own company, valuing personal growth and inner peace over constant social interaction.
The image is an illustration of a female elf holding a crystal ball in her hand. She is standing in a forest with tall trees and colorful foliage in the background. The elf is wearing a green hooded cloak with a pointed hat and has long white hair. She has a fierce expression on her face and is holding the crystal ball with both hands. The crystal ball has a blue and white swirl pattern on it. The overall mood of the image is mystical and mystical.
The image is a digital illustration of a white cat with blue eyes. The cat is standing on its hind legs with its front paws resting on an open book. The book is resting on a wooden surface and the background is dark with small white dots scattered around. The overall mood of the image is peaceful and serene.
The image is a digital illustration of a futuristic landscape with a planet in the background. The sky is filled with stars and planets, and the sun is setting in the distance, casting a warm orange glow over the scene. The planet is large and round, with a blue planet on the left side and a smaller planet in front of it. On the right side of the image, there are several smaller planets and stars scattered across the sky.
The image is a promotional poster for a movie or TV show. It features a man in a military uniform, standing in front of a rocky background. The man is wearing a black cape with gold buttons and a gold emblem on the left side. He has a beard and is looking off to the side with a serious expression on his face.
The image is a painting of a beautiful night scene with a full moon in the background. The sky is filled with stars and the moon is shining brightly, creating a soft glow. The scene is set in a forest with tall trees on both sides of the river. The trees are covered in bluebells and the ground is covered in green grass. The river is calm and there is a wooden bridge crossing over it. The water is still and reflects the colors of the sky and the trees. The overall mood of the painting is peaceful and serene.
The image is a digital illustration of a young, anthropomorphic female character with animal-like ears protruding from her head. She has a petite, slender physique with fair skin and large, expressive brown eyes. Her hair is short and tousled, with dark brown and light blonde streaks, and her ears are large and pointed, with a darker hue. She has a small, pointed nose and a slightly flushed complexion, with a few freckles on her cheeks. She wears a brown, fur-lined crop top and arm bands, adorned with geometric patterns and fur accents. The background is a dark, muted blue, with small, glowing yellow dots and small, floating orbs, giving the impression of a night sky with stars. The texture of the illustration is smooth, with a glossy finish and a detailed, vibrant color palette. The overall style is reminiscent of anime, with a focus on expressive eyes and exaggerated features, combined with a realistic, detailed approach to the textures and shading. The illustration is highly polished and detailed, with a focus on the character's facial expression and the texture of her clothing and hair.
A super detailed digital painting features a white cat with big, expressive green eyes and a playful expression. The cat sports a snazzy red wizard hat with a black band and a little golden bell, giving off a magical vibe. A red cape with a golden clasp is draped over its back. The fur is super detailed with dark and light stripes, showing off its sleek coat. In the background, a fantasy village with rustic, wooden buildings and thatched roofs sprawls across a lush, green landscape. The village is partially destroyed, with wooden beams and debris scattered around. Red and pink flowers, with some white blooms, pop up among the ruins, adding a splash of color. The sky is bright with soft, fluffy clouds, adding to the whimsical and enchanting atmosphere. The whole scene is bursting with texture and color, blending fantasy and realism to create a vivid and immersive world. The style is reminiscent of modern fantasy art with a dash of magical realism.
In this photo report, we explore a dramatic space battle scene that captures the essence of warfare in a visually stunning way. The backdrop for this narrative is the planet Saturn, known for its iconic rings, which provides an impressive setting. Two imposing Dreadnought-class spaceships, similar to the attached image, are engaged in combat against a group of smaller space fighters. These ships are characterized by their numerous protrusions, weapons, and prominent blue light elements, enhancing the visual spectacle. The small space fighters, resembling speedy space planes, maneuver swiftly through the darkness, leaving behind dynamic light trails that add movement and tension to the scene. The overall illumination comes from Saturn's bright light, which not only reflects off the metal surfaces of the ships but also contributes to the dramatic atmosphere of the battle. To further emphasize scale and depth in the space landscape, several moons of Saturn are visible, adding a sense of grandeur to this cosmic conflict. Through the use of photo-realistic imagery, attention to detail, and an emphasis on action and drama, this report successfully conveys the intensity and complexity of a space battle while also showcasing the beauty and wonder of our universe.
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB