model2 commited on
Commit
a1fc2c1
·
1 Parent(s): 1c237e7

image sizing

Browse files
custom_nodes/comfyui-saveasjpeg/README.md DELETED
@@ -1,53 +0,0 @@
1
- # ComfyUI-Saveasjpeg
2
- Save a picture as jpeg file in Comfy + Workflow loading
3
-
4
- ## Warning:
5
-
6
- I'm a novice at best at coding and some of the code is pretty hacky, so this can definitely break.
7
-
8
- Also, jpeg only supports files up to 16383 x 16383.
9
-
10
- ### Known issues:
11
-
12
- Import of jpegfiles breaks if import a workflow that has }Prompt:{ in a Node that has dynamic wildcards disabled.
13
-
14
-
15
- Node doesn't resize on Save - image is in there, just needs to be resized to be visible.
16
-
17
- ## Description:
18
-
19
- This adds a custom node to save a picture as a jpeg File and also adds a script to Comfy to drag and drop generated jpegfiles into the UI to load the workflow.
20
-
21
- I've added a compression slider and a lossy/lossless option. The compression slider is a bit misleading.
22
-
23
- In lossless mode, it only affects the "effort" taken to compress where 100 is the smallest possible size and 1 is the biggest possible size, it's a tradeoff for saving speed.
24
-
25
- In lossy mode, that's the other way around, where 100 is the biggest possible size with the least compression and 1 is the smallest possible size with maximum compression.
26
-
27
- On default it's set to lossy with a compression of 80, below are examples for that.
28
-
29
-
30
-
31
- ## Installation:
32
-
33
- Use git clone https://github.com/aureagle/ComfyUI-Saveasjpeg in your ComfyUI custom nodes directory
34
-
35
- ## Examples:
36
-
37
- Lossless with compression set to 100, 17069KB
38
- https://postimg.cc/2bPkkFN9
39
-
40
- Lossless with compression set to 10, 17059KB
41
- https://postimg.cc/bZTwxt1d
42
-
43
-
44
- Lossy with compression set to 100 , 5384 KB
45
- https://postimg.cc/WFDpcYCJ
46
-
47
-
48
- Lossy with compression set to 10, 174 KB
49
- https://postimg.cc/VSkLDkFg
50
-
51
-
52
- Lossy with compression set to 80 ( Default ) , 935 KB
53
- https://postimg.cc/3yfr6QST
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
custom_nodes/comfyui-saveasjpeg/Save_as_jpeg.py DELETED
@@ -1,103 +0,0 @@
1
- import numpy as np
2
- from PIL import Image
3
- import folder_paths
4
- import os
5
- import json
6
-
7
- # by Kaharos94
8
- # https://github.com/Kaharos94/ComfyUI-Saveasjpeg
9
- # comfyUI node to save an image in jpeg format
10
-
11
- class Save_as_jpeg:
12
- def __init__(self):
13
- self.output_dir = folder_paths.get_output_directory()
14
- self.type = "output"
15
-
16
- @classmethod
17
- def INPUT_TYPES(s):
18
- return {"required":
19
- {"images": ("IMAGE", ),
20
- "filename_prefix": ("STRING", {"default": "ComfyUI"}),
21
- "savePrompt":(["yes","no"],),
22
- "compression":("INT", {"default": 80, "min": 1, "max": 100, "step": 1},)},
23
- "hidden": {"prompt": "PROMPT", "extra_pnginfo": "EXTRA_PNGINFO", "mode":"lossy" },
24
- }
25
-
26
- RETURN_TYPES = ()
27
- FUNCTION = "Save_as_jpeg"
28
-
29
- OUTPUT_NODE = True
30
-
31
- CATEGORY = "image"
32
-
33
- def Save_as_jpeg(self, savePrompt, compression, images, filename_prefix="ComfyUI", prompt=None, extra_pnginfo=None , mode="lossy"):
34
- def map_filename(filename):
35
- prefix_len = len(os.path.basename(filename_prefix))
36
- prefix = filename[:prefix_len + 1]
37
- try:
38
- digits = int(filename[prefix_len + 1:].split('_')[0])
39
- except:
40
- digits = 0
41
- return (digits, prefix)
42
-
43
- def compute_vars(input):
44
- input = input.replace("%width%", str(images[0].shape[1]))
45
- input = input.replace("%height%", str(images[0].shape[0]))
46
- return input
47
-
48
- filename_prefix = compute_vars(filename_prefix)
49
-
50
- subfolder = os.path.dirname(os.path.normpath(filename_prefix))
51
- filename = os.path.basename(os.path.normpath(filename_prefix))
52
-
53
- full_output_folder = os.path.join(self.output_dir, subfolder)
54
-
55
- if os.path.commonpath((self.output_dir, os.path.abspath(full_output_folder))) != self.output_dir:
56
- print("Saving image outside the output folder is not allowed.")
57
- return {}
58
-
59
- try:
60
- counter = max(filter(lambda a: a[1][:-1] == filename and a[1][-1] == "_", map(map_filename, os.listdir(full_output_folder))))[0] + 1
61
- except ValueError:
62
- counter = 1
63
- except FileNotFoundError:
64
- os.makedirs(full_output_folder, exist_ok=True)
65
- counter = 1
66
-
67
- results = list()
68
- for image in images:
69
- i = 255. * image.cpu().numpy()
70
- img = Image.fromarray(np.clip(i, 0, 255).astype(np.uint8))
71
- workflowmetadata = str()
72
- promptstr = str()
73
- imgexif = img.getexif() #get the (empty) Exif data of the generated Picture
74
-
75
-
76
- if prompt is not None:
77
- promptstr="".join(json.dumps(prompt)) #prepare prompt String
78
- if savePrompt == "yes":
79
- imgexif[0x010f] ="Prompt:"+ promptstr #Add PromptString to EXIF position 0x010f (Exif.Image.Make)
80
- if extra_pnginfo is not None:
81
- for x in extra_pnginfo:
82
- workflowmetadata += "".join(json.dumps(extra_pnginfo[x]))
83
- if savePrompt == "yes":
84
- imgexif[0x010e] = "Workflow:"+ workflowmetadata #Add Workflowstring to EXIF position 0x010e (Exif.Image.ImageDescription)
85
- file = f"{filename}_{counter:05}_.jpeg"
86
- if mode =="lossless":
87
- boolloss = True
88
- if mode =="lossy":
89
- boolloss = False
90
-
91
-
92
- img.save(os.path.join(full_output_folder, file), method=6 , exif= imgexif, lossless=boolloss , quality=compression) #Save as jpeg - options to be determined
93
- results.append({
94
- "filename": file,
95
- "subfolder": subfolder,
96
- "type": self.type
97
- });
98
- counter += 1
99
-
100
- return { "ui": { "images": results } }
101
- NODE_CLASS_MAPPINGS = {
102
- "Save_as_jpeg": Save_as_jpeg
103
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
custom_nodes/comfyui-saveasjpeg/__init__.py DELETED
@@ -1,31 +0,0 @@
1
- import shutil
2
- import folder_paths
3
- import os, sys, subprocess
4
- import filecmp
5
-
6
-
7
-
8
- print("### Loading: Save as Jpeg")
9
-
10
- comfy_path = os.path.dirname(folder_paths.__file__)
11
-
12
- def setup_js():
13
- jpeg_path = os.path.dirname(__file__)
14
- js_dest_path = os.path.join(comfy_path, "web", "extensions", "jpeginfo")
15
- js_src_path = os.path.join(jpeg_path, "jpeginfo", "jpeginfo.js")
16
-
17
- ## Creating folder if it's not present, then Copy.
18
- print("Copying JS files for Workflow loading")
19
- if (os.path.isdir(js_dest_path)==False):
20
- os.mkdir(js_dest_path)
21
- shutil.copy(js_src_path, js_dest_path)
22
- else:
23
- shutil.copy(js_src_path, js_dest_path)
24
-
25
-
26
-
27
- setup_js()
28
-
29
- from .Save_as_jpeg import NODE_CLASS_MAPPINGS
30
-
31
- __all__ = ['NODE_CLASS_MAPPINGS']
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
custom_nodes/comfyui-saveasjpeg/jpeginfo/jpeginfo.js DELETED
@@ -1,73 +0,0 @@
1
- import { app } from "/scripts/app.js";
2
- app.registerExtension({
3
- name: "kaharos.jpegsave",
4
- setup(app,file){
5
-
6
- async function getjpegExifData(jpegFile) {
7
- const reader = new FileReader();
8
- reader.readAsArrayBuffer(jpegFile);
9
-
10
- return new Promise((resolve, reject) => {
11
- reader.onloadend = function() {
12
- const buffer = reader.result;
13
- const view = new DataView(buffer);
14
- let offset = 0;
15
-
16
- // Search for the "EXIF" tag
17
- while (offset < view.byteLength - 4) {
18
- if (view.getUint32(offset, true) === 0x46495845 /* "EXIF" in big-endian */) {
19
- const exifOffset = offset + 6;
20
- const exifData = buffer.slice(exifOffset);
21
- const exifString = new TextDecoder().decode(exifData).replaceAll(String.fromCharCode(0), ''); //Remove Null Terminators from string
22
- let exifJsonString = exifString.slice(exifString.indexOf("Workflow")); //find beginning of Workflow Exif Tag
23
- let promptregex="(?<!\{)}Prompt:{(?![\w\s]*[\}])"; //Regex to split }Prompt:{ // Hacky as fuck - theoretically if somebody has a text encode with dynamic prompts turned off, they could enter }Prompt:{ which breaks this
24
- let exifJsonStringMap = new Map([
25
-
26
- ["workflow",exifJsonString.slice(9,exifJsonString.search(promptregex)+1)], // Remove "Workflow:" keyword in front of the JSON workflow data passed
27
- ["prompt",exifJsonString.substring((exifJsonString.search(promptregex)+8))] //Find and remove "Prompt:" keyword in front of the JSON prompt data
28
-
29
- ]);
30
- let fullJson=Object.fromEntries(exifJsonStringMap); //object to pass back
31
-
32
- resolve(fullJson);
33
-
34
- }
35
-
36
- offset++;
37
- }
38
-
39
- reject(new Error('EXIF metadata not found'));
40
- }})};
41
-
42
-
43
-
44
- const handleFile = app.handleFile;
45
- app.handleFile = async function(file) { // Add the 'file' parameter to the function definition
46
- if (file.type === "image/jpeg") {
47
-
48
- const jpegInfo =await getjpegExifData(file);
49
- if (jpegInfo) {
50
- if (jpegInfo.workflow) {
51
- if(app.load_workflow_with_components) {
52
- app.load_workflow_with_components(jpegInfo.workflow);
53
- }
54
- else
55
- this.loadGraphData(JSON.parse(jpegInfo.workflow));
56
- }
57
- }
58
- } else {
59
- return handleFile.apply(this, arguments);
60
- }
61
- }
62
-
63
-
64
-
65
-
66
-
67
-
68
-
69
-
70
-
71
-
72
-
73
- },});