From 93e3bf9335ec79270733f382d3a1d011dd429d3d Mon Sep 17 00:00:00 2001 From: qaq_fei Date: Fri, 25 Oct 2024 20:53:26 +0800 Subject: [PATCH] --- .github/workflows/ppr-build.yml | 26 +++++ src/phicore.py | 30 +++--- src/phigame_obj.py | 14 +-- requirements.txt => src/requirements.txt | 0 src/resources/{Start.png => le_warn.png} | Bin src/tool-compile.py | 27 ++++- src/tool_funcs.py | 2 +- src/web_canvas.html | 60 +---------- src/webcv.py | 122 ++++++++++------------- 9 files changed, 124 insertions(+), 157 deletions(-) create mode 100644 .github/workflows/ppr-build.yml rename requirements.txt => src/requirements.txt (100%) rename src/resources/{Start.png => le_warn.png} (100%) diff --git a/.github/workflows/ppr-build.yml b/.github/workflows/ppr-build.yml new file mode 100644 index 0000000..d29c289 --- /dev/null +++ b/.github/workflows/ppr-build.yml @@ -0,0 +1,26 @@ +name: PhigrosPlayer Auto Build + +on: + push: + branches: [ "main" ] + +jobs: + build: + runs-on: windows-latest + steps: + - uses: actions/checkout@v4 + + - name: py3.12 + uses: actions/setup-python@v3 + with: + python-version: 3.12 + + - name: build + run: | + cd src + python tool-compile.py -y --zip + + - name: upload + uses: actions/upload-artifact@v4 + with: + path: ${{ github.workspace }}/compile_result.zip \ No newline at end of file diff --git a/src/phicore.py b/src/phicore.py index 9bdb9a3..a819b94 100644 --- a/src/phicore.py +++ b/src/phicore.py @@ -717,7 +717,7 @@ def draw_ui( root.run_js_code( f"ctx.drawUIText(\ - '{root.process_code_string_syntax_tostring(score)}',\ + '{root.string2cstring(score)}',\ {w * 0.988 + scoreUI_dx},\ {h * (58 / 1080) + scoreUI_dy},\ {scoreUI_rotate},\ @@ -733,7 +733,7 @@ def draw_ui( if rtacc: root.run_js_code( f"ctx.drawUIText(\ - '{root.process_code_string_syntax_tostring(acc)}',\ + '{root.string2cstring(acc)}',\ {w * 0.988 + scoreUI_dx},\ {h * (58 / 1080) + (w + h) / 145 / 0.75 * 1.5 + scoreUI_dy},\ {scoreUI_rotate},\ @@ -749,7 +749,7 @@ def draw_ui( if combo_state: root.run_js_code( f"ctx.drawUIText(\ - '{root.process_code_string_syntax_tostring(f"{combo}")}',\ + '{root.string2cstring(f"{combo}")}',\ {w / 2 + combonumberUI_dx},\ {h * 0.05 + combonumberUI_dy},\ {combonumberUI_rotate},\ @@ -764,7 +764,7 @@ def draw_ui( root.run_js_code( f"ctx.drawUIText(\ - '{root.process_code_string_syntax_tostring(combotips)}',\ + '{root.string2cstring(combotips)}',\ {w / 2 + comboUI_dx},\ {h * 0.095 + comboUI_dy},\ {comboUI_rotate},\ @@ -794,7 +794,7 @@ def draw_ui( root.run_js_code( f"ctx.drawUIText(\ - '{root.process_code_string_syntax_tostring(chart_information["Name"])}',\ + '{root.string2cstring(chart_information["Name"])}',\ {w * 0.0125 + nameUI_dx},\ {h * 0.976 - (w + h) / 125 / 0.75 / 2 + nameUI_dy},\ {nameUI_rotate},\ @@ -809,7 +809,7 @@ def draw_ui( root.run_js_code( f"ctx.drawUIText(\ - '{root.process_code_string_syntax_tostring(chart_information["Level"])}',\ + '{root.string2cstring(chart_information["Level"])}',\ {w * 0.9875 + levelUI_dx},\ {h * 0.976 - (w + h) / 125 / 0.75 / 2 + levelUI_dy},\ {levelUI_rotate},\ @@ -1366,7 +1366,7 @@ def GetFrameRenderTask_Rpe(now_t:float, clear: bool = True, rjc: bool = True): Task( root.run_js_code, f"ctx.drawRotateText(\ - '{root.process_code_string_syntax_tostring(lineText)}',\ + '{root.string2cstring(lineText)}',\ {linePos[0]},\ {linePos[1]},\ {lineRotate},\ @@ -1949,19 +1949,19 @@ def Begin_Animation(clear: bool = True, fcb: typing.Callable[[], typing.Any] = l animation_time = 4.5 chart_name_text = chart_information["Name"] - chart_name_text_width_1px = root.run_js_code(f"ctx.font='50px PhigrosFont'; ctx.measureText({root.process_code_string_syntax_tocode(chart_name_text)}).width;") / 50 + chart_name_text_width_1px = root.run_js_code(f"ctx.font='50px PhigrosFont'; ctx.measureText({root.string2sctring_hqm(chart_name_text)}).width;") / 50 chart_level_number = Get_LevelNumber() - chart_level_number_width_1px = root.run_js_code(f"ctx.font='50px PhigrosFont'; ctx.measureText({root.process_code_string_syntax_tocode(chart_level_number) if len(chart_level_number) >= 2 else "'00'"}).width;") / 50 + chart_level_number_width_1px = root.run_js_code(f"ctx.font='50px PhigrosFont'; ctx.measureText({root.string2sctring_hqm(chart_level_number) if len(chart_level_number) >= 2 else "'00'"}).width;") / 50 if len(chart_level_number) == 1: chart_level_number_width_1px /= 1.35 chart_level_text = Get_LevelText() - chart_level_text_width_1px = root.run_js_code(f"ctx.font='50px PhigrosFont'; ctx.measureText({root.process_code_string_syntax_tocode(chart_level_text) if len(chart_level_text) >= 2 else "'00'"}).width;") / 50 + chart_level_text_width_1px = root.run_js_code(f"ctx.font='50px PhigrosFont'; ctx.measureText({root.string2sctring_hqm(chart_level_text) if len(chart_level_text) >= 2 else "'00'"}).width;") / 50 chart_artist_text = chart_information["Artist"] - chart_artist_text_width_1px = root.run_js_code(f"ctx.font='50px PhigrosFont'; ctx.measureText({root.process_code_string_syntax_tocode(chart_artist_text)}).width;") / 50 + chart_artist_text_width_1px = root.run_js_code(f"ctx.font='50px PhigrosFont'; ctx.measureText({root.string2sctring_hqm(chart_artist_text)}).width;") / 50 chart_charter_text = chart_information["Charter"] - chart_charter_text_width_1px = root.run_js_code(f"ctx.font='50px PhigrosFont'; ctx.measureText({root.process_code_string_syntax_tocode(chart_charter_text)}).width;") / 50 + chart_charter_text_width_1px = root.run_js_code(f"ctx.font='50px PhigrosFont'; ctx.measureText({root.string2sctring_hqm(chart_charter_text)}).width;") / 50 chart_illustrator_text = chart_information["Illustrator"] - chart_illustrator_text_width_1px = root.run_js_code(f"ctx.font='50px PhigrosFont'; ctx.measureText({root.process_code_string_syntax_tocode(chart_illustrator_text)}).width;") / 50 + chart_illustrator_text_width_1px = root.run_js_code(f"ctx.font='50px PhigrosFont'; ctx.measureText({root.string2sctring_hqm(chart_illustrator_text)}).width;") / 50 tip = phi_tips.get_tip() tip_font_size = w * 0.020833 / 1.25 infoframe_x = w * 0.095 @@ -2053,9 +2053,9 @@ def initFinishAnimation(): MaxCombo = chart_obj.note_num if not noautoplay else PhigrosPlayManagerObject.getMaxCombo() AccString = f"{(Acc * 100):.2f}%" ChartNameString = chart_information["Name"] - ChartNameStringFontSize = w * im_size * 0.65 / (root.run_js_code(f"ctx.font='50px PhigrosFont'; ctx.measureText({root.process_code_string_syntax_tocode(ChartNameString)}).width;") / 50) + ChartNameStringFontSize = w * im_size * 0.65 / (root.run_js_code(f"ctx.font='50px PhigrosFont'; ctx.measureText({root.string2sctring_hqm(ChartNameString)}).width;") / 50) ChartLevelString = chart_information["Level"] - ChartLevelStringFontSize = w * im_size * 0.25 / (root.run_js_code(f"ctx.font='50px PhigrosFont'; ctx.measureText({root.process_code_string_syntax_tocode(ChartLevelString)}).width;") / 50) + ChartLevelStringFontSize = w * im_size * 0.25 / (root.run_js_code(f"ctx.font='50px PhigrosFont'; ctx.measureText({root.string2sctring_hqm(ChartLevelString)}).width;") / 50) if ChartNameStringFontSize > w * 0.0275: ChartNameStringFontSize = w * 0.0275 if ChartLevelStringFontSize > w * 0.0275 * 0.5: diff --git a/src/phigame_obj.py b/src/phigame_obj.py index a9e7599..efbe5c3 100644 --- a/src/phigame_obj.py +++ b/src/phigame_obj.py @@ -200,7 +200,7 @@ def getBarWidth(self): st = self.aSTime et = self.aSTime + self.atime p = (time.time() - st) / (et - st) - p = tool_funcs.fixOutofRangeP(p) + p = tool_funcs.fixorp(p) p = self._ease_slow(p) return p * (ev - sv) + sv @@ -212,7 +212,7 @@ def getLabelWidth(self): st = self.aSTime et = self.aSTime + self.atime p = (time.time() - st) / (et - st) - p = tool_funcs.fixOutofRangeP(p) + p = tool_funcs.fixorp(p) p = self._ease_fast(p) return p * (ev - sv) + sv @@ -224,7 +224,7 @@ def getLabelX(self): st = self.aSTime et = self.aSTime + self.atime p = (time.time() - st) / (et - st) - p = tool_funcs.fixOutofRangeP(p) + p = tool_funcs.fixorp(p) p = self._ease_slow(p) return p * (ev - sv) + sv @@ -243,7 +243,7 @@ def getTextColor(self, t: int): st = self.aSTime et = self.aSTime + self.atime p = (time.time() - st) / (et - st) - p = tool_funcs.fixOutofRangeP(p) + p = tool_funcs.fixorp(p) # 这里奇怪的算法: 为了视觉上好看和还原一点 absv = abs(self.aFrom - self.aTo) if self.aFrom != self.aTo else 1.0 @@ -265,7 +265,7 @@ def getTextScale(self, t: int): st = self.aSTime et = self.aSTime + self.atime p = (time.time() - st) / (et - st) - p = tool_funcs.fixOutofRangeP(p) + p = tool_funcs.fixorp(p) p = self._ease_slow(p) return tool_funcs.linear_interpolation(p, 0.0, 1.0, 1.175, 1.0) if self.aFrom == t else tool_funcs.linear_interpolation(p, 0.0, 1.0, 1.0, 1.175) @@ -278,7 +278,7 @@ def getShadowRect(self): st = self.aSTime et = self.aSTime + self.atime p = (time.time() - st) / (et - st) - p = tool_funcs.fixOutofRangeP(p) + p = tool_funcs.fixorp(p) p = self._ease_slow(p) return ( p * (ev[0] - sv[0]) + sv[0], @@ -308,7 +308,7 @@ def render( st = self.aSTime et = self.aSTime + self.atime p = (time.time() - st) / (et - st) if self.aSTime != float("-inf") else 1.0 - p = tool_funcs.fixOutofRangeP(p) + p = tool_funcs.fixorp(p) p = self._ease_slow(p) drawPlaySettingDx = self.getSettingDx(shadowRectLeft, w, const.PHIGROS_SETTING_STATE.PLAY) diff --git a/requirements.txt b/src/requirements.txt similarity index 100% rename from requirements.txt rename to src/requirements.txt diff --git a/src/resources/Start.png b/src/resources/le_warn.png similarity index 100% rename from src/resources/Start.png rename to src/resources/le_warn.png diff --git a/src/tool-compile.py b/src/tool-compile.py index 3c60b83..d344713 100644 --- a/src/tool-compile.py +++ b/src/tool-compile.py @@ -1,11 +1,14 @@ from threading import Thread -from os import system +from os import system, mkdir +from os.path import isfile from sys import argv +from shutil import copy, copytree system("cls") -if input("Sure? (y/n) ").lower() not in ("yes", "y"): - raise SystemExit +if "-y" not in argv: + if input("Sure? (y/n) ").lower() not in ("yes", "y"): + raise SystemExit def compile(file:str, hideconsole:bool): system(f"{pyi_makespec} \"{file}\" -i icon.ico {"-w" if hideconsole and not debug else ""}") @@ -23,6 +26,13 @@ def compile(file:str, hideconsole:bool): ("gui_launcher.py", False), ("phigros.py", False) ] +res_files = [ + "_internal", + "web_canvas.html", + "7z.exe", "7z.dll", + "ecwv_installer.exe", + "resources", "shaders" +] extend = open("_compile_pyiextend.py", "r", encoding="utf-8").read() system("python -m venv compile_venv") @@ -49,5 +59,16 @@ def compile(file:str, hideconsole:bool): system("rmdir .\\compile_venv /s /q") system("rmdir .\\build /s /q") system("rmdir .\\dist /s /q") + +if "--zip" in argv: + _copy = lambda src, tar: copy(src, tar) if isfile(src) else copytree(src, f"{tar}\\{src}") + try: mkdir(".\\compile_result") + except FileExistsError: pass + for i, _ in compile_files: + _copy(i.replace(".py", ".exe"), ".\\compile_result") + for i in res_files: + _copy(i, ".\\compile_result") + system("7z a compile_result.zip .\\compile_result\\*") + print("\nCompile complete!") system("pause") \ No newline at end of file diff --git a/src/tool_funcs.py b/src/tool_funcs.py index d3d767b..c55419d 100644 --- a/src/tool_funcs.py +++ b/src/tool_funcs.py @@ -304,7 +304,7 @@ def compute_intersection(x0, y0, x1, y1, x2, y2, x3, y3): c2 = x3 * y2 - x2 * y3 return (b2 * c1 - b1 * c2) / (a1 * b2 - a2 * b1), (a1 * c2 - a2 * c1) / (a1 * b2 - a2 * b1) -def fixOutofRangeP(p: float): +def fixorp(p: float): return max(0.0, min(1.0, p)) def PhigrosChapterNameAlphaValueTransfrom(p: float): diff --git a/src/web_canvas.html b/src/web_canvas.html index 21a7365..49d1ee7 100644 --- a/src/web_canvas.html +++ b/src/web_canvas.html @@ -25,17 +25,6 @@ background-color: black; } - .ppr-start { - position: absolute; - left: 0; - top: 0; - width: 100%; - height: 100%; - z-index: 2; - opacity: 0.0; - -webkit-user-drag: none; - } - .main-canvas { z-index: 1; left: 0; @@ -80,7 +69,7 @@ ctx = canvas_ele.getContext("2d", {willReadFrequently: true, alpha: false}); dialog_canvas_ctx = dialog_canvas_ele.getContext("2d"); gl = glcanvas.getContext("webgl"); - JavaScript_WaitToExecute_CodeArray = new Array(); + jscodes = new Array(); resize_task = false; lfdaot_render_fcount = 0; render_range_more = false; @@ -139,53 +128,6 @@ // ctx.scale(window.devicePixelRatio, window.devicePixelRatio); } - function process_jswteca() { - for(var i=0;i 1.0) { - change_color_block_opacity(1.0); - return; - } - change_color_block_opacity(ease_number); - setTimeout(() => show_in_animation(false,start_time),1000 / 60); - } - else{ - show_in_animation(false,new Date().getTime() / 1000); - } - } - - function show_out_animation(first_call = true,start_time = 0.0) { - if (!first_call){ - process = (new Date().getTime() / 1000 - start_time) / 1.25; - ease_number = ease_out(process); - if (process > 1.0) { - change_color_block_opacity(0.0); - return; - } - change_color_block_opacity(1.0 - ease_number); - setTimeout(() => show_out_animation(false,start_time),1000 / 60); - } - else{ - show_out_animation(false,new Date().getTime() / 1000); - } - } - function loadFont(family, url) { var font = new FontFace(family, `url(${url})`); font.load().then((rfont) => { diff --git a/src/webcv.py b/src/webcv.py index 70d439b..228fd10 100644 --- a/src/webcv.py +++ b/src/webcv.py @@ -20,7 +20,7 @@ class WebCanvas_FileServerHandler(http.server.BaseHTTPRequestHandler): _canvas: WebCanvas - + def do_GET(self): self.send_response(200) self.send_header("Content-type", "image/png") @@ -28,6 +28,7 @@ def do_GET(self): self.send_header("Access-Control-Allow-Methods", "*") self.send_header("Access-Control-Allow-Headers", "Authorization, Content-Type") self.end_headers() + if self.path[1:] in self._canvas._regims: im:Image.Image = self._canvas._regims[self.path[1:]] temp_btyeio = io.BytesIO() @@ -36,14 +37,12 @@ def do_GET(self): elif self.path[1:] in self._canvas._regres: data:bytes = self._canvas._regres[self.path[1:]] self.wfile.write(data) - else: - self.wfile.write(bytes()) def log_request(self, *args, **kwargs) -> None: ... class JsApi: def __init__(self) -> None: - self.things:dict[str, typing.Any] = {} + self.things: dict[str, typing.Any] = {} def get_thing(self, name: str): return self.things[name] @@ -79,51 +78,59 @@ def __init__( html_path: str = ".\\web_canvas.html" ): self.jsapi = JsApi() - self._web = webview.create_window( + self.web = webview.create_window( title = title, url = abspath(html_path), resizable = resizable, js_api = self.jsapi, frameless = frameless ) - self._web_init_var = { - "width": width, - "height": height, - "x": x, - "y": y - } self._destroyed = threading.Event() - self.debug = debug self._regims: dict[str, Image.Image] = {} self._regres: dict[str, bytes] = {} self._is_loadimg: dict[str, bool] = {} - self._JavaScript_WaitToExecute_CodeArray: list[str] = [] - threading.Thread(target=webview.start, kwargs={"debug": self.debug}, daemon=True).start() - self._init() + self._jscodes: list[str] = [] + threading.Thread(target=webview.start, kwargs={"debug": debug}, daemon=True).start() + + self.web.resize(width, height) + self.web.move(x, y) + self.web.events.closed += self._destroyed.set + + title = self.web.title + temp_title = self.web.title + " " * randint(0, 4096) + self.web.set_title(temp_title) + + self.web_hwnd = 0 + while not self.web_hwnd: + self.web_hwnd = windll.user32.FindWindowW(None, temp_title) + time.sleep(0.01) + self.web.set_title(title) + + self.web_port = int(self.web._server.address.split(":")[2].split("/")[0]) + WebCanvas_FileServerHandler._canvas = self + self.file_server = http.server.HTTPServer(("localhost", self.web_port + 1), WebCanvas_FileServerHandler) + threading.Thread(target=self.file_server.serve_forever, daemon=True).start() - def title(self, title: str) -> str: self._web.set_title(title) + def title(self, title: str) -> str: self.web.set_title(title) def winfo_screenwidth(self) -> int: return screen_width def winfo_screenheight(self) -> int: return screen_height - def winfo_hwnd(self) -> int: return self._web_hwnd - def winfo_legacywindowwidth(self) -> int: return self._web.evaluate_js("window.innerWidth;") - def winfo_legacywindowheight(self) -> int: return self._web.evaluate_js("window.innerHeight;") + def winfo_hwnd(self) -> int: return self.web_hwnd + def winfo_legacywindowwidth(self) -> int: return self.web.evaluate_js("window.innerWidth;") + def winfo_legacywindowheight(self) -> int: return self.web.evaluate_js("window.innerHeight;") - def destroy(self): self._web.destroy() - def resize(self, width: int, height: int): self._web.resize(width, height) - def move(self, x: int, y:int): self._web.move(x, y) + def destroy(self): self.web.destroy() + def resize(self, width: int, height: int): self.web.resize(width, height) + def move(self, x: int, y:int): self.web.move(x, y) def run_js_code(self, code: str, add_code_array: bool = False): - return self._JavaScript_WaitToExecute_CodeArray.append(code) if add_code_array else self._web.evaluate_js(code) + return self._jscodes.append(code) if add_code_array else self.web.evaluate_js(code) def run_js_wait_code(self): - self._web.evaluate_js(f"JavaScript_WaitToExecute_CodeArray = {self._JavaScript_WaitToExecute_CodeArray}; process_jswteca();") - self._JavaScript_WaitToExecute_CodeArray.clear() + self.web.evaluate_js(f"{self._jscodes}.forEach(eval);") + self._jscodes.clear() - def process_code_string_syntax_tostring(self, code: str): - return code.replace("\\", "\\\\").replace("'", "\\'").replace("\"", "\\\"").replace("`", "\\`").replace("\n", "\\n") - - def process_code_string_syntax_tocode(self, code: str): - return f"'{self.process_code_string_syntax_tostring(code)}'" + def string2cstring(self, code: str): return code.replace("\\", "\\\\").replace("'", "\\'").replace("\"", "\\\"").replace("`", "\\`").replace("\n", "\\n") + def string2sctring_hqm(self, code: str): return f"'{self.string2cstring(code)}'" def create_rectangle( self, @@ -176,7 +183,7 @@ def create_text( method: typing.Literal["fill", "stroke"] = "fill", wait_execute: bool = False ) -> None: - text = self.process_code_string_syntax_tocode(text) + text = self.string2sctring_hqm(text) self.run_js_code(f"ctx.save(); ctx.font = \"{font}\"; ctx.textAlign = \"{textAlign}\"; ctx.textBaseline = \"{textBaseline}\"; ctx.fillStyle = \"{fillStyle}\"; ctx.strokeStyle = \"{strokeStyle}\"; ctx.{method}Text({text},{x},{y}); ctx.restore();", wait_execute) def create_polygon( @@ -217,70 +224,41 @@ def clear_rectangle( def clear_canvas(self, wait_execute: bool = False) -> None: self.run_js_code("ctx.clear();", wait_execute) - def get_img_jsvarname(self, imname:str): + def get_img_jsvarname(self, imname: str): return f"{imname}_img" - def reg_img(self, im:Image.Image, name:str) -> None: + def reg_img(self, im: Image.Image, name: str) -> None: self._regims[name] = im self._is_loadimg[name] = False - def reg_res(self, res_data:bytes, name:str) -> None: + def reg_res(self, res_data: bytes, name: str) -> None: self._regres[name] = res_data def load_allimg(self) -> None: + complete_code = f"[{",".join([f"{self.get_img_jsvarname(item)}.complete" for item in self._regims])}]" for imgname in self._regims: self._load_img(imgname) - while True: - complete_list = self.run_js_code(f"[{",".join([f"{self.get_img_jsvarname(item)}.complete" for item in self._regims])}]") - if all(complete_list): break - time.sleep(0.2) + while not all(self.run_js_code(complete_code)): + time.sleep(0.01) def reg_event(self, name: str, callback: typing.Callable) -> None: - setattr(self._web.events, name, getattr(self._web.events, name) + callback) + setattr(self.web.events, name, getattr(self.web.events, name) + callback) def wait_for_close(self) -> None: self._destroyed.wait() - def shutdown_fileserver(self) -> None: - self._file_server.shutdown() - - def get_resource_path(self, name:str) -> str: - return f"http://127.0.0.1:{self._web_port + 1}/{name}" + def get_resource_path(self, name: str) -> str: + return f"http://127.0.0.1:{self.web_port + 1}/{name}" - def _closed_callback(self) -> None: - self._destroyed.set() - - def _load_img(self, imgname:str) -> None: + def _load_img(self, imgname: str) -> None: jsvarname = self.get_img_jsvarname(imgname) code = f"\ if (!window.{jsvarname}){chr(123)}\ {jsvarname} = document.createElement('img');\ {jsvarname}.crossOrigin = \"Anonymous\";\ - {jsvarname}.src = 'http://127.0.0.1:{self._web_port + 1}/{imgname}';\ + {jsvarname}.src = 'http://127.0.0.1:{self.web_port + 1}/{imgname}';\ {jsvarname}.loading = \"eager\";\ {chr(125)}\ " self.run_js_code(code) - self._is_loadimg[imgname] = True - - def _init( - self - ) -> None: - self._web.resize(self._web_init_var["width"], self._web_init_var["height"]) - self._web.move(self._web_init_var["x"], self._web_init_var["y"]) - self._web_init_var.clear() - self._web.events.closed += self._closed_callback - - title = self._web.title - temp_title = self._web.title + " " * randint(0, 4096) - self._web.set_title(temp_title) - while True: - self._web_hwnd = windll.user32.FindWindowW(None, temp_title) - if self._web_hwnd: - break - self._web.set_title(title) - - self._web_port = int(self._web._server.address.split(":")[2].split("/")[0]) - WebCanvas_FileServerHandler._canvas = self - self._file_server = http.server.HTTPServer(("localhost", self._web_port + 1), WebCanvas_FileServerHandler) - threading.Thread(target=self._file_server.serve_forever, daemon=True).start() \ No newline at end of file + self._is_loadimg[imgname] = True \ No newline at end of file