diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9f50a9f..df827c2 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -87,7 +87,7 @@ jobs: asset_name: conduct.exe asset_content_type: application/octet-stream - release-integrations: + release-blender-integration: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 @@ -107,4 +107,26 @@ jobs: upload_url: ${{ github.event.release.upload_url }} asset_path: integration/conduct-blender.zip asset_name: conduct-blender.zip - asset_content_type: application/zip \ No newline at end of file + asset_content_type: application/zip + + release-inkscape-integration: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Zip Inkscape Integration + run: | + cd integration + mv inkscape conduct-inkscape + zip -r conduct-inkscape.zip conduct-inkscape + + - name: Upload to release + if: github.event_name == 'release' + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ github.event.release.upload_url }} + asset_path: integration/conduct-inkscape.zip + asset_name: conduct-inkscape.zip + asset_content_type: application/zip diff --git a/example/basic/manifest.yaml b/example/basic/manifest.yaml index 148a08a..be4d493 100644 --- a/example/basic/manifest.yaml +++ b/example/basic/manifest.yaml @@ -12,6 +12,10 @@ programs: .glb: import_glb_mesh.py .shadergraph.blend: import_blend_shadergraph.py .mesh.blend: import_blend_library_mesh.py + inkscape: + exports: + .png: export_png_512.py + .2x.png: export_png_1024.py departments: anim: @@ -72,6 +76,13 @@ assets: departments: layout: - !depends(defaultCubeA;defaultCubeB) cubeInstancer + 2d: + icons: + - iconA: + departments: + design: + - vector + - 2x shots: '103': diff --git a/example/basic/scripts/inkscape/export_png_1024.py b/example/basic/scripts/inkscape/export_png_1024.py new file mode 100644 index 0000000..f4f613a --- /dev/null +++ b/example/basic/scripts/inkscape/export_png_1024.py @@ -0,0 +1,33 @@ + +class InkscapeDataExport(): + + def log(self, object): + import inkex + inkex.utils.debug(object) + + def export(self, effect_context, directory=None, file_name=None, extension=None, items=None, ): + from tempfile import TemporaryDirectory + import inkex + import os + + with TemporaryDirectory(prefix='inkscape-command-') as tmpdir: + + svg_file = inkex.command.write_svg(effect_context.svg, tmpdir, 'input.svg') + output = os.path.join(directory, file_name + extension) + + pages = effect_context.svg.namedview.get_pages() + index = pages.index(items[0]) + + page = items[0] + + height = 1024 + ratio = page.width / page.height + width = round(ratio * height) + + out = inkex.command.inkscape(svg_file, + "--export-filename=%s" % output, + '--export-type=png', + '--export-width=%d' % width, + '--export-height=%d' % height, + '--export-page=%d' % (index + 1)) + \ No newline at end of file diff --git a/example/basic/scripts/inkscape/export_png_512.py b/example/basic/scripts/inkscape/export_png_512.py new file mode 100644 index 0000000..4a6c8fc --- /dev/null +++ b/example/basic/scripts/inkscape/export_png_512.py @@ -0,0 +1,33 @@ + +class InkscapeDataExport(): + + def log(self, object): + import inkex + inkex.utils.debug(object) + + def export(self, effect_context, directory=None, file_name=None, extension=None, items=None, ): + from tempfile import TemporaryDirectory + import inkex + import os + + with TemporaryDirectory(prefix='inkscape-command-') as tmpdir: + + svg_file = inkex.command.write_svg(effect_context.svg, tmpdir, 'input.svg') + output = os.path.join(directory, file_name + extension) + + pages = effect_context.svg.namedview.get_pages() + index = pages.index(items[0]) + + page = items[0] + + height = 512 + ratio = page.width / page.height + width = round(ratio * height) + + out = inkex.command.inkscape(svg_file, + "--export-filename=%s" % output, + '--export-type=png', + '--export-width=%d' % width, + '--export-height=%d' % height, + '--export-page=%d' % (index + 1)) + \ No newline at end of file diff --git a/example/basic/setup/asset/design/iconA/iconA_design.svg b/example/basic/setup/asset/design/iconA/iconA_design.svg new file mode 100644 index 0000000..351257e --- /dev/null +++ b/example/basic/setup/asset/design/iconA/iconA_design.svg @@ -0,0 +1,165 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/integration/common/conduct.py b/integration/common/conduct.py index 15d67ac..70b864f 100644 --- a/integration/common/conduct.py +++ b/integration/common/conduct.py @@ -4,6 +4,9 @@ import subprocess import json +def log(info): + print(info) + class Conduct: conduct_exe = "" current_program = "" @@ -24,12 +27,13 @@ def run_process(self, args): startupinfo.dwFlags = subprocess.CREATE_NO_WINDOW creation_flags = subprocess.CREATE_NO_WINDOW - print("Executing: " + str(args)) + log("Executing: " + str(args)) - process=subprocess.Popen(args, cwd=os.path.dirname(self.conduct_exe), startupinfo=startupinfo, stdout=subprocess.PIPE, encoding='utf-8', creationflags=creation_flags) + process=subprocess.Popen(args, cwd=os.path.dirname(self.conduct_exe), startupinfo=startupinfo, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, encoding='utf-8', creationflags=creation_flags) data = process.communicate()[0] - print(data) + + log(data) return json.loads(data) @@ -53,6 +57,18 @@ def dialog_load_asset(self, department, shot=None, asset=None ): return self.run_process(args) + def dialog_export(self, department, asset, items, prev_state=None, shot=None, ): + args = ["dialog", "export", "--", "--program", self.current_program, "--department", department, "--asset", asset, "--items", items ] + if shot != None and shot != "": + args.append("--shot") + args.append(shot) + + if prev_state != None and prev_state != "": + args.append("--prev-state") + args.append(prev_state) + + return self.run_process(args) + def list_export_formats(self, department): return self.run_process(["list-export-formats", "--from", self.current_program, "--department", department]) @@ -65,7 +81,7 @@ def export(self, department, format, asset, element, shot=None): return self.run_process(args) def get_from_manifest_path(manifest_path, current_program): - print("Getting exe from manifest path: " + manifest_path) + log("Getting exe from manifest path: " + manifest_path) dir_path = os.path.dirname(manifest_path) exe = "conduct" @@ -76,7 +92,7 @@ def get_from_manifest_path(manifest_path, current_program): return Conduct(path, current_program) def find_from_current_path(current_file, current_program): - print("Looking for conduct path for file: " + current_file) + log("Looking for conduct path for file: " + current_file) path = os.path.dirname(current_file) while path != "": checks = [ @@ -86,7 +102,7 @@ def find_from_current_path(current_file, current_program): for check in checks: if os.path.isfile(check): - print("found:" + check) + log("found:" + check) return get_from_manifest_path(check, current_program) path = os.path.dirname(path) diff --git a/integration/inkscape/conduct b/integration/inkscape/conduct new file mode 120000 index 0000000..8332399 --- /dev/null +++ b/integration/inkscape/conduct @@ -0,0 +1 @@ +../common/ \ No newline at end of file diff --git a/integration/inkscape/conduct_create_setup.inx b/integration/inkscape/conduct_create_setup.inx new file mode 100644 index 0000000..fbd9261 --- /dev/null +++ b/integration/inkscape/conduct_create_setup.inx @@ -0,0 +1,15 @@ + + + Create Setup + com.lagmachine.conduct.create_setup + + + all + + + + + + \ No newline at end of file diff --git a/integration/inkscape/conduct_create_setup.py b/integration/inkscape/conduct_create_setup.py new file mode 100644 index 0000000..277e1df --- /dev/null +++ b/integration/inkscape/conduct_create_setup.py @@ -0,0 +1,58 @@ +import inkex +from inkex import command +import os +from conduct import conduct +import subprocess + +def log_stub(info): + pass + +def log(info): + inkex.utils.debug(info) + +class ConductCreateSetup(inkex.EffectExtension): + + def add_arguments(self, pars): + pars.add_argument("-m", "--manifest", default="", help="Manifest File Path") + + + def effect(self): + manifest_path = self.options.manifest + conduct.log = log_stub + c = conduct.get_from_manifest_path(manifest_path, "inkscape") + result = c.setup('.svg') + + if result['result'] != 'ok': + return + + dialog_data = result['data'] + + self.svg.set("com.lagmachine.conduct.asset", dialog_data['asset']) + self.svg.set("com.lagmachine.conduct.department", dialog_data['department']) + if dialog_data['shot'] is not None: + self.svg.set("com.lagmachine.conduct.shot", dialog_data['shot']) + + # write to new file, and open it in a new instance of inkscape + # this is the best i can do, there is no function for changing the current file to a different location + data = self.svg.tostring().decode('utf-8') + + path = dialog_data['path'] + with open(path, mode='w') as f: + f.write(data) + + exe = inkex.command.which('inkscape') + + if(exe.startswith('/tmp/.mount')): + log("Detected running in an AppImage, this process will hang until the new instance is closed!") + inkex.command.inkscape(path) + return + + #if we could find a good way to kill the original inkscape instance after starting the new one, that would be ideal + if os.name == 'nt': + creation_flags = subprocess.CREATE_NEW_PROCESS_GROUP | subprocess.DETACHED_PROCESS + proc = subprocess.Popen([exe, path], creationflags=creation_flags, start_new_session=True) + else: + proc = subprocess.Popen([exe, path], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, stdin=subprocess.DEVNULL) + +if __name__ == '__main__': + ConductCreateSetup().run() \ No newline at end of file diff --git a/integration/inkscape/conduct_export.inx b/integration/inkscape/conduct_export.inx new file mode 100644 index 0000000..8f1a0f6 --- /dev/null +++ b/integration/inkscape/conduct_export.inx @@ -0,0 +1,14 @@ + + + Export + com.lagmachine.conduct.export + + all + + + + + + \ No newline at end of file diff --git a/integration/inkscape/conduct_export.py b/integration/inkscape/conduct_export.py new file mode 100644 index 0000000..cfda649 --- /dev/null +++ b/integration/inkscape/conduct_export.py @@ -0,0 +1,77 @@ +import inkex +from inkex import command +import os +from conduct import conduct +import subprocess +import json +import inspect + +def log_stub(info): + pass + +def log(info): + inkex.utils.debug(info) + +class SvgReader(inkex.extensions.InputExtension): + pass + +class ConductExportEffect(inkex.EffectExtension): + + def effect(self): + conduct.log = log_stub + + file_path = os.path.join(self.svg_path(), self.svg.name) + department = self.svg.get("com.lagmachine.conduct.department") + asset = self.svg.get("com.lagmachine.conduct.asset") + + prev_state = self.svg.get("com.lagmachine.conduct.export_save_state") + prev_state = json.loads(prev_state) + + c = conduct.find_from_current_path(file_path, "inkscape") + + pages = self.svg.namedview.get_pages() + items = ','.join([page.label for page in pages]) + + + result = c.dialog_export(department, asset, items, prev_state=prev_state) + + if result['result'] != 'ok': + return + + save_state = result['data']['save_state'] + self.svg.set("com.lagmachine.conduct.export_save_state", save_state) + + for export in result['data']['exports']: + items = export['items'] + export_data = export['result'] + if 'error' in export_data: + log(export_data['error']) + return + export_pages = [page for page in pages if page.label in items] + + locals = {} + globals = {} + script = export_data['script'] + exec(script, locals, globals) + + for item in globals: + instance = globals[item] + + if not inspect.isclass(instance): + continue + + exporter_instance = instance() + + exporter_instance.export( + self, + directory=export_data['directory'], + file_name=export_data['recommended_file_name'], + extension=export_data['file_format'], + items = export_pages + ) + + return + + +if __name__ == '__main__': + ConductExportEffect().run() diff --git a/integration/inkscape/shell.nix b/integration/inkscape/shell.nix new file mode 100644 index 0000000..8019118 --- /dev/null +++ b/integration/inkscape/shell.nix @@ -0,0 +1,12 @@ + +let pkgs = import {}; + +shell = pkgs.mkShell { + buildInputs = with pkgs; [ + inkscape + ]; + + WEBKIT_DISABLE_COMPOSITING_MODE=1; +}; + +in shell