GeorgLegato / Txt2Vectorgraphics

Custom Script for Automatics1111 StableDiffusion-WebUI.
GNU General Public License v3.0
365 stars 29 forks source link

Error after image generation - Execution of Protrace failed. #8

Closed some9000 closed 2 years ago

some9000 commented 2 years ago

Hello! First of all - really neat script, got some great results on the first run. Thanks for making it! But then, when running it next time this happens:

To create a public link, set `share=True` in `launch()`.
100%|██████████████████████████████████████████████████████████████████████████████████| 20/20 [00:07<00:00,  2.53it/s]
Error completing request███████████████████████████████████████████████████████████████| 20/20 [00:04<00:00,  4.62it/s]
Arguments: ('Lion', '', 'None', 'None', 20, 0, False, False, 1, 1, 7, -1.0, -1.0, 0, 0, 0, False, 512, 512, False, False, 0.7, 3, False, False, None, '', 'svg', True, True, False, 0.5, 1, '', 0, '', True, False) {}
Traceback (most recent call last):
  File "C:\Users\joedo\stable-diffusion-webui\scripts\txt2vectorgfx.py", line 78, in run
    fullfn = files[i]
IndexError: list index out of range

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\Users\joedo\stable-diffusion-webui\modules\ui.py", line 182, in f
    res = list(func(*args, **kwargs))
  File "C:\Users\joedo\stable-diffusion-webui\webui.py", line 69, in f
    res = func(*args, **kwargs)
  File "C:\Users\joedo\stable-diffusion-webui\modules\txt2img.py", line 40, in txt2img
    processed = modules.scripts.scripts_txt2img.run(p, *args)
  File "C:\Users\joedo\stable-diffusion-webui\modules\scripts.py", line 159, in run
    processed = script.run(p, *script_args)
  File "C:\Users\joedo\stable-diffusion-webui\scripts\txt2vectorgfx.py", line 96, in run
    raise Exception("TXT2Vectorgraphics: Execution of Protrace failed, check filesystem, permissions, installation or settings")
Exception: TXT2Vectorgraphics: Execution of Protrace failed, check filesystem, permissions, installation or settings

potrace.exe is in the scripts directory. In theory nothing has really changed, just having the latest updates from the main repo. Any ideas how to fix this?

And also - Potrace is named Protrace in several places, as visible in the error message above.

GeorgLegato commented 2 years ago

try to (re)-configure the output/samples setting. and maybe in addition "save images into subdirectory". As commented in code, a script does not know exactly where the images go (filenames and pathes are magicall constructed in main application)

GeorgLegato commented 2 years ago

you could post a screenshot of your settings please, just the upper part with files/directory, storage location

some9000 commented 2 years ago

Got it - I had turned off saving of individual images. Now it works ok. Would it be possible to add some sort of check and warning OR just ignore the global setting when using this script?

GeorgLegato commented 2 years ago

ok, no image produced? then the vector has indeed no chance to do something meaningful. what is your usecase? creating grids instead of images? but nice you can workaround it

GeorgLegato commented 2 years ago

there was a warning, check filesystem, permission and settings. settings in sdwebui are complicated so the warning can't do it better by now

some9000 commented 2 years ago

Yeah, finally got it because of the warning. Meanwhile, it seemed like something could be added to this. Had never used Python before, but by looking at other scripts and going through 1000+ test images I managed to slightly edit your script to add some options: 2022-10-12 15 00 49 127 0 0 1 0675474f8c44 Not all of them are great, but it was a good exercise. Also not going to add a branch or such (no idea how that works + this is your project after all), but here is the code in case you are interested:

"""
using POTRACE as backend cmd line tool for vectorizing SD output
This script will download from

https://potrace.sourceforge.net/#downloading

the windows exetuable (todo: mac, linux support)
Potrace is under GPL, you can download the source from the url above.

If you dont want to download that, please install POTRACE to your 
system manually and assign it to your PATH env variable properly.
"""
POS_PROMPT = ",(((vector graphic))), (((black white, line art))), atari graphic"
NEG_PROMPT = ",background, colors, shading, details, (((text))), (caption)"
PO_URL     = "https://potrace.sourceforge.net/download/1.16/potrace-1.16.win64.zip"
PO_ZIP     = "potrace.zip"
PO_ZIP_EXE = "potrace-1.16.win64/potrace.exe"
PO_EXE     = "scripts/potrace.exe"

##########################################################################

import os
import pathlib
import subprocess
from zipfile import ZipFile
import requests
import glob
import os.path
from sys import platform

import modules.scripts as scripts
import modules.images as Images
import gradio as gr

from modules.processing import Processed, process_images
from modules.shared import opts

class Script(scripts.Script):
    def title(self):
        return "Text to Vector Graphics"

    def ui(self, is_img2img):
        poUseColor = gr.Radio(["Image","Logo","Drawing","Artistic","Tattoo","Gothic","Anime","Cartoon"], label="Result type", value="Image")
        poFormat = gr.Dropdown(["svg","pdf"], label="Output format", value="svg")
        poOpaque = gr.Checkbox(label="White is Opaque", value=True)
        poTight = gr.Checkbox(label="Cut white margin from input", value=True)
        poKeepPnm = gr.Checkbox(label="Keep temp images", value=False)
        poThreshold = gr.Slider(label="Threshold", minimum=0.0, maximum=1.0, step=0.05, value=0.5)

        return [poUseColor,poFormat, poOpaque, poTight, poKeepPnm, poThreshold]

    def run(self, p, poUseColor,poFormat, poOpaque, poTight, poKeepPnm, poThreshold):
        PO_TO_CALL = self.check_Potrace_install()

        p.do_not_save_grid = True

        # Select result type = b/w or colored
        if poUseColor == "Image":
            POS_PROMPT = ",(((vectorised graphic))),(((black and white))),atari graphic,(high contrast),white background"
            NEG_PROMPT = ",color,shading,detailed,(((text))),(caption),signature,watermark"

        if poUseColor == "Logo":
            POS_PROMPT = ",(((vector graphic))),((black and white)),(logo),centered,stencil,trending on dribbble,(high contrast),white background"
            NEG_PROMPT = ",lowres,error,stock,color,shading,detailed,((text)),(caption),signature,watermark"

        if poUseColor == "Drawing":
            POS_PROMPT = ",(((Cartoon graphic))),((black and white)),childrens book,precise lineart,white background,2 bit"
            NEG_PROMPT = ",lowres,error,color,shading,detailed,((text)),(caption),signature,watermark"

        if poUseColor == "Artistic":
            POS_PROMPT = ",(((Artistic two color painting))),((black and white)),white background, high contrast,2 bit"
            NEG_PROMPT = ",lowres,error,color,shading,detailed,((text)),(caption),signature,watermark"

        if poUseColor == "Tattoo":
            POS_PROMPT = ",((clean Tattoo design)),(black and white),uniform lighting,lines,white background,(high contrast),((2 bit))"
            NEG_PROMPT = ",lowres,error,(((skin))),color,shading,((text)),(caption),signature,watermark"

        if poUseColor == "Gothic":
            POS_PROMPT = ",(((Gothic ink drawing))),((black and white)),H.P. Lovecraft,Arthur Rackham,white background,low detail,high contrast,2 bit"
            NEG_PROMPT = ",error,color,shading,((text)),(caption),signature,watermark"

        if poUseColor == "Anime":
            POS_PROMPT = ",(((Anime))),((black and white)),(white background),Studio Ghibli,Makoto Shinkai,Hayao Miyazaki,Audrey Kawasaki,featured on pixiv,2 bit"
            NEG_PROMPT = ",lowres,error,color,shading,detailed,((text)),(caption),signature,watermark"

        if poUseColor == "Cartoon":
            POS_PROMPT = ",((Cartoon)),(((black and white))),(white background),2D,high contrast,2 bit"
            NEG_PROMPT = ",3D,lowres,error,color,(((stock))),shading,detailed,((text)),(caption),signature,watermark"

        p.prompt += POS_PROMPT
        p.negative_prompt += NEG_PROMPT

        images = []
        proc = process_images(p)
        images += proc.images        

        # unfortunately the concrete file name is nontrivial using increment counter etc, so we have to reverse-guess the last stored images by changetime
        folder = p.outpath_samples

        if opts.save_to_dirs:
            folder = glob.glob(p.outpath_samples+"/*")
            folder = max(folder, key=os.path.getctime)

        files = glob.glob(folder+"/*."+opts.samples_format)
        # latest first
        files = sorted(files, key=os.path.getctime, reverse=True)

        try:
            # vectorize
            for i,img in enumerate(images[::-1]): 
                fullfn = files[i]
                fullofpnm = pathlib.Path(fullfn).with_suffix('.pnm')
                fullof = pathlib.Path(fullfn).with_suffix('.'+poFormat)

                img.save(fullofpnm)

                args = [PO_TO_CALL,  "-b", poFormat, "-o", fullof, "--blacklevel", format(poThreshold, 'f')]
                if poOpaque: args.append("--opaque")
                if poTight: args.append("--tight")
                args.append(fullofpnm)

                p2 = subprocess.Popen(args)

                if not poKeepPnm:
                    p2.wait()
                    os.remove(fullofpnm)

        except (Exception):
            raise Exception("TXT2Vectorgraphics: Execution of Potrace failed, check filesystem, permissions, installation or settings (is image saving on?)")

        return Processed(p, images, p.seed, "")

    def check_Potrace_install(self) -> str:
        # For Linux, run potrace from installed binary
        if platform == "darwin":
            try:
                # check whether already in PATH 
                checkPath = subprocess.Popen(["potrace","-v"])
                checkPath.wait()
                return "potrace"
            except (Exception):
                raise Exception("Cannot find installed Potrace on Mac. Please run `sudo apt install potrace`")

        elif platform == "linux"or platform == "linux2":
            try:
                # check whether already in PATH 
                checkPath = subprocess.Popen(["potrace","-v"])
                checkPath.wait()
                return "potrace"
            except (Exception):
                raise Exception("Cannot find installed Potrace. Please run `sudo apt install '  `")

        # prefer local '   over that from PATH
        elif platform == "win32":
            if not os.path.exists(PO_EXE):
                try:
                    # check whether already in PATH 
                    checkPath = subprocess.Popen(["'  ","-v"])
                    checkPath.wait()
                    return "'  "

                except (Exception):
                    try:
                        # try to download Potrace and unzip locally into "scripts"
                        if not os.path.exists(PO_ZIP):
                            r = requests.get(PO_URL)
                            with open(PO_ZIP, 'wb') as f:
                                f.write(r.content) 

                        with ZipFile(PO_ZIP, 'r') as zipObj:
                            exe = zipObj.read(PO_ZIP_EXE)
                            with open(PO_EXE,"wb") as e:
                                e.write(exe)
                                zipObj.close()
                                os.remove(PO_ZIP)
                    except:
                        raise Exception("Cannot find and or download/extract Potrace. Provide Potrace in script folder. ")
        return PO_EXE

It looks like there could be a way, but I have no idea how to do it - would it be possible to set steps to 40 when you activate this plugin?

some9000 commented 2 years ago

Managed to make a bunch of updates meanwhile. Decided not to edit previous post, but put them in here, since there are multiple changes...

"""
using POTRACE as backend cmd line tool for vectorizing SD output
This script will download from

https://potrace.sourceforge.net/#downloading

the windows exetuable (todo: mac, linux support)
Potrace is under GPL, you can download the source from the url above.

If you dont want to download that, please install POTRACE to your 
system manually and assign it to your PATH env variable properly.
"""

POSITIVE_PROMPT = ""
NEGATIVE_PROMPT = ""
PO_URL     = "https://potrace.sourceforge.net/download/1.16/potrace-1.16.win64.zip"
PO_ZIP     = "potrace.zip"
PO_ZIP_EXE = "potrace-1.16.win64/potrace.exe"
PO_EXE     = "scripts/potrace.exe"

##########################################################################

import os
import pathlib
import subprocess
from zipfile import ZipFile
import requests
import glob
import os.path
from sys import platform

import modules.scripts as scripts
import modules.images as Images
import gradio as gr

from modules.processing import Processed, process_images
from modules.shared import opts

class Script(scripts.Script):
    def title(self):
        return "Text to Vector Graphics"

    def ui(self, is_img2img):
        poUseColor = gr.Radio(["Illustration","Logo","Drawing","Artistic","Tattoo","Gothic","Anime","Cartoon"], label="Visual style", value="Illustration")
        poFormat = gr.Dropdown(["svg","pdf"], label="Output format", value="svg")
        poOpaque = gr.Checkbox(label="White is Opaque", value=True)
        poTight = gr.Checkbox(label="Cut white margin from input", value=True)
        poKeepPnm = gr.Checkbox(label="Keep temp images", value=False)
        poThreshold = gr.Slider(label="Threshold", minimum=0.0, maximum=1.0, step=0.05, value=0.5)

        return [poUseColor,poFormat, poOpaque, poTight, poKeepPnm, poThreshold]

    def run(self, p, poUseColor,poFormat, poOpaque, poTight, poKeepPnm, poThreshold):
        PO_TO_CALL = self.check_Potrace_install()

        p.do_not_save_grid = True

        # Select result type
        if poUseColor == "Illustration":
            POSITIVE_PROMPT = ",(((vector graphic))),medium detail"

        if poUseColor == "Logo":
            POSITIVE_PROMPT = ",(((centered vector graphic logo))),negative space,stencil,trending on dribbble"

        if poUseColor == "Drawing":
            POSITIVE_PROMPT = ",(((cartoon graphic))),childrens book,lineart,negative space" 

        if poUseColor == "Artistic":
            POSITIVE_PROMPT = ",(((artistic monochrome painting))),precise lineart,negative space"

        if poUseColor == "Tattoo":
            POSITIVE_PROMPT = ",(((tattoo ink on paper))),uniform lighting,lineart,negative space"

        if poUseColor == "Gothic":
            POSITIVE_PROMPT = ",(((gothic ink on paper))),H.P. Lovecraft,Arthur Rackham"

        if poUseColor == "Anime":
            POSITIVE_PROMPT = ",(((clean ink anime illustration))),Studio Ghibli,Makoto Shinkai,Hayao Miyazaki,Audrey Kawasaki"

        if poUseColor == "Cartoon":
            POSITIVE_PROMPT = ",(((clean ink funny comic cartoon illustration)))"

        # Add the prompt from above
        p.prompt += POSITIVE_PROMPT 
        # Add the selected settings 
        SETTING_PROMPT=",(((black on white))),((low detail)),(simple),no background,high contrast,sharp,2 bit"
        p.prompt += SETTING_PROMPT

        NEGATIVE_PROMPT = ",(((text))),((color)),(shading),noise,dithering,gradient,detailed,out of frame,ugly,error,Illustration"
        p.negative_prompt += NEGATIVE_PROMPT

        images = []
        proc = process_images(p)
        images += proc.images        

        # unfortunately the concrete file name is nontrivial using increment counter etc, so we have to reverse-guess the last stored images by changetime
        folder = p.outpath_samples

        if opts.save_to_dirs:
            folder = glob.glob(p.outpath_samples+"/*")
            folder = max(folder, key=os.path.getctime)

        files = glob.glob(folder+"/*."+opts.samples_format)
        # latest first
        files = sorted(files, key=os.path.getctime, reverse=True)

        try:
            # vectorize
            for i,img in enumerate(images[::-1]): 
                fullfn = files[i]
                fullofpnm = pathlib.Path(fullfn).with_suffix('.pnm')
                fullof = pathlib.Path(fullfn).with_suffix('.'+poFormat)

                img.save(fullofpnm)

                args = [PO_TO_CALL,  "-b", poFormat, "-o", fullof, "--blacklevel", format(poThreshold, 'f')]
                if poOpaque: args.append("--opaque")
                if poTight: args.append("--tight")
                args.append(fullofpnm)

                p2 = subprocess.Popen(args)

                if not poKeepPnm:
                    p2.wait()
                    os.remove(fullofpnm)

        except (Exception):
            raise Exception("TXT2Vectorgraphics: Execution of Potrace failed, check filesystem, permissions, installation or settings (is image saving on?)")

        return Processed(p, images, p.seed, "")

    def check_Potrace_install(self) -> str:
        # For Linux, run potrace from installed binary
        if platform == "darwin":
            try:
                # check whether already in PATH 
                checkPath = subprocess.Popen(["potrace","-v"])
                checkPath.wait()
                return "potrace"
            except (Exception):
                raise Exception("Cannot find installed Potrace on Mac. Please run `sudo apt install potrace`")

        elif platform == "linux"or platform == "linux2":
            try:
                # check whether already in PATH 
                checkPath = subprocess.Popen(["potrace","-v"])
                checkPath.wait()
                return "potrace"
            except (Exception):
                raise Exception("Cannot find installed Potrace. Please run `sudo apt install '  `")

        # prefer local '   over that from PATH
        elif platform == "win32":
            if not os.path.exists(PO_EXE):
                try:
                    # check whether already in PATH 
                    checkPath = subprocess.Popen(["'  ","-v"])
                    checkPath.wait()
                    return "'  "

                except (Exception):
                    try:
                        # try to download Potrace and unzip locally into "scripts"
                        if not os.path.exists(PO_ZIP):
                            r = requests.get(PO_URL)
                            with open(PO_ZIP, 'wb') as f:
                                f.write(r.content) 

                        with ZipFile(PO_ZIP, 'r') as zipObj:
                            exe = zipObj.read(PO_ZIP_EXE)
                            with open(PO_EXE,"wb") as e:
                                e.write(exe)
                                zipObj.close()
                                os.remove(PO_ZIP)
                    except:
                        raise Exception("Cannot find and or download/extract Potrace. Provide Potrace in script folder. ")
        return PO_EXE
GeorgLegato commented 2 years ago

thx, merged. closing

some9000 commented 2 years ago

Neat. More to learn. Intend to use this to prepare some simple styles, like cartoon, painting, etc. To avoid always assembling tags. But, maybe you could tell me, if it is possible to change Sampling steps from a script like this?

GeorgLegato commented 2 years ago

there is the Processing variable "p" in the beginning of Run-Method. It contains all parameter like seed and strength, cfg. You can easily tune in your params. but ther user should know about that in some way

Z4urce commented 1 year ago

Fresh install, same issue.

GeorgLegato commented 1 year ago

Please dont use this script anymore. the code base of SD-Webui is changing these days rapidly. Use instead the VectorStudio extension instead. it is easier to install and will provide more feature, for example a build in SVG-Editor, changing background of SVG-views... more will come Goto ExtensionTab in Webui and select "VectorStudio" to install. Have your potrace-executable in extensionfolder/bin (if on linux same potrace.exe there, at least as softlink,)

xDepredadorxD commented 1 year ago

https://potrace.sourceforge.net/#downloading cópielo donde potrace.exe me funciono en el 1111

Si estás instalando desde el código fuente, simplemente haz "make install" como root. Si está instalando desde una distribución binaria, simplemente copie los binarios binarios "potrace" y "mkbitmap" en un lugar donde el sistema como /usr/local/bin. Copie también los archivos "potrace.1" y "mkbitmap.1" a un directorio donde el sistema operativo busque páginas man, como /usr/local/man/man1. En instrucciones para instalar Potrace en Windows, consulte el archivo README-WIN

Traducción realizada con la versión gratuita del traductor www.DeepL.com/Translator